evennia.commands.cmdsethandler¶
CmdSethandler
The Cmdsethandler tracks an object’s ‘Current CmdSet’, which is the current merged sum of all CmdSets added to it.
A CmdSet constitues a set of commands. The CmdSet works as a special intelligent container that, when added to other CmdSet make sure that same-name commands are treated correctly (usually so there are no doublets). This temporary but up-to-date merger of CmdSet is jointly called the Current Cmset. It is this Current CmdSet that the commandhandler looks through whenever an account enters a command (it also adds CmdSets from objects in the room in real-time). All account objects have a ‘default cmdset’ containing all the normal in-game mud commands (look etc).
So what is all this cmdset complexity good for?
In its simplest form, a CmdSet has no commands, only a key name. In this case the cmdset’s use is up to each individual game - it can be used by an AI module for example (mobs in cmdset ‘roam’ move from room to room, in cmdset ‘attack’ they enter combat with accounts).
Defining commands in cmdsets offer some further powerful game-design consequences however. Here are some examples:
As mentioned above, all accounts always have at least the Default CmdSet. This contains the set of all normal-use commands in-game, stuff like look and @desc etc. Now assume our players end up in a dark room. You don’t want the player to be able to do much in that dark room unless they light a candle. You could handle this by changing all your normal commands to check if the player is in a dark room. This rapidly goes unwieldly and error prone. Instead you just define a cmdset with only those commands you want to be available in the ‘dark’ cmdset - maybe a modified look command and a ‘light candle’ command - and have this completely replace the default cmdset.
Another example: Say you want your players to be able to go fishing. You could implement this as a ‘fish’ command that fails whenever the account has no fishing rod. Easy enough. But what if you want to make fishing more complex - maybe you want four-five different commands for throwing your line, reeling in, etc? Most players won’t (we assume) have fishing gear, and having all those detailed commands is cluttering up the command list. And what if you want to use the ‘throw’ command also for throwing rocks etc instead of ‘using it up’ for a minor thing like fishing?
So instead you put all those detailed fishing commands into their own CommandSet called ‘Fishing’. Whenever the player gives the command ‘fish’ (presumably the code checks there is also water nearby), only THEN this CommandSet is added to the Cmdhandler of the account. The ‘throw’ command (which normally throws rocks) is replaced by the custom ‘fishing variant’ of throw. What has happened is that the Fishing CommandSet was merged on top of the Default ones, and due to how we defined it, its command overrules the default ones.
When we are tired of fishing, we give the ‘go home’ command (or whatever) and the Cmdhandler simply removes the fishing CommandSet so that we are back at defaults (and can throw rocks again).
Since any number of CommandSets can be piled on top of each other, you can then implement separate sets for different situations. For example, you can have a ‘On a boat’ set, onto which you then tack on the ‘Fishing’ set. Fishing from a boat? No problem!
- evennia.commands.cmdsethandler.import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False)[source]¶
This helper function is used by the cmdsethandler to load a cmdset instance from a python module, given a python_path. It’s usually accessed through the cmdsethandler’s add() and add_default() methods. path - This is the full path to the cmdset object on python dot-form
- Parameters:
path (str) – The path to the command set to load.
cmdsetobj (CmdSet) – The database object/typeclass on which this cmdset is to be assigned (this can be also channels and exits, as well as accounts but there will always be such an object)
emit_to_obj (Object, optional) – If given, error is emitted to this object (in addition to logging)
no_logging (bool, optional) – Don’t log/send error messages. This can be useful if import_cmdset is just used to check if this is a valid python path or not.
- Returns:
cmdset (CmdSet) –
- The imported command set. If an error was
encountered, commands.cmdsethandler._ErrorCmdSet is returned for the benefit of the handler.
- class evennia.commands.cmdsethandler.CmdSetHandler(obj, init_true=True)[source]¶
Bases:
objectThe CmdSetHandler is always stored on an object, this object is supplied as an argument.
The ‘current’ cmdset is the merged set currently active for this object. This is the set the game engine will retrieve when determining which commands are available to the object. The cmdset_stack holds a history of all CmdSets to allow the handler to remove/add cmdsets at will. Doing so will re-calculate the ‘current’ cmdset.
- __init__(obj, init_true=True)[source]¶
This method is called whenever an object is recreated.
- Parameters:
obj (Object) – An reference to the game object this handler belongs to.
init_true (bool, optional) – Set when the handler is initializing and loads the current cmdset.
- update(init_mode=False)[source]¶
Re-adds all sets in the handler to have an updated current
- Parameters:
init_mode (bool, optional) – Used automatically right after this handler was created; it imports all persistent cmdsets from the database.
Notes
This method is necessary in order to always have a .current cmdset when working with the cmdsethandler in code. But the CmdSetHandler doesn’t (cannot) consider external cmdsets and game state. This means that the .current calculated from this method will likely not match the true current cmdset as determined at run-time by cmdhandler.get_and_merge_cmdsets(). So in a running game the responsibility of keeping .current upt-to-date belongs to the central cmdhandler.get_and_merge_cmdsets()!
- add(cmdset, emit_to_obj=None, persistent=False, default_cmdset=False, **kwargs)[source]¶
Add a cmdset to the handler, on top of the old ones, unless it is set as the default one (it will then end up at the bottom of the stack)
- Parameters:
cmdset (CmdSet or str) – Can be a cmdset object or the python path to such an object.
emit_to_obj (Object, optional) – An object to receive error messages.
persistent (bool, optional) – Let cmdset remain across server reload.
default_cmdset (Cmdset, optional) – Insert this to replace the default cmdset position (there is only one such position, always at the bottom of the stack).
Notes
An interesting feature of this method is if you were to send it an already instantiated cmdset (i.e. not a class), the current cmdsethandler’s obj attribute will then not be transferred over to this already instantiated set (this is because it might be used elsewhere and can cause strange effects). This means you could in principle have the handler launch command sets tied to a different object than the handler. Not sure when this would be useful, but it’s a ‘quirk’ that has to be documented.
- add_default(cmdset, emit_to_obj=None, persistent=True, **kwargs)[source]¶
Shortcut for adding a default cmdset.
- Parameters:
cmdset (Cmdset) – The Cmdset to add.
emit_to_obj (Object, optional) – Gets error messages
persistent (bool, optional) – The new Cmdset should survive a server reboot.
- remove(cmdset=None, default_cmdset=False)[source]¶
Remove a cmdset from the handler.
- Parameters:
cmdset (CommandSet or str, optional) – This can can be supplied either as a cmdset-key, an instance of the CmdSet or a python path to the cmdset. If no key is given, the last cmdset in the stack is removed. Whenever the cmdset_stack changes, the cmdset is updated. If default_cmdset is set, this argument is ignored.
default_cmdset (bool, optional) – If set, this will remove the default cmdset (at the bottom of the stack).
- delete(cmdset=None, default_cmdset=False)¶
Remove a cmdset from the handler.
- Parameters:
cmdset (CommandSet or str, optional) – This can can be supplied either as a cmdset-key, an instance of the CmdSet or a python path to the cmdset. If no key is given, the last cmdset in the stack is removed. Whenever the cmdset_stack changes, the cmdset is updated. If default_cmdset is set, this argument is ignored.
default_cmdset (bool, optional) – If set, this will remove the default cmdset (at the bottom of the stack).
- delete_default()¶
This explicitly deletes only the default cmdset.
- get()[source]¶
Get all cmdsets.
- Returns:
cmdsets (list) – All the command sets currently in the handler.
- all()¶
Get all cmdsets.
- Returns:
cmdsets (list) – All the command sets currently in the handler.
- clear()[source]¶
Removes all Command Sets from the handler except the default one (use self.remove_default to remove that).
- has(cmdset, must_be_default=False)[source]¶
checks so the cmdsethandler contains a given cmdset
- Parameters:
cmdset (str or Cmdset) – Cmdset key, pythonpath or Cmdset to check the existence for.
must_be_default (bool, optional) – Only return True if the checked cmdset is the default one.
- Returns:
has_cmdset (bool) – Whether or not the cmdset is in the handler.
- has_cmdset(cmdset, must_be_default=False)¶
checks so the cmdsethandler contains a given cmdset
- Parameters:
cmdset (str or Cmdset) – Cmdset key, pythonpath or Cmdset to check the existence for.
must_be_default (bool, optional) – Only return True if the checked cmdset is the default one.
- Returns:
has_cmdset (bool) – Whether or not the cmdset is in the handler.
- class evennia.commands.cmdsethandler.CmdSet(cmdsetobj=None, key=None)[source]¶
Bases:
objectThis class describes a unique cmdset that understands priorities. CmdSets can be merged and made to perform various set operations on each other. CmdSets have priorities that affect which of their ingoing commands gets used.
In the examples, cmdset A always have higher priority than cmdset B.
key - the name of the cmdset. This can be used on its own for game operations
mergetype (partly from Set theory):
- Union - The two command sets are merged so that as many
commands as possible of each cmdset ends up in the merged cmdset. Same-name commands are merged by priority. This is the most common default. Ex: A1,A3 + B1,B2,B4,B5 = A1,B2,A3,B4,B5
- Intersect - Only commands found in both cmdsets
(i.e. which have same names) end up in the merged cmdset, with the higher-priority cmdset replacing the lower one. Ex: A1,A3 + B1,B2,B4,B5 = A1
- Replace - The commands of this cmdset completely replaces
the lower-priority cmdset’s commands, regardless of if same-name commands exist. Ex: A1,A3 + B1,B2,B4,B5 = A1,A3
- Remove - This removes the relevant commands from the
lower-priority cmdset completely. They are not replaced with anything, so this in effects uses the high-priority cmdset as a filter to affect the low-priority cmdset. Ex: A1,A3 + B1,B2,B4,B5 = B2,B4,B5
- Note: Commands longer than 2 characters and starting
with double underscrores, like ‘__noinput_command’ are considered ‘system commands’ and are excempt from all merge operations - they are ALWAYS included across mergers and only affected if same-named system commands replace them.
- priority- All cmdsets are always merged in pairs of two so that
the higher set’s mergetype is applied to the lower-priority cmdset. Default commands have priority 0, high-priority ones like Exits and Channels have 10 and 9. Priorities can be negative as well to give default commands preference.
- duplicates - determines what happens when two sets of equal
priority merge (only). Defaults to None and has the first of them in the merger (i.e. A above) automatically taking precedence. But if duplicates is true, the result will be a merger with more than one of each name match. This will usually lead to the account receiving a multiple-match error higher up the road, but can be good for things like cmdsets on non-account objects in a room, to allow the system to warn that more than one ‘ball’ in the room has the same ‘kick’ command defined on it, so it may offer a chance to select which ball to kick … Allowing duplicates only makes sense for Union and Intersect, the setting is ignored for the other mergetypes. Note that the duplicates flag is not propagated in a cmdset merger. So A + B = C will result in a cmdset with duplicate commands, but C.duplicates will be None. For duplication to apply to a whole cmdset stack merge, _all_ cmdsets in the stack must have .duplicates=True set.
Finally, if a final cmdset has .duplicates=None (the normal unless created alone with another value), the cmdhandler will assume True for object-based cmdsets and False for all other. This is usually the most intuitive outcome.
- key_mergetype (dict) - allows the cmdset to define a unique
mergetype for particular cmdsets. Format is {CmdSetkeystring:mergetype}. Priorities still apply. Example: {‘Myevilcmdset’,’Replace’} which would make sure for this set to always use ‘Replace’ on Myevilcmdset no matter what overall mergetype this set has.
- no_objs - don’t include any commands from nearby objects
when searching for suitable commands
- no_exits - ignore the names of exits when matching against
commands
- no_channels - ignore the name of channels when matching against
commands (WARNING- this is dangerous since the account can then not even ask staff for help if something goes wrong)
- __init__(cmdsetobj=None, key=None)[source]¶
Creates a new CmdSet instance.
- Parameters:
cmdsetobj (Session, Account, Object, optional) – This is the database object to which this particular instance of cmdset is related. It is often a character but may also be a regular object, Account or Session.
key (str, optional) – The idenfier for this cmdset. This helps if wanting to selectively remov cmdsets.
- add(cmd, allow_duplicates=False)[source]¶
Add a new command or commands to this CmdSet, a list of commands or a cmdset to this cmdset. Note that this is not a merge operation (that is handled by the + operator).
- Parameters:
cmd (Command, list, Cmdset) – This allows for adding one or more commands to this Cmdset in one go. If another Cmdset is given, all its commands will be added.
allow_duplicates (bool, optional) – If set, will not try to remove duplicate cmds in the set. This is needed during the merge process to avoid wiping commands coming from cmdsets with duplicate=True.
Notes
If cmd already exists in set, it will replace the old one (no priority checking etc happens here). This is very useful when overloading default commands).
If cmd is another cmdset class or -instance, the commands of that command set is added to this one, as if they were part of the original cmdset definition. No merging or priority checks are made, rather later added commands will simply replace existing ones to make a unique set.
- at_cmdset_creation()[source]¶
Hook method - this should be overloaded in the inheriting class, and should take care of populating the cmdset by use of self.add().
- duplicates = None¶
- errmessage = ''¶
- get(cmd)[source]¶
Get a command from the cmdset. This is mostly useful to check if the command is part of this cmdset or not.
- Parameters:
cmd (Command or str) – Either the Command object or its key.
- Returns:
cmd (Command) – The first matching Command in the set.
- get_all_cmd_keys_and_aliases(caller=None)[source]¶
Collects keys/aliases from commands
- Parameters:
caller (Object, optional) – If set, this is used to check access permissions on each command. Only commands that pass are returned.
- Returns:
names (list) –
- A list of all command keys and aliases in this cmdset. If caller
was given, this list will only contain commands to which caller passed the call locktype check.
- get_system_cmds()[source]¶
Get system commands in cmdset
- Returns:
sys_cmds (list) – The system commands in the set.
Notes
As far as the Cmdset is concerned, system commands are any commands with a key starting with double underscore __. These are excempt from merge operations.
- key = 'Unnamed CmdSet'¶
- key_mergetypes = {}¶
- make_unique(caller)[source]¶
Remove duplicate command-keys (unsafe)
- Parameters:
caller (object) – Commands on this object will get preference in the duplicate removal.
Notes
This is an unsafe command meant to clean out a cmdset of doublet commands after it has been created. It is useful for commands inheriting cmdsets from the cmdhandler where obj-based cmdsets always are added double. Doublets will be weeded out with preference to commands defined on caller, otherwise just by first-come-first-served.
- mergetype = 'Union'¶
- no_channels = None¶
- no_exits = None¶
- no_objs = None¶
- path = 'evennia.commands.cmdset.CmdSet'¶
- persistent = False¶
- priority = 0¶
- remove(cmd)[source]¶
Remove a command instance from the cmdset.
- Parameters:
cmd (Command or str) – Either the Command object to remove or the key of such a command.
- to_duplicate = ('key', 'cmdsetobj', 'no_exits', 'no_objs', 'no_channels', 'persistent', 'mergetype', 'priority', 'duplicates', 'errmessage')¶
- class evennia.commands.cmdsethandler.ServerConfig(*args, **kwargs)[source]¶
Bases:
WeakSharedMemoryModelOn-the fly storage of global settings.
Properties defined on ServerConfig:
key: Main identifier
value: Value stored in key. This is a pickled storage.
- exception DoesNotExist¶
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned¶
Bases:
MultipleObjectsReturned
- db_key¶
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- db_value¶
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- id¶
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- property key¶
Getter. Allows for value = self.key
- objects = <evennia.server.manager.ServerConfigManager object>¶
- path = 'evennia.server.models.ServerConfig'¶
- store(key, value)[source]¶
Wrap the storage.
- Parameters:
key (str) – The name of this store.
value (str) – The data to store with this key.
- typename = 'WeakSharedMemoryModelBase'¶
- property value¶
Getter. Allows for value = self.value
- evennia.commands.cmdsethandler.format_exc(limit=None, chain=True)[source]¶
Like print_exc() but return a string.