UDN
Search public documentation:

ConsoleManager
日本語訳
中国翻译
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 Home > Engine Programming > Console Manager: Console Variables in C++

Console Manager: Console Variables in C++


Overview


The Unreal engine has console commands since a long time. A command is simply a user input string that is sent to the engine and the engine can react is some way (e.g. console text response, changing internal state).

The new console manager unifies and simplifies a common pattern: the console variable

What is a console variable?


A console variable is some simple data type (e.g. float, int, string) that has an engine wide state and the user can read and set the state. The console variable has a name and the user gets auto completion when he starts typing the name into the console. e.g.

User console input Console output Description
MyConsoleVar MyConsoleVar = 0 The current state of the variable is printed into the console.
MyConsoleVar 123 MyConsoleVar = 123 The state of the variable is changed and the new state printed into the console.
MyConsoleVar ? Possibly multi line help text. Print the console variable help text into the console.

Creating / registering a console variable


The variable needs to be registered early when the engine is created. Example:

  GConsoleManager->RegisterConsoleVariable(TEXT("TonemapperType"),
     -1,
     TEXT("Allows to override which tonemapper function (during the post processing stage to transform HDR to LDR colors) is used:\n")
     TEXT("  -1 = use what is specified elsewhere\n")
     TEXT("   0 = off (no tonemapper)\n")
     TEXT("   1 = filmic approximation (s-curve, contrast enhances, changes saturation and hue)\n")
     TEXT("   2 = neutral soft white clamp (experimental)"),
     ECVF_Cheat);

GConsoleManager is the global access point. There you can register a console variable or find an existing one. The first parameter is the name of the console variable (unicode). The second parameter is the default value and depending on the type of of this constant a different console variable types in created: int, float or string (FString).

RegisterConsoleVariableRef also allows to register an existing float or int and simply have the console variable directly using that to store it's state.

The next parameter defined the help text that is shown when the user uses "?" after the console variable.

Another optional parameter allows to specify flags such as ECVF_Cheat. Those are explained in detail in IConsoleManager.h.

Getting the state of a console variable


Getting the state of console variables created with RegisterConsoleVariableRef can be done efficiently by using the variable that it was registered with.

Only slightly slower (virtual function call, possibly cache miss) but more convenient is it to get the state by using one of the get functions: GetInt(), GetFloat(), GetString() For best performance you should used same type the variable was registered with. In order to get the pointer to the variable you can either store the return argument of the register function or call FindConsoleVariable just before you needs the variable. Example:

   static IConsoleVariable* CVar = GConsoleManager->FindConsoleVariable(TEXT("TonemapperType")); 

   INT Value = CVar->GetInt();

The static there ensures the name search (implemented as map) is only done the first time this code is called. This is correct as the variable will never move and only gets destructed on engine shutdown.

Reacting when the state changes


The ECVF_Changed flag can be used to detect if the state was changes through the Set() method or by user input (Note that reference to variables could be changed not triggering this flag). Example:

   if(CVar->TestFlags(ECVF_Changed))
   {
      CVar->ClearFlags(ECVF_Changed);
      ... 
   }

Intended console variable behavior and style


  • Console variable should reflect the user input, not necessarily the state of the system (e.g. MotionBlur 0/1, some platform might not support it). The variable state should not be changed by code. Otherwise the user might wonder if he mistyped because the variable doesn't have the state he specified or he might not be able to change a console variable because of the state of some other variable.
  • Always provide a good help explaining what the variable is used for and what values make sense to specify.
  • Most console variables are intended for development only so specifying the ECVF_Cheat flag early would be a good idea.
  • The variable name should be as minimal as possible while being descriptive, negating meaning should be avoided (e.g. bad names would be EnableMotionBlur, MotionBlurDisable, MBlur, HideMotionBlur). Use upper and lower case to make the name easier to read and consistent (e.g. MotionBlur).
  • For indentation you can assume fixed width font (non proportional) output.

Please read IConsoleManager.h for find more details on this.

Loading console variables

On engine startup the state of console variables can be loaded from the file "Engine/Config/ConsoleVariables.ini". More details can be found in the file itself:

