Skip to content

Commit f017ea6

Browse files
authored
🐛 fallback to entity instantiation when script is invalid (#87)
1 parent d3d2d9c commit f017ea6

File tree

6 files changed

+77
-7
lines changed

6 files changed

+77
-7
lines changed

addons/pandora/backend/entity_backend.gd

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ func _init(id_generator:PandoraIdGenerator) -> void:
2929

3030
## Creates a new entity on the given PandoraCategory
3131
func create_entity(name:String, category:PandoraCategory) -> PandoraEntity:
32-
var EntityClass = get_entity_class(category.get_script_path())
33-
var entity = EntityClass.new(_id_generator.generate(), name, "", category._id)
32+
var entity = _create_entity_from_script(category.get_script_path(), _id_generator.generate(), name, "", category._id)
3433
_entities[entity._id] = entity
3534
category._children.append(entity)
3635
_propagate_properties(category)
@@ -213,14 +212,12 @@ func _deserialize_entities(data:Array) -> Dictionary:
213212
# only when entity has an overridden class, initialise it.
214213
# otherwise rely on the script path of the parent category.
215214
if entity_data.has("_script_path"):
216-
var ScriptClass = get_entity_class(entity_data["_script_path"])
217-
var entity = ScriptClass.new("", "", "", "")
215+
var entity = _create_entity_from_script(entity_data["_script_path"], "", "", "", "")
218216
entity.load_data(entity_data)
219217
dict[entity._id] = entity
220218
else:
221219
var parent_category = _categories[entity_data["_category_id"]]
222-
var ScriptClass = get_entity_class(parent_category.get_script_path())
223-
var entity = ScriptClass.new("", "", "", "")
220+
var entity = _create_entity_from_script(parent_category.get_script_path(), "", "", "", "")
224221
entity.load_data(entity_data)
225222
dict[entity._id] = entity
226223
return dict
@@ -291,9 +288,35 @@ func _collect_entities_recursive(category:PandoraCategory, list:Array[PandoraEnt
291288
_collect_entities_recursive(child, list)
292289

293290

294-
func get_entity_class(path:String) -> GDScript:
291+
func _get_entity_class(path:String) -> GDScript:
295292
var EntityClass = load(path)
296293
if EntityClass == null or not EntityClass.has_source_code():
297294
push_warning("Unable to find " + path + " - defaulting to PandoraEntity instead.")
298295
EntityClass = PandoraEntityScript
299296
return EntityClass
297+
298+
299+
func _create_entity_from_script(path:String, id:String, name:String, icon_path:String, category_id:String):
300+
var clazz = _get_entity_class(path)
301+
var new_method = _find_first_method_of_script(clazz, "_init")
302+
if not new_method.has("args"):
303+
push_error("ERROR - Pandora is unable to correctly resolve new() method.")
304+
return PandoraEntityScript.new(id, name, icon_path, category_id)
305+
var expected_method = _find_first_method_of_script(PandoraEntityScript, "_init")
306+
if new_method["args"].size() != expected_method["args"].size():
307+
push_warning("_init() method has incorrect signature! Requires " + str(expected_method["args"].size()) + " arguments - defaulting to PandoraEntity instead.")
308+
return PandoraEntityScript.new(id, name, icon_path, category_id)
309+
var entity = clazz.new(id, name, icon_path, category_id)
310+
if not entity is PandoraEntity:
311+
push_warning("Script '" + path + "' must extend PandoraEntity - defaulting to PandoraEntity instead.")
312+
entity = PandoraEntityScript.new(id, name, icon_path, category_id)
313+
return entity
314+
315+
316+
## searches for the first occurence of the method.
317+
## methods can occur multiple times in the order of inheritance.
318+
func _find_first_method_of_script(script:GDScript, method_name:String) -> Dictionary:
319+
for method in script.get_script_method_list():
320+
if method.name == method_name:
321+
return method
322+
return {}

data.pandora

-588 Bytes
Binary file not shown.

test/backend/entity_backend_test.gd

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,3 +485,39 @@ func test_saveload_invalid_entity() -> void:
485485
var loaded_entity = backend.get_entity(entity_id)
486486
assert_that(loaded_entity).is_not_null()
487487
assert_bool(loaded_entity is PandoraEntity).is_true()
488+
489+
490+
func test_saveload_non_entity() -> void:
491+
var backend = create_object_backend() as PandoraEntityBackend
492+
var category = backend.create_category("root")
493+
category.set_script_path("res://test/mock/non-entity.gd")
494+
var entity_id = backend.create_entity("root", category).get_entity_id()
495+
var data = backend.save_data()
496+
backend.load_data(data)
497+
var loaded_entity = backend.get_entity(entity_id)
498+
assert_that(loaded_entity).is_not_null()
499+
assert_bool(loaded_entity is PandoraEntity).is_true()
500+
501+
502+
func test_saveload_wrong_init() -> void:
503+
var backend = create_object_backend() as PandoraEntityBackend
504+
var category = backend.create_category("root")
505+
category.set_script_path("res://test/mock/entity-wrong-init.gd")
506+
var entity_id = backend.create_entity("root", category).get_entity_id()
507+
var data = backend.save_data()
508+
backend.load_data(data)
509+
var loaded_entity = backend.get_entity(entity_id)
510+
assert_that(loaded_entity).is_not_null()
511+
assert_bool(loaded_entity is PandoraEntity).is_true()
512+
513+
514+
func test_saveload_compilation_error_on_script() -> void:
515+
var backend = create_object_backend() as PandoraEntityBackend
516+
var category = backend.create_category("root")
517+
category.set_script_path("res://test/mock/entity-compilation-error.gd")
518+
var entity_id = backend.create_entity("root", category).get_entity_id()
519+
var data = backend.save_data()
520+
backend.load_data(data)
521+
var loaded_entity = backend.get_entity(entity_id)
522+
assert_that(loaded_entity).is_not_null()
523+
assert_bool(loaded_entity is PandoraEntity).is_true()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extends PandoraEntity
2+
3+
4+
func _ready(
5+
pass

test/mock/entity-wrong-init.gd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extends PandoraEntity
2+
3+
4+
func _init():
5+
pass

test/mock/non-entity.gd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extends Resource

0 commit comments

Comments
 (0)