Connection Process

NetcodePlus connection process has been improved to allow players to share data such as save file or game options before all objects in the scene start spawning.

This page will explain what happens in the background when a player connects to the server using the StartHost(), StartServer() or StartClient() function inside TheNetwork.cs

Server

  1. Server starts listening with StartHost() or StartServer()

  2. If a host, a PlayerID is assigned to the host.

  3. All the OnReady() functions are triggered on the server.

Client

  1. Client connect to Game server with StartClient()

  2. Server Approve or Reject the connection (You can define conditions with checkApproval)

  3. Client automatically changes scene as soon as server approved connection

  4. Server Assign PlayerID and send it to client

  5. Client receives PlayerID and send Player Data to server

  6. Server receives Player Data and send World Data to client

  7. Client receives World Data, and send Ready state to server

  8. All the OnReady() functions are triggered on the client.

  9. Server Receives Ready state and starts spawning the player and all other network objects

  10. Client receive Spawn request from server, and spawn player and other objects

There are multiple events you can connect to inside TheNetwork.cs to determine what happens at each one of these steps. You can check the script directly, it contains comments on each of those actions.

Any custom script related to the connection process should be attached to a scene persistent object so that it is still working while switching scene and not destroyed. In the demo all these following examples are defined in TheNetworkDemo.cs, which is attached to the NetworkManager prefab and has DontDestroyOnLoad.

Connection Approval

You can define conditions to approve or reject a new client connecting by listening to the checkApproval delegate.

private void Start()
{
    TheNetwork.Get().checkApproval += OnApprove;
}
private bool OnApprove(ulong client_id, ConnectionData cdata)
{
    return true; //Approve everything
}

Player ID vs Client ID

ClientID (ulong) is assigned automatically by Netcode when a client connects. And increments each connection (so it will be a different ID if a client reconnects). Player ID is unique to NetcodePlus and you have control on which ID you assign to each player by using the findPlayerID delegate. This is really useful if you want to reassign the same ID to a player who reconnects, and helps keeping track of players accurately in a save file or other data.

private void Start()
{
    TheNetwork.Get().findPlayerID += FindPlayerID;
}
private int FindPlayerID(ulong client_id)
{
        GameData gdata = GameData.Get();
        ClientData client = TheNetwork.Get().GetClient(client_id);

        //Find existing player id by username (for reconnections)
        PlayerData user_player = gdata.GetPlayer(client.username);
        if (user_player != null)
        {
            return user_player.player_id;
        }

        //No player found, assign new player ID
        PlayerData player = gdata.AddNewPlayer(client.username);
        if (player != null)
        {
            return player.player_id;
        }

        //Max player count reached
        return -1;
 }

This is just an example as GameData and PlayerData aren't class in NetcodePlus, and are instead in the game demo scripts. You can define whatever logic you like to assign player ID, if you don't define findPlayerID, then the PlayerID will just be the same than the ClientID

Player Data and World Data

These are completely optional and defined in each project. But basically player data is custom data sent from the client to the server on connection, and world data is custom data sent from the server to the client on connection. You can send any data you like if you connect to these delegates: onReceiveWorld, onSendWorld, onReceivePlayer, onSendPlayer. If those events are not defined, then an empty network message will be sent just to aknowledge that the step is completed.

private void OnSendWorld(FastBufferWriter writer)
{
    GameData sdata = GameData.Get();
    if (sdata != null)
    {
        byte[] bytes = NetworkTool.Serialize(sdata);
        writer.WriteValueSafe(bytes.Length);
        if (bytes.Length > 0)
            writer.WriteBytesSafe(bytes, bytes.Length);
    }
    else
    {
        writer.WriteValueSafe(0);
    }
}  
private void OnReceiveWorld(FastBufferReader reader)
{
    reader.ReadValueSafe(out int count);
    if(count > 0)
    {
        byte[] bytes = new byte[count];
        reader.ReadBytesSafe(ref bytes, count);
        GameData sdata = NetworkTool.Deserialize<GameData>(bytes);
        if (sdata != null)
        {
            GameData.Override(sdata);
        }
    }
}

In this example, onSendPlayer is not defined so no data is sent from the client to the server on connection. Also, GameData is a custom class specific to the project and not to NetcodePlus.

If you want more examples on how to transfer data on connection, check TheNetworkDemo.cs

Spawning the player

One of the last step is to spawn the player character. By default it will be spawned at object position that has the PlayerSpawn component attached with the same PlayerID.

But you can define your own functions to determine the prefab to spawn and position to spawn with those delegates: findPlayerSpawnPos, findPlayerPrefab

You can also return null from the findPlayerPrefab delegate to not spawn anything at all, and instead you can manually call SpawnPlayer() inside TheNetwork.cs

onReady

onReady is a new delegate you can connect to in TheNetwork that will be triggered once the connection process is completed (before objects are spawned). Objects that are spawned or instantiated after you are already connected, will trigger OnReady at the same time than the Start() function instead.

On the server side onReady is triggered at the start as long as the host/server is started and all condition are true in checkReady.

Last updated