Files
boybook 760c2dd9ad 2.6
2025-12-01 20:59:16 +08:00

160 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 作业
<iframe src="https://cc.163.com/act/m/daily/iframeplayer/?id=64818c70c31a9c0f360dc5c0" width="800" height="600" allow="fullscreen"/>
学习了服务端与客户端之间的基本通信方法之后我们可以尝试来完成一个使用模组SDK来实现的全息字的功能。
## 要求
在玩家加入游戏之后,在玩家客户端的指定位置生成一个文字面板(全息字)。
整个通信流程应该如下图所示:
```mermaid
sequenceDiagram
客户端->>服务端: 客户端加载完毕
服务端-->>客户端: 生成文字面板的参数
客户端->>服务端: 生成文字面板,返回生成是否成功
```
> **为什么需要在客户端加载完毕的时候主动通知服务端而不是直接监听服务端的PlayerJoinEvent**
>
> 因为在PlayerJoinEvent触发的时候基岩版客户端可能还没有完全加载完毕。
>
> 在这个时候给客户端发送事件,有可能客户端模组还没有初始化完成,无法处理请求。
## 实现过程
### Spigot插件
首先新建Spigot项目操作步骤和之前一致。这里新建了一个名为TutorialHologram的项目并配置pom.xml添加SpigotMaster插件的maven依赖。
在开始编写插件之前,我们预先定义好,客户端的命名空间为`testHologram`,因此,根据[开发规范](https://mc.163.com/dev/mcmanual/mc-dev/mcguide/27-%E6%89%8B%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%B8%B8%E6%88%8F/%E8%AF%BE%E7%A8%8B5%EF%BC%9A%E6%8F%92%E4%BB%B6%E6%95%99%E5%AD%A6/%E7%AC%AC1%E8%8A%82%EF%BC%9A%E5%AE%98%E7%BD%91%E6%8F%92%E4%BB%B6%E8%A7%84%E8%8C%83.html?catalog=1),客户端系统名应为`testHologramBeh`,服务端系统名应为`testHologramDev`
- 客户端通知加载完毕的事件定义为`ClientLoadFinishEvent`
- 传输生成文字面板的参数的事件定义为`HologramParameterEvent`
- 返回生成结果的事件定义为`HologramGeneratedEvent`
推荐将这部分命名空间和事件名定义为常量。
> 教程为了方便将所有代码都写入主类,在实际开发过程中,不推荐将所有代码写入一个类中!!
```java
private final String NAMESPACE = "testHologram";
private final String CLIENT_SYSTEM_NAME = "testHologramBeh";
private final String SERVER_SYSTEM_NAME = "testHologramDev";
private final String CLIENT_LOAD_FINISH_EVENT = "ClientLoadFinishEvent";
private final String HOLOGRAM_PARAMETER_EVENT = "HologramParameterEvent";
private final String HOLOGRAM_GENERATED_EVENT = "HologramGeneratedEvent";
```
首先,生成一个文字面板,需要提供这个文字面板的坐标,文本的信息,我们在作业中可以简单地硬编码坐标的位置和文本的内容。例如坐标为`(0,100,0)`,内容为`这是一个文字面板`
在监听ClientLoadFinishEvent后发送文字面板参数信息。同时监听HologramGeneratedEvent输出结果。
```java
@Override
public void onEnable() {
spigotMaster = (SpigotMaster) Bukkit.getPluginManager().getPlugin("SpigotMaster");
spigotMaster.listenForEvent(NAMESPACE, CLIENT_SYSTEM_NAME, CLIENT_LOAD_FINISH_EVENT, (player, map) -> {
Map<String, Object> data = new HashMap<>();
data.put("x", 0);
data.put("y", 100);
data.put("z", 0);
data.put("text", "这是一个文字面板");
spigotMaster.notifyToClient(player, NAMESPACE, SERVER_SYSTEM_NAME, HOLOGRAM_PARAMETER_EVENT, data);
});
spigotMaster.listenForEvent(NAMESPACE, CLIENT_SYSTEM_NAME, HOLOGRAM_GENERATED_EVENT, (player, map) -> {
boolean success = (boolean) map.get("suc");
getLogger().info("生成全息字 " + player.getName() + " " + success);
});
}
```
在HologramGeneratedEvent中我们可以监听来自客户端的事件并从中获取suc的值来判断生成是否成功可以继续拓展插件的功能。
这样我们的Spigot插件部分的代码就编写完成了可以构建后装入服务器。
### 客户端模组
和之前的操作一样新建一个插件团队名称填写test模组名填写hologram勾选游戏服和大厅服。
生成完成后打开插件文件夹,删除`developer_mods`文件夹里的内容,并将整个插件文件夹复制到部署设置的模组目录中。
#### 文字面板的生成
文字面板的API文档 [点我](https://mc.163.com/dev/mcmanual/mc-dev/mcdocs/1-ModAPI/%E6%8E%A5%E5%8F%A3/%E7%89%B9%E6%95%88/%E6%96%87%E5%AD%97%E9%9D%A2%E6%9D%BF.html?catalog=1)
通过文档的查阅,我们需要先后
1. 创建文字面板
2. 设置文字面板的位置
3. 如有需要的话 返回服务器文字面板的ID
#### 常量定义
之前在Spigot服插件编写的过程中已经定义了一些事件名常量方便起见我们也需要在客户端模组的常量文件中定义相同的常量。
`hologramConst.py`文件中定义下列变量
```python
ClientLoadFinishEvent = "ClientLoadFinishEvent"
HologramParameterEvent = "HologramParameterEvent"
HologramGeneratedEvent = "HologramGeneratedEvent"
```
#### 功能实现
首先在OnUiInitFinished函数中向服务端系统发送事件。
```python
# UI加载完成
def OnUiInitFinished(self, args):
logger.info("%s OnUiInitFinished", HologramConst.ClientSystemName)
self.NotifyToServer(HologramConst.ClientLoadFinishEvent, {})
```
接下来监听来自服务端系统的`HologramParameterEvent`事件,并设置回调函数。获取坐标,创建文字面板。
部分代码如下
```python
def __init__(self, namespace, systemName):
ClientSystem.__init__(self, namespace, systemName)
self.mUIMgr = uiMgr.UIMgr()
self.mTextBoardComp = clientApi.GetEngineCompFactory().CreateTextBoard(clientApi.GetLevelId())
self.ListenForEvent(HologramConst.ModName, HologramConst.ServerSystemName, HologramConst.HologramParameterEvent, self, self.OnHologramParameter)
self.ListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), HologramConst.UiInitFinishedEvent, self, self.OnUiInitFinished)
def OnHologramParameter(self, args):
x = args["x"]
y = args["y"]
z = args["z"]
text = args["text"]
boardId = self.mTextBoardComp.CreateTextBoardInWorld(text, (1, 1, 1, 1), (0.5, 0.5, 0.5, 0.1), True)
if not boardId:
self.NotifyToServer(HologramConst.HologramGeneratedEvent, {"suc": False})
return
self.mTextBoardComp.SetBoardPos(boardId, (x, y, z))
self.NotifyToServer(HologramConst.HologramGeneratedEvent, {"suc": True, "boardId": boardId})
def Destroy(self):
self.UnListenForEvent(HologramConst.ModName, HologramConst.ServerSystemName, HologramConst.HologramParameterEvent, self, self.OnHologramParameter)
self.UnListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), HologramConst.UiInitFinishedEvent, self, self.OnUiInitFinished)
if self.mUIMgr:
self.mUIMgr.Destroy()
```
OnHologramParameter函数会解析来自服务端的数据在指定xyz坐标创建文字面板如果失败返回信息中suc是False。如果成功suc为True并附带文字面板的id。
## 部署测试
前往服务器配置协议服勾选刚刚编写的testHologram模组重新部署后进入游戏进行测试。
![](./images/16.png)
进入游戏后,传送到坐标(0,100,0)附近,可以看到我们生成的文字面板。
![](./images/17.png)