#include "hecl/hecl.hpp" #include "hecl/CVar.hpp" #include "hecl/CVarManager.hpp" #include #include namespace hecl { extern CVar* com_developer; 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; m_allowedWrite = false; } 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_allowedWrite = false; m_name = std::string(name); m_help = help; m_type = EType::Literal; // Unlock the cvar for writing if readonly unlock(); 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(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; m_allowedWrite = false; // Unlock the cvar for writing if readonly unlock(); fromVec4f(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, 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; m_allowedWrite = false; // 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, 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; m_allowedWrite = false; // Unlock the cvar for writing if readonly unlock(); 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(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; m_allowedWrite = false; // Unlock the cvar for writing if readonly unlock(); 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::help() const { return std::string(m_help + (m_defaultValue != std::string() ? "\ndefault: " + m_defaultValue : "") + (isReadOnly() ? "[ReadOnly]" : "")); } atVec4f CVar::toVec4f(bool* isValid) const { if (m_type != EType::Vec4f) { if (isValid != nullptr) *isValid = false; return atVec4f{}; } if (isValid != NULL) *isValid = true; atVec4f vec; std::sscanf(m_value.c_str(), "%f %f %f %f", &vec.vec[0], &vec.vec[1], &vec.vec[2], &vec.vec[3]); return vec; } 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; } const std::wstring CVar::toWideLiteral(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 hecl::UTF8ToWide(m_value); } 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())) return false; m_value.assign(hecl::Format("%f %f %f %f", val.vec[0], val.vec[1], val.vec[2], val.vec[3])); m_flags |= EFlags::Modified; return true; } bool CVar::fromFloat(float val) { if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) return false; else if (isCheat()) return false; if (m_type != EType::Float) return false; if (isReadOnly() && (com_developer && !com_developer->toBoolean())) return false; m_value.assign(hecl::Format("%f", val)); setModified(); return true; } 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())) return false; if (val) m_value = "true"sv; else m_value = "false"sv; setModified(); return true; } bool CVar::fromInteger(int val) { if (isCheat() && (com_developer && !com_developer->toBoolean() && !com_enableCheats->toBoolean())) return false; else if (isCheat()) return false; if (m_type != EType::Integer) return false; if (isReadOnly() && (com_developer && !com_developer->toBoolean())) return false; m_value = hecl::Format("%i", 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())) return false; m_value.assign(val); setModified(); return true; } 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())) return false; m_value.assign(hecl::WideToUTF8(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(); } } void CVar::dispatch() { for (const ListenerFunc& listen : m_listeners) listen(this); } }