OpenTTD Source 20250205-master-gfd85ab1e2c
gamelog.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "saveload/saveload.h"
12#include "string_func.h"
13#include "settings_type.h"
14#include "gamelog_internal.h"
15#include "console_func.h"
16#include "debug.h"
19#include "rev.h"
20
21#include "safeguards.h"
22
24
26
27extern uint32_t _ttdp_version;
29extern uint8_t _sl_minor_version;
30
32
33Gamelog::Gamelog()
34{
35 this->data = std::make_unique<GamelogInternalData>();
36 this->action_type = GLAT_NONE;
37 this->current_action = nullptr;
38}
39
40Gamelog::~Gamelog()
41{
42}
43
47static std::string GetGamelogRevisionString()
48{
49 if (IsReleasedVersion()) {
50 return _openttd_revision;
51 }
52
53 /* Prefix character indication revision status */
54 assert(_openttd_revision_modified < 3);
55 return fmt::format("{}{}",
56 "gum"[_openttd_revision_modified], // g = "git", u = "unknown", m = "modified"
57 _openttd_revision_hash);
58}
59
66{
67 assert(this->action_type == GLAT_NONE); // do not allow starting new action without stopping the previous first
68 this->action_type = at;
69}
70
75{
76 assert(this->action_type != GLAT_NONE); // nobody should try to stop if there is no action in progress
77
78 bool print = this->current_action != nullptr;
79
80 this->current_action = nullptr;
81 this->action_type = GLAT_NONE;
82
83 if (print) this->PrintDebug(5);
84}
85
86void Gamelog::StopAnyAction()
87{
88 if (this->action_type != GLAT_NONE) this->StopAction();
89}
90
95{
96 assert(this->action_type == GLAT_NONE);
97 this->data->action.clear();
98 this->current_action = nullptr;
99}
100
109static void AddGrfInfo(std::back_insert_iterator<std::string> &output_iterator, uint32_t grfid, const MD5Hash *md5sum, const GRFConfig *gc)
110{
111 if (md5sum != nullptr) {
112 fmt::format_to(output_iterator, "GRF ID {:08X}, checksum {}", std::byteswap(grfid), FormatArrayAsHex(*md5sum));
113 } else {
114 fmt::format_to(output_iterator, "GRF ID {:08X}", std::byteswap(grfid));
115 }
116
117 if (gc != nullptr) {
118 fmt::format_to(output_iterator, ", filename: {} (md5sum matches)", gc->filename);
119 } else {
120 gc = FindGRFConfig(grfid, FGCM_ANY);
121 if (gc != nullptr) {
122 fmt::format_to(output_iterator, ", filename: {} (matches GRFID only)", gc->filename);
123 } else {
124 fmt::format_to(output_iterator, ", unknown GRF");
125 }
126 }
127}
128
129
131static const char * const la_text[] = {
132 "new game started",
133 "game loaded",
134 "GRF config changed",
135 "cheat was used",
136 "settings changed",
137 "GRF bug triggered",
138 "emergency savegame",
139};
140
141static_assert(lengthof(la_text) == GLAT_END);
142
147void Gamelog::Print(std::function<void(const std::string &)> proc)
148{
149 GrfIDMapping grf_names;
150
151 proc("---- gamelog start ----");
152
153 for (const LoggedAction &la : this->data->action) {
154 assert(la.at < GLAT_END);
155
156 proc(fmt::format("Tick {}: {}", la.tick, la_text[la.at]));
157
158 for (auto &lc : la.change) {
159 std::string message;
160 auto output_iterator = std::back_inserter(message);
161 lc->FormatTo(output_iterator, grf_names, la.at);
162
163 proc(message);
164 }
165 }
166
167 proc("---- gamelog end ----");
168}
169
170
171/* virtual */ void LoggedChangeMode::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &, GamelogActionType)
172{
173 /* Changing landscape, or going from scenario editor to game or back. */
174 fmt::format_to(output_iterator, "New game mode: {} landscape: {}", this->mode, this->landscape);
175}
176
177/* virtual */ void LoggedChangeRevision::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &, GamelogActionType)
178{
179 /* The game was loaded in a diffferent version than before. */
180 fmt::format_to(output_iterator, "Revision text changed to {}, savegame version {}, ",
181 this->text, this->slver);
182
183 switch (this->modified) {
184 case 0: fmt::format_to(output_iterator, "not "); break;
185 case 1: fmt::format_to(output_iterator, "maybe "); break;
186 default: break;
187 }
188
189 fmt::format_to(output_iterator, "modified, _openttd_newgrf_version = 0x{:08x}", this->newgrf);
190}
191
192/* virtual */ void LoggedChangeOldVersion::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &, GamelogActionType)
193{
194 /* The game was loaded from before 0.7.0-beta1. */
195 fmt::format_to(output_iterator, "Conversion from ");
196 switch (this->type) {
197 default: NOT_REACHED();
198 case SGT_OTTD:
199 fmt::format_to(output_iterator, "OTTD savegame without gamelog: version {}, {}",
200 GB(this->version, 8, 16), GB(this->version, 0, 8));
201 break;
202
203 case SGT_TTO:
204 fmt::format_to(output_iterator, "TTO savegame");
205 break;
206
207 case SGT_TTD:
208 fmt::format_to(output_iterator, "TTD savegame");
209 break;
210
211 case SGT_TTDP1:
212 case SGT_TTDP2:
213 fmt::format_to(output_iterator, "TTDP savegame, {} format",
214 this->type == SGT_TTDP1 ? "old" : "new");
215 if (this->version != 0) {
216 fmt::format_to(output_iterator, ", TTDP version {}.{}.{}.{}",
217 GB(this->version, 24, 8), GB(this->version, 20, 4),
218 GB(this->version, 16, 4), GB(this->version, 0, 16));
219 }
220 break;
221 }
222}
223
224/* virtual */ void LoggedChangeSettingChanged::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &, GamelogActionType)
225{
226 /* A setting with the SettingFlag::NoNetwork flag got changed; these settings usually affect NewGRFs, such as road side or wagon speed limits. */
227 fmt::format_to(output_iterator, "Setting changed: {} : {} -> {}", this->name, this->oldval, this->newval);
228}
229
230/* virtual */ void LoggedChangeGRFAdd::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType)
231{
232 /* A NewGRF got added to the game, either at the start of the game (never an issue), or later on when it could be an issue. */
233 const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, &this->md5sum);
234 fmt::format_to(output_iterator, "Added NewGRF: ");
235 AddGrfInfo(output_iterator, this->grfid, &this->md5sum, gc);
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;
239}
240
241/* virtual */ void LoggedChangeGRFRemoved::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type)
242{
243 /* A NewGRF got removed from the game, either manually or by it missing when loading the game. */
244 auto gm = grf_names.find(this->grfid);
245 if (action_type == GLAT_LOAD) {
246 fmt::format_to(output_iterator, "Missing NewGRF: ");
247 } else {
248 fmt::format_to(output_iterator, "Removed NewGRF: ");
249 }
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!");
253 } else {
254 if (action_type == GLAT_LOAD) {
255 /* Missing grfs on load are not removed from the configuration */
256 gm->second.was_missing = true;
257 } else {
258 grf_names.erase(gm);
259 }
260 }
261}
262
263/* virtual */ void LoggedChangeGRFChanged::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType)
264{
265 /* Another version of the same NewGRF got loaded. */
266 const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, &this->md5sum);
267 fmt::format_to(output_iterator, "Compatible NewGRF loaded: ");
268 AddGrfInfo(output_iterator, this->grfid, &this->md5sum, gc);
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;
271}
272
273/* virtual */ void LoggedChangeGRFParameterChanged::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType)
274{
275 /* A parameter of a NewGRF got changed after the game was started. */
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!");
280}
281
282/* virtual */ void LoggedChangeGRFMoved::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType)
283{
284 /* The order of NewGRFs got changed, which might cause some other NewGRFs to behave differently. */
285 auto gm = grf_names.find(this->grfid);
286 fmt::format_to(output_iterator, "GRF order changed: {:08X} moved {} places {}",
287 std::byteswap(this->grfid), abs(this->offset), this->offset >= 0 ? "down" : "up" );
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!");
290}
291
292/* virtual */ void LoggedChangeGRFBug::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType)
293{
294 /* A specific bug in a NewGRF, that could cause wide spread problems, has been noted during the execution of the game. */
295 auto gm = grf_names.find(this->grfid);
296 assert(this->bug == GRFBug::VehLength);
297
298 fmt::format_to(output_iterator, "Rail vehicle changes length outside a depot: GRF ID {:08X}, internal ID 0x{:X}", std::byteswap(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!");
301}
302
303/* virtual */ void LoggedChangeEmergencySave::FormatTo(std::back_insert_iterator<std::string> &, GrfIDMapping &, GamelogActionType)
304{
305 /* At one point the savegame was made during the handling of a game crash.
306 * The generic code already mentioned the emergency savegame, and there is no extra information to log. */
307}
308
311{
312 this->Print([](const std::string &s) {
314 });
315}
316
323void Gamelog::PrintDebug(int level)
324{
325 this->Print([level](const std::string &s) {
326 Debug(gamelog, level, "{}", s);
327 });
328}
329
330
335void Gamelog::Change(std::unique_ptr<LoggedChange> &&change)
336{
337 if (this->current_action == nullptr) {
338 if (this->action_type == GLAT_NONE) return;
339
340 this->current_action = &this->data->action.emplace_back();
341 this->current_action->at = this->action_type;
342 this->current_action->tick = TimerGameTick::counter;
343 }
344
345 this->current_action->change.push_back(std::move(change));
346}
347
348
353{
354 /* Terminate any active action */
355 if (this->action_type != GLAT_NONE) this->StopAction();
357 this->Change(std::make_unique<LoggedChangeEmergencySave>());
358 this->StopAction();
359}
360
365{
366 for (const LoggedAction &la : this->data->action) {
367 for (const auto &lc : la.change) {
368 if (lc->ct == GLCT_EMERGENCY) return true;
369 }
370 }
371
372 return false;
373}
374
379{
380 assert(this->action_type == GLAT_START || this->action_type == GLAT_LOAD);
381
382 this->Change(std::make_unique<LoggedChangeRevision>(
383 GetGamelogRevisionString(), _openttd_newgrf_version, SAVEGAME_VERSION, _openttd_revision_modified));
384}
385
390{
391 assert(this->action_type == GLAT_START || this->action_type == GLAT_LOAD || this->action_type == GLAT_CHEAT);
392
393 this->Change(std::make_unique<LoggedChangeMode>(_game_mode, _settings_game.game_creation.landscape));
394}
395
400{
401 assert(this->action_type == GLAT_LOAD);
402
403 this->Change(std::make_unique<LoggedChangeOldVersion>(_savegame_type,
405}
406
413void Gamelog::Setting(const std::string &name, int32_t oldval, int32_t newval)
414{
415 assert(this->action_type == GLAT_SETTING);
416
417 this->Change(std::make_unique<LoggedChangeSettingChanged>(name, oldval, newval));
418}
419
420
426{
427 const LoggedChangeRevision *rev = nullptr;
428
429 for (const LoggedAction &la : this->data->action) {
430 for (const auto &lc : la.change) {
431 if (lc->ct == GLCT_REVISION) rev = static_cast<const LoggedChangeRevision *>(lc.get());
432 }
433 }
434
435 if (rev == nullptr || rev->text != GetGamelogRevisionString() ||
436 rev->modified != _openttd_revision_modified ||
437 rev->newgrf != _openttd_newgrf_version) {
438 this->Revision();
439 }
440}
441
447{
448 const LoggedChangeMode *mode = nullptr;
449
450 for (const LoggedAction &la : this->data->action) {
451 for (const auto &lc : la.change) {
452 if (lc->ct == GLCT_MODE) mode = static_cast<const LoggedChangeMode *>(lc.get());
453 }
454 }
455
456 if (mode == nullptr || mode->mode != _game_mode || mode->landscape != _settings_game.game_creation.landscape) this->Mode();
457}
458
459
466void Gamelog::GRFBug(uint32_t grfid, ::GRFBug bug, uint64_t data)
467{
468 assert(this->action_type == GLAT_GRFBUG);
469
470 this->Change(std::make_unique<LoggedChangeGRFBug>(data, grfid, bug));
471}
472
482bool Gamelog::GRFBugReverse(uint32_t grfid, uint16_t internal_id)
483{
484 for (const LoggedAction &la : this->data->action) {
485 for (const auto &lc : la.change) {
486 if (lc->ct == GLCT_GRFBUG) {
487 LoggedChangeGRFBug *bug = static_cast<LoggedChangeGRFBug *>(lc.get());
488 if (bug->grfid == grfid && bug->bug == GRFBug::VehLength && bug->data == internal_id) {
489 return false;
490 }
491 }
492 }
493 }
494
496 this->GRFBug(grfid, GRFBug::VehLength, internal_id);
497 this->StopAction();
498
499 return true;
500}
501
502
508static inline bool IsLoggableGrfConfig(const GRFConfig &g)
509{
511}
512
517void Gamelog::GRFRemove(uint32_t grfid)
518{
519 assert(this->action_type == GLAT_LOAD || this->action_type == GLAT_GRF);
520
521 this->Change(std::make_unique<LoggedChangeGRFRemoved>(grfid));
522}
523
528void Gamelog::GRFAdd(const GRFConfig &newg)
529{
530 assert(this->action_type == GLAT_LOAD || this->action_type == GLAT_START || this->action_type == GLAT_GRF);
531
532 if (!IsLoggableGrfConfig(newg)) return;
533
534 this->Change(std::make_unique<LoggedChangeGRFAdd>(newg.ident));
535}
536
543{
544 assert(this->action_type == GLAT_LOAD || this->action_type == GLAT_GRF);
545
546 this->Change(std::make_unique<LoggedChangeGRFChanged>(newg));
547}
548
554void Gamelog::GRFMove(uint32_t grfid, int32_t offset)
555{
556 assert(this->action_type == GLAT_GRF);
557
558 this->Change(std::make_unique<LoggedChangeGRFMoved>(grfid, offset));
559}
560
566void Gamelog::GRFParameters(uint32_t grfid)
567{
568 assert(this->action_type == GLAT_GRF);
569
570 this->Change(std::make_unique<LoggedChangeGRFParameterChanged>(grfid));
571}
572
578void Gamelog::GRFAddList(const GRFConfigList &newg)
579{
580 assert(this->action_type == GLAT_START || this->action_type == GLAT_LOAD);
581
582 for (const auto &c : newg) {
583 this->GRFAdd(*c);
584 }
585}
586
591static std::vector<const GRFConfig *> GenerateGRFList(const GRFConfigList &grfc)
592{
593 std::vector<const GRFConfig *> list;
594 for (const auto &g : grfc) {
595 if (IsLoggableGrfConfig(*g)) list.push_back(g.get());
596 }
597
598 return list;
599}
600
606void Gamelog::GRFUpdate(const GRFConfigList &oldc, const GRFConfigList &newc)
607{
608 std::vector<const GRFConfig *> ol = GenerateGRFList(oldc);
609 std::vector<const GRFConfig *> nl = GenerateGRFList(newc);
610
611 uint o = 0, n = 0;
612
613 while (o < ol.size() && n < nl.size()) {
614 const GRFConfig &og = *ol[o];
615 const GRFConfig &ng = *nl[n];
616
617 if (og.ident.grfid != ng.ident.grfid) {
618 uint oi, ni;
619 for (oi = 0; oi < ol.size(); oi++) {
620 if (ol[oi]->ident.grfid == nl[n]->ident.grfid) break;
621 }
622 if (oi < o) {
623 /* GRF was moved, this change has been logged already */
624 n++;
625 continue;
626 }
627 if (oi == ol.size()) {
628 /* GRF couldn't be found in the OLD list, GRF was ADDED */
629 this->GRFAdd(*nl[n++]);
630 continue;
631 }
632 for (ni = 0; ni < nl.size(); ni++) {
633 if (nl[ni]->ident.grfid == ol[o]->ident.grfid) break;
634 }
635 if (ni < n) {
636 /* GRF was moved, this change has been logged already */
637 o++;
638 continue;
639 }
640 if (ni == nl.size()) {
641 /* GRF couldn't be found in the NEW list, GRF was REMOVED */
642 this->GRFRemove(ol[o++]->ident.grfid);
643 continue;
644 }
645
646 /* o < oi < ol->n
647 * n < ni < nl->n */
648 assert(ni > n && ni < nl.size());
649 assert(oi > o && oi < ol.size());
650
651 ni -= n; // number of GRFs it was moved downwards
652 oi -= o; // number of GRFs it was moved upwards
653
654 if (ni >= oi) { // prefer the one that is moved further
655 /* GRF was moved down */
656 this->GRFMove(ol[o++]->ident.grfid, ni);
657 } else {
658 this->GRFMove(nl[n++]->ident.grfid, -(int)oi);
659 }
660 } else {
661 if (og.ident.md5sum != ng.ident.md5sum) {
662 /* md5sum changed, probably loading 'compatible' GRF */
663 this->GRFCompatible(nl[n]->ident);
664 }
665
666 if (og.param != ng.param) {
667 this->GRFParameters(ol[o]->ident.grfid);
668 }
669
670 o++;
671 n++;
672 }
673 }
674
675 while (o < ol.size()) this->GRFRemove(ol[o++]->ident.grfid); // remaining GRFs were removed ...
676 while (n < nl.size()) this->GRFAdd (*nl[n++]); // ... or added
677}
678
685void Gamelog::Info(uint32_t *last_ottd_rev, uint8_t *ever_modified, bool *removed_newgrfs)
686{
687 for (const LoggedAction &la : this->data->action) {
688 for (const auto &lc : la.change) {
689 switch (lc->ct) {
690 default: break;
691
692 case GLCT_REVISION: {
693 const LoggedChangeRevision *rev = static_cast<const LoggedChangeRevision *>(lc.get());
694 *last_ottd_rev = rev->newgrf;
695 *ever_modified = std::max(*ever_modified, rev->modified);
696 break;
697 }
698
699 case GLCT_GRFREM:
700 *removed_newgrfs = true;
701 break;
702 }
703 }
704 }
705}
706
713{
714 const LoggedAction &la = this->data->action.back();
715 if (la.at != GLAT_LOAD) return c.ident;
716
717 for (const auto &lc : la.change) {
718 if (lc->ct != GLCT_GRFCOMPAT) continue;
719
720 const LoggedChangeGRFChanged &grf = *static_cast<const LoggedChangeGRFChanged *>(lc.get());
721 if (grf.grfid == c.ident.grfid) return grf;
722 }
723
724 return c.ident;
725}
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.
constexpr bool Test(Tenum value) const
Test if the enum value is set.
void TestRevision()
Finds out if current revision is different than last revision stored in the savegame.
Definition gamelog.cpp:425
const GRFIdentifier & GetOverriddenIdentifier(const GRFConfig &c)
Try to find the overridden GRF identifier of the given GRF.
Definition gamelog.cpp:712
void Mode()
Logs a change in game mode (scenario editor or game)
Definition gamelog.cpp:389
void Info(uint32_t *last_ottd_rev, uint8_t *ever_modified, bool *removed_newgrfs)
Get some basic information from the given gamelog.
Definition gamelog.cpp:685
void PrintDebug(int level)
Prints gamelog to debug output.
Definition gamelog.cpp:323
void PrintConsole()
Print the gamelog data to the console.
Definition gamelog.cpp:310
void GRFParameters(uint32_t grfid)
Logs change in GRF parameters.
Definition gamelog.cpp:566
void Revision()
Logs a change in game revision.
Definition gamelog.cpp:378
void StartAction(GamelogActionType at)
Stores information about new action, but doesn't allocate it Action is allocated only when there is a...
Definition gamelog.cpp:65
void Reset()
Resets and frees all memory allocated - used before loading or starting a new game.
Definition gamelog.cpp:94
void GRFRemove(uint32_t grfid)
Logs removal of a GRF.
Definition gamelog.cpp:517
void GRFAddList(const GRFConfigList &newg)
Logs adding of list of GRFs.
Definition gamelog.cpp:578
void GRFCompatible(const GRFIdentifier &newg)
Logs loading compatible GRF (the same ID, but different MD5 hash)
Definition gamelog.cpp:542
void Oldver()
Logs loading from savegame without gamelog.
Definition gamelog.cpp:399
void Emergency()
Logs a emergency savegame.
Definition gamelog.cpp:352
bool GRFBugReverse(uint32_t grfid, uint16_t internal_id)
Logs GRF bug - rail vehicle has different length after reversing.
Definition gamelog.cpp:482
void TestMode()
Finds last stored game mode or landscape.
Definition gamelog.cpp:446
void StopAction()
Stops logging of any changes.
Definition gamelog.cpp:74
void Setting(const std::string &name, int32_t oldval, int32_t newval)
Logs change in game settings.
Definition gamelog.cpp:413
void Print(std::function< void(const std::string &)> proc)
Prints active gamelog.
Definition gamelog.cpp:147
void GRFBug(uint32_t grfid, ::GRFBug bug, uint64_t data)
Logs triggered GRF bug.
Definition gamelog.cpp:466
void GRFAdd(const GRFConfig &newg)
Logs adding of a GRF.
Definition gamelog.cpp:528
void GRFUpdate(const GRFConfigList &oldg, const GRFConfigList &newg)
Compares two NewGRF lists and logs any change.
Definition gamelog.cpp:606
void Change(std::unique_ptr< LoggedChange > &&change)
Allocates a new LoggedAction if needed, and add the change when action is active.
Definition gamelog.cpp:335
bool TestEmergency()
Finds out if current game is a loaded emergency savegame.
Definition gamelog.cpp:364
void GRFMove(uint32_t grfid, int32_t offset)
Logs changing GRF order.
Definition gamelog.cpp:554
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.
Definition console.cpp:89
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.
Definition debug.h:37
uint32_t _ttdp_version
version of TTDP savegame (if applicable)
Definition saveload.cpp:65
SaveLoadVersion _sl_version
the major savegame version identifier
Definition saveload.cpp:66
uint8_t _sl_minor_version
the minor savegame version, DO NOT USE!
Definition saveload.cpp:67
static std::string GetGamelogRevisionString()
Return the revision string for the current client version, for use in gamelog.
Definition gamelog.cpp:47
Gamelog _gamelog
Gamelog instance.
Definition gamelog.cpp:31
static const char *const la_text[]
Text messages for various logged actions.
Definition gamelog.cpp:131
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.
Definition gamelog.cpp:109
static bool IsLoggableGrfConfig(const GRFConfig &g)
Decides if GRF should be logged.
Definition gamelog.cpp:508
SavegameType _savegame_type
type of savegame we are loading
Definition saveload.cpp:62
static std::vector< const GRFConfig * > GenerateGRFList(const GRFConfigList &grfc)
Generates GRFList.
Definition gamelog.cpp:591
const SaveLoadVersion SAVEGAME_VERSION
current savegame version
@ GLCT_MODE
Scenario editor x Game, different landscape.
Definition gamelog.h:30
@ GLCT_GRFCOMPAT
Loading compatible GRF.
Definition gamelog.h:36
@ GLCT_EMERGENCY
Emergency savegame.
Definition gamelog.h:40
@ GLCT_GRFREM
Added GRF.
Definition gamelog.h:35
@ GLCT_GRFBUG
GRF bug triggered.
Definition gamelog.h:39
@ GLCT_REVISION
Changed game revision string.
Definition gamelog.h:31
GamelogActionType
The actions we log.
Definition gamelog.h:16
@ GLAT_GRFBUG
GRF bug was triggered.
Definition gamelog.h:22
@ GLAT_START
Game created.
Definition gamelog.h:17
@ GLAT_NONE
No logging active; in savegames, end of list.
Definition gamelog.h:25
@ GLAT_GRF
GRF changed.
Definition gamelog.h:19
@ GLAT_END
So we know how many GLATs are there.
Definition gamelog.h:24
@ GLAT_LOAD
Game loaded.
Definition gamelog.h:18
@ GLAT_CHEAT
Cheat was used.
Definition gamelog.h:20
@ GLAT_EMERGENCY
Emergency savegame.
Definition gamelog.h:23
@ GLAT_SETTING
Setting changed.
Definition gamelog.h:21
Declaration shared among gamelog.cpp and saveload/gamelog_sl.cpp.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
@ Static
GRF file is used statically (can be used in any MP game)
GRFBug
Encountered GRF bugs.
@ VehLength
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.
Definition saveload.h:424
@ SGT_TTD
TTD savegame (can be detected incorrectly)
Definition saveload.h:425
@ SGT_OTTD
OTTD savegame.
Definition saveload.h:428
@ SGT_TTDP2
TTDP savegame in new format (data at SE border)
Definition saveload.h:427
@ SGT_TTO
TTO savegame.
Definition saveload.h:429
@ SGT_TTDP1
TTDP savegame ( -//- ) (data at NW border)
Definition saveload.h:426
SaveLoadVersion
SaveLoad versions Previous savegame versions, the trunk revision where they were introduced and the r...
Definition saveload.h:30
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:57
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.
Definition stdafx.h:277
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:81
Functions related to low-level strings.
Information about GRF, used in the game and (part of it) in savegames.
std::vector< uint32_t > param
GRF parameters.
GRFStatus status
NOSAVE: GRFStatus, enum.
GRFConfigFlags flags
NOSAVE: GCF_Flags, bitset.
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)
LandscapeType 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.
GRFBug bug
type of bug,
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.
LandscapeType 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.