You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
283 lines
18 KiB
Plaintext
283 lines
18 KiB
Plaintext
INTSourceChangelist:2566850
|
|
Availability:Public
|
|
Title:コンソール マネージャ:C++ のコンソール変数
|
|
Crumbs:%ROOT%, Engine, Programming, Programming/Basics
|
|
Description:コンソール マネージャの概要とコンソール変数を作成するための実装の詳細
|
|
Version:4.6
|
|
|
|
[TOC(start:2)]
|
|
|
|
|
|
|
|
## 概要
|
|
|
|
**コンソール コマンド** はユーザーが入力する文字列であり、エンジンに送られます。エンジンは何らかの方法でこれに対して反応します。(例 : コンソール / ログの反応。内部状態の変更)。
|
|
**コンソール変数** は何らかの状態を追加で保存し、これはコンソールを介して変更できます。コンソール コマンドと変数をコンソール マネージャに登録することで、
|
|
オートコンプリートと列挙型関数を使えるようにし、すべてのコンソール オブジェクトのリストを取得します (コンソール コマンドの **Help** または **DumpConsoleVariables**)。このため、古い Exec インターフェースは
|
|
避けてください。中央にあるコンソール マネージャは上記のものなど (例、ユーザー入力の履歴) を制御します。
|
|
|
|
|
|
## コンソール変数とは何でしょう?
|
|
|
|
コンソール変数は、エンジン全体に及ぶ状態を保持する単純なデータ型 (例 : float 型、int 型、string 型) です。ユーザーは、この状態を読み取ったり、セットしたりすることができます。
|
|
コンソール変数は名前をもちます。コンソールに名前をタイプし始めるとオートコンプリートされます。 例 :
|
|
|
|
|**ユーザーによるコンソール出力**|**コンソールの出力**|**説明**|
|
|
| --- | --- | --- |
|
|
|`MyConsoleVar`|`MyConsoleVar = 0`|変数の現在の状態がコンソールに出力されます。|
|
|
|`MyConsoleVar 123`|`MyConsoleVar = 123 LastSetBy:Constructor`|変数の状態が変更されて、新たな状態がコンソールに表示されます。|
|
|
|`MyConsoleVar ?`|`おそらくはヘルプ用テキストが複数行`|コンソール変数のヘルプ用テキストがコンソールに表示されます。|
|
|
|
|
|
|
|
|
## コンソール変数の作成 / 登録
|
|
|
|
変数は、エンジンが作成される際に早期に登録される必要があります。この例では、早期登録の最良の方法を示しています (どの C++ ファイルでも)。
|
|
|
|
static TAutoConsoleVariable<int32> CVarRefractionQuality(
|
|
TEXT("r.RefractionQuality"),
|
|
2,
|
|
TEXT("Defines the distorion/refraction quality, adjust for quality or performance.\n")
|
|
TEXT("<=0: off (fastest)\n")
|
|
TEXT(" 1: low quality (not yet implemented)\n")
|
|
TEXT(" 2: normal quality (default)\n")
|
|
TEXT(" 3: high quality (e.g. color fringe, not yet implemented)"),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe);
|
|
|
|
ここでは、型 int32 で名前が **r.RefractionQuality**、デフォルト値が 2 で何らかの複数行ヘルプテキストといくつかのフラグを持つのコンソール変数を登録します。
|
|
多くのフラグがあり、最も重要なものは **ECVF_Cheat** です。詳細は `IConsoleManager.h` で説明します。
|
|
コンソール変数の後に "?" を使用するとヘルプ テキストが表示されます。
|
|
|
|
必要があれば、関数内でコンソール変数を生成することもできます。
|
|
|
|
IConsoleManager::Get().RegisterConsoleVariable(TEXT("r.RefractionQuality"),
|
|
2,
|
|
TEXT("Defines the distorion/refraction quality, adjust for quality or performance.\n")
|
|
TEXT("<=0: off (fastest)\n")
|
|
TEXT(" 1: low quality (not yet implemented)\n")
|
|
TEXT(" 2: normal quality (default)\n")
|
|
TEXT(" 3: high quality (e.g. color fringe, not yet implemented)"),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe);
|
|
|
|
`IConsoleManager::Get()` はグローバル アクセス ポイントです。ここでコンソール変数を登録するか、既存のものを見つけることができます。最初のパラメータはコンソール変数名です。
|
|
2 つめのパラメータはデフォルト値です。この定数の型に応じて、int、float、または string (!FString) など様々なコンソール変数型が作成されます。
|
|
次のパラメータは、コンソール変数のヘルプ用テキストを定義します。
|
|
|
|
既存の変数の参照を登録することも可能です。これは便利で高速ですが、複数の機能 (例、thread safety, callback, sink, cheat) をバイパスします。そのため、この方法は使用しないことをお勧めします。以下はその例です。
|
|
|
|
FAutoConsoleVariableRef CVarVisualizeGPUSimulation(
|
|
TEXT("FX.VisualizeGPUSimulation"),
|
|
VisualizeGPUSimulation,
|
|
TEXT("Visualize the current state of GPU simulation.\n")
|
|
TEXT("0 = off\n")
|
|
TEXT("1 = visualize particle state\n")
|
|
TEXT("2 = visualize curve texture"),
|
|
ECVF_Cheat
|
|
);
|
|
|
|
ここでは型は変数の型から推論されます。
|
|
|
|
|
|
|
|
## コンソール変数の状態を取得する
|
|
|
|
`RegisterConsoleVariableRef` で作成されたコンソール変数の状態を効率的に取得するには、その状態とともに登録された変数を使用します。
|
|
|
|
// 同じ cpp ファイル内ではない場合に限り、必要。
|
|
extern TAutoConsoleVariable<int32> CVarRefractionQuality;
|
|
// ゲーム スレッドで値を取得
|
|
int32 MyVar = CVarRefractionQuality.GetValueOnGameThread();
|
|
|
|
わずかに遅くなるものの (仮想関数呼び出し、あるいはキャッシュ化の失敗の可能性) 状態を取得するには、get 関数を使用します ( !GetInt(), !GetFloat(), !GetString() )。
|
|
最善のパフォーマンスを目指すならば、変数を登録したときに使用した型と同じ型を使用すべきです。変数へのポインターを取得するには、登録関数の戻り値の引数を保存するか、
|
|
変数が必要となる直前に `FindConsoleVariable` を呼び出します。例:
|
|
|
|
static const auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("TonemapperType"));
|
|
int32 Value = CVar->GetInt();
|
|
|
|
**静的** にすることによって、名前の検索 (マップとして実装されている) が、初めてコードが呼び出された時にのみ実行されるようになります。
|
|
これが正しいのは、変数が決して移動せず、エンジンがシャットダウンした時にのみ破壊されるからです。
|
|
|
|
|
|
## コンソール変数の変化を追跡する方法
|
|
|
|
コンソール変数が変化する場合にカスタム コードを実行したい場合、方法として 3 つの選択肢があります。
|
|
|
|
ほとんどの場合、 **最もシンプルな方法** がベストです。サブシステムに古い状態を保存し、各フレームが異なっているかをチェックします。いつ (例、レンダー スレッド、ゲーム スレッド、ストリーミング スレッド、ティックまたはレンダリングの前後) これを行うかを自由にコントロールできます。違いを検知したら、コンソール変数の状態をコピーし、
|
|
例えば以下のようなカスタム コードを使用します。
|
|
|
|
void MyFunc()
|
|
{
|
|
int GBufferFormat = CVarGBufferFormat.GetValueOnRenderThread();
|
|
|
|
if(CurrentGBufferFormat != GBufferFormat)
|
|
{
|
|
CurrentGBufferFormat = GBufferFormat;
|
|
|
|
// カスタム コード
|
|
}
|
|
}
|
|
|
|
例えば、**コンソール変数 sink** を登録することもできます。
|
|
|
|
static void MySinkFunction()
|
|
{
|
|
bool bNewAtmosphere = CVarAtmosphereRender.GetValueOnGameThread() != 0;
|
|
|
|
// デフォルトで状態は true であるとします。
|
|
static bool GAtmosphere = true;
|
|
|
|
if (GAtmosphere != bNewAtmosphere)
|
|
{
|
|
GAtmosphere = bNewAtmosphere;
|
|
|
|
// カスタム コード
|
|
}
|
|
}
|
|
|
|
FAutoConsoleVariableSink CMyVarSink(FConsoleCommandDelegate::CreateStatic(&MySinkFunction));
|
|
|
|
レンダリング前のメインスレッドの特定ポイントで sink が呼び出されます。関数はコンソール変数の名前 / ポインタを取得しません。これは、誤った挙動になることが多いためです。
|
|
複数のコンソール変数 (例、r.SceneColorFormat, r.GBufferFormat) のすべてが変更をトリガーする場合、ひとつひとつではなく、すべての変更が終わってからコードを呼び出すのが最善です。
|
|
|
|
最後の方法は、**コールバック** を使うものですが、注意深く使用しないと問題を引き起こす可能性があるため使用を避けてください。
|
|
|
|
* サイクルはデッドロックを生じる可能性があります (デッドロックを防ぐことはできますが、どのコールバックを優先させるかははっきりしません)。
|
|
* !Set() が呼び出されるといつでもコールバックに戻ることができます。コードはあらゆるケース (初期化中、シリアル化中) で動作しなければなりません。
|
|
常にメインスレッド側にあると考えることができます。
|
|
|
|
上記の他の方法で解決できない場合以外は、この方法を使わないことをお勧めします。
|
|
|
|
例:
|
|
|
|
void OnChangeResQuality(IConsoleVariable* Var)
|
|
{
|
|
SetResQualityLevel(Var->GetInt());
|
|
}
|
|
|
|
CVarResQuality.AsVariable()
|
|
->SetOnChangedCallback(FConsoleVariableDelegate::CreateStatic(&OnChangeResQuality));
|
|
|
|
|
|
|
|
## 意図されたコンソール変数のビヘイビアとスタイル
|
|
|
|
* コンソール変数は、必ずしもシステムの状態ではなく、ユーザーによる入力を反映すべきです (例 :!MotionBlur 0/1 をサポートしていないプラットフォームがあることも考えられます)。
|
|
変数の状態は、コードによって変更されるべきではありません。そうでなければ、指定した状態を変数がもたないために、ミスタイプしたとユーザーが考えてしまうかもしれません。
|
|
あるいは、他の変数の状態のせいでコンソール変数をユーザーが変更することができなくなるかもしれません。
|
|
* 常に、変数が何のために使用され、どのような値を指定すると良いのかということについて説明する有用なヘルプを提供すべきです。
|
|
* 大半のコンソール変数は開発用にのみ向けられたものです。したがって、 ECVF_Cheat フラグを初期の段階で指定するのが良いでしょう。
|
|
さらに良いのは、define を使用して機能をコンパイルすることでしょう (例、#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST))。
|
|
* 変数名はできる限り最小にすべきです。同時に、説明的な名前や意味のないものは避けるべきです
|
|
(例 : 不適当な名前としては、次のようなものがあげられます。!EnableMotionBlur 、 !MotionBlurDisable 、 MBlur 、 !HideMotionBlur )。
|
|
大文字と小文字を使用することによって、可読性を高め一貫性をもたせます(例 : !MotionBlur)。
|
|
* インデント付けのために、一定の幅のフォント (非比例フォント) の出力を想定することができます。
|
|
* エンジンの初期化中に変数を登録することが重要です。これは、オートコンプリート、 !DumpConsoleCommands、 !Help が機能するようにするためです。
|
|
|
|
詳細については`IConsoleManager.h`を参照してください。
|
|
|
|
|
|
## コンソール変数のロード
|
|
|
|
エンジン起動時にコンソール変数の状態を "Engine/Config/ConsoleVariables.ini" ファイルからロードすることができます。この場所はローカル デベロッパー用にリザーブされています。プロジェクト設定には使わないでください。
|
|
詳細は、そのファイル自体の中に次のように書かれています。
|
|
|
|
このファイルによって、エンジン起動時にコンソール変数をセットすることができます。(順序は不定)。
|
|
; 現在のところ、このファイルをオーバーライドする他のファイルはありません。
|
|
; このファイルは、ソースコントロール データベースに置かれなければなりません (コメントのためと、場所を特定できるようにするために)。
|
|
; ただし、変数が入っていないようにしなければなりません。
|
|
; 開発者は、このファイルをローカルに変更することによって、変数設定を繰り返しタイプしなくても済むようにして
|
|
時間を節約することができます。変数は、[Startup] というセクションに置く必要があります。
|
|
; 後で、複数の命名されたセクションが、このセクション名によって参照される場合があります。
|
|
; これによって、プラットフォーム固有またはレベル固有のオーバーライドが可能になります。
|
|
; 名前の比較はケースセンシティブではありません。また、変数が存在しない場合は、そのまま無視されます。
|
|
;
|
|
; ファイルの中身の例 :
|
|
;
|
|
; [Startup]
|
|
; FogDensity = 0.9
|
|
; ImageGrain = 0.5
|
|
; FreezeAtPosition = 2819.5520 416.2633 75.1500 65378 -25879 0
|
|
|
|
[Startup]
|
|
|
|
例えば、"Engine/Config/BasEngine.ini" という設定を入れることもできます。
|
|
|
|
[SystemSettings]
|
|
r.MyCvar = 2
|
|
|
|
[SystemSettingsEditor]
|
|
r.MyCvar = 3
|
|
|
|
"Script/Engine.RendererSettings" という設定も可能です。こうしたプロジェクト設定は以下のようにエクスポーズされます。
|
|
|
|
UPROPERTY(config, EditAnywhere, Category=Optimizations, meta=(
|
|
ConsoleVariable="r.EarlyZPassMovable",DisplayName="Movables in early Z-pass",
|
|
ToolTip="Whether to render movable objects in the early Z pass.Need to reload the level!"))
|
|
uint32 bEarlyZPassMovable:1;
|
|
|
|
こうした設定はエディタ UI で変更できます。プロジェクト設定と拡張性の設定 (scalability settings) とを混在させないでください (優先度の問題を避けるため)。
|
|
|
|
他の設定は拡張性機能からのものである場合があります。詳しい情報は、 "Config/BaseScalability.ini" または拡張性のドキュメントをご覧ください。
|
|
|
|
## 優先度
|
|
|
|
コンソール変数は様々なソースからオーバーライドされます。例えば、user/editor/project の設定、コマンドライン、consolevariables.ini からオーバーライドされます。
|
|
設定 (例、プロジェクト設定をエディタの UI で変更可能にする) を再適用できるようにするために
|
|
優先度を導入しました。これですべての設定をどのような順序でも適用できるようになりました。
|
|
|
|
see IConsoleManager.h:
|
|
|
|
// 優先度最低 (コンソール変数作成後のデフォルト)
|
|
ECVF_SetByConstructor = 0x00000000,
|
|
// Scalability.ini から
|
|
ECVF_SetByScalability = 0x01000000,
|
|
// (ゲーム内 UI またはファイルから)
|
|
ECVF_SetByGameSetting = 0x02000000,
|
|
// プロジェクト設定
|
|
ECVF_SetByProjectSetting = 0x03000000,
|
|
// デバイス毎の設定
|
|
ECVF_SetByDeviceProfile = 0x04000000,
|
|
// プロジェクト毎の設定
|
|
ECVF_SetBySystemSettingsIni = 0x05000000,
|
|
// consolevariables.ini (複数オブジェクトに対して)
|
|
ECVF_SetByConsoleVariablesIni = 0x06000000,
|
|
// マイナス コマンド、例 -VSync
|
|
ECVF_SetByCommandline = 0x07000000,
|
|
// 最も役立ちません。ハックの可能性あり。正しい SetBy...を見つけた方がいいかもしれません。
|
|
ECVF_SetByCode = 0x08000000,
|
|
//エディタ UI、またはゲーム内、エディタ内のコンソール
|
|
ECVF_SetByConsole = 0x09000000,
|
|
|
|
以下のログ出力が表示される場合があります。
|
|
|
|
Console variable 'r.MyVar' wasn't set (Priority SetByDeviceProfile < SetByCommandline)
|
|
|
|
これは、意図したもの (例、コマンドラインがユーザー設定を強制) であるか、何らかのコード問題によって生じた可能性があります。
|
|
優先度は変数を最後に設定したのが誰であるかを見るのにも役立ちます。例えば、コンソール変数の状態を得る場合にこの情報を取得できます。
|
|
|
|
> r.GBuffer
|
|
r.GBuffer = "1" LastSetBy:Constructor
|
|
|
|
|
|
|
|
|
|
|
|
## 今後のこと
|
|
|
|
* 現在、コンソール変数は、C++ でしか作成できませんが、これは変更される可能性があります。
|
|
* 列挙型変数や bool 型変数を追加することを検討しましたが、これには問題が多々あります。現在は、int 型または必要に応じて文字列を使用するのが良いと考えています。
|
|
* ヘルプ用テキストは便利ですが、実行ファイルのサイズ抑制やチーター対策のために、定義を追加することによって、ヘルプ用テキストが実行ファイルに入らないようにすることを検討しています。
|
|
|
|
|
|
## コンソール変数の登録削除
|
|
|
|
`UnregisterConsoleVariable` メソッドによってコンソール変数を削除することができます。少なくとも、ユーザーの視点からはそのように見えます。
|
|
変数は依然として保持されています (登録削除のフラグをともなって)。これは、ポインタがデータにアクセスした場合にクラッシュしないようにするための措置です。新たな変数が同じ名前で登録されると、
|
|
古い変数がリストアされ、ヘルプとフラグが新変数からコピーされます。このようにして、変数の状態を失うことすらなしに、DLL (ダイナミック リンクライブラリ) のロードとアンロードが機能します。
|
|
なお、コンソール変数の参照については機能しません。これを修正するには、次のどれかに見切りをつけます。すなわち、ポインタの格納、登録削除、参照の使用から 1 つをあきらめます。
|
|
|
|
|
|
|
|
|