mirror of https://github.com/stella-emu/stella.git
changed high score (file) format to JSON
This commit is contained in:
parent
2e0c0549e7
commit
ebbec177f6
|
@ -347,7 +347,6 @@ void ContextMenu::drawCurrentSelection(int item)
|
||||||
if(_selectedOffset != item)
|
if(_selectedOffset != item)
|
||||||
{
|
{
|
||||||
_selectedOffset = item;
|
_selectedOffset = item;
|
||||||
cerr << "ContextMenu" << endl;
|
|
||||||
setDirty();
|
setDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -534,10 +534,28 @@ void HighScoresDialog::saveHighScores(Int32 variation) const
|
||||||
|
|
||||||
buf << instance().stateDir() << cartName() << ".hs" << variation;
|
buf << instance().stateDir() << cartName() << ".hs" << variation;
|
||||||
|
|
||||||
// Make sure the file can be opened for writing
|
//// Make sure the file can be opened for writing
|
||||||
Serializer out(buf.str());
|
//Serializer out(buf.str());
|
||||||
|
|
||||||
if(!out)
|
//if(!out)
|
||||||
|
//{
|
||||||
|
// buf.str("");
|
||||||
|
// buf << "Can't open/save to high scores file for variation " << variation;
|
||||||
|
// instance().frameBuffer().showTextMessage(buf.str());
|
||||||
|
//}
|
||||||
|
|
||||||
|
//// Do a complete high scores save
|
||||||
|
//if(!save(out, variation))
|
||||||
|
//{
|
||||||
|
// buf.str("");
|
||||||
|
// buf << "Error saving high scores for variation" << variation;
|
||||||
|
// instance().frameBuffer().showTextMessage(buf.str());
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Make sure the file can be opened for writing
|
||||||
|
FilesystemNode node(buf.str());
|
||||||
|
|
||||||
|
if(!node.isWritable())
|
||||||
{
|
{
|
||||||
buf.str("");
|
buf.str("");
|
||||||
buf << "Can't open/save to high scores file for variation " << variation;
|
buf << "Can't open/save to high scores file for variation " << variation;
|
||||||
|
@ -545,13 +563,12 @@ void HighScoresDialog::saveHighScores(Int32 variation) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do a complete high scores save
|
// Do a complete high scores save
|
||||||
if(!save(out, variation))
|
if(!save(node, variation))
|
||||||
{
|
{
|
||||||
buf.str("");
|
buf.str("");
|
||||||
buf << "Error saving high scores for variation" << variation;
|
buf << "Error saving high scores for variation" << variation;
|
||||||
instance().frameBuffer().showTextMessage(buf.str());
|
instance().frameBuffer().showTextMessage(buf.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -569,53 +586,78 @@ void HighScoresDialog::loadHighScores(Int32 variation)
|
||||||
|
|
||||||
buf << instance().stateDir() << cartName() << ".hs" << variation;
|
buf << instance().stateDir() << cartName() << ".hs" << variation;
|
||||||
|
|
||||||
// Make sure the file can be opened in read-only mode
|
FilesystemNode node(buf.str());
|
||||||
Serializer in(buf.str(), Serializer::Mode::ReadOnly);
|
stringstream in;
|
||||||
|
|
||||||
if(!in)
|
buf.str("");
|
||||||
return;
|
// Make sure the file can be opened
|
||||||
|
try {
|
||||||
|
node.read(in);
|
||||||
|
}
|
||||||
|
catch(...) { return; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
string highscores;
|
||||||
|
|
||||||
|
buf.str("");
|
||||||
|
// Make sure the file can be opened
|
||||||
|
node.read(in);
|
||||||
|
|
||||||
|
if(getline(in, highscores) && highscores.length() != 0)
|
||||||
|
{
|
||||||
|
json hsData = json::parse(highscores);
|
||||||
|
|
||||||
// First test if we have a valid header
|
// First test if we have a valid header
|
||||||
// If so, do a complete high scores load
|
// If so, do a complete high scores load
|
||||||
buf.str("");
|
if(!hsData.contains(VERSION) || hsData.at(VERSION) != HIGHSCORE_HEADER)
|
||||||
try
|
|
||||||
{
|
|
||||||
if (in.getString() != HIGHSCORE_HEADER)
|
|
||||||
buf << "Incompatible high scores for variation " << variation << " file";
|
buf << "Incompatible high scores for variation " << variation << " file";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (load(in, variation))
|
if(load(hsData, variation))
|
||||||
return;
|
return;
|
||||||
else
|
else
|
||||||
buf << "Invalid data in high scores for variation " << variation << " file";
|
buf << "Invalid data in high scores for variation " << variation << " file";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(...)
|
}
|
||||||
{
|
catch(...) {
|
||||||
buf << "Invalid data in high scores for variation " << variation << " file";
|
buf << "Invalid data in high scores for variation " << variation << " file";
|
||||||
}
|
}
|
||||||
|
|
||||||
instance().frameBuffer().showTextMessage(buf.str());
|
instance().frameBuffer().showTextMessage(buf.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool HighScoresDialog::save(Serializer& out, Int32 variation) const
|
bool HighScoresDialog::save(FilesystemNode& node, Int32 variation) const
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
json jData = json::object();
|
||||||
|
|
||||||
// Add header so that if the high score format changes in the future,
|
// Add header so that if the high score format changes in the future,
|
||||||
// we'll know right away, without having to parse the rest of the file
|
// we'll know right away, without having to parse the rest of the file
|
||||||
out.putString(HIGHSCORE_HEADER);
|
jData[VERSION] = HIGHSCORE_HEADER;
|
||||||
|
jData[MD5] = myMD5;
|
||||||
|
jData[VARIATION] = variation;
|
||||||
|
|
||||||
|
json jScores = json::array();
|
||||||
|
|
||||||
out.putString(myMD5);
|
|
||||||
out.putInt(variation);
|
|
||||||
for(uInt32 r = 0; r < NUM_RANKS; ++r)
|
for(uInt32 r = 0; r < NUM_RANKS; ++r)
|
||||||
{
|
{
|
||||||
out.putInt(myHighScores[r]);
|
json jScore = json::object();
|
||||||
out.putInt(mySpecials[r]);
|
|
||||||
out.putString(myNames[r]);
|
jScore[SCORE] = myHighScores[r];
|
||||||
out.putString(myDates[r]);
|
jScore[SPECIAL] = mySpecials[r];
|
||||||
|
jScore[NAME] = myNames[r];
|
||||||
|
jScore[DATE] = myDates[r];
|
||||||
|
|
||||||
|
jScores.push_back(jScore);
|
||||||
}
|
}
|
||||||
|
jData[SCORES] = jScores;
|
||||||
|
|
||||||
|
//stringstream ss(jData.dump());
|
||||||
|
//node.write(ss);
|
||||||
|
|
||||||
|
node.write(stringstream(jData.dump()));
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -626,27 +668,28 @@ bool HighScoresDialog::save(Serializer& out, Int32 variation) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool HighScoresDialog::load(Serializer& in, Int32 variation)
|
bool HighScoresDialog::load(const json& hsData, Int32 variation)
|
||||||
{
|
{
|
||||||
try
|
if(!hsData.contains(MD5) || hsData.at(MD5) != myMD5
|
||||||
{
|
|| !hsData.contains(VARIATION) || hsData.at(VARIATION) != variation
|
||||||
if (in.getString() != myMD5)
|
|| !hsData.contains(SCORES))
|
||||||
return false;
|
|
||||||
if (Int32(in.getInt()) != variation)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (uInt32 r = 0; r < NUM_RANKS; ++r)
|
const json& jScores = hsData.at(SCORES);
|
||||||
|
|
||||||
|
if(!jScores.empty() && jScores.is_array())
|
||||||
{
|
{
|
||||||
myHighScores[r] = in.getInt();
|
uInt32 r = 0;
|
||||||
mySpecials[r] = in.getInt();
|
for(const json& jScore : jScores)
|
||||||
myNames[r] = in.getString();
|
|
||||||
myDates[r] = in.getString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
{
|
||||||
cerr << "ERROR: HighScoresDialog::load() exception\n";
|
if(jScore.contains(SCORE)) myHighScores[r] = jScore.at(SCORE).get<Int32>();
|
||||||
return false;
|
if(jScore.contains(SPECIAL)) mySpecials[r] = jScore.at(SPECIAL).get<Int32>();
|
||||||
|
if(jScore.contains(NAME)) myNames[r] = jScore.at(NAME).get<string>();
|
||||||
|
if(jScore.contains(DATE)) myDates[r] = jScore.at(DATE).get<string>();
|
||||||
|
|
||||||
|
if(++r == NUM_RANKS)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -666,3 +709,13 @@ string HighScoresDialog::now() const
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
const string HighScoresDialog::VERSION = "version";
|
||||||
|
const string HighScoresDialog::MD5 = "md5";
|
||||||
|
const string HighScoresDialog::VARIATION = "variation";
|
||||||
|
const string HighScoresDialog::SCORES = "scores";
|
||||||
|
const string HighScoresDialog::SCORE = "score";
|
||||||
|
const string HighScoresDialog::SPECIAL = "special";
|
||||||
|
const string HighScoresDialog::NAME = "name";
|
||||||
|
const string HighScoresDialog::DATE = "date";
|
||||||
|
|
|
@ -33,6 +33,11 @@ class Serializer;
|
||||||
|
|
||||||
#include "Menu.hxx"
|
#include "Menu.hxx"
|
||||||
#include "Dialog.hxx"
|
#include "Dialog.hxx"
|
||||||
|
#include "FSNode.hxx"
|
||||||
|
#include "json_lib.hxx"
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The dialog for displaying high scores in Stella.
|
The dialog for displaying high scores in Stella.
|
||||||
|
@ -66,20 +71,20 @@ class HighScoresDialog : public Dialog
|
||||||
void loadHighScores(Int32 variation);
|
void loadHighScores(Int32 variation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Saves the current high scores for this game and variation to the given Serializer.
|
Saves the current high scores for this game and variation to the given file system node.
|
||||||
|
|
||||||
@param out The serializer device to save to.
|
@param node The file system node to save to.
|
||||||
@return The result of the save. True on success, false on failure.
|
@return The result of the save. True on success, false on failure.
|
||||||
*/
|
*/
|
||||||
bool save(Serializer& out, Int32 variation) const;
|
bool save(FilesystemNode& node, Int32 variation) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Loads the current high scores for this game and variation from the given Serializer.
|
Loads the current high scores for this game and variation from the given JSON object.
|
||||||
|
|
||||||
@param in The Serializer device to load from.
|
@param hsData The JSON to parse
|
||||||
@return The result of the load. True on success, false on failure.
|
@return The result of the load. True on success, false on failure.
|
||||||
*/
|
*/
|
||||||
bool load(Serializer& in, Int32 variation);
|
bool load(const json& hsData, Int32 variation);
|
||||||
|
|
||||||
string now() const;
|
string now() const;
|
||||||
|
|
||||||
|
@ -92,6 +97,16 @@ class HighScoresDialog : public Dialog
|
||||||
kCancelSave = 'CcSv'
|
kCancelSave = 'CcSv'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const string VERSION;
|
||||||
|
static const string MD5;
|
||||||
|
static const string VARIATION;
|
||||||
|
static const string SCORES;
|
||||||
|
static const string SCORE;
|
||||||
|
static const string SPECIAL;
|
||||||
|
static const string NAME;
|
||||||
|
static const string DATE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool myUserDefVar; // allow the user to define the variation
|
bool myUserDefVar; // allow the user to define the variation
|
||||||
bool myDirty;
|
bool myDirty;
|
||||||
|
|
Loading…
Reference in New Issue