Almost working save sytem but the data I store is totally wrong. I need to also save the entity IDs being used and map them to the components.
This commit is contained in:
parent
babc190525
commit
d113dba42f
15 changed files with 213 additions and 64 deletions
18
combat.cpp
18
combat.cpp
|
@ -1,14 +1,16 @@
|
|||
#include "combat.hpp"
|
||||
#include "rand.hpp"
|
||||
|
||||
int Combat::attack(Combat &target) {
|
||||
int attack = Random::uniform<int>(0,1);
|
||||
int my_dmg = 0;
|
||||
namespace components {
|
||||
int Combat::attack(Combat &target) {
|
||||
int attack = Random::uniform<int>(0,1);
|
||||
int my_dmg = 0;
|
||||
|
||||
if(attack) {
|
||||
my_dmg = Random::uniform<int>(1, damage);
|
||||
target.hp -= my_dmg;
|
||||
if(attack) {
|
||||
my_dmg = Random::uniform<int>(1, damage);
|
||||
target.hp -= my_dmg;
|
||||
}
|
||||
|
||||
return my_dmg;
|
||||
}
|
||||
|
||||
return my_dmg;
|
||||
}
|
||||
|
|
16
combat.hpp
16
combat.hpp
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "components.hpp"
|
||||
namespace components {
|
||||
struct Combat {
|
||||
int hp;
|
||||
int damage;
|
||||
bool dead;
|
||||
|
||||
struct Combat {
|
||||
int hp;
|
||||
int damage;
|
||||
bool dead;
|
||||
|
||||
int attack(Combat &target);
|
||||
};
|
||||
int attack(Combat &target);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,27 +3,33 @@
|
|||
#include "map.hpp"
|
||||
#include "combat.hpp"
|
||||
#include <deque>
|
||||
#include "tser.hpp"
|
||||
|
||||
namespace Components {
|
||||
namespace components {
|
||||
struct Player {
|
||||
DinkyECS::Entity entity;
|
||||
DEFINE_SERIALIZABLE(Player, entity);
|
||||
};
|
||||
|
||||
struct Position {
|
||||
Point location;
|
||||
DEFINE_SERIALIZABLE(Position, location);
|
||||
};
|
||||
|
||||
struct Motion {
|
||||
int dx;
|
||||
int dy;
|
||||
DEFINE_SERIALIZABLE(Motion, dx, dy);
|
||||
};
|
||||
|
||||
struct Treasure {
|
||||
int amount;
|
||||
DEFINE_SERIALIZABLE(Treasure, amount);
|
||||
};
|
||||
|
||||
struct Tile {
|
||||
std::string chr = "!";
|
||||
DEFINE_SERIALIZABLE(Tile, chr);
|
||||
};
|
||||
|
||||
struct MapConfig {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <any>
|
||||
#include <tuple>
|
||||
#include <queue>
|
||||
#include "tser.hpp"
|
||||
|
||||
namespace DinkyECS {
|
||||
|
||||
|
@ -116,4 +117,6 @@ namespace DinkyECS {
|
|||
return !queue.empty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
|
11
gui.cpp
11
gui.cpp
|
@ -24,7 +24,7 @@ using std::string;
|
|||
using namespace fmt;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace ftxui;
|
||||
using namespace Components;
|
||||
using namespace components;
|
||||
|
||||
|
||||
GUI::GUI(DinkyECS::World &world, Map& game_map) :
|
||||
|
@ -56,6 +56,13 @@ void GUI::resize_map(int new_size) {
|
|||
}
|
||||
}
|
||||
|
||||
void GUI::save_world() {
|
||||
tser::BinaryArchive archive;
|
||||
archive.save($world);
|
||||
std::string_view archive_view = archive.get_buffer();
|
||||
$log.log(format("Game saved! {} bytes.", archive_view.size()));
|
||||
}
|
||||
|
||||
void GUI::create_renderer() {
|
||||
Terminal::SetColorSupport(Terminal::Color::TrueColor);
|
||||
auto player = $world.get_the<Player>();
|
||||
|
@ -151,6 +158,8 @@ bool GUI::handle_ui_events() {
|
|||
resize_map(map_font_size + 10);
|
||||
} else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Hyphen)) {
|
||||
resize_map(map_font_size - 10);
|
||||
} else if(sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
|
||||
save_world();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
1
gui.hpp
1
gui.hpp
|
@ -58,6 +58,7 @@ public:
|
|||
void handle_world_events();
|
||||
void draw_screen(bool clear=true, float map_off_x=0.0f, float map_off_y=0.0f);
|
||||
void run_systems();
|
||||
void save_world();
|
||||
|
||||
int main();
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@ runtests = executable('runtests', [
|
|||
'collider.cpp',
|
||||
'ansi_parser.cpp',
|
||||
'config.cpp',
|
||||
'save.cpp',
|
||||
'tests/fsm.cpp',
|
||||
'tests/dbc.cpp',
|
||||
'tests/map.cpp',
|
||||
|
@ -29,6 +30,7 @@ runtests = executable('runtests', [
|
|||
'tests/dinkyecs.cpp',
|
||||
'tests/ansi_parser.cpp',
|
||||
'tests/config.cpp',
|
||||
'tests/save.cpp',
|
||||
],
|
||||
dependencies: dependencies)
|
||||
|
||||
|
@ -45,6 +47,7 @@ roguish = executable('roguish', [
|
|||
'ansi_parser.cpp',
|
||||
'render.cpp',
|
||||
'config.cpp',
|
||||
'save.cpp',
|
||||
],
|
||||
dependencies: dependencies)
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include "tser.hpp"
|
||||
|
||||
struct Point {
|
||||
size_t x = 0;
|
||||
|
@ -7,6 +8,8 @@ struct Point {
|
|||
bool operator==(const Point& other) const {
|
||||
return other.x == x && other.y == y;
|
||||
}
|
||||
|
||||
DEFINE_SERIALIZABLE(Point, x, y);
|
||||
};
|
||||
|
||||
typedef std::vector<Point> PointList;
|
||||
|
|
63
save.cpp
Normal file
63
save.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include "save.hpp"
|
||||
#include <fstream>
|
||||
#include "dbc.hpp"
|
||||
#include <fmt/core.h>
|
||||
|
||||
using namespace components;
|
||||
|
||||
|
||||
template<typename CompT>
|
||||
inline void extract(DinkyECS::World &world, std::vector<CompT> &into) {
|
||||
auto from_world = world.entity_map_for<CompT>();
|
||||
for(auto [entity, value] : from_world) {
|
||||
into.push_back(std::any_cast<CompT>(value));
|
||||
}
|
||||
}
|
||||
|
||||
void save::to_file(std::string path, DinkyECS::World &world) {
|
||||
SaveData save_data;
|
||||
tser::BinaryArchive archive;
|
||||
|
||||
save_data.player = world.get_the<Player>();
|
||||
extract<Position>(world, save_data.position);
|
||||
extract<Combat>(world, save_data.combat);
|
||||
extract<Motion>(world, save_data.motion);
|
||||
|
||||
archive.save(save_data);
|
||||
std::string_view archive_view = archive.get_buffer();
|
||||
|
||||
std::ofstream out(path, std::ios::binary);
|
||||
out << archive_view;
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
void save::from_file(std::string path, DinkyECS::World &world_out) {
|
||||
tser::BinaryArchive archive(0);
|
||||
|
||||
if(std::ifstream in_file{path, std::ios::binary | std::ios::ate}) {
|
||||
auto size = in_file.tellg();
|
||||
std::string in_data(size, '\0');
|
||||
in_file.seekg(0);
|
||||
|
||||
if(in_file.read(&in_data[0], size)) {
|
||||
std::string_view in_view(in_data);
|
||||
archive.initialize(in_view);
|
||||
} else {
|
||||
dbc::sentinel(fmt::format("wrong size or error reading {}", path));
|
||||
}
|
||||
} else {
|
||||
dbc::sentinel(fmt::format("failed to load file {}", path));
|
||||
}
|
||||
|
||||
auto save_data = archive.load<SaveData>();
|
||||
|
||||
// BUG: need the entities!
|
||||
world_out.set_the<Player>(save_data.player);
|
||||
|
||||
for(auto position : save_data.position) {
|
||||
auto entity = world_out.entity();
|
||||
// BUG: actually do need the entities
|
||||
world_out.set<Position>(entity, position);
|
||||
}
|
||||
}
|
21
save.hpp
Normal file
21
save.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "components.hpp"
|
||||
#include "dinkyecs.hpp"
|
||||
#include "tser.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace save {
|
||||
struct SaveData {
|
||||
components::Player player;
|
||||
std::vector<components::Position> position;
|
||||
std::vector<components::Motion> motion;
|
||||
std::vector<components::Combat> combat;
|
||||
|
||||
DEFINE_SERIALIZABLE(SaveData, player, position, motion, combat);
|
||||
};
|
||||
|
||||
void to_file(std::string path, DinkyECS::World &world);
|
||||
void from_file(std::string path, DinkyECS::World &world_out);
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
using std::string;
|
||||
using namespace fmt;
|
||||
using namespace Components;
|
||||
using namespace components;
|
||||
using ftxui::Color;
|
||||
|
||||
void System::enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "components.hpp"
|
||||
#include <ftxui/dom/canvas.hpp>
|
||||
|
||||
using namespace Components;
|
||||
using namespace components;
|
||||
|
||||
namespace System {
|
||||
void motion(DinkyECS::World &world, Map &game_map);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "dinkyecs.hpp"
|
||||
#include "components.hpp"
|
||||
|
||||
|
||||
using namespace fmt;
|
||||
using std::string;
|
||||
|
||||
|
@ -61,47 +62,3 @@ TEST_CASE("can go into a world", "[config]") {
|
|||
Config &cfg = world.get_the<Config>();
|
||||
REQUIRE(cfg["types"]["NUMBER"] == 1234);
|
||||
}
|
||||
|
||||
|
||||
#include <optional>
|
||||
#include <iostream>
|
||||
#include "tser.hpp"
|
||||
|
||||
enum class Item : char {
|
||||
RADAR = 'R',
|
||||
TRAP = 'T',
|
||||
ORE = 'O'
|
||||
};
|
||||
|
||||
struct Pixel {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
DEFINE_SERIALIZABLE(Pixel, x, y);
|
||||
};
|
||||
|
||||
struct Robot {
|
||||
Pixel point;
|
||||
std::wstring name;
|
||||
std::optional<Item> item;
|
||||
|
||||
DEFINE_SERIALIZABLE(Robot, point, name, item);
|
||||
};
|
||||
|
||||
TEST_CASE("test using tser for serialization", "[config]") {
|
||||
auto robot = Robot{ Pixel{3,4}, L"BIG NAME", Item::RADAR};
|
||||
std::cout << robot << '\n';
|
||||
|
||||
tser::BinaryArchive archive;
|
||||
archive.save(robot);
|
||||
std::string_view archive_view = archive.get_buffer();
|
||||
|
||||
tser::BinaryArchive archive2(0);
|
||||
archive2.initialize(archive_view);
|
||||
auto loadedRobot = archive2.load<Robot>();
|
||||
|
||||
REQUIRE(loadedRobot.point.x == robot.point.x);
|
||||
REQUIRE(loadedRobot.point.y == robot.point.y);
|
||||
REQUIRE(loadedRobot.name == robot.name);
|
||||
REQUIRE(loadedRobot.item == robot.item);
|
||||
}
|
||||
|
|
80
tests/save.cpp
Normal file
80
tests/save.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <fmt/core.h>
|
||||
#include <string>
|
||||
#include "dinkyecs.hpp"
|
||||
#include "components.hpp"
|
||||
#include "save.hpp"
|
||||
#include <optional>
|
||||
#include <iostream>
|
||||
#include "tser.hpp"
|
||||
|
||||
using namespace fmt;
|
||||
using std::string;
|
||||
using namespace components;
|
||||
|
||||
enum class Item : char {
|
||||
RADAR = 'R',
|
||||
TRAP = 'T',
|
||||
ORE = 'O'
|
||||
};
|
||||
|
||||
struct Pixel {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
DEFINE_SERIALIZABLE(Pixel, x, y);
|
||||
};
|
||||
|
||||
struct Robot {
|
||||
Pixel point;
|
||||
std::wstring name;
|
||||
std::optional<Item> item;
|
||||
|
||||
DEFINE_SERIALIZABLE(Robot, point, name, item);
|
||||
};
|
||||
|
||||
|
||||
TEST_CASE("test using tser for serialization", "[config]") {
|
||||
auto robot = Robot{ Pixel{3,4}, L"BIG NAME", Item::RADAR};
|
||||
std::cout << robot << '\n';
|
||||
|
||||
tser::BinaryArchive archive;
|
||||
archive.save(robot);
|
||||
std::string_view archive_view = archive.get_buffer();
|
||||
|
||||
tser::BinaryArchive archive2(0);
|
||||
archive2.initialize(archive_view);
|
||||
auto loadedRobot = archive2.load<Robot>();
|
||||
|
||||
REQUIRE(loadedRobot.point.x == robot.point.x);
|
||||
REQUIRE(loadedRobot.point.y == robot.point.y);
|
||||
REQUIRE(loadedRobot.name == robot.name);
|
||||
REQUIRE(loadedRobot.item == robot.item);
|
||||
}
|
||||
|
||||
TEST_CASE("basic save a world", "[save]") {
|
||||
DinkyECS::World world;
|
||||
|
||||
// configure a player as a fact of the world
|
||||
Player player{world.entity()};
|
||||
world.set_the<Player>(player);
|
||||
|
||||
world.set<Position>(player.entity, {10,10});
|
||||
world.set<Motion>(player.entity, {0, 0});
|
||||
world.set<Combat>(player.entity, {100, 10});
|
||||
|
||||
save::to_file("./savetest.world", world);
|
||||
|
||||
DinkyECS::World in_world;
|
||||
save::from_file("./savetest.world", in_world);
|
||||
|
||||
Position &position1 = world.get<Position>(player.entity);
|
||||
Position &position2 = in_world.get<Position>(player.entity);
|
||||
|
||||
// BUGGGGGGGG! This doesn't actually work, it's all fake
|
||||
// The world uses an internal id to increment entities so
|
||||
// by default player gets the first one, but all data after
|
||||
// that is wrong.
|
||||
REQUIRE(position1.location.x == position2.location.x);
|
||||
REQUIRE(position1.location.y == position2.location.y);
|
||||
}
|
1
tser.hpp
1
tser.hpp
|
@ -8,6 +8,7 @@
|
|||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <tuple>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
|
||||
namespace tser{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue