mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
73e57422c7
13 changed files with 66 additions and 34 deletions
|
|
@ -346,7 +346,7 @@ node3 = MenuNode("node3", text=LOGIN_SCREEN_HELP,
|
|||
|
||||
class UnloggedInCmdSet(CmdSet):
|
||||
"Cmdset for the unloggedin state"
|
||||
key = "UnloggedinState"
|
||||
key = "DefaultUnloggedin"
|
||||
priority = 0
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
|
|
@ -361,6 +361,7 @@ class CmdUnloggedinLook(Command):
|
|||
to the menu's own look command..
|
||||
"""
|
||||
key = CMD_LOGINSTART
|
||||
aliases = ["look", "l"]
|
||||
locks = "cmd:all()"
|
||||
|
||||
def func(self):
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ class MenuTree(object):
|
|||
tree as needed. For safety, being in a menu will not survive a
|
||||
server reboot.
|
||||
|
||||
A menutree have two special node keys given by 'startnode' and
|
||||
A menutree has two special node keys given by 'startnode' and
|
||||
'endnode' arguments. The startnode is where the user will start
|
||||
upon first entering the menu. The endnode need not actually
|
||||
exist, the moment it is linked to and that link is used, the menu
|
||||
|
|
@ -188,7 +188,6 @@ class MenuTree(object):
|
|||
Add a menu node object to the tree. Each node itself keeps
|
||||
track of which nodes it is connected to.
|
||||
"""
|
||||
menunode.init(self)
|
||||
self.tree[menunode.key] = menunode
|
||||
|
||||
def goto(self, key):
|
||||
|
|
@ -206,6 +205,8 @@ class MenuTree(object):
|
|||
# not exiting, look for a valid code.
|
||||
node = self.tree.get(key, None)
|
||||
if node:
|
||||
# initialize - this creates new cmdset
|
||||
node.init(self)
|
||||
if node.code:
|
||||
# Execute eventual code active on this
|
||||
# node. self.caller is available at this point.
|
||||
|
|
@ -266,7 +267,7 @@ class MenuNode(object):
|
|||
code block, as well as ev.
|
||||
nodefaultcmds - if true, don't offer the default help and look commands
|
||||
in the node
|
||||
separator - this string will be put on the line between menu nodes5B.
|
||||
separator - this string will be put on the line between menu nodes.
|
||||
"""
|
||||
self.key = key
|
||||
self.cmdset = None
|
||||
|
|
|
|||
|
|
@ -62,8 +62,6 @@ def _init_command(mcs, **kwargs):
|
|||
|
||||
if hasattr(mcs, 'arg_regex') and isinstance(mcs.arg_regex, basestring):
|
||||
mcs.arg_regex = re.compile(r"%s" % mcs.arg_regex, re.I)
|
||||
else:
|
||||
mcs.arg_regex = None
|
||||
if not hasattr(mcs, "auto_help"):
|
||||
mcs.auto_help = True
|
||||
if not hasattr(mcs, 'is_exit'):
|
||||
|
|
@ -140,14 +138,16 @@ class Command(object):
|
|||
locks = ""
|
||||
# used by the help system to group commands in lists.
|
||||
help_category = "general"
|
||||
|
||||
# This allows to turn off auto-help entry creation for individual commands.
|
||||
auto_help = True
|
||||
# optimization for quickly separating exit-commands from normal commands
|
||||
is_exit = False
|
||||
# define the command not only by key but by the regex form of its arguments
|
||||
arg_regex = None
|
||||
|
||||
# auto-set (by Evennia on command instantiation) are:
|
||||
# obj - which object this command is defined on
|
||||
# sessid - which session-id (if any) is responsible for
|
||||
# triggering this command
|
||||
#
|
||||
# sessid - which session-id (if any) is responsible for triggering this command
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""the lockhandler works the same as for objects.
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ class TickerHandler(object):
|
|||
self.save_name = save_name
|
||||
self.ticker_pool = self.ticker_pool_class()
|
||||
|
||||
def _store_key(self, obj, interval):
|
||||
def _store_key(self, obj, interval, idstring=""):
|
||||
"""
|
||||
Tries to create a store_key for the object.
|
||||
Returns a tuple (isdb, store_key) where isdb
|
||||
|
|
@ -224,7 +224,7 @@ class TickerHandler(object):
|
|||
objkey = id(obj)
|
||||
isdb = False
|
||||
# return sidb and store_key
|
||||
return isdb, (objkey, interval)
|
||||
return isdb, (objkey, interval, idstring)
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
|
|
@ -237,9 +237,11 @@ class TickerHandler(object):
|
|||
start_delays = dict((interval, ticker.task.next_call_time())
|
||||
for interval, ticker in self.ticker_pool.tickers.items())
|
||||
# update the timers for the tickers
|
||||
for (obj, interval), (args, kwargs) in self.ticker_storage.items():
|
||||
#for (obj, interval, idstring), (args, kwargs) in self.ticker_storage.items():
|
||||
for store_key, (args, kwargs) in self.ticker_storage.items():
|
||||
interval = store_key[1]
|
||||
# this is a mutable, so it's updated in-place in ticker_storage
|
||||
kwargs["_start_delay"] = start_delays.get(interval, None)
|
||||
|
||||
ServerConfig.objects.conf(key=self.save_name,
|
||||
value=dbserialize(self.ticker_storage))
|
||||
else:
|
||||
|
|
@ -254,30 +256,34 @@ class TickerHandler(object):
|
|||
if ticker_storage:
|
||||
self.ticker_storage = dbunserialize(ticker_storage)
|
||||
#print "restore:", self.ticker_storage
|
||||
for (obj, interval), (args, kwargs) in self.ticker_storage.items():
|
||||
for store_key, (args, kwargs) in self.ticker_storage.items():
|
||||
if len(store_key) == 2:
|
||||
# old form of store_key - update it
|
||||
store_key = (store_key[0], store_key[1], "")
|
||||
obj, interval, idstring = store_key
|
||||
obj = unpack_dbobj(obj)
|
||||
_, store_key = self._store_key(obj, interval)
|
||||
_, store_key = self._store_key(obj, interval, idstring)
|
||||
self.ticker_pool.add(store_key, obj, interval, *args, **kwargs)
|
||||
|
||||
def add(self, obj, interval, *args, **kwargs):
|
||||
def add(self, obj, interval, idstring="", *args, **kwargs):
|
||||
"""
|
||||
Add object to tickerhandler. The object must have an at_tick
|
||||
method. This will be called every interval seconds until the
|
||||
object is unsubscribed from the ticker.
|
||||
"""
|
||||
isdb, store_key = self._store_key(obj, interval)
|
||||
isdb, store_key = self._store_key(obj, interval, idstring)
|
||||
if isdb:
|
||||
self.ticker_storage[store_key] = (args, kwargs)
|
||||
self.save()
|
||||
self.ticker_pool.add(store_key, obj, interval, *args, **kwargs)
|
||||
|
||||
def remove(self, obj, interval=None):
|
||||
def remove(self, obj, interval=None, idstring=""):
|
||||
"""
|
||||
Remove object from ticker, or only this object ticking
|
||||
at a given interval.
|
||||
"""
|
||||
if interval:
|
||||
isdb, store_key = self._store_key(obj, interval)
|
||||
isdb, store_key = self._store_key(obj, interval, idstring)
|
||||
if isdb:
|
||||
self.ticker_storage.pop(store_key, None)
|
||||
self.save()
|
||||
|
|
@ -287,7 +293,7 @@ class TickerHandler(object):
|
|||
intervals = self.ticker_pool.tickers.keys()
|
||||
should_save = False
|
||||
for interval in intervals:
|
||||
isdb, store_key = self._store_key(obj, interval)
|
||||
isdb, store_key = self._store_key(obj, interval, idstring)
|
||||
if isdb:
|
||||
self.ticker_storage.pop(store_key, None)
|
||||
should_save = True
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ def mxp_parse(text):
|
|||
"""
|
||||
Replaces links to the correct format for MXP.
|
||||
"""
|
||||
text = text.replace("&", "&") \
|
||||
.replace("<", "<") \
|
||||
.replace(">", ">")
|
||||
|
||||
text = LINKS_SUB.sub(MXP_SEND, text)
|
||||
return text
|
||||
|
||||
|
|
@ -47,6 +51,7 @@ class Mxp(object):
|
|||
Client does not support MXP.
|
||||
"""
|
||||
self.protocol.protocol_flags["MXP"] = False
|
||||
self.protocol.handshake_done()
|
||||
|
||||
def do_mxp(self, option):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -64,6 +64,15 @@ class PortalSessionHandler(SessionHandler):
|
|||
# only use if session already has sessid (i.e. has already connected)
|
||||
sessdata = session.get_sync_data()
|
||||
if self.portal.amp_protocol:
|
||||
# we only send sessdata that should not have changed
|
||||
# at the server level at this point
|
||||
sessdata = dict((key, val) for key, val in sessdata.items() if key in ("protocol_key",
|
||||
"address",
|
||||
"sessid",
|
||||
"suid",
|
||||
"conn_time",
|
||||
"protocol_flags",
|
||||
"server_data",))
|
||||
self.portal.amp_protocol.call_remote_ServerAdmin(session.sessid,
|
||||
operation=PCONNSYNC,
|
||||
data=sessdata)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
self.msdp = msdp.Msdp(self)
|
||||
# mxp support
|
||||
self.mxp = Mxp(self)
|
||||
# keepalive watches for dead links
|
||||
self.transport.setTcpKeepAlive(1)
|
||||
# add this new connection to sessionhandler so
|
||||
# the Server becomes aware of it.
|
||||
self.sessionhandler.connect(self)
|
||||
|
|
@ -258,6 +260,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
if prompt:
|
||||
# Send prompt separately
|
||||
prompt = ansi.parse_ansi(_RE_N.sub("", prompt) + "{n", strip_ansi=nomarkup, xterm256=xterm256)
|
||||
if mxp:
|
||||
prompt = mxp_parse(prompt)
|
||||
prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n')
|
||||
prompt += IAC + GA
|
||||
self.transport.write(mccp_compress(self, prompt))
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ class WebSocketClient(Protocol, Session):
|
|||
"""
|
||||
client_address = self.transport.client
|
||||
self.init_session("websocket", client_address, self.factory.sessionhandler)
|
||||
# watch for dead links
|
||||
self.transport.setTcpKeepAlive(1)
|
||||
self.sessionhandler.connect(self)
|
||||
|
||||
def disconnect(self, reason=None):
|
||||
|
|
@ -122,10 +124,10 @@ class WebSocketClient(Protocol, Session):
|
|||
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob"))
|
||||
#print "oob data_out:", "OOB" + json.dumps(oobstruct)
|
||||
self.sendLine("OOB" + json.dumps(oobstruct))
|
||||
if "prompt" in kwargs:
|
||||
self.sendLine("PROMPT" + kwargs["prompt"])
|
||||
raw = kwargs.get("raw", False)
|
||||
nomarkup = kwargs.get("nomarkup", False)
|
||||
if "prompt" in kwargs:
|
||||
self.sendLine("PROMPT" + parse_html(kwargs["prompt"], strip_ansi=nomarkup))
|
||||
if raw:
|
||||
self.sendLine(text)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -234,12 +234,6 @@ class ServerSession(Session):
|
|||
Send Evennia -> User
|
||||
"""
|
||||
text = text if text else ""
|
||||
#if text is None:
|
||||
# text = ""
|
||||
#else:
|
||||
# text = to_unicode(text)
|
||||
# text = to_str(text, self.encoding)
|
||||
|
||||
self.sessionhandler.data_out(self, text=text, **kwargs)
|
||||
|
||||
def __eq__(self, other):
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ class Session(object):
|
|||
and loads it into the correct properties of the session.
|
||||
"""
|
||||
for propname, value in sessdata.items():
|
||||
self.__dict__[propname] = value
|
||||
setattr(self, propname, value)
|
||||
|
||||
def at_sync(self):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -220,6 +220,11 @@ class ServerSessionHandler(SessionHandler):
|
|||
sessid = portalsessiondata.get("sessid")
|
||||
session = self.sessions.get(sessid)
|
||||
if session:
|
||||
# since some of the session properties may have had
|
||||
# a chance to change already before the portal gets here
|
||||
# the portal doesn't send all sessiondata here, but only
|
||||
# ones which should only be changed from portal (like
|
||||
# protocol_flags etc)
|
||||
session.load_sync_data(portalsessiondata)
|
||||
|
||||
def portal_disconnect(self, sessid):
|
||||
|
|
@ -339,7 +344,7 @@ class ServerSessionHandler(SessionHandler):
|
|||
|
||||
session.logged_in = True
|
||||
# sync the portal to the session
|
||||
sessdata = session.get_sync_data()
|
||||
sessdata = {"logged_in": True}
|
||||
if not testmode:
|
||||
self.server.amp_protocol.call_remote_PortalAdmin(session.sessid,
|
||||
operation=SLOGIN,
|
||||
|
|
@ -407,7 +412,7 @@ class ServerSessionHandler(SessionHandler):
|
|||
def validate_sessions(self):
|
||||
"""
|
||||
Check all currently connected sessions (logged in and not)
|
||||
and see if any are dead.
|
||||
and see if any are dead or idle
|
||||
"""
|
||||
tcurr = time.time()
|
||||
reason = _("Idle timeout exceeded, disconnecting.")
|
||||
|
|
|
|||
|
|
@ -305,11 +305,15 @@ def create_script(typeclass, key=None, obj=None, player=None, locks=None,
|
|||
if persistent is not None:
|
||||
new_script.persistent = persistent
|
||||
|
||||
# must do this before starting the script since some
|
||||
# scripts may otherwise run for a very short time and
|
||||
# try to delete itself before we have a time to save it.
|
||||
new_db_script.save()
|
||||
|
||||
# a new created script should usually be started.
|
||||
if autostart:
|
||||
new_script.start()
|
||||
|
||||
new_db_script.save()
|
||||
return new_script
|
||||
#alias
|
||||
script = create_script
|
||||
|
|
|
|||
|
|
@ -782,7 +782,8 @@ def mod_import(module):
|
|||
|
||||
def all_from_module(module):
|
||||
"""
|
||||
Return all global-level variables from a module as a dict
|
||||
Return all global-level variables from a module as a dict.
|
||||
Ignores modules and variable names starting with an underscore.
|
||||
"""
|
||||
mod = mod_import(module)
|
||||
if not mod:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue