Working on entity serialization.

This commit is contained in:
Quentin Bazin 2020-04-05 16:59:34 +02:00
parent 38c49f98c6
commit a361f9e01b
17 changed files with 377 additions and 36 deletions

View File

@ -104,16 +104,16 @@ This list is non exhaustive.
- Player model display (currently without rotation nor animation)
- Dimensions (like the Nether or the Ender in Minecraft) ([#80](https://github.com/Unarelith/OpenMiner/pull/80))
- World loading/saving (using `/save <name>` and `/load <name>` commands, see [#26](https://github.com/Unarelith/OpenMiner/issues/26))
- Texture pack system (partially implemented, see [#34](https://github.com/Unarelith/OpenMiner/issues/34))
- Entities (block drops, mobs, etc...) ([#90](https://github.com/Unarelith/OpenMiner/pull/90))
### Missing features
- Texture pack system ([#34](https://github.com/Unarelith/OpenMiner/issues/34))
- Fluid propagation ([#62](https://github.com/Unarelith/OpenMiner/issues/62))
- Day/night cycle with sun/moon display ([#73](https://github.com/Unarelith/OpenMiner/issues/73))
- Real worldgen (seed-based, cave tunnels) ([#79](https://github.com/Unarelith/OpenMiner/issues/79))
- Clouds ([#52](https://github.com/Unarelith/OpenMiner/pull/52))
- Particle system
- Entities (block drops, mobs, etc...)
## Screenshots

View File

@ -49,6 +49,7 @@ endif ()
target_link_libraries(${PROJECT_NAME}
${CMAKE_PROJECT_NAME}_server_lib
${CMAKE_PROJECT_NAME}_common
${GAMEKIT_LIBRARIES}
${OPENGL_LIBRARIES}
${SDL2_LIBRARIES}
@ -60,6 +61,5 @@ target_link_libraries(${PROJECT_NAME}
${LUA_LIBRARIES}
sfml-system
sfml-network
${UNIX_LIBS}
${CMAKE_PROJECT_NAME}_common)
${UNIX_LIBS})

View File

@ -29,11 +29,10 @@
#include "InventoryCube.hpp"
void AnimationController::update(entt::DefaultRegistry &registry) {
// FIXME: This shouldn't use InventoryCube but a more generic class
registry.view<InventoryCube, AnimationComponent>().each([](auto, auto &cube, auto &animation) {
registry.view<gk::Transformable, AnimationComponent>().each([](auto, auto &transformable, auto &animation) {
for (auto &it : animation.list) {
if (it.type == AnimationType::Rotation)
cube.rotate(it.rotation.angle, {it.rotation.axisX, it.rotation.axisY, it.rotation.axisZ});
transformable.rotate(it.rotation.angle, {it.rotation.axisX, it.rotation.axisY, it.rotation.axisZ});
else if (it.type == AnimationType::Translation) {
float dx = it.translation.dx;
float dy = it.translation.dy;
@ -51,7 +50,7 @@ void AnimationController::update(entt::DefaultRegistry &registry) {
|| it.translation.cz + it.translation.dz < it.translation.min)
dz = (it.translation.loop) ? -dz : 0;
cube.move(dx, dy, dz);
transformable.move(dx, dy, dz);
it.translation.cx += dx;
it.translation.cy += dy;

View File

@ -26,22 +26,34 @@
*/
#include "AnimationController.hpp"
#include "ClientPlayer.hpp"
#include "ClientScene.hpp"
#include "CollisionController.hpp"
#include "Scene.hpp"
#include "RenderingController.hpp"
Scene::Scene(ClientPlayer &player) : m_player(player) {
ClientScene::ClientScene(ClientPlayer &player) : m_player(player) {
m_controllers.emplace_back(new AnimationController);
m_controllers.emplace_back(new CollisionController(player));
m_controllers.emplace_back(new RenderingController);
}
void Scene::update() {
void ClientScene::update() {
for (auto &controller : m_controllers)
controller->update(m_registry);
static bool test = false;
if (!test && m_registry.alive() > 2) {
gkDebug() << "serializing...";
sf::Packet packet;
serialize(packet);
gkDebug() << "deserializing...";
deserialize(packet);
gkDebug() << "serializing...";
serialize(packet);
test = true;
}
}
void Scene::draw(gk::RenderTarget &target, gk::RenderStates states) const {
void ClientScene::draw(gk::RenderTarget &target, gk::RenderStates states) const {
if (!m_camera) return;
// Subtract the camera position - see comment in ClientWorld::draw()

View File

@ -24,8 +24,8 @@
*
* =====================================================================================
*/
#ifndef SCENE_HPP_
#define SCENE_HPP_
#ifndef CLIENTSCENE_HPP_
#define CLIENTSCENE_HPP_
#include <deque>
#include <memory>
@ -36,19 +36,18 @@
#include <entt/entt.hpp>
#include "AbstractController.hpp"
#include "Scene.hpp"
class ClientPlayer;
class Scene : public gk::Drawable {
class ClientScene : public Scene, public gk::Drawable {
public:
Scene(ClientPlayer &player);
ClientScene(ClientPlayer &player);
void update();
void setCamera(gk::Camera &camera) { m_camera = &camera; }
entt::DefaultRegistry &registry() { return m_registry; }
private:
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;
@ -56,9 +55,7 @@ class Scene : public gk::Drawable {
gk::Camera *m_camera = nullptr;
mutable entt::DefaultRegistry m_registry;
std::deque<std::unique_ptr<AbstractController>> m_controllers;
};
#endif // SCENE_HPP_
#endif // CLIENTSCENE_HPP_

View File

@ -30,9 +30,8 @@
#include "ItemStack.hpp"
void CollisionController::update(entt::DefaultRegistry &registry) {
// FIXME: This shouldn't use InventoryCube, but instead a callback stored in a CollisionComponent
registry.view<InventoryCube, gk::DoubleBox, ItemStack>().each([&](auto entity, auto &cube, auto &box, auto &itemStack) {
gk::DoubleBox hitbox = box + cube.getPosition();
registry.view<gk::Transformable, gk::DoubleBox, ItemStack>().each([&](auto entity, auto &transformable, auto &box, auto &itemStack) {
gk::DoubleBox hitbox = box + transformable.getPosition();
gk::DoubleBox playerHitbox = m_player.hitbox() + gk::Vector3d{m_player.x(), m_player.y(), m_player.z()};
if (hitbox.intersects(playerHitbox)) {
m_player.inventory().addStack(itemStack.item().stringID(), itemStack.amount());

View File

@ -25,6 +25,7 @@
* =====================================================================================
*/
#include "AnimationComponent.hpp"
#include "DrawableComponent.hpp"
#include "InventoryCube.hpp"
#include "ItemDropFactory.hpp"
#include "ItemStack.hpp"
@ -33,11 +34,14 @@
void ItemDropFactory::create(entt::DefaultRegistry &registry, double x, double y, double z, const std::string &itemID, u16 amount) {
auto entity = registry.create();
InventoryCube &cube = registry.assign<InventoryCube>(entity, 0.25f, true);
auto &drawableComponent = registry.assign<DrawableComponent>(entity);
auto &cube = drawableComponent.setDrawable<InventoryCube>(0.25f, true);
cube.setOrigin(cube.size() / 2.f, cube.size() / 2.f, cube.size() / 2.f);
cube.setPosition(x + 0.5, y + 0.5, z + 0.5);
cube.updateVertexBuffer(Registry::getInstance().getBlockFromStringID(itemID));
auto &transformable = registry.assign<gk::Transformable>(entity);
transformable.setPosition(x + 0.5, y + 0.5, z + 0.5);
auto &animationComponent = registry.assign<AnimationComponent>(entity);
animationComponent.addRotation(0.f, 0.f, 1.f, 0.5f);
animationComponent.addTranslation(0.f, 0.f, -0.0005f, -0.2f, 0.f, true);

View File

@ -24,13 +24,21 @@
*
* =====================================================================================
*/
#include "DrawableComponent.hpp"
#include "InventoryCube.hpp"
#include "RenderingController.hpp"
#include <gk/core/Debug.hpp>
#include <gk/core/GameClock.hpp>
void RenderingController::draw(entt::DefaultRegistry &registry, gk::RenderTarget &target, gk::RenderStates states) {
// FIXME: There's probably another way to do this
registry.view<InventoryCube>().each([&](auto, auto &cube) {
target.draw(cube, states);
registry.view<DrawableComponent, gk::Transformable>().each([&](auto entity, auto &drawable, auto &transformable) {
if (gk::GameClock::getInstance().getTicks() % 100 < 12)
gkDebug() << "Drawing entity" << entity << "at" << transformable.getPosition();
gk::RenderStates drawStates = states;
drawStates.transform *= transformable.getTransform();
drawable.draw(target, drawStates);
});
}

View File

@ -33,8 +33,8 @@
#include <gk/core/Vector4.hpp>
#include "ClientChunk.hpp"
#include "ClientScene.hpp"
#include "Network.hpp"
#include "Scene.hpp"
#include "World.hpp"
class ClientCommandHandler;
@ -62,7 +62,7 @@ class ClientWorld : public World, public gk::Drawable {
Chunk *getChunk(int cx, int cy, int cz) const override;
Scene &scene() { return m_scene; }
ClientScene &scene() { return m_scene; }
void setClient(ClientCommandHandler &client) { m_client = &client; }
void setCamera(gk::Camera &camera) { m_camera = &camera; m_scene.setCamera(camera); }
@ -74,7 +74,7 @@ class ClientWorld : public World, public gk::Drawable {
void draw(gk::RenderTarget &target, gk::RenderStates states) const override;
Scene m_scene;
ClientScene m_scene;
ChunkMap m_chunks;

View File

@ -36,3 +36,23 @@ sf::Packet &operator>>(sf::Packet &packet, gk::Color &color) {
return packet;
}
sf::Packet &operator<<(sf::Packet &packet, const gk::Transformable &transformable) {
packet << transformable.getPosition() << transformable.getOrigin() << transformable.getScale()
<< transformable.getRotation() << transformable.getRotationTransform().getMatrix();
return packet;
}
sf::Packet &operator>>(sf::Packet &packet, gk::Transformable &transformable) {
gk::Vector3f position, origin, scale;
float rotation;
packet >> position >> origin >> scale >> rotation
>> transformable.getRotationTransform().getMatrix();
transformable.setPosition(position);
transformable.setOrigin(origin);
transformable.setScale(scale);
transformable.setRotation(rotation);
return packet;
}

View File

@ -84,6 +84,29 @@ sf::Packet &operator>>(sf::Packet &packet, std::unordered_map<T, U> &map) {
return packet;
}
//======================================================================================
// glm::mat4
//======================================================================================
#include <glm/gtc/type_ptr.hpp>
#include <glm/mat4x4.hpp>
template<typename T>
sf::Packet &operator<<(sf::Packet &packet, const glm::tmat4x4<T> &matrix) {
for (int i = 0 ; i < 4 * 4 ; ++i) {
packet << matrix[i % 4][i / 4];
}
return packet;
}
template<typename T>
sf::Packet &operator>>(sf::Packet &packet, glm::tmat4x4<T> &matrix) {
for (int i = 0 ; i < 4 * 4 ; ++i) {
packet >> matrix[i % 4][i / 4];
}
return packet;
}
//======================================================================================
// gk::Rect
//======================================================================================
@ -143,4 +166,12 @@ sf::Packet &operator>>(sf::Packet &packet, gk::Vector3<T> &vec) {
sf::Packet &operator<<(sf::Packet &packet, const gk::Color &color);
sf::Packet &operator>>(sf::Packet &packet, gk::Color &color);
//======================================================================================
// gk::Transformable
//======================================================================================
#include <gk/gl/Transformable.hpp>
sf::Packet &operator<<(sf::Packet &packet, const gk::Transformable &transformable);
sf::Packet &operator>>(sf::Packet &packet, gk::Transformable &transformable);
#endif // NETWORKUTILS_HPP_

View File

@ -29,12 +29,17 @@
#include <vector>
#include <gk/core/IntTypes.hpp>
#include "ISerializable.hpp"
#include "NetworkUtils.hpp"
enum class AnimationType {
Rotation,
Translation,
};
struct AnimationData {
struct AnimationData : public ISerializable {
AnimationType type;
union {
@ -53,9 +58,36 @@ struct AnimationData {
bool loop;
} translation;
};
void serialize(sf::Packet &packet) const override {
packet << u8(type);
if (type == AnimationType::Rotation) {
packet << rotation.axisX << rotation.axisY << rotation.axisZ << rotation.angle;
}
else if (type == AnimationType::Translation) {
packet << translation.dx << translation.dy << translation.dz
<< translation.cx << translation.cy << translation.cz
<< translation.min << translation.max << translation.loop;
}
}
void deserialize(sf::Packet &packet) override {
u8 type;
packet >> type;
if (type == u8(AnimationType::Rotation)) {
packet >> rotation.axisX >> rotation.axisY >> rotation.axisZ >> rotation.angle;
}
else if (type == u8(AnimationType::Translation)) {
packet >> translation.dx >> translation.dy >> translation.dz
>> translation.cx >> translation.cy >> translation.cz
>> translation.min >> translation.max >> translation.loop;
}
this->type = AnimationType(type);
}
};
struct AnimationComponent {
struct AnimationComponent : public ISerializable {
void addRotation(float axisX, float axisY, float axisZ, float angle) {
list.emplace_back();
AnimationData &data = list.back();
@ -89,6 +121,9 @@ struct AnimationComponent {
data.translation.loop = loop;
}
void serialize(sf::Packet &packet) const override { packet << list; }
void deserialize(sf::Packet &packet) override { packet >> list; }
std::vector<AnimationData> list;
};

View File

@ -0,0 +1,51 @@
/*
* =====================================================================================
*
* OpenMiner
*
* Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
* Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
*
* This file is part of OpenMiner.
*
* OpenMiner is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* OpenMiner is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* =====================================================================================
*/
#ifndef DRAWABLECOMPONENT_HPP_
#define DRAWABLECOMPONENT_HPP_
#include <memory>
#include <gk/gl/Drawable.hpp>
class DrawableComponent {
public:
template<typename T, typename... Args>
auto setDrawable(Args &&...args) -> typename std::enable_if<std::is_base_of<gk::Drawable, T>::value, T &>::type {
m_drawable.reset(new T(std::forward<Args>(args)...));
return *static_cast<T*>(m_drawable.get());
}
void draw(gk::RenderTarget &target, gk::RenderStates states) {
if (m_drawable)
target.draw(*m_drawable, states);
}
private:
std::unique_ptr<gk::Drawable> m_drawable;
};
#endif // DRAWABLECOMPONENT_HPP_

View File

@ -0,0 +1,47 @@
/*
* =====================================================================================
*
* OpenMiner
*
* Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
* Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
*
* This file is part of OpenMiner.
*
* OpenMiner is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* OpenMiner is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* =====================================================================================
*/
#ifndef SCENE_HPP_
#define SCENE_HPP_
#include "ISerializable.hpp"
#include "SceneSerializer.hpp"
class Scene : public ISerializable {
public:
void serialize(sf::Packet &packet) const override { m_serializer.serialize(packet); }
void deserialize(sf::Packet &packet) override { m_serializer.deserialize(packet); }
entt::DefaultRegistry &registry() { return m_registry; }
protected:
mutable entt::DefaultRegistry m_registry;
private:
SceneSerializer m_serializer{*this};
};
#endif // SCENE_HPP_

View File

@ -0,0 +1,51 @@
/*
* =====================================================================================
*
* OpenMiner
*
* Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
* Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
*
* This file is part of OpenMiner.
*
* OpenMiner is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* OpenMiner is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* =====================================================================================
*/
#include "AnimationComponent.hpp"
#include "ItemStack.hpp"
#include "Scene.hpp"
#include "SceneSerializer.hpp"
void SceneSerializer::serialize(sf::Packet &packet) const {
m_outputArchive.setPacket(packet);
m_scene.registry().snapshot().component<AnimationComponent, gk::DoubleBox, ItemStack, gk::Transformable>(m_outputArchive);
}
void SceneSerializer::deserialize(sf::Packet &packet) {
m_inputArchive.setPacket(packet);
m_scene.registry().restore().component<AnimationComponent, gk::DoubleBox, ItemStack, gk::Transformable>(m_inputArchive);
}
void SceneSerializer::OutputArchive::operator()(Entity entity) {
gkDebug() << entity;
(*m_packet) << entity;
}
void SceneSerializer::InputArchive::operator()(Entity &entity) {
(*m_packet) >> entity;
gkDebug() << entity;
}

View File

@ -0,0 +1,87 @@
/*
* =====================================================================================
*
* OpenMiner
*
* Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
* Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
*
* This file is part of OpenMiner.
*
* OpenMiner is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* OpenMiner is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* =====================================================================================
*/
#ifndef SCENESERIALIZER_HPP_
#define SCENESERIALIZER_HPP_
#include <gk/core/Debug.hpp>
#include <entt/entt.hpp>
#include "ISerializable.hpp"
#include "NetworkUtils.hpp"
class Scene;
class SceneSerializer : public ISerializable {
using Entity = entt::DefaultRegistry::entity_type;
public:
SceneSerializer(Scene &scene) : m_scene(scene) {}
void serialize(sf::Packet &packet) const;
void deserialize(sf::Packet &packet);
private:
class OutputArchive {
public:
void operator()(Entity entity);
template<typename T>
void operator()(Entity entity, const T &value) {
// gkDebug() << entity << value;
(*m_packet) << entity << value;
}
void setPacket(sf::Packet &packet) { m_packet = &packet; }
private:
sf::Packet *m_packet = nullptr;
};
class InputArchive {
public:
void operator()(Entity &entity);
template<typename T>
void operator()(Entity &entity, T &value) {
(*m_packet) >> entity >> value;
// gkDebug() << entity << value;
}
void setPacket(sf::Packet &packet) { m_packet = &packet; }
private:
sf::Packet *m_packet = nullptr;
};
Scene &m_scene;
mutable OutputArchive m_outputArchive;
mutable InputArchive m_inputArchive;
};
#endif // SCENESERIALIZER_HPP_

View File

@ -66,6 +66,7 @@ target_link_libraries(${PROJECT_NAME}_lib sfml-system sfml-network)
target_link_libraries(${PROJECT_NAME}
${PROJECT_NAME}_lib
${CMAKE_PROJECT_NAME}_common
${GAMEKIT_LIBRARIES}
${OPENGL_LIBRARIES}
${SDL2_LIBRARIES}
@ -77,6 +78,5 @@ target_link_libraries(${PROJECT_NAME}
${LUA_LIBRARIES}
sfml-system
sfml-network
${UNIX_LIBS}
${CMAKE_PROJECT_NAME}_common)
${UNIX_LIBS})