Start writing docs

This commit is contained in:
Griatch 2021-07-19 23:40:45 +02:00
parent 0a75577929
commit cf3cbed5d2
2 changed files with 290 additions and 164 deletions

View file

@ -0,0 +1,255 @@
# XYZGrid contribution
This contrib adds a 'coordinate grid' to the game, with rooms that are aware of
their X, Y, Z coordinate. It also adds shortest-path pathfinding, auto-stepping
and map visualization.
The system consists of 2D (XY) maps, where the Z
coordinate is the name of the map. Each map can be linked together.
The grid supports 8 cardinal directions (north, northeast, east etc) as well as
a 'fake' up/down directions (you enter up/down in-game but are actually moving to
a different XY position on the same map).
An (XY) map is defined as a Python string, using a simple syntax;
```
#-#-#-# #
| / d
#-# | #
\ u |\
o---#--------#---+-#-#
| ^ |/
| | #
v |
#-#-#-#-#----#
|x|x|
#-#-#-#
```
(descriptions of components are found below).
Basically the system will parse this string together with a _legend_ (a mapping
describing how each symbol of the map behaves) to generate a representation of
the map that can then be _spawned_ into actual rooms and exits. The map can also
contain links to other maps this (map transitions).
The generation and maintenance of the map topology (how rooms are placed and
relate to each other) are maintained entirely from outside of the game.
## Installation
1. Import and add the `evennia.contrib.commands.XYZGridCmdSet` to the
`CharacterCmdset` cmdset in `mygame/commands.default_cmds.py`. Reload
the server. This makes the `map`, `goto/path` and modified `teleport` and
`open` commands available in-game.
2. Edit `mygame/server/conf/settings.py` and set
EXTRA_LAUNCHER_COMMANDS['xyzgrid'] = 'evennia.contrib.launchcmd.xyzcommand'
3. Run the new `evennia xyzgrid help` for instructions on how to build the grid.
## Example usage
After installation, do the following (from your command line, where the
`evennia` command is available) to install an example grid:
evennia xyzgrid init
evennia xyzgrid add evennia.contrib.xyzgrid.map_example
evennia xyzgrid list
evennia xyzgrid show "the large tree"
evennia xyzgrid show "the small cave"
evennia xyzgrid build
evennia reload
(remember to reload the server after build operations).
Now you can log into the
server and do `teleport (3,0,the large tree)` to teleport into the map.
You can use `open togrid = (3, 0, the large tree)` to open a permanent (one-way)
exit from your current location into the grid. To make a way back to a non-grid
location just stand in a grid room and open a new exit out of it:
`open tolimbo = #2`.
Try `goto view` to go to the top of the tree and `goto dungeon` to go down to
the dungeon entrance at the bottom of the tree.
## A note on 3D = 2D + 1D
Since actual 3D movement usually is impractical to visualize in text, most
action in this contrib takes place on 2-dimenstional XY-planes we refer to as
_Maps_. Changing Z-coordinate means moving to another Map. Maps does not need
be the same size as one another and there is no (enforced) concept of moving
'up' or 'down' between maps - instead you basically 'teleport' between them,
which means you can have your characters end up anywhere you want in the next
map, regardless of which XY coordinate they were leaving from.
If you really want an actual 3D coordinate system, you could make all maps the
same size and name them `0`, `1`, `2` etc. But most users will want to just
treat each map as a location, and name the "Z-coordinate" things like `Dungeon
of Doom`, `The ice queen's palace` or `City of Blackhaven`.
Whereas the included rooms and exits can be used for 'true' 3D movement, the more
advanced tools like pathfinding will only operate within each XY `Map`.
## Components of the XYgrid
1. The Map String - describes the topology of a single
map/location/Z-coordinate.
2. The Map Legend - describes how to parse each symbol in the map string to a
topological relation, such as 'a room' or 'a two-way link east-west'.
3. The XYMap - combines the Map String and Legend into a parsed object with
pathfinding and visual-range handling.
4. The MultiMap - tracks multiple maps
5. Rooms, Exits and Prototypes - custom Typeclasses that understands XYZ coordinates.
The prototype describes how to build a database-entity from a given
Map Legend component.
6. The Grid - the combination of prototype-built rooms/exits with Maps for
pathfinding and visualization. This is kept in-sync with changes to Map
Strings.
### The Map string
A `Map` represents one Z-coordinate/location. The Map starts out as an text
string visually laying out one 2D map (so one Z-position). It is created
manually by the developer/builder outside of the game. The string-map
has one character per node(room) and descibe how rooms link together. Each
symbol is linked to a particular abstract Python class which helps parse
the map-string. While the contrib comes with a large number of nodes and links,
one can also make one's own.
```
MAP = r"""
+ 0 1 2 3
3 #-#---o
v |
2 #-# |
|x| ^
1 #-#-#
/ \
0 # #d#
+ 0 1 2 3
"""
```
Above, only the two `+`-characters in the upper-left and bottom-left are
required to mark the start of grid area - the numbered axes are optional but
recommended for readability! Note that the coordinate system has (0, 0) in the
bottom left - this means that +Y movement is 'upwards' in the string as
expected.
### Map Legend
The map legend is a mapping of one-character symbols to Python classes
representing _Nodes_ (usually equivalent to in-game rooms) or _Links_ (which
usually start as an Exit, but the length of the link only describes the
target-destination and has no in-game representation otherwise). These 'map
components' are Python classes that can be inherited and modified as needed.
The default legend support nearly 20 different symbols, including:
- Nodes (rooms) are always on XY coordinates (not between) and
- 8 two-way cardinal directions (n, ne etc)
- up/down - this is a 'fake' up-down using XY coordinates for ease of
visualization (the exit is just called 'up' or 'down', unless you display the
actual coordinate to the user they'll never know the difference).
- One-way links in 4 cardinal directions (not because it's hard to add more,
but because there are no obvious ASCII characters for the diaginal movements ...)
- Multi-step links are by default considered as one step in-game.
- 'Invisible' symbols that are used to block or act as deterrent for the
pathfinder to use certain routes (like a hidden entrance you should be
auto-pathing through).
- 'Points of interest' are nodes or links where the auto-stepper will always
stop, even if it can see what's behind. This is great for places where you
expect to have a door or a guard (which are not represented on the map).
- Teleporter-links, for jumping from one edge of the map to the other without
having to draw an actual link across. Good for maps that 'wrap around'.
- Transitional links between maps/locations/Z-positions. Note that pathfinding
will _not_ work across map transitions.
### Map
All `Map strings` are combined with their `Map Legends` to be parsed into a `Map`
object. The `Map` object has the relations between all nodes stored in a very
efficient matrix for quick lookup. This allows for:
- Shortest-path finding. The shortest-path from one coordinate to another
is calculated using an optimized implementation of the
[Dijkstra algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm).
While large solutions can be slow (up to 20 seconds for a 10 000 node map
with 8 cardinal links between every room), the solution is cached to disk -
meaning that as long as the map-string does not change, subsequent
path-finding operations are all very fast (<0.1s, usually much faster).
Once retrieving the route, the player can easily be auto-stepped along it.
- Visual-range - useful for displaying the map to the user as they move. The
system can either show everything within a certain grid-distance, or a
certain number of connected nodes away from the character's position.
- Visualize-paths. The system can highlight the path to a target on the grid.
Useful for showing where the pathfinder is moving you.
- The Map parser can be customized so as to give different weight to longer
links - by default a 3-step long link has the same 'weight' for the
pathfinder as two nodes next to each other. This could be combined with
some measure of it taking longer to traverse such exits.
### MultiMap
Multiple `Maps` (or 'Z coordinates') are combined together in the `MultiMap`
handler. The MultiMap knows all maps in the game because it must be possible to
transition from one to the other by giving the name/Z-coordinate to jump to.
It's worth pointing out that neither `Maps`, nor `MultiMap` has any direct
link to the game at this point - these are all just abstract _representations_
of the game world stored in memory.
### Rooms and Exits
The component (_Nodes_ and _Links_ both) of each `Map` can have a `prototype`
dict associated with it. This is the default used when converting this node/link
into something actually visible in-game. It is also possible to override
the default on a per-XY coordinate level.
- For _Nodes_, the `evennia.contrib.xyzgrid.room.XYZRoom` typeclass (or a child
thereof) should be used. This sets up storage of the XYZ-coordinates correctly
(using `Tags`).
- For _Links_, one uses the `evennia.contrib.xyzgrid.room.XYZExit` typeclass
(or a child thereof). This also sets up the proper coordinates, both for the
location they are in and for the exit's destination.
### The Grid
The combination of `MultiMaps` and `prototypes` are used to create the `Grid`, a
series of coordinate-bound rooms/exits actually present in the game world. Each
node of this grid has a unique `(X, Y, Z)` position (no duplicates).
Once the prototypes have been used to create the grid, it must be kept in-sync
with any changes in map-strings `Map` structures - otherwise pathfinding and
visual-range displays will not work (or at least be confusingly inaccurate). So
changes should _only_ be done on the Map-string outside of the game, _not_ by
digging new XYZRooms manually!
The contrib provides a sync mechanism. This compares the stored `Map` with
the current topology and rebuilds/removes any nodes/rooms/links/exits that
has changed. Since this process can be slow, you need to run this manually when
you know you've made a change.
Remember that syncing is only necesssary for topological changes! That is,
changes visible in the map string. Fixing the `desc` of a room or adding a new
enemy does not require any re-sync. Also, things not visible on the
map (like a secret entrance) should not be available to the pathfinder anyway.
You can dig non-XYZRoom objects and link them to `XYZRooms` with no issues -
they will work like normal in-game. But such rooms (and exits leading to/from
them) are _not_ considered part of the grid for the purposes of pathfinding etc.
Exactly how to organize this depends on your game.

View file

@ -13,179 +13,50 @@ This contrib forces each room to exist on a 3-dimensional XYZ grid and also
implements very efficient pathfinding along with tools for displaying
your current visual-range and a lot of related features.
## A note on 3D = 2D + 1D
The rooms of the grid are entirely controlled from outside the game, using
python modules with strings and dicts defining the map(s) of the game. It's
possible to combine grid- with non-grid rooms, and you can decorate
grid rooms as much as you like in-game, but you cannot build new grid
rooms without editing the map files outside of the game.
Since actual 3D movement usually is impractical to visualize in text, most
action in this contrib takes place on 2-dimenstional XY-planes we refer to as
_Maps_. Changing Z-coordinate means moving to another Map. Maps does not need
be the same size as one another and there is no (enforced) concept of moving
'up' or 'down' between maps - instead you basically 'teleport' between them,
which means you can have your characters end up anywhere you want in the next
map, regardless of which XY coordinate they were leaving from.
The full docs are found as
[Contribs/XYZGrid](https://evennia.com/docs/latest/Contributions/XYZGrid.html)
in the docs.
If you really want an actual 3D coordinate system, you could make all maps the
same size and name them `0`, `1`, `2` etc. But most users will want to just
treat each map as a location, and name the "Z-coordinate" things like `Dungeon
of Doom`, `The ice queen's palace` or `City of Blackhaven`.
## Installation
Whereas the included rooms and exits can be used for 'true' 3D movement, the more
advanced tools like pathfinding will only operate within each XY `Map`.
1. Import and add the `evennia.contrib.commands.XYZGridCmdSet` to the
`CharacterCmdset` cmdset in `mygame/commands.default_cmds.py`. Reload
the server. This makes the `map`, `goto/path` and modified `teleport` and
`open` commands available in-game.
2. Edit `mygame/server/conf/settings.py` and set
## Components of the XYgrid
EXTRA_LAUNCHER_COMMANDS['xyzgrid'] = 'evennia.contrib.launchcmd.xyzcommand'
1. The Map String - describes the topology of a single
map/location/Z-coordinate.
2. The Map Legend - describes how to parse each symbol in the map string to a
topological relation, such as 'a room' or 'a two-way link east-west'.
3. The XYMap - combines the Map String and Legend into a parsed object with
pathfinding and visual-range handling.
4. The MultiMap - tracks multiple maps
5. Rooms, Exits and Prototypes - custom Typeclasses that understands XYZ coordinates.
The prototype describes how to build a database-entity from a given
Map Legend component.
6. The Grid - the combination of prototype-built rooms/exits with Maps for
pathfinding and visualization. This is kept in-sync with changes to Map
Strings.
3. Run the new `evennia xyzgrid help` for instructions on how to build the grid.
## Example usage
### The Map string
After installation, do the following (from your command line, where the
`evennia` command is available) to install an example grid:
A `Map` represents one Z-coordinate/location. The Map starts out as an text
string visually laying out one 2D map (so one Z-position). It is created
manually by the developer/builder outside of the game. The string-map
has one character per node(room) and descibe how rooms link together. Each
symbol is linked to a particular abstract Python class which helps parse
the map-string. While the contrib comes with a large number of nodes and links,
one can also make one's own.
evennia xyzgrid init
evennia xyzgrid add evennia.contrib.xyzgrid.map_example
evennia xyzgrid list
evennia xyzgrid show "the large tree"
evennia xyzgrid show "the small cave"
evennia xyzgrid build
evennia reload
```
MAP = r"""
(remember to reload the server after build operations).
+ 0 1 2 3
Now you can log into the
server and do `teleport (3,0,the large tree)` to teleport into the map.
3 #-#---o
v |
2 #-# |
|x| ^
1 #-#-#
/ \
0 # #d#
+ 0 1 2 3
"""
```
Above, only the two `+`-characters in the upper-left and bottom-left are
required to mark the start of grid area - the numbered axes are optional but
recommended for readability! Note that the coordinate system has (0, 0) in the
bottom left - this means that +Y movement is 'upwards' in the string as
expected.
### Map Legend
The map legend is a mapping of one-character symbols to Python classes
representing _Nodes_ (usually equivalent to in-game rooms) or _Links_ (which
usually start as an Exit, but the length of the link only describes the
target-destination and has no in-game representation otherwise). These 'map
components' are Python classes that can be inherited and modified as needed.
The default legend support nearly 20 different symbols, including:
- Nodes (rooms) are always on XY coordinates (not between) and
- 8 two-way cardinal directions (n, ne etc)
- up/down - this is a 'fake' up-down using XY coordinates for ease of
visualization (the exit is just called 'up' or 'down', unless you display the
actual coordinate to the user they'll never know the difference).
- One-way links in 4 cardinal directions (not because it's hard to add more,
but because there are no obvious ASCII characters for the diaginal movements ...)
- Multi-step links are by default considered as one step in-game.
- 'Invisible' symbols that are used to block or act as deterrent for the
pathfinder to use certain routes (like a hidden entrance you should be
auto-pathing through).
- 'Points of interest' are nodes or links where the auto-stepper will always
stop, even if it can see what's behind. This is great for places where you
expect to have a door or a guard (which are not represented on the map).
- Teleporter-links, for jumping from one edge of the map to the other without
having to draw an actual link across. Good for maps that 'wrap around'.
- Transitional links between maps/locations/Z-positions. Note that pathfinding
will _not_ work across map transitions.
### Map
All `Map strings` are combined with their `Map Legends` to be parsed into a `Map`
object. The `Map` object has the relations between all nodes stored in a very
efficient matrix for quick lookup. This allows for:
- Shortest-path finding. The shortest-path from one coordinate to another
is calculated using an optimized implementation of the
[Dijkstra algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm).
While large solutions can be slow (up to 20 seconds for a 10 000 node map
with 8 cardinal links between every room), the solution is cached to disk -
meaning that as long as the map-string does not change, subsequent
path-finding operations are all very fast (<0.1s, usually much faster).
Once retrieving the route, the player can easily be auto-stepped along it.
- Visual-range - useful for displaying the map to the user as they move. The
system can either show everything within a certain grid-distance, or a
certain number of connected nodes away from the character's position.
- Visualize-paths. The system can highlight the path to a target on the grid.
Useful for showing where the pathfinder is moving you.
- The Map parser can be customized so as to give different weight to longer
links - by default a 3-step long link has the same 'weight' for the
pathfinder as two nodes next to each other. This could be combined with
some measure of it taking longer to traverse such exits.
### MultiMap
Multiple `Maps` (or 'Z coordinates') are combined together in the `MultiMap`
handler. The MultiMap knows all maps in the game because it must be possible to
transition from one to the other by giving the name/Z-coordinate to jump to.
It's worth pointing out that neither `Maps`, nor `MultiMap` has any direct
link to the game at this point - these are all just abstract _representations_
of the game world stored in memory.
### Rooms and Exits
The component (_Nodes_ and _Links_ both) of each `Map` can have a `prototype`
dict associated with it. This is the default used when converting this node/link
into something actually visible in-game. It is also possible to override
the default on a per-XY coordinate level.
- For _Nodes_, the `evennia.contrib.xyzgrid.room.XYZRoom` typeclass (or a child
thereof) should be used. This sets up storage of the XYZ-coordinates correctly
(using `Tags`).
- For _Links_, one uses the `evennia.contrib.xyzgrid.room.XYZExit` typeclass
(or a child thereof). This also sets up the proper coordinates, both for the
location they are in and for the exit's destination.
### The Grid
The combination of `MultiMaps` and `prototypes` are used to create the `Grid`, a
series of coordinate-bound rooms/exits actually present in the game world. Each
node of this grid has a unique `(X, Y, Z)` position (no duplicates).
Once the prototypes have been used to create the grid, it must be kept in-sync
with any changes in map-strings `Map` structures - otherwise pathfinding and
visual-range displays will not work (or at least be confusingly inaccurate). So
changes should _only_ be done on the Map-string outside of the game, _not_ by
digging new XYZRooms manually!
The contrib provides a sync mechanism. This compares the stored `Map` with
the current topology and rebuilds/removes any nodes/rooms/links/exits that
has changed. Since this process can be slow, you need to run this manually when
you know you've made a change.
Remember that syncing is only necesssary for topological changes! That is,
changes visible in the map string. Fixing the `desc` of a room or adding a new
enemy does not require any re-sync. Also, things not visible on the
map (like a secret entrance) should not be available to the pathfinder anyway.
You can dig non-XYZRoom objects and link them to `XYZRooms` with no issues -
they will work like normal in-game. But such rooms (and exits leading to/from
them) are _not_ considered part of the grid for the purposes of pathfinding etc.
Exactly how to organize this depends on your game.
You can use `open togrid = (3, 0, the large tree)` to open a permanent (one-way)
exit from your current location into the grid. To make a way back to a non-grid
location just stand in a grid room and open a new exit out of it:
`open tolimbo = #2`.
Try `goto view` to go to the top of the tree and `goto dungeon` to go down to
the dungeon entrance at the bottom of the tree.