From b0b742b53f517caaaed7489801a17a59d865fc9a Mon Sep 17 00:00:00 2001 From: GsLogiMaker Date: Tue, 3 Dec 2024 16:01:57 -0600 Subject: [PATCH 1/3] Tweak entity instantiations to use `new()` instead of `spawn()` --- cpp/src/component.cpp | 45 +++++++++++----- cpp/src/component.h | 11 +++- cpp/src/doc_classes/GFComponent.xml | 11 ++-- cpp/src/doc_classes/GFEntity.xml | 57 ++++++++++---------- cpp/src/doc_classes/GFPair.xml | 6 --- cpp/src/doc_classes/GFRegisterableEntity.xml | 8 +++ cpp/src/doc_classes/GFWorld.xml | 14 ++--- cpp/src/entity.cpp | 25 +++++++-- cpp/src/entity.h | 51 ++++++++++-------- cpp/src/module.cpp | 12 +++-- cpp/src/module.h | 35 ++++++++++-- cpp/src/pair.cpp | 8 --- cpp/src/pair.h | 1 - cpp/src/querylike_builder.cpp | 6 ++- cpp/src/register_types.cpp | 2 +- cpp/src/registerable_entity.cpp | 19 ++++--- cpp/src/registerable_entity.h | 10 ++-- examples/asteroids/asteroids.gd | 9 ++-- unittests/test_components.gd | 15 +++--- unittests/test_ecs_world.gd | 12 ++--- unittests/test_entities.gd | 16 +++--- unittests/test_errors.gd | 4 +- unittests/test_events.gd | 20 +++---- unittests/test_module_rendering_2d.gd | 2 +- unittests/test_prefab.gd | 2 +- unittests/test_queries.gd | 18 +++---- unittests/test_registration.gd | 4 +- unittests/test_relations.gd | 20 +++---- unittests/test_simple_systems.gd | 20 +++---- unittests/test_systems.gd | 6 +-- utils/glecs_tests_runner.gd | 2 - 31 files changed, 272 insertions(+), 199 deletions(-) diff --git a/cpp/src/component.cpp b/cpp/src/component.cpp index c8a1e8f..3528f62 100644 --- a/cpp/src/component.cpp +++ b/cpp/src/component.cpp @@ -3,6 +3,7 @@ #include "component_builder.h" #include "entity.h" #include "godot_cpp/classes/wrapped.hpp" +#include "godot_cpp/core/error_macros.hpp" #include "godot_cpp/variant/array.hpp" #include "godot_cpp/variant/dictionary.hpp" #include "godot_cpp/variant/packed_int64_array.hpp" @@ -24,27 +25,38 @@ GFComponent::GFComponent() { GFComponent::~GFComponent() { } -Ref GFComponent::spawn(GFWorld* world_) { - ERR(NULL, - "Could not instantiate ", get_class_static(), "\n", - "Use ", get_class_static(), ".from or ", - get_class_static(), ".from_id instead." - ); -} Ref GFComponent::from(Variant comp, Variant entity, GFWorld* world) { return from_id(world->coerce_id(comp), world->coerce_id(entity), world); } Ref GFComponent::from_id(ecs_entity_t comp, ecs_entity_t entity, GFWorld* world) { - const EcsComponent* comp_ptr = GFComponent::get_component_ptr(world, comp); - if (comp_ptr == nullptr) { + const EcsComponent* comp_data = GFComponent::get_component_ptr(world, comp); + if (comp_data == nullptr) { ERR(nullptr, "Could not instantiate ", get_class_static(), "\n", " Entity ", world->id_to_text(comp), " is not a component" ); } - Ref component = from_id_template(comp, world); - component->set_source_id(entity); - return component; + Ref comp_ref = Ref(memnew(GFComponent)); + comp_ref->source_entity_id = entity; + comp_ref->set_id(comp); + comp_ref->set_world(world); + return setup_template(comp_ref); +} + +Ref GFComponent::from_id_no_source(ecs_entity_t comp, GFWorld* world) { + const EcsComponent* comp_data = GFComponent::get_component_ptr(world, comp); + if (comp_data == nullptr) { + ERR(nullptr, + "Could not instantiate ", get_class_static(), "\n", + " Entity ", world->id_to_text(comp), " is not a component" + ); + } + Ref comp_ref = Ref(memnew(GFComponent)); + comp_ref->source_entity_id = 0; + comp_ref->set_id(comp); + comp_ref->set_world(world); + comp_ref->update_script(); + return comp_ref; } void GFComponent::_register_internal() { @@ -231,6 +243,13 @@ Variant GFComponent::member_value_as_type( throw "Unreachable"; } +String GFComponent::to_string() { + return String("[#") + + String::num_int64(get_source_id()) + + "--" + String::num_int64(get_id()) + + "]"; +} + Ref GFComponent::get_source_entity() { return GFEntity::from(get_source_id(), get_world()); } @@ -362,7 +381,6 @@ void GFComponent::_bind_methods() { GDVIRTUAL_BIND(_build, "b"); godot::ClassDB::bind_method(D_METHOD("_register_internal"), &GFComponent::_register_internal); - godot::ClassDB::bind_static_method(GFComponent::get_class_static(), D_METHOD("spawn", "world"), &GFComponent::spawn, nullptr); godot::ClassDB::bind_static_method(GFComponent::get_class_static(), D_METHOD("from", "component", "world"), &GFComponent::from, nullptr); godot::ClassDB::bind_static_method(GFComponent::get_class_static(), D_METHOD("from_id", "id", "world"), &GFComponent::from_id, nullptr); @@ -374,6 +392,7 @@ void GFComponent::_bind_methods() { godot::ClassDB::bind_method(D_METHOD("get_data_size"), &GFComponent::get_data_size); godot::ClassDB::bind_method(D_METHOD("get_data_alignment"), &GFComponent::get_data_alignment); godot::ClassDB::bind_method(D_METHOD("is_alive"), &GFComponent::is_alive); + godot::ClassDB::bind_method(D_METHOD("_to_string"), &GFComponent::to_string); godot::ClassDB::bind_static_method(get_class_static(), D_METHOD("_new_internal"), &GFComponent::new_internal); } diff --git a/cpp/src/component.h b/cpp/src/component.h index 4926047..da79f99 100644 --- a/cpp/src/component.h +++ b/cpp/src/component.h @@ -19,9 +19,15 @@ namespace godot { public: GFComponent(); + GFComponent(ecs_entity_t component, GFWorld* world): + GFRegisterableEntity(component, world) { + update_script(); + } GFComponent(ecs_entity_t entity, ecs_entity_t component, GFWorld* world): source_entity_id(entity), - GFRegisterableEntity(component, world) {} + GFRegisterableEntity(component, world) { + update_script(); + } ~GFComponent(); // -------------------------------------- @@ -30,9 +36,9 @@ namespace godot { GDVIRTUAL1(_build, Ref) - static Ref spawn(GFWorld*); static Ref from(Variant c, Variant e, GFWorld*); static Ref from_id(ecs_entity_t c, ecs_entity_t e, GFWorld*); + static Ref from_id_no_source(ecs_entity_t comp, GFWorld* world); Variant getm(String); void setm(String, Variant); @@ -43,6 +49,7 @@ namespace godot { int get_data_alignment(); bool is_alive(); + String to_string(); // -------------------------------------- // --- Unexposed diff --git a/cpp/src/doc_classes/GFComponent.xml b/cpp/src/doc_classes/GFComponent.xml index dd45159..e61f0c1 100644 --- a/cpp/src/doc_classes/GFComponent.xml +++ b/cpp/src/doc_classes/GFComponent.xml @@ -1,6 +1,5 @@ - + A reference to a Glecs component from a [GFWorld] that is attatached to an entity. @@ -30,7 +29,7 @@ Returns a [GFEntity] reference to the entity this component's data is from. [codeblock] var Vector2C = GFEntity.from("glecs/meta/Vector2") - var entity = GFEntity.spawn() + var entity = GFEntity.new() entity.add_component(Vector2C) var vec2 = entity.get_component(Vector2C) @@ -44,7 +43,7 @@ Returns the ID of the entity that this component's data is from. [codeblock] var Vector2C = GFEntity.from("glecs/meta/Vector2") - var entity = GFEntity.spawn() + var entity = GFEntity.new() entity.add_component(Vector2C) var vec2 = entity.get_component(Vector2C) @@ -58,7 +57,7 @@ Returns the value of a component's member. [codeblock] - var entity = GFEntity.spawn() + var entity = GFEntity.new() entity.add_component("glecs/meta/Vector2") var vec2 = entity.get_component("glecs/meta/Vector2") @@ -73,7 +72,7 @@ Sets the value of a component's member. [codeblock] - var entity = GFEntity.spawn() + var entity = GFEntity.new() entity.add_component("glecs/meta/Vector2") var vec2 = entity.get_component("glecs/meta/Vector2") diff --git a/cpp/src/doc_classes/GFEntity.xml b/cpp/src/doc_classes/GFEntity.xml index 358f239..a146cf5 100644 --- a/cpp/src/doc_classes/GFEntity.xml +++ b/cpp/src/doc_classes/GFEntity.xml @@ -1,6 +1,5 @@ - + A reference to an entity from a [GFWorld]. @@ -17,7 +16,7 @@ Adds component data of type [param component] to this entity. The component's type ID is coerced from a [Variant]. To learn more about [Variant] coercion see [method GFWorld.coerce_id]. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.add_component(GFPosition2D, Vector2(10, 10)) entity.get_component(GFPosition2D).get_vec() == Vector2(10, 10) # true [/codeblock] @@ -33,7 +32,7 @@ this entity. The component's type ID is coerced from a [Variant]. To learn more about [Variant] coercion see [method GFWorld.coerce_id]. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.add_pair(GFPosition2D, Vector2(10, 10)) entity.get_pair(GFPosition2D).get_vec() == Vector2(10, 10) # true [/codeblock] @@ -72,7 +71,7 @@ Returns a reference to this entity's component's data of type [param component]. Returns [code]null[/code] if the entity does not have the [param component] attached or if [param component] is not a component. The component is identified by an ID coerced from a [Variant]. To learn more about [Variant] coercion see [method GFWorld.coerce_id]. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.add_component("glecs/meta/Array") entity.get_component("glecs/meta/Array") != null # true [/codeblock] @@ -93,7 +92,7 @@ Returns the name of this entity. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.set_name("Entity") entity.get_name() == "Entity" # true [/codeblock] @@ -108,7 +107,7 @@ of [param first] and [param second]. Returns [code]null[/code] if the entity does not have the [param component] attached or if [param component] is not a component. The component is identified by an ID coerced from a [Variant]. To learn more about [Variant] coercion see [method GFWorld.coerce_id]. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.add_component("glecs/meta/Array") entity.get_component("glecs/meta/Array") != null # true [/codeblock] @@ -120,7 +119,7 @@ Returns the world this entity is from. [codeblock] var world:= GFWorld.new() - var entity:= GFEntity.spawn(world) + var entity:= GFEntity.new_in_world(world) entity.get_world() == world # true [/codeblock] @@ -130,7 +129,7 @@ Returns [code]true[/code] if this entity is still alive. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.is_alive() # true entity.delete() entity.is_alive() # false @@ -148,14 +147,25 @@ [/codeblock] + + + + + Returns a reference to a new entity created within [param world]. + [codeblock] + var world:= GFWorld.new() + var entity:= GFEntity.new_in_world(world) + [/codeblock] + + Creates a [GFPair] from this entity and [param second]. [codeblock] - var Eats:= GFEntity.spawn() - var Grass:= GFEntity.spawn() + var Eats:= GFEntity.new() + var Grass:= GFEntity.new() var EatsGrass:GFPair = Eats.pair(Grass) [/codeblock] @@ -166,8 +176,8 @@ Creates a pair ID from this entity and [param second_id]. [codeblock] - var Eats:= GFEntity.spawn() - var Grass:= GFEntity.spawn() + var Eats:= GFEntity.new() + var Grass:= GFEntity.new() var EatsGrass_id:int = Eats.pair_id(Grass.get_id()) [/codeblock] @@ -179,7 +189,7 @@ Sets component data of type [param component] in this entity. The component's type ID is coerced from a [Variant]. To learn more about [Variant] coercion see [method GFWorld.coerce_id]. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.add_component(GFPosition2D) entity.set_component(GFPosition2D, Vector2(10, 10)) entity.get_component(GFPosition2D).get_vec() == Vector2(10, 10) # true @@ -187,7 +197,7 @@ If the component is not added yet, then this method will add it automaticly. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.set_component(GFPosition2D, Vector2(10, 10)) entity.get_component(GFPosition2D).get_vec() == Vector2(10, 10) # true [/codeblock] @@ -200,7 +210,7 @@ Sets the name of this entity. [codeblock] - var entity:= GFEntity.spawn() + var entity:= GFEntity.new() entity.set_name("Entity") entity.get_name() == "Entity" # true [/codeblock] @@ -216,8 +226,8 @@ [param second]. The component's type ID is coerced from a [Variant]. To learn more about [Variant] coercion see [method GFWorld.coerce_id]. [codeblock] - var start:= GFEntity.spawn().set_name("Start") - var entity:= GFEntity.spawn() + var start:= GFEntity.new().set_name("Start") + var entity:= GFEntity.new() # Pair will be added if it is not already. entity.set_pair(start, GFPosition2D, Vector2(10, 10)) entity.get_pair(start, GFPosition2D).get_vec() == Vector2(10, 10) # true @@ -225,16 +235,5 @@ This method returns [code]self[/code] for chaining. - - - - - Creates a new entity ID and returns it. - If no world is specified, a default world is used. - [codeblock] - var entity:= GFEntity.spawn() - [/codeblock] - - diff --git a/cpp/src/doc_classes/GFPair.xml b/cpp/src/doc_classes/GFPair.xml index b7f1c30..a27f641 100644 --- a/cpp/src/doc_classes/GFPair.xml +++ b/cpp/src/doc_classes/GFPair.xml @@ -92,11 +92,5 @@ [/codeblock] - - - - Do not call, pairs can not be instantiated. Use [method GFPair.from] instead. Overrides [method GFEntity.spawn]. - - diff --git a/cpp/src/doc_classes/GFRegisterableEntity.xml b/cpp/src/doc_classes/GFRegisterableEntity.xml index 046fc72..b048b16 100644 --- a/cpp/src/doc_classes/GFRegisterableEntity.xml +++ b/cpp/src/doc_classes/GFRegisterableEntity.xml @@ -21,5 +21,13 @@ [/codeblock] + + + + + [GFRegisterableEntity] can't be instantiated. + Overrides [method GFEntity.new_in_world] to throw an error + + diff --git a/cpp/src/doc_classes/GFWorld.xml b/cpp/src/doc_classes/GFWorld.xml index 67a93c9..49e7fef 100644 --- a/cpp/src/doc_classes/GFWorld.xml +++ b/cpp/src/doc_classes/GFWorld.xml @@ -33,8 +33,8 @@ This example shows a coercion from a [Vector2i]: [codeblock] var world:= GFWorld.new() - var Eats:= GFEntity.spawn(world) - var Carrots:= GFEntity.spawn(world) + var Eats:= GFEntity.new_in_world(world) + var Carrots:= GFEntity.new_in_world(world) var pair:= Vector2i(Eats.get_id(), Carrots.get_id()) world.coerce_id(pair) == world.pair(Eats, Carrots) # true [/codeblock] @@ -101,8 +101,8 @@ To learn more about [Variant] coercion see [method GFWorld.coerce_id]. [codeblock] var world:= GFWorld.new() - var Attacks_tag:= GFEntity.spawn() - var Players_tag:= GFEntity.spawn() + var Attacks_tag:= GFEntity.new_in_world(world) + var Players_tag:= GFEntity.new_in_world(world) world.pair(Attacks_tag, Players_tag) [/codeblock] @@ -115,8 +115,8 @@ Creates and returns a pair ID from two IDs. [codeblock] var world:= GFWorld.new() - var Attacks_tag:= GFEntity.spawn() - var Player_tag:= GFEntity.spawn() + var Attacks_tag:= GFEntity.new_in_world(world) + var Player_tag:= GFEntity.new_in_world(world) world.pair_ids(Attacks_tag.get_id(), Player_tag.get_id()) [/codeblock] @@ -150,7 +150,7 @@ - + Registers a [Script] that derives from [GFRegisterableEntity]. diff --git a/cpp/src/entity.cpp b/cpp/src/entity.cpp index bb9fb36..add2a57 100644 --- a/cpp/src/entity.cpp +++ b/cpp/src/entity.cpp @@ -1,6 +1,7 @@ #include "entity.h" #include "godot_cpp/classes/script.hpp" +#include "godot_cpp/core/memory.hpp" #include "godot_cpp/variant/array.hpp" #include "utils.h" // needed here because entity.h does not include @@ -13,23 +14,30 @@ #include #include #include "godot_cpp/variant/variant.hpp" +#include "world.h" using namespace godot; GFEntity::GFEntity() { + GFWorld* world = GFWorld::singleton(); + id = ecs_new(world->raw()); + world_instance_id = world->get_instance_id(); +} +GFEntity::GFEntity(GFWorld* world) { + id = ecs_new(world->raw()); + world_instance_id = world->get_instance_id(); } GFEntity::~GFEntity() { } -Ref GFEntity::spawn(GFWorld* world_) { - GFWorld* world = GFWorld::world_or_singleton(world_); - return from_id(ecs_new(world->raw()), world); +Ref GFEntity::new_in_world(GFWorld* world) { + return memnew(GFEntity(world)); } Ref GFEntity::from(Variant entity, GFWorld* world) { return from_id(world->coerce_id(entity), world); } Ref GFEntity::from_id(ecs_entity_t id, GFWorld* world) { - return from_id_template(id, world); + return setup_template(memnew(GFEntity(id, world))); } Ref GFEntity::add_component( @@ -367,6 +375,12 @@ ecs_entity_t GFEntity::pair_id(ecs_entity_t second) { return get_world()->pair_ids(get_id(), second); } +String GFEntity::to_string() { + return String("[#") + + String::num_int64(get_id()) + + "]"; +} + // ---------------------------------------------- // --- Unexposed --- // ---------------------------------------------- @@ -375,7 +389,7 @@ void GFEntity::set_id(ecs_entity_t value) { id = value; } void GFEntity::set_world(GFWorld* value) { world_instance_id = value->get_instance_id(); } void GFEntity::_bind_methods() { - godot::ClassDB::bind_static_method(GFEntity::get_class_static(), D_METHOD("spawn", "world"), &GFEntity::spawn, nullptr); + godot::ClassDB::bind_static_method(GFEntity::get_class_static(), D_METHOD("new_in_world", "world"), &GFEntity::new_in_world); godot::ClassDB::bind_static_method(GFEntity::get_class_static(), D_METHOD("from", "entity", "world"), &GFEntity::from, nullptr); godot::ClassDB::bind_static_method(GFEntity::get_class_static(), D_METHOD("from_id", "id", "world"), &GFEntity::from_id, nullptr); @@ -423,6 +437,7 @@ void GFEntity::_bind_methods() { godot::ClassDB::bind_method(D_METHOD("pair", "second"), &GFEntity::pair); godot::ClassDB::bind_method(D_METHOD("pair_id", "second_id"), &GFEntity::pair_id); + godot::ClassDB::bind_method(D_METHOD("_to_string"), &GFEntity::to_string); godot::ClassDB::bind_method(D_METHOD("set_name", "name"), &GFEntity::set_name); } diff --git a/cpp/src/entity.h b/cpp/src/entity.h index d929ef4..0522fc1 100644 --- a/cpp/src/entity.h +++ b/cpp/src/entity.h @@ -3,6 +3,7 @@ #define GL_ENTITY_H #include "godot_cpp/core/class_db.hpp" +#include "godot_cpp/variant/utility_functions.hpp" #include "godot_cpp/variant/variant.hpp" #include "utils.h" #include "world.h" @@ -22,8 +23,13 @@ namespace godot { GDCLASS(GFEntity, RefCounted) public: + // New entity in global world GFEntity(); + // New entity in specific world + GFEntity(GFWorld* world) ; + // Reference an entity GFEntity(ecs_entity_t id_, GFWorld* world_): id(id_), world_instance_id(world_->get_instance_id()) {} + // Copy an entity reference GFEntity(GFEntity& ett): GFEntity(ett.get_id(), ett.get_world()) {} ~GFEntity(); @@ -31,7 +37,7 @@ namespace godot { // --- Exposed --- // -------------------------------------- - static Ref spawn(GFWorld*); + static Ref new_in_world(GFWorld*); static Ref from(Variant, GFWorld*); static Ref from_id(ecs_entity_t, GFWorld*); @@ -65,36 +71,35 @@ namespace godot { Ref pair(Variant second); ecs_entity_t pair_id(ecs_entity_t second_id); + String to_string(); + // -------------------------------------- // --- Unexposed --- // -------------------------------------- - template - static Ref from_id_template(ecs_entity_t id, GFWorld* world_) { - GFWorld* world = GFWorld::world_or_singleton(world_); - - Ref e; - e = Ref(memnew(T)); - e->set_id(id); - e->set_world(world); - - Ref