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