Serializer now has a nice register function

This commit is contained in:
2019-02-09 21:41:43 +00:00
parent a6e5deb502
commit 96ad0de01a
7 changed files with 323 additions and 245 deletions

View File

@@ -1,147 +1,63 @@
#include <iostream>
#include "ecs-serial.h"
#include "ecs.h"
#include "iohelper/memstream.h"
#include "iohelper/write.h"
#include "iohelper/read.h"
namespace ecs::serial {
std::unordered_map<size_t, std::tuple<std::function<void(std::ostream&, ecs::Component*)>, std::function<void(std::istream&, ecs::Component*)>, std::function<ecs::Component*()>>> internal::functions;
#include <fstream>
void serialize(std::ostream& os, Entity* entity) {
auto uuid_data = reinterpret_cast<const uint8_t*>(entity->uuid.as_bytes().data());
iohelper::write_vector<uint8_t>(os, std::vector<uint8_t>(uuid_data, uuid_data + 16), false);
struct Position : ecs::Component {
Position(float x, float y) : _x(x), _y(y) {}
float _x;
float _y;
};
struct Velocity : ecs::Component{
Velocity(float vx, float vy) : _vx(vx), _vy(vy) {}
float _vx;
float _vy;
};
std::unordered_map<size_t, std::pair<std::function<std::vector<uint8_t>(ecs::Component*)>, std::function<ecs::Component*(std::vector<uint8_t>)>>> _functions;
// @todo Add deserializer stuff
template <typename T>
void register_component(std::function<std::vector<uint8_t>(ecs::Component*)> serializer, std::function<ecs::Component*(std::vector<uint8_t>)> deserializer) {
_functions.insert({ecs::ComponentID::id<T>, {serializer, deserializer}});
}
enum class Marker : uint8_t {
ENTITY,
COMPONENT,
END
};
int main(int argc, const char* argv) {
ecs::Manager manager;
register_component<Position>([] (ecs::Component* component) {
Position* pos = (Position*)component;
std::vector<uint8_t> data;
iohelper::omemstream stream(data);
iohelper::write<float>(stream, pos->_x);
iohelper::write<float>(stream, pos->_y);
return data;
}, [] (std::vector<uint8_t> data) {
iohelper::imemstream stream(data);
float x = iohelper::read<float>(stream);
float y = iohelper::read<float>(stream);
return new Position(x, y);
});
register_component<Velocity>([] (ecs::Component* component) {
Velocity* vel = (Velocity*)component;
std::vector<uint8_t> data;
iohelper::omemstream stream(data);
iohelper::write<float>(stream, vel->_vx);
iohelper::write<float>(stream, vel->_vy);
return data;
}, [] (std::vector<uint8_t> data) {
iohelper::imemstream stream(data);
float vx = iohelper::read<float>(stream);
float vy = iohelper::read<float>(stream);
return new Velocity(vx, vy);
});
if (argc == 1) {
// Create entities and store them
for (int i = 0; i < 10; ++i) {
// We can create entities
ecs::Entity* entity = manager.create_entity();
// Then we can add components to them
entity->add_component<Position>(0.0f, 0.0f);
if (i % 2 == 0) {
entity->add_component<Velocity>(0.1f, 0.2f);
}
}
manager.view<Position, Velocity>().for_each([] (ecs::Entity*, Position* pos, Velocity* vel) {
pos->_x += vel->_vx;
pos->_y += vel->_vy;
});
std::ofstream file("entities", std::ios::out | std::ios::trunc);
for (auto [uuid, entity] : manager.view<>()) {
iohelper::write<uint8_t>(file, (uint8_t)Marker::ENTITY);
// iohelper::write_length(file, uuid);
auto uuid_data = reinterpret_cast<const uint8_t*>(uuid.as_bytes().data());
iohelper::write_vector<uint8_t>(file, std::vector<uint8_t>(uuid_data, uuid_data + 16), false);
for (auto [id, component] : entity->get_components()) {
iohelper::write<uint8_t>(file, (uint8_t)Marker::COMPONENT);
iohelper::write_length(file, id);
auto data = _functions[id].first(component);
iohelper::write_vector<uint8_t>(file, data);
}
}
iohelper::write<uint8_t>(file, (uint8_t)Marker::END);
file.close();
} else {
// Load entities from disk as a test
std::ifstream file("entities", std::ios::in);
bool loop = true;
ecs::Entity* entity = nullptr;
while (loop) {
Marker marker = (Marker)iohelper::read<uint8_t>(file);
switch (marker) {
case Marker::ENTITY: {
// size_t uuid = iohelper::read_length(file);
auto uuid_vector = iohelper::read_vector<uint8_t>(file, 16);
entity = manager.create_entity(uuids::uuid(uuid_vector.begin(), uuid_vector.end()));
break;
}
case Marker::COMPONENT: {
size_t id = iohelper::read_length(file);
std::vector<uint8_t> data = iohelper::read_vector<uint8_t>(file);
entity->add_component(id, _functions[id].second(data));
break;
}
case Marker::END:
loop = false;
break;
}
}
if (false) {
auto ent = manager.get_entity(uuids::uuid::from_string("6d58fdb5-6d8c-4e6f-89d4-f7d7b184f463").value());
if (ent->has_components<Position>()) {
auto pos = ent->get_component<Position>();
pos->_x = 1.2f;
pos->_y = 3.4f;
}
auto components = entity->get_components();
iohelper::write_length(os, components.size());
for (auto [id, component] : components) {
iohelper::write_length(os, id);
// @todo What if the function does not exist?
std::get<0>(internal::functions[id])(os, component);
}
}
manager.view<Position>().for_each([] (ecs::Entity* entity, Position* pos) {
std::cout << "uuid: " << entity->uuid << '\n';
std::cout << "x: " << pos->_x << '\n';
std::cout << "y: " << pos->_y << '\n';
});
void deserialize(std::istream& is, Manager& manager) {
auto uuid_vector = iohelper::read_vector<uint8_t>(is, 16);
uuids::uuid uuid(uuid_vector.begin(), uuid_vector.end());
if (manager.has_entity(uuid)) {
// Update existing entity
Entity* entity = manager.get_entity(uuid);
size_t component_count = iohelper::read_length(is);
// std::cout << "Updating " << component_count << " components in entity: " << uuid << '\n';
for (size_t i = 0; i < component_count; ++i) {
size_t id = iohelper::read_length(is);
// @todo We also need to be able to remove components
// Sending a component with length 0 -> remove component
// However we might have components that have no data and are just like tags
// So maybe instead if we send MAX_INT or something like that
// Or we send a flag in front
// @todo What if the function does not exist?
if (entity->has_components({id})) {
// Update the component
std::cout << "Updating component: " << id << '\n';
Component* component = entity->get_component(id);
std::get<1>(internal::functions[id])(is, component);
} else {
// Add new component
std::cout << "Adding component: " << id << '\n';
Component* component = std::get<2>(internal::functions[id])();
std::get<1>(internal::functions[id])(is, component);
entity->add_component(id, component);
}
}
} else {
// Create new entity
Entity* entity = manager.create_entity(uuid);
size_t component_count = iohelper::read_length(is);
// std::cout << "Creating entity with " << component_count << " components: " << uuid << '\n';
for (size_t i = 0; i < component_count; ++i) {
size_t id = iohelper::read_length(is);
std::cout << "Adding component: " << id << '\n';
Component* component = std::get<2>(internal::functions[id])();
std::get<1>(internal::functions[id])(is, component);
entity->add_component(id, component);
}
}
}
}