Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add: List recently executed commands in crashlog output. #7366

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions src/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include "signal_func.h"
#include "core/backup_type.hpp"
#include "object_base.h"
#include "string_func.h"
#include <array>

#include "table/strings.h"

Expand Down Expand Up @@ -360,6 +362,80 @@ 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_MY_CMD = 0x10, ///< locally generated command
};
DECLARE_ENUM_AS_BIT_SET(CommandLogEntryFlagEnum)
typedef SimpleTinyEnumT<CommandLogEntryFlagEnum, byte> CommandLogEntryFlag;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think C++11 enum base type declarations are acceptable to use now, i.e. declaring enum: CommandLogEntryFlag : byte { CLEF_NONE ... }; so separate enum and storage types are not required.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also wonder if we should start using enum classes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely change this to enum with underlying type ahead of #7538


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(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)
{}
};

static std::array<CommandLogEntry, 32> command_log;
static unsigned int command_log_count = 0;
static unsigned int command_log_next = 0;

void ClearRecentCommandLog()
{
command_log_count = 0;
command_log_next = 0;
}

char *DumpRecentCommandLog(char *buffer, const char *last)
{
const unsigned int count = min<unsigned int>(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 | ",
fc(CLEF_MY_CMD, 'm'), 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
*
Expand Down Expand Up @@ -673,6 +749,17 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_TESTMODE);
SetTownRatingTestMode(false);

CommandLogEntryFlag log_flags;
log_flags = CLEF_NONE;
if (res.Failed()) log_flags |= CLEF_CMD_FAILED;
if (_generating_world) log_flags |= CLEF_GENERATING_WORLD;
if (!StrEmpty(text)) log_flags |= CLEF_TEXT;
if (estimate_only) log_flags |= CLEF_ESTIMATE_ONLY;
if (my_cmd) log_flags |= CLEF_MY_CMD;
command_log[command_log_next] = CommandLogEntry(tile, p1, p2, cmd, log_flags);
command_log_next = (command_log_next + 1) % command_log.size();
command_log_count++;

/* Make sure we're not messing things up here. */
assert(exec_as_spectator ? _current_company == COMPANY_SPECTATOR : cur_company.Verify());

Expand Down
3 changes: 3 additions & 0 deletions src/command_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ static inline DoCommandFlag CommandFlagsToDCFlags(CommandFlags cmd_flags)
return flags;
}

void ClearRecentCommandLog();
char *DumpRecentCommandLog(char *buffer, const char *last);

/*** All command callbacks that exist ***/

/* ai/ai_instance.cpp */
Expand Down
15 changes: 15 additions & 0 deletions src/crashlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "language.h"
#include "fontcache.h"
#include "news_gui.h"
#include "command_func.h"

#include "ai/ai_info.hpp"
#include "game/game.hpp"
Expand Down Expand Up @@ -323,6 +324,19 @@ char *CrashLog::LogRecentNews(char *buffer, const char *last) const
return buffer;
}

/**
* Writes the recent 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::LogRecentCommands(char *buffer, const char *last) const
{
buffer = DumpRecentCommandLog(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.
Expand Down Expand Up @@ -350,6 +364,7 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const
buffer = this->LogModules(buffer, last);
buffer = this->LogGamelog(buffer, last);
buffer = this->LogRecentNews(buffer, last);
buffer = this->LogRecentCommands(buffer, last);

buffer += seprintf(buffer, last, "*** End of OpenTTD Crash Report ***\n");
return buffer;
Expand Down
1 change: 1 addition & 0 deletions src/crashlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class CrashLog {
char *LogLibraries(char *buffer, const char *last) const;
char *LogGamelog(char *buffer, const char *last) const;
char *LogRecentNews(char *buffer, const char *list) const;
char *LogRecentCommands(char *buffer, const char *last) const;

public:
/** Stub destructor to silence some compilers. */
Expand Down
3 changes: 3 additions & 0 deletions src/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "station_kdtree.h"
#include "town_kdtree.h"
#include "viewport_kdtree.h"
#include "command_func.h"

#include "safeguards.h"

Expand Down Expand Up @@ -63,6 +64,8 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin

AllocateMap(size_x, size_y);

ClearRecentCommandLog();

_pause_mode = PM_UNPAUSED;
_fast_forward = 0;
_tick_counter = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/openttd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ static void ShutdownGame()
FioCloseAll();

UninitFreeType();

ClearRecentCommandLog();
}

/**
Expand Down