From 349ddd90b71b2c77dd9f06b09ca9e556b1c48c60 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 21 Feb 2017 21:04:28 +0000 Subject: [PATCH] Maintain a circular buffer of recent commands, add to crashlog. Add console command to dump command log. Increase max crashlog size. --- src/command.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/command_func.h | 3 ++ src/console_cmds.cpp | 14 +++++++ src/crashlog.cpp | 17 ++++++++- src/crashlog.h | 1 + src/misc.cpp | 3 ++ src/openttd.cpp | 2 + 7 files changed, 129 insertions(+), 1 deletion(-) diff --git a/src/command.cpp b/src/command.cpp index b22edca681..aee9153021 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -29,6 +29,7 @@ #include "newgrf_text.h" #include "string_func.h" #include "scope_info.h" +#include #include "table/strings.h" @@ -359,6 +360,85 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT }; + +/** + * List of flags for a command log entry + */ +enum CommandLogEntryFlagEnum { + CLEF_NONE = 0x00, ///< no flag is set + CLEF_CMD_FAILED = 0x01, ///< command failed + CLEF_GENERATING_WORLD = 0x02, ///< generating world + CLEF_TEXT = 0x04, ///< have command text + CLEF_ESTIMATE_ONLY = 0x08, ///< estimate only + CLEF_ONLY_SENDING = 0x10, ///< only sending + CLEF_MY_CMD = 0x20, ///< locally generated command +}; +DECLARE_ENUM_AS_BIT_SET(CommandLogEntryFlagEnum) +typedef SimpleTinyEnumT CommandLogEntryFlag; + +struct CommandLogEntry { + TileIndex tile; + uint32 p1; + uint32 p2; + uint32 cmd; + Date date; + DateFract date_fract; + CompanyByte current_company; + CompanyByte local_company; + CommandLogEntryFlag log_flags; + + CommandLogEntry() { } + + CommandLogEntry(const CommandCost &res, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandLogEntryFlag log_flags) + : tile(tile), p1(p1), p2(p2), cmd(cmd), date(_date), date_fract(_date_fract), + current_company(_current_company), local_company(_local_company), log_flags(log_flags) + { + if (res.Failed()) this->log_flags |= CLEF_CMD_FAILED; + if (_generating_world) this->log_flags |= CLEF_GENERATING_WORLD; + } +}; + +static std::array command_log; +static unsigned int command_log_count = 0; +static unsigned int command_log_next = 0; + +void ClearCommandLog() +{ + command_log_count = 0; + command_log_next = 0; +} + +char *DumpCommandLog(char *buffer, const char *last) +{ + const unsigned int count = min(command_log_count, command_log.size()); + unsigned int log_index = command_log_next; + + buffer += seprintf(buffer, last, "Command Log:\n Showing most recent %u of %u commands\n", count, command_log_count); + + for (unsigned int i = 0 ; i < count; i++) { + if (log_index > 0) { + log_index--; + } else { + log_index = command_log.size() - 1; + } + const CommandLogEntry &entry = command_log[log_index]; + + auto fc = [&](CommandLogEntryFlagEnum flag, char c) -> char { + return entry.log_flags & flag ? c : '-'; + }; + + YearMonthDay ymd; + ConvertDateToYMD(entry.date, &ymd); + buffer += seprintf(buffer, last, " %3u | %4i-%02i-%02i, %2i | ", i, ymd.year, ymd.month + 1, ymd.day, entry.date_fract); + buffer += seprintf(buffer, last, "%c%c%c%c%c%c | ", + fc(CLEF_MY_CMD, 'm'), fc(CLEF_ONLY_SENDING, 's'), fc(CLEF_ESTIMATE_ONLY, 'e'), + fc(CLEF_TEXT, 't'), fc(CLEF_GENERATING_WORLD, 'g'), fc(CLEF_CMD_FAILED, 'f')); + buffer += seprintf(buffer, last, " %7d x %7d, p1: 0x%08X, p2: 0x%08X, cc: %2u, lc: %2u, cmd: 0x%08X (%s)\n", + TileX(entry.tile), TileY(entry.tile), entry.p1, entry.p2, (uint) entry.current_company, (uint) entry.local_company, entry.cmd, GetCommandName(entry.cmd)); + } + return buffer; +} + /*! * This function range-checks a cmd, and checks if the cmd is not NULL * @@ -605,6 +685,16 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac callback(res, tile, p1, p2); } + CommandLogEntryFlag log_flags; + log_flags = CLEF_NONE; + if (!StrEmpty(text)) log_flags |= CLEF_TEXT; + if (estimate_only) log_flags |= CLEF_ESTIMATE_ONLY; + if (only_sending) log_flags |= CLEF_ONLY_SENDING; + if (my_cmd) log_flags |= CLEF_MY_CMD; + command_log[command_log_next] = CommandLogEntry(res, tile, p1, p2, cmd, log_flags); + command_log_next = (command_log_next + 1) % command_log.size(); + command_log_count++; + return res.Succeeded(); } diff --git a/src/command_func.h b/src/command_func.h index 3369475675..b6f5ae07d3 100644 --- a/src/command_func.h +++ b/src/command_func.h @@ -68,6 +68,9 @@ static inline DoCommandFlag CommandFlagsToDCFlags(CommandFlags cmd_flags) return flags; } +void ClearCommandLog(); +char *DumpCommandLog(char *buffer, const char *last); + /*** All command callbacks that exist ***/ /* ai/ai_instance.cpp */ diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 6f28d3bb7e..6e68e9dd7c 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -1875,6 +1875,19 @@ DEF_CONSOLE_CMD(ConNewGRFReload) return true; } +DEF_CONSOLE_CMD(ConDumpCommandLog) +{ + if (argc == 0) { + IConsoleHelp("Dump log of recently executed commands."); + return true; + } + + char buffer[32768]; + DumpCommandLog(buffer, lastof(buffer)); + PrintLineByLine(buffer); + return true; +} + #ifdef _DEBUG /****************** * debug commands @@ -2018,6 +2031,7 @@ void IConsoleStdLibRegister() #ifdef _DEBUG IConsoleDebugLibRegister(); #endif + IConsoleCmdRegister("dump_command_log", ConDumpCommandLog, nullptr, true); /* NewGRF development stuff */ IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool); diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 1c82b88a04..bcf0cb0b11 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -29,6 +29,7 @@ #include "language.h" #include "fontcache.h" #include "scope_info.h" +#include "command_func.h" #include "thread/thread.h" #include "ai/ai_info.hpp" @@ -328,6 +329,19 @@ char *CrashLog::LogGamelog(char *buffer, const char *last) const return CrashLog::gamelog_buffer + seprintf(CrashLog::gamelog_buffer, last, "\n"); } +/** + * Writes the command log data to the buffer. + * @param buffer The begin where to write at. + * @param last The last position in the buffer to write to. + * @return the position of the \c '\0' character after the buffer. + */ +char *CrashLog::LogCommandLog(char *buffer, const char *last) const +{ + buffer = DumpCommandLog(buffer, last); + buffer += seprintf(buffer, last, "\n"); + return buffer; +} + /** * Fill the crash log buffer with all data of a crash log. * @param buffer The begin where to write at. @@ -362,6 +376,7 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const buffer = this->LogLibraries(buffer, last); buffer = this->LogModules(buffer, last); buffer = this->LogGamelog(buffer, last); + buffer = this->LogCommandLog(buffer, last); buffer += seprintf(buffer, last, "*** End of OpenTTD Crash Report ***\n"); return buffer; @@ -454,7 +469,7 @@ bool CrashLog::MakeCrashLog() const crashlogged = true; char filename[MAX_PATH]; - char buffer[65536]; + char buffer[65536 * 2]; bool ret = true; printf("Crash encountered, generating crash log...\n"); diff --git a/src/crashlog.h b/src/crashlog.h index 37ac9ae10e..c59f73aba8 100644 --- a/src/crashlog.h +++ b/src/crashlog.h @@ -103,6 +103,7 @@ protected: char *LogConfiguration(char *buffer, const char *last) const; char *LogLibraries(char *buffer, const char *last) const; char *LogGamelog(char *buffer, const char *last) const; + char *LogCommandLog(char *buffer, const char *last) const; public: /** Stub destructor to silence some compilers. */ diff --git a/src/misc.cpp b/src/misc.cpp index d9d506993f..864f680e05 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -28,6 +28,7 @@ #include "core/pool_type.hpp" #include "game/game.hpp" #include "linkgraph/linkgraphschedule.h" +#include "command_func.h" #include "safeguards.h" @@ -59,6 +60,8 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin AllocateMap(size_x, size_y); + ClearCommandLog(); + _pause_mode = PM_UNPAUSED; _fast_forward = 0; _tick_counter = 0; diff --git a/src/openttd.cpp b/src/openttd.cpp index cedbd58127..d7e0788142 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -331,6 +331,8 @@ static void ShutdownGame() FioCloseAll(); UninitFreeType(); + + ClearCommandLog(); } /**