diff --git a/assets/devices.json b/assets/devices.json index 4356d7c..fd2bd1b 100644 --- a/assets/devices.json +++ b/assets/devices.json @@ -9,8 +9,8 @@ "inventory_count": 0, "randomized": false, "components": [ - {"type": "Tile", "config": {"chr": "\u2ac5"}}, - {"type": "Device", + {"_type": "Tile", "config": {"chr": "\u2ac5"}}, + {"_type": "Device", "config": {"test": true}, "events": ["Events::GUI::STAIRS_DOWN"] } ] @@ -24,8 +24,8 @@ "inventory_count": 0, "placement": "fixed", "components": [ - {"type": "Tile", "config": {"chr": "\u2259"}}, - {"type": "Device", + {"_type": "Tile", "config": {"chr": "\u2259"}}, + {"_type": "Device", "config": {"test": true}, "events": ["Events::GUI::STAIRS_UP"] } ] @@ -38,8 +38,8 @@ "description": "Spikes stab you from the floor.", "inventory_count": 0, "components": [ - {"type": "Tile", "config": {"chr": "\u1ac7"}}, - {"type": "Device", + {"_type": "Tile", "config": {"chr": "\u1ac7"}}, + {"_type": "Device", "config": {"test": true}, "events": ["Events::GUI::TRAP"] } ] diff --git a/assets/enemies.json b/assets/enemies.json index a5b8d88..5b8b71a 100644 --- a/assets/enemies.json +++ b/assets/enemies.json @@ -3,21 +3,21 @@ "foreground": [255, 200, 125], "background": [30, 20, 75], "components": [ - {"type": "Tile", "config": {"chr": "\ua66b"}}, - {"type": "Combat", "config": {"hp": 200, "damage": 15}}, - {"type": "Motion", "config": {"dx": 0, "dy": 0, "random": false}}, - {"type": "LightSource", "config": {"strength": 70, "radius": 2}}, - {"type": "EnemyConfig", "config": {"hearing_distance": 5}} + {"_type": "Tile", "config": {"chr": "\ua66b"}}, + {"_type": "Combat", "config": {"hp": 200, "damage": 15}}, + {"_type": "Motion", "config": {"dx": 0, "dy": 0, "random": false}}, + {"_type": "LightSource", "config": {"strength": 70, "radius": 2}}, + {"_type": "EnemyConfig", "config": {"hearing_distance": 5}} ] }, "EVIL_EYE": { "foreground": [75, 200, 125], "background": [30, 20, 75], "components": [ - {"type": "Tile", "config": {"chr": "\u08ac"}}, - {"type": "Combat", "config": {"hp": 100, "damage": 50}}, - {"type": "Motion", "config": {"dx": 0, "dy": 0, "random": false}}, - {"type": "EnemyConfig", "config": {"hearing_distance": 10}} + {"_type": "Tile", "config": {"chr": "\u08ac"}}, + {"_type": "Combat", "config": {"hp": 100, "damage": 50}}, + {"_type": "Motion", "config": {"dx": 0, "dy": 0, "random": false}}, + {"_type": "EnemyConfig", "config": {"hearing_distance": 10}} ] } } diff --git a/assets/items.json b/assets/items.json index 3580cd5..455f8b6 100644 --- a/assets/items.json +++ b/assets/items.json @@ -7,8 +7,8 @@ "description": "A torch that barely lights the way. You wonder if it'd be better to not see the person who murders you.", "inventory_count": 1, "components": [ - {"type": "LightSource", "config": {"strength": 70, "radius": 2.0}}, - {"type": "Tile", "config": {"chr": "\u0f08"}} + {"_type": "LightSource", "config": {"strength": 70, "radius": 2.0}}, + {"_type": "Tile", "config": {"chr": "\u0f08"}} ] }, "SWORD_RUSTY": { @@ -19,8 +19,8 @@ "description": "A sword left to rot in a deep hole where it acquired a patina of dirt and tetanus. You aren't sure if it's more deadly for you to hold it or for the people you stab with it.", "inventory_count": 1, "components": [ - {"type": "Weapon", "config": {"damage": 15}}, - {"type": "Tile", "config": {"chr": "\u1e37"}} + {"_type": "Weapon", "config": {"damage": 15}}, + {"_type": "Tile", "config": {"chr": "\u1e37"}} ] }, "SWORD_LIGHT_AND_FLAME": { @@ -31,9 +31,9 @@ "description": "A sword so powerful, a great man from the Land of The Rising Sun thrust it into the ocean of Nerf to chill its effects.", "inventory_count": 1, "components": [ - {"type": "LightSource", "config": {"strength": 70, "radius": 1.8}}, - {"type": "Tile", "config": {"chr": "\u0236"}}, - {"type": "Weapon", "config": {"damage": 30}} + {"_type": "LightSource", "config": {"strength": 70, "radius": 1.8}}, + {"_type": "Tile", "config": {"chr": "\u0236"}}, + {"_type": "Weapon", "config": {"damage": 30}} ] }, "CHEST_SMALL": { @@ -43,8 +43,8 @@ "background": [150, 100, 189], "description": "A small chest of gold. You wonder who would leave something like this around.", "components": [ - {"type": "Tile", "config": {"chr": "\uaaea"}}, - {"type": "Loot", "config": {"amount": 10}} + {"_type": "Tile", "config": {"chr": "\uaaea"}}, + {"_type": "Loot", "config": {"amount": 10}} ], "inventory_count": 1 }, @@ -56,8 +56,8 @@ "description": "A torch on a wall you can't pick up.", "inventory_count": 0, "components": [ - {"type": "Tile", "config": {"chr": "\u077e"}}, - {"type": "LightSource", "config": {"strength": 60, "radius": 1.8}} + {"_type": "Tile", "config": {"chr": "\u077e"}}, + {"_type": "LightSource", "config": {"strength": 60, "radius": 1.8}} ] }, "POTION_HEALING_SMALL": { @@ -68,8 +68,8 @@ "description": "A small healing potion.", "inventory_count": 1, "components": [ - {"type": "Tile", "config": {"chr": "\u03eb"}}, - {"type": "Curative", "config": {"hp": 20}} + {"_type": "Tile", "config": {"chr": "\u03eb"}}, + {"_type": "Curative", "config": {"hp": 20}} ] } } diff --git a/components.cpp b/components.cpp deleted file mode 100644 index 06b26d3..0000000 --- a/components.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "components.hpp" - -namespace components { - void configure(DinkyECS::World &world, DinkyECS::Entity entity, json& entity_data) { - for(auto &comp : entity_data["components"]) { - json& config = comp["config"]; - const string comp_type = comp["type"]; - - if(comp_type == "Weapon") { - world.set(entity, {config["damage"]}); - } else if(comp_type == "LightSource") { - world.set(entity, {config["strength"], config["radius"]}); - } else if(comp_type == "Loot") { - world.set(entity, {config["amount"]}); - } else if(comp_type == "Tile") { - world.set(entity, { - config["chr"], - entity_data["foreground"][0], - entity_data["foreground"][1], - entity_data["foreground"][2], - entity_data["background"][0], - entity_data["background"][1], - entity_data["background"][2]}); - - } else if(comp_type == "EnemyConfig") { - world.set(entity, {config["hearing_distance"]}); - } else if(comp_type == "Combat") { - world.set(entity, {config["hp"], config["damage"]}); - } else if(comp_type == "Curative") { - world.set(entity, {config["hp"]}); - } else if(comp_type == "Motion") { - world.set(entity, {config["dx"], config["dy"], config["random"]}); - } else if(comp_type == "Device") { - Device device{.config=config, .events={}}; - device.configure_events(comp["events"]); - world.set(entity, device); - } else { - dbc::sentinel(fmt::format("ITEM COMPONENT TYPE MISSING: {}", - std::string(comp_type))); - } - - // json config variable dies - } - } -} diff --git a/components.hpp b/components.hpp index 33ea39f..e54dde0 100644 --- a/components.hpp +++ b/components.hpp @@ -3,43 +3,38 @@ #include "devices.hpp" #include "combat.hpp" #include "inventory.hpp" -#include "tser.hpp" #include "config.hpp" 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; bool random=false; - DEFINE_SERIALIZABLE(Motion, dx, dy); }; struct Loot { int amount; - DEFINE_SERIALIZABLE(Loot, amount); }; struct Tile { std::string chr; + std::array foreground; + std::array background; uint8_t fg_h = 200; uint8_t fg_s = 20; uint8_t fg_v = 200; uint8_t bg_h = 100; uint8_t bg_s = 20; uint8_t bg_v = 0; - - DEFINE_SERIALIZABLE(Tile, chr); }; struct GameConfig { @@ -66,6 +61,13 @@ namespace components { struct Curative { int hp = 10; }; - - void configure(DinkyECS::World &world, DinkyECS::Entity entity, json& entity_data); } + +DINKY_HAS_COMPONENT(components::Loot, amount); +DINKY_HAS_COMPONENT(Point, x, y); +DINKY_HAS_COMPONENT(components::Position, location); +DINKY_HAS_COMPONENT(components::Weapon, damage); +DINKY_HAS_COMPONENT(components::Curative, hp); +DINKY_HAS_COMPONENT(components::EnemyConfig, hearing_distance); +DINKY_HAS_COMPONENT(components::Tile, chr, foreground, background); +DINKY_HAS_COMPONENT(components::Motion, dx, dy, random); diff --git a/dinkyecs.cpp b/dinkyecs.cpp index 0bfae37..9799203 100644 --- a/dinkyecs.cpp +++ b/dinkyecs.cpp @@ -1,10 +1,12 @@ #include "dinkyecs.hpp" +#include "dbc.hpp" +#include namespace DinkyECS { - void configure(World& world, const ComponentMap& component_map, Entity ent, json& data) { + void configure(const ComponentMap& component_map, World& world, Entity ent, json& data) { for (auto &i : data) { - assert(i.contains("_type") && i["_type"].is_string()); - assert(component_map.contains(i["_type"])); + dbc::check(i.contains("_type") && i["_type"].is_string(), fmt::format("component has no _type: {}", data.dump())); + dbc::check(component_map.contains(i["_type"]), fmt::format("component_map doesn't have type {}", std::string(i["_type"]))); component_map.at(i["_type"])(world, ent, i); } } diff --git a/dinkyecs.hpp b/dinkyecs.hpp index 18353d4..70d4b96 100644 --- a/dinkyecs.hpp +++ b/dinkyecs.hpp @@ -178,6 +178,6 @@ namespace DinkyECS { }; } - void configure(World& world, const ComponentMap& component_map, Entity ent, json& data); + void configure(const ComponentMap& component_map, World& world, Entity ent, json& data); } diff --git a/levelmanager.cpp b/levelmanager.cpp index 9cff359..f4d45b2 100644 --- a/levelmanager.cpp +++ b/levelmanager.cpp @@ -32,7 +32,7 @@ size_t LevelManager::create_level(shared_ptr prev_world) { auto scaling = scale_level(); auto map = make_shared(scaling.map_width, scaling.map_height); - WorldBuilder builder(*map); + WorldBuilder builder(*map, $components); builder.generate(*world); size_t index = $levels.size(); diff --git a/levelmanager.hpp b/levelmanager.hpp index f207d76..da5da91 100644 --- a/levelmanager.hpp +++ b/levelmanager.hpp @@ -24,6 +24,7 @@ struct LevelScaling { class LevelManager { public: + DinkyECS::ComponentMap $components; std::vector $levels; size_t $current_level = 0; diff --git a/map.hpp b/map.hpp index 0c69f0a..e835f8d 100644 --- a/map.hpp +++ b/map.hpp @@ -6,7 +6,6 @@ #include #include #include "point.hpp" -#include "tser.hpp" #include "lights.hpp" #include "pathing.hpp" #include "matrix.hpp" @@ -22,8 +21,6 @@ struct Room { size_t height = 0; Point entry{(size_t)-1, (size_t)-1}; Point exit{(size_t)-1, (size_t)-1}; - - DEFINE_SERIALIZABLE(Room, x, y, width, height); }; class Map { diff --git a/meson.build b/meson.build index a42c4cb..d5e3874 100644 --- a/meson.build +++ b/meson.build @@ -47,7 +47,6 @@ sources = [ 'ansi_parser.cpp', 'camera.cpp', 'combat.cpp', - 'components.cpp', 'config.cpp', 'dbc.cpp', 'devices.cpp', @@ -87,7 +86,6 @@ executable('runtests', sources + [ 'tests/pathing.cpp', 'tests/spatialmap.cpp', 'tests/tilemap.cpp', - 'tests/worldbuilder.cpp', ], override_options: exe_defaults, dependencies: dependencies + [catch2]) diff --git a/point.hpp b/point.hpp index 2409b43..8f8886b 100644 --- a/point.hpp +++ b/point.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include "tser.hpp" struct Point { size_t x = 0; @@ -9,8 +8,6 @@ struct Point { bool operator==(const Point& other) const { return other.x == x && other.y == y; } - - DEFINE_SERIALIZABLE(Point, x, y); }; typedef std::vector PointList; diff --git a/save.cpp b/save.cpp index 031c81b..43ef935 100644 --- a/save.cpp +++ b/save.cpp @@ -17,70 +17,16 @@ inline void extract(DinkyECS::World &world, std::map &i } 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(); - save_data.map = MapData{ - map.$width, map.$height, - map.$rooms, map.$walls}; - - // BUG: lights aren't saved/restored - extract(world, save_data.position); - extract(world, save_data.combat); - extract(world, save_data.motion); - extract(world, save_data.tile); - // extract(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(); + (void)path; + (void)world; + (void)map; } -template -inline void inject(DinkyECS::World &world, std::map &outof) { - for(auto [entity, value] : outof) { - world.set(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(); - - world_out.set_the(save_data.facts.player); - inject(world_out, save_data.position); - inject(world_out, save_data.combat); - inject(world_out, save_data.motion); - inject(world_out, save_data.tile); - // inject(world_out, save_data.inventory); - - size_t width = save_data.map.width; - size_t height = save_data.map.height; - - Pathing paths(width, height); - map_out = Map(save_data.map.walls, paths); - - save::load_configs(world_out); + (void)path; + (void)world_out; + (void)map_out; } void save::load_configs(DinkyECS::World &world) { diff --git a/save.hpp b/save.hpp index 7f3149a..a13558d 100644 --- a/save.hpp +++ b/save.hpp @@ -3,7 +3,6 @@ #include "components.hpp" #include "map.hpp" #include "dinkyecs.hpp" -#include "tser.hpp" #include #include #include @@ -16,14 +15,10 @@ namespace save { size_t height; std::vector rooms; Matrix walls; - - DEFINE_SERIALIZABLE(MapData, width, height, rooms, walls); }; struct Facts { components::Player player; - - DEFINE_SERIALIZABLE(Facts, player); }; struct SaveData { @@ -35,8 +30,6 @@ namespace save { std::map combat; std::map tile; // std::map inventory; - - DEFINE_SERIALIZABLE(SaveData, facts, map, position, motion, combat, tile); }; void to_file(fs::path path, DinkyECS::World &world, Map &map); diff --git a/tests/dinkyecs.cpp b/tests/dinkyecs.cpp index 847034c..a43dbc9 100644 --- a/tests/dinkyecs.cpp +++ b/tests/dinkyecs.cpp @@ -234,8 +234,8 @@ TEST_CASE("test serialization with nlohmann::json", "[ecs-serialize]") { DinkyECS::Entity ent1 = world.entity(); DinkyECS::Entity ent2 = world.entity(); - DinkyECS::configure(world, component_map, ent1, data); - DinkyECS::configure(world, component_map, ent2, data); + DinkyECS::configure(component_map, world, ent1, data); + DinkyECS::configure(component_map, world, ent2, data); world.query([&](const auto ent, auto &pos, auto &motion) { fmt::println("entity: {}; position={},{} and motion={},{} motion.random={}", diff --git a/tests/inventory.cpp b/tests/inventory.cpp index a054778..e4788dd 100644 --- a/tests/inventory.cpp +++ b/tests/inventory.cpp @@ -15,15 +15,18 @@ using std::string; using namespace components; -DinkyECS::Entity add_items(DinkyECS::World &world, GameConfig &config) { +DinkyECS::Entity add_items(DinkyECS::ComponentMap component_map, DinkyECS::World &world, GameConfig &config) { auto sword = world.entity(); json& item_data = config.items["SWORD_RUSTY"]; world.set(sword, {item_data["inventory_count"], item_data}); - components::configure(world, sword, item_data); + DinkyECS::configure(component_map, world, sword, item_data); return sword; } TEST_CASE("basic inventory test", "[inventory]") { + // BUG: rewrite this + REQUIRE(true == false); + /* DinkyECS::World world; save::load_configs(world); auto& config = world.get_the(); @@ -68,4 +71,5 @@ TEST_CASE("basic inventory test", "[inventory]") { inventory.erase_item(0); REQUIRE(inventory.count() == 0); + */ } diff --git a/tests/lighting.cpp b/tests/lighting.cpp index 92b32b5..da0e833 100644 --- a/tests/lighting.cpp +++ b/tests/lighting.cpp @@ -3,16 +3,17 @@ #include #include #include "map.hpp" -#include "worldbuilder.hpp" +#include "levelmanager.hpp" #include "lights.hpp" #include "point.hpp" using namespace lighting; TEST_CASE("lighting a map works", "[lighting]") { - Map map(20,23); - WorldBuilder builder(map); - builder.generate_map(); + LevelManager levels; + GameLevel level = levels.current(); + auto &map = *level.map; + Point light1, light2; REQUIRE(map.place_entity(0, light1)); diff --git a/tests/map.cpp b/tests/map.cpp index 1dfba9e..6102930 100644 --- a/tests/map.cpp +++ b/tests/map.cpp @@ -3,7 +3,7 @@ #include #include #include "map.hpp" -#include "worldbuilder.hpp" +#include "levelmanager.hpp" using namespace fmt; using namespace nlohmann; @@ -15,9 +15,9 @@ json load_test_data(const string &fname) { } TEST_CASE("camera control", "[map]") { - Map map(20, 20); - WorldBuilder builder(map); - builder.generate_map(); + LevelManager levels; + GameLevel level = levels.current(); + auto &map = *level.map; Point center = map.center_camera({10,10}, 5, 5); @@ -32,11 +32,10 @@ TEST_CASE("camera control", "[map]") { TEST_CASE("map placement test", "[map:placement]") { for(int i = 0; i < 50; i++) { - size_t width = Random::uniform(9, 21); - size_t height = Random::uniform(13, 25); - Map map(width, height); - WorldBuilder builder(map); - builder.generate_rooms(); + LevelManager levels; + GameLevel level = levels.current(); + auto &map = *level.map; + map.invert_space(); for(size_t rnum = 0; rnum < map.room_count(); rnum++) { diff --git a/tests/matrix.cpp b/tests/matrix.cpp index b28bdd5..5e33864 100644 --- a/tests/matrix.cpp +++ b/tests/matrix.cpp @@ -4,7 +4,7 @@ #include "config.hpp" #include "matrix.hpp" #include "rand.hpp" -#include "worldbuilder.hpp" +#include "levelmanager.hpp" #include #include @@ -13,6 +13,12 @@ using namespace fmt; using std::string; using matrix::Matrix; +shared_ptr make_map() { + LevelManager levels; + GameLevel level = levels.current(); + return level.map; +} + TEST_CASE("basic matrix iterator", "[matrix:basic]") { std::ifstream infile("./tests/dijkstra.json"); json data = json::parse(infile); @@ -252,20 +258,18 @@ TEST_CASE("prototype circle algorithm", "[matrix:circle]") { TEST_CASE("viewport iterator", "[matrix:viewport]") { size_t width = Random::uniform(20, 22); size_t height = Random::uniform(21, 25); - Map map(width,height); - WorldBuilder builder(map); - builder.generate_map(); + shared_ptr map = make_map(); size_t view_width = width/2; size_t view_height = height/2; Point player; - REQUIRE(map.place_entity(1, player)); - Point start = map.center_camera(player, view_width, view_height); + REQUIRE(map->place_entity(1, player)); + Point start = map->center_camera(player, view_width, view_height); - size_t end_x = std::min(view_width, map.width() - start.x); - size_t end_y = std::min(view_height, map.height() - start.y); + size_t end_x = std::min(view_width, map->width() - start.x); + size_t end_y = std::min(view_height, map->height() - start.y); - matrix::viewport it{map.walls(), start, int(view_width), int(view_height)}; + matrix::viewport it{map->walls(), start, int(view_width), int(view_height)}; for(size_t y = 0; y < end_y; ++y) { for(size_t x = 0; x < end_x && it.next(); ++x) { @@ -276,25 +280,21 @@ TEST_CASE("viewport iterator", "[matrix:viewport]") { TEST_CASE("random rectangle", "[matrix:rando_rect]") { for(int i = 0; i < 10; i++) { - size_t width = Random::uniform(9, 21); - size_t height = Random::uniform(13, 25); - Map map(width, height); - WorldBuilder builder(map); - builder.generate_rooms(); - map.invert_space(); - auto wall_copy = map.walls(); - - for(size_t rnum = 0; rnum < map.room_count(); rnum++) { - Room &room = map.room(rnum); + shared_ptr map = make_map(); + map->invert_space(); + auto wall_copy = map->walls(); + + for(size_t rnum = 0; rnum < map->room_count(); rnum++) { + Room &room = map->room(rnum); Point pos; - for(matrix::rando_rect it{map.walls(), room.x, room.y, room.width, room.height}; it.next();) + for(matrix::rando_rect it{map->walls(), room.x, room.y, room.width, room.height}; it.next();) { - if(map.iswall(it.x, it.y)) { - matrix::dump("BAD RECTANGLE SPOT", map.walls(), it.x, it.y); + if(map->iswall(it.x, it.y)) { + matrix::dump("BAD RECTANGLE SPOT", map->walls(), it.x, it.y); } - REQUIRE(!map.iswall(it.x, it.y)); + REQUIRE(!map->iswall(it.x, it.y)); REQUIRE(size_t(it.x) >= room.x); REQUIRE(size_t(it.y) >= room.y); REQUIRE(size_t(it.x) <= room.x + room.width); @@ -310,25 +310,21 @@ TEST_CASE("random rectangle", "[matrix:rando_rect]") { TEST_CASE("standard rectangle", "[matrix:rectangle]") { for(int i = 0; i < 20; i++) { - size_t width = Random::uniform(9, 21); - size_t height = Random::uniform(13, 25); - Map map(width, height); - WorldBuilder builder(map); - builder.generate_rooms(); - map.invert_space(); - auto wall_copy = map.walls(); - - for(size_t rnum = 0; rnum < map.room_count(); rnum++) { - Room &room = map.room(rnum); + shared_ptr map = make_map(); + map->invert_space(); + auto wall_copy = map->walls(); + + for(size_t rnum = 0; rnum < map->room_count(); rnum++) { + Room &room = map->room(rnum); Point pos; - for(matrix::rectangle it{map.walls(), room.x, room.y, room.width, room.height}; it.next();) + for(matrix::rectangle it{map->walls(), room.x, room.y, room.width, room.height}; it.next();) { - if(map.iswall(it.x, it.y)) { - matrix::dump("BAD RECTANGLE SPOT", map.walls(), it.x, it.y); + if(map->iswall(it.x, it.y)) { + matrix::dump("BAD RECTANGLE SPOT", map->walls(), it.x, it.y); } - REQUIRE(!map.iswall(it.x, it.y)); + REQUIRE(!map->iswall(it.x, it.y)); REQUIRE(size_t(it.x) >= room.x); REQUIRE(size_t(it.y) >= room.y); REQUIRE(size_t(it.x) <= room.x + room.width); diff --git a/tests/save.cpp b/tests/save.cpp index c70d6dd..b887106 100644 --- a/tests/save.cpp +++ b/tests/save.cpp @@ -14,47 +14,8 @@ 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; - - 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}; - - 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(); - - 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; Map map(20, 20); WorldBuilder builder(map); @@ -100,4 +61,5 @@ TEST_CASE("basic save a world", "[save]") { Inventory &inv = world.get(player.entity); REQUIRE(inv.gold == 102); + */ } diff --git a/tests/tilemap.cpp b/tests/tilemap.cpp index bae4b20..4a82518 100644 --- a/tests/tilemap.cpp +++ b/tests/tilemap.cpp @@ -1,7 +1,7 @@ #include #include #include "map.hpp" -#include "worldbuilder.hpp" +#include "levelmanager.hpp" #include "tilemap.hpp" #include "config.hpp" #include "rand.hpp" @@ -10,12 +10,9 @@ using namespace fmt; using std::string; TEST_CASE("tilemap can load tiles and make a map", "[tilemap]") { - size_t width = Random::uniform(10, 25); - size_t height = Random::uniform(10, 33); - - Map map(width,height); - WorldBuilder builder(map); - builder.generate_map(); + LevelManager levels; + GameLevel level = levels.current(); + auto &map = *level.map; TileMap tiles(map.width(), map.height()); auto& walls = map.walls(); diff --git a/tests/worldbuilder.cpp b/tests/worldbuilder.cpp deleted file mode 100644 index ff97012..0000000 --- a/tests/worldbuilder.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include -#include -#include "map.hpp" -#include "worldbuilder.hpp" - -using namespace fmt; -using namespace nlohmann; -using std::string; - -TEST_CASE("bsp algo test", "[builder]") { - Map map(31, 20); - WorldBuilder builder(map); - builder.generate_map(); -} - -TEST_CASE("pathing", "[builder]") { - Map map(23, 14); - WorldBuilder builder(map); - builder.generate_map(); - - matrix::dump("WALLS", map.$walls, 0,0); - println("wall at 0,0=={}", map.$walls[0][0]); - - for(matrix::each_cell it{map.$walls}; it.next();) { - if(map.$walls[it.y][it.x] == WALL_VALUE) { - REQUIRE(map.iswall(it.x, it.y) == true); - REQUIRE(map.can_move({it.x, it.y}) == false); - } else { - REQUIRE(map.iswall(it.x, it.y) == false); - REQUIRE(map.can_move({it.x, it.y}) == true); - } - } -} diff --git a/tser.hpp b/tser.hpp deleted file mode 100644 index 0fe6972..0000000 --- a/tser.hpp +++ /dev/null @@ -1,220 +0,0 @@ -// Licensed under the Boost License . -// SPDX-License-Identifier: BSL-1.0 -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace tser{ - //implementation details for C++20 is_detected - namespace detail { - struct ns { - ~ns() = delete; - ns(ns const&) = delete; - }; - - template class Op, class... Args> - struct detector { - using value_t = std::false_type; - using type = Default; - }; - - template class Op, class... Args> - struct detector>, Op, Args...> { - using value_t = std::true_type; - using type = Op; - }; - - template - struct is_array : std::is_array {}; - - template class TArray, typename T, size_t N> - struct is_array> : std::true_type {}; - - constexpr size_t n_args(char const* c, size_t nargs = 1) { - for (; *c; ++c) if (*c == ',') ++nargs; - return nargs; - } - - constexpr size_t str_size(char const* c, size_t strSize = 1) { - for (; *c; ++c) ++strSize; - return strSize; - } - } - - // we need a bunch of template metaprogramming for being able to differentiate between different types - template class Op, class... Args> - constexpr bool is_detected_v = detail::detector::value_t::value; - - class BinaryArchive; - template using has_begin_t = decltype(*std::begin(std::declval())); - - template using has_members_t = decltype(std::declval().members()); - - template using has_smaller_t = decltype(std::declval() < std::declval()); - - template using has_equal_t = decltype(std::declval() == std::declval()); - - template using has_nequal_t = decltype(std::declval() != std::declval()); - - template using has_outstream_op_t = decltype(std::declval() << std::declval()); - - template using has_tuple_t = std::tuple_element_t<0, T>; - - template using has_optional_t = decltype(std::declval().has_value()); - - template using has_element_t = typename T::element_type; - - template using has_mapped_t = typename T::mapped_type; - - template using has_custom_save_t = decltype(std::declval().save(std::declval())); - - template using has_free_save_t = decltype(std::declval() << std::declval()); - - template constexpr bool is_container_v = is_detected_v; - - template constexpr bool is_tuple_v = is_detected_v; - - template constexpr bool is_tser_t_v = is_detected_v; - - template constexpr bool is_pointer_like_v = std::is_pointer_v || is_detected_v || is_detected_v; - - class BinaryArchive { - std::string m_bytes = std::string(1024, '\0'); - size_t m_bufferSize = 0, m_readOffset = 0; - - public: - explicit BinaryArchive(const size_t initialSize = 1024) : m_bytes(initialSize, '\0') {} - - template - explicit BinaryArchive(const T& t) { save(t); } - - template - void save(const T& t) { - if constexpr (is_detected_v) { - operator<<(t,*this); - } else if constexpr (is_detected_v) { - t.save(*this); - } else if constexpr(is_tser_t_v) { - std::apply([&](auto& ... mVal) { (save(mVal), ...); }, t.members()); - } else if constexpr(is_tuple_v) { - std::apply([&](auto& ... tVal) { (save(tVal), ...); }, t); - } else if constexpr (is_pointer_like_v) { - save(static_cast(t)); - if (t) - save(*t); - } else if constexpr (is_container_v) { - if constexpr (!detail::is_array::value) { - save(t.size()); - } - - for (auto& val : t) save(val); - } else { - if (m_bufferSize + sizeof(T) + sizeof(T) / 4 > m_bytes.size()) { - m_bytes.resize((m_bufferSize + sizeof(T)) * 2); - } - - std::memcpy(m_bytes.data() + m_bufferSize, std::addressof(t), sizeof(T)); - m_bufferSize += sizeof(T); - } - } - - template - void load(T& t) { - using V = std::decay_t; - if constexpr (is_detected_v) { - operator>>(t, *this); - } else if constexpr (is_detected_v) { - t.load(*this); - } else if constexpr (is_tser_t_v) { - std::apply([&](auto& ... mVal) { (load(mVal), ...); }, t.members()); - } else if constexpr (is_tuple_v) { - std::apply([&](auto& ... tVal) { (load(tVal), ...); }, t); - } else if constexpr (is_pointer_like_v) { - if constexpr (std::is_pointer_v) { - t = load() ? (t = new std::remove_pointer_t(), load(*t), t) : nullptr; - } else if constexpr (is_detected_v) { - t = load() ? T(load()) : T(); - } else { //smart pointer - t = T(load*>()); - } - } else if constexpr (is_container_v) { - if constexpr (!detail::is_array::value) { - const auto size = load(); - using VT = typename V::value_type; - for (size_t i = 0; i < size; ++i) { - if constexpr (!is_detected_v) { - t.insert(t.end(), load()); - } else { - //we have to special case map, because of the const key - t.emplace(VT{ load(), load() }); - } - } - } else { - for (auto& val : t) load(val); - } - } else { - std::memcpy(&t, m_bytes.data() + m_readOffset, sizeof(T)); - m_readOffset += sizeof(T); - } - } - - template - T load() { - std::remove_const_t t{}; load(t); return t; - } - - template - friend BinaryArchive& operator<<(BinaryArchive& ba, const T& t) { - ba.save(t); return ba; - } - - template - friend BinaryArchive& operator>>(BinaryArchive& ba, T& t) { - ba.load(t); return ba; - } - - void reset() { - m_bufferSize = 0; - m_readOffset = 0; - } - - void initialize(std::string_view str) { - m_bytes = str; - m_bufferSize = str.size(); - m_readOffset = 0; - } - - std::string_view get_buffer() const { - return std::string_view(m_bytes.data(), m_bufferSize); - } - - }; - - template - std::conditional_t, const Base, Base>& base(Derived* thisPtr) { return *thisPtr; } - - template - auto load(std::string_view encoded) { BinaryArchive ba(encoded); return ba.load(); } -} - -//this macro defines printing, serialisation and comparision operators (==,!=,<) for custom types -#define DEFINE_SERIALIZABLE(Type, ...) \ -inline decltype(auto) members() const { return std::tie(__VA_ARGS__); } \ -inline decltype(auto) members() { return std::tie(__VA_ARGS__); } \ -static constexpr std::array _memberNameData = [](){ \ -std::array chars{'\0'}; size_t _idx = 0; constexpr auto* ini(#__VA_ARGS__); \ -for (char const* _c = ini; *_c; ++_c, ++_idx) { if(*_c != ',' && *_c != ' ') chars[_idx] = *_c; } return chars;}(); \ -static constexpr const char* _typeName = #Type; \ -static constexpr std::array _memberNames = \ -[](){ std::array out{ }; \ -for(size_t _i = 0, nArgs = 0; nArgs < tser::detail::n_args(#__VA_ARGS__) ; ++_i) { \ -while(Type::_memberNameData[_i] == '\0') {_i++;} out[nArgs++] = &Type::_memberNameData[_i]; \ -while(Type::_memberNameData[++_i] != '\0'); } return out;}(); diff --git a/worldbuilder.cpp b/worldbuilder.cpp index a7a23b0..94d4e02 100644 --- a/worldbuilder.cpp +++ b/worldbuilder.cpp @@ -182,10 +182,10 @@ void WorldBuilder::generate_map() { } -DinkyECS::Entity configure_entity_in_map(DinkyECS::World &world, Map &game_map, json &entity_data, int in_room) { +DinkyECS::Entity WorldBuilder::configure_entity_in_map(DinkyECS::World &world, json &entity_data, int in_room) { auto item = world.entity(); Point pos_out; - bool placed = game_map.place_entity(in_room, pos_out); + bool placed = $map.place_entity(in_room, pos_out); dbc::check(placed, "failed to randomly place item in room"); world.set(item, {pos_out.x+1, pos_out.y+1}); @@ -194,7 +194,7 @@ DinkyECS::Entity configure_entity_in_map(DinkyECS::World &world, Map &game_map, } if(entity_data.contains("components")) { - components::configure(world, item, entity_data); + DinkyECS::configure($components, world, item, entity_data["components"]); } return item; } @@ -235,16 +235,16 @@ void WorldBuilder::randomize_entities(DinkyECS::World &world, GameConfig &config auto entity_data = entity_db[key]; // pass that to the config as it'll be a generic json - auto entity = configure_entity_in_map(world, $map, entity_data, room_num); + auto entity = configure_entity_in_map(world, entity_data, room_num); check_player(world, entity); } } -inline void place_stairs(DinkyECS::World& world, GameConfig& config, Map& map) { +void WorldBuilder::place_stairs(DinkyECS::World& world, GameConfig& config) { auto& device_config = config.devices.json(); auto entity_data = device_config["STAIRS_DOWN"]; - int last_room = map.room_count() - 1; - auto entity = configure_entity_in_map(world, map, entity_data, last_room); + int last_room = $map.room_count() - 1; + auto entity = configure_entity_in_map(world, entity_data, last_room); check_player(world, entity); } @@ -260,7 +260,7 @@ void WorldBuilder::place_entities(DinkyECS::World &world) { world.set(player.entity, {pos_out.x+1, pos_out.y+1}); } else { auto player_data = config.enemies["PLAYER_TILE"]; - auto player_ent = configure_entity_in_map(world, $map, player_data, 0); + auto player_ent = configure_entity_in_map(world, player_data, 0); // configure player in the world Player player{player_ent}; world.set_the(player); @@ -269,7 +269,7 @@ void WorldBuilder::place_entities(DinkyECS::World &world) { } randomize_entities(world, config); - place_stairs(world, config, $map); + place_stairs(world, config); } void WorldBuilder::generate(DinkyECS::World &world) { diff --git a/worldbuilder.hpp b/worldbuilder.hpp index dad04f6..ac7fbaa 100644 --- a/worldbuilder.hpp +++ b/worldbuilder.hpp @@ -7,8 +7,12 @@ class WorldBuilder { public: Map& $map; + DinkyECS::ComponentMap& $components; - WorldBuilder(Map &map) : $map(map) { } + WorldBuilder(Map &map, DinkyECS::ComponentMap& components) : + $map(map), + $components(components) + { } void partition_map(Room &cur, int depth); void make_room(size_t origin_y, size_t origin_x, size_t width, size_t height); @@ -20,8 +24,11 @@ class WorldBuilder { void stylize_room(int room, string tile_name, float size); void generate_rooms(); void generate_map(); + + DinkyECS::Entity configure_entity_in_map(DinkyECS::World &world, nlohmann::json &entity_data, int in_room); void place_entities(DinkyECS::World &world); void generate(DinkyECS::World &world); void random_entity(DinkyECS::World &world, components::GameConfig &config); void randomize_entities(DinkyECS::World &world, components::GameConfig &config); + void place_stairs(DinkyECS::World& world, components::GameConfig& config); };