00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "saveload/saveload.h"
00008 #include "core/alloc_func.hpp"
00009 #include "core/bitmath_func.hpp"
00010 #include "core/math_func.hpp"
00011 #include "network/core/config.h"
00012 #include "variables.h"
00013 #include "string_func.h"
00014 #include "settings_type.h"
00015 #include "newgrf_config.h"
00016 #include "gamelog.h"
00017 #include "gamelog_internal.h"
00018 #include "console_func.h"
00019 #include "debug.h"
00020 #include "rev.h"
00021
00022 #include <string.h>
00023 #include <stdarg.h>
00024
00025 extern const uint16 SAVEGAME_VERSION;
00026
00027 extern SavegameType _savegame_type;
00028
00029 extern uint32 _ttdp_version;
00030 extern uint16 _sl_version;
00031 extern byte _sl_minor_version;
00032
00033
00034 static GamelogActionType _gamelog_action_type = GLAT_NONE;
00035
00036 LoggedAction *_gamelog_action = NULL;
00037 uint _gamelog_actions = 0;
00038 static LoggedAction *_current_action = NULL;
00039
00040
00045 void GamelogStartAction(GamelogActionType at)
00046 {
00047 assert(_gamelog_action_type == GLAT_NONE);
00048 _gamelog_action_type = at;
00049 }
00050
00053 void GamelogStopAction()
00054 {
00055 assert(_gamelog_action_type != GLAT_NONE);
00056
00057 bool print = _current_action != NULL;
00058
00059 _current_action = NULL;
00060 _gamelog_action_type = GLAT_NONE;
00061
00062 if (print) GamelogPrintDebug(5);
00063 }
00064
00067 void GamelogReset()
00068 {
00069 assert(_gamelog_action_type == GLAT_NONE);
00070
00071 for (uint i = 0; i < _gamelog_actions; i++) {
00072 const LoggedAction *la = &_gamelog_action[i];
00073 for (uint j = 0; j < la->changes; j++) {
00074 const LoggedChange *lc = &la->change[j];
00075 if (lc->ct == GLCT_PATCH) free(lc->patch.name);
00076 }
00077 free(la->change);
00078 }
00079
00080 free(_gamelog_action);
00081
00082 _gamelog_action = NULL;
00083 _gamelog_actions = 0;
00084 _current_action = NULL;
00085 }
00086
00087 enum {
00088 GAMELOG_BUF_LEN = 1024
00089 };
00090
00091 static int _dbgofs = 0;
00092
00093 static void AddDebugText(char *buf, const char *s, ...)
00094 {
00095 if (GAMELOG_BUF_LEN <= _dbgofs) return;
00096
00097 va_list va;
00098
00099 va_start(va, s);
00100 _dbgofs += vsnprintf(buf + _dbgofs, GAMELOG_BUF_LEN - _dbgofs, s, va);
00101 va_end(va);
00102 }
00103
00104
00108 static void PrintGrfFilename(char *buf, uint grfid)
00109 {
00110 const GRFConfig *gc = FindGRFConfig(grfid);
00111
00112 if (gc == NULL) return;
00113
00114 AddDebugText(buf, ", filename: %s", gc->filename);
00115 }
00116
00121 static void PrintGrfInfo(char *buf, uint grfid, const uint8 *md5sum)
00122 {
00123 char txt[40];
00124
00125 md5sumToString(txt, lastof(txt), md5sum);
00126
00127 AddDebugText(buf, "GRF ID %08X, checksum %s", BSWAP32(grfid), txt);
00128
00129 PrintGrfFilename(buf, grfid);
00130
00131 return;
00132 }
00133
00134
00136 static const char *la_text[] = {
00137 "new game started",
00138 "game loaded",
00139 "GRF config changed",
00140 "cheat was used",
00141 "patch settings changed",
00142 "GRF bug triggered",
00143 };
00144
00145 assert_compile(lengthof(la_text) == GLAT_END);
00146
00147
00149 void GamelogPrint(GamelogPrintProc *proc)
00150 {
00151 char buf[GAMELOG_BUF_LEN];
00152
00153 proc("---- gamelog start ----");
00154
00155 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00156
00157 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00158 assert((uint)la->at < GLAT_END);
00159
00160 snprintf(buf, GAMELOG_BUF_LEN, "Tick %u: %s", (uint)la->tick, la_text[(uint)la->at]);
00161 proc(buf);
00162
00163 const LoggedChange *lcend = &la->change[la->changes];
00164
00165 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00166 _dbgofs = 0;
00167 AddDebugText(buf, " ");
00168
00169 switch (lc->ct) {
00170 default: NOT_REACHED();
00171 case GLCT_MODE:
00172 AddDebugText(buf, "New game mode: %u landscape: %u",
00173 (uint)lc->mode.mode, (uint)lc->mode.landscape);
00174 break;
00175
00176 case GLCT_REVISION:
00177 AddDebugText(buf, "Revision text changed to %s, savegame version %u, ",
00178 lc->revision.text, lc->revision.slver);
00179
00180 switch (lc->revision.modified) {
00181 case 0: AddDebugText(buf, "not "); break;
00182 case 1: AddDebugText(buf, "maybe "); break;
00183 default: break;
00184 }
00185
00186 AddDebugText(buf, "modified, _openttd_newgrf_version = 0x%08x", lc->revision.newgrf);
00187 break;
00188
00189 case GLCT_OLDVER:
00190 AddDebugText(buf, "Conversion from ");
00191 switch (lc->oldver.type) {
00192 default: NOT_REACHED();
00193 case SGT_OTTD:
00194 AddDebugText(buf, "OTTD savegame without gamelog: version %u, %u",
00195 GB(lc->oldver.version, 8, 16), GB(lc->oldver.version, 0, 8));
00196 break;
00197
00198 case SGT_TTD:
00199 AddDebugText(buf, "TTD savegame");
00200 break;
00201
00202 case SGT_TTDP1:
00203 case SGT_TTDP2:
00204 AddDebugText(buf, "TTDP savegame, %s format",
00205 lc->oldver.type == SGT_TTDP1 ? "old" : "new");
00206 if (lc->oldver.version != 0) {
00207 AddDebugText(buf, ", TTDP version %u.%u.%u.%u",
00208 GB(lc->oldver.version, 24, 8), GB(lc->oldver.version, 20, 4),
00209 GB(lc->oldver.version, 16, 4), GB(lc->oldver.version, 0, 16));
00210 }
00211 break;
00212 }
00213 break;
00214
00215 case GLCT_PATCH:
00216 AddDebugText(buf, "Patch setting changed: %s : %d -> %d", lc->patch.name, lc->patch.oldval, lc->patch.newval);
00217 break;
00218
00219 case GLCT_GRFADD:
00220 AddDebugText(buf, "Added NewGRF: ");
00221 PrintGrfInfo(buf, lc->grfadd.grfid, lc->grfadd.md5sum);
00222 break;
00223
00224 case GLCT_GRFREM:
00225 AddDebugText(buf, "Removed NewGRF: %08X", BSWAP32(lc->grfrem.grfid));
00226 PrintGrfFilename(buf, lc->grfrem.grfid);
00227 break;
00228
00229 case GLCT_GRFCOMPAT:
00230 AddDebugText(buf, "Compatible NewGRF loaded: ");
00231 PrintGrfInfo(buf, lc->grfcompat.grfid, lc->grfcompat.md5sum);
00232 break;
00233
00234 case GLCT_GRFPARAM:
00235 AddDebugText(buf, "GRF parameter changed: %08X", BSWAP32(lc->grfparam.grfid));
00236 PrintGrfFilename(buf, lc->grfparam.grfid);
00237 break;
00238
00239 case GLCT_GRFMOVE:
00240 AddDebugText(buf, "GRF order changed: %08X moved %d places %s",
00241 BSWAP32(lc->grfmove.grfid), abs(lc->grfmove.offset), lc->grfmove.offset >= 0 ? "down" : "up" );
00242 PrintGrfFilename(buf, lc->grfmove.grfid);
00243 break;
00244
00245 case GLCT_GRFBUG:
00246 switch (lc->grfbug.bug) {
00247 default: NOT_REACHED();
00248 case GBUG_VEH_LENGTH:
00249 AddDebugText(buf, "Rail vehicle changes length outside a depot: GRF ID %08X, internal ID 0x%X", BSWAP32(lc->grfbug.grfid), (uint)lc->grfbug.data);
00250 PrintGrfFilename(buf, lc->grfbug.grfid);
00251 break;
00252 }
00253 }
00254
00255 proc(buf);
00256 }
00257 }
00258
00259 proc("---- gamelog end ----");
00260 }
00261
00262
00263 static void GamelogPrintConsoleProc(const char *s)
00264 {
00265 IConsolePrint(CC_WARNING, s);
00266 }
00267
00268 void GamelogPrintConsole()
00269 {
00270 GamelogPrint(&GamelogPrintConsoleProc);
00271 }
00272
00273 static int _gamelog_print_level = 0;
00274
00275 static void GamelogPrintDebugProc(const char *s)
00276 {
00277 DEBUG(gamelog, _gamelog_print_level, s);
00278 }
00279
00280
00286 void GamelogPrintDebug(int level)
00287 {
00288 _gamelog_print_level = level;
00289 GamelogPrint(&GamelogPrintDebugProc);
00290 }
00291
00292
00298 static LoggedChange *GamelogChange(GamelogChangeType ct)
00299 {
00300 if (_current_action == NULL) {
00301 if (_gamelog_action_type == GLAT_NONE) return NULL;
00302
00303 _gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1);
00304 _current_action = &_gamelog_action[_gamelog_actions++];
00305
00306 _current_action->at = _gamelog_action_type;
00307 _current_action->tick = _tick_counter;
00308 _current_action->change = NULL;
00309 _current_action->changes = 0;
00310 }
00311
00312 _current_action->change = ReallocT(_current_action->change, _current_action->changes + 1);
00313
00314 LoggedChange *lc = &_current_action->change[_current_action->changes++];
00315 lc->ct = ct;
00316
00317 return lc;
00318 }
00319
00320
00324 void GamelogRevision()
00325 {
00326 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD);
00327
00328 LoggedChange *lc = GamelogChange(GLCT_REVISION);
00329 if (lc == NULL) return;
00330
00331 strecpy(lc->revision.text, _openttd_revision, lastof(lc->revision.text));
00332 lc->revision.slver = SAVEGAME_VERSION;
00333 lc->revision.modified = _openttd_revision_modified;
00334 lc->revision.newgrf = _openttd_newgrf_version;
00335 }
00336
00339 void GamelogMode()
00340 {
00341 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_CHEAT);
00342
00343 LoggedChange *lc = GamelogChange(GLCT_MODE);
00344 if (lc == NULL) return;
00345
00346 lc->mode.mode = _game_mode;
00347 lc->mode.landscape = _settings_game.game_creation.landscape;
00348 }
00349
00352 void GamelogOldver()
00353 {
00354 assert(_gamelog_action_type == GLAT_LOAD);
00355
00356 LoggedChange *lc = GamelogChange(GLCT_OLDVER);
00357 if (lc == NULL) return;
00358
00359 lc->oldver.type = _savegame_type;
00360 lc->oldver.version = (_savegame_type == SGT_OTTD ? ((uint32)_sl_version << 8 | _sl_minor_version) : _ttdp_version);
00361 }
00362
00368 void GamelogPatch(const char *name, int32 oldval, int32 newval)
00369 {
00370 assert(_gamelog_action_type == GLAT_PATCH);
00371
00372 LoggedChange *lc = GamelogChange(GLCT_PATCH);
00373 if (lc == NULL) return;
00374
00375 lc->patch.name = strdup(name);
00376 lc->patch.oldval = oldval;
00377 lc->patch.newval = newval;
00378 }
00379
00380
00384 void GamelogTestRevision()
00385 {
00386 const LoggedChange *rev = NULL;
00387
00388 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00389 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00390 const LoggedChange *lcend = &la->change[la->changes];
00391 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00392 if (lc->ct == GLCT_REVISION) rev = lc;
00393 }
00394 }
00395
00396 if (rev == NULL || strcmp(rev->revision.text, _openttd_revision) != 0 ||
00397 rev->revision.modified != _openttd_revision_modified ||
00398 rev->revision.newgrf != _openttd_newgrf_version) {
00399 GamelogRevision();
00400 }
00401 }
00402
00406 void GamelogTestMode()
00407 {
00408 const LoggedChange *mode = NULL;
00409
00410 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00411 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00412 const LoggedChange *lcend = &la->change[la->changes];
00413 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00414 if (lc->ct == GLCT_MODE) mode = lc;
00415 }
00416 }
00417
00418 if (mode == NULL || mode->mode.mode != _game_mode || mode->mode.landscape != _settings_game.game_creation.landscape) GamelogMode();
00419 }
00420
00421
00427 static void GamelogGRFBug(uint32 grfid, byte bug, uint64 data)
00428 {
00429 assert(_gamelog_action_type == GLAT_GRFBUG);
00430
00431 LoggedChange *lc = GamelogChange(GLCT_GRFBUG);
00432 if (lc == NULL) return;
00433
00434 lc->grfbug.data = data;
00435 lc->grfbug.grfid = grfid;
00436 lc->grfbug.bug = bug;
00437 }
00438
00446 bool GamelogGRFBugReverse(uint32 grfid, uint16 internal_id)
00447 {
00448 const LoggedAction *laend = &_gamelog_action[_gamelog_actions];
00449 for (const LoggedAction *la = _gamelog_action; la != laend; la++) {
00450 const LoggedChange *lcend = &la->change[la->changes];
00451 for (const LoggedChange *lc = la->change; lc != lcend; lc++) {
00452 if (lc->ct == GLCT_GRFBUG && lc->grfbug.grfid == grfid &&
00453 lc->grfbug.bug == GBUG_VEH_LENGTH && lc->grfbug.data == internal_id) {
00454 return false;
00455 }
00456 }
00457 }
00458
00459 GamelogStartAction(GLAT_GRFBUG);
00460 GamelogGRFBug(grfid, GBUG_VEH_LENGTH, internal_id);
00461 GamelogStopAction();
00462
00463 return true;
00464 }
00465
00466
00471 static inline bool IsLoggableGrfConfig(const GRFConfig *g)
00472 {
00473 return !HasBit(g->flags, GCF_STATIC) && g->status != GCS_NOT_FOUND;
00474 }
00475
00479 void GamelogGRFRemove(uint32 grfid)
00480 {
00481 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF);
00482
00483 LoggedChange *lc = GamelogChange(GLCT_GRFREM);
00484 if (lc == NULL) return;
00485
00486 lc->grfrem.grfid = grfid;
00487 }
00488
00492 void GamelogGRFAdd(const GRFConfig *newg)
00493 {
00494 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_GRF);
00495
00496 if (!IsLoggableGrfConfig(newg)) return;
00497
00498 LoggedChange *lc = GamelogChange(GLCT_GRFADD);
00499 if (lc == NULL) return;
00500
00501 memcpy(&lc->grfadd, newg, sizeof(GRFIdentifier));
00502 }
00503
00508 void GamelogGRFCompatible(const GRFIdentifier *newg)
00509 {
00510 assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF);
00511
00512 LoggedChange *lc = GamelogChange(GLCT_GRFCOMPAT);
00513 if (lc == NULL) return;
00514
00515 memcpy(&lc->grfcompat, newg, sizeof(GRFIdentifier));
00516 }
00517
00522 static void GamelogGRFMove(uint32 grfid, int32 offset)
00523 {
00524 assert(_gamelog_action_type == GLAT_GRF);
00525
00526 LoggedChange *lc = GamelogChange(GLCT_GRFMOVE);
00527 if (lc == NULL) return;
00528
00529 lc->grfmove.grfid = grfid;
00530 lc->grfmove.offset = offset;
00531 }
00532
00537 static void GamelogGRFParameters(uint32 grfid)
00538 {
00539 assert(_gamelog_action_type == GLAT_GRF);
00540
00541 LoggedChange *lc = GamelogChange(GLCT_GRFPARAM);
00542 if (lc == NULL) return;
00543
00544 lc->grfparam.grfid = grfid;
00545 }
00546
00551 void GamelogGRFAddList(const GRFConfig *newg)
00552 {
00553 assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD);
00554
00555 for (; newg != NULL; newg = newg->next) {
00556 GamelogGRFAdd(newg);
00557 }
00558 }
00559
00561 struct GRFList {
00562 uint n;
00563 const GRFConfig *grf[VARARRAY_SIZE];
00564 };
00565
00569 static GRFList *GenerateGRFList(const GRFConfig *grfc)
00570 {
00571 uint n = 0;
00572 for (const GRFConfig *g = grfc; g != NULL; g = g->next) {
00573 if (IsLoggableGrfConfig(g)) n++;
00574 }
00575
00576 GRFList *list = (GRFList*)MallocT<byte>(sizeof(GRFList) + n * sizeof(GRFConfig*));
00577
00578 list->n = 0;
00579 for (const GRFConfig *g = grfc; g != NULL; g = g->next) {
00580 if (IsLoggableGrfConfig(g)) list->grf[list->n++] = g;
00581 }
00582
00583 return list;
00584 }
00585
00590 void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc)
00591 {
00592 GRFList *ol = GenerateGRFList(oldc);
00593 GRFList *nl = GenerateGRFList(newc);
00594
00595 uint o = 0, n = 0;
00596
00597 while (o < ol->n && n < nl->n) {
00598 const GRFConfig *og = ol->grf[o];
00599 const GRFConfig *ng = nl->grf[n];
00600
00601 if (og->grfid != ng->grfid) {
00602 uint oi, ni;
00603 for (oi = 0; oi < ol->n; oi++) {
00604 if (ol->grf[oi]->grfid == nl->grf[n]->grfid) break;
00605 }
00606 if (oi < o) {
00607
00608 n++;
00609 continue;
00610 }
00611 if (oi == ol->n) {
00612
00613 GamelogGRFAdd(nl->grf[n++]);
00614 continue;
00615 }
00616 for (ni = 0; ni < nl->n; ni++) {
00617 if (nl->grf[ni]->grfid == ol->grf[o]->grfid) break;
00618 }
00619 if (ni < n) {
00620
00621 o++;
00622 continue;
00623 }
00624 if (ni == nl->n) {
00625
00626 GamelogGRFRemove(ol->grf[o++]->grfid);
00627 continue;
00628 }
00629
00630
00631
00632 assert(ni > n && ni < nl->n);
00633 assert(oi > o && oi < ol->n);
00634
00635 ni -= n;
00636 oi -= o;
00637
00638 if (ni >= oi) {
00639
00640 GamelogGRFMove(ol->grf[o++]->grfid, ni);
00641 } else {
00642 GamelogGRFMove(nl->grf[n++]->grfid, -(int)oi);
00643 }
00644 } else {
00645 if (memcmp(og->md5sum, ng->md5sum, sizeof(og->md5sum)) != 0) {
00646
00647 GamelogGRFCompatible(nl->grf[n]);
00648 }
00649
00650 if (og->num_params != ng->num_params || memcmp(og->param, ng->param, og->num_params * sizeof(og->param[0])) != 0) {
00651 GamelogGRFParameters(ol->grf[o]->grfid);
00652 }
00653
00654 o++;
00655 n++;
00656 }
00657 }
00658
00659 while (o < ol->n) GamelogGRFRemove(ol->grf[o++]->grfid);
00660 while (n < nl->n) GamelogGRFAdd (nl->grf[n++]);
00661
00662 free(ol);
00663 free(nl);
00664 }