mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 11:10:47 +00:00
- save custom data as JSON.
This makes it a lot easier to debug and test than binary blobs.
This commit is contained in:
parent
619a7541f1
commit
ab9c532d89
4 changed files with 141 additions and 80 deletions
|
@ -6,6 +6,7 @@
|
||||||
#include "c_cvars.h"
|
#include "c_cvars.h"
|
||||||
#include "v_font.h"
|
#include "v_font.h"
|
||||||
#include "v_draw.h"
|
#include "v_draw.h"
|
||||||
|
#include "sjson.h"
|
||||||
#include "savegamehelp.h"
|
#include "savegamehelp.h"
|
||||||
|
|
||||||
// Unlike in GZDoom we have to maintain this list here, because we got different game frontents that all store this info differently.
|
// Unlike in GZDoom we have to maintain this list here, because we got different game frontents that all store this info differently.
|
||||||
|
@ -109,28 +110,51 @@ CCMD(secret)
|
||||||
|
|
||||||
void SECRET_Save()
|
void SECRET_Save()
|
||||||
{
|
{
|
||||||
auto fil = WriteSavegameChunk("secrets.dat");
|
sjson_context* ctx = sjson_create_context(0, 0, NULL);
|
||||||
fil->Write("SECR", 4);
|
if (!ctx)
|
||||||
unsigned count = discovered_secrets.Size();
|
{
|
||||||
fil->Write(&count, 4);
|
return;
|
||||||
fil->Write(discovered_secrets.Data(), 4 * count);
|
}
|
||||||
fil->Write("RCES", 4);
|
sjson_node* root = sjson_mkobject(ctx);
|
||||||
|
sjson_put_ints(ctx, root, "secrets", discovered_secrets.Data(), discovered_secrets.Size());
|
||||||
|
|
||||||
|
char* encoded = sjson_stringify(ctx, root, " ");
|
||||||
|
|
||||||
|
FileWriter* fil = WriteSavegameChunk("secrets.json");
|
||||||
|
if (!fil)
|
||||||
|
{
|
||||||
|
sjson_destroy_context(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fil->Write(encoded, strlen(encoded));
|
||||||
|
|
||||||
|
sjson_free_string(ctx, encoded);
|
||||||
|
sjson_destroy_context(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SECRET_Load()
|
bool SECRET_Load()
|
||||||
{
|
{
|
||||||
char buf[4];
|
auto fil = ReadSavegameChunk("statistics.json");
|
||||||
unsigned count;
|
if (!fil.isOpen())
|
||||||
auto fil = ReadSavegameChunk("secrets.dat");
|
{
|
||||||
if (!fil.isOpen()) return false;
|
return false;
|
||||||
fil.Read(buf, 4);
|
}
|
||||||
if (memcmp(buf, "SECR", 4)) return false;
|
|
||||||
fil.Read(&count, 4);
|
auto text = fil.ReadPadded(1);
|
||||||
discovered_secrets.Resize(count);
|
fil.Close();
|
||||||
fil.Read(discovered_secrets.Data(), count * 4);
|
|
||||||
fil.Read(buf, 4);
|
if (text.Size() == 0)
|
||||||
if (memcmp(buf, "RCES", 4)) return false;
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sjson_context* ctx = sjson_create_context(0, 0, NULL);
|
||||||
|
sjson_node* root = sjson_decode(ctx, (const char*)text.Data());
|
||||||
|
discovered_secrets.Resize(1000); // Retarted interface alert
|
||||||
|
int realsize = sjson_get_ints(discovered_secrets.Data(), 1000, root, "secrets");
|
||||||
|
discovered_secrets.Resize(realsize);
|
||||||
|
sjson_destroy_context(ctx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "sc_man.h"
|
#include "sc_man.h"
|
||||||
#include "baselayer.h"
|
#include "baselayer.h"
|
||||||
#include "savegamehelp.h"
|
#include "savegamehelp.h"
|
||||||
|
#include "sjson.h"
|
||||||
|
|
||||||
CVAR(Int, savestatistics, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR(Int, savestatistics, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
CVAR(String, statfile, "demolitionstat.txt", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR(String, statfile, "demolitionstat.txt", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
@ -67,9 +68,9 @@ struct OneLevel
|
||||||
|
|
||||||
// Current game's statistics
|
// Current game's statistics
|
||||||
static TArray<OneLevel> LevelData;
|
static TArray<OneLevel> LevelData;
|
||||||
static char StartEpisode[MAX_PATH];
|
static FString StartEpisode;
|
||||||
static int StartSkill;
|
static int StartSkill;
|
||||||
static char LevelName[MAX_PATH];
|
static FString LevelName;
|
||||||
|
|
||||||
// The statistics for one level
|
// The statistics for one level
|
||||||
struct FLevelStatistics
|
struct FLevelStatistics
|
||||||
|
@ -352,15 +353,15 @@ static void LevelStatEntry(FSessionStatistics *es, const char *level, const char
|
||||||
|
|
||||||
void STAT_StartNewGame(const char *episode, int skill)
|
void STAT_StartNewGame(const char *episode, int skill)
|
||||||
{
|
{
|
||||||
strncpy(StartEpisode, episode, MAX_PATH);
|
StartEpisode = episode;
|
||||||
StartSkill = skill;
|
StartSkill = skill;
|
||||||
LevelData.Clear();
|
LevelData.Clear();
|
||||||
*LevelName = 0;
|
LevelName = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void STAT_NewLevel(const char* mapname)
|
void STAT_NewLevel(const char* mapname)
|
||||||
{
|
{
|
||||||
strncpy(LevelName, mapname, MAX_PATH);
|
LevelName = mapname;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -443,14 +444,14 @@ void STAT_Update(bool endofgame)
|
||||||
}
|
}
|
||||||
SaveStatistics(statfile, EpisodeStatistics);
|
SaveStatistics(statfile, EpisodeStatistics);
|
||||||
LevelData.Clear();
|
LevelData.Clear();
|
||||||
*StartEpisode = *LevelName = 0;
|
StartEpisode = LevelName = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void STAT_Cancel()
|
void STAT_Cancel()
|
||||||
{
|
{
|
||||||
LevelData.Clear();
|
LevelData.Clear();
|
||||||
*StartEpisode = *LevelName = 0;
|
StartEpisode = LevelName = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -459,67 +460,109 @@ void STAT_Cancel()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void SaveOneLevel(FileWriter& fil, OneLevel& l)
|
void SaveOneLevel(sjson_context *ctx, sjson_node *lev, OneLevel& l)
|
||||||
{
|
{
|
||||||
fil.Write(&l.totalkills, 4);
|
sjson_put_int(ctx, lev, "totalkills", l.totalkills);
|
||||||
fil.Write(&l.killcount, 4);
|
sjson_put_int(ctx, lev, "kills", l.killcount);
|
||||||
fil.Write(&l.totalsecrets, 4);
|
sjson_put_int(ctx, lev, "totalsecrets", l.totalsecrets);
|
||||||
fil.Write(&l.secretcount, 4);
|
sjson_put_int(ctx, lev, "secrets", l.secretcount);
|
||||||
fil.Write(&l.leveltime, 4);
|
sjson_put_int(ctx, lev, "leveltime", l.leveltime);
|
||||||
uint8_t siz = l.Levelname.Len();
|
sjson_put_string(ctx, lev, "levelname", l.Levelname);
|
||||||
fil.Write(&siz, 1);
|
|
||||||
fil.Write(l.Levelname.GetChars(), siz);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadOneLevel(FileReader& fil, OneLevel& l)
|
void ReadOneLevel(sjson_node *lev, OneLevel& l)
|
||||||
{
|
{
|
||||||
fil.Read(&l.totalkills, 4);
|
|
||||||
fil.Read(&l.killcount, 4);
|
l.totalkills = sjson_get_int(lev, "totalkills", 0);
|
||||||
fil.Read(&l.totalsecrets, 4);
|
l.killcount = sjson_get_int(lev, "kills", 0);
|
||||||
fil.Read(&l.secretcount, 4);
|
l.totalsecrets = sjson_get_int(lev, "totalsecrets", 0);
|
||||||
fil.Read(&l.leveltime, 4);
|
l.secretcount = sjson_get_int(lev, "secrets", 0);
|
||||||
uint8_t siz;
|
l.leveltime = sjson_get_int(lev, "leveltime", 0);
|
||||||
fil.Read(&siz, 1);
|
l.Levelname = sjson_get_string(lev, "levelname", "");
|
||||||
auto p = l.Levelname.LockNewBuffer(siz);
|
|
||||||
fil.Read(p, siz);
|
|
||||||
l.Levelname.UnlockBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveStatistics()
|
void SaveStatistics()
|
||||||
{
|
{
|
||||||
auto fil = WriteSavegameChunk("statistics.dat");
|
sjson_context* ctx = sjson_create_context(0, 0, NULL);
|
||||||
fil->Write("STAT", 4);
|
if (!ctx)
|
||||||
fil->Write(LevelName, MAX_PATH);
|
{
|
||||||
fil->Write(&StartEpisode, MAX_PATH);
|
return;
|
||||||
fil->Write(&StartSkill, 4);
|
}
|
||||||
int p = LevelData.Size();
|
sjson_node* root = sjson_mkobject(ctx);
|
||||||
fil->Write(&p, 4);
|
|
||||||
|
sjson_put_string(ctx, root, "levelname", LevelName);
|
||||||
|
sjson_put_string(ctx, root, "episode", StartEpisode);
|
||||||
|
sjson_put_int(ctx, root, "skill", StartSkill);
|
||||||
|
|
||||||
|
sjson_node* levels = sjson_mkarray(ctx);
|
||||||
for (auto& lev : LevelData)
|
for (auto& lev : LevelData)
|
||||||
{
|
{
|
||||||
SaveOneLevel(*fil, lev);
|
sjson_node* levj = sjson_mkobject(ctx);
|
||||||
|
SaveOneLevel(ctx, levj, lev);
|
||||||
}
|
}
|
||||||
fil->Write("TATS", 4);
|
sjson_append_member(ctx, root, "levels", levels);
|
||||||
|
|
||||||
|
char errmsg[256];
|
||||||
|
if (!sjson_check(root, errmsg))
|
||||||
|
{
|
||||||
|
buildprint(errmsg, "\n");
|
||||||
|
sjson_destroy_context(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* encoded = sjson_stringify(ctx, root, " ");
|
||||||
|
|
||||||
|
FileWriter* fil = WriteSavegameChunk("statistics.json");
|
||||||
|
if (!fil)
|
||||||
|
{
|
||||||
|
sjson_destroy_context(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fil->Write(encoded, strlen(encoded));
|
||||||
|
|
||||||
|
sjson_free_string(ctx, encoded);
|
||||||
|
sjson_destroy_context(ctx);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadStatistics()
|
bool ReadStatistics()
|
||||||
{
|
{
|
||||||
char id[4];
|
auto fil = ReadSavegameChunk("statistics.json");
|
||||||
auto fil = ReadSavegameChunk("statistics.dat");
|
if (!fil.isOpen())
|
||||||
if (!fil.isOpen()) return false;
|
{
|
||||||
fil.Read(id, 4);
|
return false;
|
||||||
if (memcmp(id, "STAT", 4)) return false;
|
}
|
||||||
fil.Read(LevelName, MAX_PATH);
|
|
||||||
fil.Read(&StartEpisode, MAX_PATH);
|
auto text = fil.ReadPadded(1);
|
||||||
fil.Read(&StartSkill, 4);
|
fil.Close();
|
||||||
int p;
|
|
||||||
fil.Read(&p, 4);
|
if (text.Size() == 0)
|
||||||
LevelData.Resize(p);
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sjson_context* ctx = sjson_create_context(0, 0, NULL);
|
||||||
|
sjson_node* root = sjson_decode(ctx, (const char*)text.Data());
|
||||||
|
|
||||||
|
LevelName = sjson_get_string(root, "levelname", "");
|
||||||
|
StartEpisode = sjson_get_int(root, "episode", -1);
|
||||||
|
StartSkill = sjson_get_int(root, "skill", -1);
|
||||||
|
sjson_node* levels = sjson_find_member(root, "levels");
|
||||||
|
|
||||||
|
if (LevelName.Len() == 0 || StartEpisode == -1 || StartSkill == -1 || levels == nullptr)
|
||||||
|
{
|
||||||
|
sjson_destroy_context(ctx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numlevels = sjson_child_count(levels);
|
||||||
|
LevelData.Resize(numlevels);
|
||||||
for (auto& lev : LevelData)
|
for (auto& lev : LevelData)
|
||||||
{
|
{
|
||||||
ReadOneLevel(fil, lev);
|
ReadOneLevel(levels, lev);
|
||||||
}
|
}
|
||||||
fil.Read(id, 4);
|
sjson_destroy_context(ctx);
|
||||||
if (memcmp(id, "TATS", 4)) return false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "gamecvars.h"
|
#include "gamecvars.h"
|
||||||
#include "d_event.h"
|
#include "d_event.h"
|
||||||
#include "i_specialpaths.h"
|
#include "i_specialpaths.h"
|
||||||
|
#include "savegamehelp.h"
|
||||||
|
|
||||||
BEGIN_DUKE_NS
|
BEGIN_DUKE_NS
|
||||||
|
|
||||||
|
@ -5631,13 +5632,6 @@ int portableBackupSave(const char * path, const char * name, int volume, int lev
|
||||||
if (!FURY)
|
if (!FURY)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
char fn[BMAX_PATH];
|
|
||||||
|
|
||||||
if (snprintf(fn, sizeof(fn), "%s%s.ext", M_GetSavegamesPath().GetChars(), path))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sjson_context * ctx = sjson_create_context(0, 0, NULL);
|
sjson_context * ctx = sjson_create_context(0, 0, NULL);
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
{
|
{
|
||||||
|
@ -5729,7 +5723,7 @@ int portableBackupSave(const char * path, const char * name, int volume, int lev
|
||||||
|
|
||||||
char * encoded = sjson_stringify(ctx, root, " ");
|
char * encoded = sjson_stringify(ctx, root, " ");
|
||||||
|
|
||||||
FileWriter *fil = FileWriter::Open(fn);
|
FileWriter* fil = WriteSavegameChunk("ext.json");
|
||||||
if (!fil)
|
if (!fil)
|
||||||
{
|
{
|
||||||
sjson_destroy_context(ctx);
|
sjson_destroy_context(ctx);
|
||||||
|
|
8
source/thirdparty/include/sjson.h
vendored
8
source/thirdparty/include/sjson.h
vendored
|
@ -228,7 +228,7 @@ double sjson_get_double(sjson_node* parent, const char* key, double default_va
|
||||||
const char* sjson_get_string(sjson_node* parent, const char* key, const char* default_val);
|
const char* sjson_get_string(sjson_node* parent, const char* key, const char* default_val);
|
||||||
bool sjson_get_bool(sjson_node* parent, const char* key, bool default_val);
|
bool sjson_get_bool(sjson_node* parent, const char* key, bool default_val);
|
||||||
bool sjson_get_floats(float* out, int count, sjson_node* parent, const char* key);
|
bool sjson_get_floats(float* out, int count, sjson_node* parent, const char* key);
|
||||||
bool sjson_get_ints(int* out, int count, sjson_node* parent, const char* key);
|
int sjson_get_ints(int* out, int count, sjson_node* parent, const char* key);
|
||||||
bool sjson_get_uints(uint32_t* out, int count, sjson_node* parent, const char* key);
|
bool sjson_get_uints(uint32_t* out, int count, sjson_node* parent, const char* key);
|
||||||
bool sjson_get_int16s(int16_t* out, int count, sjson_node* parent, const char* key);
|
bool sjson_get_int16s(int16_t* out, int count, sjson_node* parent, const char* key);
|
||||||
bool sjson_get_uint16s(uint16_t* out, int count, sjson_node* parent, const char* key);
|
bool sjson_get_uint16s(uint16_t* out, int count, sjson_node* parent, const char* key);
|
||||||
|
@ -1283,7 +1283,7 @@ bool sjson_get_floats(float* out, int count, sjson_node* parent, const char* key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sjson_get_ints(int* out, int count, sjson_node* parent, const char* key)
|
int sjson_get_ints(int* out, int count, sjson_node* parent, const char* key)
|
||||||
{
|
{
|
||||||
sjson_node* p = key ? sjson_find_member(parent, key) : parent;
|
sjson_node* p = key ? sjson_find_member(parent, key) : parent;
|
||||||
if (p) {
|
if (p) {
|
||||||
|
@ -1293,9 +1293,9 @@ bool sjson_get_ints(int* out, int count, sjson_node* parent, const char* key)
|
||||||
sjson_assert(elem->tag == SJSON_NUMBER);
|
sjson_assert(elem->tag == SJSON_NUMBER);
|
||||||
out[index++] = (int)elem->number_;
|
out[index++] = (int)elem->number_;
|
||||||
}
|
}
|
||||||
return index == count;
|
return index;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue