Fixes + validate h2 mod config

This commit is contained in:
fed 2023-02-22 04:36:28 +01:00
parent 806c206fe8
commit 818f35cfeb
5 changed files with 127 additions and 36 deletions

View File

@ -3,6 +3,7 @@
#include "config.hpp" #include "config.hpp"
#include "console.hpp" #include "console.hpp"
#include "language.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
@ -11,6 +12,55 @@
namespace config namespace config
{ {
namespace
{
using validate_type_callback_t = std::function<bool(const field_value&)>;
using validate_callback_t = std::function<bool(const field_value&)>;
struct field_definition_t
{
field_type type;
field_value default_value;
std::optional<validate_callback_t> validate_value = {};
};
template <typename... Args>
std::pair<std::string, field_definition_t> define_field(const std::string& name, Args&&... args)
{
return std::make_pair(name, field_definition_t{std::forward<Args>(args)...});
}
std::unordered_map<std::string, field_definition_t> field_definitions =
{
{define_field("language", config::field_type::string, language::get_default_language(), language::is_valid_language)},
};
}
nlohmann::json validate_config_field(const std::string& key, const nlohmann::json& value)
{
const auto iter = field_definitions.find(key);
if (iter == field_definitions.end())
{
return value;
}
if (value.type() != iter->second.type)
{
return iter->second.default_value;
}
if (iter->second.validate_value.has_value())
{
const auto& validate_value = iter->second.validate_value.value();
if (!validate_value(value))
{
iter->second.default_value;
}
}
return value;
}
void write_config(const nlohmann::json& json) void write_config(const nlohmann::json& json)
{ {
try try

View File

@ -2,9 +2,14 @@
namespace config namespace config
{ {
typedef nlohmann::json::value_t field_type;
typedef nlohmann::json field_value;
nlohmann::json read_config(); nlohmann::json read_config();
void write_config(const nlohmann::json& json); void write_config(const nlohmann::json& json);
nlohmann::json validate_config_field(const std::string& key, const field_value& value);
template <typename T> template <typename T>
std::optional<T> get(const std::string& key) std::optional<T> get(const std::string& key)
{ {
@ -14,14 +19,15 @@ namespace config
return {}; return {};
} }
return {cfg[key].get<T>()}; const auto value = validate_config_field(key, cfg[key]);
return {value.get<T>()};
} }
template <typename T> template <typename T>
void set(const std::string& key, const T& value) void set(const std::string& key, const T& value)
{ {
auto cfg = read_config(); auto cfg = read_config();
cfg[key] = value; cfg[key] = validate_config_field(key, value);
write_config(cfg); write_config(cfg);
} }
} }

View File

@ -7,6 +7,7 @@
#include "filesystem.hpp" #include "filesystem.hpp"
#include "console.hpp" #include "console.hpp"
#include "command.hpp" #include "command.hpp"
#include "language.hpp"
#include <utils/io.hpp> #include <utils/io.hpp>
#include <utils/hook.hpp> #include <utils/hook.hpp>
@ -116,25 +117,6 @@ namespace database
return file.ends_with(".ff") || file.ends_with(".pak"); return file.ends_with(".ff") || file.ends_with(".pak");
} }
std::unordered_set<game::language_t> unsuppored_languages =
{
{game::LANGUAGE_CZECH}
};
bool is_unsupported_language(const std::string& name)
{
for (auto i = 0; i < 17; i++)
{
if ((game::languages[i].name == name || game::languages[i].shortname == name) &&
unsuppored_languages.contains(static_cast<game::language_t>(i)))
{
return true;
}
}
return false;
}
bool is_loc_folder(game::Sys_Folder folder) bool is_loc_folder(game::Sys_Folder folder)
{ {
return folder == game::SF_PAKFILE_LOC || folder == game::SF_ZONE_LOC || folder == game::SF_VIDEO_LOC; return folder == game::SF_PAKFILE_LOC || folder == game::SF_ZONE_LOC || folder == game::SF_VIDEO_LOC;
@ -160,7 +142,7 @@ namespace database
{ {
const auto loc = name.substr(0, 3); const auto loc = name.substr(0, 3);
const auto found = find_fastfile(name); const auto found = find_fastfile(name);
if (is_unsupported_language(loc) && !found.has_value()) if (language::is_custom_language(loc) && !found.has_value())
{ {
name = "eng" + name.substr(3); name = "eng" + name.substr(3);
file_ = name; file_ = name;
@ -421,7 +403,7 @@ namespace database
utils::hook::detour sys_set_folder_hook; utils::hook::detour sys_set_folder_hook;
void sys_set_folder_stub(game::Sys_Folder folder, const char* path) void sys_set_folder_stub(game::Sys_Folder folder, const char* path)
{ {
if (is_loc_folder(folder) && is_unsupported_language(path)) if (is_loc_folder(folder) && language::is_custom_language(path))
{ {
path = "english"; path = "english";
} }

View File

@ -8,6 +8,9 @@
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
#include <utils/string.hpp>
#define OLD_LANGUAGE_FILE "players2/default/language"
namespace language namespace language
{ {
@ -27,20 +30,25 @@ namespace language
{game::LANGUAGE_RUSSIAN_PARTIAL}, {game::LANGUAGE_RUSSIAN_PARTIAL},
}; };
std::unordered_set<game::language_t> cyrillic_languages = std::unordered_set<game::language_t> polish_russian_languages =
{ {
game::LANGUAGE_RUSSIAN, {game::LANGUAGE_RUSSIAN},
game::LANGUAGE_POLISH, {game::LANGUAGE_POLISH},
game::LANGUAGE_CZECH, {game::LANGUAGE_CZECH},
game::LANGUAGE_RUSSIAN_PARTIAL, {game::LANGUAGE_RUSSIAN_PARTIAL},
}; };
std::unordered_set<game::language_t> asian_languages = std::unordered_set<game::language_t> asian_languages =
{ {
game::LANGUAGE_JAPANESE_FULL, {game::LANGUAGE_JAPANESE_FULL},
game::LANGUAGE_JAPANESE_PARTIAL, {game::LANGUAGE_JAPANESE_PARTIAL},
game::LANGUAGE_TRADITIONAL_CHINESE, {game::LANGUAGE_TRADITIONAL_CHINESE},
game::LANGUAGE_SIMPLIFIED_CHINESE, {game::LANGUAGE_SIMPLIFIED_CHINESE},
};
std::unordered_set<game::language_t> custom_languages =
{
{game::LANGUAGE_CZECH},
}; };
const char* get_loc_language_string() const char* get_loc_language_string()
@ -58,6 +66,40 @@ namespace language
} }
} }
std::string get_default_language()
{
return "english";
}
bool is_valid_language(const std::string& name)
{
const auto lower = utils::string::to_lower(name);
for (auto i = 0; i < game::LANGUAGE_COUNT; i++)
{
const auto a = game::languages[i].name;
const auto b = game::languages[i].is_supported;
if (game::languages[i].name == lower)
{
return true;
}
}
return false;
}
bool is_custom_language(const std::string& name)
{
for (const auto& language : custom_languages)
{
if (game::languages[language].name == name || game::languages[language].shortname == name)
{
return true;
}
}
return false;
}
game::language_t current() game::language_t current()
{ {
static auto* loc_language = game::Dvar_FindVar("loc_language"); static auto* loc_language = game::Dvar_FindVar("loc_language");
@ -71,7 +113,7 @@ namespace language
bool is_polrus() bool is_polrus()
{ {
return cyrillic_languages.contains(current()); return polish_russian_languages.contains(current());
} }
bool is_arabic() bool is_arabic()
@ -91,7 +133,7 @@ namespace language
void set_from_index(const int index) void set_from_index(const int index)
{ {
if (index < 0 || index > 17) if (index < 0 || index >= game::LANGUAGE_COUNT)
{ {
return; return;
} }
@ -107,9 +149,16 @@ namespace language
{ {
utils::hook::call(0x14060AFFB, get_loc_language_string); utils::hook::call(0x14060AFFB, get_loc_language_string);
for (auto i = 0; i < 17; i++) if (utils::io::file_exists(OLD_LANGUAGE_FILE))
{ {
game::languages[i].is_supported = 1; const auto lang = utils::io::read_file(OLD_LANGUAGE_FILE);
config::set("language", lang);
utils::io::remove_file(OLD_LANGUAGE_FILE);
}
for (const auto& language : custom_languages)
{
game::languages[language].is_supported = 1;
} }
} }
}; };

View File

@ -4,6 +4,10 @@
namespace language namespace language
{ {
std::string get_default_language();
bool is_valid_language(const std::string& name);
bool is_custom_language(const std::string& name);
void set(const std::string& language); void set(const std::string& language);
void set_from_index(const int index); void set_from_index(const int index);