From 9ca41b5d0d850f2578d46604f2d63d63bddb7c75 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 27 Jun 2024 15:58:11 +0200 Subject: [PATCH] Update game template class doc strings to be more up-to-date. Resolve #3387 --- CHANGELOG.md | 3 + evennia/accounts/accounts.py | 75 +++++-- evennia/comms/comms.py | 66 +++++- evennia/game_template/typeclasses/accounts.py | 136 +++++++----- evennia/game_template/typeclasses/channels.py | 66 +++++- .../game_template/typeclasses/characters.py | 19 +- evennia/game_template/typeclasses/exits.py | 23 +-- evennia/game_template/typeclasses/objects.py | 104 +++++++--- evennia/game_template/typeclasses/scripts.py | 13 +- evennia/objects/objects.py | 195 ++++++++++++++++-- evennia/scripts/scripts.py | 86 +++++++- 11 files changed, 628 insertions(+), 158 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84735c95f4..43f6d0ad1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ - [Fix][pull3554]: Fix/readd custom `ic` command to the `character_creator` contrib (InspectorCaracal) - [Fix][pull3466]: Make sure the `website/base.html` website base is targeted explicitly so it doesn't get overridden by same file name elsewhere in app (InspectorCaracal) +- [fix][issue3387]: Update all game template doc strings to be more up-to-date + (Griatch) - [Docs]: Doc fixes (Griatch, chiizujin, InspectorCaracal, iLPDev) [pull3470]: https://github.com/evennia/evennia/pull/3470 @@ -83,6 +85,7 @@ [pull3523]: https://github.com/evennia/evennia/pull/3523 [pull3566]: https://github.com/evennia/evennia/pull/3566 [issue3522]: https://github.com/evennia/evennia/issue/3522 +[issue3387]: https://github.com/evennia/evennia/issue/3387 ## Evennia 4.1.1 diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 89137ff672..828dc53563 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -16,14 +16,13 @@ import time import typing from random import getrandbits +import evennia from django.conf import settings from django.contrib.auth import authenticate, password_validation from django.core.exceptions import ImproperlyConfigured, ValidationError from django.utils import timezone from django.utils.module_loading import import_string from django.utils.translation import gettext as _ - -import evennia from evennia.accounts.manager import AccountManager from evennia.accounts.models import AccountDB from evennia.commands.cmdsethandler import CmdSetHandler @@ -31,24 +30,17 @@ from evennia.comms.models import ChannelDB from evennia.objects.models import ObjectDB from evennia.scripts.scripthandler import ScriptHandler from evennia.server.models import ServerConfig -from evennia.server.signals import ( - SIGNAL_ACCOUNT_POST_CREATE, - SIGNAL_ACCOUNT_POST_LOGIN_FAIL, - SIGNAL_OBJECT_POST_PUPPET, - SIGNAL_OBJECT_POST_UNPUPPET, -) +from evennia.server.signals import (SIGNAL_ACCOUNT_POST_CREATE, + SIGNAL_ACCOUNT_POST_LOGIN_FAIL, + SIGNAL_OBJECT_POST_PUPPET, + SIGNAL_OBJECT_POST_UNPUPPET) from evennia.server.throttle import Throttle from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler from evennia.typeclasses.models import TypeclassBase from evennia.utils import class_from_module, create, logger from evennia.utils.optionhandler import OptionHandler -from evennia.utils.utils import ( - is_iter, - lazy_property, - make_iter, - to_str, - variable_from_module, -) +from evennia.utils.utils import (is_iter, lazy_property, make_iter, to_str, + variable_from_module) __all__ = ("DefaultAccount", "DefaultGuest") @@ -226,7 +218,6 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase): - user (User, read-only) - django User authorization object - obj (Object) - game object controlled by account. 'character' can also be used. - - sessions (list of Sessions) - sessions connected to this account - is_superuser (bool, read-only) - if the connected user is a superuser * Handlers @@ -239,18 +230,47 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase): - scripts - script-handler. Add new scripts to object with scripts.add() - cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object - nicks - nick-handler. New nicks with nicks.add(). + - sessions - session-handler. Use session.get() to see all sessions connected, if any + - options - option-handler. Defaults are taken from settings.OPTIONS_ACCOUNT_DEFAULT + - characters - handler for listing the account's playable characters - * Helper methods + * Helper methods (check autodocs for full updated listing) - msg(text=None, from_obj=None, session=None, options=None, **kwargs) - execute_cmd(raw_string) - - search(ostring, global_search=False, attribute_name=None, - use_nicks=False, location=None, - ignore_errors=False, account=False) + - search(searchdata, return_puppet=False, search_object=False, typeclass=None, + nofound_string=None, multimatch_string=None, use_nicks=True, + quiet=False, **kwargs) - is_typeclass(typeclass, exact=False) - swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) - - access(accessing_obj, access_type='read', default=False, no_superuser_bypass=False) + - access(accessing_obj, access_type='read', default=False, no_superuser_bypass=False, **kwargs) - check_permstring(permstring) + - get_cmdsets(caller, current, **kwargs) + - get_cmdset_providers() + - uses_screenreader(session=None) + - get_display_name(looker, **kwargs) + - get_extra_display_name_info(looker, **kwargs) + - disconnect_session_from_account() + - puppet_object(session, obj) + - unpuppet_object(session) + - unpuppet_all() + - get_puppet(session) + - get_all_puppets() + - is_banned(**kwargs) + - get_username_validators(validator_config=settings.AUTH_USERNAME_VALIDATORS) + - authenticate(username, password, ip="", **kwargs) + - normalize_username(username) + - validate_username(username) + - validate_password(password, account=None) + - set_password(password, **kwargs) + - get_character_slots() + - get_available_character_slots() + - create_character(*args, **kwargs) + - create(*args, **kwargs) + - delete(*args, **kwargs) + - channel_msg(message, channel, senders=None, **kwargs) + - idle_time() + - connection_time() * Hook methods @@ -261,15 +281,26 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase): usually handled on the character level: - at_init() + - at_first_save() - at_access() - at_cmdset_get(**kwargs) + - at_password_change(**kwargs) - at_first_login() + - at_pre_login() - at_post_login(session=None) - - at_disconnect() + - at_failed_login(session, **kwargs) + - at_disconnect(reason=None, **kwargs) + - at_post_disconnect(**kwargs) - at_message_receive() - at_message_send() - at_server_reload() - at_server_shutdown() + - at_look(target=None, session=None, **kwargs) + - at_post_create_character(character, **kwargs) + - at_post_add_character(char) + - at_post_remove_character(char) + - at_pre_channel_msg(message, channel, senders=None, **kwargs) + - at_post_chnnel_msg(message, channel, senders=None, **kwargs) """ diff --git a/evennia/comms/comms.py b/evennia/comms/comms.py index d6666a2bd4..e901d4860d 100644 --- a/evennia/comms/comms.py +++ b/evennia/comms/comms.py @@ -50,6 +50,70 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase): the account-level `channel` command is used. If you were to rename that command you must tweak the output to something like `yourchannelcommandname {channelname} = $1`. + * Properties: + mutelist + banlist + wholist + + * Working methods: + get_log_filename() + set_log_filename(filename) + has_connection(account) - check if the given account listens to this channel + connect(account) - connect account to this channel + disconnect(account) - disconnect account from channel + access(access_obj, access_type='listen', default=False) - check the + access on this channel (default access_type is listen) + create(key, creator=None, *args, **kwargs) + delete() - delete this channel + message_transform(msg, emit=False, prefix=True, + sender_strings=None, external=False) - called by + the comm system and triggers the hooks below + msg(msgobj, header=None, senders=None, sender_strings=None, + persistent=None, online=False, emit=False, external=False) - main + send method, builds and sends a new message to channel. + tempmsg(msg, header=None, senders=None) - wrapper for sending non-persistent + messages. + distribute_message(msg, online=False) - send a message to all + connected accounts on channel, optionally sending only + to accounts that are currently online (optimized for very large sends) + mute(subscriber, **kwargs) + unmute(subscriber, **kwargs) + ban(target, **kwargs) + unban(target, **kwargs) + add_user_channel_alias(user, alias, **kwargs) + remove_user_channel_alias(user, alias, **kwargs) + + + Useful hooks: + at_channel_creation() - called once, when the channel is created + basetype_setup() + at_init() + at_first_save() + channel_prefix() - how the channel should be + prefixed when returning to user. Returns a string + format_senders(senders) - should return how to display multiple + senders to a channel + pose_transform(msg, sender_string) - should detect if the + sender is posing, and if so, modify the string + format_external(msg, senders, emit=False) - format messages sent + from outside the game, like from IRC + format_message(msg, emit=False) - format the message body before + displaying it to the user. 'emit' generally means that the + message should not be displayed with the sender's name. + channel_prefix() + + pre_join_channel(joiner) - if returning False, abort join + post_join_channel(joiner) - called right after successful join + pre_leave_channel(leaver) - if returning False, abort leave + post_leave_channel(leaver) - called right after successful leave + at_pre_msg(message, **kwargs) + at_post_msg(message, **kwargs) + web_get_admin_url() + web_get_create_url() + web_get_detail_url() + web_get_update_url() + web_get_delete_url() + """ objects = ChannelManager() @@ -856,7 +920,7 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase): # Used by Django Sites/Admin get_absolute_url = web_get_detail_url - # TODO Evennia 1.0+ removed hooks. Remove in 1.1. + # TODO Evennia 1.0+ removed hooks. Remove in 5.0 def message_transform(self, *args, **kwargs): raise RuntimeError( "Channel.message_transform is no longer used in 1.0+. " diff --git a/evennia/game_template/typeclasses/accounts.py b/evennia/game_template/typeclasses/accounts.py index 89d5e41295..12650e2cb8 100644 --- a/evennia/game_template/typeclasses/accounts.py +++ b/evennia/game_template/typeclasses/accounts.py @@ -27,68 +27,112 @@ from evennia.accounts.accounts import DefaultAccount, DefaultGuest class Account(DefaultAccount): """ - This class describes the actual OOC account (i.e. the user connecting - to the MUD). It does NOT have visual appearance in the game world (that - is handled by the character which is connected to this). Comm channels - are attended/joined using this object. + An Account is the actual OOC player entity. It doesn't exist in the game, + but puppets characters. - It can be useful e.g. for storing configuration options for your game, but - should generally not hold any character-related info (that's best handled - on the character level). + This is the base Typeclass for all Accounts. Accounts represent + the person playing the game and tracks account info, password + etc. They are OOC entities without presence in-game. An Account + can connect to a Character Object in order to "enter" the + game. - Can be set using BASE_ACCOUNT_TYPECLASS. + Account Typeclass API: + * Available properties (only available on initiated typeclass objects) - * available properties - - key (string) - name of account - name (string)- wrapper for user.username - aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings. - dbref (int, read-only) - unique #id-number. Also "id" can be used. - date_created (string) - time stamp of object creation - permissions (list of strings) - list of permission strings - - user (User, read-only) - django User authorization object - obj (Object) - game object controlled by account. 'character' can also be used. - sessions (list of Sessions) - sessions connected to this account - is_superuser (bool, read-only) - if the connected user is a superuser + - key (string) - name of account + - name (string)- wrapper for user.username + - aliases (list of strings) - aliases to the object. Will be saved to + database as AliasDB entries but returned as strings. + - dbref (int, read-only) - unique #id-number. Also "id" can be used. + - date_created (string) - time stamp of object creation + - permissions (list of strings) - list of permission strings + - user (User, read-only) - django User authorization object + - obj (Object) - game object controlled by account. 'character' can also + be used. + - is_superuser (bool, read-only) - if the connected user is a superuser * Handlers - locks - lock-handler: use locks.add() to add new lock strings - db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr - ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data - scripts - script-handler. Add new scripts to object with scripts.add() - cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object - nicks - nick-handler. New nicks with nicks.add(). + - locks - lock-handler: use locks.add() to add new lock strings + - db - attribute-handler: store/retrieve database attributes on this + self.db.myattr=val, val=self.db.myattr + - ndb - non-persistent attribute handler: same as db but does not + create a database entry when storing data + - scripts - script-handler. Add new scripts to object with scripts.add() + - cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object + - nicks - nick-handler. New nicks with nicks.add(). + - sessions - session-handler. Use session.get() to see all sessions connected, if any + - options - option-handler. Defaults are taken from settings.OPTIONS_ACCOUNT_DEFAULT + - characters - handler for listing the account's playable characters - * Helper methods + * Helper methods (check autodocs for full updated listing) - msg(text=None, **kwargs) - execute_cmd(raw_string, session=None) - search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, account=False) - is_typeclass(typeclass, exact=False) - swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) - access(accessing_obj, access_type='read', default=False) - check_permstring(permstring) + - msg(text=None, from_obj=None, session=None, options=None, **kwargs) + - execute_cmd(raw_string) + - search(searchdata, return_puppet=False, search_object=False, typeclass=None, + nofound_string=None, multimatch_string=None, use_nicks=True, + quiet=False, **kwargs) + - is_typeclass(typeclass, exact=False) + - swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) + - access(accessing_obj, access_type='read', default=False, no_superuser_bypass=False, **kwargs) + - check_permstring(permstring) + - get_cmdsets(caller, current, **kwargs) + - get_cmdset_providers() + - uses_screenreader(session=None) + - get_display_name(looker, **kwargs) + - get_extra_display_name_info(looker, **kwargs) + - disconnect_session_from_account() + - puppet_object(session, obj) + - unpuppet_object(session) + - unpuppet_all() + - get_puppet(session) + - get_all_puppets() + - is_banned(**kwargs) + - get_username_validators(validator_config=settings.AUTH_USERNAME_VALIDATORS) + - authenticate(username, password, ip="", **kwargs) + - normalize_username(username) + - validate_username(username) + - validate_password(password, account=None) + - set_password(password, **kwargs) + - get_character_slots() + - get_available_character_slots() + - create_character(*args, **kwargs) + - create(*args, **kwargs) + - delete(*args, **kwargs) + - channel_msg(message, channel, senders=None, **kwargs) + - idle_time() + - connection_time() - * Hook methods (when re-implementation, remember methods need to have self as first arg) + * Hook methods basetype_setup() at_account_creation() - - note that the following hooks are also found on Objects and are + > note that the following hooks are also found on Objects and are usually handled on the character level: - at_init() - at_cmdset_get(**kwargs) - at_first_login() - at_post_login(session=None) - at_disconnect() - at_message_receive() - at_message_send() - at_server_reload() - at_server_shutdown() + - at_init() + - at_first_save() + - at_access() + - at_cmdset_get(**kwargs) + - at_password_change(**kwargs) + - at_first_login() + - at_pre_login() + - at_post_login(session=None) + - at_failed_login(session, **kwargs) + - at_disconnect(reason=None, **kwargs) + - at_post_disconnect(**kwargs) + - at_message_receive() + - at_message_send() + - at_server_reload() + - at_server_shutdown() + - at_look(target=None, session=None, **kwargs) + - at_post_create_character(character, **kwargs) + - at_post_add_character(char) + - at_post_remove_character(char) + - at_pre_channel_msg(message, channel, senders=None, **kwargs) + - at_post_chnnel_msg(message, channel, senders=None, **kwargs) """ diff --git a/evennia/game_template/typeclasses/channels.py b/evennia/game_template/typeclasses/channels.py index f16e8897dc..39cc7885c4 100644 --- a/evennia/game_template/typeclasses/channels.py +++ b/evennia/game_template/typeclasses/channels.py @@ -16,14 +16,53 @@ from evennia.comms.comms import DefaultChannel class Channel(DefaultChannel): - """ - Working methods: - at_channel_creation() - called once, when the channel is created + r""" + This is the base class for all Channel Comms. Inherit from this to + create different types of communication channels. + + Class-level variables: + - `send_to_online_only` (bool, default True) - if set, will only try to + send to subscribers that are actually active. This is a useful optimization. + - `log_file` (str, default `"channel_{channelname}.log"`). This is the + log file to which the channel history will be saved. The `{channelname}` tag + will be replaced by the key of the Channel. If an Attribute 'log_file' + is set, this will be used instead. If this is None and no Attribute is found, + no history will be saved. + - `channel_prefix_string` (str, default `"[{channelname} ]"`) - this is used + as a simple template to get the channel prefix with `.channel_prefix()`. It is used + in front of every channel message; use `{channelmessage}` token to insert the + name of the current channel. Set to `None` if you want no prefix (or want to + handle it in a hook during message generation instead. + - `channel_msg_nick_pattern`(str, default `"{alias}\s*?|{alias}\s+?(?P.+?)") - + this is what used when a channel subscriber gets a channel nick assigned to this + channel. The nickhandler uses the pattern to pick out this channel's name from user + input. The `{alias}` token will get both the channel's key and any set/custom aliases + per subscriber. You need to allow for an `` regex group to catch any message + that should be send to the channel. You usually don't need to change this pattern + unless you are changing channel command-style entirely. + - `channel_msg_nick_replacement` (str, default `"channel {channelname} = $1"` - this + is used by the nickhandler to generate a replacement string once the nickhandler (using + the `channel_msg_nick_pattern`) identifies that the channel should be addressed + to send a message to it. The `` regex pattern match from `channel_msg_nick_pattern` + will end up at the `$1` position in the replacement. Together, this allows you do e.g. + 'public Hello' and have that become a mapping to `channel public = Hello`. By default, + the account-level `channel` command is used. If you were to rename that command you must + tweak the output to something like `yourchannelcommandname {channelname} = $1`. + + * Properties: + mutelist + banlist + wholist + + * Working methods: + get_log_filename() + set_log_filename(filename) has_connection(account) - check if the given account listens to this channel connect(account) - connect account to this channel disconnect(account) - disconnect account from channel access(access_obj, access_type='listen', default=False) - check the access on this channel (default access_type is listen) + create(key, creator=None, *args, **kwargs) delete() - delete this channel message_transform(msg, emit=False, prefix=True, sender_strings=None, external=False) - called by @@ -36,8 +75,19 @@ class Channel(DefaultChannel): distribute_message(msg, online=False) - send a message to all connected accounts on channel, optionally sending only to accounts that are currently online (optimized for very large sends) + mute(subscriber, **kwargs) + unmute(subscriber, **kwargs) + ban(target, **kwargs) + unban(target, **kwargs) + add_user_channel_alias(user, alias, **kwargs) + remove_user_channel_alias(user, alias, **kwargs) + Useful hooks: + at_channel_creation() - called once, when the channel is created + basetype_setup() + at_init() + at_first_save() channel_prefix() - how the channel should be prefixed when returning to user. Returns a string format_senders(senders) - should return how to display multiple @@ -49,13 +99,19 @@ class Channel(DefaultChannel): format_message(msg, emit=False) - format the message body before displaying it to the user. 'emit' generally means that the message should not be displayed with the sender's name. + channel_prefix() pre_join_channel(joiner) - if returning False, abort join post_join_channel(joiner) - called right after successful join pre_leave_channel(leaver) - if returning False, abort leave post_leave_channel(leaver) - called right after successful leave - pre_send_message(msg) - runs just before a message is sent to channel - post_send_message(msg) - called just after message was sent to channel + at_pre_msg(message, **kwargs) + at_post_msg(message, **kwargs) + web_get_admin_url() + web_get_create_url() + web_get_detail_url() + web_get_update_url() + web_get_delete_url() """ diff --git a/evennia/game_template/typeclasses/characters.py b/evennia/game_template/typeclasses/characters.py index b022c1f293..eeb1b2d737 100644 --- a/evennia/game_template/typeclasses/characters.py +++ b/evennia/game_template/typeclasses/characters.py @@ -15,22 +15,11 @@ from .objects import ObjectParent class Character(ObjectParent, DefaultCharacter): """ - The Character defaults to reimplementing some of base Object's hook methods with the - following functionality: + The Character just re-implements some of the Object's methods and hooks + to represent a Character entity in-game. - at_basetype_setup - always assigns the DefaultCmdSet to this object type - (important!)sets locks so character cannot be picked up - and its commands only be called by itself, not anyone else. - (to change things, use at_object_creation() instead). - at_post_move(source_location) - Launches the "look" command after every move. - at_post_unpuppet(account) - when Account disconnects from the Character, we - store the current location in the prelogout_location Attribute and - move it to a None-location so the "unpuppeted" character - object does not need to stay on grid. Echoes "Account has disconnected" - to the room. - at_pre_puppet - Just before Account re-connects, retrieves the character's - prelogout_location Attribute and move it back on the grid. - at_post_puppet - Echoes "AccountName has entered the game" to the room. + See mygame/typeclasses/objects.py for a list of + properties and methods available on all Object child classes like this. """ diff --git a/evennia/game_template/typeclasses/exits.py b/evennia/game_template/typeclasses/exits.py index 3a53753c2e..1b1c00561b 100644 --- a/evennia/game_template/typeclasses/exits.py +++ b/evennia/game_template/typeclasses/exits.py @@ -15,27 +15,12 @@ from .objects import ObjectParent class Exit(ObjectParent, DefaultExit): """ Exits are connectors between rooms. Exits are normal Objects except - they defines the `destination` property. It also does work in the - following methods: + they defines the `destination` property and overrides some hooks + and methods to represent the exits. - basetype_setup() - sets default exit locks (to change, use `at_object_creation` instead). - at_cmdset_get(**kwargs) - this is called when the cmdset is accessed and should - rebuild the Exit cmdset along with a command matching the name - of the Exit object. Conventionally, a kwarg `force_init` - should force a rebuild of the cmdset, this is triggered - by the `@alias` command when aliases are changed. - at_failed_traverse() - gives a default error message ("You cannot - go there") if exit traversal fails and an - attribute `err_traverse` is not defined. + See mygame/typeclasses/objects.py for a list of + properties and methods available on all Objects child classes like this. - Relevant hooks to overload (compared to other types of Objects): - at_traverse(traveller, target_loc) - called to do the actual traversal and calling of the other hooks. - If overloading this, consider using super() to use the default - movement implementation (and hook-calling). - at_post_traverse(traveller, source_loc) - called by at_traverse just after traversing. - at_failed_traverse(traveller) - called by at_traverse if traversal failed for some reason. Will - not be called if the attribute `err_traverse` is - defined, in which case that will simply be echoed. """ pass diff --git a/evennia/game_template/typeclasses/objects.py b/evennia/game_template/typeclasses/objects.py index 11b7363505..9734c2fbde 100644 --- a/evennia/game_template/typeclasses/objects.py +++ b/evennia/game_template/typeclasses/objects.py @@ -1,13 +1,10 @@ """ Object -The Object is the "naked" base class for things in the game world. +The Object is the class for general items in the game world. -Note that the default Character, Room and Exit does not inherit from -this Object, but from their respective default implementations in the -evennia library. If you want to use this class as a parent to change -the other types, you can do so by adding this as a multiple -inheritance. +Use the ObjectParent class to implement common features for *all* entities +with a location in the game world (like Characters, Rooms, Exits). """ @@ -28,20 +25,18 @@ class ObjectParent: class Object(ObjectParent, DefaultObject): """ - This is the root typeclass object, implementing an in-game Evennia - game object, such as having a location, being able to be - manipulated or looked at, etc. If you create a new typeclass, it - must always inherit from this object (or any of the other objects - in this file, since they all actually inherit from BaseObject, as - seen in src.object.objects). + This is the root Object typeclass, representing all entities that + have an actual presence in-game. DefaultObjects generally have a + location. They can also be manipulated and looked at. Game + entities you define should inherit from DefaultObject at some distance. - The BaseObject class implements several hooks tying into the game - engine. By re-implementing these hooks you can control the - system. You should never need to re-implement special Python - methods, such as __init__ and especially never __getattribute__ and - __setattr__ since these are used heavily by the typeclass system - of Evennia and messing with them might well break things for you. + It is recommended to create children of this class using the + `evennia.create_object()` function rather than to initialize the class + directly - this will both set things up and efficiently save the object + without `obj.save()` having to be called explicitly. + Note: Check the autodocs for complete class members, this may not always + be up-to date. * Base properties defined/available on all Objects @@ -58,12 +53,16 @@ class Object(ObjectParent, DefaultObject): location (Object) - current location. Is None if this is a room home (Object) - safety start-location has_account (bool, read-only)- will only return *connected* accounts - contents (list of Objects, read-only) - returns all objects inside this - object (including exits) + contents (list, read only) - returns all objects inside this object exits (list of Objects, read-only) - returns all exits from this object, if any destination (Object) - only set if this object is an exit. is_superuser (bool, read-only) - True/False if this user is a superuser + is_connected (bool, read-only) - True if this object is associated with + an Account with any connected sessions. + has_account (bool, read-only) - True is this object has an associated account. + is_superuser (bool, read-only): True if this object has an account and that + account is a superuser. * Handlers available @@ -84,18 +83,49 @@ class Object(ObjectParent, DefaultObject): * Helper methods (see src.objects.objects.py for full headers) - search(ostring, global_search=False, attribute_name=None, - use_nicks=False, location=None, ignore_errors=False, account=False) - execute_cmd(raw_string) - msg(text=None, **kwargs) - msg_contents(message, exclude=None, from_obj=None, **kwargs) + get_search_query_replacement(searchdata, **kwargs) + get_search_direct_match(searchdata, **kwargs) + get_search_candidates(searchdata, **kwargs) + get_search_result(searchdata, attribute_name=None, typeclass=None, + candidates=None, exact=False, use_dbref=None, tags=None, **kwargs) + get_stacked_result(results, **kwargs) + handle_search_results(searchdata, results, **kwargs) + search(searchdata, global_search=False, use_nicks=True, typeclass=None, + location=None, attribute_name=None, quiet=False, exact=False, + candidates=None, use_locks=True, nofound_string=None, + multimatch_string=None, use_dbref=None, tags=None, stacked=0) + search_account(searchdata, quiet=False) + execute_cmd(raw_string, session=None, **kwargs)) + msg(text=None, from_obj=None, session=None, options=None, **kwargs) + for_contents(func, exclude=None, **kwargs) + msg_contents(message, exclude=None, from_obj=None, mapping=None, + raise_funcparse_errors=False, **kwargs) move_to(destination, quiet=False, emit_to_obj=None, use_destination=True) + clear_contents() + create(key, account, caller, method, **kwargs) copy(new_key=None) + at_object_post_copy(new_obj, **kwargs) delete() is_typeclass(typeclass, exact=False) swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) - access(accessing_obj, access_type='read', default=False) + access(accessing_obj, access_type='read', default=False, + no_superuser_bypass=False, **kwargs) + filter_visible(obj_list, looker, **kwargs) + get_default_lockstring() + get_cmdsets(caller, current, **kwargs) check_permstring(permstring) + get_cmdset_providers() + get_display_name(looker=None, **kwargs) + get_extra_display_name_info(looker=None, **kwargs) + get_numbered_name(count, looker, **kwargs) + get_display_header(looker, **kwargs) + get_display_desc(looker, **kwargs) + get_display_exits(looker, **kwargs) + get_display_characters(looker, **kwargs) + get_display_things(looker, **kwargs) + get_display_footer(looker, **kwargs) + format_appearance(appearance, looker, **kwargs) + return_apperance(looker, **kwargs) * Hooks (these are class methods, so args should start with self): @@ -113,6 +143,7 @@ class Object(ObjectParent, DefaultObject): at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload + at_first_save() at_cmdset_get(**kwargs) - this is called just before the command handler requests a cmdset from this object. The kwargs are not normally used unless the cmdset is created @@ -140,12 +171,16 @@ class Object(ObjectParent, DefaultObject): after move, if obj.move_to() has quiet=False at_post_move(source_location) - always called after a move has been successfully performed. + at_pre_object_leave(leaving_object, destination, **kwargs) + at_object_leave(obj, target_location, move_type="move", **kwargs) at_object_leave(obj, target_location) - called when an object leaves this object in any fashion - at_object_receive(obj, source_location) - called when this object receives + at_pre_object_receive(obj, source_location) + at_object_receive(obj, source_location, move_type="move", **kwargs) - called when this object receives another object + at_post_move(source_location, move_type="move", **kwargs) - at_traverse(traversing_object, source_loc) - (exit-objects only) + at_traverse(traversing_object, target_location, **kwargs) - (exit-objects only) handles all moving across the exit, including calling the other exit hooks. Use super() to retain the default functionality. @@ -164,11 +199,18 @@ class Object(ObjectParent, DefaultObject): command by default at_desc(looker=None) - called by 'look' whenever the appearance is requested. + at_pre_get(getter, **kwargs) at_get(getter) - called after object has been picked up. Does not stop pickup. - at_drop(dropper) - called when this object has been dropped. - at_say(speaker, message) - by default, called if an object inside this - object speaks + at_pre_give(giver, getter, **kwargs) + at_give(giver, getter, **kwargs) + at_pre_drop(dropper, **kwargs) + at_drop(dropper, **kwargs) - called when this object has been dropped. + at_pre_say(speaker, message, **kwargs) + at_say(message, msg_self=None, msg_location=None, receivers=None, msg_receivers=None, **kwargs) + + at_look(target, **kwargs) + at_desc(looker=None) """ diff --git a/evennia/game_template/typeclasses/scripts.py b/evennia/game_template/typeclasses/scripts.py index 63f3bb8e83..06e2385143 100644 --- a/evennia/game_template/typeclasses/scripts.py +++ b/evennia/game_template/typeclasses/scripts.py @@ -17,10 +17,17 @@ from evennia.scripts.scripts import DefaultScript class Script(DefaultScript): """ + This is the base TypeClass for all Scripts. Scripts describe + all entities/systems without a physical existence in the game world + that require database storage (like an economic system or + combat tracker). They + can also have a timer/ticker component. + A script type is customized by redefining some or all of its hook methods and variables. - * available properties + * available properties (check docs for full listing, this could be + outdated). key (string) - name of object name (string)- same as key @@ -52,6 +59,7 @@ class Script(DefaultScript): * Helper methods + create(key, **kwargs) start() - start script (this usually happens automatically at creation and obj.script.add() etc) stop() - stop script, and delete it @@ -81,11 +89,14 @@ class Script(DefaultScript): will delay the first call of this method by self.interval seconds. If self.interval==0, this method will never be called. + at_pause() at_stop() - Called as the script object is stopped and is about to be removed from the game, e.g. because is_valid() returned False. + at_script_delete() at_server_reload() - Called when server reloads. Can be used to save temporary variables you want should survive a reload. at_server_shutdown() - called at a full server shutdown. + at_server_start() """ diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 7e4b72bb4c..7cc4266324 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -10,11 +10,10 @@ import time import typing from collections import defaultdict +import evennia import inflect from django.conf import settings from django.utils.translation import gettext as _ - -import evennia from evennia.commands import cmdset from evennia.commands.cmdsethandler import CmdSetHandler from evennia.objects.manager import ObjectManager @@ -24,17 +23,9 @@ from evennia.server.signals import SIGNAL_EXIT_TRAVERSED from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler from evennia.typeclasses.models import TypeclassBase from evennia.utils import ansi, create, funcparser, logger, search -from evennia.utils.utils import ( - class_from_module, - compress_whitespace, - dbref, - is_iter, - iter_to_str, - lazy_property, - make_iter, - to_str, - variable_from_module, -) +from evennia.utils.utils import (class_from_module, compress_whitespace, dbref, + is_iter, iter_to_str, lazy_property, + make_iter, to_str, variable_from_module) _INFLECT = inflect.engine() _MULTISESSION_MODE = settings.MULTISESSION_MODE @@ -204,6 +195,184 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): directly - this will both set things up and efficiently save the object without `obj.save()` having to be called explicitly. + Note: Check the autodocs for complete class members, this may not always + be up-to date. + + * Base properties defined/available on all Objects + + key (string) - name of object + name (string)- same as key + dbref (int, read-only) - unique #id-number. Also "id" can be used. + date_created (string) - time stamp of object creation + + account (Account) - controlling account (if any, only set together with + sessid below) + sessid (int, read-only) - session id (if any, only set together with + account above). Use `sessions` handler to get the + Sessions directly. + location (Object) - current location. Is None if this is a room + home (Object) - safety start-location + has_account (bool, read-only)- will only return *connected* accounts + contents (list, read only) - returns all objects inside this object + exits (list of Objects, read-only) - returns all exits from this + object, if any + destination (Object) - only set if this object is an exit. + is_superuser (bool, read-only) - True/False if this user is a superuser + is_connected (bool, read-only) - True if this object is associated with + an Account with any connected sessions. + has_account (bool, read-only) - True is this object has an associated account. + is_superuser (bool, read-only): True if this object has an account and that + account is a superuser. + + * Handlers available + + aliases - alias-handler: use aliases.add/remove/get() to use. + permissions - permission-handler: use permissions.add/remove() to + add/remove new perms. + locks - lock-handler: use locks.add() to add new lock strings + scripts - script-handler. Add new scripts to object with scripts.add() + cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object + nicks - nick-handler. New nicks with nicks.add(). + sessions - sessions-handler. Get Sessions connected to this + object with sessions.get() + attributes - attribute-handler. Use attributes.add/remove/get. + db - attribute-handler: Shortcut for attribute-handler. Store/retrieve + database attributes using self.db.myattr=val, val=self.db.myattr + ndb - non-persistent attribute handler: same as db but does not create + a database entry when storing data + + * Helper methods (see src.objects.objects.py for full headers) + + get_search_query_replacement(searchdata, **kwargs) + get_search_direct_match(searchdata, **kwargs) + get_search_candidates(searchdata, **kwargs) + get_search_result(searchdata, attribute_name=None, typeclass=None, + candidates=None, exact=False, use_dbref=None, tags=None, **kwargs) + get_stacked_result(results, **kwargs) + handle_search_results(searchdata, results, **kwargs) + search(searchdata, global_search=False, use_nicks=True, typeclass=None, + location=None, attribute_name=None, quiet=False, exact=False, + candidates=None, use_locks=True, nofound_string=None, + multimatch_string=None, use_dbref=None, tags=None, stacked=0) + search_account(searchdata, quiet=False) + execute_cmd(raw_string, session=None, **kwargs)) + msg(text=None, from_obj=None, session=None, options=None, **kwargs) + for_contents(func, exclude=None, **kwargs) + msg_contents(message, exclude=None, from_obj=None, mapping=None, + raise_funcparse_errors=False, **kwargs) + move_to(destination, quiet=False, emit_to_obj=None, use_destination=True) + clear_contents() + create(key, account, caller, method, **kwargs) + copy(new_key=None) + at_object_post_copy(new_obj, **kwargs) + delete() + is_typeclass(typeclass, exact=False) + swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) + access(accessing_obj, access_type='read', default=False, + no_superuser_bypass=False, **kwargs) + filter_visible(obj_list, looker, **kwargs) + get_default_lockstring() + get_cmdsets(caller, current, **kwargs) + check_permstring(permstring) + get_cmdset_providers() + get_display_name(looker=None, **kwargs) + get_extra_display_name_info(looker=None, **kwargs) + get_numbered_name(count, looker, **kwargs) + get_display_header(looker, **kwargs) + get_display_desc(looker, **kwargs) + get_display_exits(looker, **kwargs) + get_display_characters(looker, **kwargs) + get_display_things(looker, **kwargs) + get_display_footer(looker, **kwargs) + format_appearance(appearance, looker, **kwargs) + return_apperance(looker, **kwargs) + + * Hooks (these are class methods, so args should start with self): + + basetype_setup() - only called once, used for behind-the-scenes + setup. Normally not modified. + basetype_posthook_setup() - customization in basetype, after the object + has been created; Normally not modified. + + at_object_creation() - only called once, when object is first created. + Object customizations go here. + at_object_delete() - called just before deleting an object. If returning + False, deletion is aborted. Note that all objects + inside a deleted object are automatically moved + to their , they don't need to be removed here. + + at_init() - called whenever typeclass is cached from memory, + at least once every server restart/reload + at_first_save() + at_cmdset_get(**kwargs) - this is called just before the command handler + requests a cmdset from this object. The kwargs are + not normally used unless the cmdset is created + dynamically (see e.g. Exits). + at_pre_puppet(account)- (account-controlled objects only) called just + before puppeting + at_post_puppet() - (account-controlled objects only) called just + after completing connection account<->object + at_pre_unpuppet() - (account-controlled objects only) called just + before un-puppeting + at_post_unpuppet(account) - (account-controlled objects only) called just + after disconnecting account<->object link + at_server_reload() - called before server is reloaded + at_server_shutdown() - called just before server is fully shut down + + at_access(result, accessing_obj, access_type) - called with the result + of a lock access check on this object. Return value + does not affect check result. + + at_pre_move(destination) - called just before moving object + to the destination. If returns False, move is cancelled. + announce_move_from(destination) - called in old location, just + before move, if obj.move_to() has quiet=False + announce_move_to(source_location) - called in new location, just + after move, if obj.move_to() has quiet=False + at_post_move(source_location) - always called after a move has + been successfully performed. + at_pre_object_leave(leaving_object, destination, **kwargs) + at_object_leave(obj, target_location, move_type="move", **kwargs) + at_object_leave(obj, target_location) - called when an object leaves + this object in any fashion + at_pre_object_receive(obj, source_location) + at_object_receive(obj, source_location, move_type="move", **kwargs) - called when this object receives + another object + at_post_move(source_location, move_type="move", **kwargs) + + at_traverse(traversing_object, target_location, **kwargs) - (exit-objects only) + handles all moving across the exit, including + calling the other exit hooks. Use super() to retain + the default functionality. + at_post_traverse(traversing_object, source_location) - (exit-objects only) + called just after a traversal has happened. + at_failed_traverse(traversing_object) - (exit-objects only) called if + traversal fails and property err_traverse is not defined. + + at_msg_receive(self, msg, from_obj=None, **kwargs) - called when a message + (via self.msg()) is sent to this obj. + If returns false, aborts send. + at_msg_send(self, msg, to_obj=None, **kwargs) - called when this objects + sends a message to someone via self.msg(). + + return_appearance(looker) - describes this object. Used by "look" + command by default + at_desc(looker=None) - called by 'look' whenever the + appearance is requested. + at_pre_get(getter, **kwargs) + at_get(getter) - called after object has been picked up. + Does not stop pickup. + at_pre_give(giver, getter, **kwargs) + at_give(giver, getter, **kwargs) + at_pre_drop(dropper, **kwargs) + at_drop(dropper, **kwargs) - called when this object has been dropped. + at_pre_say(speaker, message, **kwargs) + at_say(message, msg_self=None, msg_location=None, receivers=None, msg_receivers=None, **kwargs) + + at_look(target, **kwargs) + at_desc(looker=None) + + """ # Determines which order command sets begin to be assembled from. diff --git a/evennia/scripts/scripts.py b/evennia/scripts/scripts.py index c4417af3ad..2fb0de1408 100644 --- a/evennia/scripts/scripts.py +++ b/evennia/scripts/scripts.py @@ -6,13 +6,12 @@ ability to run timers. """ from django.utils.translation import gettext as _ -from twisted.internet.defer import Deferred, maybeDeferred -from twisted.internet.task import LoopingCall - from evennia.scripts.manager import ScriptManager from evennia.scripts.models import ScriptDB from evennia.typeclasses.models import TypeclassBase from evennia.utils import create, logger +from twisted.internet.defer import Deferred, maybeDeferred +from twisted.internet.task import LoopingCall __all__ = ["DefaultScript", "DoNothing", "Store"] @@ -672,8 +671,85 @@ class ScriptBase(ScriptDB, metaclass=TypeclassBase): class DefaultScript(ScriptBase): """ This is the base TypeClass for all Scripts. Scripts describe - events, timers and states in game, they can have a time component - or describe a state that changes under certain conditions. + all entities/systems without a physical existence in the game world + that require database storage (like an economic system or + combat tracker). They + can also have a timer/ticker component. + + A script type is customized by redefining some or all of its hook + methods and variables. + + * available properties (check docs for full listing, this could be + outdated). + + key (string) - name of object + name (string)- same as key + aliases (list of strings) - aliases to the object. Will be saved + to database as AliasDB entries but returned as strings. + dbref (int, read-only) - unique #id-number. Also "id" can be used. + date_created (string) - time stamp of object creation + permissions (list of strings) - list of permission strings + + desc (string) - optional description of script, shown in listings + obj (Object) - optional object that this script is connected to + and acts on (set automatically by obj.scripts.add()) + interval (int) - how often script should run, in seconds. <0 turns + off ticker + start_delay (bool) - if the script should start repeating right away or + wait self.interval seconds + repeats (int) - how many times the script should repeat before + stopping. 0 means infinite repeats + persistent (bool) - if script should survive a server shutdown or not + is_active (bool) - if script is currently running + + * Handlers + + locks - lock-handler: use locks.add() to add new lock strings + db - attribute-handler: store/retrieve database attributes on this + self.db.myattr=val, val=self.db.myattr + ndb - non-persistent attribute handler: same as db but does not + create a database entry when storing data + + * Helper methods + + create(key, **kwargs) + start() - start script (this usually happens automatically at creation + and obj.script.add() etc) + stop() - stop script, and delete it + pause() - put the script on hold, until unpause() is called. If script + is persistent, the pause state will survive a shutdown. + unpause() - restart a previously paused script. The script will continue + from the paused timer (but at_start() will be called). + time_until_next_repeat() - if a timed script (interval>0), returns time + until next tick + + * Hook methods (should also include self as the first argument): + + at_script_creation() - called only once, when an object of this + class is first created. + is_valid() - is called to check if the script is valid to be running + at the current time. If is_valid() returns False, the running + script is stopped and removed from the game. You can use this + to check state changes (i.e. an script tracking some combat + stats at regular intervals is only valid to run while there is + actual combat going on). + at_start() - Called every time the script is started, which for persistent + scripts is at least once every server start. Note that this is + unaffected by self.delay_start, which only delays the first + call to at_repeat(). + at_repeat() - Called every self.interval seconds. It will be called + immediately upon launch unless self.delay_start is True, which + will delay the first call of this method by self.interval + seconds. If self.interval==0, this method will never + be called. + at_pause() + at_stop() - Called as the script object is stopped and is about to be + removed from the game, e.g. because is_valid() returned False. + at_script_delete() + at_server_reload() - Called when server reloads. Can be used to + save temporary variables you want should survive a reload. + at_server_shutdown() - called at a full server shutdown. + at_server_start() """