UDN
Search public documentation:

MakingACommandletJP
English Translation
中国翻译
한국어

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

コマンドレットの作成方法

ドキュメントの概要: コマンドレット (コマンドライン プログラム) 作成ガイド。

ドキュメントの変更ログ: Joe Graf により作成および更新。

概要

コマンドレットとは、Unreal Engine の環境内で作動するコマンドライン プログラムです。コンテンツの大幅変更、コンテンツの反復による情報の取得、またはメカニズムのテストを行う際に最もよく利用されます。

基本的には、これらはエンジンにより初期化された小さなアプレットですが、そのほとんどは Windows のコンソール出力の範囲にとどめられています。例えば、=game.exe make= は UnrealScript? クラスをコンパイルする make commandlet を実行します。

エンジンは、コマンドラインで渡されたコマンドがコマンドレットかどうかを自動的に判断し、コマンドレットに一致する場合は関連コードを実行します。

UContentCommandlets?.cpp と UnPackageUtilities? にあるコマンドレットのサンプルを参照してください。

コマンドレットを作成する

コマンドレット用のスクリプトクラスを以下のようにして作成します。:

  class HelloWorldCommandlet extends Commandlet;
  
  event int Main( string Params )
  {
     log( " hello world " );
  
     return 0;
  }
  

また、ネイティブなコマンドレットは以下のようになります。:

  class HelloWorldCommandlet extends Commandlet
  native;
  
  cpptext
  {
  INT Main(const FString& CmdLine)
  {
     warnf(TEXT("hello world"));
     return 0;
  }
  }
  
  native event int Main( string Params );
  
Main() 関数はコマンドレットのエントリ ポイントです。コマンドレットは実行時に文字列をひとつ受け取りますが、ここにはパラメータがすべて含まれています。次の行をご覧下さい。

  gamename.exe helloworld param1 param2 param3
  

この場合、コマンドレットでは 「param1 param2 param3」 をコマンドラインのパラメータとみなします。

Native コードでコマンドレットを作成する方法

コマンドレットは、大半が Native コードの組み込み型クラスとして実装されていますが、この方法によるコマンドレットの作成手順は上記とまったく異なります。ほとんどのコマンドレット宣言は EditorCommandlets.h に保存されています。

最初に、ヘッダーファイルで EditorCommandlets.h のようにクラス宣言をします。:

  BEGIN_COMMANDLET(Name,Package)
   // ここで他のメソッドを宣言します。
  END_COMMANDLET
  
コマンドレットにはクラス名 "UNameCommandlet" が与えられ、指定パッケージ内 (Editor など) に格納されます。

次に、.cpp ファイルで (UContentCommandlets.cpp など)、作成するコマンドレットの Main() 関数を実装します。必要に応じて、=virtual CreateCustomEngine()= 関数をオーバーライドすることもできます。詳細については、UCommandlet ソースを参照してください。

  INT UNameCommandlet::Main(const FString& Params)
  {
      // do yer stuff here...
      return 0;
  }
  

これで完成、ではありません。これは組み込み型クラスなので、スクリプトシステムにその存在を伝えなければならず、そのために PackageClasses.h ファイルの AUTO_INITIALIZE_REGISTRANTS_EDITOR #define を手動で編集する必要があります。このリストに、作成したコマンドレットの StaticClass() 関数呼び出しを追加します。

  #define AUTO_INITIALIZE_REGISTRANTS_EDITOR \
     UNameCommandlet::StaticClass(); \
  

スクリプトを次回にリビルドするときに、コンパイラはリストに追加されたコマンドレット クラスを使用して、アルファベット順にこのファイルをオーバーライドしていきます。

便利なヘルプ情報

