Started work on #673; refactored the data flow. Still issues with correctly puppeting/unpuppeting in modes > 0.
This commit is contained in:
parent
c0aafe74ab
commit
a87fbff366
5 changed files with 141 additions and 102 deletions
|
|
@ -14,7 +14,7 @@ access the character when these commands are triggered with
|
||||||
a connected character (such as the case of the @ooc command), it
|
a connected character (such as the case of the @ooc command), it
|
||||||
is None if we are OOC.
|
is None if we are OOC.
|
||||||
|
|
||||||
Note that under MULTISESSION_MODE=2, Player- commands should use
|
Note that under MULTISESSION_MODE > 2, Player- commands should use
|
||||||
self.msg() and similar methods to reroute returns to the correct
|
self.msg() and similar methods to reroute returns to the correct
|
||||||
method. Otherwise all text will be returned to all connected sessions.
|
method. Otherwise all text will be returned to all connected sessions.
|
||||||
|
|
||||||
|
|
@ -249,10 +249,11 @@ class CmdIC(MuxPlayerCommand):
|
||||||
else:
|
else:
|
||||||
self.msg("That is not a valid character choice.")
|
self.msg("That is not a valid character choice.")
|
||||||
return
|
return
|
||||||
if player.puppet_object(sessid, new_character):
|
try:
|
||||||
|
player.puppet_object(sessid, new_character)
|
||||||
player.db._last_puppet = new_character
|
player.db._last_puppet = new_character
|
||||||
else:
|
except RuntimeError, exc:
|
||||||
self.msg("{rYou cannot become {C%s{n." % new_character.name)
|
self.msg("{rYou cannot become {C%s{n: %s" % (new_character.name, exc))
|
||||||
|
|
||||||
|
|
||||||
class CmdOOC(MuxPlayerCommand):
|
class CmdOOC(MuxPlayerCommand):
|
||||||
|
|
@ -287,11 +288,12 @@ class CmdOOC(MuxPlayerCommand):
|
||||||
player.db._last_puppet = old_char
|
player.db._last_puppet = old_char
|
||||||
|
|
||||||
# disconnect
|
# disconnect
|
||||||
if player.unpuppet_object(sessid):
|
try:
|
||||||
|
player.unpuppet_object(sessid)
|
||||||
self.msg("\n{GYou go OOC.{n\n")
|
self.msg("\n{GYou go OOC.{n\n")
|
||||||
player.execute_cmd("look", sessid=sessid)
|
player.execute_cmd("look", sessid=sessid)
|
||||||
else:
|
except RuntimeError, exc:
|
||||||
raise RuntimeError("Could not unpuppet!")
|
self.msg("{rCould not unpuppet from {c%s{n: %s" % (old_char, exc))
|
||||||
|
|
||||||
class CmdSessions(MuxPlayerCommand):
|
class CmdSessions(MuxPlayerCommand):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -501,23 +501,19 @@ class DefaultObject(ObjectDB):
|
||||||
"""
|
"""
|
||||||
Emits something to a session attached to the object.
|
Emits something to a session attached to the object.
|
||||||
|
|
||||||
message (str): The message to send
|
Args:
|
||||||
from_obj (obj): object that is sending.
|
text (str, optional): The message to send
|
||||||
data (object): an optional data object that may or may not
|
from_obj (obj, optional): object that is sending. If
|
||||||
be used by the protocol.
|
given, at_msg_send will be called
|
||||||
sessid (int): sessid to relay to, if any.
|
sessid (int or list, optional): sessid or list of
|
||||||
If set to 0 (default), use either from_obj.sessid (if set) or self.sessid automatically
|
sessids to relay to, if any. If set, will
|
||||||
If None, echo to all connected sessions
|
force send regardless of MULTISESSION_MODE.
|
||||||
|
Notes:
|
||||||
When this message is called, from_obj.at_msg_send and self.at_msg_receive are called.
|
`at_msg_receive` will be called on this Object.
|
||||||
|
All extra kwargs will be passed on to the protocol.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global _SESSIONS
|
|
||||||
if not _SESSIONS:
|
|
||||||
from evennia.server.sessionhandler import SESSIONS as _SESSIONS
|
|
||||||
|
|
||||||
text = to_str(text, force_string=True) if text else ""
|
text = to_str(text, force_string=True) if text else ""
|
||||||
|
|
||||||
if from_obj:
|
if from_obj:
|
||||||
# call hook
|
# call hook
|
||||||
try:
|
try:
|
||||||
|
|
@ -531,9 +527,25 @@ class DefaultObject(ObjectDB):
|
||||||
except Exception:
|
except Exception:
|
||||||
log_trace()
|
log_trace()
|
||||||
|
|
||||||
sessions = _SESSIONS.session_from_sessid([sessid] if sessid else make_iter(self.sessid.get()))
|
# session relay
|
||||||
for session in sessions:
|
|
||||||
session.msg(text=text, **kwargs)
|
if self.player:
|
||||||
|
# for there to be a session there must be a Player.
|
||||||
|
if sessid:
|
||||||
|
# this could still be an iterable if sessid is.
|
||||||
|
sessions = self.player.get_session(sessid)
|
||||||
|
if sessions:
|
||||||
|
# this is a special instruction to ignore MULTISESSION_MODE
|
||||||
|
# and only relay to this given session.
|
||||||
|
kwargs["_nomulti"] = True
|
||||||
|
for session in make_iter(sessions):
|
||||||
|
session.msg(text=text, **kwargs)
|
||||||
|
return
|
||||||
|
# we only send to the first of any connected sessions - the sessionhandler
|
||||||
|
# will disperse this to the other sessions based on MULTISESSION_MODE.
|
||||||
|
sessions = self.player.get_all_sessions()
|
||||||
|
if sessions:
|
||||||
|
sessions[0].msg(text=text, **kwargs)
|
||||||
|
|
||||||
def msg_contents(self, message, exclude=None, from_obj=None, **kwargs):
|
def msg_contents(self, message, exclude=None, from_obj=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -166,26 +166,30 @@ class DefaultPlayer(PlayerDB):
|
||||||
Use the given session to control (puppet) the given object (usually
|
Use the given session to control (puppet) the given object (usually
|
||||||
a Character type).
|
a Character type).
|
||||||
|
|
||||||
sessid - session id of session to connect
|
Args:
|
||||||
obj - the object to connect to
|
sessid (int): session id of session to connect
|
||||||
normal_mode - trigger hooks and extra checks - this is turned off when
|
obj (Object): the object to start puppeting
|
||||||
the server reloads, to quickly re-connect puppets.
|
normal_mode (bool, optional): trigger hooks and extra
|
||||||
|
checks - this is turned off when the server reloads, to
|
||||||
|
quickly re-connect puppets.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError with message if puppeting is not possible
|
||||||
|
|
||||||
returns True if successful, False otherwise
|
returns True if successful, False otherwise
|
||||||
"""
|
"""
|
||||||
# safety checks
|
# safety checks
|
||||||
if not obj:
|
if not obj:
|
||||||
return
|
raise RuntimeError("Object not found")
|
||||||
session = self.get_session(sessid)
|
session = self.get_session(sessid)
|
||||||
if not session:
|
if not session:
|
||||||
return False
|
raise RuntimeError("Session not found")
|
||||||
if self.get_puppet(sessid) == obj:
|
if self.get_puppet(sessid) == obj:
|
||||||
# already puppeting this object
|
# already puppeting this object
|
||||||
return
|
raise RuntimeError("You are already puppeting this object.")
|
||||||
if not obj.access(self, 'puppet'):
|
if not obj.access(self, 'puppet'):
|
||||||
# no access
|
# no access
|
||||||
self.msg("You don't have permission to puppet '%s'." % obj.key)
|
raise RuntimeError("You don't have permission to puppet '%s'." % obj.key)
|
||||||
return
|
|
||||||
if normal_mode and obj.player:
|
if normal_mode and obj.player:
|
||||||
# object already puppeted
|
# object already puppeted
|
||||||
if obj.player == self:
|
if obj.player == self:
|
||||||
|
|
@ -198,13 +202,12 @@ class DefaultPlayer(PlayerDB):
|
||||||
else:
|
else:
|
||||||
txt1 = "{c%s{n{R is now acted from another of your sessions.{n"
|
txt1 = "{c%s{n{R is now acted from another of your sessions.{n"
|
||||||
txt2 = "Taking over {c%s{n from another of your sessions."
|
txt2 = "Taking over {c%s{n from another of your sessions."
|
||||||
|
self.unpuppet_object(obj.sessid.get())
|
||||||
self.msg(txt1 % obj.name, sessid=obj.sessid.get())
|
self.msg(txt1 % obj.name, sessid=obj.sessid.get())
|
||||||
self.msg(txt2 % obj.name, sessid=sessid)
|
self.msg(txt2 % obj.name, sessid=sessid)
|
||||||
self.unpuppet_object(obj.sessid.get())
|
|
||||||
elif obj.player.is_connected:
|
elif obj.player.is_connected:
|
||||||
# controlled by another player
|
# controlled by another player
|
||||||
self.msg("{R{c%s{R is already puppeted by another Player.")
|
raise RuntimeError("{R{c%s{R is already puppeted by another Player.")
|
||||||
return
|
|
||||||
|
|
||||||
# do the puppeting
|
# do the puppeting
|
||||||
if normal_mode and session.puppet:
|
if normal_mode and session.puppet:
|
||||||
|
|
@ -227,34 +230,38 @@ class DefaultPlayer(PlayerDB):
|
||||||
obj.at_post_puppet()
|
obj.at_post_puppet()
|
||||||
# re-cache locks to make sure superuser bypass is updated
|
# re-cache locks to make sure superuser bypass is updated
|
||||||
obj.locks.cache_lock_bypass(obj)
|
obj.locks.cache_lock_bypass(obj)
|
||||||
return True
|
|
||||||
|
|
||||||
def unpuppet_object(self, sessid):
|
def unpuppet_object(self, sessid):
|
||||||
"""
|
"""
|
||||||
Disengage control over an object
|
Disengage control over an object
|
||||||
|
|
||||||
sessid - the session id to disengage
|
Args:
|
||||||
|
sessid(int): the session id to disengage
|
||||||
|
|
||||||
returns True if successful
|
Raises:
|
||||||
|
RuntimeError with message about error.
|
||||||
"""
|
"""
|
||||||
session = self.get_session(sessid)
|
if _MULTISESSION_MODE == 1:
|
||||||
if not session:
|
sessions = self.get_all_sessions()
|
||||||
return False
|
else:
|
||||||
session = make_iter(session)[0]
|
sessions = self.get_session(sessid)
|
||||||
#print "unpuppet, session:", session, session.puppet
|
if not sessions:
|
||||||
obj = hasattr(session, "puppet") and session.puppet or None
|
raise RuntimeError("No session was found.")
|
||||||
#print "unpuppet, obj:", obj
|
for session in make_iter(sessions):
|
||||||
if not obj:
|
#print "unpuppet, session:", session, session.puppet
|
||||||
return False
|
obj = hasattr(session, "puppet") and session.puppet or None
|
||||||
# do the disconnect, but only if we are the last session to puppet
|
#print "unpuppet, obj:", obj
|
||||||
obj.at_pre_unpuppet()
|
if not obj:
|
||||||
obj.sessid.remove(sessid)
|
raise RuntimeError("No puppet was found to disconnect from.")
|
||||||
if not obj.sessid.count():
|
# do the disconnect, but only if we are the last session to puppet
|
||||||
del obj.player
|
obj.at_pre_unpuppet()
|
||||||
obj.at_post_unpuppet(self, sessid=sessid)
|
obj.sessid.remove(sessid)
|
||||||
session.puppet = None
|
if not obj.sessid.count():
|
||||||
session.puid = None
|
del obj.player
|
||||||
return True
|
obj.at_post_unpuppet(self, sessid=sessid)
|
||||||
|
session.puppet = None
|
||||||
|
session.puid = None
|
||||||
|
|
||||||
def unpuppet_all(self):
|
def unpuppet_all(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -329,15 +336,14 @@ class DefaultPlayer(PlayerDB):
|
||||||
This is the main route for sending data back to the user from the
|
This is the main route for sending data back to the user from the
|
||||||
server.
|
server.
|
||||||
|
|
||||||
outgoing_string (string) - text data to send
|
Args:
|
||||||
from_obj (Object/Player) - source object of message to send. Its
|
text (str, optional): text data to send
|
||||||
at_msg_send() hook will be called.
|
from_obj (Object or Player, optional): object sending. If given,
|
||||||
sessid - the session id of the session to send to. If not given, return
|
its at_msg_send() hook will be called.
|
||||||
to all sessions connected to this player. This is usually only
|
sessid (int or list, optional): session id or ids to receive this
|
||||||
relevant when using msg() directly from a player-command (from
|
send. If given, overrules MULTISESSION_MODE.
|
||||||
a command on a Character, the character automatically stores
|
Notes:
|
||||||
and handles the sessid). Can also be a list of sessids.
|
All other keywords are passed on to the protocol.
|
||||||
kwargs (dict) - All other keywords are parsed as extra data.
|
|
||||||
"""
|
"""
|
||||||
text = to_str(text, force_string=True) if text else ""
|
text = to_str(text, force_string=True) if text else ""
|
||||||
if from_obj:
|
if from_obj:
|
||||||
|
|
@ -346,18 +352,24 @@ class DefaultPlayer(PlayerDB):
|
||||||
from_obj.at_msg_send(text=text, to_obj=self, **kwargs)
|
from_obj.at_msg_send(text=text, to_obj=self, **kwargs)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
sessions = _MULTISESSION_MODE > 1 and sessid and self.get_session(sessid) or None
|
|
||||||
|
# session relay
|
||||||
|
|
||||||
|
if sessid:
|
||||||
|
# this could still be an iterable if sessid is an iterable
|
||||||
|
sessions = self.get_session(sessid)
|
||||||
|
if sessions:
|
||||||
|
# this is a special instruction to ignore MULTISESSION_MODE
|
||||||
|
# and only relay to this given session.
|
||||||
|
kwargs["_nomulti"] = True
|
||||||
|
for session in make_iter(sessions):
|
||||||
|
session.msg(text=text, **kwargs)
|
||||||
|
return
|
||||||
|
# we only send to the first of any connected sessions - the sessionhandler
|
||||||
|
# will disperse this to the other sessions based on MULTISESSION_MODE.
|
||||||
|
sessions = self.get_all_sessions()
|
||||||
if sessions:
|
if sessions:
|
||||||
for session in make_iter(sessions):
|
sessions[0].msg(text=text, **kwargs)
|
||||||
obj = session.puppet
|
|
||||||
if obj and not obj.at_msg_receive(text=text, **kwargs):
|
|
||||||
# if hook returns false, cancel send
|
|
||||||
continue
|
|
||||||
session.msg(text=text, **kwargs)
|
|
||||||
else:
|
|
||||||
# if no session was specified, send to them all
|
|
||||||
for sess in self.get_all_sessions():
|
|
||||||
sess.msg(text=text, **kwargs)
|
|
||||||
|
|
||||||
def execute_cmd(self, raw_string, sessid=None, **kwargs):
|
def execute_cmd(self, raw_string, sessid=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -629,12 +641,8 @@ class DefaultPlayer(PlayerDB):
|
||||||
# try to auto-connect to our last conneted object, if any
|
# try to auto-connect to our last conneted object, if any
|
||||||
self.puppet_object(sessid, self.db._last_puppet)
|
self.puppet_object(sessid, self.db._last_puppet)
|
||||||
elif _MULTISESSION_MODE == 1:
|
elif _MULTISESSION_MODE == 1:
|
||||||
# in this mode the first session to connect acts like mode 0,
|
# in this mode all sessions connect to the same puppet.
|
||||||
# the following sessions "share" the same view and should
|
self.puppet_object(sessid, self.db._last_puppet)
|
||||||
# not perform any actions
|
|
||||||
if not self.get_all_puppets():
|
|
||||||
# we are first. Connect.
|
|
||||||
self.puppet_object(sessid, self.db._last_puppet)
|
|
||||||
elif _MULTISESSION_MODE in (2, 3):
|
elif _MULTISESSION_MODE in (2, 3):
|
||||||
# In this mode we by default end up at a character selection
|
# In this mode we by default end up at a character selection
|
||||||
# screen. We execute look on the player.
|
# screen. We execute look on the player.
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,8 @@ class ServerSession(Session):
|
||||||
if INLINEFUNC_ENABLED and not "raw" in kwargs:
|
if INLINEFUNC_ENABLED and not "raw" in kwargs:
|
||||||
text = parse_inlinefunc(text, strip="strip_inlinefunc" in kwargs, session=self)
|
text = parse_inlinefunc(text, strip="strip_inlinefunc" in kwargs, session=self)
|
||||||
self.sessionhandler.data_out(self, text=text, **kwargs)
|
self.sessionhandler.data_out(self, text=text, **kwargs)
|
||||||
|
# alias
|
||||||
|
msg = data_out
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.address == other.address
|
return self.address == other.address
|
||||||
|
|
@ -251,18 +253,6 @@ class ServerSession(Session):
|
||||||
"""
|
"""
|
||||||
return u"%s" % str(self)
|
return u"%s" % str(self)
|
||||||
|
|
||||||
# easy-access functions
|
|
||||||
|
|
||||||
#def login(self, player):
|
|
||||||
# "alias for at_login"
|
|
||||||
# self.session_login(player)
|
|
||||||
#def disconnect(self):
|
|
||||||
# "alias for session_disconnect"
|
|
||||||
# self.session_disconnect()
|
|
||||||
def msg(self, text='', **kwargs):
|
|
||||||
"alias for at_data_out"
|
|
||||||
self.data_out(text=text, **kwargs)
|
|
||||||
|
|
||||||
# Dummy API hooks for use during non-loggedin operation
|
# Dummy API hooks for use during non-loggedin operation
|
||||||
|
|
||||||
def at_cmdset_get(self, **kwargs):
|
def at_cmdset_get(self, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ PCONNSYNC = chr(10) # portal post-syncing session
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
SERVERNAME = settings.SERVERNAME
|
SERVERNAME = settings.SERVERNAME
|
||||||
MULTISESSION_MODE = settings.MULTISESSION_MODE
|
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||||
IDLE_TIMEOUT = settings.IDLE_TIMEOUT
|
IDLE_TIMEOUT = settings.IDLE_TIMEOUT
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -278,7 +278,7 @@ class ServerSessionHandler(SessionHandler):
|
||||||
|
|
||||||
player.at_pre_login()
|
player.at_pre_login()
|
||||||
|
|
||||||
if MULTISESSION_MODE == 0:
|
if _MULTISESSION_MODE == 0:
|
||||||
# disconnect all previous sessions.
|
# disconnect all previous sessions.
|
||||||
self.disconnect_duplicate_sessions(session)
|
self.disconnect_duplicate_sessions(session)
|
||||||
|
|
||||||
|
|
@ -418,14 +418,15 @@ class ServerSessionHandler(SessionHandler):
|
||||||
uid = player.uid
|
uid = player.uid
|
||||||
return [session for session in self.sessions.values() if session.logged_in and session.uid == uid]
|
return [session for session in self.sessions.values() if session.logged_in and session.uid == uid]
|
||||||
|
|
||||||
def sessions_from_character(self, character):
|
def sessions_from_puppet(self, puppet):
|
||||||
"""
|
"""
|
||||||
Given a game character, return any matching sessions.
|
Given a puppeted object, return all controlling sessions.
|
||||||
"""
|
"""
|
||||||
sessid = character.sessid.get()
|
sessid = puppet.sessid.get()
|
||||||
if is_iter(sessid):
|
if is_iter(sessid):
|
||||||
return [self.sessions.get(sess) for sess in sessid if sessid in self.sessions]
|
return [self.sessions.get(sid) for sid in sessid if sid in self.sessions]
|
||||||
return self.sessions.get(sessid)
|
return self.sessions.get(sessid)
|
||||||
|
sessions_from_character = sessions_from_puppet
|
||||||
|
|
||||||
def announce_all(self, message):
|
def announce_all(self, message):
|
||||||
"""
|
"""
|
||||||
|
|
@ -437,9 +438,35 @@ class ServerSessionHandler(SessionHandler):
|
||||||
def data_out(self, session, text="", **kwargs):
|
def data_out(self, session, text="", **kwargs):
|
||||||
"""
|
"""
|
||||||
Sending data Server -> Portal
|
Sending data Server -> Portal
|
||||||
|
|
||||||
|
Args:
|
||||||
|
session (Session): Session object
|
||||||
|
text (str, optional): text data to return
|
||||||
|
_nomulti (bool, optional): if given, only this
|
||||||
|
session will receive the rest of the data,
|
||||||
|
regardless of MULTISESSION_MODE. This is an
|
||||||
|
internal variable that will not be passed on.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
text = text and to_str(to_unicode(text), encoding=session.encoding)
|
text = text and to_str(to_unicode(text), encoding=session.encoding)
|
||||||
self.server.amp_protocol.call_remote_MsgServer2Portal(sessid=session.sessid,
|
multi = not kwargs.pop("_nomulti", None)
|
||||||
|
sessions = [session]
|
||||||
|
if _MULTISESSION_MODE == 1:
|
||||||
|
if session.player:
|
||||||
|
sessions = self.sessions_from_player(session.player)
|
||||||
|
elif multi:
|
||||||
|
if _MULTISESSION_MODE == 2:
|
||||||
|
if session.player:
|
||||||
|
sessions = self.sessions_from_player(session.player)
|
||||||
|
elif _MULTISESSION_MODE == 3:
|
||||||
|
if session.puppet:
|
||||||
|
sessions = self.sessions_from_puppet(session.puppet)
|
||||||
|
elif session.player:
|
||||||
|
sessions = self.sessions_from_player(session.player)
|
||||||
|
|
||||||
|
# send to all found sessions
|
||||||
|
for session in sessions:
|
||||||
|
self.server.amp_protocol.call_remote_MsgServer2Portal(sessid=session.sessid,
|
||||||
msg=text,
|
msg=text,
|
||||||
data=kwargs)
|
data=kwargs)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue