9 #include <core/Assertions.h>
10 #include <core/Logger.h>
11 #include <loader/settings/JSONSettingsLoader.h>
13 CHIRA_GET_LOG(CONENTRY);
19 CON_FLAG_CHEAT = 1 << 0,
20 CON_FLAG_HIDDEN = 1 << 1,
21 CON_FLAG_CACHE = 1 << 2,
22 CON_FLAG_READONLY = 1 << 3,
23 CON_FLAG_DEVONLY = 1 << 4,
28 ConEntry(std::string name_, std::string description_,
int flags_ = CON_FLAG_NONE);
30 [[nodiscard]] std::string_view getName()
const;
31 [[nodiscard]] std::string_view getDescription()
const;
32 [[nodiscard]]
bool hasFlag(ConFlags flag)
const;
35 std::string description;
41 using CallbackArgs =
const std::vector<std::string>&;
43 ConCommand(std::string name_,
const std::function<
void()>& callback_,
int flags_ = CON_FLAG_NONE);
44 ConCommand(std::string name_, std::function<
void(CallbackArgs)> callback_,
int flags_ = CON_FLAG_NONE);
45 ConCommand(std::string name_, std::string description_,
const std::function<
void()>& callback_,
int flags_ = CON_FLAG_NONE);
46 ConCommand(std::string name_, std::string description_, std::function<
void(CallbackArgs)> callback_,
int flags_ = CON_FLAG_NONE);
49 void fire(CallbackArgs args);
50 [[nodiscard]]
explicit inline operator std::string()
const {
51 return std::string{this->getName()} +
" - " + this->getDescription().data();
54 std::function<void(CallbackArgs)> callback;
66 [[nodiscard]]
static bool hasConCommand(std::string_view name);
67 [[nodiscard]]
static ConCommand* getConCommand(std::string_view name);
68 [[nodiscard]]
static std::vector<std::string> getConCommandList();
70 [[nodiscard]]
static bool hasConVar(std::string_view name);
71 [[nodiscard]]
static ConVar* getConVar(std::string_view name);
72 [[nodiscard]]
static std::vector<std::string> getConVarList();
74 static std::vector<ConCommand*>& getConCommands();
75 static bool registerConCommand(
ConCommand* concommand);
76 static void deregisterConCommand(
ConCommand* concommand);
78 static std::vector<ConVar*>& getConVars();
80 static bool registerConVar(
ConVar* convar);
81 static void deregisterConVar(
ConVar* convar);
86 concept ConVarValidType = std::same_as<bool, T> ||
87 std::same_as<int, T> ||
88 std::same_as<double, T> ||
89 std::same_as<std::string, T>;
92 enum class ConVarType {
101 using CallbackArg = std::string_view;
103 ConVar(std::string name_, ConVarValidType
auto defaultValue,
int flags_ = CON_FLAG_NONE, std::function<
void(CallbackArg)> onChanged = [](CallbackArg) {})
104 :
ConEntry(std::move(name_),
"No description provided.", flags_)
105 , changedCallback(std::move(onChanged)) {
106 if constexpr (std::is_same_v<decltype(defaultValue), std::string>) {
107 this->value = std::move(defaultValue);
108 this->type = ConVarType::STRING;
110 this->value = std::to_string(defaultValue);
111 if constexpr (std::is_same_v<decltype(defaultValue),
bool>) {
112 this->type = ConVarType::BOOLEAN;
113 }
else if constexpr (std::is_same_v<decltype(defaultValue),
int>) {
114 this->type = ConVarType::INTEGER;
116 this->type = ConVarType::DOUBLE;
119 runtime_assert(ConEntryRegistry::registerConVar(
this),
"This ConVar already exists!");
122 ConVar(std::string name_, ConVarValidType
auto defaultValue, std::string description_,
int flags_ = CON_FLAG_NONE, std::function<
void(CallbackArg)> onChanged = [](CallbackArg) {})
123 :
ConEntry(std::move(name_), std::move(description_), flags_)
124 , changedCallback(std::move(onChanged)) {
125 if constexpr (std::is_same_v<decltype(defaultValue), std::string>) {
126 this->value = std::move(defaultValue);
127 this->type = ConVarType::STRING;
129 this->value = std::to_string(defaultValue);
130 if constexpr (std::is_same_v<decltype(defaultValue),
bool>) {
131 this->type = ConVarType::BOOLEAN;
132 }
else if constexpr (std::is_same_v<decltype(defaultValue),
int>) {
133 this->type = ConVarType::INTEGER;
135 this->type = ConVarType::DOUBLE;
138 runtime_assert(ConEntryRegistry::registerConVar(
this),
"This ConVar already exists!");
142 [[nodiscard]] ConVarType getType()
const;
143 [[nodiscard]] std::string_view getTypeAsString()
const;
145 template<ConVarVal
idType T>
146 [[nodiscard]]
inline T getValue()
const {
147 if constexpr (std::is_same_v<T, std::string>) {
150 if (this->type == ConVarType::STRING) {
151 return static_cast<T
>(this->value.size());
152 }
else if (this->type == ConVarType::DOUBLE) {
153 return static_cast<T
>(std::stod(this->value));
155 return static_cast<T
>(std::stoi(this->value));
160 void setValue(ConVarValidType
auto newValue,
bool runCallback =
true) {
162 LOG_CONENTRY.error(
"Cannot set value of cheat-protected ConVar with cheats disabled.");
166 if constexpr (std::is_same_v<decltype(newValue), std::string>) {
167 switch (this->type) {
168 using enum ConVarType;
170 if (newValue ==
"true") {
173 }
else if (newValue ==
"false") {
179 this->value = std::to_string(std::stoi(newValue));
180 }
catch (
const std::invalid_argument&) {
181 this->value = std::to_string(newValue.size());
186 this->value = std::to_string(std::stod(newValue));
187 }
catch (
const std::invalid_argument&) {
188 this->value = std::to_string(
static_cast<double>(newValue.size()));
192 this->value = newValue;
196 switch (this->type) {
197 using enum ConVarType;
199 this->value = std::to_string(
static_cast<bool>(newValue));
202 this->value = std::to_string(
static_cast<int>(newValue));
205 this->value = std::to_string(
static_cast<double>(newValue));
208 this->value = std::to_string(newValue);
215 this->changedCallback(this->value);
216 }
catch (
const std::exception& e) {
217 LOG_CONENTRY.error(
"Encountered error executing ConVar callback: {}", e.what());
222 [[nodiscard]]
explicit inline operator std::string()
const {
223 return std::string{this->getName()} +
": " + this->getTypeAsString().data() +
" - " + this->getDescription().data();
229 std::function<void(CallbackArg)> changedCallback;
237 this->command = ConEntryRegistry::getConCommand(name);
238 if (!this->command) {
239 LOG_CONENTRY.error(
"ConCommandRef named \"{}\" refers to a nonexistent ConVar!", name);
242 [[nodiscard]]
inline std::string_view getName()
const {
return this->command->getName(); }
243 [[nodiscard]]
inline std::string_view getDescription()
const {
return this->command->getDescription(); }
244 [[nodiscard]]
inline bool hasFlag(ConFlags flag)
const {
return this->command->hasFlag(flag); }
245 inline void fire(ConCommand::CallbackArgs args) {
return this->command->fire(args); }
246 [[nodiscard]]
explicit inline operator std::string()
const {
return this->command->operator std::string(); }
248 [[nodiscard]]
explicit inline operator bool()
const {
return this->command; }
255 explicit ConVarRef(std::string_view name) {
256 this->var = ConEntryRegistry::getConVar(name);
258 LOG_CONENTRY.error(
"ConVarRef named \"{}\" refers to a nonexistent ConVar!", name);
261 [[nodiscard]]
inline std::string_view getName()
const {
return this->var->getName(); }
262 [[nodiscard]]
inline std::string_view getDescription()
const {
return this->var->getDescription(); }
263 [[nodiscard]]
inline bool hasFlag(ConFlags flag)
const {
return this->var->hasFlag(flag); }
264 [[nodiscard]]
inline ConVarType getType()
const {
return this->var->getType(); }
265 [[nodiscard]]
inline std::string_view getTypeAsString()
const {
return this->var->getTypeAsString(); }
266 template<ConVarVal
idType T> [[nodiscard]]
inline T getValue()
const {
return this->var->getValue<T>(); }
267 inline void setValue(ConVarValidType
auto value,
bool runCallback =
true)
const {
return this->var->setValue(value, runCallback); }
268 [[nodiscard]]
explicit inline operator std::string()
const {
return this->var->operator std::string(); }
270 [[nodiscard]]
explicit inline operator bool()
const {
return this->var; }
static bool areCheatsEnabled()
Convenience function to check the value of sv_cheats.