# HG changeset patch # User yexo # Date 2011-10-30 13:47:45 # Node ID 9a85d923ce33719560bf538c81e7e5d7f76831e5 # Parent 2a27481f55c8049229af08020bfab8f66dde56fc (svn r23065) -Add: -q option to read a savegame, write some general info and exit diff --git a/docs/openttd.6 b/docs/openttd.6 --- a/docs/openttd.6 +++ b/docs/openttd.6 @@ -21,6 +21,7 @@ .Op Fl n Ar host[:port][#player] .Op Fl p Ar password .Op Fl P Ar password +.Op Fl q Ar savegame .Op Fl r Ar widthxheight .Op Fl s Ar driver .Op Fl S Ar soundset @@ -83,6 +84,8 @@ Password used to join server. Only usefu .It Fl P Ar password Password used to join company. Only useful with .Fl n +.It Fl q Ar savegame +Write some information about the savegame and exit .It Fl r Ar widthxheight Set the resolution .It Fl s Ar driver diff --git a/src/fios.h b/src/fios.h --- a/src/fios.h +++ b/src/fios.h @@ -37,7 +37,10 @@ struct LoadCheckData { GRFConfig *grfconfig; ///< NewGrf configuration from save. GRFListCompatibility grf_compatibility; ///< Summary state of NewGrfs, whether missing files or only compatible found. - LoadCheckData() : error_data(NULL), grfconfig(NULL) + struct LoggedAction *gamelog_action; ///< Gamelog actions + uint gamelog_actions; ///< Number of gamelog actions + + LoadCheckData() : error_data(NULL), grfconfig(NULL), gamelog_action(NULL) { this->Clear(); } diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -57,6 +57,10 @@ void LoadCheckData::Clear() } companies.Clear(); + free(this->gamelog_action); + this->gamelog_action = NULL; + this->gamelog_actions = 0; + ClearGRFConfigList(&this->grfconfig); } diff --git a/src/gamelog.cpp b/src/gamelog.cpp --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -774,3 +774,33 @@ void GamelogGRFUpdate(const GRFConfig *o free(ol); free(nl); } + +/** + * Get some basic information from the given gamelog. + * @param gamelog_action Pointer to the gamelog to extract information from. + * @param gamelog_actions Number of actions in the given gamelog. + * @param [out] last_ottd_rev OpenTTD NewGRF version from the binary that saved the savegame last. + * @param [out] ever_modified Max value of 'modified' from all binaries that ever saved this savegame. + * @param [out] removed_newgrfs Set to true if any NewGRFs have been removed. + */ +void GamelogInfo(LoggedAction *gamelog_action, uint gamelog_actions, uint32 *last_ottd_rev, byte *ever_modified, bool *removed_newgrfs) +{ + const LoggedAction *laend = &gamelog_action[gamelog_actions]; + for (const LoggedAction *la = gamelog_action; la != laend; la++) { + const LoggedChange *lcend = &la->change[la->changes]; + for (const LoggedChange *lc = la->change; lc != lcend; lc++) { + switch (lc->ct) { + default: break; + + case GLCT_REVISION: + *last_ottd_rev = lc->revision.newgrf; + *ever_modified = max(*ever_modified, lc->revision.modified); + break; + + case GLCT_GRFREM: + *removed_newgrfs = true; + break; + } + } + } +} diff --git a/src/gamelog.h b/src/gamelog.h --- a/src/gamelog.h +++ b/src/gamelog.h @@ -61,4 +61,6 @@ void GamelogTestMode(); bool GamelogGRFBugReverse(uint32 grfid, uint16 internal_id); +void GamelogInfo(struct LoggedAction *gamelog_action, uint gamelog_actions, uint32 *last_ottd_rev, byte *ever_modified, bool *removed_newgrfs); + #endif /* GAMELOG_H */ diff --git a/src/openttd.cpp b/src/openttd.cpp --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -179,6 +179,7 @@ static void ShowHelp() " -M music_set = Force the music set (see below)\n" " -c config_file = Use 'config_file' instead of 'openttd.cfg'\n" " -x = Do not automatically save to config file on exit\n" + " -q savegame = Write some information about the savegame and exit\n" "\n", lastof(buf) ); @@ -213,6 +214,44 @@ static void ShowHelp() #endif } +static void WriteSavegameInfo(const char *name) +{ + extern uint16 _sl_version; + uint32 last_ottd_rev = 0; + byte ever_modified = 0; + bool removed_newgrfs = false; + + GamelogInfo(_load_check_data.gamelog_action, _load_check_data.gamelog_actions, &last_ottd_rev, &ever_modified, &removed_newgrfs); + + char buf[8192]; + char *p = buf; + p += seprintf(p, lastof(buf), "Name: %s\n", name); + p += seprintf(p, lastof(buf), "Savegame ver: %d\n", _sl_version); + p += seprintf(p, lastof(buf), "NewGRF ver: 0x%08X\n", last_ottd_rev); + p += seprintf(p, lastof(buf), "Modified: %d\n", ever_modified); + + if (removed_newgrfs) { + p += seprintf(p, lastof(buf), "NewGRFs have been removed\n"); + } + + p = strecpy(p, "NewGRFs:\n", lastof(buf)); + if (_load_check_data.HasNewGrfs()) { + for (GRFConfig *c = _load_check_data.grfconfig; c != NULL; c = c->next) { + char md5sum[33]; + md5sumToString(md5sum, lastof(md5sum), HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum); + p += seprintf(p, lastof(buf), "%08X %s %s\n", c->ident.grfid, md5sum, c->filename); + } + } + + /* ShowInfo put output to stderr, but version information should go + * to stdout; this is the only exception */ +#if !defined(WIN32) && !defined(WIN64) + printf("%s\n", buf); +#else + ShowInfo(buf); +#endif +} + /** * Extract the resolution from the given string and store @@ -432,6 +471,7 @@ static const OptionData _options[] = { GETOPT_SHORT_VALUE('G'), GETOPT_SHORT_VALUE('c'), GETOPT_SHORT_NOVAL('x'), + GETOPT_SHORT_VALUE('q'), GETOPT_SHORT_NOVAL('h'), GETOPT_END() }; @@ -542,6 +582,30 @@ int ttd_main(int argc, char *argv[]) scanner->generation_seed = InteractiveRandom(); } break; + case 'q': { + DeterminePaths(argv[0]); + if (StrEmpty(mgo.opt)) return 1; + char title[80]; + title[0] = '\0'; + FiosGetSavegameListCallback(SLD_LOAD_GAME, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title)); + + _load_check_data.Clear(); + SaveOrLoadResult res = SaveOrLoad(mgo.opt, SL_LOAD_CHECK, SAVE_DIR, false); + if (res != SL_OK || _load_check_data.HasErrors()) { + fprintf(stderr, "Failed to open savegame\n"); + if (_load_check_data.HasErrors()) { + char buf[256]; + SetDParamStr(0, _load_check_data.error_data); + GetString(buf, _load_check_data.error, lastof(buf)); + fprintf(stderr, "%s\n", buf); + } + return 1; + } + + WriteSavegameInfo(title); + + return 0; + } case 'G': scanner->generation_seed = atoi(mgo.opt); break; case 'c': _config_file = strdup(mgo.opt); break; case 'x': save_config = false; break; diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp --- a/src/saveload/gamelog_sl.cpp +++ b/src/saveload/gamelog_sl.cpp @@ -11,6 +11,7 @@ #include "../stdafx.h" #include "../gamelog_internal.h" +#include "../fios.h" #include "saveload.h" @@ -101,15 +102,15 @@ static const SaveLoad * const _glog_desc assert_compile(lengthof(_glog_desc) == GLCT_END); -static void Load_GLOG() +static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_actions) { - assert(_gamelog_action == NULL); - assert(_gamelog_actions == 0); + assert(gamelog_action == NULL); + assert(gamelog_actions == 0); GamelogActionType at; while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) { - _gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1); - LoggedAction *la = &_gamelog_action[_gamelog_actions++]; + gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1); + LoggedAction *la = &gamelog_action[gamelog_actions++]; la->at = at; @@ -165,7 +166,16 @@ static void Save_GLOG() SlWriteByte(GLAT_NONE); } +static void Load_GLOG() +{ + Load_GLOG_common(_gamelog_action, _gamelog_actions); +} + +static void Check_GLOG() +{ + Load_GLOG_common(_load_check_data.gamelog_action, _load_check_data.gamelog_actions); +} extern const ChunkHandler _gamelog_chunk_handlers[] = { - { 'GLOG', Save_GLOG, Load_GLOG, NULL, NULL, CH_RIFF | CH_LAST } + { 'GLOG', Save_GLOG, Load_GLOG, NULL, Check_GLOG, CH_RIFF | CH_LAST } };