From 8c68f54f50af134b82ce187d4ac88da84e9e7a2f Mon Sep 17 00:00:00 2001 From: 20k Date: Fri, 20 Jan 2023 18:02:55 +0000 Subject: [PATCH 1/7] update with squad removal support --- library/modules/Buildings.cpp | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 653f8bccf..d010210f5 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -82,6 +82,7 @@ using namespace DFHack; #include "df/map_block.h" #include "df/tile_occupancy.h" #include "df/plotinfost.h" +#include "df/squad.h" #include "df/ui_look_list.h" #include "df/unit.h" #include "df/unit_relationship_type.h" @@ -1348,6 +1349,43 @@ bool Buildings::constructWithFilters(df::building *bld, std::vectorgetType() != building_type::Civzone) + return; + + auto zone = strict_virtual_cast(bld); + + if (zone == nullptr) + return; + + for (df::building_civzonest::T_squad_room_info* room_info : zone->squad_room_info) + { + int32_t squad_id = room_info->squad_id; + + df::squad* squad = df::squad::find(squad_id); + + //if this is null, something has gone just *terribly* wrong + if (squad) + { + for (int i=0; i < squad->rooms.size(); i++) + { + if (squad->rooms[i]->building_id == bld->id) + { + auto room = squad->rooms[i]; + squad->rooms.erase(squad->rooms.begin() + i); + delete room; + i--; + } + } + } + + delete room_info; + } + + zone->squad_room_info.clear(); +} + bool Buildings::deconstruct(df::building *bld) { using df::global::plotinfo; @@ -1388,6 +1426,8 @@ bool Buildings::deconstruct(df::building *bld) remove_building_from_all_zones(bld); remove_zone_from_all_buildings(bld); + delete_civzone_squad_links(bld); + delete bld; if (world->selected_building == bld) From 1dbf01e5d19de1d5979574ca4b8a9ddee431dc9d Mon Sep 17 00:00:00 2001 From: 20k Date: Fri, 20 Jan 2023 18:30:38 +0000 Subject: [PATCH 2/7] Civzone interop style changes --- library/modules/Buildings.cpp | 58 ++++++++++------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index d010210f5..4ec9f9e12 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -169,34 +169,24 @@ void buildings_onUpdate(color_ostream &out) static void building_into_zone_unidir(df::building* bld, df::building_civzonest* zone) { - for (size_t bid = 0; bid < zone->contained_buildings.size(); bid++) + for (auto contained_building : zone->contained_buildings) { - if (zone->contained_buildings[bid] == bld) + if (contained_building == bld) return; } - zone->contained_buildings.push_back(bld); - - std::sort(zone->contained_buildings.begin(), zone->contained_buildings.end(), [](df::building* b1, df::building* b2) - { - return b1->id < b2->id; - }); + insert_into_vector(zone->contained_buildings, &df::building::id, bld); } static void zone_into_building_unidir(df::building* bld, df::building_civzonest* zone) { - for (size_t bid = 0; bid < bld->relations.size(); bid++) + for (auto relation : bld->relations) { - if (bld->relations[bid] == zone) + if (relation == zone) return; } - bld->relations.push_back(zone); - - std::sort(bld->relations.begin(), bld->relations.end(), [](df::building* b1, df::building* b2) - { - return b1->id < b2->id; - }); + insert_into_vector(bld->relations, &df::building::id, (df::building*)zone); } static bool is_suitable_building_for_zoning(df::building* bld) @@ -223,10 +213,8 @@ static void add_building_to_all_zones(df::building* bld) std::vector cv; Buildings::findCivzonesAt(&cv, coord); - for (size_t i=0; i < cv.size(); i++) - { - add_building_to_zone(bld, cv[i]); - } + for (auto zone : cv) + add_building_to_zone(bld, zone); } static void add_zone_to_all_buildings(df::building* zone_as_building) @@ -239,20 +227,16 @@ static void add_zone_to_all_buildings(df::building* zone_as_building) if (zone == nullptr) return; - auto& vec = world->buildings.other[buildings_other_id::IN_PLAY]; - - for (size_t i = 0; i < vec.size(); i++) + for (auto bld : world->buildings.other.IN_PLAY) { - auto against = vec[i]; - - if (zone->z != against->z) + if (zone->z != bld->z) continue; - if (!is_suitable_building_for_zoning(against)) + if (!is_suitable_building_for_zoning(bld)) continue; - int32_t cx = against->centerx; - int32_t cy = against->centery; + int32_t cx = bld->centerx; + int32_t cy = bld->centery; df::coord2d coord(cx, cy); @@ -263,7 +247,7 @@ static void add_zone_to_all_buildings(df::building* zone_as_building) if (!etile || !*etile) continue; - add_building_to_zone(against, zone); + add_building_to_zone(bld, zone); } } } @@ -296,10 +280,8 @@ static void remove_building_from_all_zones(df::building* bld) std::vector cv; Buildings::findCivzonesAt(&cv, coord); - for (size_t i=0; i < cv.size(); i++) - { - remove_building_from_zone(bld, cv[i]); - } + for (auto zone : cv) + remove_building_from_zone(bld, zone); } static void remove_zone_from_all_buildings(df::building* zone_as_building) @@ -312,16 +294,10 @@ static void remove_zone_from_all_buildings(df::building* zone_as_building) if (zone == nullptr) return; - auto& vec = world->buildings.other[buildings_other_id::IN_PLAY]; - //this is a paranoid check and slower than it could be. Zones contain a list of children //good for fixing potentially bad game states when deleting a zone - for (size_t i = 0; i < vec.size(); i++) - { - df::building* bld = vec[i]; - + for (auto bld : world->buildings.other.IN_PLAY) remove_building_from_zone(bld, zone); - } } uint32_t Buildings::getNumBuildings() From 3024c4a0dfdf3a281cf96d6576b33f44b1db23a7 Mon Sep 17 00:00:00 2001 From: 20k Date: Sat, 21 Jan 2023 18:43:45 +0000 Subject: [PATCH 3/7] update to remove ambiguity after structures change --- library/modules/Buildings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 4ec9f9e12..8f0c68eb2 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -186,7 +186,7 @@ static void zone_into_building_unidir(df::building* bld, df::building_civzonest* return; } - insert_into_vector(bld->relations, &df::building::id, (df::building*)zone); + insert_into_vector(bld->relations, &df::building_civzonest::id, zone); } static bool is_suitable_building_for_zoning(df::building* bld) From 9054efd7c8b9ecf487816c1d59de7b92293ee9e9 Mon Sep 17 00:00:00 2001 From: 20k Date: Sat, 21 Jan 2023 19:15:28 +0000 Subject: [PATCH 4/7] Update miscutils to support member pointer to a variable defined in the base when passing in a derived type --- library/include/MiscUtils.h | 8 ++++---- library/modules/Buildings.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 124987535..c9a5f66d6 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -167,8 +167,8 @@ int linear_index(const std::vector &vec, FT CT::*field, FT key) return -1; } -template -int binsearch_index(const std::vector &vec, FT CT::*field, FT key, bool exact = true) +template +int binsearch_index(const std::vector &vec, FT MT::*field, FT key, bool exact = true) { // Returns the index of the value >= the key int min = -1, max = (int)vec.size(); @@ -245,8 +245,8 @@ unsigned insert_into_vector(std::vector &vec, FT key, bool *inserted = NULL) return pos; } -template -unsigned insert_into_vector(std::vector &vec, FT CT::*field, CT *obj, bool *inserted = NULL) +template +unsigned insert_into_vector(std::vector &vec, FT MT::*field, CT *obj, bool *inserted = NULL) { unsigned pos = (unsigned)binsearch_index(vec, field, obj->*field, false); bool to_ins = (pos >= vec.size() || vec[pos] != obj); diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 8f0c68eb2..9d525d96b 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -186,7 +186,7 @@ static void zone_into_building_unidir(df::building* bld, df::building_civzonest* return; } - insert_into_vector(bld->relations, &df::building_civzonest::id, zone); + insert_into_vector(bld->relations, &df::building_civzonest::id, zone); } static bool is_suitable_building_for_zoning(df::building* bld) @@ -1344,7 +1344,7 @@ static void delete_civzone_squad_links(df::building* bld) //if this is null, something has gone just *terribly* wrong if (squad) { - for (int i=0; i < squad->rooms.size(); i++) + for (int i=0; i < (int)squad->rooms.size(); i++) { if (squad->rooms[i]->building_id == bld->id) { From c7ca9d0d7b7fd0c207467022cdaad106acf85ae7 Mon Sep 17 00:00:00 2001 From: 20k Date: Sun, 22 Jan 2023 13:56:33 +0000 Subject: [PATCH 5/7] reverse squad iteration delete --- library/modules/Buildings.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 9d525d96b..a17c79de2 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1344,14 +1344,13 @@ static void delete_civzone_squad_links(df::building* bld) //if this is null, something has gone just *terribly* wrong if (squad) { - for (int i=0; i < (int)squad->rooms.size(); i++) + for (int i=(int)squad->rooms.size() - 1; i >= 0; i--) { if (squad->rooms[i]->building_id == bld->id) { auto room = squad->rooms[i]; squad->rooms.erase(squad->rooms.begin() + i); delete room; - i--; } } } From b15fcc93d2247e144de6c51979d7bb9a92d7c2b3 Mon Sep 17 00:00:00 2001 From: 20k Date: Sun, 22 Jan 2023 14:53:56 +0000 Subject: [PATCH 6/7] remove assignments on zone destroy --- library/modules/Buildings.cpp | 46 ++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index a17c79de2..c4615c61a 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1325,16 +1325,8 @@ bool Buildings::constructWithFilters(df::building *bld, std::vectorgetType() != building_type::Civzone) - return; - - auto zone = strict_virtual_cast(bld); - - if (zone == nullptr) - return; - for (df::building_civzonest::T_squad_room_info* room_info : zone->squad_room_info) { int32_t squad_id = room_info->squad_id; @@ -1346,7 +1338,7 @@ static void delete_civzone_squad_links(df::building* bld) { for (int i=(int)squad->rooms.size() - 1; i >= 0; i--) { - if (squad->rooms[i]->building_id == bld->id) + if (squad->rooms[i]->building_id == zone->id) { auto room = squad->rooms[i]; squad->rooms.erase(squad->rooms.begin() + i); @@ -1361,6 +1353,31 @@ static void delete_civzone_squad_links(df::building* bld) zone->squad_room_info.clear(); } +//unit owned_building pointers are known-bad as of 50.05 and dangle on zone delete +//do not use anything that touches anything other than the pointer value +//this means also that if dwarf fortress reuses a memory allocation, we will end up with duplicates +//this vector is also not sorted by id +static void delete_assigned_unit_links(df::building_civzonest* zone) +{ + if (zone->assigned_unit_id == -1) + return; + + df::unit* unit = zone->assigned_unit; + + for (int i=(int)unit->owned_buildings.size() - 1; i >= 0; i--) + { + if (unit->owned_buildings[i] == zone) + unit->owned_buildings.erase(unit->owned_buildings.begin() + i); + } +} + +static void on_civzone_delete(df::building_civzonest* civzone) +{ + remove_zone_from_all_buildings(civzone); + delete_civzone_squad_links(civzone); + delete_assigned_unit_links(civzone); +} + bool Buildings::deconstruct(df::building *bld) { using df::global::plotinfo; @@ -1399,9 +1416,14 @@ bool Buildings::deconstruct(df::building *bld) bld->uncategorize(); remove_building_from_all_zones(bld); - remove_zone_from_all_buildings(bld); - delete_civzone_squad_links(bld); + if (bld->getType() == df::building_type::Civzone) + { + auto zone = strict_virtual_cast(bld); + + if (zone) + on_civzone_delete(zone); + } delete bld; From 4559168005ccf7c496dbf8a5e982b802be551c64 Mon Sep 17 00:00:00 2001 From: 20k Date: Sun, 22 Jan 2023 22:56:51 +0000 Subject: [PATCH 7/7] update for multiple ownership --- library/modules/Buildings.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index c4615c61a..5077b5b52 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1357,17 +1357,20 @@ static void delete_civzone_squad_links(df::building_civzonest* zone) //do not use anything that touches anything other than the pointer value //this means also that if dwarf fortress reuses a memory allocation, we will end up with duplicates //this vector is also not sorted by id +//it also turns out that multiple units eg (solely?) spouses can point to one room static void delete_assigned_unit_links(df::building_civzonest* zone) { - if (zone->assigned_unit_id == -1) - return; - - df::unit* unit = zone->assigned_unit; + //not clear if this is always true + /*if (zone->assigned_unit_id == -1) + return;*/ - for (int i=(int)unit->owned_buildings.size() - 1; i >= 0; i--) + for (df::unit* unit : world->units.active) { - if (unit->owned_buildings[i] == zone) - unit->owned_buildings.erase(unit->owned_buildings.begin() + i); + for (int i=(int)unit->owned_buildings.size() - 1; i >= 0; i--) + { + if (unit->owned_buildings[i] == zone) + unit->owned_buildings.erase(unit->owned_buildings.begin() + i); + } } }