mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-23 01:59:43 +01:00
Move all settings to settings.vvv
The game previously did this dumb thing where it lumped in all its settings with its file that tracked your records and unlocks, `unlock.vvv`. It wasn't really an issue, until 2.3 came along and added a few settings, suddenly making a problem where 2.3 settings would be reset by chance if you decided to touch 2.2. The solution to this is to move all settings to a new file, `settings.vvv`. However, for compatibility with 2.2, settings will still be written to `unlock.vvv`. The game will prioritize reading from `settings.vvv` instead of `unlock.vvv`, so if there's a setting that's missing from `unlock.vvv`, no worries there. But if `settings.vvv` is missing, then it'll read settings from `unlock.vvv`. As well, if `unlock.vvv` is missing, then `settings.vvv` will be read from instead (I explicitly tested for this, and found that I had to write special code to handle this case, otherwise the game would overwrite the existing `settings.vvv` before reading from it; kids, make sure to always test your code!). Closes #373 fully.
This commit is contained in:
parent
9e1ba97f63
commit
5aa8b99113
6 changed files with 144 additions and 27 deletions
|
@ -4436,6 +4436,14 @@ void Game::deletestats()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::deletesettings()
|
||||||
|
{
|
||||||
|
if (!FILESYSTEM_delete("saves/settings.vvv"))
|
||||||
|
{
|
||||||
|
puts("Error deleting saves/settings.vvv");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Game::unlocknum( int t )
|
void Game::unlocknum( int t )
|
||||||
{
|
{
|
||||||
#if !defined(MAKEANDPLAY)
|
#if !defined(MAKEANDPLAY)
|
||||||
|
@ -4471,7 +4479,10 @@ void Game::loadstats(int *width, int *height, bool *vsync)
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
if (!FILESYSTEM_loadTiXml2Document("saves/unlock.vvv", doc))
|
if (!FILESYSTEM_loadTiXml2Document("saves/unlock.vvv", doc))
|
||||||
{
|
{
|
||||||
savestats();
|
// Save unlock.vvv only. Maybe we have a settings.vvv laying around too,
|
||||||
|
// and we don't want to overwrite that!
|
||||||
|
savestats(true);
|
||||||
|
|
||||||
printf("No Stats found. Assuming a new player\n");
|
printf("No Stats found. Assuming a new player\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4493,7 +4504,9 @@ void Game::loadstats(int *width, int *height, bool *vsync)
|
||||||
hRoot=tinyxml2::XMLHandle(pElem);
|
hRoot=tinyxml2::XMLHandle(pElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
for( pElem = hRoot.FirstChildElement( "Data" ).FirstChild().ToElement(); pElem; pElem=pElem->NextSiblingElement())
|
tinyxml2::XMLElement* dataNode = hRoot.FirstChildElement("Data").FirstChild().ToElement();
|
||||||
|
|
||||||
|
for( pElem = dataNode; pElem; pElem=pElem->NextSiblingElement())
|
||||||
{
|
{
|
||||||
std::string pKey(pElem->Value());
|
std::string pKey(pElem->Value());
|
||||||
const char* pText = pElem->GetText() ;
|
const char* pText = pElem->GetText() ;
|
||||||
|
@ -4526,6 +4539,35 @@ void Game::loadstats(int *width, int *height, bool *vsync)
|
||||||
stat_trinkets = help.Int(pText);
|
stat_trinkets = help.Int(pText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pKey == "swnbestrank")
|
||||||
|
{
|
||||||
|
swnbestrank = help.Int(pText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pKey == "swnrecord")
|
||||||
|
{
|
||||||
|
swnrecord = help.Int(pText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializesettings(dataNode, width, height, vsync);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::deserializesettings(tinyxml2::XMLElement* dataNode, int* width, int* height, bool* vsync)
|
||||||
|
{
|
||||||
|
// Don't duplicate controller buttons!
|
||||||
|
controllerButton_flip.clear();
|
||||||
|
controllerButton_map.clear();
|
||||||
|
controllerButton_esc.clear();
|
||||||
|
controllerButton_restart.clear();
|
||||||
|
|
||||||
|
for (tinyxml2::XMLElement* pElem = dataNode;
|
||||||
|
pElem != NULL;
|
||||||
|
pElem = pElem->NextSiblingElement())
|
||||||
|
{
|
||||||
|
std::string pKey(pElem->Value());
|
||||||
|
const char* pText = pElem->GetText();
|
||||||
|
|
||||||
if (pKey == "fullscreen")
|
if (pKey == "fullscreen")
|
||||||
{
|
{
|
||||||
fullscreen = help.Int(pText);
|
fullscreen = help.Int(pText);
|
||||||
|
@ -4595,16 +4637,6 @@ void Game::loadstats(int *width, int *height, bool *vsync)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pKey == "swnbestrank")
|
|
||||||
{
|
|
||||||
swnbestrank = help.Int(pText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pKey == "swnrecord")
|
|
||||||
{
|
|
||||||
swnrecord = help.Int(pText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pKey == "advanced_smoothing")
|
if (pKey == "advanced_smoothing")
|
||||||
{
|
{
|
||||||
fullScreenEffect_badSignal = help.Int(pText);
|
fullScreenEffect_badSignal = help.Int(pText);
|
||||||
|
@ -4734,7 +4766,7 @@ void Game::loadstats(int *width, int *height, bool *vsync)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::savestats()
|
void Game::savestats(const bool stats_only /*= true*/)
|
||||||
{
|
{
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
bool already_exists = FILESYSTEM_loadTiXml2Document("saves/unlock.vvv", doc);
|
bool already_exists = FILESYSTEM_loadTiXml2Document("saves/unlock.vvv", doc);
|
||||||
|
@ -4804,6 +4836,24 @@ void Game::savestats()
|
||||||
|
|
||||||
xml::update_tag(dataNode, "stat_trinkets", stat_trinkets);
|
xml::update_tag(dataNode, "stat_trinkets", stat_trinkets);
|
||||||
|
|
||||||
|
xml::update_tag(dataNode, "swnbestrank", swnbestrank);
|
||||||
|
|
||||||
|
xml::update_tag(dataNode, "swnrecord", swnrecord);
|
||||||
|
|
||||||
|
serializesettings(dataNode);
|
||||||
|
|
||||||
|
FILESYSTEM_saveTiXml2Document("saves/unlock.vvv", doc);
|
||||||
|
|
||||||
|
if (!stats_only)
|
||||||
|
{
|
||||||
|
savesettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::serializesettings(tinyxml2::XMLElement* dataNode)
|
||||||
|
{
|
||||||
|
tinyxml2::XMLDocument& doc = xml::get_document(dataNode);
|
||||||
|
|
||||||
xml::update_tag(dataNode, "fullscreen", fullscreen);
|
xml::update_tag(dataNode, "fullscreen", fullscreen);
|
||||||
|
|
||||||
xml::update_tag(dataNode, "stretch", stretchMode);
|
xml::update_tag(dataNode, "stretch", stretchMode);
|
||||||
|
@ -4834,10 +4884,6 @@ void Game::savestats()
|
||||||
|
|
||||||
xml::update_tag(dataNode, "slowdown", slowdown);
|
xml::update_tag(dataNode, "slowdown", slowdown);
|
||||||
|
|
||||||
xml::update_tag(dataNode, "swnbestrank", swnbestrank);
|
|
||||||
|
|
||||||
xml::update_tag(dataNode, "swnrecord", swnrecord);
|
|
||||||
|
|
||||||
|
|
||||||
xml::update_tag(dataNode, "advanced_smoothing", fullScreenEffect_badSignal);
|
xml::update_tag(dataNode, "advanced_smoothing", fullScreenEffect_badSignal);
|
||||||
|
|
||||||
|
@ -4927,8 +4973,58 @@ void Game::savestats()
|
||||||
}
|
}
|
||||||
|
|
||||||
xml::update_tag(dataNode, "controllerSensitivity", controllerSensitivity);
|
xml::update_tag(dataNode, "controllerSensitivity", controllerSensitivity);
|
||||||
|
}
|
||||||
|
|
||||||
FILESYSTEM_saveTiXml2Document("saves/unlock.vvv", doc);
|
void Game::loadsettings(int* width, int* height, bool* vsync)
|
||||||
|
{
|
||||||
|
tinyxml2::XMLDocument doc;
|
||||||
|
if (!FILESYSTEM_loadTiXml2Document("saves/settings.vvv", doc))
|
||||||
|
{
|
||||||
|
savesettings();
|
||||||
|
puts("No settings.vvv found");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 doesn't
|
||||||
|
if (!pElem)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
// save this for later
|
||||||
|
hRoot = tinyxml2::XMLHandle(pElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
tinyxml2::XMLElement* dataNode = hRoot.FirstChildElement("Data").FirstChild().ToElement();
|
||||||
|
|
||||||
|
deserializesettings(dataNode, width, height, vsync);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::savesettings()
|
||||||
|
{
|
||||||
|
tinyxml2::XMLDocument doc;
|
||||||
|
bool already_exists = FILESYSTEM_loadTiXml2Document("saves/settings.vvv", doc);
|
||||||
|
if (!already_exists)
|
||||||
|
{
|
||||||
|
puts("No settings.vvv found. Creating new file");
|
||||||
|
}
|
||||||
|
|
||||||
|
xml::update_declaration(doc);
|
||||||
|
|
||||||
|
tinyxml2::XMLElement* root = xml::update_element(doc, "Settings");
|
||||||
|
|
||||||
|
xml::update_comment(root, " Settings (duplicated from unlock.vvv) ");
|
||||||
|
|
||||||
|
tinyxml2::XMLElement* dataNode = xml::update_element(root, "Data");
|
||||||
|
|
||||||
|
serializesettings(dataNode);
|
||||||
|
|
||||||
|
FILESYSTEM_saveTiXml2Document("saves/settings.vvv", doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::customstart()
|
void Game::customstart()
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// Forward decl without including all of <tinyxml2.h>
|
// Forward decl without including all of <tinyxml2.h>
|
||||||
namespace tinyxml2 { class XMLDocument; }
|
namespace tinyxml2
|
||||||
|
{
|
||||||
|
class XMLDocument;
|
||||||
|
class XMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
struct MenuOption
|
struct MenuOption
|
||||||
{
|
{
|
||||||
|
@ -126,10 +130,20 @@ public:
|
||||||
|
|
||||||
void loadstats(int *width, int *height, bool *vsync);
|
void loadstats(int *width, int *height, bool *vsync);
|
||||||
|
|
||||||
void savestats();
|
void savestats(const bool stats_only = false);
|
||||||
|
|
||||||
void deletestats();
|
void deletestats();
|
||||||
|
|
||||||
|
void deserializesettings(tinyxml2::XMLElement* dataNode, int* width, int* height, bool* vsync);
|
||||||
|
|
||||||
|
void serializesettings(tinyxml2::XMLElement* dataNode);
|
||||||
|
|
||||||
|
void loadsettings(int* width, int* height, bool* vsync);
|
||||||
|
|
||||||
|
void savesettings();
|
||||||
|
|
||||||
|
void deletesettings();
|
||||||
|
|
||||||
void deletequick();
|
void deletequick();
|
||||||
|
|
||||||
bool savetele();
|
bool savetele();
|
||||||
|
|
|
@ -1280,6 +1280,7 @@ void menuactionpress()
|
||||||
game.deletequick();
|
game.deletequick();
|
||||||
game.deletetele();
|
game.deletetele();
|
||||||
game.deletestats();
|
game.deletestats();
|
||||||
|
game.deletesettings();
|
||||||
game.flashlight = 5;
|
game.flashlight = 5;
|
||||||
game.screenshake = 15;
|
game.screenshake = 15;
|
||||||
game.createmenu(Menu::mainmenu);
|
game.createmenu(Menu::mainmenu);
|
||||||
|
|
|
@ -4,17 +4,16 @@
|
||||||
namespace xml
|
namespace xml
|
||||||
{
|
{
|
||||||
|
|
||||||
// Helper functions for these utils (not exported)
|
// Just get the document, because TinyXML-2 is annoying.
|
||||||
|
// Useful outside of this file.
|
||||||
static inline tinyxml2::XMLDocument& get_document(tinyxml2::XMLNode* parent)
|
// TODO: But XML handling should really be put in a separate file (maybe this
|
||||||
|
// one renamed?) instead of lumped in with Game.cpp, and when that happens
|
||||||
|
// maybe this will be unexported again?
|
||||||
|
tinyxml2::XMLDocument& get_document(tinyxml2::XMLNode* parent)
|
||||||
{
|
{
|
||||||
return *(parent->GetDocument());
|
return *(parent->GetDocument());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// EXPORTED FUNCTIONS
|
|
||||||
|
|
||||||
|
|
||||||
// Create a new element if it doesn't exist. Returns the element.
|
// Create a new element if it doesn't exist. Returns the element.
|
||||||
tinyxml2::XMLElement* update_element(tinyxml2::XMLNode* parent, const char* name)
|
tinyxml2::XMLElement* update_element(tinyxml2::XMLNode* parent, const char* name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,6 +11,8 @@ namespace tinyxml2
|
||||||
namespace xml
|
namespace xml
|
||||||
{
|
{
|
||||||
|
|
||||||
|
tinyxml2::XMLDocument& get_document(tinyxml2::XMLNode* parent);
|
||||||
|
|
||||||
tinyxml2::XMLElement* update_element(tinyxml2::XMLNode* parent, const char* name);
|
tinyxml2::XMLElement* update_element(tinyxml2::XMLNode* parent, const char* name);
|
||||||
// Same thing as above, but takes &parent instead of *parent
|
// Same thing as above, but takes &parent instead of *parent
|
||||||
tinyxml2::XMLElement* update_element(tinyxml2::XMLNode& parent, const char* name);
|
tinyxml2::XMLElement* update_element(tinyxml2::XMLNode& parent, const char* name);
|
||||||
|
|
|
@ -217,7 +217,12 @@ int main(int argc, char *argv[])
|
||||||
int width = 320;
|
int width = 320;
|
||||||
int height = 240;
|
int height = 240;
|
||||||
bool vsync = false;
|
bool vsync = false;
|
||||||
|
|
||||||
|
// Prioritize unlock.vvv first (2.2 and below),
|
||||||
|
// but settings have been migrated to settings.vvv (2.3 and up)
|
||||||
game.loadstats(&width, &height, &vsync);
|
game.loadstats(&width, &height, &vsync);
|
||||||
|
game.loadsettings(&width, &height, &vsync);
|
||||||
|
|
||||||
gameScreen.init(
|
gameScreen.init(
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
|
Loading…
Reference in a new issue