Skip to content

Commit 817863a

Browse files
authored
Merge pull request #5058 from myk002/myk_occupancy
[fix-occupancy] fix occupancy when a building exists but the tile doesn't know
2 parents 77da1d3 + 9a3c1a0 commit 817863a

2 files changed

Lines changed: 64 additions & 16 deletions

File tree

docs/changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Template for new versions:
7575
- `preserve-rooms`: automatically release room reservations for captured squad members. we were kidding ourselves with our optimistic kept reservations. they're unlikely to come back : ((
7676
- `buildingplan`: add value info to item selection dialog (effectively ungrouping items with different values) and add sorting by value
7777
- `timestream`: reduce CPU utilization
78+
- `fix/occupancy`: additionally handle the case where tile occupancy doesn't reflect the actual existence of a building
7879

7980
## Documentation
8081
- Dreamfort: add link to Dreamfort tutorial youtube series: https://www.youtube.com/playlist?list=PLzXx9JcB9oXxmrtkO1y8ZXzBCFEZrKxve

plugins/fix-occupancy.cpp

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,25 +40,28 @@ struct Expected {
4040
int32_t dim_x, dim_y, dim_z;
4141
size_t size;
4242
df::tile_occupancy * occ_buf;
43+
df::building ** bld_buf;
4344
std::unordered_map<df::map_block *, std::set<int32_t>> block_items_buf;
4445

4546
public:
4647
Expected() {
4748
Maps::getTileSize(dim_x, dim_y, dim_z);
4849
size = dim_x * dim_y * dim_z;
4950
occ_buf = (df::tile_occupancy *)calloc(size, sizeof(*occ_buf));
51+
bld_buf = (df::building **)calloc(size, sizeof(*bld_buf));
5052
}
5153

5254
~Expected() {
5355
free(occ_buf);
56+
free(bld_buf);
5457
}
5558

5659
size_t get_size() const {
5760
return size;
5861
}
5962

6063
df::tile_occupancy * occ(int32_t x, int32_t y, int32_t z) {
61-
size_t off = (dim_x * dim_y * z) + (dim_x * y) + x;
64+
size_t off = get_offset(x, y, z);
6265
if (off < size)
6366
return &occ_buf[off];
6467
return nullptr;
@@ -67,6 +70,16 @@ struct Expected {
6770
return occ(pos.x, pos.y, pos.z);
6871
}
6972

73+
df::building ** bld(int32_t x, int32_t y, int32_t z) {
74+
size_t off = get_offset(x, y, z);
75+
if (off < size)
76+
return &bld_buf[off];
77+
return nullptr;
78+
}
79+
df::building ** bld(const df::coord & pos) {
80+
return bld(pos.x, pos.y, pos.z);
81+
}
82+
7083
std::set<int32_t> * block_items(df::map_block * block) {
7184
if (!block)
7285
return nullptr;
@@ -78,13 +91,27 @@ struct Expected {
7891
std::set<int32_t> * block_items(const df::coord & pos) {
7992
return block_items(pos.x, pos.y, pos.z);
8093
}
94+
95+
private:
96+
size_t get_offset(int32_t x, int32_t y, int32_t z) {
97+
return (dim_x * dim_y * z) + (dim_x * y) + x;
98+
}
8199
};
82100

83-
static void scan_building(df::building * bld, Expected & expected) {
101+
static void scan_building(color_ostream &out, df::building * bld, Expected & expected) {
84102
for (int y = bld->y1; y <= bld->y2; ++y) {
85103
for (int x = bld->x1; x <= bld->x2; ++x) {
86104
if (!Buildings::containsTile(bld, df::coord2d(x, y)))
87105
continue;
106+
auto expected_bld = expected.bld(x, y, bld->z);
107+
if (bld->isSettingOccupancy() && expected_bld) {
108+
if (*expected_bld) {
109+
WARN(log,out).print("Buildings overlap at (%d, %d, %d); please manually remove overlapping building."
110+
" Run ':lua dfhack.gui.revealInDwarfmodeMap(%d, %d, %d, true, true)' to zoom to the tile.\n",
111+
x, y, bld->z, x, y, bld->z);
112+
}
113+
*expected_bld = bld;
114+
}
88115
if (auto expected_occ = expected.occ(x, y, bld->z)) {
89116
auto bld_occ = df::tile_building_occ::Impassable;
90117
if (auto block_occ = Maps::getTileOccupancy(x, y, bld->z))
@@ -142,8 +169,8 @@ static void normalize_item_vector(color_ostream &out, df::map_block *block, bool
142169
}
143170
}
144171

145-
static void reconcile_map_tile(color_ostream &out, const df::tile_occupancy & expected_occ, df::tile_occupancy & block_occ,
146-
bool dry_run, int x, int y, int z)
172+
static void reconcile_map_tile(color_ostream &out, df::building * bld, const df::tile_occupancy & expected_occ,
173+
df::tile_occupancy & block_occ, bool dry_run, int x, int y, int z)
147174
{
148175
// clear building occupancy if there is no building there
149176
if (expected_occ.bits.building == df::tile_building_occ::None && block_occ.bits.building != df::tile_building_occ::None) {
@@ -153,6 +180,21 @@ static void reconcile_map_tile(color_ostream &out, const df::tile_occupancy & ex
153180
block_occ.bits.building = df::tile_building_occ::None;
154181
}
155182

183+
// recalculate bulding occupancy if there *is* a building there
184+
if (bld) {
185+
auto prev_occ = block_occ.bits.building;
186+
bld->updateOccupancy(x, y);
187+
// if this resets the occupancy to Dynamic, trust the original value
188+
if (block_occ.bits.building == df::tile_building_occ::Dynamic)
189+
block_occ.bits.building = prev_occ;
190+
else if (prev_occ != block_occ.bits.building) {
191+
INFO(log,out).print("%s building occupancy at (%d, %d, %d)\n",
192+
dry_run ? "would fix" : "fixing", x, y, z);
193+
if (dry_run)
194+
block_occ.bits.building = prev_occ;
195+
}
196+
}
197+
156198
// clear unit occupancy if there are no units there
157199
if (!expected_occ.bits.unit && block_occ.bits.unit) {
158200
INFO(log,out).print("%s standing unit occupancy at (%d, %d, %d)\n",
@@ -186,11 +228,13 @@ static void fix_tile(color_ostream &out, df::coord pos, bool dry_run) {
186228

187229
Expected expected;
188230

189-
// building occupancy
231+
// building occupancy (scan all buildings since we can't depend on Buildings::findAtTile)
190232
size_t num_buildings = 0;
191-
if (auto bld = Buildings::findAtTile(pos)) {
192-
++num_buildings;
193-
scan_building(bld, expected);
233+
for (auto bld : world->buildings.all) {
234+
if (Buildings::containsTile(bld, pos)) {
235+
++num_buildings;
236+
scan_building(out, bld, expected);
237+
}
194238
}
195239

196240
// unit occupancy (make sure we pick up wagons that might be overlapping the tile)
@@ -214,8 +258,10 @@ static void fix_tile(color_ostream &out, df::coord pos, bool dry_run) {
214258
}
215259

216260
// check/fix occupancy
217-
if (auto expected_occ = expected.occ(pos))
218-
reconcile_map_tile(out, *expected_occ, block->occupancy[pos.x&15][pos.y&15], dry_run, pos.x, pos.y, pos.z);
261+
auto expected_occ = expected.occ(pos);
262+
auto expected_bld = expected.bld(pos);
263+
if (expected_bld && expected_occ)
264+
reconcile_map_tile(out, *expected_bld, *expected_occ, block->occupancy[pos.x&15][pos.y&15], dry_run, pos.x, pos.y, pos.z);
219265

220266
INFO(log,out).print("verified %zd building(s), %zd unit(s), %zd item(s), 1 map block(s), and 1 map tile(s)\n",
221267
num_buildings, num_units, num_items);
@@ -252,7 +298,7 @@ static void fix_map(color_ostream &out, bool dry_run) {
252298

253299
// set expected building occupancy
254300
for (auto bld : world->buildings.all)
255-
scan_building(bld, expected);
301+
scan_building(out, bld, expected);
256302

257303
// set expected unit occupancy
258304
for (auto unit : world->units.active)
@@ -275,15 +321,16 @@ static void fix_map(color_ostream &out, bool dry_run) {
275321
for (int xoff = 0; xoff < 16; ++xoff) {
276322
int x = block->map_pos.x + xoff;
277323
auto expected_occ = expected.occ(x, y, z);
278-
if (!expected_occ) {
324+
auto expected_bld = expected.bld(x, y, z);
325+
if (!expected_occ || !expected_bld) {
279326
TRACE(log,out).print("pos out of bounds (%d, %d, %d)\n", x, y, z);
280327
continue;
281328
}
282329
df::tile_occupancy &block_occ = block->occupancy[xoff][yoff];
283-
if ((expected_occ->whole & occ_mask) != (block_occ.whole & occ_mask)) {
284-
DEBUG(log,out).print("reconciling occupancy at (%d, %d, %d) (0x%x != 0x%x)\n",
285-
x, y, z, expected_occ->whole & occ_mask, block_occ.whole & occ_mask);
286-
reconcile_map_tile(out, *expected_occ, block_occ, dry_run, x, y, z);
330+
if (*expected_bld || (expected_occ->whole & occ_mask) != (block_occ.whole & occ_mask)) {
331+
DEBUG(log,out).print("reconciling occupancy at (%d, %d, %d) (bld=%p, 0x%x ?= 0x%x)\n",
332+
x, y, z, *expected_bld, expected_occ->whole & occ_mask, block_occ.whole & occ_mask);
333+
reconcile_map_tile(out, *expected_bld, *expected_occ, block_occ, dry_run, x, y, z);
287334
}
288335
}
289336
}

0 commit comments

Comments
 (0)