From 5ed7aee8d3c63d6001a1ebf2eb993778d2a49031 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 3 Oct 2021 23:03:26 +0100 Subject: [PATCH] Add flags field to CheckCaches for which checks to run Add header file for CheckCaches --- src/CMakeLists.txt | 1 + src/company_cmd.cpp | 2 +- src/console_cmds.cpp | 2 +- src/crashlog.cpp | 2 +- src/debug_desync.h | 25 ++ src/economy.cpp | 2 +- src/openttd.cpp | 635 ++++++++++++++++++++++--------------------- 7 files changed, 351 insertions(+), 318 deletions(-) create mode 100644 src/debug_desync.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8022223ed3..c3ef71917a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,6 +118,7 @@ add_files( date_type.h debug.cpp debug.h + debug_desync.h debug_settings.h dedicated.cpp departures.cpp diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 51bc4f95cf..965816ec3e 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -37,6 +37,7 @@ #include "zoning.h" #include "tbtr_template_vehicle_func.h" #include "widgets/statusbar_widget.h" +#include "debug_desync.h" #include "table/strings.h" @@ -937,7 +938,6 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowClassesData(WC_DEPARTURES_BOARD, 0); - extern void CheckCaches(bool force_check, std::function log); CheckCaches(true, nullptr); break; } diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 74b47a945b..4cec71eae2 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -53,6 +53,7 @@ #include "linkgraph/linkgraphjob.h" #include "base_media_base.h" #include "debug_settings.h" +#include "debug_desync.h" #include #include "safeguards.h" @@ -2687,7 +2688,6 @@ DEF_CONSOLE_CMD(ConCheckCaches) if (broadcast) { DoCommandP(0, 0, 0, CMD_DESYNC_CHECK); } else { - extern void CheckCaches(bool force_check, std::function log); CheckCaches(true, nullptr); } diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 16ae1245e5..0fbd23ea91 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -30,6 +30,7 @@ #include "scope_info.h" #include "command_func.h" #include "thread.h" +#include "debug_desync.h" #include "ai/ai_info.hpp" #include "game/game.hpp" @@ -522,7 +523,6 @@ char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last, const DesyncE buffer = DumpDesyncMsgLog(buffer, last); bool have_cache_log = false; - extern void CheckCaches(bool force_check, std::function log); CheckCaches(true, [&](const char *str) { if (!have_cache_log) buffer += seprintf(buffer, last, "CheckCaches:\n"); buffer += seprintf(buffer, last, " %s\n", str); diff --git a/src/debug_desync.h b/src/debug_desync.h new file mode 100644 index 0000000000..98b8760f00 --- /dev/null +++ b/src/debug_desync.h @@ -0,0 +1,25 @@ +/* + * 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 debug_desync.h Desync debugging. */ + +#ifndef DEBUG_DESYNC_H +#define DEBUG_DESYNC_H + +#include + +enum CheckCachesFlags : uint32 { + CHECK_CACHE_NONE = 0, + CHECK_CACHE_GENERAL = 1 << 0, + CHECK_CACHE_INFRA_TOTALS = 1 << 1, + CHECK_CACHE_ALL = UINT32_MAX, +}; +DECLARE_ENUM_AS_BIT_SET(CheckCachesFlags) + +extern void CheckCaches(bool force_check, std::function log = nullptr, CheckCachesFlags flags = CHECK_CACHE_ALL); + +#endif /* DEBUG_DESYNC_H */ diff --git a/src/economy.cpp b/src/economy.cpp index f8c6a0afe6..6098f835ae 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -54,6 +54,7 @@ #include "tbtr_template_vehicle_func.h" #include "scope_info.h" #include "pathfinder/yapf/yapf_cache.h" +#include "debug_desync.h" #include "table/strings.h" #include "table/pricebase.h" @@ -2287,7 +2288,6 @@ static void DoAcquireCompany(Company *c) delete c; - extern void CheckCaches(bool force_check, std::function log); CheckCaches(true, nullptr); } diff --git a/src/openttd.cpp b/src/openttd.cpp index c3ae283e5c..0cb3d7221f 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -79,6 +79,7 @@ #include "core/checksum_func.hpp" #include "tbtr_template_vehicle_func.h" #include "debug_settings.h" +#include "debug_desync.h" #include "linkgraph/linkgraphschedule.h" #include "tracerestrict.h" @@ -1358,7 +1359,7 @@ void WriteVehicleInfo(char *&p, const char *last, const Vehicle *u, const Vehicl * the cached value and what the value would * be when calculated from the 'base' data. */ -void CheckCaches(bool force_check, std::function log) +void CheckCaches(bool force_check, std::function log, CheckCachesFlags flags) { if (!force_check) { int desync_level = _debug_desync_level; @@ -1398,362 +1399,368 @@ void CheckCaches(bool force_check, std::function log) } \ } - /* Check the town caches. */ - std::vector old_town_caches; - std::vector old_town_stations_nears; - for (const Town *t : Town::Iterate()) { - old_town_caches.push_back(t->cache); - old_town_stations_nears.push_back(t->stations_near); - } + if (flags & CHECK_CACHE_GENERAL) { + /* Check the town caches. */ + std::vector old_town_caches; + std::vector old_town_stations_nears; + for (const Town *t : Town::Iterate()) { + old_town_caches.push_back(t->cache); + old_town_stations_nears.push_back(t->stations_near); + } - std::vector old_station_industries_nears; - std::vector old_station_catchment_tiles; - std::vector old_station_tiles; - for (Station *st : Station::Iterate()) { - old_station_industries_nears.push_back(st->industries_near); - old_station_catchment_tiles.push_back(st->catchment_tiles); - old_station_tiles.push_back(st->station_tiles); - } + std::vector old_station_industries_nears; + std::vector old_station_catchment_tiles; + std::vector old_station_tiles; + for (Station *st : Station::Iterate()) { + old_station_industries_nears.push_back(st->industries_near); + old_station_catchment_tiles.push_back(st->catchment_tiles); + old_station_tiles.push_back(st->station_tiles); + } - std::vector old_industry_stations_nears; - for (Industry *ind : Industry::Iterate()) { - old_industry_stations_nears.push_back(ind->stations_near); - } + std::vector old_industry_stations_nears; + for (Industry *ind : Industry::Iterate()) { + old_industry_stations_nears.push_back(ind->stations_near); + } - extern void RebuildTownCaches(bool cargo_update_required, bool old_map_position); - RebuildTownCaches(false, false); - RebuildSubsidisedSourceAndDestinationCache(); + extern void RebuildTownCaches(bool cargo_update_required, bool old_map_position); + RebuildTownCaches(false, false); + RebuildSubsidisedSourceAndDestinationCache(); - Station::RecomputeCatchmentForAll(); + Station::RecomputeCatchmentForAll(); - uint i = 0; - for (Town *t : Town::Iterate()) { - if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) { - CCLOG("town cache mismatch: town %i", (int)t->index); - } - if (old_town_stations_nears[i] != t->stations_near) { - CCLOG("town stations_near mismatch: town %i, (old size: %u, new size: %u)", (int)t->index, (uint)old_town_stations_nears[i].size(), (uint)t->stations_near.size()); - } - i++; - } - i = 0; - for (Station *st : Station::Iterate()) { - if (old_station_industries_nears[i] != st->industries_near) { - CCLOG("station industries_near mismatch: st %i, (old size: %u, new size: %u)", (int)st->index, (uint)old_station_industries_nears[i].size(), (uint)st->industries_near.size()); - } - if (!(old_station_catchment_tiles[i] == st->catchment_tiles)) { - CCLOG("station catchment_tiles mismatch: st %i", (int)st->index); - } - if (!(old_station_tiles[i] == st->station_tiles)) { - CCLOG("station station_tiles mismatch: st %i, (old: %u, new: %u)", (int)st->index, old_station_tiles[i], st->station_tiles); + uint i = 0; + for (Town *t : Town::Iterate()) { + if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) { + CCLOG("town cache mismatch: town %i", (int)t->index); + } + if (old_town_stations_nears[i] != t->stations_near) { + CCLOG("town stations_near mismatch: town %i, (old size: %u, new size: %u)", (int)t->index, (uint)old_town_stations_nears[i].size(), (uint)t->stations_near.size()); + } + i++; } - i++; - } - i = 0; - for (Industry *ind : Industry::Iterate()) { - if (old_industry_stations_nears[i] != ind->stations_near) { - CCLOG("industry stations_near mismatch: ind %i, (old size: %u, new size: %u)", (int)ind->index, (uint)old_industry_stations_nears[i].size(), (uint)ind->stations_near.size()); + i = 0; + for (Station *st : Station::Iterate()) { + if (old_station_industries_nears[i] != st->industries_near) { + CCLOG("station industries_near mismatch: st %i, (old size: %u, new size: %u)", (int)st->index, (uint)old_station_industries_nears[i].size(), (uint)st->industries_near.size()); + } + if (!(old_station_catchment_tiles[i] == st->catchment_tiles)) { + CCLOG("station catchment_tiles mismatch: st %i", (int)st->index); + } + if (!(old_station_tiles[i] == st->station_tiles)) { + CCLOG("station station_tiles mismatch: st %i, (old: %u, new: %u)", (int)st->index, old_station_tiles[i], st->station_tiles); + } + i++; } - StationList stlist; - if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) { - stlist.insert(ind->neutral_station); - if (ind->stations_near != stlist) { - CCLOG("industry neutral station stations_near mismatch: ind %i, (recalc size: %u, neutral size: %u)", (int)ind->index, (uint)ind->stations_near.size(), (uint)stlist.size()); + i = 0; + for (Industry *ind : Industry::Iterate()) { + if (old_industry_stations_nears[i] != ind->stations_near) { + CCLOG("industry stations_near mismatch: ind %i, (old size: %u, new size: %u)", (int)ind->index, (uint)old_industry_stations_nears[i].size(), (uint)ind->stations_near.size()); } - } else { - ForAllStationsAroundTiles(ind->location, [ind, &stlist](Station *st, TileIndex tile) { - if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false; - stlist.insert(st); - return true; - }); - if (ind->stations_near != stlist) { - CCLOG("industry FindStationsAroundTiles mismatch: ind %i, (recalc size: %u, find size: %u)", (int)ind->index, (uint)ind->stations_near.size(), (uint)stlist.size()); + StationList stlist; + if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) { + stlist.insert(ind->neutral_station); + if (ind->stations_near != stlist) { + CCLOG("industry neutral station stations_near mismatch: ind %i, (recalc size: %u, neutral size: %u)", (int)ind->index, (uint)ind->stations_near.size(), (uint)stlist.size()); + } + } else { + ForAllStationsAroundTiles(ind->location, [ind, &stlist](Station *st, TileIndex tile) { + if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false; + stlist.insert(st); + return true; + }); + if (ind->stations_near != stlist) { + CCLOG("industry FindStationsAroundTiles mismatch: ind %i, (recalc size: %u, find size: %u)", (int)ind->index, (uint)ind->stations_near.size(), (uint)stlist.size()); + } } + i++; } - i++; } - /* Check company infrastructure cache. */ - std::vector old_infrastructure; - for (const Company *c : Company::Iterate()) old_infrastructure.push_back(c->infrastructure); - - extern void AfterLoadCompanyStats(); - AfterLoadCompanyStats(); - - i = 0; - for (const Company *c : Company::Iterate()) { - if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) { - CCLOG("infrastructure cache mismatch: company %i", (int)c->index); - char buffer[4096]; - old_infrastructure[i].Dump(buffer, lastof(buffer)); - CCLOG("Previous:"); - ProcessLineByLine(buffer, [&](const char *line) { - CCLOG(" %s", line); - }); - c->infrastructure.Dump(buffer, lastof(buffer)); - CCLOG("Recalculated:"); - ProcessLineByLine(buffer, [&](const char *line) { - CCLOG(" %s", line); - }); + if (flags & CHECK_CACHE_INFRA_TOTALS) { + /* Check company infrastructure cache. */ + std::vector old_infrastructure; + for (const Company *c : Company::Iterate()) old_infrastructure.push_back(c->infrastructure); + + extern void AfterLoadCompanyStats(); + AfterLoadCompanyStats(); + + uint i = 0; + for (const Company *c : Company::Iterate()) { + if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) { + CCLOG("infrastructure cache mismatch: company %i", (int)c->index); + char buffer[4096]; + old_infrastructure[i].Dump(buffer, lastof(buffer)); + CCLOG("Previous:"); + ProcessLineByLine(buffer, [&](const char *line) { + CCLOG(" %s", line); + }); + c->infrastructure.Dump(buffer, lastof(buffer)); + CCLOG("Recalculated:"); + ProcessLineByLine(buffer, [&](const char *line) { + CCLOG(" %s", line); + }); + } + i++; } - i++; } - /* Strict checking of the road stop cache entries */ - for (const RoadStop *rs : RoadStop::Iterate()) { - 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); - } + if (flags & CHECK_CACHE_GENERAL) { + /* Strict checking of the road stop cache entries */ + for (const RoadStop *rs : RoadStop::Iterate()) { + if (IsStandardRoadStopTile(rs->xy)) continue; - for (Vehicle *v : Vehicle::Iterate()) { - extern bool ValidateVehicleTileHash(const Vehicle *v); - if (!ValidateVehicleTileHash(v)) { - CCLOG("vehicle tile hash mismatch: type %i, vehicle %i, company %i, unit number %i", (int)v->type, v->index, (int)v->owner, v->unitnumber); + assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); + rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); + rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); } - extern void FillNewGRFVehicleCache(const Vehicle *v); - if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; + for (Vehicle *v : Vehicle::Iterate()) { + extern bool ValidateVehicleTileHash(const Vehicle *v); + if (!ValidateVehicleTileHash(v)) { + CCLOG("vehicle tile hash mismatch: type %i, vehicle %i, company %i, unit number %i", (int)v->type, v->index, (int)v->owner, v->unitnumber); + } + + 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 != nullptr; u = u->Next()) { - if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) { - CCLOGV("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (1)"); + uint length = 0; + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { + if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) { + CCLOGV("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (1)"); + } + if (u->type == VEH_TRAIN && u->breakdown_ctr != 0 && !HasBit(Train::From(v)->flags, VRF_CONSIST_BREAKDOWN)) { + CCLOGV("VRF_CONSIST_BREAKDOWN incorrectly not set"); + } + if (u->type == VEH_TRAIN && ((Train::From(u)->track & TRACK_BIT_WORMHOLE && !(Train::From(u)->vehstatus & VS_HIDDEN)) || Train::From(u)->track == TRACK_BIT_DEPOT) && !HasBit(Train::From(v)->flags, VRF_CONSIST_SPEED_REDUCTION)) { + CCLOGV("VRF_CONSIST_SPEED_REDUCTION incorrectly not set"); + } + length++; } - if (u->type == VEH_TRAIN && u->breakdown_ctr != 0 && !HasBit(Train::From(v)->flags, VRF_CONSIST_BREAKDOWN)) { - CCLOGV("VRF_CONSIST_BREAKDOWN incorrectly not set"); + + NewGRFCache *grf_cache = CallocT(length); + VehicleCache *veh_cache = CallocT(length); + GroundVehicleCache *gro_cache = CallocT(length); + AircraftCache *air_cache = CallocT(length); + TrainCache *tra_cache = CallocT(length); + Vehicle **veh_old = 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; + veh_old[length] = CallocT(1); + memcpy((void *) veh_old[length], (const void *) Train::From(u), sizeof(Train)); + break; + case VEH_ROAD: + gro_cache[length] = RoadVehicle::From(u)->gcache; + veh_old[length] = CallocT(1); + memcpy((void *) veh_old[length], (const void *) RoadVehicle::From(u), sizeof(RoadVehicle)); + break; + case VEH_AIRCRAFT: + air_cache[length] = Aircraft::From(u)->acache; + veh_old[length] = CallocT(1); + memcpy((void *) veh_old[length], (const void *) Aircraft::From(u), sizeof(Aircraft)); + break; + default: + veh_old[length] = CallocT(1); + memcpy((void *) veh_old[length], (const void *) u, sizeof(Vehicle)); + break; + } + length++; } - if (u->type == VEH_TRAIN && ((Train::From(u)->track & TRACK_BIT_WORMHOLE && !(Train::From(u)->vehstatus & VS_HIDDEN)) || Train::From(u)->track == TRACK_BIT_DEPOT) && !HasBit(Train::From(v)->flags, VRF_CONSIST_SPEED_REDUCTION)) { - CCLOGV("VRF_CONSIST_SPEED_REDUCTION incorrectly not set"); + + 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++; - } - NewGRFCache *grf_cache = CallocT(length); - VehicleCache *veh_cache = CallocT(length); - GroundVehicleCache *gro_cache = CallocT(length); - AircraftCache *air_cache = CallocT(length); - TrainCache *tra_cache = CallocT(length); - Vehicle **veh_old = 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; - veh_old[length] = CallocT(1); - memcpy((void *) veh_old[length], (const void *) Train::From(u), sizeof(Train)); - break; - case VEH_ROAD: - gro_cache[length] = RoadVehicle::From(u)->gcache; - veh_old[length] = CallocT(1); - memcpy((void *) veh_old[length], (const void *) RoadVehicle::From(u), sizeof(RoadVehicle)); - break; - case VEH_AIRCRAFT: - air_cache[length] = Aircraft::From(u)->acache; - veh_old[length] = CallocT(1); - memcpy((void *) veh_old[length], (const void *) Aircraft::From(u), sizeof(Aircraft)); - break; - default: - veh_old[length] = CallocT(1); - memcpy((void *) veh_old[length], (const void *) u, sizeof(Vehicle)); - 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) { + CCLOGV("newgrf cache mismatch"); + } + if (veh_cache[length].cached_max_speed != u->vcache.cached_max_speed || veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period || + veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect || HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT)) { + CCLOGV("vehicle cache mismatch: %c%c%c%c", + veh_cache[length].cached_max_speed != u->vcache.cached_max_speed ? 'm' : '-', + veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period ? 'c' : '-', + veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect ? 'v' : '-', + HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT) ? 'l' : '-'); + } + if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) { + CCLOGV("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (2)"); + } + if (veh_old[length]->acceleration != u->acceleration) { + CCLOGV("acceleration mismatch"); + } + if (veh_old[length]->breakdown_chance != u->breakdown_chance) { + CCLOGV("breakdown_chance mismatch"); + } + if (veh_old[length]->breakdown_ctr != u->breakdown_ctr) { + CCLOGV("breakdown_ctr mismatch"); + } + if (veh_old[length]->breakdown_delay != u->breakdown_delay) { + CCLOGV("breakdown_delay mismatch"); + } + if (veh_old[length]->breakdowns_since_last_service != u->breakdowns_since_last_service) { + CCLOGV("breakdowns_since_last_service mismatch"); + } + if (veh_old[length]->breakdown_severity != u->breakdown_severity) { + CCLOGV("breakdown_severity mismatch"); + } + if (veh_old[length]->breakdown_type != u->breakdown_type) { + CCLOGV("breakdown_type mismatch"); + } + if (veh_old[length]->vehicle_flags != u->vehicle_flags) { + CCLOGV("vehicle_flags mismatch"); + } + auto print_gv_cache_diff = [&](const char *vtype, const GroundVehicleCache &a, const GroundVehicleCache &b) { + CCLOGV("%s ground vehicle cache mismatch: %c%c%c%c%c%c%c%c%c%c", + vtype, + a.cached_weight != b.cached_weight ? 'w' : '-', + a.cached_slope_resistance != b.cached_slope_resistance ? 'r' : '-', + a.cached_max_te != b.cached_max_te ? 't' : '-', + a.cached_axle_resistance != b.cached_axle_resistance ? 'a' : '-', + a.cached_max_track_speed != b.cached_max_track_speed ? 's' : '-', + a.cached_power != b.cached_power ? 'p' : '-', + a.cached_air_drag != b.cached_air_drag ? 'd' : '-', + a.cached_total_length != b.cached_total_length ? 'l' : '-', + a.first_engine != b.first_engine ? 'e' : '-', + a.cached_veh_length != b.cached_veh_length ? 'L' : '-'); + }; + switch (u->type) { + case VEH_TRAIN: + if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { + print_gv_cache_diff("train", gro_cache[length], Train::From(u)->gcache); + } + if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { + CCLOGV("train cache mismatch: %c%c%c%c%c%c%c%c%c", + tra_cache[length].cached_override != Train::From(u)->tcache.cached_override ? 'o' : '-', + tra_cache[length].cached_tflags != Train::From(u)->tcache.cached_tflags ? 'f' : '-', + tra_cache[length].cached_num_engines != Train::From(u)->tcache.cached_num_engines ? 'e' : '-', + tra_cache[length].cached_centre_mass != Train::From(u)->tcache.cached_centre_mass ? 'm' : '-', + tra_cache[length].cached_veh_weight != Train::From(u)->tcache.cached_veh_weight ? 'w' : '-', + tra_cache[length].cached_uncapped_decel != Train::From(u)->tcache.cached_uncapped_decel ? 'D' : '-', + tra_cache[length].cached_deceleration != Train::From(u)->tcache.cached_deceleration ? 'd' : '-', + tra_cache[length].user_def_data != Train::From(u)->tcache.user_def_data ? 'u' : '-', + tra_cache[length].cached_max_curve_speed != Train::From(u)->tcache.cached_max_curve_speed ? 'c' : '-'); + } + if (Train::From(veh_old[length])->railtype != Train::From(u)->railtype) { + CCLOGV("railtype mismatch"); + } + if (Train::From(veh_old[length])->compatible_railtypes != Train::From(u)->compatible_railtypes) { + CCLOGV("compatible_railtypes mismatch"); + } + if (Train::From(veh_old[length])->flags != Train::From(u)->flags) { + CCLOGV("train flags mismatch"); + } + break; + case VEH_ROAD: + if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { + print_gv_cache_diff("road vehicle", gro_cache[length], Train::From(u)->gcache); + } + break; + case VEH_AIRCRAFT: + if (memcmp(&air_cache[length], &Aircraft::From(u)->acache, sizeof(AircraftCache)) != 0) { + CCLOGV("Aircraft vehicle cache mismatch: %c%c", + air_cache[length].cached_max_range != Aircraft::From(u)->acache.cached_max_range ? 'r' : '-', + air_cache[length].cached_max_range_sqr != Aircraft::From(u)->acache.cached_max_range_sqr ? 's' : '-'); + } + break; + default: + break; + } + free(veh_old[length]); + length++; } - length++; + + free(grf_cache); + free(veh_cache); + free(gro_cache); + free(air_cache); + free(tra_cache); + free(veh_old); } - 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; + /* Check whether the caches are still valid */ + for (Vehicle *v : Vehicle::Iterate()) { + byte buff[sizeof(VehicleCargoList)]; + memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); + v->cargo.InvalidateCache(); + assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); } - 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) { - CCLOGV("newgrf cache mismatch"); - } - if (veh_cache[length].cached_max_speed != u->vcache.cached_max_speed || veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period || - veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect || HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT)) { - CCLOGV("vehicle cache mismatch: %c%c%c%c", - veh_cache[length].cached_max_speed != u->vcache.cached_max_speed ? 'm' : '-', - veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period ? 'c' : '-', - veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect ? 'v' : '-', - HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT) ? 'l' : '-'); - } - if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) { - CCLOGV("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (2)"); - } - if (veh_old[length]->acceleration != u->acceleration) { - CCLOGV("acceleration mismatch"); - } - if (veh_old[length]->breakdown_chance != u->breakdown_chance) { - CCLOGV("breakdown_chance mismatch"); - } - if (veh_old[length]->breakdown_ctr != u->breakdown_ctr) { - CCLOGV("breakdown_ctr mismatch"); - } - if (veh_old[length]->breakdown_delay != u->breakdown_delay) { - CCLOGV("breakdown_delay mismatch"); + for (Station *st : Station::Iterate()) { + 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); } - if (veh_old[length]->breakdowns_since_last_service != u->breakdowns_since_last_service) { - CCLOGV("breakdowns_since_last_service mismatch"); - } - if (veh_old[length]->breakdown_severity != u->breakdown_severity) { - CCLOGV("breakdown_severity mismatch"); - } - if (veh_old[length]->breakdown_type != u->breakdown_type) { - CCLOGV("breakdown_type mismatch"); + + /* Check docking tiles */ + TileArea ta; + std::map docking_tiles; + TILE_AREA_LOOP(tile, st->docking_station) { + ta.Add(tile); + docking_tiles[tile] = IsDockingTile(tile); } - if (veh_old[length]->vehicle_flags != u->vehicle_flags) { - CCLOGV("vehicle_flags mismatch"); + UpdateStationDockingTiles(st); + if (ta.tile != st->docking_station.tile || ta.w != st->docking_station.w || ta.h != st->docking_station.h) { + CCLOG("station docking mismatch: station %i, company %i, prev: (%X, %u, %u), recalc: (%X, %u, %u)", + st->index, (int)st->owner, ta.tile, ta.w, ta.h, st->docking_station.tile, st->docking_station.w, st->docking_station.h); } - auto print_gv_cache_diff = [&](const char *vtype, const GroundVehicleCache &a, const GroundVehicleCache &b) { - CCLOGV("%s ground vehicle cache mismatch: %c%c%c%c%c%c%c%c%c%c", - vtype, - a.cached_weight != b.cached_weight ? 'w' : '-', - a.cached_slope_resistance != b.cached_slope_resistance ? 'r' : '-', - a.cached_max_te != b.cached_max_te ? 't' : '-', - a.cached_axle_resistance != b.cached_axle_resistance ? 'a' : '-', - a.cached_max_track_speed != b.cached_max_track_speed ? 's' : '-', - a.cached_power != b.cached_power ? 'p' : '-', - a.cached_air_drag != b.cached_air_drag ? 'd' : '-', - a.cached_total_length != b.cached_total_length ? 'l' : '-', - a.first_engine != b.first_engine ? 'e' : '-', - a.cached_veh_length != b.cached_veh_length ? 'L' : '-'); - }; - switch (u->type) { - case VEH_TRAIN: - if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { - print_gv_cache_diff("train", gro_cache[length], Train::From(u)->gcache); - } - if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { - CCLOGV("train cache mismatch: %c%c%c%c%c%c%c%c%c", - tra_cache[length].cached_override != Train::From(u)->tcache.cached_override ? 'o' : '-', - tra_cache[length].cached_tflags != Train::From(u)->tcache.cached_tflags ? 'f' : '-', - tra_cache[length].cached_num_engines != Train::From(u)->tcache.cached_num_engines ? 'e' : '-', - tra_cache[length].cached_centre_mass != Train::From(u)->tcache.cached_centre_mass ? 'm' : '-', - tra_cache[length].cached_veh_weight != Train::From(u)->tcache.cached_veh_weight ? 'w' : '-', - tra_cache[length].cached_uncapped_decel != Train::From(u)->tcache.cached_uncapped_decel ? 'D' : '-', - tra_cache[length].cached_deceleration != Train::From(u)->tcache.cached_deceleration ? 'd' : '-', - tra_cache[length].user_def_data != Train::From(u)->tcache.user_def_data ? 'u' : '-', - tra_cache[length].cached_max_curve_speed != Train::From(u)->tcache.cached_max_curve_speed ? 'c' : '-'); - } - if (Train::From(veh_old[length])->railtype != Train::From(u)->railtype) { - CCLOGV("railtype mismatch"); - } - if (Train::From(veh_old[length])->compatible_railtypes != Train::From(u)->compatible_railtypes) { - CCLOGV("compatible_railtypes mismatch"); - } - if (Train::From(veh_old[length])->flags != Train::From(u)->flags) { - CCLOGV("train flags mismatch"); - } - break; - case VEH_ROAD: - if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { - print_gv_cache_diff("road vehicle", gro_cache[length], Train::From(u)->gcache); - } - break; - case VEH_AIRCRAFT: - if (memcmp(&air_cache[length], &Aircraft::From(u)->acache, sizeof(AircraftCache)) != 0) { - CCLOGV("Aircraft vehicle cache mismatch: %c%c", - air_cache[length].cached_max_range != Aircraft::From(u)->acache.cached_max_range ? 'r' : '-', - air_cache[length].cached_max_range_sqr != Aircraft::From(u)->acache.cached_max_range_sqr ? 's' : '-'); - } - break; - default: - break; + TILE_AREA_LOOP(tile, ta) { + if (docking_tiles[tile] != IsDockingTile(tile)) { + CCLOG("docking tile mismatch: tile %i", (int)tile); + } } - free(veh_old[length]); - length++; } - free(grf_cache); - free(veh_cache); - free(gro_cache); - free(air_cache); - free(tra_cache); - free(veh_old); - } - - /* Check whether the caches are still valid */ - for (Vehicle *v : Vehicle::Iterate()) { - byte buff[sizeof(VehicleCargoList)]; - memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); - v->cargo.InvalidateCache(); - assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); - } - - for (Station *st : Station::Iterate()) { - 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); + for (OrderList *order_list : OrderList::Iterate()) { + order_list->DebugCheckSanity(); } - /* Check docking tiles */ - TileArea ta; - std::map docking_tiles; - TILE_AREA_LOOP(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) { - CCLOG("station docking mismatch: station %i, company %i, prev: (%X, %u, %u), recalc: (%X, %u, %u)", - st->index, (int)st->owner, ta.tile, ta.w, ta.h, st->docking_station.tile, st->docking_station.w, st->docking_station.h); + extern void ValidateVehicleTickCaches(); + ValidateVehicleTickCaches(); + + for (Vehicle *v : Vehicle::Iterate()) { + if (v->Previous()) assert_msg(v->Previous()->Next() == v, "%u", v->index); + if (v->Next()) assert_msg(v->Next()->Previous() == v, "%u", v->index); } - TILE_AREA_LOOP(tile, ta) { - if (docking_tiles[tile] != IsDockingTile(tile)) { - CCLOG("docking tile mismatch: tile %i", (int)tile); - } + for (const TemplateVehicle *tv : TemplateVehicle::Iterate()) { + if (tv->Prev()) assert_msg(tv->Prev()->Next() == tv, "%u", tv->index); + if (tv->Next()) assert_msg(tv->Next()->Prev() == tv, "%u", tv->index); } - } - for (OrderList *order_list : OrderList::Iterate()) { - order_list->DebugCheckSanity(); - } + if (!TraceRestrictSlot::ValidateVehicleIndex()) CCLOG("Trace restrict slot vehicle index validation failed"); + TraceRestrictSlot::ValidateSlotOccupants(log); - extern void ValidateVehicleTickCaches(); - ValidateVehicleTickCaches(); + if (!CargoPacket::ValidateDeferredCargoPayments()) CCLOG("Cargo packets deferred payments validation failed"); - for (Vehicle *v : Vehicle::Iterate()) { - if (v->Previous()) assert_msg(v->Previous()->Next() == v, "%u", v->index); - if (v->Next()) assert_msg(v->Next()->Previous() == v, "%u", v->index); - } - for (const TemplateVehicle *tv : TemplateVehicle::Iterate()) { - if (tv->Prev()) assert_msg(tv->Prev()->Next() == tv, "%u", tv->index); - if (tv->Next()) assert_msg(tv->Next()->Prev() == tv, "%u", tv->index); - } - - if (!TraceRestrictSlot::ValidateVehicleIndex()) CCLOG("Trace restrict slot vehicle index validation failed"); - TraceRestrictSlot::ValidateSlotOccupants(log); - - if (!CargoPacket::ValidateDeferredCargoPayments()) CCLOG("Cargo packets deferred payments validation failed"); - - if (_order_destination_refcount_map_valid) { - btree::btree_map saved_order_destination_refcount_map = std::move(_order_destination_refcount_map); - for (auto iter = saved_order_destination_refcount_map.begin(); iter != saved_order_destination_refcount_map.end();) { - if (iter->second == 0) { - iter = saved_order_destination_refcount_map.erase(iter); - } else { - ++iter; + if (_order_destination_refcount_map_valid) { + btree::btree_map saved_order_destination_refcount_map = std::move(_order_destination_refcount_map); + for (auto iter = saved_order_destination_refcount_map.begin(); iter != saved_order_destination_refcount_map.end();) { + if (iter->second == 0) { + iter = saved_order_destination_refcount_map.erase(iter); + } else { + ++iter; + } } + IntialiseOrderDestinationRefcountMap(); + if (saved_order_destination_refcount_map != _order_destination_refcount_map) CCLOG("Order destination refcount map mismatch"); + } else { + CCLOG("Order destination refcount map not valid"); } - IntialiseOrderDestinationRefcountMap(); - if (saved_order_destination_refcount_map != _order_destination_refcount_map) CCLOG("Order destination refcount map mismatch"); - } else { - CCLOG("Order destination refcount map not valid"); } #undef CCLOGV