A **console command** is simply a user input string that is sent to the engine and the engine can react is some way (e.g. console/log response, changing internal state).
A **console variable** additionally stores some state that can be changed through the console. By registering console commands and variables in the console manager you get
auto completion and enumeration to get a list of all console objects (console command Help or DumpConsoleVariables). Because of this, you should avoid the old Exec
Here we register a console variables of the type int32, with the name r.RefractionQuality, the default value of 2 and some multi line help text and some flags.
There are many flags, the most important one is ECVF_Cheat. That is explained in detail in IConsoleManager.h.
TEXT(" 3: high quality (e.g. color fringe, not yet implemented)"),
ECVF_Scalability | ECVF_RenderThreadSafe);
`IConsoleManager::Get()` 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.
The second parameter is the default value, and depending on the type of this constant, a different console variable type is created: int, float, or string (!FString).
The next parameter defines the console variable help text.
It is also possible to register a reference to an existing variable. This is convenient and fast but bypasses multiple features (e.g. thread safety, callback, sink, cheat) so we suggest to avoiding this method. Here is an example:
Getting the state of console variables created with **RegisterConsoleVariableRef** can be done efficiently by using the variable that it was registered with. e.g.
Using Getter functions (ie. !GetInt(), !GetFloat(), !GetString()) to determine a console variables state results in a slightly slower implementation (virtual function call, possibly cache miss, etc.).
For best performance you should use same type the variable was registered with. In order to get the pointer to the variable, you can either store the return
Often the simplest method is the best: You can store the old state in your subsystem and check each frame if they differ. Here you control when this happens very freely e.g. render thread or game thread, streaming thread, before/after tick or rendering. When you detect the difference, you copy
The sink is called at a specific point on the main thread before rendering. The function does not get the console variable name/pointer as this often would lead to the wrong behavior.
If multiple console variables (e.g. r.SceneColorFormat, r.GBufferFormat) should all trigger the change, it is best to call the code after all have been changed, not one after another.
* The callback can come back at any point in time whenever **!Set()** is getting called. You code has to work in all cases (during init, during serialization).
* Console variable should reflect the user input, not necessarily the state of the system (e.g. !MotionBlur 0/1, some platforms might not support it).
The variable state should not be changed by code. Otherwise the user might wonder if he mistyped because the variable does not 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.
Even better might be to compile out the feature using defines (e.g. #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)).
* 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.
* It is important to register the variable during engine initialization so that auto completion and !DumpConsoleCommands and !Help can work.
Please read `IConsoleManager.h` for find more details on this.
On engine startup, the state of console variables can be loaded from the file **Engine/Config/ConsoleVariables.ini**. This place is reserved for the local developer - it should not be used for project settings.
In order to be able to reapply some settings (e.g. project settings can be changed in editor UI) while keeping the specified overrides (e.g. from command line),
we introduced a priority. Now all settings can be applied in any order.
see IConsoleManager.h:
// lowest priority (default after console variable creation)
ECVF_SetByConstructor = 0x00000000,
// from Scalability.ini
ECVF_SetByScalability = 0x01000000,
// (in game UI or from file)
ECVF_SetByGameSetting = 0x02000000,
// project settings
ECVF_SetByProjectSetting = 0x03000000,
// per device setting
ECVF_SetByDeviceProfile = 0x04000000,
// per project setting
ECVF_SetBySystemSettingsIni = 0x05000000,
// consolevariables.ini (for multiple projects)
ECVF_SetByConsoleVariablesIni = 0x06000000,
// a minus command e.g. -VSync
ECVF_SetByCommandline = 0x07000000,
// least useful, likely a hack, maybe better to find the correct SetBy...
ECVF_SetByCode = 0x08000000,
// editor UI or console in game or editor
ECVF_SetByConsole = 0x09000000,
In some cases, you might see this log printout:
Console variable 'r.MyVar' wasn't set (Priority SetByDeviceProfile < SetByCommandline)
It might be intended (e.g. command line forces a user setting) or caused by some code issue.
The priority is also helpful to see who set the variable the last time. You can get this information when getting the console variable state. e.g.
* 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 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 flags get copied from the new variable. This way DLL loading and unloading can work even without losing the variable state.
Note that this will not work for console variable references.
<!--Sentence below deprecated for clarification.-->
<!--This can be fixed by giving up on one: do not store pointers, do not unregistered or not use references.-->