; This file allows to set console variables on engine startup (In undefined order).
; Currently there is no other file overriding this one.
; This file should be in the source control database (for the comments and to know where to find it)
; but kept empty from variables.
; A developer can change it locally to save time not having to type repetitive
; console variable settings. The variables need to be in the section called [Startup].
; Later on we might have multiple named sections referenced by the section name.
; This would allow platform specific or level specific overrides.
; The name comparison is not case sensitive and if the variable doesn't exists it's silently ignored.
;
; Example file content:
;
; [Startup]
; FogDensity = 0.9
; ImageGrain = 0.5
; FreezeAtPosition = 2819.5520 416.2633 75.1500 65378 -25879 0

[Startup]

Future


  • The current system is explicitly simple to make it very easy to use.
  • We also consider doing console commands (unified interface, using callbacks or delegates, auto complete and help).
  • To have nice help text printout in all resolutions we should check for a maximum line width and make sure we always use a fixed width font.
  • Currently console variable can only be created in C++ but that might change.
  • We should think about grouping the variables. Other systems have a leading character or string for that purpose (e.g. s_MusicBufferSize)
  • We plan to add a console command to output all console variables with their help (sorted, grouped).
  • We thought about adding an enum and bool type but there are many problems attached to it. For now we suggest to use int, or if needed strings.
  • The help text is convenient but to save executable size or to make it harder for cheaters we consider adding a define to prevent the help text to go into the executable.
  • The current auto completion feature also prints out a single line help for some commands. This is disabled for console variables as we don't want to specify another single line help and we should not shorten the multi line help. This might change.

Unregistering console variables

The UnregisterConsoleVariable method allows to remove the variable. At least this is what is happening from the users perspective. The variable is still kept (with the unregistered flags) to not crash when pointers access the data. If a new variable is registered with the same name the old variable is restored and help and flags get copied from the new variable. This way DLL loading and unloading can work even without lossing the variable state. Note this will not work for console variable references. This can be fixed by giving up on one: do not store pointers, do not unregistered or not use references.

Comparison to manual console variable implementation


Example:

some .cpp file, globals

   // for documentation see "MotionBlurSoftEdge" console command
   FLOAT GMotionBlurSoftEdge = -1;

some other .cpp file, Exec() method

   else if (ParseCommand(&Cmd, TEXT("MotionBlurSoftEdge")))
   {
      extern FLOAT GMotionBlurSoftEdge;
      FString Parameter(ParseToken(Cmd, 0));
      if(Parameter.Len())
      {
         GMotionBlurSoftEdge = appAtof(*Parameter);
      }
      else
      {
         Ar.Logf(TEXT("Allows to override the motion blur soft edge amount.\n"));
         Ar.Logf(TEXT("<0: use post process settings (default: -1)"));
         Ar.Logf(TEXT(" 0: override post process settings, feature is off"));
         Ar.Logf(TEXT(">0: override post process settings by the given value"));
      }
      Ar.Logf( TEXT("MotionBlurSoftEdge = %g"), GMotionBlurSoftEdge );
      return TRUE;
   } 

In BaseInput.ini

   ManualAutoCompleteList=(Command="MotionBlurSoftEdge",Desc="")

usage in some function:

   extern FLOAT GMotionBlurSoftEdge;
   ... use GMotionBlurSoftEdge ...

becomes:

in some .cpp file, on engine startup

   GConsoleManager->RegisterConsoleVariable(TEXT("MotionBlurSoftEdge"),
      -1.0f,
      TEXT("Allows to override the motion blur soft edge amount.\n")
      TEXT("<0: use post process settings (default: -1)\n")
      TEXT(" 0: override post process settings, feature is off\n")
      TEXT(">0: override post process settings by the given value"),
      ECVF_Cheat);

usage in some function:

   {
      static IConsoleVariable* CVar = GConsoleManager->FindConsoleVariable(TEXT("MotionBlurSoftEdge")); 
      FLOAT Value = CVar->GetFloat();
      ... use Value ...
   }

This could be even smaller when creating the console variable just before reading it. However it's important to register the variable during engine initialization so that auto completion can work. It's also important to be able to output all console variables with their help, a feature we plan to do.