Unreal プラグイン言語 (UPL) は XML を処理して文字列を返すシンプルな XML ベースの言語です。他のセクションの前にアーキテクチャごとに 1 回評価されるセクションを含みます。State (状態) は維持されて次に評価するセクションに引き継がれるため、セクションの実行順序が重要です。UPL は XML を変更およびクエリする一般的なシステムですが、プラグインが組み込まれたパッケージのグローバル構成に影響を与えるために特に使用されます。たとえば、この仕組みによりプラグインは Android APK AndroidManfiest.xml ファイルや IOS IPA plist ファイルを変更できます。UBT は、Android におけるいくつかの .java ファイルのようにパッケージに共通で存在しなければならないファイルに含まれる文字列を、プラグインの UPL xml ファイルにクエリします。
トレーシングの有効化
プラグイン コンテキストで実行される命令を確認する必要がある場合は、次を追加してトレースを有効化します。
<trace enable="true"/>
この命令の後、コンテキストで実際に実行されたすべてのノードは
<dumpvars/>
変数型
Bool、Int、String 変数型がサポートされています。すべての属性は変数を参照でき、この構文を使用して評価する前に同等の文字列に置き換えられます。
$B(name) = ブール変数「name」の値
$I(name) = 整数変数「name」の値
$S(name) = 文字列変数「name」の値
$E(name) = 要素変数「name」の値
次の変数は自動的に初期化されます。
$S(Output) = セクションを評価するために返される出力 (入力に初期化)
$S(Architecture) = 対象のアーキテクチャ (armeabi-armv7a、arm64-v8a、 x86、x86_64)
$S(PluginDir) = XML ファイルを読み込むディレクトリ
$S(EngineDir) = engine ディレクトリ
$S(BuildDir) = プロジェクトのプラットフォームに適したビルド ディレクトリ (中間フォルダー内)
$S(Configuration) = 構成タイプ (デバッグ、DebugGame、開発、テスト、シッピング)
$B(Distribution) = 配布ビルドの場合は true
上記を除くすべての変数は、名前空間の衝突を防ぐためにプラグインのコンテキストにあります。出力を除く上記のいずれかに新しい値を設定しても現在のコンテキストにのみ影響します。
変数の操作
次のノードでは変数を操作できます。
<setBool result="" value=""/>
<setInt result="" value=""/>
<setString result="" value=""/>
<setElement result="" value=""/>
<setElement result="" value="" text=""/>
<setElement result="" xml=""/>
値を持つ <setElement> は値に設定されたタグの空の XML 要素を作成します。
値とテキストを持つ <setElement> は、未解析テキストの値に設定されたタグの XML 要素を作成します。
XML を持つ <setElement> は与えられた XML を解析します。特殊文字は必ずエスケープする必要があります!
変数は ini ファイルのプロパティから設定することもできます。
<setBoolFromProperty result="" ini="" section="" property="" default=""/>
<setBoolFromPropertyContains result="" ini="" section="" property="" default="" contains=""/>
<setIntFromProperty result="" ini="" section="" property="" default=""/>
<setStringFromProperty result="" ini="" section="" property="" default=""/>
文字列は
<setStringFromEnvVar result="" value=""/>
特定の環境変数が定義されているかも確認できます (同様に「%」文字で挟む)。
<setBoolEnvVarDefined result="" value=""/>
環境変数ノードを使用する一般的な例。
<setBoolEnvVarDefined result="bHasNDK" value="%NDKROOT%"/>
<setStringFromEnvVar result="NDKPath" value="%NDKROOT%"/>
ブール変数は演算子を適用した結果にも設定できます。
<setBoolNot result="" source=""/>
<setBoolAnd result="" arg1="" arg2=""/>
<setBoolOr result="" arg1="" arg2=""/>
<setBoolIsEqual result="" arg1="" arg2=""/>
<setBoolIsLess result="" arg1="" arg2=""/>
<setBoolIsLessEqual result="" arg1="" arg2=""/>
<setBoolIsGreater result="" arg1="" arg2=""/>
<setBoolIsGreaterEqual result="" arg1="" arg2=""/>
<setBoolFromPropertyContains result="" ini="" section="" property="" contains=""/>
整数変数はこれらの算術演算を使用できます。
<setIntAdd result="" arg1="" arg2=""/>
<setIntSubtract result="" arg1="" arg2=""/>
<setIntMultiply result="" arg1="" arg2=""/>
<setIntDivide result="" arg1="" arg2=""/>
文字列は次のように操作します。
<setStringAdd result="" arg1="" arg2=""/>
<setStringSubstring result="" source="" start="" length=""/>
<setStringReplace result="" source="" find="" with=""/>
文字列の長さは次の方法で取得できます。
<setIntLength result="" source=""/>
検索文字列のインデックスは次のソースで見つけることができます。
<setIntFindString result="" source="" find=""/>
<setBoolStartsWith result="" source="" find=""/>
<setBoolEndsWith result="" source="" find=""/>
<setBoolContains result="" source="" find=""/>
メッセージの書き込み
このノードでメッセージがログに書き込まれます。
<log text=""/>
条件付き実行
条件付き実行は次の形式を使用します。
<if condition="">
<true>
<-- Executes if boolean variable if the condition is true -->
</true>
<false>
<-- executes if boolean variable in condition is false -->
</false>
</if>
<setBoolNot result="notDistribution" source="$B(Distribution)/>
<setBoolIsEqual result="isX86" arg1="$S(Architecture)" arg2="x86"/>
<setBoolIsEqual result="isX86_64" arg2="$S(Architecture)" arg2="x86_64/">
<setBoolOr result="isIntel" arg1="$B(isX86)" arg2="$B(isX86_64)"/>
<setBoolAnd result="intelAndNotDistribution" arg1="$B(isIntel)" arg2="$B(notDistribution)"/>
<if condition="intelAndNotDistribution">
<true>
<-- do something for Intel if not a distribution build -->
</true>
</if>
「isIntel」も次のように実行できます。
<setStringSubstring result="subarch" source="$S(Architecture)" start="0" length="3"/>
<setBoolEquals result="isIntel" arg1="$S(subarch)" arg2="x86"/>
条件付き実行は 2 つのショートカット ノードを使用できます。 このコードは、
<isArch arch="armeabi-armv7">
<-- do stuff -->
</isArch>
以下と同等になります。
<setBoolEquals result="temp" arg1="$S(Architecture)" arg2="armeabi-armv7">
<if condition="temp">
<true>
<-- do stuff -->
</true>
</if>
このコードは、
<isDistribution> など
<-- do stuff -->
</isDistribution>
以下と同等になります。
<if condition="Distribution">
<-- do stuff -->
</if>
次の方法で実行を停止できます。
<return/>
ループ
これらのノードを使用してループを作成できます。
<while condition="">
<-- do stuff -->
</while>
<break/>
<continue/>
<while>
本文の外側の <break/>
は <return></return>
と同じように機能します。
3 をスキップして 1 ~ 5 をログに書き込むループの例を示します。while 条件の更新は continue の前に実行する必要があり、そうでない場合はループを抜けない可能性があります。
<setInt result="index" value="0"/>
<setBool result="loopRun" value="true"/>
<while condition="loopRun">
<setIntAdd result="index" arg1="$I(index)" arg2="1"/>
<setBoolIsLess result="loopRun" arg1="$I(index)" arg2="5"/>
<setBoolIsEqual result="indexIs3" arg1="$I(index)" arg2="3"/>
<if condition="indexIs3">
<true>
<continue/>
</true>
</if>
<log text="$I(index)"/>
</while>
Result Variable Name (結果変数名) の生成にも変数置換を使用できます。これによりループ内で配列を作成できます。
<setString result="array_$I(index)" value="element $I(index) in array"/>
次のコードを使用して取得できます (値が変数名として扱われます)。
<setStringFrom result="out" value="array_$I(index)"/>
Result Variable Name (結果変数名) の生成にも変数置換を使用できます。これによりループ内で配列を作成できます。
<setString result="array_$I(index)" value="element $I(index) in array"/>
次をコードを使用して取得できます (値が変数名として扱われます)。
<setStringFrom result="out" value="array_$I(index)"/>
ブール型と整数型には
テキストの挿入
セクションにテキストを挿入するノードは以下のようになります。
<insert> 本文 </insert>
<insertNewline/>
<insertValue value=""/>
<loadLibrary name="" failmsg=""/>
最初のものは、返されたセクション文字列にテキストやノードを挿入します。以下に対してエスケープ文字を使用する必要があることにご注意ください。
< = <
> = >
& = &
<insertValue value=""> /pre>
- 挿入前に変数の値を評価します。値がダブル クオート (") を含む場合、クオートでエスケープする必要があります。
<loadLibrary name="" failmsg="">
- ケースの読み込み失敗を示すオプションのログ メッセージとともに、system.LoadLibrary try/catch ブロックを挿入するショートカットです。
検索と置換
検索を実行して、その出力を次のように置換できます。
<replace find="" with=""/>
実際の $S(Output) を直接操作することもできますが、上記の方がより効率的です。
<setStringAdd result="Input" arg1="$S(Output)" arg2="sample\n"/>
<setStringReplace result="Input" source="$S(Output)" find=".LAUNCH" with=".INFO"/>
XML の操作
次のノードを使用して XML を操作します。
<addElement tag="" name=""/>
<addElements tag=""> 本文 </addElements>
<removeElement tag=""/>
<setStringFromTag result="" tag=""/>
<setStringFromAttribute result="" tag="" name=""/>
<setStringFromTagText result="" tag=""/>
<addAttribute tag="" name="" value=""/>
<removeAttribute tag="" name=""/>
<loopElements tag=""> 命令 </loopElements>
現在の要素は tag = "$" で参照します。$E(varname) を使用すると XML で相当する文字列に展開されるため、要素変数を $varname で参照します。デフォルトで addElement、addElements、removeElement は一致するすべてのタグに適用されます。オプションで once = "true" 属性を追加すると最初に一致したタグにのみに適用できます。
<addPermission android:name="" .. />
<addFeature android:name="" .. />
<addLibrary android:name="" .. />
上記のコマンドの属性がマニフェストに追加された要素にコピーされるので、次の例に示すことが可能です。
<addFeature android:name="android.hardware.usb.host" android:required="true"/>
ファイルのコピー
最後に、これらのノードで jar などのファイルをステージングするのに役立つファイルのコピーが可能になります。
<copyFile src="" dst="" force=""/>
<copyDir src="" dst="" force=""/>
Force (強制) が False の場合、長さやタイムスタンプが一致しない場合にのみファイルが置換されます。これは True がデフォルトです。
src と dst パスのベースとして以下を使用する必要があります。
$S(PluginDir) = XML ファイルを読み込むディレクトリ
$S(EngineDir) = Engine ディレクトリ
$S(BuildDir) = プロジェクトのプラットフォームに適したビルド ディレクトリ
APK ディレクトリの外部に書き込むことも可能ですが、これは非推奨です。
ファイルの削除
どうしてもファイル (配布ビルドの開発専用ファイルなど) を削除する必要がある場合、このノードを使用できます。
<deleteFiles filespec=""/>
削除するのは BuildDir のファイルだけに限られます。Oculus 署名ファイル (osig) をアセット ディレクトリから削除する使用例を次に示します。
<deleteFiles filespec="assets/oculussig_*"/>
パッケージ化やデプロイ
以下のセクションはパッケージ化やデプロイの段階で評価されます:
すべてのプラットフォームが対象
<-- init section is always evaluated once per architecture -->
<init> </init>
Android に固有のセクション
<-- optional updates applied to AndroidManifest.xml -->
<androidManifestUpdates> </androidManifestUpdates>
<-- optional additions to proguard -->
<proguardAdditions> </proguardAdditions>
<-- optional AAR imports additions -->
<AARImports> </AARImports>
<-- optional base build.gradle additions -->
<baseBuildGradleAdditions> </baseBuildGradleAdditions>
<-- optional base build.gradle buildscript additions -->
<buildscriptGradleAdditions> </buildscriptGradleAdditions>
<-- optional app build.gradle additions -->
<buildGradleAdditions> </buildGradleAdditions>
<-- optional additions to generated build.xml before ${sdk.dir}/tools/ant/build.xml import -->
<buildXmlPropertyAdditions> </buildXmlPropertyAdditions>
<-- optional files or directories to copy or delete from Intermediate/Android/APK before ndk-build -->
<prebuildCopies> </prebuildCopies>
<-- optional files or directories to copy or delete from Intermediate/Android/APK after ndk-build -->
<resourceCopies> </resourceCopies>
<-- optional files or directories to copy or delete from Intermediate/Android/APK before Gradle -->
<gradleCopies> </gradleCopies>
<-- optional properties to add to gradle.properties -->
<gradleProperties> </gradleProperties>
<-- optional parameters to add to Gradle commandline (prefix with a space or will run into previous parameter(s)) -->
<gradleParameters> </gradleParameters>
<-- optional minimum SDK API level required -->
<minimumSDKAPI> </minimumSDKAPI>
<-- optional additions to the GameActivity imports in GameActivity.java -->
<gameActivityImportAdditions> </gameActivityImportAdditions>
<-- optional additions to the GameActivity after imports in GameActivity.java -->
<gameActivityPostImportAdditions> </gameActivityPostImportAdditions>
<-- optional additions to the GameActivity class implements in GameActivity.java (end each line with a comma) -->
<gameActivityImplementsAdditions> </gameActivityImplementsAdditions>
<-- optional additions to the GameActivity class body in GameActivity.java -->
<gameActivityClassAdditions> </gameActivityOnClassAdditions>
<-- optional additions to GameActivity onCreate metadata reading in GameActivity.java -->
<gameActivityReadMetadata> </gameActivityReadMetadata>
<-- optional additions to GameActivity onCreate in GameActivity.java -->
<gameActivityOnCreateAdditions> </gameActivityOnCreateAdditions>
<-- optional additions to GameActivity onDestroy in GameActivity.java -->
<gameActivityOnDestroyAdditions> </gameActivityOnDestroyAdditions>
<-- optional additions to GameActivity onStart in GameActivity.java -->
<gameActivityOnStartAdditions> </gameActivityOnStartAdditions>
<-- optional additions to GameActivity onStop in GameActivity.java -->
<gameActivityOnStopAdditions> </gameActivityOnStopAdditions>
<-- optional additions to GameActivity onPause in GameActivity.java -->
<gameActivityOnPauseAdditions> </gameActivityOnPauseAdditions>
<-- optional additions to GameActivity onResume in GameActivity.java -->
<gameActivityOnResumeAdditions> </gameActivityOnResumeAdditions>
<-- optional additions to GameActivity onNewIntent in GameActivity.java -->
<gameActivityOnNewIntentAdditions> </gameActivityOnNewIntentAdditions>
<-- optional additions to GameActivity onActivityResult in GameActivity.java -->
<gameActivityOnActivityResultAdditions> </gameActivityOnActivityResultAdditions>
<-- optional libraries to load in GameActivity.java before libUE4.so -->
<soLoadLibrary> </soLoadLibrary>
サポートされるノード
サポートされるノードの完全なリストを示します。
<isArch arch="">
<isDistribution>
<if> => <true> / <false>
<while condition="">
<return/>
<break/>
<continue/>
<log text=""/>
<insert> </insert>
<insertValue value=""/>
<replace find="" with""/>
<copyFile src="" dst=""/>
<copyDir src="" dst=""/>
<loadLibrary name="" failmsg=""/>
<setBool result="" value=""/>
<setBoolEnvVarDefined result="" value=""/>
<setBoolFrom result="" value=""/>
<setBoolFromProperty result="" ini="" section="" property="" default=""/>
<setBoolFromPropertyContains result="" ini="" section="" property="" contains=""/>
<setBoolNot result="" source=""/>
<setBoolAnd result="" arg1="" arg2=""/>
<setBoolOr result="" arg1="" arg2=""/>
<setBoolIsEqual result="" arg1="" arg2=""/>
<setBoolIsLess result="" arg1="" arg2=""/>
<setBoolIsLessEqual result="" arg1="" arg2=""/>
<setBoolIsGreater result="" arg1="" arg2=""/>
<setBoolIsGreaterEqual result="" arg1="" arg2=""/>
<setInt result="" value=""/>
<setIntFrom result="" value=""/>
<setIntFromProperty result="" ini="" section="" property="" default=""/>
<setIntAdd result="" arg1="" arg2=""/>
<setIntSubtract result="" arg1="" arg2=""/>
<setIntMultiply result="" arg1="" arg2=""/>
<setIntDivide result="" arg1="" arg2=""/>
<setIntLength result="" source=""/>
<setIntFindString result="" source="" find=""/>
<setString result="" value=""/>
<setStringFrom result="" value=""/>
<setStringFromEnvVar result="" value=""/>
<setStringFromProperty result="" ini="" section="" property="" default=""/>
<setStringAdd result="" arg1="" arg2=""/>
<setStringSubstring result="" source="" index="" length=""/>
<setStringReplace result="" source="" find="" with=""/>