diff --git a/.github/workflows/github_action_build_docs.yml b/.github/workflows/github_action_build_docs.yml index 2dce47873f..006de35412 100644 --- a/.github/workflows/github_action_build_docs.yml +++ b/.github/workflows/github_action_build_docs.yml @@ -7,10 +7,12 @@ on: branches: [ master, develop ] paths: - 'docs/**' + - 'evennia/contrib/**' pull_request: branches: [ master, develop ] paths: - 'docs/**' + - 'evennia/contrib/**' jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d15be0167..2e27e93ed5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -160,18 +160,26 @@ Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10 - Attribute storage support defaultdics (Hendher) - Add ObjectParent mixin to default game folder template as an easy, ready-made way to override features on all ObjectDB-inheriting objects easily. + source location, mimicking behavior of `at_pre_move` hook - returning False will abort move. - Add `TagProperty`, `AliasProperty` and `PermissionProperty` to assign these data in a similar way to django fields. +- New `at_pre_object_receive(obj, source_location)` method on Objects. Called on + destination, mimicking behavior of `at_pre_move` hook - returning False will abort move. +- New `at_pre_object_leave(obj, destination)` method on Objects. Called on - The db pickle-serializer now checks for methods `__serialize_dbobjs__` and `__deserialize_dbobjs__` to allow custom packing/unpacking of nested dbobjs, to allow storing in Attribute. - Optimizations to rpsystem contrib performance. Breaking change: `.get_sdesc()` will now return `None` instead of `.db.desc` if no sdesc is set; fallback in hook (inspectorCaracal) - Reworked text2html parser to avoid problems with stateful color tags (inspectorCaracal) - Simplified `EvMenu.options_formatter` hook to use `EvColumn` and f-strings (inspectorcaracal) +- Allow `# CODE`, `# HEADER` etc as well as `#CODE`/`#HEADER` in batchcode + files - this works better with black linting. - Added `move_type` str kwarg to `move_to()` calls, optionally identifying the type of move being done ('teleport', 'disembark', 'give' etc). (volund) - Made RPSystem contrib msg calls pass `pose` or `say` as msg-`type` for use in e.g. webclient pane filtering where desired. (volund) +- Added `Account.uses_screenreader(session=None)` as a quick shortcut for + finding if a user uses a screenreader (and adjust display accordingly). - Fixed bug in `cmdset.remove()` where a command could not be deleted by `key`, even though doc suggested one could (ChrisLR) - New contrib `name_generator` for building random real-world based or fantasy-names @@ -184,7 +192,19 @@ Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10 - Contrib `buffs` for managing temporary and permanent RPG status buffs effects (tegiminis) - New `at_server_init()` hook called before all other startup hooks for all startup modes. Used for more generic overriding (volund) - +- New `search` lock type used to completely hide an object from being found by + the `DefaultObject.search` (`caller.search`) method. (CloudKeeper) +- Change setting `MULTISESSION_MODE` to now only control sessions, not how many + characters can be puppeted simultaneously. New settings now control that. +- Add new setting `AUTO_CREATE_CHARACTER_WITH_ACCOUNT`, a boolean deciding if + the new account should also get a matching character (legacy MUD style). +- Add new setting `AUTO_PUPPET_ON_LOGIN`, boolean deciding if one should + automatically puppet the last/available character on connection (legacy MUD style) +- Add new setting `MAX_NR_SIMULTANEUS_PUPPETS` - how many puppets the account + can run at the same time. Used to limit multi-playing. +- Make setting `MAX_NR_CHARACTERS` interact better with the new settings above. +- Allow `$search` funcparser func to search tags and to accept kwargs for more + powerful searches passed into the regular search functions. ## Evennia 0.9.5 diff --git a/Dockerfile b/Dockerfile index 8e09d70359..36995430bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,7 +53,7 @@ COPY . /usr/src/evennia # add the game source when rebuilding a new docker image from inside # a game dir -ONBUILD COPY . /usr/src/game +ONBUILD COPY --chown=evennia . /usr/src/game # make the game source hierarchy persistent with a named volume. # mount on-disk game location here when using the container diff --git a/docs/source/Coding/Changelog.md b/docs/source/Coding/Changelog.md index be0527668a..5b5f2c62b9 100644 --- a/docs/source/Coding/Changelog.md +++ b/docs/source/Coding/Changelog.md @@ -160,15 +160,49 @@ Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10 - Attribute storage support defaultdics (Hendher) - Add ObjectParent mixin to default game folder template as an easy, ready-made way to override features on all ObjectDB-inheriting objects easily. + source location, mimicking behavior of `at_pre_move` hook - returning False will abort move. - Add `TagProperty`, `AliasProperty` and `PermissionProperty` to assign these data in a similar way to django fields. +- New `at_pre_object_receive(obj, source_location)` method on Objects. Called on + destination, mimicking behavior of `at_pre_move` hook - returning False will abort move. +- New `at_pre_object_leave(obj, destination)` method on Objects. Called on - The db pickle-serializer now checks for methods `__serialize_dbobjs__` and `__deserialize_dbobjs__` to allow custom packing/unpacking of nested dbobjs, to allow storing in Attribute. - Optimizations to rpsystem contrib performance. Breaking change: `.get_sdesc()` will now return `None` instead of `.db.desc` if no sdesc is set; fallback in hook (inspectorCaracal) - Reworked text2html parser to avoid problems with stateful color tags (inspectorCaracal) - Simplified `EvMenu.options_formatter` hook to use `EvColumn` and f-strings (inspectorcaracal) - +- Allow `# CODE`, `# HEADER` etc as well as `#CODE`/`#HEADER` in batchcode + files - this works better with black linting. +- Added `move_type` str kwarg to `move_to()` calls, optionally identifying the type of + move being done ('teleport', 'disembark', 'give' etc). (volund) +- Made RPSystem contrib msg calls pass `pose` or `say` as msg-`type` for use in + e.g. webclient pane filtering where desired. (volund) +- Added `Account.uses_screenreader(session=None)` as a quick shortcut for + finding if a user uses a screenreader (and adjust display accordingly). +- Fixed bug in `cmdset.remove()` where a command could not be deleted by `key`, + even though doc suggested one could (ChrisLR) +- New contrib `name_generator` for building random real-world based or fantasy-names + based on phonetic rules. +- Enable proper serialization of dict subclasses in Attributes (aogier) +- `object.search` fuzzy-matching now uses `icontains` instead of `istartswith` + to better match how search works elsewhere (volund) +- The `.at_traverse` hook now receives a `exit_obj` kwarg, linking back to the + exit triggering the hook (volund) +- Contrib `buffs` for managing temporary and permanent RPG status buffs effects (tegiminis) +- New `at_server_init()` hook called before all other startup hooks for all + startup modes. Used for more generic overriding (volund) +- New `search` lock type used to completely hide an object from being found by + the `DefaultObject.search` (`caller.search`) method. (CloudKeeper) +- Change setting `MULTISESSION_MODE` to now only control sessions, not how many + characters can be puppeted simultaneously. New settings now control that. +- Add new setting `AUTO_CREATE_CHARACTER_WITH_ACCOUNT`, a boolean deciding if + the new account should also get a matching character (legacy MUD style). +- Add new setting `AUTO_PUPPET_ON_LOGIN`, boolean deciding if one should + automatically puppet the last/available character on connection (legacy MUD style) +- Add new setting `MAX_NR_SIMULTANEUS_PUPPETS` - how many puppets the account + can run at the same time. Used to limit multi-playing. +- Make setting `MAX_NR_CHARACTERS` interact better with the new settings above. ## Evennia 0.9.5 diff --git a/docs/source/Coding/Coding-Introduction.md b/docs/source/Coding/Coding-Introduction.md index b6aca1e59b..8e43cbc43b 100644 --- a/docs/source/Coding/Coding-Introduction.md +++ b/docs/source/Coding/Coding-Introduction.md @@ -14,7 +14,7 @@ you only the beginning or some part of it, it covers much of the things needed t Evennia is developed using Python. Even if you are more of a designer than a coder, it is wise to learn how to read and understand basic Python code. If you are new to Python, or need a refresher, -take a look at our [Python introduction](../Howtos/Beginner-Tutorial/Part1/Python-basic-introduction.md). +take a look at our [Python introduction](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Python-basic-introduction.md). ## Explore Evennia interactively @@ -91,7 +91,7 @@ using such a checker can be a good start to weed out the simple problems. ## Plan before you code -Before you start coding away at your dream game, take a look at our [Game Planning](../Howtos/Beginner-Tutorial/Part2/Game-Planning.md) +Before you start coding away at your dream game, take a look at our [Game Planning](../Howtos/Beginner-Tutorial/Part2/Beginner-Tutorial-Game-Planning.md) page. It might hopefully help you avoid some common pitfalls and time sinks. ## Code in your game folder, not in the evennia/ repository diff --git a/docs/source/Coding/Unit-Testing.md b/docs/source/Coding/Unit-Testing.md index 8f35930bf3..d4b29f0efb 100644 --- a/docs/source/Coding/Unit-Testing.md +++ b/docs/source/Coding/Unit-Testing.md @@ -35,7 +35,7 @@ unexpected bug. If you have implemented your own tests for your game you can run them from your game dir with - evennia test . + evennia test --settings settings.py . The period (`.`) means to run all tests found in the current directory and all subdirectories. You could also specify, say, `typeclasses` or `world` if you wanted to just run tests in those subdirs. diff --git a/docs/source/Components/Command-Sets.md b/docs/source/Components/Command-Sets.md index 1f98839bb4..22c8bdbd91 100644 --- a/docs/source/Components/Command-Sets.md +++ b/docs/source/Components/Command-Sets.md @@ -26,7 +26,7 @@ on. The tutorial world included with Evennia showcases a dark room that replaces commands with its own versions because the Character cannot see. If you want a quick start into defining your first commands and using them with command sets, you -can head over to the [Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md) which steps through things +can head over to the [Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.md) which steps through things without the explanations. ## Defining Command Sets @@ -112,7 +112,7 @@ back even if all other cmdsets fail or are removed. It is always persistent and by `cmdset.delete()`. To remove a default cmdset you must explicitly call `cmdset.remove_default()`. Command sets are often added to an object in its `at_object_creation` method. For more examples of -adding commands, read the [Step by step tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md). Generally you can +adding commands, read the [Step by step tutorial](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.md). Generally you can customize which command sets are added to your objects by using `self.cmdset.add()` or `self.cmdset.add_default()`. diff --git a/docs/source/Components/Command-System.md b/docs/source/Components/Command-System.md index db13dbd69b..c5ce240427 100644 --- a/docs/source/Components/Command-System.md +++ b/docs/source/Components/Command-System.md @@ -6,4 +6,4 @@ See also: - [Default Commands](./Default-Commands.md) -- [Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md) +- [Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.md) diff --git a/docs/source/Components/Commands.md b/docs/source/Components/Commands.md index 328144650d..d172abb730 100644 --- a/docs/source/Components/Commands.md +++ b/docs/source/Components/Commands.md @@ -29,7 +29,7 @@ object in various ways. Consider a "Tree" object with a cmdset defining the comm This page goes into full detail about how to use Commands. To fully use them you must also read the page detailing [Command Sets](./Command-Sets.md). There is also a step-by-step -[Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Adding-Commands.md) that will get you started quickly without the +[Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.md) that will get you started quickly without the extra explanations. ## Defining Commands diff --git a/docs/source/Components/EvMenu.md b/docs/source/Components/EvMenu.md index b283298783..5ee1612881 100644 --- a/docs/source/Components/EvMenu.md +++ b/docs/source/Components/EvMenu.md @@ -268,7 +268,7 @@ after start node as if it was entered on a fictional previous node. This can be very useful in order to start a menu differently depending on the Command's arguments in which it was initialized. - `session` (Session): Useful when calling the menu from an [Account](./Accounts.md) in - `MULTISESSION_MODDE` higher than 2, to make sure only the right Session sees the menu output. + `MULTISESSION_MODE` higher than 2, to make sure only the right Session sees the menu output. - `debug` (bool): If set, the `menudebug` command will be made available in the menu. Use it to list the current state of the menu and use `menudebug ` to inspect a specific state variable from the list. diff --git a/docs/source/Components/Locks.md b/docs/source/Components/Locks.md index 7bfc076db3..78e163b36b 100644 --- a/docs/source/Components/Locks.md +++ b/docs/source/Components/Locks.md @@ -105,7 +105,16 @@ something like `call:false()`. - `examine` - who may examine this object's properties. - `delete` - who may delete the object. - `edit` - who may edit properties and attributes of the object. - - `view` - if the `look` command will display/list this object + - `view` - if the `look` command will display/list this object in descriptions + and if you will be able to see its description. Note that if + you target it specifically by name, the system will still find it, just + not be able to look at it. See `search` lock to completely hide the item. + - `search` - this controls if the object can be found with the + `DefaultObject.search` method (usually referred to with `caller.search` + in Commands). This is how to create entirely 'undetectable' in-game objects. + If not setting this lock excplicitly, all objects are assumed searchable. + Note that if you are aiming to make some _permanently invisible game system, + using a [Script](./Scripts.md) is a better bet. - `get`- who may pick up the object and carry it around. - `puppet` - who may "become" this object and control it as their "character". - `attrcreate` - who may create new attributes on the object (default True) diff --git a/docs/source/Components/Prototypes.md b/docs/source/Components/Prototypes.md index ea69afaf91..dc58c13bd9 100644 --- a/docs/source/Components/Prototypes.md +++ b/docs/source/Components/Prototypes.md @@ -211,7 +211,7 @@ The default protfuncs available out of the box are defined in `evennia/prototype override the ones available, just add the same-named function in your own protfunc module. | Protfunc | Description | - +| --- | --- | | `$random()` | Returns random value in range [0, 1) | | `$randint(start, end)` | Returns random value in range [start, end] | | `$left_justify()` | Left-justify text | @@ -224,13 +224,10 @@ override the ones available, just add the same-named function in your own protfu | `$mult(, )` | Returns value1 * value2 | | `$div(, )` | Returns value2 / value1 | | `$toint()` | Returns value converted to integer (or value if not possible) | -| `$eval()` | Returns result of [literal- -eval](https://docs.python.org/2/library/ast.html#ast.literal_eval) of code string. Only simple -python expressions. | -| `$obj()` | Returns object #dbref searched globally by key, tag or #dbref. Error if more -than one found." | +| `$eval()` | Returns result of [literal-eval](https://docs.python.org/2/library/ast.html#ast.literal_eval) of code string. Only simple python expressions. | +| `$obj()` | Returns object #dbref searched globally by key, tag or #dbref. Error if more than one found. | | `$objlist()` | Like `$obj`, except always returns a list of zero, one or more results. | -| `$dbref(dbref)` | Returns argument if it is formed as a #dbref (e.g. #1234), otherwise error. +| `$dbref(dbref)` | Returns argument if it is formed as a #dbref (e.g. #1234), otherwise error. | For developers with access to Python, using protfuncs in prototypes is generally not useful. Passing real Python functions is a lot more powerful and flexible. Their main use is to allow in-game diff --git a/docs/source/Components/Webclient.md b/docs/source/Components/Webclient.md index da2e3a5506..ea24a81972 100644 --- a/docs/source/Components/Webclient.md +++ b/docs/source/Components/Webclient.md @@ -2,7 +2,7 @@ Evennia comes with a MUD client accessible from a normal web browser. During development you can try it at `http://localhost:4001/webclient`. The client consists of several parts, all under -`evennia/web/webclient/`: +`evennia/web`: `templates/webclient/webclient.html` and `templates/webclient/base.html` are the very simplistic django html templates describing the webclient layout. @@ -18,7 +18,7 @@ be used also if swapping out the gui front end. various plugins, and uses the Evennia object library for all in/out. `static/webclient/js/plugins` provides a default set of plugins that implement a "telnet-like" -interface. +interface, and a couple of example plugins to show how you could implement new plugin features. `static/webclient/css/webclient.css` is the CSS file for the client; it also defines things like how to display ANSI/Xterm256 colors etc. @@ -30,17 +30,17 @@ these. ## Customizing the web client Like was the case for the website, you override the webclient from your game directory. You need to -add/modify a file in the matching directory location within one of the _overrides directories. -These _override directories are NOT directly used by the web server when the game is running, the -server copies everything web related in the Evennia folder over to `mygame/web/static/` and then -copies in all of your _overrides. This can cause some cases were you edit a file, but it doesn't +add/modify a file in the matching directory locations within your project's `mygame/web/` directories. +These directories are NOT directly used by the web server when the game is running, the +server copies everything web related in the Evennia folder over to `mygame/server/.static/` and then +copies in all of your `mygame/web/` files. This can cause some cases were you edit a file, but it doesn't seem to make any difference in the servers behavior. **Before doing anything else, try shutting down the game and running `evennia collectstatic` from the command line then start it back up, clear your browser cache, and see if your edit shows up.** -Example: To change the utilized plugin list, you need to override base.html by copying -`evennia/web/webclient/templates/webclient/base.html` to -`mygame/web/template_overrides/webclient/base.html` and editing it to add your new plugin. +Example: To change the list of in-use plugins, you need to override base.html by copying +`evennia/web/templates/webclient/base.html` to +`mygame/web/templates/webclient/base.html` and editing it to add your new plugin. # Evennia Web Client API (from evennia.js) * `Evennia.init( opts )` @@ -96,6 +96,8 @@ manager for drag-n-drop windows, text routing and more. keys to peruse. * `hotbuttons.js` Defines onGotOptions. A Disabled-by-default plugin that defines a button bar with user-assignable commands. +* `html.js` A basic plugin to allow the client to handle "raw html" messages from the server, this +allows the server to send native HTML messages like >div style='s'<styled text>/div< * `iframe.js` Defines onOptionsUI. A goldenlayout-only plugin to create a restricted browsing sub- window for a side-by-side web/text interface, mostly an example of how to build new HTML "components" for goldenlayout. @@ -108,8 +110,50 @@ from the server and display them as inline HTML. while the tab is hidden. * `oob.js` Defines onSend. Allows the user to test/send Out Of Band json messages to the server. * `options.js` Defines most callbacks. Provides a popup-based UI to coordinate options settings with the server. -* `options2.js` Defines most callbacks. Provides a goldenlayout-based version of the options/settings tab. Integrates with other plugins via the custom onOptionsUI callback. +* `options2.js` Defines most callbacks. Provides a goldenlayout-based version of the options/settings tab. +Integrates with other plugins via the custom onOptionsUI callback. * `popups.js` Provides default popups/Dialog UI for other plugins to use. +* `text2html.js` Provides a new message handler type: `text2html`, similar to the multimedia and html +plugins. This plugin provides a way to offload rendering the regular pipe-styled ASCII messages +to the client. This allows the server to do less work, while also allowing the client a place to +customize this conversion process. To use this plugin you will need to override the current commands +in Evennia, changing any place where a raw text output message is generated and turn it into a +`text2html` message. For example: `target.msg("my text")` becomes: `target.msg(text2html=("my text"))` +(even better, use a webclient pane routing tag: `target.msg(text2html=("my text", {"type": "sometag"}))`) +`text2html` messages should format and behave identically to the server-side generated text2html() output. + +# A side note on html messages vrs text2html messages + +So...lets say you have a desire to make your webclient output more like standard webpages... +For telnet clients, you could collect a bunch of text lines together, with ASCII formatted borders, etc. +Then send the results to be rendered client-side via the text2html plugin. + +But for webclients, you could format a message directly with the html plugin to render the whole thing as an +HTML table, like so: +``` + # Server Side Python Code: + + if target.is_webclient(): + # This can be styled however you like using CSS, just add the CSS file to web/static/webclient/css/... + table = [ + "", + "", + "", + "
123
456
" + ] + target.msg( html=( "".join(table), {"type": "mytag"}) ) + else: + # This will use the client to render this as "plain, simple" ASCII text, the same + # as if it was rendered server-side via the Portal's text2html() functions + table = [ + "#############", + "# 1 # 2 # 3 #", + "#############", + "# 4 # 5 # 6 #", + "#############" + ] + target.msg( html2html=( "\n".join(table), {"type": "mytag"}) ) +``` # Writing your own Plugins @@ -131,7 +175,7 @@ output and the one starting input window. This is done by modifying your server goldenlayout_default_config.js. Start by creating a new -`mygame/web/static_overrides/webclient/js/plugins/goldenlayout_default_config.js` file, and adding +`mygame/web/static/webclient/js/plugins/goldenlayout_default_config.js` file, and adding the following JSON variable: ``` @@ -222,7 +266,7 @@ type="text/javascript"> Remember, plugins are load-order dependent, so make sure the new ` + + {% endblock %} diff --git a/evennia/web/website/tests.py b/evennia/web/website/tests.py index 1ac5e1a9c5..22fe9c7891 100644 --- a/evennia/web/website/tests.py +++ b/evennia/web/website/tests.py @@ -1,11 +1,11 @@ from django.conf import settings -from django.utils.text import slugify from django.test import Client, override_settings from django.urls import reverse +from django.utils.text import slugify +from evennia.help import filehelp from evennia.utils import class_from_module from evennia.utils.create import create_help_entry from evennia.utils.test_resources import BaseEvenniaTest -from evennia.help import filehelp _FILE_HELP_ENTRIES = None @@ -216,7 +216,7 @@ class CharacterCreateView(EvenniaWebTest): url_name = "character-create" unauthenticated_response = 302 - @override_settings(MULTISESSION_MODE=0) + @override_settings(MAX_NR_CHARACTERS=1) def test_valid_access_multisession_0(self): "Account1 with no characters should be able to create a new one" self.account.db._playable_characters = [] @@ -237,10 +237,9 @@ class CharacterCreateView(EvenniaWebTest): % self.account.db._playable_characters, ) - @override_settings(MULTISESSION_MODE=2) - @override_settings(MAX_NR_CHARACTERS=10) + @override_settings(MAX_NR_CHARACTERS=5) def test_valid_access_multisession_2(self): - "Account1 should be able to create a new character" + "Account1 should be able to create multiple new characters" # Login account self.login() @@ -275,8 +274,8 @@ class CharacterPuppetView(EvenniaWebTest): response = self.client.get(reverse(self.url_name, kwargs=kwargs), follow=True) self.assertTrue( response.status_code >= 400, - "Invalid access should return a 4xx code-- either obj not found or permission denied! (Returned %s)" - % response.status_code, + "Invalid access should return a 4xx code-- either obj not found or permission denied!" + " (Returned %s)" % response.status_code, ) diff --git a/requirements.txt b/requirements.txt index a08725076e..92c67adb14 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,6 +15,7 @@ lunr == 0.6.0 simpleeval <= 1.0 uritemplate == 4.1.1 Jinja2 < 3.1 +tzdata # try to resolve dependency issue in py3.7 attrs >= 19.2.0