2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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 <http://www.gnu.org/licenses/>.
8 /** @file cachecheck.cpp Check caches. */
12 #include "company_base.h"
15 #include "roadstop_base.h"
18 #include "station_base.h"
19 #include "station_map.h"
20 #include "subsidy_func.h"
23 #include "vehicle_base.h"
25 #include "safeguards.h"
27 extern void AfterLoadCompanyStats();
28 extern void RebuildTownCaches();
31 * Check the validity of some of the caches.
32 * Especially in the sense of desyncs between
33 * the cached value and what the value would
34 * be when calculated from the 'base' data.
38 /* Return here so it is easy to add checks that are run
39 * always to aid testing of caches. */
40 if (_debug_desync_level
<= 1) return;
42 /* Check the town caches. */
43 std::vector
<TownCache
> old_town_caches
;
44 for (const Town
*t
: Town::Iterate()) {
45 old_town_caches
.push_back(t
->cache
);
49 RebuildSubsidisedSourceAndDestinationCache();
52 for (Town
*t
: Town::Iterate()) {
53 if (old_town_caches
[i
] != t
->cache
) {
54 Debug(desync
, 2, "warning: town cache mismatch: town {}", t
->index
);
59 /* Check company infrastructure cache. */
60 std::vector
<CompanyInfrastructure
> old_infrastructure
;
61 for (const Company
*c
: Company::Iterate()) old_infrastructure
.push_back(c
->infrastructure
);
63 AfterLoadCompanyStats();
66 for (const Company
*c
: Company::Iterate()) {
67 if (old_infrastructure
[i
] != c
->infrastructure
) {
68 Debug(desync
, 2, "warning: infrastructure cache mismatch: company {}", c
->index
);
73 /* Strict checking of the road stop cache entries */
74 for (const RoadStop
*rs
: RoadStop::Iterate()) {
75 if (IsBayRoadStopTile(rs
->xy
)) continue;
77 assert(rs
->GetEntry(DIAGDIR_NE
) != rs
->GetEntry(DIAGDIR_NW
));
78 rs
->GetEntry(DIAGDIR_NE
)->CheckIntegrity(rs
);
79 rs
->GetEntry(DIAGDIR_NW
)->CheckIntegrity(rs
);
82 std::vector
<NewGRFCache
> grf_cache
;
83 std::vector
<VehicleCache
> veh_cache
;
84 std::vector
<GroundVehicleCache
> gro_cache
;
85 std::vector
<TrainCache
> tra_cache
;
87 for (Vehicle
*v
: Vehicle::Iterate()) {
88 if (v
!= v
->First() || v
->vehstatus
& VS_CRASHED
|| !v
->IsPrimaryVehicle()) continue;
90 for (const Vehicle
*u
= v
; u
!= nullptr; u
= u
->Next()) {
91 FillNewGRFVehicleCache(u
);
92 grf_cache
.emplace_back(u
->grf_cache
);
93 veh_cache
.emplace_back(u
->vcache
);
96 gro_cache
.emplace_back(Train::From(u
)->gcache
);
97 tra_cache
.emplace_back(Train::From(u
)->tcache
);
100 gro_cache
.emplace_back(RoadVehicle::From(u
)->gcache
);
108 case VEH_TRAIN
: Train::From(v
)->ConsistChanged(CCF_TRACK
); break;
109 case VEH_ROAD
: RoadVehUpdateCache(RoadVehicle::From(v
)); break;
110 case VEH_AIRCRAFT
: UpdateAircraftCache(Aircraft::From(v
)); break;
111 case VEH_SHIP
: Ship::From(v
)->UpdateCache(); break;
116 for (const Vehicle
*u
= v
; u
!= nullptr; u
= u
->Next()) {
117 FillNewGRFVehicleCache(u
);
118 if (grf_cache
[length
] != u
->grf_cache
) {
119 Debug(desync
, 2, "warning: newgrf cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v
->type
, v
->index
, v
->owner
, v
->unitnumber
, length
);
121 if (veh_cache
[length
] != u
->vcache
) {
122 Debug(desync
, 2, "warning: vehicle cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v
->type
, v
->index
, v
->owner
, v
->unitnumber
, length
);
126 if (gro_cache
[length
] != Train::From(u
)->gcache
) {
127 Debug(desync
, 2, "warning: train ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v
->index
, v
->owner
, v
->unitnumber
, length
);
129 if (tra_cache
[length
] != Train::From(u
)->tcache
) {
130 Debug(desync
, 2, "warning: train cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v
->index
, v
->owner
, v
->unitnumber
, length
);
134 if (gro_cache
[length
] != RoadVehicle::From(u
)->gcache
) {
135 Debug(desync
, 2, "warning: road vehicle ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v
->index
, v
->owner
, v
->unitnumber
, length
);
150 /* Check whether the caches are still valid */
151 for (Vehicle
*v
: Vehicle::Iterate()) {
152 [[maybe_unused
]] const auto a
= v
->cargo
.PeriodsInTransit();
153 [[maybe_unused
]] const auto b
= v
->cargo
.TotalCount();
154 [[maybe_unused
]] const auto c
= v
->cargo
.GetFeederShare();
155 v
->cargo
.InvalidateCache();
156 assert(a
== v
->cargo
.PeriodsInTransit());
157 assert(b
== v
->cargo
.TotalCount());
158 assert(c
== v
->cargo
.GetFeederShare());
161 /* Backup stations_near */
162 std::vector
<StationList
> old_town_stations_near
;
163 for (Town
*t
: Town::Iterate()) old_town_stations_near
.push_back(t
->stations_near
);
165 std::vector
<StationList
> old_industry_stations_near
;
166 for (Industry
*ind
: Industry::Iterate()) old_industry_stations_near
.push_back(ind
->stations_near
);
168 std::vector
<IndustryList
> old_station_industries_near
;
169 for (Station
*st
: Station::Iterate()) old_station_industries_near
.push_back(st
->industries_near
);
171 for (Station
*st
: Station::Iterate()) {
172 for (GoodsEntry
&ge
: st
->goods
) {
173 [[maybe_unused
]] const auto a
= ge
.cargo
.PeriodsInTransit();
174 [[maybe_unused
]] const auto b
= ge
.cargo
.TotalCount();
175 ge
.cargo
.InvalidateCache();
176 assert(a
== ge
.cargo
.PeriodsInTransit());
177 assert(b
== ge
.cargo
.TotalCount());
180 /* Check docking tiles */
182 std::map
<TileIndex
, bool> docking_tiles
;
183 for (TileIndex tile
: st
->docking_station
) {
185 docking_tiles
[tile
] = IsDockingTile(tile
);
187 UpdateStationDockingTiles(st
);
188 if (ta
.tile
!= st
->docking_station
.tile
|| ta
.w
!= st
->docking_station
.w
|| ta
.h
!= st
->docking_station
.h
) {
189 Debug(desync
, 2, "warning: station docking mismatch: station {}, company {}", st
->index
, st
->owner
);
191 for (TileIndex tile
: ta
) {
192 if (docking_tiles
[tile
] != IsDockingTile(tile
)) {
193 Debug(desync
, 2, "warning: docking tile mismatch: tile {}", tile
);
198 Station::RecomputeCatchmentForAll();
200 /* Check industries_near */
202 for (Station
*st
: Station::Iterate()) {
203 if (st
->industries_near
!= old_station_industries_near
[i
]) {
204 Debug(desync
, 2, "warning: station industries near mismatch: station {}", st
->index
);
209 /* Check stations_near */
211 for (Town
*t
: Town::Iterate()) {
212 if (t
->stations_near
!= old_town_stations_near
[i
]) {
213 Debug(desync
, 2, "warning: town stations near mismatch: town {}", t
->index
);
218 for (Industry
*ind
: Industry::Iterate()) {
219 if (ind
->stations_near
!= old_industry_stations_near
[i
]) {
220 Debug(desync
, 2, "warning: industry stations near mismatch: industry {}", ind
->index
);