ドメインのリロードをスキップ:MethodReload特徴を使用した高速なイテレーション

Oct 22, 2026
Programming and DevOps
メソッドリロード

このウェブページは、お客様の便宜のために機械翻訳されたものです。翻訳されたコンテンツの正確性や信頼性は保証いたしかねます。翻訳されたコンテンツの正確性について疑問をお持ちの場合は、ウェブページの公式な英語版をご覧ください。

皆経験あるはずです。ゲームプレイのコードを調整して、エディタがドメインのリロードを完了するのを待つ、という状況です。そのプロセスはイテレーション時間を遅らせ、創造性を本当に消耗させます。デバイスでの反復作業に費やされる余分な時間、各サイクルで完全なビルドが必要なことを言うまでもない。

それに対する私たちの答えはMethodReloadです。Unite Seoulのステージでデモを行い、現在実験的なパッケージとして利用可能です。この記事では、MethodReloadの使い方、その制限事項、そしてプロジェクトですでに持っている可能性のあるホットリロードツールとの比較について解説します。

なぜリロードで詰まっているのか

少しの履歴があると助かります。なぜドメインリロードが存在するのか、その理由が消し去ることが難しい理由でもあるからです。

再生モードは、MonoのAppDomainを基に構築されており、コードの変更は、ドメインの破棄、新しいアセンブリのロード、再JIT、そして同じプロセス内での再開という馴染みのあるプロセスオフ開始しました。長年それは本物のスーパーパワーであり、Unityで反復作業を行うことがプレイヤーを構築するのと比べて速く感じられた大きな理由の一つです。

それはまた、ブランクなインストルメント化でもあり、リロード中にすべてが消え、一つだけメソッドを変更したのか百個変更したのかに関わらずすべてが戻ってきます。さらに、IL2CPPはドメインのリロードを全くサポートしていないため、すべての変更にプレイヤー全体の再ビルドが必要です。

「CoreCLRがこれを修正してくれるのでは?」と自問しているかもしれませんが、答えは次のとおりです。魔法のようにではなく。CoreCLRはドメインのリロードを廃止しますが、アセンブリをリロードする必要があり、MethodReloadもここで役立ちます。

MethodReloadの使い方

上記で述べたように、MethodReloadは利用可能であり、com.unity.pipelineに同梱されており、現在は0.7.0-exp.1です。

MethodReloadを使用するプロセスはかなり簡単です。1つ以上のメソッドに[MethodReload]属性をタグ付けし、ウォッチャーを開始し、再生モードに入力するか、開発プレイヤーをアタッチしてから、メソッドのボディを編集してください。実行中のインスタンスは、次のコールで新しいボディを取得します。

しかし、MethodReloadはドメインのリロードを完全に置き換えるわけではありません。より大きな変更も通常通りコンパイルされます。しかし、イテレーションループの大部分を占める小さな調整については、エディタでもデバイス上でも、長い待ち時間を数秒のことに変えます。

是非お試しください

MethodReloadを理解する最も速い方法は実行することなので、ご自身で試してみたい場合は、始めるためのいくつかの手順を以下に示します。注:これは実験的的な特徴であるため、プロセスは将来変更され、ここに記載されているものと異なる場合があります

1.パッケージをインストールしてください(Unity 6.0以上が必要です)。は、Unity CLI経由でインストールするか、Package Managerを使用して「技術名によるパッケージのインストール」でこの文字列:com.unity.pipeline@0.7.0-exp.1を使ってパイプラインパッケージを手動で追加することができます。

2.反復するメソッドにタグを付けなさい。その属性は、ディスパッチチェックがコンパイル時に織り込まれているため、再生モードに入る前、またはプレイヤーをビルドする前に存在しなければなりません。タグ付けされたメソッドはpublic(インスタンスまたは静的)で、voidまたはIEnumeratorを返す必要があります。それ以外はビルド時に注意付きでスキップされます。

using Unity.Pipeline.MethodReload;
using UnityEngine;

public class Spinner : MonoBehaviour
{
    public float rotationSpeed = 90f;

    [MethodReload]
    public void Update()
    {
        transform.Rotate(Vector3.up, rotationSpeed * Time.deltaTime);
    }
}

3.監視を開始してください。MethodReloadで変更をライブで確認するには、MethodReload Watcherを開始する必要があります。プロジェクト設定 → パイプライン → エディタに移動し、「メソッドリロードインタープリタウォッチ」セクションで「ウォッチを開始」をクリックしてください。

プロジェクト設定

監視者がアセットのツリー全体をカバーしている間、保存された.csはMethodReload属性を含んでいる場合にのみコンパイルされるため、無関係な保存は何もコストがかかりません。

4.エディタでテストする場合は、再生モードに入力してください。一度実行されると、タグ付けされたコードの変更はコンパイルされ、その場で注入されます。再生モードを終了すると、変更がコンパイルされ、通常のドメインリロードが行われます。

5.デバイスでテストする場合:デバイスをプラグインしてください。ランタイムパイプラインドライバーが有効な開発プレイヤーをビルドしてください。Autoconnect プロファイラーを使用してデバイスを接続するか、プロファイラーまたはコンソールウィンドウを介してアタッチ、設定、添付してください。それ以降、すべてのセーブはplayer'sプリプロセッサ定義を使用してエディタでコンパイルされ、接続されているすべてのプレイヤーにプッシュされます。どちらの向きでも再起動は必要ありません。

正面に知っておくべき2つのワークフローフローの詳細:

  • ウォッチが実行されている間、自動リフレッシュはオフになっているため、ドメインのリロードをトリガーする代わりに保存がリロードします。他のアセットは Ctrl/Cmd+R を押すまでインポートされず、ウォッチを停止すると設定が元に戻ります。
  • ウォッチはドメインのリロードを生き残ります。これは、再生モードのリロードによって消去された編集を再適用し、再接続するプレイヤーに対して再プッシュするためです。なぜなら、再起動したプレイヤーは元のコンパイルされたコードを起動するからです。

CLIを使うのはどうですか?

端末での作業を好む場合、エージェント経由で作業したい場合、またはウォッチ開始以降に変更されたものだけでなくタグ付けされたすべてのメソッドをプッシュしたい場合は、同じ機能がUnity CLIコマンドとして公開されたされています。

# Reload in the Editor through the interpreter
unity command reload_file_editor_interpreter "Assets/Scripts/Spinner.cs"

# Compile in the Editor, push to connected players (folders work too)
unity command reload_file_player_interpreter "Assets/Scripts" --player 2

制限事項

ドメインリロードを妥協なしで回避する方法はなく、MethodReloadの制限は3つの点にあります。適用できる変更の種類、実行できるC#、実行速度です。

タグ付けされたメソッド本体のみが変更されます。リロードは、コールサイト、フィールド、または型レイアウトに一切触れません。新しいフィールドも、新しいクラスもありません。そのコンストレイントこそが、本番インスタンスに適用しても安全である理由であり、それに基づいて計画を立てるべきものです。どのメソッドを反復処理するかを決定し、それらにタグを付けましょう。リロードは新しいメソッドを宣言し、リロードされたボディからそれを呼び出すことが でき ますが、そのメソッドはリロードのエントリポイントにはできません。なぜなら、次の実際のコンパイルまで、それを呼び出すことを知っているコンパイルされたものは何もないからです。

それはC#のサブセットを実行します。インタープリタは手作りであり、プレイヤーの中に収まるほど小さく保たなければならないため、C#のすべてを実装しているわけではありません。[MethodReload] ボディ内では、次のものを使用できません。

  • await と Task、 try/catch/finally、 lock、LINQクエリ構文、 checked
  • decimal, 動的, リフレクション型、スレッディング型
  • ref, out, および in パラメータ、ref 戻り値とローカル変数、多次元配列(ジャグドで可)、ジェネリックメソッド

doesは、プリミティブ、メソッド呼び出し、ループ、デリゲート、文字列補間、コルーチン yield、Collectionsのほとんどのゲームプレイコードをカバーします。Roslyn アナライザーはパッケージに同梱されており、タグ付けされたボディでのみ違反をIDEでフラグ付けするため、プッシュ後ではなく入力中に検出できます。

デバイス上では、解釈されたコードはプレイヤーが公開しているものしかコールできません。IL2CPPは参照のないコードを削除するため、UnityのメンバーやBCLメンバーを呼び出すが、ビルドでは使用されていないリロードされたボディはコールものがありません。エディタでは、不足しているメンバーはオンデマンドでバインドされます。デバイスでは、プッシュは正面をチェックし、不足しているメンバーを警告としてリストアップします。それでもコードがそれに到達すると、例外をスローします。経験則:メソッドが何をするかを変えるのであって、それが依存しているAPIのセットを変えるのではない。

解釈されたコードはコンパイルされたコードよりも遅い。それがインタープリタの性質であり、比較がIL2CPPの事前コンパイルであれ、MonoとCoreCLRのジャストインタイムであれ同じです。開発ビルドではタグ付けされたメソッドのみに影響します。リリースビルドにはプロローグもインタープリタもなく、タグ付きメソッドはコンパイルされたボディを実行するだけです。最終的に、イテレーション中のパフォーマンスヒットが、改善されたイテレーションスピードと利便性に見合うかどうかを判断するのはあなた次第です。

