diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index 6ffe66b7..b4f2f791 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -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 ) { #if !defined(MAKEANDPLAY) @@ -4471,7 +4479,10 @@ void Game::loadstats(int *width, int *height, bool *vsync) tinyxml2::XMLDocument 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"); } @@ -4493,7 +4504,9 @@ void Game::loadstats(int *width, int *height, bool *vsync) 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()); const char* pText = pElem->GetText() ; @@ -4526,6 +4539,35 @@ void Game::loadstats(int *width, int *height, bool *vsync) 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") { 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") { 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; 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, "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, "stretch", stretchMode); @@ -4834,10 +4884,6 @@ void Game::savestats() 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); @@ -4927,8 +4973,58 @@ void Game::savestats() } 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() diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h index d73e6367..c41cbf47 100644 --- a/desktop_version/src/Game.h +++ b/desktop_version/src/Game.h @@ -6,7 +6,11 @@ #include // Forward decl without including all of -namespace tinyxml2 { class XMLDocument; } +namespace tinyxml2 +{ + class XMLDocument; + class XMLElement; +} struct MenuOption { @@ -126,10 +130,20 @@ public: void loadstats(int *width, int *height, bool *vsync); - void savestats(); + void savestats(const bool stats_only = false); 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(); bool savetele(); diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp index 402fa5cc..8e54ef4e 100644 --- a/desktop_version/src/Input.cpp +++ b/desktop_version/src/Input.cpp @@ -1280,6 +1280,7 @@ void menuactionpress() game.deletequick(); game.deletetele(); game.deletestats(); + game.deletesettings(); game.flashlight = 5; game.screenshake = 15; game.createmenu(Menu::mainmenu); diff --git a/desktop_version/src/XMLUtils.cpp b/desktop_version/src/XMLUtils.cpp index bd0f4d7b..f0010563 100644 --- a/desktop_version/src/XMLUtils.cpp +++ b/desktop_version/src/XMLUtils.cpp @@ -4,17 +4,16 @@ namespace xml { -// Helper functions for these utils (not exported) - -static inline tinyxml2::XMLDocument& get_document(tinyxml2::XMLNode* parent) +// Just get the document, because TinyXML-2 is annoying. +// Useful outside of this file. +// 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()); } - -// EXPORTED FUNCTIONS - - // Create a new element if it doesn't exist. Returns the element. tinyxml2::XMLElement* update_element(tinyxml2::XMLNode* parent, const char* name) { diff --git a/desktop_version/src/XMLUtils.h b/desktop_version/src/XMLUtils.h index 40efa634..b56f2361 100644 --- a/desktop_version/src/XMLUtils.h +++ b/desktop_version/src/XMLUtils.h @@ -11,6 +11,8 @@ namespace tinyxml2 namespace xml { +tinyxml2::XMLDocument& get_document(tinyxml2::XMLNode* parent); + tinyxml2::XMLElement* update_element(tinyxml2::XMLNode* parent, const char* name); // Same thing as above, but takes &parent instead of *parent tinyxml2::XMLElement* update_element(tinyxml2::XMLNode& parent, const char* name); diff --git a/desktop_version/src/main.cpp b/desktop_version/src/main.cpp index 9938bdf6..704eac61 100644 --- a/desktop_version/src/main.cpp +++ b/desktop_version/src/main.cpp @@ -217,7 +217,12 @@ int main(int argc, char *argv[]) int width = 320; int height = 240; 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.loadsettings(&width, &height, &vsync); + gameScreen.init( width, height,