Update docs with contrib auto-generated content

This commit is contained in:
Griatch 2022-07-11 09:07:08 +02:00
parent fc7a49f152
commit a18e5d0a81
11 changed files with 281 additions and 4 deletions

View file

@ -160,6 +160,14 @@ 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.
- Add `TagProperty`, `AliasProperty` and `PermissionProperty` to assign these
data in a similar way to django fields.
- 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)
## Evennia 0.9.5

View file

@ -367,8 +367,8 @@ obj.db.mydata = container # will raise error!
By adding two methods `__serialize_dbobjs__` and `__deserialize_dbobjs__` to the
object you want to save, you can pre-serialize and post-deserialize all 'hidden'
objects before Evennia's main serializer gets to work. Inside these methods, use Evennia's
[evennia.utils.dbserialize.dbserialize](api:evennia.utils.dbserialize.dbserialize) and
[dbunserialize](api:evennia.utils.dbserialize.dbunserialize) functions to safely
[evennia.utils.dbserialize.dbserialize](evennia.utils.dbserialize.dbserialize) and
[dbunserialize](evennia.utils.dbserialize.dbunserialize) functions to safely
serialize the db-objects you want to store.
```{code-block} python

View file

@ -22,7 +22,7 @@ class Sword(DefaultObject):
```
_Tags_ are short text lables one can 'hang' on objects in order to organize, group and quickly find out their properties. An Evennia entity can be tagged by any number of tags. They are more efficient than [Attributes](Attributes) since on the database-side, Tags are _shared_ between all objects with that particular tag. A tag does not carry a value in itself; it either sits on the entity
_Tags_ are short text lables one can 'hang' on objects in order to organize, group and quickly find out their properties. An Evennia entity can be tagged by any number of tags. They are more efficient than [Attributes](./Attributes.md) since on the database-side, Tags are _shared_ between all objects with that particular tag. A tag does not carry a value in itself; it either sits on the entity
Above, the tags inform us that the `Sword` is both sharp and can be wielded. If that's all they do, they could just be a normal Python flag. When tags become important is if there are a lot of objects with different combinations of tags. Maybe you have a magical spell that dulls _all_ sharp-edged objects in the castle - whether sword, dagger, spear or kitchen knife! You can then just grab all objects with the `has_sharp_edge` tag.
Another example would be a weather script affecting all rooms tagged as `outdoors` or finding all characters tagged with `belongs_to_fighter_guild`.

View file

