Merge commit 'f47d7d9'

This commit is contained in:
Phillip Stephens 2018-01-21 18:41:17 -08:00
commit 2f840e5321
7 changed files with 676 additions and 594 deletions

View File

@ -9,46 +9,97 @@
namespace hecl
{
class CVar
namespace DNACVAR
{
enum class EType : atUint8
{
Boolean,
Integer,
Float,
Literal,
Vec4f
};
enum EFlags
{
System = (1 << 0),
Game = (1 << 1),
Editor = (1 << 2),
Gui = (1 << 3),
Cheat = (1 << 4),
Hidden = (1 << 5),
ReadOnly = (1 << 6),
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 */
};
ENABLE_BITWISE_ENUM(EFlags)
class CVar : public athena::io::DNAYaml<athena::BigEndian>
{
public:
DECL_YAML
String<-1> m_name;
String<-1> m_value;
};
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;
public:
enum EFlags
{
System = (1 << 0),
Game = (1 << 1),
Editor = (1 << 2),
Gui = (1 << 3),
Cheat = (1 << 4),
Hidden = (1 << 5),
ReadOnly = (1 << 6),
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 */
};
protected:
std::string m_name;
std::string m_help;
EFlags m_flags;
EFlags m_oldFlags;
bool m_wasDeserialized = false;
bool m_unlocked = false;
Delete _d;
virtual bool _fromString(std::string_view sv) = 0;
public:
CVar(std::string_view name, std::string_view help, EFlags flags);
virtual ~CVar() = default;
std::string name() const { return m_name; }
typedef std::function<void(CVar*)> ListenerFunc;
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);
std::string_view name() const { return m_name; }
std::string_view rawHelp() const { return m_help; }
std::string help() const;
std::string rawHelp() const { return m_help; }
virtual std::string toString() const=0;
bool fromString(std::string_view v);
virtual void deserialize(athena::io::YAMLDocReader& reader) = 0;
virtual void serialize(athena::io::YAMLDocWriter& writer) const = 0;
virtual bool hasDefaultValue() const = 0;
virtual std::string defaultValueString() const = 0;
std::string value() const { return m_value; }
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(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 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 modificationRequiresRestart() const;
bool isReadOnly() const;
@ -57,36 +108,43 @@ public:
bool isArchive() const;
bool isInternalArchivable() const;
bool wasDeserialized() const;
bool hasDefaultValue() 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();
};
ENABLE_BITWISE_ENUM(CVar::EFlags)
void addListener(ListenerFunc func) { m_listeners.push_back(func); }
template<typename T>
class TCVar : public CVar
{
friend class CVarManager;
protected:
T& m_value;
T m_defaultValue;
bool _fromString(std::string_view sv);
public:
TCVar(T& value, std::string_view name, std::string_view help, EFlags flags);
private:
void dispatch();
EType m_type;
std::string m_help;
std::string m_defaultValue;
EFlags m_flags;
EFlags m_oldFlags;
bool m_unlocked = false;
bool m_wasDeserialized = false;
virtual std::string toString() const;
std::wstring toWideString() const;
virtual void deserialize(athena::io::YAMLDocReader& reader);
virtual void serialize(athena::io::YAMLDocWriter& writer) const;
virtual bool hasDefaultValue() const;
CVarManager& m_mgr;
T value() const;
T defaultValue() const;
std::string defaultValueString() const;
std::vector<ListenerFunc> m_listeners;
};
class CVarUnlocker
@ -97,107 +155,6 @@ public:
~CVarUnlocker() { if (m_cvar) m_cvar->lock(); }
};
class Vec3fCVar : public CVar
{
friend class CVarManager;
atVec3f& m_value;
atVec3f m_defaultValue;
bool _fromString(std::string_view v);
public:
Vec3fCVar(atVec3f& value, std::string_view name, std::string_view help, EFlags flags);
std::string toString() const;
bool hasDefaultValue() const;
void deserialize(athena::io::YAMLDocReader& reader);
void serialize(athena::io::YAMLDocWriter& writer) const;
atVec3f value() const { return m_value; }
atVec3f defaultValue() const { return m_defaultValue; }
std::string defaultValueString() const;
};
class Vec3dCVar : public CVar
{
friend class CVarManager;
atVec3d& m_value;
atVec3d m_defaultValue;
bool _fromString(std::string_view v);
public:
Vec3dCVar(atVec3d& value, std::string_view name, std::string_view help, EFlags flags);
std::string toString() const;
bool hasDefaultValue() const;
void deserialize(athena::io::YAMLDocReader& reader);
void serialize(athena::io::YAMLDocWriter& writer) const;
atVec3d value() const { return m_value; }
atVec3d defaultValue() const { return m_defaultValue; }
std::string defaultValueString() const;
};
class Vec4fCVar : public CVar
{
friend class CVarManager;
atVec4f& m_value;
atVec4f m_defaultValue;
bool _fromString(std::string_view v);
public:
Vec4fCVar(atVec4f& value, std::string_view name, std::string_view help, EFlags flags);
virtual ~Vec4fCVar() = default;
std::string toString() const;
bool hasDefaultValue() const;
void deserialize(athena::io::YAMLDocReader& reader);
void serialize(athena::io::YAMLDocWriter& writer) const;
atVec4f value() const { return m_value; }
atVec4f defaultValue() const { return m_defaultValue; }
std::string defaultValueString() const;
};
class Vec4dCVar : public CVar
{
friend class CVarManager;
atVec4d& m_value;
atVec4d m_defaultValue;
bool _fromString(std::string_view v);
public:
Vec4dCVar(atVec4d& value, std::string_view name, std::string_view help, EFlags flags);
std::string toString() const;
bool hasDefaultValue() const;
void deserialize(athena::io::YAMLDocReader& reader);
void serialize(athena::io::YAMLDocWriter& writer) const;
atVec4d value() const { return m_value; }
atVec4d defaultValue() const { return m_defaultValue; }
std::string defaultValueString() const;
};
class StringCVar : public CVar
{
friend class CVarManager;
std::string& m_value;
std::string m_defaultValue;
bool _fromString(std::string_view v);
public:
StringCVar(std::string& value, std::string_view name, std::string_view help, EFlags flags);
std::string toString() const;
bool hasDefaultValue() const;
void deserialize(athena::io::YAMLDocReader& reader);
void serialize(athena::io::YAMLDocWriter& writer) const;
const std::string& value() const { return m_value; }
const std::string& defaultValue() const { return m_defaultValue; }
std::string defaultValueString() const { return defaultValue(); }
};
using BoolCVar = TCVar<bool>;
using Int16CVar = TCVar<int16_t>;
using Uint16CVar = TCVar<uint16_t>;
using Int32CVar = TCVar<int32_t>;
using Uint32CVar = TCVar<uint32_t>;
using Int64CVar = TCVar<int64_t>;
using Uint64CVar = TCVar<uint64_t>;
using FloatCVar = TCVar<float>;
using DoubleCVar = TCVar<double>;
}
#endif // CVAR_HPP

View File

@ -12,75 +12,75 @@ namespace hecl
using namespace std::literals;
#ifdef _WIN32
#define DEFAULT_GRAPHICS_API "D3D11"
#define DEFAULT_GRAPHICS_API "D3D11"sv
#elif defined(__APPLE__)
#define DEFAULT_GRAPHICS_API "Metal"
#define DEFAULT_GRAPHICS_API "Metal"sv
#else
#define DEFAULT_GRAPHICS_API "OpenGL"
#define DEFAULT_GRAPHICS_API "OpenGL"sv
#endif
class CVarCommons
{
CVarManager& m_mgr;
std::string m_graphicsApi = DEFAULT_GRAPHICS_API;
uint32_t m_drawSamples = 1;
uint32_t m_texAnisotropy = 1;
bool m_deepColor = false;
CVar* m_graphicsApi = nullptr;
CVar* m_drawSamples = nullptr;
CVar* m_texAnisotropy = nullptr;
CVar* m_deepColor = nullptr;
public:
CVarCommons(CVarManager& manager) : m_mgr(manager)
{
m_mgr.findOrMakeCVar("graphicsApi"sv,
m_graphicsApi = m_mgr.findOrMakeCVar("graphicsApi"sv,
"API to use for rendering graphics"sv,
m_graphicsApi, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
m_mgr.findOrMakeCVar("drawSamples"sv,
DEFAULT_GRAPHICS_API, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
m_drawSamples = m_mgr.findOrMakeCVar("drawSamples"sv,
"Number of MSAA samples to use for render targets"sv,
m_drawSamples, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
m_mgr.findOrMakeCVar("texAnisotropy"sv,
1, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
m_texAnisotropy = m_mgr.findOrMakeCVar("texAnisotropy"sv,
"Number of anisotropic samples to use for sampling textures"sv,
m_texAnisotropy, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
m_mgr.findOrMakeCVar("deepColor"sv,
1, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
m_deepColor = m_mgr.findOrMakeCVar("deepColor"sv,
"Allow framebuffer with color depth greater-then 24-bits"sv,
m_deepColor, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
false, hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ModifyRestart);
}
std::string getGraphicsApi() const
{
return m_graphicsApi;
return m_graphicsApi->toLiteral();
}
void setGraphicsApi(std::string_view api)
{
m_graphicsApi = api;
m_graphicsApi->fromLiteral(api);
}
uint32_t getSamples() const
{
return std::max(uint32_t(1), m_drawSamples);
return std::max(uint32_t(1), uint32_t(m_drawSamples->toInteger()));
}
void setSamples(uint32_t v)
{
m_drawSamples = std::max(uint32_t(1), v);
m_drawSamples->fromInteger(std::max(uint32_t(1), v));
}
uint32_t getAnisotropy() const
{
return std::max(uint32_t(1), m_texAnisotropy);
return std::max(uint32_t(1), uint32_t(m_texAnisotropy->toInteger()));
}
void setAnisotropy(uint32_t v)
{
m_texAnisotropy = std::max(uint32_t(1), v);
m_texAnisotropy->fromInteger(std::max(uint32_t(1), v));
}
bool getDeepColor() const
{
return m_deepColor;
return m_deepColor->toBoolean();
}
void setDeepColor(bool b)
{
m_deepColor = b;
m_deepColor->fromBoolean(b);
}
void serialize()

View File

@ -7,36 +7,31 @@
namespace hecl
{
extern BoolCVar* com_developer;
extern StringCVar* com_configfile;
extern BoolCVar* com_enableCheats;
namespace Runtime
{
class FileStoreManager;
}
extern CVar* com_developer;
extern CVar* com_configfile;
extern CVar* com_enableCheats;
class CVarManager final
{
CVar* _newCVar(CVar* cvar)
using CVarContainer = DNACVAR::CVarContainer;
template <typename T>
CVar* _newCVar(std::string_view name, std::string_view help, const T& value, CVar::EFlags flags)
{
if (registerCVar(cvar))
CVar* ret(new CVar(name, value, help, flags, *this));
if (registerCVar(ret))
{
deserialize(cvar);
return cvar;
deserialize(ret);
return ret;
}
delete cvar;
delete ret;
return nullptr;
}
template <typename T>
CVar* _newCVar(std::string_view name, std::string_view help, T& value, CVar::EFlags flags)
{ return _newCVar(new TCVar<T>(value, name, help, flags)); }
hecl::Runtime::FileStoreManager& m_store;
std::string m_configFile = "config";
bool m_useBinary;
bool m_developerMode = false;
bool m_enableCheats = false;
static CVarManager* m_instance;
public:
CVarManager() = delete;
@ -46,35 +41,16 @@ public:
CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary = false);
~CVarManager();
void update();
CVar* newCVar(std::string_view name, std::string_view help, atVec3f& value, CVar::EFlags flags)
{ return _newCVar(new Vec3fCVar(value, name, help, flags)); }
CVar* newCVar(std::string_view name, std::string_view help, atVec3d& value, CVar::EFlags flags)
{ return _newCVar(new Vec3dCVar(value, name, help, flags)); }
CVar* newCVar(std::string_view name, std::string_view help, atVec4f& value, CVar::EFlags flags)
{ return _newCVar(new Vec4fCVar(value, name, help, flags)); }
CVar* newCVar(std::string_view name, std::string_view help, atVec4d& value, CVar::EFlags flags)
{ return _newCVar(new Vec4dCVar(value, name, help, flags)); }
CVar* newCVar(std::string_view name, std::string_view help, std::string& value, CVar::EFlags flags)
{ return _newCVar(new StringCVar(value, name, help, flags)); }
CVar* newCVar(std::string_view name, std::string_view help, bool& value, CVar::EFlags flags)
CVar* newCVar(std::string_view name, std::string_view help, const atVec4f& value, CVar::EFlags flags)
{ return _newCVar<atVec4f>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, std::string_view value, CVar::EFlags flags)
{ return _newCVar<std::string_view>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, bool value, CVar::EFlags flags)
{ return _newCVar<bool>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, float& value, CVar::EFlags flags)
CVar* newCVar(std::string_view name, std::string_view help, float value, CVar::EFlags flags)
{ return _newCVar<float>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, double& value, CVar::EFlags flags)
{ return _newCVar<double>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, int16_t& value, CVar::EFlags flags)
{ return _newCVar<int16_t>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, uint16_t& value, CVar::EFlags flags)
{ return _newCVar<uint16_t>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, int32_t& value, CVar::EFlags flags)
{ return _newCVar<int32_t>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, uint32_t& value, CVar::EFlags flags)
{ return _newCVar<uint32_t>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, int64_t& value, CVar::EFlags flags)
{ return _newCVar<int64_t>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, uint64_t& value, CVar::EFlags flags)
{ return _newCVar<uint64_t>(name, help, value, flags); }
CVar* newCVar(std::string_view name, std::string_view help, int value, CVar::EFlags flags)
{ return _newCVar<int>(name, help, value, flags); }
bool registerCVar(CVar* cvar);
@ -100,8 +76,8 @@ public:
void getCVar(class Console* con, const std::vector<std::string>& args);
void setDeveloperMode(bool v, bool setDeserialized=false);
bool restartRequired() const;
void setDeveloperMode(bool v, bool setDeserialized = false);
private:
bool suppressDeveloper();
void restoreDeveloper(bool oldDeveloper);

View File

@ -11,6 +11,7 @@
namespace hecl
{
class CVarManager;
class CVar;
struct SConsoleCommand
{
std::string m_displayName;
@ -72,8 +73,10 @@ private:
bool m_overwrite : 1;
bool m_cursorAtEnd : 1;
State m_state = State::Closed;
float m_conSpeed = 1.f;
float m_conHeight = 0.5f;
CVar* m_conSpeed;
CVar* m_conHeight;
float m_cachedConSpeed;
float m_cachedConHeight;
public:
Console(CVarManager*);
void registerCommand(std::string_view name, std::string_view helpText, std::string_view usage, const std::function<void(Console*, const std::vector<std::string>&)>&& func);

View File

@ -1,5 +1,6 @@
#include "hecl/hecl.hpp"
#include "hecl/CVar.hpp"
#include "hecl/CVarManager.hpp"
#include <athena/Utility.hpp>
#include <algorithm>
@ -7,40 +8,427 @@
namespace hecl
{
using namespace std::literals;
extern BoolCVar* com_developer;
extern BoolCVar* com_enableCheats;
extern CVar* com_developer;
extern CVar* com_enableCheats;
CVar::CVar(std::string_view name, std::string_view help, CVar::EFlags flags)
: m_name(name)
, m_help(help)
, m_flags(flags)
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();
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;
// 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;
// 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;
// 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;
// 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 + (hasDefaultValue() ? " (default: " + defaultValueString() : "") +
(isReadOnly() ? " [ReadOnly]" : "")) + ")";
return std::string(m_help + (m_defaultValue != std::string() ? "\ndefault: " + m_defaultValue : "") +
(isReadOnly() ? "[ReadOnly]" : ""));
}
bool CVar::fromString(std::string_view v)
atVec4f CVar::toVec4f(bool* isValid) const
{
if (isCheat() && (com_developer && !com_developer->value() && !com_enableCheats->value()))
if (m_type != EType::Vec4f)
{
if (isValid != nullptr)
*isValid = false;
return atVec4f{};
}
if (isValid != nullptr)
*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;
athena::utility::tolower(tmp);
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 (isReadOnly() && (com_developer && !com_developer->value()))
if (m_type != EType::Vec4f)
return false;
bool ret = _fromString(v);
if (ret)
m_flags |= EFlags::Modified;
return ret;
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::isModified() const { return int(m_flags & EFlags::Modified) != 0; }
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::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;
std::sscanf(val.data(), "%f %f %f %f", &vec.vec[0], &vec.vec[1], &vec.vec[2], &vec.vec[3]);
return fromVec4f(vec);
}
}
if (setDefault)
m_value = m_defaultValue;
return false;
}
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;
std::swscanf(val.data(), L"%f %f %f %f", &vec.vec[0], &vec.vec[1], &vec.vec[2], &vec.vec[3]);
return fromVec4f(vec);
}
}
if (setDefault)
m_value = m_defaultValue;
return false;
}
bool CVar::isModified() const { return int(m_flags & EFlags::Modified) != 0;}
bool CVar::modificationRequiresRestart() const { return int(m_flags & EFlags::ModifyRestart) != 0; }
bool CVar::isReadOnly() const { return int(m_flags & EFlags::ReadOnly) != 0; }
@ -55,6 +443,8 @@ bool CVar::isInternalArchivable() const { return int(m_flags & EFlags::InternalA
bool CVar::wasDeserialized() const { return m_wasDeserialized; }
bool CVar::hasDefaultValue() const { return m_defaultValue == m_value; }
void CVar::clearModified()
{
if (!modificationRequiresRestart())
@ -82,293 +472,10 @@ void CVar::lock()
}
}
template <typename T>
TCVar<T>::TCVar(T& value, std::string_view name, std::string_view description, EFlags flags)
: CVar(name, description, flags)
, m_value(value)
, m_defaultValue(value)
void CVar::dispatch()
{
}
template<typename T>
std::string TCVar<T>::toString() const
{
std::stringstream ss;
ss << std::boolalpha << m_value;
return ss.str();
}
template<typename T>
std::wstring TCVar<T>::toWideString() const
{
return hecl::UTF8ToWide(toString());
}
template<typename T>
bool TCVar<T>::_fromString(std::string_view v)
{
T tmp;
std::stringstream ss;
ss << std::boolalpha << v;
ss >> tmp;
if (ss.good())
m_value = tmp;
return ss.good();
}
template<typename T>
void TCVar<T>::deserialize(athena::io::YAMLDocReader &reader)
{
m_value = reader.readVal<T>(m_name.c_str());
}
template<typename T>
void TCVar<T>::serialize(athena::io::YAMLDocWriter& writer) const
{
writer.writeVal(m_name.c_str(), m_value);
}
template<typename T>
bool TCVar<T>::hasDefaultValue() const
{
return m_value == m_defaultValue;
}
template<typename T>
T TCVar<T>::value() const
{
return m_value;
}
template<typename T>
T TCVar<T>::defaultValue() const
{
return m_defaultValue;
}
template<typename T>
std::string TCVar<T>::defaultValueString() const
{
std::stringstream ss;
ss << std::boolalpha << m_defaultValue;
return ss.str();
}
Vec3fCVar::Vec3fCVar(atVec3f &value, std::string_view name, std::string_view description, CVar::EFlags flags)
: CVar(name, description, flags)
, m_value(value)
, m_defaultValue(value)
{}
std::string Vec3fCVar::toString() const
{
return athena::utility::sprintf("%f %f %f", double(m_value.vec[0]), double(m_value.vec[1]), double(m_value.vec[2]));
}
bool Vec3fCVar::_fromString(std::string_view v)
{
float x, y, z;
if (std::sscanf(v.data(), "%f %f %f", &x, &y, &z) != 3)
return false;
m_value.vec[0] = x;
m_value.vec[1] = y;
m_value.vec[2] = y;
return true;
}
bool Vec3fCVar::hasDefaultValue() const
{
return !memcmp(&m_value.vec, &m_defaultValue.vec[0], sizeof(atVec3f));
}
void Vec3fCVar::deserialize(athena::io::YAMLDocReader& reader)
{
m_value = reader.readVec3f(m_name.c_str());
}
void Vec3fCVar::serialize(athena::io::YAMLDocWriter& writer) const
{
writer.writeVec3f(m_name.c_str(), m_value);
}
std::string Vec3fCVar::defaultValueString() const
{
return athena::utility::sprintf("%f %f %f", double(m_defaultValue.vec[0]), double(m_defaultValue.vec[1]), double(m_defaultValue.vec[2]));
}
Vec3dCVar::Vec3dCVar(atVec3d &value, std::string_view name, std::string_view description, CVar::EFlags flags)
: CVar(name, description, flags)
, m_value(value)
, m_defaultValue(value)
{}
std::string Vec3dCVar::toString() const
{
return athena::utility::sprintf("%lf %lf %lf", m_value.vec[0], m_value.vec[1], m_value.vec[2]);
}
bool Vec3dCVar::_fromString(std::string_view v)
{
double x, y, z;
if (std::sscanf(v.data(), "%lf %lf %lf", &x, &y, &z) != 3)
return false;
m_value.vec[0] = x;
m_value.vec[1] = y;
m_value.vec[2] = y;
return true;
}
bool Vec3dCVar::hasDefaultValue() const
{
return !memcmp(&m_value.vec, &m_defaultValue.vec[0], sizeof(atVec3d));
}
void Vec3dCVar::deserialize(athena::io::YAMLDocReader& reader)
{
m_value = reader.readVec3d(m_name.c_str());
}
void Vec3dCVar::serialize(athena::io::YAMLDocWriter& writer) const
{
writer.writeVec3d(m_name.c_str(), m_value);
}
std::string Vec3dCVar::defaultValueString() const
{
return athena::utility::sprintf("%g %g %g", m_defaultValue.vec[0], m_defaultValue.vec[1], m_defaultValue.vec[2]);
}
Vec4fCVar::Vec4fCVar(atVec4f &value, std::string_view name, std::string_view description, CVar::EFlags flags)
: CVar(name, description, flags)
, m_value(value)
, m_defaultValue(value)
{}
std::string Vec4fCVar::toString() const
{
return athena::utility::sprintf("%g %g %g %g", &m_value.vec[0], &m_value.vec[1], &m_value.vec[2], &m_value.vec[3]);
}
bool Vec4fCVar::_fromString(std::string_view v)
{
float x, y, z, w;
if (std::sscanf(v.data(), "%f %f %f %f", &x, &y, &z, &w) != 4)
return false;
m_value.vec[0] = x;
m_value.vec[1] = y;
m_value.vec[2] = y;
m_value.vec[3] = w;
return true;
}
bool Vec4fCVar::hasDefaultValue() const
{
return !memcmp(&m_value.vec, &m_defaultValue.vec[0], sizeof(atVec4f));
}
void Vec4fCVar::deserialize(athena::io::YAMLDocReader& reader)
{
m_value = reader.readVec4f(m_name.c_str());
}
void Vec4fCVar::serialize(athena::io::YAMLDocWriter& writer) const
{
writer.writeVec4f(m_name.c_str(), m_value);
}
std::string Vec4fCVar::defaultValueString() const
{
return athena::utility::sprintf("%f %f %f", &m_defaultValue.vec[0], &m_defaultValue.vec[1], &m_defaultValue.vec[2]);
}
Vec4dCVar::Vec4dCVar(atVec4d &value, std::string_view name, std::string_view description, CVar::EFlags flags)
: CVar(name, description, flags)
, m_value(value)
, m_defaultValue(value)
{}
std::string Vec4dCVar::toString() const
{
return athena::utility::sprintf("%f %f %f %f", m_value.vec[0], m_value.vec[1], m_value.vec[2], m_value.vec[3]);
}
bool Vec4dCVar::_fromString(std::string_view v)
{
double x, y, z, w;
if (std::sscanf(v.data(), "%lf %lf %lf %lf", &x, &y, &z, &w) != 4)
return false;
m_value.vec[0] = x;
m_value.vec[1] = y;
m_value.vec[2] = y;
m_value.vec[3] = w;
return true;
}
bool Vec4dCVar::hasDefaultValue() const
{
return !memcmp(&m_value.vec, &m_defaultValue.vec[0], sizeof(atVec4d));
}
void Vec4dCVar::deserialize(athena::io::YAMLDocReader& reader)
{
m_value = reader.readVec4d(m_name.c_str());
}
void Vec4dCVar::serialize(athena::io::YAMLDocWriter& writer) const
{
writer.writeVec4d(m_name.c_str(), m_value);
}
std::string Vec4dCVar::defaultValueString() const
{
return athena::utility::sprintf("%g %g %g", m_defaultValue.vec[0], m_defaultValue.vec[1], m_defaultValue.vec[2]);
}
StringCVar::StringCVar(std::string& value, std::string_view name, std::string_view help, CVar::EFlags flags)
: CVar(name, help, flags)
, m_value(value)
, m_defaultValue(value)
{
}
std::string StringCVar::toString() const
{
return m_value;
}
bool StringCVar::_fromString(std::string_view v)
{
m_value = v;
return true;
}
bool StringCVar::hasDefaultValue() const
{
return m_value == m_defaultValue;
}
void StringCVar::deserialize(athena::io::YAMLDocReader& reader)
{
m_value = reader.readString(m_name.c_str());
}
void StringCVar::serialize(athena::io::YAMLDocWriter& writer) const
{
writer.writeString(m_name.c_str(), m_value.c_str());
}
template class TCVar<bool>;
template class TCVar<int16_t>;
template class TCVar<uint16_t>;
template class TCVar<int32_t>;
template class TCVar<uint32_t>;
template class TCVar<int64_t>;
template class TCVar<uint64_t>;
template class TCVar<float>;
template class TCVar<double>;
for (const ListenerFunc& listen : m_listeners)
listen(this);
}
}

View File

@ -1,5 +1,4 @@
#include "hecl/CVarManager.hpp"
#include "hecl/CVar.hpp"
#include "hecl/Console.hpp"
#include <athena/FileWriter.hpp>
#include <athena/Utility.hpp>
@ -9,10 +8,9 @@
namespace hecl
{
BoolCVar* com_developer = nullptr;
StringCVar* com_configfile = nullptr;
BoolCVar* com_enableCheats = nullptr;
CVar* com_developer = nullptr;
CVar* com_configfile = nullptr;
CVar* com_enableCheats = nullptr;
CVarManager* CVarManager::m_instance = nullptr;
@ -22,24 +20,15 @@ CVarManager::CVarManager(hecl::Runtime::FileStoreManager& store, bool useBinary)
m_useBinary(useBinary)
{
m_instance = this;
com_configfile = dynamic_cast<StringCVar*>(findOrMakeCVar("config", "File to store configuration", m_configFile, CVar::EFlags::System));
com_developer = dynamic_cast<BoolCVar*>(findOrMakeCVar("developer", "Enables developer mode", m_developerMode, (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::InternalArchivable)));
com_enableCheats = dynamic_cast<BoolCVar*>(findOrMakeCVar("iamaweiner", "Enable cheats", m_enableCheats, (CVar::EFlags::System | CVar::EFlags::ReadOnly | CVar::EFlags::Hidden)));
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::ReadOnly | CVar::EFlags::InternalArchivable));
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->clearModified();
}
}
bool CVarManager::registerCVar(CVar* cvar)
{
std::string tmp(cvar->name());
@ -86,53 +75,88 @@ void CVarManager::deserialize(CVar* cvar)
if (!cvar || (!cvar->isArchive() && !cvar->isInternalArchivable()))
return;
CVarContainer container;
#if _WIN32
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _S('/') + hecl::UTF8ToWide(m_configFile);
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _S('/') + com_configfile->toWideLiteral();
#else
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _S('/') + m_configFile;
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _S('/') + com_configfile->toLiteral();
#endif
hecl::Sstat st;
filename += _S(".yaml");
if (hecl::Stat(filename.c_str(), &st) || !S_ISREG(st.st_mode))
return;
athena::io::FileReader reader(filename);
if (reader.isOpen())
if (m_useBinary)
{
athena::io::YAMLDocReader doc;
doc.parse(&reader);
if (doc.hasVal(cvar->name().c_str()))
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;
athena::io::FileReader reader(filename);
if (reader.isOpen())
container.fromYAMLStream(reader);
}
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())
{
cvar->unlock();
cvar->deserialize(doc);
cvar->m_wasDeserialized = true;;
cvar->lock();
DNACVAR::CVar& tmp = *serialized;
if (cvar->m_value != tmp.m_value)
{
cvar->unlock();
cvar->fromLiteralToType(tmp.m_value, true);
cvar->m_wasDeserialized = true;
cvar->lock();
}
}
}
}
void CVarManager::serialize()
{
CVarContainer container;
for (const std::pair<std::string, CVar*>& pair : m_cvars)
if (pair.second->isArchive() || (pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
{
CVar tmp = *pair.second;
container.cvars.push_back(tmp);
}
container.cvarCount = atUint32(container.cvars.size());
#if _WIN32
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _S('/') + hecl::UTF8ToWide(m_configFile);
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _S('/') + com_configfile->toWideLiteral();
#else
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _S('/') + m_configFile;
hecl::SystemString filename = hecl::SystemString(m_store.getStoreRoot()) + _S('/') + com_configfile->toLiteral();
#endif
filename += _S(".yaml");
athena::io::FileWriter writer(filename);
if (writer.isOpen())
if (m_useBinary)
{
athena::io::YAMLDocWriter doc(nullptr);
for (const std::pair<std::string, CVar*>& pair : m_cvars)
if (pair.second->isArchive() || (pair.second->isInternalArchivable() && pair.second->wasDeserialized() && !pair.second->hasDefaultValue()))
pair.second->serialize(doc);
doc.finish(&writer);
filename += _S(".bin");
athena::io::FileWriter writer(filename);
if (writer.isOpen())
container.write(writer);
}
else
{
filename += _S(".yaml");
athena::io::FileWriter writer(filename);
if (writer.isOpen())
container.toYAMLStream(writer);
}
}
CVarManager* CVarManager::instance()
{
return m_instance;
@ -169,9 +193,8 @@ void CVarManager::setCVar(Console* con, const std::vector<std::string> &args)
for (; it != args.end(); ++it)
value += " " + *it;
if (!cv->fromString(value))
con->report(Console::Level::Warning, "Unable to cvar '%s' to value '%s'", args[0].c_str(), value.c_str());
if (!cv->fromLiteralToType(value))
con->report(Console::Level::Warning, "Unable to set cvar '%s' to value '%s'", args[0].c_str(), value.c_str());
}
void CVarManager::getCVar(Console* con, const std::vector<std::string> &args)
@ -191,7 +214,18 @@ void CVarManager::getCVar(Console* con, const std::vector<std::string> &args)
}
const CVar* cv = m_cvars[cvName];
con->report(Console::Level::Info, "'%s' = '%s'", cv->name().data(), cv->toString().c_str());
con->report(Console::Level::Info, "'%s' = '%s'", cv->name().data(), cv->value().c_str());
}
void CVarManager::setDeveloperMode(bool v, bool setDeserialized)
{
com_developer->unlock();
com_developer->fromBoolean(v);
if (setDeserialized)
com_developer->m_wasDeserialized = true;
com_developer->lock();
com_developer->setModified();
}
bool CVarManager::restartRequired() const
@ -205,27 +239,19 @@ bool CVarManager::restartRequired() const
return false;
}
void CVarManager::setDeveloperMode(bool v, bool setDeserialized)
{
com_developer->unlock();
com_developer->m_value = v;
if (setDeserialized)
com_developer->m_wasDeserialized = true;
com_developer->lock();
com_developer->setModified();
}
bool CVarManager::suppressDeveloper()
{
bool oldDeveloper = m_developerMode;
m_developerMode = false;
return oldDeveloper;
bool oldDeveloper = com_developer->toBoolean();
CVarUnlocker unlock(com_developer);
com_developer->fromBoolean(false);
return oldDeveloper;
}
void CVarManager::restoreDeveloper(bool oldDeveloper)
{
m_developerMode = oldDeveloper;
CVarUnlocker unlock(com_developer);
com_developer->fromBoolean(oldDeveloper);
}
}

