From 20a57d4167fa762d46d022c07d09b80f8fed0dfe Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 6 Apr 2013 21:36:52 +0200 Subject: [PATCH] Further fixes to the system, still some issues remaining. --- src/commands/default/general.py | 2 +- src/objects/objects.py | 112 ++++++++++++++++++++++---------- src/players/models.py | 45 +++++++------ src/players/player.py | 13 ++-- src/server/initial_setup.py | 2 +- src/server/server.py | 2 +- src/server/serversession.py | 12 ++-- 7 files changed, 119 insertions(+), 69 deletions(-) diff --git a/src/commands/default/general.py b/src/commands/default/general.py index b6b8243c8c..69471d615e 100644 --- a/src/commands/default/general.py +++ b/src/commands/default/general.py @@ -978,7 +978,7 @@ class CmdIC(MuxCommandOOC): return if caller.connect_character(new_character, sessid=sessid): self.msg("\n{gYou become {c%s{n.\n" % new_character.name) - caller.db.last_puppet = old_character + caller.db._last_puppet = old_character if not new_character.location: # this might be due to being hidden away at logout; check loc = new_character.db.prelogout_location diff --git a/src/objects/objects.py b/src/objects/objects.py index ff7bdc9f2b..ae47bce206 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -106,11 +106,11 @@ class Object(TypeClass): inside a deleted object are automatically moved to their , they don't need to be removed here. at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload - at_cmdset_get() - this is called just before the command handler requests a cmdset from this object - at_first_login() - (player-controlled objects only) called once, the very first time user logs in. - at_pre_login() - (player-controlled objects only) called every time the user connects, after they have identified, before other setup - at_post_login() - (player-controlled objects only) called at the end of login, just before setting the player loose in the world. - at_disconnect() - (player-controlled objects only) called just before the user disconnects (or goes linkless) + at_cmdset_get() - this is called just before the command handler requests a cmdset from this objecth + at_pre_puppet(player)- (player-controlled objects only) called just before puppeting + at_post_puppet() - (player-controlled objects only) called just after completing connection player<->object + at_pre_unpuppet() - (player-controlled objects only) called just before un-puppeting + at_post_unpuppet(player) - (player-controlled objects only) called just after disconnecting player<->object link at_server_reload() - called before server is reloaded at_server_shutdown() - called just before server is fully shut down @@ -458,33 +458,66 @@ class Object(TypeClass): """ pass - def at_first_login(self): + def at_pre_puppet(self, player): """ - Only called once, the very first - time the user logs in. - """ - pass - def at_pre_login(self): - """ - Called every time the user logs in, - before they are actually logged in. - """ - pass - def at_post_login(self): - """ - Called at the end of the login - process, just before letting - them loose. + Called just before a Player connects to this object + to puppet it. + + player - connecting player object """ pass - def at_disconnect(self): + def at_post_puppet(self): """ - Called just before user - is disconnected. + Called just after puppeting has been completed and + all Player<->Object links have been established. """ pass + def at_pre_unpuppet(self): + """ + Called just before beginning to un-connect a puppeting + from this Player. + """ + pass + + def at_post_unpuppet(self, player): + """ + Called just after the Player successfully disconnected + from this object, severing all connections. + + player - the player object that just disconnected from + this object. + """ + pass + + #def at_first_login(self): + # """ + # Only called once, the very first + # time the user logs in. + # """ + # pass + #def at_pre_login(self): + # """ + # Called every time the user logs in, + # before they are actually logged in. + # """ + # pass + #def at_post_login(self): + # """ + # Called at the end of the login + # process, just before letting + # them loose. + # """ + # pass + + #def at_disconnect(self): + # """ + # Called just before user + # is disconnected. + # """ + # pass + def at_server_reload(self): """ This hook is called whenever the server is shutting down for restart/reboot. @@ -780,21 +813,12 @@ class Character(Object): "Default is to look around after a move." self.execute_cmd('look') - def at_disconnect(self): + def at_pre_puppet(self, player): """ - We stove away the character when logging off, otherwise the character object will - remain in the room also after the player logged off ("headless", so to say). + This recovers the character again after having been "stoved away" at the unpuppet """ - if self.location: # have to check, in case of multiple connections closing - self.location.msg_contents("%s has left the game." % self.name, exclude=[self]) - self.db.prelogout_location = self.location - self.location = None + print "object at_pre_puppet", self, player - def at_post_login(self): - """ - This recovers the character again after having been "stoved away" at disconnect. - """ - print "char:at_post_login", self if self.db.prelogout_location: # try to recover self.location = self.db.prelogout_location @@ -806,8 +830,24 @@ class Character(Object): self.location.msg_contents("%s has entered the game." % self.name, exclude=[self]) self.location.at_object_receive(self, self.location) + + def at_post_puppet(self): + "Once puppeting is complete, make sure to view the location." # call look + print "object at_post_puppet", self self.execute_cmd("look") + + def at_post_unpuppet(self, player): + """ + We stove away the character when the player goes ooc/logs off, otherwise the character object will + remain in the room also after the player logged off ("headless", so to say). + """ + print "at_post_unpuppet", player + if self.location: # have to check, in case of multiple connections closing + self.location.msg_contents("%s has left the game." % self.name, exclude=[self]) + self.db.prelogout_location = self.location + self.location = None + # # Base Room object # diff --git a/src/players/models.py b/src/players/models.py index aa167e2c64..bf7a512399 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -31,6 +31,7 @@ from django.utils.encoding import smart_str 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 from src.players import manager +from src.scripts.models import ScriptDB from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler from src.typeclasses.typeclass import TypeClass from src.commands.cmdsethandler import CmdSetHandler @@ -364,8 +365,6 @@ class PlayerDB(TypedObject): data - dictionary of optional data sessid - session sending this data """ - if _MULTISESSION_MODE < 2: - sessid = None character = _GA(self, "get_character")(sessid=sessid) if character: # execute command on character @@ -406,15 +405,18 @@ class PlayerDB(TypedObject): """ sessions = self.get_session_from_sessid(sessid) for session in make_iter(sessions): + # this will also trigger disconnection of character(s) session.sessionhandler.disconnect(session) - def connect_session_to_character(self, sessid, character, force=False): + def connect_session_to_character(self, sessid, character, force=False, call_hooks=True): """ 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(). force - drop existing connection to other character + call_hooks - call puppet/unpuppet hooks. This is not wanted e.g. if + server is reloading Returns True if connection was successful, False otherwise """ @@ -425,24 +427,21 @@ class PlayerDB(TypedObject): _GA(self, "disconnect_session_from_character")(sessid) else: return + # pre-puppet hook + if call_hooks: + # if e.g. server reloads we don't want to call any hooks anew + _GA(character.typeclass, "at_pre_puppet")(self.typeclass) # 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: - # start (persistent) scripts on this object - #ScriptDB.objects.validate(obj=character) - pass - if character.db._first_login: - character.at_first_login() - del character.db._first_login - character.at_pre_login() - print "player: calling at_post_login on char" - character.at_post_login() + # start/validate (persistent) scripts on this object + ScriptDB.objects.validate(obj=character) + # post-puppet hook + if call_hooks: + _GA(character.typeclass, "at_post_puppet")() return True def disconnect_session_from_character(self, sessid): @@ -451,21 +450,26 @@ class PlayerDB(TypedObject): connection to the Player) returns the newly disconnected character, if it existed """ + print "player disconnect_session_from_character", sessid if not sessid: return char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True) + print char if char: # call hook before disconnecting - _GA(char.typeclass, "at_disconnect")() + _GA(char.typeclass, "at_pre_unpuppet")() 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) + # call post-unpuppet hook + _GA(char.typeclass, "at_post_unpuppet")(self.typeclass) + print "... leaving player disconnect_session_from_character", sessid return char - def reconnect_session_to_character(self, sessid): + def server_reconnect_session_to_character(self, sessid): """ Auto-re-connect a session to a character. This is called by the sessionhandler during a server reload. It goes through the characters stored in this player's @@ -478,19 +482,20 @@ class PlayerDB(TypedObject): char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True) if not char: return - _GA(self, "connect_session_to_character")(sessid, char, force=True) + _GA(self, "connect_session_to_character")(sessid, char, force=True, call_hooks=False) def get_character(self, sessid=None, character=None, return_dbobj=False): """ - Get the character connected to this player and sessid + Get the character connected to this player and sessid. This is the main + method for retrieving the character from the player's end. 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. + keywords are given, returns all connected characters as a list. """ cache = get_prop_cache(self, "_characters") or {} if sessid: diff --git a/src/players/player.py b/src/players/player.py index 5a96c49e78..1074b56827 100644 --- a/src/players/player.py +++ b/src/players/player.py @@ -296,9 +296,10 @@ class Player(TypeClass): def at_pre_login(self): """ - Called every time the user logs in, - before they are actually logged in. + Called every time the user logs in, just before the actual + login-state is set. """ + print "player at_pre_login", self pass def _send_to_connect_channel(self, message): @@ -322,6 +323,7 @@ class Player(TypeClass): them loose. This is called before an eventual Character's at_post_login hook. """ + print "player at_post_login", self self._send_to_connect_channel("{G%s connected{n" % self.key) if _MULTISESSION_MODE == 2 or not self.get_all_characters(): @@ -331,10 +333,11 @@ class Player(TypeClass): def at_disconnect(self, reason=None): """ - Called just before user - is disconnected. + Called just before user is disconnected. """ - self._send_to_connect_channel("{R%s disconnected{n" % self.key) + print "player at_disconnect", self + reason = reason and "(%s)" % reason or "" + self._send_to_connect_channel("{R%s disconnected %s{n" % (self.key, reason)) def at_message_receive(self, message, from_obj=None): """ diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index 5dde6350e0..28498da5ba 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -61,7 +61,7 @@ def create_objects(): god_character.save() god_character.set_attribute("_superuser_character", True) - gor_character.set_attribute("_first_login", True) + god_character.set_attribute("_first_login", True) # Limbo is the default "nowhere" starting room diff --git a/src/server/server.py b/src/server/server.py index 8d96184df2..23c24bad7e 100644 --- a/src/server/server.py +++ b/src/server/server.py @@ -272,7 +272,7 @@ class Evennia(object): yield [(o.typeclass, o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()] else: # shutdown yield [_SA(p, "is_connected", False) for p in PlayerDB.get_all_cached_instances()] - yield [(o.typeclass, o.at_disconnect(), o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()] + yield [(o.typeclass, o.at_server_shutdown()) for o in ObjectDB.get_all_cached_instances()] yield [(p.typeclass, p.at_server_shutdown()) for p in PlayerDB.get_all_cached_instances()] yield [(s.typeclass, s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances()] diff --git a/src/server/serversession.py b/src/server/serversession.py index 59f5953f0c..41e47ab0b3 100644 --- a/src/server/serversession.py +++ b/src/server/serversession.py @@ -17,6 +17,7 @@ from src.commands import cmdhandler, cmdsethandler from src.server.session import Session IDLE_COMMAND = settings.IDLE_COMMAND +_GA = object.__getattribute__ # load optional out-of-band function module OOB_FUNC_MODULE = settings.OOB_FUNC_MODULE @@ -57,7 +58,7 @@ class ServerSession(Session): self.cmdset.update(init_mode=True) return else: - self.player.reconnect_session_to_character(self.sessid) + self.player.server_reconnect_session_to_character(self.sessid) def at_login(self, player): """ @@ -83,17 +84,18 @@ class ServerSession(Session): if self.logged_in: sessid = self.sessid player = self.player - if player.get_character(sessid): - player.disconnect_session_from_character(sessid) - uaccount = player.user + print "session at_disconnect", self + _GA(player.dbobj, "disconnect_session_from_character")(sessid) + uaccount = _GA(player.dbobj, "user") uaccount.last_login = datetime.now() uaccount.save() + # calling player hook + _GA(player.typeclass, "at_disconnect")() self.logged_in = False if not self.sessionhandler.sessions_from_player(player): # no more sessions connected to this player player.is_connected = False - def get_player(self): """ Get the player associated with this session