# 客户端模组编写
本节将主要介绍如何制作客户端模组与Java服插件进行通信。
# 语言基础
编写中国版基岩版客户端模组需要掌握Python2.7、模组SDK。
该部分较为基础,需要开发者自行安装并学习。推荐提前安装补全库 (opens new window)。
# 项目创建
在开始代码编写之前,首先需要创建项目。
切换到插件标签页,点击新建插件。
然后我们按照团队名,插件名称来填写信息,并且勾选大厅服/游戏服。
因为我们在之前已经在Spigot插件中定义好了插件的命名空间和系统名,所以我们这里按照下方截图填写,方便后面直接和Java服通信。
创建完成后,对插件右键,打开目录。就可以看到插件的目录结构。
- behavior_packs - 行为包目录
- developer_mods - 在开服工具2.0中无用
- resource_packs - 资源包目录
- worlds - 存档(在开服工具2.0中仅用来配置行为包和资源包)
在这里,我们主要需要编写的地方就是行为包目录、资源包目录。
- 行为包主要用来存放客户端模组的代码、物品定义、实体定义等等。
- 资源包主要用来存放客户端模组的美术资源,文本资源等等。
因为developer_mods在开服工具2.0中没有用途,所以我们可以打开文件夹,将截图所示内容删除。
完成删除后,我们可以将整个testMod文件夹剪切到服务器配置中的Mod目录文件夹。
接下来,打开装有Python插件的IDEA或者PyCharm,对客户端模组进行脚本编辑。
在File->Open中复制文件路径,打开这个模组文件夹。
然后对testModBehavior
右键,将其标记为Sources Root
,这样补全库才能正常工作。
接下来,我们可以打开modConst.py
,在这里可以看到这个模组的一些常量。
ModName
代表 模组命名空间ClientSystemName
代表 模组客户端系统名
可以回顾一下Java服插件中的命名空间和客户端系统名,可以看到这它们是一一对应的。
只有在服务器和客户端通信时使用相同命名空间和系统名,通信数据才会被成功处理。
# -*- coding: utf-8 -*-
# 整个Mod的一些绑定配置
ModVersion = "1.0.0"
ModName = "testMod"
ClientSystemName = "testModBeh"
ClientSystemClsPath = "testModScript.modClientSystem.ModClientSystem"
ServerSystemName = "testModDev"
ServerSystemClsPath = "testModScript.modServerSystem.ModServerSystem"
# 引擎事件
UiInitFinishedEvent = "UiInitFinished"
接下来打开modClientSystem.py
import client.extraClientApi as clientApi
将文件顶部的代码修改为,方便正常使用补全库。
import mod.client.extraClientApi as clientApi
# 代码编写
功能需求:
- 在玩家客户端UI初始化完成时,向服务器发送TestEvent事件,参数任意。
- 监听服务器TestServerEvent,并打印信息到控制台。
会用到以下两个函数:
除此之外,还有更多的事件相关的接口,可以参考官方文档 (opens new window)。
# 向服务器发送TestEvent事件
在创建项目后的模板中,已经生成了监听UI初始化完成的事件,我们可以直接在这个事件的回调函数中向服务器通信。
直接使用NotifyToServer函数即可。发送的数据是一个Python字典。
# UI加载完成
def OnUiInitFinished(self, args):
logger.info("%s OnUiInitFinished", ModConst.ClientSystemName)
self.NotifyToServer("TestEvent", {"data": "测试数据"})
Python的类型会被转换成Java的类型,对照表如下:
Python类型 | Java类型 |
---|---|
None | null |
bool | Boolean |
int/long(-2^31到2^31-1) | Integer |
int/long(-2^63到-2^31-1,2^31到2^63-1) | Long |
int/long(2^63到2^64-1) | BigInteger |
float | Double |
str | String |
list | List<Object> |
dict(key必须为str) | Map<String, Object> |
# 监听服务器TestServerEvent事件
我们可以在客户端系统初始化时,监听这个事件并注册回调函数。在Destroy时注销监听。
def __init__(self, namespace, systemName):
ClientSystem.__init__(self, namespace, systemName)
self.mUIMgr = uiMgr.UIMgr()
self.ListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), ModConst.UiInitFinishedEvent, self, self.OnUiInitFinished)
self.ListenForEvent(ModConst.ModName, ModConst.ServerSystemName, "TestServerEvent", self, self.OnServerEvent)
def OnServerEvent(self, args):
print "OnServerEvent", args
def Destroy(self):
self.UnListenForEvent(ModConst.ModName, ModConst.ServerSystemName, "TestServerEvent", self, self.OnServerEvent)
self.UnListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), ModConst.UiInitFinishedEvent, self, self.OnUiInitFinished)
if self.mUIMgr:
self.mUIMgr.Destroy()
在这里,我们监听的命名空间,引用了ModConst中的ModName,对应Spigot插件中的命名空间testMod
。还引用了ModConst中的ServerSystemName,对应Spigot插件中的系统名testModDev
。因此这个监听函数将会正常监听来自服务器的信息。
# 部署测试
至此我们完成了客户端与服务端之间双端通信的最基础的实现。接下来将客户端模组进行部署,进入服务器测试。
找到服务器配置->游戏配置->协议服,勾选testMod。进行部署。
随后点击启动测试,进入游戏。并输入指令/apollotest
可以看到服务器控制台正常输出
客户端控制台也正常输出。
Python命令行执行:
"OnServerEvent {'msg': '\xe8\xbf\x99\xe6\x98\xaf\xe4\xb8\x80\xe6\x9d\xa1\xe6\x9d\xa5\xe8\x87\xaaJava\xe6\x9c\x8d\xe7\x9a\x84\xe6\xb6\x88\xe6\x81\xaf'}".decode("utf-8")
u"OnServerEvent {'msg': '\u8fd9\u662f\u4e00\u6761\u6765\u81eaJava\u670d\u7684\u6d88\u606f'}"
消息经过utf8解码,是我们传输的消息
← Spigot插件编写 作业 →