Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure entity instances have unique ids, closes #213 #214

Merged
merged 1 commit into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions addons/pandora/api.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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(), "", "", "", "")
Expand Down
25 changes: 17 additions & 8 deletions addons/pandora/model/entity.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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:
Expand All @@ -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.
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -634,15 +639,19 @@ 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:
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_instance_id() is already reserved for Godot.

return self._instance_id


## Initializes this entity with the given data dictionary.
## Dictionary needs to confirm the structure of this entity.
func load_data(data: Dictionary) -> void:
if data.has("_id"):
_id = data["_id"]
if data.has("_instanced_from_id"):
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change.

_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"]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
19 changes: 15 additions & 4 deletions pandora/categories.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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"


17 changes: 17 additions & 0 deletions test/model/entity_test.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down