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