#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.$input_map, 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); map_out = Map(save_data.map.input_map, save_data.map.walls, save_data.map.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"] }); }