diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 56cb816248..b3339bae04 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -77,6 +77,7 @@ add_files(
bridge_map.cpp
bridge_map.h
build_vehicle_gui.cpp
+ cachecheck.cpp
cargo_type.h
cargoaction.cpp
cargoaction.h
diff --git a/src/cachecheck.cpp b/src/cachecheck.cpp
new file mode 100644
index 0000000000..e1f600c174
--- /dev/null
+++ b/src/cachecheck.cpp
@@ -0,0 +1,225 @@
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file cachecheck.cpp Check caches. */
+
+#include "stdafx.h"
+#include "aircraft.h"
+#include "company_base.h"
+#include "debug.h"
+#include "industry.h"
+#include "roadstop_base.h"
+#include "roadveh.h"
+#include "ship.h"
+#include "station_base.h"
+#include "station_map.h"
+#include "subsidy_func.h"
+#include "town.h"
+#include "train.h"
+#include "vehicle_base.h"
+
+#include "safeguards.h"
+
+extern void AfterLoadCompanyStats();
+extern void 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.
+ */
+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. */
+ std::vector old_town_caches;
+ for (const Town *t : Town::Iterate()) {
+ old_town_caches.push_back(t->cache);
+ }
+
+ RebuildTownCaches();
+ RebuildSubsidisedSourceAndDestinationCache();
+
+ uint i = 0;
+ for (Town *t : Town::Iterate()) {
+ if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) {
+ Debug(desync, 2, "warning: town cache mismatch: town {}", t->index);
+ }
+ i++;
+ }
+
+ /* Check company infrastructure cache. */
+ std::vector old_infrastructure;
+ for (const Company *c : Company::Iterate()) old_infrastructure.push_back(c->infrastructure);
+
+ AfterLoadCompanyStats();
+
+ i = 0;
+ for (const Company *c : Company::Iterate()) {
+ if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) {
+ Debug(desync, 2, "warning: infrastructure cache mismatch: company {}", c->index);
+ }
+ i++;
+ }
+
+ /* Strict checking of the road stop cache entries */
+ for (const RoadStop *rs : RoadStop::Iterate()) {
+ if (IsBayRoadStopTile(rs->xy)) continue;
+
+ assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW));
+ rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs);
+ rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs);
+ }
+
+ for (Vehicle *v : Vehicle::Iterate()) {
+ if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue;
+
+ uint length = 0;
+ for (const Vehicle *u = v; u != nullptr; u = u->Next()) length++;
+
+ NewGRFCache *grf_cache = CallocT(length);
+ VehicleCache *veh_cache = CallocT(length);
+ GroundVehicleCache *gro_cache = CallocT(length);
+ TrainCache *tra_cache = CallocT(length);
+
+ length = 0;
+ for (const Vehicle *u = v; u != nullptr; 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 != nullptr; u = u->Next()) {
+ FillNewGRFVehicleCache(u);
+ if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) {
+ Debug(desync, 2, "warning: newgrf cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length);
+ }
+ if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) {
+ Debug(desync, 2, "warning: vehicle cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, 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, "warning: train ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
+ }
+ if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) {
+ Debug(desync, 2, "warning: train cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
+ }
+ break;
+ case VEH_ROAD:
+ if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) {
+ Debug(desync, 2, "warning: road vehicle ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, 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 (Vehicle *v : Vehicle::Iterate()) {
+ uint8_t buff[sizeof(VehicleCargoList)];
+ memcpy(buff, &v->cargo, sizeof(VehicleCargoList));
+ v->cargo.InvalidateCache();
+ assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0);
+ }
+
+ /* Backup stations_near */
+ std::vector old_town_stations_near;
+ for (Town *t : Town::Iterate()) old_town_stations_near.push_back(t->stations_near);
+
+ std::vector old_industry_stations_near;
+ for (Industry *ind : Industry::Iterate()) old_industry_stations_near.push_back(ind->stations_near);
+
+ std::vector old_station_industries_near;
+ for (Station *st : Station::Iterate()) old_station_industries_near.push_back(st->industries_near);
+
+ for (Station *st : Station::Iterate()) {
+ for (GoodsEntry &ge : st->goods) {
+ uint8_t buff[sizeof(StationCargoList)];
+ memcpy(buff, &ge.cargo, sizeof(StationCargoList));
+ ge.cargo.InvalidateCache();
+ assert(memcmp(&ge.cargo, buff, sizeof(StationCargoList)) == 0);
+ }
+
+ /* Check docking tiles */
+ TileArea ta;
+ std::map docking_tiles;
+ for (TileIndex tile : st->docking_station) {
+ ta.Add(tile);
+ docking_tiles[tile] = IsDockingTile(tile);
+ }
+ UpdateStationDockingTiles(st);
+ if (ta.tile != st->docking_station.tile || ta.w != st->docking_station.w || ta.h != st->docking_station.h) {
+ Debug(desync, 2, "warning: station docking mismatch: station {}, company {}", st->index, st->owner);
+ }
+ for (TileIndex tile : ta) {
+ if (docking_tiles[tile] != IsDockingTile(tile)) {
+ Debug(desync, 2, "warning: docking tile mismatch: tile {}", tile);
+ }
+ }
+ }
+
+ Station::RecomputeCatchmentForAll();
+
+ /* Check industries_near */
+ i = 0;
+ for (Station *st : Station::Iterate()) {
+ if (st->industries_near != old_station_industries_near[i]) {
+ Debug(desync, 2, "warning: station industries near mismatch: station {}", st->index);
+ }
+ i++;
+ }
+
+ /* Check stations_near */
+ i = 0;
+ for (Town *t : Town::Iterate()) {
+ if (t->stations_near != old_town_stations_near[i]) {
+ Debug(desync, 2, "warning: town stations near mismatch: town {}", t->index);
+ }
+ i++;
+ }
+ i = 0;
+ for (Industry *ind : Industry::Iterate()) {
+ if (ind->stations_near != old_industry_stations_near[i]) {
+ Debug(desync, 2, "warning: industry stations near mismatch: industry {}", ind->index);
+ }
+ i++;
+ }
+}
diff --git a/src/openttd.cpp b/src/openttd.cpp
index fc6e60c4b1..5b53be6dd6 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -95,10 +95,9 @@ void MusicLoop();
void CallWindowGameTickEvent();
bool HandleBootstrap();
-extern void AfterLoadCompanyStats();
+extern void CheckCaches();
extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY);
extern void OSOpenBrowser(const std::string &url);
-extern void RebuildTownCaches();
extern void ShowOSErrorBox(const char *buf, bool system);
extern std::string _config_file;
@@ -1224,202 +1223,6 @@ void SwitchToMode(SwitchMode new_mode)
}
-/**
- * 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. */
- std::vector old_town_caches;
- for (const Town *t : Town::Iterate()) {
- old_town_caches.push_back(t->cache);
- }
-
- RebuildTownCaches();
- RebuildSubsidisedSourceAndDestinationCache();
-
- uint i = 0;
- for (Town *t : Town::Iterate()) {
- if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) {
- Debug(desync, 2, "warning: town cache mismatch: town {}", t->index);
- }
- i++;
- }
-
- /* Check company infrastructure cache. */
- std::vector old_infrastructure;
- for (const Company *c : Company::Iterate()) old_infrastructure.push_back(c->infrastructure);
-
- AfterLoadCompanyStats();
-
- i = 0;
- for (const Company *c : Company::Iterate()) {
- if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) {
- Debug(desync, 2, "warning: infrastructure cache mismatch: company {}", c->index);
- }
- i++;
- }
-
- /* Strict checking of the road stop cache entries */
- for (const RoadStop *rs : RoadStop::Iterate()) {
- if (IsBayRoadStopTile(rs->xy)) continue;
-
- assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW));
- rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs);
- rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs);
- }
-
- for (Vehicle *v : Vehicle::Iterate()) {
- if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue;
-
- uint length = 0;
- for (const Vehicle *u = v; u != nullptr; u = u->Next()) length++;
-
- NewGRFCache *grf_cache = CallocT(length);
- VehicleCache *veh_cache = CallocT(length);
- GroundVehicleCache *gro_cache = CallocT(length);
- TrainCache *tra_cache = CallocT(length);
-
- length = 0;
- for (const Vehicle *u = v; u != nullptr; 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 != nullptr; u = u->Next()) {
- FillNewGRFVehicleCache(u);
- if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) {
- Debug(desync, 2, "warning: newgrf cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length);
- }
- if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) {
- Debug(desync, 2, "warning: vehicle cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, 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, "warning: train ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
- }
- if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) {
- Debug(desync, 2, "warning: train cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
- }
- break;
- case VEH_ROAD:
- if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) {
- Debug(desync, 2, "warning: road vehicle ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, 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 (Vehicle *v : Vehicle::Iterate()) {
- uint8_t buff[sizeof(VehicleCargoList)];
- memcpy(buff, &v->cargo, sizeof(VehicleCargoList));
- v->cargo.InvalidateCache();
- assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0);
- }
-
- /* Backup stations_near */
- std::vector old_town_stations_near;
- for (Town *t : Town::Iterate()) old_town_stations_near.push_back(t->stations_near);
-
- std::vector old_industry_stations_near;
- for (Industry *ind : Industry::Iterate()) old_industry_stations_near.push_back(ind->stations_near);
-
- std::vector old_station_industries_near;
- for (Station *st : Station::Iterate()) old_station_industries_near.push_back(st->industries_near);
-
- for (Station *st : Station::Iterate()) {
- for (GoodsEntry &ge : st->goods) {
- uint8_t buff[sizeof(StationCargoList)];
- memcpy(buff, &ge.cargo, sizeof(StationCargoList));
- ge.cargo.InvalidateCache();
- assert(memcmp(&ge.cargo, buff, sizeof(StationCargoList)) == 0);
- }
-
- /* Check docking tiles */
- TileArea ta;
- std::map docking_tiles;
- for (TileIndex tile : st->docking_station) {
- ta.Add(tile);
- docking_tiles[tile] = IsDockingTile(tile);
- }
- UpdateStationDockingTiles(st);
- if (ta.tile != st->docking_station.tile || ta.w != st->docking_station.w || ta.h != st->docking_station.h) {
- Debug(desync, 2, "warning: station docking mismatch: station {}, company {}", st->index, st->owner);
- }
- for (TileIndex tile : ta) {
- if (docking_tiles[tile] != IsDockingTile(tile)) {
- Debug(desync, 2, "warning: docking tile mismatch: tile {}", tile);
- }
- }
- }
-
- Station::RecomputeCatchmentForAll();
-
- /* Check industries_near */
- i = 0;
- for (Station *st : Station::Iterate()) {
- if (st->industries_near != old_station_industries_near[i]) {
- Debug(desync, 2, "warning: station industries near mismatch: station {}", st->index);
- }
- i++;
- }
-
- /* Check stations_near */
- i = 0;
- for (Town *t : Town::Iterate()) {
- if (t->stations_near != old_town_stations_near[i]) {
- Debug(desync, 2, "warning: town stations near mismatch: town {}", t->index);
- }
- i++;
- }
- i = 0;
- for (Industry *ind : Industry::Iterate()) {
- if (ind->stations_near != old_industry_stations_near[i]) {
- Debug(desync, 2, "warning: industry stations near mismatch: industry {}", ind->index);
- }
- i++;
- }
-}
/**
* State controlling game loop.