diff --git a/client/CMT.cpp b/client/CMT.cpp index 658764c24..2c4328bb4 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -61,6 +61,7 @@ #include #include "mainmenu/CPrologEpilogVideo.h" +#include #ifdef VCMI_WINDOWS #include "SDL_syswm.h" @@ -259,7 +260,29 @@ int main(int argc, char * argv[]) preinitDLL(::console); settings.init(); Settings session = settings.write["session"]; - session["onlyai"].Bool() = vm.count("onlyAI"); + auto setSettingBool = [](std::string key, std::string arg) { + Settings s = settings.write(vstd::split(key, "/")); + if(::vm.count(arg)) + s->Bool() = true; + else if(s->isNull()) + s->Bool() = false; + }; + auto setSettingInteger = [](std::string key, std::string arg, si64 defaultValue) { + Settings s = settings.write(vstd::split(key, "/")); + if(::vm.count(arg)) + s->Integer() = ::vm[arg].as(); + else if(s->isNull()) + s->Integer() = defaultValue; + }; + auto setSettingString = [](std::string key, std::string arg, std::string defaultValue) { + Settings s = settings.write(vstd::split(key, "/")); + if(::vm.count(arg)) + s->String() = ::vm[arg].as(); + else if(s->isNull()) + s->String() = defaultValue; + }; + + setSettingBool("session/onlyai", "onlyAI"); if(vm.count("headless")) { session["headless"].Bool() = true; @@ -277,19 +300,20 @@ int main(int argc, char * argv[]) session["spectate-battle-speed"].Float() = vm["spectate-battle-speed"].as(); } // Server settings - session["donotstartserver"].Bool() = vm.count("donotstartserver"); + setSettingBool("session/donotstartserver", "donotstartserver"); // Shared memory options - session["disable-shm"].Bool() = vm.count("disable-shm"); - session["enable-shm-uuid"].Bool() = vm.count("enable-shm-uuid"); + setSettingBool("session/disable-shm", "disable-shm"); + setSettingBool("session/enable-shm-uuid", "enable-shm-uuid"); // Init special testing settings - session["serverport"].Integer() = vm.count("serverport") ? vm["serverport"].as() : 0; - session["saveprefix"].String() = vm.count("saveprefix") ? vm["saveprefix"].as() : ""; - session["savefrequency"].Integer() = vm.count("savefrequency") ? vm["savefrequency"].as() : 1; + setSettingInteger("session/serverport", "serverport", 0); + setSettingString("session/saveprefix", "saveprefix", ""); + setSettingInteger("general/saveFrequency", "savefrequency", 1); // Initialize logging based on settings logConfig.configure(); + logGlobal->debug("settings = %s", settings.toJsonNode().toJson()); // Some basic data validation to produce better error messages in cases of incorrect install auto testFile = [](std::string filename, std::string message) -> bool diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 52a827280..fcd635aa6 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -165,6 +165,7 @@ void CPlayerInterface::yourTurn() adventureInt->selection = nullptr; std::string prefix = settings["session"]["saveprefix"].String(); + int frequency = settings["general"]["saveFrequency"].Integer(); if (firstCall) { if(CSH->howManyPlayerInterfaces() == 1) @@ -180,7 +181,7 @@ void CPlayerInterface::yourTurn() } firstCall = 0; } - else if (cb->getDate() % static_cast(settings["session"]["savefrequency"].Integer()) == 0) + else if(frequency > 0 && cb->getDate() % frequency == 0) { LOCPLINT->cb->save("Saves/" + prefix + "Autosave_" + boost::lexical_cast(autosaveCount++ + 1)); autosaveCount %= 5; diff --git a/config/schemas/settings.json b/config/schemas/settings.json index 30ed8333f..3de4c6895 100644 --- a/config/schemas/settings.json +++ b/config/schemas/settings.json @@ -17,7 +17,7 @@ "type" : "object", "default": {}, "additionalProperties" : false, - "required" : [ "playerName", "showfps", "music", "sound", "encoding", "swipe", "saveRandomMaps" ], + "required" : [ "playerName", "showfps", "music", "sound", "encoding", "swipe", "saveRandomMaps", "saveFrequency" ], "properties" : { "playerName" : { "type":"string", @@ -58,6 +58,10 @@ "lastCampaign" : { "type":"string", "default" : "" + }, + "saveFrequency" : { + "type" : "number", + "default" : 1 } } }, diff --git a/include/vstd/StringUtils.h b/include/vstd/StringUtils.h new file mode 100644 index 000000000..a9b2a3578 --- /dev/null +++ b/include/vstd/StringUtils.h @@ -0,0 +1,6 @@ +namespace vstd +{ + + DLL_LINKAGE std::vector split(std::string s, std::string separators); + +} diff --git a/launcher/mainwindow_moc.cpp b/launcher/mainwindow_moc.cpp index bac1225a7..476b64b47 100644 --- a/launcher/mainwindow_moc.cpp +++ b/launcher/mainwindow_moc.cpp @@ -36,7 +36,7 @@ void MainWindow::load() QDir::addSearchPath("icons", pathToQString(string / "launcher" / "icons")); QDir::addSearchPath("icons", pathToQString(VCMIDirs::get().userDataPath() / "launcher" / "icons")); - settings.init(); + settings.init(true); } MainWindow::MainWindow(QWidget * parent) : diff --git a/launcher/settingsView/csettingsview_moc.cpp b/launcher/settingsView/csettingsview_moc.cpp index a5be7626b..d83b0d4bb 100644 --- a/launcher/settingsView/csettingsview_moc.cpp +++ b/launcher/settingsView/csettingsview_moc.cpp @@ -94,6 +94,7 @@ void CSettingsView::loadSettings() size_t encodingIndex = boost::range::find(knownEncodingsList, encoding) - knownEncodingsList; if (encodingIndex < ui->comboBoxEncoding->count()) ui->comboBoxEncoding->setCurrentIndex(encodingIndex); + ui->comboBoxAutoSave->setCurrentIndex(settings["general"]["saveFrequency"].Integer() > 0 ? 1 : 0); } CSettingsView::CSettingsView(QWidget *parent) : @@ -223,3 +224,9 @@ void CSettingsView::on_changeGameDataDir_clicked() { } + +void CSettingsView::on_comboBoxAutoSave_currentIndexChanged(int index) +{ + Settings node = settings.write["general"]["saveFrequency"]; + node->Integer() = index; +} diff --git a/launcher/settingsView/csettingsview_moc.h b/launcher/settingsView/csettingsview_moc.h index fdebb2b98..eafbaa8cf 100644 --- a/launcher/settingsView/csettingsview_moc.h +++ b/launcher/settingsView/csettingsview_moc.h @@ -59,6 +59,8 @@ private slots: void on_comboBoxDisplayIndex_currentIndexChanged(int index); + void on_comboBoxAutoSave_currentIndexChanged(int index); + private: Ui::CSettingsView *ui; }; diff --git a/launcher/settingsView/csettingsview_moc.ui b/launcher/settingsView/csettingsview_moc.ui index 195618cad..7b31eef08 100644 --- a/launcher/settingsView/csettingsview_moc.ui +++ b/launcher/settingsView/csettingsview_moc.ui @@ -603,6 +603,30 @@ + + + + Autosave + + + + + + + 1 + + + + Off + + + + + On + + + + diff --git a/lib/CConfigHandler.cpp b/lib/CConfigHandler.cpp index d6d95ee3a..f63d0b119 100644 --- a/lib/CConfigHandler.cpp +++ b/lib/CConfigHandler.cpp @@ -42,7 +42,7 @@ SettingsStorage::NodeAccessor::operator Accessor() const } template -SettingsStorage::NodeAccessor SettingsStorage::NodeAccessor::operator () (std::vector _path) +SettingsStorage::NodeAccessor SettingsStorage::NodeAccessor::operator () (std::vector _path) const { std::vector newPath = path; newPath.insert( newPath.end(), _path.begin(), _path.end()); @@ -51,11 +51,12 @@ SettingsStorage::NodeAccessor SettingsStorage::NodeAccessor: SettingsStorage::SettingsStorage(): write(NodeAccessor(*this, std::vector() )), - listen(NodeAccessor(*this, std::vector() )) + listen(NodeAccessor(*this, std::vector() )), + autoSaveConfig(false) { } -void SettingsStorage::init() +void SettingsStorage::init(bool autoSave) { std::string confName = "config/settings.json"; @@ -67,6 +68,7 @@ void SettingsStorage::init() JsonUtils::maximize(config, "vcmi:settings"); JsonUtils::validate(config, "vcmi:settings", "settings"); + autoSaveConfig = autoSave; } void SettingsStorage::invalidateNode(const std::vector &changedPath) @@ -74,14 +76,14 @@ void SettingsStorage::invalidateNode(const std::vector &changedPath for(SettingsListener * listener : listeners) listener->nodeInvalidated(changedPath); - JsonNode savedConf = config; - JsonNode schema(ResourceID("config/schemas/settings.json")); + if(autoSaveConfig) + { + JsonNode savedConf = config; + JsonUtils::minimize(savedConf, "vcmi:settings"); - savedConf.Struct().erase("session"); - JsonUtils::minimize(savedConf, "vcmi:settings"); - - FileStream file(*CResourceHandler::get()->getResourceName(ResourceID("config/settings.json")), std::ofstream::out | std::ofstream::trunc); - file << savedConf.toJson(); + FileStream file(*CResourceHandler::get()->getResourceName(ResourceID("config/settings.json")), std::ofstream::out | std::ofstream::trunc); + file << savedConf.toJson(); + } } JsonNode & SettingsStorage::getNode(std::vector path) @@ -98,11 +100,16 @@ Settings SettingsStorage::get(std::vector path) return Settings(*this, path); } -const JsonNode& SettingsStorage::operator [](std::string value) +const JsonNode & SettingsStorage::operator [](std::string value) const { return config[value]; } +const JsonNode & SettingsStorage::toJsonNode() const +{ + return config; +} + SettingsListener::SettingsListener(SettingsStorage &_parent, const std::vector &_path): parent(_parent), path(_path) diff --git a/lib/CConfigHandler.h b/lib/CConfigHandler.h index 512398648..392e8594d 100644 --- a/lib/CConfigHandler.h +++ b/lib/CConfigHandler.h @@ -26,12 +26,14 @@ class DLL_LINKAGE SettingsStorage NodeAccessor(SettingsStorage & _parent, std::vector _path); NodeAccessor operator [] (std::string nextNode) const; - NodeAccessor operator () (std::vector _path); + NodeAccessor operator () (std::vector _path) const; operator Accessor() const; }; std::set listeners; JsonNode config; + bool autoSaveConfig; + JsonNode & getNode(std::vector path); // Calls all required listeners @@ -41,7 +43,7 @@ class DLL_LINKAGE SettingsStorage public: // Initialize config structure SettingsStorage(); - void init(); + void init(bool autoSave=false); // Get write access to config node at path const NodeAccessor write; @@ -50,7 +52,8 @@ public: const NodeAccessor listen; //Read access, see JsonNode::operator[] - const JsonNode& operator [](std::string value); + const JsonNode & operator [](std::string value) const; + const JsonNode & toJsonNode() const; friend class SettingsListener; friend class Settings; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9568550e9..b5de47afd 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -124,6 +124,8 @@ set(lib_SRCS spells/effects/RemoveObstacle.cpp spells/effects/Sacrifice.cpp + vstd/StringUtils.cpp + CAndroidVMHelper.cpp CArtHandler.cpp CBonusTypeHandler.cpp @@ -169,6 +171,7 @@ set(lib_HEADERS ${CMAKE_HOME_DIRECTORY}/include/vstd/CLoggerBase.h ${CMAKE_HOME_DIRECTORY}/include/vstd/ContainerUtils.h ${CMAKE_HOME_DIRECTORY}/include/vstd/RNG.h + ${CMAKE_HOME_DIRECTORY}/include/vstd/StringUtils.h StdInc.h ../Global.h diff --git a/lib/vstd/StringUtils.cpp b/lib/vstd/StringUtils.cpp new file mode 100644 index 000000000..97c0faf59 --- /dev/null +++ b/lib/vstd/StringUtils.cpp @@ -0,0 +1,14 @@ +#include "StdInc.h" +#include + +namespace vstd +{ + + DLL_LINKAGE std::vector split(std::string s, std::string separators) + { + std::vector result; + boost::split(result, s, boost::is_any_of(separators)); + return result; + } + +}