コルーチンは作成時に変更を拾います。[MethodReload] IEnumerator メソッドは、次に StartCoroutine が実行されるときに新しいボディを使用します。すでに実行中のコルーチンは、開始したボディを保持します。それを、リロードがその型に到達するたびにすべてのライブインスタンスで発火する引数なしのインスタンスメソッドである[OnMethodReloaded]とペアにし、長寿命ループを再開するためのドメインリロードフリーのOnEnableを使用します。

[OnMethodReloaded]
void OnMethodReloaded()
{
    StopAllCoroutines();
    StartCoroutine(MainLoop());
}

内部でどのように機能するか

それは2つの考え方の組み合わせです。一つ目は、C#をコンパイルするとILバイトコードが生成されるということ、そして二つ目は、ILが限定されたサブセット内に留まる限り、コンパイルされるのではなくインタープリタによって実行できるということです。そのインタープリタ自体が通常のC#なので、IL2CPPはそれをゲームの残りの部分と一緒にコンパイルし、それがデバイスで実行できる理由となっています。

2つ目のアイデアは、それに飛び込むことです。すべての[MethodReload]メソッドには、インタープリタへの配線されたパスがあります。インタープリタへの分岐は、コンパイル時にタグ付きメソッドにプロローグを織り込むことによって行われる。逆コンパイルすると、次のようになります。

[MethodReload]
public void TakeDamage(int amount)
{
    // weaved during compilation
    if (MethodReloadRegistry.HasOverride("Player.TakeDamage") &&
        MethodReloadRegistry.TryInvokeMethodReload(
            "Player.TakeDamage", this, amount))
    {
        return;
    }

    // initial code
    hp -= amount;
}

織り込まれたチェックは、このメソッドに対するオーバーライドが存在するかどうかをレジストリに尋ねます。ウォッチャーとCLIは、そのレジストリを新しくコンパイルされたILで満たします。エントリーがある場合、インタープリタはそれを実行し、元のボディはスキップされます。さもなければ、コンパイルされたコードは通常通り実行されます。

これがどう比較されるか

C#でドメインのリロードなしで反復作業を行うための優れたツールはすでに存在しており、それらがどこに適用されるかを装うのではなく正確に区別したいと考えています。

実行中のMonoランタイムにおけるAsset Storeからのパッケージパッチメソッド。それは彼らに優れたエディタ体験をもたらし、リロードされたボディ全体で完全なC#が利用でき、タグ付けステップがなく、ホットリロードの場合はMonoプレイヤービルド用のオンデバイスモードがあります。すべての真の利点また、パッチを適用するランタイムがないため、IL2CPPプレイヤーとは互換性がないという意味でもあります。

.NET Hot Reloadは、Visual StudioおよびRiderにおける.NETアプリケーションの機能であり、ランタイムの編集と継続のパスを通じて編集を適用します。CoreCLR向けに構築されており、UnityのMonoやIL2CPPランタイムをターゲットにしていません。

MethodReloadは、そのインタープリタバックエンドが言語カバレッジを異なる場所で持つという点で際立っています。それはC#のサブセットですが、通常は携帯電話やコンソール開発キットに再デプロイする必要があるのと同じIL2CPP開発ビルド上で動作し、すでに接続されているケーブル経由で、プレイヤー内に余分なサーバーも、開くべきポートもなく動作します。

正直な話:イテレーションの痛みがエディタにあるのであれば、既存のツールは成熟しており、あなたにとって機能しているものを使い続けるべきです。イテレーションの痛みがデバイス上に存在し、特にIL2CPP上にある場合、これが最初に来るオプションです。

最終的なヒント

もし今プロジェクトのワークフローを設定しているなら:

  • ホットスポットをタグ付けしてください。 [MethodReload] はリリースビルドでは費用がかからないため、デバイス上で触るつもりだとわかっている Update、チューニング、ゲームフィールのメソッドをタグ付けしてください。
  • アナライザーにサブセット内に留まらせてください。メソッドがtry/catchまたはawaitを必要とする場合は、その部分をタグ付けされていないヘルパーに移動し、その周りのロジックをリロードしてください。アナライザーは、何か間違ったことをしている場合に知らせてくれます。
  • まずエディターで試してみてください。CLIからのウォッチャー、またはreload_file_editor_interpreterは、デバイス上で実行されるのと同じインタープリタを通してあなたの編集を実行します。そこで動作すれば、ハードウェアでも動作するので、ビルドを待たずにサブセットやAPIの欠落の問題を捕捉できます。

将来の計画

コマンドリファレンス、ランタイム設定ページ、および完全なコンストレイントリストは、com.unity.pipeline docsにあります。

この機能をプロジェクトで試していただき、結果を教えてください。フィードバックは大変ありがたく、実験的なパッケージは人々がそれらに働きかけるときが最も速く改善されます。

ドメインのリロードは、それが必要とする変更に対してどこにも行きません。変更がない場合は、待つのを停止てもいいです。