diff --git a/evennia/commands/command.py b/evennia/commands/command.py index 5a2f47b819..f1a0c9e77a 100644 --- a/evennia/commands/command.py +++ b/evennia/commands/command.py @@ -318,8 +318,11 @@ class Command(with_metaclass(CommandMeta, object)): """ from_obj = from_obj or self.caller to_obj = to_obj or from_obj - if not session or to_obj == self.caller: - session = to_obj.sessions.get() + if not session: + if to_obj == self.caller: + session = self.session + else: + session = to_obj.sessions.get() to_obj.msg(msg, from_obj=from_obj, session=session, **kwargs) # Common Command hooks diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index bf979e6ca2..4d2bcf8bc8 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -1870,7 +1870,7 @@ class CmdExamine(ObjManipCommand): string += "\n{wAliases{n: %s" % (", ".join(utils.make_iter(str(obj.aliases)))) if hasattr(obj, "sessions") and obj.sessions: string += "\n{wsession(s){n: %s" % (", ".join(str(sess.sessid) - for sess in obj.sessions)) + for sess in obj.sessions.all())) if hasattr(obj, "has_player") and obj.has_player: string += "\n{wPlayer{n: {c%s{n" % obj.player.name perms = obj.player.permissions.all() diff --git a/evennia/commands/default/player.py b/evennia/commands/default/player.py index 8720879ddb..3a78bab454 100644 --- a/evennia/commands/default/player.py +++ b/evennia/commands/default/player.py @@ -276,7 +276,7 @@ class CmdSessions(MuxPlayerCommand): def func(self): "Implement function" player = self.player - sessions = player.get_all_sessions() + sessions = player.sessions.all() table = prettytable.PrettyTable(["{wsessid", "{wprotocol", @@ -284,9 +284,8 @@ class CmdSessions(MuxPlayerCommand): "{wpuppet/character", "{wlocation"]) for sess in sorted(sessions, key=lambda x: x.sessid): - sessid = sess.sessid - char = player.get_puppet(sessid) - table.add_row([str(sessid), str(sess.protocol_key), + char = player.get_puppet(sess) + table.add_row([str(sess.sessid), str(sess.protocol_key), type(sess.address) == tuple and sess.address[0] or sess.address, char and str(char) or "None", char and str(char.location) or "N/A"]) @@ -602,7 +601,7 @@ class CmdQuell(MuxPlayerCommand): def _recache_locks(self, player): "Helper method to reset the lockhandler on an already puppeted object" if self.session: - char = session.puppet + char = self.session.puppet if char: # we are already puppeting an object. We need to reset # the lock caches (otherwise the superuser status change diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 2af78f0c11..fc2d64a6da 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -48,7 +48,7 @@ class ObjectSessionHandler(object): """ self.obj = obj - self._cache = set() + self._sessid_cache = set() self._recache() def _recache(self): @@ -149,8 +149,9 @@ class ObjectSessionHandler(object): Returns: sesslen (int): Number of sessions handled. + """ - return len(self._cache) + return len(self._sessid_cache) @@ -470,6 +471,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): # relay to session(s) sessions = make_iter(session) if session else self.sessions.all() + from evennia.utils.utils import calledby for session in sessions: session.msg(text=text, **kwargs) @@ -478,8 +480,12 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): Runs a function on every object contained within this one. Args: - func (callable): Function to call. - exclude (list, optional): A list of object not to call the function on. + func (callable): Function to call. This must have the + formal call sign func(obj, **kwargs), where obj is the + object currently being processed and `**kwargs` are + passed on from the call to `for_contents`. + exclude (list, optional): A list of object not to call the + function on. Kwargs: Keyword arguments will be passed to the function for all objects. @@ -771,7 +777,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): # See if we need to kick the player off. - for session in self.sessions: + for session in self.sessions.all(): session.msg(_("Your character %s has been destroyed.") % self.key) # no need to disconnect, Player just jumps to OOC mode. # sever the connection (important!) @@ -1472,12 +1478,14 @@ class DefaultCharacter(DefaultObject): session (Session): Session controlling the connection that just disconnected. """ - if self.location: # have to check, in case of multiple connections closing - def message(obj, from_obj): - obj.msg("%s has left the game." % self.get_display_name(obj), from_obj=from_obj) - self.location.for_contents(message, exclude=[self], from_obj=self) - self.db.prelogout_location = self.location - self.location = None + if not self.sessions.count(): + # only remove this char from grid if no sessions control it anymore. + if self.location: + def message(obj, from_obj): + obj.msg("%s has left the game." % self.get_display_name(obj), from_obj=from_obj) + self.location.for_contents(message, exclude=[self], from_obj=self) + self.db.prelogout_location = self.location + self.location = None # # Base Room object diff --git a/evennia/players/bots.py b/evennia/players/bots.py index 5ce4ba77bf..4eacf54182 100644 --- a/evennia/players/bots.py +++ b/evennia/players/bots.py @@ -155,7 +155,7 @@ class Bot(DefaultPlayer): a reset. """ - for session in self.get_all_sessions(): + for session in self.sessions.all(): session.sessionhandler.disconnect(session) diff --git a/evennia/players/players.py b/evennia/players/players.py index a2e6bbc0fb..b77f41a3d0 100644 --- a/evennia/players/players.py +++ b/evennia/players/players.py @@ -87,6 +87,16 @@ class PlayerSessionHandler(object): """ return self.get() + def count(self): + """ + Get amount of sessions connected. + + Returns: + sesslen (int): Number of sessions handled. + + """ + return len(self.get()) + class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): @@ -290,7 +300,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): obj.sessions.remove(session) if not obj.sessions.count(): del obj.player - obj.at_post_unpuppet(self, session=session) + obj.at_post_unpuppet(self, session=session) # Just to be sure we're always clear. session.puppet = None session.puid = None @@ -357,7 +367,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): mechanism (these are usually not used). """ - for session in self.get_all_sessions(): + for session in self.sessions.all(): # unpuppeting all objects and disconnecting the user, if any # sessions remain (should usually be handled from the # deleting command) @@ -786,7 +796,6 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): else: # list of targets - make list characters = target - sessions = self.sessions.all() is_su = self.is_superuser @@ -798,7 +807,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): for isess, sess in enumerate(sessions): csessid = sess.sessid addr = "%s (%s)" % (sess.protocol_key, isinstance(sess.address, tuple) and str(sess.address[0]) or str(sess.address)) - string += "\n %s %s" % (session.sessid == csessid and "{w%s{n" % (isess + 1) or (isess + 1), addr) + string += "\n %s %s" % (session.sessid == csessid and "{w* %s{n" % (isess + 1) or " %s" % (isess + 1), addr) string += "\n\n {whelp{n - more commands" string += "\n {wooc {n - talk on public channel" @@ -821,13 +830,14 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): for char in characters: csessions = char.sessions.all() - for sess in csessions: - # character is already puppeted - sid = sess in sessions and sessions.index(sess) + 1 - if sess and sid: - string += "\n - {G%s{n [%s] (played by you in session %i)" % (char.key, ", ".join(char.permissions.all()), sid) - else: - string += "\n - {R%s{n [%s] (played by someone else)" % (char.key, ", ".join(char.permissions.all())) + if csessions: + for sess in csessions: + # character is already puppeted + sid = sess in sessions and sessions.index(sess) + 1 + if sess and sid: + string += "\n - {G%s{n [%s] (played by you in session %i)" % (char.key, ", ".join(char.permissions.all()), sid) + else: + string += "\n - {R%s{n [%s] (played by someone else)" % (char.key, ", ".join(char.permissions.all())) else: # character is "free to puppet" string += "\n - %s [%s]" % (char.key, ", ".join(char.permissions.all())) diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index cc1f0bd922..47b7f90c90 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -443,10 +443,11 @@ class ServerSessionHandler(SessionHandler): Get session based on sessid, or None if not found Args: - sessid (int or list): Session id(s) + sessid (int or list): Session id(s). Return: - sessions (Session or list): Session(s) found. + sessions (Session or list): Session(s) found. This + is a list if input was a list. """ if is_iter(sessid): diff --git a/evennia/utils/test_resources.py b/evennia/utils/test_resources.py index d8eefd75d3..a4cf63a98c 100644 --- a/evennia/utils/test_resources.py +++ b/evennia/utils/test_resources.py @@ -50,11 +50,12 @@ class EvenniaTest(TestCase): # set up a fake session - session = ServerSession() - session.init_session("telnet", ("localhost", "testmode"), SESSIONS) - session.sessid = 1 - SESSIONS.portal_connect(session.get_sync_data()) - SESSIONS.login(SESSIONS.session_from_sessid(1), self.player, testmode=True) + dummysession = ServerSession() + dummysession.init_session("telnet", ("localhost", "testmode"), SESSIONS) + dummysession.sessid = 1 + SESSIONS.portal_connect(dummysession.get_sync_data()) # note that this creates a new Session! + session = SESSIONS.session_from_sessid(1) # the real session + SESSIONS.login(session, self.player, testmode=True) self.session = session def tearDown(self):