Skip to content

Commit

Permalink
Merge pull request #60 from GsLogiMaker:feature/tag-class
Browse files Browse the repository at this point in the history
Add GFTag class and related tests
  • Loading branch information
GsLogiMaker authored Jan 10, 2025
2 parents a03af4b + 444fb2a commit 7e1a062
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 21 deletions.
3 changes: 1 addition & 2 deletions cpp/src/doc_classes/GFComponent.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?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
3 changes: 2 additions & 1 deletion cpp/src/doc_classes/GFComponentBuilder.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GFComponentBuilder" 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="GFComponentBuilder" 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>
Builder for a new component type.
</brief_description>
Expand Down
31 changes: 15 additions & 16 deletions cpp/src/doc_classes/GFEntity.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?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 @@ -10,6 +9,20 @@
<link title="More on Flecs Entities">https://www.flecs.dev/flecs/md_docs_2EntitiesComponents.html</link>
</tutorials>
<methods>
<method name="add" 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.new()
entity.add(GFPosition2D, Vector2(10, 10))
entity.get(GFPosition2D).get_vec() == Vector2(10, 10) # true
[/codeblock]
This method returns [code]self[/code] for chaining.
</description>
</method>
<method name="add_child">
<return type="GFEntity" />
<param index="0" name="entity" type="Variant" />
Expand All @@ -32,20 +45,6 @@
This codeblock returns [code]self[/code] for chaining.
</description>
</method>
<method name="add" 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.new()
entity.add(GFPosition2D, Vector2(10, 10))
entity.get(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" />
Expand Down
51 changes: 51 additions & 0 deletions cpp/src/doc_classes/GFTag.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GFTag" 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 an entity with no data.
</brief_description>
<description>
Tags are a kind of entity that can be attached to other entities to mark them without adding data, unlike components which will add data when attatched.
</description>
<tutorials>
<link title="More on Flecs Tags">https://www.flecs.dev/flecs/md_docs_2Quickstart.html#tag</link>
</tutorials>
<methods>
<method name="from" qualifiers="static">
<return type="GFTag" />
<param index="0" name="tag" type="Variant" />
<param index="1" name="world" type="GFWorld" default="null" />
<description>
Returns an entity from an ID coerced from a [Variant].
If no world is specified, a default world is used.
To learn more about [Variant] coercion see [method GFWorld.coerce_id].
[codeblock]
var entity:= GFTag.from("flecs/core/Trait")
[/codeblock]
</description>
</method>
<method name="from_id" qualifiers="static">
<return type="GFTag" />
<param index="0" name="tag_id" type="int" />
<param index="1" name="world" type="GFWorld" default="null" />
<description>
Returns an tag from an ID.
If no world is specified, a default world is used.
[codeblock]
var entity:= GFEntity.from_id(255)
[/codeblock]
</description>
</method>
<method name="new_in_world" qualifiers="static">
<return type="GFTag" />
<param index="0" name="world" type="GFWorld" />
<description>
Returns a reference to a new entity created within [param world].
[codeblock]
var world:= GFWorld.new()
var entity:= GFEntity.new_in_world(world)
[/codeblock]
</description>
</method>
</methods>
</class>
9 changes: 9 additions & 0 deletions cpp/src/register_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "entity_builder.h"
#include "gdextension_interface.h"
#include "godot_cpp/classes/engine.hpp"
#include "godot_cpp/core/memory.hpp"
#include "module.h"
#include "observer_builder.h"
#include "pair.h"
Expand All @@ -16,6 +17,7 @@
#include "register_types.h"
#include "registerable_entity.h"
#include "system_builder.h"
#include "tag.h"
#include "world.h"

using namespace godot;
Expand All @@ -34,6 +36,7 @@ void initialize_module(ModuleInitializationLevel p_level) {
godot::ClassDB::register_class<GFRegisterableEntity>();
godot::ClassDB::register_class<GFComponent>();
godot::ClassDB::register_class<GFModule>();
godot::ClassDB::register_class<GFTag>();

godot::ClassDB::register_class<GFEntityBuilder>();
godot::ClassDB::register_class<GFComponentBuilder>();
Expand All @@ -44,6 +47,12 @@ void initialize_module(ModuleInitializationLevel p_level) {
godot::ClassDB::register_class<GFObserverBuilder>();
godot::ClassDB::register_class<GFQueryBuilder>();
godot::ClassDB::register_class<GFSystemBuilder>();

if (Engine::get_singleton()->has_singleton(GFWorld::SINGLETON_NAME)) {
Object* world = Engine::get_singleton()->get_singleton(GFWorld::SINGLETON_NAME);
Engine::get_singleton()->unregister_singleton(GFWorld::SINGLETON_NAME);
memdelete(world);
}
Engine::get_singleton()->register_singleton(GFWorld::SINGLETON_NAME, memnew(GFWorld));
break;
case MODULE_INITIALIZATION_LEVEL_EDITOR:
Expand Down
46 changes: 46 additions & 0 deletions cpp/src/tag.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

#include "tag.h"
#include "utils.h"
#include <stdint.h>
#include <flecs.h>
#include "godot_cpp/classes/wrapped.hpp"
#include "godot_cpp/variant/array.hpp"
#include "world.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>

using namespace godot;

GFTag::~GFTag() {
}

Ref<GFTag> GFTag::new_in_world(GFWorld* world) {
return memnew(GFTag(world));
}

Ref<GFTag> GFTag::from(Variant tag, GFWorld* world) {
ecs_entity_t tag_id = world->coerce_id(tag);
return from_id(tag_id, world);
}

Ref<GFTag> GFTag::from_id(ecs_entity_t tag_id, GFWorld* world_) {
GFWorld* world = GFWorld::world_or_singleton(world_);
Ref<GFTag> ett = memnew(GFTag(
tag_id,
world
));
if (!ett->is_alive()) {
ERR(nullptr,
"Could not instantiate tag from ID\n",
"World/ID is not valid/alive"
);
}
return ett;
}


void GFTag::_bind_methods() {
godot::ClassDB::bind_static_method(get_class_static(), D_METHOD("new_in_world", "world"), &GFTag::new_in_world);
godot::ClassDB::bind_static_method(get_class_static(), D_METHOD("from", "tag", "world"), &GFTag::from, nullptr);
godot::ClassDB::bind_static_method(get_class_static(), D_METHOD("from_id", "tag_id", "world"), &GFTag::from_id, nullptr);
}
63 changes: 63 additions & 0 deletions cpp/src/tag.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

#ifndef GF_TAG_H
#define GF_TAG_H

#include "registerable_entity.h"
#include "world.h"

#include <flecs.h>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/variant/string.hpp>

namespace godot {

class GFTag : public GFRegisterableEntity {
GDCLASS(GFTag, GFRegisterableEntity)

public:
/// Create a new named module
GFTag(GFWorld* world):
GFRegisterableEntity(
ecs_new(
world->raw()
),
world
)
{}
/// Create from existing ID
GFTag(ecs_entity_t id, GFWorld* world):
GFRegisterableEntity(
id,
world
)
{}
GFTag():
GFRegisterableEntity(GFWorld::singleton())
{}

~GFTag();

// --------------------------------------
// --- Exposed
// --------------------------------------

static Ref<GFTag> new_in_world(GFWorld* world);
static Ref<GFTag> new_named_in_world(String name, GFWorld*);
static Ref<GFTag> from(Variant module, GFWorld*);
static Ref<GFTag> from_id(ecs_entity_t, GFWorld*);

// --------------------------------------
// --- Unexposed
// --------------------------------------

protected:
static void _bind_methods();


private:

};

}

#endif
4 changes: 2 additions & 2 deletions unittests/test_entities.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ extends GutTest

var world:GFWorld = null

func before_all():
func before_each():
world = GFWorld.new()

func after_all():
func after_each():
world.free()

#region Tests
Expand Down
29 changes: 29 additions & 0 deletions unittests/test_tags.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

extends GutTest

var world:GFWorld = null

func before_each():
world = GFWorld.new()

func after_each():
world.free()

#region Tests

func _test_tag_creation():
var enemy:= GFTag.new_in_world(world)
var robot:=GFEntity.new_in_world(world) \
.add(enemy)

assert_true(robot.has_entity(enemy), "Expected `robot` to have the `enemy` tag")

#endregion

#region Classes

class Eats extends GFTag: pass

class Grass extends GFTag: pass

#endregion

0 comments on commit 7e1a062

Please sign in to comment.