Streamlined library and reworked the way runtime components work
This commit is contained in:
parent
c794e4a5d2
commit
de5af0a5aa
|
@ -9,8 +9,7 @@
|
||||||
namespace ecs::lua {
|
namespace ecs::lua {
|
||||||
struct Wrapper : Component {
|
struct Wrapper : Component {
|
||||||
// @todo Figure out a more elegant way
|
// @todo Figure out a more elegant way
|
||||||
Wrapper(sol::table _table) : Component(ComponentID::id<Wrapper>), table(_table) {}
|
Wrapper() {}
|
||||||
Wrapper() : Component(ComponentID::id<Wrapper>) {}
|
|
||||||
|
|
||||||
sol::table table;
|
sol::table table;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
#include "ecs.h"
|
#include "ecs.h"
|
||||||
|
|
||||||
|
#ifdef _OPTIONAL_ECS_SERIAL
|
||||||
|
#include "ecs-serial.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
template<>
|
template<>
|
||||||
struct is_container<ecs::View<>> : std::true_type {};
|
struct is_container<ecs::View<>> : std::true_type {};
|
||||||
|
@ -14,36 +18,160 @@ namespace ecs::lua {
|
||||||
preload["ecs"] = [&lua] {
|
preload["ecs"] = [&lua] {
|
||||||
sol::table ecs = lua.create_table();
|
sol::table ecs = lua.create_table();
|
||||||
|
|
||||||
|
ecs.set_function("register", [&lua] (std::string name, sol::table table) {
|
||||||
|
size_t id = ComponentID::regist(name);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, sol::type> map;
|
||||||
|
|
||||||
|
for (auto [skey, stype] : table) {
|
||||||
|
std::string key = skey.as<std::string>();
|
||||||
|
std::string type = stype.as<std::string>();
|
||||||
|
|
||||||
|
if (!type.compare("string")) {
|
||||||
|
map.insert({key, sol::type::string});
|
||||||
|
} else if (!type.compare("number")) {
|
||||||
|
map.insert({key, sol::type::number});
|
||||||
|
} else if (!type.compare("boolean")) {
|
||||||
|
map.insert({key, sol::type::boolean});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _OPTIONAL_ECS_SERIAL
|
||||||
|
auto serialize = [map, name] (std::ostream& os, ecs::Component* component) {
|
||||||
|
std::cout << "SERIALIZE: " << name << '\n';
|
||||||
|
Wrapper* wrapper = (Wrapper*)component;
|
||||||
|
|
||||||
|
// Write each of the entries
|
||||||
|
io::write<size_t>(os, map.size());
|
||||||
|
for (auto [key, type] : map) {
|
||||||
|
io::write<std::string>(os, key);
|
||||||
|
switch (type) {
|
||||||
|
case sol::type::string:
|
||||||
|
io::write<std::string>(os, wrapper->table.get<std::string>(key));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sol::type::number:
|
||||||
|
io::write<float>(os, wrapper->table.get<float>(key));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sol::type::boolean:
|
||||||
|
io::write<bool>(os, wrapper->table.get<bool>(key));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto deserialize = [map] (std::istream& is, Component* component) {
|
||||||
|
std::cout << "DESERIALIZE\n";
|
||||||
|
|
||||||
|
Wrapper* wrapper = (Wrapper*)component;
|
||||||
|
|
||||||
|
// Write each of the entries
|
||||||
|
size_t size = io::read<size_t>(is);
|
||||||
|
for (size_t i = 0; i < size; ++i) {
|
||||||
|
std::string key = io::read<std::string>(is);
|
||||||
|
const auto it = map.find(key);
|
||||||
|
sol::type type = it->second;
|
||||||
|
|
||||||
|
std::cout << key << '\n';
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case sol::type::string:
|
||||||
|
std::cout << "STRING\n";
|
||||||
|
wrapper->table[key] = io::read<std::string>(is);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sol::type::number:
|
||||||
|
std::cout << "NUMBER\n";
|
||||||
|
wrapper->table[key] = io::read<float>(is);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sol::type::boolean:
|
||||||
|
std::cout << "BOOL\n";
|
||||||
|
wrapper->table[key] = io::read<bool>(is);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto create = [&lua, map] {
|
||||||
|
std::cout << "CREATE\n";
|
||||||
|
Wrapper* wrapper = new Wrapper();
|
||||||
|
wrapper->table = lua.create_table();
|
||||||
|
|
||||||
|
for (auto [key, type] : map) {
|
||||||
|
switch (type) {
|
||||||
|
case sol::type::string:
|
||||||
|
wrapper->table[key] = "";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sol::type::number:
|
||||||
|
wrapper->table[key] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sol::type::boolean:
|
||||||
|
wrapper->table[key] = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
};
|
||||||
|
|
||||||
|
ecs::serial::register_component_custom(id, serialize, deserialize, create);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lua.set_function("_internal_to_" + name, [] (ecs::Component* component) {
|
||||||
|
return (Wrapper*)component;
|
||||||
|
});
|
||||||
|
|
||||||
|
sol::table component = lua.create_table();
|
||||||
|
|
||||||
|
component.set_function("new", sol::factories([&lua, id, map] (sol::table table) {
|
||||||
|
Wrapper* wrapper = new Wrapper();
|
||||||
|
wrapper->table = lua.create_table();
|
||||||
|
|
||||||
|
for (auto [key, type] : map) {
|
||||||
|
wrapper->table[key] = table[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(id, wrapper);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return component;
|
||||||
|
});
|
||||||
|
|
||||||
ecs.new_usertype<Entity>("Entity",
|
ecs.new_usertype<Entity>("Entity",
|
||||||
"__tostring", [] (Entity* thiz) {
|
"__tostring", [] (Entity* thiz) {
|
||||||
return uuids::to_string(thiz->uuid);
|
return uuids::to_string(thiz->uuid);
|
||||||
},
|
},
|
||||||
"add_component", [] (Entity* thiz, Component* component, std::string name) {
|
"add_component", [] (Entity* thiz, size_t id, Component* component) {
|
||||||
return thiz->add_component(ComponentID::get_id({name})[0], component);
|
return thiz->add_component(id, component);
|
||||||
},
|
},
|
||||||
"has_components", [] (Entity* thiz, sol::variadic_args args) {
|
"has_components", [] (Entity* thiz, sol::variadic_args args) {
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
for (std::string name : args) {
|
for (std::string name : args) {
|
||||||
names.push_back(name);
|
names.push_back(name);
|
||||||
}
|
}
|
||||||
return thiz->has_components(ComponentID::get_id(names));
|
return thiz->has_components(ComponentID::resolve(names));
|
||||||
},
|
},
|
||||||
"get_component", [&lua] (Entity* thiz, std::string name) -> sol::object {
|
"get_component", [&lua] (Entity* thiz, std::string name) -> sol::object {
|
||||||
// Convert to the correct component type
|
// Convert to the correct component type
|
||||||
Component* component = thiz->get_component(ComponentID::get_id({name})[0]);
|
Component* component = thiz->get_component(ComponentID::resolve(name));
|
||||||
if (!component->_runtime) {
|
|
||||||
// @todo Figure out a more elegant way to convert
|
// @todo Figure out a more elegant way to convert
|
||||||
auto f1 = lua["_internal_to_" + name];
|
auto f1 = lua["_internal_to_" + name];
|
||||||
if (f1.valid()) {
|
if (f1.valid()) {
|
||||||
return f1(component);
|
return f1(component);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// @todo This call is not very fast...
|
|
||||||
auto f1 = lua["_internal_to_" + ComponentID::get_name(component->_id)];
|
|
||||||
if (f1.valid()) {
|
|
||||||
return f1(component);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw std::runtime_error("Unknown component");
|
throw std::runtime_error("Unknown component");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -71,7 +199,7 @@ namespace ecs::lua {
|
||||||
for (std::string name : args) {
|
for (std::string name : args) {
|
||||||
names.push_back(name);
|
names.push_back(name);
|
||||||
}
|
}
|
||||||
return thiz->view(ComponentID::get_id(names));
|
return thiz->view(ComponentID::resolve(names));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -79,8 +207,7 @@ namespace ecs::lua {
|
||||||
};
|
};
|
||||||
|
|
||||||
preload["ecs.Wrapper"] = [&lua] {
|
preload["ecs.Wrapper"] = [&lua] {
|
||||||
sol::table component = lua.create_table();
|
lua.new_usertype<Wrapper>("Wrapper",
|
||||||
component.new_usertype<Wrapper>("Wrapper",
|
|
||||||
"__index", [] (Wrapper* thiz, std::string key) {
|
"__index", [] (Wrapper* thiz, std::string key) {
|
||||||
return thiz->table[key];
|
return thiz->table[key];
|
||||||
},
|
},
|
||||||
|
@ -89,16 +216,6 @@ namespace ecs::lua {
|
||||||
},
|
},
|
||||||
sol::base_classes, sol::bases<ecs::Component>()
|
sol::base_classes, sol::bases<ecs::Component>()
|
||||||
);
|
);
|
||||||
|
|
||||||
component.set_function("new", sol::factories([](std::string _name, sol::table _table) {
|
|
||||||
return std::make_pair(new Wrapper(_table), _name);
|
|
||||||
}));
|
|
||||||
|
|
||||||
lua.set_function("_internal_to_Wrapper", [] (ecs::Component* component) {
|
|
||||||
return (Wrapper*)component;
|
|
||||||
});
|
|
||||||
|
|
||||||
return component;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,32 +41,25 @@ namespace ecs::serial {
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
void register_component(Args... args) {
|
void register_component(Args... args) {
|
||||||
// Serialize component
|
// Serialize component
|
||||||
auto func1 = [args...] (std::ostream& os, ecs::Component* component) {
|
auto serialize = [args...] (std::ostream& os, ecs::Component* component) {
|
||||||
T* t = (T*)component;
|
T* t = (T*)component;
|
||||||
serialize_member(os, t, args...);
|
serialize_member(os, t, args...);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Deserialize component
|
// Deserialize component
|
||||||
auto func2 = [args...] (std::istream& is, ecs::Component* component) {
|
auto deserialize = [args...] (std::istream& is, ecs::Component* component) {
|
||||||
T* t = (T*)component;
|
T* t = (T*)component;
|
||||||
deserialize_member(is, t, args...);
|
deserialize_member(is, t, args...);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto func3 = [] () -> Component* {
|
auto create = [] () -> Component* {
|
||||||
return new T();
|
return new T();
|
||||||
};
|
};
|
||||||
|
|
||||||
internal::functions.insert({ComponentID::id<T>, {func1, func2, func3}});
|
internal::functions.insert({ComponentID::id<T>, {serialize, deserialize, create}});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
void register_component_custom(size_t id, std::function<void(std::ostream&, ecs::Component*)> serialize, std::function<void(std::istream&, Component*)> deserialize, std::function<ecs::Component*()> create);
|
||||||
void register_component_custom(std::function<void(std::ostream&, ecs::Component*)> func1, std::function<void(std::istream&, Component*)> func2) {
|
|
||||||
auto func3 = [] () -> Component* {
|
|
||||||
return new T();
|
|
||||||
};
|
|
||||||
|
|
||||||
internal::functions.insert({ComponentID::id<T>, {func1, func2, func3}});
|
|
||||||
}
|
|
||||||
|
|
||||||
void serialize(std::ostream& os, Entity* entity);
|
void serialize(std::ostream& os, Entity* entity);
|
||||||
void deserialize(std::istream& is, Manager& manager);
|
void deserialize(std::istream& is, Manager& manager);
|
||||||
|
|
|
@ -12,6 +12,10 @@ namespace ecs::serial {
|
||||||
|
|
||||||
std::unordered_map<size_t, size_t> conversion;
|
std::unordered_map<size_t, size_t> conversion;
|
||||||
|
|
||||||
|
void register_component_custom(size_t id, std::function<void(std::ostream&, ecs::Component*)> serialize, std::function<void(std::istream&, Component*)> deserialize, std::function<ecs::Component*()> create) {
|
||||||
|
internal::functions.insert({id, {serialize, deserialize, create}});
|
||||||
|
}
|
||||||
|
|
||||||
void serialize(std::ostream& os, Entity* entity) {
|
void serialize(std::ostream& os, Entity* entity) {
|
||||||
auto uuid_data = reinterpret_cast<const uint8_t*>(entity->uuid.as_bytes().data());
|
auto uuid_data = reinterpret_cast<const uint8_t*>(entity->uuid.as_bytes().data());
|
||||||
io::write<std::vector<uint8_t>>(os, std::vector<uint8_t>(uuid_data, uuid_data + 16), false);
|
io::write<std::vector<uint8_t>>(os, std::vector<uint8_t>(uuid_data, uuid_data + 16), false);
|
||||||
|
@ -19,28 +23,13 @@ namespace ecs::serial {
|
||||||
auto components = entity->get_components();
|
auto components = entity->get_components();
|
||||||
io::write<size_t>(os, components.size());
|
io::write<size_t>(os, components.size());
|
||||||
for (auto [id, component] : components) {
|
for (auto [id, component] : components) {
|
||||||
if (!component->_runtime) {
|
|
||||||
auto functions = internal::functions.find(id);
|
auto functions = internal::functions.find(id);
|
||||||
if (functions == internal::functions.end()) {
|
if (functions == internal::functions.end()) {
|
||||||
throw std::runtime_error("No known serializer for id");
|
throw std::runtime_error("No known serializer for id");
|
||||||
}
|
}
|
||||||
|
|
||||||
io::write<size_t>(os, id);
|
io::write<size_t>(os, id);
|
||||||
io::write<bool>(os, false);
|
|
||||||
std::get<0>(internal::functions[id])(os, component);
|
std::get<0>(internal::functions[id])(os, component);
|
||||||
} else {
|
|
||||||
auto new_id = component->_id;
|
|
||||||
auto functions = internal::functions.find(new_id);
|
|
||||||
|
|
||||||
if (functions == internal::functions.end()) {
|
|
||||||
throw std::runtime_error("No known serializer for id");
|
|
||||||
}
|
|
||||||
|
|
||||||
io::write<size_t>(os, new_id);
|
|
||||||
io::write<bool>(os, true);
|
|
||||||
io::write<size_t>(os, id);
|
|
||||||
std::get<0>(internal::functions[new_id])(os, component);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,12 +49,7 @@ namespace ecs::serial {
|
||||||
size_t component_count = io::read<size_t>(is);
|
size_t component_count = io::read<size_t>(is);
|
||||||
// std::cout << "Updating " << component_count << " components in entity: " << uuid << '\n';
|
// std::cout << "Updating " << component_count << " components in entity: " << uuid << '\n';
|
||||||
for (size_t i = 0; i < component_count; ++i) {
|
for (size_t i = 0; i < component_count; ++i) {
|
||||||
size_t new_id = conversion[io::read<size_t>(is)];
|
size_t id = conversion[io::read<size_t>(is)];
|
||||||
bool runtime = io::read<bool>(is);
|
|
||||||
size_t id = new_id;
|
|
||||||
if (runtime) {
|
|
||||||
id = conversion[io::read<size_t>(is)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo We also need to be able to remove components
|
// @todo We also need to be able to remove components
|
||||||
// Sending a component with length 0 -> remove component
|
// Sending a component with length 0 -> remove component
|
||||||
|
@ -75,22 +59,14 @@ namespace ecs::serial {
|
||||||
// @todo What if the function does not exist?
|
// @todo What if the function does not exist?
|
||||||
if (entity->has_components({id})) {
|
if (entity->has_components({id})) {
|
||||||
// Update the component
|
// Update the component
|
||||||
std::cout << "Updating component: " << id << " [" << ComponentID::get_name(id) << "]";
|
std::cout << "Updating component: " << id << " [" << ComponentID::reverse_resolve(id) << "]\n";
|
||||||
if (new_id != id) {
|
|
||||||
std::cout << " (base: " << new_id << " [" << ComponentID::get_name(new_id) << "])";
|
|
||||||
}
|
|
||||||
std::cout << '\n';
|
|
||||||
Component* component = entity->get_component(id);
|
Component* component = entity->get_component(id);
|
||||||
// @note We do not have to check if this exists as the entity already has the component
|
// @note We do not have to check if this exists as the entity already has the component
|
||||||
std::get<1>(internal::functions[new_id])(is, component);
|
std::get<1>(internal::functions[id])(is, component);
|
||||||
} else {
|
} else {
|
||||||
// Add new component
|
// Add new component
|
||||||
std::cout << "Adding component: " << id << " [" << ComponentID::get_name(id) << "]";
|
std::cout << "Adding component: " << id << " [" << ComponentID::reverse_resolve(id) << "]\n";
|
||||||
if (new_id != id) {
|
auto func = internal::functions.find(id);
|
||||||
std::cout << " (base: " << new_id << " [" << ComponentID::get_name(new_id) << "])";
|
|
||||||
}
|
|
||||||
std::cout << '\n';
|
|
||||||
auto func = internal::functions.find(new_id);
|
|
||||||
if (func == internal::functions.end()) {
|
if (func == internal::functions.end()) {
|
||||||
throw std::runtime_error("No known serializers for component");
|
throw std::runtime_error("No known serializers for component");
|
||||||
}
|
}
|
||||||
|
@ -102,7 +78,7 @@ namespace ecs::serial {
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialize_ids(std::ostream& os) {
|
void serialize_ids(std::ostream& os) {
|
||||||
auto& ids = ComponentID::_ids();
|
auto& ids = ComponentID::get_map();
|
||||||
|
|
||||||
io::write<size_t>(os, ids.size());
|
io::write<size_t>(os, ids.size());
|
||||||
for (auto& [name, id] : ids) {
|
for (auto& [name, id] : ids) {
|
||||||
|
@ -117,7 +93,7 @@ namespace ecs::serial {
|
||||||
std::string name = io::read<std::string>(is);
|
std::string name = io::read<std::string>(is);
|
||||||
size_t id = io::read<size_t>(is);
|
size_t id = io::read<size_t>(is);
|
||||||
|
|
||||||
conversion[id] = ComponentID::get_id({name})[0];
|
conversion[id] = ComponentID::resolve(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto [remote_id, local_id] : conversion) {
|
for (auto [remote_id, local_id] : conversion) {
|
||||||
|
|
|
@ -4,68 +4,79 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
#include <typeinfo>
|
#include <iostream>
|
||||||
#if __has_include(<cxxabi.h>)
|
|
||||||
#include <cxxabi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
|
|
||||||
namespace ecs {
|
namespace ecs {
|
||||||
template <typename T>
|
// @todo Redo the component id system to require registering the components
|
||||||
std::string get_typename() {
|
// This would hopefully clear up some of the jank related to this part of the codebase (No weird lookups)
|
||||||
#if __has_include(<cxxabi.h>)
|
// It would also make runtime generated / meta components much easier
|
||||||
std::string name = abi::__cxa_demangle(typeid(T).name(), 0, 0, 0);
|
|
||||||
#else
|
|
||||||
std::string name = typeid(T).name();
|
|
||||||
// This is really janky
|
|
||||||
name = name.substr(name.find(' ')+1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto index = name.find_last_of(':');
|
|
||||||
if (index != std::string::npos) {
|
|
||||||
name = name.substr(index+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComponentID {
|
class ComponentID {
|
||||||
private:
|
private:
|
||||||
static size_t _id;
|
static size_t next_id;
|
||||||
|
static std::unordered_map<std::string, size_t> _ids;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// This needs to be a function because otherwise it might not be initialized on time
|
template <typename T>
|
||||||
static std::unordered_map<std::string, size_t>& _ids();
|
static size_t regist(std::string name) {
|
||||||
static std::vector<size_t> get_id(std::vector<std::string> names);
|
_ids.insert({name, id<T>});
|
||||||
|
// @todo Do some other register stuff
|
||||||
// @todo This is slow...
|
return id<T>;
|
||||||
static std::string get_name(size_t id) {
|
|
||||||
for (auto it = _ids().begin(); it != _ids().end(); ++it) {
|
|
||||||
if (it->second == id) {
|
|
||||||
return it->first;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("ID does not exist");
|
static size_t regist(std::string name) {
|
||||||
|
size_t id = next_id++;
|
||||||
|
_ids.insert({name, id});
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This looks kind of ugly
|
// This looks kind of ugly
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline static const size_t id = get_id({get_typename<T>()})[0];
|
inline static const size_t id = next_id++;
|
||||||
|
|
||||||
|
static size_t resolve(std::string name) {
|
||||||
|
auto it = _ids.find(name);
|
||||||
|
if (it == _ids.end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<size_t> resolve(std::vector<std::string> names) {
|
||||||
|
std::vector<size_t> ids;
|
||||||
|
|
||||||
|
for (const auto& name : names) {
|
||||||
|
ids.push_back(resolve(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string reverse_resolve(size_t id) {
|
||||||
|
for (auto& [name, _id] : _ids) {
|
||||||
|
if (id == _id) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const auto& get_map() {
|
||||||
|
return _ids;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Component {
|
struct Component {
|
||||||
Component() : _runtime(false), _id(0) {}
|
Component() {}
|
||||||
|
|
||||||
// @todo Would be nice if this worked with templates
|
|
||||||
Component(size_t id) : _runtime(true), _id(id) {}
|
|
||||||
|
|
||||||
virtual ~Component() {}
|
virtual ~Component() {}
|
||||||
|
//
|
||||||
const bool _runtime;
|
// @todo Store parent entity and also make a vector for all components of this type
|
||||||
const size_t _id;
|
// that way we can do some nice stuff without having to search the entities
|
||||||
|
// For example we could loop over all sprite components and then draw them (using parent to find location)
|
||||||
};
|
};
|
||||||
|
|
||||||
class Entity {
|
class Entity {
|
||||||
|
@ -73,52 +84,48 @@ namespace ecs {
|
||||||
Entity(uuids::uuid _uuid) : uuid(_uuid) {}
|
Entity(uuids::uuid _uuid) : uuid(_uuid) {}
|
||||||
~Entity();
|
~Entity();
|
||||||
|
|
||||||
|
void add_component(size_t id, Component* component);
|
||||||
|
bool has_components(std::vector<size_t> ids) const;
|
||||||
|
bool has_components(size_t id) const;
|
||||||
|
Component* get_component(size_t id) const;
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
void add_component(Args... args) {
|
void add_component(Args... args) {
|
||||||
size_t id = ComponentID::id<T>;
|
size_t id = ComponentID::id<T>;
|
||||||
|
|
||||||
|
std::cout << "ID: " << id << '\n';
|
||||||
|
|
||||||
if (_components.find(id) != _components.end()) {
|
if (_components.find(id) != _components.end()) {
|
||||||
throw std::runtime_error("Component already exists");
|
throw std::runtime_error("Component already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @todo Also register the component to the manager
|
||||||
_components[id] = new T(args...);
|
_components[id] = new T(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
bool has_components() const {
|
bool has_components() const {
|
||||||
std::vector<size_t> ids = {ComponentID::id<Ts>...};
|
std::vector<size_t> ids = {ComponentID::id<Ts>...};
|
||||||
for (const auto& id : ids) {
|
|
||||||
if (_components.find(id) == _components.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return has_components(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* get_component() const {
|
T* get_component() const {
|
||||||
size_t id = ComponentID::id<T>;
|
size_t id = ComponentID::id<T>;
|
||||||
auto it = _components.find(id);
|
|
||||||
if (it == _components.end()) {
|
|
||||||
throw std::runtime_error("Component does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (T*)it->second;
|
return (T*)get_component(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<size_t, Component*> get_components() const {
|
const std::unordered_map<size_t, Component*> get_components() const {
|
||||||
return _components;
|
return _components;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_component(size_t id, Component* component);
|
|
||||||
bool has_components(std::vector<size_t> ids);
|
|
||||||
Component* get_component(size_t id);
|
|
||||||
|
|
||||||
const uuids::uuid uuid;
|
const uuids::uuid uuid;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<size_t, Component*> _components;
|
std::unordered_map<size_t, Component*> _components;
|
||||||
|
// @todo Store manager, this allows the entity to register components to the manager
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
|
@ -183,6 +190,18 @@ namespace ecs {
|
||||||
return View<Ts...>(entities);
|
return View<Ts...>(entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
View<> view(size_t id) {
|
||||||
|
std::unordered_map<uuids::uuid, Entity*> entities;
|
||||||
|
|
||||||
|
for (auto [uuid, entity] : _entities) {
|
||||||
|
if (entity->has_components(id)) {
|
||||||
|
entities.insert({uuid, entity});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return View<>(entities);
|
||||||
|
}
|
||||||
|
|
||||||
View<> view(std::vector<size_t> ids) {
|
View<> view(std::vector<size_t> ids) {
|
||||||
std::unordered_map<uuids::uuid, Entity*> entities;
|
std::unordered_map<uuids::uuid, Entity*> entities;
|
||||||
|
|
||||||
|
|
|
@ -3,29 +3,8 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace ecs {
|
namespace ecs {
|
||||||
size_t ComponentID::_id;
|
size_t ComponentID::next_id = 1;
|
||||||
// This needs to be a function because otherwise it might not be initialized on time
|
std::unordered_map<std::string, size_t> ComponentID::_ids;
|
||||||
std::unordered_map<std::string, size_t>& ComponentID::_ids() {
|
|
||||||
static std::unordered_map<std::string, size_t> ids;
|
|
||||||
return ids;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<size_t> ComponentID::get_id(std::vector<std::string> names) {
|
|
||||||
std::vector<size_t> ids;
|
|
||||||
|
|
||||||
for (const auto& name : names) {
|
|
||||||
auto it = _ids().find(name);
|
|
||||||
if (it != _ids().end()) {
|
|
||||||
ids.push_back(it->second);
|
|
||||||
} else {
|
|
||||||
size_t id = _id++;
|
|
||||||
_ids()[name] = id;
|
|
||||||
ids.push_back(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity::~Entity() {
|
Entity::~Entity() {
|
||||||
// @todo This does not work...
|
// @todo This does not work...
|
||||||
|
@ -37,6 +16,9 @@ namespace ecs {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::add_component(size_t id, Component* component) {
|
void Entity::add_component(size_t id, Component* component) {
|
||||||
|
if (id == 0) {
|
||||||
|
throw std::runtime_error("Unknown component!");
|
||||||
|
}
|
||||||
if (_components.find(id) != _components.end()) {
|
if (_components.find(id) != _components.end()) {
|
||||||
throw std::runtime_error("Component already exists");
|
throw std::runtime_error("Component already exists");
|
||||||
}
|
}
|
||||||
|
@ -44,7 +26,15 @@ namespace ecs {
|
||||||
_components[id] = component;
|
_components[id] = component;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Entity::has_components(std::vector<size_t> ids) {
|
bool Entity::has_components(size_t id) const {
|
||||||
|
if (_components.find(id) == _components.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Entity::has_components(std::vector<size_t> ids) const {
|
||||||
for (const auto& id : ids) {
|
for (const auto& id : ids) {
|
||||||
if (_components.find(id) == _components.end()) {
|
if (_components.find(id) == _components.end()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -54,10 +44,10 @@ namespace ecs {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Component* Entity::get_component(size_t id) {
|
Component* Entity::get_component(size_t id) const {
|
||||||
auto it = _components.find(id);
|
auto it = _components.find(id);
|
||||||
if (it == _components.end()) {
|
if (it == _components.end()) {
|
||||||
throw std::runtime_error("Component does not exist");
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
18
flint.yaml
18
flint.yaml
|
@ -37,19 +37,21 @@ targets:
|
||||||
dependency:
|
dependency:
|
||||||
- stduuid
|
- stduuid
|
||||||
|
|
||||||
|
ecs_serial:
|
||||||
|
type: lib
|
||||||
|
path: ecs-serial
|
||||||
|
dependency:
|
||||||
|
- ecs
|
||||||
|
- io
|
||||||
|
|
||||||
ecs-lua:
|
ecs-lua:
|
||||||
type: lib
|
type: lib
|
||||||
path: ecs-lua
|
path: ecs-lua
|
||||||
dependency:
|
dependency:
|
||||||
- ecs
|
- ecs
|
||||||
- sol2
|
- sol2
|
||||||
|
optional:
|
||||||
ecs-serial:
|
- ecs_serial
|
||||||
type: lib
|
|
||||||
path: ecs-serial
|
|
||||||
dependency:
|
|
||||||
- ecs
|
|
||||||
- io
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
type: exe
|
type: exe
|
||||||
|
@ -59,5 +61,5 @@ targets:
|
||||||
dependency:
|
dependency:
|
||||||
- ecs
|
- ecs
|
||||||
- ecs-lua
|
- ecs-lua
|
||||||
- ecs-serial
|
- ecs_serial
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace generated {
|
||||||
);
|
);
|
||||||
|
|
||||||
component.set_function("new", sol::factories([](float _x, float _y) {
|
component.set_function("new", sol::factories([](float _x, float _y) {
|
||||||
return std::make_pair(new Position(_x, _y), "Position");
|
return std::make_pair(ecs::ComponentID::id<Position>, new Position(_x, _y));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
lua.set_function("_internal_to_Position", [] (ecs::Component* component) {
|
lua.set_function("_internal_to_Position", [] (ecs::Component* component) {
|
||||||
|
@ -33,7 +33,7 @@ namespace generated {
|
||||||
);
|
);
|
||||||
|
|
||||||
component.set_function("new", sol::factories([](float _x, float _y) {
|
component.set_function("new", sol::factories([](float _x, float _y) {
|
||||||
return std::make_pair(new Velocity(_x, _y), "Velocity");
|
return std::make_pair(ecs::ComponentID::id<Velocity>, new Velocity(_x, _y));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
lua.set_function("_internal_to_Velocity", [] (ecs::Component* component) {
|
lua.set_function("_internal_to_Velocity", [] (ecs::Component* component) {
|
||||||
|
@ -51,7 +51,7 @@ namespace generated {
|
||||||
);
|
);
|
||||||
|
|
||||||
component.set_function("new", sol::factories([](std::string _name) {
|
component.set_function("new", sol::factories([](std::string _name) {
|
||||||
return std::make_pair(new Meta(_name), "Meta");
|
return std::make_pair(ecs::ComponentID::id<Meta>, new Meta(_name));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
lua.set_function("_internal_to_Meta", [] (ecs::Component* component) {
|
lua.set_function("_internal_to_Meta", [] (ecs::Component* component) {
|
||||||
|
|
|
@ -38,6 +38,11 @@ int main(int argc, const char** argv) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ecs::ComponentID::regist<ecs::lua::Wrapper>("Wrapper");
|
||||||
|
ecs::ComponentID::regist<Position>("Position");
|
||||||
|
ecs::ComponentID::regist<Velocity>("Velocity");
|
||||||
|
ecs::ComponentID::regist<Meta>("Meta");
|
||||||
|
|
||||||
sol::state lua(sol::c_call<decltype(&handle_error), &handle_error>);
|
sol::state lua(sol::c_call<decltype(&handle_error), &handle_error>);
|
||||||
lua.open_libraries(sol::lib::base, sol::lib::package);
|
lua.open_libraries(sol::lib::base, sol::lib::package);
|
||||||
|
|
||||||
|
@ -46,95 +51,6 @@ int main(int argc, const char** argv) {
|
||||||
generated::init(lua);
|
generated::init(lua);
|
||||||
generated::init();
|
generated::init();
|
||||||
|
|
||||||
// @todo I am pretty sure that iohelper actually has an api that allows us to write a custom (de)serializer
|
|
||||||
ecs::serial::register_component_custom<ecs::lua::Wrapper>(
|
|
||||||
[](std::ostream& os, ecs::Component* component) {
|
|
||||||
ecs::lua::Wrapper* wrapper = (ecs::lua::Wrapper*)component;
|
|
||||||
|
|
||||||
// iohelper::write<std::string>(os, wrapper->name);
|
|
||||||
|
|
||||||
// #todo .size() does not work
|
|
||||||
size_t size = 0;
|
|
||||||
for (auto [a, b] : wrapper->table) {
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
io::write<size_t>(os, size);
|
|
||||||
|
|
||||||
for (auto [a, b] : wrapper->table) {
|
|
||||||
io::write<std::string>(os, a.as<std::string>());
|
|
||||||
|
|
||||||
sol::type type = b.get_type();
|
|
||||||
io::write<uint8_t>(os, (uint8_t)type);
|
|
||||||
switch (type) {
|
|
||||||
case sol::type::none:
|
|
||||||
case sol::type::nil:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sol::type::string:
|
|
||||||
io::write<std::string>(os, b.as<std::string>());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sol::type::number:
|
|
||||||
// @todo These should be doubles instead of floats
|
|
||||||
io::write<float>(os, b.as<float>());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sol::type::boolean:
|
|
||||||
io::write<bool>(os, b.as<bool>());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sol::type::table:
|
|
||||||
// @todo Make this happen
|
|
||||||
break;
|
|
||||||
|
|
||||||
// All other types are not supported
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Unsupported type in wrapped lua table");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[&lua](std::istream& is, ecs::Component* component) {
|
|
||||||
ecs::lua::Wrapper* wrapper = (ecs::lua::Wrapper*)component;
|
|
||||||
// @todo Only do this if table is not created yet
|
|
||||||
wrapper->table = lua.create_table();
|
|
||||||
|
|
||||||
size_t size = io::read<size_t>(is);
|
|
||||||
std::cout << "Size: " << size << '\n';
|
|
||||||
for (size_t i = 0; i < size; ++i) {
|
|
||||||
std::string name = io::read<std::string>(is);
|
|
||||||
|
|
||||||
std::cout << "Name: " << name << '\n';
|
|
||||||
|
|
||||||
sol::type type = (sol::type)io::read<uint8_t>(is);
|
|
||||||
switch (type) {
|
|
||||||
case sol::type::none:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sol::type::nil:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sol::type::string:
|
|
||||||
wrapper->table[name] = io::read<std::string>(is);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sol::type::number:
|
|
||||||
wrapper->table[name] = io::read<float>(is);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sol::type::boolean:
|
|
||||||
{
|
|
||||||
wrapper->table[name] = io::read<bool>(is);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (save) {
|
if (save) {
|
||||||
ecs::Manager manager;
|
ecs::Manager manager;
|
||||||
|
|
||||||
|
@ -147,6 +63,14 @@ int main(int argc, const char** argv) {
|
||||||
|
|
||||||
lua.safe_script_file("test.lua");
|
lua.safe_script_file("test.lua");
|
||||||
|
|
||||||
|
sol::protected_function init = lua["init"];
|
||||||
|
std::cout << "Running init()\n";
|
||||||
|
init();
|
||||||
|
|
||||||
|
sol::protected_function run = lua["run"];
|
||||||
|
std::cout << "Running run()\n";
|
||||||
|
run();
|
||||||
|
|
||||||
std::cout << "Update position\n";
|
std::cout << "Update position\n";
|
||||||
manager.view<Position, Velocity>().for_each([](ecs::Entity*, Position* pos, Velocity* vel) {
|
manager.view<Position, Velocity>().for_each([](ecs::Entity*, Position* pos, Velocity* vel) {
|
||||||
pos->x += vel->x;
|
pos->x += vel->x;
|
||||||
|
@ -160,15 +84,15 @@ int main(int argc, const char** argv) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// These are really just an internal api that should not be used
|
// These are really just an internal api that should not be used
|
||||||
for (auto [uuid, entity] : manager.view(ecs::ComponentID::get_id({"Random"}))) {
|
for (auto [uuid, entity] : manager.view(ecs::ComponentID::resolve("Random"))) {
|
||||||
sol::table random = ((ecs::lua::Wrapper*)entity->get_component(ecs::ComponentID::get_id({"Random"})[0]))->table;
|
sol::table random = ((ecs::lua::Wrapper*)entity->get_component(ecs::ComponentID::resolve("Random")))->table;
|
||||||
|
|
||||||
random["a"] = 21;
|
random["a"] = 21;
|
||||||
std::cout << random["a"].get<std::string>() << '\n';
|
std::cout << random["a"].get<std::string>() << '\n';
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto [uuid, entity] : manager.view(ecs::ComponentID::get_id({"Random"}))) {
|
for (auto [uuid, entity] : manager.view(ecs::ComponentID::resolve("Random"))) {
|
||||||
sol::table random = ((ecs::lua::Wrapper*)entity->get_component(ecs::ComponentID::get_id({"Random"})[0]))->table;
|
sol::table random = ((ecs::lua::Wrapper*)entity->get_component(ecs::ComponentID::resolve("Random")))->table;
|
||||||
|
|
||||||
std::cout << random["a"].get<std::string>() << '\n';
|
std::cout << random["a"].get<std::string>() << '\n';
|
||||||
};
|
};
|
||||||
|
@ -214,6 +138,11 @@ int main(int argc, const char** argv) {
|
||||||
{
|
{
|
||||||
std::cout << "LOAD\n";
|
std::cout << "LOAD\n";
|
||||||
|
|
||||||
|
lua.safe_script_file("test2.lua");
|
||||||
|
sol::protected_function init = lua["init"];
|
||||||
|
std::cout << "Running init()\n";
|
||||||
|
init();
|
||||||
|
|
||||||
// Load entities from disk as a test
|
// Load entities from disk as a test
|
||||||
std::ifstream file("entities", std::ios::in);
|
std::ifstream file("entities", std::ios::in);
|
||||||
|
|
||||||
|
@ -248,11 +177,13 @@ int main(int argc, const char** argv) {
|
||||||
return manager;
|
return manager;
|
||||||
});
|
});
|
||||||
|
|
||||||
lua.safe_script_file("test2.lua");
|
sol::protected_function run = lua["run"];
|
||||||
|
std::cout << "Running run()\n";
|
||||||
|
run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto [name, id] : ecs::ComponentID::_ids()) {
|
for (auto [name, id] : ecs::ComponentID::get_map()) {
|
||||||
std::cout << name << ' ' << id << '\n';
|
std::cout << name << ' ' << id << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
105
test/test.lua
105
test/test.lua
|
@ -1,42 +1,58 @@
|
||||||
local ecs = require "ecs"
|
local ecs = require "ecs"
|
||||||
-- local test = require "ecs_test"
|
|
||||||
local Position = require "ecs.Position"
|
local Position = require "ecs.Position"
|
||||||
local Velocity = require "ecs.Velocity"
|
local Velocity = require "ecs.Velocity"
|
||||||
local Meta = require "ecs.Meta"
|
local Meta = require "ecs.Meta"
|
||||||
local Wrapper = require 'ecs.Wrapper'
|
local Wrapper = require 'ecs.Wrapper'
|
||||||
|
|
||||||
manager = get_manager()
|
function init()
|
||||||
ent = manager:create_entity()
|
print("Registering components")
|
||||||
ent:add_component(Velocity.new(0.2, 0.3))
|
|
||||||
ent:add_component(Position.new(1.9, 9.7))
|
|
||||||
ent:add_component(Meta.new("Soldier"))
|
|
||||||
|
|
||||||
data = {
|
LuaData = ecs.register("LuaData", {
|
||||||
|
speed = "number",
|
||||||
|
something = "string",
|
||||||
|
alive = "boolean"
|
||||||
|
})
|
||||||
|
TestThing = ecs.register("TestThing", {
|
||||||
|
test = "string"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function run()
|
||||||
|
print("Running!")
|
||||||
|
manager = get_manager()
|
||||||
|
ent = manager:create_entity()
|
||||||
|
ent:add_component(Position.new(1.9, 9.7))
|
||||||
|
ent:add_component(Velocity.new(0.2, 0.3))
|
||||||
|
ent:add_component(Meta.new("Soldier"))
|
||||||
|
|
||||||
|
ent:add_component(LuaData.new({
|
||||||
speed = 10,
|
speed = 10,
|
||||||
something = "Hello, World!",
|
something = "Hello, World!",
|
||||||
alive = true
|
alive = true
|
||||||
}
|
}))
|
||||||
ent:add_component(Wrapper.new("LuaData", data))
|
ent:add_component(TestThing.new({
|
||||||
ent:add_component(Wrapper.new("TestThing", { test = 1.23563 }))
|
test = "This is a test!"
|
||||||
|
}))
|
||||||
|
|
||||||
-- @todo Make this happen...
|
-- @todo Make this happen...
|
||||||
-- stats = {
|
-- stats = {
|
||||||
-- hp = 100,
|
-- hp = 100,
|
||||||
-- magic = 30
|
-- magic = 30
|
||||||
-- }
|
-- }
|
||||||
--
|
--
|
||||||
-- ent:add_component(ecs.Wrapper.new("Stats", stats))
|
-- ent:add_component(ecs.Wrapper.new("Stats", stats))
|
||||||
|
|
||||||
print(ent:has_components("Position", "Velocity"))
|
print(ent:has_components("Position", "Velocity"))
|
||||||
pos = ent:get_component("Position")
|
pos = ent:get_component("Position")
|
||||||
print("x: " .. pos.x)
|
print("x: " .. pos.x)
|
||||||
print("y: " .. pos.y)
|
print("y: " .. pos.y)
|
||||||
vel = ent:get_component("Velocity")
|
vel = ent:get_component("Velocity")
|
||||||
print("v_x: " .. vel.x)
|
print("v_x: " .. vel.x)
|
||||||
print("v_y: " .. vel.y)
|
print("v_y: " .. vel.y)
|
||||||
|
|
||||||
print("View test")
|
print("View test")
|
||||||
manager:view("Position", "Velocity"):for_each(function(ent)
|
manager:view("Position", "Velocity"):for_each(function(ent)
|
||||||
pos = ent:get_component("Position")
|
pos = ent:get_component("Position")
|
||||||
vel = ent:get_component("Velocity")
|
vel = ent:get_component("Velocity")
|
||||||
|
|
||||||
|
@ -55,33 +71,32 @@ manager:view("Position", "Velocity"):for_each(function(ent)
|
||||||
meta = ent:get_component("Meta")
|
meta = ent:get_component("Meta")
|
||||||
print("name: " .. meta.name)
|
print("name: " .. meta.name)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- @todo Implement this
|
-- @todo Implement this
|
||||||
-- for uuid,entity in pairs(view) do
|
-- for uuid,entity in pairs(view) do
|
||||||
-- print "TEST"
|
-- print "TEST"
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
manager:view("LuaData"):for_each(function(ent)
|
manager:view("LuaData"):for_each(function(ent)
|
||||||
d = ent:get_component("LuaData")
|
d = ent:get_component("LuaData")
|
||||||
|
|
||||||
print(d.speed)
|
print("speed: " .. d.speed)
|
||||||
d.speed = 11
|
d.speed = 11
|
||||||
print(d.speed)
|
print("speed: " .. d.speed)
|
||||||
print(data.speed)
|
|
||||||
data.speed = 20
|
|
||||||
print(d.speed)
|
|
||||||
print(data.speed)
|
|
||||||
|
|
||||||
print(d.alive)
|
print("alive: ") print(d.alive)
|
||||||
d.alive = false
|
d.alive = false
|
||||||
print(d.alive)
|
print("alive: ") print(d.alive)
|
||||||
|
|
||||||
print(d.something)
|
print("Something: " .. d.something)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
manager:view("TestThing"):for_each(function(ent)
|
manager:view("TestThing"):for_each(function(ent)
|
||||||
t = ent:get_component("TestThing")
|
t = ent:get_component("TestThing")
|
||||||
|
|
||||||
print(t.test)
|
print("test: " .. t.test)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
print("Done running!")
|
||||||
|
end
|
||||||
|
|
|
@ -1,14 +1,33 @@
|
||||||
require "ecs"
|
local ecs = require "ecs"
|
||||||
require "ecs.Wrapper"
|
require "ecs.Wrapper"
|
||||||
|
|
||||||
manager = get_manager()
|
function init()
|
||||||
|
print("Registering components")
|
||||||
|
|
||||||
manager:view("TestThing"):for_each(function(ent)
|
LuaData = ecs.register("LuaData", {
|
||||||
|
speed = "number",
|
||||||
|
something = "string",
|
||||||
|
alive = "boolean"
|
||||||
|
})
|
||||||
|
TestThing = ecs.register("TestThing", {
|
||||||
|
test = "string"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function run()
|
||||||
|
print("Running!")
|
||||||
|
|
||||||
|
manager = get_manager()
|
||||||
|
|
||||||
|
print("AAA")
|
||||||
|
|
||||||
|
manager:view("TestThing"):for_each(function(ent)
|
||||||
data = ent:get_component("TestThing")
|
data = ent:get_component("TestThing")
|
||||||
print("test: " .. data.test)
|
print("test: " .. data.test)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
manager:view("LuaData"):for_each(function(ent)
|
|
||||||
|
manager:view("LuaData"):for_each(function(ent)
|
||||||
-- @todo It would be nice if this could somehow be passed in as function arg
|
-- @todo It would be nice if this could somehow be passed in as function arg
|
||||||
data = ent:get_component("LuaData")
|
data = ent:get_component("LuaData")
|
||||||
print("speed: " .. data.speed)
|
print("speed: " .. data.speed)
|
||||||
|
@ -16,11 +35,15 @@ manager:view("LuaData"):for_each(function(ent)
|
||||||
-- @todo You cannot concatenate bool to string
|
-- @todo You cannot concatenate bool to string
|
||||||
print("alive: ")
|
print("alive: ")
|
||||||
print(data.alive)
|
print(data.alive)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- @todo Allow this
|
-- @todo Allow this
|
||||||
-- for i, v in pairs(manager:view("TestThing")) do
|
-- for i, v in pairs(manager:view("TestThing")) do
|
||||||
-- print(i, v)
|
-- print(i, v)
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
print(manager:has_entity("70bca3cf-33dd-40dc-8b0f-2e19aa0b4a17"))
|
print("Exists: ")
|
||||||
|
print(manager:has_entity("70bca3cf-33dd-40dc-8b0f-2e19aa0b4a17"))
|
||||||
|
|
||||||
|
print("Done running!")
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user