Further fixes to the system, still some issues remaining.

This commit is contained in:
Griatch 2013-04-06 21:36:52 +02:00
parent 9eb1903f02
commit 20a57d4167
7 changed files with 119 additions and 69 deletions

View file

@ -978,7 +978,7 @@ class CmdIC(MuxCommandOOC):
return return
if caller.connect_character(new_character, sessid=sessid): if caller.connect_character(new_character, sessid=sessid):
self.msg("\n{gYou become {c%s{n.\n" % new_character.name) 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: if not new_character.location:
# this might be due to being hidden away at logout; check # this might be due to being hidden away at logout; check
loc = new_character.db.prelogout_location loc = new_character.db.prelogout_location

View file

@ -106,11 +106,11 @@ class Object(TypeClass):
inside a deleted object are automatically moved to their <home>, they don't need to be removed here. inside a deleted object are automatically moved to their <home>, 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_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_cmdset_get() - this is called just before the command handler requests a cmdset from this objecth
at_first_login() - (player-controlled objects only) called once, the very first time user logs in. at_pre_puppet(player)- (player-controlled objects only) called just before puppeting
at_pre_login() - (player-controlled objects only) called every time the user connects, after they have identified, before other setup at_post_puppet() - (player-controlled objects only) called just after completing connection player<->object
at_post_login() - (player-controlled objects only) called at the end of login, just before setting the player loose in the world. at_pre_unpuppet() - (player-controlled objects only) called just before un-puppeting
at_disconnect() - (player-controlled objects only) called just before the user disconnects (or goes linkless) 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_reload() - called before server is reloaded
at_server_shutdown() - called just before server is fully shut down at_server_shutdown() - called just before server is fully shut down
@ -458,33 +458,66 @@ class Object(TypeClass):
""" """
pass pass
def at_first_login(self): def at_pre_puppet(self, player):
""" """
Only called once, the very first Called just before a Player connects to this object
time the user logs in. to puppet it.
"""
pass player - connecting player object
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 pass
def at_disconnect(self): def at_post_puppet(self):
""" """
Called just before user Called just after puppeting has been completed and
is disconnected. all Player<->Object links have been established.
""" """
pass 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): def at_server_reload(self):
""" """
This hook is called whenever the server is shutting down for restart/reboot. 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." "Default is to look around after a move."
self.execute_cmd('look') 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 This recovers the character again after having been "stoved away" at the unpuppet
remain in the room also after the player logged off ("headless", so to say).
""" """
if self.location: # have to check, in case of multiple connections closing print "object at_pre_puppet", self, player
self.location.msg_contents("%s has left the game." % self.name, exclude=[self])
self.db.prelogout_location = self.location
self.location = None
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: if self.db.prelogout_location:
# try to recover # try to recover
self.location = self.db.prelogout_location 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.msg_contents("%s has entered the game." % self.name, exclude=[self])
self.location.at_object_receive(self, self.location) 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 # call look
print "object at_post_puppet", self
self.execute_cmd("look") 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 # Base Room object
# #

View file

@ -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_field_cache, set_field_cache, del_field_cache
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
from src.players import manager from src.players import manager
from src.scripts.models import ScriptDB
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
from src.typeclasses.typeclass import TypeClass from src.typeclasses.typeclass import TypeClass
from src.commands.cmdsethandler import CmdSetHandler from src.commands.cmdsethandler import CmdSetHandler
@ -364,8 +365,6 @@ class PlayerDB(TypedObject):
data - dictionary of optional data data - dictionary of optional data
sessid - session sending this data sessid - session sending this data
""" """
if _MULTISESSION_MODE < 2:
sessid = None
character = _GA(self, "get_character")(sessid=sessid) character = _GA(self, "get_character")(sessid=sessid)
if character: if character:
# execute command on character # execute command on character
@ -406,15 +405,18 @@ class PlayerDB(TypedObject):
""" """
sessions = self.get_session_from_sessid(sessid) sessions = self.get_session_from_sessid(sessid)
for session in make_iter(sessions): for session in make_iter(sessions):
# this will also trigger disconnection of character(s)
session.sessionhandler.disconnect(session) 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. Connect the given session to a character through this player.
Note that this assumes the character has previously been Note that this assumes the character has previously been
linked to the player using self.connect_character(). linked to the player using self.connect_character().
force - drop existing connection to other 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 Returns True if connection was successful, False otherwise
""" """
@ -425,24 +427,21 @@ class PlayerDB(TypedObject):
_GA(self, "disconnect_session_from_character")(sessid) _GA(self, "disconnect_session_from_character")(sessid)
else: else:
return 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 # do the connection
character.sessid = sessid character.sessid = sessid
# update cache # update cache
cache = get_prop_cache(self, "_characters") or {} cache = get_prop_cache(self, "_characters") or {}
cache[sessid] = character cache[sessid] = character
set_prop_cache(self, "_characters", cache) set_prop_cache(self, "_characters", cache)
# call hooks # start/validate (persistent) scripts on this object
character.at_init() ScriptDB.objects.validate(obj=character)
if character: # post-puppet hook
# start (persistent) scripts on this object if call_hooks:
#ScriptDB.objects.validate(obj=character) _GA(character.typeclass, "at_post_puppet")()
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()
return True return True
def disconnect_session_from_character(self, sessid): def disconnect_session_from_character(self, sessid):
@ -451,21 +450,26 @@ class PlayerDB(TypedObject):
connection to the Player) connection to the Player)
returns the newly disconnected character, if it existed returns the newly disconnected character, if it existed
""" """
print "player disconnect_session_from_character", sessid
if not sessid: if not sessid:
return return
char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True) char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True)
print char
if char: if char:
# call hook before disconnecting # call hook before disconnecting
_GA(char.typeclass, "at_disconnect")() _GA(char.typeclass, "at_pre_unpuppet")()
del char.sessid del char.sessid
# update cache # update cache
cache = get_prop_cache(self, "_characters") or {} cache = get_prop_cache(self, "_characters") or {}
if sessid in cache: if sessid in cache:
del cache[sessid] del cache[sessid]
set_prop_cache(self, "_characters", cache) 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 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 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 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) char = _GA(self, "get_character")(sessid=sessid, return_dbobj=True)
if not char: if not char:
return 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): 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, sessid - return character connected to this sessid,
character - return character if connected to this player, else None. character - return character if connected to this player, else None.
Combining both keywords will check the entire connection - if the Combining both keywords will check the entire connection - if the
given session is currently connected to the given char. If no 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 {} cache = get_prop_cache(self, "_characters") or {}
if sessid: if sessid:

View file

@ -296,9 +296,10 @@ class Player(TypeClass):
def at_pre_login(self): def at_pre_login(self):
""" """
Called every time the user logs in, Called every time the user logs in, just before the actual
before they are actually logged in. login-state is set.
""" """
print "player at_pre_login", self
pass pass
def _send_to_connect_channel(self, message): def _send_to_connect_channel(self, message):
@ -322,6 +323,7 @@ class Player(TypeClass):
them loose. This is called before an eventual Character's them loose. This is called before an eventual Character's
at_post_login hook. at_post_login hook.
""" """
print "player at_post_login", self
self._send_to_connect_channel("{G%s connected{n" % self.key) self._send_to_connect_channel("{G%s connected{n" % self.key)
if _MULTISESSION_MODE == 2 or not self.get_all_characters(): if _MULTISESSION_MODE == 2 or not self.get_all_characters():
@ -331,10 +333,11 @@ class Player(TypeClass):
def at_disconnect(self, reason=None): def at_disconnect(self, reason=None):
""" """
Called just before user Called just before user is disconnected.
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): def at_message_receive(self, message, from_obj=None):
""" """

View file

@ -61,7 +61,7 @@ def create_objects():
god_character.save() god_character.save()
god_character.set_attribute("_superuser_character", True) 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 # Limbo is the default "nowhere" starting room

View file

@ -272,7 +272,7 @@ class Evennia(object):
yield [(o.typeclass, 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()]
else: # shutdown else: # shutdown
yield [_SA(p, "is_connected", False) for p in PlayerDB.get_all_cached_instances()] 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 [(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()] yield [(s.typeclass, s.at_server_shutdown()) for s in ScriptDB.get_all_cached_instances()]

View file

@ -17,6 +17,7 @@ from src.commands import cmdhandler, cmdsethandler
from src.server.session import Session from src.server.session import Session
IDLE_COMMAND = settings.IDLE_COMMAND IDLE_COMMAND = settings.IDLE_COMMAND
_GA = object.__getattribute__
# load optional out-of-band function module # load optional out-of-band function module
OOB_FUNC_MODULE = settings.OOB_FUNC_MODULE OOB_FUNC_MODULE = settings.OOB_FUNC_MODULE
@ -57,7 +58,7 @@ class ServerSession(Session):
self.cmdset.update(init_mode=True) self.cmdset.update(init_mode=True)
return return
else: else:
self.player.reconnect_session_to_character(self.sessid) self.player.server_reconnect_session_to_character(self.sessid)
def at_login(self, player): def at_login(self, player):
""" """
@ -83,17 +84,18 @@ class ServerSession(Session):
if self.logged_in: if self.logged_in:
sessid = self.sessid sessid = self.sessid
player = self.player player = self.player
if player.get_character(sessid): print "session at_disconnect", self
player.disconnect_session_from_character(sessid) _GA(player.dbobj, "disconnect_session_from_character")(sessid)
uaccount = player.user uaccount = _GA(player.dbobj, "user")
uaccount.last_login = datetime.now() uaccount.last_login = datetime.now()
uaccount.save() uaccount.save()
# calling player hook
_GA(player.typeclass, "at_disconnect")()
self.logged_in = False self.logged_in = False
if not self.sessionhandler.sessions_from_player(player): if not self.sessionhandler.sessions_from_player(player):
# no more sessions connected to this player # no more sessions connected to this player
player.is_connected = False player.is_connected = False
def get_player(self): def get_player(self):
""" """
Get the player associated with this session Get the player associated with this session