integrate mods system w/ fs_game + cleanup
doing `+set fs_game "mods/deathrun` or `-mod "mods/deathrun"` will result in the same effect. `-mod` is mainly for singleplayer usage but also works in multiplayer.
This commit is contained in:
parent
4083e5a5d0
commit
d1ff8a8f9c
@ -4,11 +4,12 @@
|
|||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "dvars.hpp"
|
#include "dvars.hpp"
|
||||||
#include "game_console.hpp"
|
|
||||||
#include "fastfiles.hpp"
|
#include "fastfiles.hpp"
|
||||||
#include "filesystem.hpp"
|
#include "filesystem.hpp"
|
||||||
#include "scheduler.hpp"
|
#include "game_console.hpp"
|
||||||
#include "logfile.hpp"
|
#include "logfile.hpp"
|
||||||
|
#include "mods.hpp"
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
#include "game/dvars.hpp"
|
#include "game/dvars.hpp"
|
||||||
@ -28,8 +29,6 @@ namespace command
|
|||||||
std::unordered_map<std::string, std::function<void(params&)>> handlers;
|
std::unordered_map<std::string, std::function<void(params&)>> handlers;
|
||||||
std::unordered_map<std::string, std::function<void(int, params_sv&)>> handlers_sv;
|
std::unordered_map<std::string, std::function<void(int, params_sv&)>> handlers_sv;
|
||||||
|
|
||||||
std::optional<std::string> saved_fs_game;
|
|
||||||
|
|
||||||
void main_handler()
|
void main_handler()
|
||||||
{
|
{
|
||||||
params params = {};
|
params params = {};
|
||||||
@ -557,43 +556,11 @@ namespace command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_fs_game_path()
|
|
||||||
{
|
|
||||||
const auto* fs_game = game::Dvar_FindVar("fs_game");
|
|
||||||
const auto new_mod_path = fs_game->current.string;
|
|
||||||
|
|
||||||
// check if the last saved fs_game value isn't empty and if it doesn't equal the new fs_game
|
|
||||||
if (saved_fs_game.has_value() && saved_fs_game != new_mod_path)
|
|
||||||
{
|
|
||||||
// unregister path to be used as a fs directory
|
|
||||||
filesystem::unregister_path(saved_fs_game.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_mod_path && !new_mod_path[0])
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// register fs_game value as a fs directory used for many things
|
|
||||||
filesystem::register_path(new_mod_path);
|
|
||||||
saved_fs_game = new_mod_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
// it might be overdone to change the filesystem path on every new value change, but to be fair,
|
|
||||||
// for the mods that don't need full restarts, this is good because it'll adjust and work like so
|
|
||||||
// in my opinion, this is fine. if a user tries to modify the dvar themselves, they'll have problems
|
|
||||||
// but i seriously doubt it'll be bad.
|
|
||||||
dvars::callback::on_new_value("fs_game", []()
|
|
||||||
{
|
|
||||||
console::warn("fs_game value changed, filesystem paths will be adjusted to new dvar value.");
|
|
||||||
register_fs_game_path();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (game::environment::is_sp())
|
if (game::environment::is_sp())
|
||||||
{
|
{
|
||||||
add_commands_sp();
|
add_commands_sp();
|
||||||
|
@ -49,6 +49,4 @@ namespace command
|
|||||||
void add_sv(const char* name, std::function<void(int, const params_sv&)> callback);
|
void add_sv(const char* name, std::function<void(int, const params_sv&)> callback);
|
||||||
|
|
||||||
void execute(std::string command, bool sync = false);
|
void execute(std::string command, bool sync = false);
|
||||||
|
|
||||||
void register_fs_game_path();
|
|
||||||
}
|
}
|
@ -255,13 +255,13 @@ namespace dvars
|
|||||||
|
|
||||||
namespace callback
|
namespace callback
|
||||||
{
|
{
|
||||||
static std::unordered_map<int, std::function<void()>> new_value_callbacks;
|
static std::unordered_map<int, std::function<void(game::dvar_value*)>> dvar_new_value_callbacks;
|
||||||
|
|
||||||
static std::unordered_map<int, std::function<void()>> dvar_on_register_function_map;
|
static std::unordered_map<int, std::function<void()>> dvar_on_register_function_map;
|
||||||
|
|
||||||
void on_new_value(const std::string& name, const std::function<void()> callback)
|
void on_new_value(const std::string& name, const std::function<void(game::dvar_value*)> callback)
|
||||||
{
|
{
|
||||||
new_value_callbacks[game::generateHashValue(name.data())] = callback;
|
dvar_new_value_callbacks[game::generateHashValue(name.data())] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_register(const std::string& name, const std::function<void()>& callback)
|
void on_register(const std::string& name, const std::function<void()>& callback)
|
||||||
@ -532,9 +532,9 @@ namespace dvars
|
|||||||
{
|
{
|
||||||
dvar_set_variant_hook.invoke<void>(dvar, value, source);
|
dvar_set_variant_hook.invoke<void>(dvar, value, source);
|
||||||
|
|
||||||
if (callback::new_value_callbacks.find(dvar->hash) != callback::new_value_callbacks.end())
|
if (callback::dvar_new_value_callbacks.contains(dvar->hash))
|
||||||
{
|
{
|
||||||
callback::new_value_callbacks[dvar->hash]();
|
callback::dvar_new_value_callbacks[dvar->hash](value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
namespace dvars
|
namespace dvars
|
||||||
{
|
{
|
||||||
namespace disable
|
namespace disable
|
||||||
@ -29,7 +31,7 @@ namespace dvars
|
|||||||
|
|
||||||
namespace callback
|
namespace callback
|
||||||
{
|
{
|
||||||
void on_new_value(const std::string& name, const std::function<void()> callback);
|
void on_new_value(const std::string& name, const std::function<void(game::dvar_value* value)> callback);
|
||||||
|
|
||||||
void on_register(const std::string& name, const std::function<void()>& callback);
|
void on_register(const std::string& name, const std::function<void()>& callback);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "filesystem.hpp"
|
#include "filesystem.hpp"
|
||||||
#include "localized_strings.hpp"
|
#include "localized_strings.hpp"
|
||||||
|
#include "mods.hpp"
|
||||||
#include "updater.hpp"
|
#include "updater.hpp"
|
||||||
|
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
@ -39,11 +40,10 @@ namespace filesystem
|
|||||||
|
|
||||||
void fs_startup_stub(const char* name)
|
void fs_startup_stub(const char* name)
|
||||||
{
|
{
|
||||||
console::debug("[FS] Startup\n");
|
console::info("[FS] Startup\n");
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
// hardcoded paths
|
|
||||||
filesystem::register_path(utils::properties::get_appdata_path() / CLIENT_DATA_FOLDER);
|
filesystem::register_path(utils::properties::get_appdata_path() / CLIENT_DATA_FOLDER);
|
||||||
filesystem::register_path(L".");
|
filesystem::register_path(L".");
|
||||||
filesystem::register_path(L"h1-mod");
|
filesystem::register_path(L"h1-mod");
|
||||||
@ -53,9 +53,13 @@ namespace filesystem
|
|||||||
filesystem::register_path(L"raw");
|
filesystem::register_path(L"raw");
|
||||||
filesystem::register_path(L"main");
|
filesystem::register_path(L"main");
|
||||||
|
|
||||||
fs_startup_hook.invoke<void>(name);
|
const auto mod_path = utils::flags::get_flag("mod");
|
||||||
|
if (mod_path.has_value())
|
||||||
|
{
|
||||||
|
mods::set_mod(mod_path.value());
|
||||||
|
}
|
||||||
|
|
||||||
command::register_fs_game_path();
|
fs_startup_hook.invoke<void>(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::filesystem::path> get_paths(const std::filesystem::path& path)
|
std::vector<std::filesystem::path> get_paths(const std::filesystem::path& path)
|
||||||
@ -175,7 +179,7 @@ namespace filesystem
|
|||||||
{
|
{
|
||||||
if (can_insert_path(path_))
|
if (can_insert_path(path_))
|
||||||
{
|
{
|
||||||
console::debug("[FS] Registering path '%s'\n", path_.generic_string().data());
|
console::info("[FS] Registering path '%s'\n", path_.generic_string().data());
|
||||||
get_search_paths_internal().push_front(path_);
|
get_search_paths_internal().push_front(path_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ namespace gsc
|
|||||||
free_script_memory();
|
free_script_memory();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read_script_file(const std::string& name, std::string* data)
|
bool read_scriptfile(const std::string& name, std::string* data)
|
||||||
{
|
{
|
||||||
if (filesystem::read_file(name, data))
|
if (filesystem::read_file(name, data))
|
||||||
{
|
{
|
||||||
@ -91,7 +91,6 @@ namespace gsc
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto name_str = name.data();
|
const auto name_str = name.data();
|
||||||
|
|
||||||
if (game::DB_XAssetExists(game::ASSET_TYPE_RAWFILE, name_str) &&
|
if (game::DB_XAssetExists(game::ASSET_TYPE_RAWFILE, name_str) &&
|
||||||
!game::DB_IsXAssetDefault(game::ASSET_TYPE_RAWFILE, name_str))
|
!game::DB_IsXAssetDefault(game::ASSET_TYPE_RAWFILE, name_str))
|
||||||
{
|
{
|
||||||
@ -117,13 +116,13 @@ namespace gsc
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto itr = loaded_scripts.find(real_name); itr != loaded_scripts.end())
|
if (loaded_scripts.contains(real_name))
|
||||||
{
|
{
|
||||||
return itr->second;
|
return loaded_scripts[real_name];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string source_buffer;
|
std::string source_buffer;
|
||||||
if (!read_script_file(real_name + ".gsc", &source_buffer) || source_buffer.empty())
|
if (!read_scriptfile(real_name + ".gsc", &source_buffer) || source_buffer.empty())
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -139,8 +138,7 @@ namespace gsc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::uint8_t> data;
|
auto data = std::vector<std::uint8_t>{source_buffer.begin(), source_buffer.end()};
|
||||||
data.assign(source_buffer.begin(), source_buffer.end());
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -201,10 +199,10 @@ namespace gsc
|
|||||||
return std::to_string(id);
|
return std::to_string(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::uint8_t> decompile_script_file(const std::string& name, const std::string& real_name)
|
std::vector<std::uint8_t> decompile_scriptfile(const std::string& name, const std::string& real_name)
|
||||||
{
|
{
|
||||||
const auto* script_file = game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, name.data(), false).scriptfile;
|
const auto* script_file = game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, name.data(), false).scriptfile;
|
||||||
if (!script_file)
|
if (script_file == nullptr)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(std::format("Could not load scriptfile '{}'", real_name));
|
throw std::runtime_error(std::format("Could not load scriptfile '{}'", real_name));
|
||||||
}
|
}
|
||||||
@ -385,12 +383,12 @@ namespace gsc
|
|||||||
const auto real_name = include_name + ".gsc";
|
const auto real_name = include_name + ".gsc";
|
||||||
|
|
||||||
std::string file_buffer;
|
std::string file_buffer;
|
||||||
if (!read_script_file(real_name, &file_buffer) || file_buffer.empty())
|
if (!read_scriptfile(real_name, &file_buffer) || file_buffer.empty())
|
||||||
{
|
{
|
||||||
const auto name = get_script_file_name(include_name);
|
const auto name = get_script_file_name(include_name);
|
||||||
if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, name.data()))
|
if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, name.data()))
|
||||||
{
|
{
|
||||||
return decompile_script_file(name, real_name);
|
return decompile_scriptfile(name, real_name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
|
#include "dvars.hpp"
|
||||||
#include "filesystem.hpp"
|
#include "filesystem.hpp"
|
||||||
#include "fonts.hpp"
|
#include "fonts.hpp"
|
||||||
#include "localized_strings.hpp"
|
#include "localized_strings.hpp"
|
||||||
@ -53,7 +54,6 @@ namespace mods
|
|||||||
{
|
{
|
||||||
if (game::environment::is_mp())
|
if (game::environment::is_mp())
|
||||||
{
|
{
|
||||||
// vid_restart works on multiplayer, but not on singleplayer
|
|
||||||
command::execute("vid_restart");
|
command::execute("vid_restart");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -69,32 +69,37 @@ namespace mods
|
|||||||
return utils::io::file_exists(path + "/mod.ff") || utils::io::file_exists(path + "/zone/mod.ff");
|
return utils::io::file_exists(path + "/mod.ff") || utils::io::file_exists(path + "/zone/mod.ff");
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_filesystem_data(const std::string& path)
|
void set_filesystem_data(const std::string& path, bool change_fs_game)
|
||||||
{
|
{
|
||||||
if (mod_path.has_value())
|
if (mod_path.has_value())
|
||||||
{
|
{
|
||||||
filesystem::unregister_path(mod_path.value());
|
filesystem::unregister_path(mod_path.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!game::environment::is_sp())
|
if (change_fs_game)
|
||||||
{
|
{
|
||||||
// modify fs_game on mp/dedi because its not set when we obviously vid_restart (sp does a full relaunch with command line arguments)
|
game::Dvar_SetFromStringByNameFromSource("fs_game", path.data(), game::DVAR_SOURCE_INTERNAL);
|
||||||
game::Dvar_SetFromStringByNameFromSource("fs_game", path.data(),
|
}
|
||||||
game::DVAR_SOURCE_INTERNAL);
|
|
||||||
|
if (path != "")
|
||||||
|
{
|
||||||
|
filesystem::register_path(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_mod(const std::string& path)
|
void set_mod(const std::string& path, bool change_fs_game)
|
||||||
{
|
{
|
||||||
set_filesystem_data(path);
|
set_filesystem_data(path, change_fs_game);
|
||||||
mod_path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_mod()
|
if (path != "")
|
||||||
{
|
{
|
||||||
set_filesystem_data("");
|
mod_path = path;
|
||||||
mod_path.reset();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mod_path.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> get_mod()
|
std::optional<std::string> get_mod()
|
||||||
@ -114,6 +119,12 @@ namespace mods
|
|||||||
|
|
||||||
db_release_xassets_hook.create(SELECT_VALUE(0x1F4DB0_b, 0x399740_b), db_release_xassets_stub);
|
db_release_xassets_hook.create(SELECT_VALUE(0x1F4DB0_b, 0x399740_b), db_release_xassets_stub);
|
||||||
|
|
||||||
|
dvars::callback::on_new_value("fs_game", [](game::dvar_value* value)
|
||||||
|
{
|
||||||
|
console::warn("fs_game value changed to '%s'\n", value->string);
|
||||||
|
set_mod(value->string, false);
|
||||||
|
});
|
||||||
|
|
||||||
command::add("loadmod", [](const command::params& params)
|
command::add("loadmod", [](const command::params& params)
|
||||||
{
|
{
|
||||||
if (params.size() < 2)
|
if (params.size() < 2)
|
||||||
@ -143,7 +154,7 @@ namespace mods
|
|||||||
mod_requires_restart(path))
|
mod_requires_restart(path))
|
||||||
{
|
{
|
||||||
console::info("Restarting...\n");
|
console::info("Restarting...\n");
|
||||||
full_restart("+set fs_game \""s + path + "\"");
|
full_restart("-mod \""s + path + "\"");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -171,12 +182,12 @@ namespace mods
|
|||||||
if (mod_requires_restart(mod_path.value()))
|
if (mod_requires_restart(mod_path.value()))
|
||||||
{
|
{
|
||||||
console::info("Restarting...\n");
|
console::info("Restarting...\n");
|
||||||
clear_mod();
|
set_mod("");
|
||||||
full_restart("");
|
full_restart("");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
clear_mod();
|
set_mod("");
|
||||||
restart();
|
restart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace mods
|
namespace mods
|
||||||
{
|
{
|
||||||
void set_mod(const std::string& path);
|
void set_mod(const std::string& path, bool change_fs_game = true);
|
||||||
void clear_mod();
|
|
||||||
std::optional<std::string> get_mod();
|
std::optional<std::string> get_mod();
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ namespace party
|
|||||||
|
|
||||||
if (server_fs_game.empty() && !client_fs_game.empty())
|
if (server_fs_game.empty() && !client_fs_game.empty())
|
||||||
{
|
{
|
||||||
mods::clear_mod();
|
mods::set_mod("");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ namespace ui_scripting
|
|||||||
|
|
||||||
game_type["virtuallobbypresentable"] = [](const game&)
|
game_type["virtuallobbypresentable"] = [](const game&)
|
||||||
{
|
{
|
||||||
::game::Dvar_SetFromStringByNameFromSource("virtualLobbyPresentable", "1", ::game::DvarSetSource::DVAR_SOURCE_INTERNAL);
|
::game::Dvar_SetFromStringByNameFromSource("virtualLobbyPresentable", "1", ::game::DVAR_SOURCE_INTERNAL);
|
||||||
};
|
};
|
||||||
|
|
||||||
game_type["getcurrentgamelanguage"] = [](const game&)
|
game_type["getcurrentgamelanguage"] = [](const game&)
|
||||||
|
@ -6,42 +6,110 @@
|
|||||||
|
|
||||||
namespace utils::flags
|
namespace utils::flags
|
||||||
{
|
{
|
||||||
void parse_flags(std::vector<std::string>& flags)
|
namespace
|
||||||
{
|
{
|
||||||
int num_args;
|
bool parsed = false;
|
||||||
auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
|
|
||||||
|
|
||||||
flags.clear();
|
using flag_map_t = std::unordered_map<std::string, std::optional<std::string>>;
|
||||||
|
|
||||||
if (argv)
|
flag_map_t& get_flags()
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < num_args; ++i)
|
static flag_map_t map = {};
|
||||||
{
|
return map;
|
||||||
std::wstring wide_flag(argv[i]);
|
}
|
||||||
if (wide_flag[0] == L'-')
|
|
||||||
{
|
|
||||||
wide_flag.erase(wide_flag.begin());
|
|
||||||
const auto flag = string::convert(wide_flag);
|
|
||||||
flags.emplace_back(string::to_lower(flag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalFree(argv);
|
void parse_flags(flag_map_t& flags)
|
||||||
|
{
|
||||||
|
int num_args;
|
||||||
|
auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
|
||||||
|
|
||||||
|
flags.clear();
|
||||||
|
|
||||||
|
if (argv)
|
||||||
|
{
|
||||||
|
std::optional<std::string> last_flag{};
|
||||||
|
for (auto i = 0; i < num_args; ++i)
|
||||||
|
{
|
||||||
|
std::wstring wide_flag(argv[i]);
|
||||||
|
if (wide_flag[0] == L'-')
|
||||||
|
{
|
||||||
|
wide_flag.erase(wide_flag.begin());
|
||||||
|
const auto flag = string::convert(wide_flag);
|
||||||
|
|
||||||
|
last_flag = flag;
|
||||||
|
flags[flag] = {};
|
||||||
|
}
|
||||||
|
else if (last_flag.has_value())
|
||||||
|
{
|
||||||
|
const auto& flag = last_flag.value();
|
||||||
|
|
||||||
|
flags[flag] = string::convert(wide_flag);
|
||||||
|
last_flag = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFree(argv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_parse_flags()
|
||||||
|
{
|
||||||
|
if (!parsed)
|
||||||
|
{
|
||||||
|
parse_flags(get_flags());
|
||||||
|
parsed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_flag(const std::string& flag)
|
bool has_flag(const std::string& flag)
|
||||||
{
|
{
|
||||||
static auto parsed = false;
|
check_parse_flags();
|
||||||
static std::vector<std::string> enabled_flags;
|
|
||||||
|
|
||||||
if (!parsed)
|
for (const auto& [name, value] : get_flags())
|
||||||
{
|
{
|
||||||
parse_flags(enabled_flags);
|
if (string::to_lower(name) == string::to_lower(flag))
|
||||||
parsed = true;
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::ranges::any_of(enabled_flags.cbegin(), enabled_flags.cend(),
|
return false;
|
||||||
[flag](const auto& elem) { return elem == string::to_lower(flag); });
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> get_flag(const std::string& flag)
|
||||||
|
{
|
||||||
|
check_parse_flags();
|
||||||
|
|
||||||
|
for (const auto& [name, value] : get_flags())
|
||||||
|
{
|
||||||
|
if (string::to_lower(name) == string::to_lower(flag))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> get_flag(const std::string& flag, const std::string& shortname)
|
||||||
|
{
|
||||||
|
auto value = get_flag(flag);
|
||||||
|
if (!value.has_value())
|
||||||
|
{
|
||||||
|
value = get_flag(shortname);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_flag(const std::string& flag, const std::string& shortname,
|
||||||
|
const std::string& default_)
|
||||||
|
{
|
||||||
|
const auto value = get_flag(flag, shortname);
|
||||||
|
if (!value.has_value())
|
||||||
|
{
|
||||||
|
return default_;
|
||||||
|
}
|
||||||
|
return value.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace utils::flags
|
namespace utils::flags
|
||||||
{
|
{
|
||||||
bool has_flag(const std::string& flag);
|
bool has_flag(const std::string& flag);
|
||||||
|
std::optional<std::string> get_flag(const std::string& flag);
|
||||||
|
std::optional<std::string> get_flag(const std::string& flag, const std::string& shortname);
|
||||||
|
std::string get_flag(const std::string& flag, const std::string& shortname,
|
||||||
|
const std::string& default_);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user