diff options
author | clyne <clyne@bitgloo.com> | 2019-09-03 18:17:51 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-03 18:17:51 -0400 |
commit | ec1d57aeadbd0f34616eeec8f1a922ca61b90085 (patch) | |
tree | 9d2233f2437b8e85d151f9610b1a147310b9c13e /src | |
parent | 0b3d24c4295bb89eb4ce3f91163cabd64d0ca6e2 (diff) | |
parent | 95cc88ad5f6c2abb4890d00a57ae4ad0db030e9b (diff) |
Merge pull request #1 from tcsullivan/save-load
Save load looks good
Diffstat (limited to 'src')
-rw-r--r-- | src/components/Component.hpp | 16 | ||||
-rw-r--r-- | src/components/Light.hpp | 14 | ||||
-rw-r--r-- | src/components/Name.hpp | 14 | ||||
-rw-r--r-- | src/components/Player.hpp | 11 | ||||
-rw-r--r-- | src/components/Position.hpp | 14 | ||||
-rw-r--r-- | src/components/Render.hpp | 14 | ||||
-rw-r--r-- | src/components/Script.hpp | 9 | ||||
-rw-r--r-- | src/components/Velocity.hpp | 14 | ||||
-rw-r--r-- | src/engine.cpp | 11 | ||||
-rw-r--r-- | src/gamestate.hpp | 108 | ||||
-rw-r--r-- | src/script.cpp | 4 |
11 files changed, 220 insertions, 9 deletions
diff --git a/src/components/Component.hpp b/src/components/Component.hpp index 5a062bd..2928366 100644 --- a/src/components/Component.hpp +++ b/src/components/Component.hpp @@ -18,13 +18,27 @@ #ifndef COMPONENT_HPP_ #define COMPONENT_HPP_ +#include <cereal/cereal.hpp> +#include <cereal/archives/json.hpp> + +#include <entityx/entityx.h> #include <sol/sol.hpp> template<typename T> -class Component +class Component : public entityx::Component<T> { public: virtual T FromLua(sol::object) = 0; + + virtual void serialize(cereal::JSONOutputArchive& ar) = 0; + virtual void serialize(cereal::JSONInputArchive& ar) = 0; + + void internal_serialize(bool save, void *ar) final { + if (save) + serialize(*reinterpret_cast<cereal::JSONOutputArchive*>(ar)); + else + serialize(*reinterpret_cast<cereal::JSONInputArchive*>(ar)); + } }; #endif // COMPONENT_HPP_ diff --git a/src/components/Light.hpp b/src/components/Light.hpp index ee215a6..6849d7c 100644 --- a/src/components/Light.hpp +++ b/src/components/Light.hpp @@ -22,7 +22,7 @@ #include "Component.hpp" -struct Light : Component<Light>, entityx::Component<Light> +struct Light : Component<Light> { public: float r, g, b; @@ -49,6 +49,18 @@ public: } return *this; } + + void serialize(cereal::JSONOutputArchive& ar) final { + ar(CEREAL_NVP(r), CEREAL_NVP(g), CEREAL_NVP(b), CEREAL_NVP(strength)); + } + + void serialize(cereal::JSONInputArchive& ar) final { + ar(CEREAL_NVP(r), CEREAL_NVP(g), CEREAL_NVP(b), CEREAL_NVP(strength)); + } + + std::string serializeName(void) const final { + return "Light"; + } }; #endif//COMPONENT_LIGHT_HPP_ diff --git a/src/components/Name.hpp b/src/components/Name.hpp index 94b7531..a6a6d8a 100644 --- a/src/components/Name.hpp +++ b/src/components/Name.hpp @@ -21,7 +21,7 @@ #include "Component.hpp" #include <string> -struct Name : Component<Name>, entityx::Component<Name> +struct Name : Component<Name> { public: std::string name; @@ -38,6 +38,18 @@ public: return *this; } + + void serialize(cereal::JSONOutputArchive& ar) final { + ar(CEREAL_NVP(name)); + } + + void serialize(cereal::JSONInputArchive& ar) final { + ar(CEREAL_NVP(name)); + } + + std::string serializeName(void) const final { + return "Name"; + } }; #endif // COMPONENT_NAME_HPP_ diff --git a/src/components/Player.hpp b/src/components/Player.hpp index 5c1e870..33db1eb 100644 --- a/src/components/Player.hpp +++ b/src/components/Player.hpp @@ -23,13 +23,22 @@ #include "Component.hpp" -struct Player : Component<Player>, entityx::Component<Player> +struct Player : Component<Player> { public: + char _unused; + Player FromLua([[maybe_unused]] sol::object ref) { return *this; } + + void serialize([[maybe_unused]] cereal::JSONOutputArchive& ar) final {} + void serialize([[maybe_unused]] cereal::JSONInputArchive& ar) final {} + + std::string serializeName(void) const final { + return "Player"; + } }; #endif // COMPONENT_PLAYER_HPP_ diff --git a/src/components/Position.hpp b/src/components/Position.hpp index c801998..56e8707 100644 --- a/src/components/Position.hpp +++ b/src/components/Position.hpp @@ -21,7 +21,7 @@ #include "Component.hpp" -struct Position : Component<Position>, entityx::Component<Position> +struct Position : Component<Position> { public: double x, y; @@ -42,6 +42,18 @@ public: } return *this; } + + void serialize(cereal::JSONOutputArchive& ar) final { + ar(CEREAL_NVP(x), CEREAL_NVP(y)); + } + + void serialize(cereal::JSONInputArchive& ar) final { + ar(CEREAL_NVP(x), CEREAL_NVP(y)); + } + + std::string serializeName(void) const final { + return "Position"; + } }; #endif // COMPONENT_POSITION_HPP_ diff --git a/src/components/Render.hpp b/src/components/Render.hpp index 073cbdf..81ca591 100644 --- a/src/components/Render.hpp +++ b/src/components/Render.hpp @@ -21,7 +21,7 @@ #include "Component.hpp" #include "texture.hpp" -struct Render : Component<Render>, entityx::Component<Render> +struct Render : Component<Render> { public: Texture texture; @@ -53,6 +53,18 @@ public: } return *this; } + + void serialize(cereal::JSONOutputArchive& ar) final { + ar(CEREAL_NVP(visible), CEREAL_NVP(flipX)); + } + + void serialize(cereal::JSONInputArchive& ar) final { + ar(CEREAL_NVP(visible), CEREAL_NVP(flipX)); + } + + std::string serializeName(void) const final { + return "Render"; + } }; #endif // COMPONENT_RENDER_HPP_ diff --git a/src/components/Script.hpp b/src/components/Script.hpp index b3c89f3..f792750 100644 --- a/src/components/Script.hpp +++ b/src/components/Script.hpp @@ -21,7 +21,7 @@ #include "Component.hpp" -struct Scripted : Component<Scripted>, entityx::Component<Scripted> +struct Scripted : Component<Scripted> { public: sol::table caller; @@ -60,6 +60,13 @@ public: if (caller["RenderIdle"] == sol::type::function) caller["RenderIdle"](caller); } + + void serialize([[maybe_unused]] cereal::JSONOutputArchive& ar) final {} + void serialize([[maybe_unused]] cereal::JSONInputArchive& ar) final {} + + std::string serializeName(void) const final { + return "Scripted"; + } }; #endif // COMPONENT_SCRIPT_HPP_ diff --git a/src/components/Velocity.hpp b/src/components/Velocity.hpp index 29c0e5c..776c1dd 100644 --- a/src/components/Velocity.hpp +++ b/src/components/Velocity.hpp @@ -22,7 +22,7 @@ #include "Component.hpp" -struct Velocity : Component<Velocity>, entityx::Component<Velocity> +struct Velocity : Component<Velocity> { public: double x, y; @@ -43,6 +43,18 @@ public: } return *this; } + + void serialize(cereal::JSONOutputArchive& ar) final { + ar(CEREAL_NVP(x), CEREAL_NVP(y)); + } + + void serialize(cereal::JSONInputArchive& ar) final { + ar(CEREAL_NVP(x), CEREAL_NVP(y)); + } + + std::string serializeName(void) const final { + return "Velocity"; + } }; #endif // COMPONENT_VELOCITY_HPP_ diff --git a/src/engine.cpp b/src/engine.cpp index 61d119a..e959f21 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -20,6 +20,7 @@ */ #include "engine.hpp" +#include "gamestate.hpp" #include "gamerun.hpp" #include "input.hpp" #include "player.hpp" @@ -30,6 +31,8 @@ #include "components/Position.hpp" #include "components/Velocity.hpp" +#include <fstream> + using namespace std::chrono_literals; namespace cr = std::chrono; typedef std::chrono::high_resolution_clock mc; @@ -43,7 +46,12 @@ int Engine::init(void) systems.add<ScriptSystem>(); systems.configure(); + // Load game script and entity data systems.system<ScriptSystem>()->init(); + if (GameState::load("save.json", entities)) { + std::cout << "Loaded from save.json. Delete the file if you don't want " + "it." << std::endl; + } return 0; } @@ -116,6 +124,9 @@ void Engine::run(void) // Done, bring logic thread back logicThread.join(); + + // Save the entities' data + GameState::save("save.json", entities); } bool Engine::shouldRun(void) diff --git a/src/gamestate.hpp b/src/gamestate.hpp new file mode 100644 index 0000000..55f4e47 --- /dev/null +++ b/src/gamestate.hpp @@ -0,0 +1,108 @@ +/** + * @file gamestate.hpp + * Provides functionality to load and save entity data to or from JSON files. + * + * Copyright (C) 2019 Clyne Sullivan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GAMELOAD_HPP_ +#define GAMELOAD_HPP_ + +#include <cereal/cereal.hpp> +#include <cereal/archives/json.hpp> +#include <entityx/entityx.h> + +#include <fstream> + +/** + * @class GameState + * Manages save files that contain entity data. + */ +class GameState +{ +public: + /** + * Loads entity data from a JSON file into entities contained in the + * entity manager. + * + * The order of entities and the components they have must match between + * those in the manager and those in the file. + * + * @param file The file to load from + * @param entities The entity manager to load into + * @return True if successful load + */ + static bool load(const std::string& file, entityx::EntityManager &entities) + { + std::ifstream saveFile (file); + bool opened = saveFile.good(); + + if (opened) { + cereal::JSONInputArchive archive (saveFile); + serializeEntities(archive, false, entities); + } + + return opened; + } + + /** + * Saves entity data from the entities in the provided manager into a JSON + * file, + * + * @param file The file to load from + * @param entities The entity manager to get entity data from + * @return True if successful save + */ + static bool save(const std::string& file, entityx::EntityManager &entities) + { + std::ofstream saveFile (file); + bool opened = saveFile.good(); + + if (opened) { + cereal::JSONOutputArchive archive (saveFile); + serializeEntities(archive, true, entities); + } + + return opened; + } + +private: + /** + * Calls the serialization funciton for each entity in the given entity + * manager. + * @param archive The archive to save/load with (cereal::JSON...) + * @param save True to save data, false to load + * @param entities The entity manager to iterate through + */ + template<class Archive> + static void serializeEntities(Archive& archive, + bool save, + entityx::EntityManager& entities) + { + std::string name ("entity"); + int i = 0; + + for (auto entity : entities.entities_for_debugging()) { + archive.setNextName((name + std::to_string(i++)).c_str()); + archive.startNode(); + entities.entity_serialize(entity, save, archive); + archive.finishNode(); + } + } +}; + +#endif // GAMELOAD_HPP_ + diff --git a/src/script.cpp b/src/script.cpp index fa485bc..351aae4 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -57,7 +57,7 @@ void ScriptSystem::receive([[maybe_unused]] const EntitySpawnEvent &toSpawn) int ScriptSystem::init(void) { - lua.open_libraries(sol::lib::base, sol::lib::math); + lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string); scriptExport(); doFile(); @@ -176,6 +176,8 @@ sol::table ScriptSystem::spawn(sol::object param) } if (tab["Light"] != nullptr) { + if (!e.has_component<Position>()) // Position must exist for vel. + (*toRet)["Position"] = e.assign<Position>().get(); (*toRet)["Light"] = e.assign<Light>(Light().FromLua(tab["Light"])).get(); } |