From fd8f72c5f02f80440c6d756037aa1947c58482cf Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 21 Nov 2015 20:24:51 -0800 Subject: [PATCH] Add CVar Update HECL --- DataSpec/DNACommon/CMakeLists.txt | 3 +- DataSpec/DNACommon/CVar.hpp | 49 +++++ Runtime/CMakeLists.txt | 2 + Runtime/CVar.cpp | 352 ++++++++++++++++++++++++++++++ Runtime/CVar.hpp | 92 ++++++++ Runtime/CVarManager.cpp | 77 +++++++ Runtime/CVarManager.hpp | 54 +++++ hecl | 2 +- 8 files changed, 629 insertions(+), 2 deletions(-) create mode 100644 DataSpec/DNACommon/CVar.hpp create mode 100755 Runtime/CVar.cpp create mode 100755 Runtime/CVar.hpp create mode 100755 Runtime/CVarManager.cpp create mode 100755 Runtime/CVarManager.hpp diff --git a/DataSpec/DNACommon/CMakeLists.txt b/DataSpec/DNACommon/CMakeLists.txt index a19684ef0..b4e2da88a 100644 --- a/DataSpec/DNACommon/CMakeLists.txt +++ b/DataSpec/DNACommon/CMakeLists.txt @@ -1,5 +1,6 @@ make_dnalist(liblist - CMDL) + CMDL + CVar) add_library(DNACommon DNACommon.hpp DNACommon.cpp ${liblist} diff --git a/DataSpec/DNACommon/CVar.hpp b/DataSpec/DNACommon/CVar.hpp new file mode 100644 index 000000000..d9c6cb876 --- /dev/null +++ b/DataSpec/DNACommon/CVar.hpp @@ -0,0 +1,49 @@ +#ifndef _DNACOMMON_CVAR_HPP_ +#define _DNACOMMON_CVAR_HPP_ + +#include +#include +#include "DNACommon.hpp" + +namespace Retro +{ +namespace DNACVAR +{ +enum class EType +{ + Boolean, + Integer, + Float, + Literal, + Color, + Bind +}; + +enum EFlags +{ + All = -1, // NOTE: is this really necessary? It seems rather overkill + System = (1 << 0), + Game = (1 << 1), + Gui = (1 << 2), + Cheat = (1 << 3), + Hidden = (1 << 4), + ReadOnly = (1 << 5), + Archive = (1 << 6), + Modified = (1 << 7) +}; +ENABLE_BITWISE_ENUM(EFlags) + +class CVar : BigYAML +{ +public: + DECL_YAML + String<-1> m_name; + String<-1> m_value; + Value m_type; + Value m_flags; +}; + +} +} + +#endif diff --git a/Runtime/CMakeLists.txt b/Runtime/CMakeLists.txt index b338ce9da..1f1349377 100644 --- a/Runtime/CMakeLists.txt +++ b/Runtime/CMakeLists.txt @@ -67,6 +67,8 @@ add_library(RuntimeCommon CGameDebug.hpp CGameDebug.cpp rstl.hpp rstl.cpp GameGlobalObjects.hpp + CVar.hpp CVar.cpp + CVarManager.hpp CVarManager.cpp RetroTypes.hpp GCNTypes.hpp ${PLAT_SRCS}) diff --git a/Runtime/CVar.cpp b/Runtime/CVar.cpp new file mode 100755 index 000000000..d14085018 --- /dev/null +++ b/Runtime/CVar.cpp @@ -0,0 +1,352 @@ +#include "CVar.hpp" +#include "CVarManager.hpp" +#include "CVarManager.hpp" +#include "CBasics.hpp" + +#include + +namespace Retro +{ +CVar::CVar(const std::string& name, const std::string &value, const std::string &help, EType type, EFlags flags, CVarManager* parent) +{ + m_name= name; + m_value = value; + m_defaultValue = value; + m_help = help; + m_type = type; + m_flags = flags; + m_allowedWrite = false; + m_mgr = parent; +} + +CVar::CVar(const std::string& name, const std::string& value, const std::string& help, CVar::EFlags flags, CVarManager* parent) +{ + // Unlock the cvar for writing if readonly + unlock(); + + m_name= name; + m_help = help; + m_type = EType::Literal; + m_flags = flags; + m_allowedWrite = false; + m_mgr = parent; + + fromLiteral(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(const std::string& name, const Zeus::CColor& value, const std::string& help, EFlags flags, CVarManager* parent) +{ + // Unlock the cvar for writing if readonly + unlock(); + + m_name= name; + m_help = help; + m_type = EType::Color; + m_flags = flags; + m_allowedWrite = false; + m_mgr = parent; + + fromColor(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(const std::string& name, float value, const std::string& help, EFlags flags, CVarManager* parent) +{ + // Unlock the cvar for writing if readonly + unlock(); + + m_name= name; + m_help = help; + m_type = EType::Float; + m_flags = flags; + m_allowedWrite = false; + m_mgr = parent; + + 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(const std::string& name, bool value, const std::string& help, CVar::EFlags flags, CVarManager* parent) +{ + // Unlock the cvar for writing if readonly + unlock(); + + m_name= name; + m_help = help; + m_type = EType::Boolean; + m_flags = flags; + m_allowedWrite = false; + m_mgr = parent; + + fromBoolean(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(const std::string& name, int value, const std::string& help, CVar::EFlags flags, CVarManager* parent) +{ + // Unlock the cvar for writing if readonly + unlock(); + + m_name= name; + m_help = help; + m_type = EType::Integer; + m_flags = flags; + m_allowedWrite = false; + m_mgr = parent; + + fromInteger(value); + m_defaultValue = m_value; + + // Lock the cvar + lock(); + // Clear the modified flag, just incase lock didn't do it. + m_flags = flags; +} + +std::string CVar::name() const +{ + return m_name; +} + +std::string CVar::help() const +{ + return std::string(m_help + (m_defaultValue != std::string() ? "\ndefault: " + m_defaultValue : "") + + (isReadOnly() ? "[ReadOnly]" : "")); +} + +Zeus::CColor CVar::toColor(bool* isValid) const +{ + if (m_type != EType::Color) + { + if (isValid != nullptr) + *isValid = false; + + return Zeus::CColor(); + } + + if (isValid != NULL) + *isValid = true; + + int r, g, b, a; + std::sscanf(m_value.c_str(), "%i %i %i %i", &r, &g, &b, &a); + + return Zeus::CColor(Zeus::Comp8(r), Zeus::Comp8(g), Zeus::Comp8(b), Zeus::Comp8(a)); +} + +float CVar::toFloat(bool* isValid) const +{ + if (m_type != EType::Float) + { + if (isValid) + *isValid = false; + return 0.0f; + } + + return strtof(m_value.c_str(), nullptr); +} + +bool CVar::toBoolean(bool* isValid) const +{ + if (m_type != EType::Boolean) + { + if (isValid) + *isValid = false; + + return false; + } + + // We don't want to modify the original value; + std::string tmp = m_value; + std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower); + + 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; +} + +int CVar::toInteger(bool* isValid) const +{ + if (m_type != EType::Integer) + { + if (isValid) + *isValid = false; + return 0; + } + + return strtol(m_value.c_str(), nullptr, 0); +} + + +const std::string& CVar::toLiteral(bool* isValid) const +{ + if (m_type != EType::Literal /*&& (com_developer && com_developer->toBoolean())*/) + { + if (isValid != nullptr) + *isValid = false; + } + else if (isValid != nullptr) + *isValid = true; + + // Even if it's not a literal, it's still safe to return + return m_value; +} + +bool CVar::fromColor(const Zeus::CColor& val) +{ + if (isCheat()) + return false; + + if (m_type != EType::Color) + return false; + + if (isReadOnly()) + return false; + + m_value.assign(CBasics::Stringize("%i %i %i %i", unsigned(val.r), unsigned(val.g), unsigned(val.b), unsigned(val.a))); + m_flags |= EFlags::Modified; + return true; +} + +bool CVar::fromFloat(float val) +{ + if (isCheat() /*&& (!com_developer->toBoolean() && !com_enableCheats->toBoolean())*/) + return false; + + if (m_type != EType::Float) + return false; + + if (isReadOnly() /*&& (com_developer && !com_developer->toBoolean())*/) + return false; + + m_value.assign(CBasics::Stringize("%f", val)); + setModified(); + return true; +} + +bool CVar::fromBoolean(bool val) +{ + if (isCheat() /*&& (!com_developer->toBoolean() && !com_enableCheats->toBoolean())*/) + return false; + + if (m_type != EType::Boolean) + return false; + + if (isReadOnly() /*&& (com_developer && !com_developer->toBoolean())*/) + return false; + + if (val) + m_value = "true"; + else + m_value = "false"; + + setModified(); + return true; +} + +bool CVar::fromInteger(int val) +{ + if (isCheat() /*&& (!com_developer->toBoolean() && !com_enableCheats->toBoolean())*/) + return false; + + if (m_type != EType::Integer) + return false; + + if (isReadOnly() /*&& (com_developer && !com_developer->toBoolean())*/) + return false; + + m_value = CBasics::Stringize("%i", val); + setModified(); + return true; +} + +bool CVar::fromLiteral(const std::string& val) +{ + if (isCheat() /*&& (!com_developer->toBoolean() && !com_enableCheats->toBoolean())*/) + return false; + + if (m_type != EType::Literal) + return false; + + if (isReadOnly() /*&& (com_developer && !com_developer->toBoolean())*/) + return false; + + m_value.assign(val); + setModified(); + return true; +} + +bool CVar::isModified() const { return int(m_flags & EFlags::Modified) != 0;} + +bool CVar::isReadOnly() const { return int(m_flags & EFlags::ReadOnly) != 0; } + +bool CVar::isCheat() const { return int(m_flags & EFlags::Cheat) != 0; } + +bool CVar::isHidden() const { return int(m_flags & EFlags::Hidden) != 0; } + +bool CVar::isArchive() const { return int(m_flags & EFlags::Archive) != 0; } + +void CVar::clearModified() { m_flags &= ~EFlags::Modified; } + +void CVar::setModified() { m_flags |= EFlags::Modified; } + +void CVar::unlock() +{ + if (!isReadOnly()) + return; + + if (!m_allowedWrite) + { + m_allowedWrite = true; + m_flags &= ~EFlags::ReadOnly; + } +} + +void CVar::lock() +{ + if (!isReadOnly()) + return; + + if (m_allowedWrite) + { + m_flags |= EFlags::ReadOnly; + m_allowedWrite = false; + clearModified(); + } +} +} + diff --git a/Runtime/CVar.hpp b/Runtime/CVar.hpp new file mode 100755 index 000000000..aa56adb86 --- /dev/null +++ b/Runtime/CVar.hpp @@ -0,0 +1,92 @@ +#ifndef CVAR_HPP +#define CVAR_HPP + +#include +#include "CColor.hpp" +#include "DataSpec/DNACommon/CVar.hpp" + +namespace Retro +{ + +class CVarManager; +class CVar : protected DNACVAR::CVar +{ +public: + using EType = DNACVAR::EType; + using EFlags = DNACVAR::EFlags; + + CVar(const std::string& name, const std::string& value, const std::string& help, EType type, EFlags flags, CVarManager* parent); + CVar(const std::string& name, const std::string& value, const std::string& help, EFlags flags, CVarManager* parent); + CVar(const std::string& name, const Zeus::CColor& value, const std::string& help, EFlags flags, CVarManager* parent); + CVar(const std::string& name, float value, const std::string& help, EFlags flags, CVarManager* parent); + CVar(const std::string& name, bool value, const std::string& help, EFlags flags, CVarManager* parent); + CVar(const std::string& name, int value, const std::string& help, EFlags flags, CVarManager* parent); + + + std::string name() const; + std::string help() const; + + Zeus::CColor toColor(bool* isValid = nullptr) const; + float toFloat(bool* isValid = nullptr) const; + bool toBoolean(bool* isValid = nullptr) const; + int toInteger(bool* isValid = nullptr) const; + const std::string& toLiteral(bool* isValid = nullptr) const; + + bool fromColor(const Zeus::CColor& val); + bool fromFloat(float val); + bool fromBoolean(bool val); + bool fromInteger(int val); + bool fromLiteral(const std::string& 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 isBinding() const { return m_type == EType::Bind; } + bool isColor() const { return m_type == EType::Color; } + bool isModified() const; + bool isReadOnly() const; + bool isCheat() const; + bool isHidden() const; + bool isArchive() const; + void clearModified(); + void setModified(); + + EType type() const { return m_type; } + EFlags flags() const { return m_flags; } + + /*! + * \brief Unlocks the CVar for writing if it is ReadOnly. + * Handle with care!!! if you use unlock(), make sure + * you lock the cvar using lock() + * \see lock + */ + void unlock(); + + /*! + * \brief Locks the CVar to prevent writing if it is ReadOnly. + * Unlike it's partner function unlock, lock is harmless + * \see unlock + */ + void lock(); +private: + std::string m_help; + std::string m_defaultValue; + bool m_allowedWrite; + + const CVarManager* m_mgr; +}; + + + +class CVarUnlocker +{ + CVar* m_cvar; +public: + CVarUnlocker(CVar* cvar) : m_cvar(cvar) { if (m_cvar) m_cvar->unlock(); } + ~CVarUnlocker() { if (m_cvar) m_cvar->lock(); } +}; + +} +#endif // CVAR_HPP + diff --git a/Runtime/CVarManager.cpp b/Runtime/CVarManager.cpp new file mode 100755 index 000000000..984476e06 --- /dev/null +++ b/Runtime/CVarManager.cpp @@ -0,0 +1,77 @@ +#include "CVarManager.hpp" +#include "CVar.hpp" +#include +#include + +namespace Retro +{ +CVarManager::CVarManager() +{ +} + +CVarManager::~CVarManager() +{ +} + +void CVarManager::initialize() +{ +} + +bool CVarManager::registerCVar(std::shared_ptr cvar) +{ + std::string tmp = cvar->name(); + Athena::utility::tolower(tmp); + if (m_cvars.find(tmp) != m_cvars.end()) + return false; + + m_cvars[tmp] = cvar; + return true; +} + +std::shared_ptr CVarManager::findCVar(const std::string &name) +{ + std::string tmp = std::string(name); + Athena::utility::tolower(tmp); + if (m_cvars.find(tmp) == m_cvars.end()) + return nullptr; + + return m_cvars[tmp]; +} + +std::vector> CVarManager::archivedCVars() const +{ + std::vector> ret; + for (std::pair> pair : m_cvars) + { + if (int(pair.second->flags() & CVar::EFlags::Archive) != 0) + ret.push_back(pair.second); + } + + return ret; +} + +std::vector> CVarManager::cvars() const +{ + std::vector> ret; + for (std::pair> pair : m_cvars) + ret.push_back(pair.second); + + return ret; +} + +bool CVarManager::suppressDeveloper() +{ + /*bool oldDeveloper = com_developer->toBoolean(); + CVarUnlocker unlock(com_developer); + com_developer->fromBoolean(false);*/ + + return false; //oldDeveloper; +} + +void CVarManager::restoreDeveloper(bool oldDeveloper) +{ +// CVarUnlocker unlock(com_developer); +// com_developer->fromBoolean(oldDeveloper); +} + +} diff --git a/Runtime/CVarManager.hpp b/Runtime/CVarManager.hpp new file mode 100755 index 000000000..27a8689bc --- /dev/null +++ b/Runtime/CVarManager.hpp @@ -0,0 +1,54 @@ +#ifndef CVARMANAGER_HPP +#define CVARMANAGER_HPP + +#include +#include +#include +#include "CVar.hpp" + +namespace Retro +{ + +class CVarManager +{ + template + std::shared_ptr _newCVar(const std::string& name, const std::string& help, const T& value, CVar::EFlags flags) + { + std::shared_ptr ret(new CVar(name, value, help, flags, this)); + if (registerCVar(ret)) + return ret; + return nullptr; + } +public: + CVarManager(); + ~CVarManager(); + + void initialize(); + + std::shared_ptr newCVar(const std::string& name, const std::string& help, const Zeus::CColor& value, CVar::EFlags flags) + { return _newCVar(name, help, value, flags); } + std::shared_ptr newCVar(const std::string& name, const std::string& help, const std::string& value, CVar::EFlags flags) + { return _newCVar(name, help, value, flags); } + std::shared_ptr newCVar(const std::string& name, const std::string& help, bool value, CVar::EFlags flags) + { return _newCVar(name, help, value, flags); } + std::shared_ptr newCVar(const std::string& name, const std::string& help, float value, CVar::EFlags flags) + { return _newCVar(name, help, value, flags); } + std::shared_ptr newCVar(const std::string& name, const std::string& help, int value, CVar::EFlags flags) + { return _newCVar(name, help, value, flags); } + + bool registerCVar(std::shared_ptr cvar); + + std::shared_ptrfindCVar(const std::string& name); + + std::vector> archivedCVars() const; + std::vector> cvars() const; + +private: + bool suppressDeveloper(); + void restoreDeveloper(bool oldDeveloper); + + std::unordered_map> m_cvars; +}; +} + +#endif // CVARMANAGER_HPP diff --git a/hecl b/hecl index d21e47eac..bc0aba098 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit d21e47eac6e8f8c81a7ccbc53e8df3285a2fdc64 +Subproject commit bc0aba098c43d27839f20df0c32029705def98bf