/** * Check and update town and house values. * * Checked are the HouseIDs. Updated are the * town population the number of houses per * town, the town radius and the max passengers * of the town. */ void UpdateHousesAndTowns() { for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_id = GetCleanHouseType(t); if (!HouseSpec::Get(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) { /* The specs for this type of house are not available any more, so * replace it with the substitute original house type. */ house_id = _house_mngr.GetSubstituteID(house_id); SetHouseType(t, house_id); } } /* Check for cases when a NewGRF has set a wrong house substitute type. */ for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_type = GetCleanHouseType(t); TileIndex north_tile = t + GetHouseNorthPart(house_type); // modifies 'house_type'! if (t == north_tile) { const HouseSpec *hs = HouseSpec::Get(house_type); bool valid_house = true; if (hs->building_flags & TILE_SIZE_2x1) { TileIndex tile = t + TileDiffXY(1, 0); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; } else if (hs->building_flags & TILE_SIZE_1x2) { TileIndex tile = t + TileDiffXY(0, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; } else if (hs->building_flags & TILE_SIZE_2x2) { TileIndex tile = t + TileDiffXY(0, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; tile = t + TileDiffXY(1, 0); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 2) valid_house = false; tile = t + TileDiffXY(1, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 3) valid_house = false; } /* If not all tiles of this house are present remove the house. * The other tiles will get removed later in this loop because * their north tile is not the correct type anymore. */ if (!valid_house) DoClearSquare(t); } else if (!IsTileType(north_tile, MP_HOUSE) || GetCleanHouseType(north_tile) != house_type) { /* This tile should be part of a multi-tile building but the * north tile of this house isn't on the map. */ DoClearSquare(t); } } RebuildTownCaches(); }
/** * Check the validity of some of the caches. * Especially in the sense of desyncs between * the cached value and what the value would * be when calculated from the 'base' data. */ static void CheckCaches() { /* Return here so it is easy to add checks that are run * always to aid testing of caches. */ if (_debug_desync_level <= 1) return; /* Check the town caches. */ SmallVector<TownCache, 4> old_town_caches; Town *t; FOR_ALL_TOWNS(t) { MemCpyT(old_town_caches.Append(), &t->cache); } extern void RebuildTownCaches(); RebuildTownCaches(); RebuildSubsidisedSourceAndDestinationCache(); uint i = 0; FOR_ALL_TOWNS(t) { if (MemCmpT(old_town_caches.Get(i), &t->cache) != 0) { DEBUG(desync, 2, "town cache mismatch: town %i", (int)t->index); } i++; } /* Check company infrastructure cache. */ SmallVector<CompanyInfrastructure, 4> old_infrastructure; Company *c; FOR_ALL_COMPANIES(c) MemCpyT(old_infrastructure.Append(), &c->infrastructure); extern void AfterLoadCompanyStats(); AfterLoadCompanyStats(); i = 0; FOR_ALL_COMPANIES(c) { if (MemCmpT(old_infrastructure.Get(i), &c->infrastructure) != 0) { DEBUG(desync, 2, "infrastructure cache mismatch: company %i", (int)c->index); } i++; } /* Strict checking of the road stop cache entries */ const RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { if (IsStandardRoadStopTile(rs->xy)) continue; assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); } Vehicle *v; FOR_ALL_VEHICLES(v) { extern void FillNewGRFVehicleCache(const Vehicle *v); if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; uint length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) length++; NewGRFCache *grf_cache = CallocT<NewGRFCache>(length); VehicleCache *veh_cache = CallocT<VehicleCache>(length); GroundVehicleCache *gro_cache = CallocT<GroundVehicleCache>(length); TrainCache *tra_cache = CallocT<TrainCache>(length); length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); grf_cache[length] = u->grf_cache; veh_cache[length] = u->vcache; switch (u->type) { case VEH_TRAIN: gro_cache[length] = Train::From(u)->gcache; tra_cache[length] = Train::From(u)->tcache; break; case VEH_ROAD: gro_cache[length] = RoadVehicle::From(u)->gcache; break; default: break; } length++; } switch (v->type) { case VEH_TRAIN: Train::From(v)->ConsistChanged(CCF_TRACK); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break; case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break; case VEH_SHIP: Ship::From(v)->UpdateCache(); break; default: break; } length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { DEBUG(desync, 2, "newgrf cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) { DEBUG(desync, 2, "vehicle cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } switch (u->type) { case VEH_TRAIN: if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "train ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { DEBUG(desync, 2, "train cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; case VEH_ROAD: if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "road vehicle ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; default: break; } length++; } free(grf_cache); free(veh_cache); free(gro_cache); free(tra_cache); } /* Check whether the caches are still valid */ FOR_ALL_VEHICLES(v) { byte buff[sizeof(VehicleCargoList)]; memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); v->cargo.InvalidateCache(); assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); } Station *st; FOR_ALL_STATIONS(st) { for (CargoID c = 0; c < NUM_CARGO; c++) { byte buff[sizeof(StationCargoList)]; memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); st->goods[c].cargo.InvalidateCache(); assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); } } }