瀏覽代碼

Settings: savefrequency is now configurable in launcher

* Client command-line can modify arbitrary settings now
* Only launcher auto-saves to settings.json
Henning Koehler 7 年之前
父節點
當前提交
2ede3783dd

+ 31 - 7
client/CMT.cpp

@@ -61,6 +61,7 @@
 #include <boost/asio.hpp>
 
 #include "mainmenu/CPrologEpilogVideo.h"
+#include <vstd/StringUtils.h>
 
 #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<si64>();
+		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<std::string>();
+		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<int>();
 	}
 	// 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<si64>() : 0;
-	session["saveprefix"].String() = vm.count("saveprefix") ? vm["saveprefix"].as<std::string>() : "";
-	session["savefrequency"].Integer() = vm.count("savefrequency") ? vm["savefrequency"].as<si64>() : 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

+ 2 - 1
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<int>(settings["session"]["savefrequency"].Integer()) == 0)
+		else if(frequency > 0 && cb->getDate() % frequency == 0)
 		{
 			LOCPLINT->cb->save("Saves/" + prefix + "Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
 			autosaveCount %= 5;

+ 5 - 1
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
 				}
 			}
 		},

+ 6 - 0
include/vstd/StringUtils.h

@@ -0,0 +1,6 @@
+namespace vstd
+{
+
+	DLL_LINKAGE std::vector<std::string> split(std::string s, std::string separators);
+
+}

+ 1 - 1
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) :

+ 7 - 0
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;
+}

+ 2 - 0
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;
 };

+ 24 - 0
launcher/settingsView/csettingsview_moc.ui

@@ -603,6 +603,30 @@
      </property>
     </widget>
    </item>
+   <item row="11" column="6">
+    <widget class="QLabel" name="labelAutoSave">
+     <property name="text">
+      <string>Autosave</string>
+     </property>
+    </widget>
+   </item>
+   <item row="11" column="7">
+    <widget class="QComboBox" name="comboBoxAutoSave">
+     <property name="currentIndex">
+      <number>1</number>
+     </property>
+     <item>
+      <property name="text">
+       <string>Off</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>On</string>
+      </property>
+     </item>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>

+ 18 - 11
lib/CConfigHandler.cpp

@@ -42,7 +42,7 @@ SettingsStorage::NodeAccessor<Accessor>::operator Accessor() const
 }
 
 template<typename Accessor>
-SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>::operator () (std::vector<std::string> _path)
+SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>::operator () (std::vector<std::string> _path) const
 {
 	std::vector<std::string> newPath = path;
 	newPath.insert( newPath.end(), _path.begin(), _path.end());
@@ -51,11 +51,12 @@ SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>:
 
 SettingsStorage::SettingsStorage():
 	write(NodeAccessor<Settings>(*this, std::vector<std::string>() )),
-	listen(NodeAccessor<SettingsListener>(*this, std::vector<std::string>() ))
+	listen(NodeAccessor<SettingsListener>(*this, std::vector<std::string>() )),
+	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<std::string> &changedPath)
@@ -74,14 +76,14 @@ void SettingsStorage::invalidateNode(const std::vector<std::string> &changedPath
 	for(SettingsListener * listener : listeners)
 		listener->nodeInvalidated(changedPath);
 
-	JsonNode savedConf = config;
-	JsonNode schema(ResourceID("config/schemas/settings.json"));
-
-	savedConf.Struct().erase("session");
-	JsonUtils::minimize(savedConf, "vcmi:settings");
+	if(autoSaveConfig)
+	{
+		JsonNode savedConf = config;
+		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<std::string> path)
@@ -98,11 +100,16 @@ Settings SettingsStorage::get(std::vector<std::string> 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<std::string> &_path):
 	parent(_parent),
 	path(_path)

+ 6 - 3
lib/CConfigHandler.h

@@ -26,12 +26,14 @@ class DLL_LINKAGE SettingsStorage
 
 		NodeAccessor(SettingsStorage & _parent, std::vector<std::string> _path);
 		NodeAccessor<Accessor> operator [] (std::string nextNode) const;
-		NodeAccessor<Accessor> operator () (std::vector<std::string> _path);
+		NodeAccessor<Accessor> operator () (std::vector<std::string> _path) const;
 		operator Accessor() const;
 	};
 
 	std::set<SettingsListener*> listeners;
 	JsonNode config;
+	bool autoSaveConfig;
+
 	JsonNode & getNode(std::vector<std::string> 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<Settings> write;
@@ -50,7 +52,8 @@ public:
 	const NodeAccessor<SettingsListener> 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;

+ 3 - 0
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
 

+ 14 - 0
lib/vstd/StringUtils.cpp

@@ -0,0 +1,14 @@
+#include "StdInc.h"
+#include <vstd/StringUtils.h>
+
+namespace vstd
+{
+
+	DLL_LINKAGE std::vector<std::string> split(std::string s, std::string separators)
+	{
+		std::vector<std::string> result;
+		boost::split(result, s, boost::is_any_of(separators));
+		return result;
+	}
+
+}