From 4bd9f6ef95f60bbcc6b55e63c7072c4c75d7f5fb Mon Sep 17 00:00:00 2001 From: bitbrain Date: Sat, 30 Nov 2024 18:23:11 +0000 Subject: [PATCH] Ensure entity instances have unique ids, closes #213 --- addons/pandora/api.gd | 4 ++-- addons/pandora/model/entity.gd | 25 +++++++++++++++++-------- pandora/categories.gd | 19 +++++++++++++++---- test/model/entity_test.gd | 17 +++++++++++++++++ 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/addons/pandora/api.gd b/addons/pandora/api.gd index 4081f0c..754c5d7 100644 --- a/addons/pandora/api.gd +++ b/addons/pandora/api.gd @@ -225,12 +225,12 @@ func deserialize(data: Dictionary) -> PandoraEntity: if not _loaded: push_warning("Pandora - cannot deserialize: data not initialized yet.") return null - if not data.has("_instanced_from_id"): + if not data.has("_instance_id"): push_error( "Unable to deserialize data! Not an instance! Call PandoraEntity.instantiate() to create instances." ) return - var entity = Pandora.get_entity(data["_instanced_from_id"]) + var entity = Pandora.get_entity(data["_id"]) if not entity: return var instance = ScriptUtil.create_entity_from_script(entity.get_script_path(), "", "", "", "") diff --git a/addons/pandora/model/entity.gd b/addons/pandora/model/entity.gd index 5d10244..2fbe2a3 100644 --- a/addons/pandora/model/entity.gd +++ b/addons/pandora/model/entity.gd @@ -4,9 +4,14 @@ class_name PandoraEntity extends Resource const ScriptUtil = preload("res://addons/pandora/util/script_util.gd") +const NanoIdGenerator = preload("res://addons/pandora/util/nanoid_generator.gd") const CATEGORY_ICON_PATH = "res://addons/pandora/icons/Folder.svg" const ENTITY_ICON_PATH = "res://addons/pandora/icons/Object.svg" +# we require nano ids for instances as they are non-incremental +# and instances are persisted outside of Pandora. +static var _INSTANCE_ID_GENERATOR = NanoIdGenerator.new() + signal name_changed(new_name: String) signal order_changed(new_index: int) signal icon_changed(new_icon_path: String) @@ -24,7 +29,7 @@ var _icon_path: String var _category_id: String: get(): if is_instance(): - var original = Pandora.get_entity(_instanced_from_id) + var original = Pandora.get_entity(_id) if original: return original._category_id else: @@ -48,7 +53,7 @@ var _ids_generation_class = "" # String -> PandoraPropertyInstance var _instance_properties: Dictionary = {} -var _instanced_from_id: String +var _instance_id: String ## Wrapper around PandoraProperty that is used to manage overrides. @@ -187,12 +192,12 @@ func instantiate() -> PandoraEntity: if entity != null: # ensure to store the id on instances too, so scene saving does not break. entity._id = get_entity_id() - entity._instanced_from_id = get_entity_id() + entity._instance_id = _INSTANCE_ID_GENERATOR.generate() return entity func is_instance() -> bool: - return _instanced_from_id != "" + return _instance_id != "" func get_entity_id() -> String: @@ -634,6 +639,10 @@ func is_category(category_id: String) -> bool: category = Pandora.get_category(parent_id) parent_id = category._category_id return false + + +func get_entity_instance_id() -> String: + return self._instance_id ## Initializes this entity with the given data dictionary. @@ -641,8 +650,8 @@ func is_category(category_id: String) -> bool: func load_data(data: Dictionary) -> void: if data.has("_id"): _id = data["_id"] - if data.has("_instanced_from_id"): - _instanced_from_id = data["_instanced_from_id"] + if data.has("_instance_id"): + _instance_id = data["_instance_id"] _instance_properties = _load_instance_properties(data["_instance_properties"]) else: _name = data["_name"] @@ -673,7 +682,7 @@ func save_data() -> Dictionary: dict["_id"] = _id if is_instance(): - dict["_instanced_from_id"] = _instanced_from_id + dict["_instance_id"] = _instance_id dict["_instance_properties"] = _save_instance_properties() else: dict["_name"] = _name @@ -780,7 +789,7 @@ func _initialize_if_not_loaded() -> void: func _get_instanced_from_entity() -> PandoraEntity: if not is_instance(): return self - return Pandora.get_entity(self._instanced_from_id) + return Pandora.get_entity(self._id) func _get_instanced_from_category() -> PandoraCategory: diff --git a/pandora/categories.gd b/pandora/categories.gd index 0192055..d1c830c 100644 --- a/pandora/categories.gd +++ b/pandora/categories.gd @@ -2,11 +2,22 @@ class_name PandoraCategories -const ROOT = "ZgT7rvfoPX" +const ITEMS = "1" +const RARITY = "16" +const QUESTS = "27" +const DIALOGUES = "28" +const SPELLS = "29" +const MOCK__REQUIRED_FOR_TESTING__ = "54" +const NPCS = "2" -class RootCategories: - const ITEMS = "wUsxss_qiZ" - const NPCS = "uhJOk6M0gs" +class ItemsArmoryCategories: + const SHIELDS = "8" + + +class ItemsCategories: + const ARMORY = "3" + const TOOLS = "4" + const ORES = "13" diff --git a/test/model/entity_test.gd b/test/model/entity_test.gd index 9805d2a..1b16c92 100644 --- a/test/model/entity_test.gd +++ b/test/model/entity_test.gd @@ -21,6 +21,15 @@ func test_instantiate_entity() -> void: var instance = entity.instantiate() assert_that(instance.get_entity_id()).is_equal("123") assert_bool(instance.is_instance()).is_true() + assert_that(instance.get_entity_instance_id()).is_not_equal("123") + + +func test_instantiate_entity_unique_instance_ids() -> void: + var entity = PandoraEntity.new() + entity.init_entity("123", "Test Entity", "res://hello.jpg", "123") + var instance_1 = entity.instantiate() + var instance_2 = entity.instantiate() + assert_that(instance_1.get_entity_instance_id()).is_not_equal(instance_2.get_entity_instance_id()) func test_duplicate_entity() -> void: @@ -29,6 +38,14 @@ func test_duplicate_entity() -> void: var instance = entity.duplicate_instance() assert_that(instance.get_entity_id()).is_equal("123") assert_bool(instance.is_instance()).is_true() + + +func test_duplicate_entity_unique_instance_ids() -> void: + var entity = PandoraEntity.new() + entity.init_entity("123", "Test Entity", "res://hello.jpg", "123") + var instance_1 = entity.duplicate_instance() + var instance_2 = entity.duplicate_instance() + assert_that(instance_1.get_entity_instance_id()).is_not_equal(instance_2.get_entity_instance_id()) func test_entity_set_get_vector2_property() -> void: