はじめに
先日の State of Unreal 2026(2026/6/17)で Unreal Engine 6 が発表されました。
詳細は公式のまとめ記事に譲りますが、UE6 の方向性はざっくり 3 本柱です。
- ゲームプレイのプログラミングモデルを Verse へ移行する(Epic は「C++ をトランザクション化する」と表現)
- コード・コンテンツ・経済圏を ゲーム/エンジンをまたいで可搬・相互運用可能にする
- AI 連携(MCP など)をエンジン標準に取り込む
そして界隈をざわつかせたのが、Actor と Blueprint がいずれ「非推奨化」されるという点です。
Epic のロードマップでは、Actor / BP は UE6 の Early Access〜初期リリースには残るものの、新フレームワークが成熟した段階で非推奨化され、Verse への移行ツールが用意される、とされています(UE6 Early Access は 2027 年末目標、正式版はその 12〜18 か月後の見込み)。
発表後の数日を見ていると、国内外を問わず BP / Actor 廃止への反発はかなり強めです。
Change.org の署名まで立ち上がっていて、論点はおおむね「非プログラマのアクセシビリティが失われる」「10 年分のチュートリアル・Marketplace 資産が無効化される」あたりに集約されています。Clair Obscur: Expedition 33 が小規模チームの BP 主体で作られた、という話も引き合いに出されていました。
コミュニティの空気としては「BP はこれ以上機能追加しなくていいから、オプショナルなプラグインとして残してほしい」という声が強い印象です。
この記事の調査環境について:
本記事の後半は、発表と同時に公開されたue6-mainリポジトリ(HEAD91c1df5、2026-06-20 時点)のソースを直接読んで調べたものです。
UE6 はまだ研究/開発ブランチで、ここで挙げるモジュール・API は すべて不安定(変わる前提) です。Experimental以前の段階だと思って読んでください。
確証が取れなかった点は「未確認」として明示しています。
記事が長くなったので、要点だけ知りたい方は直下の「できること / できないこと」と末尾の「おわりに」だけでも。
結論先出し:Verse グラフビューワは「どこまで」作れるか
先に結論です。Verse をソース・オブ・トゥルースとした読み取り専用の BP 風グラフビューワは、現状のソースを見る限り技術的には作れそうです。
さらに、ランタイム側も想定よりかなり踏み込めることが分かりました。ステップ実行・スタック取得・ローカル変数検査の土台は、実は VerseVM 側に実装済みで存在します。ただし「標準 DAP(VS Code など)からは使えず、Verse VM 独自のソケットプロトコルを話す必要がある」「プラグインがトレースを購読する公開 API は未確認」という癖があり、配布面(installed build に一部バイナリが乗るか)も依然として不確実です。
静的(コンパイル時情報)でできること
| やりたいこと | 可否 | 根拠(ue6-main 内) |
|---|---|---|
| Verse ソースを構文解析して構文木を得る | ✅ |
CParserPass::ProcessSnippet → Verse::Vst::Node(VST) |
| グラフノード ⇄ ソース位置のマッピング | ✅ | 全 VST ノードが _Whence(STextRange/行・列)を保持 |
| 関数シグネチャ・型・モジュールパスの取得 | ✅ |
CSemanticProgram / CFunction / SSignature 系 |
| コンパイル診断をノードに重ねる | ✅ |
CDiagnostics の SGlitchLocus._VstIdentifier で VST ノードへ逆引き |
| 効果バッジの自動導出(後述) | ✅ |
SEffectSet(8 効果)+ CFunctionType::GetEffects()
|
| 式単位の failable 判定 | ✅ | CExprInvocation::CanFail() |
実行時(ランタイム)でできること / できないこと
| やりたいこと | 可否 | 補足 |
|---|---|---|
| 実行中の Verse コード位置のハイライト | ✅ |
BytecodeSample イベントが Line(1-based)を直接保持。PC→行のテーブル引きすら不要(VerseTraceAnalysis) |
| 現在のスタックフレーム取得 | ✅ |
VVMDebugger の FFrame / ForEachStackFrame()、ソケットデバッガの stackTrace
|
| スコープ・変数の検査 | ✅ |
FFrame.Registers は VM が実際に populate(SELF/SCOPE/引数)。scopes/variables で取得可 |
| ローカル変数の値表示 | ✅ |
VVMValuePrinting::ToString(VValue, ...) が COREUOBJECT_API で公開 |
| ステップ実行(step in/out/over) | △ |
標準 DAP では不可だが、VerseVMSocketDebugger の独自 JSON-over-socket(next/stepIn/stepOut)経由なら可 |
| ソース位置の列情報 | ❌ | ランタイム側 FLocation は 行のみ(列なし) |
| 任意式の評価(evaluate) | ❌ | DAP / ソケット双方に evaluate 系が見当たらず |
| プラグインからのトレース購読 | ❓ | 公開 reader(IVerseProvider 相当)が未発見。Insights-private 経路の間接利用は要追加調査 |
ここは正直あまり期待していなかったのですが、ソースを読むと意外と揃っていました。
ステップ実行・スタック・変数検査の実体は VerseVM 側に実装済みで、FFrame.Registers も宣言だけのスタブではなく実際に値が入ります。
ただし注意が要ります。これらは uLangDAP の標準 DAP インターフェースには載っていない(step 系メソッドが宣言すらされていない)ため、VS Code のような汎用 DAP クライアントからは触れません。VerseVMSocketDebugger が話す Verse 専用の JSON-over-socket プロトコルを、こちら側で実装して喋る必要があります。
また、トレースのイベント自体は良質(行が直接取れる)ですが、プラグインがランタイムで購読する公式 reader 経路は確認できませんでした。ここは「Insights 経由か、TraceServices/Public の汎用 reader を間接利用できるか」を別途詰める必要があります。
まとめると、MVP の中心は依然「静的可視化 + 診断オーバーレイ」ですが、ランタイムの実行ハイライト・変数検査も“専用クライアントを書く前提なら”射程に入る、という温度感です。
本題の前に:この転換を、いちプラグイン開発者としてどう受け止めているか
技術記事に主観を挟むのは野暮かもしれませんが、今回はモチベーションの話が本題に直結するので少しだけ。
私はこれまで「UE のエディタをもっと使いやすく・便利に」を理念に、公式が手当てしていない部分をプラグインとして作って出してきました。なので今回の発表は、正直けっこう複雑な気持ちで見ていました。
ただ、プログラマ視点で見ると、この大転換を素直に批判するのは難しいとも思っています。
- BP と Actor をフルサポートし続ける限り、それぞれに良さはありつつも技術的負債は切れず、Verse / Scene Graph に振り切れない
- Epic が言う「C++ のトランザクション化」── つまり巻き戻し可能なゲームプレイ実行モデルは、大規模・永続・多人数のライブ運営を本気で狙うなら、後付けではなく言語レベルで効果(effect)を扱える Verse の方が筋が良い
このあたりの正当性は理解できます。一方で、BP が非プログラマから積み上げてきた信頼を一度ゼロに戻す判断でもあり、コミュニティの反発もまた当然だと感じます。
公式の動きを振り返ると、UE6 に向けた BP / Actor 廃止の構想自体は、かなり前から内部で固まっていたように見える節もあります(このあたりは憶測なので踏み込みません)。
そして現時点での X 上の(未確定の)情報を総合すると、Epic は BP 相当の「ノードを正データとするグラフプログラミング」を公式には提供しない方向のようです。実際、Epic のエンジニアも「BP のようなコーディング手段を復活させる予定はない」と述べたと報じられています。代わりに提供されるのは、Scratch のようなブロック方式のビジュアルプログラミングらしい、と。
ここで ue6-main を見ると腑に落ちる点があります。後述しますが、ソースには Visual Verse(VersaTiles) というタイル/ブロック状の Verse 編集 UI が存在します。発表で言及された“ブロック方式”は、おそらくこれを指していると考えるのが自然です。
ということは、BP のようにグラフを置いていく操作感は、公式からは出てこない可能性が高い。
ならば作ろうか、というのが今回の動機です。
ただし作りたいのは BP の復活ではありません。BP は「グラフデータが正データ」でしたが、そこに戻すつもりはなく、
Verse コード(あるいはそのコンパイラ中間データ)を正データとし、そこから BP 風のグラフを“描画”して読む/たどる
ためのツールを考えています。グラフは表示・ナビゲーション用のビューであって、保存の正本は常に Verse。これなら言語の進化にも追従しやすく、BP の技術的負債論とも衝突しません。
その実現可能性を確かめるために、ue6-main を調べました。ここからが本題です。
調査:ue6-main の Verse まわりはどうなっているか
Verse 関連モジュールの全体像
まず大局観です。Verse のコンパイラ/ランタイム/ツールチェーンは、おおむね次のように分かれています。
Engine/Source/Runtime/
├─ VerseCompiler/ … パーサ・VST・意味解析・診断・効果(VERSECOMPILER_API で公開)
├─ Solaris/
│ ├─ uLangCore / uLangJSON … 基盤(テキスト/レンジ/コンテナ等)
│ ├─ uLangLSP / uLangDAP … IDE 連携(LSP 3.17 / DAP)
│ ├─ uLangDigests / uLangIdeSupport … ダイジェスト・補完
│ ├─ VerseAssist … 解析支援
│ └─ ProtoLem … Visual Verse(VersaTiles)の Slate UI
└─ CoreUObject/Public/VerseVM/ … VerseVM ランタイム・デバッガ・バイトコード
Engine/Source/Developer/
├─ TraceServices(.../VerseTraceAnalysis) … "Verse" トレースプロバイダ(Private)
└─ TraceInsights(.../VerseTimingTrack) … Insights 上の Verse トラック(Private)
Engine/Plugins/
├─ Solaris/ … Verse コンパイラ/IDE 統合の中核
├─ VerseVM/(VerseVMSocketDebugger) … VM のソケットデバッガ
└─ EntityFramework/ … Scene Graph(/Verse.org/SceneGraph)
ここで重要なのが、コンパイラ中核の VerseCompiler は Public/uLang/ 配下にヘッダを持ち、VERSECOMPILER_API でエクスポートされていること。つまり理屈の上では、Build.cs の依存に VerseCompiler を足せば、C++ プラグインから include して使えます。
// プラグインの *.Build.cs(理論上)
PublicDependencyModuleNames.AddRange(new string[] {
"Core",
"VerseCompiler", // ← パーサ・VST・意味解析・効果
"uLangCore", // ← テキスト/レンジ等の基盤
});
…が、ここには大きめの留保があります。後述の「配布前に確認すべきこと」を必ず合わせて読んでください。
パーサ / VST / ソースレンジ
グラフビューワの土台になる部分です。ここは素直に揃っていました。
| 用途 | API | 場所 |
|---|---|---|
| ソース → 構文木 | CParserPass::ProcessSnippet(...) |
VerseCompiler/Public/uLang/Parser/ParserPass.h |
| 構文木ノード基底 |
Verse::Vst::Node(38 ノード種) |
.../Syntax/VstNode.h, NodeDecls.inl
|
| ノード → ソース位置 |
Node::Whence() / STextRange
|
.../Common/Text/TextRange.h |
| 位置 → ノード |
Node::FindChildByPosition 等 |
VstNode.h |
VST は Verse Syntax Tree(uLang 系の用語。Verse の構文木)で、各ノードが _Whence(SLocus / STextRange、行・列)を持ちます。これがあるおかげで「グラフノードをクリックしたら該当ソース行へジャンプ」「ソースを選択したら対応ノードを強調」といった双方向ハイライトが実装できます。
なお VerseGrammar.h(約 75 KB の単一ヘッダ、Result<> 形式のパーサコンビネータ)も Public ですが、これは完全には読み切れていません。for / loop / case 等に専用 VST ノードがあるかは未確認です。
追加調査:VerseGrammar.hを読む ── Verse 文法の正体
for / loop / case 等に専用 VST ノードがあるかと更に調べたところ、for / loop / case は「キーワード」ですらありませんでした。
結論がなかなか面白かったので、グラフビューワ設計への効き方とあわせて書いておきます。
予約語は 31 個だけ。残りは「ただの識別子」
VerseGrammar.h のトークン表(Tokens[], VerseGrammar.h:645-796)を端から確認すると、予約語として登録されているキーワードは 31 個しかありません。if / else / var / set / return / break / where / while などはここに入っています。
一方で、次の語はトークン表に存在しません。つまり字句解析の段階では普通の識別子(Identifier)として扱われます。
- 反復:
for,loop - パターンマッチ:
case,match,switch - 並行・非同期:
sync,race,rush,branch,spawn - リソース管理:
defer,using - 効果指定子:
decides,transacts,suspends,computes,reads,writes,allocates,dictates,no_rollback,native - 型キーワード:
class,struct,interface,enum,module - アクセス修飾子:
public,private,protected,final,abstractなど
最初は意外でしたが、これは Verse の文法が**「マクロ呼び出し」中心に設計されている**ためです。for {} や sync {} は文法に焼き込まれた構文ではなく、**識別子 for に後置のブロック/節がぶら下がった「マクロ呼び出し」**として一律にパースされます。ちなみに、予約語であっても直後が := なら UpdateToken() が識別子へ降格させる仕組みまであり(if := ... のような定義が書ける)、「キーワードは特別扱いしすぎない」という思想が一貫しています。
だから、これらに専用 VST ノードは無い
NodeDecls.inl の VST ノード型は 38 種。このうち制御フロー寄りの専用ノードは FlowIf / Control / Mutation / Where / Lambda の 5 種程度で、For / Loop / Case / Sync / Race / Branch / Spawn / Defer / Using という名前のノード型は存在しません。
これらの構文はすべて、
Identifier("for") + マクロ呼び出し(最大 3 つの節)
↓
Gen.Invoke(snippet, Identifier, Clause0, Clause1?, Clause2?)
↓
Macro ノード(_Children[0] = 名前, _Children[1..] = 節の列)
という形に収束します。for も loop も case も sync も、VST 上では同じ Macro ノードで、違いは先頭の Identifier の名前だけ、というわけです。
ひとつ重要な留保。
if/var/set/returnは、パーサ側では専用関数(If()/VarKeyword()/ControlFlowKeyword())で処理されます。ただしヘッダ内のデフォルト ジェネレータ(TGenerate)は、これらを最終的にprefix'if'のような識別子 + Call/Invoke へ正規化してしまいます。つまり最終 VST がFlowIf/Mutation/Controlといった専用ノードになるかどうかは、uLang 内部のカスタム ジェネレータ(VerseCompiler/Private/uLang/Parser/...)がPrefixToken/Invoke等をオーバーライドして専用ノードを返すか次第で、本ヘッダ単独では確定できません(ここは未確認、Private/ParserPass.cppを読めば決着します)。
確実に言えるのは、Macro/PrePostCall/Identifier/Clause/Parens/ 各種リテラルは確実に生成される、という点です。
効果指定子 <decides> はどこに入るのか
これも未確認だった項目で、パース経路までは追えました。Foo<decides>() のような指定子は、< を InvokeLess() が解析し、InvokeClause() が EMode::With の呼び出しを Specifiers リストに集約して、最終的に節(SBlock)の Specifiers フィールドに格納されます。
// VerseGrammar.h の SBlock(中間構造体)
struct SBlock {
...
SyntaxesType Specifiers; // ← <decides> 等の効果指定子はここに溜まる
SText Token; // do / then / else / catch などの後置ラベル
...
};
最終 VST ノードのどこに載るか(おそらく Node 基底の _Aux = Clause 参照)は、やはりジェネレータ実装次第で未確認です。ただ実用上は、効果の判定は VST を覗くより Semantic 側の SSignature::GetEffects() を使うのが正規ルート(前述)なので、グラフの効果バッジはそちらから取れば問題ありません。VST の Specifiers は補助的に使える、くらいの位置づけです。
構文 → VST ノード マッピング(改訂版)
通読を踏まえて、主要構文の対応を更新します。「〜の可能性(ジェネレータ次第)」は前述の留保がかかる項目です。
| Verse 構文 | パース経路(要約) | 想定 VST ノード |
|---|---|---|
foo() |
QualIdent → PostfixMacroInvoke → InvokeParens
|
PrePostCall |
if c {..} else {..} |
専用 If() → 2〜3 節を蓄積 |
FlowIf の可能性(既定は Macro 化) |
for X in C do B |
Identifier("for") + マクロ呼び出し |
Macro |
loop {..} / case X {..}
|
同上 | Macro |
sync / race / branch / spawn / defer / using {..}
|
同上 | Macro |
set X = v / var X:int = v / live
|
専用 VarKeyword()
|
Mutation の可能性 |
X := v |
PostfixArrow(:=) |
Definition |
Foo<decides>() |
InvokeLess → Specifiers に保持 |
効果指定子は節の Specifiers(VST 上は _Aux 等、ジェネレータ次第) |
return / break / continue / yield X
|
専用 ControlFlowKeyword()
|
Control の可能性 |
(X) => B |
=>(PostfixArrow) |
Lambda の可能性 |
X where Y |
PostfixWhere |
Where の可能性 |
X : int |
In(: は Choose 扱い) |
TypeSpec の可能性 |
{ X; Y; Z } |
ブロック関数群 | Clause |
グラフビューワ設計への効き方
この「マクロ中心」設計、ビューワにとってはむしろ朗報でした。
実装ルートA(VerseCompiler 直接)の場合。 for / loop / case / sync / … を個別にノード型として扱う必要がなく、VST 上は一律 Macro ノードとして来ます。グラフのノード種別は、先頭 Identifier の名前を見て分岐するだけで済みます。
// VST の Macro ノードから、先頭識別子で種別を決める
switch (macro.Name()) {
case "for": return MakeForNode(macro);
case "loop": return MakeLoopNode(macro);
case "case": return MakeCaseNode(macro);
case "sync": case "race": case "branch": case "spawn":
return MakeConcurrencyNode(macro);
// ...
}
数十のキーワードを文法レベルで特別扱いする実装に比べて、ずっと素直です。if/else が FlowIf で来るか Macro で来るか確定していない件も、両方を受けられるように書いておけば吸収できます。効果バッジは前述どおり Semantic の GetEffects() から取るので、VST 側の不確実性に引っ張られません。
実装ルートC(独立軽量パーサ)の場合。 自前で再現するなら、必要な主要 production 関数は 約 50 個、サポート ヘルパまで含めて 80〜100 関数規模、というのが通読後の見積もりです。最大の難所は2つで、
-
マクロ呼び出しの状態機械(
SInvoke/Invoke/InvokeClause)。最大 3 節の累積、do/then/until/catch/elseの連鎖、if{a} else if{b}の特殊規則など、約 600 行のステートフルなロジック。 -
効果指定子
<...>の収集(InvokeLess/InvokeClause)。<を>=/>と衝突させずに右結合でパースし、Specifiersに積む処理。
逆に MVP では、Markup(<tag>...</tag> 風記法)/インデント認識ブロック({} だけ対応すれば多くのコードは通る)/単位付き数値(123ms) あたりは省いても成立します。<decides> などの効果指定子は、字面(識別子の並び)としては捕捉できるが、「失敗可能関数かどうか」という意味は失う、という割り切りが現実的です(意味が欲しければ結局 Semantic が要る)。
まとめると、文法を読んだことで 「実装ルートA なら識別子名で分岐するだけで大半の制御構文を捌ける」「実装ルートC は約 50〜100 関数、二大難所はマクロ呼び出しと効果指定子」 と、両ルートの像がかなり具体化しました。前述の「A を主軸、C をフォールバック」という方針は、ここでも崩れていません。
診断(Diagnostics)
コンパイルエラー/警告をグラフに重ねたい、という需要にはきれいに応えられそうでした。
-
CDiagnosticsがコンテナ。OnGlitchEvent()でコンパイル中のストリーミング取得も、一括取得も可能。 - 個々の診断
SGlitch/SGlitchLocusが_SnippetPath(ファイル)+_Range(行/列)+_VstIdentifier(VST ノード参照) を併せ持つ。 - つまり「診断 → ソース位置 → 対応グラフノード → 赤ハイライト/ツールチップ」が、追加の対応表を自前で持たずに成立します。
コンパイルエラー
└─ SGlitchLocus._VstIdentifier ──→ VST ノード ──→ グラフノードを赤く
意味解析 / 効果(Effects)── 効果バッジは自動で出せるか
個人的に一番面白かったのがここです。
Verse は関数の「効果(effect)」を型システムで扱います。ue6-main の Effects.h には 8 種の効果がビットフラグで定義されていました。
suspends / decides / diverges / reads / writes / allocates / dictates / no_rollback
さらに合成セットも定義されていて、例えば
Computes = divergesTransacts = diverges | reads | writes | allocates | dictates
のように組み合わさっています。これらは CFunctionType::GetEffects() / SSignature::GetEffects() から SEffectSet として取得できます。
ということは、効果から BP 風のノード種別/バッジを自動で割り当てられるわけです。私が考えているマッピングはこんな感じです(提案段階)。
| 効果 | ノード/バッジ案 |
|---|---|
computes(純粋) |
Pure ノード |
reads |
Query / Read ノード |
writes |
Write バッジ |
transacts |
Transaction バッジ |
decides(失敗しうる) |
Branch ではなく Try / Success / Failure ノード |
transacts + decides
|
トランザクショナル Try(Commit / Rollback) |
suspends(非同期) |
Latent / Clock バッジ |
decides を単なる Branch ではなく Try/Success/Failure として描けるのは、Verse の failure コンテキストの意味論をそのままグラフに落とせるという意味で、BP より素直に書けるかもしれない、と少し期待しています。式単位の failable 判定も CExprInvocation::CanFail() で取れます。
なお当初、「意味解析を走らせるには Epic の標準ライブラリ digest(事前コンパイル済みパッケージ)が要るのでは? それが配布物に無いとシンボル解決が走らないのでは?」という懸念がありました。これは杞憂でした。.digest / .verse の標準ライブラリ ソースは公開ツリーに 1 つも無いのですが、int / float / logic などの組み込み型は CSemanticProgram::Initialize() + PopulateCoreAPI() が C++ 側で動的生成します。.verse テキストから CSemanticProgram を得る最小ドライバは実質 30 行程度、パース専用の fast path なら 12 行程度で組めることも確認できました(型解決まで要らない初期 MVP は後者で足ります)。
Visual Verse(VersaTiles)── 公式のブロック UI
冒頭で触れた、ブロック方式ビジュアルプログラミングの正体と思われるものです。
Engine/Source/Runtime/Solaris/ProtoLem/ に IVersaTilesIde / IVplWidget / IVplHost が存在し、タブ名は "VisualVerseTab"。Slate + ProtoLem 上に、タイル状の Verse 編集 UI を提供しているようです(UI の完成度・公開範囲は本調査の範囲外)。なおコード内で頻出する略称 **VPL は、UI/ログ上の正式名称が「Visual Verse」**であることを確認しました(SVplWidget.cpp の LogVisualVerse、Solaris.uplugin の説明文など)。
ただ、ここに乗っかって Graph レイヤを足すより、Verse の構造化データから独自に Graph を描く方が独立性が高いと考えています。ブロック編集中心の前提と、BP 風のグラフ表現は、そもそも狙いが少し違うので。Visual Verse は「参考実装として読む」くらいの距離感が良さそうです。
ランタイムトレース / デバッガ ── 思ったより踏み込めるが、癖がある
実行ハイライトや値検査をやりたい場合の話です。あまり期待していなかったのですが、実装の実体を読むと、ステップ実行も変数検査も VerseVM 側に揃っていました。順に。
実行中の行ハイライト:データは良質。
VerseTraceAnalysis("Verse" プロバイダ、旧名 "VerseVMSampler")の BytecodeSample イベントは、BytecodeOffset と一緒に Line(int32, 1-based)を直接持っています。つまり PC→行の対応表を自前で復元する必要がなく、イベントから即座にソース行が分かります。
ステップ実行:標準 DAP には無いが、独自プロトコルにはある。
uLangDAP の IServerImpl には step 系メソッドが宣言すらされていません。ところが VerseVMSocketDebugger の実装を読むと、ソケット上の独自 JSON RPC として next / stepIn / stepOut を受け付けていました。EState enum にも Continue / Pause / Next / StepIn / StepOut / Disconnect があります。受け付けるメッセージは setBreakpoints / continue / pause / next / stepIn / stepOut / threads / stackTrace / scopes / variables / disconnect の一式です。
[標準 DAP クライアント(VS Code 等)] ──✕── step 不可(uLangDAP に未宣言)
[Verse VM 専用 JSON-over-socket を喋るクライアント]
↕ next / stepIn / stepOut / scopes / variables / stackTrace ...
[VerseVMSocketDebugger] ──→ ステップ実行・スタック・変数すべて可
変数検査:レジスタは実際に埋まる。
FFrame.Registers は宣言だけのスタブかと疑っていましたが、VVMInterpreter 側で SELF / SCOPE / 各パラメータが実際に Set() されており、デバッガ側(VVMDebugger)でも名前付きで取り出していました。値の文字列化も VVMValuePrinting::ToString(VValue, ..., EValueStringFormat) が COREUOBJECT_API で公開されています(VerseSyntax / Diagnostic などのフォーマット指定可)。
残る制約。
- ソース位置は依然 行のみで列がない(
FLocation)。 - ステップ実行を使うには、Verse VM 専用のソケットプロトコルを話すクライアントを自前で書く必要があります(VS Code 等の汎用 DAP では届かない)。
-
プラグインがランタイムで Verse トレースを購読する公開 reader(
IVerseProvider相当)が見つかりません。VerseTraceAnalysisはTraceServices/Private配下なので、現実的には Insights 経由か、TraceServices/Publicの汎用 reader を間接利用できるかを別途詰める必要があります。 - 任意式の評価(evaluate)は DAP / ソケットどちらにも見当たりませんでした。
なので方針としては、ランタイムオーバーレイは「行粒度ハイライト+スタック+変数表示までは射程内。ただし専用クライアント実装と、購読経路の確定が前提」となります。
Scene Graph との関係
「Scene Graph」という単独クラスは見つかりませんでした。実体は EntityFramework(entity / component 階層 + EntityRegistry の階層クエリ + TEDS 統合) で、Verse モジュール /Verse.org/SceneGraph が VerseScope.PublicAPI として宣言されています(EntityRegistry.Build.cs)。
EntityRegistry には FindDescendantEntities / FindDescendantComponents など階層クエリの API があり、ENTITYREGISTRY_API で公開されています。将来的に「Verse コード ⇄ Scene Graph エンティティ」を相互リンクするなら、Verse のモジュールパスと EntityRegistry の階層クエリを突き合わせる経路が見えます(が、まずは MVP の対象外)。
実装ルートの評価
調査を踏まえ、取りうるルートを整理します。
| ルート | 概要 | 評価 |
|---|---|---|
| A: VerseCompiler 直接利用 | Public ヘッダのパーサ/意味解析/効果をそのまま使う | ◎ 情報は正確・低コスト。ただし配布安定性が未知 |
| B: Private API 依存 | API マクロ付きの内部シンボルに依存 | △ PrivateIncludePaths 経由で利用自体は可能(実際これまでのプラグインでも使ってきた)。Public より不安定で直接利用は想定外、installed build では Private ヘッダが非同梱の可能性、には注意 |
| C: 軽量独自パーサ | 表示に必要な範囲だけ自前で解析 | ○ Fab 配布リスクは小。ただし for/loop/case/マクロ/効果/オーバーロード解決の再現コスト大 |
| D: Visual Verse 流用 | VersaTiles の内部モデルに乗る | △ ブロック編集前提。Graph 向きとは限らない |
| E: ランタイムトレース先行 | 実行ログ/トレースのオーバーレイから入る | △ 単独では Graph 構造を持てない。A と併用前提 |
私の結論は 「A を主軸に、C を抽象境界の裏のフォールバックとして同居させる二段構え」 です。
理由は、(1) A で得られる構文/型/効果の正確さは独自パーサで再現するのが大変、(2) しかし A の配布安定性が読めない、という相反する事情を、抽象化で吸収したいからです。
実装としては、コンパイル時情報(パース・意味解析・効果)と実行時情報(トレース・デバッグ)を別々の薄いインターフェースに分け、VerseCompiler 直接 / 独自パーサ / トレース経由のバックエンドを差し替えられる構成を想定しています(具体的な API 設計は、実際に作るときの記事に譲ります)。
配布前に確認すべきこと(鬼門はかなり絞り込めた)
技術的に「作れる」ことと、Fab/Marketplace でサードパーティが安定配布できることは別問題です。ソースを読む限り、ここは懸念の大半が潰れ、本丸が 1 つに絞られました。
まず、潰れた(安心できる)方から。
-
必要ヘッダはすべて通常の
Public/配下にあります。Engine/Restricted/ディレクトリは ue6-main ツリーに存在せず、「Restricted 配下にヘッダが隠れていて使えない」というシナリオは否定できました。 -
BinariesSubFolder = "NotForLicensees"は バイナリ(DLL)の出力サブフォルダを指定するだけで、ヘッダのソースパスには影響しません(ModuleRules.csのドキュメント文字列で確認)。しかも中核のVerseCompiler自体はこの設定すら持たず、通常のEngine/Binaries/<Platform>/に出力される設計でした。 -
VerseCompilerの主要 API(CParserPass/CSemanticAnalyzer/CDiagnostics/SEffectSet等)にUE_DEPRECATED/UE_INTERNAL/ experimental マーカーは見当たりません。少なくとも明示の不安定マークは付いていない、という意味では安定側です(とはいえ研究ブランチなので将来の変更は別問題)。 -
Solaris.upluginのCategory: "Epic Internal.Fortnite"を見て「Fortnite に直結していて、それ以外では動かないのでは」と身構えていましたが、これは誤解でした。Fortnite 連携はFFortSolarisDelegatesという opt-in の delegate ハブ(公開ツリーの SolarisBridge モジュールが提供)経由で、Fortnite 側が任意に hook するだけ。Non-Fortnite 環境ではそのデリゲートが誰にも発火されないだけで、Solaris の動作自体は止まりません。 - 意味解析に Epic 内部の digest が要る、という懸念も前述のとおり杞憂でした(組み込み型は C++ 生成)。
そのうえで、残った本丸は実質これ 1 つです。
唯一にして最大の未確認事項: Epic が配布する installed(バイナリ)エンジンに、
uLangCoreなどのNotForLicensees/バイナリが実際に同梱されるのか。
ソースツリーから言えるのは「ヘッダは公開・VerseCompiler本体は通常配置」までで、NotForLicensees/階層のバイナリが installed build に乗るかどうかは、実機の installed build manifest を見ないと Yes/No が確定できません(本調査では未実施)。ここが No なら、Fab 配布の現実解は 実装ルートC(独自パーサ)に寄ります。
加えて、ビルド設定面で消費側プラグインが守るべき点も分かりました。
-
bDisableAutoRTFMInstrumentationは transitive に伝播しないので、VerseCompiler等に依存する自分のプラグイン側でも個別にtrueを設定する必要があります(PCHUsage = NoPCHsも要検証)。 - AutoRTFM の計装が効くのは Win64 / Linux 系のみ。Mac / モバイル / コンソールは計装対象外です(ただし元々計装を切っている設定なので、動かないわけではない見込み)。
要するに、**「ソースビルド環境なら 実装ルートA は問題なく成立」「installed build 配布だけが未確定」**まで絞れたので、静的解析を薄い抽象境界で包んで 実装ルートC を裏に控えさせる二段構えは、引き続き理にかなっている、という結論です。
おわりに
例によって書きたいことを書いていたら長くなりました。
まとめると、ue6-main の現状ソースから判断する限り、「Verse を正データにした読み取り専用の BP 風グラフビューワ(静的可視化 + 診断オーバーレイ)」は、VerseCompiler の Public API を直接使うルートで技術的に実装可能、というのが今回の結論です。
効果(effect)から Try/Transaction/Latent といったバッジを自動導出できるのは、Verse ならではで素直に楽しそうでした。
一方で、
- ランタイムのステップ実行・変数検査は、実は VerseVM 側に実装済みでした。ただし標準 DAP では届かず、Verse VM 専用ソケットプロトコルを話すクライアントを自前で書く必要があり、プラグイン向けのトレース購読経路も未確認
- 配布面は大きく絞り込めて、残る本丸は「installed build に
NotForLicensees/バイナリが乗るか」の一点
という状況です。なので実装は最初から、静的解析と実行時情報をそれぞれ薄い抽象境界に隔離して、独自パーサやトレース経由に差し替えられる形で始めるつもりです。
BP / Actor の廃止には賛否それぞれに理があって、私自身も割り切れない部分があります。ただ、**「公式が出さないなら、使いやすくする部分を自分で作る」**というのは、これまでプラグインを作ってきた動機そのものなので、今回もそこは変わりません。BP を懐かしんで復活させるのではなく、Verse という新しい正本の上に、読みやすいビューを一枚足す。そういう温度感で手を動かしてみようと思います。
ue6-main はまだ動くものを触れる段階ではありませんが、ソースを読むだけでも UE6 の設計思想がかなり見えてきます。日本語の情報もこれから増えていくはずなので、続報や実装の進捗もまた書ければと思います。
この記事が、UE6 と Verse の「現状」を掴む入り口になればうれしいです。