diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 25d89604c4..153bb59852 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -918,8 +918,8 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (StoryPage::GetNumItems() == 0 || Goal::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); - extern void CheckCaches(bool force_check); - CheckCaches(true); + 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 784c8c3316..899b9d902c 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2005,8 +2005,8 @@ DEF_CONSOLE_CMD(ConCheckCaches) if (broadcast) { DoCommandP(0, 0, 0, CMD_DESYNC_CHECK); } else { - extern void CheckCaches(bool force_check); - CheckCaches(true); + extern void CheckCaches(bool force_check, std::function log); + CheckCaches(true, nullptr); } return true; diff --git a/src/crashlog.cpp b/src/crashlog.cpp index c5b2aa4e97..4675009f74 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -460,6 +460,15 @@ char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last) const buffer = this->LogRecentNews(buffer, last); buffer = this->LogCommandLog(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); + have_cache_log = true; + }); + if (have_cache_log) buffer += seprintf(buffer, last, "\n"); + buffer += seprintf(buffer, last, "*** End of OpenTTD Multiplayer %s Desync Report ***\n", _network_server ? "Server" : "Client"); return buffer; } diff --git a/src/economy.cpp b/src/economy.cpp index 6d3bda9454..dfa27bbabc 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -2235,8 +2235,8 @@ static void DoAcquireCompany(Company *c) delete c; - extern void CheckCaches(bool force_check); - CheckCaches(true); + extern void CheckCaches(bool force_check, std::function log); + CheckCaches(true, nullptr); } extern int GetAmountOwnedBy(const Company *c, Owner owner); diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 8d7e39990c..b5aaee19c6 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -284,9 +284,6 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) my_client->ClientError(NETWORK_RECV_STATUS_DESYNC); CrashLog::DesyncCrashLog(); - - extern void CheckCaches(bool force_check); - CheckCaches(true); return false; } diff --git a/src/openttd.cpp b/src/openttd.cpp index 062c8a0bfe..259d17e844 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -73,6 +73,7 @@ #include "zoning.h" #include "cargopacket.h" #include "tbtr_template_vehicle.h" +#include "string_func_extra.h" #include "linkgraph/linkgraphschedule.h" #include "tracerestrict.h" @@ -1287,7 +1288,7 @@ void SwitchToMode(SwitchMode new_mode) * the cached value and what the value would * be when calculated from the 'base' data. */ -void CheckCaches(bool force_check) +void CheckCaches(bool force_check, std::function log) { if (!force_check) { /* Return here so it is easy to add checks that are run @@ -1297,6 +1298,13 @@ void CheckCaches(bool force_check) if (_debug_desync_level == 1 && _scaled_date_ticks % 500 != 0) return; } + char cclog_buffer[1024]; +#define CCLOG(...) { \ + seprintf(cclog_buffer, lastof(cclog_buffer), __VA_ARGS__); \ + DEBUG(desync, 0, "%s", cclog_buffer); \ + if (log) log(cclog_buffer); \ +} + /* Check the town caches. */ std::vector old_town_caches; Town *t; @@ -1311,7 +1319,7 @@ void CheckCaches(bool force_check) uint i = 0; FOR_ALL_TOWNS(t) { if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) { - DEBUG(desync, 0, "town cache mismatch: town %i", (int)t->index); + CCLOG("town cache mismatch: town %i", (int)t->index); } i++; } @@ -1327,12 +1335,18 @@ void CheckCaches(bool force_check) i = 0; FOR_ALL_COMPANIES(c) { if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) { - DEBUG(desync, 0, "infrastructure cache mismatch: company %i", (int)c->index); + CCLOG("infrastructure cache mismatch: company %i", (int)c->index); char buffer[4096]; old_infrastructure[i].Dump(buffer, lastof(buffer)); - DEBUG(desync, 0, "Previous:\n%s", buffer); + CCLOG("Previous:"); + ProcessLineByLine(buffer, [&](const char *line) { + CCLOG(" %s", line); + }); c->infrastructure.Dump(buffer, lastof(buffer)); - DEBUG(desync, 0, "Recalculated:\n%s", buffer); + CCLOG("Recalculated:"); + ProcessLineByLine(buffer, [&](const char *line) { + CCLOG(" %s", line); + }); } i++; } @@ -1404,65 +1418,65 @@ void CheckCaches(bool force_check) 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, 0, "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); + CCLOG("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 (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)) { - DEBUG(desync, 0, "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); + CCLOG("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); } 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)) { - DEBUG(desync, 0, "VCF_GV_ZERO_SLOPE_RESIST set incorrectly: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); + CCLOG("VCF_GV_ZERO_SLOPE_RESIST set incorrectly: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } if (veh_old[length]->acceleration != u->acceleration) { - DEBUG(desync, 0, "acceleration mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("acceleration mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (veh_old[length]->breakdown_chance != u->breakdown_chance) { - DEBUG(desync, 0, "breakdown_chance mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("breakdown_chance mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (veh_old[length]->breakdown_ctr != u->breakdown_ctr) { - DEBUG(desync, 0, "breakdown_ctr mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("breakdown_ctr mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (veh_old[length]->breakdown_delay != u->breakdown_delay) { - DEBUG(desync, 0, "breakdown_delay mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("breakdown_delay mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (veh_old[length]->breakdowns_since_last_service != u->breakdowns_since_last_service) { - DEBUG(desync, 0, "breakdowns_since_last_service mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("breakdowns_since_last_service mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (veh_old[length]->breakdown_severity != u->breakdown_severity) { - DEBUG(desync, 0, "breakdown_severity mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("breakdown_severity mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (veh_old[length]->breakdown_type != u->breakdown_type) { - DEBUG(desync, 0, "breakdown_type mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("breakdown_type mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (veh_old[length]->vehicle_flags != u->vehicle_flags) { - DEBUG(desync, 0, "vehicle_flags mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("vehicle_flags mismatch: vehicle %i, company %i, unit number %i, wagon %i", 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, 0, "train ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("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, 0, "train cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("train cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (Train::From(veh_old[length])->railtype != Train::From(u)->railtype) { - DEBUG(desync, 0, "railtype mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("railtype mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (Train::From(veh_old[length])->compatible_railtypes != Train::From(u)->compatible_railtypes) { - DEBUG(desync, 0, "compatible_railtypes mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("compatible_railtypes mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (Train::From(veh_old[length])->flags != Train::From(u)->flags) { - DEBUG(desync, 0, "flags mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("flags 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, 0, "road vehicle ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("road vehicle ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; case VEH_AIRCRAFT: if (memcmp(&air_cache[length], &Aircraft::From(u)->acache, sizeof(AircraftCache)) != 0) { - DEBUG(desync, 0, "Aircraft vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); + CCLOG("Aircraft vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; default: @@ -1515,6 +1529,8 @@ void CheckCaches(bool force_check) if (tv->Prev()) assert_msg(tv->Prev()->Next() == tv, "%u", tv->index); if (tv->Next()) assert_msg(tv->Next()->Prev() == tv, "%u", tv->index); } + +#undef CCLOG } /** @@ -1529,7 +1545,7 @@ void CheckCaches(bool force_check) CommandCost CmdDesyncCheck(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (flags & DC_EXEC) { - CheckCaches(true); + CheckCaches(true, nullptr); } return CommandCost(); @@ -1588,7 +1604,7 @@ void StateGameLoop() SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false); } - CheckCaches(false); + CheckCaches(false, nullptr); /* All these actions has to be done from OWNER_NONE * for multiplayer compatibility */