From e0588847fa77e742de2e78c2366c1cd3d183c36f Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Sun, 22 Jun 2025 12:50:09 -0400 Subject: [PATCH] Tracked down the bug that was caused by picking up an item but not removing its Position in the world, so when you go to another level it gets brought back to life causing a dupe. --- dinkyecs.hpp | 17 ++++++++++++++--- gui/fsm.cpp | 7 ++++++- gui/guecstra.cpp | 3 +++ gui/loot_ui.cpp | 5 ++++- gui/status_ui.cpp | 11 +++++++++++ levelmanager.cpp | 10 ++++++++++ systems.cpp | 14 ++++++++++++++ 7 files changed, 62 insertions(+), 5 deletions(-) diff --git a/dinkyecs.hpp b/dinkyecs.hpp index f1bea64..34b4869 100644 --- a/dinkyecs.hpp +++ b/dinkyecs.hpp @@ -36,17 +36,22 @@ namespace DinkyECS std::unordered_map $facts; std::unordered_map $events; std::unordered_map $component_storages; - std::vector $constants; + std::unordered_map $constants; Entity entity() { return ++entity_count; } void clone_into(DinkyECS::World &to_world) { to_world.$constants = $constants; to_world.$facts = $facts; + // BUG*10: entity IDs should be a global counter, not per world to_world.entity_count = entity_count; to_world.$component_storages = $component_storages; - for(auto eid : $constants) { + for(auto [eid, is_set] : $constants) { + dbc::check(is_set == true, "is_set was not true? WHAT?!"); + dbc::check(eid <= entity_count, fmt::format( + "eid {} is not less than entity_count {}", eid, entity_count)); + for(const auto &[tid, eid_map] : $components) { auto &their_map = to_world.$components[tid]; if(eid_map.contains(eid)) { @@ -57,7 +62,13 @@ namespace DinkyECS } void make_constant(DinkyECS::Entity entity) { - $constants.push_back(entity); + fmt::println(">>> Entity {} is now constant", entity); + $constants.try_emplace(entity, true); + } + + void not_constant(DinkyECS::Entity entity) { + fmt::println("<<< Entity {} is NOT constant", entity); + $constants.erase(entity); } template diff --git a/gui/fsm.cpp b/gui/fsm.cpp index d02dbff..8567f81 100644 --- a/gui/fsm.cpp +++ b/gui/fsm.cpp @@ -454,7 +454,7 @@ namespace gui { break; case eGUI::AIM_CLICK: if(auto aimed_at = $main_ui.camera_aim()) { - dbc::log("clicked on a thing"); + fmt::println("clicked on a thing: {}", aimed_at); System::pickup($level, aimed_at); } else { dbc::log("there's no thing there!"); @@ -463,6 +463,7 @@ namespace gui { case eGUI::LOOT_ITEM: { dbc::check(world.has(entity), "INVALID LOOT_ITEM, that entity has no InventoryItem"); + fmt::println("in FSM LOOT_ITEM the entity is {}", entity); System::place_in_container(*$level.world, $temp_loot, "item_0", entity); $loot_ui.set_target($temp_loot); $loot_ui.update(); @@ -509,6 +510,10 @@ namespace gui { $levels.create_level($level.world); $level = $levels.next(); + // this has to go away, but clear out the inventory + $temp_loot = $level.world->entity(); + $level.world->set($temp_loot, {}); + $status_ui.update_level($level); $map_ui.update_level($level); $mini_map.update_level($level); diff --git a/gui/guecstra.cpp b/gui/guecstra.cpp index 4b5e106..7e7ecb8 100644 --- a/gui/guecstra.cpp +++ b/gui/guecstra.cpp @@ -16,12 +16,15 @@ namespace guecs { } DinkyECS::Entity GrabSource::grab() { + fmt::println("> Grab entity {}", world_entity); return world_entity; } void GrabSource::setSprite(guecs::UI& gui, guecs::Entity gui_id) { dbc::check(gui.has(gui_id), "GrabSource given sprite gui_id that doesn't exist"); + fmt::println("> Grabsource Set sprite entity {}", world_entity); + auto& sp = gui.get(gui_id); sprite = sp.sprite; } diff --git a/gui/loot_ui.cpp b/gui/loot_ui.cpp index 47644cd..d8b19b8 100644 --- a/gui/loot_ui.cpp +++ b/gui/loot_ui.cpp @@ -94,13 +94,16 @@ namespace gui { } } - void LootUI::remove_slot(DinkyECS::Entity slot_id) { + void LootUI::remove_slot(guecs::Entity slot_id) { auto& name = $slot_to_name.at(slot_id); + fmt::println("LootUI remove slot inv::Model id={} slot={}", $target, name); System::remove_from_container(*$level.world, $target, name); update(); } bool LootUI::place_slot(guecs::Entity id, DinkyECS::Entity world_entity) { + fmt::println("LootUI target={} placing world entity {} in slot id {}", + $target, id, world_entity); auto& name = $slot_to_name.at(id); bool worked = System::place_in_container(*$level.world, $target, name, world_entity); if(worked) update(); diff --git a/gui/status_ui.cpp b/gui/status_ui.cpp index ce998c9..b75bced 100644 --- a/gui/status_ui.cpp +++ b/gui/status_ui.cpp @@ -102,6 +102,16 @@ namespace gui { bool StatusUI::place_slot(guecs::Entity gui_id, DinkyECS::Entity world_entity) { auto& slot_name = $slot_to_name.at(gui_id); auto& inventory = $level.world->get_the(); + + for(auto [ent, slot] : inventory.by_entity) { + fmt::println("BY_ENTITY: ent={}, slot={}", ent, slot); + } + + for(auto [slot, ent] : inventory.by_slot) { + fmt::println("BY_SLOT: ent={}, slot={}", ent, slot); + } + + $level.world->make_constant(world_entity); inventory.add(slot_name, world_entity); update(); return true; @@ -109,6 +119,7 @@ namespace gui { bool StatusUI::drop_item(DinkyECS::Entity item_id) { bool dropped = System::drop_item($level, item_id); + $level.world->not_constant(item_id); if(dropped) update(); return dropped; } diff --git a/levelmanager.cpp b/levelmanager.cpp index 5039035..364fd14 100644 --- a/levelmanager.cpp +++ b/levelmanager.cpp @@ -27,7 +27,16 @@ inline shared_ptr clone_load_world(shared_ptr auto world = make_shared(); if(prev_world != nullptr) { + fmt::println("############### NEW WORLD #################"); prev_world->clone_into(*world); + + fmt::println("new world entity_count={}, prev={}", world->entity_count, prev_world->entity_count); + + for(auto [ent, is_set] : prev_world->$constants) { + if(world->has(ent)) { + fmt::println("#### Sprite {} copied to new world.", ent); + } + } } else { save::load_configs(*world); } @@ -83,6 +92,7 @@ DinkyECS::Entity LevelManager::spawn_enemy(std::string named) { size_t LevelManager::create_level(shared_ptr prev_world) { auto world = clone_load_world(prev_world); + auto scaling = scale_level(); auto map = make_shared(scaling.map_width, scaling.map_height); diff --git a/systems.cpp b/systems.cpp index 09067cb..6419271 100644 --- a/systems.cpp +++ b/systems.cpp @@ -102,6 +102,8 @@ void System::enemy_pathing(GameLevel &level) { } void System::init_positions(World &world, SpatialMap &collider) { + auto& inv = world.get_the(); + world.query([&](auto ent, auto &pos) { if(world.has(ent)) { const auto& combat = world.get(ent); @@ -109,6 +111,10 @@ void System::init_positions(World &world, SpatialMap &collider) { collider.insert(pos.location, ent); } } else { + fmt::println("System::init_positions for ent={}", ent); + dbc::check(!inv.has(ent), + fmt::format("!!! Entity {} is in player inventory and _also_ has a position in the world.", ent)); + collider.insert(pos.location, ent); } }); @@ -326,6 +332,9 @@ void System::pickup(GameLevel &level, Entity entity) { auto& item_pos = world.get(entity); level.collision->remove(item_pos.location); world.remove(entity); + // if you don't do this you get the bug that you can pickup + // an item and it'll also be in your inventory + world.remove(entity); if(world.has(entity)) { auto& pile = world.get(entity); @@ -499,16 +508,21 @@ bool System::drop_item(GameLevel& level, Entity item) { return false; } +// NOTE: I tink pickup and this need to be different bool System::place_in_container(World& world, Entity cont_id, const std::string& name, Entity world_entity) { auto& container = world.get(cont_id); if(container.has(world_entity)) { + fmt::println("container {} already has entity {}, skip", cont_id, world_entity); // NOTE: I think this would be a move?! return false; } else if(container.has(name)) { // this is an already occupied slot + fmt::println("container {} already has SLOT {}, skip", cont_id, name); return false; } else { + // this should only apply to the player's inventory + fmt::println("adding {} entity to loot with name {}", world_entity, name); container.add(name, world_entity); return true; }