DarkRift 2 Tutorial for Unity 3D – Part 10 – Get spawn messages from server

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

Tell the client to listen messages

First thing to perform, is to update our client to tell him to listen when a message is arrived. We will tell him to connect in background instead of auto-connect (on the inspector). Why ? Just to show you that we can connect easely with code. There is two way of connecting :

  • Client.Connect() : Connect to the server, but keep “freezed” until the connection is made. It must be used when a connection to the server is mandatory or when you need to be sure that the connection is made.
  • Client.ConnectInBackground() : Performs the connection asynchronously. Means that the game won’t freeze, even if the connection is not made.

Disable the auto connect in the client :

So, let’s update the ClientManager script with this code :

void Start()
{        
    //////////////////
    /// Load the game scene
    SceneManager.LoadScene("MainGameScene", LoadSceneMode.Additive);

    //////////////////
    /// Suscribe to events
    clientReference.MessageReceived += SpawnGameObjects;

    //////////////////
    /// Connect to the server manually
    clientReference.ConnectInBackground(
        IPAddress.Parse("127.0.0.1"),
        4296,
        DarkRift.IPVersion.IPv4,
        null
        );

}

I’ve put the server adress without variables, but in your game, you should use another way. That’s only for the example.
As you can see, we’ve added a listener on message received called SpawnGameObjects. Let’s now create this function !

Create the spawn function

ok, what wee need to do ? i will sum up this function feature :

  • Check if the received message is tagged as SPAWN_OBJECT (see Part 9)
  • Load the specified game object
  • Instantiate him at the specified position

And that’s all. Are you ready ? … but wait a minute. How can i know what is the desired ressource ? Yes, you’re right, at this point we can’t know. We need to create our NetworkDictionnary !

Network Game Object Dictionnary

The dictionnary will be useful to determines wich resource is focus for a specified ID. He will looks like this :

IDResourcePath
0“BouncyBall”
1“MyFolder/AnotherGameObjectToSpawn”
2“OnMoreGameObjectToSpawn”

As said before, for loading object, we’ll use the resource folder wich is a special folder within unity3D (see this for more information). I don’t encourage to use this in a production environnement ! But for prototypes, it’s ok.

Let’s create a new script called NetworkObjectDictionnary in the Scripts/Network folder :

Here is the code :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class NetworkObjectDictionnary
{
    /// <summary>
    /// Dictionnary that contains all gameobjects spawnable
    /// </summary>
    private static readonly Dictionary<int, string> dictionnary = new Dictionary<int, string>
    {
        {1, "BouncyBall" } 
    };

    /// <summary>
    /// Returns the specified object name 
    /// </summary>
    /// <param name="pID"></param>
    /// <returns></returns>
    public static string GetResourcePathFor(int pID)
    {
        string objectName;
        dictionnary.TryGetValue(pID, out objectName);
        return objectName;
    }
}

The dictionnary cannot be modified during run time, that’s why we specify the readonly keyword. We create a function to get the resource path for a specific if (GetResourcePathFor)

Doing it with a function enable us to modify the way how the path is retrieved whitout modifyng everywhere the dictionnary is used.

Finally, just need to create the Resources folder and add our BouncyBall as a prefab (you will need to open the MainGameScene) :

Perfect ! we propably may now writing our SpawnFunction ? not yet, because, if you take a look on the message receveid, we only have 2 informations :

  • NetworkID : wich is the network identifier
  • Position : Position where the object has to be spwaned

We are missing one information : the ressourceID wich is defined in our dictionnary. So, i think you guessed, we need to update our message model and the way we send the message.

Update the server message

Let’s firstly update our message spawn model wich contains the data structure of the message. The script to update is SpawnMessageModel :

We just will add a new property called RessourceID :

...

/// <summary>
/// Resource to spawn
/// </summary>
public int resourceID { get; set; }

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

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

Now, we need to add this property into the NetworkObject Script. This property will be manually filled within the inspector :

/// <summary>
/// Resource identifier for the spawner
/// </summary>
public int resourceId;

#region Unity Callbacks

private void Start()
{
	//If we are not on the server and id is not set, destroy the gameobject
	if (Equals(GameServerManager.instance, null) && id == 0)
	{
		Destroy(gameObject);
	}
	else if(!Equals(GameServerManager.instance, null))
	{
		// Get the instance id of the gameobject on the server scene
		id = GetInstanceID();
		//Register with the server
		GameServerManager.instance.RegisterNetworkObject(this);
		//Test for resource ID
		if (resourceId == 0)
			throw new System.Exception(string.Format("There is no resource id for {0} gameobject", name));
	}
}
#endregion

Just look on the Start() function, i added a check to inform us if we forget to set the resourceId for a NetworkObject. So let’s do this now. Open the prefab and set the resourceID to 1 :

And now, we’ll simply modifiy the SendObjectToSpawnTo function within the GameServerManager script :

/// <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,
        resourceID = pNetworkObject.resourceId,
        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);
    }
}

The spawn function (finally)

Here we are, we now can write our function within the ClientManager script. There is nothing complicated with this and the code speaks by itself :

/// <summary>
/// Spawn object if message received is tagged as SPAWN_OBJECT
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SpawnGameObjects(object sender, MessageReceivedEventArgs e)
{
	if (e.Tag == NetworkTags.InGame.SPAWN_OBJECT)
	{
		//Get message data
		SpawnMessageModel spawnMessage = e.GetMessage().Deserialize<SpawnMessageModel>();

		//Spawn the game object
		string resourcePath = NetworkObjectDictionnary.GetResourcePathFor(spawnMessage.resourceID);
		GameObject go = Resources.Load(resourcePath) as GameObject;
		go.GetComponent<NetworkObject>().id = spawnMessage.networkID;
		Instantiate(go, new Vector3(spawnMessage.x, spawnMessage.y, 0), Quaternion.identity);
	}
}

Build server and try the client

Let’s try our implementation. Here is how you need to process :

  1. Build the server by selecting these 2 scenes : MainServerScene and MainGameScene
  2. Launch the exe previously builded
  3. Open your client scene in unity : MainClientScene and start the game.

If you need more information about how to build, see the part

You should see the ball appears in the scene ! That’s cool but the position of the ball should be random because as the ball bounce in the server scene, the spawn message will send the current position of the ball. That’s why when you lauch the game several time, the ball is not spawned on the same position !

What’s next ?

On the next article, we’ll now synchronize the position of the ball with the server position. Exciting, isn’t it ?

Thanks for reading.

Posted in Dark Rift 2 and tagged , .

Leave a Reply

Your email address will not be published. Required fields are marked *