Skip to content

Commit

Permalink
Support varargs in pair functions
Browse files Browse the repository at this point in the history
  • Loading branch information
GsLogiMaker committed Dec 1, 2024
1 parent df2fb92 commit 8d8f027
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 81 deletions.
27 changes: 19 additions & 8 deletions cpp/src/component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ Ref<GFComponent> GFComponent::from(Variant comp, Variant entity, GFWorld* world)
return from_id(world->coerce_id(comp), world->coerce_id(entity), world);
}
Ref<GFComponent> GFComponent::from_id(ecs_entity_t comp, ecs_entity_t entity, GFWorld* world) {
if (!ecs_has_id(world->raw(), comp, ecs_id(EcsComponent))) {
const EcsComponent* comp_ptr = GFComponent::get_component_ptr(world, comp);
if (comp_ptr == nullptr) {
ERR(nullptr,
"Could not instantiate ", get_class_static(), "\n",
"ID is not a component"
" Entity ", world->id_to_text(comp), " is not a component"
);
}
Ref<GFComponent> component = from_id_template<GFComponent>(comp, world);
Expand Down Expand Up @@ -117,15 +118,17 @@ const EcsMember* GFComponent::get_member_data(String member) {
ecs_world_t* raw = get_world()->raw();
const char* c_str = member.utf8().get_data();

ecs_entity_t main_id = get_world()->get_main_id(get_id());

// Get member ID
ecs_entity_t member_id = ecs_lookup_child(raw, get_id(), c_str);
ecs_entity_t member_id = ecs_lookup_child(raw, main_id, c_str);

if (member_id == 0) {
ERR(nullptr,
"No member named \"",
member,
"\" found in component \"",
ecs_get_name(raw, get_id()),
get_world()->id_to_text(get_id()),
"\""
);
}
Expand Down Expand Up @@ -181,7 +184,7 @@ Variant GFComponent::member_value_as_type(
}

ERR(nullptr,
"Can't convert type ", ecs_get_name(raw, type), " to Variant"
"Can't convert type ", get_world()->id_to_text(type), " to Variant"
);
}
case(Variant::Type::BOOL): return Variant( *static_cast<bool*>(ptr) );
Expand Down Expand Up @@ -306,6 +309,14 @@ void GFComponent::build_data_from_variant(
}
}

const EcsComponent* GFComponent::get_component_ptr(GFWorld* world, ecs_entity_t id) {
return ecs_get(world->raw(), world->get_main_id(id), EcsComponent);
}

const EcsStruct* GFComponent::get_struct_ptr(GFWorld* world, ecs_entity_t id) {
return ecs_get(world->raw(), world->get_main_id(id), EcsStruct);
}

void GFComponent::build_data_from_members(
Array members,
void* output,
Expand All @@ -314,11 +325,11 @@ void GFComponent::build_data_from_members(
) {
ecs_world_t* w_raw = world->raw();

const EcsStruct* struct_data = ecs_get(w_raw, component_id, EcsStruct);
const EcsStruct* struct_data = GFComponent::get_struct_ptr(world, component_id);
if (struct_data == nullptr) {
ERR(/**/,
"Could not build data from Variant\n",
"Component is not a struct."
"Could not build data from Array\n",
" Entity ", world->id_to_text(component_id), " is not a struct."
);
}

Expand Down
3 changes: 3 additions & 0 deletions cpp/src/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "entity.h"
#include "godot_cpp/core/gdvirtual.gen.inc"
#include "registerable_entity.h"
#include "world.h"

#include <flecs.h>
#include <godot_cpp/classes/ref_counted.hpp>
Expand Down Expand Up @@ -51,6 +52,8 @@ namespace godot {

void build_data_from_variant(Variant, void* output);
static void build_data_from_members(Array, void*, ecs_entity_t, GFWorld*);
static const EcsComponent* get_component_ptr(GFWorld*, ecs_entity_t);
static const EcsStruct* get_struct_ptr(GFWorld*, ecs_entity_t);
void set_source_id(ecs_entity_t id);

static Ref<GFRegisterableEntity> new_internal();
Expand Down
49 changes: 49 additions & 0 deletions cpp/src/doc_classes/GFEntity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@
This method returns [code]self[/code] for chaining.
</description>
</method>
<method name="add_pair" qualifiers="const vararg">
<return type="GFEntity" />
<param index="0" name="first" type="Variant" />
<param index="1" name="second" type="Variant" />
<description>
Adds component data to the pair of [param first] and [param second] 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()
entity.add_pair(GFPosition2D, Vector2(10, 10))
entity.get_pair(GFPosition2D).get_vec() == Vector2(10, 10) # true
[/codeblock]
This method returns [code]self[/code] for chaining.
</description>
</method>
<method name="from" qualifiers="static">
<return type="GFEntity" />
<param index="0" name="entity" type="Variant" />
Expand Down Expand Up @@ -83,6 +99,21 @@
[/codeblock]
</description>
</method>
<method name="get_pair">
<return type="GFComponent" />
<param index="0" name="first" type="Variant" />
<param index="1" name="second" type="Variant" />
<description>
Returns a reference to this entity's component's data in the pair
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()
entity.add_component("glecs/meta/Array")
entity.get_component("glecs/meta/Array") != null # true
[/codeblock]
</description>
</method>
<method name="get_world">
<return type="GFWorld" />
<description>
Expand Down Expand Up @@ -176,6 +207,24 @@
This method returns [code]self[/code] for chaining.
</description>
</method>
<method name="set_pair" qualifiers="const vararg">
<return type="GFEntity" />
<param index="0" name="first" type="Variant" />
<param index="1" name="second" type="Variant" />
<description>
Sets component data is this entity from the pair of [param first] and
[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()
# 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
[/codeblock]
This method returns [code]self[/code] for chaining.
</description>
</method>
<method name="spawn" qualifiers="static">
<return type="GFEntity" />
<param index="0" name="world" type="GFWorld" default="null" />
Expand Down
84 changes: 82 additions & 2 deletions cpp/src/entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,31 @@ Ref<GFEntity> GFEntity::_add_component(Variant component, Array members) {
return this;
}

Ref<GFEntity> GFEntity::add_pair(Variant first, Variant second, Array members) {
Ref<GFEntity> GFEntity::add_pair(
const Variant** args, GDExtensionInt arg_count, GDExtensionCallError &error
) {
if (arg_count < 2) {
// Too few arguments, return with error.
error.error = GDExtensionCallErrorType::GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
error.argument = arg_count;
error.expected = 2;
return this;
}

// Parse arguments
Array members = Array();
members.resize(arg_count);
for (int i=0; i != arg_count; i++) {
members[i] = *args[i];
}
Variant first = members.pop_front();
Variant sec = members.pop_front();

_add_pair(first, sec, members);

return this;
}
Ref<GFEntity> GFEntity::_add_pair(Variant first, Variant second, Array members) {
GFWorld* w = get_world();

ecs_entity_t first_id = w->coerce_id(first);
Expand Down Expand Up @@ -132,6 +156,12 @@ Ref<GFComponent> GFEntity::get_component(Variant component) {
return c;
}

Ref<GFComponent> GFEntity::get_pair(Variant first, Variant second) {
ecs_entity_t first_id = get_world()->coerce_id(first);
ecs_entity_t second_id = get_world()->coerce_id(second);
return get_component(ecs_pair(first_id, second_id));
}

Ref<GFEntity> GFEntity::set_component(
const Variant** args, GDExtensionInt arg_count, GDExtensionCallError &error
) {
Expand Down Expand Up @@ -204,6 +234,41 @@ Ref<GFEntity> GFEntity::_set_component(
return Ref(this);
}

Ref<GFEntity> GFEntity::set_pair(
const Variant** args, GDExtensionInt arg_count, GDExtensionCallError &error
) {
if (arg_count < 1) {
// Too few arguments, return with error.
error.error = GDExtensionCallErrorType::GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
error.argument = arg_count;
error.expected = 1;
return this;
}

// Parse arguments
Array members = Array();
members.resize(arg_count);
for (int i=0; i != arg_count; i++) {
members[i] = *args[i];
}
Variant first = members.pop_front();
Variant sec = members.pop_front();

return _set_pair(first, sec, members);
}

Ref<GFEntity> GFEntity::_set_pair(
Variant first,
Variant second,
Array members
) {
ecs_entity_t first_id = get_world()->coerce_id(first);
ecs_entity_t second_id = get_world()->coerce_id(second);
_set_component(ecs_pair(first_id, second_id), members);

return Ref(this);
}

void GFEntity::delete_() {
ecs_delete(get_world()->raw(), get_id());
}
Expand Down Expand Up @@ -327,9 +392,24 @@ void GFEntity::_bind_methods() {
godot::ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, StringName("set_component"), &GFEntity::set_component, mi);
}

godot::ClassDB::bind_method(D_METHOD("add_pair", "first", "second", "data"), &GFEntity::add_pair, Array());
{
MethodInfo mi;
mi.arguments.push_back(PropertyInfo(Variant::NIL, "first"));
mi.arguments.push_back(PropertyInfo(Variant::NIL, "second"));
mi.name = "add_pair";
godot::ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, StringName("add_pair"), &GFEntity::add_pair, mi);
}
{
MethodInfo mi;
mi.arguments.push_back(PropertyInfo(Variant::NIL, "first"));
mi.arguments.push_back(PropertyInfo(Variant::NIL, "second"));
mi.name = "set_pair";
godot::ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, StringName("set_pair"), &GFEntity::set_pair, mi);
}

godot::ClassDB::bind_method(D_METHOD("add_tag", "tag"), &GFEntity::add_tag);
godot::ClassDB::bind_method(D_METHOD("get_component", "component"), &GFEntity::get_component);
godot::ClassDB::bind_method(D_METHOD("get_pair", "first", "second"), &GFEntity::get_pair);

godot::ClassDB::bind_method(D_METHOD("delete"), &GFEntity::delete_);

Expand Down
13 changes: 8 additions & 5 deletions cpp/src/entity.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ namespace godot {

Ref<GFEntity> add_component(const Variant**, GDExtensionInt, GDExtensionCallError&);
Ref<GFEntity> _add_component(Variant, Array);
Ref<GFEntity> set_component(const Variant**, GDExtensionInt, GDExtensionCallError&);
Ref<GFEntity> _set_component(Variant, Array);

Ref<GFEntity> add_pair(const Variant**, GDExtensionInt, GDExtensionCallError&);
Ref<GFEntity> _add_pair(Variant, Variant, Array);
Ref<GFEntity> set_pair(const Variant**, GDExtensionInt, GDExtensionCallError&);
Ref<GFEntity> _set_pair(Variant, Variant, Array);

Ref<GFEntity> add_pair(Variant, Variant, Array data);
Ref<GFEntity> add_tag(Variant);

Ref<GFComponent> get_component(Variant);

Ref<GFEntity> set_component(const Variant**, GDExtensionInt, GDExtensionCallError&);
Ref<GFEntity> _set_component(Variant, Array);

Ref<GFComponent> get_pair(Variant, Variant);

void delete_();

Expand Down
69 changes: 42 additions & 27 deletions cpp/src/register_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "entity.h"
#include "gdextension_interface.h"
#include "godot_cpp/classes/engine.hpp"
#include "godot_cpp/classes/resource_loader.hpp"
#include "godot_cpp/variant/utility_functions.hpp"
#include "module.h"
#include "observer_builder.h"
#include "pair.h"
Expand All @@ -20,40 +22,53 @@
using namespace godot;

void initialize_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen editor_help_load_xml_from_utf8_chars_and_len = (GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)internal::gdextension_interface_get_proc_address("editor_help_load_xml_from_utf8_chars_and_len");
editor_help_load_xml_from_utf8_chars_and_len(_doc_data, _doc_data_size);
}
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}

godot::ClassDB::register_class<GFWorld>();
switch (p_level) {
case MODULE_INITIALIZATION_LEVEL_CORE:
case MODULE_INITIALIZATION_LEVEL_SERVERS:
case MODULE_INITIALIZATION_LEVEL_MAX:
break;
case MODULE_INITIALIZATION_LEVEL_SCENE:
godot::ClassDB::register_class<GFWorld>();

godot::ClassDB::register_abstract_class<GFEntity>();
godot::ClassDB::register_abstract_class<GFPair>();
godot::ClassDB::register_class<GFRegisterableEntity>();
godot::ClassDB::register_class<GFComponent>();
godot::ClassDB::register_class<GFModule>();
godot::ClassDB::register_abstract_class<GFEntity>();
godot::ClassDB::register_abstract_class<GFPair>();
godot::ClassDB::register_class<GFRegisterableEntity>();
godot::ClassDB::register_class<GFComponent>();
godot::ClassDB::register_class<GFModule>();

godot::ClassDB::register_abstract_class<GFComponentBuilder>();
godot::ClassDB::register_abstract_class<GFQuery>();
godot::ClassDB::register_abstract_class<GFQueryIterator>();
godot::ClassDB::register_abstract_class<GFComponentBuilder>();
godot::ClassDB::register_abstract_class<GFQuery>();
godot::ClassDB::register_abstract_class<GFQueryIterator>();

godot::ClassDB::register_abstract_class<GFQuerylikeBuilder>();
godot::ClassDB::register_abstract_class<GFObserverBuilder>();
godot::ClassDB::register_abstract_class<GFQueryBuilder>();
godot::ClassDB::register_abstract_class<GFSystemBuilder>();

Engine::get_singleton()->register_singleton(GFWorld::SINGLETON_NAME, memnew(GFWorld));
godot::ClassDB::register_abstract_class<GFQuerylikeBuilder>();
godot::ClassDB::register_abstract_class<GFObserverBuilder>();
godot::ClassDB::register_abstract_class<GFQueryBuilder>();
godot::ClassDB::register_abstract_class<GFSystemBuilder>();
Engine::get_singleton()->register_singleton(GFWorld::SINGLETON_NAME, memnew(GFWorld));
break;
case MODULE_INITIALIZATION_LEVEL_EDITOR:
GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen
editor_help_load_xml_from_utf8_chars_and_len
= (GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)
internal::gdextension_interface_get_proc_address(
"editor_help_load_xml_from_utf8_chars_and_len"
);
editor_help_load_xml_from_utf8_chars_and_len(_doc_data, _doc_data_size);
break;
}
}

void uninitialize_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
switch (p_level) {
case MODULE_INITIALIZATION_LEVEL_CORE:
case MODULE_INITIALIZATION_LEVEL_SERVERS:
case MODULE_INITIALIZATION_LEVEL_EDITOR:
case MODULE_INITIALIZATION_LEVEL_MAX:
break;
case MODULE_INITIALIZATION_LEVEL_SCENE:
Engine::get_singleton()->unregister_singleton(GFWorld::SINGLETON_NAME);
break;
}

Engine::get_singleton()->unregister_singleton(GFWorld::SINGLETON_NAME);
}

extern "C" {
Expand Down
Loading

0 comments on commit 8d8f027

Please sign in to comment.