Moved CVars to HECL

This commit is contained in:
Jack Andersen 2015-12-02 11:11:10 -10:00
parent fff3100f17
commit 47fb36def6
6 changed files with 804 additions and 1 deletions

2
hecl/extern/libBoo vendored

@ -1 +1 @@
Subproject commit cd4df5cb270be177740bd6ab1fed60f68481002b
Subproject commit 13cf33d75f60b8929e5d1794a3e597722d084ed0

151
hecl/include/HECL/CVar.hpp Executable file
View File

@ -0,0 +1,151 @@
#ifndef CVAR_HPP
#define CVAR_HPP
#include <string>
#include <functional>
#include <Athena/Types.hpp>
#include <Athena/Global.hpp>
#include <Athena/DNAYaml.hpp>
namespace HECL
{
namespace DNACVAR
{
enum class EType : atUint8
{
Boolean,
Integer,
Float,
Literal,
Vec4f
};
enum EFlags
{
All = -1, // NOTE: is this really necessary? It seems rather overkill
System = (1 << 0),
Game = (1 << 1),
Editor = (1 << 2),
Gui = (1 << 3),
Cheat = (1 << 4),
Hidden = (1 << 5),
ReadOnly = (1 << 6),
Archive = (1 << 7),
Modified = (1 << 8)
};
ENABLE_BITWISE_ENUM(EFlags)
class CVar : public Athena::io::DNAYaml<Athena::BigEndian>
{
public:
DECL_YAML
String<-1> m_name;
String<-1> m_value;
Value<EType> m_type;
};
struct CVarContainer : public Athena::io::DNAYaml<Athena::BigEndian>
{
DECL_YAML
Value<atUint32> magic = 'CVAR';
Value<atUint32> cvarCount;
Vector<CVar, DNA_COUNT(cvarCount)> cvars;
};
}
class CVarManager;
class CVar : protected DNACVAR::CVar
{
friend class CVarManager;
Delete _d;
public:
typedef std::function<void(CVar*)> ListenerFunc;
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, 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);
CVar(const std::string& name, const atVec4f& value, const std::string& help, EFlags flags, CVarManager& parent);
const std::string& name() const { return m_name; }
std::string help() const;
atVec4f toVec4f(bool* isValid = nullptr) const;
float toFloat(bool* isValid = nullptr) const;
bool toBoolean(bool* isValid = nullptr) const;
int toInteger(bool* isValid = nullptr) const;
const std::wstring toWideLiteral(bool* isValid = nullptr) const;
const std::string toLiteral(bool* isValid = nullptr) const;
bool fromVec4f(const atVec4f& val);
bool fromFloat(float val);
bool fromBoolean(bool val);
bool fromInteger(int val);
bool fromLiteral(const std::string& val);
bool fromLiteral(const std::wstring& 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 isVec4f() const { return m_type == EType::Vec4f; }
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.
* <b>Handle with care!!!</b> 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 its partner function unlock, lock is harmless
* \see unlock
*/
void lock();
void addListener(ListenerFunc func) { m_listeners.push_back(func); }
private:
void dispatch();
std::string m_help;
std::string m_defaultValue;
EFlags m_flags;
bool m_allowedWrite;
CVarManager& m_mgr;
std::vector<ListenerFunc> m_listeners;
};
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

View File

@ -0,0 +1,68 @@
#ifndef CVARMANAGER_HPP
#define CVARMANAGER_HPP
#include <unordered_map>
#include <vector>
#include "CVar.hpp"
namespace HECL
{
namespace Runtime
{
class FileStoreManager;
}
class CVarManager
{
using CVarContainer = DNACVAR::CVarContainer;
template <typename T>
CVar* _newCVar(const std::string& name, const std::string& help, const T& value, CVar::EFlags flags)
{
CVar* ret(new CVar(name, value, help, flags, *this));
if (registerCVar(ret))
{
if (ret->isArchive())
deserialize(ret);
return ret;
}
delete ret;
return nullptr;
}
HECL::Runtime::FileStoreManager& m_store;
bool m_useBinary;
public:
CVarManager(HECL::Runtime::FileStoreManager& store, bool useBinary = false);
~CVarManager();
void update();
CVar* newCVar(const std::string& name, const std::string& help, const atVec4f& value, CVar::EFlags flags)
{ return _newCVar<atVec4f>(name, help, value, flags); }
CVar* newCVar(const std::string& name, const std::string& help, const std::string& value, CVar::EFlags flags)
{ return _newCVar<std::string>(name, help, value, flags); }
CVar* newCVar(const std::string& name, const std::string& help, bool value, CVar::EFlags flags)
{ return _newCVar<bool>(name, help, value, flags); }
CVar* newCVar(const std::string& name, const std::string& help, float value, CVar::EFlags flags)
{ return _newCVar<float>(name, help, value, flags); }
CVar* newCVar(const std::string& name, const std::string& help, int value, CVar::EFlags flags)
{ return _newCVar<int>(name, help, value, flags); }
bool registerCVar(CVar* cvar);
CVar* findCVar(std::string name);
std::vector<CVar*> archivedCVars() const;
std::vector<CVar*> cvars() const;
void deserialize(CVar* cvar);
void serialize();
private:
bool suppressDeveloper();
void restoreDeveloper(bool oldDeveloper);
std::unordered_map<std::string, CVar*> m_cvars;
};
}
#endif // CVARMANAGER_HPP

View File

@ -10,11 +10,16 @@ endif()
atdna(atdna_HMDLMeta.cpp ../include/HECL/HMDLMeta.hpp)
atdna(atdna_Frontend.cpp ../include/HECL/Frontend.hpp)
atdna(atdna_Runtime.cpp ../include/HECL/Runtime.hpp)
atdna(atdna_CVar.cpp ../include/HECL/CVar.hpp)
add_library(HECLCommon
HECL.cpp
ProjectPath.cpp
WideStringConvert.cpp
CVar.cpp
CVarManager.cpp
../include/HECL/CVar.hpp
../include/HECL/CVarManager.hpp
../include/HECL/HECL.hpp
../include/HECL/HMDLMeta.hpp
../include/HECL/Backend/Backend.hpp
@ -29,5 +34,6 @@ add_library(HECLCommon
atdna_HMDLMeta.cpp
atdna_Frontend.cpp
atdna_Runtime.cpp
atdna_CVar.cpp
${PLAT_SRCS})

397
hecl/lib/CVar.cpp Executable file
View File

@ -0,0 +1,397 @@
#include "HECL/HECL.hpp"
#include "HECL/CVar.hpp"
#include "HECL/CVarManager.hpp"
#include <Athena/Utility.hpp>
#include <algorithm>
namespace HECL
{
extern CVar* com_developer;
extern CVar* com_enableCheats;
CVar::CVar(const std::string& name, const std::string &value, const std::string &help, EType type, EFlags flags, CVarManager& parent)
: m_mgr(parent)
{
m_name= name;
m_value = value;
m_defaultValue = value;
m_help = help;
m_type = type;
m_flags = flags;
m_allowedWrite = false;
}
CVar::CVar(const std::string& name, const std::string& value, const std::string& help, CVar::EFlags flags, CVarManager& parent)
: m_mgr(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;
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 atVec4f& value, const std::string& help, EFlags flags, CVarManager& parent)
: m_mgr(parent)
{
// Unlock the cvar for writing if readonly
unlock();
m_name= name;
m_help = help;
m_type = EType::Vec4f;
m_flags = flags;
m_allowedWrite = false;
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(const std::string& name, float value, const std::string& help, EFlags flags, CVarManager& parent)
: m_mgr(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;
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)
: m_mgr(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;
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)
: m_mgr(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;
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 {};
}
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";
else
m_value = "false";
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(const std::string& 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(const std::wstring& 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);
}
}

181
hecl/lib/CVarManager.cpp Executable file
View File

@ -0,0 +1,181 @@
#include "HECL/CVarManager.hpp"
#include "HECL/CVar.hpp"
#include <Athena/FileWriter.hpp>
#include <Athena/Utility.hpp>
#include <HECL/Runtime.hpp>
#include <memory>
namespace HECL
{
CVar* com_developer = nullptr;
CVar* com_configfile = nullptr;
CVar* com_enableCheats = nullptr;
LogVisor::LogModule CVarLog("CVarManager");
CVarManager::CVarManager(HECL::Runtime::FileStoreManager& store, bool useBinary)
: m_store(store),
m_useBinary(useBinary)
{
com_configfile = newCVar("config", "File to store configuration", std::string("config"), CVar::EFlags::System);
com_developer = newCVar("developer", "Enables developer mode", false, (CVar::EFlags::System | CVar::EFlags::Cheat | CVar::EFlags::ReadOnly));
com_enableCheats = newCVar("iamaweiner", "Enable cheats", false, (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden));
}
CVarManager::~CVarManager()
{
}
void CVarManager::update()
{
for (const std::pair<std::string, CVar*>& pair : m_cvars)
if (pair.second->isModified())
{
pair.second->dispatch();
pair.second->clearModified();
}
}
bool CVarManager::registerCVar(CVar* 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;
}
CVar* CVarManager::findCVar(std::string name)
{
Athena::utility::tolower(name);
if (m_cvars.find(name) == m_cvars.end())
return nullptr;
return m_cvars[name];
}
std::vector<CVar*> CVarManager::archivedCVars() const
{
std::vector<CVar*> ret;
for (const std::pair<std::string, CVar*>& pair : m_cvars)
if (pair.second->isArchive())
ret.push_back(pair.second);
return ret;
}
std::vector<CVar*> CVarManager::cvars() const
{
std::vector<CVar*> ret;
for (const std::pair<std::string, CVar*>& pair : m_cvars)
ret.push_back(pair.second);
return ret;
}
void CVarManager::deserialize(CVar* cvar)
{
if (!cvar || !cvar->isArchive())
return;
CVarContainer container;
#if _WIN32
HECL::SystemString filename = m_store.getStoreRoot() + _S('/') + com_configfile->toWideLiteral();
#else
HECL::SystemString filename = m_store.getStoreRoot() + _S('/') + com_configfile->toLiteral();
#endif
HECL::Sstat st;
if (m_useBinary)
{
filename += _S(".bin");
if (HECL::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
return;
Athena::io::FileReader reader(filename);
if (reader.isOpen())
container.read(reader);
}
else
{
filename += _S(".yaml");
if (HECL::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
return;
FILE* f = HECL::Fopen(filename.c_str(), _S("rb"));
if (f)
container.fromYAMLFile(f);
fclose(f);
}
if (container.cvars.size() > 0)
{
auto serialized = std::find_if(container.cvars.begin(), container.cvars.end(), [&cvar](const DNACVAR::CVar& c) -> bool
{ return c.m_name == cvar->name(); });
if (serialized != container.cvars.end())
{
DNACVAR::CVar& tmp = *serialized;
if (tmp.m_type != cvar->type())
{
CVarLog.report(LogVisor::Error, _S("Stored type for %s does not match actual type!"), tmp.m_name.c_str());
return;
}
cvar->m_value = tmp.m_value;
}
}
}
void CVarManager::serialize()
{
CVarContainer container;
for (const std::pair<std::string, CVar*>& pair : m_cvars)
if (pair.second->isArchive())
{
CVar tmp = *pair.second;
container.cvars.push_back(tmp);
}
container.cvarCount = container.cvars.size();
#if _WIN32
HECL::SystemString filename = m_store.getStoreRoot() + _S('/') + com_configfile->toWideLiteral();
#else
HECL::SystemString filename = m_store.getStoreRoot() + _S('/') + com_configfile->toLiteral();
#endif
if (m_useBinary)
{
filename += _S(".bin");
Athena::io::FileWriter writer(filename);
if (writer.isOpen())
container.write(writer);
}
else
{
filename += _S(".yaml");
FILE* f = HECL::Fopen(filename.c_str(), _S("wb"));
if (f)
container.toYAMLFile(f);
fclose(f);
}
}
bool CVarManager::suppressDeveloper()
{
bool oldDeveloper = com_developer->toBoolean();
CVarUnlocker unlock(com_developer);
com_developer->fromBoolean(false);
return oldDeveloper;
}
void CVarManager::restoreDeveloper(bool oldDeveloper)
{
CVarUnlocker unlock(com_developer);
com_developer->fromBoolean(oldDeveloper);
}
}