diff --git a/CHANGELOG.md b/CHANGELOG.md index dcafd63b32..de0c55d58a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/evennia/commands/cmdhandler.py b/evennia/commands/cmdhandler.py index 6babbabab0..762f808d96 100644 --- a/evennia/commands/cmdhandler.py +++ b/evennia/commands/cmdhandler.py @@ -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) diff --git a/evennia/commands/command.py b/evennia/commands/command.py index a81f8b6efb..ce1eb3397b 100644 --- a/evennia/commands/command.py +++ b/evennia/commands/command.py @@ -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 diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index ba9b755c94..72e010130e 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -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)