changeset 18229:31df2e8b9565 draft

(svn r23065) -Add: -q option to read a savegame, write some general info and exit
author yexo <yexo@openttd.org>
date Sun, 30 Oct 2011 13:47:45 +0000
parents e96148be8f1c
children 45ffd1f16f34
files docs/openttd.6 src/fios.h src/fios_gui.cpp src/gamelog.cpp src/gamelog.h src/openttd.cpp src/saveload/gamelog_sl.cpp
diffstat 7 files changed, 123 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
 .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
--- a/src/fios.h
+++ b/src/fios.h
@@ -37,7 +37,10 @@
 	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();
 	}
--- a/src/fios_gui.cpp
+++ b/src/fios_gui.cpp
@@ -57,6 +57,10 @@
 	}
 	companies.Clear();
 
+	free(this->gamelog_action);
+	this->gamelog_action = NULL;
+	this->gamelog_actions = 0;
+
 	ClearGRFConfigList(&this->grfconfig);
 }
 
--- a/src/gamelog.cpp
+++ b/src/gamelog.cpp
@@ -774,3 +774,33 @@
 	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;
+			}
+		}
+	}
+}
--- a/src/gamelog.h
+++ b/src/gamelog.h
@@ -61,4 +61,6 @@
 
 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 */
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -179,6 +179,7 @@
 		"  -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 @@
 #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 @@
 	 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 @@
 				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;
--- 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 @@
 
 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 @@
 	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 }
 };