00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "saveload/saveload.h"
00014 #include "string_func.h"
00015 #include "settings_type.h"
00016 #include "gamelog_internal.h"
00017 #include "console_func.h"
00018 #include "debug.h"
00019 #include "date_func.h"
00020 #include "rev.h"
00021
00022 #include <stdarg.h>
00023
00024 extern const uint16 SAVEGAME_VERSION;
00025
00026 extern SavegameType _savegame_type;
00027
00028 extern uint32 _ttdp_version;
00029 extern uint16 _sl_version;
00030 extern byte _sl_minor_version;
00031
00032
00033 static GamelogActionType _gamelog_action_type = GLAT_NONE;
00034
00035 LoggedAction *_gamelog_action = NULL;
00036 uint _gamelog_actions = 0;
00037 static LoggedAction *_current_action = NULL;
00038
00039
00045 void GamelogStartAction(GamelogActionType at)
00046 {
00047 assert(_gamelog_action_type == GLAT_NONE);
00048 _gamelog_action_type = at;
00049 }
00050
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
00069 void GamelogReset()
00070 {
00071 assert(_gamelog_action_type == GLAT_NONE);
00072
00073 for (uint i = 0; i < _gamelog_actions; i++) {
00074 const LoggedAction *la = &_gamelog_action[i];
00075 for (uint j = 0; j < la->changes; j++) {
00076 const LoggedChange *lc = &la->change[j];
00077 if (lc->ct == GLCT_SETTING) free(lc->setting.name);
00078 }
00079 free(la->change);
00080 }
00081
00082 free(_gamelog_action);
00083
00084 _gamelog_action = NULL;
00085 _gamelog_actions = 0;
00086 _current_action = NULL;
00087 }
00088
00089 static const uint GAMELOG_BUF_LEN = 1024;
00090
00091 static uint _dbgofs = 0;
00092
00093 static void AddDebugText(char *buf, const char *s, ...) WARN_FORMAT(2, 3);
00094
00095 static void AddDebugText(char *buf, const char *s, ...)
00096 {
00097 if (GAMELOG_BUF_LEN <= _dbgofs) return;
00098
00099 va_list va;
00100
00101 va_start(va, s);
00102 _dbgofs += vsnprintf(buf + _dbgofs, GAMELOG_BUF_LEN - _dbgofs, s, va);
00103 va_end(va);
00104 }
00105
00106
00114 static void PrintGrfInfo(char *buf, uint grfid, const uint8 *md5sum, const GRFConfig *gc)
00115 {
00116 char txt[40];
00117
00118 if (md5sum != NULL) {
00119 md5sumToString(txt, lastof(txt), md5sum);
00120 AddDebugText(buf, "GRF ID %08X, checksum %s", BSWAP32(grfid), txt);
00121 } else {
00122 AddDebugText(buf, "GRF ID %08X", BSWAP32(grfid));
00123 }
00124
00125 if (gc != NULL) {
00126 AddDebugText(buf, ", filename: %s (md5sum matches)", gc->filename);
00127 } else {
00128 gc = FindGRFConfig(grfid, FGCM_ANY);
00129 if (gc != NULL) {
00130 AddDebugText(buf, ", filename: %s (matches GRFID only)", gc->filename);
00131 } else {
00132 AddDebugText(buf, ", unknown GRF");
00133 }
00134 }
00135 return;
00136 }
00137
00138
00140 static const char * const la_text[] = {
00141 "new game started",
00142 "game loaded",
00143 "GRF config changed",
00144 "cheat was used",
00145 "settings changed",
00146 "GRF bug triggered",
00147 "emergency savegame",
00148 };
00149
00150 assert_compile(lengthof(la_text) == GLAT_END);
00151
00159 struct GRFPresence{
00160 const GRFConfig *gc;
00161 bool was_missing;
00162
00163 GRFPresence(const GRFConfig *gc) : gc(gc), was_missing(false) {}
00164 };
00165 typedef SmallMap<uint32, GRFPresence> GrfIDMapping;
00166
00171 void GamelogPrint(GamelogPrintProc *proc)
00172 {
00173 char buf[GAMELOG_BUF_LEN];
00174 GrfIDMapping grf_names;
00175
00176 proc("---- gamelog start ----");
00177
00178 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00179
00180 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00181 assert((uint)la->at < GLAT_END);
00182
00183 snprintf(buf, GAMELOG_BUF_LEN, "Tick %u: %s", (uint)la->tick, la_text[(uint)la->at]);
00184 proc(buf);
00185
00186 const LoggedChange *lcend = &la->change[la->changes];
00187
00188 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00189 _dbgofs = 0;
00190 AddDebugText(buf, " ");
00191
00192 switch (lc->ct) {
00193 default: NOT_REACHED();
00194 case GLCT_MODE:
00195 AddDebugText(buf, "New game mode: %u landscape: %u",
00196 (uint)lc->mode.mode, (uint)lc->mode.landscape);
00197 break;
00198
00199 case GLCT_REVISION:
00200 AddDebugText(buf, "Revision text changed to %s, savegame version %u, ",
00201 lc->revision.text, lc->revision.slver);
00202
00203 switch (lc->revision.modified) {
00204 case 0: AddDebugText(buf, "not "); break;
00205 case 1: AddDebugText(buf, "maybe "); break;
00206 default: break;
00207 }
00208
00209 AddDebugText(buf, "modified, _openttd_newgrf_version = 0x%08x", lc->revision.newgrf);
00210 break;
00211
00212 case GLCT_OLDVER:
00213 AddDebugText(buf, "Conversion from ");
00214 switch (lc->oldver.type) {
00215 default: NOT_REACHED();
00216 case SGT_OTTD:
00217 AddDebugText(buf, "OTTD savegame without gamelog: version %u, %u",
00218 GB(lc->oldver.version, 8, 16), GB(lc->oldver.version, 0, 8));
00219 break;
00220
00221 case SGT_TTO:
00222 AddDebugText(buf, "TTO savegame");
00223 break;
00224
00225 case SGT_TTD:
00226 AddDebugText(buf, "TTD savegame");
00227 break;
00228
00229 case SGT_TTDP1:
00230 case SGT_TTDP2:
00231 AddDebugText(buf, "TTDP savegame, %s format",
00232 lc->oldver.type == SGT_TTDP1 ? "old" : "new");
00233 if (lc->oldver.version != 0) {
00234 AddDebugText(buf, ", TTDP version %u.%u.%u.%u",
00235 GB(lc->oldver.version, 24, 8), GB(lc->oldver.version, 20, 4),
00236 GB(lc->oldver.version, 16, 4), GB(lc->oldver.version, 0, 16));
00237 }
00238 break;
00239 }
00240 break;
00241
00242 case GLCT_SETTING:
00243 AddDebugText(buf, "Setting changed: %s : %d -> %d", lc->setting.name, lc->setting.oldval, lc->setting.newval);
00244 break;
00245
00246 case GLCT_GRFADD: {
00247 const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum);
00248 AddDebugText(buf, "Added NewGRF: ");
00249 PrintGrfInfo(buf, lc->grfadd.grfid, lc->grfadd.md5sum, gc);
00250 GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
00251 if (gm != grf_names.End() && !gm->second.was_missing) AddDebugText(buf, ". Gamelog inconsistency: GrfID was already added!");
00252 grf_names[lc->grfadd.grfid] = gc;
00253 break;
00254 }
00255
00256 case GLCT_GRFREM: {
00257 GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
00258 AddDebugText(buf, la->at == GLAT_LOAD ? "Missing NewGRF: " : "Removed NewGRF: ");
00259 PrintGrfInfo(buf, lc->grfrem.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL);
00260 if (gm == grf_names.End()) {
00261 AddDebugText(buf, ". Gamelog inconsistency: GrfID was never added!");
00262 } else {
00263 if (la->at == GLAT_LOAD) {
00264
00265 gm->second.was_missing = true;
00266 } else {
00267 grf_names.Erase(gm);
00268 }
00269 }
00270 break;
00271 }
00272
00273 case GLCT_GRFCOMPAT: {
00274 const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum);
00275 AddDebugText(buf, "Compatible NewGRF loaded: ");
00276 PrintGrfInfo(buf, lc->grfcompat.grfid, lc->grfcompat.md5sum, gc);
00277 if (!grf_names.Contains(lc->grfcompat.grfid)) AddDebugText(buf, ". Gamelog inconsistency: GrfID was never added!");
00278 grf_names[lc->grfcompat.grfid] = gc;
00279 break;
00280 }
00281
00282 case GLCT_GRFPARAM: {
00283 GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
00284 AddDebugText(buf, "GRF parameter changed: ");
00285 PrintGrfInfo(buf, lc->grfparam.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL);
00286 if (gm == grf_names.End()) AddDebugText(buf, ". Gamelog inconsistency: GrfID was never added!");
00287 break;
00288 }
00289
00290 case GLCT_GRFMOVE: {
00291 GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
00292 AddDebugText(buf, "GRF order changed: %08X moved %d places %s",
00293 BSWAP32(lc->grfmove.grfid), abs(lc->grfmove.offset), lc->grfmove.offset >= 0 ? "down" : "up" );
00294 PrintGrfInfo(buf, lc->grfmove.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL);
00295 if (gm == grf_names.End()) AddDebugText(buf, ". Gamelog inconsistency: GrfID was never added!");
00296 break;
00297 }
00298
00299 case GLCT_GRFBUG: {
00300 GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid);
00301 switch (lc->grfbug.bug) {
00302 default: NOT_REACHED();
00303 case GBUG_VEH_LENGTH:
00304 AddDebugText(buf, "Rail vehicle changes length outside a depot: GRF ID %08X, internal ID 0x%X", BSWAP32(lc->grfbug.grfid), (uint)lc->grfbug.data);
00305 break;
00306 }
00307 PrintGrfInfo(buf, lc->grfbug.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL);
00308 if (gm == grf_names.End()) AddDebugText(buf, ". Gamelog inconsistency: GrfID was never added!");
00309 break;
00310 }
00311
00312 case GLCT_EMERGENCY:
00313 break;
00314 }
00315
00316 proc(buf);
00317 }
00318 }
00319
00320 proc("---- gamelog end ----");
00321 }
00322
00323
00324 static void GamelogPrintConsoleProc(const char *s)
00325 {
00326 IConsolePrint(CC_WARNING, s);
00327 }
00328
00330 void GamelogPrintConsole()
00331 {
00332 GamelogPrint(&GamelogPrintConsoleProc);
00333 }
00334
00335 static int _gamelog_print_level = 0;
00336
00337 static void GamelogPrintDebugProc(const char *s)
00338 {
00339 DEBUG(gamelog, _gamelog_print_level, "%s", s);
00340 }
00341
00342
00349 void GamelogPrintDebug(int level)
00350 {
00351 _gamelog_print_level = level;
00352 GamelogPrint(&GamelogPrintDebugProc);
00353 }
00354
00355
00362 static LoggedChange *GamelogChange(GamelogChangeType ct)
00363 {
00364 if (_current_action == NULL) {
00365 if (_gamelog_action_type == GLAT_NONE) return NULL;
00366
00367 _gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1);
00368 _current_action = &_gamelog_action[_gamelog_actions++];
00369
00370 _current_action->at = _gamelog_action_type;
00371 _current_action->tick = _tick_counter;
00372 _current_action->change = NULL;
00373 _current_action->changes = 0;
00374 }
00375
00376 _current_action->change = ReallocT(_current_action->change, _current_action->changes + 1);
00377
00378 LoggedChange *lc = &_current_action->change[_current_action->changes++];
00379 lc->ct = ct;
00380
00381 return lc;
00382 }
00383
00384
00388 void GamelogEmergency()
00389 {
00390
00391 if (_gamelog_action_type != GLAT_NONE) GamelogStopAction();
00392 GamelogStartAction(GLAT_EMERGENCY);
00393 GamelogChange(GLCT_EMERGENCY);
00394 GamelogStopAction();
00395 }
00396
00400 bool GamelogTestEmergency()
00401 {
00402 const LoggedChange *emergency = NULL;
00403
00404 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00405 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00406 const LoggedChange *lcend = &la->change[la->changes];
00407 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00408 if (lc->ct == GLCT_EMERGENCY) emergency = lc;
00409 }
00410 }
00411
00412 return (emergency != NULL);
00413 }
00414
00418 void GamelogRevision()
00419 {
00420 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD);
00421
00422 LoggedChange *lc = GamelogChange(GLCT_REVISION);
00423 if (lc == NULL) return;
00424
00425 memset(lc->revision.text, 0, sizeof(lc->revision.text));
00426 strecpy(lc->revision.text, _openttd_revision, lastof(lc->revision.text));
00427 lc->revision.slver = SAVEGAME_VERSION;
00428 lc->revision.modified = _openttd_revision_modified;
00429 lc->revision.newgrf = _openttd_newgrf_version;
00430 }
00431
00435 void GamelogMode()
00436 {
00437 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_CHEAT);
00438
00439 LoggedChange *lc = GamelogChange(GLCT_MODE);
00440 if (lc == NULL) return;
00441
00442 lc->mode.mode = _game_mode;
00443 lc->mode.landscape = _settings_game.game_creation.landscape;
00444 }
00445
00449 void GamelogOldver()
00450 {
00451 assert(_gamelog_action_type == GLAT_LOAD);
00452
00453 LoggedChange *lc = GamelogChange(GLCT_OLDVER);
00454 if (lc == NULL) return;
00455
00456 lc->oldver.type = _savegame_type;
00457 lc->oldver.version = (_savegame_type == SGT_OTTD ? ((uint32)_sl_version << 8 | _sl_minor_version) : _ttdp_version);
00458 }
00459
00466 void GamelogSetting(const char *name, int32 oldval, int32 newval)
00467 {
00468 assert(_gamelog_action_type == GLAT_SETTING);
00469
00470 LoggedChange *lc = GamelogChange(GLCT_SETTING);
00471 if (lc == NULL) return;
00472
00473 lc->setting.name = strdup(name);
00474 lc->setting.oldval = oldval;
00475 lc->setting.newval = newval;
00476 }
00477
00478
00483 void GamelogTestRevision()
00484 {
00485 const LoggedChange *rev = NULL;
00486
00487 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00488 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00489 const LoggedChange *lcend = &la->change[la->changes];
00490 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00491 if (lc->ct == GLCT_REVISION) rev = lc;
00492 }
00493 }
00494
00495 if (rev == NULL || strcmp(rev->revision.text, _openttd_revision) != 0 ||
00496 rev->revision.modified != _openttd_revision_modified ||
00497 rev->revision.newgrf != _openttd_newgrf_version) {
00498 GamelogRevision();
00499 }
00500 }
00501
00506 void GamelogTestMode()
00507 {
00508 const LoggedChange *mode = NULL;
00509
00510 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00511 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00512 const LoggedChange *lcend = &la->change[la->changes];
00513 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00514 if (lc->ct == GLCT_MODE) mode = lc;
00515 }
00516 }
00517
00518 if (mode == NULL || mode->mode.mode != _game_mode || mode->mode.landscape != _settings_game.game_creation.landscape) GamelogMode();
00519 }
00520
00521
00528 static void GamelogGRFBug(uint32 grfid, byte bug, uint64 data)
00529 {
00530 assert(_gamelog_action_type == GLAT_GRFBUG);
00531
00532 LoggedChange *lc = GamelogChange(GLCT_GRFBUG);
00533 if (lc == NULL) return;
00534
00535 lc->grfbug.data = data;
00536 lc->grfbug.grfid = grfid;
00537 lc->grfbug.bug = bug;
00538 }
00539
00549 bool GamelogGRFBugReverse(uint32 grfid, uint16 internal_id)
00550 {
00551 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00552 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00553 const LoggedChange *lcend = &la->change[la->changes];
00554 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00555 if (lc->ct == GLCT_GRFBUG && lc->grfbug.grfid == grfid &&
00556 lc->grfbug.bug == GBUG_VEH_LENGTH && lc->grfbug.data == internal_id) {
00557 return false;
00558 }
00559 }
00560 }
00561
00562 GamelogStartAction(GLAT_GRFBUG);
00563 GamelogGRFBug(grfid, GBUG_VEH_LENGTH, internal_id);
00564 GamelogStopAction();
00565
00566 return true;
00567 }
00568
00569
00575 static inline bool IsLoggableGrfConfig(const GRFConfig *g)
00576 {
00577 return !HasBit(g->flags, GCF_STATIC) && g->status != GCS_NOT_FOUND;
00578 }
00579
00584 void GamelogGRFRemove(uint32 grfid)
00585 {
00586 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF);
00587
00588 LoggedChange *lc = GamelogChange(GLCT_GRFREM);
00589 if (lc == NULL) return;
00590
00591 lc->grfrem.grfid = grfid;
00592 }
00593
00598 void GamelogGRFAdd(const GRFConfig *newg)
00599 {
00600 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_GRF);
00601
00602 if (!IsLoggableGrfConfig(newg)) return;
00603
00604 LoggedChange *lc = GamelogChange(GLCT_GRFADD);
00605 if (lc == NULL) return;
00606
00607 lc->grfadd = newg->ident;
00608 }
00609
00615 void GamelogGRFCompatible(const GRFIdentifier *newg)
00616 {
00617 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF);
00618
00619 LoggedChange *lc = GamelogChange(GLCT_GRFCOMPAT);
00620 if (lc == NULL) return;
00621
00622 lc->grfcompat = *newg;
00623 }
00624
00630 static void GamelogGRFMove(uint32 grfid, int32 offset)
00631 {
00632 assert(_gamelog_action_type == GLAT_GRF);
00633
00634 LoggedChange *lc = GamelogChange(GLCT_GRFMOVE);
00635 if (lc == NULL) return;
00636
00637 lc->grfmove.grfid = grfid;
00638 lc->grfmove.offset = offset;
00639 }
00640
00646 static void GamelogGRFParameters(uint32 grfid)
00647 {
00648 assert(_gamelog_action_type == GLAT_GRF);
00649
00650 LoggedChange *lc = GamelogChange(GLCT_GRFPARAM);
00651 if (lc == NULL) return;
00652
00653 lc->grfparam.grfid = grfid;
00654 }
00655
00661 void GamelogGRFAddList(const GRFConfig *newg)
00662 {
00663 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD);
00664
00665 for (; newg != NULL; newg = newg->next) {
00666 GamelogGRFAdd(newg);
00667 }
00668 }
00669
00671 struct GRFList {
00672 uint n;
00673 const GRFConfig *grf[];
00674 };
00675
00680 static GRFList *GenerateGRFList(const GRFConfig *grfc)
00681 {
00682 uint n = 0;
00683 for (const GRFConfig *g = grfc; g != NULL; g = g->next) {
00684 if (IsLoggableGrfConfig(g)) n++;
00685 }
00686
00687 GRFList *list = (GRFList*)MallocT<byte>(sizeof(GRFList) + n * sizeof(GRFConfig*));
00688
00689 list->n = 0;
00690 for (const GRFConfig *g = grfc; g != NULL; g = g->next) {
00691 if (IsLoggableGrfConfig(g)) list->grf[list->n++] = g;
00692 }
00693
00694 return list;
00695 }
00696
00702 void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc)
00703 {
00704 GRFList *ol = GenerateGRFList(oldc);
00705 GRFList *nl = GenerateGRFList(newc);
00706
00707 uint o = 0, n = 0;
00708
00709 while (o < ol->n && n < nl->n) {
00710 const GRFConfig *og = ol->grf[o];
00711 const GRFConfig *ng = nl->grf[n];
00712
00713 if (og->ident.grfid != ng->ident.grfid) {
00714 uint oi, ni;
00715 for (oi = 0; oi < ol->n; oi++) {
00716 if (ol->grf[oi]->ident.grfid == nl->grf[n]->ident.grfid) break;
00717 }
00718 if (oi < o) {
00719
00720 n++;
00721 continue;
00722 }
00723 if (oi == ol->n) {
00724
00725 GamelogGRFAdd(nl->grf[n++]);
00726 continue;
00727 }
00728 for (ni = 0; ni < nl->n; ni++) {
00729 if (nl->grf[ni]->ident.grfid == ol->grf[o]->ident.grfid) break;
00730 }
00731 if (ni < n) {
00732
00733 o++;
00734 continue;
00735 }
00736 if (ni == nl->n) {
00737
00738 GamelogGRFRemove(ol->grf[o++]->ident.grfid);
00739 continue;
00740 }
00741
00742
00743
00744 assert(ni > n && ni < nl->n);
00745 assert(oi > o && oi < ol->n);
00746
00747 ni -= n;
00748 oi -= o;
00749
00750 if (ni >= oi) {
00751
00752 GamelogGRFMove(ol->grf[o++]->ident.grfid, ni);
00753 } else {
00754 GamelogGRFMove(nl->grf[n++]->ident.grfid, -(int)oi);
00755 }
00756 } else {
00757 if (memcmp(og->ident.md5sum, ng->ident.md5sum, sizeof(og->ident.md5sum)) != 0) {
00758
00759 GamelogGRFCompatible(&nl->grf[n]->ident);
00760 }
00761
00762 if (og->num_params != ng->num_params || memcmp(og->param, ng->param, og->num_params * sizeof(og->param[0])) != 0) {
00763 GamelogGRFParameters(ol->grf[o]->ident.grfid);
00764 }
00765
00766 o++;
00767 n++;
00768 }
00769 }
00770
00771 while (o < ol->n) GamelogGRFRemove(ol->grf[o++]->ident.grfid);
00772 while (n < nl->n) GamelogGRFAdd (nl->grf[n++]);
00773
00774 free(ol);
00775 free(nl);
00776 }