The next little game in the series where I make a fancy rogue game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
roguish/save.cpp

101 lines
2.8 KiB

#include "save.hpp"
#include <fstream>
#include "dbc.hpp"
#include <fmt/core.h>
#include "config.hpp"
#include <filesystem>
using namespace components;
using namespace fmt;
template<typename CompT>
inline void extract(DinkyECS::World &world, std::map<DinkyECS::Entity, CompT> &into) {
auto from_world = world.entity_map_for<CompT>();
for(auto [entity, value] : from_world) {
into[entity] = std::any_cast<CompT>(value);
}
}
void save::to_file(fs::path path, DinkyECS::World &world, Map &map) {
SaveData save_data;
tser::BinaryArchive archive;
save_data.facts.player = world.get_the<Player>();
save_data.map = MapData{map.$rooms, map.$walls, map.$limit};
extract<Position>(world, save_data.position);
extract<Combat>(world, save_data.combat);
extract<Motion>(world, save_data.motion);
extract<Tile>(world, save_data.tile);
extract<Inventory>(world, save_data.inventory);
archive.save(save_data);
std::string_view archive_view = archive.get_buffer();
std::ofstream out(path, std::ios::binary);
out << archive_view;
out.flush();
}
template<typename CompT>
inline void inject(DinkyECS::World &world, std::map<DinkyECS::Entity, CompT> &outof) {
for(auto [entity, value] : outof) {
world.set<CompT>(entity, value);
}
}
void save::from_file(fs::path path, DinkyECS::World &world_out, Map &map_out) {
tser::BinaryArchive archive(0);
dbc::check(fs::exists(path), format("save file does not exist {}", path.string()));
auto size = fs::file_size(path);
if(std::ifstream in_file{path, std::ios::binary}) {
std::string in_data(size, '\0');
if(in_file.read(&in_data[0], size)) {
std::string_view in_view(in_data);
archive.initialize(in_view);
} else {
dbc::sentinel(format("wrong size or error reading {}", path.string()));
}
} else {
dbc::sentinel(format("failed to load file {}", path.string()));
}
auto save_data = archive.load<SaveData>();
world_out.set_the<Player>(save_data.facts.player);
inject<Position>(world_out, save_data.position);
inject<Combat>(world_out, save_data.combat);
inject<Motion>(world_out, save_data.motion);
inject<Tile>(world_out, save_data.tile);
inject<Inventory>(world_out, save_data.inventory);
size_t width = save_data.map.walls[0].size();
size_t height = save_data.map.walls.size();
int limit = save_data.map.limit;
Pathing paths(width, height, limit);
map_out = Map(save_data.map.walls, paths, limit);
save::load_configs(world_out);
}
void save::load_configs(DinkyECS::World &world) {
Config config("./assets/config.json");
world.set_the<Config>(config);
auto map = config["map"];
world.set_the<MapConfig>({
map["WALL_TILE"],
map["FLOOR_TILE"],
map["PLAYER_TILE"],
map["ENEMY_TILE"],
map["BG_TILE"]
});
auto enemy = config["enemy"];
world.set_the<EnemyConfig>({
enemy["HEARING_DISTANCE"]
});
}