UDN
Search public documentation:

DebuggerInterfaceJP
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

UnrealScript デバッガ インターフェース

ドキュメント概要: このドキュメントは、UDK のための新しい外部デバッガを開発するのに必要な情報を提供。

ドキュメントの変更ログ: JoeWilcox により作成。

概観

典型的なデバッギング セッションとそこで何が行われるかを見てみましょう。UnrealScript をデバッグする前に、 (UDK make –debug のように、コマンドラインに "-debug" を追加することにより) スクリプトをデバッグ モードでコンパイルする必要があります。これは、コンパイルされたパッケージに付加的なコントロールやマッピング情報を追加します。 デバッグ情報とともにスクリプトをコンパイルしたら、2 つの方法のどちらかを使用して、エンジン内でデバッガをアクティブにすることができます。1 つは、最初の UnrealScript? バイトコードがプロセスされた瞬間に UE3 がスクリプト デバッガをアクティブにするような "-autodebug" コマンドライン スイッチを使用する方法です。もう 1 つは、"toggledebugger" コンソール コマンドを使用する方法です。これは、ゲーム コンソールから使用して、デバッガをアクティブにし、すぐに壊すことができます。

(どちらかの方法を使用して) デバッガをアクティブにすると、どうなるかを見てみましょう。

  1. まず、UE3 がインターフェース DLL を読み込みます。デフォルトで、ファイル "DebuggerInterface.dll" を読み込みますが、この設定は Debugger.ini ファイルでオーバーライドすることができます。この DLL は、デバッグ コマンドをエンジンに送り、結果を取得するためのルートとなります。
  2. 一度読み込まれると、UE3 は即座にエクスポートされた関数である SetCallback?() を呼び出します。これは、エンジンへの伝達ルートを作成します。その後、3 つ (ローカル、グローバル、ユーザー ウォッチ) の変数ウォッチ リストをクリアします。
  3. 最後に、エクスポートされた関数である ShowDllForm? を呼び出し、これがデバッガを表示、またはアクティブにします。

オリジナルの外部デバッガ インターフェースは、小さな Borland Delphi 形式 DLL でしたが、インターフェースは下位互換性のために同じままです。インターフェース DLL からエクスポートされる必要のある関数を見てみましょう。

インターフェース

デバッガ インターフェースが実装する必要のある関数は 19 個あります。それらは、以下の通りです。

void SetCallback(void* CallbackFunc)
 これは、DLL 内で管理するのにもっとも重要な関数です。初めてアクティブになると、エンジンはこの関数を通してコールバックをセットアップしようと試みます。パスインされた関数ポインタを格納し、後ほどエンジンと通信させるのに使用するべきです。どのようなコマンドを送ることができるかに関しては、後ほど解説していきます。

void ShowDllForm()
 これが呼び出されると、!ShowDLLForm() がデバッガのウィンドウをアクティブにして、表示させる必要があります。

void BuildHierarchy()
void ClearHierarchy()
これら 2 つの関数は、エンジンがデバッガに、現在読み込まれているクラス階層を送ろうとしていることを通知したい場合に呼び出されます。これらの間で、UE3 はいくつかの AddClassToHierarchy() 呼び出しを行い、呼び出されたすべてのクラスのツリーをパスインします。

void AddClassToHierarchy(const char* ClassName)
この関数は、クラスをデバッガのクラス階層に追加するために使用されます。オリジナル デバッガは、読み込まれたクラスのリストを階層ツリー ビューに維持していました。この情報は、以下のフォーマットを使用して文字列としてパスされます。 .. 例えば、以下があったとします。 "core..object" (オブジェクトにペアレントがないため) "engine.object.actor" "utgame.gameinfo.utgame" この情報でデバッガが何をするかは、外部アプリケーション次第です。

void ClearWatch(int WatchType)
void ClearAWatch(int WatchType)
UE3 は、ローカル、グローバル、ユーザー ウォッチの 3 つの異なるタイプのウォッチをサポートしています。この関数は、UE3 がこれらのリストのうちの 1 つをクリアしたい場合に呼び出されます。以下のウォッチ タイプをサポートしています。

  1. Local Watches (ローカル ウォッチ)
  2. Global Watches (グローバル ウォッチ)
  3. User Watches (ユーザー ウォッチ)
外部デバッガは、ウォッチ リストでデータを管理し、表示する役割を担っています。!ClearWatch() は、オリジナル Delphi デバッガ例から持ち越されています。エンジンは、いまだにこれを呼び出すので、実装する必要があります。呼び出しを単純に ClearWatch() から ClearAWatch() ハンドラへリダイレクトすることを推奨します。

int AddAWatch(int WatchType, int ParentIndex, const char* VarName, const char* VarValue)
エンジンは、デバッガのウォッチ リストをアップデートするために、この関数を使用します。1 つの変数は、たいていの場合、複数の AddAWatch() 呼び出しに結果します。例えば、ベクトル (3 つの子を持つ構造体) にウォッチを追加すると、4 つの AddAWatch() 呼び出しに結果します。これは、最初の呼び出しが変数であり、次の 3 つが X、Y、Z です。 この関数のパラメータは以下の通りです。

   • WatchType: ウォッチ タイプは、!ClearWatch() で使用される値のタイプと同じです。
   • ParentIndex: これは、現在のオブジェクト内のそのペアレントの固有のインデックスです。エンジンが、追加するためのメンバ変数を探してオブジェクトを循環すると同時に、各個が固有のインデックスを取得します。
   • VarName: これは、変数の名前です。
   • VarValue: これは、表示する値、または変数に関する追加で表示するデータです。

AddAWatch() で返される結果は、ウォッチ リストでこの特定の変数を説明する固有の ID である必要があります。

ベクトルの例をもう少し見てみましょう。以下のスクリプト コードを例にします。

function TestFunc()
{
    local vector TestVec;
    TestVec.X = 10;
    TestVec.Y=20;
    TestVec.Z=30;
    log(TestVec);
}

ログ ステートメントにブレイクポイントを設定すると、デバッガが壊れた際に UE3 が最初にすることは、!ClearWatch(0) を使用してローカル ウォッチをクリアすることです。その後、ウォッチを TestVec? に追加しようと試みます。これは、以下の AddAWatch() 呼び出しに結果します。

AddAWatch(0, 0, "!TestVec",""); // 1 を返すはずです。
AddAWatch(0,1,"X","10"); // 2 を返すはずです。
AddAWatch(0,1,"Y","20"); // 3 を返すはずです。
AddAWatch(0,1,"Z","20"); // 4 を返すはずです。

void LockList(int WatchList)
void UnlockList(int WatchList)
これら 2 つの関数は、UE3 が任意のウォッチ リストにアップデートを行おうとする際に呼び出されます。デバッガは、!UnlockList() 関数が呼び出されるまで、アップデートをできる限りスムーズにするのに必要なステップを取るはずです。

void AddBreakpoint(const char* ClassName, int LineNo)
void RemoveBreakpoint(const char* ClassName, int LineNo)
UE3 が表示にトラックしていることが分かるようなブレイクポイントを追加する必要がある場合、デバッガで登録するために AddBreakPoint? を呼び出します。!ClassName は、ブレイクポイントが存在するクラスの名前であり、!LineNo が行数です。外部デバッガは、これらのトラックと、関連付けられた行でのブレイクポイントの表示をする役割を担っています。 同様に RemoveBreakPoint() は、デバッガに既存のブレイクポイントを削除させます。

void EditorLoadClass(const char* ClassName)
UE3 は、この関数を使用して ClassName 変数によって指定されたクラスのスクリプトを読み込むように、デバッガに指示します。!ClassName は . としてパスされます。デバッガは、文字列を分割し、適切なファイルを読み込む役割をしています。

void EditorGotoLine(int LineNo, int bHighlight)
UE3 は、この関数を使用して、現在のソース ファイル内の特定の行を表示するように、デバッガに指示します。!EditorGotoLine() の前には、常に EditorLoadClass() 呼び出しが先行することに留意してください。

void AddLineToLog(const char* Text)
UE3 は、デバッガのログ ファイルに何かを出力する必要がある場合に、この関数を呼び出します。テキストが追加する文字列です。

void CallStackClear()
UE3 が壊れ、デバッガでコールスタックをアップデートする必要がある場合、まず最初にすることは CallStackClear() を実行することです。これは、UE3 がコールスタックをリビルドしたがっていることをデバッガに知らせます。

