mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
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
|
||||
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
|
||||
method. Otherwise all text will be returned to all connected sessions.
|
||||
|
||||
|
|
@ -249,10 +249,11 @@ class CmdIC(MuxPlayerCommand):
|
|||
else:
|
||||
self.msg("That is not a valid character choice.")
|
||||
return
|
||||
if player.puppet_object(sessid, new_character):
|
||||
try:
|
||||
player.puppet_object(sessid, new_character)
|
||||
player.db._last_puppet = new_character
|
||||
else:
|
||||
self.msg("{rYou cannot become {C%s{n." % new_character.name)
|
||||
except RuntimeError, exc:
|
||||
self.msg("{rYou cannot become {C%s{n: %s" % (new_character.name, exc))
|
||||
|
||||
|
||||
class CmdOOC(MuxPlayerCommand):
|
||||
|
|
@ -287,11 +288,12 @@ class CmdOOC(MuxPlayerCommand):
|
|||
player.db._last_puppet = old_char
|
||||
|
||||
# disconnect
|
||||
if player.unpuppet_object(sessid):
|
||||
try:
|
||||
player.unpuppet_object(sessid)
|
||||
self.msg("\n{GYou go OOC.{n\n")
|
||||
player.execute_cmd("look", sessid=sessid)
|
||||
else:
|
||||
raise RuntimeError("Could not unpuppet!")
|
||||
except RuntimeError, exc:
|
||||
self.msg("{rCould not unpuppet from {c%s{n: %s" % (old_char, exc))
|
||||
|
||||
class CmdSessions(MuxPlayerCommand):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -501,23 +501,19 @@ class DefaultObject(ObjectDB):
|
|||
"""
|
||||
Emits something to a session attached to the object.
|
||||
|
||||
message (str): The message to send
|
||||
from_obj (obj): object that is sending.
|
||||
data (object): an optional data object that may or may not
|
||||
be used by the protocol.
|
||||
sessid (int): sessid to relay to, if any.
|
||||
If set to 0 (default), use either from_obj.sessid (if set) or self.sessid automatically
|
||||
If None, echo to all connected sessions
|
||||
|
||||
When this message is called, from_obj.at_msg_send and self.at_msg_receive are called.
|
||||
Args:
|
||||
text (str, optional): The message to send
|
||||
from_obj (obj, optional): object that is sending. If
|
||||
given, at_msg_send will be called
|
||||
sessid (int or list, optional): sessid or list of
|
||||
sessids to relay to, if any. If set, will
|
||||
force send regardless of MULTISESSION_MODE.
|
||||
Notes:
|
||||
`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 ""
|
||||
|
||||
if from_obj:
|
||||
# call hook
|
||||
try:
|
||||
|
|
@ -531,9 +527,25 @@ class DefaultObject(ObjectDB):
|
|||
except Exception:
|
||||
log_trace()
|
||||
|
||||
sessions = _SESSIONS.session_from_sessid([sessid] if sessid else make_iter(self.sessid.get()))
|
||||
for session in sessions:
|
||||
session.msg(text=text, **kwargs)
|
||||
# session relay
|
||||
|
||||
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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -166,26 +166,30 @@ class DefaultPlayer(PlayerDB):
|
|||
Use the given session to control (puppet) the given object (usually
|
||||
a Character type).
|
||||
|
||||
sessid - session id of session to connect
|
||||
obj - the object to connect to
|
||||
normal_mode - trigger hooks and extra checks - this is turned off when
|
||||
the server reloads, to quickly re-connect puppets.
|
||||
Args:
|
||||
sessid (int): session id of session to connect
|
||||
obj (Object): the object to start puppeting
|
||||
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
|
||||
"""
|
||||
# safety checks
|
||||
if not obj:
|
||||
return
|
||||
raise RuntimeError("Object not found")
|
||||
session = self.get_session(sessid)
|
||||
if not session:
|
||||
return False
|
||||
raise RuntimeError("Session not found")
|
||||
if self.get_puppet(sessid) == obj:
|
||||
# already puppeting this object
|
||||
return
|
||||
raise RuntimeError("You are already puppeting this object.")
|
||||
if not obj.access(self, 'puppet'):
|
||||
# no access
|
||||
self.msg("You don't have permission to puppet '%s'." % obj.key)
|
||||
return
|
||||
raise RuntimeError("You don't have permission to puppet '%s'." % obj.key)
|
||||
if normal_mode and obj.player:
|
||||
# object already puppeted
|
||||
if obj.player == self:
|
||||
|
|
@ -198,13 +202,12 @@ class DefaultPlayer(PlayerDB):
|
|||
else:
|
||||
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."
|
||||
self.unpuppet_object(obj.sessid.get())
|
||||
self.msg(txt1 % obj.name, sessid=obj.sessid.get())
|
||||
self.msg(txt2 % obj.name, sessid=sessid)
|
||||
self.unpuppet_object(obj.sessid.get())
|
||||
elif obj.player.is_connected:
|
||||
# controlled by another player
|
||||
self.msg("{R{c%s{R is already puppeted by another Player.")
|
||||
return
|
||||
raise RuntimeError("{R{c%s{R is already puppeted by another Player.")
|
||||
|
||||
# do the puppeting
|
||||
if normal_mode and session.puppet:
|
||||
|
|
@ -227,34 +230,38 @@ class DefaultPlayer(PlayerDB):
|
|||
obj.at_post_puppet()
|
||||
# re-cache locks to make sure superuser bypass is updated
|
||||
obj.locks.cache_lock_bypass(obj)
|
||||
return True
|
||||
|
||||
|
||||
def unpuppet_object(self, sessid):
|
||||
"""
|
||||
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 not session:
|
||||
return False
|
||||
session = make_iter(session)[0]
|
||||
#print "unpuppet, session:", session, session.puppet
|
||||
obj = hasattr(session, "puppet") and session.puppet or None
|
||||
#print "unpuppet, obj:", obj
|
||||
if not obj:
|
||||
return False
|
||||
# do the disconnect, but only if we are the last session to puppet
|
||||
obj.at_pre_unpuppet()
|
||||
obj.sessid.remove(sessid)
|
||||
if not obj.sessid.count():
|
||||
del obj.player
|
||||
obj.at_post_unpuppet(self, sessid=sessid)
|
||||
session.puppet = None
|
||||
session.puid = None
|
||||
return True
|
||||
if _MULTISESSION_MODE == 1:
|
||||
sessions = self.get_all_sessions()
|
||||
else:
|
||||
sessions = self.get_session(sessid)
|
||||
if not sessions:
|
||||
raise RuntimeError("No session was found.")
|
||||
for session in make_iter(sessions):
|
||||
#print "unpuppet, session:", session, session.puppet
|
||||
obj = hasattr(session, "puppet") and session.puppet or None
|
||||
#print "unpuppet, obj:", obj
|
||||
if not obj:
|
||||
raise RuntimeError("No puppet was found to disconnect from.")
|
||||
# do the disconnect, but only if we are the last session to puppet
|
||||
obj.at_pre_unpuppet()
|
||||
obj.sessid.remove(sessid)
|
||||
if not obj.sessid.count():
|
||||
del obj.player
|
||||
obj.at_post_unpuppet(self, sessid=sessid)
|
||||
session.puppet = None
|
||||
session.puid = None
|
||||
|
||||
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
|
||||
server.
|
||||
|
||||
outgoing_string (string) - text data to send
|
||||
from_obj (Object/Player) - source object of message to send. Its
|
||||
at_msg_send() hook will be called.
|
||||
sessid - the session id of the session to send to. If not given, return
|
||||
to all sessions connected to this player. This is usually only
|
||||
relevant when using msg() directly from a player-command (from
|
||||
a command on a Character, the character automatically stores
|
||||
and handles the sessid). Can also be a list of sessids.
|
||||
kwargs (dict) - All other keywords are parsed as extra data.
|
||||
Args:
|
||||
text (str, optional): text data to send
|
||||
from_obj (Object or Player, optional): object sending. If given,
|
||||
its at_msg_send() hook will be called.
|
||||
sessid (int or list, optional): session id or ids to receive this
|
||||
send. If given, overrules MULTISESSION_MODE.
|
||||
Notes:
|
||||
All other keywords are passed on to the protocol.
|
||||
"""
|
||||
text = to_str(text, force_string=True) if text else ""
|
||||
if from_obj:
|
||||
|
|
@ -346,18 +352,24 @@ class DefaultPlayer(PlayerDB):
|
|||
from_obj.at_msg_send(text=text, to_obj=self, **kwargs)
|
||||
except Exception:
|
||||
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:
|
||||
for session in make_iter(sessions):
|
||||
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)
|
||||
sessions[0].msg(text=text, **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
|
||||
self.puppet_object(sessid, self.db._last_puppet)
|
||||
elif _MULTISESSION_MODE == 1:
|
||||
# in this mode the first session to connect acts like mode 0,
|
||||
# the following sessions "share" the same view and should
|
||||
# not perform any actions
|
||||
if not self.get_all_puppets():
|
||||
# we are first. Connect.
|
||||
self.puppet_object(sessid, self.db._last_puppet)
|
||||
# in this mode all sessions connect to the same puppet.
|
||||
self.puppet_object(sessid, self.db._last_puppet)
|
||||
elif _MULTISESSION_MODE in (2, 3):
|
||||
# In this mode we by default end up at a character selection
|
||||
# screen. We execute look on the player.
|
||||
|
|
|
|||
|
|
@ -224,6 +224,8 @@ class ServerSession(Session):
|
|||
if INLINEFUNC_ENABLED and not "raw" in kwargs:
|
||||
text = parse_inlinefunc(text, strip="strip_inlinefunc" in kwargs, session=self)
|
||||
self.sessionhandler.data_out(self, text=text, **kwargs)
|
||||
# alias
|
||||
msg = data_out
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.address == other.address
|
||||
|
|
@ -251,18 +253,6 @@ class ServerSession(Session):
|
|||
"""
|
||||
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
|
||||
|
||||
def at_cmdset_get(self, **kwargs):
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ PCONNSYNC = chr(10) # portal post-syncing session
|
|||
from django.utils.translation import ugettext as _
|
||||
|
||||
SERVERNAME = settings.SERVERNAME
|
||||
MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||
IDLE_TIMEOUT = settings.IDLE_TIMEOUT
|
||||
|
||||
|
||||
|
|
@ -278,7 +278,7 @@ class ServerSessionHandler(SessionHandler):
|
|||
|
||||
player.at_pre_login()
|
||||
|
||||
if MULTISESSION_MODE == 0:
|
||||
if _MULTISESSION_MODE == 0:
|
||||
# disconnect all previous sessions.
|
||||
self.disconnect_duplicate_sessions(session)
|
||||
|
||||
|
|
@ -418,14 +418,15 @@ class ServerSessionHandler(SessionHandler):
|
|||
uid = player.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):
|
||||
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)
|
||||
sessions_from_character = sessions_from_puppet
|
||||
|
||||
def announce_all(self, message):
|
||||
"""
|
||||
|
|
@ -437,9 +438,35 @@ class ServerSessionHandler(SessionHandler):
|
|||
def data_out(self, session, text="", **kwargs):
|
||||
"""
|
||||
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)
|
||||
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,
|
||||
data=kwargs)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue