Generic selectors
Exact matches only
Search in title
Search in content
Search in project

Server to Client Messages

Sending a Message from the Server to the Client

Sending a message from the Server to the Client is much easier than the opposite direction and is very useful for getting information to a player. Messages that are sent to the client are best sent as a TargetedExtensionMessage which means the message is only sent to the specified player.

The instructions below explain in steps how to set up the Message on the Server and then how to catch it in Unity and retrieve the information. An example from the Crafting Grid system is provided at the bottom to give a bit more direction.

1) Creating a Properties Map

TargetedExtensionMessages use a Java HashMap to contain all the data that is going to be sent to the Client in the Message. The Map uses String for the Keys and Serializable for the Values. This is easily created by writing:

  Map<String, Serializable> props = new HashMap<String, Serializable>();

2) Setting the Message Sub-Type

The Message being sent now needs a Sub-Type so the Client can differentiate it between other messages and it can be handled by the right function. The subtype is just a string property added to the map with the key “ext_msg_subtype”, and needs to be unique between all other TargetedExtensionMessages. For example:

  props.put("ext_msg_subtype", "put_your_subtype_here");

3) Adding Properties to the Map

After the Sub-Type has been set any other properties can be added to the Properties Map. Note that the data added needs to be of a standard type (integers, strings, floats, booleans etc.). Each piece of data needs a unique key defined as a string for example:

  props.put("test_num", 5);

4) Sending the Message

When the message has all the needed data added to the Properties Map it can be sent by using:

  TargetedExtensionMessage playerMsg = new TargetedExtensionMessage(WorldManagerClient.MSG_TYPE_EXTENSION, playerOid, playerOid, false, props);
  Engine.getAgent().sendBroadcast(playerMsg);

Where the playerOid is the OID of the player the message is going to be sent to and props is the PropertyMap defined above.

5) Creating the Message Handler in Unity

Once the message is being sent from the Server, code needs to be added to Unity to pick up the Message and process it. The message handling function needs to return void and have one parameter: Dictionary<string, object>. It will end up looking like:

  public void HandleMessage(Dictionary<string, object> props) {
  

Inside the function you can get the properties from the message by using the same keys as you specified on the server. You will need to cast the value though. For example:

  int someNumber = (int)props["test_num"];

From here you can do whatever you need to do with the data from the message.

6) Registering the Message Handler

The final step is to register the Message Handler created in step 5. This is simply done by linking up the message sub type from step 2 with the function name from step 5 by adding code like:

  NetworkAPI.RegisterExtensionMessageHandler("put_your_subtype_here", HandleMessage);

This line of code generally should go in the Start() function of your class so the Message Handler is registered as soon as the script is loaded by Unity.

Testing

All of the code on both the server and the client is now in place and the system can be tested. The agis.jar will need to be rebuilt with your server code changes and the server restarted. It’s a good idea to add a Debug.Log() at the top of the Message handler (see step 5) to write out that it has received the message.

Example: Sending a Message to a Player when they put an Item in the Crafting Grid

The example covered here is known as the Crafting Grid Response Message which is sent to a player when the player has placed an item in the Crafting Grid and the server has worked out whether or not what they player has placed in the grid will create an item. It can be found in the CraftingPlugin.java file (in the CraftingGridUpdatedHook) on the server and in the Crafting.cs script in Unity.

Server Code

  
  // Step 1: Creating the Map
  Map<String, Serializable> props = new HashMap<String, Serializable>();
  // Step 2: Setting the message subtype. Setting it to 'CraftingGridMsg'
  // this will be referenced in the client script
  props.put("ext_msg_subtype", "CraftingGridMsg");
  // Step 3: Adding the properties. In this case we change the data being sent 
  // depending on whether a recipe was found
  if (foundRecipe != null) {
      props.put("recipeID", foundRecipe.getID());
      props.put("recipeName", foundRecipe.getName());
      props.put("recipeItem", foundRecipe.getRecipeItemId());
      props.put("resultItem", foundRecipe.getResultItemId());
  } else {
      props.put("recipeID", -1);
      props.put("recipeName", "");
      props.put("recipeItem", -1);
      props.put("resultItem", -1);
  }
  
  // Step 4: Send the message. Use the playerOid to tell the system who the message is going to.			
  TargetedExtensionMessage playerMsg = new TargetedExtensionMessage(WorldManagerClient.MSG_TYPE_EXTENSION, playerOid, playerOid, false, props);
  Engine.getAgent().sendBroadcast(playerMsg);
  

Client (Unity) Code

The start function. The … means other code that isn’t relevant.:

  void Start() {
      ...
      
      // Step 6: Listen for messages from the server. 
      // Using 'CraftingGridMsg' that was set as the ext_msg_subtype in step 2.
      NetworkAPI.RegisterExtensionMessageHandler("CraftingGridMsg", HandleCraftingGridResponse);
      
      ...
  }
  

The Message Handler:

  // Step 5: The message handler class. Gets the props from the message then updates 
  // some local variables and sends an event out
  public void HandleCraftingGridResponse(Dictionary<string, object> props) {
      recipeID = (int)props["recipeID"];
      recipeName = (string)props["recipeName"];
      recipeItemID = (int)props["recipeItem"];
      resultItemID = (int)props["resultItem"];
      
      if (resultItemID != -1) {
          resultItem = GetComponent<Inventory>().GetItemByTemplateID(resultItemID);
      } else {
          resultItem = null;
      }
      if (recipeItemID != -1) {
          recipeItem = GetComponent<Inventory>().GetItemByTemplateID(recipeItemID);
      } else {
          recipeItem = null;
      }
      
      string[] args = new string[1];
      EventSystem.DispatchEvent("CRAFTING_GRID_UPDATE", args);
  }