diff --git a/ChaosMod/Components/CrossingChallenge.cpp b/ChaosMod/Components/CrossingChallenge.cpp index 048978832..06631ce7f 100644 --- a/ChaosMod/Components/CrossingChallenge.cpp +++ b/ChaosMod/Components/CrossingChallenge.cpp @@ -24,7 +24,7 @@ void CrossingChallenge::SetStartParams() _SET_WEATHER_TYPE_TRANSITION(m_StartWeatherType1, m_StartWeatherType2, m_StartWeatherPercent); SET_CLOCK_TIME(m_ClockHours, m_ClockMinutes, m_ClockSeconds); REMOVE_ALL_PED_WEAPONS(player, false); - for (WeaponInfo weapon : m_StartWeapons) + for (const auto &weapon : m_StartWeapons) GIVE_WEAPON_TO_PED(player, weapon.hash, weapon.ammo, false, false); CLEAR_PLAYER_WANTED_LEVEL(PLAYER_ID()); @@ -196,28 +196,28 @@ static std::string GetWeaponOptionName(Hash weapon) void CrossingChallenge::SaveConfig() { - m_ConfigFile.SetValue("StartEnabled", m_StartEnabled); - m_ConfigFile.SetValue("StartLocationX", m_StartLocation.x); - m_ConfigFile.SetValue("StartLocationY", m_StartLocation.y); - m_ConfigFile.SetValue("StartLocationZ", m_StartLocation.z); - m_ConfigFile.SetValue("StartVehicle", m_StartVehicleHash); - m_ConfigFile.SetValue("StartHeading", m_StartHeading); - m_ConfigFile.SetValue("StartCameraHeading", m_StartCameraHeading); - m_ConfigFile.SetValue("StartWeather1", m_StartWeatherType1); - m_ConfigFile.SetValue("StartWeather2", m_StartWeatherType2); - m_ConfigFile.SetValue("StartWeatherPercent", m_StartWeatherPercent); - m_ConfigFile.SetValue("StartHours", m_ClockHours); - m_ConfigFile.SetValue("StartMinutes", m_ClockMinutes); - m_ConfigFile.SetValue("StartSeconds", m_ClockSeconds); - - for (WeaponInfo weapon : m_StartWeapons) - m_ConfigFile.SetValue(GetWeaponOptionName(weapon.hash), weapon.ammo); - - m_ConfigFile.SetValue("EndEnabled", m_EndEnabled); - m_ConfigFile.SetValue("EndLocationX", m_EndLocation.x); - m_ConfigFile.SetValue("EndLocationY", m_EndLocation.y); - m_ConfigFile.SetValue("EndLocationZ", m_EndLocation.z); - m_ConfigFile.SetValue("EndRadius", m_EndRadius); + m_ConfigFile.SetValue("StartEnabled", m_StartEnabled); + m_ConfigFile.SetValue("StartLocationX", m_StartLocation.x); + m_ConfigFile.SetValue("StartLocationY", m_StartLocation.y); + m_ConfigFile.SetValue("StartLocationZ", m_StartLocation.z); + m_ConfigFile.SetValue("StartVehicle", m_StartVehicleHash); + m_ConfigFile.SetValue("StartHeading", m_StartHeading); + m_ConfigFile.SetValue("StartCameraHeading", m_StartCameraHeading); + m_ConfigFile.SetValue("StartWeather1", m_StartWeatherType1); + m_ConfigFile.SetValue("StartWeather2", m_StartWeatherType2); + m_ConfigFile.SetValue("StartWeatherPercent", m_StartWeatherPercent); + m_ConfigFile.SetValue("StartHours", m_ClockHours); + m_ConfigFile.SetValue("StartMinutes", m_ClockMinutes); + m_ConfigFile.SetValue("StartSeconds", m_ClockSeconds); + + for (const auto &weapon : m_StartWeapons) + m_ConfigFile.SetValue(GetWeaponOptionName(weapon.hash), weapon.ammo); + + m_ConfigFile.SetValue("EndEnabled", m_EndEnabled); + m_ConfigFile.SetValue("EndLocationX", m_EndLocation.x); + m_ConfigFile.SetValue("EndLocationY", m_EndLocation.y); + m_ConfigFile.SetValue("EndLocationZ", m_EndLocation.z); + m_ConfigFile.SetValue("EndRadius", m_EndRadius); m_ConfigFile.WriteFile(); } @@ -259,42 +259,42 @@ void CrossingChallenge::CaptureEnd() CrossingChallenge::CrossingChallenge() { - m_Enabled = g_OptionsManager.GetConfigValue({ "EnableCrossingChallenge" }, false); + m_Enabled = g_OptionsManager.GetConfigValue({ "EnableCrossingChallenge" }, false); if (!m_Enabled) return; - m_StartEnabled = m_ConfigFile.ReadValue("StartEnabled", false); + m_StartEnabled = m_ConfigFile.ReadValue({ "StartEnabled" }, false); if (m_StartEnabled) { - m_StartLocation = Vector3(m_ConfigFile.ReadValue("StartLocationX", 0.f), - m_ConfigFile.ReadValue("StartLocationY", 0.f), - m_ConfigFile.ReadValue("StartLocationZ", 0.f)); - m_StartVehicleHash = m_ConfigFile.ReadValue("StartVehicle", 0); - m_StartHeading = m_ConfigFile.ReadValue("StartHeading", 0.f); - m_StartCameraHeading = m_ConfigFile.ReadValue("StartCameraHeading", 0.f); - m_StartWeatherType1 = m_ConfigFile.ReadValue("StartWeather1", 0); - m_StartWeatherType2 = m_ConfigFile.ReadValue("StartWeather2", 0); - m_StartWeatherPercent = m_ConfigFile.ReadValue("StartWeatherPercent", 0.f); - m_ClockHours = m_ConfigFile.ReadValue("StartHours", 0); - m_ClockMinutes = m_ConfigFile.ReadValue("StartMinutes", 0); - m_ClockSeconds = m_ConfigFile.ReadValue("StartSeconds", 0); + m_StartLocation = Vector3(m_ConfigFile.ReadValue({ "StartLocationX" }, 0.f), + m_ConfigFile.ReadValue({ "StartLocationY" }, 0.f), + m_ConfigFile.ReadValue({ "StartLocationZ" }, 0.f)); + m_StartVehicleHash = m_ConfigFile.ReadValue({ "StartVehicle" }, 0); + m_StartHeading = m_ConfigFile.ReadValue({ "StartHeading" }, 0.f); + m_StartCameraHeading = m_ConfigFile.ReadValue({ "StartCameraHeading" }, 0.f); + m_StartWeatherType1 = m_ConfigFile.ReadValue({ "StartWeather1" }, 0); + m_StartWeatherType2 = m_ConfigFile.ReadValue({ "StartWeather2" }, 0); + m_StartWeatherPercent = m_ConfigFile.ReadValue({ "StartWeatherPercent" }, 0.f); + m_ClockHours = m_ConfigFile.ReadValue({ "StartHours" }, 0); + m_ClockMinutes = m_ConfigFile.ReadValue({ "StartMinutes" }, 0); + m_ClockSeconds = m_ConfigFile.ReadValue({ "StartSeconds" }, 0); for (Hash hash : Memory::GetAllWeapons()) { - int ammo = m_ConfigFile.ReadValue(GetWeaponOptionName(hash), -1); + int ammo = m_ConfigFile.ReadValue({ GetWeaponOptionName(hash) }, -1); if (ammo >= 0) m_StartWeapons.emplace_back(WeaponInfo { hash, ammo }); } } - m_EndEnabled = m_ConfigFile.ReadValue("EndEnabled", false); + m_EndEnabled = m_ConfigFile.ReadValue({ "EndEnabled" }, false); if (m_EndEnabled) { - m_EndLocation = Vector3(m_ConfigFile.ReadValue("EndLocationX", 0.f), - m_ConfigFile.ReadValue("EndLocationY", 0.f), - m_ConfigFile.ReadValue("EndLocationZ", 0.f)); - m_EndRadius = m_ConfigFile.ReadValue("EndRadius", 0.f); + m_EndLocation = + Vector3(m_ConfigFile.ReadValue({ "EndLocationX" }, 0.f), m_ConfigFile.ReadValue({ "EndLocationY" }, 0.f), + m_ConfigFile.ReadValue({ "EndLocationZ" }, 0.f)); + m_EndRadius = m_ConfigFile.ReadValue({ "EndRadius" }, 0.f); } if (ComponentExists()) diff --git a/ChaosMod/Components/CrossingChallenge.h b/ChaosMod/Components/CrossingChallenge.h index cdc3f0063..d0304392e 100644 --- a/ChaosMod/Components/CrossingChallenge.h +++ b/ChaosMod/Components/CrossingChallenge.h @@ -4,9 +4,9 @@ #include "Component.h" #include "Components/EffectDispatcher.h" +#include "Util/Events.h" #include "Util/OptionsFile.h" #include "Util/Text.h" -#include "Util/Events.h" #define SPLASH_TEXT_DUR_SECS 10 @@ -19,7 +19,7 @@ class CrossingChallenge : public Component int ammo; }; - OptionsFile m_ConfigFile { "chaosmod/configs/crossing.ini", { "chaosmod/crossing.ini" } }; + OptionsFile m_ConfigFile { { "chaosmod/configs/cached/crossingchallenge.json", "chaosmod/crossing.ini" } }; bool m_Enabled = false; diff --git a/ChaosMod/Components/DebugMenu.cpp b/ChaosMod/Components/DebugMenu.cpp index 00f7a9741..62c7656b2 100644 --- a/ChaosMod/Components/DebugMenu.cpp +++ b/ChaosMod/Components/DebugMenu.cpp @@ -4,8 +4,8 @@ #include "Components/EffectDispatcher.h" #include "Effects/EnabledEffects.h" -#include "Util/OptionsManager.h" #include "Util/HelpText.h" +#include "Util/OptionsManager.h" #define MAX_VIS_ITEMS 15 diff --git a/ChaosMod/Components/EffectDispatchTimer.cpp b/ChaosMod/Components/EffectDispatchTimer.cpp index 21c92a96a..ad0ed69b1 100644 --- a/ChaosMod/Components/EffectDispatchTimer.cpp +++ b/ChaosMod/Components/EffectDispatchTimer.cpp @@ -13,8 +13,11 @@ EffectDispatchTimer::EffectDispatchTimer(const std::array &timerColor) m_DrawTimerBar = !g_OptionsManager.GetConfigValue({ "DisableTimerBarDraw" }, OPTION_DEFAULT_NO_EFFECT_BAR); m_EffectSpawnTime = g_OptionsManager.GetConfigValue({ "NewEffectSpawnTime" }, OPTION_DEFAULT_EFFECT_SPAWN_TIME); - m_DistanceChaosState.EnableDistanceBasedEffectDispatch = g_OptionsManager.GetConfigValue( - { "EnableDistanceBasedEffectDispatch" }, OPTION_DEFAULT_DISTANCE_BASED_DISPATCH_ENABLED); + m_DistanceChaosState.EnableDistanceBasedEffectDispatch = + g_OptionsManager.GetConfigValue({ "EffectDispatchMode", " EnableDistanceBasedEffectDispatch " }, + OPTION_DEFAULT_DISTANCE_BASED_DISPATCH_ENABLED) + ? true + : false; m_DistanceChaosState.DistanceToActivateEffect = g_OptionsManager.GetConfigValue({ "DistanceToActivateEffect" }, OPTION_DEFAULT_EFFECT_SPAWN_DISTANCE); m_DistanceChaosState.DistanceType = static_cast( diff --git a/ChaosMod/Components/Voting.cpp b/ChaosMod/Components/Voting.cpp index 08c6ee609..087e5322a 100644 --- a/ChaosMod/Components/Voting.cpp +++ b/ChaosMod/Components/Voting.cpp @@ -20,7 +20,7 @@ Voting::Voting(const std::array &textColor) : Component(), m_TextColor( { m_EnableVoting = g_OptionsManager.GetVotingValue({ "EnableVoting", "EnableTwitchVoting" }, OPTION_DEFAULT_TWITCH_VOTING_ENABLED); - m_VoteablePrefix = g_OptionsManager.GetVotingValue({ "VoteablePrefix" }, ""); + m_VoteablePrefix = g_OptionsManager.GetVotingValue({ "VoteablePrefix" }); } bool Voting::Init() diff --git a/ChaosMod/Effects/EffectConfig.h b/ChaosMod/Effects/EffectConfig.h index d088bdc93..34a48e52d 100644 --- a/ChaosMod/Effects/EffectConfig.h +++ b/ChaosMod/Effects/EffectConfig.h @@ -29,10 +29,13 @@ namespace EffectConfig return -1; } - inline void ReadConfig(const char *configPath, auto &out, std::vector compatConfigPaths = {}) + inline void ReadConfig(std::vector lookupPaths, auto &out) { - OptionsFile effectsFile(configPath, compatConfigPaths); + DEBUG_LOG("Parsing effect config"); + OptionsFile effectsFile(lookupPaths); + + bool isJson = effectsFile.GetFoundFileName().ends_with(".json"); for (auto &[effectId, effectMetadata] : g_RegisteredEffectsMetadata) { struct ConfigValues @@ -59,35 +62,47 @@ namespace EffectConfig // HACK: Store EffectCustomName seperately std::string valueEffectName; - auto value = effectsFile.ReadValueString({ std::string(effectId) }); - if (!value.empty()) + if (isJson) { - size_t splitIndex = GetNextDelimiterOffset(value); - for (int j = 0;; j++) - { - // Effect-Name override - if (j == 6) - { - auto split = value.substr(0, splitIndex); - // Trim surrounding quotations - if (split.length() >= 2 && split[0] == '\"' && split[split.length() - 1] == '\"') - split = split.substr(1, split.size() - 2); - // Names can't be "0" to support older configs - if (!split.empty() && split != "0") - valueEffectName = split; - } + auto jsonArray = effectsFile.ReadValue({ std::string(effectId) }); + for (size_t i = 0; i < jsonArray.size(); i++) + if (i == 6) + valueEffectName = jsonArray[i]; else + configValues.ValuesRaw[i] = jsonArray[i]; + } + else + { + auto value = effectsFile.ReadValue({ std::string(effectId) }); + if (!value.empty()) + { + size_t splitIndex = GetNextDelimiterOffset(value); + for (int i = 0;; i++) { - const auto &split = value.substr(0, splitIndex); - - Util::TryParse(split, configValues.ValuesRaw[j]); + // Effect-Name override + if (i == 6) + { + auto split = value.substr(0, splitIndex); + // Trim surrounding quotations + if (split.length() >= 2 && split[0] == '\"' && split[split.length() - 1] == '\"') + split = split.substr(1, split.size() - 2); + // Names can't be "0" to support older configs + if (!split.empty() && split != "0") + valueEffectName = split; + } + else + { + const auto &split = value.substr(0, splitIndex); + + Util::TryParse(split, configValues.ValuesRaw[i]); + } + + if (splitIndex == value.npos) + break; + + value = value.substr(splitIndex + 1); + splitIndex = GetNextDelimiterOffset(value); } - - if (splitIndex == value.npos) - break; - - value = value.substr(splitIndex + 1); - splitIndex = GetNextDelimiterOffset(value); } } @@ -148,5 +163,7 @@ namespace EffectConfig out.emplace(EffectIdentifier(std::string(effectId)), effectData); } + + DEBUG_LOG("Parsed effect config"); } } diff --git a/ChaosMod/Main.cpp b/ChaosMod/Main.cpp index fb7a66c4f..b3a9185aa 100644 --- a/ChaosMod/Main.cpp +++ b/ChaosMod/Main.cpp @@ -56,7 +56,8 @@ static void ParseEffectsFile() { g_EnabledEffects.clear(); - EffectConfig::ReadConfig("chaosmod/configs/effects.ini", g_EnabledEffects, { "chaosmod/effects.ini" }); + EffectConfig::ReadConfig( + { "chaosmod/configs/effects.json", "chaosmod/configs/effects.ini", "chaosmod/effects.ini" }, g_EnabledEffects); } static void Init() @@ -139,7 +140,9 @@ static void Init() const auto &effectTimerColor = ParseConfigColorString( g_OptionsManager.GetConfigValue({ "EffectTimedTimerColor" }, OPTION_DEFAULT_TIMED_COLOR)); - g_Random.SetSeed(g_OptionsManager.GetConfigValue({ "Seed" }, 0)); + auto seed = g_OptionsManager.GetConfigValue({ "Seed" }); + if (!seed.empty()) + g_Random.SetSeed(std::hash {}(seed)); g_RandomNoDeterm.SetSeed(GetTickCount64()); std::set blacklistedComponentNames; diff --git a/ChaosMod/Util/OptionsFile.h b/ChaosMod/Util/OptionsFile.h index f6c2a0e7c..e97eefdff 100644 --- a/ChaosMod/Util/OptionsFile.h +++ b/ChaosMod/Util/OptionsFile.h @@ -4,6 +4,8 @@ #include "Util/Text.h" #include "Util/TryParse.h" +#include + #include #include #include @@ -12,14 +14,12 @@ class OptionsFile { private: - const char *m_FileName; - const char *m_FoundFileName; - std::vector m_CompatFileNames; - std::unordered_map m_Options; + std::vector m_LookupFilePaths; + std::string_view m_FoundFilePath; + std::unordered_map m_Options; public: - OptionsFile(const char *fileName, std::vector compatFileNames = {}) - : m_FileName(fileName), m_FoundFileName(fileName), m_CompatFileNames(compatFileNames) + OptionsFile(std::vector lookupFilePaths) : m_LookupFilePaths(lookupFilePaths) { Reset(); } @@ -28,102 +28,146 @@ class OptionsFile { m_Options.clear(); - auto readData = [&](const char *fileName) + bool dataRead = false; + for (auto filePath : m_LookupFilePaths) { - std::ifstream file(fileName); + std::ifstream file(filePath.data()); if (file.fail()) - return false; - - std::string line; - line.resize(128); - while (file.getline(line.data(), 128)) - { - const auto &key = StringTrim(line.substr(0, line.find("="))); + continue; - // Ignore line if there's no "=" - if (line == key) - continue; + DEBUG_LOG("Parsing config file \"" << filePath << "\""); - const auto &value = StringTrim( - line.substr(line.find("=") + 1).substr(0, line.find('\n'))); // Also do trimming of newline - - m_Options.emplace(key, value); + if (filePath.ends_with(".json")) + { + std::string fileContent; + file >> fileContent; + try + { + auto json = nlohmann::json::parse(fileContent); + for (const auto &[key, value] : json.items()) + m_Options.emplace(key, value); + } + catch (nlohmann::json::exception &) + { + break; + } } + else if (filePath.ends_with(".ini")) + { + std::string line; + line.resize(128); + while (file.getline(line.data(), 128)) + { + const auto &key = StringTrim(line.substr(0, line.find("="))); - return true; - }; + // Ignore line if there's no "=" + if (line == key) + continue; - if (!readData(m_FileName)) - { - bool dataRead = false; - for (auto compatFileName : m_CompatFileNames) - if ((dataRead = readData(compatFileName))) - { - m_FoundFileName = compatFileName; - break; + const auto &value = StringTrim( + line.substr(line.find("=") + 1).substr(0, line.find('\n'))); // Also do trimming of newline + + m_Options.emplace(key, value); } + } + else + { + DEBUG_LOG("Config file \"" << filePath << "\" has invalid file extension, continuing search"); + continue; + } - if (!dataRead) - LOG("Config file " << m_FileName << " not found!"); + DEBUG_LOG("Parsed config file \"" << filePath << "\""); + m_FoundFilePath = filePath; + dataRead = true; + break; } + + if (!dataRead) + LOG("Could not load config file " << m_LookupFilePaths[0] << "!"); } inline void WriteFile() { - std::ofstream file(m_FoundFileName, std::ofstream::out | std::ofstream::trunc); + const auto &filePath = m_LookupFilePaths[0]; + + auto dir = filePath.substr(0, filePath.find_last_of('/')); + if (dir != filePath) + std::filesystem::create_directory(dir); + std::ofstream file(filePath.data(), std::ofstream::out | std::ofstream::trunc); if (!file) { - LOG("Couldn't write config file " << m_FoundFileName); + LOG("Couldn't write config file " << filePath << "!"); return; } - for (auto &[key, value] : m_Options) - file << key << "=" << value << std::endl; - } - template inline T ReadValue(const std::string &key, T defaultValue) const - { - return ReadValue(std::vector { key }, defaultValue); - } + nlohmann::json json; + for (const auto &[key, value] : m_Options) + json[key] = value; + file << json.dump(4); - template inline T ReadValue(const std::vector &keys, T defaultValue) const - { - for (const auto &key : keys) - { - const auto &result = m_Options.find(key); + LOG("Wrote config file " << filePath); - if (result != m_Options.end() && !result->second.empty()) + for (const auto &filePath : m_LookupFilePaths) + if (filePath != m_FoundFilePath) { - T parsedResult; - if (Util::TryParse(result->second, parsedResult)) - return parsedResult; + std::error_code error; + std::filesystem::remove(filePath, error); } - } - - return defaultValue; } - inline std::string ReadValueString(const std::vector &keys, const std::string &defaultValue = {}) const + template inline T ReadValue(const std::vector &lookupKeys, T defaultValue = {}) const { - for (const auto &key : keys) + for (const auto &key : lookupKeys) { const auto &result = m_Options.find(key); - if (result != m_Options.end()) - return result->second; + { + DEBUG_LOG("Reading value of key \"" << key << "\" from config file \"" << m_FoundFilePath << "\""); + + try + { + const auto &value = result->second; + if constexpr (std::is_base_of() || std::is_base_of()) + { + if (!value.is_string()) + return defaultValue; + + return value; + } + else if (value.is_string()) + { + T parsedResult; + std::string strValue = value; + if (!Util::TryParse(strValue.c_str(), parsedResult)) + return defaultValue; + + return parsedResult; + } + + return value; + } + catch (nlohmann::json::exception &) + { + // We aren't interested in potential other matches + LOG("WARNING: Config file \"" << m_FoundFilePath << "\" has invalid value for key \"" << key + << "\", reverting to default value!"); + break; + } + } } return defaultValue; } - inline void SetValueString(const std::string &key, const std::string &value) + template inline void SetValue(const std::string &key, T value) { - if (m_Options.contains(key)) - m_Options[key] = value; - else - m_Options.emplace(key, value); + DEBUG_LOG("Writing value \"" << value << "\" for key \"" << key << "\" to config file \"" + << m_LookupFilePaths[0] << "\""); + m_Options[key] = value; } - template inline void SetValue(const std::string &key, T value) + + inline std::string_view GetFoundFileName() const { - SetValueString(key, std::to_string(value)); + return m_FoundFilePath; } }; \ No newline at end of file diff --git a/ChaosMod/Util/OptionsManager.h b/ChaosMod/Util/OptionsManager.h index ef1e0f5b2..6431eb3d2 100644 --- a/ChaosMod/Util/OptionsManager.h +++ b/ChaosMod/Util/OptionsManager.h @@ -9,9 +9,10 @@ class OptionsManager { private: - OptionsFile m_ConfigFile { "chaosmod/configs/config.ini", { "chaosmod/config.ini" } }; - OptionsFile m_TwitchFile { "chaosmod/configs/voting.ini", - { "chaosmod/configs/twitch.ini", "chaosmod/twitch.ini" } }; + OptionsFile m_ConfigFile { { "chaosmod/configs/config.json", "chaosmod/configs/config.ini", + "chaosmod/config.ini" } }; + OptionsFile m_TwitchFile { { "chaosmod/configs/voting.json", "chaosmod/configs/voting.ini", + "chaosmod/configs/twitch.ini", "chaosmod/twitch.ini" } }; public: void Reset() @@ -20,29 +21,21 @@ class OptionsManager m_TwitchFile.Reset(); } - template inline T GetConfigValue(const std::vector &keys, T defaultValue) + template inline T GetConfigValue(const std::vector &lookupKeys, T defaultValue = {}) { - return GetOptionValue(m_ConfigFile, keys, defaultValue); + return GetOptionValue(m_ConfigFile, lookupKeys, defaultValue); } - template inline T GetVotingValue(const std::vector &keys, T defaultValue) + template inline T GetVotingValue(const std::vector &lookupKeys, T defaultValue = {}) { - return GetOptionValue(m_TwitchFile, keys, defaultValue); + return GetOptionValue(m_TwitchFile, lookupKeys, defaultValue); } private: template inline T GetOptionValue(const OptionsFile &optionsFile, const std::vector &keys, T defaultValue = {}) { - if constexpr (std::is_same::type, std::string>() - || std::is_same::type, char *>()) - { - return optionsFile.ReadValueString(keys, defaultValue); - } - else - { - return optionsFile.ReadValue(keys, defaultValue); - } + return optionsFile.ReadValue(keys, defaultValue); } }; diff --git a/ChaosMod/Util/Random.h b/ChaosMod/Util/Random.h index 96de0fb4c..157e8ccdc 100644 --- a/ChaosMod/Util/Random.h +++ b/ChaosMod/Util/Random.h @@ -11,8 +11,7 @@ class Random public: inline void SetSeed(int seed) { - if (seed > 0) - m_Random.seed(seed); + m_Random.seed(seed); } inline int GetRandomInt(int lower, int upper) diff --git a/ConfigApp/MainWindow.xaml.cs b/ConfigApp/MainWindow.xaml.cs index 6f8b44761..7add3f6e6 100644 --- a/ConfigApp/MainWindow.xaml.cs +++ b/ConfigApp/MainWindow.xaml.cs @@ -7,6 +7,7 @@ using ConfigApp.Tabs; using ConfigApp.Tabs.Settings; using ConfigApp.Tabs.Voting; +using Newtonsoft.Json.Linq; using static ConfigApp.Effects; namespace ConfigApp @@ -160,25 +161,29 @@ private EffectData GetEffectData(string effectId) private void ParseConfigFile() { // Meta Effects - meta_effects_spawn_dur.Text = OptionsManager.ConfigFile.ReadValue("NewMetaEffectSpawnTime", "600"); - meta_effects_timed_dur.Text = OptionsManager.ConfigFile.ReadValue("MetaEffectDur", "95"); - meta_effects_short_timed_dur.Text = OptionsManager.ConfigFile.ReadValue("MetaShortEffectDur", "65"); + meta_effects_spawn_dur.Text = $"{OptionsManager.ConfigFile.ReadValue("NewMetaEffectSpawnTime", 600)}"; + meta_effects_timed_dur.Text = $"{OptionsManager.ConfigFile.ReadValue("MetaEffectDur", 95)}"; + meta_effects_short_timed_dur.Text = $"{OptionsManager.ConfigFile.ReadValue("MetaShortEffectDur", 65)}"; } private void WriteConfigFile() { // Meta Effects - OptionsManager.ConfigFile.WriteValue("NewMetaEffectSpawnTime", meta_effects_spawn_dur.Text); - OptionsManager.ConfigFile.WriteValue("MetaEffectDur", meta_effects_timed_dur.Text); - OptionsManager.ConfigFile.WriteValue("MetaShortEffectDur", meta_effects_short_timed_dur.Text); + OptionsManager.ConfigFile.WriteValueAsInt("NewMetaEffectSpawnTime", meta_effects_spawn_dur.Text); + OptionsManager.ConfigFile.WriteValueAsInt("MetaEffectDur", meta_effects_timed_dur.Text); + OptionsManager.ConfigFile.WriteValueAsInt("MetaShortEffectDur", meta_effects_short_timed_dur.Text); } private void ParseEffectsFile() { + bool isJson = OptionsManager.EffectsFile.FoundFilePath.EndsWith(".json"); foreach (string key in OptionsManager.EffectsFile.GetKeys()) { - var value = OptionsManager.EffectsFile.ReadValue(key); - var effectData = Utils.ValueStringToEffectData(value); + EffectData effectData; + if (isJson) + effectData = Utils.ValuesArrayToEffectData(OptionsManager.EffectsFile.ReadValue(key)); + else + effectData = Utils.ValuesArrayToEffectData(OptionsManager.EffectsFile.ReadValue(key)); m_EffectDataMap?.Add(key, effectData); } @@ -186,18 +191,23 @@ private void ParseEffectsFile() private void WriteEffectsFile() { - foreach (var pair in EffectsMap) + foreach (var (effectId, _) in EffectsMap) { - var effectData = GetEffectData(pair.Key); - - OptionsManager.EffectsFile.WriteValue(pair.Key, $"{(m_TreeMenuItemsMap?[pair.Key].IsChecked is true ? 1 : 0)}" - + $",{(int)effectData.TimedType.GetValueOrDefault(EffectTimedType.NotTimed)}" - + $",{effectData.CustomTime.GetValueOrDefault(0)}" - + $",{effectData.WeightMult.GetValueOrDefault(0)}" - + $",{(effectData.TimedType.GetValueOrDefault(EffectTimedType.NotTimed) == EffectTimedType.Permanent ? 1 : 0)}" - + $",{(effectData.ExcludedFromVoting.GetValueOrDefault(false) ? 1 : 0)}" - + $",\"{(string.IsNullOrEmpty(effectData.CustomName) ? "" : effectData.CustomName)}\"" - + $",{effectData.ShortcutKeycode.GetValueOrDefault(0)}"); + var effectData = GetEffectData(effectId); + + var jsonArray = new JArray + { + m_TreeMenuItemsMap?[effectId].IsChecked, + (int)effectData.TimedType.GetValueOrDefault(EffectTimedType.NotTimed), + effectData.CustomTime.GetValueOrDefault(0), + effectData.WeightMult.GetValueOrDefault(0), + effectData.TimedType.GetValueOrDefault(EffectTimedType.NotTimed) == EffectTimedType.Permanent, + effectData.ExcludedFromVoting.GetValueOrDefault(false), + string.IsNullOrEmpty(effectData.CustomName) ? "" : effectData.CustomName, + effectData.ShortcutKeycode.GetValueOrDefault(0) + }; + + OptionsManager.EffectsFile.WriteValue(effectId, jsonArray); } OptionsManager.EffectsFile.WriteFile(); @@ -347,12 +357,35 @@ private void NoCopyPastePreviewExecuted(object sender, ExecutedRoutedEventArgs e private void OnUserSaveClick(object sender, RoutedEventArgs e) { - if (OptionsManager.ConfigFile.HasCompatFile("config.ini") || OptionsManager.TwitchFile.HasCompatFile("twitch.ini") - || OptionsManager.EffectsFile.HasCompatFile("effects.ini")) - if (MessageBox.Show("Note: Config files reside inside the configs/ subdirectory now. Clicking OK will move the files there. " + + // Config migration stuff + bool oldIniFilesExist = false; + if (OptionsManager.ConfigFile.FoundFilePath == "config.ini" || OptionsManager.VotingFile.FoundFilePath == "twitch.ini" + || OptionsManager.EffectsFile.FoundFilePath == "effects.ini") + { + oldIniFilesExist = true; + if (MessageBox.Show("Config files reside inside the configs/ subdirectory now. Clicking OK will move the config files there. " + "If you want to play older versions of the mod you will have to move them back. Continue?", "ChaosModV", MessageBoxButton.OKCancel, MessageBoxImage.Warning) != MessageBoxResult.OK) return; + } + + if (oldIniFilesExist || OptionsManager.ConfigFile.FoundFilePath == "configs/config.ini" || OptionsManager.VotingFile.FoundFilePath == "configs/twitch.ini" || OptionsManager.VotingFile.FoundFilePath == "configs/voting.ini" + || OptionsManager.EffectsFile.FoundFilePath == "configs/effects.ini") + { + oldIniFilesExist = true; + if (MessageBox.Show("WARNING: Starting with mod version 2.2 config files are automatically migrated to the new JSON format. Clicking OK will migrate to your config files. " + + "This will prevent you from using earlier mod versions with your existing config. Your old config files will be backed up to the configs/old/ directory. Continue?", "ChaosModV", MessageBoxButton.OKCancel, MessageBoxImage.Warning) + != MessageBoxResult.OK) + return; + } + + if (oldIniFilesExist) + { + Directory.CreateDirectory("configs/old"); + File.Move(OptionsManager.ConfigFile.FoundFilePath, $"configs/old/{Path.GetFileName(OptionsManager.ConfigFile.FoundFilePath)}", true); + File.Move(OptionsManager.VotingFile.FoundFilePath, $"configs/old/{Path.GetFileName(OptionsManager.VotingFile.FoundFilePath)}", true); + File.Move(OptionsManager.EffectsFile.FoundFilePath, $"configs/old/{Path.GetFileName(OptionsManager.EffectsFile.FoundFilePath)}", true); + } WriteConfigFile(); WriteEffectsFile(); @@ -384,7 +417,7 @@ private void OnUserResetClick(object sender, RoutedEventArgs e) MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) - OptionsManager.TwitchFile.ResetFile(); + OptionsManager.VotingFile.ResetFile(); Init(); diff --git a/ConfigApp/OptionsManager.cs b/ConfigApp/OptionsManager.cs index 8a5763d20..7c852fcfb 100644 --- a/ConfigApp/OptionsManager.cs +++ b/ConfigApp/OptionsManager.cs @@ -5,17 +5,17 @@ namespace ConfigApp { public static class OptionsManager { - public static OptionsFile ConfigFile { get; } = new OptionsFile("configs/config.ini", "config.ini"); - public static OptionsFile TwitchFile { get; } = new OptionsFile("configs/voting.ini", "configs/twitch.ini", "twitch.ini"); - public static OptionsFile EffectsFile { get; } = new OptionsFile("configs/effects.ini", "effects.ini"); + public static OptionsFile ConfigFile { get; } = new OptionsFile("configs/config.json", "configs/config.ini", "config.ini"); + public static OptionsFile VotingFile { get; } = new OptionsFile("configs/voting.json", "configs/voting.ini", "configs/twitch.ini", "twitch.ini"); + public static OptionsFile EffectsFile { get; } = new OptionsFile("configs/effects.json", "configs/effects.ini", "effects.ini"); // These are written to manually - public static OptionsFile WorkshopFile { get; } = new OptionsFile("configs/workshop.ini"); + public static OptionsFile WorkshopFile { get; } = new OptionsFile("configs/workshop.json", "configs/workshop.ini"); public static void ReadFiles() { ConfigFile.ReadFile(); - TwitchFile.ReadFile(); + VotingFile.ReadFile(); EffectsFile.ReadFile(); WorkshopFile.ReadFile(); } @@ -23,14 +23,13 @@ public static void ReadFiles() public static void WriteFiles() { ConfigFile.WriteFile(); - TwitchFile.WriteFile(); + VotingFile.WriteFile(); EffectsFile.WriteFile(); } public static void ResetFiles() { // Exclude TwitchFile as that one is reset separately - ConfigFile.ResetFile(); EffectsFile.ResetFile(); } @@ -43,12 +42,9 @@ static void deleteFiles(string[] files) File.Delete(file); } - if (ConfigFile.HasCompatFile()) - deleteFiles(ConfigFile.GetCompatFiles()); - if (TwitchFile.HasCompatFile()) - deleteFiles(TwitchFile.GetCompatFiles()); - if (EffectsFile.HasCompatFile()) - deleteFiles(EffectsFile.GetCompatFiles()); + deleteFiles(ConfigFile.CompatFilePaths); + deleteFiles(VotingFile.CompatFilePaths); + deleteFiles(EffectsFile.CompatFilePaths); } } } diff --git a/ConfigApp/Tabs/MetaTab.cs b/ConfigApp/Tabs/MetaTab.cs index adf657942..3b1e7dfc1 100644 --- a/ConfigApp/Tabs/MetaTab.cs +++ b/ConfigApp/Tabs/MetaTab.cs @@ -72,18 +72,18 @@ protected override void InitContent() public override void OnLoadValues() { if (m_MetaEffectDispatchTimer is not null) - m_MetaEffectDispatchTimer.Text = OptionsManager.ConfigFile.ReadValue("NewMetaEffectSpawnTime", "600"); + m_MetaEffectDispatchTimer.Text = $"{OptionsManager.ConfigFile.ReadValue("NewMetaEffectSpawnTime", 600)}"; if (m_MetaEffectDuration is not null) - m_MetaEffectDuration.Text = OptionsManager.ConfigFile.ReadValue("MetaEffectDur", "95"); + m_MetaEffectDuration.Text = $"{OptionsManager.ConfigFile.ReadValue("MetaEffectDur", 95)}"; if (m_MetaEffectShortDuration is not null) - m_MetaEffectShortDuration.Text = OptionsManager.ConfigFile.ReadValue("MetaShortEffectDur", "65"); + m_MetaEffectShortDuration.Text = $"{OptionsManager.ConfigFile.ReadValue("MetaShortEffectDur", 65)}"; } public override void OnSaveValues() { - OptionsManager.ConfigFile.WriteValue("NewMetaEffectSpawnTime", m_MetaEffectDispatchTimer?.Text); - OptionsManager.ConfigFile.WriteValue("MetaEffectDur", m_MetaEffectDuration?.Text); - OptionsManager.ConfigFile.WriteValue("MetaShortEffectDur", m_MetaEffectShortDuration?.Text); + OptionsManager.ConfigFile.WriteValueAsInt("NewMetaEffectSpawnTime", m_MetaEffectDispatchTimer?.Text); + OptionsManager.ConfigFile.WriteValueAsInt("MetaEffectDur", m_MetaEffectDuration?.Text); + OptionsManager.ConfigFile.WriteValueAsInt("MetaShortEffectDur", m_MetaEffectShortDuration?.Text); } } } diff --git a/ConfigApp/Tabs/Settings/ColorsTab.cs b/ConfigApp/Tabs/Settings/ColorsTab.cs index 160446e33..280162aca 100644 --- a/ConfigApp/Tabs/Settings/ColorsTab.cs +++ b/ConfigApp/Tabs/Settings/ColorsTab.cs @@ -53,11 +53,11 @@ protected override void InitContent() public override void OnLoadValues() { if (OptionsManager.ConfigFile.HasKey("EffectTimerColor") && m_TimerBarColor is not null) - m_TimerBarColor.SelectedColor = (Color)ColorConverter.ConvertFromString(OptionsManager.ConfigFile.ReadValue("EffectTimerColor")); + m_TimerBarColor.SelectedColor = (Color)ColorConverter.ConvertFromString(OptionsManager.ConfigFile.ReadValue("EffectTimerColor")); if (OptionsManager.ConfigFile.HasKey("EffectTextColor") && m_EffectTextColor is not null) - m_EffectTextColor.SelectedColor = (Color)ColorConverter.ConvertFromString(OptionsManager.ConfigFile.ReadValue("EffectTextColor")); + m_EffectTextColor.SelectedColor = (Color)ColorConverter.ConvertFromString(OptionsManager.ConfigFile.ReadValue("EffectTextColor")); if (OptionsManager.ConfigFile.HasKey("EffectTimedTimerColor") && m_EffectTimerBarColor is not null) - m_EffectTimerBarColor.SelectedColor = (Color)ColorConverter.ConvertFromString(OptionsManager.ConfigFile.ReadValue("EffectTimedTimerColor")); + m_EffectTimerBarColor.SelectedColor = (Color)ColorConverter.ConvertFromString(OptionsManager.ConfigFile.ReadValue("EffectTimedTimerColor")); } public override void OnSaveValues() diff --git a/ConfigApp/Tabs/Settings/GeneralTab.cs b/ConfigApp/Tabs/Settings/GeneralTab.cs index e2c68eac8..f32cdd5e8 100644 --- a/ConfigApp/Tabs/Settings/GeneralTab.cs +++ b/ConfigApp/Tabs/Settings/GeneralTab.cs @@ -37,7 +37,11 @@ protected override void InitContent() grid.PushRowSpacedPair("Don't draw effect text", m_DisableDrawEffectText = Utils.GenerateCommonCheckBox()); grid.PopRow(); - grid.PushRowSpacedPair("Random Seed (Leave empty for random seed every time)", m_RandomSeed = Utils.GenerateCommonNumericOnlyTextBox()); + grid.PushRowSpacedPair("Random Seed (Leave empty for random seed every time)", m_RandomSeed = new TextBox() + { + Width = 200f, + Height = 20f + }); grid.PushRowSpacedPair("Enable effect group weighting", m_EnableEffectGroupWeighting = Utils.GenerateCommonCheckBox()); grid.PopRow(); @@ -53,21 +57,21 @@ protected override void InitContent() public override void OnLoadValues() { if (m_DisableDrawTimer is not null) - m_DisableDrawTimer.IsChecked = OptionsManager.ConfigFile.ReadValueBool("DisableTimerBarDraw", false); + m_DisableDrawTimer.IsChecked = OptionsManager.ConfigFile.ReadValue("DisableTimerBarDraw", false); if (m_DisableDrawEffectText is not null) - m_DisableDrawEffectText.IsChecked = OptionsManager.ConfigFile.ReadValueBool("DisableEffectTextDraw", false); + m_DisableDrawEffectText.IsChecked = OptionsManager.ConfigFile.ReadValue("DisableEffectTextDraw", false); if (m_RandomSeed is not null) - m_RandomSeed.Text = OptionsManager.ConfigFile.ReadValue("Seed"); + m_RandomSeed.Text = OptionsManager.ConfigFile.ReadValue("Seed"); if (m_MaxRunningEffects is not null) - m_MaxRunningEffects.Text = OptionsManager.ConfigFile.ReadValue("MaxParallelRunningEffects", "99"); + m_MaxRunningEffects.Text = $"{OptionsManager.ConfigFile.ReadValue("MaxParallelRunningEffects", 99)}"; if (m_EnableEffectGroupWeighting is not null) - m_EnableEffectGroupWeighting.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnableGroupWeightingAdjustments", true); + m_EnableEffectGroupWeighting.IsChecked = OptionsManager.ConfigFile.ReadValue("EnableGroupWeightingAdjustments", true); if (m_DisableModOnStartup is not null) - m_DisableModOnStartup.IsChecked = OptionsManager.ConfigFile.ReadValueBool("DisableStartup", false); + m_DisableModOnStartup.IsChecked = OptionsManager.ConfigFile.ReadValue("DisableStartup", false); if (m_EnableFailsafe is not null) - m_EnableFailsafe.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnableFailsafe", true); + m_EnableFailsafe.IsChecked = OptionsManager.ConfigFile.ReadValue("EnableFailsafe", true); if (m_EnableModSplashTexts is not null) - m_EnableModSplashTexts.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnableModSplashTexts", true); + m_EnableModSplashTexts.IsChecked = OptionsManager.ConfigFile.ReadValue("EnableModSplashTexts", true); } public override void OnSaveValues() @@ -75,7 +79,7 @@ public override void OnSaveValues() OptionsManager.ConfigFile.WriteValue("DisableTimerBarDraw", m_DisableDrawTimer?.IsChecked); OptionsManager.ConfigFile.WriteValue("DisableEffectTextDraw", m_DisableDrawEffectText?.IsChecked); OptionsManager.ConfigFile.WriteValue("Seed", m_RandomSeed?.Text); - OptionsManager.ConfigFile.WriteValue("MaxParallelRunningEffects", m_MaxRunningEffects?.Text); + OptionsManager.ConfigFile.WriteValueAsInt("MaxParallelRunningEffects", m_MaxRunningEffects?.Text); OptionsManager.ConfigFile.WriteValue("EnableGroupWeightingAdjustments", m_EnableEffectGroupWeighting?.IsChecked); OptionsManager.ConfigFile.WriteValue("DisableStartup", m_DisableModOnStartup?.IsChecked); OptionsManager.ConfigFile.WriteValue("EnableFailsafe", m_EnableFailsafe?.IsChecked); diff --git a/ConfigApp/Tabs/Settings/ModesTab.cs b/ConfigApp/Tabs/Settings/ModesTab.cs index 878815ac1..eda977a82 100644 --- a/ConfigApp/Tabs/Settings/ModesTab.cs +++ b/ConfigApp/Tabs/Settings/ModesTab.cs @@ -121,30 +121,30 @@ public override void OnLoadValues() { if (m_DispatchMode is not null) { - m_DispatchMode.SelectedIndex = !OptionsManager.ConfigFile.ReadValueBool("EnableDistanceBasedEffectDispatch", false) ? 0 : 1; + m_DispatchMode.SelectedIndex = !OptionsManager.ConfigFile.ReadValue("EffectDispatchMode", false, "EnableDistanceBasedEffectDispatch") ? 0 : 1; UpdateDispatchModeGridVisibility(); } if (m_EffectDispatchTimer is not null) - m_EffectDispatchTimer.Text = OptionsManager.ConfigFile.ReadValue("NewEffectSpawnTime", "30"); + m_EffectDispatchTimer.Text = $"{OptionsManager.ConfigFile.ReadValue("NewEffectSpawnTime", 30)}"; if (m_TimedEffectDuration is not null) - m_TimedEffectDuration.Text = OptionsManager.ConfigFile.ReadValue("EffectTimedDur", "90"); + m_TimedEffectDuration.Text = $"{OptionsManager.ConfigFile.ReadValue("EffectTimedDur", 90)}"; if (m_ShortTimedEffectDuration is not null) - m_ShortTimedEffectDuration.Text = OptionsManager.ConfigFile.ReadValue("EffectTimedShortDur", "30"); + m_ShortTimedEffectDuration.Text = $"{OptionsManager.ConfigFile.ReadValue("EffectTimedShortDur", 30)}"; if (m_DistanceBasedDispatchDistance is not null) - m_DistanceBasedDispatchDistance.Text = OptionsManager.ConfigFile.ReadValue("DistanceToActivateEffect", "250"); + m_DistanceBasedDispatchDistance.Text = $"{OptionsManager.ConfigFile.ReadValue("DistanceToActivateEffect", 250)}"; if (m_DistanceBasedDispatchType is not null) - m_DistanceBasedDispatchType.SelectedIndex = OptionsManager.ConfigFile.ReadValueInt("DistanceType", 0); + m_DistanceBasedDispatchType.SelectedIndex = OptionsManager.ConfigFile.ReadValue("DistanceType", 0); if (m_EnableCrossingChallenge is not null) - m_EnableCrossingChallenge.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnableCrossingChallenge", false); + m_EnableCrossingChallenge.IsChecked = OptionsManager.ConfigFile.ReadValue("EnableCrossingChallenge", false); } public override void OnSaveValues() { - OptionsManager.ConfigFile.WriteValue("NewEffectSpawnTime", m_EffectDispatchTimer?.Text); - OptionsManager.ConfigFile.WriteValue("EffectTimedDur", m_TimedEffectDuration?.Text); - OptionsManager.ConfigFile.WriteValue("EffectTimedShortDur", m_ShortTimedEffectDuration?.Text); - OptionsManager.ConfigFile.WriteValue("EnableDistanceBasedEffectDispatch", m_DispatchMode?.SelectedIndex); - OptionsManager.ConfigFile.WriteValue("DistanceToActivateEffect", m_DistanceBasedDispatchDistance?.Text); + OptionsManager.ConfigFile.WriteValueAsInt("NewEffectSpawnTime", m_EffectDispatchTimer?.Text); + OptionsManager.ConfigFile.WriteValueAsInt("EffectTimedDur", m_TimedEffectDuration?.Text); + OptionsManager.ConfigFile.WriteValueAsInt("EffectTimedShortDur", m_ShortTimedEffectDuration?.Text); + OptionsManager.ConfigFile.WriteValue("EffectDispatchMode", m_DispatchMode?.SelectedIndex); + OptionsManager.ConfigFile.WriteValueAsInt("DistanceToActivateEffect", m_DistanceBasedDispatchDistance?.Text); OptionsManager.ConfigFile.WriteValue("DistanceType", m_DistanceBasedDispatchType?.SelectedIndex); OptionsManager.ConfigFile.WriteValue("EnableCrossingChallenge", m_EnableCrossingChallenge?.IsChecked); } diff --git a/ConfigApp/Tabs/Settings/ShortcutsTab.cs b/ConfigApp/Tabs/Settings/ShortcutsTab.cs index 128939e5d..8a71c26d0 100644 --- a/ConfigApp/Tabs/Settings/ShortcutsTab.cs +++ b/ConfigApp/Tabs/Settings/ShortcutsTab.cs @@ -46,15 +46,15 @@ protected override void InitContent() public override void OnLoadValues() { if (m_EnableToggleModShortcut is not null) - m_EnableToggleModShortcut.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnableToggleModShortcut", true); + m_EnableToggleModShortcut.IsChecked = OptionsManager.ConfigFile.ReadValue("EnableToggleModShortcut", true); if (m_EnableClearActiveEffectsShortcut is not null) - m_EnableClearActiveEffectsShortcut.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnableClearEffectsShortcut", true); + m_EnableClearActiveEffectsShortcut.IsChecked = OptionsManager.ConfigFile.ReadValue("EnableClearEffectsShortcut", true); if (m_EnablePauseTimerShortcut is not null) - m_EnablePauseTimerShortcut.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnablePauseTimerShortcut", false); + m_EnablePauseTimerShortcut.IsChecked = OptionsManager.ConfigFile.ReadValue("EnablePauseTimerShortcut", false); if (m_EnableEffectsMenu is not null) - m_EnableEffectsMenu.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnableDebugMenu", false); + m_EnableEffectsMenu.IsChecked = OptionsManager.ConfigFile.ReadValue("EnableDebugMenu", false); if (m_EnableAntiSoftlockShortcut is not null) - m_EnableAntiSoftlockShortcut.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EnableAntiSoftlockShortcut", true); + m_EnableAntiSoftlockShortcut.IsChecked = OptionsManager.ConfigFile.ReadValue("EnableAntiSoftlockShortcut", true); } public override void OnSaveValues() diff --git a/ConfigApp/Tabs/Settings/SoundsTab.cs b/ConfigApp/Tabs/Settings/SoundsTab.cs index a706cf9f7..7e6819777 100644 --- a/ConfigApp/Tabs/Settings/SoundsTab.cs +++ b/ConfigApp/Tabs/Settings/SoundsTab.cs @@ -32,7 +32,7 @@ protected override void InitContent() public override void OnLoadValues() { if (m_UseMCI is not null) - m_UseMCI.IsChecked = OptionsManager.ConfigFile.ReadValueBool("EffectSoundUseMCI", false); + m_UseMCI.IsChecked = OptionsManager.ConfigFile.ReadValue("EffectSoundUseMCI", false); } public override void OnSaveValues() diff --git a/ConfigApp/Tabs/Voting/DiscordTab.cs b/ConfigApp/Tabs/Voting/DiscordTab.cs index 23e7f6556..e5e558148 100644 --- a/ConfigApp/Tabs/Voting/DiscordTab.cs +++ b/ConfigApp/Tabs/Voting/DiscordTab.cs @@ -71,16 +71,8 @@ protected override void InitContent() }); PopRow(); - PushRowSpacedPair("Server ID", m_GuildId = new TextBox() - { - Width = 125f, - Height = 20f - }); - PushRowSpacedPair("Channel ID", m_ChannelId = new TextBox() - { - Width = 125f, - Height = 20f - }); + PushRowSpacedPair("Server ID", m_GuildId = Utils.GenerateCommonNumericOnlyTextBox(default, 125f, 20f)); + PushRowSpacedPair("Channel ID", m_ChannelId = Utils.GenerateCommonNumericOnlyTextBox(default, 125f, 20f)); SetElementsEnabled(false); } @@ -89,24 +81,24 @@ public override void OnLoadValues() { if (m_EnableDiscordVoting is not null) { - m_EnableDiscordVoting.IsChecked = OptionsManager.TwitchFile.ReadValueBool("EnableVotingDiscord", false); + m_EnableDiscordVoting.IsChecked = OptionsManager.VotingFile.ReadValue("EnableVotingDiscord", false); SetElementsEnabled(m_EnableDiscordVoting.IsChecked.GetValueOrDefault()); } if (m_Token is not null) - m_Token.Password = OptionsManager.TwitchFile.ReadValue("DiscordBotToken"); + m_Token.Password = OptionsManager.VotingFile.ReadValue("DiscordBotToken"); if (m_GuildId is not null) - m_GuildId.Text = OptionsManager.TwitchFile.ReadValue("DiscordGuildId"); + m_GuildId.Text = OptionsManager.VotingFile.ReadValue("DiscordGuildId"); if (m_ChannelId is not null) - m_ChannelId.Text = OptionsManager.TwitchFile.ReadValue("DiscordChannelId"); + m_ChannelId.Text = OptionsManager.VotingFile.ReadValue("DiscordChannelId"); } public override void OnSaveValues() { - OptionsManager.TwitchFile.WriteValue("EnableVotingDiscord", m_EnableDiscordVoting?.IsChecked); - OptionsManager.TwitchFile.WriteValue("DiscordBotToken", m_Token?.Password); - OptionsManager.TwitchFile.WriteValue("DiscordGuildId", m_GuildId?.Text); - OptionsManager.TwitchFile.WriteValue("DiscordChannelId", m_ChannelId?.Text); + OptionsManager.VotingFile.WriteValue("EnableVotingDiscord", m_EnableDiscordVoting?.IsChecked); + OptionsManager.VotingFile.WriteValue("DiscordBotToken", m_Token?.Password); + OptionsManager.VotingFile.WriteValue("DiscordGuildId", m_GuildId?.Text); + OptionsManager.VotingFile.WriteValue("DiscordChannelId", m_ChannelId?.Text); } } } diff --git a/ConfigApp/Tabs/Voting/GeneralTab.cs b/ConfigApp/Tabs/Voting/GeneralTab.cs index 85b311222..3e983ea00 100644 --- a/ConfigApp/Tabs/Voting/GeneralTab.cs +++ b/ConfigApp/Tabs/Voting/GeneralTab.cs @@ -132,36 +132,36 @@ public override void OnLoadValues() { if (m_EnableVoting is not null) { - m_EnableVoting.IsChecked = OptionsManager.TwitchFile.ReadValueBool("EnableVoting", false, "EnableTwitchVoting"); + m_EnableVoting.IsChecked = OptionsManager.VotingFile.ReadValue("EnableVoting", false, "EnableTwitchVoting"); SetGridsEnabled(m_EnableVoting.IsChecked.GetValueOrDefault()); } if (m_OverlayMode is not null) - m_OverlayMode.SelectedIndex = OptionsManager.TwitchFile.ReadValueInt("VotingOverlayMode", 0, "TwitchVotingOverlayMode"); + m_OverlayMode.SelectedIndex = OptionsManager.VotingFile.ReadValue("VotingOverlayMode", 0, "TwitchVotingOverlayMode"); if (m_EnableRandomEffect is not null) - m_EnableRandomEffect.IsChecked = OptionsManager.TwitchFile.ReadValueBool("RandomEffectVoteableEnable", true, "TwitchRandomEffectVoteableEnable"); + m_EnableRandomEffect.IsChecked = OptionsManager.VotingFile.ReadValue("RandomEffectVoteableEnable", true, "TwitchRandomEffectVoteableEnable"); if (m_SecsBeforeVoting is not null) - m_SecsBeforeVoting.Text = OptionsManager.TwitchFile.ReadValue("VotingSecsBeforeVoting", "0", "TwitchVotingSecsBeforeVoting"); + m_SecsBeforeVoting.Text = $"{OptionsManager.VotingFile.ReadValue("VotingSecsBeforeVoting", 0, "TwitchVotingSecsBeforeVoting")}"; if (m_PermittedUserNames is not null) - m_PermittedUserNames.Text = OptionsManager.TwitchFile.ReadValue("PermittedUsernames", null, "TwitchPermittedUsernames"); + m_PermittedUserNames.Text = OptionsManager.VotingFile.ReadValue("PermittedUsernames", null, "TwitchPermittedUsernames"); if (m_VoteablePrefix is not null) - m_VoteablePrefix.Text = OptionsManager.TwitchFile.ReadValue("VoteablePrefix", ""); + m_VoteablePrefix.Text = OptionsManager.VotingFile.ReadValue("VoteablePrefix", ""); if (m_EnableProportionalVoting is not null) - m_EnableProportionalVoting.IsChecked = OptionsManager.TwitchFile.ReadValueBool("VotingChanceSystem", false, "TwitchVotingChanceSystem"); + m_EnableProportionalVoting.IsChecked = OptionsManager.VotingFile.ReadValue("VotingChanceSystem", false, "TwitchVotingChanceSystem"); if (m_EnableProportionalVotingRetainInitialChance is not null) - m_EnableProportionalVotingRetainInitialChance.IsChecked = OptionsManager.TwitchFile.ReadValueBool("VotingChanceSystemRetainChance", true, + m_EnableProportionalVotingRetainInitialChance.IsChecked = OptionsManager.VotingFile.ReadValue("VotingChanceSystemRetainChance", true, "TwitchVotingChanceSystemRetainChance"); } public override void OnSaveValues() { - OptionsManager.TwitchFile.WriteValue("EnableVoting", m_EnableVoting?.IsChecked); - OptionsManager.TwitchFile.WriteValue("VotingOverlayMode", m_OverlayMode?.SelectedIndex); - OptionsManager.TwitchFile.WriteValue("RandomEffectVoteableEnable", m_EnableRandomEffect?.IsChecked); - OptionsManager.TwitchFile.WriteValue("VotingSecsBeforeVoting", m_SecsBeforeVoting?.Text); - OptionsManager.TwitchFile.WriteValue("PermittedUsernames", m_PermittedUserNames?.Text); - OptionsManager.TwitchFile.WriteValue("VoteablePrefix", m_VoteablePrefix?.Text); - OptionsManager.TwitchFile.WriteValue("VotingChanceSystem", m_EnableProportionalVoting?.IsChecked); - OptionsManager.TwitchFile.WriteValue("VotingChanceSystemRetainChance", m_EnableProportionalVotingRetainInitialChance?.IsChecked); + OptionsManager.VotingFile.WriteValue("EnableVoting", m_EnableVoting?.IsChecked); + OptionsManager.VotingFile.WriteValue("VotingOverlayMode", m_OverlayMode?.SelectedIndex); + OptionsManager.VotingFile.WriteValue("RandomEffectVoteableEnable", m_EnableRandomEffect?.IsChecked); + OptionsManager.VotingFile.WriteValueAsInt("VotingSecsBeforeVoting", m_SecsBeforeVoting?.Text); + OptionsManager.VotingFile.WriteValue("PermittedUsernames", m_PermittedUserNames?.Text); + OptionsManager.VotingFile.WriteValue("VoteablePrefix", m_VoteablePrefix?.Text); + OptionsManager.VotingFile.WriteValue("VotingChanceSystem", m_EnableProportionalVoting?.IsChecked); + OptionsManager.VotingFile.WriteValue("VotingChanceSystemRetainChance", m_EnableProportionalVotingRetainInitialChance?.IsChecked); } } } diff --git a/ConfigApp/Tabs/Voting/TwitchTab.cs b/ConfigApp/Tabs/Voting/TwitchTab.cs index b9b9faf16..b212849fb 100644 --- a/ConfigApp/Tabs/Voting/TwitchTab.cs +++ b/ConfigApp/Tabs/Voting/TwitchTab.cs @@ -70,23 +70,23 @@ public override void OnLoadValues() { if (m_EnableTwitchVoting is not null) { - m_EnableTwitchVoting.IsChecked = OptionsManager.TwitchFile.ReadValueBool("EnableVotingTwitch", false); + m_EnableTwitchVoting.IsChecked = OptionsManager.VotingFile.ReadValue("EnableVotingTwitch", false); SetElementsEnabled(m_EnableTwitchVoting.IsChecked.GetValueOrDefault()); } if (m_ChannelName is not null) - m_ChannelName.Text = OptionsManager.TwitchFile.ReadValue("TwitchChannelName"); + m_ChannelName.Text = OptionsManager.VotingFile.ReadValue("TwitchChannelName"); if (m_UserName is not null) - m_UserName.Text = OptionsManager.TwitchFile.ReadValue("TwitchUserName"); + m_UserName.Text = OptionsManager.VotingFile.ReadValue("TwitchUserName"); if (m_Token is not null) - m_Token.Password = OptionsManager.TwitchFile.ReadValue("TwitchChannelOAuth"); + m_Token.Password = OptionsManager.VotingFile.ReadValue("TwitchChannelOAuth"); } public override void OnSaveValues() { - OptionsManager.TwitchFile.WriteValue("EnableVotingTwitch", m_EnableTwitchVoting?.IsChecked); - OptionsManager.TwitchFile.WriteValue("TwitchChannelName", m_ChannelName?.Text); - OptionsManager.TwitchFile.WriteValue("TwitchUserName", m_UserName?.Text); - OptionsManager.TwitchFile.WriteValue("TwitchChannelOAuth", m_Token?.Password); + OptionsManager.VotingFile.WriteValue("EnableVotingTwitch", m_EnableTwitchVoting?.IsChecked); + OptionsManager.VotingFile.WriteValue("TwitchChannelName", m_ChannelName?.Text); + OptionsManager.VotingFile.WriteValue("TwitchUserName", m_UserName?.Text); + OptionsManager.VotingFile.WriteValue("TwitchChannelOAuth", m_Token?.Password); } } } diff --git a/ConfigApp/Utils.cs b/ConfigApp/Utils.cs index f0caa799b..fde29255b 100644 --- a/ConfigApp/Utils.cs +++ b/ConfigApp/Utils.cs @@ -2,47 +2,76 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using Newtonsoft.Json.Linq; namespace ConfigApp { public static class Utils { - public static EffectData ValueStringToEffectData(string? value) + public static EffectData ValuesArrayToEffectData(T? value) { var effectData = new EffectData(); if (value is null) return effectData; - // Split by comma, ignoring commas in between quotation marks - var values = Regex.Split(value, ",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))"); + dynamic[] values; + bool isNewConfig = true; + switch (value) + { + case JArray arrayValue: + values = arrayValue.Children().ToArray(); + break; + case string strValue: + // Split by comma, ignoring commas in between quotation marks + values = Regex.Split(strValue, ",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))"); + isNewConfig = false; + break; + default: + throw new NotImplementedException("Invalid Value Type"); + } - /* Has compatibility checks as previous mod versions had less options */ + // .ini configs stored everything (except CustomName) as an int + // Also has compatibility checks as very ancient mod versions had less options if (values.Length >= 4) { - if (int.TryParse(values[0], out int enabled)) - effectData.Enabled = enabled != 0; - - if (Enum.TryParse(values[1], out Effects.EffectTimedType timedType)) - effectData.TimedType = timedType != Effects.EffectTimedType.NotTimed ? timedType : null; - if (int.TryParse(values[2], out int customTime)) - effectData.CustomTime = customTime; - if (int.TryParse(values[3], out int weightMult)) - effectData.WeightMult = weightMult; + int enabled = isNewConfig ? (bool)values[0] ? 1 : 0 : int.Parse(values[0]); + effectData.Enabled = enabled != 0; + + Effects.EffectTimedType timedType = (Effects.EffectTimedType)(isNewConfig ? values[1] : Enum.Parse(typeof(Effects.EffectTimedType), values[1])); + effectData.TimedType = timedType != Effects.EffectTimedType.NotTimed ? timedType : null; + + int customTime = isNewConfig ? values[2] : int.Parse(values[2]); + effectData.CustomTime = customTime; + + int weightMult = isNewConfig ? values[3] : int.Parse(values[3]); + effectData.WeightMult = weightMult; } - if (values.Length >= 5 && int.TryParse(values[4], out int tmp) && tmp != 0) - effectData.TimedType = Effects.EffectTimedType.Permanent; + if (values.Length >= 5) + { + int isPermanent = isNewConfig ? (bool)values[4] ? 1 : 0 : int.Parse(values[4]); + if (isPermanent != 0) + effectData.TimedType = Effects.EffectTimedType.Permanent; + } - if (values.Length >= 6 && int.TryParse(values[5], out tmp)) - effectData.ExcludedFromVoting = tmp != 0; + if (values.Length >= 6) + { + int excludedFromVoting = isNewConfig ? (bool)values[5] ? 1 : 0 : int.Parse(values[5]); + effectData.ExcludedFromVoting = excludedFromVoting != 0; + } if (values.Length >= 7) - effectData.CustomName = values[6] == "0" ? null : values[6].Trim('\"'); + effectData.CustomName = values[6] == "0" ? null : ((string)values[6]).Trim('\"'); - if (values.Length >= 8 && int.TryParse(values[7], out int shortcut)) + if (values.Length >= 8) + { + int shortcut = isNewConfig ? values[7] : int.Parse(values[7]); effectData.ShortcutKeycode = shortcut; + } + + // New JSON-exclusive stored values below here, meaning we can properly use the stored type return effectData; } @@ -91,5 +120,14 @@ public static TextBox GenerateCommonNumericOnlyTextBox(int maxLength = 6, double return textBox; } + + public static bool IsNumeric(this T value) + { + if (value is null) + return false; + + var t = Nullable.GetUnderlyingType(value.GetType()) ?? value.GetType(); + return t.IsPrimitive || t == typeof(decimal); + } } } diff --git a/ConfigApp/Workshop/WorkshopSettingsDialog.xaml.cs b/ConfigApp/Workshop/WorkshopSettingsDialog.xaml.cs index 11d083ac9..32eacc661 100644 --- a/ConfigApp/Workshop/WorkshopSettingsDialog.xaml.cs +++ b/ConfigApp/Workshop/WorkshopSettingsDialog.xaml.cs @@ -15,7 +15,7 @@ public WorkshopSettingsDialog() { InitializeComponent(); - workshop_custom_url.Text = OptionsManager.WorkshopFile.ReadValue("WorkshopCustomUrl"); + workshop_custom_url.Text = OptionsManager.WorkshopFile.ReadValue("WorkshopCustomUrl"); workshop_custom_url.Watermark = Info.WORKSHOP_DEFAULT_URL; } diff --git a/Shared/OptionsFile.cs b/Shared/OptionsFile.cs index 0e2f977df..740ceb274 100644 --- a/Shared/OptionsFile.cs +++ b/Shared/OptionsFile.cs @@ -1,17 +1,22 @@ using System.IO; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Shared { public class OptionsFile { - private readonly string m_FileName; - private readonly string[] m_CompatFileNames; - private Dictionary m_Options = new(); + public string FoundFilePath { get; private set; } = string.Empty; + public string[] CompatFilePaths { get; private set; } - public OptionsFile(string fileName, params string[] compatFileNames) + private readonly string m_FilePath; + private bool m_IsJson = false; + private Dictionary m_Options = new(); + + public OptionsFile(string filePath, params string[] compatFilePaths) { - m_FileName = fileName; - m_CompatFileNames = compatFileNames; + m_FilePath = filePath; + CompatFilePaths = compatFilePaths; } public bool HasKey(params string[] keys) @@ -31,7 +36,7 @@ public IEnumerable GetKeys() yield return option.Key; } - public string? ReadValue(string key, string? defaultValue = null, params string[] compatKeys) + public T? ReadValue(string key, T? defaultValue = default, params string[] compatKeys) { var keys = compatKeys.Prepend(key); foreach (var _key in keys) @@ -39,56 +44,37 @@ public IEnumerable GetKeys() if (!m_Options.ContainsKey(_key) || m_Options[_key] is null) continue; - return m_Options[_key]; - } - - return defaultValue; - } - - public int ReadValueInt(string key, int defaultValue, params string[] compatKeys) - { - if (!int.TryParse(ReadValue(key, null, compatKeys), out int result)) - result = defaultValue; - - return result; - } - - public long ReadValueLong(string key, long defaultValue, params string[] compatKeys) - { - if (!long.TryParse(ReadValue(key, null, compatKeys), out long result)) - result = defaultValue; - - return result; - } + if (typeof(T) == typeof(bool) && !m_IsJson) + { + string? str = ReadValue(_key, $"{((bool?)Convert.ChangeType(defaultValue, typeof(bool)) == true ? "1" : "0")}"); + if (str is null) + return defaultValue; - public bool ReadValueBool(string key, bool defaultValue, params string[] compatKeys) - { - var keys = compatKeys.Prepend(key); - foreach (var _key in keys) - { - if (!m_Options.ContainsKey(_key) || m_Options[_key] == null) - continue; + if (int.TryParse(str, out int result)) + return (T?)Convert.ChangeType(result != 0, typeof(T)); + } - if (int.TryParse(ReadValue(_key), out int result)) - return result != 0; + return m_Options[_key].ToObject(); } return defaultValue; } - public void WriteValue(string key, string? value) + public void WriteValue(string key, T? value) { - m_Options[key] = value is null || string.IsNullOrEmpty(value) ? null : value; + if (value is null || (value is string && string.IsNullOrEmpty(value as string))) + m_Options[key] = null; + else if (value is JObject o) + m_Options[key] = o; + else if (value is JArray a) + m_Options[key] = a; + else + m_Options[key] = new JValue(value); } - public void WriteValue(string key, int? value) + public void WriteValueAsInt(string key, string? value) { - WriteValue(key, $"{value}"); - } - - public void WriteValue(string key, bool? value) - { - WriteValue(key, value is true ? 1 : 0); + m_Options[key] = value is null || string.IsNullOrEmpty(value) ? null : new JValue(int.Parse(value)); } public void ReadFile() @@ -106,14 +92,17 @@ public void ReadFile() } string? data; - if ((data = readData(m_FileName)) == null) + if ((data = readData(m_FilePath)) != null) + FoundFilePath = m_FilePath; + else { bool dataRead = false; - foreach (var compatFileName in m_CompatFileNames) + foreach (var compatFileName in CompatFilePaths) { if ((data = readData(compatFileName)) != null) { dataRead = true; + FoundFilePath = compatFileName; break; } } @@ -124,46 +113,62 @@ public void ReadFile() m_Options.Clear(); - if (data is not null) + if (data is not null && FoundFilePath is not null) { - foreach (string line in data.Split('\n')) + if (FoundFilePath.EndsWith(".json")) + { + m_IsJson = true; + + var json = JObject.Parse(data); + foreach (var (key, value) in json) + m_Options[key] = value; + } + else if (FoundFilePath.EndsWith(".ini")) { - if (!line.Contains('=')) - continue; + m_IsJson = false; - var keyValuePair = line.Split('=', 2, System.StringSplitOptions.RemoveEmptyEntries - | System.StringSplitOptions.TrimEntries); + foreach (string line in data.Split('\n')) + { + if (!line.Contains('=')) + continue; - m_Options[keyValuePair[0]] = keyValuePair.Length == 2 ? keyValuePair[1] : null; + var keyValuePair = line.Split('=', 2, System.StringSplitOptions.RemoveEmptyEntries + | System.StringSplitOptions.TrimEntries); + + m_Options[keyValuePair[0]] = keyValuePair.Length == 2 ? new JValue(keyValuePair[1]) : null; + } } } } public void WriteFile() { - if (m_FileName is null) + if (m_FilePath is null) return; - string data = string.Empty; + FoundFilePath = m_FilePath; - foreach (var option in m_Options) - data += $"{option.Key}={option.Value}\n"; + var json = new JObject(); + foreach (var (key, value) in m_Options) + json[key] = value; - var directory = Path.GetDirectoryName(m_FileName); + var directory = Path.GetDirectoryName(m_FilePath); if (directory is not null) Directory.CreateDirectory(directory); - File.WriteAllText(m_FileName, data); + + File.WriteAllText(m_FilePath, JsonConvert.SerializeObject(json)); } public void ResetFile() { - if (m_FileName is null) + if (m_FilePath is null) return; - var directory = Path.GetDirectoryName(m_FileName); + var directory = Path.GetDirectoryName(m_FilePath); if (directory is not null) Directory.CreateDirectory(directory); - File.WriteAllText(m_FileName, null); + + File.WriteAllText(m_FilePath, null); // Reset all options too m_Options = new(); @@ -171,7 +176,7 @@ public void ResetFile() public bool HasCompatFile() { - foreach (var compatFileName in m_CompatFileNames) + foreach (var compatFileName in CompatFilePaths) { if (File.Exists(compatFileName)) return true; @@ -179,15 +184,5 @@ public bool HasCompatFile() return false; } - - public bool HasCompatFile(string fileName) - { - return m_CompatFileNames.Contains(fileName) && File.Exists(fileName); - } - - public string[] GetCompatFiles() - { - return m_CompatFileNames; - } } } diff --git a/TwitchChatVotingProxy/TwitchChatVotingProxy.cs b/TwitchChatVotingProxy/TwitchChatVotingProxy.cs index a7fa37a35..87a503e69 100644 --- a/TwitchChatVotingProxy/TwitchChatVotingProxy.cs +++ b/TwitchChatVotingProxy/TwitchChatVotingProxy.cs @@ -32,22 +32,22 @@ private static async Task Main(string[] args) m_Logger.Information("Starting chaos mod twitch proxy"); m_Logger.Information("==============================="); - var config = new OptionsFile("chaosmod/configs/voting.ini", "chaosmod/configs/twitch.ini", "chaosmod/twitch.ini"); + var config = new OptionsFile("chaosmod/configs/voting.json", "chaosmod/configs/voting.ini", "chaosmod/configs/twitch.ini", "chaosmod/twitch.ini"); config.ReadFile(); var mutex = new Mutex(false, "ChaosModVVotingMutex"); mutex.WaitOne(); - var votingMode = (EVotingMode)config.ReadValueInt("VotingChanceSystem", 0, "TwitchVotingChanceSystem"); - var overlayMode = (EOverlayMode)config.ReadValueInt("VotingOverlayMode", 0, "TwitchVotingOverlayMode"); - var retainInitialVotes = config.ReadValueBool("VotingChanceSystemRetainChance", false, "TwitchVotingChanceSystemRetainChance"); + var votingMode = (EVotingMode)config.ReadValue("VotingChanceSystem", 0, "TwitchVotingChanceSystem"); + var overlayMode = (EOverlayMode)config.ReadValue("VotingOverlayMode", 0, "TwitchVotingOverlayMode"); + var retainInitialVotes = config.ReadValue("VotingChanceSystemRetainChance", false, "TwitchVotingChanceSystemRetainChance"); // Check if OBS overlay should be shown OverlayServer.OverlayServer? overlayServer = null; if (overlayMode == EOverlayMode.OVERLAY_OBS) { // Create component - var overlayServerPort = config.ReadValueInt("OverlayServerPort", 9091); + var overlayServerPort = config.ReadValue("OverlayServerPort", 9091); var overlayServerConfig = new OverlayServerConfig(votingMode, retainInitialVotes, overlayServerPort); overlayServer = new OverlayServer.OverlayServer(overlayServerConfig); } @@ -56,9 +56,9 @@ private static async Task Main(string[] args) var chaosPipe = new ChaosPipeClient(); var votingReceivers = new List<(string Name, IVotingReceiver VotingReceiver)>(); - if (config.ReadValueBool("EnableVotingTwitch", false)) + if (config.ReadValue("EnableVotingTwitch", false)) votingReceivers.Add(("Twitch", new TwitchVotingReceiver(config, chaosPipe))); - if (config.ReadValueBool("EnableVotingDiscord", false)) + if (config.ReadValue("EnableVotingDiscord", false)) votingReceivers.Add(("Discord", new DiscordVotingReceiver(config, chaosPipe))); foreach (var votingReceiver in votingReceivers) diff --git a/TwitchChatVotingProxy/VotingReceiver/DiscordVotingReceiver.cs b/TwitchChatVotingProxy/VotingReceiver/DiscordVotingReceiver.cs index a1d658e66..07898d04c 100644 --- a/TwitchChatVotingProxy/VotingReceiver/DiscordVotingReceiver.cs +++ b/TwitchChatVotingProxy/VotingReceiver/DiscordVotingReceiver.cs @@ -26,9 +26,9 @@ class DiscordVotingReceiver : IVotingReceiver public DiscordVotingReceiver(OptionsFile config, ChaosPipeClient chaosPipe) { - m_BotToken = config.ReadValue("DiscordBotToken"); - m_GuildId = (ulong)config.ReadValueLong("DiscordGuildId", 0); - m_ChannelId = (ulong)config.ReadValueLong("DiscordChannelId", 0); + m_BotToken = config.ReadValue("DiscordBotToken"); + m_GuildId = config.ReadValue("DiscordGuildId", 0); + m_ChannelId = config.ReadValue("DiscordChannelId", 0); m_ChaosPipe = chaosPipe; } diff --git a/TwitchChatVotingProxy/VotingReceiver/TwitchVotingReceiver.cs b/TwitchChatVotingProxy/VotingReceiver/TwitchVotingReceiver.cs index 37af5479d..45621da2c 100644 --- a/TwitchChatVotingProxy/VotingReceiver/TwitchVotingReceiver.cs +++ b/TwitchChatVotingProxy/VotingReceiver/TwitchVotingReceiver.cs @@ -30,9 +30,9 @@ class TwitchVotingReceiver : IVotingReceiver public TwitchVotingReceiver(OptionsFile config, ChaosPipeClient chaosPipe) { - m_ChannelName = config.ReadValue("TwitchChannelName"); - m_OAuth = config.ReadValue("TwitchChannelOAuth"); - m_UserName = config.ReadValue("TwitchUserName"); + m_ChannelName = config.ReadValue("TwitchChannelName"); + m_OAuth = config.ReadValue("TwitchChannelOAuth"); + m_UserName = config.ReadValue("TwitchUserName"); m_ChaosPipe = chaosPipe; }