-
Notifications
You must be signed in to change notification settings - Fork 6
Live Funcs ja JP
ゲームが実際に何を呼び出したかで UFunction を発見します。Start/Stop の記録中にディスパッチされた UFunction を数え上げ、ゲーム内で行動したときに本当に発火した関数を、原因となるエントリポイントが上位に来るようにランク付けします。
Live Funcs は、挙動ベースの UFunction 発見を行うタブです。UObject::ProcessEvent をフックし、Start/Stop の記録ウィンドウの間にゲームがディスパッチしたすべての UFunction をカウントします。
これは名前でスコアリングする Interesting Functions タブの、挙動でスコアリングする対になる存在です。関数を名前から推測する代わりに、ゲーム内で実際にアクション(ショップを開く、ダッシュ、攻撃など)を 実行 すると、このタブは本当に発火した UFunction を、原因となるエントリポイントが上位に浮かび上がるようにランク付けして表示します。名前からは推測できない、ゲーム固有の関数を見つけられます。
記録を開始すると、ゲームスレッド上の ProcessEvent フックが強制的にインストールされるため、事前の invoke は不要です。
- Set Baseline: まず Start を押し、数秒間何もせずに待機してから Stop し、Set Baseline をクリックします。これでアイドル状態の基準が取得され、Diff モードがオンになります。
- アクションを記録: Start を押し、ALT-TAB でゲームに切り替え、対象のアクションを 1 つだけ 実行し、ALT-TAB で戻ってから Stop します。
- 差分を読む: アクション中に のみ 発火した行には NEW タグ(緑)が付きます。New/changed only をオンにすると、フレームごとに発火する変化のない Tick ノイズが非表示になります。
- Hide UI widgets: メニューやショップを開くと、その widget が 生成 されるため、widget 自身のメソッドがすべて一斉に発火してリストを埋め尽くします(Kind 列に "UI" タグが付きます)。Hide UI widgets で隠すと、それを開いた側の恒久的な関数(PlayerController / UI マネージャの subsystem / interaction コンポーネント上のもの)が残ります。
- Hide events/delegates: On* / コールバック関数(Type 列で Event / Deleg タグが付くもの)は、エンジンがゲームに 向けて 発火させる反応であり、アクションを起こすために自分から呼ぶ関数ではありません。Hide events/delegates で隠すと、命令的な "Call" 関数が残ります。
- Earliest first: アクションのエントリポイントは、それが引き起こす反応 よりも先に 発火します。そのため呼び出し順(Order 列の昇順)で並べ替えると、真の起点が最上部に浮かび上がります。これが名前に依存しない、因果関係にもとづくシグナルです。
- 実行: 行の Live をクリックすると、その関数がライブインスタンス上の Live Walker で開かれ(インスタンスが無ければ Class Struct にフォールバック)、そこで invoke できます。Name は関数名をコピーします。
なお、リストは Refresh で更新、Clear で消去できます。
上記のワークフローは、単発のアクションの背後にある関数を見つけます。その逆は、繰り返すタイマーで発火する関数 — クールダウン、リスポーン、継続ダメージ(DoT)の tick、あるいは周期的な AI 判断を駆動するコールバック — を見つけます。
- 調べたい状態に入ります(例:継続ダメージ地帯に立つ、あるいは値がタイマーで回復する場所にいる)。
- Start を押し、15〜20 秒ほど何もせずに待機します — 対象の最も遅いタイマーが少なくとも 4 回ほど発火するのに十分な長さです。
- Stop を押し、Periodic only をオンにします。
残るのは、フレームごとの Tick 帯域の外で規則的な周期で発火している関数です — Kind 列に Timer タグが付き、Period 列に測定された間隔が表示されます。このタブは各関数の到着間隔の規則性を測定するため、フレームごとの Tick(および不規則で入力駆動の関数)は除外されます。実例として、ある UE4 ゲームでのアイドル記録では、約 90 個の関数の中から Blueprint の TryAttackEnable が安定した 約 325 ms(実際に約 3 Hz のタイマー)としてフラグ付けされました。
限界: 見えるのは UFUNCTION にバインドされたタイマーだけです(Blueprint の Set Timer by Event / Function Name、または動的デリゲートのタイマー)。ネイティブ C++ の SetTimer(this, &UClass::Method) はコールバックを直接呼び出して ProcessEvent をバイパスするため、ここには決して現れません — このタブの他の部分と同じ原理的な限界です。
- Order: 最初に発火した時点の、呼び出しストリーム上の位置。小さいほど早い=エントリポイントである可能性が高い。
- Calls: 発火回数。
- Δ vs base: ベースラインに対する差分。新規なら NEW、ベースラインより多く発火したときは +N。
- Type: FunctionFlags から判定した Event / Deleg / Call / native。
- Kind: 周期的なタイマー周期のコールバックには "Timer"、一時的な widget のメソッドには "UI" が付く。
- Class: 関数を保有するクラス。
- Function: 関数名。
- Params: パラメータ。
-
Period: 周期的な関数について、測定された発火間隔(例:
325 ms、1 s);それ以外は空欄。
ここは正直に理解しておく必要があります。ProcessEvent フックが観測できるのは、リフレクション経由 / Blueprint 経由でディスパッチされた呼び出しだけです。ネイティブ C++ からネイティブ C++ への直接呼び出しは、このフックからは 見えません。
Hide events/delegates をオンにするとリストが空になる場合、そのアクションの本当のエントリポイントはネイティブです(あるいはパネルがまだ完全に表示されきっていなかった可能性もあります — パネルが画面に出るまで記録を続けてください)。これは挙動ベース発見の原理的な限界であり、バグではありません。
多くの UE ゲーム(Blueprint 駆動のゲームプレイ)では、アクションに対応する関数は直接見つかります。実例として、あるゲームはショップをネイティブ C++ 呼び出しで開いていたため、見えたのはその Blueprint イベントコールバック(On*)だけでした。別のゲームではショップがストリーミングされるメニューレベルになっており、きれいにサーフェスされました。
Start で「PE フックをインストールできなかった」と表示され、ゲームは動いているのにカウントが 0 のままになることがあります。これは、MinHook がこのプロセス内で ProcessEvent の近くにトランポリンを配置できなかった状態です。
別のマップ / シーンに移動してから再度 Start してください。レベルのリロードでメモリの配置が入れ替わり、ほぼ確実に必要な領域が空きます。それでも解消しない場合は、ゲームを再起動して再インジェクトしてください。これはゲームがサポート対象かどうかとは無関係で、同じゲームでも新しく / 別の読み込まれ方をしたプロセスなら問題なくフックできます。Start をもう一度クリックすること自体もインストールの再試行になります。
- 記録はオプトインで、アイドル時のコストはほぼゼロです。
- タブを離れると、記録中のセッションは自動的に停止します。
- Pipe 専用機能です(CE Lua / .CT はありません)。
- キーワードフィルタボックス(スペース = 関数名とクラス名にまたがる AND)でリストを絞り込めます。
- Interesting Functions & Properties — 名前ベースの対になるタブ
- Live Walker — 見つけた関数をライブインスタンス上で invoke するため
- Console — UFUNCTION(exec) コマンドの発見