コマンドレットにはヘルプ情報機能が組み込まれているので、ユーザーはその機能やオプション内容を十分に把握することができます。コマンドレットに関するヘルプ情報を作成するには、そのコマンドレットが含まれているローカライズテキスト ファイルに、エントリを追加する必要があります。 パッケージが Core にある場合は、Core.int を修正するとヘルプ情報が表示されるようになります。以下に Core に属する 「hello world」 (ハローワールド)のコマンドレット設定例を示します。

  [HelloWorldCommandlet]
  HelpDescription="This commandlet displays hello world" HelpUsage="gamename.exe helloworld"
  HelpWebLink="https://udn.epicgames.com/bin/view/Three/MakingACommandlet"
  HelpParamNames[0]="param1"
  HelpParamDescriptions[0]="Ignored since helloworld doesn't need params"
  

セクション名にはクラス名の一部として 「commandlet」 が含まれていなければなりません。これがない場合、コマンドレットは検出されません。この情報の扱いについては、次のコマンドを実行していただくとお分かり頂けます。

  game.exe help help
  game.exe help list
  game.exe help webhelp help
  

コマンドレットの使用法

コマンドレットは、実行したいコマンドレット名をゲーム起動時にパラメータとして引き渡して実行します。 例えば、:

  examplegame make -full
  

UT 内のメイク コマンドレットが起動されます。ネイティブなコマンドレットについてはパッケージ名を指定する必要はありません。メイク コマンドレットがスクリプトのみのものなら、以下を使用して呼び出します。:

  examplegame editor.make -full
  

として実行されて、スタートアップ時には起動されません。また、名前の一部に 「commandlet」 を入れておく必要はありません。指定のコマンドレットを検出する際、スタートアップのコードによって、「commandlet」 が自動的に付加されます。

よく実行されるコマンドレット タスク

日常的なタスクには、パッケージ上を反復的に移動し、そのデータを処理するタスクがあります。以下のコードを利用してこれを書き始めることができます (同じコードは UContentCommandlets.cpp の冒頭にもコメントとして挿入されています)。

  // 以下のテンプレート コマンドレットは、すべてのパッケージに対して操作を実行する必要があるときに利用できます。
  
  INT UPerformAnOperationOnEveryPackage::Main(const FString& Params)
  {
     // コマンドライン引数を解析。
     TArray<FString> Tokens;
     TArray<FString> Switches;
  
     const TCHAR* Parms = *Params;
     ParseCommandLine(Parms, Tokens, Switches);
  
     // パッケージ ファイルのリストを作成。
     const TArray<FString> FilesInPath( GPackageFileCache->GetPackageFileList() );
     if( FilesInPath.Num() == 0 )
     {
        warnf( NAME_Warning, TEXT("No packages found") );
        return 1;
     }
  
     // すべてのファイルを反復処理。
     for( INT FileIndex = 0 ; FileIndex < FilesInPath.Num() ; ++FileIndex )
     {
        const FFilename& Filename = FilesInPath(FileIndex);
        warnf( NAME_Log, TEXT("Loading %s"), *Filename );
  
        UPackage* Package = UObject::LoadPackage( NULL, *Filename, LOAD_None );
        if( Package == NULL )
        {
           warnf( NAME_Error, TEXT("Error loading %s!"), *Filename );
        }
  
        /////////////////
        //
        //  ここに自分のコードを追加。
        //
        /////////////////
  
        TObjectIterator<UStaticMesh> It;...
  
        UStaticMesh* StaticMesh = *It;
        if( StaticMesh->IsIn( Package )
  
  
  
  
        UObject::CollectGarbage( RF_Native );
     }
  
     return 0;
  }
  

さらに、=PackageHelperFunctions.h= の NormalizePackageNames() を参照されることをお勧めします (これは QA_APPROVED_BUILD_JUNE_2007 (2007 年 6 月 QA 承認ビルド) で登場しました)。この関数は、反復処理するパッケージのフィルタリストを作成することができ、=GPackageFileCache= の単純な反復処理以上の微細な操作を実行できます (詳細はコードを参照)。

コマンドレット一覧

コマンドレット一覧 ページを参照してください。