From ebcff5193274f4d9ea40fdaa7871887b11f4cc68 Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 10 May 2021 00:12:36 +0200 Subject: [PATCH] Start adding new help documentation --- docs/source/Components/Channels.md | 13 +- docs/source/Components/Help-System.md | 322 ++++++++++++++++---- evennia/commands/default/help.py | 16 +- evennia/game_template/world/help_entries.py | 2 +- evennia/help/filehelp.py | 8 +- evennia/settings_default.py | 6 +- evennia/typeclasses/attributes.py | 2 +- 7 files changed, 290 insertions(+), 79 deletions(-) diff --git a/docs/source/Components/Channels.md b/docs/source/Components/Channels.md index 2fb5706773..1438448eb7 100644 --- a/docs/source/Components/Channels.md +++ b/docs/source/Components/Channels.md @@ -1,11 +1,11 @@ # Channels In a multiplayer game, players often need other means of in-game communication -than just walking from room to room using `say` or `emote`. +than moving to the same room and use `say` or `emote`. -_Channels_ are Evennia's system for letting the server act as a fancy chat -program. When a player is connected to a channel, sending a message to it will -automatically distribute it to every other subscriber. +_Channels_ allows Evennia's to act as a fancy chat program. When a player is +connected to a channel, sending a message to it will automatically distribute +it to every other subscriber. Channels can be used both for chats between [Accounts](./Accounts) and between [Objects](./Objects) (usually Characters) and (in principle) a mix of the two. @@ -92,6 +92,11 @@ You can now just do foo Hello world! bar Hello again! +And even remove the default one if they don't want to use it + + channel/unalias public + public Hello + But you can also use your alias with the `channel` command: channel foo Hello world! diff --git a/docs/source/Components/Help-System.md b/docs/source/Components/Help-System.md index 9914da6447..537a692d45 100644 --- a/docs/source/Components/Help-System.md +++ b/docs/source/Components/Help-System.md @@ -1,37 +1,164 @@ # Help System - -An important part of Evennia is the online help system. This allows the players and staff alike to -learn how to use the game's commands as well as other information pertinent to the game. The help -system has many different aspects, from the normal editing of help entries from inside the game, to -auto-generated help entries during code development using the *auto-help system*. - -## Viewing the help database - -The main command is `help`: - - help [searchstring] - -This will show a list of help entries, ordered after categories. You will find two sections, -*Command help entries* and *Other help entries* (initially you will only have the first one). You -can use help to get more info about an entry; you can also give partial matches to get suggestions. -If you give category names you will only be shown the topics in that category. +Evennia has an extensive help system covering both command-help and regular +free-form help documentation. It supports subtopics and if failing to find a +match it will provide suggestsions, first from alternative topics and then by +finding mentions of the search term in help entries. -## Command Auto-help system +``` +------------------------------------------------------------------------------ +Help for The theatre (aliases: the hub, curtains) -A common item that requires help entries are in-game commands. Keeping these entries up-to-date with -the actual source code functionality can be a chore. Evennia's commands are therefore auto- -documenting straight from the sources through its *auto-help system*. Only commands that you and -your character can actually currently use are picked up by the auto-help system. That means an admin -will see a considerably larger amount of help topics than a normal player when using the default -`help` command. +The theatre is at the centre of the city, both literally and figuratively ... +(A lot more text about it follows ...) -The auto-help system uses the `__doc__` strings of your command classes and formats this to a nice- -looking help entry. This makes for a very easy way to keep the help updated - just document your -commands well and updating the help file is just a `@reload` away. There is no need to manually -create and maintain help database entries for commands; as long as you keep the docstrings updated -your help will be dynamically updated for you as well. +Subtopics: + theatre/lore + theatre/layout + theatre/dramatis personae +------------------------------------------------------------------------------ +``` +``` +------------------------------------------------------------------------------ +No help found + +There is no help topic matching 'evennia'. +... But matches where found within the help texts of the suggestions below. + +Suggestions: + grapevine2chan, about, irc2chan +----------------------------------------------------------------------------- +``` + +## Using the help system from in-game + +The help system is accessed in-game by use of the `help` command: + + help + +Sub-topics are accessed as `help //...`. + +Creating a new help entry from in-game is done with + + sethelp [;aliases] [,category] [,lockstring] = + +For example + + sethelp The Gods;pantheon, Lore = In the beginning all was dark ... + +Use the `/edit` switch to open the EvEditor for more convenient in-game writing +(but note that devs can also create help entries outside the game using their +regular code editor, see below). + +## Sources of help entries + +Evennia collects help entries from three sources: + +- _Auto-generated command help_ - this is literally the doc-strings of the [Command classes](./Commands). + The idea is that the command docs are easier to maintain and keep up-to-date if + the developer can change them at the same time as they do the code. +- _Database-stored help entries_ - These are created in-game (using the default `sethelp` command + as exemplified in the previous section). +- _File-stored help entries_ - These are created outside the game, as dicts in + normal Python modules. They allows developers to write and maintain their help files using + a proper text editor. + +### The Help Entry + +All help entries (no matter the source) have the following properties: + +- `key` - This is the main topic-name. For Commands, this is literally the command's `key`. +- `aliases` - Alternate names for the help entry. This can be useful if the main name is hard to remember. +- `help_category` - The general grouping of the entry. This is optional. If not given it will use the + default category given by `settings.COMMAND_DEFAULT_HELP_CATEGORY` for Commands and `settings.DEFAULT_HELP_CATEGORY` + for file+db help entries. +- `locks` - This defines who may read this entry. The locktype checked by the `help` command is `view`. In the + case of Commands, it's more common that the `cmd` lock fails - in that case the command is not loaded + into the help parser at all. +- `tags` - This is not used by default, but could be used to further organize help entries. +- `text` - The actual help entry text. This will be dedented and stripped of + extra space at beginning and end. + + +A `text` that scrolls off the screen will automatically be paginated by +the [EvMore](./EvMore) pager (you can control this with +`settings.HELP_MORE_ENABLED=False`). If you use EvMore and want to control +exactly where the pager should break the page, mark the break with the control +character `\f`. + + +#### Subtopics + +```versionadded:: 1.0 +``` + +Rather than making a very long help entry, the `text` may also be broken up +into _subtopics_. A list of the next level of subtopics are shown below the +main help text and allows the user to read more about some particular detail +that wouldn't fit in the main text. + +Subtopics use a markup slightly similar to markdown headings. The top level +heading must be named `# subtopics` (non case-sensitive) and the following +headers must be sub-headings to this (so `## subtopic name` etc). All headings +are non-case sensitive (the help command will format them). The topics can be +nested at most to a depth of 5 (which is probably too many levels already). The +parser uses fuzzy matching to find the subtopic, so one does not have to type +it all out exactly. + +Below is an example of a `text` with sub topics. + + +``` +The theatre is the heart of the city, here you can find ... +(This is the main help text, what you get with `help theatre`) + +# subtopics + +## lore + +The theatre holds many mysterious things... +(`help theatre/lore`) + +### the grand opening + +The grand opening is the name for a mysterious event where ghosts appeared ... +(`this is a subsub-topic to lore, accessible as `help theatre/lore/grand` or +any other partial match). + +### the Phantom + +Deep under the theatre, rumors has it a monster hides ... +(another subsubtopic, accessible as `help theatre/lore/phantom`) + +## layout + +The theatre is a two-story building situated at ... +(`help theatre/layout`) + +## dramatis personae + +There are many interesting people prowling the halls of the theatre ... +(`help theatre/dramatis` or `help theathre/drama` or `help theatre/personae` would work) + +### Primadonna Ada + +Everyone knows the primadonna! She is ... +(A subtopic under dramatis personae, accessible as `help theatre/drama/ada` etc) + +### The gatekeeper + +He always keeps an eye on the door and ... +(`help theatre/drama/gate`) + +``` + +### Command Auto-help system + +The auto-help system uses the `__doc__` strings of your command classes and +formats this to a nice- looking help entry. This makes for a very easy way to +keep the help updated - just document your commands well and updating the help +file is just a `reload` away. Example (from a module with command definitions): @@ -64,7 +191,8 @@ structure shown above. You should also supply the `help_category` class property if you can; this helps to group help entries together for people to more easily find them. See the `help` command in-game to see the -default categories. If you don't specify the category, "General" is assumed. +default categories. If you don't specify the category, `settings.COMMAND_DEFAULT_HELP_CATEGORY` +(default is "General") is used. If you don't want your command to be picked up by the auto-help system at all (like if you want to write its docs manually using the info in the next section or you use a [cmdset](./Command-Sets) that @@ -72,51 +200,127 @@ has its own help functionality) you can explicitly set `auto_help` class propert command definition. Alternatively, you can keep the advantages of *auto-help* in commands, but control the display of -command helps. You can do so by overriding the command's `get_help()` method. By default, this +command helps. You can do so by overriding the command's `get_help(caller, cmdset)` method. By default, this method will return the class docstring. You could modify it to add custom behavior: the text returned by this method will be displayed to the character asking for help in this command. -## Database help entries +### Database-help entries -These are all help entries not involving commands (this is handled automatically by the [Command -Auto-help system](Help-System#command-auto-help-system)). Non-automatic help entries describe how -your particular game is played - its rules, world descriptions and so on. - -A help entry consists of four parts: - -- The *topic*. This is the name of the help entry. This is what players search for when they are -looking for help. The topic can contain spaces and also partial matches will be found. -- The *help category*. Examples are *Administration*, *Building*, *Comms* or *General*. This is an -overall grouping of similar help topics, used by the engine to give a better overview. -- The *text* - the help text itself, of any length. -- locks - a [lock definition](./Locks). This can be used to limit access to this help entry, maybe -because it's staff-only or otherwise meant to be restricted. Help commands check for `access_type`s -`view` and `edit`. An example of a lock string would be `view:perm(Builders)`. - -You can create new help entries in code by using `evennia.create_help_entry()`. +These are most commonly created in-game using the `sethelp` command. If you need to create one +manually, you can do so with `evennia.create_help_entry()`: ```python + from evennia import create_help_entry entry = create_help_entry("emote", "Emoting is important because ...", category="Roleplaying", locks="view:all()") ``` -From inside the game those with the right permissions can use the `@sethelp` command to add and -modify help entries. +The entity being created is a [evennia.help.models.HelpEntry](api:evennia.help.models.HelpEntry) +object. This is _not_ a [Typeclassed](./Typeclasses) entity and is not meant to +be modified to any great degree. It holds the properties listed earlier. The +text is stored in a field `entrytext`. It does not provide a `get_help` method +like commands, stores and returns the `entrytext` directly. - > @sethelp/add emote = The emote command is ... +You can search for `HelpEntry` objects using `evennia.search_help` but note +that this will not return the two other types of help entries. -Using `@sethelp` you can add, delete and append text to existing entries. By default new entries -will go in the *General* help category. You can change this using a different form of the `@sethelp` -command: - > @sethelp/add emote, Roleplaying = Emoting is important because ... +### File-help entries -If the category *Roleplaying* did not already exist, it is created and will appear in the help -index. +```versionadded:: 1.0 +``` -You can, finally, define a lock for the help entry by following the category with a [lock -definition](Locks): +File-help entries are created by the game development team outside of the game. The +help entries are defined in normal Python modules (`.py` file ending) containing +a `dict` to represent each entry. They require a server `reload` before any changes +apply. - > @sethelp/add emote, Roleplaying, view:all() = Emoting is ... \ No newline at end of file +- Evennia will look through all modules given by `settings.FILE_HELP_ENTRY_MODULES`. This + should be a list of python-paths for Evennia to import. +- If this module contains a top-level variable `HELP_ENTRY_DICTS`, this will be imported + and must be a `list` of help-entry dicts. +- If no `HELP_ENTRY_DICTS` list is found, _every_ top-level variable in the + module that is a `dict` will be read as a help entry. The variable-names will + be ignored in this case. + +If you add multiple modules to be read, same-keyed help entries added later in the list +will override coming before. + +Each entry dict must define keys to match that needed by all help entries. +Here's an example of a help module: + +```python + +# in a module pointed to by settings.FILE_HELP_ENTRY_MODULES + +HELP_ENTRY_DICTS = [ + { + "key": "The Gods", # case-insensitive, can be searched by 'gods' too + "aliases": ['pantheon', 'religion'] + "category": "Lore", + "text": ''' + The gods formed the world ... + + # Subtopics + + ## Pantheon + + The pantheon consists of 40 gods that ... + + ### God of love + + The most prominent god is ... + + ### God of war + + Also known as 'the angry god', this god is known to ... + + ''' + }, + { + "key": "The mortals", + + } +] + +``` + +The help entry text will be dedented and will retain paragraphs. You should try +to keep your strings a reasonable width (it will look better). Just reload the +server and the file-based help entries will be available to view. + + +## Customizing the look of the help system + +This is done almost exclusively by overriding the `help` command +[evennia.commands.default.help.CmdHelp](api:evennia.commands.default.help#CmdHelp). + +Since the available commands may vary from moment to moment, `help` is +responsible for collating the three sources of help-entries (commands/db/file) +together and search through them on the fly. It also does all the formatting of +the output. + +To make it easier to tweak the look, the parts of the code that changes the +visual presentation has been broken out into separate methods `format_help_entry` and +`format_help_index` - override these in your version of `help` to change the display +as you please. See the api link above for details. + + +## Technical notes + +Since it needs to search so different types of data, the help system has to +collect all possibilities in memory before searching through the entire set. It +uses the [Lunr](https://github.com/yeraydiazdiaz/lunr.py) search engine to +search through the main bulk of help entries. Lunr is a mature engine used for +web-pages and produces much more sensible results than previous solutions. + +Once the main entry has been found, subtopics are then searched with +simple `==`, `startswith` and `in` matching (there are so relatively few of them +at that point). + +```versionchanged:: 1.0 + Replaced the bag-of-words algorithm with lunr. + +``` diff --git a/evennia/commands/default/help.py b/evennia/commands/default/help.py index 5393d98587..a0bcf41150 100644 --- a/evennia/commands/default/help.py +++ b/evennia/commands/default/help.py @@ -26,8 +26,8 @@ from evennia.utils.utils import ( from evennia.help.utils import help_search_with_index, parse_entry_for_subcategories COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) -HELP_MORE = settings.HELP_MORE -CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES +HELP_MORE_ENABLED = settings.HELP_MORE_ENABLED +DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY # limit symbol import for API __all__ = ("CmdHelp", "CmdSetHelp") @@ -83,8 +83,8 @@ class CmdHelp(COMMAND_DEFAULT_CLASS): # Help messages are wrapped in an EvMore call (unless using the webclient # with separate help popups) If you want to avoid this, simply add - # 'HELP_MORE = False' in your settings/conf/settings.py - help_more = HELP_MORE + # 'HELP_MORE_ENABLED = False' in your settings/conf/settings.py + help_more = HELP_MORE_ENABLED # colors for the help index index_type_separator_clr = "|w" @@ -572,9 +572,9 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS): sethelp/replace pickpocketing, ,attr(is_thief) = This steals ... sethelp/edit thievery - If not assigning a category, the "General" category will be used. If no - lockstring is specified, everyone will be able to read the help entry. - Sub-topics are embedded in the help text. + If not assigning a category, the `settings.DEFAULT_HELP_CATEGORY` category + will be used. If no lockstring is specified, everyone will be able to read + the help entry. Sub-topics are embedded in the help text. Note that this cannot modify command-help entries - these are modified in-code, outside the game. @@ -656,7 +656,7 @@ class CmdSetHelp(COMMAND_DEFAULT_CLASS): lockstring = ",".join(lhslist[2:]) if nlist > 2 else old_entry.locks.get() except Exception: old_entry = None - category = lhslist[1] if nlist > 1 else "General" + category = lhslist[1] if nlist > 1 else DEFAULT_HELP_CATEGORY lockstring = ",".join(lhslist[2:]) if nlist > 2 else "view:all()" category = category.lower() diff --git a/evennia/game_template/world/help_entries.py b/evennia/game_template/world/help_entries.py index 70c795ecab..559aeb63a9 100644 --- a/evennia/game_template/world/help_entries.py +++ b/evennia/game_template/world/help_entries.py @@ -14,7 +14,7 @@ Each dict is on the form :: {'key': , - 'category': , # optional, otherwise settings.FILE_DEFAULT_HELP_CATEGORY + 'category': , # optional, otherwise settings.DEFAULT_HELP_CATEGORY 'aliases': , # optional 'text': }`` # the actual help text. Can contain # subtopic sections diff --git a/evennia/help/filehelp.py b/evennia/help/filehelp.py index ae7fc61dbd..d1c672bb89 100644 --- a/evennia/help/filehelp.py +++ b/evennia/help/filehelp.py @@ -13,7 +13,7 @@ Each help-entry dict is on the form :: {'key': , - 'category': , # optional, otherwise settings.FILE_DEFAULT_HELP_CATEGORY + 'category': , # optional, otherwise settings.DEFAULT_HELP_CATEGORY 'aliases': , # optional 'text': }`` @@ -23,7 +23,7 @@ same form as other help entry-texts and contain ``# subtopics`` as normal. New help-entry modules are added to the system by providing the python-path to the module to `settings.FILE_HELP_ENTRY_MODULES`. Note that if same-key entries are added, entries in latter modules will override that of earlier ones. Use -``settings.FILE_DEFAULT_HELP_CATEGORY`` to customize what category is used if +``settings.DEFAULT_HELP_CATEGORY`` to customize what category is used if not set explicitly. An example of the contents of a module: @@ -69,6 +69,8 @@ from evennia.utils.utils import ( variable_from_module, make_iter, all_from_module) from evennia.utils import logger +_DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY + @dataclass class FileHelpEntry: @@ -144,7 +146,7 @@ class FileHelpStorageHandler: for dct in loaded_help_dicts: key = dct.get('key').lower().strip() - category = dct.get('category', settings.FILE_DEFAULT_HELP_CATEGORY).strip() + category = dct.get('category', _DEFAULT_HELP_CATEGORY).strip() aliases = list(dct.get('aliases', [])) entrytext = dct.get('text') diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 94676dc825..9018c9013f 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -589,11 +589,11 @@ TIME_IGNORE_DOWNTIMES = False # Help output from CmdHelp are wrapped in an EvMore call # (excluding webclient with separate help popups). If continuous scroll # is preferred, change 'HELP_MORE' to False. EvMORE uses CLIENT_DEFAULT_HEIGHT -HELP_MORE = True +HELP_MORE_ENABLED = True # The help category of a command if not specified. COMMAND_DEFAULT_HELP_CATEGORY = "general" -# The help category of a file-based help entry if not specified -FILE_DEFAULT_HELP_CATEGORY = "general" +# The help category of a db or file-based help entry if not specified +DEFAULT_HELP_CATEGORY = "general" # File-based help entries. These are modules containing dicts defining help # entries. They can be used together with in-database entries created in-game. FILE_HELP_ENTRY_MODULES = ["world.help_entries"] diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index b5574b26ce..ec85744afc 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -1235,7 +1235,7 @@ _GA = object.__getattribute__ _SA = object.__setattr__ -class DbHolder(object): +class DbHolder: "Holder for allowing property access of attributes" def __init__(self, obj, name, manager_name="attributes"):