@@ -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
4546public:
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