CVarSystem.cpp (31997B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 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. 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 "../idlib/precompiled.h" 30 #pragma hdrstop 31 32 idCVar * idCVar::staticVars = NULL; 33 34 extern idCVar net_allowCheats; 35 36 /* 37 =============================================================================== 38 39 idInternalCVar 40 41 =============================================================================== 42 */ 43 44 class idInternalCVar : public idCVar { 45 friend class idCVarSystemLocal; 46 public: 47 idInternalCVar(); 48 idInternalCVar( const char *newName, const char *newValue, int newFlags ); 49 idInternalCVar( const idCVar *cvar ); 50 virtual ~idInternalCVar(); 51 52 const char ** CopyValueStrings( const char **strings ); 53 void Update( const idCVar *cvar ); 54 void UpdateValue(); 55 void UpdateCheat(); 56 void Set( const char *newValue, bool force, bool fromServer ); 57 void Reset(); 58 59 private: 60 idStr nameString; // name 61 idStr resetString; // resetting will change to this value 62 idStr valueString; // value 63 idStr descriptionString; // description 64 65 virtual const char * InternalGetResetString() const; 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 */ 79 idInternalCVar::idInternalCVar() { 80 } 81 82 /* 83 ============ 84 idInternalCVar::idInternalCVar 85 ============ 86 */ 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 */ 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 */ 133 idInternalCVar::~idInternalCVar() { 134 Mem_Free( valueStrings ); 135 valueStrings = NULL; 136 } 137 138 139 /* 140 ============ 141 idInternalCVar::CopyValueStrings 142 ============ 143 */ 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, TAG_CVAR ); 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 */ 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 */ 226 void idInternalCVar::UpdateValue() { 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 */ 295 void idInternalCVar::UpdateCheat() { 296 // all variables are considered cheats except for a few types 297 if ( flags & ( CVAR_NOCHEAT | CVAR_INIT | CVAR_ROM | CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NETWORKSYNC ) ) { 298 flags &= ~CVAR_CHEAT; 299 } else { 300 flags |= CVAR_CHEAT; 301 } 302 } 303 304 /* 305 ============ 306 idInternalCVar::Set 307 ============ 308 */ 309 void idInternalCVar::Set( const char *newValue, bool force, bool fromServer ) { 310 if ( common->IsMultiplayer() && !fromServer ) { 311 #ifndef ID_TYPEINFO 312 if ( ( flags & CVAR_NETWORKSYNC ) && common->IsClient() ) { 313 common->Printf( "%s is a synced over the network and cannot be changed on a multiplayer client.\n", nameString.c_str() ); 314 return; 315 } 316 #endif 317 if ( ( flags & CVAR_CHEAT ) && !net_allowCheats.GetBool() ) { 318 common->Printf( "%s cannot be changed in multiplayer.\n", nameString.c_str() ); 319 return; 320 } 321 } 322 323 if ( !newValue ) { 324 newValue = resetString.c_str(); 325 } 326 327 if ( !force ) { 328 if ( flags & CVAR_ROM ) { 329 common->Printf( "%s is read only.\n", nameString.c_str() ); 330 return; 331 } 332 333 if ( flags & CVAR_INIT ) { 334 common->Printf( "%s is write protected.\n", nameString.c_str() ); 335 return; 336 } 337 } 338 339 if ( valueString.Icmp( newValue ) == 0 ) { 340 return; 341 } 342 343 valueString = newValue; 344 value = valueString.c_str(); 345 UpdateValue(); 346 347 SetModified(); 348 cvarSystem->SetModifiedFlags( flags ); 349 } 350 351 /* 352 ============ 353 idInternalCVar::Reset 354 ============ 355 */ 356 void idInternalCVar::Reset() { 357 valueString = resetString; 358 value = valueString.c_str(); 359 UpdateValue(); 360 } 361 362 /* 363 ============ 364 idInternalCVar::InternalGetResetString 365 ============ 366 */ 367 const char * idInternalCVar::InternalGetResetString() const { 368 return resetString; 369 } 370 371 /* 372 ============ 373 idInternalCVar::InternalSetString 374 ============ 375 */ 376 void idInternalCVar::InternalSetString( const char *newValue ) { 377 Set( newValue, true, false ); 378 } 379 380 /* 381 =============== 382 idInternalCVar::InternalServerSetString 383 =============== 384 */ 385 void idInternalCVar::InternalServerSetString( const char *newValue ) { 386 Set( newValue, true, true ); 387 } 388 389 /* 390 ============ 391 idInternalCVar::InternalSetBool 392 ============ 393 */ 394 void idInternalCVar::InternalSetBool( const bool newValue ) { 395 Set( idStr( newValue ), true, false ); 396 } 397 398 /* 399 ============ 400 idInternalCVar::InternalSetInteger 401 ============ 402 */ 403 void idInternalCVar::InternalSetInteger( const int newValue ) { 404 Set( idStr( newValue ), true, false ); 405 } 406 407 /* 408 ============ 409 idInternalCVar::InternalSetFloat 410 ============ 411 */ 412 void idInternalCVar::InternalSetFloat( const float newValue ) { 413 Set( idStr( newValue ), true, false ); 414 } 415 416 417 /* 418 =============================================================================== 419 420 idCVarSystemLocal 421 422 =============================================================================== 423 */ 424 425 class idCVarSystemLocal : public idCVarSystem { 426 public: 427 idCVarSystemLocal(); 428 429 virtual ~idCVarSystemLocal() {} 430 431 virtual void Init(); 432 virtual void Shutdown(); 433 virtual bool IsInitialized() const; 434 435 virtual void Register( idCVar *cvar ); 436 437 virtual idCVar * Find( const char *name ); 438 439 virtual void SetCVarString( const char *name, const char *value, int flags = 0 ); 440 virtual void SetCVarBool( const char *name, const bool value, int flags = 0 ); 441 virtual void SetCVarInteger( const char *name, const int value, int flags = 0 ); 442 virtual void SetCVarFloat( const char *name, const float value, int flags = 0 ); 443 444 virtual const char * GetCVarString( const char *name ) const; 445 virtual bool GetCVarBool( const char *name ) const; 446 virtual int GetCVarInteger( const char *name ) const; 447 virtual float GetCVarFloat( const char *name ) const; 448 449 virtual bool Command( const idCmdArgs &args ); 450 451 virtual void CommandCompletion( void(*callback)( const char *s ) ); 452 virtual void ArgCompletion( const char *cmdString, void(*callback)( const char *s ) ); 453 454 virtual void SetModifiedFlags( int flags ); 455 virtual int GetModifiedFlags() const; 456 virtual void ClearModifiedFlags( int flags ); 457 458 virtual void ResetFlaggedVariables( int flags ); 459 virtual void RemoveFlaggedAutoCompletion( int flags ); 460 virtual void WriteFlaggedVariables( int flags, const char *setCmd, idFile *f ) const; 461 462 virtual void MoveCVarsToDict( int flags, idDict & dict, bool onlyModified ) const; 463 virtual void SetCVarsFromDict( const idDict &dict ); 464 465 void RegisterInternal( idCVar *cvar ); 466 idInternalCVar * FindInternal( const char *name ) const; 467 void SetInternal( const char *name, const char *value, int flags ); 468 469 private: 470 bool initialized; 471 idList<idInternalCVar*, TAG_CVAR> cvars; 472 idHashIndex cvarHash; 473 int modifiedFlags; 474 475 private: 476 static void Toggle_f( const idCmdArgs &args ); 477 static void Set_f( const idCmdArgs &args ); 478 static void Reset_f( const idCmdArgs &args ); 479 static void ListByFlags( const idCmdArgs &args, cvarFlags_t flags ); 480 static void List_f( const idCmdArgs &args ); 481 static void Restart_f( const idCmdArgs &args ); 482 static void CvarAdd_f( const idCmdArgs &args ); 483 }; 484 485 idCVarSystemLocal localCVarSystem; 486 idCVarSystem * cvarSystem = &localCVarSystem; 487 488 #define NUM_COLUMNS 77 // 78 - 1 489 #define NUM_NAME_CHARS 33 490 #define NUM_DESCRIPTION_CHARS ( NUM_COLUMNS - NUM_NAME_CHARS ) 491 #define FORMAT_STRING "%-32s " 492 493 const char *CreateColumn( const char *text, int columnWidth, const char *indent, idStr &string ) { 494 int i, lastLine; 495 496 string.Clear(); 497 for ( lastLine = i = 0; text[i] != '\0'; i++ ) { 498 if ( i - lastLine >= columnWidth || text[i] == '\n' ) { 499 while( i > 0 && text[i] > ' ' && text[i] != '/' && text[i] != ',' && text[i] != '\\' ) { 500 i--; 501 } 502 while( lastLine < i ) { 503 string.Append( text[lastLine++] ); 504 } 505 string.Append( indent ); 506 lastLine++; 507 } 508 } 509 while( lastLine < i ) { 510 string.Append( text[lastLine++] ); 511 } 512 return string.c_str(); 513 } 514 515 /* 516 ============ 517 idCVarSystemLocal::FindInternal 518 ============ 519 */ 520 idInternalCVar *idCVarSystemLocal::FindInternal( const char *name ) const { 521 int hash = cvarHash.GenerateKey( name, false ); 522 for ( int i = cvarHash.First( hash ); i != -1; i = cvarHash.Next( i ) ) { 523 if ( cvars[i]->nameString.Icmp( name ) == 0 ) { 524 return cvars[i]; 525 } 526 } 527 return NULL; 528 } 529 530 /* 531 ============ 532 idCVarSystemLocal::SetInternal 533 ============ 534 */ 535 void idCVarSystemLocal::SetInternal( const char *name, const char *value, int flags ) { 536 int hash; 537 idInternalCVar *internal; 538 539 internal = FindInternal( name ); 540 541 if ( internal ) { 542 internal->InternalSetString( value ); 543 internal->flags |= flags & ~CVAR_STATIC; 544 internal->UpdateCheat(); 545 } else { 546 internal = new (TAG_SYSTEM) idInternalCVar( name, value, flags ); 547 hash = cvarHash.GenerateKey( internal->nameString.c_str(), false ); 548 cvarHash.Add( hash, cvars.Append( internal ) ); 549 } 550 } 551 552 /* 553 ============ 554 idCVarSystemLocal::idCVarSystemLocal 555 ============ 556 */ 557 idCVarSystemLocal::idCVarSystemLocal() { 558 initialized = false; 559 modifiedFlags = 0; 560 } 561 562 /* 563 ============ 564 idCVarSystemLocal::Init 565 ============ 566 */ 567 void idCVarSystemLocal::Init() { 568 569 modifiedFlags = 0; 570 571 cmdSystem->AddCommand( "toggle", Toggle_f, CMD_FL_SYSTEM, "toggles a cvar" ); 572 cmdSystem->AddCommand( "set", Set_f, CMD_FL_SYSTEM, "sets a cvar" ); 573 cmdSystem->AddCommand( "seta", Set_f, CMD_FL_SYSTEM, "sets a cvar" ); 574 cmdSystem->AddCommand( "sets", Set_f, CMD_FL_SYSTEM, "sets a cvar" ); 575 cmdSystem->AddCommand( "sett", Set_f, CMD_FL_SYSTEM, "sets a cvar" ); 576 cmdSystem->AddCommand( "setu", Set_f, CMD_FL_SYSTEM, "sets a cvar" ); 577 cmdSystem->AddCommand( "reset", Reset_f, CMD_FL_SYSTEM, "resets a cvar" ); 578 cmdSystem->AddCommand( "listCvars", List_f, CMD_FL_SYSTEM, "lists cvars" ); 579 cmdSystem->AddCommand( "cvar_restart", Restart_f, CMD_FL_SYSTEM, "restart the cvar system" ); 580 cmdSystem->AddCommand( "cvarAdd", CvarAdd_f, CMD_FL_SYSTEM, "adds a value to a numeric cvar" ); 581 582 initialized = true; 583 } 584 585 /* 586 ============ 587 idCVarSystemLocal::Shutdown 588 ============ 589 */ 590 void idCVarSystemLocal::Shutdown() { 591 cvars.DeleteContents( true ); 592 cvarHash.Free(); 593 initialized = false; 594 } 595 596 /* 597 ============ 598 idCVarSystemLocal::IsInitialized 599 ============ 600 */ 601 bool idCVarSystemLocal::IsInitialized() const { 602 return initialized; 603 } 604 605 /* 606 ============ 607 idCVarSystemLocal::Register 608 ============ 609 */ 610 void idCVarSystemLocal::Register( idCVar *cvar ) { 611 int hash; 612 idInternalCVar *internal; 613 614 cvar->SetInternalVar( cvar ); 615 616 internal = FindInternal( cvar->GetName() ); 617 618 if ( internal ) { 619 internal->Update( cvar ); 620 } else { 621 internal = new (TAG_SYSTEM) idInternalCVar( cvar ); 622 hash = cvarHash.GenerateKey( internal->nameString.c_str(), false ); 623 cvarHash.Add( hash, cvars.Append( internal ) ); 624 } 625 626 cvar->SetInternalVar( internal ); 627 } 628 629 /* 630 ============ 631 idCVarSystemLocal::Find 632 ============ 633 */ 634 idCVar *idCVarSystemLocal::Find( const char *name ) { 635 return FindInternal( name ); 636 } 637 638 /* 639 ============ 640 idCVarSystemLocal::SetCVarString 641 ============ 642 */ 643 void idCVarSystemLocal::SetCVarString( const char *name, const char *value, int flags ) { 644 SetInternal( name, value, flags ); 645 } 646 647 /* 648 ============ 649 idCVarSystemLocal::SetCVarBool 650 ============ 651 */ 652 void idCVarSystemLocal::SetCVarBool( const char *name, const bool value, int flags ) { 653 SetInternal( name, idStr( value ), flags ); 654 } 655 656 /* 657 ============ 658 idCVarSystemLocal::SetCVarInteger 659 ============ 660 */ 661 void idCVarSystemLocal::SetCVarInteger( const char *name, const int value, int flags ) { 662 SetInternal( name, idStr( value ), flags ); 663 } 664 665 /* 666 ============ 667 idCVarSystemLocal::SetCVarFloat 668 ============ 669 */ 670 void idCVarSystemLocal::SetCVarFloat( const char *name, const float value, int flags ) { 671 SetInternal( name, idStr( value ), flags ); 672 } 673 674 /* 675 ============ 676 idCVarSystemLocal::GetCVarString 677 ============ 678 */ 679 const char *idCVarSystemLocal::GetCVarString( const char *name ) const { 680 idInternalCVar *internal = FindInternal( name ); 681 if ( internal ) { 682 return internal->GetString(); 683 } 684 return ""; 685 } 686 687 /* 688 ============ 689 idCVarSystemLocal::GetCVarBool 690 ============ 691 */ 692 bool idCVarSystemLocal::GetCVarBool( const char *name ) const { 693 idInternalCVar *internal = FindInternal( name ); 694 if ( internal ) { 695 return internal->GetBool(); 696 } 697 return false; 698 } 699 700 /* 701 ============ 702 idCVarSystemLocal::GetCVarInteger 703 ============ 704 */ 705 int idCVarSystemLocal::GetCVarInteger( const char *name ) const { 706 idInternalCVar *internal = FindInternal( name ); 707 if ( internal ) { 708 return internal->GetInteger(); 709 } 710 return 0; 711 } 712 713 /* 714 ============ 715 idCVarSystemLocal::GetCVarFloat 716 ============ 717 */ 718 float idCVarSystemLocal::GetCVarFloat( const char *name ) const { 719 idInternalCVar *internal = FindInternal( name ); 720 if ( internal ) { 721 return internal->GetFloat(); 722 } 723 return 0.0f; 724 } 725 726 /* 727 ============ 728 idCVarSystemLocal::Command 729 ============ 730 */ 731 bool idCVarSystemLocal::Command( const idCmdArgs &args ) { 732 idInternalCVar *internal; 733 734 internal = FindInternal( args.Argv( 0 ) ); 735 736 if ( internal == NULL ) { 737 return false; 738 } 739 740 if ( args.Argc() == 1 ) { 741 // print the variable 742 common->Printf( "\"%s\" is:\"%s\"" S_COLOR_WHITE " default:\"%s\"\n", 743 internal->nameString.c_str(), internal->valueString.c_str(), internal->resetString.c_str() ); 744 if ( idStr::Length( internal->GetDescription() ) > 0 ) { 745 common->Printf( S_COLOR_WHITE "%s\n", internal->GetDescription() ); 746 } 747 } else { 748 // set the value 749 internal->Set( args.Args(), false, false ); 750 } 751 return true; 752 } 753 754 /* 755 ============ 756 idCVarSystemLocal::CommandCompletion 757 ============ 758 */ 759 void idCVarSystemLocal::CommandCompletion( void(*callback)( const char *s ) ) { 760 for( int i = 0; i < cvars.Num(); i++ ) { 761 callback( cvars[i]->GetName() ); 762 } 763 } 764 765 /* 766 ============ 767 idCVarSystemLocal::ArgCompletion 768 ============ 769 */ 770 void idCVarSystemLocal::ArgCompletion( const char *cmdString, void(*callback)( const char *s ) ) { 771 idCmdArgs args; 772 773 args.TokenizeString( cmdString, false ); 774 775 for( int i = 0; i < cvars.Num(); i++ ) { 776 if ( !cvars[i]->valueCompletion ) { 777 continue; 778 } 779 if ( idStr::Icmp( args.Argv( 0 ), cvars[i]->nameString.c_str() ) == 0 ) { 780 cvars[i]->valueCompletion( args, callback ); 781 break; 782 } 783 } 784 } 785 786 /* 787 ============ 788 idCVarSystemLocal::SetModifiedFlags 789 ============ 790 */ 791 void idCVarSystemLocal::SetModifiedFlags( int flags ) { 792 modifiedFlags |= flags; 793 } 794 795 /* 796 ============ 797 idCVarSystemLocal::GetModifiedFlags 798 ============ 799 */ 800 int idCVarSystemLocal::GetModifiedFlags() const { 801 return modifiedFlags; 802 } 803 804 /* 805 ============ 806 idCVarSystemLocal::ClearModifiedFlags 807 ============ 808 */ 809 void idCVarSystemLocal::ClearModifiedFlags( int flags ) { 810 modifiedFlags &= ~flags; 811 } 812 813 /* 814 ============ 815 idCVarSystemLocal::ResetFlaggedVariables 816 ============ 817 */ 818 void idCVarSystemLocal::ResetFlaggedVariables( int flags ) { 819 for( int i = 0; i < cvars.Num(); i++ ) { 820 idInternalCVar *cvar = cvars[i]; 821 if ( cvar->GetFlags() & flags ) { 822 cvar->Set( NULL, true, true ); 823 } 824 } 825 } 826 827 /* 828 ============ 829 idCVarSystemLocal::RemoveFlaggedAutoCompletion 830 ============ 831 */ 832 void idCVarSystemLocal::RemoveFlaggedAutoCompletion( int flags ) { 833 for( int i = 0; i < cvars.Num(); i++ ) { 834 idInternalCVar *cvar = cvars[i]; 835 if ( cvar->GetFlags() & flags ) { 836 cvar->valueCompletion = NULL; 837 } 838 } 839 } 840 841 /* 842 ============ 843 idCVarSystemLocal::WriteFlaggedVariables 844 845 Appends lines containing "set variable value" for all variables 846 with the "flags" flag set to true. 847 ============ 848 */ 849 void idCVarSystemLocal::WriteFlaggedVariables( int flags, const char *setCmd, idFile *f ) const { 850 for( int i = 0; i < cvars.Num(); i++ ) { 851 idInternalCVar *cvar = cvars[i]; 852 if ( cvar->GetFlags() & flags ) { 853 f->Printf( "%s %s \"%s\"\n", setCmd, cvar->GetName(), cvar->GetString() ); 854 } 855 } 856 } 857 858 /* 859 ============ 860 idCVarSystemLocal::MoveCVarsToDict 861 ============ 862 */ 863 void idCVarSystemLocal::MoveCVarsToDict( int flags, idDict & dict, bool onlyModified ) const { 864 dict.Clear(); 865 for( int i = 0; i < cvars.Num(); i++ ) { 866 idCVar *cvar = cvars[i]; 867 if ( cvar->GetFlags() & flags ) { 868 if ( onlyModified && idStr::Icmp( cvar->GetString(), cvar->GetDefaultString() ) == 0 ) { 869 continue; 870 } 871 dict.Set( cvar->GetName(), cvar->GetString() ); 872 } 873 } 874 } 875 876 /* 877 ============ 878 idCVarSystemLocal::SetCVarsFromDict 879 ============ 880 */ 881 void idCVarSystemLocal::SetCVarsFromDict( const idDict &dict ) { 882 idInternalCVar *internal; 883 884 for( int i = 0; i < dict.GetNumKeyVals(); i++ ) { 885 const idKeyValue *kv = dict.GetKeyVal( i ); 886 internal = FindInternal( kv->GetKey() ); 887 if ( internal ) { 888 internal->InternalServerSetString( kv->GetValue() ); 889 } 890 } 891 } 892 893 /* 894 ============ 895 idCVarSystemLocal::Toggle_f 896 ============ 897 */ 898 void idCVarSystemLocal::Toggle_f( const idCmdArgs &args ) { 899 int argc, i; 900 float current, set; 901 const char *text; 902 903 argc = args.Argc(); 904 if ( argc < 2 ) { 905 common->Printf ("usage:\n" 906 " toggle <variable> - toggles between 0 and 1\n" 907 " toggle <variable> <value> - toggles between 0 and <value>\n" 908 " toggle <variable> [string 1] [string 2]...[string n] - cycles through all strings\n"); 909 return; 910 } 911 912 idInternalCVar *cvar = localCVarSystem.FindInternal( args.Argv( 1 ) ); 913 914 if ( cvar == NULL ) { 915 common->Warning( "Toggle_f: cvar \"%s\" not found", args.Argv( 1 ) ); 916 return; 917 } 918 919 if ( argc > 3 ) { 920 // cycle through multiple values 921 text = cvar->GetString(); 922 for( i = 2; i < argc; i++ ) { 923 if ( !idStr::Icmp( text, args.Argv( i ) ) ) { 924 // point to next value 925 i++; 926 break; 927 } 928 } 929 if ( i >= argc ) { 930 i = 2; 931 } 932 933 common->Printf( "set %s = %s\n", args.Argv(1), args.Argv( i ) ); 934 cvar->Set( va("%s", args.Argv( i ) ), false, false ); 935 } else { 936 // toggle between 0 and 1 937 current = cvar->GetFloat(); 938 if ( argc == 3 ) { 939 set = atof( args.Argv( 2 ) ); 940 } else { 941 set = 1.0f; 942 } 943 if ( current == 0.0f ) { 944 current = set; 945 } else { 946 current = 0.0f; 947 } 948 common->Printf( "set %s = %f\n", args.Argv(1), current ); 949 cvar->Set( idStr( current ), false, false ); 950 } 951 } 952 953 /* 954 ============ 955 idCVarSystemLocal::Set_f 956 ============ 957 */ 958 void idCVarSystemLocal::Set_f( const idCmdArgs &args ) { 959 const char *str; 960 961 str = args.Args( 2, args.Argc() - 1 ); 962 localCVarSystem.SetCVarString( args.Argv(1), str ); 963 } 964 965 /* 966 ============ 967 idCVarSystemLocal::Reset_f 968 ============ 969 */ 970 void idCVarSystemLocal::Reset_f( const idCmdArgs &args ) { 971 idInternalCVar *cvar; 972 973 if ( args.Argc() != 2 ) { 974 common->Printf ("usage: reset <variable>\n"); 975 return; 976 } 977 cvar = localCVarSystem.FindInternal( args.Argv( 1 ) ); 978 if ( !cvar ) { 979 return; 980 } 981 982 cvar->Reset(); 983 } 984 985 /* 986 ============ 987 idCVarSystemLocal::CvarAdd_f 988 ============ 989 */ 990 void idCVarSystemLocal::CvarAdd_f( const idCmdArgs &args ) { 991 if ( args.Argc() != 3 ) { 992 common->Printf ("usage: cvarAdd <variable> <value>\n"); 993 } 994 995 idInternalCVar *cvar = localCVarSystem.FindInternal( args.Argv( 1 ) ); 996 if ( !cvar ) { 997 return; 998 } 999 1000 const float newValue = cvar->GetFloat() + atof( args.Argv( 2 ) ); 1001 cvar->SetFloat( newValue ); 1002 common->Printf( "%s = %f\n", cvar->GetName(), newValue ); 1003 } 1004 // 1005 ///* 1006 //================================================ 1007 //idSort_CommandDef 1008 //================================================ 1009 //*/ 1010 //class idSort_InternalCVar : public idSort_Quick< const idInternalCVar *, idSort_InternalCVar > { 1011 //public: 1012 // int Compare( const idInternalCVar * & a, const idInternalCVar * & b ) const { return idStr::Icmp( a.GetName(), b.GetName() ); } 1013 //}; 1014 1015 void idCVarSystemLocal::ListByFlags( const idCmdArgs &args, cvarFlags_t flags ) { 1016 int i, argNum; 1017 idStr match, indent, string; 1018 const idInternalCVar *cvar; 1019 idList<const idInternalCVar *, TAG_CVAR>cvarList; 1020 1021 enum { 1022 SHOW_VALUE, 1023 SHOW_DESCRIPTION, 1024 SHOW_TYPE, 1025 SHOW_FLAGS 1026 } show; 1027 1028 argNum = 1; 1029 show = SHOW_VALUE; 1030 1031 if ( idStr::Icmp( args.Argv( argNum ), "-" ) == 0 || idStr::Icmp( args.Argv( argNum ), "/" ) == 0 ) { 1032 if ( idStr::Icmp( args.Argv( argNum + 1 ), "help" ) == 0 || idStr::Icmp( args.Argv( argNum + 1 ), "?" ) == 0 ) { 1033 argNum = 3; 1034 show = SHOW_DESCRIPTION; 1035 } else if ( idStr::Icmp( args.Argv( argNum + 1 ), "type" ) == 0 || idStr::Icmp( args.Argv( argNum + 1 ), "range" ) == 0 ) { 1036 argNum = 3; 1037 show = SHOW_TYPE; 1038 } else if ( idStr::Icmp( args.Argv( argNum + 1 ), "flags" ) == 0 ) { 1039 argNum = 3; 1040 show = SHOW_FLAGS; 1041 } 1042 } 1043 1044 if ( args.Argc() > argNum ) { 1045 match = args.Args( argNum, -1 ); 1046 match.Replace( " ", "" ); 1047 } else { 1048 match = ""; 1049 } 1050 1051 for ( i = 0; i < localCVarSystem.cvars.Num(); i++ ) { 1052 cvar = localCVarSystem.cvars[i]; 1053 1054 if ( !( cvar->GetFlags() & flags ) ) { 1055 continue; 1056 } 1057 1058 if ( match.Length() && !cvar->nameString.Filter( match, false ) ) { 1059 continue; 1060 } 1061 1062 cvarList.Append( cvar ); 1063 } 1064 1065 //cvarList.SortWithTemplate( idSort_InternalCVar() ); 1066 1067 switch( show ) { 1068 case SHOW_VALUE: { 1069 for ( i = 0; i < cvarList.Num(); i++ ) { 1070 cvar = cvarList[i]; 1071 common->Printf( FORMAT_STRING S_COLOR_WHITE "\"%s\"\n", cvar->nameString.c_str(), cvar->valueString.c_str() ); 1072 } 1073 break; 1074 } 1075 case SHOW_DESCRIPTION: { 1076 indent.Fill( ' ', NUM_NAME_CHARS ); 1077 indent.Insert( "\n", 0 ); 1078 1079 for ( i = 0; i < cvarList.Num(); i++ ) { 1080 cvar = cvarList[i]; 1081 common->Printf( FORMAT_STRING S_COLOR_WHITE "%s\n", cvar->nameString.c_str(), CreateColumn( cvar->GetDescription(), NUM_DESCRIPTION_CHARS, indent, string ) ); 1082 } 1083 break; 1084 } 1085 case SHOW_TYPE: { 1086 for ( i = 0; i < cvarList.Num(); i++ ) { 1087 cvar = cvarList[i]; 1088 if ( cvar->GetFlags() & CVAR_BOOL ) { 1089 common->Printf( FORMAT_STRING S_COLOR_CYAN "bool\n", cvar->GetName() ); 1090 } else if ( cvar->GetFlags() & CVAR_INTEGER ) { 1091 if ( cvar->GetMinValue() < cvar->GetMaxValue() ) { 1092 common->Printf( FORMAT_STRING S_COLOR_GREEN "int " S_COLOR_WHITE "[%d, %d]\n", cvar->GetName(), (int) cvar->GetMinValue(), (int) cvar->GetMaxValue() ); 1093 } else { 1094 common->Printf( FORMAT_STRING S_COLOR_GREEN "int\n", cvar->GetName() ); 1095 } 1096 } else if ( cvar->GetFlags() & CVAR_FLOAT ) { 1097 if ( cvar->GetMinValue() < cvar->GetMaxValue() ) { 1098 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() ); 1099 } else { 1100 common->Printf( FORMAT_STRING S_COLOR_RED "float\n", cvar->GetName() ); 1101 } 1102 } else if ( cvar->GetValueStrings() ) { 1103 common->Printf( FORMAT_STRING S_COLOR_WHITE "string " S_COLOR_WHITE "[", cvar->GetName() ); 1104 for ( int j = 0; cvar->GetValueStrings()[j] != NULL; j++ ) { 1105 if ( j ) { 1106 common->Printf( S_COLOR_WHITE ", %s", cvar->GetValueStrings()[j] ); 1107 } else { 1108 common->Printf( S_COLOR_WHITE "%s", cvar->GetValueStrings()[j] ); 1109 } 1110 } 1111 common->Printf( S_COLOR_WHITE "]\n" ); 1112 } else { 1113 common->Printf( FORMAT_STRING S_COLOR_WHITE "string\n", cvar->GetName() ); 1114 } 1115 } 1116 break; 1117 } 1118 case SHOW_FLAGS: { 1119 for ( i = 0; i < cvarList.Num(); i++ ) { 1120 cvar = cvarList[i]; 1121 common->Printf( FORMAT_STRING, cvar->GetName() ); 1122 string = ""; 1123 if ( cvar->GetFlags() & CVAR_BOOL ) { 1124 string += S_COLOR_CYAN "B "; 1125 } else if ( cvar->GetFlags() & CVAR_INTEGER ) { 1126 string += S_COLOR_GREEN "I "; 1127 } else if ( cvar->GetFlags() & CVAR_FLOAT ) { 1128 string += S_COLOR_RED "F "; 1129 } else { 1130 string += S_COLOR_WHITE "S "; 1131 } 1132 if ( cvar->GetFlags() & CVAR_SYSTEM ) { 1133 string += S_COLOR_WHITE "SYS "; 1134 } else if ( cvar->GetFlags() & CVAR_RENDERER ) { 1135 string += S_COLOR_WHITE "RNDR "; 1136 } else if ( cvar->GetFlags() & CVAR_SOUND ) { 1137 string += S_COLOR_WHITE "SND "; 1138 } else if ( cvar->GetFlags() & CVAR_GUI ) { 1139 string += S_COLOR_WHITE "GUI "; 1140 } else if ( cvar->GetFlags() & CVAR_GAME ) { 1141 string += S_COLOR_WHITE "GAME "; 1142 } else if ( cvar->GetFlags() & CVAR_TOOL ) { 1143 string += S_COLOR_WHITE "TOOL "; 1144 } else { 1145 string += S_COLOR_WHITE " "; 1146 } 1147 string += ( cvar->GetFlags() & CVAR_SERVERINFO ) ? "SI " : " "; 1148 string += ( cvar->GetFlags() & CVAR_STATIC ) ? "ST " : " "; 1149 string += ( cvar->GetFlags() & CVAR_CHEAT ) ? "CH " : " "; 1150 string += ( cvar->GetFlags() & CVAR_INIT ) ? "IN " : " "; 1151 string += ( cvar->GetFlags() & CVAR_ROM ) ? "RO " : " "; 1152 string += ( cvar->GetFlags() & CVAR_ARCHIVE ) ? "AR " : " "; 1153 string += ( cvar->GetFlags() & CVAR_MODIFIED ) ? "MO " : " "; 1154 string += "\n"; 1155 common->Printf( string ); 1156 } 1157 break; 1158 } 1159 } 1160 1161 common->Printf( "\n%i cvars listed\n\n", cvarList.Num() ); 1162 common->Printf( "listCvar [search string] = list cvar values\n" 1163 "listCvar -help [search string] = list cvar descriptions\n" 1164 "listCvar -type [search string] = list cvar types\n" 1165 "listCvar -flags [search string] = list cvar flags\n" ); 1166 } 1167 1168 /* 1169 ============ 1170 idCVarSystemLocal::List_f 1171 ============ 1172 */ 1173 void idCVarSystemLocal::List_f( const idCmdArgs &args ) { 1174 ListByFlags( args, CVAR_ALL ); 1175 } 1176 1177 /* 1178 ============ 1179 idCVarSystemLocal::Restart_f 1180 ============ 1181 */ 1182 void idCVarSystemLocal::Restart_f( const idCmdArgs &args ) { 1183 int i, hash; 1184 idInternalCVar *cvar; 1185 1186 for ( i = 0; i < localCVarSystem.cvars.Num(); i++ ) { 1187 cvar = localCVarSystem.cvars[i]; 1188 1189 // don't mess with rom values 1190 if ( cvar->flags & ( CVAR_ROM | CVAR_INIT ) ) { 1191 continue; 1192 } 1193 1194 // throw out any variables the user created 1195 if ( !( cvar->flags & CVAR_STATIC ) ) { 1196 hash = localCVarSystem.cvarHash.GenerateKey( cvar->nameString, false ); 1197 delete cvar; 1198 localCVarSystem.cvars.RemoveIndex( i ); 1199 localCVarSystem.cvarHash.RemoveIndex( hash, i ); 1200 i--; 1201 continue; 1202 } 1203 1204 cvar->Reset(); 1205 } 1206 }