服务器到客户端訊息
从服务器向客户端发送消息
从服务器向客户端发送消息要比相反方向容易得多,并且对于向玩家获取信息非常有用。发送到客户端的消息最好作为TargetedExtensionMessage发送,这意味着消息仅发送到指定的播放器。
下面的说明分步说明如何在服务器上设置消息,然后如何在Unity中捕获它并检索信息。底部提供了Crafting Grid系统的一个示例,以提供更多方向。
1)创建属性映射(Properties Map)
TargetedExtensionMessages使用Java HashMap来包含将在Message中发送到客户端的所有数据。 Map使用String表示Keys,Serializable表示值。通过编写可以轻松创建:
Map<String, Serializable> props = new HashMap<String, Serializable>();
2)设置消息子类型
现在发送的消息需要一个子类型,因此客户端可以在其他訊息之间区分它,它可以由正确的功能处理。子类型只是一个字符串属性,使用键“ext_msg_subtype”添加到Map中,并且在所有其他TargetedExtensionMessages之间需要是唯一的。例如:
props.put("ext_msg_subtype", "put_your_subtype_here");
3)向Map添加属性
设置Sub-Type后,可以将任何其他属性添加到Properties Map中。请注意,添加的数据必须是标准类型(整数,字符串,浮点数,布尔值等)。每条数据都需要一个唯一的键定义为字符串,例如:
props.put("test_num", 5);
4)发送消息
当訊息将所有需要的数据添加到属性映射(Properties Map)时,可以使用以下命令发送:
TargetedExtensionMessage playerMsg = new TargetedExtensionMessage(WorldManagerClient.MSG_TYPE_EXTENSION, playerOid, playerOid, false, props); Engine.getAgent().sendBroadcast(playerMsg);
其中playerOid是播放器的OID,消息将被发送到,props是上面定义的PropertyMap。
5)在Unity中创建消息处理程序
从服务器发送消息后,需要将代码添加到Unity以获取消息并对其进行处理。消息处理函数需要返回void并有一个参数:Dictionary <string,object>。最终看起来像:
public void HandleMessage(Dictionary<string, object> props) {
在函数内部,您可以使用服务器上指定的相同密钥从消息中获取属性。您需要投射(cast the value)该值。例如:
int someNumber = (int)props["test_num"];
从这里,您可以对消息中的数据执行任何操作。
6)注册消息处理程序
最后一步是注册在步骤5中创建的訊息处理程序(Message Handler) 。这可以通过添加以下代码来完成:将步骤2中的消息子类型与步骤5中的函数名称链接起来:
NetworkAPI.RegisterExtensionMessageHandler("put_your_subtype_here", HandleMessage);
这行代码通常应该放在类的Start()函数中,以便在Unity加载脚本后立即注册Message Handler。
测试
服务器和客户端上的所有代码现在都已就绪,系统可以进行测试。需要在重新启动服务器代码并重新启动服务器的情况下重建agis.jar。最好在Message处理程序的顶部添加一个Debug.Log()(参见步骤5),写出它已收到消息。
示例:将一个项目放入Crafting Grid中时向其发送消息
此处介绍的示例称为Crafting Grid Response Message,当玩家在Crafting Grid中放置一个项目并且服务器确定他们的玩家是否在网格中放置了什么项目时,该消息将发送给玩家。它可以在服务器上的CraftingPlugin.java文件(在CraftingGridUpdatedHook中)和Unity中的Crafting.cs脚本中找到。
服务器代码
// 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);
客户端(Unity)代码
启动功能。 ……意味着其他不相关的代码:
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); }