View File

@ -17,10 +17,11 @@ Console::Console(CVarManager* cvarMgr)
registerCommand("listCVars", "Lists all available CVars", "", std::bind(&CVarManager::list, m_cvarMgr, std::placeholders::_1, std::placeholders::_2));
registerCommand("setCVar", "Sets a given Console Variable to the specified value", "<cvar> <value>", std::bind(&CVarManager::setCVar, m_cvarMgr, std::placeholders::_1, std::placeholders::_2));
registerCommand("getCVar", "Prints the value stored in the specified Console Variable", "<cvar>", std::bind(&CVarManager::getCVar, m_cvarMgr, std::placeholders::_1, std::placeholders::_2));
m_cvarMgr->findOrMakeCVar("con_speed", "Speed at which the console opens and closes, calculated as pixels per second", m_conSpeed,
m_conSpeed = cvarMgr->findOrMakeCVar("con_speed", "Speed at which the console opens and closes, calculated as pixels per second", 1.f,
hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive);
m_cvarMgr->findOrMakeCVar("con_height", "Maximum absolute height of the console, height is calculated from the top of the window, expects values ranged from [0.f,1.f]", m_conHeight,
m_conHeight = cvarMgr->findOrMakeCVar("con_height", "Maximum absolute height of the console, height is calculated from the top of the window, expects values ranged from [0.f,1.f]", 0.5f,
hecl::CVar::EFlags::System | hecl::CVar::EFlags::Archive);
}
void Console::registerCommand(std::string_view name, std::string_view helpText, std::string_view usage, const std::function<void(Console*, const std::vector<std::string> &)>&& func)
@ -115,6 +116,18 @@ void Console::report(Level level, const char* fmt, ...)
void Console::proc()
{
if (m_conHeight->isModified())
{
m_cachedConHeight = m_conHeight->toFloat();
m_conHeight->clearModified();
}
if (m_conSpeed->isModified())
{
m_cachedConSpeed = m_conSpeed->toFloat();
m_conSpeed->clearModified();
}
if (m_state == State::Opened)
{
printf("\r%s ", m_commandString.c_str());
@ -161,7 +174,7 @@ void Console::handleCharCode(unsigned long chr, boo::EModifierKey /*mod*/, bool
m_commandString.insert(m_commandString.begin() + m_cursorPosition + 1, char(chr));
}
else
m_commandString += char(chr);
m_commandString += char(chr);
++m_cursorPosition;
}
@ -282,8 +295,8 @@ void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, b
else
m_cursorPosition++;
// m_showCursor = true;
// m_cursorTime = 0;
// m_showCursor = true;
// m_cursorTime = 0;
break;
}
@ -373,7 +386,7 @@ void Console::dumpLog()
{
case Level::Info:
printf("%s\n", l.first.c_str());
break;
break;
case Level::Warning:
printf("[Warning] %s\n", l.first.c_str());
break;