Skip to content

Commit

Permalink
Merge pull request #33 from GsLogiMaker/fix/allow-adding-components-v…
Browse files Browse the repository at this point in the history
…ia-set-component

Support varargs in get/set component functions
  • Loading branch information
GsLogiMaker authored Dec 4, 2024
2 parents 7bd684a + 393c68f commit 5ee7c7e
Show file tree
Hide file tree
Showing 24 changed files with 643 additions and 176 deletions.
6 changes: 3 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
"program": "${config:godotTools.editorPath.godot4}",
"args": [
"--path",
"../../${workspaceFolder}",
"--headless"
"./",
"--unittest=all"
],
"cwd": "../../${workspaceFolder}"
"cwd": "${workspaceFolder}/../../"
}
]
}
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"label": "godot-extension: Doctool Dump Documentation Files",
"detail": "Dumps GDExtension documentation xml files",
"type": "shell",
"command": "${config:godotTools.editorPath.godot4} --doctool ./cpp/src/ --gdextension-docs --editor --headless --quit",
"command": "cd ../../ && ${config:godotTools.editorPath.godot4} --doctool ./addons/glecs/cpp/src --gdextension-docs --editor --headless --quit",
"problemMatcher": []
}
]
Expand Down
54 changes: 49 additions & 5 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,47 @@ 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,
ecs_entity_t component_id,
GFWorld* world
) {
ecs_world_t* w_raw = world->raw();

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

for (int i=0; i != members.size() && i != ecs_vec_size(&struct_data->members); i++) {
// Iterate the combined sizes of the passed array and the members vector
Variant value = members[i];

ecs_member_t* member_data = /* Get member metadata */ ecs_vec_get_t(
&struct_data->members,
ecs_member_t,
i
);
void* member_ptr = /* Get member pointer */ static_cast<void*>(
static_cast<uint8_t*>(output) + member_data->offset
);
// Set member value
Utils::set_type_from_variant(value, member_data->type, w_raw, member_ptr);
}
}

void GFComponent::set_source_id(ecs_entity_t id) {
source_entity_id = id;
}
Expand Down
4 changes: 4 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 @@ -50,6 +51,9 @@ namespace godot {
void _register_internal();

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
11 changes: 8 additions & 3 deletions cpp/src/component_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,16 @@ Ref<GFComponentBuilder> GFComponentBuilder::set_name(
}

void GFComponentBuilder::build() {
const char* FAILED_TO_BUILD = "Failed to build component\n";
if (built) {
ERR(/**/,
FAILED_TO_BUILD,
"Component builder was already built"
"Failed to build component \"" + name + "\".\n",
" Component is already built."
);
}
if (get_member_count() == 0) {
ERR(/**/,
"Failed to build component \"" + name + "\".\n",
" No members were defined. Specify at least one member."
);
}
built = true;
Expand Down
7 changes: 4 additions & 3 deletions cpp/src/doc_classes/GFComponent.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GFComponent" inherits="GFRegisterableEntity" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd">
<class name="GFComponent" inherits="GFRegisterableEntity"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd">
<brief_description>
A reference to a Glecs component from a [GFWorld] that is attatached to an entity.
</brief_description>
Expand Down Expand Up @@ -55,7 +56,7 @@
<return type="Variant" />
<param index="0" name="member" type="String" />
<description>
Returns the value of a component's member
Returns the value of a component's member.
[codeblock]
var entity = GFEntity.spawn()
entity.add_component("glecs/meta/Vector2")
Expand All @@ -70,7 +71,7 @@
<param index="0" name="member" type="String" />
<param index="1" name="value" type="Variant" />
<description>
Sets the value of a component's member
Sets the value of a component's member.
[codeblock]
var entity = GFEntity.spawn()
entity.add_component("glecs/meta/Vector2")
Expand Down
84 changes: 79 additions & 5 deletions cpp/src/doc_classes/GFEntity.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GFEntity" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd">
<class name="GFEntity" inherits="RefCounted"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd">
<brief_description>
A reference to an entity from a [GFWorld].
</brief_description>
Expand All @@ -9,17 +10,34 @@
<link title="More on Flecs Entities">https://www.flecs.dev/flecs/md_docs_2EntitiesComponents.html</link>
</tutorials>
<methods>
<method name="add_component">
<method name="add_component" qualifiers="const vararg">
<return type="GFEntity" />
<param index="0" name="component" type="Variant" />
<description>
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()
entity.add_component("glecs/meta/Array")
entity.get_component("glecs/meta/Array") != null # true
entity.add_component(GFPosition2D, Vector2(10, 10))
entity.get_component(GFPosition2D).get_vec() == Vector2(10, 10) # true
[/codeblock]
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">
Expand Down Expand Up @@ -81,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 @@ -135,10 +168,32 @@
[codeblock]
var Eats:= GFEntity.spawn()
var Grass:= GFEntity.spawn()
var EatsGrass_id:int = Eats.pair(Grass.get_id())
var EatsGrass_id:int = Eats.pair_id(Grass.get_id())
[/codeblock]
</description>
</method>
<method name="set_component" qualifiers="const vararg">
<return type="GFEntity" />
<param index="0" name="component" type="Variant" />
<description>
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()
entity.add_component(GFPosition2D)
entity.set_component(GFPosition2D, Vector2(10, 10))
entity.get_component(GFPosition2D).get_vec() == Vector2(10, 10) # true
[/codeblock]
If the component is not added yet, then this method will add
it automaticly.
[codeblock]
var entity:= GFEntity.spawn()
entity.set_component(GFPosition2D, Vector2(10, 10))
entity.get_component(GFPosition2D).get_vec() == Vector2(10, 10) # true
[/codeblock]
This method returns [code]self[/code] for chaining.
</description>
</method>
<method name="set_name">
<return type="GFEntity" />
<param index="0" name="name" type="String" />
Expand All @@ -149,6 +204,25 @@
entity.set_name("Entity")
entity.get_name() == "Entity" # true
[/codeblock]
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">
Expand Down
Loading

0 comments on commit 5ee7c7e

Please sign in to comment.