diff --git a/src/command.cpp b/src/command.cpp index 4f0cd2942a..b5d3e9bfd3 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -933,8 +933,10 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, SetTownRatingTestMode(false); if (!random_state.Check()) { - DEBUG(desync, 0, "Random seed changed in test command: date{%08x; %02x; %02x}; company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; cmd: %08x; \"%s\" %X (%s)", - _date, _date_fract, _tick_skip_counter, (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, binary_length, GetCommandName(cmd)); + std::string msg = stdstr_fmt("Random seed changed in test command: company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; cmd: %08x; \"%s\" %X (%s)", + (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, binary_length, GetCommandName(cmd)); + DEBUG(desync, 0, "msg: date{%08x; %02x; %02x}; %s", _date, _date_fract, _tick_skip_counter, msg.c_str()); + LogDesyncMsg(std::move(msg)); } /* Make sure we're not messing things up here. */ diff --git a/src/crashlog.cpp b/src/crashlog.cpp index baef530cab..0d376fcf21 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -459,6 +459,7 @@ char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last) const buffer = this->LogGamelog(buffer, last); buffer = this->LogRecentNews(buffer, last); buffer = this->LogCommandLog(buffer, last); + buffer = DumpDesyncMsgLog(buffer, last); bool have_cache_log = false; extern void CheckCaches(bool force_check, std::function log); diff --git a/src/debug.cpp b/src/debug.cpp index 210a150012..f7fcc8353f 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -16,6 +16,8 @@ #include "string_func.h" #include "fileio_func.h" #include "settings_type.h" +#include "date_func.h" +#include #if defined(_WIN32) #include "os/windows/win32.h" @@ -305,3 +307,56 @@ const char *GetLogPrefix() return _log_prefix; } +struct DesyncMsgLogEntry { + Date date; + DateFract date_fract; + uint8 tick_skip_counter; + std::string msg; + + DesyncMsgLogEntry() { } + + DesyncMsgLogEntry(std::string msg) + : date(_date), date_fract(_date_fract), tick_skip_counter(_tick_skip_counter), msg(msg) { } +}; + +static std::array desync_msg_log; +static unsigned int desync_msg_log_count = 0; +static unsigned int desync_msg_log_next = 0; + +void ClearDesyncMsgLog() +{ + desync_msg_log_count = 0; + desync_msg_log_next = 0; +} + +char *DumpDesyncMsgLog(char *buffer, const char *last) +{ + if (!desync_msg_log_count) return buffer; + + const unsigned int count = min(desync_msg_log_count, desync_msg_log.size()); + unsigned int log_index = desync_msg_log_next; + + buffer += seprintf(buffer, last, "Desync Msg Log:\n Showing most recent %u of %u messages\n", count, desync_msg_log_count); + + for (unsigned int i = 0 ; i < count; i++) { + if (log_index > 0) { + log_index--; + } else { + log_index = desync_msg_log.size() - 1; + } + const DesyncMsgLogEntry &entry = desync_msg_log[log_index]; + + YearMonthDay ymd; + ConvertDateToYMD(entry.date, &ymd); + buffer += seprintf(buffer, last, " %2u | %4i-%02i-%02i, %2i, %3i | %s\n", i, ymd.year, ymd.month + 1, ymd.day, entry.date_fract, entry.tick_skip_counter, entry.msg.c_str()); + } + buffer += seprintf(buffer, last, "\n"); + return buffer; +} + +void LogDesyncMsg(std::string msg) +{ + desync_msg_log[desync_msg_log_next] = DesyncMsgLogEntry(std::move(msg)); + desync_msg_log_next = (desync_msg_log_next + 1) % desync_msg_log.size(); + desync_msg_log_count++; +} diff --git a/src/debug.h b/src/debug.h index 2f8ce7db2d..a6e6c4de17 100644 --- a/src/debug.h +++ b/src/debug.h @@ -133,4 +133,8 @@ const char *GetLogPrefix(); /** The real time in the game. */ extern uint32 _realtime_tick; +void ClearDesyncMsgLog(); +void LogDesyncMsg(std::string msg); +char *DumpDesyncMsgLog(char *buffer, const char *last); + #endif /* DEBUG_H */ diff --git a/src/misc.cpp b/src/misc.cpp index d9a7534a8b..8fc15a5d15 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -72,6 +72,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin ViewportMapClearTunnelCache(); ClearCommandLog(); + ClearDesyncMsgLog(); _pause_mode = PM_UNPAUSED; _fast_forward = 0; diff --git a/src/openttd.cpp b/src/openttd.cpp index 6ba396f27e..50d05eda6f 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -382,6 +382,7 @@ static void ShutdownGame() InvalidateVehicleTickCaches(); ClearVehicleTickCaches(); ClearCommandLog(); + ClearDesyncMsgLog(); _game_events_since_load = (GameEventFlags) 0; _game_events_overall = (GameEventFlags) 0; @@ -1304,7 +1305,11 @@ void CheckCaches(bool force_check, std::function log) #define CCLOG(...) { \ seprintf(cclog_buffer, lastof(cclog_buffer), __VA_ARGS__); \ DEBUG(desync, 0, "%s", cclog_buffer); \ - if (log) log(cclog_buffer); \ + if (log) { \ + log(cclog_buffer); \ + } else { \ + LogDesyncMsg(cclog_buffer); \ + } \ } /* Check the town caches. */