00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "saveload/saveload.h"
00015 #include "core/alloc_func.hpp"
00016 #include "variables.h"
00017 #include "string_func.h"
00018 #include "settings_type.h"
00019 #include "gamelog_internal.h"
00020 #include "console_func.h"
00021 #include "debug.h"
00022 #include "rev.h"
00023
00024 #include <stdarg.h>
00025
00026 extern const uint16 SAVEGAME_VERSION;
00027
00028 extern SavegameType _savegame_type;
00029
00030 extern uint32 _ttdp_version;
00031 extern uint16 _sl_version;
00032 extern byte _sl_minor_version;
00033
00034
00035 static GamelogActionType _gamelog_action_type = GLAT_NONE;
00036
00037 LoggedAction *_gamelog_action = NULL;
00038 uint _gamelog_actions = 0;
00039 static LoggedAction *_current_action = NULL;
00040
00041
00046 void GamelogStartAction(GamelogActionType at)
00047 {
00048 assert(_gamelog_action_type == GLAT_NONE);
00049 _gamelog_action_type = at;
00050 }
00051
00054 void GamelogStopAction()
00055 {
00056 assert(_gamelog_action_type != GLAT_NONE);
00057
00058 bool print = _current_action != NULL;
00059
00060 _current_action = NULL;
00061 _gamelog_action_type = GLAT_NONE;
00062
00063 if (print) GamelogPrintDebug(5);
00064 }
00065
00068 void GamelogReset()
00069 {
00070 assert(_gamelog_action_type == GLAT_NONE);
00071
00072 for (uint i = 0; i < _gamelog_actions; i++) {
00073 const LoggedAction *la = &_gamelog_action[i];
00074 for (uint j = 0; j < la->changes; j++) {
00075 const LoggedChange *lc = &la->change[j];
00076 if (lc->ct == GLCT_SETTING) free(lc->setting.name);
00077 }
00078 free(la->change);
00079 }
00080
00081 free(_gamelog_action);
00082
00083 _gamelog_action = NULL;
00084 _gamelog_actions = 0;
00085 _current_action = NULL;
00086 }
00087
00088 enum {
00089 GAMELOG_BUF_LEN = 1024
00090 };
00091
00092 static int _dbgofs = 0;
00093
00094 static void AddDebugText(char *buf, const char *s, ...) WARN_FORMAT(2, 3);
00095
00096 static void AddDebugText(char *buf, const char *s, ...)
00097 {
00098 if (GAMELOG_BUF_LEN <= _dbgofs) return;
00099
00100 va_list va;
00101
00102 va_start(va, s);
00103 _dbgofs += vsnprintf(buf + _dbgofs, GAMELOG_BUF_LEN - _dbgofs, s, va);
00104 va_end(va);
00105 }
00106
00107
00112 static void PrintGrfFilename(char *buf, uint grfid)
00113 {
00114 const GRFConfig *gc = FindGRFConfig(grfid);
00115
00116 if (gc == NULL) return;
00117
00118 AddDebugText(buf, ", filename: %s", gc->filename);
00119 }
00120
00126 static void PrintGrfInfo(char *buf, uint grfid, const uint8 *md5sum)
00127 {
00128 char txt[40];
00129
00130 md5sumToString(txt, lastof(txt), md5sum);
00131
00132 AddDebugText(buf, "GRF ID %08X, checksum %s", BSWAP32(grfid), txt);
00133
00134 PrintGrfFilename(buf, grfid);
00135
00136 return;
00137 }
00138
00139
00141 static const char * const la_text[] = {
00142 "new game started",
00143 "game loaded",
00144 "GRF config changed",
00145 "cheat was used",
00146 "settings changed",
00147 "GRF bug triggered",
00148 "emergency savegame",
00149 };
00150
00151 assert_compile(lengthof(la_text) == GLAT_END);
00152
00153
00158 void GamelogPrint(GamelogPrintProc *proc)
00159 {
00160 char buf[GAMELOG_BUF_LEN];
00161
00162 proc("---- gamelog start ----");
00163
00164 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00165
00166 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00167 assert((uint)la->at < GLAT_END);
00168
00169 snprintf(buf, GAMELOG_BUF_LEN, "Tick %u: %s", (uint)la->tick, la_text[(uint)la->at]);
00170 proc(buf);
00171
00172 const LoggedChange *lcend = &la->change[la->changes];
00173
00174 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00175 _dbgofs = 0;
00176 AddDebugText(buf, " ");
00177
00178 switch (lc->ct) {
00179 default: NOT_REACHED();
00180 case GLCT_MODE:
00181 AddDebugText(buf, "New game mode: %u landscape: %u",
00182 (uint)lc->mode.mode, (uint)lc->mode.landscape);
00183 break;
00184
00185 case GLCT_REVISION:
00186 AddDebugText(buf, "Revision text changed to %s, savegame version %u, ",
00187 lc->revision.text, lc->revision.slver);
00188
00189 switch (lc->revision.modified) {
00190 case 0: AddDebugText(buf, "not "); break;
00191 case 1: AddDebugText(buf, "maybe "); break;
00192 default: break;
00193 }
00194
00195 AddDebugText(buf, "modified, _openttd_newgrf_version = 0x%08x", lc->revision.newgrf);
00196 break;
00197
00198 case GLCT_OLDVER:
00199 AddDebugText(buf, "Conversion from ");
00200 switch (lc->oldver.type) {
00201 default: NOT_REACHED();
00202 case SGT_OTTD:
00203 AddDebugText(buf, "OTTD savegame without gamelog: version %u, %u",
00204 GB(lc->oldver.version, 8, 16), GB(lc->oldver.version, 0, 8));
00205 break;
00206
00207 case SGT_TTO:
00208 AddDebugText(buf, "TTO savegame");
00209 break;
00210
00211 case SGT_TTD:
00212 AddDebugText(buf, "TTD savegame");
00213 break;
00214
00215 case SGT_TTDP1:
00216 case SGT_TTDP2:
00217 AddDebugText(buf, "TTDP savegame, %s format",
00218 lc->oldver.type == SGT_TTDP1 ? "old" : "new");
00219 if (lc->oldver.version != 0) {
00220 AddDebugText(buf, ", TTDP version %u.%u.%u.%u",
00221 GB(lc->oldver.version, 24, 8), GB(lc->oldver.version, 20, 4),
00222 GB(lc->oldver.version, 16, 4), GB(lc->oldver.version, 0, 16));
00223 }
00224 break;
00225 }
00226 break;
00227
00228 case GLCT_SETTING:
00229 AddDebugText(buf, "Setting changed: %s : %d -> %d", lc->setting.name, lc->setting.oldval, lc->setting.newval);
00230 break;
00231
00232 case GLCT_GRFADD:
00233 AddDebugText(buf, "Added NewGRF: ");
00234 PrintGrfInfo(buf, lc->grfadd.grfid, lc->grfadd.md5sum);
00235 break;
00236
00237 case GLCT_GRFREM:
00238 AddDebugText(buf, "Removed NewGRF: %08X", BSWAP32(lc->grfrem.grfid));
00239 PrintGrfFilename(buf, lc->grfrem.grfid);
00240 break;
00241
00242 case GLCT_GRFCOMPAT:
00243 AddDebugText(buf, "Compatible NewGRF loaded: ");
00244 PrintGrfInfo(buf, lc->grfcompat.grfid, lc->grfcompat.md5sum);
00245 break;
00246
00247 case GLCT_GRFPARAM:
00248 AddDebugText(buf, "GRF parameter changed: %08X", BSWAP32(lc->grfparam.grfid));
00249 PrintGrfFilename(buf, lc->grfparam.grfid);
00250 break;
00251
00252 case GLCT_GRFMOVE:
00253 AddDebugText(buf, "GRF order changed: %08X moved %d places %s",
00254 BSWAP32(lc->grfmove.grfid), abs(lc->grfmove.offset), lc->grfmove.offset >= 0 ? "down" : "up" );
00255 PrintGrfFilename(buf, lc->grfmove.grfid);
00256 break;
00257
00258 case GLCT_GRFBUG:
00259 switch (lc->grfbug.bug) {
00260 default: NOT_REACHED();
00261 case GBUG_VEH_LENGTH:
00262 AddDebugText(buf, "Rail vehicle changes length outside a depot: GRF ID %08X, internal ID 0x%X", BSWAP32(lc->grfbug.grfid), (uint)lc->grfbug.data);
00263 PrintGrfFilename(buf, lc->grfbug.grfid);
00264 break;
00265 }
00266
00267 case GLCT_EMERGENCY:
00268 break;
00269 }
00270
00271 proc(buf);
00272 }
00273 }
00274
00275 proc("---- gamelog end ----");
00276 }
00277
00278
00279 static void GamelogPrintConsoleProc(const char *s)
00280 {
00281 IConsolePrint(CC_WARNING, s);
00282 }
00283
00284 void GamelogPrintConsole()
00285 {
00286 GamelogPrint(&GamelogPrintConsoleProc);
00287 }
00288
00289 static int _gamelog_print_level = 0;
00290
00291 static void GamelogPrintDebugProc(const char *s)
00292 {
00293 DEBUG(gamelog, _gamelog_print_level, "%s", s);
00294 }
00295
00296
00302 void GamelogPrintDebug(int level)
00303 {
00304 _gamelog_print_level = level;
00305 GamelogPrint(&GamelogPrintDebugProc);
00306 }
00307
00308
00314 static LoggedChange *GamelogChange(GamelogChangeType ct)
00315 {
00316 if (_current_action == NULL) {
00317 if (_gamelog_action_type == GLAT_NONE) return NULL;
00318
00319 _gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1);
00320 _current_action = &_gamelog_action[_gamelog_actions++];
00321
00322 _current_action->at = _gamelog_action_type;
00323 _current_action->tick = _tick_counter;
00324 _current_action->change = NULL;
00325 _current_action->changes = 0;
00326 }
00327
00328 _current_action->change = ReallocT(_current_action->change, _current_action->changes + 1);
00329
00330 LoggedChange *lc = &_current_action->change[_current_action->changes++];
00331 lc->ct = ct;
00332
00333 return lc;
00334 }
00335
00336
00339 void GamelogEmergency()
00340 {
00341
00342 if (_gamelog_action_type != GLAT_NONE) GamelogStopAction();
00343 GamelogStartAction(GLAT_EMERGENCY);
00344 GamelogChange(GLCT_EMERGENCY);
00345 GamelogStopAction();
00346 }
00347
00350 bool GamelogTestEmergency()
00351 {
00352 const LoggedChange *emergency = NULL;
00353
00354 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00355 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00356 const LoggedChange *lcend = &la->change[la->changes];
00357 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00358 if (lc->ct == GLCT_EMERGENCY) emergency = lc;
00359 }
00360 }
00361
00362 return (emergency != NULL);
00363 }
00364
00367 void GamelogRevision()
00368 {
00369 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD);
00370
00371 LoggedChange *lc = GamelogChange(GLCT_REVISION);
00372 if (lc == NULL) return;
00373
00374 memset(lc->revision.text, 0, sizeof(lc->revision.text));
00375 strecpy(lc->revision.text, _openttd_revision, lastof(lc->revision.text));
00376 lc->revision.slver = SAVEGAME_VERSION;
00377 lc->revision.modified = _openttd_revision_modified;
00378 lc->revision.newgrf = _openttd_newgrf_version;
00379 }
00380
00383 void GamelogMode()
00384 {
00385 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_CHEAT);
00386
00387 LoggedChange *lc = GamelogChange(GLCT_MODE);
00388 if (lc == NULL) return;
00389
00390 lc->mode.mode = _game_mode;
00391 lc->mode.landscape = _settings_game.game_creation.landscape;
00392 }
00393
00396 void GamelogOldver()
00397 {
00398 assert(_gamelog_action_type == GLAT_LOAD);
00399
00400 LoggedChange *lc = GamelogChange(GLCT_OLDVER);
00401 if (lc == NULL) return;
00402
00403 lc->oldver.type = _savegame_type;
00404 lc->oldver.version = (_savegame_type == SGT_OTTD ? ((uint32)_sl_version << 8 | _sl_minor_version) : _ttdp_version);
00405 }
00406
00412 void GamelogSetting(const char *name, int32 oldval, int32 newval)
00413 {
00414 assert(_gamelog_action_type == GLAT_SETTING);
00415
00416 LoggedChange *lc = GamelogChange(GLCT_SETTING);
00417 if (lc == NULL) return;
00418
00419 lc->setting.name = strdup(name);
00420 lc->setting.oldval = oldval;
00421 lc->setting.newval = newval;
00422 }
00423
00424
00428 void GamelogTestRevision()
00429 {
00430 const LoggedChange *rev = NULL;
00431
00432 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00433 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00434 const LoggedChange *lcend = &la->change[la->changes];
00435 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00436 if (lc->ct == GLCT_REVISION) rev = lc;
00437 }
00438 }
00439
00440 if (rev == NULL || strcmp(rev->revision.text, _openttd_revision) != 0 ||
00441 rev->revision.modified != _openttd_revision_modified ||
00442 rev->revision.newgrf != _openttd_newgrf_version) {
00443 GamelogRevision();
00444 }
00445 }
00446
00450 void GamelogTestMode()
00451 {
00452 const LoggedChange *mode = NULL;
00453
00454 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00455 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00456 const LoggedChange *lcend = &la->change[la->changes];
00457 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00458 if (lc->ct == GLCT_MODE) mode = lc;
00459 }
00460 }
00461
00462 if (mode == NULL || mode->mode.mode != _game_mode || mode->mode.landscape != _settings_game.game_creation.landscape) GamelogMode();
00463 }
00464
00465
00471 static void GamelogGRFBug(uint32 grfid, byte bug, uint64 data)
00472 {
00473 assert(_gamelog_action_type == GLAT_GRFBUG);
00474
00475 LoggedChange *lc = GamelogChange(GLCT_GRFBUG);
00476 if (lc == NULL) return;
00477
00478 lc->grfbug.data = data;
00479 lc->grfbug.grfid = grfid;
00480 lc->grfbug.bug = bug;
00481 }
00482
00491 bool GamelogGRFBugReverse(uint32 grfid, uint16 internal_id)
00492 {
00493 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00494 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00495 const LoggedChange *lcend = &la->change[la->changes];
00496 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00497 if (lc->ct == GLCT_GRFBUG && lc->grfbug.grfid == grfid &&
00498 lc->grfbug.bug == GBUG_VEH_LENGTH && lc->grfbug.data == internal_id) {
00499 return false;
00500 }
00501 }
00502 }
00503
00504 GamelogStartAction(GLAT_GRFBUG);
00505 GamelogGRFBug(grfid, GBUG_VEH_LENGTH, internal_id);
00506 GamelogStopAction();
00507
00508 return true;
00509 }
00510
00511
00516 static inline bool IsLoggableGrfConfig(const GRFConfig *g)
00517 {
00518 return !HasBit(g->flags, GCF_STATIC) && g->status != GCS_NOT_FOUND;
00519 }
00520
00524 void GamelogGRFRemove(uint32 grfid)
00525 {
00526 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF);
00527
00528 LoggedChange *lc = GamelogChange(GLCT_GRFREM);
00529 if (lc == NULL) return;
00530
00531 lc->grfrem.grfid = grfid;
00532 }
00533
00537 void GamelogGRFAdd(const GRFConfig *newg)
00538 {
00539 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_GRF);
00540
00541 if (!IsLoggableGrfConfig(newg)) return;
00542
00543 LoggedChange *lc = GamelogChange(GLCT_GRFADD);
00544 if (lc == NULL) return;
00545
00546 memcpy(&lc->grfadd, newg, sizeof(GRFIdentifier));
00547 }
00548
00553 void GamelogGRFCompatible(const GRFIdentifier *newg)
00554 {
00555 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF);
00556
00557 LoggedChange *lc = GamelogChange(GLCT_GRFCOMPAT);
00558 if (lc == NULL) return;
00559
00560 memcpy(&lc->grfcompat, newg, sizeof(GRFIdentifier));
00561 }
00562
00567 static void GamelogGRFMove(uint32 grfid, int32 offset)
00568 {
00569 assert(_gamelog_action_type == GLAT_GRF);
00570
00571 LoggedChange *lc = GamelogChange(GLCT_GRFMOVE);
00572 if (lc == NULL) return;
00573
00574 lc->grfmove.grfid = grfid;
00575 lc->grfmove.offset = offset;
00576 }
00577
00582 static void GamelogGRFParameters(uint32 grfid)
00583 {
00584 assert(_gamelog_action_type == GLAT_GRF);
00585
00586 LoggedChange *lc = GamelogChange(GLCT_GRFPARAM);
00587 if (lc == NULL) return;
00588
00589 lc->grfparam.grfid = grfid;
00590 }
00591
00596 void GamelogGRFAddList(const GRFConfig *newg)
00597 {
00598 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD);
00599
00600 for (; newg != NULL; newg = newg->next) {
00601 GamelogGRFAdd(newg);
00602 }
00603 }
00604
00606 struct GRFList {
00607 uint n;
00608 const GRFConfig *grf[];
00609 };
00610
00614 static GRFList *GenerateGRFList(const GRFConfig *grfc)
00615 {
00616 uint n = 0;
00617 for (const GRFConfig *g = grfc; g != NULL; g = g->next) {
00618 if (IsLoggableGrfConfig(g)) n++;
00619 }
00620
00621 GRFList *list = (GRFList*)MallocT<byte>(sizeof(GRFList) + n * sizeof(GRFConfig*));
00622
00623 list->n = 0;
00624 for (const GRFConfig *g = grfc; g != NULL; g = g->next) {
00625 if (IsLoggableGrfConfig(g)) list->grf[list->n++] = g;
00626 }
00627
00628 return list;
00629 }
00630
00635 void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc)
00636 {
00637 GRFList *ol = GenerateGRFList(oldc);
00638 GRFList *nl = GenerateGRFList(newc);
00639
00640 uint o = 0, n = 0;
00641
00642 while (o < ol->n && n < nl->n) {
00643 const GRFConfig *og = ol->grf[o];
00644 const GRFConfig *ng = nl->grf[n];
00645
00646 if (og->grfid != ng->grfid) {
00647 uint oi, ni;
00648 for (oi = 0; oi < ol->n; oi++) {
00649 if (ol->grf[oi]->grfid == nl->grf[n]->grfid) break;
00650 }
00651 if (oi < o) {
00652
00653 n++;
00654 continue;
00655 }
00656 if (oi == ol->n) {
00657
00658 GamelogGRFAdd(nl->grf[n++]);
00659 continue;
00660 }
00661 for (ni = 0; ni < nl->n; ni++) {
00662 if (nl->grf[ni]->grfid == ol->grf[o]->grfid) break;
00663 }
00664 if (ni < n) {
00665
00666 o++;
00667 continue;
00668 }
00669 if (ni == nl->n) {
00670
00671 GamelogGRFRemove(ol->grf[o++]->grfid);
00672 continue;
00673 }
00674
00675
00676
00677 assert(ni > n && ni < nl->n);
00678 assert(oi > o && oi < ol->n);
00679
00680 ni -= n;
00681 oi -= o;
00682
00683 if (ni >= oi) {
00684
00685 GamelogGRFMove(ol->grf[o++]->grfid, ni);
00686 } else {
00687 GamelogGRFMove(nl->grf[n++]->grfid, -(int)oi);
00688 }
00689 } else {
00690 if (memcmp(og->md5sum, ng->md5sum, sizeof(og->md5sum)) != 0) {
00691
00692 GamelogGRFCompatible(nl->grf[n]);
00693 }
00694
00695 if (og->num_params != ng->num_params || memcmp(og->param, ng->param, og->num_params * sizeof(og->param[0])) != 0) {
00696 GamelogGRFParameters(ol->grf[o]->grfid);
00697 }
00698
00699 o++;
00700 n++;
00701 }
00702 }
00703
00704 while (o < ol->n) GamelogGRFRemove(ol->grf[o++]->grfid);
00705 while (n < nl->n) GamelogGRFAdd (nl->grf[n++]);
00706
00707 free(ol);
00708 free(nl);
00709 }
00710
00716 void GamelogGetOriginalGRFMD5Checksum(uint32 grfid, byte *md5sum)
00717 {
00718 const LoggedAction *la = &_gamelog_action[_gamelog_actions - 1];
00719
00720 assert(_gamelog_actions > 0);
00721
00722 do {
00723 const LoggedChange *lc = &la->change[la->changes - 1];
00724
00725 assert(la->changes > 0);
00726
00727 do {
00728 if (lc->ct == GLCT_GRFADD && lc->grfadd.grfid == grfid) {
00729 memcpy(md5sum, lc->grfadd.md5sum, sizeof(lc->grfadd.md5sum));
00730 return;
00731 }
00732 } while (lc-- != la->change);
00733 } while (la-- != _gamelog_action);
00734
00735 DEBUG(grf, 0, "The NewGRF with GRF ID %08X is not listed in the game's log. Can't recover the original MD5 checksum.", BSWAP32(grfid));
00736 }