mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-23 10:09:43 +01:00
Merge pull request #326 from InfoTeddy/general-refactors
Refactor how custom level stats are stored, read, and written
This commit is contained in:
commit
e85d5a8714
2 changed files with 137 additions and 85 deletions
|
@ -541,13 +541,8 @@ void Game::lifesequence()
|
||||||
|
|
||||||
void Game::clearcustomlevelstats()
|
void Game::clearcustomlevelstats()
|
||||||
{
|
{
|
||||||
//just clearing the arrays
|
//just clearing the array
|
||||||
for(int i=0; i<200; i++)
|
customlevelstats.clear();
|
||||||
{
|
|
||||||
customlevelstats[i]="";
|
|
||||||
customlevelscore[i]=0;
|
|
||||||
}
|
|
||||||
numcustomlevelstats=0;
|
|
||||||
|
|
||||||
customlevelstatsloaded=false; //To ensure we don't load it where it isn't needed
|
customlevelstatsloaded=false; //To ensure we don't load it where it isn't needed
|
||||||
}
|
}
|
||||||
|
@ -560,28 +555,24 @@ void Game::updatecustomlevelstats(std::string clevel, int cscore)
|
||||||
clevel = clevel.substr(7);
|
clevel = clevel.substr(7);
|
||||||
}
|
}
|
||||||
int tvar=-1;
|
int tvar=-1;
|
||||||
for(int j=0; j<numcustomlevelstats; j++)
|
for(size_t j=0; j<customlevelstats.size(); j++)
|
||||||
{
|
{
|
||||||
if(clevel==customlevelstats[j])
|
if(clevel==customlevelstats[j].name)
|
||||||
{
|
{
|
||||||
tvar=j;
|
tvar=j;
|
||||||
j=numcustomlevelstats+1;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(tvar>=0 && cscore > customlevelscore[tvar])
|
if(tvar>=0 && cscore > customlevelstats[tvar].score)
|
||||||
{
|
{
|
||||||
//update existing entry
|
//update existing entry
|
||||||
customlevelscore[tvar]=cscore;
|
customlevelstats[tvar].score=cscore;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//add a new entry
|
//add a new entry
|
||||||
if(numcustomlevelstats<200)
|
CustomLevelStat levelstat = {clevel, cscore};
|
||||||
{
|
customlevelstats.push_back(levelstat);
|
||||||
customlevelstats[numcustomlevelstats]=clevel;
|
|
||||||
customlevelscore[numcustomlevelstats]=cscore;
|
|
||||||
numcustomlevelstats++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
savecustomlevelstats();
|
savecustomlevelstats();
|
||||||
}
|
}
|
||||||
|
@ -589,76 +580,117 @@ void Game::updatecustomlevelstats(std::string clevel, int cscore)
|
||||||
void Game::loadcustomlevelstats()
|
void Game::loadcustomlevelstats()
|
||||||
{
|
{
|
||||||
//testing
|
//testing
|
||||||
if(!customlevelstatsloaded)
|
if(customlevelstatsloaded)
|
||||||
{
|
{
|
||||||
tinyxml2::XMLDocument doc;
|
return;
|
||||||
if (!FILESYSTEM_loadTiXml2Document("saves/levelstats.vvv", doc))
|
}
|
||||||
{
|
|
||||||
//No levelstats file exists; start new
|
|
||||||
numcustomlevelstats=0;
|
|
||||||
savecustomlevelstats();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tinyxml2::XMLHandle hDoc(&doc);
|
|
||||||
tinyxml2::XMLElement* pElem;
|
|
||||||
tinyxml2::XMLHandle hRoot(NULL);
|
|
||||||
|
|
||||||
|
tinyxml2::XMLDocument doc;
|
||||||
|
if (!FILESYSTEM_loadTiXml2Document("saves/levelstats.vvv", doc))
|
||||||
|
{
|
||||||
|
//No levelstats file exists; start new
|
||||||
|
customlevelstats.clear();
|
||||||
|
savecustomlevelstats();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Old system
|
||||||
|
std::vector<std::string> customlevelnames;
|
||||||
|
std::vector<int> customlevelscores;
|
||||||
|
|
||||||
|
tinyxml2::XMLHandle hDoc(&doc);
|
||||||
|
tinyxml2::XMLElement* pElem;
|
||||||
|
tinyxml2::XMLHandle hRoot(NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
pElem=hDoc.FirstChildElement().ToElement();
|
||||||
|
// should always have a valid root but handle gracefully if it does
|
||||||
|
if (!pElem)
|
||||||
|
{
|
||||||
|
printf("Error: Levelstats file corrupted\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// save this for later
|
||||||
|
hRoot=tinyxml2::XMLHandle(pElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// First pass, look for the new system of storing stats
|
||||||
|
// If they don't exist, then fall back to the old system
|
||||||
|
for (pElem = hRoot.FirstChildElement("Data").FirstChild().ToElement(); pElem; pElem = pElem->NextSiblingElement())
|
||||||
|
{
|
||||||
|
std::string pKey(pElem->Value());
|
||||||
|
const char* pText = pElem->GetText();
|
||||||
|
if (pText == NULL)
|
||||||
|
{
|
||||||
|
pText = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pKey == "stats")
|
||||||
|
{
|
||||||
|
for (tinyxml2::XMLElement* stat_el = pElem->FirstChildElement(); stat_el; stat_el = stat_el->NextSiblingElement())
|
||||||
{
|
{
|
||||||
pElem=hDoc.FirstChildElement().ToElement();
|
CustomLevelStat stat = {};
|
||||||
// should always have a valid root but handle gracefully if it does
|
|
||||||
if (!pElem)
|
if (stat_el->GetText() != NULL)
|
||||||
{
|
{
|
||||||
printf("Error: Levelstats file corrupted\n");
|
stat.score = atoi(stat_el->GetText());
|
||||||
}
|
}
|
||||||
|
|
||||||
// save this for later
|
if (stat_el->Attribute("name"))
|
||||||
hRoot=tinyxml2::XMLHandle(pElem);
|
{
|
||||||
|
stat.name = stat_el->Attribute("name");
|
||||||
|
}
|
||||||
|
|
||||||
|
customlevelstats.push_back(stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for( pElem = hRoot.FirstChildElement( "Data" ).FirstChild().ToElement(); pElem; pElem=pElem->NextSiblingElement())
|
|
||||||
|
// Since we're still here, we must be on the old system
|
||||||
|
for( pElem = hRoot.FirstChildElement( "Data" ).FirstChild().ToElement(); pElem; pElem=pElem->NextSiblingElement())
|
||||||
|
{
|
||||||
|
std::string pKey(pElem->Value());
|
||||||
|
const char* pText = pElem->GetText() ;
|
||||||
|
if(pText == NULL)
|
||||||
|
{
|
||||||
|
pText = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pKey == "customlevelscore")
|
||||||
|
{
|
||||||
|
std::string TextString = (pText);
|
||||||
|
if(TextString.length())
|
||||||
{
|
{
|
||||||
std::string pKey(pElem->Value());
|
std::vector<std::string> values = split(TextString,',');
|
||||||
const char* pText = pElem->GetText() ;
|
for(size_t i = 0; i < values.size(); i++)
|
||||||
if(pText == NULL)
|
|
||||||
{
|
{
|
||||||
pText = "";
|
customlevelscores.push_back(atoi(values[i].c_str()));
|
||||||
}
|
|
||||||
|
|
||||||
if (pKey == "numcustomlevelstats")
|
|
||||||
{
|
|
||||||
numcustomlevelstats = atoi(pText);
|
|
||||||
if(numcustomlevelstats>=200) numcustomlevelstats=199;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pKey == "customlevelscore")
|
|
||||||
{
|
|
||||||
std::string TextString = (pText);
|
|
||||||
if(TextString.length())
|
|
||||||
{
|
|
||||||
std::vector<std::string> values = split(TextString,',');
|
|
||||||
for(size_t i = 0; i < values.size(); i++)
|
|
||||||
{
|
|
||||||
if(i<200) customlevelscore[i]=(atoi(values[i].c_str()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pKey == "customlevelstats")
|
|
||||||
{
|
|
||||||
std::string TextString = (pText);
|
|
||||||
if(TextString.length())
|
|
||||||
{
|
|
||||||
std::vector<std::string> values = split(TextString,'|');
|
|
||||||
for(size_t i = 0; i < values.size(); i++)
|
|
||||||
{
|
|
||||||
if(i<200) customlevelstats[i]=values[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pKey == "customlevelstats")
|
||||||
|
{
|
||||||
|
std::string TextString = (pText);
|
||||||
|
if(TextString.length())
|
||||||
|
{
|
||||||
|
std::vector<std::string> values = split(TextString,'|');
|
||||||
|
for(size_t i = 0; i < values.size(); i++)
|
||||||
|
{
|
||||||
|
customlevelnames.push_back(values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the two arrays happen to differ in length, just go with the smallest one
|
||||||
|
for (size_t i = 0; i < std::min(customlevelnames.size(), customlevelscores.size()); i++)
|
||||||
|
{
|
||||||
|
CustomLevelStat stat = {customlevelnames[i], customlevelscores[i]};
|
||||||
|
customlevelstats.push_back(stat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,6 +710,7 @@ void Game::savecustomlevelstats()
|
||||||
tinyxml2::XMLElement * msgs = doc.NewElement( "Data" );
|
tinyxml2::XMLElement * msgs = doc.NewElement( "Data" );
|
||||||
root->LinkEndChild( msgs );
|
root->LinkEndChild( msgs );
|
||||||
|
|
||||||
|
int numcustomlevelstats = customlevelstats.size();
|
||||||
if(numcustomlevelstats>=200)numcustomlevelstats=199;
|
if(numcustomlevelstats>=200)numcustomlevelstats=199;
|
||||||
msg = doc.NewElement( "numcustomlevelstats" );
|
msg = doc.NewElement( "numcustomlevelstats" );
|
||||||
msg->LinkEndChild( doc.NewText( help.String(numcustomlevelstats).c_str() ));
|
msg->LinkEndChild( doc.NewText( help.String(numcustomlevelstats).c_str() ));
|
||||||
|
@ -686,7 +719,7 @@ void Game::savecustomlevelstats()
|
||||||
std::string customlevelscorestr;
|
std::string customlevelscorestr;
|
||||||
for(int i = 0; i < numcustomlevelstats; i++ )
|
for(int i = 0; i < numcustomlevelstats; i++ )
|
||||||
{
|
{
|
||||||
customlevelscorestr += help.String(customlevelscore[i]) + ",";
|
customlevelscorestr += help.String(customlevelstats[i].score) + ",";
|
||||||
}
|
}
|
||||||
msg = doc.NewElement( "customlevelscore" );
|
msg = doc.NewElement( "customlevelscore" );
|
||||||
msg->LinkEndChild( doc.NewText( customlevelscorestr.c_str() ));
|
msg->LinkEndChild( doc.NewText( customlevelscorestr.c_str() ));
|
||||||
|
@ -695,12 +728,27 @@ void Game::savecustomlevelstats()
|
||||||
std::string customlevelstatsstr;
|
std::string customlevelstatsstr;
|
||||||
for(int i = 0; i < numcustomlevelstats; i++ )
|
for(int i = 0; i < numcustomlevelstats; i++ )
|
||||||
{
|
{
|
||||||
customlevelstatsstr += customlevelstats[i] + "|";
|
customlevelstatsstr += customlevelstats[i].name + "|";
|
||||||
}
|
}
|
||||||
msg = doc.NewElement( "customlevelstats" );
|
msg = doc.NewElement( "customlevelstats" );
|
||||||
msg->LinkEndChild( doc.NewText( customlevelstatsstr.c_str() ));
|
msg->LinkEndChild( doc.NewText( customlevelstatsstr.c_str() ));
|
||||||
msgs->LinkEndChild( msg );
|
msgs->LinkEndChild( msg );
|
||||||
|
|
||||||
|
// New system
|
||||||
|
msg = doc.NewElement("stats");
|
||||||
|
tinyxml2::XMLElement* stat_el;
|
||||||
|
for (size_t i = 0; i < customlevelstats.size(); i++)
|
||||||
|
{
|
||||||
|
stat_el = doc.NewElement("stat");
|
||||||
|
CustomLevelStat& stat = customlevelstats[i];
|
||||||
|
|
||||||
|
stat_el->SetAttribute("name", stat.name.c_str());
|
||||||
|
stat_el->LinkEndChild(doc.NewText(help.String(stat.score).c_str()));
|
||||||
|
|
||||||
|
msg->LinkEndChild(stat_el);
|
||||||
|
}
|
||||||
|
msgs->LinkEndChild(msg);
|
||||||
|
|
||||||
if(FILESYSTEM_saveTiXml2Document("saves/levelstats.vvv", doc))
|
if(FILESYSTEM_saveTiXml2Document("saves/levelstats.vvv", doc))
|
||||||
{
|
{
|
||||||
printf("Level stats saved\n");
|
printf("Level stats saved\n");
|
||||||
|
@ -7028,26 +7076,26 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
|
||||||
{
|
{
|
||||||
//This is, er, suboptimal. Whatever, life optimisation and all that
|
//This is, er, suboptimal. Whatever, life optimisation and all that
|
||||||
int tvar=-1;
|
int tvar=-1;
|
||||||
for(int j=0; j<numcustomlevelstats; j++)
|
for(size_t j=0; j<customlevelstats.size(); j++)
|
||||||
{
|
{
|
||||||
if(ed.ListOfMetaData[i].filename.substr(7) == customlevelstats[j])
|
if(ed.ListOfMetaData[i].filename.substr(7) == customlevelstats[j].name)
|
||||||
{
|
{
|
||||||
tvar=j;
|
tvar=j;
|
||||||
j=numcustomlevelstats+1;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string text;
|
std::string text;
|
||||||
if(tvar>=0)
|
if(tvar>=0)
|
||||||
{
|
{
|
||||||
if(customlevelscore[tvar]==0)
|
if(customlevelstats[tvar].score==0)
|
||||||
{
|
{
|
||||||
text = " " + ed.ListOfMetaData[i].title;
|
text = " " + ed.ListOfMetaData[i].title;
|
||||||
}
|
}
|
||||||
else if(customlevelscore[tvar]==1)
|
else if(customlevelstats[tvar].score==1)
|
||||||
{
|
{
|
||||||
text = " * " + ed.ListOfMetaData[i].title;
|
text = " * " + ed.ListOfMetaData[i].title;
|
||||||
}
|
}
|
||||||
else if(customlevelscore[tvar]==3)
|
else if(customlevelstats[tvar].score==3)
|
||||||
{
|
{
|
||||||
text = "** " + ed.ListOfMetaData[i].title;
|
text = "** " + ed.ListOfMetaData[i].title;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,12 @@ struct MenuStackFrame
|
||||||
enum Menu::MenuName name;
|
enum Menu::MenuName name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CustomLevelStat
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
int score; //0 - not played, 1 - finished, 2 - all trinkets, 3 - finished, all trinkets
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Game
|
class Game
|
||||||
{
|
{
|
||||||
|
@ -364,9 +370,7 @@ public:
|
||||||
void savecustomlevelstats();
|
void savecustomlevelstats();
|
||||||
void updatecustomlevelstats(std::string clevel, int cscore);
|
void updatecustomlevelstats(std::string clevel, int cscore);
|
||||||
|
|
||||||
std::string customlevelstats[200]; //string array containing level filenames
|
std::vector<CustomLevelStat> customlevelstats;
|
||||||
int customlevelscore[200];//0 - not played, 1 - finished, 2 - all trinkets, 3 - finished, all trinkets
|
|
||||||
int numcustomlevelstats;
|
|
||||||
bool customlevelstatsloaded;
|
bool customlevelstatsloaded;
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue