Start add evennia xyzgrid launch command

This commit is contained in:
Griatch 2021-07-05 00:22:45 +02:00
parent 0e3ce49a5a
commit 2af82b19e1
4 changed files with 266 additions and 7 deletions

View file

@ -0,0 +1,181 @@
"""
Custom Evennia launcher command option for building/rebuilding the grid in a separate process than
the main server (since this can be slow).
To use, add to the settings:
::
EXTRA_LAUNCHER_COMMANDS.update({'xyzgrid': 'evennia.contrib.xyzgrid.launchcmd.xyzcommand'})
You should now be able to do
::
evennia xyzgrid <options>
Use `evennia xyzgrid help` for usage help.
"""
from evennia.contrib.xyzgrid.xyzgrid import get_xyzgrid
_HELP_SHORT = """
evennia xyzgrid help|list|init|add|build|initpath|delete [<options>]
Manages the XYZ grid. Use 'xyzgrid help' for documentation.
"""
_HELP_LONG = """
evennia xyzgrid list
Lists the map grid structure and any loaded maps.
evennia xyzgrid list Z|mapname
Display the given XYmap in more detail. Also 'show' works.
evennia xyzgrid init
First start of the grid. This will create the XYZGrid global script. No maps are loaded yet!
It's safe to run this command multiple times; the grid will only be initialized once.
evennia xyzgrid add path.to.xymap.module
Add one or more XYmaps (each a string-map representing one Z position along with prototypes
etc). The module will be parsed for
- a XYMAP_DATA a dict
{"map": mapstring, "zcoord": mapname/zcoord, "legend": dict, "prototypes": dict}
describing one single XYmap, or
- a XYMAP_LIST - a list of multiple dicts on the XYMAP_DATA form. This allows to load
multiple maps from the same module.
Note that adding a map does *not* build it. If maps are linked to one another, you should add
all linked maps before building, or you'll get errors when spawning the linking exits.
evennia xyzgrid build
Builds/updates the entire database grid based on the added maps. For a new grid, this will spawn
all new rooms/exits (and may take a good while!). For updating, rooms may be removed/spawned if
a map changed since the last build.
evennia xyzgrid build (X,Y,Z|mapname)
Builds/updates only a part of the grid. This should usually only be used if the full grid has
already been built once - otherwise inter-map transitions may fail! Z is the name/z-coordinate
of the map. Use '*' as a wildcard. For example (*, *, mymap) will only update map `mymap` and
(12, 6, mymap) will only update position (12, 6) on the map 'mymap'.
evennia xyzgrid initpath
Recreates the pathfinder matrices for the entire grid. These are used for all shortest-path
calculations. The result will be cached to disk (in mygame/server/.cache/). If not run, each map
will run this automatically first time it's used. Running this will always force to rebuild the
cache.
evennia xyzgrid initpath Z|mapname
recreate the pathfinder matrix for a specific map only. Z is the name/z-coordinate of the map.
evennia xyzgrid delete Z|mapname
Remove a previously added XYmap with the name/z-coordinate Z. E.g. 'remove mymap'. If the map
was built, this will also wipe all its spawned rooms/exits. You will be asked to confirm before
continuing with this operation.
evennia xyzgrid delete
WARNING: This will delete the entire xyz-grid (all maps), and *all* rooms/exits built to match
it (they serve no purpose without the grid). You will be asked to confirm before continuing with
this operation.
"""
def _option_list(**suboptions):
"""
List/view grid.
"""
xyzgrid = get_xyzgrid()
xymap_data = xyzgrid.grid
if not xymap_data:
print("The XYZgrid is currently empty. Use 'add' to add paths to your map data.")
return
if not suboptions:
print("XYMaps stored in grid:")
for zcoord, xymap in sorted(xymap_data.items(), key=lambda tup: tup[0]):
print(str(xymap))
def _option_init(**suboptions):
"""
Initialize a new grid. Will fail if a Grid already exists.
"""
grid = get_xyzgrid()
print(f"The grid is initalized as the Script 'XYZGrid'({grid.dbref})")
def _option_add(**suboptions):
"""
Add a new map to the grid.
"""
def _option_build(**suboptions):
"""
Build the grid or part of it.
"""
def _option_initpath(**suboptions):
"""
Initialize the pathfinding matrices for grid or part of it.
"""
def _option_delete(**suboptions):
"""
Delete the grid or parts of it.
"""
if not suboptions:
repl = input("WARNING: This will delete the ENTIRE Grid and wipe all rooms/exits!"
"\nObjects/Chars inside deleted rooms will be moved to their home locations."
"\nThis can't be undone. Are you sure you want to continue? Y/[N]?")
if repl.lower() not in ('yes', 'y'):
print("Aborted.")
else:
print("Deleting grid ...")
grid = get_xyzgrid()
grid.delete()
else:
pass
def xyzcommand(*args):
"""
Evennia launcher command. This is made available as `evennia xyzgrid` on the command line,
once `settings.EXTRA_LAUNCHER_COMMANDS` is updated.
"""
if not args:
print(_HELP_SHORT.strip())
return
option, *suboptions = args
if option in ('help', 'h'):
print(f"{_HELP_SHORT.strip()}\n{_HELP_LONG.rstrip()}")
if option in ('list', 'show'):
_option_list(*suboptions)
elif option == 'init':
_option_init(*suboptions)
elif option == 'add':
_option_add(*suboptions)
elif option == 'build':
_option_build(*suboptions)
elif option == 'initpath':
_option_initpath(*suboptions)
elif option == 'delete':
_option_delete(*suboptions)