void CallStackAdd(const char* CallStackEntry)
壊れた後、デバッガ上でコールスタックをビルドするために、UE3 はいくつかの CallStackAdd() 呼び出しを行います。デバッガは入ってくるデータを取得し、どこかに表示するはずです。!CallStackEntry は、クラス名と行数を含む文字列です。

void SetCurrentObjectName(const char* ObjectName)
UE3 は、デバッガ内で現在のオブジェクト名を設定するために、この関数を使用します。各内部アップデート コール中に呼び出されます。この情報は好きなように処理して構いません。

void DebugWindowState(int StateCode)
この関数は、現在使用されていません。

コールバック

UE3 がどのようにデバッガと通信するかを見てきたので、今度は他の方向を見てみましょう。デバッガは、コールバック関数を介して UE3 と通信する必要があります。インターフェース DLL がエンジンにバウンドしている場合、エンジンはそのコールバックを登録します。このコールスタックを通して、いくつかのコマンドをパスさせることができます。すべてのコマンドは文字列としてパスされます。

コールバックの typedef は、以下の通りです。

typedef void (*CallbackPointer)(const char*);

以下がコマンドのリストです。

addbreakpoint

<classname>  <linenumber>

removebreakpoint
<classname>  <linenumber>

これらのコマンドは、UE3 にブレイクポイントを追加/削除するように指示するのに使用されます。 は、ブレイクポイントが存在する呼び出しの名前であり、 が行数です。

addwatch

<varname>

removewatch
<varname>

これらのコマンドは、UE3 にユーザーによって定義されたウォッチを追加/削除するように指示するのに使用されます。これは、完全に説明するべきです (例: pawn.playerreplicationinfo.playername)。

clearwatch
このコマンドは、パラメータを持たず、すべてのユーザー ウォッチをクリアします。

changestack

<stackid>

このコマンドは、コールスタック内の任意の位置にエンジンをジャンプさせます。

setdatawatch

<watchtext>

このコマンドは、任意の変数のデータ アクセス上でブレイクポイントを設定します。

breakonnone

<0=false|1=true>

breakonnone コマンドを使用して、「アクセスなし」のエラーが起きると常に、デバッガが壊れるように指示します。

break
UE3 に一刻も早く壊れるように指示します。

stopdebugging
このコマンドは、デバッガをシャットダウンし、デバッギング セッションを停止します。

go
stepinto
stepover
stepoutof
これらのコマンドは、デバッガの実行をコントロールします。

でも少し待ってください。"addwatch" コマンドを UE3 に送ると、!AddAWatch() インターフェース呼び出しを得るということでしょうか? その通りです。UE3 を物事が起きる場所であり、インターフェース DLL を起きていることをレンダリングするものであると考えてみてください。従って、"addwatch" コマンドを送ると、UE3 はまずオブジェクトへのパスが有効であることを確認し、その後そのオブジェクトでウォッチを内部でセットアップします。そして、すべてが終わったときに、任意のオブジェクトをウォッチしていることをインターフェースに伝えます。それぐらいシンプルなのです。

その他の有用な情報

このドキュメントを終える前に、デバッガを壊すと実際に何が起きるのか見てみましょう。これにより、外部アプリケーションで何を探せばよいかのヒントとなるはずです。 "break" コマンドをコールバックに送ると、UE3 が処理を開始します。これは、次のスクリプト バイト コードの実行時に壊すようにというフラグを設定します。これが起こると、いくつかのステップを実行します。
  1. UE3 はインターフェースに、どのクラスとどの行にそれがあるかを EditorLoadClass() と EditorGotoLine() への呼び出しを通じて通知します。
  2. その後、!ObjectName を SetCurrentObjectName とともに設定します。
  3. 次に、まず ClearAWatch() を呼び出し、そして AddAWatch() を複数回呼び出すことにより、すべてのウォッチを更新します。
  4. その後、!CallStackClear() を呼び出し、!CallStackAdd() への複数回の呼び出しをすることにより、コールスタックを更新します。

「壊れた」状態にある間は、ゲームがフリーズ (すべてのタイミングを含む) しますが、レンダリングはし続け、Windows のメッセージを承諾します。