Merge pull request #2904 from Henddher/issue_2695
fix: xyzgrid spawn doesn't call at_object_creation
This commit is contained in:
commit
4ba7df7f61
3 changed files with 105 additions and 24 deletions
|
|
@ -53,28 +53,31 @@ Exits: northeast and east
|
||||||
(then go back to your mygame/ folder)
|
(then go back to your mygame/ folder)
|
||||||
|
|
||||||
This will install all optional requirements of Evennia.
|
This will install all optional requirements of Evennia.
|
||||||
2. Import and add the `evennia.contrib.commands.XYZGridCmdSet` to the
|
2. Import and [add] the `evennia.contrib.grid.xyzgrid.commands.XYZGridCmdSet` to the
|
||||||
`CharacterCmdset` cmdset in `mygame/commands.default_cmds.py`. Reload
|
`CharacterCmdset` cmdset in `mygame/commands.default_cmds.py`. Reload
|
||||||
the server. This makes the `map`, `goto/path` and the modified `teleport` and
|
the server. This makes the `map`, `goto/path` and the modified `teleport` and
|
||||||
`open` commands available in-game.
|
`open` commands available in-game.
|
||||||
|
|
||||||
|
[add]: docs/source/Command-Sets.md#defining-command-sets
|
||||||
|
|
||||||
3. Edit `mygame/server/conf/settings.py` and add
|
3. Edit `mygame/server/conf/settings.py` and add
|
||||||
|
|
||||||
EXTRA_LAUNCHER_COMMANDS['xyzgrid'] = 'evennia.contrib.launchcmd.xyzcommand'
|
EXTRA_LAUNCHER_COMMANDS['xyzgrid'] = 'evennia.contrib.grid.xyzgrid.launchcmd.xyzcommand'
|
||||||
|
PROTOTYPE_MODULES += ['evennia.contrib.grid.xyzgrid.prototypes']
|
||||||
and
|
|
||||||
|
|
||||||
PROTOTYPE_MODULES += [’evennia.contrib.grid.xyzgrid.prototypes’]
|
|
||||||
|
|
||||||
This will add the new ability to enter `evennia xyzgrid <option>` on the
|
This will add the new ability to enter `evennia xyzgrid <option>` on the
|
||||||
command line. It will also make the `xyz_room` and `xyz_exit` prototypes
|
command line. It will also make the `xyz_room` and `xyz_exit` prototypes
|
||||||
available for use as prototype-parents when spawning the grid.
|
available for use as prototype-parents when spawning the grid.
|
||||||
|
|
||||||
4. Run `evennia xyzgrid help` for available options.
|
4. Run `evennia xyzgrid help` for available options.
|
||||||
|
|
||||||
5. (Optional): By default, the xyzgrid will only spawn module-based
|
5. (Optional): By default, the xyzgrid will only spawn module-based
|
||||||
[prototypes](../Components/Prototypes.md). This is an optimization and usually makes sense
|
[prototypes]. This is an optimization and usually makes sense
|
||||||
since the grid is entirely defined outside the game anyway. If you want to
|
since the grid is entirely defined outside the game anyway. If you want to
|
||||||
also make use of in-game (db-) created prototypes, add
|
also make use of in-game (db-) created prototypes, add
|
||||||
`XYZGRID_USE_DB_PROTOTYPES = True` to settings.
|
`XYZGRID_USE_DB_PROTOTYPES = True` to settings.
|
||||||
|
|
||||||
|
[prototypes]: ../Components/Prototypes.md
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
Tests for the XYZgrid system.
|
Tests for the XYZgrid system.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from random import randint
|
from random import randint
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
|
|
@ -1415,3 +1416,78 @@ class TestBuildExampleGrid(BaseEvenniaTest):
|
||||||
self.assertTrue(room2a.db.desc.startswith("This is the entrance to"))
|
self.assertTrue(room2a.db.desc.startswith("This is the entrance to"))
|
||||||
self.assertEqual(room2b.key, "North-west corner of the atrium")
|
self.assertEqual(room2b.key, "North-west corner of the atrium")
|
||||||
self.assertTrue(room2b.db.desc.startswith("Sunlight sifts down"))
|
self.assertTrue(room2b.db.desc.startswith("Sunlight sifts down"))
|
||||||
|
|
||||||
|
|
||||||
|
mock_room_callbacks = mock.MagicMock()
|
||||||
|
mock_exit_callbacks = mock.MagicMock()
|
||||||
|
|
||||||
|
class TestXyzRoom(xyzroom.XYZRoom):
|
||||||
|
def at_object_creation(self):
|
||||||
|
mock_room_callbacks.at_object_creation()
|
||||||
|
|
||||||
|
class TestXyzExit(xyzroom.XYZExit):
|
||||||
|
def at_object_creation(self):
|
||||||
|
mock_exit_callbacks.at_object_creation()
|
||||||
|
|
||||||
|
MAP_DATA = {
|
||||||
|
"map": """
|
||||||
|
|
||||||
|
+ 0 1
|
||||||
|
|
||||||
|
0 #-#
|
||||||
|
|
||||||
|
+ 0 1
|
||||||
|
|
||||||
|
""",
|
||||||
|
"zcoord": "map1",
|
||||||
|
"prototypes": {
|
||||||
|
("*", "*"): {
|
||||||
|
"key": "room",
|
||||||
|
"desc": "A room.",
|
||||||
|
"prototype_parent": "xyz_room",
|
||||||
|
},
|
||||||
|
("*", "*", "*"): {
|
||||||
|
"desc": "A passage.",
|
||||||
|
"prototype_parent": "xyz_exit",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"map_visual_range": 1,
|
||||||
|
"map_mode": "scan",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestCallbacks(BaseEvenniaTest):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
mock_room_callbacks.reset_mock()
|
||||||
|
mock_exit_callbacks.reset_mock()
|
||||||
|
|
||||||
|
def setup_grid(self, map_data):
|
||||||
|
self.grid, err = xyzgrid.XYZGrid.create("testgrid")
|
||||||
|
|
||||||
|
def _log(msg):
|
||||||
|
print(msg)
|
||||||
|
self.grid.log = _log
|
||||||
|
|
||||||
|
self.map_data = map_data
|
||||||
|
self.grid.add_maps(map_data)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super().tearDown()
|
||||||
|
self.grid.delete()
|
||||||
|
|
||||||
|
def test_typeclassed_xyzroom_and_xyzexit_with_at_object_creation_are_called(self):
|
||||||
|
map_data = dict(MAP_DATA)
|
||||||
|
for prototype_key, prototype_value in map_data["prototypes"].items():
|
||||||
|
if len(prototype_key) == 2:
|
||||||
|
prototype_value["typeclass"] = "evennia.contrib.grid.xyzgrid.tests.TestXyzRoom"
|
||||||
|
if len(prototype_key) == 3:
|
||||||
|
prototype_value["typeclass"] = "evennia.contrib.grid.xyzgrid.tests.TestXyzExit"
|
||||||
|
self.setup_grid(map_data)
|
||||||
|
|
||||||
|
self.grid.spawn()
|
||||||
|
|
||||||
|
# Two rooms and 2 exits, Each one should have gotten one `at_object_creation` callback.
|
||||||
|
self.assertEqual(mock_room_callbacks.at_object_creation.mock_calls, [mock.call(), mock.call()])
|
||||||
|
self.assertEqual(mock_exit_callbacks.at_object_creation.mock_calls, [mock.call(), mock.call()])
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,9 @@ from collections import defaultdict
|
||||||
|
|
||||||
from django.core import exceptions as django_exceptions
|
from django.core import exceptions as django_exceptions
|
||||||
from evennia.prototypes import spawner
|
from evennia.prototypes import spawner
|
||||||
|
from evennia.utils.utils import class_from_module
|
||||||
|
|
||||||
from .utils import MAPSCAN, REVERSE_DIRECTIONS, MapParserError, BIGVAL
|
from .utils import MAPSCAN, REVERSE_DIRECTIONS, MapParserError, BIGVAL, MapError
|
||||||
|
|
||||||
NodeTypeclass = None
|
NodeTypeclass = None
|
||||||
ExitTypeclass = None
|
ExitTypeclass = None
|
||||||
|
|
@ -316,13 +317,14 @@ class MapNode:
|
||||||
try:
|
try:
|
||||||
nodeobj = NodeTypeclass.objects.get_xyz(xyz=xyz)
|
nodeobj = NodeTypeclass.objects.get_xyz(xyz=xyz)
|
||||||
except django_exceptions.ObjectDoesNotExist:
|
except django_exceptions.ObjectDoesNotExist:
|
||||||
# create a new entity with proper coordinates etc
|
# create a new entity, using the specified typeclass (if there's one) and
|
||||||
tclass = self.prototype["typeclass"]
|
# with proper coordinates etc
|
||||||
tclass = (
|
typeclass = self.prototype.get("typeclass")
|
||||||
f" ({tclass})" if tclass != "evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom" else ""
|
if typeclass is None:
|
||||||
)
|
raise MapError(f"The prototype {self.prototype} for this node has no 'typeclass' key.", self)
|
||||||
self.log(f" spawning room at xyz={xyz}{tclass}")
|
self.log(f" spawning room at xyz={xyz} ({typeclass})")
|
||||||
nodeobj, err = NodeTypeclass.create(self.prototype.get("key", "An empty room"), xyz=xyz)
|
Typeclass = class_from_module(typeclass)
|
||||||
|
nodeobj, err = Typeclass.create(self.prototype.get("key", "An empty room"), xyz=xyz)
|
||||||
if err:
|
if err:
|
||||||
raise RuntimeError(err)
|
raise RuntimeError(err)
|
||||||
else:
|
else:
|
||||||
|
|
@ -400,7 +402,14 @@ class MapNode:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
exitnode = self.links[direction]
|
exitnode = self.links[direction]
|
||||||
exi, err = ExitTypeclass.create(
|
prot = maplinks[key.lower()][3].prototype
|
||||||
|
typeclass = prot.get("typeclass")
|
||||||
|
if typeclass is None:
|
||||||
|
raise MapError(f"The prototype {self.prototype} for this node has no 'typeclass' key.", self)
|
||||||
|
self.log(f" spawning/updating exit xyz={xyz}, direction={key} ({typeclass})")
|
||||||
|
|
||||||
|
Typeclass = class_from_module(typeclass)
|
||||||
|
exi, err = Typeclass.create(
|
||||||
key,
|
key,
|
||||||
xyz=xyz,
|
xyz=xyz,
|
||||||
xyz_destination=exitnode.get_spawn_xyz(),
|
xyz_destination=exitnode.get_spawn_xyz(),
|
||||||
|
|
@ -408,15 +417,8 @@ class MapNode:
|
||||||
)
|
)
|
||||||
if err:
|
if err:
|
||||||
raise RuntimeError(err)
|
raise RuntimeError(err)
|
||||||
|
|
||||||
linkobjs[key.lower()] = exi
|
linkobjs[key.lower()] = exi
|
||||||
prot = maplinks[key.lower()][3].prototype
|
|
||||||
tclass = prot["typeclass"]
|
|
||||||
tclass = (
|
|
||||||
f" ({tclass})"
|
|
||||||
if tclass != "evennia.contrib.grid.xyzgrid.xyzroom.XYZExit"
|
|
||||||
else ""
|
|
||||||
)
|
|
||||||
self.log(f" spawning/updating exit xyz={xyz}, direction={key}{tclass}")
|
|
||||||
|
|
||||||
# apply prototypes to catch any changes
|
# apply prototypes to catch any changes
|
||||||
for key, linkobj in linkobjs.items():
|
for key, linkobj in linkobjs.items():
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue