This document is about: FUSION 2
SWITCH TO

Coming from Fusion 1

New Features

Fusion 2 brings a variety of new features and improvements to Fusion enhancing the API while keeping true to the core principles of Fusion. Here is a list of the most important improvements:

Interest Enter/Exit Callbacks

New IInterestEnter and IInterestExit callbacks have been added to Fusion. These are fired when an Network Object enters/exists a given Player's AOI regions, as well as when a player explicitly has interest in an Object added or removed (using Runner.SetPlayerAlwaysInterested()). The callbacks are reliably computed on the server in Server, Host and Shared Mode.

Interpolation Targets

Working with interpolation targets could be difficult to get right with fusion 1 especially when parenting Network Objects. With Fusion 2 we have simplified interpolation. There are no interpolation targets anymore, instead the Transform with the NetworkTransform itself is interpolated.

NetworkTransform

There have been a few changes to NetworkTransform. See Network Transform

Local Space

NetworkTransform now stores its TRS data (Position/Rotation/Scale) in local space. This means:

  • Child and Nested NetworkTransforms are MUCH more data efficient
  • However, Area Of Interest position is no longer valid for nested NetworkObjects. AreaOfInterestOverride has been introduced to account for this, and allows a NetworkObject to specify another NetworkObject position to be used to determine Player Interest.

Sync Scale

The Transform's localScale now can optionally be synced.

Sync Parent

A NetworkObjects parent now can optionally be synced. A valid NetworkBehaviour must be present on the parent transform, and the NetworkTransform must be on the root of the Network Object.

Network Physics

NetworkRigidBody and NetworkPhysicsSimulation have been removed from the Fusion DLL and have been replaced with the Unity Physics Addon, which currently is included in the main Fusion SDK download. The full feature set of server-only and full-prediction physics is available, and we plan to add a new forward-only mode.

Providing the physics addon via source code allows you to modify/extend it to fit your projects needs. This allows complex use cases such as VR games more flexibility when working with physics. While NetworkTransform has removed its InterpolationTarget requirement in Fusion 2, NetworkRigidbody still has an InterpolationTarget property. However, an Interpolation Target is only needed for very specific use cases, and typically can be left as null (indicating that the rigidbody transform will be be moved for interpolation).

Change Detection

A new change detection API actually allows not only to detect changes in Render but also in FixedUpdateNetwork to trigger gameplay logic. It is more complete and flexible, while we still plan to investigate if we should offer a simplified syntax sugar that behaves like the old OnChanged as well.

Tick-Accurate Shared Mode

Shared Mode is now tick-accurate. This brings many improvements;

  • Shared Mode interpolation is now much snappier and more accurate.
  • TickTimer is now valid in Shared Mode.
  • Networked Tick values are now meaningful in Shared Mode.

Custom Interpolation

We add a new interpolation API to access data points. It gives you access of the from/to data buffers and the interpolation alpha that Fusion uses to interpolate all Networked Properties.

Lag Compensation Improvements

Lag compensation has been improved. There is no longer a need to position animated hitboxes ahead of Render to have them in the correct position. The lag compensation will automatically use the correct interpolated animation position from Render which matches what the player saw on their screen. Additionally lag compensation supports 2d uses cases and allows querying against the 2d physics scene now.

Upgrading to Fusion 2

Video

There is a video tutorial covering the upgrade process for simple Fusion projects.

Upgrade the Unity Version

Fusion 2 supports Unity 2021.x and newer versions of Unity. For projects on older Unity versions first upgrade Unity before attempting to upgrade Fusion.

