diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 167fc83515..6df9f80244 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -274,9 +274,9 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase): # Determines which order command sets begin to be assembled from. # Accounts are usually second. - cmd_order = 50 - cmd_order_error = 0 - cmd_type = "account" + cmdset_provider_order = 50 + cmdset_provider_error_order = 0 + cmdset_provider_type = "account" objects = AccountManager() @@ -315,17 +315,16 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase): def characters(self): return CharactersHandler(self) - def get_command_objects(self) -> dict[str, "CommandObject"]: + def get_cmdset_providers(self) -> dict[str, "CmdSetProvider"]: """ - Overrideable method which returns a dictionary of all the kinds of CommandObjects - linked to this Account. + Overrideable method which returns a dictionary of every kind of object which + has a cmdsethandler linked to this Account, and should participate in cmdset + merging. - In all normal cases, that's just the account itself. - - The cmdhandler uses this to determine available cmdsets when executing a command. + Accounts have no way of being aware of anything besides themselves, unfortunately. Returns: - dict[str, CommandObject]: The CommandObjects linked to this Account. + dict[str, CmdSetProvider]: The CmdSetProviders linked to this Object. """ return {"account": self} diff --git a/evennia/commands/cmdhandler.py b/evennia/commands/cmdhandler.py index c0df779615..261ff3108e 100644 --- a/evennia/commands/cmdhandler.py +++ b/evennia/commands/cmdhandler.py @@ -151,9 +151,13 @@ _GET_INPUT = None # helper functions +def err_helper(raw_string, cmdid=None): + if cmdid is not None: + return raw_string, {"cmdid": cmdid} + return raw_string -def _msg_err(receiver, stringtuple): +def _msg_err(receiver, stringtuple, cmdid=None): """ Helper function for returning an error to the caller. @@ -169,19 +173,16 @@ def _msg_err(receiver, stringtuple): tracestring = format_exc() logger.log_trace() if _IN_GAME_ERRORS: - receiver.msg( - string.format( - traceback=tracestring, errmsg=stringtuple[0].strip(), timestamp=timestamp - ).strip() - ) + out = string.format( + traceback=tracestring, errmsg=stringtuple[0].strip(), timestamp=timestamp + ).strip() else: - receiver.msg( - string.format( - traceback=tracestring.splitlines()[-1], - errmsg=stringtuple[1].strip(), - timestamp=timestamp, - ).strip() - ) + out = string.format( + traceback=tracestring.splitlines()[-1], + errmsg=stringtuple[1].strip(), + timestamp=timestamp, + ).strip() + receiver.msg(err_helper(out, cmdid=cmdid)) def _process_input(caller, prompt, result, cmd, generator): @@ -281,37 +282,39 @@ class ErrorReported(Exception): # Helper function -def generate_command_objects(called_by, session=None): - command_objects = dict() - command_objects.update(called_by.get_command_objects()) +def generate_cmdset_providers(called_by, session=None): + cmdset_providers = dict() + cmdset_providers.update(called_by.get_cmdset_providers()) if session and session is not called_by: - command_objects.update(session.get_command_objects()) + cmdset_providers.update(session.get_cmdset_providers()) - command_objects_list = list(command_objects.values()) - command_objects_list.sort(key=lambda x: getattr(x, "cmd_order", 0)) + cmdset_providers_list = list(cmdset_providers.values()) + cmdset_providers_list.sort(key=lambda x: getattr(x, "cmdset_provider_order", 0)) # sort the dictionary by priority. This can be done because Python now cares about dictionary insert order. - command_objects = {c.cmd_type: c for c in command_objects_list} + cmdset_providers = {c.cmdset_provider_type: c for c in cmdset_providers_list} - if not command_objects: + if not cmdset_providers: raise RuntimeError("cmdhandler: no command objects found.") # the caller will be the one to receive messages and excert its permissions. # we assign the caller with preference 'bottom up' - caller = command_objects_list[-1] + caller = cmdset_providers_list[-1] - command_objects_list_error = sorted( - command_objects_list, key=lambda x: getattr(x, "cmd_order_error", 0) + cmdset_providers_errors_list = sorted( + cmdset_providers_list, key=lambda x: getattr(x, "cmdset_provider_error_order", 0) ) # The error_to is the default recipient for errors. Tries to make sure an account # does not get spammed for errors while preserving character mirroring. - error_to = command_objects_list_error[-1] + error_to = cmdset_providers_errors_list[-1] - return command_objects, command_objects_list, command_objects_list_error, caller, error_to + return cmdset_providers, cmdset_providers_list, cmdset_providers_errors_list, caller, error_to @inlineCallbacks -def get_and_merge_cmdsets(caller, command_objects, callertype, raw_string, report_to=None): +def get_and_merge_cmdsets( + caller, cmdset_providers, callertype, raw_string, report_to=None, cmdid=None +): """ Gather all relevant cmdsets and merge them. @@ -321,7 +324,7 @@ def get_and_merge_cmdsets(caller, command_objects, callertype, raw_string, repor when the user is not logged in, this will be a Session, when being OOC it will be an Account and when puppeting an object this will (often) be a Character Object. In the end it depends on where the cmdset is stored. - command_objects (list): A list of sorted objects which provide cmdsets. + cmdset_providers (list): A list of sorted objects which provide cmdsets. callertype (str): This identifies caller as either "account", "object" or "session" to avoid having to do this check internally. raw_string (str): The input string. This is only used for error reporting. @@ -413,13 +416,13 @@ def get_and_merge_cmdsets(caller, command_objects, callertype, raw_string, repor current_cmdset = CmdSet() object_cmdsets = list() - for cmdobj in command_objects: + for cmdobj in cmdset_providers: current, cur_cmdsets = yield _get_cmdsets(cmdobj, current_cmdset) if current: current_cmdset = current_cmdset + current if cur_cmdsets: object_cmdsets += cur_cmdsets - match cmdobj.cmd_type: + match cmdobj.cmdset_provider_type: case "object": if not current.no_objs: local_obj_cmdsets = yield _get_local_obj_cmdsets(cmdobj) @@ -436,7 +439,9 @@ def get_and_merge_cmdsets(caller, command_objects, callertype, raw_string, repor ] # report cmdset errors to user (these should already have been logged) yield [ - report_to.msg(cmdset.errmessage) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR" + report_to.msg(err_helper(cmdset.errmessage, cmdid=cmdid)) + for cmdset in cmdsets + if cmdset.key == "_CMDSET_ERROR" ] if cmdsets: @@ -546,9 +551,10 @@ def cmdhandler( default Evennia. """ + cmdid = kwargs.get("cmdid", None) @inlineCallbacks - def _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account, command_objects): + def _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account, cmdset_providers): """ Helper function: This initializes and runs the Command instance once the parser has identified it as either a normal @@ -564,7 +570,7 @@ def cmdhandler( cmdset (CmdSet): Command sert the command belongs to (if any).. session (Session): Session of caller (if any). account (Account): Account of caller (if any). - command_objects (dict): Dictionary of all command objects. + cmdset_providers (dict): Dictionary of all cmdset-providing objects. Returns: deferred (Deferred): this will fire with the return of the @@ -583,7 +589,7 @@ def cmdhandler( cmd.cmdstring = cmdname # deprecated cmd.args = args cmd.cmdset = cmdset - cmd.command_objects = command_objects.copy() + cmd.cmdset_providers = cmdset_providers.copy() cmd.session = session cmd.account = account cmd.raw_string = unformatted_raw_string @@ -654,14 +660,14 @@ def cmdhandler( _COMMAND_NESTING[called_by] -= 1 ( - command_objects, - command_objects_list, - command_objects_list_error, + cmdset_providers, + cmdset_providers_list, + cmdset_providers_list_error, caller, error_to, - ) = generate_command_objects(called_by, session=session) + ) = generate_cmdset_providers(called_by, session=session) - account = command_objects.get("account", None) + account = cmdset_providers.get("account", None) try: # catch bugs in cmdhandler itself try: # catch special-type commands @@ -679,7 +685,7 @@ def cmdhandler( else: # no explicit cmdobject given, figure it out cmdset = yield get_and_merge_cmdsets( - caller, command_objects_list, callertype, raw_string + caller, cmdset_providers_list, callertype, raw_string, cmdid=cmdid ) if not cmdset: # this is bad and shouldn't happen. @@ -753,7 +759,7 @@ def cmdhandler( # A normal command. ret = yield _run_command( - cmd, cmdname, args, raw_cmdname, cmdset, session, account, command_objects + cmd, cmdname, args, raw_cmdname, cmdset, session, account, cmdset_providers ) returnValue(ret) @@ -777,17 +783,17 @@ def cmdhandler( cmdset, session, account, - command_objects, + cmdset_providers, ) returnValue(ret) elif sysarg: # return system arg - error_to.msg(exc.sysarg) + error_to.msg(err_helper(exc.sysarg, cmdid=cmdid)) except NoCmdSets: # Critical error. logger.log_err("No cmdsets found: %s" % caller) - error_to.msg(_ERROR_NOCMDSETS) + error_to.msg(err_helper(_ERROR_NOCMDSETS, cmdid=cmdid)) except Exception: # We should not end up here. If we do, it's a programming bug. diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 2a2dd6e367..50d3d20966 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -10,7 +10,7 @@ from django.db.models import Max, Min, Q import evennia from evennia import InterruptCommand -from evennia.commands.cmdhandler import get_and_merge_cmdsets, generate_command_objects +from evennia.commands.cmdhandler import get_and_merge_cmdsets, generate_cmdset_providers from evennia.locks.lockhandler import LockException from evennia.objects.models import ObjectDB from evennia.prototypes import menus as olc_menus @@ -3128,7 +3128,7 @@ class CmdExamine(ObjManipCommand): command_objects_list_error, caller, error_to, - ) = generate_command_objects(obj, session=session) + ) = generate_cmdset_providers(obj, session=session) get_and_merge_cmdsets( obj, command_objects_list, mergemode, self.raw_string, error_to diff --git a/evennia/commands/tests.py b/evennia/commands/tests.py index bd23f94dda..10eb5143a7 100644 --- a/evennia/commands/tests.py +++ b/evennia/commands/tests.py @@ -1026,7 +1026,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, BaseEvenniaTest): command_objects_list_error, caller, error_to, - ) = cmdhandler.generate_command_objects(self.session) + ) = cmdhandler.generate_cmdset_providers(self.session) deferred = cmdhandler.get_and_merge_cmdsets( self.session, [self.session], "session", "", error_to @@ -1050,7 +1050,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, BaseEvenniaTest): command_objects_list_error, caller, error_to, - ) = cmdhandler.generate_command_objects(self.account) + ) = cmdhandler.generate_cmdset_providers(self.account) deferred = cmdhandler.get_and_merge_cmdsets( self.account, command_objects_list, "account", "", error_to @@ -1075,7 +1075,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, BaseEvenniaTest): command_objects_list_error, caller, error_to, - ) = cmdhandler.generate_command_objects(self.obj1) + ) = cmdhandler.generate_cmdset_providers(self.obj1) deferred = cmdhandler.get_and_merge_cmdsets( self.obj1, command_objects_list, "object", "", error_to @@ -1101,7 +1101,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, BaseEvenniaTest): command_objects_list_error, caller, error_to, - ) = cmdhandler.generate_command_objects(self.obj1) + ) = cmdhandler.generate_cmdset_providers(self.obj1) deferred = cmdhandler.get_and_merge_cmdsets( self.obj1, command_objects_list, "object", "", error_to ) @@ -1127,7 +1127,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, BaseEvenniaTest): command_objects_list_error, caller, error_to, - ) = cmdhandler.generate_command_objects(self.obj1, session=None) + ) = cmdhandler.generate_cmdset_providers(self.obj1, session=None) deferred = cmdhandler.get_and_merge_cmdsets( self.obj1, command_objects_list, "object", "", error_to diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 8b3c55dba6..d0af66fece 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -206,9 +206,9 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): # Determines which order command sets begin to be assembled from. # Objects are usually third. - cmd_order = 100 - cmd_order_error = 100 - cmd_type = "object" + cmdset_provider_order = 100 + cmdset_provider_error_order = 100 + cmdset_provider_type = "object" # Used for sorting / filtering in inventories / room contents. _content_types = ("object",) @@ -262,18 +262,16 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): """ return self.sessions.count() - def get_command_objects(self) -> dict[str, "CommandObject"]: + def get_cmdset_providers(self) -> dict[str, "CmdSetProvider"]: """ - Overrideable method which returns a dictionary of all the kinds of CommandObjects - linked to this Object. + Overrideable method which returns a dictionary of every kind of object which + has a cmdsethandler linked to this Object, and should participate in cmdset + merging. - In all normal cases, that's the Object itself, and maybe an Account if the Object - is being puppeted. - - The cmdhandler uses this to determine available cmdsets when executing a command. + Objects might be aware of an Account. Otherwise, just themselves, by default. Returns: - dict[str, CommandObject]: The CommandObjects linked to this Object. + dict[str, CmdSetProvider]: The CmdSetProviders linked to this Object. """ out = {"object": self} if self.account: diff --git a/evennia/server/serversession.py b/evennia/server/serversession.py index 50777ad61e..09488303b1 100644 --- a/evennia/server/serversession.py +++ b/evennia/server/serversession.py @@ -48,9 +48,9 @@ class ServerSession(_BASE_SESSION_CLASS): # Determines which order command sets begin to be assembled from. # Sessions are usually first. - cmd_order = 0 - cmd_order_error = 50 - cmd_type = "session" + cmdset_provider_order = 0 + cmdset_provider_error_order = 50 + cmdset_provider_type = "session" def __init__(self): """ @@ -70,24 +70,23 @@ class ServerSession(_BASE_SESSION_CLASS): cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set) - def get_command_objects(self) -> dict[str, "CommandObject"]: + def get_cmdset_providers(self) -> dict[str, "CmdSetProvider"]: """ - Overrideable method which returns a dictionary of all the kinds of CommandObjects - linked to this ServerSession. + Overrideable method which returns a dictionary of every kind of object which + has a cmdsethandler linked to this ServerSession, and should participate in cmdset + merging. In all normal cases, that's the Session itself, and possibly an account and puppeted object. - The cmdhandler uses this to determine available cmdsets when executing a command. - Returns: - dict[str, CommandObject]: The CommandObjects linked to this Object. + dict[str, CmdSetProvider]: The CmdSetProviders linked to this Object. """ out = {"session": self} if self.account: out["account"] = self.account if self.puppet: - out["puppet"] = self.puppet + out["object"] = self.puppet return out @property