Rewritten config to use JSON instead of INI
parent
fde2b901bd
commit
1034c2e45c
|
@ -597,17 +597,16 @@ bool CApplication::Create()
|
|||
// for list of resolutions in options menu, not calling it results in empty list
|
||||
auto modes = GetVideoResolutionList();
|
||||
|
||||
if ( GetConfigFile().GetStringProperty("Setup", "Resolution", sValue) && !m_resolutionOverride )
|
||||
std::vector<int> values;
|
||||
|
||||
if ( GetConfigFile().GetArrayProperty("Setup", "Resolution", values) && !m_resolutionOverride )
|
||||
{
|
||||
std::istringstream resolution(sValue);
|
||||
std::string ws, hs;
|
||||
std::getline(resolution, ws, 'x');
|
||||
std::getline(resolution, hs, 'x');
|
||||
int w = 800, h = 600;
|
||||
if (!ws.empty() && !hs.empty())
|
||||
|
||||
if (values.size() >= 2)
|
||||
{
|
||||
w = atoi(ws.c_str());
|
||||
h = atoi(hs.c_str());
|
||||
w = values[0];
|
||||
h = values[1];
|
||||
}
|
||||
|
||||
// Why not just set m_deviceConfig.size to w,h? Because this way if the resolution is no longer supported (e.g. changing monitor) defaults will be used instead
|
||||
|
|
|
@ -338,17 +338,19 @@ InputSlot CInput::FindBinding(unsigned int key)
|
|||
|
||||
void CInput::SaveKeyBindings()
|
||||
{
|
||||
std::stringstream key;
|
||||
std::vector<int> key;
|
||||
GetConfigFile().SetStringProperty("Keybindings", "_Version", "SDL2");
|
||||
|
||||
for (int i = 0; i < INPUT_SLOT_MAX; i++)
|
||||
{
|
||||
InputBinding b = GetInputBinding(static_cast<InputSlot>(i));
|
||||
|
||||
key.clear();
|
||||
key.str("");
|
||||
key << b.primary << " " << b.secondary;
|
||||
|
||||
GetConfigFile().SetStringProperty("Keybindings", m_keyTable[static_cast<InputSlot>(i)], key.str());
|
||||
if (b.primary != KEY_INVALID) key.push_back(b.primary);
|
||||
if (b.secondary != KEY_INVALID) key.push_back(b.secondary);
|
||||
|
||||
GetConfigFile().SetArrayProperty("Keybindings", m_keyTable[static_cast<InputSlot>(i)], key);
|
||||
}
|
||||
|
||||
for (int i = 0; i < JOY_AXIS_SLOT_MAX; i++)
|
||||
|
@ -363,21 +365,22 @@ void CInput::SaveKeyBindings()
|
|||
|
||||
void CInput::LoadKeyBindings()
|
||||
{
|
||||
std::stringstream skey;
|
||||
std::string keys;
|
||||
if (GetConfigFile().GetStringProperty("Keybindings", "_Version", keys) && keys == "SDL2") // Keybindings from SDL1.2 are incompatible with SDL2 !!
|
||||
std::string version;
|
||||
|
||||
// Keybindings from SDL1.2 are incompatible with SDL2 !!
|
||||
if (GetConfigFile().GetStringProperty("Keybindings", "_Version", version) && version == "SDL2")
|
||||
{
|
||||
std::vector<int> keys;
|
||||
|
||||
for (int i = 0; i < INPUT_SLOT_MAX; i++)
|
||||
{
|
||||
InputBinding b;
|
||||
|
||||
if (!GetConfigFile().GetStringProperty("Keybindings", m_keyTable[static_cast<InputSlot>(i)], keys))
|
||||
if (!GetConfigFile().GetArrayProperty("Keybindings", m_keyTable[static_cast<InputSlot>(i)], keys))
|
||||
continue;
|
||||
skey.clear();
|
||||
skey.str(keys);
|
||||
|
||||
skey >> b.primary;
|
||||
skey >> b.secondary;
|
||||
|
||||
if (keys.size() >= 1) b.primary = keys[0];
|
||||
if (keys.size() >= 2) b.secondary = keys[1];
|
||||
|
||||
SetInputBinding(static_cast<InputSlot>(i), b);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,10 @@
|
|||
|
||||
#include "common/system/system.h"
|
||||
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <cstring>
|
||||
|
||||
namespace bp = boost::property_tree;
|
||||
#include <fstream>
|
||||
|
||||
CConfigFile::CConfigFile()
|
||||
: m_needsSave(false)
|
||||
|
@ -65,20 +62,20 @@ bool CConfigFile::Init()
|
|||
bool good;
|
||||
if (m_useCurrentDirectory)
|
||||
{
|
||||
auto inputStream = std::make_unique<std::ifstream>("./colobot.ini");
|
||||
auto inputStream = std::make_unique<std::ifstream>("./colobot.json");
|
||||
good = inputStream->good();
|
||||
stream = std::move(inputStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto inputStream = std::make_unique<CInputStream>("colobot.ini");
|
||||
auto inputStream = std::make_unique<CInputStream>("colobot.json");
|
||||
good = inputStream->is_open();
|
||||
stream = std::move(inputStream);
|
||||
}
|
||||
|
||||
if (good)
|
||||
{
|
||||
bp::ini_parser::read_ini(*stream, m_propertyTree);
|
||||
m_properties = nlohmann::json::parse(*stream);
|
||||
m_loaded = true;
|
||||
}
|
||||
else
|
||||
|
@ -105,20 +102,20 @@ bool CConfigFile::Save()
|
|||
bool good;
|
||||
if (m_useCurrentDirectory)
|
||||
{
|
||||
auto outputStream = std::make_unique<std::ofstream>("./colobot.ini");
|
||||
auto outputStream = std::make_unique<std::ofstream>("./colobot.json");
|
||||
good = outputStream->good();
|
||||
stream = std::move(outputStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto outputStream = std::make_unique<COutputStream>("colobot.ini");
|
||||
auto outputStream = std::make_unique<COutputStream>("colobot.json");
|
||||
good = outputStream->is_open();
|
||||
stream = std::move(outputStream);
|
||||
}
|
||||
|
||||
if (good)
|
||||
{
|
||||
bp::ini_parser::write_ini(*stream, m_propertyTree);
|
||||
*stream << m_properties.dump(4);
|
||||
m_needsSave = false;
|
||||
}
|
||||
else
|
||||
|
@ -138,119 +135,68 @@ bool CConfigFile::Save()
|
|||
|
||||
bool CConfigFile::SetStringProperty(std::string section, std::string key, std::string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_propertyTree.put(section + "." + key, value);
|
||||
m_needsSave = true;
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
GetLogger()->Error("Error on editing config file: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
m_properties[section][key] = value;
|
||||
m_needsSave = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigFile::GetStringProperty(std::string section, std::string key, std::string &value)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string readValue = m_propertyTree.get<std::string>(section + "." + key);
|
||||
value = std::move(readValue);
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
GetLogger()->Log(m_loaded ? LOG_INFO : LOG_TRACE, "Error on parsing config file: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
auto element = m_properties[section][key];
|
||||
|
||||
if (!element.is_string()) return false;
|
||||
|
||||
value = element.get<std::string>();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigFile::SetIntProperty(std::string section, std::string key, int value)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_propertyTree.put(section + "." + key, value);
|
||||
m_needsSave = true;
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
GetLogger()->Error("Error on editing config file: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
m_properties[section][key] = value;
|
||||
m_needsSave = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigFile::GetIntProperty(std::string section, std::string key, int &value)
|
||||
{
|
||||
try
|
||||
{
|
||||
int readValue = m_propertyTree.get<int>(section + "." + key);
|
||||
value = readValue;
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
GetLogger()->Log(m_loaded ? LOG_INFO : LOG_TRACE, "Error on parsing config file: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
auto element = m_properties[section][key];
|
||||
|
||||
if (!element.is_number()) return false;
|
||||
|
||||
value = element.get<int>();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigFile::SetBoolProperty(std::string section, std::string key, bool value)
|
||||
{
|
||||
return SetIntProperty(section, key, value ? 1 : 0);
|
||||
m_properties[section][key] = value;
|
||||
m_needsSave = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigFile::GetBoolProperty(std::string section, std::string key, bool& value)
|
||||
{
|
||||
int intValue = 0;
|
||||
bool result = GetIntProperty(section, key, intValue);
|
||||
if (result)
|
||||
{
|
||||
if (intValue == 0)
|
||||
{
|
||||
value = false;
|
||||
}
|
||||
else if (intValue == 1)
|
||||
{
|
||||
value = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
GetLogger()->Log(m_loaded ? LOG_INFO : LOG_TRACE, "Error on parsing bool property %s.%s (expected 0 or 1, not %d)\n",
|
||||
section.c_str(), key.c_str(), intValue);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
auto element = m_properties[section][key];
|
||||
|
||||
if (!element.is_boolean()) return false;
|
||||
|
||||
value = element.get<bool>();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigFile::SetFloatProperty(std::string section, std::string key, float value)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_propertyTree.put(section + "." + key, value);
|
||||
m_needsSave = true;
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
GetLogger()->Error("Error on editing config file: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
m_properties[section][key] = value;
|
||||
m_needsSave = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConfigFile::GetFloatProperty(std::string section, std::string key, float &value)
|
||||
{
|
||||
try
|
||||
{
|
||||
float readValue = m_propertyTree.get<float>(section + "." + key);
|
||||
value = readValue;
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
GetLogger()->Log(m_loaded ? LOG_INFO : LOG_TRACE, "Error on parsing config file: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
auto element = m_properties[section][key];
|
||||
|
||||
if (!element.is_number()) return false;
|
||||
|
||||
value = element.get<float>();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
#include "common/logger.h"
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
@ -115,8 +115,14 @@ public:
|
|||
{
|
||||
try
|
||||
{
|
||||
std::string convertedValue = ArrayToString(array);
|
||||
m_propertyTree.put(section + "." + key, convertedValue);
|
||||
auto property = nlohmann::json::array();
|
||||
|
||||
for (const auto& value : array)
|
||||
{
|
||||
property.push_back(value);
|
||||
}
|
||||
|
||||
m_properties[section][key] = property;
|
||||
m_needsSave = true;
|
||||
}
|
||||
catch (std::exception & e)
|
||||
|
@ -137,9 +143,12 @@ public:
|
|||
{
|
||||
try
|
||||
{
|
||||
std::string readValue = m_propertyTree.get<std::string>(section + "." + key);
|
||||
std::vector<T> convertedValue = StringToArray<T>(readValue);
|
||||
array = std::move(convertedValue);
|
||||
array.clear();
|
||||
|
||||
for (auto& value : m_properties[section][key])
|
||||
{
|
||||
array.push_back(value.get<T>());
|
||||
}
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
|
@ -189,7 +198,7 @@ private:
|
|||
}
|
||||
|
||||
private:
|
||||
boost::property_tree::ptree m_propertyTree;
|
||||
nlohmann::json m_properties;
|
||||
bool m_needsSave;
|
||||
bool m_useCurrentDirectory;
|
||||
bool m_loaded;
|
||||
|
|
|
@ -58,11 +58,8 @@ CSettings::CSettings()
|
|||
|
||||
void CSettings::SaveResolutionSettings(const Gfx::DeviceConfig& config)
|
||||
{
|
||||
// NOTE: These settings are loaded in CApplication
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << config.size.x << "x" << config.size.y;
|
||||
GetConfigFile().SetStringProperty("Setup", "Resolution", ss.str());
|
||||
std::vector<int> values = { config.size.x, config.size.y };
|
||||
GetConfigFile().SetArrayProperty("Setup", "Resolution", values);
|
||||
GetConfigFile().SetBoolProperty("Setup", "Fullscreen", config.fullScreen);
|
||||
GetConfigFile().Save();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
set(TEST_FILES
|
||||
common/colobot.ini
|
||||
common/colobot.json
|
||||
)
|
||||
|
||||
file(COPY ${TEST_FILES} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
[test_float]
|
||||
float_value=1.5
|
||||
|
||||
[test_string]
|
||||
string_value=Hello world
|
||||
|
||||
[test_int]
|
||||
int_value=42
|
||||
|
||||
[test_array]
|
||||
string_array=AAA,Hello world,Gold Edition
|
||||
int_array=2,3,1
|
||||
bool_array=1,0,1
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"test_float": {
|
||||
"float_value": 1.5
|
||||
},
|
||||
"test_string": {
|
||||
"string_value": "Hello world"
|
||||
},
|
||||
"test_int": {
|
||||
"int_value": 42
|
||||
},
|
||||
"test_array": {
|
||||
"string_array": [
|
||||
"AAA",
|
||||
"Hello world",
|
||||
"Gold Edition"
|
||||
],
|
||||
"int_array": [
|
||||
2, 3, 1
|
||||
],
|
||||
"bool_array": [
|
||||
true, false, true
|
||||
]
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ TEST_F(CConfigFileTest, ReadTest)
|
|||
{
|
||||
m_configFile.SetUseCurrentDirectory(true);
|
||||
|
||||
ASSERT_TRUE(m_configFile.Init()); // load colobot.ini file
|
||||
ASSERT_TRUE(m_configFile.Init()); // load colobot.json file
|
||||
|
||||
std::string result;
|
||||
ASSERT_TRUE(m_configFile.GetStringProperty("test_string", "string_value", result));
|
||||
|
@ -57,7 +57,7 @@ TEST_F(CConfigFileTest, ReadArrayTest)
|
|||
{
|
||||
m_configFile.SetUseCurrentDirectory(true);
|
||||
|
||||
ASSERT_TRUE(m_configFile.Init()); // load colobot.ini file
|
||||
ASSERT_TRUE(m_configFile.Init()); // load colobot.json file
|
||||
|
||||
std::vector<std::string> expected_string_values = { "AAA", "Hello world", "Gold Edition" };
|
||||
std::vector<std::string> string_values;
|
||||
|
|
Loading…
Reference in New Issue