You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Legacy/CrySystem/XConsoleVariable.cpp

569 lines
12 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// Description : implementation of the CXConsoleVariable class.
#include "CrySystem_precompiled.h"
#include "XConsole.h"
#include "XConsoleVariable.h"
#include <IConsole.h>
#include <ISystem.h>
#include <algorithm>
namespace
{
using stack_string = AZStd::fixed_string<512>;
uint64 AlphaBit64(char c)
{
return (c >= 'a' && c <= 'z' ? 1U << (c - 'z' + 31) : 0) |
(c >= 'A' && c <= 'Z' ? 1LL << (c - 'Z' + 63) : 0);
}
int64 TextToInt64(const char* s, int64 nCurrent, bool bBitfield)
{
int64 nValue = 0;
if (s)
{
char* e;
if (bBitfield)
{
// Bit manipulation.
if (*s == '^')
// Bit number
#if defined(_MSC_VER)
{
nValue = 1LL << _strtoi64(++s, &e, 10);
}
#else
{
nValue = 1LL << strtoll(++s, &e, 10);
}
#endif
else
// Full number
#if defined(_MSC_VER)
{
nValue = _strtoi64(s, &e, 10);
}
#else
{
nValue = strtoll(s, &e, 10);
}
#endif
// Check letter codes.
for (; (*e >= 'a' && *e <= 'z') || (*e >= 'A' && *e <= 'Z'); e++)
{
nValue |= AlphaBit64(*e);
}
if (*e == '+')
{
nValue = nCurrent | nValue;
}
else if (*e == '-')
{
nValue = nCurrent & ~nValue;
}
else if (*e == '^')
{
nValue = nCurrent ^ nValue;
}
}
else
#if defined(_MSC_VER)
{
nValue = _strtoi64(s, &e, 10);
}
#else
{
nValue = strtoll(s, &e, 10);
}
#endif
}
return nValue;
}
int TextToInt(const char* s, int nCurrent, bool bBitfield)
{
return (int)TextToInt64(s, nCurrent, bBitfield);
}
} // namespace
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CXConsoleVariableBase::CXConsoleVariableBase(CXConsole* pConsole, const char* sName, int nFlags, const char* help)
: m_valueMin(0.0f)
, m_valueMax(100.0f)
, m_hasCustomLimits(false)
{
assert(pConsole);
m_psHelp = (char*)help;
m_pChangeFunc = NULL;
m_pConsole = pConsole;
m_nFlags = nFlags;
if (nFlags & VF_COPYNAME)
{
m_szName = new char[strlen(sName) + 1];
azstrcpy(m_szName, strlen(sName) + 1, sName);
}
else
{
m_szName = (char*)sName;
}
if (gEnv->IsDedicated())
{
m_pDataProbeString = NULL;
}
}
//////////////////////////////////////////////////////////////////////////
CXConsoleVariableBase::~CXConsoleVariableBase()
{
if (m_nFlags & VF_COPYNAME)
{
delete[] m_szName;
}
if (gEnv->IsDedicated() && m_pDataProbeString)
{
delete[] m_pDataProbeString;
}
}
//////////////////////////////////////////////////////////////////////////
void CXConsoleVariableBase::ForceSet(const char* s)
{
int excludeFlags = (VF_CHEAT | VF_READONLY | VF_NET_SYNCED);
int oldFlags = (m_nFlags & excludeFlags);
m_nFlags &= ~(excludeFlags);
Set(s);
m_nFlags |= oldFlags;
}
//////////////////////////////////////////////////////////////////////////
void CXConsoleVariableBase::ClearFlags(int flags)
{
m_nFlags &= ~flags;
}
//////////////////////////////////////////////////////////////////////////
int CXConsoleVariableBase::GetFlags() const
{
return m_nFlags;
}
//////////////////////////////////////////////////////////////////////////
int CXConsoleVariableBase::SetFlags(int flags)
{
m_nFlags = flags;
return m_nFlags;
}
//////////////////////////////////////////////////////////////////////////
const char* CXConsoleVariableBase::GetName() const
{
return m_szName;
}
//////////////////////////////////////////////////////////////////////////
const char* CXConsoleVariableBase::GetHelp()
{
return m_psHelp;
}
void CXConsoleVariableBase::Release()
{
m_pConsole->UnregisterVariable(m_szName);
}
void CXConsoleVariableBase::SetOnChangeCallback(ConsoleVarFunc pChangeFunc)
{
m_pChangeFunc = pChangeFunc;
}
uint64 CXConsoleVariableBase::AddOnChangeFunctor(const AZStd::function<void()>& pChangeFunctor)
{
static int uniqueIdGenerator = 0;
int newId = uniqueIdGenerator++;
m_changeFunctors.push_back(std::make_pair(newId, pChangeFunctor));
return newId;
}
ConsoleVarFunc CXConsoleVariableBase::GetOnChangeCallback() const
{
return m_pChangeFunc;
}
void CXConsoleVariableBase::CallOnChangeFunctions()
{
if (m_pChangeFunc)
{
m_pChangeFunc(this);
}
const size_t nTotal(m_changeFunctors.size());
for (size_t nCount = 0; nCount < nTotal; ++nCount)
{
m_changeFunctors[nCount].second();
}
}
void CXConsoleVariableBase::SetLimits(float min, float max)
{
m_valueMin = min;
m_valueMax = max;
// Flag to determine when this variable has custom limits set
m_hasCustomLimits = true;
}
void CXConsoleVariableBase::GetLimits(float& min, float& max)
{
min = m_valueMin;
max = m_valueMax;
}
bool CXConsoleVariableBase::HasCustomLimits()
{
return m_hasCustomLimits;
}
const char* CXConsoleVariableBase::GetDataProbeString() const
{
if (gEnv->IsDedicated() && m_pDataProbeString)
{
return m_pDataProbeString;
}
return GetOwnDataProbeString();
}
void CXConsoleVariableString::Set(const char* s)
{
if (!s)
{
return;
}
if ((m_sValue == s) && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
if (m_pConsole->OnBeforeVarChange(this, s))
{
m_nFlags |= VF_MODIFIED;
{
m_sValue = s;
}
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
void CXConsoleVariableString::Set(float f)
{
stack_string s = stack_string::format("%g", f);
if ((m_sValue == s.c_str()) && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
m_nFlags |= VF_MODIFIED;
Set(s.c_str());
}
void CXConsoleVariableString::Set(int i)
{
stack_string s = stack_string::format("%d", i);
if ((m_sValue == s.c_str()) && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
m_nFlags |= VF_MODIFIED;
Set(s.c_str());
}
const char* CXConsoleVariableInt::GetString() const
{
static char szReturnString[256];
sprintf_s(szReturnString, "%d", GetIVal());
return szReturnString;
}
void CXConsoleVariableInt::Set(const char* s)
{
int nValue = TextToInt(s, m_iValue, (m_nFlags & VF_BITFIELD) != 0);
Set(nValue);
}
void CXConsoleVariableInt::Set(float f)
{
Set((int)f);
}
void CXConsoleVariableInt::Set(int i)
{
if (i == m_iValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
stack_string s = stack_string::format("%d", i);
if (m_pConsole->OnBeforeVarChange(this, s.c_str()))
{
m_nFlags |= VF_MODIFIED;
m_iValue = i;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
const char* CXConsoleVariableIntRef::GetString() const
{
static char szReturnString[256];
sprintf_s(szReturnString, "%d", m_iValue);
return szReturnString;
}
void CXConsoleVariableIntRef::Set(const char* s)
{
int nValue = TextToInt(s, m_iValue, (m_nFlags & VF_BITFIELD) != 0);
if (nValue == m_iValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
if (m_pConsole->OnBeforeVarChange(this, s))
{
m_nFlags |= VF_MODIFIED;
m_iValue = nValue;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
void CXConsoleVariableIntRef::Set(float f)
{
if ((int)f == m_iValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
char sTemp[128];
sprintf_s(sTemp, "%g", f);
if (m_pConsole->OnBeforeVarChange(this, sTemp))
{
m_nFlags |= VF_MODIFIED;
m_iValue = (int)f;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
void CXConsoleVariableIntRef::Set(int i)
{
if (i == m_iValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
char sTemp[128];
sprintf_s(sTemp, "%d", i);
if (m_pConsole->OnBeforeVarChange(this, sTemp))
{
m_nFlags |= VF_MODIFIED;
m_iValue = i;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
const char* CXConsoleVariableFloat::GetString() const
{
static char szReturnString[256];
sprintf_s(szReturnString, "%g", m_fValue); // %g -> "2.01", %f -> "2.01000"
return szReturnString;
}
void CXConsoleVariableFloat::Set(const char* s)
{
float fValue = 0;
if (s)
{
fValue = (float)atof(s);
}
if (fValue == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
if (m_pConsole->OnBeforeVarChange(this, s))
{
m_nFlags |= VF_MODIFIED;
m_fValue = fValue;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
void CXConsoleVariableFloat::Set(float f)
{
if (f == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
stack_string s = stack_string::format("%g", f);
if (m_pConsole->OnBeforeVarChange(this, s.c_str()))
{
m_nFlags |= VF_MODIFIED;
m_fValue = f;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
void CXConsoleVariableFloat::Set(int i)
{
if ((float)i == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
char sTemp[128];
sprintf_s(sTemp, "%d", i);
if (m_pConsole->OnBeforeVarChange(this, sTemp))
{
m_nFlags |= VF_MODIFIED;
m_fValue = (float)i;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
const char* CXConsoleVariableFloatRef::GetString() const
{
static char szReturnString[256];
sprintf_s(szReturnString, "%g", m_fValue);
return szReturnString;
}
void CXConsoleVariableFloatRef::Set(const char *s)
{
float fValue = 0;
if (s)
{
fValue = (float)atof(s);
}
if (fValue == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
if (m_pConsole->OnBeforeVarChange(this, s))
{
m_nFlags |= VF_MODIFIED;
m_fValue = fValue;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
void CXConsoleVariableFloatRef::Set(float f)
{
if (f == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
char sTemp[128];
sprintf_s(sTemp, "%g", f);
if (m_pConsole->OnBeforeVarChange(this, sTemp))
{
m_nFlags |= VF_MODIFIED;
m_fValue = f;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
void CXConsoleVariableFloatRef::Set(int i)
{
if ((float)i == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
char sTemp[128];
sprintf_s(sTemp, "%d", i);
if (m_pConsole->OnBeforeVarChange(this, sTemp))
{
m_nFlags |= VF_MODIFIED;
m_fValue = (float)i;
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}
void CXConsoleVariableStringRef::Set(const char *s)
{
if ((m_sValue == s) && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
{
return;
}
if (m_pConsole->OnBeforeVarChange(this, s))
{
m_nFlags |= VF_MODIFIED;
{
m_sValue = s;
m_userPtr = m_sValue.c_str();
}
CallOnChangeFunctions();
m_pConsole->OnAfterVarChange(this);
}
}