35 this->data = std::make_unique<GamelogInternalData>();
37 this->current_action =
nullptr;
49 if (IsReleasedVersion()) {
50 return _openttd_revision;
54 assert(_openttd_revision_modified < 3);
55 return fmt::format(
"{}{}",
56 "gum"[_openttd_revision_modified],
57 _openttd_revision_hash);
68 this->action_type = at;
78 bool print = this->current_action !=
nullptr;
80 this->current_action =
nullptr;
86void Gamelog::StopAnyAction()
97 this->data->action.clear();
98 this->current_action =
nullptr;
109static void AddGrfInfo(std::back_insert_iterator<std::string> &output_iterator, uint32_t grfid,
const MD5Hash *md5sum,
const GRFConfig *gc)
111 if (md5sum !=
nullptr) {
114 fmt::format_to(output_iterator,
"GRF ID {:08X}",
BSWAP32(grfid));
118 fmt::format_to(output_iterator,
", filename: {} (md5sum matches)", gc->
filename);
122 fmt::format_to(output_iterator,
", filename: {} (matches GRFID only)", gc->
filename);
124 fmt::format_to(output_iterator,
", unknown GRF");
134 "GRF config changed",
138 "emergency savegame",
149 GrfIDMapping grf_names;
151 proc(
"---- gamelog start ----");
156 proc(fmt::format(
"Tick {}: {}", la.tick,
la_text[la.at]));
158 for (
auto &lc : la.change) {
160 auto output_iterator = std::back_inserter(message);
161 lc->FormatTo(output_iterator, grf_names, la.at);
167 proc(
"---- gamelog end ----");
171 void LoggedChangeMode::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &,
GamelogActionType)
174 fmt::format_to(output_iterator,
"New game mode: {} landscape: {}", this->
mode, this->
landscape);
177 void LoggedChangeRevision::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &,
GamelogActionType)
180 fmt::format_to(output_iterator,
"Revision text changed to {}, savegame version {}, ",
183 switch (this->modified) {
184 case 0: fmt::format_to(output_iterator,
"not ");
break;
185 case 1: fmt::format_to(output_iterator,
"maybe ");
break;
189 fmt::format_to(output_iterator,
"modified, _openttd_newgrf_version = 0x{:08x}", this->
newgrf);
192 void LoggedChangeOldVersion::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &,
GamelogActionType)
195 fmt::format_to(output_iterator,
"Conversion from ");
196 switch (this->
type) {
197 default: NOT_REACHED();
199 fmt::format_to(output_iterator,
"OTTD savegame without gamelog: version {}, {}",
204 fmt::format_to(output_iterator,
"TTO savegame");
208 fmt::format_to(output_iterator,
"TTD savegame");
213 fmt::format_to(output_iterator,
"TTDP savegame, {} format",
216 fmt::format_to(output_iterator,
", TTDP version {}.{}.{}.{}",
224 void LoggedChangeSettingChanged::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &,
GamelogActionType)
227 fmt::format_to(output_iterator,
"Setting changed: {} : {} -> {}", this->
name, this->
oldval, this->
newval);
230 void LoggedChangeGRFAdd::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names,
GamelogActionType)
234 fmt::format_to(output_iterator,
"Added NewGRF: ");
236 auto gm = grf_names.find(this->
grfid);
237 if (gm != grf_names.end() && !gm->second.was_missing) fmt::format_to(output_iterator,
". Gamelog inconsistency: GrfID was already added!");
238 grf_names[this->
grfid] = gc;
241 void LoggedChangeGRFRemoved::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names,
GamelogActionType action_type)
244 auto gm = grf_names.find(this->
grfid);
246 fmt::format_to(output_iterator,
"Missing NewGRF: ");
248 fmt::format_to(output_iterator,
"Removed NewGRF: ");
250 AddGrfInfo(output_iterator, this->
grfid,
nullptr, gm != grf_names.end() ? gm->second.gc : nullptr);
251 if (gm == grf_names.end()) {
252 fmt::format_to(output_iterator,
". Gamelog inconsistency: GrfID was never added!");
256 gm->second.was_missing =
true;
263 void LoggedChangeGRFChanged::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names,
GamelogActionType)
267 fmt::format_to(output_iterator,
"Compatible NewGRF loaded: ");
269 if (grf_names.count(this->grfid) == 0) fmt::format_to(output_iterator,
". Gamelog inconsistency: GrfID was never added!");
270 grf_names[this->
grfid] = gc;
273 void LoggedChangeGRFParameterChanged::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names,
GamelogActionType)
276 auto gm = grf_names.find(this->
grfid);
277 fmt::format_to(output_iterator,
"GRF parameter changed: ");
278 AddGrfInfo(output_iterator, this->
grfid,
nullptr, gm != grf_names.end() ? gm->second.gc : nullptr);
279 if (gm == grf_names.end()) fmt::format_to(output_iterator,
". Gamelog inconsistency: GrfID was never added!");
282 void LoggedChangeGRFMoved::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names,
GamelogActionType)
285 auto gm = grf_names.find(this->
grfid);
286 fmt::format_to(output_iterator,
"GRF order changed: {:08X} moved {} places {}",
288 AddGrfInfo(output_iterator, this->
grfid,
nullptr, gm != grf_names.end() ? gm->second.gc : nullptr);
289 if (gm == grf_names.end()) fmt::format_to(output_iterator,
". Gamelog inconsistency: GrfID was never added!");
292 void LoggedChangeGRFBug::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names,
GamelogActionType)
295 auto gm = grf_names.find(this->
grfid);
298 fmt::format_to(output_iterator,
"Rail vehicle changes length outside a depot: GRF ID {:08X}, internal ID 0x{:X}",
BSWAP32(this->
grfid), this->
data);
299 AddGrfInfo(output_iterator, this->
grfid,
nullptr, gm != grf_names.end() ? gm->second.gc : nullptr);
300 if (gm == grf_names.end()) fmt::format_to(output_iterator,
". Gamelog inconsistency: GrfID was never added!");
303 void LoggedChangeEmergencySave::FormatTo(std::back_insert_iterator<std::string> &, GrfIDMapping &,
GamelogActionType)
312 this->
Print([](
const std::string &s) {
325 this->
Print([level](
const std::string &s) {
326 Debug(gamelog, level,
"{}", s);
337 if (this->current_action ==
nullptr) {
338 if (this->action_type ==
GLAT_NONE)
return;
340 this->current_action = &this->data->action.emplace_back();
341 this->current_action->
at = this->action_type;
345 this->current_action->
change.push_back(std::move(change));
357 this->
Change(std::make_unique<LoggedChangeEmergencySave>());
367 for (
const auto &lc : la.change) {
382 this->
Change(std::make_unique<LoggedChangeRevision>(
417 this->
Change(std::make_unique<LoggedChangeSettingChanged>(name, oldval, newval));
430 for (
const auto &lc : la.change) {
436 rev->modified != _openttd_revision_modified ||
437 rev->
newgrf != _openttd_newgrf_version) {
451 for (
const auto &lc : la.change) {
470 this->
Change(std::make_unique<LoggedChangeGRFBug>(data, grfid, bug));
485 for (
const auto &lc : la.change) {
521 this->
Change(std::make_unique<LoggedChangeGRFRemoved>(grfid));
534 this->
Change(std::make_unique<LoggedChangeGRFAdd>(newg->
ident));
546 this->
Change(std::make_unique<LoggedChangeGRFChanged>(*newg));
556 assert(this->action_type ==
GLAT_GRF);
558 this->
Change(std::make_unique<LoggedChangeGRFMoved>(grfid, offset));
568 assert(this->action_type ==
GLAT_GRF);
570 this->
Change(std::make_unique<LoggedChangeGRFParameterChanged>(grfid));
582 for (; newg !=
nullptr; newg = newg->
next) {
593 std::vector<const GRFConfig *> list;
613 while (o < ol.size() && n < nl.size()) {
619 for (oi = 0; oi < ol.size(); oi++) {
620 if (ol[oi]->ident.grfid == nl[n]->ident.grfid)
break;
627 if (oi == ol.size()) {
632 for (ni = 0; ni < nl.size(); ni++) {
633 if (nl[ni]->ident.grfid == ol[o]->ident.grfid)
break;
640 if (ni == nl.size()) {
648 assert(ni > n && ni < nl.size());
649 assert(oi > o && oi < ol.size());
656 this->
GRFMove(ol[o++]->ident.grfid, ni);
658 this->
GRFMove(nl[n++]->ident.grfid, -(
int)oi);
675 while (o < ol.size()) this->
GRFRemove(ol[o++]->ident.grfid);
676 while (n < nl.size()) this->
GRFAdd (nl[n++]);
685void Gamelog::Info(uint32_t *last_ottd_rev, uint8_t *ever_modified,
bool *removed_newgrfs)
688 for (
const auto &lc : la.change) {
694 *last_ottd_rev = rev->
newgrf;
695 *ever_modified = std::max(*ever_modified, rev->modified);
700 *removed_newgrfs =
true;
714 assert(c !=
nullptr);
718 for (
const auto &lc : la.
change) {
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static uint32_t BSWAP32(uint32_t x)
Perform a 32 bits endianness bitswap on x.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
void TestRevision()
Finds out if current revision is different than last revision stored in the savegame.
void GRFBug(uint32_t grfid, uint8_t bug, uint64_t data)
Logs triggered GRF bug.
void Mode()
Logs a change in game mode (scenario editor or game)
void Info(uint32_t *last_ottd_rev, uint8_t *ever_modified, bool *removed_newgrfs)
Get some basic information from the given gamelog.
void PrintDebug(int level)
Prints gamelog to debug output.
void GRFAddList(const GRFConfig *newg)
Logs adding of list of GRFs.
void PrintConsole()
Print the gamelog data to the console.
void GRFCompatible(const GRFIdentifier *newg)
Logs loading compatible GRF (the same ID, but different MD5 hash)
void GRFParameters(uint32_t grfid)
Logs change in GRF parameters.
void Revision()
Logs a change in game revision.
void StartAction(GamelogActionType at)
Stores information about new action, but doesn't allocate it Action is allocated only when there is a...
void Reset()
Resets and frees all memory allocated - used before loading or starting a new game.
const GRFIdentifier * GetOverriddenIdentifier(const GRFConfig *c)
Try to find the overridden GRF identifier of the given GRF.
void GRFRemove(uint32_t grfid)
Logs removal of a GRF.
void GRFUpdate(const GRFConfig *oldg, const GRFConfig *newg)
Compares two NewGRF lists and logs any change.
void Oldver()
Logs loading from savegame without gamelog.
void Emergency()
Logs a emergency savegame.
bool GRFBugReverse(uint32_t grfid, uint16_t internal_id)
Logs GRF bug - rail vehicle has different length after reversing.
void TestMode()
Finds last stored game mode or landscape.
void StopAction()
Stops logging of any changes.
void Setting(const std::string &name, int32_t oldval, int32_t newval)
Logs change in game settings.
void Print(std::function< void(const std::string &)> proc)
Prints active gamelog.
void Change(std::unique_ptr< LoggedChange > &&change)
Allocates a new LoggedAction if needed, and add the change when action is active.
bool TestEmergency()
Finds out if current game is a loaded emergency savegame.
void GRFMove(uint32_t grfid, int32_t offset)
Logs changing GRF order.
void GRFAdd(const GRFConfig *newg)
Logs adding of a GRF.
static TickCounter counter
Monotonic counter, in ticks, since start of game.
void IConsolePrint(TextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Console functions used outside of the console code.
static const TextColour CC_WARNING
Colour for warning lines.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
uint32_t _ttdp_version
version of TTDP savegame (if applicable)
SaveLoadVersion _sl_version
the major savegame version identifier
uint8_t _sl_minor_version
the minor savegame version, DO NOT USE!
static std::string GetGamelogRevisionString()
Return the revision string for the current client version, for use in gamelog.
Gamelog _gamelog
Gamelog instance.
static const char *const la_text[]
Text messages for various logged actions.
static void AddGrfInfo(std::back_insert_iterator< std::string > &output_iterator, uint32_t grfid, const MD5Hash *md5sum, const GRFConfig *gc)
Adds the GRF ID, checksum and filename if found to the output iterator.
SavegameType _savegame_type
type of savegame we are loading
static bool IsLoggableGrfConfig(const GRFConfig *g)
Decides if GRF should be logged.
const SaveLoadVersion SAVEGAME_VERSION
current savegame version
static std::vector< const GRFConfig * > GenerateGRFList(const GRFConfig *grfc)
Generates GRFList.
@ GLCT_MODE
Scenario editor x Game, different landscape.
@ GLCT_GRFCOMPAT
Loading compatible GRF.
@ GLCT_EMERGENCY
Emergency savegame.
@ GLCT_GRFBUG
GRF bug triggered.
@ GLCT_REVISION
Changed game revision string.
GamelogActionType
The actions we log.
@ GLAT_GRFBUG
GRF bug was triggered.
@ GLAT_START
Game created.
@ GLAT_NONE
No logging active; in savegames, end of list.
@ GLAT_END
So we know how many GLATs are there.
@ GLAT_CHEAT
Cheat was used.
@ GLAT_EMERGENCY
Emergency savegame.
@ GLAT_SETTING
Setting changed.
Declaration shared among gamelog.cpp and saveload/gamelog_sl.cpp.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
@ GCF_STATIC
GRF file is used statically (can be used in any MP game)
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
@ GBUG_VEH_LENGTH
Length of rail vehicle changes when not inside a depot.
@ FGCM_ANY
Use first found.
@ FGCM_EXACT
Only find Grfs matching md5sum.
declaration of OTTD revision dependent variables
A number of safeguards to prevent using unsafe methods.
Functions/types related to saving and loading games.
SavegameType
Types of save games.
@ SGT_TTD
TTD savegame (can be detected incorrectly)
@ SGT_TTDP2
TTDP savegame in new format (data at SE border)
@ SGT_TTDP1
TTDP savegame ( -//- ) (data at NW border)
SaveLoadVersion
SaveLoad versions Previous savegame versions, the trunk revision where they were introduced and the r...
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Types related to global configuration settings.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Functions related to low-level strings.
Information about GRF, used in the game and (part of it) in savegames.
uint8_t flags
NOSAVE: GCF_Flags, bitset.
std::vector< uint32_t > param
GRF parameters.
struct GRFConfig * next
NOSAVE: Next item in the linked list.
GRFStatus status
NOSAVE: GRFStatus, enum.
std::string filename
Filename - either with or without full path.
GRFIdentifier ident
grfid and md5sum to uniquely identify newgrfs
Basic data to distinguish a GRF.
uint32_t grfid
GRF ID (defined by Action 0x08)
MD5Hash md5sum
MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
uint8_t landscape
the landscape we're currently in
GameCreationSettings game_creation
settings used during the creation of a game (map)
Contains information about one logged action that caused at least one logged change.
uint64_t tick
Tick when it happened.
std::vector< std::unique_ptr< LoggedChange > > change
Logged changes in this action.
GamelogActionType at
Type of action.
uint64_t data
additional data
uint32_t grfid
ID of problematic GRF.
uint32_t grfid
ID of moved GRF.
int32_t offset
offset, positive = move down
uint32_t grfid
ID of GRF with changed parameters.
uint32_t grfid
ID of removed GRF.
uint8_t landscape
landscape (temperate, arctic, ...)
uint8_t mode
new game mode - Editor x Game
uint32_t type
type of savegame,
uint32_t version
major and minor version OR ttdp version
std::string text
revision string, _openttd_revision
uint16_t slver
_sl_version
uint32_t newgrf
_openttd_newgrf_version
std::string name
name of the setting
Definition of the game-calendar-timer.
Definition of the tick-based game-timer.