From e9c3a3f142766ea29582c1814e00791569bbec83 Mon Sep 17 00:00:00 2001 From: lovelyXiaoQi <1493623908@qq.com> Date: Thu, 31 Jul 2025 20:38:57 +0900 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=BF=9B=E9=98=B6=E4=BC=98=E5=8C=96=E6=95=99=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20-玩法开发/18-性能优化/代码进阶优化.md | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 mcguide/20-玩法开发/18-性能优化/代码进阶优化.md diff --git a/mcguide/20-玩法开发/18-性能优化/代码进阶优化.md b/mcguide/20-玩法开发/18-性能优化/代码进阶优化.md new file mode 100644 index 0000000..0140d0c --- /dev/null +++ b/mcguide/20-玩法开发/18-性能优化/代码进阶优化.md @@ -0,0 +1,130 @@ +--- +front: https://nie.res.netease.com/r/pic/20210728/5507b669-4c6f-4958-b5d0-b8556ab4cfb5.png +hard: 进阶 +time: 10分钟 +--- + +# ModAPI代码进阶优化 + +> 本文档介绍了一些高级的ModAPI代码优化技巧,帮助开发者们编写更高效的代码。 +> 我们将结合一些开发情景,逐一讲解优化流程 + +## 使用实体Attr实现Molang同步 + +### 背景说明 + +在开发过程中,假设我们需要给玩家添加创造飞行或鞘翅动画效果。但是翻找wiki却发现原版并没有提供相关的Molang,所以我们需要自定义以下两个Molang变量: + +``` +query.mod.ysm_is_create_flying # 是否正在创造飞行 +query.mod.ysm_is_elytra_flying # 是否正在鞘翅飞行 +``` + +### 实现方案对比 + +**不推荐的方案:** + +通过tick函数持续获取玩家状态并与客户端通信来设置Molang值 +这种方式会导致严重的性能开销,十分的不友好 + +**推荐的方案:** + +结合以下两个关键功能实现: + +1. [OnPlayerActionServerEvent](https://mc.163.com/dev/mcmanual/mc-dev/mcdocs/1-ModAPI-beta/事件/玩家.html#onplayeractionserverevent) - 用于监听玩家动作状态 +2. [实体自定义属性](https://mc.163.com/dev/mcmanual/mc-dev/mcdocs/1-ModAPI-beta/接口/实体/索引.html?catalog=1#自定义属性) - 实现Molang值的自动同步 + +### 工作原理 + +众所周知,当使用服务端的`SetAttr`接口设置属性值后,系统会自动将这些值同步到客户端 +在实体Attr文档中,我们可以找到一个关键接口`RegisterUpdateFunc`,它用于注册属性值变化时的回调函数 +这个机制就是实现实体Molang值自动同步的核心 + +### Attr同步优点 + +- 高性能、低功耗的实现方式 +- 使用游戏原生发包的Attr通信,比直接通信接口更快 +- 自动处理可见渲染范围内的同步,无需手动监听`AddPlayerCreatedClientEvent`事件 +- 适合在tick内进行多次操作,统一更新数据 + +### 代码实现 + +##### 服务端代码 + +```python +# 服务端代码实现 +ServerComp = serverApi.GetEngineCompFactory() + +class PlayerActionServerSystem(ServerSystem): + def __init__(self, namespace, systemName): + ServerSystem.__init__(self, namespace, systemName) + + def OnPlayerActionServerEvent(self, args): + # 玩家动作事件,当玩家开始/停止某些动作时触发该事件 + playerId = args["playerId"] + actionType = args["actionType"] + modAttr = ServerComp.CreateModAttr(playerId) + + # 使用鞘翅飞行/创造飞行的动作枚举值为(15,16,34,35) + if actionType == 34: + # 开始创造飞行 + modAttr.SetAttr("playerIsCreateFlying", 1) + elif actionType == 35: + # 停止创造飞行 + modAttr.SetAttr("playerIsCreateFlying", 0) + elif actionType == 15: + # 开始鞘翅飞行 + modAttr.SetAttr("playerIsElytraFlying", 1) + elif actionType == 16: + # 停止鞘翅飞行 + modAttr.SetAttr("playerIsElytraFlying", 0) +``` + +##### 客户端代码 + +```python +# 客户端代码实现 +ClientComp = clientApi.GetEngineCompFactory() +levelId = clientApi.GetLevelId() +playerId = clientApi.GetLocalPlayerId() + +# 注册自定义Molang变量 +ClientComp.CreateQueryVariable(levelId).Register("query.mod.ysm_is_create_flying", 0) +ClientComp.CreateQueryVariable(levelId).Register("query.mod.ysm_is_elytra_flying", 0) + +class PlayerActionClientSystem(ClientSystem): + def __init__(self, namespace, systemName): + ClientSystem.__init__(self, namespace, systemName) + # 注册本地玩家的属性值变化回调函数 + modAttr = ClientComp.CreateModAttr(playerId) + modAttr.RegisterUpdateFunc("playerIsCreateFlying", self.PlayerCreateFlyStateChanged) + modAttr.RegisterUpdateFunc("playerIsElytraFlying", self.PlayerElytraFlyStateChanged) + + def OnAddPlayerAOIClient(self, args): + """玩家加入游戏或进入视野时触发,注册属性值变化回调""" + pId = args["playerId"] + modAttr = ClientComp.CreateModAttr(pId) + modAttr.RegisterUpdateFunc("playerIsCreateFlying", self.PlayerCreateFlyStateChanged) + modAttr.RegisterUpdateFunc("playerIsElytraFlying", self.PlayerElytraFlyStateChanged) + + def PlayerCreateFlyStateChanged(self, args): + """创造飞行状态变化回调""" + molangVar = args["newValue"] # 属性变化后的值 + pId = args["entityId"] # 属性变化对应的实体Id + ClientComp.CreateQueryVariable(pId).Set("query.mod.ysm_is_create_flying", molangVar) + + def PlayerElytraFlyStateChanged(self, args): + """鞘翅飞行状态变化回调""" + molangVar = args["newValue"] # 属性变化后的值 + pId = args["entityId"] # 属性变化对应的实体Id + ClientComp.CreateQueryVariable(pId).Set("query.mod.ysm_is_elytra_flying", molangVar) +``` + +### 工作流程说明 + +1. 客户端为本地玩家和其他玩家注册属性值变化的回调函数 +2. 服务端通过`OnPlayerActionServerEvent`事件监测玩家的飞行状态 +3. 使用`SetAttr`设置属性值,自动同步到客户端 +4. 客户端的回调函数被触发,更新相应的Molang值 + +#### 其他性能优化教程,敬请期待...