CVarSystem.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. idCVar * idCVar::staticVars = NULL;
  23. extern idCVar net_allowCheats;
  24. /*
  25. ===============================================================================
  26. idInternalCVar
  27. ===============================================================================
  28. */
  29. class idInternalCVar : public idCVar {
  30. friend class idCVarSystemLocal;
  31. public:
  32. idInternalCVar();
  33. idInternalCVar( const char *newName, const char *newValue, int newFlags );
  34. idInternalCVar( const idCVar *cvar );
  35. virtual ~idInternalCVar();
  36. const char ** CopyValueStrings( const char **strings );
  37. void Update( const idCVar *cvar );
  38. void UpdateValue();
  39. void UpdateCheat();
  40. void Set( const char *newValue, bool force, bool fromServer );
  41. void Reset();
  42. private:
  43. idStr nameString; // name
  44. idStr resetString; // resetting will change to this value
  45. idStr valueString; // value
  46. idStr descriptionString; // description
  47. virtual const char * InternalGetResetString() const;
  48. virtual void InternalSetString( const char *newValue );
  49. virtual void InternalServerSetString( const char *newValue );
  50. virtual void InternalSetBool( const bool newValue );
  51. virtual void InternalSetInteger( const int newValue );
  52. virtual void InternalSetFloat( const float newValue );
  53. };
  54. /*
  55. ============
  56. idInternalCVar::idInternalCVar
  57. ============
  58. */
  59. idInternalCVar::idInternalCVar() {
  60. }
  61. /*
  62. ============
  63. idInternalCVar::idInternalCVar
  64. ============
  65. */
  66. idInternalCVar::idInternalCVar( const char *newName, const char *newValue, int newFlags ) {
  67. nameString = newName;
  68. name = nameString.c_str();
  69. valueString = newValue;
  70. value = valueString.c_str();
  71. resetString = newValue;
  72. descriptionString = "";
  73. description = descriptionString.c_str();
  74. flags = ( newFlags & ~CVAR_STATIC ) | CVAR_MODIFIED;
  75. valueMin = 1;
  76. valueMax = -1;
  77. valueStrings = NULL;
  78. valueCompletion = 0;
  79. UpdateValue();
  80. UpdateCheat();
  81. internalVar = this;
  82. }
  83. /*
  84. ============
  85. idInternalCVar::idInternalCVar
  86. ============
  87. */
  88. idInternalCVar::idInternalCVar( const idCVar *cvar ) {
  89. nameString = cvar->GetName();
  90. name = nameString.c_str();
  91. valueString = cvar->GetString();
  92. value = valueString.c_str();
  93. resetString = cvar->GetString();
  94. descriptionString = cvar->GetDescription();
  95. description = descriptionString.c_str();
  96. flags = cvar->GetFlags() | CVAR_MODIFIED;
  97. valueMin = cvar->GetMinValue();
  98. valueMax = cvar->GetMaxValue();
  99. valueStrings = CopyValueStrings( cvar->GetValueStrings() );
  100. valueCompletion = cvar->GetValueCompletion();
  101. UpdateValue();
  102. UpdateCheat();
  103. internalVar = this;
  104. }
  105. /*
  106. ============
  107. idInternalCVar::~idInternalCVar
  108. ============
  109. */
  110. idInternalCVar::~idInternalCVar() {
  111. Mem_Free( valueStrings );
  112. valueStrings = NULL;
  113. }
  114. /*
  115. ============
  116. idInternalCVar::CopyValueStrings
  117. ============
  118. */
  119. const char **idInternalCVar::CopyValueStrings( const char **strings ) {
  120. int i, totalLength;
  121. const char **ptr;
  122. char *str;
  123. if ( !strings ) {
  124. return NULL;
  125. }
  126. totalLength = 0;
  127. for ( i = 0; strings[i] != NULL; i++ ) {
  128. totalLength += idStr::Length( strings[i] ) + 1;
  129. }
  130. ptr = (const char **) Mem_Alloc( ( i + 1 ) * sizeof( char * ) + totalLength, TAG_CVAR );
  131. str = (char *) (((byte *)ptr) + ( i + 1 ) * sizeof( char * ) );
  132. for ( i = 0; strings[i] != NULL; i++ ) {
  133. ptr[i] = str;
  134. strcpy( str, strings[i] );
  135. str += idStr::Length( strings[i] ) + 1;
  136. }
  137. ptr[i] = NULL;
  138. return ptr;
  139. }
  140. /*
  141. ============
  142. idInternalCVar::Update
  143. ============
  144. */
  145. void idInternalCVar::Update( const idCVar *cvar ) {
  146. // if this is a statically declared variable
  147. if ( cvar->GetFlags() & CVAR_STATIC ) {
  148. if ( flags & CVAR_STATIC ) {
  149. // the code has more than one static declaration of the same variable, make sure they have the same properties
  150. if ( resetString.Icmp( cvar->GetString() ) != 0 ) {
  151. common->Warning( "CVar '%s' declared multiple times with different initial value", nameString.c_str() );
  152. }
  153. if ( ( flags & (CVAR_BOOL|CVAR_INTEGER|CVAR_FLOAT) ) != ( cvar->GetFlags() & (CVAR_BOOL|CVAR_INTEGER|CVAR_FLOAT) ) ) {
  154. common->Warning( "CVar '%s' declared multiple times with different type", nameString.c_str() );
  155. }
  156. if ( valueMin != cvar->GetMinValue() || valueMax != cvar->GetMaxValue() ) {
  157. common->Warning( "CVar '%s' declared multiple times with different minimum/maximum", nameString.c_str() );
  158. }
  159. }
  160. // the code is now specifying a variable that the user already set a value for, take the new value as the reset value
  161. resetString = cvar->GetString();
  162. descriptionString = cvar->GetDescription();
  163. description = descriptionString.c_str();
  164. valueMin = cvar->GetMinValue();
  165. valueMax = cvar->GetMaxValue();
  166. Mem_Free( valueStrings );
  167. valueStrings = CopyValueStrings( cvar->GetValueStrings() );
  168. valueCompletion = cvar->GetValueCompletion();
  169. UpdateValue();
  170. cvarSystem->SetModifiedFlags( cvar->GetFlags() );
  171. }
  172. flags |= cvar->GetFlags();
  173. UpdateCheat();
  174. // only allow one non-empty reset string without a warning
  175. if ( resetString.Length() == 0 ) {
  176. resetString = cvar->GetString();
  177. } else if ( cvar->GetString()[0] && resetString.Cmp( cvar->GetString() ) != 0 ) {
  178. common->Warning( "cvar \"%s\" given initial values: \"%s\" and \"%s\"\n", nameString.c_str(), resetString.c_str(), cvar->GetString() );
  179. }
  180. }
  181. /*
  182. ============
  183. idInternalCVar::UpdateValue
  184. ============
  185. */
  186. void idInternalCVar::UpdateValue() {
  187. bool clamped = false;
  188. if ( flags & CVAR_BOOL ) {
  189. integerValue = ( atoi( value ) != 0 );
  190. floatValue = integerValue;
  191. if ( idStr::Icmp( value, "0" ) != 0 && idStr::Icmp( value, "1" ) != 0 ) {
  192. valueString = idStr( (bool)( integerValue != 0 ) );
  193. value = valueString.c_str();
  194. }
  195. } else if ( flags & CVAR_INTEGER ) {
  196. integerValue = (int)atoi( value );
  197. if ( valueMin < valueMax ) {
  198. if ( integerValue < valueMin ) {
  199. integerValue = (int)valueMin;
  200. clamped = true;
  201. } else if ( integerValue > valueMax ) {
  202. integerValue = (int)valueMax;
  203. clamped = true;
  204. }
  205. }
  206. if ( clamped || !idStr::IsNumeric( value ) || idStr::FindChar( value, '.' ) ) {
  207. valueString = idStr( integerValue );
  208. value = valueString.c_str();
  209. }
  210. floatValue = (float)integerValue;
  211. } else if ( flags & CVAR_FLOAT ) {
  212. floatValue = (float)atof( value );
  213. if ( valueMin < valueMax ) {
  214. if ( floatValue < valueMin ) {
  215. floatValue = valueMin;
  216. clamped = true;
  217. } else if ( floatValue > valueMax ) {
  218. floatValue = valueMax;
  219. clamped = true;
  220. }
  221. }
  222. if ( clamped || !idStr::IsNumeric( value ) ) {
  223. valueString = idStr( floatValue );
  224. value = valueString.c_str();
  225. }
  226. integerValue = (int)floatValue;
  227. } else {
  228. if ( valueStrings && valueStrings[0] ) {
  229. integerValue = 0;
  230. for ( int i = 0; valueStrings[i]; i++ ) {
  231. if ( valueString.Icmp( valueStrings[i] ) == 0 ) {
  232. integerValue = i;
  233. break;
  234. }
  235. }
  236. valueString = valueStrings[integerValue];
  237. value = valueString.c_str();
  238. floatValue = (float)integerValue;
  239. } else if ( valueString.Length() < 32 ) {
  240. floatValue = (float)atof( value );
  241. integerValue = (int)floatValue;
  242. } else {
  243. floatValue = 0.0f;
  244. integerValue = 0;
  245. }
  246. }
  247. }
  248. /*
  249. ============
  250. idInternalCVar::UpdateCheat
  251. ============
  252. */
  253. void idInternalCVar::UpdateCheat() {
  254. // all variables are considered cheats except for a few types
  255. if ( flags & ( CVAR_NOCHEAT | CVAR_INIT | CVAR_ROM | CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NETWORKSYNC ) ) {
  256. flags &= ~CVAR_CHEAT;
  257. } else {
  258. flags |= CVAR_CHEAT;
  259. }
  260. }
  261. /*
  262. ============
  263. idInternalCVar::Set
  264. ============
  265. */
  266. void idInternalCVar::Set( const char *newValue, bool force, bool fromServer ) {
  267. if ( common->IsMultiplayer() && !fromServer ) {
  268. #ifndef ID_TYPEINFO
  269. if ( ( flags & CVAR_NETWORKSYNC ) && common->IsClient() ) {
  270. common->Printf( "%s is a synced over the network and cannot be changed on a multiplayer client.\n", nameString.c_str() );
  271. return;
  272. }
  273. #endif
  274. if ( ( flags & CVAR_CHEAT ) && !net_allowCheats.GetBool() ) {
  275. common->Printf( "%s cannot be changed in multiplayer.\n", nameString.c_str() );
  276. return;
  277. }
  278. }
  279. if ( !newValue ) {
  280. newValue = resetString.c_str();
  281. }
  282. if ( !force ) {
  283. if ( flags & CVAR_ROM ) {
  284. common->Printf( "%s is read only.\n", nameString.c_str() );
  285. return;
  286. }
  287. if ( flags & CVAR_INIT ) {
  288. common->Printf( "%s is write protected.\n", nameString.c_str() );
  289. return;
  290. }
  291. }
  292. if ( valueString.Icmp( newValue ) == 0 ) {
  293. return;
  294. }
  295. valueString = newValue;
  296. value = valueString.c_str();
  297. UpdateValue();
  298. SetModified();
  299. cvarSystem->SetModifiedFlags( flags );
  300. }
  301. /*
  302. ============
  303. idInternalCVar::Reset
  304. ============
  305. */
  306. void idInternalCVar::Reset() {
  307. valueString = resetString;
  308. value = valueString.c_str();
  309. UpdateValue();
  310. }
  311. /*
  312. ============
  313. idInternalCVar::InternalGetResetString
  314. ============
  315. */
  316. const char * idInternalCVar::InternalGetResetString() const {
  317. return resetString;
  318. }
  319. /*
  320. ============
  321. idInternalCVar::InternalSetString
  322. ============
  323. */
  324. void idInternalCVar::InternalSetString( const char *newValue ) {
  325. Set( newValue, true, false );
  326. }
  327. /*
  328. ===============
  329. idInternalCVar::InternalServerSetString
  330. ===============
  331. */
  332. void idInternalCVar::InternalServerSetString( const char *newValue ) {
  333. Set( newValue, true, true );
  334. }
  335. /*
  336. ============
  337. idInternalCVar::InternalSetBool
  338. ============
  339. */
  340. void idInternalCVar::InternalSetBool( const bool newValue ) {
  341. Set( idStr( newValue ), true, false );
  342. }
  343. /*
  344. ============
  345. idInternalCVar::InternalSetInteger
  346. ============
  347. */
  348. void idInternalCVar::InternalSetInteger( const int newValue ) {
  349. Set( idStr( newValue ), true, false );
  350. }
  351. /*
  352. ============
  353. idInternalCVar::InternalSetFloat
  354. ============
  355. */
  356. void idInternalCVar::InternalSetFloat( const float newValue ) {
  357. Set( idStr( newValue ), true, false );
  358. }
  359. /*
  360. ===============================================================================
  361. idCVarSystemLocal
  362. ===============================================================================
  363. */
  364. class idCVarSystemLocal : public idCVarSystem {
  365. public:
  366. idCVarSystemLocal();
  367. virtual ~idCVarSystemLocal() {}
  368. virtual void Init();
  369. virtual void Shutdown();
  370. virtual bool IsInitialized() const;
  371. virtual void Register( idCVar *cvar );
  372. virtual idCVar * Find( const char *name );
  373. virtual void SetCVarString( const char *name, const char *value, int flags = 0 );
  374. virtual void SetCVarBool( const char *name, const bool value, int flags = 0 );
  375. virtual void SetCVarInteger( const char *name, const int value, int flags = 0 );
  376. virtual void SetCVarFloat( const char *name, const float value, int flags = 0 );
  377. virtual const char * GetCVarString( const char *name ) const;
  378. virtual bool GetCVarBool( const char *name ) const;
  379. virtual int GetCVarInteger( const char *name ) const;
  380. virtual float GetCVarFloat( const char *name ) const;
  381. virtual bool Command( const idCmdArgs &args );
  382. virtual void CommandCompletion( void(*callback)( const char *s ) );
  383. virtual void ArgCompletion( const char *cmdString, void(*callback)( const char *s ) );
  384. virtual void SetModifiedFlags( int flags );
  385. virtual int GetModifiedFlags() const;
  386. virtual void ClearModifiedFlags( int flags );
  387. virtual void ResetFlaggedVariables( int flags );
  388. virtual void RemoveFlaggedAutoCompletion( int flags );
  389. virtual void WriteFlaggedVariables( int flags, const char *setCmd, idFile *f ) const;
  390. virtual void MoveCVarsToDict( int flags, idDict & dict, bool onlyModified ) const;
  391. virtual void SetCVarsFromDict( const idDict &dict );
  392. void RegisterInternal( idCVar *cvar );
  393. idInternalCVar * FindInternal( const char *name ) const;
  394. void SetInternal( const char *name, const char *value, int flags );
  395. private:
  396. bool initialized;
  397. idList<idInternalCVar*, TAG_CVAR> cvars;
  398. idHashIndex cvarHash;
  399. int modifiedFlags;
  400. private:
  401. static void Toggle_f( const idCmdArgs &args );
  402. static void Set_f( const idCmdArgs &args );
  403. static void Reset_f( const idCmdArgs &args );
  404. static void ListByFlags( const idCmdArgs &args, cvarFlags_t flags );
  405. static void List_f( const idCmdArgs &args );
  406. static void Restart_f( const idCmdArgs &args );
  407. static void CvarAdd_f( const idCmdArgs &args );
  408. };
  409. idCVarSystemLocal localCVarSystem;
  410. idCVarSystem * cvarSystem = &localCVarSystem;
  411. #define NUM_COLUMNS 77 // 78 - 1
  412. #define NUM_NAME_CHARS 33
  413. #define NUM_DESCRIPTION_CHARS ( NUM_COLUMNS - NUM_NAME_CHARS )
  414. #define FORMAT_STRING "%-32s "
  415. const char *CreateColumn( const char *text, int columnWidth, const char *indent, idStr &string ) {
  416. int i, lastLine;
  417. string.Clear();
  418. for ( lastLine = i = 0; text[i] != '\0'; i++ ) {
  419. if ( i - lastLine >= columnWidth || text[i] == '\n' ) {
  420. while( i > 0 && text[i] > ' ' && text[i] != '/' && text[i] != ',' && text[i] != '\\' ) {
  421. i--;
  422. }
  423. while( lastLine < i ) {
  424. string.Append( text[lastLine++] );
  425. }
  426. string.Append( indent );
  427. lastLine++;
  428. }
  429. }
  430. while( lastLine < i ) {
  431. string.Append( text[lastLine++] );
  432. }
  433. return string.c_str();
  434. }
  435. /*
  436. ============
  437. idCVarSystemLocal::FindInternal
  438. ============
  439. */
  440. idInternalCVar *idCVarSystemLocal::FindInternal( const char *name ) const {
  441. int hash = cvarHash.GenerateKey( name, false );
  442. for ( int i = cvarHash.First( hash ); i != -1; i = cvarHash.Next( i ) ) {
  443. if ( cvars[i]->nameString.Icmp( name ) == 0 ) {
  444. return cvars[i];
  445. }
  446. }
  447. return NULL;
  448. }
  449. /*
  450. ============
  451. idCVarSystemLocal::SetInternal
  452. ============
  453. */
  454. void idCVarSystemLocal::SetInternal( const char *name, const char *value, int flags ) {
  455. int hash;
  456. idInternalCVar *internal;
  457. internal = FindInternal( name );
  458. if ( internal ) {
  459. internal->InternalSetString( value );
  460. internal->flags |= flags & ~CVAR_STATIC;
  461. internal->UpdateCheat();
  462. } else {
  463. internal = new (TAG_SYSTEM) idInternalCVar( name, value, flags );
  464. hash = cvarHash.GenerateKey( internal->nameString.c_str(), false );
  465. cvarHash.Add( hash, cvars.Append( internal ) );
  466. }
  467. }
  468. /*
  469. ============
  470. idCVarSystemLocal::idCVarSystemLocal
  471. ============
  472. */
  473. idCVarSystemLocal::idCVarSystemLocal() {
  474. initialized = false;
  475. modifiedFlags = 0;
  476. }
  477. /*
  478. ============
  479. idCVarSystemLocal::Init
  480. ============
  481. */
  482. void idCVarSystemLocal::Init() {
  483. modifiedFlags = 0;
  484. cmdSystem->AddCommand( "toggle", Toggle_f, CMD_FL_SYSTEM, "toggles a cvar" );
  485. cmdSystem->AddCommand( "set", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
  486. cmdSystem->AddCommand( "seta", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
  487. cmdSystem->AddCommand( "sets", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
  488. cmdSystem->AddCommand( "sett", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
  489. cmdSystem->AddCommand( "setu", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
  490. cmdSystem->AddCommand( "reset", Reset_f, CMD_FL_SYSTEM, "resets a cvar" );
  491. cmdSystem->AddCommand( "listCvars", List_f, CMD_FL_SYSTEM, "lists cvars" );
  492. cmdSystem->AddCommand( "cvar_restart", Restart_f, CMD_FL_SYSTEM, "restart the cvar system" );
  493. cmdSystem->AddCommand( "cvarAdd", CvarAdd_f, CMD_FL_SYSTEM, "adds a value to a numeric cvar" );
  494. initialized = true;
  495. }
  496. /*
  497. ============
  498. idCVarSystemLocal::Shutdown
  499. ============
  500. */
  501. void idCVarSystemLocal::Shutdown() {
  502. cvars.DeleteContents( true );
  503. cvarHash.Free();
  504. initialized = false;
  505. }
  506. /*
  507. ============
  508. idCVarSystemLocal::IsInitialized
  509. ============
  510. */
  511. bool idCVarSystemLocal::IsInitialized() const {
  512. return initialized;
  513. }
  514. /*
  515. ============
  516. idCVarSystemLocal::Register
  517. ============
  518. */
  519. void idCVarSystemLocal::Register( idCVar *cvar ) {
  520. int hash;
  521. idInternalCVar *internal;
  522. cvar->SetInternalVar( cvar );
  523. internal = FindInternal( cvar->GetName() );
  524. if ( internal ) {
  525. internal->Update( cvar );
  526. } else {
  527. internal = new (TAG_SYSTEM) idInternalCVar( cvar );
  528. hash = cvarHash.GenerateKey( internal->nameString.c_str(), false );
  529. cvarHash.Add( hash, cvars.Append( internal ) );
  530. }
  531. cvar->SetInternalVar( internal );
  532. }
  533. /*
  534. ============
  535. idCVarSystemLocal::Find
  536. ============
  537. */
  538. idCVar *idCVarSystemLocal::Find( const char *name ) {
  539. return FindInternal( name );
  540. }
  541. /*
  542. ============
  543. idCVarSystemLocal::SetCVarString
  544. ============
  545. */
  546. void idCVarSystemLocal::SetCVarString( const char *name, const char *value, int flags ) {
  547. SetInternal( name, value, flags );
  548. }
  549. /*
  550. ============
  551. idCVarSystemLocal::SetCVarBool
  552. ============
  553. */
  554. void idCVarSystemLocal::SetCVarBool( const char *name, const bool value, int flags ) {
  555. SetInternal( name, idStr( value ), flags );
  556. }
  557. /*
  558. ============
  559. idCVarSystemLocal::SetCVarInteger
  560. ============
  561. */
  562. void idCVarSystemLocal::SetCVarInteger( const char *name, const int value, int flags ) {
  563. SetInternal( name, idStr( value ), flags );
  564. }
  565. /*
  566. ============
  567. idCVarSystemLocal::SetCVarFloat
  568. ============
  569. */
  570. void idCVarSystemLocal::SetCVarFloat( const char *name, const float value, int flags ) {
  571. SetInternal( name, idStr( value ), flags );
  572. }
  573. /*
  574. ============
  575. idCVarSystemLocal::GetCVarString
  576. ============
  577. */
  578. const char *idCVarSystemLocal::GetCVarString( const char *name ) const {
  579. idInternalCVar *internal = FindInternal( name );
  580. if ( internal ) {
  581. return internal->GetString();
  582. }
  583. return "";
  584. }
  585. /*
  586. ============
  587. idCVarSystemLocal::GetCVarBool
  588. ============
  589. */
  590. bool idCVarSystemLocal::GetCVarBool( const char *name ) const {
  591. idInternalCVar *internal = FindInternal( name );
  592. if ( internal ) {
  593. return internal->GetBool();
  594. }
  595. return false;
  596. }
  597. /*
  598. ============
  599. idCVarSystemLocal::GetCVarInteger
  600. ============
  601. */
  602. int idCVarSystemLocal::GetCVarInteger( const char *name ) const {
  603. idInternalCVar *internal = FindInternal( name );
  604. if ( internal ) {
  605. return internal->GetInteger();
  606. }
  607. return 0;
  608. }
  609. /*
  610. ============
  611. idCVarSystemLocal::GetCVarFloat
  612. ============
  613. */
  614. float idCVarSystemLocal::GetCVarFloat( const char *name ) const {
  615. idInternalCVar *internal = FindInternal( name );
  616. if ( internal ) {
  617. return internal->GetFloat();
  618. }
  619. return 0.0f;
  620. }
  621. /*
  622. ============
  623. idCVarSystemLocal::Command
  624. ============
  625. */
  626. bool idCVarSystemLocal::Command( const idCmdArgs &args ) {
  627. idInternalCVar *internal;
  628. internal = FindInternal( args.Argv( 0 ) );
  629. if ( internal == NULL ) {
  630. return false;
  631. }
  632. if ( args.Argc() == 1 ) {
  633. // print the variable
  634. common->Printf( "\"%s\" is:\"%s\"" S_COLOR_WHITE " default:\"%s\"\n",
  635. internal->nameString.c_str(), internal->valueString.c_str(), internal->resetString.c_str() );
  636. if ( idStr::Length( internal->GetDescription() ) > 0 ) {
  637. common->Printf( S_COLOR_WHITE "%s\n", internal->GetDescription() );
  638. }
  639. } else {
  640. // set the value
  641. internal->Set( args.Args(), false, false );
  642. }
  643. return true;
  644. }
  645. /*
  646. ============
  647. idCVarSystemLocal::CommandCompletion
  648. ============
  649. */
  650. void idCVarSystemLocal::CommandCompletion( void(*callback)( const char *s ) ) {
  651. for( int i = 0; i < cvars.Num(); i++ ) {
  652. callback( cvars[i]->GetName() );
  653. }
  654. }
  655. /*
  656. ============
  657. idCVarSystemLocal::ArgCompletion
  658. ============
  659. */
  660. void idCVarSystemLocal::ArgCompletion( const char *cmdString, void(*callback)( const char *s ) ) {
  661. idCmdArgs args;
  662. args.TokenizeString( cmdString, false );
  663. for( int i = 0; i < cvars.Num(); i++ ) {
  664. if ( !cvars[i]->valueCompletion ) {
  665. continue;
  666. }
  667. if ( idStr::Icmp( args.Argv( 0 ), cvars[i]->nameString.c_str() ) == 0 ) {
  668. cvars[i]->valueCompletion( args, callback );
  669. break;
  670. }
  671. }
  672. }
  673. /*
  674. ============
  675. idCVarSystemLocal::SetModifiedFlags
  676. ============
  677. */
  678. void idCVarSystemLocal::SetModifiedFlags( int flags ) {
  679. modifiedFlags |= flags;
  680. }
  681. /*
  682. ============
  683. idCVarSystemLocal::GetModifiedFlags
  684. ============
  685. */
  686. int idCVarSystemLocal::GetModifiedFlags() const {
  687. return modifiedFlags;
  688. }
  689. /*
  690. ============
  691. idCVarSystemLocal::ClearModifiedFlags
  692. ============
  693. */
  694. void idCVarSystemLocal::ClearModifiedFlags( int flags ) {
  695. modifiedFlags &= ~flags;
  696. }
  697. /*
  698. ============
  699. idCVarSystemLocal::ResetFlaggedVariables
  700. ============
  701. */
  702. void idCVarSystemLocal::ResetFlaggedVariables( int flags ) {
  703. for( int i = 0; i < cvars.Num(); i++ ) {
  704. idInternalCVar *cvar = cvars[i];
  705. if ( cvar->GetFlags() & flags ) {
  706. cvar->Set( NULL, true, true );
  707. }
  708. }
  709. }
  710. /*
  711. ============
  712. idCVarSystemLocal::RemoveFlaggedAutoCompletion
  713. ============
  714. */
  715. void idCVarSystemLocal::RemoveFlaggedAutoCompletion( int flags ) {
  716. for( int i = 0; i < cvars.Num(); i++ ) {
  717. idInternalCVar *cvar = cvars[i];
  718. if ( cvar->GetFlags() & flags ) {
  719. cvar->valueCompletion = NULL;
  720. }
  721. }
  722. }
  723. /*
  724. ============
  725. idCVarSystemLocal::WriteFlaggedVariables
  726. Appends lines containing "set variable value" for all variables
  727. with the "flags" flag set to true.
  728. ============
  729. */
  730. void idCVarSystemLocal::WriteFlaggedVariables( int flags, const char *setCmd, idFile *f ) const {
  731. for( int i = 0; i < cvars.Num(); i++ ) {
  732. idInternalCVar *cvar = cvars[i];
  733. if ( cvar->GetFlags() & flags ) {
  734. f->Printf( "%s %s \"%s\"\n", setCmd, cvar->GetName(), cvar->GetString() );
  735. }
  736. }
  737. }
  738. /*
  739. ============
  740. idCVarSystemLocal::MoveCVarsToDict
  741. ============
  742. */
  743. void idCVarSystemLocal::MoveCVarsToDict( int flags, idDict & dict, bool onlyModified ) const {
  744. dict.Clear();
  745. for( int i = 0; i < cvars.Num(); i++ ) {
  746. idCVar *cvar = cvars[i];
  747. if ( cvar->GetFlags() & flags ) {
  748. if ( onlyModified && idStr::Icmp( cvar->GetString(), cvar->GetDefaultString() ) == 0 ) {
  749. continue;
  750. }
  751. dict.Set( cvar->GetName(), cvar->GetString() );
  752. }
  753. }
  754. }
  755. /*
  756. ============
  757. idCVarSystemLocal::SetCVarsFromDict
  758. ============
  759. */
  760. void idCVarSystemLocal::SetCVarsFromDict( const idDict &dict ) {
  761. idInternalCVar *internal;
  762. for( int i = 0; i < dict.GetNumKeyVals(); i++ ) {
  763. const idKeyValue *kv = dict.GetKeyVal( i );
  764. internal = FindInternal( kv->GetKey() );
  765. if ( internal ) {
  766. internal->InternalServerSetString( kv->GetValue() );
  767. }
  768. }
  769. }
  770. /*
  771. ============
  772. idCVarSystemLocal::Toggle_f
  773. ============
  774. */
  775. void idCVarSystemLocal::Toggle_f( const idCmdArgs &args ) {
  776. int argc, i;
  777. float current, set;
  778. const char *text;
  779. argc = args.Argc();
  780. if ( argc < 2 ) {
  781. common->Printf ("usage:\n"
  782. " toggle <variable> - toggles between 0 and 1\n"
  783. " toggle <variable> <value> - toggles between 0 and <value>\n"
  784. " toggle <variable> [string 1] [string 2]...[string n] - cycles through all strings\n");
  785. return;
  786. }
  787. idInternalCVar *cvar = localCVarSystem.FindInternal( args.Argv( 1 ) );
  788. if ( cvar == NULL ) {
  789. common->Warning( "Toggle_f: cvar \"%s\" not found", args.Argv( 1 ) );
  790. return;
  791. }
  792. if ( argc > 3 ) {
  793. // cycle through multiple values
  794. text = cvar->GetString();
  795. for( i = 2; i < argc; i++ ) {
  796. if ( !idStr::Icmp( text, args.Argv( i ) ) ) {
  797. // point to next value
  798. i++;
  799. break;
  800. }
  801. }
  802. if ( i >= argc ) {
  803. i = 2;
  804. }
  805. common->Printf( "set %s = %s\n", args.Argv(1), args.Argv( i ) );
  806. cvar->Set( va("%s", args.Argv( i ) ), false, false );
  807. } else {
  808. // toggle between 0 and 1
  809. current = cvar->GetFloat();
  810. if ( argc == 3 ) {
  811. set = atof( args.Argv( 2 ) );
  812. } else {
  813. set = 1.0f;
  814. }
  815. if ( current == 0.0f ) {
  816. current = set;
  817. } else {
  818. current = 0.0f;
  819. }
  820. common->Printf( "set %s = %f\n", args.Argv(1), current );
  821. cvar->Set( idStr( current ), false, false );
  822. }
  823. }
  824. /*
  825. ============
  826. idCVarSystemLocal::Set_f
  827. ============
  828. */
  829. void idCVarSystemLocal::Set_f( const idCmdArgs &args ) {
  830. const char *str;
  831. str = args.Args( 2, args.Argc() - 1 );
  832. localCVarSystem.SetCVarString( args.Argv(1), str );
  833. }
  834. /*
  835. ============
  836. idCVarSystemLocal::Reset_f
  837. ============
  838. */
  839. void idCVarSystemLocal::Reset_f( const idCmdArgs &args ) {
  840. idInternalCVar *cvar;
  841. if ( args.Argc() != 2 ) {
  842. common->Printf ("usage: reset <variable>\n");
  843. return;
  844. }
  845. cvar = localCVarSystem.FindInternal( args.Argv( 1 ) );
  846. if ( !cvar ) {
  847. return;
  848. }
  849. cvar->Reset();
  850. }
  851. /*
  852. ============
  853. idCVarSystemLocal::CvarAdd_f
  854. ============
  855. */
  856. void idCVarSystemLocal::CvarAdd_f( const idCmdArgs &args ) {
  857. if ( args.Argc() != 3 ) {
  858. common->Printf ("usage: cvarAdd <variable> <value>\n");
  859. }
  860. idInternalCVar *cvar = localCVarSystem.FindInternal( args.Argv( 1 ) );
  861. if ( !cvar ) {
  862. return;
  863. }
  864. const float newValue = cvar->GetFloat() + atof( args.Argv( 2 ) );
  865. cvar->SetFloat( newValue );
  866. common->Printf( "%s = %f\n", cvar->GetName(), newValue );
  867. }
  868. //
  869. ///*
  870. //================================================
  871. //idSort_CommandDef
  872. //================================================
  873. //*/
  874. //class idSort_InternalCVar : public idSort_Quick< const idInternalCVar *, idSort_InternalCVar > {
  875. //public:
  876. // int Compare( const idInternalCVar * & a, const idInternalCVar * & b ) const { return idStr::Icmp( a.GetName(), b.GetName() ); }
  877. //};
  878. void idCVarSystemLocal::ListByFlags( const idCmdArgs &args, cvarFlags_t flags ) {
  879. int i, argNum;
  880. idStr match, indent, string;
  881. const idInternalCVar *cvar;
  882. idList<const idInternalCVar *, TAG_CVAR>cvarList;
  883. enum {
  884. SHOW_VALUE,
  885. SHOW_DESCRIPTION,
  886. SHOW_TYPE,
  887. SHOW_FLAGS
  888. } show;
  889. argNum = 1;
  890. show = SHOW_VALUE;
  891. if ( idStr::Icmp( args.Argv( argNum ), "-" ) == 0 || idStr::Icmp( args.Argv( argNum ), "/" ) == 0 ) {
  892. if ( idStr::Icmp( args.Argv( argNum + 1 ), "help" ) == 0 || idStr::Icmp( args.Argv( argNum + 1 ), "?" ) == 0 ) {
  893. argNum = 3;
  894. show = SHOW_DESCRIPTION;
  895. } else if ( idStr::Icmp( args.Argv( argNum + 1 ), "type" ) == 0 || idStr::Icmp( args.Argv( argNum + 1 ), "range" ) == 0 ) {
  896. argNum = 3;
  897. show = SHOW_TYPE;
  898. } else if ( idStr::Icmp( args.Argv( argNum + 1 ), "flags" ) == 0 ) {
  899. argNum = 3;
  900. show = SHOW_FLAGS;
  901. }
  902. }
  903. if ( args.Argc() > argNum ) {
  904. match = args.Args( argNum, -1 );
  905. match.Replace( " ", "" );
  906. } else {
  907. match = "";
  908. }
  909. for ( i = 0; i < localCVarSystem.cvars.Num(); i++ ) {
  910. cvar = localCVarSystem.cvars[i];
  911. if ( !( cvar->GetFlags() & flags ) ) {
  912. continue;
  913. }
  914. if ( match.Length() && !cvar->nameString.Filter( match, false ) ) {
  915. continue;
  916. }
  917. cvarList.Append( cvar );
  918. }
  919. //cvarList.SortWithTemplate( idSort_InternalCVar() );
  920. switch( show ) {
  921. case SHOW_VALUE: {
  922. for ( i = 0; i < cvarList.Num(); i++ ) {
  923. cvar = cvarList[i];
  924. common->Printf( FORMAT_STRING S_COLOR_WHITE "\"%s\"\n", cvar->nameString.c_str(), cvar->valueString.c_str() );
  925. }
  926. break;
  927. }
  928. case SHOW_DESCRIPTION: {
  929. indent.Fill( ' ', NUM_NAME_CHARS );
  930. indent.Insert( "\n", 0 );
  931. for ( i = 0; i < cvarList.Num(); i++ ) {
  932. cvar = cvarList[i];
  933. common->Printf( FORMAT_STRING S_COLOR_WHITE "%s\n", cvar->nameString.c_str(), CreateColumn( cvar->GetDescription(), NUM_DESCRIPTION_CHARS, indent, string ) );
  934. }
  935. break;
  936. }
  937. case SHOW_TYPE: {
  938. for ( i = 0; i < cvarList.Num(); i++ ) {
  939. cvar = cvarList[i];
  940. if ( cvar->GetFlags() & CVAR_BOOL ) {
  941. common->Printf( FORMAT_STRING S_COLOR_CYAN "bool\n", cvar->GetName() );
  942. } else if ( cvar->GetFlags() & CVAR_INTEGER ) {
  943. if ( cvar->GetMinValue() < cvar->GetMaxValue() ) {
  944. common->Printf( FORMAT_STRING S_COLOR_GREEN "int " S_COLOR_WHITE "[%d, %d]\n", cvar->GetName(), (int) cvar->GetMinValue(), (int) cvar->GetMaxValue() );
  945. } else {
  946. common->Printf( FORMAT_STRING S_COLOR_GREEN "int\n", cvar->GetName() );
  947. }
  948. } else if ( cvar->GetFlags() & CVAR_FLOAT ) {
  949. if ( cvar->GetMinValue() < cvar->GetMaxValue() ) {
  950. common->Printf( FORMAT_STRING S_COLOR_RED "float " S_COLOR_WHITE "[%s, %s]\n", cvar->GetName(), idStr( cvar->GetMinValue() ).c_str(), idStr( cvar->GetMaxValue() ).c_str() );
  951. } else {
  952. common->Printf( FORMAT_STRING S_COLOR_RED "float\n", cvar->GetName() );
  953. }
  954. } else if ( cvar->GetValueStrings() ) {
  955. common->Printf( FORMAT_STRING S_COLOR_WHITE "string " S_COLOR_WHITE "[", cvar->GetName() );
  956. for ( int j = 0; cvar->GetValueStrings()[j] != NULL; j++ ) {
  957. if ( j ) {
  958. common->Printf( S_COLOR_WHITE ", %s", cvar->GetValueStrings()[j] );
  959. } else {
  960. common->Printf( S_COLOR_WHITE "%s", cvar->GetValueStrings()[j] );
  961. }
  962. }
  963. common->Printf( S_COLOR_WHITE "]\n" );
  964. } else {
  965. common->Printf( FORMAT_STRING S_COLOR_WHITE "string\n", cvar->GetName() );
  966. }
  967. }
  968. break;
  969. }
  970. case SHOW_FLAGS: {
  971. for ( i = 0; i < cvarList.Num(); i++ ) {
  972. cvar = cvarList[i];
  973. common->Printf( FORMAT_STRING, cvar->GetName() );
  974. string = "";
  975. if ( cvar->GetFlags() & CVAR_BOOL ) {
  976. string += S_COLOR_CYAN "B ";
  977. } else if ( cvar->GetFlags() & CVAR_INTEGER ) {
  978. string += S_COLOR_GREEN "I ";
  979. } else if ( cvar->GetFlags() & CVAR_FLOAT ) {
  980. string += S_COLOR_RED "F ";
  981. } else {
  982. string += S_COLOR_WHITE "S ";
  983. }
  984. if ( cvar->GetFlags() & CVAR_SYSTEM ) {
  985. string += S_COLOR_WHITE "SYS ";
  986. } else if ( cvar->GetFlags() & CVAR_RENDERER ) {
  987. string += S_COLOR_WHITE "RNDR ";
  988. } else if ( cvar->GetFlags() & CVAR_SOUND ) {
  989. string += S_COLOR_WHITE "SND ";
  990. } else if ( cvar->GetFlags() & CVAR_GUI ) {
  991. string += S_COLOR_WHITE "GUI ";
  992. } else if ( cvar->GetFlags() & CVAR_GAME ) {
  993. string += S_COLOR_WHITE "GAME ";
  994. } else if ( cvar->GetFlags() & CVAR_TOOL ) {
  995. string += S_COLOR_WHITE "TOOL ";
  996. } else {
  997. string += S_COLOR_WHITE " ";
  998. }
  999. string += ( cvar->GetFlags() & CVAR_SERVERINFO ) ? "SI " : " ";
  1000. string += ( cvar->GetFlags() & CVAR_STATIC ) ? "ST " : " ";
  1001. string += ( cvar->GetFlags() & CVAR_CHEAT ) ? "CH " : " ";
  1002. string += ( cvar->GetFlags() & CVAR_INIT ) ? "IN " : " ";
  1003. string += ( cvar->GetFlags() & CVAR_ROM ) ? "RO " : " ";
  1004. string += ( cvar->GetFlags() & CVAR_ARCHIVE ) ? "AR " : " ";
  1005. string += ( cvar->GetFlags() & CVAR_MODIFIED ) ? "MO " : " ";
  1006. string += "\n";
  1007. common->Printf( string );
  1008. }
  1009. break;
  1010. }
  1011. }
  1012. common->Printf( "\n%i cvars listed\n\n", cvarList.Num() );
  1013. common->Printf( "listCvar [search string] = list cvar values\n"
  1014. "listCvar -help [search string] = list cvar descriptions\n"
  1015. "listCvar -type [search string] = list cvar types\n"
  1016. "listCvar -flags [search string] = list cvar flags\n" );
  1017. }
  1018. /*
  1019. ============
  1020. idCVarSystemLocal::List_f
  1021. ============
  1022. */
  1023. void idCVarSystemLocal::List_f( const idCmdArgs &args ) {
  1024. ListByFlags( args, CVAR_ALL );
  1025. }
  1026. /*
  1027. ============
  1028. idCVarSystemLocal::Restart_f
  1029. ============
  1030. */
  1031. void idCVarSystemLocal::Restart_f( const idCmdArgs &args ) {
  1032. int i, hash;
  1033. idInternalCVar *cvar;
  1034. for ( i = 0; i < localCVarSystem.cvars.Num(); i++ ) {
  1035. cvar = localCVarSystem.cvars[i];
  1036. // don't mess with rom values
  1037. if ( cvar->flags & ( CVAR_ROM | CVAR_INIT ) ) {
  1038. continue;
  1039. }
  1040. // throw out any variables the user created
  1041. if ( !( cvar->flags & CVAR_STATIC ) ) {
  1042. hash = localCVarSystem.cvarHash.GenerateKey( cvar->nameString, false );
  1043. delete cvar;
  1044. localCVarSystem.cvars.RemoveIndex( i );
  1045. localCVarSystem.cvarHash.RemoveIndex( hash, i );
  1046. i--;
  1047. continue;
  1048. }
  1049. cvar->Reset();
  1050. }
  1051. }