2020-04-07 23:13:24 +02:00
|
|
|
# Scripts
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
[Script API reference](evennia.scripts.scripts)
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
*Scripts* are the out-of-character siblings to the in-character
|
2021-10-21 21:04:14 +02:00
|
|
|
[Objects](./Objects.md). Scripts are so flexible that the name "Script" is a bit limiting
|
2021-03-07 17:41:48 +01:00
|
|
|
in itself - but we had to pick _something_ to name them. Other possible names
|
2021-08-06 20:31:01 +02:00
|
|
|
(depending on what you'd use them for) would be `OOBObjects`, `StorageContainers` or `TimerObjects`.
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
If you ever consider creating an [Object](./Objects.md) with a `None`-location just to store some game data,
|
2021-03-07 17:41:48 +01:00
|
|
|
you should really be using a Script instead.
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
- Scripts are full [Typeclassed](./Typeclasses.md) entities - they have [Attributes](./Attributes.md) and
|
2021-03-07 17:41:48 +01:00
|
|
|
can be modified in the same way. But they have _no in-game existence_, so no
|
2021-10-21 21:04:14 +02:00
|
|
|
location or command-execution like [Objects](./Objects.md) and no connection to a particular
|
|
|
|
|
player/session like [Accounts](./Accounts.md). This means they are perfectly suitable for acting
|
2021-08-06 20:31:01 +02:00
|
|
|
as database-storage backends for game _systems_: Storing the current state of the economy,
|
|
|
|
|
who is involved in the current fight, tracking an ongoing barter and so on. They are great as
|
2021-03-07 17:41:48 +01:00
|
|
|
persistent system handlers.
|
2021-08-06 20:31:01 +02:00
|
|
|
- Scripts have an optional _timer component_. This means that you can set up the script
|
|
|
|
|
to tick the `at_repeat` hook on the Script at a certain interval. The timer can be controlled
|
2021-03-07 17:41:48 +01:00
|
|
|
independently of the rest of the script as needed. This component is optional
|
2021-08-06 20:31:01 +02:00
|
|
|
and complementary to other timing functions in Evennia, like
|
2021-10-21 21:04:14 +02:00
|
|
|
[evennia.utils.delay](evennia.utils.utils.delay) and
|
|
|
|
|
[evennia.utils.repeat](evennia.utils.utils.repeat).
|
2021-08-06 20:31:01 +02:00
|
|
|
- Scripts can _attach_ to Objects and Accounts via e.g. `obj.scripts.add/remove`. In the
|
|
|
|
|
script you can then access the object/account as `self.obj` or `self.account`. This can be used to
|
|
|
|
|
dynamically extend other typeclasses but also to use the timer component to affect the parent object
|
|
|
|
|
in various ways. For historical reasons, a Script _not_ attached to an object is referred to as a
|
2021-03-07 17:41:48 +01:00
|
|
|
_Global_ Script.
|
2021-08-06 20:31:01 +02:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
```{versionchanged} 1.0
|
2021-08-06 20:31:01 +02:00
|
|
|
In previus Evennia versions, stopping the Script's timer also meant deleting the Script object.
|
|
|
|
|
Starting with this version, the timer can be start/stopped separately and `.delete()` must be called
|
2021-03-07 17:41:48 +01:00
|
|
|
on the Script explicitly to delete it.
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
```
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
## In-game command examples
|
2021-03-07 17:41:48 +01:00
|
|
|
|
|
|
|
|
There are two main commands controlling scripts in the default cmdset:
|
|
|
|
|
|
|
|
|
|
The `addscript` command is used for attaching scripts to existing objects:
|
|
|
|
|
|
|
|
|
|
> addscript obj = bodyfunctions.BodyFunctions
|
2021-08-06 20:31:01 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
The `scripts` command is used to view all scripts and perform operations on them:
|
|
|
|
|
|
|
|
|
|
> scripts
|
|
|
|
|
> scripts/stop bodyfunctions.BodyFunctions
|
|
|
|
|
> scripts/start #244
|
|
|
|
|
> scripts/pause #11
|
|
|
|
|
> scripts/delete #566
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
```{versionchanged} 1.0
|
2021-03-07 17:41:48 +01:00
|
|
|
The `addscript` command used to be only `script` which was easy to confuse with `scripts`.
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
## Code examples
|
2021-03-07 17:41:48 +01:00
|
|
|
|
|
|
|
|
Here are some examples of working with Scripts in-code (more details to follow in later
|
|
|
|
|
sections).
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
Create a new script:
|
2020-04-07 23:13:24 +02:00
|
|
|
```python
|
2021-03-07 17:41:48 +01:00
|
|
|
new_script = evennia.create_script(key="myscript", typeclass=...)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Create script with timer component:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# (note that this will call `timed_script.at_repeat` which is empty by default)
|
2021-08-06 20:31:01 +02:00
|
|
|
timed_script = evennia.create_script(key="Timed script",
|
2021-03-07 17:41:48 +01:00
|
|
|
interval=34, # seconds <=0 means off
|
|
|
|
|
start_delay=True, # wait interval before first call
|
|
|
|
|
autostart=True) # start timer (else needing .start() )
|
|
|
|
|
|
|
|
|
|
# manipulate the script's timer
|
|
|
|
|
timed_script.stop()
|
|
|
|
|
timed_script.start()
|
2021-08-06 20:31:01 +02:00
|
|
|
timed_script.pause()
|
2021-03-07 17:41:48 +01:00
|
|
|
timed_script.unpause()
|
|
|
|
|
```
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
Attach script to another object:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
```python
|
|
|
|
|
myobj.scripts.add(new_script)
|
|
|
|
|
myobj.scripts.add(evennia.DefaultScript)
|
|
|
|
|
all_scripts_on_obj = myobj.scripts.all()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Search/find scripts in various ways:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# regular search (this is always a list, also if there is only one match)
|
|
|
|
|
list_of_myscripts = evennia.search_script("myscript")
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
# search through Evennia's GLOBAL_SCRIPTS container (based on
|
2021-03-07 17:41:48 +01:00
|
|
|
# script's key only)
|
|
|
|
|
from evennia import GLOBAL_SCRIPTS
|
|
|
|
|
|
|
|
|
|
myscript = GLOBAL_SCRIPTS.myscript
|
|
|
|
|
GLOBAL_SCRIPTS.get("Timed script").db.foo = "bar"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Delete the Script (this will also stop its timer):
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
new_script.delete()
|
|
|
|
|
timed_script.delete()
|
2020-04-07 23:13:24 +02:00
|
|
|
```
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
# Defining new Scripts
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
A Script is defined as a class and is created in the same way as other
|
2021-10-21 21:04:14 +02:00
|
|
|
[typeclassed](./Typeclasses.md) entities. The parent class is `evennia.DefaultScript`.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
## Simple storage script
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
In `mygame/typeclasses/scripts.py` is an empty `Script` class already set up. You
|
2021-03-07 17:41:48 +01:00
|
|
|
can use this as a base for your own scripts.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
2021-03-07 17:41:48 +01:00
|
|
|
# in mygame/typeclasses/scripts.py
|
|
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
from evennia import DefaultScript
|
|
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
class Script(DefaultScript):
|
|
|
|
|
# stuff common for all your scripts goes here
|
|
|
|
|
|
|
|
|
|
class MyScript(Script):
|
2022-02-05 23:20:05 +01:00
|
|
|
def at_script_creation(self):
|
2021-03-07 17:41:48 +01:00
|
|
|
"""Called once, when script is first created"""
|
|
|
|
|
self.key = "myscript"
|
|
|
|
|
self.db.foo = "bar"
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Once created, this simple Script could act as a global storage:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
evennia.create_script('typeclasses.scripts.MyScript')
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
# from somewhere else
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2022-02-05 23:20:05 +01:00
|
|
|
myscript = evennia.search_script("myscript").first()
|
2021-03-07 17:41:48 +01:00
|
|
|
bar = myscript.db.foo
|
|
|
|
|
myscript.db.something_else = 1000
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Note that if you give keyword arguments to `create_script` you can override the values
|
|
|
|
|
you set in your `at_script_creation`:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
|
|
evennia.create_script('typeclasses.scripts.MyScript', key="another name",
|
|
|
|
|
attributes=[("foo", "bar-alternative")])
|
2021-08-06 20:31:01 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
See the [create_script](evennia.utils.create.create_script) and
|
|
|
|
|
[search_script](evennia.utils.search.search_script) API documentation for more options
|
2021-03-07 17:41:48 +01:00
|
|
|
on creating and finding Scripts.
|
|
|
|
|
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
## Timed Scripts
|
2021-03-07 17:41:48 +01:00
|
|
|
|
|
|
|
|
There are several properties one can set on the Script to control its timer component.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# in mygame/typeclasses/scripts.py
|
|
|
|
|
|
|
|
|
|
class TimerScript(Script):
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
def at_script_creation(self):
|
|
|
|
|
self.key = "myscript"
|
2021-03-07 17:41:48 +01:00
|
|
|
self.desc = "An example script"
|
2020-04-07 23:13:24 +02:00
|
|
|
self.interval = 60 # 1 min repeat
|
|
|
|
|
|
|
|
|
|
def at_repeat(self):
|
2021-08-06 20:31:01 +02:00
|
|
|
# do stuff every minute
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
```
|
|
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
This example will call `at_repeat` every minute. The `create_script` function has an `autostart=True` keyword
|
2021-08-06 20:31:01 +02:00
|
|
|
set by default - this means the script's timer component will be started automatically. Otherwise
|
2021-03-07 17:41:48 +01:00
|
|
|
`.start()` must be called separately.
|
|
|
|
|
|
|
|
|
|
Supported properties are:
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
- `key` (str): The name of the script. This makes it easier to search for it later. If it's a script
|
2021-03-07 17:41:48 +01:00
|
|
|
attached to another object one can also get all scripts off that object and get the script that way.
|
|
|
|
|
- `desc` (str): Note - not `.db.desc`! This is a database field on the Script shown in script listings
|
|
|
|
|
to help identifying what does what.
|
2021-08-06 20:31:01 +02:00
|
|
|
- `interval` (int): The amount of time (in seconds) between every 'tick' of the timer. Note that
|
2021-03-07 17:41:48 +01:00
|
|
|
it's generally bad practice to use sub-second timers for anything in a text-game - the player will
|
|
|
|
|
not be able to appreciate the precision (and if you print it, it will just spam the screen). For
|
2021-08-06 20:31:01 +02:00
|
|
|
calculations you can pretty much always do them on-demand, or at a much slower interval without the
|
2021-03-07 17:41:48 +01:00
|
|
|
player being the wiser.
|
|
|
|
|
- `start_delay` (bool): If timer should start right away or wait `interval` seconds first.
|
2021-08-06 20:31:01 +02:00
|
|
|
- `repeats` (int): If >0, the timer will only run this many times before stopping. Otherwise the
|
2021-03-07 17:41:48 +01:00
|
|
|
number of repeats are infinite. If set to 1, the Script mimics a `delay` action.
|
2021-08-06 20:31:01 +02:00
|
|
|
- `persistent` (bool): This defaults to `True` and means the timer will survive a server reload/reboot.
|
2021-03-07 17:41:48 +01:00
|
|
|
If not, a reload will have the timer come back in a stopped state. Setting this to `False` will _not_
|
2021-08-06 20:31:01 +02:00
|
|
|
delete the Script object itself (use `.delete()` for this).
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
The timer component is controlled with methods on the Script class:
|
|
|
|
|
|
|
|
|
|
- `.at_repeat()` - this method is called every `interval` seconds while the timer is
|
2021-03-07 17:41:48 +01:00
|
|
|
active.
|
|
|
|
|
- `.is_valid()` - this method is called by the timer just before `at_repeat()`. If it returns `False`
|
|
|
|
|
the timer is immediately stopped.
|
2021-08-06 20:31:01 +02:00
|
|
|
- `.start()` - start/update the timer. If keyword arguments are given, they can be used to
|
|
|
|
|
change `interval`, `start_delay` etc on the fly. This calls the `.at_start()` hook.
|
2021-03-07 17:41:48 +01:00
|
|
|
This is also called after a server reload assuming the timer was not previously stopped.
|
|
|
|
|
- `.update()` - legacy alias for `.start`.
|
|
|
|
|
- `.stop()` - stops and resets the timer. This calls the `.at_stop()` hook.
|
2021-08-06 20:31:01 +02:00
|
|
|
- `.pause()` - pauses the timer where it is, storing its current position. This calls
|
2021-03-07 17:41:48 +01:00
|
|
|
the `.at_pause(manual_pause=True)` hook. This is also called on a server reload/reboot,
|
|
|
|
|
at which time the `manual_pause` will be `False`.
|
|
|
|
|
- `.unpause()` - unpause a previously paused script. This will call the `at_start` hook.
|
|
|
|
|
- `.time_until_next_repeat()` - get the time until next time the timer fires.
|
|
|
|
|
- `.remaining_repeats()` - get the number of repeats remaining, or `None` if repeats are infinite.
|
|
|
|
|
- `.reset_callcount()` - this resets the repeat counter to start over from 0. Only useful if `repeats>0`.
|
|
|
|
|
- `.force_repeat()` - this prematurely forces `at_repeat` to be called right away. Doing so will reset the
|
|
|
|
|
countdown so that next call will again happen after `interval` seconds.
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
### Script timers vs delay/repeat
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
If the _only_ goal is to get a repeat/delay effect, the
|
2021-10-21 21:04:14 +02:00
|
|
|
[evennia.utils.delay](evennia.utils.utils.delay) and
|
|
|
|
|
[evennia.utils.repeat](evennia.utils.utils.repeat) functions
|
2021-08-06 20:31:01 +02:00
|
|
|
should generally be considered first. A Script is a lot 'heavier' to create/delete on the fly.
|
|
|
|
|
In fact, for making a single delayed call (`script.repeats==1`), the `utils.delay` call is
|
2021-03-07 17:41:48 +01:00
|
|
|
probably always the better choice.
|
|
|
|
|
|
|
|
|
|
For repeating tasks, the `utils.repeat` is optimized for quick repeating of a large number of objects. It
|
2021-08-06 20:31:01 +02:00
|
|
|
uses the TickerHandler under the hood. Its subscription-based model makes it very efficient to
|
|
|
|
|
start/stop the repeating action for an object. The side effect is however that all objects set to tick
|
2021-03-07 17:41:48 +01:00
|
|
|
at a given interval will _all do so at the same time_. This may or may not look strange in-game depending
|
2021-08-06 20:31:01 +02:00
|
|
|
on the situation. By contrast the Script uses its own ticker that will operate independently from the
|
2021-03-07 17:41:48 +01:00
|
|
|
tickers of all other Scripts.
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
It's also worth noting that once the script object has _already been created_,
|
|
|
|
|
starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update
|
2021-03-07 17:41:48 +01:00
|
|
|
methods of the script also offers a bit more fine-control than using `utils.delays/repeat`.
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
## Script attached to another object
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
Scripts can be attached to an [Account](./Accounts.md) or (more commonly) an [Object](./Objects.md).
|
2021-03-07 17:41:48 +01:00
|
|
|
If so, the 'parent object' will be available to the script as either `.obj` or `.account`.
|
|
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
2021-08-06 20:31:01 +02:00
|
|
|
# mygame/typeclasses/scripts.py
|
2020-04-07 23:13:24 +02:00
|
|
|
# Script class is defined at the top of this module
|
|
|
|
|
|
|
|
|
|
import random
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
class Weather(Script):
|
2020-04-07 23:13:24 +02:00
|
|
|
"""
|
2021-08-06 20:31:01 +02:00
|
|
|
A timer script that displays weather info. Meant to
|
|
|
|
|
be attached to a room.
|
|
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
"""
|
|
|
|
|
def at_script_creation(self):
|
|
|
|
|
self.key = "weather_script"
|
|
|
|
|
self.desc = "Gives random weather messages."
|
|
|
|
|
self.interval = 60 * 5 # every 5 minutes
|
|
|
|
|
|
|
|
|
|
def at_repeat(self):
|
2021-08-06 20:31:01 +02:00
|
|
|
"called every self.interval seconds."
|
2020-04-07 23:13:24 +02:00
|
|
|
rand = random.random()
|
|
|
|
|
if rand < 0.5:
|
|
|
|
|
weather = "A faint breeze is felt."
|
|
|
|
|
elif rand < 0.7:
|
2021-08-06 20:31:01 +02:00
|
|
|
weather = "Clouds sweep across the sky."
|
2020-04-07 23:13:24 +02:00
|
|
|
else:
|
|
|
|
|
weather = "There is a light drizzle of rain."
|
|
|
|
|
# send this message to everyone inside the object this
|
|
|
|
|
# script is attached to (likely a room)
|
|
|
|
|
self.obj.msg_contents(weather)
|
|
|
|
|
```
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
If attached to a room, this Script will randomly report some weather
|
2020-04-07 23:13:24 +02:00
|
|
|
to everyone in the room every 5 minutes.
|
|
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
```python
|
2020-04-07 23:13:24 +02:00
|
|
|
myroom.scripts.add(scripts.Weather)
|
|
|
|
|
```
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
> Note that `typeclasses` in your game dir is added to the setting `TYPECLASS_PATHS`.
|
2020-04-07 23:13:24 +02:00
|
|
|
> Therefore we don't need to give the full path (`typeclasses.scripts.Weather`
|
|
|
|
|
> but only `scripts.Weather` above.
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
You can also attach the script as part of creating it:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
create_script('typeclasses.weather.Weather', obj=myroom)
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
# Other Script methods
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
A Script has all the properties of a typeclassed object, such as `db` and `ndb`(see
|
2021-10-21 21:04:14 +02:00
|
|
|
[Typeclasses](./Typeclasses.md)). Setting `key` is useful in order to manage scripts (delete them by name
|
2020-06-16 16:53:35 +02:00
|
|
|
etc). These are usually set up in the Script's typeclass, but can also be assigned on the fly as
|
|
|
|
|
keyword arguments to `evennia.create_script`.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
- `at_script_creation()` - this is only called once - when the script is first created.
|
2020-06-16 16:53:35 +02:00
|
|
|
- `at_server_reload()` - this is called whenever the server is warm-rebooted (e.g. with the
|
2021-03-07 17:41:48 +01:00
|
|
|
`reload` command). It's a good place to save non-persistent data you might want to survive a
|
2020-06-16 16:53:35 +02:00
|
|
|
reload.
|
2020-04-07 23:13:24 +02:00
|
|
|
- `at_server_shutdown()` - this is called when a system reset or systems shutdown is invoked.
|
2021-03-07 17:41:48 +01:00
|
|
|
- `at_server_start()` - this is called when the server comes back (from reload/shutdown/reboot). It
|
|
|
|
|
can be usuful for initializations and caching of non-persistent data when starting up a script's
|
|
|
|
|
functionality.
|
|
|
|
|
- `at_repeat()`
|
|
|
|
|
- `at_start()`
|
|
|
|
|
- `at_pause()`
|
|
|
|
|
- `at_stop()`
|
|
|
|
|
- `delete()` - same as for other typeclassed entities, this will delete the Script. Of note is that
|
|
|
|
|
it will also stop the timer (if it runs), leading to the `at_stop` hook being called.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
In addition, Scripts support [Attributes](./Attributes.md), [Tags](./Tags.md) and [Locks](./Locks.md) etc like other
|
2021-03-07 17:41:48 +01:00
|
|
|
Typeclassed entities.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
See also the methods involved in controlling a [Timed Script](#timed-scripts) above.
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
# The GLOBAL_SCRIPTS container
|
2021-03-07 17:41:48 +01:00
|
|
|
|
|
|
|
|
A Script not attached to another entity is commonly referred to as a _Global_ script since it't available
|
|
|
|
|
to access from anywhere. This means they need to be searched for in order to be used.
|
|
|
|
|
|
|
|
|
|
Evennia supplies a convenient "container" `evennia.GLOBAL_SCRIPTS` to help organize your global
|
|
|
|
|
scripts. All you need is the Script's `key`.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
from evennia import GLOBAL_SCRIPTS
|
|
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
# access as a property on the container, named the same as the key
|
2020-04-07 23:13:24 +02:00
|
|
|
my_script = GLOBAL_SCRIPTS.my_script
|
|
|
|
|
# needed if there are spaces in name or name determined on the fly
|
|
|
|
|
another_script = GLOBAL_SCRIPTS.get("another script")
|
2021-03-07 17:41:48 +01:00
|
|
|
# get all global scripts (this returns a Django Queryset)
|
2020-04-07 23:13:24 +02:00
|
|
|
all_scripts = GLOBAL_SCRIPTS.all()
|
|
|
|
|
# you can operate directly on the script
|
|
|
|
|
GLOBAL_SCRIPTS.weather.db.current_weather = "Cloudy"
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
```{warning}
|
2021-08-06 20:31:01 +02:00
|
|
|
Note that global scripts appear as properties on `GLOBAL_SCRIPTS` based on their `key`.
|
2021-03-07 17:41:48 +01:00
|
|
|
If you were to create two global scripts with the same `key` (even with different typeclasses),
|
2021-08-06 20:31:01 +02:00
|
|
|
the `GLOBAL_SCRIPTS` container will only return one of them (which one depends on order in
|
2021-03-07 17:41:48 +01:00
|
|
|
the database). Best is to organize your scripts so that this does not happen. Otherwise, use
|
|
|
|
|
`evennia.search_scripts` to get exactly the script you want.
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
There are two ways to make a script appear as a property on `GLOBAL_SCRIPTS`:
|
|
|
|
|
|
|
|
|
|
1. Manually create a new global script with a `key` using `create_script`.
|
2021-08-06 20:31:01 +02:00
|
|
|
2. Define the script's properties in the `GLOBAL_SCRIPTS` settings variable. This tells Evennia
|
2021-03-07 17:41:48 +01:00
|
|
|
that it should check if a script with that `key` exists and if not, create it for you.
|
2021-08-06 20:31:01 +02:00
|
|
|
This is very useful for scripts that must always exist and/or should be auto-created
|
|
|
|
|
when your server restarts. If you use this method, you must make sure all
|
|
|
|
|
script keys are globally unique.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
Here's how to tell Evennia to manage the script in settings:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
2021-03-07 17:41:48 +01:00
|
|
|
# in mygame/server/conf/settings.py
|
|
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
GLOBAL_SCRIPTS = {
|
2021-08-06 20:31:01 +02:00
|
|
|
"my_script": {
|
2020-04-07 23:13:24 +02:00
|
|
|
"typeclass": "scripts.Weather",
|
|
|
|
|
"repeats": -1,
|
|
|
|
|
"interval": 50,
|
|
|
|
|
"desc": "Weather script"
|
|
|
|
|
},
|
2021-03-07 17:41:48 +01:00
|
|
|
"storagescript": {}
|
2020-04-07 23:13:24 +02:00
|
|
|
}
|
|
|
|
|
```
|
2021-08-06 20:31:01 +02:00
|
|
|
|
|
|
|
|
Above we add two scripts with keys `myscript` and `storagescript`respectively. The following dict
|
|
|
|
|
can be empty - the `settings.BASE_SCRIPT_TYPECLASS` will then be used. Under the hood, the provided
|
|
|
|
|
dict (along with the `key`) will be passed into `create_script` automatically, so
|
2021-10-21 21:04:14 +02:00
|
|
|
all the [same keyword arguments as for create_script](evennia.utils.create.create_script) are
|
2021-03-07 17:41:48 +01:00
|
|
|
supported here.
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
```{warning}
|
2021-08-06 20:31:01 +02:00
|
|
|
Before setting up Evennia to manage your script like this, make sure that your Script typeclass
|
|
|
|
|
does not have any critical errors (test it separately). If there are, you'll see errors in your log
|
2021-03-07 17:41:48 +01:00
|
|
|
and your Script will temporarily fall back to being a `DefaultScript` type.
|
|
|
|
|
```
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
Moreover, a script defined this way is *guaranteed* to exist when you try to access it:
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
```python
|
|
|
|
|
from evennia import GLOBAL_SCRIPTS
|
2021-03-07 17:41:48 +01:00
|
|
|
# Delete the script
|
|
|
|
|
GLOBAL_SCRIPTS.storagescript.delete()
|
2020-04-07 23:13:24 +02:00
|
|
|
# running the `scripts` command now will show no storagescript
|
2021-08-06 20:31:01 +02:00
|
|
|
# but below it's automatically recreated again!
|
2020-04-07 23:13:24 +02:00
|
|
|
storage = GLOBAL_SCRIPTS.storagescript
|
|
|
|
|
```
|
|
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
That is, if the script is deleted, next time you get it from `GLOBAL_SCRIPTS`, Evennia will use the
|
2021-08-06 20:31:01 +02:00
|
|
|
information in settings to recreate it for you on the fly.
|
2021-03-07 17:41:48 +01:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
# Hints: Dealing with Script Errors
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-03-07 17:41:48 +01:00
|
|
|
Errors inside a timed, executing script can sometimes be rather terse or point to
|
2020-04-07 23:13:24 +02:00
|
|
|
parts of the execution mechanism that is hard to interpret. One way to make it
|
|
|
|
|
easier to debug scripts is to import Evennia's native logger and wrap your
|
|
|
|
|
functions in a try/catch block. Evennia's logger can show you where the
|
|
|
|
|
traceback occurred in your script.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
|
|
from evennia.utils import logger
|
|
|
|
|
|
2021-08-06 20:31:01 +02:00
|
|
|
class Weather(Script):
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
# [...]
|
|
|
|
|
|
|
|
|
|
def at_repeat(self):
|
2021-08-06 20:31:01 +02:00
|
|
|
|
|
|
|
|
try:
|
2021-03-07 17:41:48 +01:00
|
|
|
# [...]
|
2020-04-07 23:13:24 +02:00
|
|
|
except Exception:
|
2021-08-06 20:31:01 +02:00
|
|
|
logger.log_trace()
|