From 7fd54effc94f0c43d9afa343e5842268a19b00db Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sun, 29 Sep 2019 05:44:01 -0700 Subject: [PATCH] Various fixes and improvements to CVars --- hecl/include/hecl/CVar.hpp | 83 +++-- hecl/include/hecl/CVarCommons.hpp | 8 +- hecl/include/hecl/CVarManager.hpp | 36 +- hecl/lib/CVar.cpp | 593 ++++++++++++++++++------------ hecl/lib/CVarManager.cpp | 29 +- hecl/lib/Console.cpp | 4 +- 6 files changed, 462 insertions(+), 291 deletions(-) diff --git a/hecl/include/hecl/CVar.hpp b/hecl/include/hecl/CVar.hpp index f6729c83d..d38b5496a 100644 --- a/hecl/include/hecl/CVar.hpp +++ b/hecl/include/hecl/CVar.hpp @@ -10,10 +10,10 @@ namespace hecl { namespace DNACVAR { -enum class EType : atUint8 { Boolean, Integer, Float, Literal, Vec4f }; +enum class EType : atUint8 { Boolean, Signed, Unsigned, Real, Literal, Vec2f, Vec2d, Vec3f, Vec3d, Vec4f, Vec4d }; -enum EFlags { - None = -1, +enum class EFlags { + None = 0, System = (1 << 0), Game = (1 << 1), Editor = (1 << 2), @@ -24,7 +24,10 @@ enum EFlags { Archive = (1 << 7), InternalArchivable = (1 << 8), Modified = (1 << 9), - ModifyRestart = (1 << 10) /*!< If this bit is set, any modification will inform the user that a restart is required */ + ModifyRestart = (1 << 10), //!< If this bit is set, any modification will inform the user that a restart is required + Color = (1 << 11), //!< If this bit is set, Vec3f and Vec4f will be displayed in the console with a colored square + NoDeveloper = (1 << 12), //!< Not even developer mode can modify this + Any = -1 }; ENABLE_BITWISE_ENUM(EFlags) @@ -55,40 +58,61 @@ public: using EType = DNACVAR::EType; using EFlags = DNACVAR::EFlags; - CVar(std::string_view name, std::string_view value, std::string_view help, EType type, EFlags flags, - CVarManager& parent); - CVar(std::string_view name, std::string_view value, std::string_view help, EFlags flags, CVarManager& parent); - CVar(std::string_view name, float value, std::string_view help, EFlags flags, CVarManager& parent); - CVar(std::string_view name, bool value, std::string_view help, EFlags flags, CVarManager& parent); - CVar(std::string_view name, int value, std::string_view help, EFlags flags, CVarManager& parent); - CVar(std::string_view name, const atVec4f& value, std::string_view help, EFlags flags, CVarManager& parent); + CVar(std::string_view name, std::string_view value, std::string_view help, EFlags flags); + CVar(std::string_view name, const atVec2f& value, std::string_view help, EFlags flags); + CVar(std::string_view name, const atVec2d& value, std::string_view help, EFlags flags); + CVar(std::string_view name, const atVec3f& value, std::string_view help, EFlags flags); + CVar(std::string_view name, const atVec3d& value, std::string_view help, EFlags flags); + CVar(std::string_view name, const atVec4f& value, std::string_view help, EFlags flags); + CVar(std::string_view name, const atVec4d& value, std::string_view help, EFlags flags); + CVar(std::string_view name, double value, std::string_view help, EFlags flags); + CVar(std::string_view name, bool value, std::string_view help, EFlags flags); + CVar(std::string_view name, int32_t value, std::string_view help, EFlags flags); + CVar(std::string_view name, uint32_t value, std::string_view help, EFlags flags); std::string_view name() const { return m_name; } std::string_view rawHelp() const { return m_help; } std::string help() const; std::string value() const { return m_value; } + atVec2f toVec2f(bool* isValid = nullptr) const; + atVec2d toVec2d(bool* isValie = nullptr) const; + atVec3f toVec3f(bool* isValid = nullptr) const; + atVec3d toVec3d(bool* isValie = nullptr) const; atVec4f toVec4f(bool* isValid = nullptr) const; - float toFloat(bool* isValid = nullptr) const; + atVec4d toVec4d(bool* isValie = nullptr) const; + double toReal(bool* isValid = nullptr) const; bool toBoolean(bool* isValid = nullptr) const; - int toInteger(bool* isValid = nullptr) const; + int32_t toSigned(bool* isValid = nullptr) const; + uint32_t toUnsigned(bool* isValid = nullptr) const; std::wstring toWideLiteral(bool* isValid = nullptr) const; std::string toLiteral(bool* isValid = nullptr) const; + bool fromVec2f(const atVec2f& val); + bool fromVec2d(const atVec2d& val); + bool fromVec3f(const atVec3f& val); + bool fromVec3d(const atVec3d& val); bool fromVec4f(const atVec4f& val); - bool fromFloat(float val); + bool fromVec4d(const atVec4d& val); + bool fromReal(double val); bool fromBoolean(bool val); - bool fromInteger(int val); + bool fromInteger(int32_t val); + bool fromInteger(uint32_t val); bool fromLiteral(std::string_view val); bool fromLiteral(std::wstring_view val); - bool fromLiteralToType(std::string_view val, bool setDefault = false); - bool fromLiteralToType(std::wstring_view val, bool setDefault = false); + bool fromLiteralToType(std::string_view val); + bool fromLiteralToType(std::wstring_view val); - bool isFloat() const { return m_type == EType::Float; } - bool isBoolean() const { return m_type == EType::Boolean; } - bool isInteger() const { return m_type == EType::Integer; } - bool isLiteral() const { return m_type == EType::Literal; } + bool isVec2f() const { return m_type == EType::Vec2f; } + bool isVec2d() const { return m_type == EType::Vec2d; } + bool isVec3f() const { return m_type == EType::Vec3f; } + bool isVec3d() const { return m_type == EType::Vec3d; } bool isVec4f() const { return m_type == EType::Vec4f; } + bool isVec4d() const { return m_type == EType::Vec4d; } + bool isFloat() const { return m_type == EType::Real; } + bool isBoolean() const { return m_type == EType::Boolean; } + bool isInteger() const { return m_type == EType::Signed || m_type == EType::Unsigned; } + bool isLiteral() const { return m_type == EType::Literal; } bool isModified() const; bool modificationRequiresRestart() const; bool isReadOnly() const; @@ -96,6 +120,8 @@ public: bool isHidden() const; bool isArchive() const; bool isInternalArchivable() const; + bool isNoDeveloper() const; + bool isColor() const; bool wasDeserialized() const; bool hasDefaultValue() const; void clearModified(); @@ -121,19 +147,22 @@ public: void addListener(ListenerFunc func) { m_listeners.push_back(std::move(func)); } + bool isValidInput(std::string_view input) const; + bool isValidInput(std::wstring_view input) const; + private: + CVar(std::string_view name, std::string_view help, EType type) : m_help(help), m_type(type) { m_name = name; } void dispatch(); - EType m_type; std::string m_help; + EType m_type; std::string m_defaultValue; - EFlags m_flags; - EFlags m_oldFlags; + EFlags m_flags = EFlags::None; + EFlags m_oldFlags = EFlags::None; bool m_unlocked = false; bool m_wasDeserialized = false; - - CVarManager& m_mgr; - std::vector m_listeners; + bool safeToModify(EType type) const; + void init(EFlags flags, bool removeColor=true); }; class CVarUnlocker { diff --git a/hecl/include/hecl/CVarCommons.hpp b/hecl/include/hecl/CVarCommons.hpp index 43087d06b..9ace27e51 100644 --- a/hecl/include/hecl/CVarCommons.hpp +++ b/hecl/include/hecl/CVarCommons.hpp @@ -18,7 +18,7 @@ using namespace std::literals; #elif defined(__APPLE__) #define DEFAULT_GRAPHICS_API "Metal"sv #else -#define DEFAULT_GRAPHICS_API "OpenGL"sv +#define DEFAULT_GRAPHICS_API "Vulkan"sv #endif struct CVarCommons { @@ -47,13 +47,13 @@ struct CVarCommons { void setGraphicsApi(std::string_view api) { m_graphicsApi->fromLiteral(api); } - uint32_t getSamples() const { return std::max(uint32_t(1), uint32_t(m_drawSamples->toInteger())); } + uint32_t getSamples() const { return std::max(1u, m_drawSamples->toUnsigned()); } void setSamples(uint32_t v) { m_drawSamples->fromInteger(std::max(uint32_t(1), v)); } - uint32_t getAnisotropy() const { return std::max(uint32_t(1), uint32_t(m_texAnisotropy->toInteger())); } + uint32_t getAnisotropy() const { return std::max(1u, uint32_t(m_texAnisotropy->toUnsigned())); } - void setAnisotropy(uint32_t v) { m_texAnisotropy->fromInteger(std::max(uint32_t(1), v)); } + void setAnisotropy(uint32_t v) { m_texAnisotropy->fromInteger(std::max(1u, v)); } bool getDeepColor() const { return m_deepColor->toBoolean(); } diff --git a/hecl/include/hecl/CVarManager.hpp b/hecl/include/hecl/CVarManager.hpp index e07efaf6a..292ef3179 100644 --- a/hecl/include/hecl/CVarManager.hpp +++ b/hecl/include/hecl/CVarManager.hpp @@ -20,7 +20,7 @@ class CVarManager final { using CVarContainer = DNACVAR::CVarContainer; template CVar* _newCVar(std::string_view name, std::string_view help, const T& value, CVar::EFlags flags) { - if (CVar* ret = registerCVar(std::make_unique(name, value, help, flags, *this))) { + if (CVar* ret = registerCVar(std::make_unique(name, value, help, flags))) { deserialize(ret); return ret; } @@ -39,20 +39,44 @@ public: CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary = false); ~CVarManager(); + CVar* newCVar(std::string_view name, std::string_view help, const atVec2f& value, CVar::EFlags flags) { + return _newCVar(name, help, value, flags); + } + CVar* newCVar(std::string_view name, std::string_view help, const atVec2d& value, CVar::EFlags flags) { + return _newCVar(name, help, value, flags); + } + CVar* newCVar(std::string_view name, std::string_view help, const atVec3f& value, CVar::EFlags flags) { + return _newCVar(name, help, value, flags); + } + CVar* newCVar(std::string_view name, std::string_view help, const atVec3d& value, CVar::EFlags flags) { + return _newCVar(name, help, value, flags); + } CVar* newCVar(std::string_view name, std::string_view help, const atVec4f& value, CVar::EFlags flags) { return _newCVar(name, help, value, flags); } + CVar* newCVar(std::string_view name, std::string_view help, const atVec4d& value, CVar::EFlags flags) { + return _newCVar(name, help, value, flags); + } CVar* newCVar(std::string_view name, std::string_view help, std::string_view value, CVar::EFlags flags) { return _newCVar(name, help, value, flags); } CVar* newCVar(std::string_view name, std::string_view help, bool value, CVar::EFlags flags) { return _newCVar(name, help, value, flags); } + // Float and double are internally identical, all floating point values are stored as `double` CVar* newCVar(std::string_view name, std::string_view help, float value, CVar::EFlags flags) { - return _newCVar(name, help, value, flags); + return _newCVar(name, help, static_cast(value), flags); } - CVar* newCVar(std::string_view name, std::string_view help, int value, CVar::EFlags flags) { - return _newCVar(name, help, value, flags); + CVar* newCVar(std::string_view name, std::string_view help, double value, CVar::EFlags flags) { + return _newCVar(name, help, value, flags); + } + // Integer CVars can be seamlessly converted between either type, the distinction is to make usage absolutely clear + CVar* newCVar(std::string_view name, std::string_view help, int32_t value, CVar::EFlags flags) { + return _newCVar(name, help, value, flags); + } + + CVar* newCVar(std::string_view name, std::string_view help, uint32_t value, CVar::EFlags flags) { + return _newCVar(name, help, value, flags); } CVar* registerCVar(std::unique_ptr&& cvar); @@ -66,13 +90,15 @@ public: } std::vector archivedCVars() const; - std::vector cvars(CVar::EFlags filter = CVar::EFlags::None) const; + std::vector cvars(CVar::EFlags filter = CVar::EFlags::Any) const; void deserialize(CVar* cvar); void serialize(); static CVarManager* instance(); + void proc(); + void list(class Console* con, const std::vector& args); void setCVar(class Console* con, const std::vector& args); void getCVar(class Console* con, const std::vector& args); diff --git a/hecl/lib/CVar.cpp b/hecl/lib/CVar.cpp index 9e55967b1..64cbbca87 100644 --- a/hecl/lib/CVar.cpp +++ b/hecl/lib/CVar.cpp @@ -13,111 +13,70 @@ extern CVar* com_enableCheats; using namespace std::literals; -CVar::CVar(std::string_view name, std::string_view value, std::string_view help, EType type, EFlags flags, - CVarManager& parent) -: m_mgr(parent) { - m_name = std::string(name); - m_value = std::string(value); - m_defaultValue = std::string(value); - m_help = help; - m_type = type; - m_flags = flags; -} - -CVar::CVar(std::string_view name, std::string_view value, std::string_view help, CVar::EFlags flags, - CVarManager& parent) -: m_mgr(parent) { - m_flags = flags; - m_name = std::string(name); - m_help = help; - m_type = EType::Literal; - - // Unlock the cvar for writing if readonly - unlock(); - +CVar::CVar(std::string_view name, std::string_view value, std::string_view help, CVar::EFlags flags) +: CVar(name, help, EType::Literal) { fromLiteral(value); - m_defaultValue = m_value; - - // Lock the cvar - lock(); - // Clear the modified flag, just incase lock didn't do it. - m_flags = flags; + init(flags); } -CVar::CVar(std::string_view name, const atVec4f& value, std::string_view help, EFlags flags, CVarManager& parent) -: m_mgr(parent) { - m_name = std::string(name); - m_help = help; - m_type = EType::Vec4f; - m_flags = flags; +CVar::CVar(std::string_view name, const atVec2f& value, std::string_view help, EFlags flags) +: CVar(name, help, EType::Vec2f) { + fromVec2f(value); + init(flags); +} - // Unlock the cvar for writing if readonly - unlock(); +CVar::CVar(std::string_view name, const atVec2d& value, std::string_view help, EFlags flags) +: CVar(name, help, EType::Vec2d) { + fromVec2d(value); + init(flags); +} + +CVar::CVar(std::string_view name, const atVec3f& value, std::string_view help, EFlags flags) +: CVar(name, help, EType::Vec3f) { + fromVec3f(value); + init(flags, false); +} + +CVar::CVar(std::string_view name, const atVec3d& value, std::string_view help, EFlags flags) +: CVar(name, help, EType::Vec3d) { + fromVec3d(value); + init(flags, false); +} + +CVar::CVar(std::string_view name, const atVec4f& value, std::string_view help, EFlags flags) +: CVar(name, help, EType::Vec4f) { fromVec4f(value); - m_defaultValue = m_value; - - // Lock the cvar - lock(); - // Clear the modified flag, just incase lock didn't do it. - m_flags = flags; + init(flags, false); } -CVar::CVar(std::string_view name, float value, std::string_view help, EFlags flags, CVarManager& parent) -: m_mgr(parent) { - m_name = std::string(name); - m_help = help; - m_type = EType::Float; - m_flags = flags; - - // Unlock the cvar for writing if readonly - unlock(); - - fromFloat(value); - m_defaultValue = m_value; - - // Lock the cvar - lock(); - // Clear the modified flag, just incase lock didn't do it. - m_flags = flags; +CVar::CVar(std::string_view name, const atVec4d& value, std::string_view help, EFlags flags) +: CVar(name, help, EType::Vec4d) { + fromVec4d(value); + init(flags, false); } -CVar::CVar(std::string_view name, bool value, std::string_view help, CVar::EFlags flags, CVarManager& parent) -: m_mgr(parent) { - m_name = std::string(name); - m_help = help; - m_type = EType::Boolean; - m_flags = flags; - - // Unlock the cvar for writing if readonly - unlock(); +CVar::CVar(std::string_view name, double value, std::string_view help, EFlags flags) : CVar(name, help, EType::Real) { + fromReal(value); + init(flags); +} +CVar::CVar(std::string_view name, bool value, std::string_view help, CVar::EFlags flags) +: CVar(name, help, EType::Boolean) { fromBoolean(value); - m_defaultValue = m_value; - - // Lock the cvar - lock(); - // Clear the modified flag, just incase lock didn't do it. - m_flags = flags; + init(flags); } -CVar::CVar(std::string_view name, int value, std::string_view help, CVar::EFlags flags, CVarManager& parent) -: m_mgr(parent) { - m_name = std::string(name); - m_help = help; - m_type = EType::Integer; - m_flags = flags; - - // Unlock the cvar for writing if readonly - unlock(); - +CVar::CVar(std::string_view name, int32_t value, std::string_view help, CVar::EFlags flags) +: CVar(name, help, EType::Signed) { fromInteger(value); - m_defaultValue = m_value; + init(flags); +} - // Lock the cvar - lock(); - // Clear the modified flag, just incase lock didn't do it. - m_flags = flags; +CVar::CVar(std::string_view name, uint32_t value, std::string_view help, CVar::EFlags flags) +: CVar(name, help, EType::Unsigned) { + fromInteger(value); + init(flags); } std::string CVar::help() const { @@ -125,6 +84,82 @@ std::string CVar::help() const { (isReadOnly() ? " [ReadOnly]" : "")); } +atVec2f CVar::toVec2f(bool* isValid) const { + if (m_type != EType::Vec2f) { + if (isValid != nullptr) + *isValid = false; + + return atVec2f{}; + } + + if (isValid != nullptr) + *isValid = true; + + atVec2f vec{}; + athena::simd_floats f; + std::sscanf(m_value.c_str(), "%g %g", &f[0], &f[1]); + vec.simd.copy_from(f); + + return vec; +} + +atVec2d CVar::toVec2d(bool* isValid) const { + if (m_type != EType::Vec2d) { + if (isValid != nullptr) + *isValid = false; + + return atVec2d{}; + } + + if (isValid != nullptr) + *isValid = true; + + atVec2d vec{}; + athena::simd_doubles f; + std::sscanf(m_value.c_str(), "%lg %lg", &f[0], &f[1]); + vec.simd.copy_from(f); + + return vec; +} + +atVec3f CVar::toVec3f(bool* isValid) const { + if (m_type != EType::Vec3f) { + if (isValid != nullptr) + *isValid = false; + + return atVec3f{}; + } + + if (isValid != nullptr) + *isValid = true; + + atVec3f vec{}; + athena::simd_floats f; + std::sscanf(m_value.c_str(), "%g %g %g", &f[0], &f[1], &f[2]); + vec.simd.copy_from(f); + + return vec; +} + +atVec3d CVar::toVec3d(bool* isValid) const { + if (m_type != EType::Vec3d) { + if (isValid != nullptr) + *isValid = false; + + return atVec3d{}; + } + + if (isValid != nullptr) + *isValid = true; + + atVec3d vec{}; + athena::simd_doubles f; + std::sscanf(m_value.c_str(), "%lg %lg %lg", &f[0], &f[1], &f[2]); + vec.simd.copy_from(f); + + return vec; +} + atVec4f CVar::toVec4f(bool* isValid) const { if (m_type != EType::Vec4f) { if (isValid != nullptr) @@ -136,22 +171,44 @@ atVec4f CVar::toVec4f(bool* isValid) const { if (isValid != nullptr) *isValid = true; - atVec4f vec; + atVec4f vec{}; athena::simd_floats f; - std::sscanf(m_value.c_str(), "%f %f %f %f", &f[0], &f[1], &f[2], &f[3]); + std::sscanf(m_value.c_str(), "%g %g %g %g", &f[0], &f[1], &f[2], &f[3]); vec.simd.copy_from(f); return vec; } -float CVar::toFloat(bool* isValid) const { - if (m_type != EType::Float) { +atVec4d CVar::toVec4d(bool* isValid) const { + if (m_type != EType::Vec4d) { + if (isValid != nullptr) + *isValid = false; + + return atVec4d{}; + } + + if (isValid != nullptr) + *isValid = true; + + atVec4d vec{}; + athena::simd_doubles f; + std::sscanf(m_value.c_str(), "%lg %lg %lg %lg", &f[0], &f[1], &f[2], &f[3]); + vec.simd.copy_from(f); + + return vec; +} + +double CVar::toReal(bool* isValid) const { + if (m_type != EType::Real) { if (isValid) *isValid = false; return 0.0f; } - return strtof(m_value.c_str(), nullptr); + if (isValid != nullptr) + *isValid = true; + + return strtod(m_value.c_str(), nullptr); } bool CVar::toBoolean(bool* isValid) const { @@ -162,36 +219,38 @@ bool CVar::toBoolean(bool* isValid) const { return false; } - // We don't want to modify the original value; - std::string tmp = m_value; - athena::utility::tolower(tmp); + if (isValid != nullptr) + *isValid = true; - if (!tmp.compare("yes") || !tmp.compare("true") || !tmp.compare("1")) { - if (isValid) - *isValid = true; - return true; - } else if (!tmp.compare("no") || !tmp.compare("false") || !tmp.compare("0")) { - if (isValid) - *isValid = true; - return false; - } - - if (isValid) - *isValid = false; - - return false; + return athena::utility::parseBool(m_value); } -int CVar::toInteger(bool* isValid) const { - if (m_type != EType::Integer) { +int32_t CVar::toSigned(bool* isValid) const { + if (m_type != EType::Signed && m_type != EType::Unsigned) { if (isValid) *isValid = false; return 0; } + if (isValid != nullptr) + *isValid = true; + return strtol(m_value.c_str(), nullptr, 0); } +uint32_t CVar::toUnsigned(bool* isValid) const { + if (m_type != EType::Signed && m_type != EType::Unsigned) { + if (isValid) + *isValid = false; + return 0; + } + + if (isValid != nullptr) + *isValid = true; + + return strtoul(m_value.c_str(), nullptr, 0); +} + std::string CVar::toLiteral(bool* isValid) const { if (m_type != EType::Literal && (com_developer && com_developer->toBoolean())) { if (isValid != nullptr) @@ -216,16 +275,48 @@ std::wstring CVar::toWideLiteral(bool* isValid) const { return hecl::UTF8ToWide(m_value); } +bool CVar::fromVec2f(const atVec2f& val) { + if (!safeToModify(EType::Vec2f)) + return false; + + athena::simd_floats f(val.simd); + m_value.assign(fmt::format(fmt("{} {}"), f[0], f[1])); + m_flags |= EFlags::Modified; + return true; +} + +bool CVar::fromVec2d(const atVec2d& val) { + if (!safeToModify(EType::Vec2d)) + return false; + + athena::simd_doubles f(val.simd); + m_value.assign(fmt::format(fmt("{} {}"), f[0], f[1])); + m_flags |= EFlags::Modified; + return true; +} + +bool CVar::fromVec3f(const atVec3f& val) { + if (!safeToModify(EType::Vec3f)) + return false; + + athena::simd_floats f(val.simd); + m_value.assign(fmt::format(fmt("{} {} {}"), f[0], f[1], f[2])); + m_flags |= EFlags::Modified; + return true; +} + +bool CVar::fromVec3d(const atVec3d& val) { + if (!safeToModify(EType::Vec3d)) + return false; + + athena::simd_doubles f(val.simd); + m_value.assign(fmt::format(fmt("{} {} {}"), f[0], f[1], f[2])); + m_flags |= EFlags::Modified; + return true; +} + bool CVar::fromVec4f(const atVec4f& val) { - if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) - return false; - else if (isCheat()) - return false; - - if (m_type != EType::Vec4f) - return false; - - if (isReadOnly() && (com_developer && !com_developer->toBoolean())) + if (!safeToModify(EType::Vec4f)) return false; athena::simd_floats f(val.simd); @@ -234,16 +325,18 @@ bool CVar::fromVec4f(const atVec4f& val) { return true; } -bool CVar::fromFloat(float val) { - if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) - return false; - else if (isCheat()) +bool CVar::fromVec4d(const atVec4d& val) { + if (!safeToModify(EType::Vec4d)) return false; - if (m_type != EType::Float) - return false; + athena::simd_doubles f(val.simd); + m_value.assign(fmt::format(fmt("{} {} {} {}"), f[0], f[1], f[2], f[3])); + m_flags |= EFlags::Modified; + return true; +} - if (isReadOnly() && (com_developer && !com_developer->toBoolean())) +bool CVar::fromReal(double val) { + if (!safeToModify(EType::Real)) return false; m_value.assign(fmt::format(fmt("{}"), val)); @@ -252,15 +345,7 @@ bool CVar::fromFloat(float val) { } bool CVar::fromBoolean(bool val) { - if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) - return false; - else if (isCheat()) - return false; - - if (m_type != EType::Boolean) - return false; - - if (isReadOnly() && (com_developer && !com_developer->toBoolean())) + if (!safeToModify(EType::Boolean)) return false; if (val) @@ -272,33 +357,44 @@ bool CVar::fromBoolean(bool val) { return true; } -bool CVar::fromInteger(int val) { - if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) - return false; - else if (isCheat()) +bool CVar::fromInteger(int32_t val) { + if ((com_developer && com_enableCheats) && (!com_developer->toBoolean() || !com_enableCheats->toBoolean()) && + isCheat()) return false; - if (m_type != EType::Integer) + // We'll accept both signed an unsigned input + if (m_type != EType::Signed && m_type != EType::Unsigned) return false; if (isReadOnly() && (com_developer && !com_developer->toBoolean())) return false; - m_value = fmt::format(fmt("{}"), val); + // Properly format based on signedness + m_value = fmt::format(fmt("{}"), (m_type == EType::Signed ? val : static_cast(val))); + setModified(); + return true; +} + +bool CVar::fromInteger(uint32_t val) { + if ((com_developer && com_enableCheats) && (!com_developer->toBoolean() || !com_enableCheats->toBoolean()) && + isCheat()) + return false; + + // We'll accept both signed an unsigned input + if (m_type != EType::Signed && m_type != EType::Unsigned) + return false; + + if (isReadOnly() && (com_developer && !com_developer->toBoolean())) + return false; + + // Properly format based on signedness + m_value = fmt::format(fmt("{}"), (m_type == EType::Unsigned ? val : static_cast(val))); setModified(); return true; } bool CVar::fromLiteral(std::string_view val) { - if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) - return false; - else if (isCheat()) - return false; - - if (m_type != EType::Literal) - return false; - - if (isReadOnly() && (com_developer && !com_developer->toBoolean())) + if (!safeToModify(EType::Literal)) return false; m_value.assign(val); @@ -307,15 +403,7 @@ bool CVar::fromLiteral(std::string_view val) { } bool CVar::fromLiteral(std::wstring_view val) { - if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) - return false; - else if (isCheat()) - return false; - - if (m_type != EType::Literal) - return false; - - if (isReadOnly() && (com_developer && !com_developer->toBoolean())) + if (!safeToModify(EType::Literal)) return false; m_value.assign(hecl::WideToUTF8(val)); @@ -323,94 +411,36 @@ bool CVar::fromLiteral(std::wstring_view val) { return true; } -bool CVar::fromLiteralToType(std::string_view val, bool setDefault) { - switch (m_type) { - case EType::Literal: - return fromLiteral(val); - case EType::Boolean: { - std::stringstream ss; - ss << std::boolalpha << val; - bool v; - ss >> v; - return fromBoolean(v); - } - case EType::Float: { - std::stringstream ss; - ss << val; - float v; - ss >> v; - return fromFloat(v); - } - case EType::Integer: { - std::stringstream ss; - ss << val; - int v; - ss >> v; - return fromInteger(v); - } - case EType::Vec4f: { - atVec4f vec; - athena::simd_floats f; - std::sscanf(val.data(), "%f %f %f %f", &f[0], &f[1], &f[2], &f[3]); - vec.simd.copy_from(f); - return fromVec4f(vec); - } - } - if (setDefault) - m_value = m_defaultValue; - return false; +bool CVar::fromLiteralToType(std::string_view val) { + if (!safeToModify(m_type) || !isValidInput(val)) + return false; + m_value = val; + return true; } -bool CVar::fromLiteralToType(std::wstring_view val, bool setDefault) { - switch (m_type) { - case EType::Literal: - return fromLiteral(val); - case EType::Boolean: { - std::wstringstream ss; - ss << std::boolalpha << val; - bool v; - ss >> v; - return fromBoolean(v); - } - case EType::Float: { - std::wstringstream ss; - ss << val; - float v; - ss >> v; - return fromFloat(v); - } - case EType::Integer: { - std::wstringstream ss; - ss << val; - int v; - ss >> v; - return fromInteger(v); - } - case EType::Vec4f: { - atVec4f vec; - athena::simd_floats f; - std::swscanf(val.data(), L"%f %f %f %f", &f[0], &f[1], &f[2], &f[3]); - vec.simd.copy_from(f); - return fromVec4f(vec); - } - } - if (setDefault) - m_value = m_defaultValue; - return false; +bool CVar::fromLiteralToType(std::wstring_view val) { + return fromLiteralToType(hecl::WideToUTF8(val)); } -bool CVar::isModified() const { return int(m_flags & EFlags::Modified) != 0; } -bool CVar::modificationRequiresRestart() const { return int(m_flags & EFlags::ModifyRestart) != 0; } +bool CVar::isModified() const { return True(m_flags & EFlags::Modified); } +bool CVar::modificationRequiresRestart() const { return True(m_flags & EFlags::ModifyRestart); } -bool CVar::isReadOnly() const { return int(m_flags & EFlags::ReadOnly) != 0; } +bool CVar::isReadOnly() const { return True(m_flags & EFlags::ReadOnly); } -bool CVar::isCheat() const { return int(m_flags & EFlags::Cheat) != 0; } +bool CVar::isCheat() const { return True(m_flags & EFlags::Cheat); } -bool CVar::isHidden() const { return int(m_flags & EFlags::Hidden) != 0; } +bool CVar::isHidden() const { return True(m_flags & EFlags::Hidden); } -bool CVar::isArchive() const { return int(m_flags & EFlags::Archive) != 0; } +bool CVar::isArchive() const { return True(m_flags & EFlags::Archive); } -bool CVar::isInternalArchivable() const { return int(m_flags & EFlags::InternalArchivable) != 0; } +bool CVar::isInternalArchivable() const { return True(m_flags & EFlags::InternalArchivable); } + +bool CVar::isColor() const { + return True(m_flags & EFlags::Color) && + (m_type == EType::Vec3f || m_type == EType::Vec3d || m_type == EType::Vec3f || m_type == EType::Vec4d); +} + +bool CVar::isNoDeveloper() const { return True(m_flags & EFlags::NoDeveloper); } bool CVar::wasDeserialized() const { return m_wasDeserialized; } @@ -442,4 +472,85 @@ void CVar::dispatch() { for (const ListenerFunc& listen : m_listeners) listen(this); } + + +bool isReal(std::string_view v) { + char* p; + std::strtod(v.data(), &p); + return *p == 0; +} +bool isReal(const std::vector& v) { + for (auto& s : v) { + if (!isReal(s)) + return false; + } + return true; +} + +bool CVar::isValidInput(std::string_view input) const { + std::vector parts = athena::utility::split(input, ' '); + char* p; + switch(m_type) { + case EType::Boolean: { + bool valid = false; + athena::utility::parseBool(input, &valid); + return valid; + } + case EType::Signed: + std::strtol(input.data(), &p, 0); + return p == nullptr; + case EType::Unsigned: + std::strtoul(input.data(), &p, 0); + return p == nullptr; + case EType::Real: { + bool size = parts.size() == 1; + bool ret = isReal(input); + return ret && size; + } + case EType::Literal: + return true; + case EType::Vec2f: + case EType::Vec2d: + return parts.size() == 2 && isReal(parts); + case EType::Vec3f: + case EType::Vec3d: + return parts.size() == 3 && isReal(parts); + case EType::Vec4f: + case EType::Vec4d: + return parts.size() == 4 && isReal(parts); + } + + return false; +} + +bool CVar::isValidInput(std::wstring_view input) const { + return isValidInput(hecl::WideToUTF8(input)); +} + +bool CVar::safeToModify(EType type) const { + // Are we NoDevelper? + if (isNoDeveloper()) + return false; + + // Are we a cheat? + if (isCheat() && (com_developer && com_enableCheats) && + (!com_developer->toBoolean() || !com_enableCheats->toBoolean())) + return false; + + // Are we read only? + if (isReadOnly() && (com_developer && !com_developer->toBoolean())) + return false; + + return m_type == type; +} + +void CVar::init(EFlags flags, bool removeColor) { + m_defaultValue = m_value; + m_flags = flags; + if (removeColor) { + // If the user specifies color, we don't want it + m_flags &= ~EFlags::Color; + } +} + } // namespace hecl diff --git a/hecl/lib/CVarManager.cpp b/hecl/lib/CVarManager.cpp index 14938e5c3..07647df67 100644 --- a/hecl/lib/CVarManager.cpp +++ b/hecl/lib/CVarManager.cpp @@ -25,7 +25,9 @@ static logvisor::Module CVarLog("CVarManager"); CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary) : m_store(store), m_useBinary(useBinary) { m_instance = this; - com_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System); + com_configfile = + newCVar("config", "File to store configuration", std::string("config"), + CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::NoDeveloper | CVar::EFlags::Hidden); com_developer = newCVar("developer", "Enables developer mode", false, (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable)); com_enableCheats = newCVar( @@ -72,14 +74,15 @@ std::vector CVarManager::archivedCVars() const { std::vector CVarManager::cvars(CVar::EFlags filter) const { std::vector ret; for (const auto& pair : m_cvars) - if (filter == CVar::EFlags::None || (pair.second->flags() & filter) != 0) + if (filter == CVar::EFlags::Any || True(pair.second->flags() & filter)) ret.push_back(pair.second.get()); return ret; } void CVarManager::deserialize(CVar* cvar) { - if (!cvar) + /* Make sure we're not trying to deserialize a CVar that is invalid or not exposed */ + if (!cvar || (!cvar->isArchive() && !cvar->isInternalArchivable())) return; /* First let's check for a deferred value */ @@ -93,9 +96,6 @@ void CVarManager::deserialize(CVar* cvar) { } /* We were either unable to find a deferred value or got an invalid value */ - if (!cvar->isArchive() && !cvar->isInternalArchivable()) - return; - #if _WIN32 hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _SYS_STR('/') + com_configfile->toWideLiteral(); @@ -122,10 +122,9 @@ void CVarManager::deserialize(CVar* cvar) { DNACVAR::CVar& tmp = *serialized; if (cvar->m_value != tmp.m_value) { - cvar->unlock(); - cvar->fromLiteralToType(tmp.m_value, true); + CVarUnlocker lc(cvar); + cvar->fromLiteralToType(tmp.m_value); cvar->m_wasDeserialized = true; - cvar->lock(); } } } @@ -145,10 +144,9 @@ void CVarManager::deserialize(CVar* cvar) { const std::unique_ptr& tmp = serialized->second; if (cvar->m_value != tmp->m_scalarString) { - cvar->unlock(); - cvar->fromLiteralToType(tmp->m_scalarString, true); + CVarUnlocker lc(cvar); + cvar->fromLiteralToType(tmp->m_scalarString); cvar->m_wasDeserialized = true; - cvar->lock(); } } } @@ -329,5 +327,12 @@ void CVarManager::restoreDeveloper(bool oldDeveloper) { CVarUnlocker unlock(com_developer); com_developer->fromBoolean(oldDeveloper); } +void CVarManager::proc() { + for (const auto& [name, cvar] : m_cvars) { + if (cvar->isModified() && !cvar->modificationRequiresRestart()) { + cvar->dispatch(); + } + } +} } // namespace hecl diff --git a/hecl/lib/Console.cpp b/hecl/lib/Console.cpp index 3e678626f..3a8390e28 100644 --- a/hecl/lib/Console.cpp +++ b/hecl/lib/Console.cpp @@ -174,12 +174,12 @@ void Console::init(boo::IWindow* window) { void Console::proc() { if (m_conHeight->isModified()) { - m_cachedConHeight = m_conHeight->toFloat(); + m_cachedConHeight = m_conHeight->toReal(); m_conHeight->clearModified(); } if (m_conSpeed->isModified()) { - m_cachedConSpeed = m_conSpeed->toFloat(); + m_cachedConSpeed = m_conSpeed->toReal(); m_conSpeed->clearModified(); }