Cleaned up Components page

This commit is contained in:
Griatch 2022-11-26 23:18:11 +01:00
parent ecf4b5c524
commit 857984b26c
29 changed files with 969 additions and 1735 deletions

View file

@ -4,6 +4,8 @@
Evennia comes with many utilities to help with common coding tasks. Most are accessible directly
from the flat API, otherwise you can find them in the `evennia/utils/` folder.
> This is just a small selection of the tools in `evennia/utils`. It's worth to browse [the directory](evennia.utils) and in particular the content of [evennia/utils/utils.py](evennia.utils.utils) directly to find more useful stuff.
## Searching
A common thing to do is to search for objects. There it's easiest to use the `search` method defined
@ -13,13 +15,9 @@ on all objects. This will search for objects in the same location and inside the
obj = self.search(objname)
```
The most common time one needs to do this is inside a command body. `obj =
self.caller.search(objname)` will search inside the caller's (typically, the character that typed
the command) `.contents` (their "inventory") and `.location` (their "room").
The most common time one needs to do this is inside a command body. `obj = self.caller.search(objname)` will search inside the caller's (typically, the character that typed the command) `.contents` (their "inventory") and `.location` (their "room").
Give the keyword `global_search=True` to extend search to encompass entire database. Aliases will
also be matched by this search. You will find multiple examples of this functionality in the default
command set.
Give the keyword `global_search=True` to extend search to encompass entire database. Aliases will also be matched by this search. You will find multiple examples of this functionality in the default command set.
If you need to search for objects in a code module you can use the functions in
`evennia.utils.search`. You can access these as shortcuts `evennia.search_*`.
@ -29,42 +27,39 @@ If you need to search for objects in a code module you can use the functions in
obj = search_object(objname)
```
- [`evennia.search_account`](evennia.accounts.manager.AccountDBManager.search_account)
- [`evennia.search_object`](evennia.objects.manager.ObjectDBManager.search_object)
- [`evennia.search(object)_by_tag`](evennia.utils.search.search_tag)
- [`evennia.search_script`](evennia.scripts.manager.ScriptDBManager.search_script)
- [`evennia.search_channel`](evennia.comms.managers.ChannelDBManager.search_channel)
- [`evennia.search_message`](evennia.comms.managers.MsgManager.search_message)
- [`evennia.search_help`](evennia.help.manager.HelpEntryManager.search_help)
- [evennia.search_account](evennia.accounts.manager.AccountDBManager.search_account)
- [evennia.search_object](evennia.objects.manager.ObjectDBManager.search_object)
- [evennia.search(object)_by_tag](evennia.utils.search.search_tag)
- [evennia.search_script](evennia.scripts.manager.ScriptDBManager.search_script)
- [evennia.search_channel](evennia.comms.managers.ChannelDBManager.search_channel)
- [evennia.search_message](evennia.comms.managers.MsgManager.search_message)
- [evennia.search_help](evennia.help.manager.HelpEntryManager.search_help)
Note that these latter methods will always return a `list` of results, even if the list has one or
zero entries.
Note that these latter methods will always return a `list` of results, even if the list has one or zero entries.
## Create
Apart from the in-game build commands (`@create` etc), you can also build all of Evennia's game
entities directly in code (for example when defining new create commands).
Apart from the in-game build commands (`@create` etc), you can also build all of Evennia's game entities directly in code (for example when defining new create commands).
```python
import evennia
myobj = evennia.create_objects("game.gamesrc.objects.myobj.MyObj", key="MyObj")
```
- [`evennia.create_account`](evennia.utils.create.create_account)
- [`evennia.create_object`](evennia.utils.create.create_object)
- [`evennia.create_script`](evennia.utils.create.create_script)
- [`evennia.create_channel`](evennia.utils.create.create_channel)
- [`evennia.create_help_entry`](evennia.utils.create.create_help_entry)
- [`evennia.create_message`](evennia.utils.create.create_message)
- [evennia.create_account](evennia.utils.create.create_account)
- [evennia.create_object](evennia.utils.create.create_object)
- [evennia.create_script](evennia.utils.create.create_script)
- [evennia.create_channel](evennia.utils.create.create_channel)
- [evennia.create_help_entry](evennia.utils.create.create_help_entry)
- [evennia.create_message](evennia.utils.create.create_message)
Each of these create-functions have a host of arguments to further customize the created entity. See
`evennia/utils/create.py` for more information.
Each of these create-functions have a host of arguments to further customize the created entity. See `evennia/utils/create.py` for more information.
## Logging
Normally you can use Python `print` statements to see output to the terminal/log. The `print`
statement should only be used for debugging though. For producion output, use the `logger` which
will create proper logs either to terminal or to file.
statement should only be used for debugging though. For producion output, use the `logger` which will create proper logs either to terminal or to file.
```python
from evennia import logger
@ -75,8 +70,7 @@ will create proper logs either to terminal or to file.
logger.log_dep("This feature is deprecated")
```
There is a special log-message type, `log_trace()` that is intended to be called from inside a
traceback - this can be very useful for relaying the traceback message back to log without having it
There is a special log-message type, `log_trace()` that is intended to be called from inside a traceback - this can be very useful for relaying the traceback message back to log without having it
kill the server.
```python
@ -86,25 +80,21 @@ kill the server.
logger.log_trace("This text will show beneath the traceback itself.")
```
The `log_file` logger, finally, is a very useful logger for outputting arbitrary log messages. This
is a heavily optimized asynchronous log mechanism using
[threads](https://en.wikipedia.org/wiki/Thread_%28computing%29) to avoid overhead. You should be
able to use it for very heavy custom logging without fearing disk-write delays.
The `log_file` logger, finally, is a very useful logger for outputting arbitrary log messages. This is a heavily optimized asynchronous log mechanism using [threads](https://en.wikipedia.org/wiki/Thread_%28computing%29) to avoid overhead. You should be able to use it for very heavy custom logging without fearing disk-write delays.
```python
logger.log_file(message, filename="mylog.log")
```
If not an absolute path is given, the log file will appear in the `mygame/server/logs/` directory.
If the file already exists, it will be appended to. Timestamps on the same format as the normal
Evennia logs will be automatically added to each entry. If a filename is not specified, output will
be written to a file `game/logs/game.log`.
If not an absolute path is given, the log file will appear in the `mygame/server/logs/` directory. If the file already exists, it will be appended to. Timestamps on the same format as the normal Evennia logs will be automatically added to each entry. If a filename is not specified, output will be written to a file `game/logs/game.log`.
See also the [Debugging](../Coding/Debugging.md) documentation for help with finding elusive bugs.
## Time Utilities
### Game time
Evennia tracks the current server time. You can access this time via the `evennia.gametime`
shortcut:
Evennia tracks the current server time. You can access this time via the `evennia.gametime` shortcut:
```python
from evennia import gametime
@ -131,13 +121,8 @@ gametime.reset_gametime()
```
The setting `TIME_FACTOR` determines how fast/slow in-game time runs compared to the real world. The
setting `TIME_GAME_EPOCH` sets the starting game epoch (in seconds). The functions from the
`gametime` module all return their times in seconds. You can convert this to whatever units of time
you desire for your game. You can use the `@time` command to view the server time info.
You can also *schedule* things to happen at specific in-game times using the
[gametime.schedule](evennia.utils.gametime.schedule) function:
The setting `TIME_FACTOR` determines how fast/slow in-game time runs compared to the real world. The setting `TIME_GAME_EPOCH` sets the starting game epoch (in seconds). The functions from the `gametime` module all return their times in seconds. You can convert this to whatever units of time you desire for your game. You can use the `@time` command to view the server time info.
You can also *schedule* things to happen at specific in-game times using the [gametime.schedule](evennia.utils.gametime.schedule) function:
```python
import evennia
@ -151,9 +136,7 @@ gametime.schedule(church_clock, hour=2)
### utils.time_format()
This function takes a number of seconds as input (e.g. from the `gametime` module above) and
converts it to a nice text output in days, hours etc. It's useful when you want to show how old
something is. It converts to four different styles of output using the *style* keyword:
This function takes a number of seconds as input (e.g. from the `gametime` module above) and converts it to a nice text output in days, hours etc. It's useful when you want to show how old something is. It converts to four different styles of output using the *style* keyword:
- style 0 - `5d:45m:12s` (standard colon output)
- style 1 - `5d` (shows only the longest time unit)
@ -162,6 +145,8 @@ something is. It converts to four different styles of output using the *style* k
### utils.delay()
This allows for making a delayed call.
```python
from evennia import utils
@ -169,44 +154,23 @@ def _callback(obj, text):
obj.msg(text)
# wait 10 seconds before sending "Echo!" to obj (which we assume is defined)
deferred = utils.delay(10, _callback, obj, "Echo!", persistent=False)
utils.delay(10, _callback, obj, "Echo!", persistent=False)
# code here will run immediately, not waiting for the delay to fire!
```
This creates an asynchronous delayed call. It will fire the given callback function after the given
number of seconds. This is a very light wrapper over a Twisted
[Deferred](https://twistedmatrix.com/documents/current/core/howto/defer.html). Normally this is run
non-persistently, which means that if the server is `@reload`ed before the delay is over, the
callback will never run (the server forgets it). If setting `persistent` to True, the delay will be
stored in the database and survive a `@reload` - but for this to work it is susceptible to the same
limitations incurred when saving to an [Attribute](./Attributes.md).
See [The Asynchronous process](../Concepts/Async-Process.md#delay) for more information.
The `deferred` return object can usually be ignored, but calling its `.cancel()` method will abort
the delay prematurely.
## Finding Classes
`utils.delay` is the lightest form of delayed call in Evennia. For other way to create time-bound
tasks, see the [TickerHandler](./TickerHandler.md) and [Scripts](./Scripts.md).
> Note that many delayed effects can be achieved without any need for an active timer. For example
if you have a trait that should recover a point every 5 seconds you might just need its value when
it's needed, but checking the current time and calculating on the fly what value it should have.
## Object Classes
### utils.inherits_from()
This useful function takes two arguments - an object to check and a parent. It returns `True` if
object inherits from parent *at any distance* (as opposed to Python's in-built `is_instance()` that
This useful function takes two arguments - an object to check and a parent. It returns `True` if object inherits from parent *at any distance* (as opposed to Python's in-built `is_instance()` that
will only catch immediate dependence). This function also accepts as input any combination of
classes, instances or python-paths-to-classes.
Note that Python code should usually work with [duck
typing](https://en.wikipedia.org/wiki/Duck_typing). But in Evennia's case it can sometimes be useful
to check if an object inherits from a given [Typeclass](./Typeclasses.md) as a way of identification. Say
for example that we have a typeclass *Animal*. This has a subclass *Felines* which in turn has a
subclass *HouseCat*. Maybe there are a bunch of other animal types too, like horses and dogs. Using
`inherits_from` will allow you to check for all animals in one go:
Note that Python code should usually work with [duck typing](https://en.wikipedia.org/wiki/Duck_typing). But in Evennia's case it can sometimes be useful to check if an object inherits from a given [Typeclass](./Typeclasses.md) as a way of identification. Say for example that we have a typeclass *Animal*. This has a subclass *Felines* which in turn has a subclass *HouseCat*. Maybe there are a bunch of other animal types too, like horses and dogs. Using `inherits_from` will allow you to check for all animals in one go:
```python
from evennia import utils
@ -214,8 +178,6 @@ subclass *HouseCat*. Maybe there are a bunch of other animal types too, like hor
obj.msg("The bouncer stops you in the door. He says: 'No talking animals allowed.'")
```
## Text utilities
In a text game, you are naturally doing a lot of work shuffling text back and forth. Here is a *non-
@ -224,8 +186,7 @@ If nothing else it can be good to look here before starting to develop a solutio
### utils.fill()
This flood-fills a text to a given width (shuffles the words to make each line evenly wide). It also
indents as needed.
This flood-fills a text to a given width (shuffles the words to make each line evenly wide). It also indents as needed.
```python
outtxt = fill(intxt, width=78, indent=4)
@ -244,11 +205,7 @@ can be useful in listings when showing multiple lines would mess up things.
### utils.dedent()
This solves what may at first glance appear to be a trivial problem with text - removing
indentations. It is used to shift entire paragraphs to the left, without disturbing any further
formatting they may have. A common case for this is when using Python triple-quoted strings in code
- they will retain whichever indentation they have in the code, and to make easily-readable source
code one usually don't want to shift the string to the left edge.
This solves what may at first glance appear to be a trivial problem with text - removing indentations. It is used to shift entire paragraphs to the left, without disturbing any further formatting they may have. A common case for this is when using Python triple-quoted strings in code - they will retain whichever indentation they have in the code, and to make easily-readable source code one usually don't want to shift the string to the left edge.
```python
#python code is entered at a given indentation
@ -267,31 +224,6 @@ help entries).
### to_str() and to_bytes()
Evennia supplies two utility functions for converting text to the correct
encodings. `to_str()` and `to_bytes()`. Unless you are adding a custom protocol and
need to send byte-data over the wire, `to_str` is the only one you'll need.
Evennia supplies two utility functions for converting text to the correct encodings. `to_str()` and `to_bytes()`. Unless you are adding a custom protocol and need to send byte-data over the wire, `to_str` is the only one you'll need.
The difference from Python's in-built `str()` and `bytes()` operators are that
the Evennia ones makes use of the `ENCODINGS` setting and will try very hard to
never raise a traceback but instead echo errors through logging. See
[here](../Concepts/Text-Encodings.md) for more info.
### Ansi Coloring Tools
- [evennia.utils.ansi](evennia.utils.ansi)
## Display utilities
### Making ascii tables
The [EvTable](evennia.utils.evtable.EvTable) class (`evennia/utils/evtable.py`) can be used
to create correctly formatted text tables. There is also
[EvForm](evennia.utils.evform.EvForm) (`evennia/utils/evform.py`). This reads a fixed-format
text template from a file in order to create any level of sophisticated ascii layout. Both evtable
and evform have lots of options and inputs so see the header of each module for help.
The third-party [PrettyTable](https://code.google.com/p/prettytable/) module is also included in
Evennia. PrettyTable is considered deprecated in favor of EvTable since PrettyTable cannot handle
ANSI colour. PrettyTable can be found in `evennia/utils/prettytable/`. See its homepage above for
instructions.
### Menus
- [evennia.EvMenu](evennia.utils.evmenu.EvMenu)
The difference from Python's in-built `str()` and `bytes()` operators are that the Evennia ones makes use of the `ENCODINGS` setting and will try very hard to never raise a traceback but instead echo errors through logging. See [here](../Concepts/Text-Encodings.md) for more info.