X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fsettings.cpp;h=0c34eb10c921b7236db6423204ec7a5fd3d4a1b0;hb=f4fedfed070ffd85c3446bc5d38d2fbd577640d6;hp=9485c7d74fa6414090978faa131dfb654e3cdf4a;hpb=175b7a28e5f82bd6da9f4c3e22ce6493c05f4f09;p=dragonfireclient.git diff --git a/src/settings.cpp b/src/settings.cpp index 9485c7d74..0c34eb10c 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -20,8 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "irrlichttypes_bloated.h" #include "exceptions.h" -#include "jthread/jmutexautolock.h" -#include "strfnd.h" +#include "threading/mutex_auto_lock.h" +#include "util/strfnd.h" #include #include #include @@ -29,14 +29,17 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "util/serialize.h" #include "filesys.h" +#include "noise.h" #include +#include +static Settings main_settings; +Settings *g_settings = &main_settings; +std::string g_settings_path; Settings::~Settings() { - std::map::const_iterator it; - for (it = m_settings.begin(); it != m_settings.end(); ++it) - delete it->second.group; + clear(); } @@ -53,8 +56,8 @@ Settings & Settings::operator = (const Settings &other) if (&other == this) return *this; - JMutexAutoLock lock(m_mutex); - JMutexAutoLock lock2(other.m_mutex); + MutexAutoLock lock(m_mutex); + MutexAutoLock lock2(other.m_mutex); clearNoLock(); updateNoLock(other); @@ -63,12 +66,38 @@ Settings & Settings::operator = (const Settings &other) } -std::string Settings::getMultiline(std::istream &is) +bool Settings::checkNameValid(const std::string &name) +{ + bool valid = name.find_first_of("=\"{}#") == std::string::npos; + if (valid) valid = trim(name) == name; + if (!valid) { + errorstream << "Invalid setting name \"" << name << "\"" + << std::endl; + return false; + } + return true; +} + + +bool Settings::checkValueValid(const std::string &value) +{ + if (value.substr(0, 3) == "\"\"\"" || + value.find("\n\"\"\"") != std::string::npos) { + errorstream << "Invalid character sequence '\"\"\"' found in" + " setting value!" << std::endl; + return false; + } + return true; +} + +std::string Settings::getMultiline(std::istream &is, size_t *num_lines) { + size_t lines = 1; std::string value; std::string line; while (is.good()) { + lines++; std::getline(is, line); if (line == "\"\"\"") break; @@ -80,13 +109,26 @@ std::string Settings::getMultiline(std::istream &is) if (len) value.erase(len - 1); + if (num_lines) + *num_lines = lines; + return value; } +bool Settings::readConfigFile(const char *filename) +{ + std::ifstream is(filename); + if (!is.good()) + return false; + + return parseConfigLines(is, ""); +} + + bool Settings::parseConfigLines(std::istream &is, const std::string &end) { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); std::string line, name, value; @@ -105,11 +147,12 @@ bool Settings::parseConfigLines(std::istream &is, const std::string &end) case SPE_END: return true; case SPE_GROUP: { - Settings *branch = new Settings; - if (!branch->parseConfigLines(is, "}")) + Settings *group = new Settings; + if (!group->parseConfigLines(is, "}")) { + delete group; return false; - - m_settings[name] = SettingsEntry(branch); + } + m_settings[name] = SettingsEntry(group); break; } case SPE_MULTILINE: @@ -122,53 +165,36 @@ bool Settings::parseConfigLines(std::istream &is, const std::string &end) } -bool Settings::readConfigFile(const char *filename) -{ - std::ifstream is(filename); - if (!is.good()) - return false; - - return parseConfigLines(is, ""); -} - - void Settings::writeLines(std::ostream &os, u32 tab_depth) const { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); - for (std::map::const_iterator - it = m_settings.begin(); - it != m_settings.end(); ++it) { - bool is_multiline = it->second.value.find('\n') != std::string::npos; - printValue(os, it->first, it->second, is_multiline, tab_depth); - } + for (const auto &setting_it : m_settings) + printEntry(os, setting_it.first, setting_it.second, tab_depth); } -void Settings::printValue(std::ostream &os, const std::string &name, - const SettingsEntry &entry, bool is_value_multiline, u32 tab_depth) +void Settings::printEntry(std::ostream &os, const std::string &name, + const SettingsEntry &entry, u32 tab_depth) { for (u32 i = 0; i != tab_depth; i++) os << "\t"; - os << name << " = "; - - if (is_value_multiline) - os << "\"\"\"\n" << entry.value << "\n\"\"\"\n"; - else - os << entry.value << "\n"; - - Settings *group = entry.group; - if (group) { - for (u32 i = 0; i != tab_depth; i++) - os << "\t"; + if (entry.is_group) { os << name << " = {\n"; - group->writeLines(os, tab_depth + 1); + + entry.group->writeLines(os, tab_depth + 1); for (u32 i = 0; i != tab_depth; i++) os << "\t"; - os << "}\n"; + } else { + os << name << " = "; + + if (entry.value.find('\n') != std::string::npos) + os << "\"\"\"\n" << entry.value << "\n\"\"\"\n"; + else + os << entry.value << "\n"; } } @@ -176,11 +202,11 @@ void Settings::printValue(std::ostream &os, const std::string &name, bool Settings::updateConfigObject(std::istream &is, std::ostream &os, const std::string &end, u32 tab_depth) { - std::map::const_iterator it; - std::set settings_in_config; + SettingEntries::const_iterator it; + std::set present_entries; + std::string line, name, value; bool was_modified = false; bool end_found = false; - std::string line, name, value; // Add any settings that exist in the config file with the current value // in the object if existing @@ -190,49 +216,38 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, switch (event) { case SPE_END: + os << line << (is.eof() ? "" : "\n"); end_found = true; break; - case SPE_KVPAIR: case SPE_MULTILINE: + value = getMultiline(is); + /* FALLTHROUGH */ + case SPE_KVPAIR: it = m_settings.find(name); - if (it != m_settings.end()) { + if (it != m_settings.end() && + (it->second.is_group || it->second.value != value)) { + printEntry(os, name, it->second, tab_depth); + was_modified = true; + } else { + os << line << "\n"; if (event == SPE_MULTILINE) - value = getMultiline(is); - - if (value != it->second.value) { - value = it->second.value; - was_modified = true; - } + os << value << "\n\"\"\"\n"; } - - settings_in_config.insert(name); - - printValue(os, name, SettingsEntry(value), - event == SPE_MULTILINE, tab_depth); - + present_entries.insert(name); break; - case SPE_GROUP: { - Settings *group = NULL; + case SPE_GROUP: it = m_settings.find(name); - if (it != m_settings.end()) - group = it->second.group; - - settings_in_config.insert(name); - - os << name << " = {\n"; - - if (group) { - was_modified |= group->updateConfigObject(is, os, "}", tab_depth + 1); + if (it != m_settings.end() && it->second.is_group) { + os << line << "\n"; + sanity_check(it->second.group != NULL); + was_modified |= it->second.group->updateConfigObject(is, os, + "}", tab_depth + 1); } else { - Settings dummy_settings; - dummy_settings.updateConfigObject(is, os, "}", tab_depth + 1); + printEntry(os, name, it->second, tab_depth); + was_modified = true; } - - for (u32 i = 0; i != tab_depth; i++) - os << "\t"; - os << "}\n"; + present_entries.insert(name); break; - } default: os << line << (is.eof() ? "" : "\n"); break; @@ -241,13 +256,11 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, // Add any settings in the object that don't exist in the config file yet for (it = m_settings.begin(); it != m_settings.end(); ++it) { - if (settings_in_config.find(it->first) != settings_in_config.end()) + if (present_entries.find(it->first) != present_entries.end()) continue; + printEntry(os, it->first, it->second, tab_depth); was_modified = true; - - bool is_multiline = it->second.value.find('\n') != std::string::npos; - printValue(os, it->first, it->second, is_multiline, tab_depth); } return was_modified; @@ -256,12 +269,15 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, bool Settings::updateConfigFile(const char *filename) { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); std::ifstream is(filename); std::ostringstream os(std::ios_base::binary); - if (!updateConfigObject(is, os, "")) + bool was_modified = updateConfigObject(is, os, ""); + is.close(); + + if (!was_modified) return true; if (!fs::safeWriteToFile(filename, os.str())) { @@ -306,7 +322,7 @@ bool Settings::parseCommandLine(int argc, char *argv[], ValueType type = n->second.type; - std::string value = ""; + std::string value; if (type == VALUETYPE_FLAG) { value = "true"; @@ -334,9 +350,9 @@ bool Settings::parseCommandLine(int argc, char *argv[], const SettingsEntry &Settings::getEntry(const std::string &name) const { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); - std::map::const_iterator n; + SettingEntries::const_iterator n; if ((n = m_settings.find(name)) == m_settings.end()) { if ((n = m_defaults.find(name)) == m_defaults.end()) throw SettingNotFoundException("Setting [" + name + "] not found."); @@ -345,15 +361,42 @@ const SettingsEntry &Settings::getEntry(const std::string &name) const } +const SettingsEntry &Settings::getEntryDefault(const std::string &name) const +{ + MutexAutoLock lock(m_mutex); + + SettingEntries::const_iterator n; + if ((n = m_defaults.find(name)) == m_defaults.end()) { + throw SettingNotFoundException("Setting [" + name + "] not found."); + } + return n->second; +} + + Settings *Settings::getGroup(const std::string &name) const { - return getEntry(name).group; + const SettingsEntry &entry = getEntry(name); + if (!entry.is_group) + throw SettingNotFoundException("Setting [" + name + "] is not a group."); + return entry.group; } -std::string Settings::get(const std::string &name) const +const std::string &Settings::get(const std::string &name) const { - return getEntry(name).value; + const SettingsEntry &entry = getEntry(name); + if (entry.is_group) + throw SettingNotFoundException("Setting [" + name + "] is a group."); + return entry.value; +} + + +const std::string &Settings::getDefault(const std::string &name) const +{ + const SettingsEntry &entry = getEntryDefault(name); + if (entry.is_group) + throw SettingNotFoundException("Setting [" + name + "] is a group."); + return entry.value; } @@ -375,6 +418,11 @@ s16 Settings::getS16(const std::string &name) const } +u32 Settings::getU32(const std::string &name) const +{ + return (u32) stoi(get(name)); +} + s32 Settings::getS32(const std::string &name) const { return stoi(get(name)); @@ -450,9 +498,68 @@ bool Settings::getStruct(const std::string &name, const std::string &format, } +bool Settings::getNoiseParams(const std::string &name, NoiseParams &np) const +{ + return getNoiseParamsFromGroup(name, np) || getNoiseParamsFromValue(name, np); +} + + +bool Settings::getNoiseParamsFromValue(const std::string &name, + NoiseParams &np) const +{ + std::string value; + + if (!getNoEx(name, value)) + return false; + + Strfnd f(value); + + np.offset = stof(f.next(",")); + np.scale = stof(f.next(",")); + f.next("("); + np.spread.X = stof(f.next(",")); + np.spread.Y = stof(f.next(",")); + np.spread.Z = stof(f.next(")")); + f.next(","); + np.seed = stoi(f.next(",")); + np.octaves = stoi(f.next(",")); + np.persist = stof(f.next(",")); + + std::string optional_params = f.next(""); + if (!optional_params.empty()) + np.lacunarity = stof(optional_params); + + return true; +} + + +bool Settings::getNoiseParamsFromGroup(const std::string &name, + NoiseParams &np) const +{ + Settings *group = NULL; + + if (!getGroupNoEx(name, group)) + return false; + + group->getFloatNoEx("offset", np.offset); + group->getFloatNoEx("scale", np.scale); + group->getV3FNoEx("spread", np.spread); + group->getS32NoEx("seed", np.seed); + group->getU16NoEx("octaves", np.octaves); + group->getFloatNoEx("persistence", np.persist); + group->getFloatNoEx("lacunarity", np.lacunarity); + + np.flags = 0; + if (!group->getFlagStrNoEx("flags", np.flags, flagdesc_noiseparams)) + np.flags = NOISE_FLAG_DEFAULTS; + + return true; +} + + bool Settings::exists(const std::string &name) const { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); return (m_settings.find(name) != m_settings.end() || m_defaults.find(name) != m_defaults.end()); @@ -462,10 +569,8 @@ bool Settings::exists(const std::string &name) const std::vector Settings::getNames() const { std::vector names; - for (std::map::const_iterator - i = m_settings.begin(); - i != m_settings.end(); ++i) { - names.push_back(i->first); + for (const auto &settings_it : m_settings) { + names.push_back(settings_it.first); } return names; } @@ -487,6 +592,17 @@ bool Settings::getEntryNoEx(const std::string &name, SettingsEntry &val) const } +bool Settings::getEntryDefaultNoEx(const std::string &name, SettingsEntry &val) const +{ + try { + val = getEntryDefault(name); + return true; + } catch (SettingNotFoundException &e) { + return false; + } +} + + bool Settings::getGroupNoEx(const std::string &name, Settings *&val) const { try { @@ -509,6 +625,17 @@ bool Settings::getNoEx(const std::string &name, std::string &val) const } +bool Settings::getDefaultNoEx(const std::string &name, std::string &val) const +{ + try { + val = getDefault(name); + return true; + } catch (SettingNotFoundException &e) { + return false; + } +} + + bool Settings::getFlag(const std::string &name) const { try { @@ -621,93 +748,119 @@ bool Settings::getFlagStrNoEx(const std::string &name, u32 &val, * Setters * ***********/ - -void Settings::set(const std::string &name, const std::string &value) +bool Settings::setEntry(const std::string &name, const void *data, + bool set_group, bool set_default) { - JMutexAutoLock lock(m_mutex); + Settings *old_group = NULL; + + if (!checkNameValid(name)) + return false; + if (!set_group && !checkValueValid(*(const std::string *)data)) + return false; + + { + MutexAutoLock lock(m_mutex); + + SettingsEntry &entry = set_default ? m_defaults[name] : m_settings[name]; + old_group = entry.group; - m_settings[name].value = value; + entry.value = set_group ? "" : *(const std::string *)data; + entry.group = set_group ? *(Settings **)data : NULL; + entry.is_group = set_group; + } + + delete old_group; + + return true; } -void Settings::setGroup(const std::string &name, Settings *group) +bool Settings::set(const std::string &name, const std::string &value) { - JMutexAutoLock lock(m_mutex); + if (!setEntry(name, &value, false, false)) + return false; - delete m_settings[name].group; - m_settings[name].group = group; + doCallbacks(name); + return true; } -void Settings::setDefault(const std::string &name, const std::string &value) +bool Settings::setDefault(const std::string &name, const std::string &value) { - JMutexAutoLock lock(m_mutex); + return setEntry(name, &value, false, true); +} + - m_defaults[name].value = value; +bool Settings::setGroup(const std::string &name, Settings *group) +{ + return setEntry(name, &group, true, false); } -void Settings::setGroupDefault(const std::string &name, Settings *group) +bool Settings::setGroupDefault(const std::string &name, Settings *group) { - JMutexAutoLock lock(m_mutex); + return setEntry(name, &group, true, true); +} + - delete m_defaults[name].group; - m_defaults[name].group = group; +bool Settings::setBool(const std::string &name, bool value) +{ + return set(name, value ? "true" : "false"); } -void Settings::setBool(const std::string &name, bool value) +bool Settings::setS16(const std::string &name, s16 value) { - set(name, value ? "true" : "false"); + return set(name, itos(value)); } -void Settings::setS16(const std::string &name, s16 value) +bool Settings::setU16(const std::string &name, u16 value) { - set(name, itos(value)); + return set(name, itos(value)); } -void Settings::setS32(const std::string &name, s32 value) +bool Settings::setS32(const std::string &name, s32 value) { - set(name, itos(value)); + return set(name, itos(value)); } -void Settings::setU64(const std::string &name, u64 value) +bool Settings::setU64(const std::string &name, u64 value) { std::ostringstream os; os << value; - set(name, os.str()); + return set(name, os.str()); } -void Settings::setFloat(const std::string &name, float value) +bool Settings::setFloat(const std::string &name, float value) { - set(name, ftos(value)); + return set(name, ftos(value)); } -void Settings::setV2F(const std::string &name, v2f value) +bool Settings::setV2F(const std::string &name, v2f value) { std::ostringstream os; os << "(" << value.X << "," << value.Y << ")"; - set(name, os.str()); + return set(name, os.str()); } -void Settings::setV3F(const std::string &name, v3f value) +bool Settings::setV3F(const std::string &name, v3f value) { std::ostringstream os; os << "(" << value.X << "," << value.Y << "," << value.Z << ")"; - set(name, os.str()); + return set(name, os.str()); } -void Settings::setFlagStr(const std::string &name, u32 flags, +bool Settings::setFlagStr(const std::string &name, u32 flags, const FlagDesc *flagdesc, u32 flagmask) { - set(name, writeFlagString(flags, flagdesc, flagmask)); + return set(name, writeFlagString(flags, flagdesc, flagmask)); } @@ -718,36 +871,64 @@ bool Settings::setStruct(const std::string &name, const std::string &format, if (!serializeStructToString(&structstr, format, value)) return false; - set(name, structstr); - return true; + return set(name, structstr); +} + + +bool Settings::setNoiseParams(const std::string &name, + const NoiseParams &np, bool set_default) +{ + Settings *group = new Settings; + + group->setFloat("offset", np.offset); + group->setFloat("scale", np.scale); + group->setV3F("spread", np.spread); + group->setS32("seed", np.seed); + group->setU16("octaves", np.octaves); + group->setFloat("persistence", np.persist); + group->setFloat("lacunarity", np.lacunarity); + group->setFlagStr("flags", np.flags, flagdesc_noiseparams, np.flags); + + return setEntry(name, &group, true, set_default); } bool Settings::remove(const std::string &name) { - JMutexAutoLock lock(m_mutex); - return m_settings.erase(name); + MutexAutoLock lock(m_mutex); + + SettingEntries::iterator it = m_settings.find(name); + if (it != m_settings.end()) { + delete it->second.group; + m_settings.erase(it); + return true; + } + + return false; } void Settings::clear() { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); clearNoLock(); } +void Settings::clearDefaults() +{ + MutexAutoLock lock(m_mutex); + clearDefaultsNoLock(); +} void Settings::updateValue(const Settings &other, const std::string &name) { if (&other == this) return; - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); try { - std::string val = other.get(name); - - m_settings[name] = val; + m_settings[name] = other.get(name); } catch (SettingNotFoundException &e) { } } @@ -758,8 +939,8 @@ void Settings::update(const Settings &other) if (&other == this) return; - JMutexAutoLock lock(m_mutex); - JMutexAutoLock lock2(other.m_mutex); + MutexAutoLock lock(m_mutex); + MutexAutoLock lock2(other.m_mutex); updateNoLock(other); } @@ -802,32 +983,56 @@ void Settings::updateNoLock(const Settings &other) void Settings::clearNoLock() { + + for (SettingEntries::const_iterator it = m_settings.begin(); + it != m_settings.end(); ++it) + delete it->second.group; m_settings.clear(); + + clearDefaultsNoLock(); +} + +void Settings::clearDefaultsNoLock() +{ + for (SettingEntries::const_iterator it = m_defaults.begin(); + it != m_defaults.end(); ++it) + delete it->second.group; m_defaults.clear(); } -void Settings::registerChangedCallback(std::string name, - setting_changed_callback cbf) +void Settings::registerChangedCallback(const std::string &name, + SettingsChangedCallback cbf, void *userdata) { - m_callbacks[name].push_back(cbf); + MutexAutoLock lock(m_callback_mutex); + m_callbacks[name].emplace_back(cbf, userdata); } - -void Settings::doCallbacks(const std::string name) +void Settings::deregisterChangedCallback(const std::string &name, + SettingsChangedCallback cbf, void *userdata) { - std::vector tempvector; - { - JMutexAutoLock lock(m_mutex); - if (m_callbacks.find(name) != m_callbacks.end()) - { - tempvector = m_callbacks[name]; - } + MutexAutoLock lock(m_callback_mutex); + SettingsCallbackMap::iterator it_cbks = m_callbacks.find(name); + + if (it_cbks != m_callbacks.end()) { + SettingsCallbackList &cbks = it_cbks->second; + + SettingsCallbackList::iterator position = + std::find(cbks.begin(), cbks.end(), std::make_pair(cbf, userdata)); + + if (position != cbks.end()) + cbks.erase(position); } +} - for (std::vector::iterator iter = tempvector.begin(); - iter != tempvector.end(); iter ++) - { - (*iter)(name); +void Settings::doCallbacks(const std::string &name) const +{ + MutexAutoLock lock(m_callback_mutex); + + SettingsCallbackMap::const_iterator it_cbks = m_callbacks.find(name); + if (it_cbks != m_callbacks.end()) { + SettingsCallbackList::const_iterator it; + for (it = it_cbks->second.begin(); it != it_cbks->second.end(); ++it) + (it->first)(name, it->second); } }