View file

@ -62,3 +62,7 @@ MAP_DATA = {
"legend": LEGEND,
"rooms": ROOMS,
}
XYMAP_LIST = [
MAP_DATA
]

View file

@ -0,0 +1,35 @@
"""
Prototypes for building the XYZ-grid into actual game-rooms.
Add this to mygame/conf/settings/settings.py:
PROTOTYPE_MODULES += ['evennia.contrib.xyzgrid.prototypes']
"""
# Note - the XYZRoom/exit parents track the XYZ coordinates automatically
# so we don't need to add custom tags to them here.
_ROOM_PARENT = {
'prototype_tags': ("xyzroom", ),
'typeclass': 'evennia.contrib.xyzgrid.xyzroom.XYZRoom'
}
_EXIT_PARENT = {
'prototype_tags': ("xyzexit", ),
'typeclass': 'evennia.contrib.xyzgrid.xyzroom.XYZExit'
}
PROTOTYPE_LIST = [
{
'prototype_key': 'xyz_room_prototype',
'prototype_parent': _ROOM_PARENT,
'key': "A non-descript room",
},{
'prototype_key': 'xyz_transition_room_prototype',
'prototype_parent': _ROOM_PARENT,
'typeclass': 'evennia.contrib.xyzgrid.xyzroom.XYZMapTransitionRoom',
},{
'prototype_key': 'xyz_exit_prototype',
'prototype_parent': _EXIT_PARENT,
}
]

View file

@ -16,11 +16,10 @@ The grid has three main functions:
"""
import itertools
from evennia.scripts.scripts import DefaultScript
from evennia.utils import logger
from .xymap import XYMap
from .xyzroom import XYZRoom, XYZExit
from .xyzroom import XYZRoom
class XYZGrid(DefaultScript):
@ -41,8 +40,28 @@ class XYZGrid(DefaultScript):
self.reload()
return self.ndb.grid
def get(self, mapname, default=None):
return self.grid.get(mapname, default)
def get(self, zcoord):
"""
Get a specific xymap.
Args:
zcoord (str): The name/zcoord of the xymap.
Returns:
XYMap: Or None if no map was found.
"""
return self.grid.get(zcoord)
def all(self):
"""
Get all xymaps stored in the grid.
Returns:
dict: All initialized xymaps stored with this grid.
"""
return self.grid
def reload(self):
"""
@ -119,10 +138,11 @@ class XYZGrid(DefaultScript):
def delete(self):
"""
Clear the entire grid, including database entities.
Clear the entire grid, including database entities, then the grid too.
"""
self.remove_map(*(zcoord for zcoord in self.db.map_data), remove_objects=True)
super().delete()
def spawn(self, xyz=('*', '*', '*'), directions=None):
"""
@ -161,5 +181,24 @@ class XYZGrid(DefaultScript):
# next build all links between nodes (including between maps)
for zcoord, xymap in xymaps.items():
logger.log_info(f"[grid] spawning/updating links for {zcoord} ...")
xymap.spawn_links(xy=(x, y), directions=directions)
logger.log_info(f"[grid] spawning/updating links for {zcoord} ...")
xymap.spawn_links(xy=(x, y), directions=directions)
def get_xyzgrid():
"""
Helper for getting the grid. This will create the XYZGrid global script if it didn't
previously exist.
"""
xyzgrid = XYZGrid.objects.all()
if not xyzgrid:
# create a new one
xyzgrid, err = XYZGrid.create("XYZGrid")
if err:
raise RuntimeError(err)
return xyzgrid
elif len(xyzgrid) > 1:
("Warning: More than one XYZGrid instances were found. This is an error and "
"only the first one will be used. Delete the other one(s) manually.")
return xyzgrid[0]