diff --git a/src/command.cpp b/src/command.cpp index 4fa5c4eb46..89cfdba1d7 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -36,6 +36,7 @@ #include "order_backup.h" #include "core/ring_buffer.hpp" #include "core/checksum_func.hpp" +#include "3rdparty/nlohmann/json.hpp" #include #include "table/strings.h" @@ -1180,6 +1181,31 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, /* Make sure we're not messing things up here. */ assert(exec_as_spectator ? _current_company == COMPANY_SPECTATOR : cur_company.Verify()); + auto log_desync_cmd = [&](const char *prefix) { + if (_debug_desync_level >= 1) { + std::string aux_str; + if (aux_data != nullptr) { + std::vector buffer; + CommandSerialisationBuffer serialiser(buffer, SHRT_MAX); + aux_data->Serialise(serialiser); + aux_str = FormatArrayAsHex(buffer); + } + std::string text_buf; + if (text != nullptr) { + nlohmann::json j_string = text; + text_buf = j_string.dump(-1, ' ', true); + } else { + text_buf = "\"\""; + } + + /* Use stdstr_fmt and debug_print to avoid truncation limits of DEBUG, text/aux_data may be very large */ + std::string dbg_info = stdstr_fmt("%s: %s; company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; %s <%s> (%s)", + prefix, debug_date_dumper().HexDate(), (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, + cmd & ~CMD_NETWORK_COMMAND, text_buf.c_str(), aux_str.c_str(), GetCommandName(cmd)); + debug_print("desync", dbg_info.c_str()); + } + }; + /* If the command fails, we're doing an estimate * or the player does not have enough money * (unless it's a command where the test and @@ -1190,8 +1216,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, if (!_networking || _generating_world || (cmd & CMD_NETWORK_COMMAND) != 0) { /* Log the failed command as well. Just to be able to be find * causes of desyncs due to bad command test implementations. */ - DEBUG(desync, 1, "cmdf: %s; company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; \"%s\"%s (%s)", - debug_date_dumper().HexDate(), (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, cmd & ~CMD_NETWORK_COMMAND, text, aux_data != nullptr ? ", aux data present" : "", GetCommandName(cmd)); + log_desync_cmd("cmdf"); } cur_company.Restore(); return_dcpi(res); @@ -1211,8 +1236,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint64 p3, * reset the storages as we've not executed the command. */ return_dcpi(CommandCost()); } - DEBUG(desync, 1, "cmd: %s; company: %02x; tile: %06x (%u x %u); p1: %08x; p2: %08x; p3: " OTTD_PRINTFHEX64PAD "; cmd: %08x; \"%s\"%s(%s)", - debug_date_dumper().HexDate(), (int)_current_company, tile, TileX(tile), TileY(tile), p1, p2, p3, cmd & ~CMD_NETWORK_COMMAND, text, aux_data != nullptr ? ", aux data present" : "", GetCommandName(cmd)); + log_desync_cmd("cmd"); /* Actually try and execute the command. If no cost-type is given * use the construction one */