This page is a work in progress and could be pending updates.

Quickstart

Quickstart

You have just created a new Unity project, imported the Fusion SDK and now want to get started writing your next multiplayer game. Or perhaps you have an existing single player prototype. In either case, where do you start?

The recommendation is to start with one of the samples. They will give you straight-forward implementations of the best-practices and design patterns for multiplayer games, many of which can be directly copied into your own production project.

But before you start coding, this document explains most essential components and indicates what they do so you'll know what to look for once you dig into actual sample code.

Back To Top

The Basics

The two primary Fusion components that you will use are NetworkRunner and NetworkObject. NetworkRunner can be thought of as the core of Fusion - you'll only have one of these in your scene and it will manage both networking and simulation. This happens on both servers and clients.

Adding NetworkObject to an otherwise regular Unity prefab or scene object, will assign it a network identity in runtime, and let it be part of the synchronized tick-based simulation. It also lets you configure a few options (like for example making this particular object always part of the data transfers - global object).

Two other base behaviours are there to be inherited from and add the actual networking to Game Objects: SimulationBehaviour and NetworkBehaviour.

Networked properties (that comprise the game state) are to be added to NetworkBehaviour (a specialized sub-class of SimulationBehaviour), while the latter can be used to control simulation steps and callbacks without carrying networked properties.

NetworkBehaviour should be used to hold data that is automatically synchronized across the network. In order to define a network state value, simply create a property and mark it as [Networked], like this:

[Networked] public byte life { get; set; }

[Networked] works for all primitive types (except for bool, for which you should use NetworkBool instead since it will get properly serialized as a single bit). It also works for structs and references to other NetworkObject's (even prefabs) since these can be safely identified on all clients.

Important: Fusion will replace the empty get/set stubs with code that access the actual networked state data, so these shall be kept empty.

It is also easy to register a callback to be triggered every time a networked property value changes:

[Networked(OnChanged = "OnTypeChanged")] public Type type { get; set; }

public static void OnTypeChanged(Changed<TheClassWhichHasTheProperty> changed)
{
  // your code here - check API docs for more details
}

In addition to the actual callback name, you can also control where the callback is executed:

  • OnChangedLocal (true/false) - set to true to also have the event hook called on the machine that changed the property, for example a server (default false)
  • OnChangedRemote (true/false) - set to false to only have the event hook called on the machine that changed the property (default true)

Back To Top

Built-in Network Behaviours

Fusion offers various prebuilt NetworkBehaviours to get a game or prototype up and running quickly.

NetworkTransform keeps an object transform synchronized (can also contain colliders). Rendering is automatically kept butter smooth with state of the art snapshot interpolation. It is also straight-forward to do full client-side prediction (on any game client) by directly changing data on Unity's Transform.

For physics-controlled rigidbodies, NetworkRigidbody is the recommendation. Same interpolation options work, and Fusion can do full predict/rollback directly with PhysX by just setting a configuration option.

For objects controlled directly by players, like humanoid characters, Fusion has a built-in NetworkCharacterController. For more complex use cases, it is possible to reuse the basic static query (that gives you surface tangents, penetration corrections, etc) and match with your custom code for steering/movement.

Back To Top

Tick-based Callbacks

To write gameplay simulation code, SimulationBehaviours lifecycle comes into play. It is possible to still use Unity's built in Awake() and Start() etc., but it is generally more recommended to be aware of the network-safe counterparts:

Fusion's equivalent to Start() is called Spawned() and it is triggered when that object is brought to life for the first time on a specific machine (server or client). Use Awake() for one-time initialization of things that will not change over the lifetime of the object - Calls to GetComponent<>() often falls into this category, but generally use Spawned() where you would normally have used Start().

The most important Fusion callback is FixedUpdateNetwork(). FixedUpdateNetwork() is what Fusion uses both to execute logic for the next network state, and to resimulate during reconciliations.

