summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/openttd.63
-rw-r--r--src/fios.h5
-rw-r--r--src/fios_gui.cpp4
-rw-r--r--src/gamelog.cpp30
-rw-r--r--src/gamelog.h2
-rw-r--r--src/openttd.cpp64
-rw-r--r--src/saveload/gamelog_sl.cpp22
7 files changed, 123 insertions, 7 deletions
diff --git a/docs/openttd.6 b/docs/openttd.6
index 1c451ccb6..0382306d7 100644
--- 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 useful with
.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
index c34de10e9..bf354617d 100644
--- 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
index 27c0f5625..c5a657dd6 100644
--- 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
index 4cda9de14..f4f009166 100644
--- a/src/gamelog.cpp
+++ b/src/gamelog.cpp
@@ -774,3 +774,33 @@ void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc)
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
index 0fa54e9c2..8357cb90a 100644
--- 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
index 1f63fe558..9d729fd2f 100644
--- 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
index 0218a5a20..f25a8d1eb 100644
--- 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 }
};