DarkRift 2 Tutorial for Unity 3D – Part 9 – Send spawn messages to clients

Reminder : You can find all the DarkRift2 related articles here 
You can find the entire project on my official GitHub

Create the serializable class

As seen in the last article, we’ll use serializable class to send message. We need two information.

  • The network ID
  • The object spawn position

In fact, we need a third information wich contains what object it is but it will be discussed in dedicated article.
Create a new folder into Scripts/Network and name it SpawnMessageModel :

Here is the code :

using DarkRift;

public class SpawnMessageModel : IDarkRiftSerializable
{

    #region Properties
    /// <summary>
    /// Id of the object in the server
    /// </summary>
    public int networkID { get; set; }

    /// <summary>
    /// X position
    /// </summary>
    public float x { get; set; }

    /// <summary>
    /// Y position
    /// </summary>
    public float y { get; set; }
    #endregion


    #region DarkRift IDarkRiftSerializable implementation
    public void Deserialize(DeserializeEvent e)
    {
        networkID = e.Reader.ReadInt32();
        x = e.Reader.ReadSingle();
        y = e.Reader.ReadSingle();
    }

    public void Serialize(SerializeEvent e)
    {
        e.Writer.Write(networkID);
        e.Writer.Write(x);
        e.Writer.Write(y);
    } 
    #endregion
}

You don’t need any reference to unity namespace. This class is elementary. It’s the representation of a spawn message.

Create a tag dictionnary

As you know each message is tagged to give a general meaning of what it concerns. Thus, for that, i decided to create a specific class that will contains all code tags.
Create a new Script into the folder previously created and name it NetworkTags :

For now, we just need one tag, but it’s good to be organized in order to add some tags easely. I use a classe and structs to build this “dictionnary”. Here is the implementation :

/// <summary>
/// Classes that stores all tags
/// </summary>
public static class NetworkTags
{
    /// <summary>
    /// Tags used in game
    /// </summary>
    public struct InGame
    {
        public const ushort SPAWN_OBJECT = 1001;
    }

}

Update the GameServerManager

OK, all it’s ready to create our messages and send them trough the network, but, what we exactly need to send ? There is two cases :

  1. When a client connects, send a spawn message for all network objects
  2. When a new object appears, send a spawn message for all clients.

In the first case, in a production environnement, this step is made during the loading phase. The second case is when the game runs.

First step is to create a property in the GameServerManager that will keep in memory all network objects :

/// <summary>
/// List of objects handled by the server
/// </summary>
public List<NetworkObject> networkObjects;

Don’t forget to initialize it into the Start() unity callback :

private void Start()
{
	...
    networkObjects = new List<NetworkObject>();

Then, let’s create the two functions to send our messages plus on function that will be called by all network objects in the scene : RegisterNetworkObject

#region Implementation

    /// <summary>
    /// Use this function to add a network object that must be handle by the server
    /// </summary>
    /// <param name="pNetworkObject"></param>
    public void RegisterNetworkObject(NetworkObject pNetworkObject)
    {
        //Add the object to the list
        networkObjects.Add(pNetworkObject);
    }

    /// <summary>
    /// Send a message to the client to spawn an object into its scene
    /// </summary>
    /// <param name="pClient"></param>
    public void SendObjectToSpawnTo(NetworkObject pNetworkObject, IClient pClient)
    {
        //Spawn data to send
        SpawnMessageModel spawnMessageData = new SpawnMessageModel
        {
            networkID = pNetworkObject.id,
            x = pNetworkObject.gameObject.transform.position.x,
            y = pNetworkObject.gameObject.transform.position.y
        };

        //create the message 
        using (Message m = Message.Create(
            NetworkTags.InGame.SPAWN_OBJECT,                //Tag
            spawnMessageData)                               //Data
        ){
            //Send the message in TCP mode (Reliable)
            pClient.SendMessage(m, SendMode.Reliable);
        }
    }

    /// <summary>
    /// Send a message with all objects to spawn
    /// </summary>
    /// <param name="pClient"></param>
    public void SendAllObjectsToSpawnTo(IClient pClient)
    {
        foreach (NetworkObject networkObject in networkObjects)
            SendObjectToSpawnTo(networkObject, pClient);
    }

    #endregion

Finally, we just need to call the function SendAllObjectsToSpawnTo() when a client connects. For that, we already have a listener, so just modify the callback as below :

/// <summary>
    /// When a client connects to the DarkRift server
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ClientConnected(object sender, ClientConnectedEventArgs e)
    {
        clientsId.Add(e.Client.ID);

        //Send all objects to spawn
        SendAllObjectsToSpawnTo(e.Client);
    }

Here we are ! the server will send all necessary spawn message when a client connects ! but there is something missing to make it working ! we need to register each network object to the server.

In the NetworkObject script, just modify the Start() function to have this :

private void Start()
{
    //If we are not on the server, destroy the gameobject
    if (Equals(GameServerManager.instance, null))
    {
        Destroy(gameObject);
    }
    else
    {
        // Get the instance id of the gameobject on the server scene
        id = GetInstanceID();
        //Register with the server
        GameServerManager.instance.RegisterNetworkObject(this);
    }
}
#endregion

In fact we already have written this, you just need to uncomment the line where we call the registration method.

Now, you can try it. Run the MainServerScene and take a look to the GameServerManager into the inspector. You should see in the networkObjects list that there is one entry. It’s our ball !

What’s next ?

In the next article, we will receive the message within the client. We’ll need to create a new component name SpawnManager that will be in charge to instantiate the right game object depending to the message received !

Thanks for reading, don’t hesitate to give me your feedbacks !