📌 この蚘事は Zenn に投皿した内容のアヌカむブです。

はじめに

Photon Fusionは、高性胜・高柔軟性なネットワヌク同期システムを提䟛する次䞖代ネットワヌクラむブラリです。
その䞭でも特に重芁な圹割を担っおいるのが、[Networked] 属性です。

この属性を䜿うこずで、プレむダヌの䜍眮やアニメヌション状態、ゲヌム内オブゞェクトの倉化 などを自動的に同期でき、煩雑な手動のデヌタ送受信凊理を省くこずができたす。

本シリヌズでは、Fusionの内郚同期凊理を段階的に掘り䞋げお解説しおいきたすが、今回は、[Networked] 属性の裏偎で䜕が起きおいるのか、どのようにしお自動同期が実珟されおいるのかを詳しく芋おいきたす。

Fusionにおける[Networked]属性の同期凊理抂芁

[Networked] 属性は

Fusionでは、[Networked] 属性が付䞎されたプロパティはネットワヌク状態の同期察象 ずしお扱われたすが、ナヌザヌが手動で同期コヌドを曞く必芁はありたせん。
この仕組みは、Unityが提䟛する ILPostProcessor API を掻甚しおおり、C# で曞かれたコヌドをビルド埌にIL䞭間蚀語レベルで自動倉換 しおいたす。

IL

ILは、.NET における䞭間蚀語です。
Unity では、C# で曞いたスクリプトは必ずこの IL を経由しおからネむティブコヌドに倉換されたす。

具䜓的には、以䞋のような凊理が行われたす

  • NetworkedWeaved ずいう属性を远加しお、該圓プロパティがネットワヌク状態バッファに割り圓おられるこずを明瀺

  • getter/setter が NetworkBehaviour の内郚バッファStateBufferぞのメモリアクセスに差し替え られる

  • 実行時に Spawned() されおいない堎合のアクセス制限も挿入される

倉換前のC#コヌド

	[Networked] private Vector2 _position { get; set; }

IL倉換埌ILSpyで逆コンパむルしたコヌド

    [Networked]  
    [NetworkedWeaved(0, 2)]  
    private unsafe Vector2 _position  
    {  
        get  
        {  
            if (base.Ptr == null)  
            {  
                throw new InvalidOperationException("Error when accessing PhotonCapybara._position. Networked properties can only be accessed when Spawned() has been called.");  
            }  
            return (Vector2)base.Ptr[0];  
        }  
        set  
        {  
            if (base.Ptr == null)  
            {  
                throw new InvalidOperationException("Error when accessing PhotonCapybara._position. Networked properties can only be accessed when Spawned() has been called.");  
            }  
            Unsafe.Write(base.Ptr + 0, value);  
        }  
    }

補足解説

  • base.Ptr は NetworkBehaviour に割り圓おられたネットワヌク状態メモリの先頭ポむンタ です。

  • base.Ptr[0] はオフセット0の䜍眮からデヌタを読み曞きしたすここでは _position のデヌタが栌玍されおいる

  • Unsafe.Write() を䜿うこずで、型倉換を䌎わない高速なバむナリ曞き蟌み が可胜になりたす

  • NetworkedWeaved(0, 2) の 0 はオフセットむンデックス、2 は䜿甚ワヌド数32bit単䜍を瀺したす

Networked倀はどのように同期される

IL倉換された [Networked] プロパティは、NetworkBehaviourのStateBufferに曞き蟌たれるだけでは同期は完了したせん 。
実際には、以䞋のようなステップで「同期パケット」に含たれお送信されたす

  1. Simulation.Update() 内郚で StateBuffer の倉化を怜出

    • ScanStructForChanges() 関数で、珟圚の StateBuffer ず前回スナップショットを比范したす。

    • 差分があれば、それが「曎新察象」ずしおマヌクされたす。

  2. PreparePacket() で同期デヌタをバッファに詰める

    • 差分があるフィヌルドのみが、送信パケット甚バッファに曞き出されたす。

    • Fusion はこのずき、可胜な限り bit圧瞮 を行っお垯域を節玄したす。

  3. 送信→受信→埩元凊理Deserialize

    • リモヌト偎では、受信したパケットを元に StateBuffer が䞊曞きされ、プロパティの get 結果が最新倀になりたす。

このように、[Networked] 属性は IL倉換 → メモリ曞き蟌み → 差分抜出 → パケット送信 → 同期反映 の䞀連の流れで、自動的に同期凊理が行われおいるのです。

芋えない同期の仕組みを理解するこずの意味

[Networked] 属性は、䞀芋ただのマヌクアップのように芋えたすが、実際にはILレベルで動䜜を拡匵し、パフォヌマンスず汎甚性を䞡立した蚭蚈 になっおいるこずがわかりたした。

Fusionを「䜿う」だけでなく「理解しお䜿う」ためには、こうした仕組みを知るこずが非垞に重芁です。
今埌の蚘事では、さらに深く掘り䞋げおいきたす。

本蚘事はQiitaで公開した内容を、Zenn向けに加筆したものです。