@ -0,0 +1,198 @@
# Components
_Contrib by ChrisLR 2021_
# The Components Contrib
This contrib introduces Components and Composition to Evennia.
Each 'Component' class represents a feature that will be 'enabled' on a typeclass instance.
You can register these components on an entire typeclass or a single object at runtime.
It supports both persisted attributes and in-memory attributes by using Evennia's AttributeHandler.
# Pros
- You can reuse a feature across multiple typeclasses without inheritance
- You can cleanly organize each feature into a self-contained class.
- You can check if your object supports a feature without checking its instance.
# Cons
- It introduces additional complexity.
- A host typeclass instance is required.
# How to install
To enable component support for a typeclass,
import and inherit the ComponentHolderMixin, similar to this
```python
from evennia.contrib.base_systems.components import ComponentHolderMixin
class Character(ComponentHolderMixin, DefaultCharacter):
# ...
```
Components need to inherit the Component class directly and require a name.
```python
from evennia.contrib.components import Component
class Health(Component):
name = "health"
```
Components may define DBFields or NDBFields at the class level.
DBField will store its values in the host's DB with a prefixed key.
NDBField will store its values in the host's NDB and will not persist.
The key used will be 'component_name::field_name'.
They use AttributeProperty under the hood.
Example:
```python
from evennia.contrib.base_systems.components import Component, DBField
class Health(Component):
health = DBField(default=1)
```
Note that default is optional and will default to None.
Adding a component to a host will also a similarly named tag with 'components' as category.
A Component named health will appear as key="health, category="components".
This allows you to retrieve objects with specific components by searching with the tag.
It is also possible to add Component Tags the same way, using TagField.
TagField accepts a default value and can be used to store a single or multiple tags.
Default values are automatically added when the component is added.
Component Tags are cleared from the host if the component is removed.
Example:
```python
from evennia.contrib.base_systems.components import Component, TagField
class Health(Component):
resistances = TagField()
vulnerability = TagField(default="fire", enforce_single=True)
```
The 'resistances' field in this example can be set to multiple times and it will keep the added tags.
The 'vulnerability' field in this example will override the previous tag with the new one.
Each typeclass using the ComponentHolderMixin can declare its components
in the class via the ComponentProperty.
These are components that will always be present in a typeclass.
You can also pass kwargs to override the default values
Example
```python
from evennia.contrib.base_systems.components import ComponentHolderMixin
class Character(ComponentHolderMixin, DefaultCharacter):
health = ComponentProperty("health", hp=10, max_hp=50)
```
You can then use character.components.health to access it.
The shorter form character.cmp.health also exists.
character.health would also be accessible but only for typeclasses that have
this component defined on the class.
Alternatively you can add those components at runtime.
You will have to access those via the component handler.
Example
```python
character = self
vampirism = components.Vampirism.create(character)
character.components.add(vampirism)
...
vampirism_from_elsewhere = character.components.get("vampirism")
```
Keep in mind that all components must be imported to be visible in the listing.
As such, I recommend regrouping them in a package.
You can then import all your components in that package's __init__
Because of how Evennia import typeclasses and the behavior of python imports
I recommend placing the components package inside the typeclass package.
In other words, create a folder named components inside your typeclass folder.
Then, inside the 'typeclasses/__init__.py' file add the import to the folder, like
```python
from typeclasses import components
```
This ensures that the components package will be imported when the typeclasses are imported.
You will also need to import each components inside the package's own 'typeclasses/components/__init__.py' file.
You only need to import each module/file from there but importing the right class is a good practice.
```python
from typeclasses.components.health import Health
```
```python
from typeclasses.components import health
```
Both of the above examples will work.
# Full Example
```python
from evennia.contrib.base_systems import components
# This is the Component class
class Health(components.Component):
name = "health"
# Stores the current and max values as Attributes on the host, defaulting to 100
current = components.DBField(default=100)
max = components.DBField(default=100)
def damage(self, value):
if self.current <= 0:
return
self.current -= value
if self.current > 0:
return
self.current = 0
self.on_death()
def heal(self, value):
hp = self.current
hp += value
if hp >= self.max_hp:
hp = self.max_hp
self.current = hp
@property
def is_dead(self):
return self.current <= 0
def on_death(self):
# Behavior is defined on the typeclass
self.host.on_death()
# This is how the Character inherits the mixin and registers the component 'health'
class Character(ComponentHolderMixin, DefaultCharacter):
health = ComponentProperty("health")
# This is an example of a command that checks for the component
class Attack(Command):
key = "attack"
aliases = ('melee', 'hit')
def at_pre_cmd(self):
caller = self.caller
targets = self.caller.search(args, quiet=True)
valid_target = None
for target in targets:
# Attempt to retrieve the component, None is obtained if it does not exist.
if target.components.health:
valid_target = target
if not valid_target:
caller.msg("You can't attack that!")
return True
```
----
<small>This document page is generated from `evennia/contrib/base_systems/components/README.md`. Changes to this
file will be overwritten, so edit that file rather than this one.</small>

View file

@ -728,4 +728,4 @@ available at https://evennia.github.io/evennia/latest/.
[linkdemo]: #Links
[retext]: https://github.com/retext-project/retext
[grip]: https://github.com/joeyespo/grip
[pycharm]: https://www.jetbrains.com/pycharm/
[pycharm]: https://www.jetbrains.com/pycharm/

View file

@ -0,0 +1,10 @@
```{eval-rst}
evennia.contrib.base\_systems.components.component
=========================================================
.. automodule:: evennia.contrib.base_systems.components.component
:members:
:undoc-members:
:show-inheritance:
```

View file

@ -0,0 +1,10 @@
```{eval-rst}
evennia.contrib.base\_systems.components.dbfield
=======================================================
.. automodule:: evennia.contrib.base_systems.components.dbfield
:members:
:undoc-members:
:show-inheritance:
```

View file

@ -0,0 +1,10 @@
```{eval-rst}
evennia.contrib.base\_systems.components.holder
======================================================
.. automodule:: evennia.contrib.base_systems.components.holder
:members:
:undoc-members:
:show-inheritance:
```

View file

@ -0,0 +1,21 @@
```{eval-rst}
evennia.contrib.base\_systems.components
================================================
.. automodule:: evennia.contrib.base_systems.components
:members:
:undoc-members:
:show-inheritance:
.. toctree::
:maxdepth: 6
evennia.contrib.base_systems.components.component
evennia.contrib.base_systems.components.dbfield
evennia.contrib.base_systems.components.holder
evennia.contrib.base_systems.components.signals
evennia.contrib.base_systems.components.tests
```

View file

@ -0,0 +1,10 @@
```{eval-rst}
evennia.contrib.base\_systems.components.signals
=======================================================
.. automodule:: evennia.contrib.base_systems.components.signals
:members:
:undoc-members:
:show-inheritance:
```

View file

@ -0,0 +1,10 @@
```{eval-rst}
evennia.contrib.base\_systems.components.tests
=====================================================
.. automodule:: evennia.contrib.base_systems.components.tests
:members:
:undoc-members:
:show-inheritance:
```