aob: removed mod stuff
This commit is contained in:
@@ -160,7 +160,6 @@ if(BUILD_TESTING)
|
||||
|
||||
option(BUILD_BENCHMARK "Build benchmark." OFF)
|
||||
option(BUILD_LIB "Build lib example." OFF)
|
||||
option(BUILD_MOD "Build mod example." OFF)
|
||||
option(BUILD_SNAPSHOT "Build snapshot example." OFF)
|
||||
|
||||
enable_testing()
|
||||
|
||||
1
TODO
1
TODO
@@ -17,5 +17,4 @@
|
||||
* observer: user defined filters (eg .replace<T, &function> or .group<T, U, &func>)
|
||||
* any-of rule for views/groups (eg entity has A and any of B/C/D)
|
||||
- get -> all, exclude -> none
|
||||
* remove duktape example (and eventually provide a new one)?
|
||||
* extract only the type within type_info, hash its name (more portable)
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
project(duktape-download NONE)
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
duktape
|
||||
GIT_REPOSITORY https://github.com/svaarala/duktape-releases.git
|
||||
GIT_TAG v2.2.0
|
||||
GIT_SHALLOW 1
|
||||
DOWNLOAD_DIR ${DUKTAPE_DEPS_DIR}
|
||||
TMP_DIR ${DUKTAPE_DEPS_DIR}/tmp
|
||||
STAMP_DIR ${DUKTAPE_DEPS_DIR}/stamp
|
||||
SOURCE_DIR ${DUKTAPE_DEPS_DIR}/src
|
||||
BINARY_DIR ${DUKTAPE_DEPS_DIR}/build
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -15,8 +15,6 @@
|
||||
* [The Registry, the Entity and the Component](#the-registry-the-entity-and-the-component)
|
||||
* [Observe changes](#observe-changes)
|
||||
* [They call me Reactive System](#they-call-me-reactive-system)
|
||||
* [Runtime components](#runtime-components)
|
||||
* [A journey through a plugin](#a-journey-through-a-plugin)
|
||||
* [Sorting: is it possible?](#sorting-is-it-possible)
|
||||
* [Helpers](#helpers)
|
||||
* [Null entity](#null-entity)
|
||||
@@ -30,6 +28,7 @@
|
||||
* [Continuous loader](#continuous-loader)
|
||||
* [Archives](#archives)
|
||||
* [One example to rule them all](#one-example-to-rule-them-all)
|
||||
* [Runtime components](#runtime-components)
|
||||
* [Views and Groups](#views-and-groups)
|
||||
* [Views](#views)
|
||||
* [Runtime views](#runtime-views)
|
||||
@@ -551,54 +550,6 @@ multiple elements in the exclusion list. Moreover, every matcher can have it's
|
||||
own clause and multiple clauses for the same matcher are combined in a single
|
||||
one.
|
||||
|
||||
## Runtime components
|
||||
|
||||
Defining components at runtime is useful to support plugin systems and mods in
|
||||
general. However, it seems impossible with a tool designed around a bunch of
|
||||
templates. Indeed it's not that difficult.<br/>
|
||||
Of course, some features cannot be easily exported into a runtime
|
||||
environment. As an example, sorting a group of components defined at runtime
|
||||
isn't for free if compared to most of the other operations. However, the basic
|
||||
functionalities of an entity-component system such as `EnTT` fit the problem
|
||||
perfectly and can also be used to manage runtime components if required.<br/>
|
||||
All that is necessary to do it is to know the identifiers of the components. An
|
||||
identifier is nothing more than a number or similar that can be used at runtime
|
||||
to work with the type system.
|
||||
|
||||
In `EnTT`, identifiers are easily accessible:
|
||||
|
||||
```cpp
|
||||
entt::registry registry;
|
||||
|
||||
// component identifier
|
||||
auto type = registry.type<position>();
|
||||
```
|
||||
|
||||
Once the identifiers are made available, almost everything becomes pretty
|
||||
simple.
|
||||
|
||||
### A journey through a plugin
|
||||
|
||||
`EnTT` comes with an example (actually a test) that shows how to integrate
|
||||
compile-time and runtime components in a stack based JavaScript environment. It
|
||||
uses [`Duktape`](https://github.com/svaarala/duktape) under the hood, mainly
|
||||
because I wanted to learn how it works at the time I was writing the code.
|
||||
|
||||
The code is not production-ready and overall performance can be highly improved.
|
||||
However, I sacrificed optimizations in favor of a more readable piece of code. I
|
||||
hope I succeeded.<br/>
|
||||
Note also that this isn't neither the only nor (probably) the best way to do it.
|
||||
In fact, the right way depends on the scripting language and the problem one is
|
||||
facing in general.<br/>
|
||||
That being said, feel free to use it at your own risk.
|
||||
|
||||
The basic idea is that of creating a compile-time component aimed to map all the
|
||||
runtime components assigned to an entity.<br/>
|
||||
Identifiers come in use to address the right function from a map when invoked
|
||||
from the runtime environment and to filter entities when iterating.<br/>
|
||||
With a bit of gymnastic, one can narrow views and improve the performance to
|
||||
some extent but it was not the goal of the example.
|
||||
|
||||
## Sorting: is it possible?
|
||||
|
||||
It goes without saying that sorting entities and components is possible with
|
||||
@@ -1035,6 +986,30 @@ the best way to do it. However, feel free to use it at your own risk.
|
||||
The basic idea is to store everything in a group of queues in memory, then bring
|
||||
everything back to the registry with different loaders.
|
||||
|
||||
## Runtime components
|
||||
|
||||
Defining components at runtime is useful to support plugin systems and mods in
|
||||
general. However, it seems impossible with a tool designed around a bunch of
|
||||
templates. Indeed it's not that difficult.<br/>
|
||||
Of course, some features cannot be easily exported into a runtime environment.
|
||||
As an example, sorting a group of components defined at runtime isn't for free
|
||||
if compared to most of the other operations. However, the basic functionalities
|
||||
of an entity-component system such as `EnTT` fit the problem perfectly and can
|
||||
also be used to manage runtime components if required.<br/>
|
||||
All that is necessary to do it is to know the identifiers of the components. An
|
||||
identifier is nothing more than a number or similar that can be used at runtime
|
||||
to work with the type system.
|
||||
|
||||
In `EnTT`, identifiers are easily accessible:
|
||||
|
||||
```cpp
|
||||
// component identifier
|
||||
const auto type = entt::type_info<position>::id();
|
||||
```
|
||||
|
||||
Once the identifiers are made available, almost everything becomes pretty
|
||||
simple.
|
||||
|
||||
# Views and Groups
|
||||
|
||||
First of all, it is worth answering an obvious question: why views and
|
||||
@@ -1192,7 +1167,7 @@ thrown away. The reasons for this go far beyond the scope of this document.<br/>
|
||||
To iterate a runtime view, either use it in a range-for loop:
|
||||
|
||||
```cpp
|
||||
entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
|
||||
entt::component types[] = { entt::type_info<position>::id(), entt::type_info<velocity>::id() };
|
||||
auto view = registry.runtime_view(std::cbegin(types), std::cend(types));
|
||||
|
||||
for(auto entity: view) {
|
||||
@@ -1210,7 +1185,7 @@ for(auto entity: view) {
|
||||
Or rely on the `each` member function to iterate entities:
|
||||
|
||||
```cpp
|
||||
entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
|
||||
entt::component types[] = { entt::type_info<position>::id(), entt::type_info<velocity>::id() };
|
||||
|
||||
registry.runtime_view(std::cbegin(types), std::cend(types)).each([](auto entity) {
|
||||
// ...
|
||||
|
||||
@@ -102,22 +102,6 @@ if(BUILD_LIB)
|
||||
SETUP_PLUGIN_TEST(registry_plugin_std ENTT_STANDARD_CPP)
|
||||
endif()
|
||||
|
||||
# Test mod
|
||||
|
||||
if(BUILD_MOD)
|
||||
enable_language(C)
|
||||
|
||||
set(DUKTAPE_DEPS_DIR ${EnTT_SOURCE_DIR}/deps/duktape)
|
||||
configure_file(${EnTT_SOURCE_DIR}/cmake/in/duktape.in ${DUKTAPE_DEPS_DIR}/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${DUKTAPE_DEPS_DIR})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${DUKTAPE_DEPS_DIR})
|
||||
set(DUKTAPE_SRC_DIR ${DUKTAPE_DEPS_DIR}/src/src)
|
||||
|
||||
set(MOD_TEST_SOURCE ${DUKTAPE_SRC_DIR}/duktape.c mod/mod.cpp)
|
||||
SETUP_BASIC_TEST(mod "${MOD_TEST_SOURCE}")
|
||||
target_include_directories(mod PRIVATE ${DUKTAPE_SRC_DIR})
|
||||
endif()
|
||||
|
||||
# Test snapshot
|
||||
|
||||
if(BUILD_SNAPSHOT)
|
||||
|
||||
409
test/mod/mod.cpp
409
test/mod/mod.cpp
@@ -1,409 +0,0 @@
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <duktape.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
template<typename Type>
|
||||
struct tag { using type = Type; };
|
||||
|
||||
struct position {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
struct renderable {};
|
||||
|
||||
struct duktape_runtime {
|
||||
std::map<duk_uint_t, std::string> components;
|
||||
};
|
||||
|
||||
template<typename Comp>
|
||||
duk_ret_t set(duk_context *ctx, entt::registry ®istry) {
|
||||
const entt::entity entity{duk_require_uint(ctx, 0)};
|
||||
|
||||
if constexpr(std::is_same_v<Comp, position>) {
|
||||
const auto x = duk_require_number(ctx, 2);
|
||||
const auto y = duk_require_number(ctx, 3);
|
||||
registry.assign_or_replace<position>(entity, x, y);
|
||||
} else if constexpr(std::is_same_v<Comp, duktape_runtime>) {
|
||||
const auto type = duk_require_uint(ctx, 1);
|
||||
|
||||
duk_dup(ctx, 2);
|
||||
|
||||
if(!registry.has<duktape_runtime>(entity)) {
|
||||
registry.assign<duktape_runtime>(entity).components[type] = duk_json_encode(ctx, -1);
|
||||
} else {
|
||||
registry.get<duktape_runtime>(entity).components[type] = duk_json_encode(ctx, -1);
|
||||
}
|
||||
|
||||
duk_pop(ctx);
|
||||
} else {
|
||||
registry.assign_or_replace<Comp>(entity);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename Comp>
|
||||
duk_ret_t unset(duk_context *ctx, entt::registry ®istry) {
|
||||
const entt::entity entity{duk_require_uint(ctx, 0)};
|
||||
|
||||
if constexpr(std::is_same_v<Comp, duktape_runtime>) {
|
||||
const auto type = duk_require_uint(ctx, 1);
|
||||
|
||||
auto &components = registry.get<duktape_runtime>(entity).components;
|
||||
assert(components.find(type) != components.cend());
|
||||
components.erase(type);
|
||||
|
||||
if(components.empty()) {
|
||||
registry.remove<duktape_runtime>(entity);
|
||||
}
|
||||
} else {
|
||||
registry.remove<Comp>(entity);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename Comp>
|
||||
duk_ret_t has(duk_context *ctx, entt::registry ®istry) {
|
||||
const entt::entity entity{duk_require_uint(ctx, 0)};
|
||||
|
||||
if constexpr(std::is_same_v<Comp, duktape_runtime>) {
|
||||
duk_push_boolean(ctx, registry.has<duktape_runtime>(entity));
|
||||
|
||||
if(registry.has<duktape_runtime>(entity)) {
|
||||
const auto type = duk_require_uint(ctx, 1);
|
||||
const auto &components = registry.get<duktape_runtime>(entity).components;
|
||||
duk_push_boolean(ctx, components.find(type) != components.cend());
|
||||
} else {
|
||||
duk_push_false(ctx);
|
||||
}
|
||||
} else {
|
||||
duk_push_boolean(ctx, registry.has<Comp>(entity));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename Comp>
|
||||
duk_ret_t get(duk_context *ctx, entt::registry ®istry) {
|
||||
[[maybe_unused]] const entt::entity entity{duk_require_uint(ctx, 0)};
|
||||
|
||||
if constexpr(std::is_same_v<Comp, position>) {
|
||||
const auto &pos = registry.get<position>(entity);
|
||||
|
||||
const auto idx = duk_push_object(ctx);
|
||||
|
||||
duk_push_string(ctx, "x");
|
||||
duk_push_number(ctx, pos.x);
|
||||
duk_def_prop(ctx, idx, DUK_DEFPROP_HAVE_VALUE);
|
||||
|
||||
duk_push_string(ctx, "y");
|
||||
duk_push_number(ctx, pos.y);
|
||||
duk_def_prop(ctx, idx, DUK_DEFPROP_HAVE_VALUE);
|
||||
} if constexpr(std::is_same_v<Comp, duktape_runtime>) {
|
||||
const auto type = duk_require_uint(ctx, 1);
|
||||
|
||||
auto &runtime = registry.get<duktape_runtime>(entity);
|
||||
assert(runtime.components.find(type) != runtime.components.cend());
|
||||
|
||||
duk_push_string(ctx, runtime.components[type].c_str());
|
||||
duk_json_decode(ctx, -1);
|
||||
} else {
|
||||
assert(registry.has<Comp>(entity));
|
||||
duk_push_object(ctx);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
class duktape_registry {
|
||||
struct func_map {
|
||||
using func_type = duk_ret_t(*)(duk_context *, entt::registry &);
|
||||
|
||||
func_type set;
|
||||
func_type unset;
|
||||
func_type has;
|
||||
func_type get;
|
||||
};
|
||||
|
||||
template<typename... Comp>
|
||||
void reg() {
|
||||
((func[entt::type_info<Comp>::id()] = {
|
||||
&::set<Comp>,
|
||||
&::unset<Comp>,
|
||||
&::has<Comp>,
|
||||
&::get<Comp>
|
||||
}), ...);
|
||||
}
|
||||
|
||||
static duktape_registry & instance(duk_context *ctx) {
|
||||
duk_push_this(ctx);
|
||||
|
||||
duk_push_string(ctx, DUK_HIDDEN_SYMBOL("dreg"));
|
||||
duk_get_prop(ctx, -2);
|
||||
auto &dreg = *static_cast<duktape_registry *>(duk_require_pointer(ctx, -1));
|
||||
duk_pop_2(ctx);
|
||||
|
||||
return dreg;
|
||||
}
|
||||
|
||||
template<func_map::func_type func_map::*Op>
|
||||
static duk_ret_t invoke(duk_context *ctx) {
|
||||
auto &dreg = instance(ctx);
|
||||
auto &func = dreg.func;
|
||||
auto ®istry = dreg.registry;
|
||||
auto type = duk_require_uint(ctx, 1);
|
||||
|
||||
const auto it = func.find(type);
|
||||
|
||||
return (it == func.cend())
|
||||
? (func[entt::type_info<duktape_runtime>::id()].*Op)(ctx, registry)
|
||||
: (it->second.*Op)(ctx, registry);
|
||||
}
|
||||
|
||||
public:
|
||||
duktape_registry(entt::registry &ref)
|
||||
: registry{ref}
|
||||
{
|
||||
reg<position, renderable, duktape_runtime>();
|
||||
}
|
||||
|
||||
static duk_ret_t identifier(duk_context *ctx) {
|
||||
static ENTT_ID_TYPE next{1000u};
|
||||
duk_push_uint(ctx, next++);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static duk_ret_t create(duk_context *ctx) {
|
||||
auto &dreg = instance(ctx);
|
||||
const auto entity = dreg.registry.create();
|
||||
duk_push_uint(ctx, static_cast<std::underlying_type_t<entt::entity>>(entity));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static duk_ret_t set(duk_context *ctx) {
|
||||
return invoke<&func_map::set>(ctx);
|
||||
}
|
||||
|
||||
static duk_ret_t unset(duk_context *ctx) {
|
||||
return invoke<&func_map::unset>(ctx);
|
||||
}
|
||||
|
||||
static duk_ret_t has(duk_context *ctx) {
|
||||
return invoke<&func_map::has>(ctx);
|
||||
}
|
||||
|
||||
static duk_ret_t get(duk_context *ctx) {
|
||||
return invoke<&func_map::get>(ctx);
|
||||
}
|
||||
|
||||
static duk_ret_t entities(duk_context *ctx) {
|
||||
const duk_idx_t nargs = duk_get_top(ctx);
|
||||
auto &dreg = instance(ctx);
|
||||
|
||||
duk_push_array(ctx);
|
||||
|
||||
std::vector<ENTT_ID_TYPE> components;
|
||||
std::vector<ENTT_ID_TYPE> runtime;
|
||||
|
||||
for(duk_idx_t arg = 0; arg < nargs; arg++) {
|
||||
auto type = duk_require_uint(ctx, arg);
|
||||
|
||||
if(dreg.func.find(type) == dreg.func.cend()) {
|
||||
if(runtime.empty()) {
|
||||
components.push_back(entt::type_info<duktape_runtime>::id());
|
||||
}
|
||||
|
||||
runtime.push_back(type);
|
||||
} else {
|
||||
components.push_back(type);
|
||||
}
|
||||
}
|
||||
|
||||
auto view = dreg.registry.runtime_view(components.cbegin(), components.cend());
|
||||
duk_uarridx_t pos = 0;
|
||||
|
||||
for(const auto entity: view) {
|
||||
if(runtime.empty()) {
|
||||
duk_push_uint(ctx, static_cast<std::underlying_type_t<entt::entity>>(entity));
|
||||
duk_put_prop_index(ctx, -2, pos++);
|
||||
} else {
|
||||
const auto &others = dreg.registry.get<duktape_runtime>(entity).components;
|
||||
const auto match = std::all_of(runtime.cbegin(), runtime.cend(), [&others](const auto type) {
|
||||
return others.find(type) != others.cend();
|
||||
});
|
||||
|
||||
if(match) {
|
||||
duk_push_uint(ctx, static_cast<std::underlying_type_t<entt::entity>>(entity));
|
||||
duk_put_prop_index(ctx, -2, pos++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<duk_uint_t, func_map> func;
|
||||
entt::registry ®istry;
|
||||
};
|
||||
|
||||
const duk_function_list_entry js_duktape_registry_methods[] = {
|
||||
{ "identifier", &duktape_registry::identifier, 0 },
|
||||
{ "create", &duktape_registry::create, 0 },
|
||||
{ "set", &duktape_registry::set, DUK_VARARGS },
|
||||
{ "unset", &duktape_registry::unset, 2 },
|
||||
{ "has", &duktape_registry::has, 2 },
|
||||
{ "get", &duktape_registry::get, 2 },
|
||||
{ "entities", &duktape_registry::entities, DUK_VARARGS },
|
||||
{ nullptr, nullptr, 0 }
|
||||
};
|
||||
|
||||
void export_types(duk_context *context) {
|
||||
auto export_type = [idx = duk_push_object(context)](auto *ctx, auto type, const auto *name) {
|
||||
duk_push_string(ctx, name);
|
||||
duk_push_uint(ctx, entt::type_info<typename decltype(type)::type>::id());
|
||||
duk_def_prop(ctx, idx, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_CLEAR_WRITABLE);
|
||||
};
|
||||
|
||||
export_type(context, tag<position>{}, "position");
|
||||
export_type(context, tag<renderable>{}, "renderable");
|
||||
|
||||
duk_put_global_string(context, "Types");
|
||||
}
|
||||
|
||||
void export_duktape_registry(duk_context *ctx, duktape_registry &dreg) {
|
||||
auto idx = duk_push_object(ctx);
|
||||
|
||||
duk_push_string(ctx, DUK_HIDDEN_SYMBOL("dreg"));
|
||||
duk_push_pointer(ctx, &dreg);
|
||||
duk_put_prop(ctx, idx);
|
||||
|
||||
duk_put_function_list(ctx, idx, js_duktape_registry_methods);
|
||||
duk_put_global_string(ctx, "Registry");
|
||||
}
|
||||
|
||||
TEST(Mod, Duktape) {
|
||||
entt::registry registry;
|
||||
duktape_registry dreg{registry};
|
||||
duk_context *ctx = duk_create_heap_default();
|
||||
|
||||
if(!ctx) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
export_types(ctx);
|
||||
export_duktape_registry(ctx, dreg);
|
||||
|
||||
const char *s0 = ""
|
||||
"Types[\"PLAYING_CHARACTER\"] = Registry.identifier();"
|
||||
"Types[\"VELOCITY\"] = Registry.identifier();"
|
||||
"";
|
||||
|
||||
if(duk_peval_string(ctx, s0)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.assign<position>(e0, 0., 0.);
|
||||
registry.assign<renderable>(e0);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
registry.assign<position>(e1, 0., 0.);
|
||||
|
||||
const char *s1 = ""
|
||||
"Registry.entities(Types.position, Types.renderable).forEach(function(entity) {"
|
||||
"Registry.set(entity, Types.position, 100., 100.);"
|
||||
"});"
|
||||
"var entity = Registry.create();"
|
||||
"Registry.set(entity, Types.position, 100., 100.);"
|
||||
"Registry.set(entity, Types.renderable);"
|
||||
"";
|
||||
|
||||
if(duk_peval_string(ctx, s1)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
ASSERT_EQ(registry.view<duktape_runtime>().size(), 0u);
|
||||
ASSERT_EQ(registry.view<position>().size(), 3u);
|
||||
ASSERT_EQ(registry.view<renderable>().size(), 2u);
|
||||
|
||||
registry.view<position>().each([®istry](auto entity, const auto &position) {
|
||||
ASSERT_FALSE(registry.has<duktape_runtime>(entity));
|
||||
|
||||
if(registry.has<renderable>(entity)) {
|
||||
ASSERT_EQ(position.x, 100.);
|
||||
ASSERT_EQ(position.y, 100.);
|
||||
} else {
|
||||
ASSERT_EQ(position.x, 0.);
|
||||
ASSERT_EQ(position.y, 0.);
|
||||
}
|
||||
});
|
||||
|
||||
const char *s2 = ""
|
||||
"Registry.entities(Types.position).forEach(function(entity) {"
|
||||
"if(!Registry.has(entity, Types.renderable)) {"
|
||||
"Registry.set(entity, Types.VELOCITY, { \"dx\": -100., \"dy\": -100. });"
|
||||
"Registry.set(entity, Types.PLAYING_CHARACTER, {});"
|
||||
"}"
|
||||
"});"
|
||||
"";
|
||||
|
||||
if(duk_peval_string(ctx, s2)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
ASSERT_EQ(registry.view<duktape_runtime>().size(), 1u);
|
||||
ASSERT_EQ(registry.view<position>().size(), 3u);
|
||||
ASSERT_EQ(registry.view<renderable>().size(), 2u);
|
||||
|
||||
registry.view<duktape_runtime>().each([](const duktape_runtime &runtime) {
|
||||
ASSERT_EQ(runtime.components.size(), 2u);
|
||||
});
|
||||
|
||||
const char *s3 = ""
|
||||
"Registry.entities(Types.position, Types.renderable, Types.VELOCITY, Types.PLAYING_CHARACTER).forEach(function(entity) {"
|
||||
"var velocity = Registry.get(entity, Types.VELOCITY);"
|
||||
"Registry.set(entity, Types.position, velocity.dx, velocity.dy)"
|
||||
"});"
|
||||
"";
|
||||
|
||||
if(duk_peval_string(ctx, s3)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
ASSERT_EQ(registry.view<duktape_runtime>().size(), 1u);
|
||||
ASSERT_EQ(registry.view<position>().size(), 3u);
|
||||
ASSERT_EQ(registry.view<renderable>().size(), 2u);
|
||||
|
||||
registry.view<position, renderable, duktape_runtime>().each([](const position &position, auto &&...) {
|
||||
ASSERT_EQ(position.x, -100.);
|
||||
ASSERT_EQ(position.y, -100.);
|
||||
});
|
||||
|
||||
const char *s4 = ""
|
||||
"Registry.entities(Types.VELOCITY, Types.PLAYING_CHARACTER).forEach(function(entity) {"
|
||||
"Registry.unset(entity, Types.VELOCITY);"
|
||||
"Registry.unset(entity, Types.PLAYING_CHARACTER);"
|
||||
"});"
|
||||
"Registry.entities(Types.position).forEach(function(entity) {"
|
||||
"Registry.unset(entity, Types.position);"
|
||||
"});"
|
||||
"";
|
||||
|
||||
if(duk_peval_string(ctx, s4)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
ASSERT_EQ(registry.view<duktape_runtime>().size(), 0u);
|
||||
ASSERT_EQ(registry.view<position>().size(), 0u);
|
||||
ASSERT_EQ(registry.view<renderable>().size(), 2u);
|
||||
|
||||
duk_destroy_heap(ctx);
|
||||
}
|
||||
Reference in New Issue
Block a user