diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b17c7081e..ac5358d75f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Main branch (git) +- Bug fix: Make sure spawned objects get `typeclass_path` pointing to the true + location rather than alias (in line with `create_object`). - Bug fix: Building Menu contrib menu no using Replace over Union mergetype to avoid clashing with in-game commands while building - Feature: RPSystem contrib `sdesc` command can now view/delete your sdesc. diff --git a/evennia/prototypes/spawner.py b/evennia/prototypes/spawner.py index ce2e6e8992..a21077119d 100644 --- a/evennia/prototypes/spawner.py +++ b/evennia/prototypes/spawner.py @@ -137,10 +137,9 @@ import copy import hashlib import time +import evennia from django.conf import settings from django.utils.translation import gettext as _ - -import evennia from evennia.objects.models import ObjectDB from evennia.prototypes import prototypes as protlib from evennia.prototypes.prototypes import ( @@ -151,7 +150,7 @@ from evennia.prototypes.prototypes import ( value_to_obj_or_any, ) from evennia.utils import logger -from evennia.utils.utils import is_iter, make_iter +from evennia.utils.utils import class_from_module, is_iter, make_iter _CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination") _PROTOTYPE_META_NAMES = ( @@ -979,8 +978,13 @@ def spawn(*prototypes, caller=None, **kwargs): val = prot.pop("destination", None) create_kwargs["db_destination"] = init_spawn_value(val, value_to_obj, **init_spawn_kwargs) + # we need the 'true' path to the typeclass (not its alias), so we make sure to load the typeclass + # and use its path directly val = prot.pop("typeclass", settings.BASE_OBJECT_TYPECLASS) - create_kwargs["db_typeclass_path"] = init_spawn_value(val, str, **init_spawn_kwargs) + typeclass = class_from_module( + init_spawn_value(val, str, **init_spawn_kwargs), settings.TYPECLASS_PATHS + ) + create_kwargs["db_typeclass_path"] = f"{typeclass.__module__}.{typeclass.__name__}" # extract calls to handlers val = prot.pop("permissions", []) diff --git a/evennia/prototypes/tests.py b/evennia/prototypes/tests.py index 42e69986be..c7cc8fbbbc 100644 --- a/evennia/prototypes/tests.py +++ b/evennia/prototypes/tests.py @@ -10,12 +10,15 @@ from time import time import mock from anything import Something from django.test.utils import override_settings +from evennia.commands.default import building +from evennia.objects.models import ObjectDB from evennia.prototypes import menus as olc_menus from evennia.prototypes import protfuncs as protofuncs from evennia.prototypes import prototypes as protlib from evennia.prototypes import spawner from evennia.prototypes.prototypes import _PROTOTYPE_TAG_META_CATEGORY -from evennia.utils.test_resources import BaseEvenniaTest +from evennia.utils.create import create_object +from evennia.utils.test_resources import BaseEvenniaTest, EvenniaCommandTest from evennia.utils.tests.test_evmenu import TestEvMenu _PROTPARENTS = { @@ -1047,3 +1050,28 @@ class TestIssue2908(BaseEvenniaTest): obj = spawner.spawn(prot, caller=self.char1) self.assertEqual(obj[0].location, self.room1) + + +class TestIssue3101(EvenniaCommandTest): + """ + Spawning and using create_object should store the same `typeclass_path` if using + the same actual typeclass. + + """ + + def test_spawn_vs_create_paths(self): + self.call( + building.CmdSpawn(), + '{"key": "first thing", "typeclass": "evennia.DefaultObject"}', + "Spawned first thing", + ) + self.call( + building.CmdCreate(), + "second thing:evennia.DefaultObject", + "You create a new DefaultObject: second thing", + ) + + obj1 = ObjectDB.objects.get(db_key="first thing") + obj2 = ObjectDB.objects.get(db_key="second thing") + + self.assertEqual(obj1.typeclass_path, obj2.typeclass_path)