Avoid yield-command crossover problems. Add .retain_instance ability for Command class for implementing state execution.

This commit is contained in:
Griatch 2021-08-06 15:59:48 +02:00
parent e8eb5f7586
commit 6e38d0ae4c
4 changed files with 17 additions and 2 deletions

View file

@ -76,6 +76,8 @@ Up requirements to Django 3.2+
pathfinding. Controlled outside of the game via custom evennia launcher command.
- `Script.delete` has new kwarg `stop_task=True`, that can be used to avoid
infinite recursion when wanting to set up Script to delete-on-stop.
- Command executions now done on copies to make sure `yield` don't cause crossovers. Add
`Command.retain_instance` flag for reusing the same command instance.
### Evennia 0.9.5 (2019-2020)

View file

@ -738,6 +738,10 @@ def cmdhandler(
sysarg += _(' Type "help" for help.')
raise ExecSystemCommand(syscmd, sysarg)
if not cmd.retain_instance:
# making a copy allows multiple users to share the command also when yield is used
cmd = copy(cmd)
# A normal command.
ret = yield _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account)
returnValue(ret)

View file

@ -84,6 +84,9 @@ def _init_command(cls, **kwargs):
cls.is_exit = False
if not hasattr(cls, "help_category"):
cls.help_category = "general"
if not hasattr(cls, "retain_instance"):
cls.retain_instance = False
# make sure to pick up the parent's docstring if the child class is
# missing one (important for auto-help)
if cls.__doc__ is None:
@ -189,6 +192,11 @@ class Command(metaclass=CommandMeta):
# whether self.msg sends to all sessions of a related account/object (default
# is to only send to the session sending the command).
msg_all_sessions = settings.COMMAND_DEFAULT_MSG_ALL_SESSIONS
# whether the exact command instance should be retained between command calls.
# By default it's False; this allows for retaining state and saves some CPU, but
# can cause cross-talk between users if multiple users access the same command
# (especially if the command is using yield)
retain_instance = False
# auto-set (by Evennia on command instantiation) are:
# obj - which object this command is defined on

View file

@ -1540,7 +1540,8 @@ class CmdGetInput(Command):
getinput = caller.ndb._getinput
if not getinput and hasattr(caller, "account"):
getinput = caller.account.ndb._getinput
caller = caller.account
if getinput:
caller = caller.account
callback = getinput._callback
caller.ndb._getinput._session = self.session
@ -1642,7 +1643,7 @@ def get_input(caller, prompt, callback, session=None, *args, **kwargs):
caller.ndb._getinput._session = session
caller.ndb._getinput._args = args
caller.ndb._getinput._kwargs = kwargs
caller.cmdset.add(InputCmdSet)
caller.cmdset.add(InputCmdSet, persistent=False)
caller.msg(prompt, session=session)