XConsoleVariable.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : implementation of the CXConsoleVariable class.
  9. #include "CrySystem_precompiled.h"
  10. #include "XConsole.h"
  11. #include "XConsoleVariable.h"
  12. #include <IConsole.h>
  13. #include <ISystem.h>
  14. #include <algorithm>
  15. #include <AzCore/Serialization/Locale.h>
  16. namespace
  17. {
  18. using stack_string = AZStd::fixed_string<512>;
  19. uint64 AlphaBit64(char c)
  20. {
  21. return (c >= 'a' && c <= 'z' ? 1U << (c - 'z' + 31) : 0) |
  22. (c >= 'A' && c <= 'Z' ? 1LL << (c - 'Z' + 63) : 0);
  23. }
  24. int64 TextToInt64(const char* s, int64 nCurrent, bool bBitfield)
  25. {
  26. int64 nValue = 0;
  27. if (s)
  28. {
  29. char* e;
  30. if (bBitfield)
  31. {
  32. // Bit manipulation.
  33. if (*s == '^')
  34. // Bit number
  35. #if defined(_MSC_VER)
  36. {
  37. nValue = 1LL << _strtoi64(++s, &e, 10);
  38. }
  39. #else
  40. {
  41. nValue = 1LL << strtoll(++s, &e, 10);
  42. }
  43. #endif
  44. else
  45. // Full number
  46. #if defined(_MSC_VER)
  47. {
  48. nValue = _strtoi64(s, &e, 10);
  49. }
  50. #else
  51. {
  52. nValue = strtoll(s, &e, 10);
  53. }
  54. #endif
  55. // Check letter codes.
  56. for (; (*e >= 'a' && *e <= 'z') || (*e >= 'A' && *e <= 'Z'); e++)
  57. {
  58. nValue |= AlphaBit64(*e);
  59. }
  60. if (*e == '+')
  61. {
  62. nValue = nCurrent | nValue;
  63. }
  64. else if (*e == '-')
  65. {
  66. nValue = nCurrent & ~nValue;
  67. }
  68. else if (*e == '^')
  69. {
  70. nValue = nCurrent ^ nValue;
  71. }
  72. }
  73. else
  74. #if defined(_MSC_VER)
  75. {
  76. nValue = _strtoi64(s, &e, 10);
  77. }
  78. #else
  79. {
  80. nValue = strtoll(s, &e, 10);
  81. }
  82. #endif
  83. }
  84. return nValue;
  85. }
  86. int TextToInt(const char* s, int nCurrent, bool bBitfield)
  87. {
  88. return (int)TextToInt64(s, nCurrent, bBitfield);
  89. }
  90. } // namespace
  91. //////////////////////////////////////////////////////////////////////
  92. // Construction/Destruction
  93. //////////////////////////////////////////////////////////////////////
  94. CXConsoleVariableBase::CXConsoleVariableBase(CXConsole* pConsole, const char* sName, int nFlags, const char* help)
  95. : m_valueMin(0.0f)
  96. , m_valueMax(100.0f)
  97. , m_hasCustomLimits(false)
  98. {
  99. assert(pConsole);
  100. m_psHelp = (char*)help;
  101. m_pChangeFunc = NULL;
  102. m_pConsole = pConsole;
  103. m_nFlags = nFlags;
  104. if (nFlags & VF_COPYNAME)
  105. {
  106. m_szName = new char[strlen(sName) + 1];
  107. azstrcpy(m_szName, strlen(sName) + 1, sName);
  108. }
  109. else
  110. {
  111. m_szName = (char*)sName;
  112. }
  113. if (gEnv->IsDedicated())
  114. {
  115. m_pDataProbeString = NULL;
  116. }
  117. }
  118. //////////////////////////////////////////////////////////////////////////
  119. CXConsoleVariableBase::~CXConsoleVariableBase()
  120. {
  121. if (m_nFlags & VF_COPYNAME)
  122. {
  123. delete[] m_szName;
  124. }
  125. if (gEnv->IsDedicated() && m_pDataProbeString)
  126. {
  127. delete[] m_pDataProbeString;
  128. }
  129. }
  130. //////////////////////////////////////////////////////////////////////////
  131. void CXConsoleVariableBase::ForceSet(const char* s)
  132. {
  133. int excludeFlags = (VF_CHEAT | VF_READONLY | VF_NET_SYNCED);
  134. int oldFlags = (m_nFlags & excludeFlags);
  135. m_nFlags &= ~(excludeFlags);
  136. Set(s);
  137. m_nFlags |= oldFlags;
  138. }
  139. //////////////////////////////////////////////////////////////////////////
  140. void CXConsoleVariableBase::ClearFlags(int flags)
  141. {
  142. m_nFlags &= ~flags;
  143. }
  144. //////////////////////////////////////////////////////////////////////////
  145. int CXConsoleVariableBase::GetFlags() const
  146. {
  147. return m_nFlags;
  148. }
  149. //////////////////////////////////////////////////////////////////////////
  150. int CXConsoleVariableBase::SetFlags(int flags)
  151. {
  152. m_nFlags = flags;
  153. return m_nFlags;
  154. }
  155. //////////////////////////////////////////////////////////////////////////
  156. const char* CXConsoleVariableBase::GetName() const
  157. {
  158. return m_szName;
  159. }
  160. //////////////////////////////////////////////////////////////////////////
  161. const char* CXConsoleVariableBase::GetHelp()
  162. {
  163. return m_psHelp;
  164. }
  165. void CXConsoleVariableBase::Release()
  166. {
  167. m_pConsole->UnregisterVariable(m_szName);
  168. }
  169. void CXConsoleVariableBase::SetOnChangeCallback(ConsoleVarFunc pChangeFunc)
  170. {
  171. m_pChangeFunc = pChangeFunc;
  172. }
  173. bool CXConsoleVariableBase::AddOnChangeFunctor(AZ::Name functorName, const AZStd::function<void()>& pChangeFunctor)
  174. {
  175. return m_changeFunctors.insert_or_assign(functorName, pChangeFunctor).second;
  176. }
  177. ConsoleVarFunc CXConsoleVariableBase::GetOnChangeCallback() const
  178. {
  179. return m_pChangeFunc;
  180. }
  181. void CXConsoleVariableBase::CallOnChangeFunctions()
  182. {
  183. if (m_pChangeFunc)
  184. {
  185. m_pChangeFunc(this);
  186. }
  187. for ([[maybe_unused]] auto [name, functor] : m_changeFunctors)
  188. {
  189. functor();
  190. }
  191. }
  192. void CXConsoleVariableBase::SetLimits(float min, float max)
  193. {
  194. m_valueMin = min;
  195. m_valueMax = max;
  196. // Flag to determine when this variable has custom limits set
  197. m_hasCustomLimits = true;
  198. }
  199. void CXConsoleVariableBase::GetLimits(float& min, float& max)
  200. {
  201. min = m_valueMin;
  202. max = m_valueMax;
  203. }
  204. bool CXConsoleVariableBase::HasCustomLimits()
  205. {
  206. return m_hasCustomLimits;
  207. }
  208. const char* CXConsoleVariableBase::GetDataProbeString() const
  209. {
  210. if (gEnv->IsDedicated() && m_pDataProbeString)
  211. {
  212. return m_pDataProbeString;
  213. }
  214. return GetOwnDataProbeString();
  215. }
  216. void CXConsoleVariableString::Set(const char* s)
  217. {
  218. if (!s)
  219. {
  220. return;
  221. }
  222. if ((m_sValue == s) && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  223. {
  224. return;
  225. }
  226. if (m_pConsole->OnBeforeVarChange(this, s))
  227. {
  228. m_nFlags |= VF_MODIFIED;
  229. {
  230. m_sValue = s;
  231. }
  232. CallOnChangeFunctions();
  233. m_pConsole->OnAfterVarChange(this);
  234. }
  235. }
  236. void CXConsoleVariableString::Set(float f)
  237. {
  238. stack_string s = stack_string::format("%g", f);
  239. if ((m_sValue == s.c_str()) && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  240. {
  241. return;
  242. }
  243. m_nFlags |= VF_MODIFIED;
  244. Set(s.c_str());
  245. }
  246. void CXConsoleVariableString::Set(int i)
  247. {
  248. stack_string s = stack_string::format("%d", i);
  249. if ((m_sValue == s.c_str()) && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  250. {
  251. return;
  252. }
  253. m_nFlags |= VF_MODIFIED;
  254. Set(s.c_str());
  255. }
  256. const char* CXConsoleVariableInt::GetString() const
  257. {
  258. static char szReturnString[256];
  259. sprintf_s(szReturnString, "%d", GetIVal());
  260. return szReturnString;
  261. }
  262. void CXConsoleVariableInt::Set(const char* s)
  263. {
  264. int nValue = TextToInt(s, m_iValue, (m_nFlags & VF_BITFIELD) != 0);
  265. Set(nValue);
  266. }
  267. void CXConsoleVariableInt::Set(float f)
  268. {
  269. Set((int)f);
  270. }
  271. void CXConsoleVariableInt::Set(int i)
  272. {
  273. if (i == m_iValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  274. {
  275. return;
  276. }
  277. stack_string s = stack_string::format("%d", i);
  278. if (m_pConsole->OnBeforeVarChange(this, s.c_str()))
  279. {
  280. m_nFlags |= VF_MODIFIED;
  281. m_iValue = i;
  282. CallOnChangeFunctions();
  283. m_pConsole->OnAfterVarChange(this);
  284. }
  285. }
  286. const char* CXConsoleVariableIntRef::GetString() const
  287. {
  288. static char szReturnString[256];
  289. sprintf_s(szReturnString, "%d", m_iValue);
  290. return szReturnString;
  291. }
  292. void CXConsoleVariableIntRef::Set(const char* s)
  293. {
  294. int nValue = TextToInt(s, m_iValue, (m_nFlags & VF_BITFIELD) != 0);
  295. if (nValue == m_iValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  296. {
  297. return;
  298. }
  299. if (m_pConsole->OnBeforeVarChange(this, s))
  300. {
  301. m_nFlags |= VF_MODIFIED;
  302. m_iValue = nValue;
  303. CallOnChangeFunctions();
  304. m_pConsole->OnAfterVarChange(this);
  305. }
  306. }
  307. void CXConsoleVariableIntRef::Set(float f)
  308. {
  309. if ((int)f == m_iValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  310. {
  311. return;
  312. }
  313. char sTemp[128];
  314. sprintf_s(sTemp, "%g", f);
  315. if (m_pConsole->OnBeforeVarChange(this, sTemp))
  316. {
  317. m_nFlags |= VF_MODIFIED;
  318. m_iValue = (int)f;
  319. CallOnChangeFunctions();
  320. m_pConsole->OnAfterVarChange(this);
  321. }
  322. }
  323. void CXConsoleVariableIntRef::Set(int i)
  324. {
  325. if (i == m_iValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  326. {
  327. return;
  328. }
  329. char sTemp[128];
  330. sprintf_s(sTemp, "%d", i);
  331. if (m_pConsole->OnBeforeVarChange(this, sTemp))
  332. {
  333. m_nFlags |= VF_MODIFIED;
  334. m_iValue = i;
  335. CallOnChangeFunctions();
  336. m_pConsole->OnAfterVarChange(this);
  337. }
  338. }
  339. const char* CXConsoleVariableFloat::GetString() const
  340. {
  341. static char szReturnString[256];
  342. sprintf_s(szReturnString, "%g", m_fValue); // %g -> "2.01", %f -> "2.01000"
  343. return szReturnString;
  344. }
  345. void CXConsoleVariableFloat::Set(const char* s)
  346. {
  347. float fValue = 0;
  348. if (s)
  349. {
  350. // console commands are interpreted in the invarant locale as they come from cfg files which need to be
  351. // portable.
  352. AZ::Locale::ScopedSerializationLocale scopedLocale;
  353. fValue = (float)atof(s);
  354. }
  355. if (fValue == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  356. {
  357. return;
  358. }
  359. if (m_pConsole->OnBeforeVarChange(this, s))
  360. {
  361. m_nFlags |= VF_MODIFIED;
  362. m_fValue = fValue;
  363. CallOnChangeFunctions();
  364. m_pConsole->OnAfterVarChange(this);
  365. }
  366. }
  367. void CXConsoleVariableFloat::Set(float f)
  368. {
  369. if (f == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  370. {
  371. return;
  372. }
  373. stack_string s = stack_string::format("%g", f);
  374. if (m_pConsole->OnBeforeVarChange(this, s.c_str()))
  375. {
  376. m_nFlags |= VF_MODIFIED;
  377. m_fValue = f;
  378. CallOnChangeFunctions();
  379. m_pConsole->OnAfterVarChange(this);
  380. }
  381. }
  382. void CXConsoleVariableFloat::Set(int i)
  383. {
  384. if ((float)i == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  385. {
  386. return;
  387. }
  388. char sTemp[128];
  389. sprintf_s(sTemp, "%d", i);
  390. if (m_pConsole->OnBeforeVarChange(this, sTemp))
  391. {
  392. m_nFlags |= VF_MODIFIED;
  393. m_fValue = (float)i;
  394. CallOnChangeFunctions();
  395. m_pConsole->OnAfterVarChange(this);
  396. }
  397. }
  398. const char* CXConsoleVariableFloatRef::GetString() const
  399. {
  400. static char szReturnString[256];
  401. sprintf_s(szReturnString, "%g", m_fValue);
  402. return szReturnString;
  403. }
  404. void CXConsoleVariableFloatRef::Set(const char *s)
  405. {
  406. float fValue = 0;
  407. if (s)
  408. {
  409. AZ::Locale::ScopedSerializationLocale scopedLocale;
  410. fValue = (float)atof(s);
  411. }
  412. if (fValue == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  413. {
  414. return;
  415. }
  416. if (m_pConsole->OnBeforeVarChange(this, s))
  417. {
  418. m_nFlags |= VF_MODIFIED;
  419. m_fValue = fValue;
  420. CallOnChangeFunctions();
  421. m_pConsole->OnAfterVarChange(this);
  422. }
  423. }
  424. void CXConsoleVariableFloatRef::Set(float f)
  425. {
  426. if (f == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  427. {
  428. return;
  429. }
  430. char sTemp[128];
  431. sprintf_s(sTemp, "%g", f);
  432. if (m_pConsole->OnBeforeVarChange(this, sTemp))
  433. {
  434. m_nFlags |= VF_MODIFIED;
  435. m_fValue = f;
  436. CallOnChangeFunctions();
  437. m_pConsole->OnAfterVarChange(this);
  438. }
  439. }
  440. void CXConsoleVariableFloatRef::Set(int i)
  441. {
  442. if ((float)i == m_fValue && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  443. {
  444. return;
  445. }
  446. char sTemp[128];
  447. sprintf_s(sTemp, "%d", i);
  448. if (m_pConsole->OnBeforeVarChange(this, sTemp))
  449. {
  450. m_nFlags |= VF_MODIFIED;
  451. m_fValue = (float)i;
  452. CallOnChangeFunctions();
  453. m_pConsole->OnAfterVarChange(this);
  454. }
  455. }
  456. void CXConsoleVariableStringRef::Set(const char *s)
  457. {
  458. if ((m_sValue == s) && (m_nFlags & VF_ALWAYSONCHANGE) == 0)
  459. {
  460. return;
  461. }
  462. if (m_pConsole->OnBeforeVarChange(this, s))
  463. {
  464. m_nFlags |= VF_MODIFIED;
  465. {
  466. m_sValue = s;
  467. m_userPtr = m_sValue.c_str();
  468. }
  469. CallOnChangeFunctions();
  470. m_pConsole->OnAfterVarChange(this);
  471. }
  472. }