Upgrading the SDK

  1. Before upgrading your project make sure to back up your project using a version control system software or equivalent method.
  2. Backup the NetworkProjectConfig by moving it from Assets/Photon/Fusion/Resources/NetworkProjectConfig to Assets/NetworkProjectConfig.
  3. Delete the /Photon folder from your project.
  4. Download the Fusion 2 SDK and import the Unity package.
  5. Move NetworkProjectConfig back under ``Assets/Photon/Fusion/Resources/NetworkProjectConfig`.
  6. Fusion 2 needs a separate App Id than Fusion 1 projects to work. Create a new AppId here and select Fusion 2 while creating. Insert the new AppId under Fusion > Fusion Hub in Unity.
  7. Open /Packages/manifest.json and replace the existing addressable package with "com.unity.addressables": "1.21.12" (or add new if Addressables are not installed). Save the file.

After you are done importing the package there will be many errors in the console. These need to be manually corrected by upgrading the API.

API Changes

Simple API Changes

Previous API New API
(int)PlayerRef PlayerRef.PlayerId
PlayerRef.IsValid PlayerRef.IsRealPlayer
(int)SceneRef SceneRef.FromIndex
NetworkObject.NetworkGuid NetworkObject.NetworkTypeId
INetworkObjectPool INetworkObjectProvider.
NetworkTransform/NetworkTRSP.TeleportToPosition() NetworkTransform.Teleport()
Runner.Config.DefaultPlayers Runner.Config.Simulation.PlayerCount
[Accuracy] Remove the attribute. No replacment.
NetworkRunner.IsVisible NetworkRunner.GetVisible() and SetVisible()
Runner.SimulationConfig.Topology Runner.Topology
NetworkCharacterControllerPrototype NetworkCharacterController
Runner.Simulation.X (Runner.Simulation.Tick) Runner.X (Runner.Tick)
Runner.MultiplePeerUnityScene Runner.SimulationUnityScene
Runner.SetActiveScene Runner.LoadScene (must only be called on host/master client)

NetworkObjectPool

The pooling API has changed significantly to allow for asynchronous loads.

INetworkObjectPool has been renamed to INetworkObjectProvider.

Two new simpler functions to provide instances have been added that can be used for simple use cases like pooling:

C#

public class PooledNetworkObjectProvider : NetworkObjectProviderDefault
{
    protected override NetworkObject InstantiatePrefab(NetworkRunner runner, NetworkObject prefab)
    {
        // Get object from pool and return it.
    }

    protected override void DestroyPrefabInstance(NetworkRunner runner, NetworkPrefabId prefabId, NetworkObject instance)
    {
        // Return the instance to the pool.
    }
}

The ReleaseInstance and AcquireInstanceFunctions have been adjusted.

C#

public void ReleaseInstance(NetworkRunner runner, NetworkObject no, bool isSceneObject)
{
    ....
}

to

C#

public void ReleaseInstance(NetworkRunner runner, in NetworkObjectReleaseContext context)
{
    var no = context.Object;
}

AcquireInstance(NetworkRunner runner, NetworkPrefabInfo info) is now AqcuirePrefabInstance(NetworkRunner runner, in NetworkPrefabAcquireContext context, out NetworkObject result). The return parameter is no longer the object but the result (NetworkObjectAcquireResult.Success). The object is passed via the out parameter instead.

IsSceneObject in the context parameter has been replaced with context.TypeId.IsSceneObject.

From:

C#

public NetworkObject AcquireInstance(NetworkRunner runner, NetworkPrefabInfo info)
{
    NetworkObject prefab;
    if (NetworkProjectConfig.Global.PrefabTable.TryGetPrefab(info.Prefab, out prefab))
    {
        var newO = ...
        return newO;
    }
    return null;
}

To:

C#

public NetworkObjectAcquireResult AcquirePrefabInstance(NetworkRunner runner, in NetworkPrefabAcquireContext context, out NetworkObject result)
{
    NetworkObject prefab;
    if (NetworkProjectConfig.Global.PrefabTable.TryGetPrefab(context.PrefabId, out prefab, true) == NetworkPrefabTableGetPrefabResult.Success)
    {
        var newO = ....
        result = newO;
        return NetworkObjectAcquireResult.Success;
    }

    result = null;
    return NetworkObjectAcquireResult.Failed;
}

NetworkProjectConfig.Global.PrefabTable.TryGetPrefab(info.Prefab, out prefab) now has an additional bool IsSynchronous parameter (set to true to keep same behavior) and returns a NetworkPrefabTableGetPrefabResult enum instead of a bool.

Change Detection

OnChanged has been removed. Fusion 2 offers a new more extensive API that allows to detect changes both in Render and FixedUpdateNetwork. You can learn more about the new change detection API here.

Here is a simple example of replacing OnChanged with the equivalent Render based change detection.

From:

C#

public class Example : NetworkBehaviour
{
    [Networked(OnChanged = nameof(OnStateChanged))]
    public int State { get; set; }
    
    public static void OnStateChanged(Changed<Example> changed)
    {
        var value = changed.Behaviour.State;

        changed.LoadOld;
        var oldValue = changed.Behaviour.State;
    }
}

To:

C#

public class Example : NetworkBehaviour
{
    private ChangeDetector _changes;
    
    [Networked]
    public int State { get; set; }

    public override void Spawned()
    {
        _changes = GetChangeDetector(ChangeDetector.Source.SimulationState);
    }

    public override void Render()
    {
        foreach (var change in _changes.DetectChanges(this, out var previousBuffer, out var currentBuffer))
        {
            switch (change)
            {
                case nameof(State):
                    var reader = GetPropertyReader<int>(nameof(State));
                    var (previous,current) = reader.Read(previousBuffer, currentBuffer);
                    OnStateChanged(previous, current);
                    break;
            }
        }
    }

    private void OnStateChanged(int oldValue,int value)
    {
    }
}

Interpolation Target

Interpolation Targets do no longer exist and are not necessary to use with NetworkTransform. The object with the NetworkTransform itself will be interpolated accordingly in Render.

Predicted Spawning

Predicted spawning has been removed and there is no new APi to replaced it. NetworkObjectPredictionKey is no longer needed, remove it from the Spawn function.

Physics

NetworkRigidBody and NetworkPhysicsSimulation have been removed from the Fusion dll. These have been replaced with the Unity Physics Addon IBeforePhysicsStep (and after) have been removed and need to be remapped to RunnerPhysicsSimulate.OnBeforeSimulate (and after)

Shared Mode Improvements

Ticks are now aligned. This means you can use Runner.Tick to refer to a specific tick in shared mode and share that information with other clients. This also allows for the use of TickTimer in shared mode.

Simulation Behaviours

SimulationBehaviours are no longer supported on NetworkObjects. Replace them with NetworkBehaviour and remove IOnSpawned/IOnDespawned interfaces and use override Spawned/Despawned instead.

FixedUpdateNetwork on Proxies

FixedUpdateNetwork no longer executes on proxies by default.

It can be manually enabled by calling Runner.SetIsSimulated(Object, true);. It's best to call this in Spawned to ensure that FixedUpdateNetwork starts running immediately.

Scene Management

Scene management has been significantly changed to allow for addressable scenes and additive loading.

OrderAfter / Before

The OrderAfter and OrderBefore attributes have been removed. Instead, Unity's execution order is used. You can find the Script Execution Order of built-in Fusion types under Edit > Project Settings > Script Execution Order. Do NOT modify the execution order of built-in Fusion types.

To adjust the execution order of your scripts either manually add them to the list in the project settings or use the [DefaultExecutionOrder(x)] attribute.

E.g. [OrderAfter(typeof(HitboxManager))] becomes [DefaultExecutionOrder(-1995)].

AOI INetworkRunnerCallbacks

There are two new callbacks that are called whenever an object enters or exits the AOI area of the client. Use these callbacks to hide/show objects accordingly.

In Fusion 1 manual detection of entering / exiting AOI was needed instead.

C#

public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player)
{
}

public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player)
{
}
Back to top