There are detailed descriptions of all these callbacks on API documentation, but the important part that you need to understand is that FixedUpdateNetwork(), like FixedUpdate() is called at fixed intervals, which are independent of the rendering rate. And, unlike FixedUpdate(), it can be called many times over for the same state/frame/tick when resimulation happens to reconciliate updates that came from a server.

For network properties, resimulation is transparent because Fusion will implicitly reset all network state properties before calling FixedUpdateNetwork().

It is perfectly safe, for example to run something like this from within FixedUpdateNetwork(), as long as the object in question uses NetworkTransform or one of the other built-in components:

transform.position += transform.forward * Runner.DeltaTime;

Notice the use of Runner.DeltaTime, necessary to keep simulation in accordance with the network tick rate.

Render() is guaranteed to run after all calls to FixedUpdateNetwork() and before LateUpdate().

Back To Top

Input

Fusion splits input handling into two separate steps:

  1. Collect Input from the local hardware and place it in a struct. This is always done only on clients and a host (not on dedicated server), once per new tick. This is sent to the server, and also used locally for immediate client side prediction (on clients).
  2. From FixedUpdateNetwork() this input can be read to change the game state (advance the simulation). This can be done on both the client (from any Network Object for which is has Input Authority) and the Host/server. On clients, this can happen multiple times for the same tick/frame to resimulate on reconciliation rollbacks.

The first step can be thought as a regular Unity input handling mechanism that simply records what the player is doing and stores it for later use, while the second step is a decoupled script to apply that input to modify the networked state.

The first step is polled by Fusion in its OnGetInput() callback and the second is handled by calling GetInput() or TryGetInput() from within FixedUpdateNetwork(), typically by a SimulationBehaviour on your main character.

Back To Top

Remote Procedure Calls

While Input structs and the use of [Networked] properties should be your go-to method for keeping game state synchronized between network clients (and keeping server authority), there are times when that simply isn't the most practical solution.

For example when a client wants to perform a rare complex interaction with an object that it does not have Input Authority over: like using a specific key in your inventory to open a locked door.

One could include some fields in the Input struct that would tell the server which key to use and for which door, but that approach would quickly end up creating a lot of clutter in the Input Struct that is rarely used.

Another thing to consider is that regular Fusion Input is not reliable - packets may be lost. This is rarely noticeable if you're doing some form of continuous input like moving a character, but if you're doing a single one-time action you might want to make sure it arrives at the server.

For these cases, Fusion supports RPCs (Remote Procedure Calls).

Fusion implements a simple yet powerful syntax for RPCs. To define an RPC on any SimulationBehaviour you declare a regular C# method with return type ;void and tag it with the [Rpc] attribute. It may take any primitive parameter (except bool, see above) as well as structs and references to Fusion objects (e.g. a NetworkObject or a PlayerRef - anything that has a network identity).

The [Rpc] attribute allow you to filter where it may be called from and where it gets executed:

[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color)
{
    playerName = name;
    playerColor = color;
}

Also note the use of the "RPC" prefix - while you don't have to use this exact notation, you must either pre- or post-fix the method name with "rpc" (not case sensitive).

In addition to the source and target properties, the [Rpc] attribute has a couple of additional optional parameters:

  • Channel (Reliable/Unreliable) - Set to Unreliable if you don't care about the RPC being lost in transmission (defaults to Reliable)
  • InvokeLocal (true/false) - Set to false if you don't want to invoke the RPC on the local client (defaults to true)
  • InvokeResim (true/false) - Set to true if you want the RPC to be invoked even during re-simulations (defaults to false)

One final note on RPCs is that you should keep in mind that RPCs have no explicit state - Even if you're sending to "all clients", clients who are not yet online will not receive it, and clients that jump out and back in will forget it ever happened. For this reason you should always make sure that the state of the RPC is either truly transient (e.g. a chat message) or that its effect is indirectly recorded in [Networked] properties.

To Document Top