Introduced FileSystem and Out classes
[openstranded.git] / src / settings.cc
blob2ad4ca935a9901981652fa1e0275ca47f05c806b
1 /*
2 * See settings.hh for information about this file.
4 * Copyright (C) 2008 David Kolossa
6 * This file is part of OpenStranded
8 * OpenStranded is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * OpenStranded is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with OpenStranded. If not, see <http://www.gnu.org/licenses/>.
22 #include <cassert>
23 #include <iostream>
24 #include "tinyxml/tinyxml.h"
25 #include "settings.hh"
26 #include "s2string.hh"
27 #include "output.hh"
29 GlobalSettings::GlobalSettings(std::string configPath) :
30 configPath(configPath)
32 this->initializeStandardValues();
33 this->readConfigFile();
36 GlobalSettings::~GlobalSettings()
39 void
40 GlobalSettings::initializeStandardValues()
42 this->setResolutionX(1024);
43 this->setResolutionY(768);
44 this->setColorDepth(32);
45 this->setFullScreen(false);
47 #ifdef HAVE_IRRLICHT
48 this->setRenderer("Irrlicht");
49 #elif defined(HAVE_HORDE3D)
50 this->setRenderer("Horde3D");
51 #else
52 this->setRenderer("");
53 #endif
55 this->setViewRange(2);
57 this->setTerrainDetail(1);
58 this->setWaterDetail(3);
59 this->setSkyDetail(1);
60 this->setEffectDetail(1);
61 this->setGrassDetail(2);
63 this->setMusicVolume(1.0);
64 this->setSoundVolume(1.0);
66 this->setPp2d(true);
67 this->setLightFx(true);
68 this->setWindSwayFx(true);
69 this->setFog(true);
70 this->setMultiTex(true);
71 this->setMotionBlur(true);
72 this->setMotionBlurIntensity(1.0);
74 this->setPlayerName("Mr. Stranded");
75 this->setPort(39369);
78 bool
79 GlobalSettings::updateConfigFile()
81 TiXmlDocument xml;
83 // Create XML declaration
84 TiXmlDeclaration *declaration = new TiXmlDeclaration("1.0", "utf-8", "");
85 xml.LinkEndChild(declaration);
87 // Create <config> environment
88 TiXmlElement *root = new TiXmlElement("config");
89 xml.LinkEndChild(root);
91 // Traverse setting map
92 for (std::map<std::string, std::string>::iterator i = this->settings.begin(); i != this->settings.end(); i++)
94 std::string substrings[2];
95 int flag;
96 std::string key = std::string(i->first);
97 std::string value = std::string(i->second);
99 flag = s2str::explode(key, substrings, "_", 2);
100 if (inFlag(flag, EXPLODE_GREATER) || inFlag(flag, EXPLODE_LOWER) )
102 Out::debug << "Malformed setting name, skipped it." << Out::endl;
103 continue;
105 else if (inFlag(flag, EXPLODE_NO_TOKEN))
107 // TODO: Catch special case of categoryless setting
108 Out::debug << "Not Implemented: Categoryless setting, skipped it" << Out::endl;
109 continue;
111 else
113 // Check for existing category
114 TiXmlElement *categoryElement = NULL;
115 TiXmlNode *categoryNode = NULL;
116 while((categoryNode = root->IterateChildren(categoryNode)) != 0)
118 categoryElement = categoryNode->Clone()->ToElement();
119 if (std::string(categoryElement->Attribute("name")) == substrings[0])
120 break;
121 delete categoryElement;
122 categoryElement = NULL;
124 delete categoryElement;
125 categoryElement = NULL;
127 // No matching category found: Create it
128 if (categoryNode == NULL)
130 categoryElement = new TiXmlElement("category");
131 categoryElement->SetAttribute("name", substrings[0].c_str());
132 root->LinkEndChild(categoryElement);
134 else
136 categoryElement = categoryNode->ToElement();
140 // Create setting
141 TiXmlElement *element = new TiXmlElement("setting");
142 element->SetAttribute("name", substrings[1].c_str());
144 // Set the type of the setting
145 // FIXME: This is both BUGGY and UGLY
146 if (s2str::isInteger(value))
148 element->SetAttribute("type", "int");
150 else if (s2str::isDecimal(value))
152 element->SetAttribute("type", "float");
154 else if (s2str::isBool(value))
156 element->SetAttribute("type", "bool");
158 else
160 element->SetAttribute("type", "string");
163 categoryElement->LinkEndChild(element);
165 // Store value in setting
166 TiXmlText *text = new TiXmlText(value.c_str());
167 element->LinkEndChild(text);
172 if (!xml.SaveFile(this->configPath.c_str()))
174 Out::fatal << "Error when writing config file: " << xml.ErrorDesc() << Out::endl;
175 return false;
178 return true;
181 bool
182 GlobalSettings::readConfigFile()
184 TiXmlDocument xml(this->configPath.c_str());
185 // Check for regular file problems.
186 if (!xml.LoadFile())
188 Out::fatal << "Error when reading config file: " << xml.ErrorDesc() << Out::endl;
189 return false;
192 TiXmlHandle handle(&xml);
193 TiXmlElement *root;
195 root = handle.FirstChild("config").ToElement();
197 // Make sure that the top-level of our XML file is <config>
198 if (!root)
200 Out::fatal << "Invalid Markup: Top level element in config file is not <config> or missing" << Out::endl;
201 return false;
204 for (TiXmlElement *e = root->FirstChild("category")->ToElement(); e; e = e->NextSiblingElement())
206 for (TiXmlElement *f = e->FirstChild("setting")->ToElement(); f; f = f->NextSiblingElement())
208 std::string category = std::string(e->Attribute("name"));
209 std::string type = std::string(f->Attribute("type"));
210 std::string name = std::string(f->Attribute("name"));
211 std::string value = std::string(f->GetText());
212 if (type == "int")
214 if (s2str::isInteger(value))
216 this->setSetting(category + "_" + name, value);
218 else
220 Out::error << "Invalid int value for setting with name \"" << name << "\" in config file!" << Out::endl;
224 else if (type == "float")
226 if (s2str::isDecimal(value))
228 this->setSetting(category + "_" + name, value);
230 else
232 Out::error << "Invalid float value for setting with name \"" << name << "\" in config file!" << Out::endl;
235 else if (type == "bool")
237 if (s2str:: isBool(value))
239 this->setSetting(category + "_" + name, value);
241 else
243 Out::error << "Invalid bool value for setting with name \"" << name << "\" in config file!" << Out::endl;
246 else if (type == "string")
248 this->setSetting(category + "_" + name, value);
250 else
252 Out::error << "Invalid type of setting with name \"" << name << "\" in config file!" << Out::endl;
257 return true;
260 std::string
261 GlobalSettings::getSetting(const std::string &setting)
263 std::map<std::string, std::string>::iterator settingIterator;
264 if (settings.empty())
265 return "";
267 settingIterator = settings.find(setting);
268 if (settingIterator != settings.end())
269 return settingIterator->second;
270 else
271 return "";
274 std::string
275 GlobalSettings::getTemporary(const std::string &setting)
277 std::map<std::string, std::string>::iterator settingIterator;
278 if (tempSettings.empty())
279 return "";
281 settingIterator = tempSettings.find(setting);
282 if (settingIterator != tempSettings.end())
283 return settingIterator->second;
284 else
285 return "";
288 void
289 GlobalSettings::setSetting(const std::string &setting, const std::string &settingString)
291 settings[setting] = settingString;
294 void
295 GlobalSettings::setTemporary(const std::string &setting, const std::string &settingString)
297 tempSettings[setting] = settingString;