Added sessids to command objects and changed how the "login"-hooks are called. Those will probably have to be changed to better names, at least for characters.
This commit is contained in:
parent
231af4a351
commit
00584365ae
5 changed files with 113 additions and 96 deletions
|
|
@ -41,7 +41,6 @@ from twisted.internet.defer import inlineCallbacks, returnValue
|
|||
from django.conf import settings
|
||||
from src.comms.channelhandler import CHANNELHANDLER
|
||||
from src.utils import logger, utils
|
||||
from src.commands.cmdset import CmdSet
|
||||
from src.commands.cmdparser import at_multimatch_cmd
|
||||
from src.utils.utils import string_suggestions
|
||||
|
||||
|
|
@ -165,7 +164,7 @@ def get_and_merge_cmdsets(caller):
|
|||
# Main command-handler function
|
||||
|
||||
@inlineCallbacks
|
||||
def cmdhandler(caller, raw_string, testing=False):
|
||||
def cmdhandler(caller, raw_string, testing=False, sessid=None):
|
||||
"""
|
||||
This is the main function to handle any string sent to the engine.
|
||||
|
||||
|
|
@ -251,6 +250,7 @@ def cmdhandler(caller, raw_string, testing=False):
|
|||
cmd.cmdstring = cmdname
|
||||
cmd.args = args
|
||||
cmd.cmdset = cmdset
|
||||
cmd.sessid = sessid
|
||||
cmd.raw_string = unformatted_raw_string
|
||||
|
||||
if hasattr(cmd, 'obj') and hasattr(cmd.obj, 'scripts'):
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from django.conf import settings
|
|||
from src.utils.idmapper.models import SharedMemoryModel
|
||||
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
|
||||
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
|
||||
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache, hashid
|
||||
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
|
||||
from src.typeclasses.typeclass import TypeClass
|
||||
from src.players.models import PlayerNick
|
||||
from src.objects.manager import ObjectManager
|
||||
|
|
@ -178,7 +178,7 @@ class ObjectDB(TypedObject):
|
|||
help_text='a Player connected to this object, if any.')
|
||||
# the session id associated with this player, if any
|
||||
db_sessid = models.IntegerField(null=True, verbose_name="session id",
|
||||
help_text="unique session id of connected Player, if any."
|
||||
help_text="unique session id of connected Player, if any.")
|
||||
# The location in the game world. Since this one is likely
|
||||
# to change often, we set this with the 'location' property
|
||||
# to transparently handle Typeclassing.
|
||||
|
|
@ -271,20 +271,18 @@ class ObjectDB(TypedObject):
|
|||
a sessid without a player being connected (but the
|
||||
opposite could be true).
|
||||
"""
|
||||
if not get_field_cache(self, "player"):
|
||||
if not get_field_cache(self, "sessid"):
|
||||
del_field_cache(self, "sessid")
|
||||
return get_field_cache(self, "sessid")
|
||||
#@sessid.setter
|
||||
def __sessid_set(self, player):
|
||||
def __sessid_set(self, sessid):
|
||||
"Setter. Allows for self.player = value"
|
||||
if inherits_from(player, TypeClass):
|
||||
player = player.dbobj
|
||||
set_field_cache(self, "player", player)
|
||||
set_field_cache(self, "sessid", sessid)
|
||||
#@sessid.deleter
|
||||
def __player_del(self):
|
||||
def __sessid_del(self):
|
||||
"Deleter. Allows for del self.player"
|
||||
del_field_cache(self, "player")
|
||||
player = property(__player_get, __player_set, __player_del)
|
||||
del_field_cache(self, "sessid")
|
||||
player = property(__sessid_get, __sessid_set, __sessid_del)
|
||||
# location property (wraps db_location)
|
||||
#@property
|
||||
def __location_get(self):
|
||||
|
|
@ -637,7 +635,7 @@ class ObjectDB(TypedObject):
|
|||
# Execution/action methods
|
||||
#
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
def execute_cmd(self, raw_string, sessid=None):
|
||||
"""
|
||||
Do something as this object. This command transparently
|
||||
lets its typeclass execute the command. Evennia also calls
|
||||
|
|
@ -669,11 +667,11 @@ class ObjectDB(TypedObject):
|
|||
if nick.db_nick in raw_list:
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string)
|
||||
return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string, sessid=sessid)
|
||||
|
||||
def msg(self, message, from_obj=None, data=None):
|
||||
"""
|
||||
Emits something to any sessions attached to the object.
|
||||
Emits something to a session attached to the object.
|
||||
|
||||
message (str): The message to send
|
||||
from_obj (obj): object that is sending.
|
||||
|
|
@ -681,8 +679,8 @@ class ObjectDB(TypedObject):
|
|||
be used by the protocol.
|
||||
"""
|
||||
if _GA(self, 'player'):
|
||||
# note that we check the typeclass' msg, otherwise one couldn't overload it.
|
||||
_GA(_GA(self, 'player'), "typeclass").msg(message, from_obj=from_obj, data=data)
|
||||
# note that we must call the player *typeclass'* msg(), otherwise one couldn't overload it.
|
||||
_GA(_GA(self, 'player'), "typeclass").msg(message, from_obj=from_obj, data=data, sessid=_GA(self, "sessid"))
|
||||
|
||||
def emit_to(self, message, from_obj=None, data=None):
|
||||
"Deprecated. Alias for msg"
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ class PlayerDB(TypedObject):
|
|||
for sess in _GA(self, 'get_sessions'):
|
||||
sess.msg(outgoing_string, data)
|
||||
|
||||
def inmsg(self, ingoing_string, data, sessid):
|
||||
def inmsg(self, ingoing_string, sessid):
|
||||
"""
|
||||
This is the reverse of msg - used by sessions to relay
|
||||
messages/data back into the game. It is normally not called
|
||||
|
|
@ -400,58 +400,101 @@ class PlayerDB(TypedObject):
|
|||
character = _GA(self, "get_character")(sessid)
|
||||
if character:
|
||||
# execute command on character
|
||||
_GA(character, "execute_cmd")(ingoing_string)
|
||||
_GA(character, "execute_cmd")(ingoing_string, sessid=sessid)
|
||||
else:
|
||||
# a non-character session; this goes to player directly
|
||||
_GA(self, "execute_cmd")(ingoing_string)
|
||||
_GA(self, "execute_cmd")(ingoing_string, sessid=sessid)
|
||||
|
||||
def connect_session(self, sessid):
|
||||
"""
|
||||
Connect session to this player to a session through
|
||||
its session id.
|
||||
def connect_session_to_character(self, sessid, character, force=False):
|
||||
"""
|
||||
Connect the given session to a character through this player.
|
||||
Note that this assumes the character has previously been
|
||||
linked to the player using self.connect_character().
|
||||
|
||||
def get_session(self, sessid=None):
|
||||
force - drop existing connection to other character
|
||||
"""
|
||||
Return session with given sessid connected to this player. If sessid is
|
||||
not given, return all connected sessions.
|
||||
Note that this method will always return a list, even if it only has one
|
||||
(or zero) element(s).
|
||||
# first check if we already have a character tied to this session
|
||||
char = _GA(self, "get_character")(sessid=sessid)
|
||||
if char:
|
||||
if force and char != character:
|
||||
_GA(self, "disconnect_session_from_character")(sessid)
|
||||
else:
|
||||
return
|
||||
# do the connection
|
||||
character.sessid = sessid
|
||||
# update cache
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
cache[sessid] = character
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
# call hooks
|
||||
character.at_init()
|
||||
if character.db.FIRST_LOGIN:
|
||||
character.at_first_login()
|
||||
del character.db.FIRST_LOGIN
|
||||
character.at_pre_login()
|
||||
character.at_post_login()
|
||||
|
||||
def disconnect_session_from_character(self, sessid):
|
||||
"""
|
||||
Disconnect a session from the characterm (still keeping the
|
||||
connection to the Player)
|
||||
"""
|
||||
char = _GA(self, "get_character")(sessid=sessid)
|
||||
if char:
|
||||
del char.sessid
|
||||
# update cache
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
if sessid in cache:
|
||||
del cache[sessid]
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
|
||||
def get_session(self, sessid):
|
||||
"""
|
||||
Return session with given sessid connected to this player.
|
||||
"""
|
||||
return SESSIONS.get_session_from_player(self, sessid=sessid)
|
||||
|
||||
def get_character(self, sessid=None, key=None):
|
||||
def get_all_sessions(self):
|
||||
"Return all sessions connected to this player"
|
||||
return SESSIONS.get_session_from_player(self)
|
||||
|
||||
def get_character(self, sessid=None, character=None):
|
||||
"""
|
||||
Get the character connected through this sessid, if any. May also
|
||||
try to return a character based on key. If neither sessid nor key
|
||||
is given, return all characters connected to this player
|
||||
Get the character connected to this player
|
||||
|
||||
sessid - return character connected to this sessid,
|
||||
character - return character if connected to this player, else None.
|
||||
|
||||
Combining both keywords will check the entire connection - if the
|
||||
given session is currently connected to the given char. If no
|
||||
keywords are given, returns all connected characters.
|
||||
"""
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
if sessid:
|
||||
# try to return a character with a given sessid
|
||||
char = cache.get(sessid)
|
||||
if not char:
|
||||
char = self.db_objs.filter(player=self, sessid=sessid) or None
|
||||
char = _GA(self, "db_objs").filter(player=self, sessid=sessid) or None
|
||||
if char:
|
||||
cache[sessid] = char[0]
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
if key:
|
||||
return char.key.lower() == key.lower() and char or None
|
||||
if character:
|
||||
return char == character.dbobj or None
|
||||
return char
|
||||
elif key:
|
||||
char = self.db_objs.filter(player=self, db_key__iexact=key)
|
||||
elif character:
|
||||
char = _GA(self, "db_objs").filter(character)
|
||||
return char and char[0] or None
|
||||
else:
|
||||
# no sessid given - return all available characters
|
||||
return list(self.db_objs.filter(player=self, sessid=sessid))
|
||||
return list(self.db_objs.all())
|
||||
|
||||
def get_all_characters(self):
|
||||
"""
|
||||
Readability-wrapper for getting all characters
|
||||
"""
|
||||
return self.get_character(sessid=None)
|
||||
return _GA(self, "get_character")(sessid=None, character=None)
|
||||
|
||||
def connect_character(self, character, sessid):
|
||||
def connect_character(self, char):
|
||||
"""
|
||||
Use the Player to connect a Character to a session. Note that
|
||||
we don't do any access checks at this point. Note that if the
|
||||
|
|
@ -459,38 +502,34 @@ class PlayerDB(TypedObject):
|
|||
used, since sessids will have changed as players reconnect.
|
||||
"""
|
||||
# first disconnect any other character from this session
|
||||
self.disconnect_character(sessid=sessid)
|
||||
character = character.dbobj
|
||||
character.player = self
|
||||
character.sessid = sessid
|
||||
self.db_objs.add(character)
|
||||
self.save()
|
||||
# update cache
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
cache[sessid] = character
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
char = char.dbobj
|
||||
_GA(self, "disconnect_character")(char)
|
||||
char = char.dbobj
|
||||
char.player = self
|
||||
_GA(self, "db_objs").add(char)
|
||||
_GA(self, "save")()
|
||||
|
||||
def disconnect_character(self, sessid=None, char=None):
|
||||
def disconnect_character(self, char):
|
||||
"""
|
||||
Disconnect a character from this player, either based
|
||||
on sessid or by giving the character object directly
|
||||
"""
|
||||
char = char.dbobj
|
||||
key = char and char.key or None
|
||||
char = self.get_character(sessid=sessid, key=key)
|
||||
char = _GA(self, "get_character")(key=key)
|
||||
if char:
|
||||
self.db_objs.remove(char)
|
||||
_GA(self, "db_objs").remove(char)
|
||||
del char.player
|
||||
del char.sessid
|
||||
self.save()
|
||||
# clear cache
|
||||
cache = get_prop_cache(self, "_characters") or {}
|
||||
if cache and sessid in cache:
|
||||
del cache[sessid]
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
[cache.pop(sessid) for sessid,stored_char in cache.items() if stored_char==char]
|
||||
set_prop_cache(self, "_characters", cache)
|
||||
|
||||
def disconnect_all_characters(self):
|
||||
for char in self.db_objs.all():
|
||||
self.disconnect_character(char)
|
||||
_GA(self, "disconnect_character")(char)
|
||||
|
||||
def swap_character(self, new_character, delete_old_character=False):
|
||||
"""
|
||||
|
|
@ -514,7 +553,7 @@ class PlayerDB(TypedObject):
|
|||
# Execution/action methods
|
||||
#
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
def execute_cmd(self, raw_string, sessid=None):
|
||||
"""
|
||||
Do something as this player. This command transparently
|
||||
lets its typeclass execute the command.
|
||||
|
|
@ -530,7 +569,7 @@ class PlayerDB(TypedObject):
|
|||
if nick.db_nick in raw_list:
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
return cmdhandler.cmdhandler(self.typeclass, raw_string)
|
||||
return cmdhandler.cmdhandler(self.typeclass, raw_string, sessid=sessid)
|
||||
|
||||
def search(self, ostring, return_character=False):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -91,25 +91,14 @@ class ServerSession(Session):
|
|||
self.user.save()
|
||||
|
||||
# player init
|
||||
#print "at_init() - player"
|
||||
player.at_init()
|
||||
|
||||
# Check if this is the first time the *player* logs in
|
||||
if player.db.FIRST_LOGIN:
|
||||
player.at_first_login()
|
||||
del player.db.FIRST_LOGIN
|
||||
player.at_pre_login()
|
||||
|
||||
character = player.character
|
||||
if character:
|
||||
# this player has a character. Check if it's the
|
||||
# first time *this character* logs in
|
||||
character.at_init()
|
||||
if character.db.FIRST_LOGIN:
|
||||
character.at_first_login()
|
||||
del character.db.FIRST_LOGIN
|
||||
# run character login hook
|
||||
character.at_pre_login()
|
||||
player.at_pre_login()
|
||||
|
||||
self.log(_('Logged in: %(self)s') % {'self': self})
|
||||
|
||||
|
|
@ -119,10 +108,7 @@ class ServerSession(Session):
|
|||
#add session to connected list
|
||||
self.sessionhandler.login(self)
|
||||
|
||||
# post-login hooks
|
||||
player.at_post_login()
|
||||
if character:
|
||||
character.at_post_login()
|
||||
|
||||
def session_disconnect(self):
|
||||
"""
|
||||
|
|
@ -193,20 +179,13 @@ class ServerSession(Session):
|
|||
if str(command_string).strip() == IDLE_COMMAND:
|
||||
self.update_session_counters(idle=True)
|
||||
return
|
||||
|
||||
# all other inputs, including empty inputs
|
||||
character = self.get_character()
|
||||
if character:
|
||||
character.execute_cmd(command_string)
|
||||
if self.logged_in:
|
||||
# the inmsg handler will relay to the right place
|
||||
self.player.inmsg(command_string, self.sessid)
|
||||
else:
|
||||
if self.logged_in:
|
||||
# there is no character, but we are logged in. Use player instead.
|
||||
self.get_player().execute_cmd(command_string)
|
||||
else:
|
||||
# we are not logged in. Use the session directly
|
||||
# (it uses the settings.UNLOGGEDIN cmdset)
|
||||
cmdhandler.cmdhandler(self, command_string)
|
||||
self.update_session_counters()
|
||||
# we are not logged in. Use the session directly
|
||||
# (it uses the settings.UNLOGGEDIN cmdset)
|
||||
cmdhandler.cmdhandler(self, command_string)
|
||||
|
||||
def data_out(self, msg, data=None):
|
||||
"""
|
||||
|
|
@ -243,11 +222,11 @@ class ServerSession(Session):
|
|||
func = OOB_FUNC_MODULE.__dict__.get(functuple[0])
|
||||
if func:
|
||||
try:
|
||||
outdata[funcname] = func(oobkey, self, *functuple[1], **functuple[2])
|
||||
outdata[functuple[0]] = func(oobkey, self, *functuple[1], **functuple[2])
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
else:
|
||||
logger.log_errmsg("oob_data_in error: funcname '%s' not found in OOB_FUNC_MODULE." % funcname)
|
||||
logger.log_errmsg("oob_data_in error: funcname '%s' not found in OOB_FUNC_MODULE." % functuple[0])
|
||||
if outdata:
|
||||
# we have a direct result - send it back right away
|
||||
self.oob_data_out(outdata)
|
||||
|
|
|
|||
|
|
@ -223,8 +223,8 @@ class ServerSessionHandler(SessionHandler):
|
|||
|
||||
def player_count(self):
|
||||
"""
|
||||
Get the number of connected players (not sessions since a player
|
||||
may have more than one session connected if ALLOW_MULTISESSION is True)
|
||||
Get the number of connected players (not sessions since a
|
||||
player may have more than one session depending on settings).
|
||||
Only logged-in players are counted here.
|
||||
"""
|
||||
return len(set(session.uid for session in self.sessions.values() if session.logged_in))
|
||||
|
|
@ -235,7 +235,8 @@ class ServerSessionHandler(SessionHandler):
|
|||
"""
|
||||
uid = player.uid
|
||||
if sessid:
|
||||
return [session for session in self.sessions.values() if session.logged_in and session.sessid == sessid and session.uid == uid]
|
||||
session = self.sessions.get(sessid)
|
||||
return session and session.logged_in and session.uid == uid and session or None
|
||||
else:
|
||||
return [session for session in self.sessions.values() if session.logged_in and session.uid == uid]
|
||||
|
||||
|
|
@ -243,9 +244,9 @@ class ServerSessionHandler(SessionHandler):
|
|||
"""
|
||||
Given a game character, return any matching sessions.
|
||||
"""
|
||||
player = character.player
|
||||
if player:
|
||||
return self.sessions_from_player(player)
|
||||
sessid = character.sessid
|
||||
if sessid:
|
||||
return self.sessions.get(sessid)
|
||||
return None
|
||||
|
||||
def announce_all(self, message):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue