mirror of https://github.com/OpenTTD/OpenTTD
(svn r23065) -Add: -q option to read a savegame, write some general info and exit
parent
bd6d490987
commit
433f74edd9
|
@ -21,6 +21,7 @@
|
||||||
.Op Fl n Ar host[:port][#player]
|
.Op Fl n Ar host[:port][#player]
|
||||||
.Op Fl p Ar password
|
.Op Fl p Ar password
|
||||||
.Op Fl P Ar password
|
.Op Fl P Ar password
|
||||||
|
.Op Fl q Ar savegame
|
||||||
.Op Fl r Ar widthxheight
|
.Op Fl r Ar widthxheight
|
||||||
.Op Fl s Ar driver
|
.Op Fl s Ar driver
|
||||||
.Op Fl S Ar soundset
|
.Op Fl S Ar soundset
|
||||||
|
@ -83,6 +84,8 @@ Password used to join server. Only useful with
|
||||||
.It Fl P Ar password
|
.It Fl P Ar password
|
||||||
Password used to join company. Only useful with
|
Password used to join company. Only useful with
|
||||||
.Fl n
|
.Fl n
|
||||||
|
.It Fl q Ar savegame
|
||||||
|
Write some information about the savegame and exit
|
||||||
.It Fl r Ar widthxheight
|
.It Fl r Ar widthxheight
|
||||||
Set the resolution
|
Set the resolution
|
||||||
.It Fl s Ar driver
|
.It Fl s Ar driver
|
||||||
|
|
|
@ -37,7 +37,10 @@ struct LoadCheckData {
|
||||||
GRFConfig *grfconfig; ///< NewGrf configuration from save.
|
GRFConfig *grfconfig; ///< NewGrf configuration from save.
|
||||||
GRFListCompatibility grf_compatibility; ///< Summary state of NewGrfs, whether missing files or only compatible found.
|
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();
|
this->Clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,10 @@ void LoadCheckData::Clear()
|
||||||
}
|
}
|
||||||
companies.Clear();
|
companies.Clear();
|
||||||
|
|
||||||
|
free(this->gamelog_action);
|
||||||
|
this->gamelog_action = NULL;
|
||||||
|
this->gamelog_actions = 0;
|
||||||
|
|
||||||
ClearGRFConfigList(&this->grfconfig);
|
ClearGRFConfigList(&this->grfconfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -774,3 +774,33 @@ void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc)
|
||||||
free(ol);
|
free(ol);
|
||||||
free(nl);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -61,4 +61,6 @@ void GamelogTestMode();
|
||||||
|
|
||||||
bool GamelogGRFBugReverse(uint32 grfid, uint16 internal_id);
|
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 */
|
#endif /* GAMELOG_H */
|
||||||
|
|
|
@ -179,6 +179,7 @@ static void ShowHelp()
|
||||||
" -M music_set = Force the music set (see below)\n"
|
" -M music_set = Force the music set (see below)\n"
|
||||||
" -c config_file = Use 'config_file' instead of 'openttd.cfg'\n"
|
" -c config_file = Use 'config_file' instead of 'openttd.cfg'\n"
|
||||||
" -x = Do not automatically save to config file on exit\n"
|
" -x = Do not automatically save to config file on exit\n"
|
||||||
|
" -q savegame = Write some information about the savegame and exit\n"
|
||||||
"\n",
|
"\n",
|
||||||
lastof(buf)
|
lastof(buf)
|
||||||
);
|
);
|
||||||
|
@ -213,6 +214,44 @@ static void ShowHelp()
|
||||||
#endif
|
#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
|
* Extract the resolution from the given string and store
|
||||||
|
@ -432,6 +471,7 @@ static const OptionData _options[] = {
|
||||||
GETOPT_SHORT_VALUE('G'),
|
GETOPT_SHORT_VALUE('G'),
|
||||||
GETOPT_SHORT_VALUE('c'),
|
GETOPT_SHORT_VALUE('c'),
|
||||||
GETOPT_SHORT_NOVAL('x'),
|
GETOPT_SHORT_NOVAL('x'),
|
||||||
|
GETOPT_SHORT_VALUE('q'),
|
||||||
GETOPT_SHORT_NOVAL('h'),
|
GETOPT_SHORT_NOVAL('h'),
|
||||||
GETOPT_END()
|
GETOPT_END()
|
||||||
};
|
};
|
||||||
|
@ -542,6 +582,30 @@ int ttd_main(int argc, char *argv[])
|
||||||
scanner->generation_seed = InteractiveRandom();
|
scanner->generation_seed = InteractiveRandom();
|
||||||
}
|
}
|
||||||
break;
|
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 'G': scanner->generation_seed = atoi(mgo.opt); break;
|
||||||
case 'c': _config_file = strdup(mgo.opt); break;
|
case 'c': _config_file = strdup(mgo.opt); break;
|
||||||
case 'x': save_config = false; break;
|
case 'x': save_config = false; break;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
#include "../gamelog_internal.h"
|
#include "../gamelog_internal.h"
|
||||||
|
#include "../fios.h"
|
||||||
|
|
||||||
#include "saveload.h"
|
#include "saveload.h"
|
||||||
|
|
||||||
|
@ -101,15 +102,15 @@ static const SaveLoad * const _glog_desc[] = {
|
||||||
|
|
||||||
assert_compile(lengthof(_glog_desc) == GLCT_END);
|
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_action == NULL);
|
||||||
assert(_gamelog_actions == 0);
|
assert(gamelog_actions == 0);
|
||||||
|
|
||||||
GamelogActionType at;
|
GamelogActionType at;
|
||||||
while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) {
|
while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) {
|
||||||
_gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1);
|
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
|
||||||
LoggedAction *la = &_gamelog_action[_gamelog_actions++];
|
LoggedAction *la = &gamelog_action[gamelog_actions++];
|
||||||
|
|
||||||
la->at = at;
|
la->at = at;
|
||||||
|
|
||||||
|
@ -165,7 +166,16 @@ static void Save_GLOG()
|
||||||
SlWriteByte(GLAT_NONE);
|
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[] = {
|
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 }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue