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