同步官网文档8m_25d

This commit is contained in:
kwiilh
2025-08-25 18:36:29 +08:00
parent 4dc0ecf18d
commit 9e8855eeb4
5089 changed files with 8798 additions and 4799 deletions

View File

@@ -0,0 +1,362 @@
---
front: https://nie.res.netease.com/r/pic/20211104/69055361-2e7a-452f-8b1a-f23e1262a03a.jpg
hard: 进阶
time: 30分钟
---
# 挑战:自定义传送点
在本节中,我们一起来制作一个传送点模组。我们知道,在我的世界中,地形可以近似认为是无限广阔的,所以,我们在探索的过程中可能经常迷失方向,找不到回到据点的路。因此,我们可以自定义一个传送点模组。通过保存一个传送点来做到在迷路时快速回到传送点所指定的位置。
下面我们一起使用模组SDK来制作一个传送点模组。
## 创建项目
我们在我的世界开发工作台中创建一个“传送点模组”的组件然后使用编辑器“资源管理”窗格中“创建”按钮来快速创建一个Python模组模块将其命名为`TeleportPointMod`
![](./images/11.7_tp_point_server_create.png)
由于我们知道,只有服务端才能获取和控制每个玩家的位置,所以我们只需创建一个服务端系统,将其命名为`TeleportPointServerSystem`。对于每个玩家来说,客户端一般只负责屏幕的渲染和本地的一些计算,是无法直接改变玩家处于整个世界中的位置的,所以我们无需使服务端与客户端交互。因此我们无需创建客户端系统。
![](./images/11.7_tp_point_server_created.png)
创建结束后我们可以在“资源管理”窗格中看到如图的文件排布。我们将整个行为包文件夹在Python的IDE中打开以便之后的代码编写。此时的Python文件内容如下。
`modMain.py`
```python
# -*- coding: utf-8 -*-
from common.mod import Mod
@Mod.Binding(name="TeleportPointMod", version="0.0.1")
class TeleportPointMod(object):
def __init__(self):
pass
@Mod.InitServer()
def TeleportPointModServerInit(self):
pass
@Mod.DestroyServer()
def TeleportPointModServerDestroy(self):
pass
@Mod.InitClient()
def TeleportPointModClientInit(self):
pass
@Mod.DestroyClient()
def TeleportPointModClientDestroy(self):
pass
```
`TeleportPointServerSystem.py`
```python
# -*- coding: utf-8 -*-
import server.extraServerApi as serverApi
ServerSystem = serverApi.GetServerSystemCls()
class TeleportPointServerSystem(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
# ScriptTickServerEvent的回调函数会在引擎tick的时候调用1秒30帧被调用30次
def OnTickServer(self):
"""
Driven by event, One tick way
"""
pass
# 这个Update函数是基类的方法同样会在引擎tick的时候被调用1秒30帧被调用30次
def Update(self):
"""
Driven by system manager, Two tick way
"""
pass
def Destroy(self):
pass
```
## 注册服务端系统
我们知道,单纯创建了服务端系统文件是无法在主模组文件中同时将其注册的。我们手动将我们的服务端系统注册。我们在`TeleportPointModServerInit`函数中输入注册系统的方法:
```python
@Mod.InitServer()
def TeleportPointModServerInit(self):
serverApi.RegisterSystem('TeleportPointMod', 'TeleportPointServerSystem', 'Script_TeleportPointMod.TeleportPointServerSystem.TeleportPointServerSystem')
```
其中`Script_TeleportPointMod.TeleportPointServerSystem.TeleportPointServerSystem`对应着`Script_TeleportPointMod`文件夹中`TeleportPointServerSystem.py`文件的`TeleportPointServerSystem`类。这样,我们便成功注册了系统。
## 制作传送点模组的主体
传送点模组的主体部分应该都位于服务单系统中,我们只需要考虑实现的逻辑即可。
我们可以允许玩家使用多种方式来触发传送。最简单的一种便是使用聊天栏触发。我们不妨就采取这种方式来制作模组。我们可以设置一些关键词,用于传送点的设置、传送和移除,比如`tppoint set``tppoint apply``tppoint remove`。而每个玩家为其使用一个变量来保存其设置的传送点坐标的数据。为了方便保存我们可以使用一个字典来做到这一点。字典中的键为玩家的ID而值为玩家保存的传送点坐标。当玩家执行传送时我们主需要检索该玩家的ID获取字典保存的值然后将玩家的坐标设定为这个值即可。
我们依次来实现这个逻辑。
### 监听玩家的聊天栏消息
我们通过查阅文档可知,服务端的`ServerChatEvent`事件可以做到响应玩家发送聊天栏信息,于是我们为其设置事件监听。
```python
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerChatEvent", self, self.on_chat)
```
同时加入一个`on_chat`方法,用于充当回调函数。
```python
def on_chat(self, event):
pass
```
### 记录传说点
下面我们按照我们刚才的设想开始写入基本逻辑。我们读取事件数据中的`playerId``message`。它们分别是发送消息的玩家ID和所发送的消息。我们使用字符串的`startswith`方法来判定消息是否以`tppoint set`开头。如果消息以`tppoint set`开头那么就通过玩家ID创建一个`pos`引擎组件。`pos`引擎组件具备`GetFootPos`方法、`GetPos`方法和`SetPos`方法。我们可以使用`GetFootPos`方法来获取玩家脚步坐标并存入一个字典,我们不妨起名为`player_tp_cache``player_tp_cache`字典变量由于是需要在整个类中实现的,所以我们将其放在类的初始化方法里。
```python
class TeleportPointServerSystem(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerChatEvent", self, self.on_chat)
# 用来暂时缓存玩家的传送点信息,在每次重新开启一次游戏后会被重置
self.player_tp_cache = {}
def on_chat(self, event):
# 获取玩家ID
player_id = event['playerId']
# 获取聊天消息
message = event['message']
if message.startswith('tppoint set'):
pos_comp = serverApi.GetEngineCompFactory().CreatePos(player_id)
teleport_pos = pos_comp.GetFootPos()
# 保存玩家的当前坐标至字典缓存中
self.player_tp_cache[player_id] = teleport_pos
print '已设置玩家传送点'
```
### 删除传送点
依据同样的原理,我们使用字典的`pop`方法来移除一个玩家的键值对。我们加入删除传送点的逻辑。
```python
def on_chat(self, event):
# 获取玩家ID
player_id = event['playerId']
# 获取聊天消息
message = event['message']
if message.startswith('tppoint set'):
pos_comp = serverApi.GetEngineCompFactory().CreatePos(player_id)
teleport_pos = pos_comp.GetFootPos()
# 保存玩家的当前坐标至字典缓存中
self.player_tp_cache[player_id] = teleport_pos
print '已设置玩家传送点'
if message.startswith('tppoint remove'):
# 判断该玩家是否存有数据
if player_id in self.player_tp_cache:
# 弹出字典中的玩家数据
self.player_tp_cache.pop(player_id)
print '已移除玩家传送点'
else:
print '该玩家没有设置传送点'
```
### 传送至传送点
最后,我们使用`pos`引擎组件的`SetPos`方法来实现传送逻辑。
```python
def on_chat(self, event):
# 获取玩家ID
player_id = event['playerId']
# 获取聊天消息
message = event['message']
if message.startswith('tppoint set'):
pos_comp = serverApi.GetEngineCompFactory().CreatePos(player_id)
teleport_pos = pos_comp.GetFootPos()
# 保存玩家的当前坐标至字典缓存中
self.player_tp_cache[player_id] = teleport_pos
print '已设置玩家传送点'
if message.startswith('tppoint remove'):
# 判断该玩家是否存有数据
if player_id in self.player_tp_cache:
# 弹出字典中的玩家数据
self.player_tp_cache.pop(player_id)
print '已移除玩家传送点'
else:
print '该玩家没有设置传送点'
if message.startswith('tppoint apply'):
pos_comp = serverApi.GetEngineCompFactory().CreatePos(player_id)
# 判断该玩家是否存有数据
if player_id in self.player_tp_cache:
teleport_pos = self.player_tp_cache[player_id]
# 传送玩家
pos_comp.SetPos(teleport_pos)
print '已应用玩家传送点'
else:
print '该玩家没有设置传送点'
```
这样,我们便完成了传送逻辑的编写。额外地,我们还可以通过`msg`组件来为玩家显示消息提示,展示设置、传送或移除成功的提示。我们可以修改如下:
```python
def on_chat(self, event):
# 获取玩家ID
player_id = event['playerId']
# 获取聊天消息
message = event['message']
if message.startswith('tppoint set'):
pos_comp = serverApi.GetEngineCompFactory().CreatePos(player_id)
teleport_pos = pos_comp.GetFootPos()
# 保存玩家的当前坐标至字典缓存中
self.player_tp_cache[player_id] = teleport_pos
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "已设置传送点")
print '已设置玩家传送点'
if message.startswith('tppoint remove'):
# 判断该玩家是否存有数据
if player_id in self.player_tp_cache:
# 弹出字典中的玩家数据
self.player_tp_cache.pop(player_id)
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "已移除传送点")
print '已移除玩家传送点'
else:
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "请先设置传送点")
print '该玩家没有设置传送点'
if message.startswith('tppoint apply'):
pos_comp = serverApi.GetEngineCompFactory().CreatePos(player_id)
# 判断该玩家是否存有数据
if player_id in self.player_tp_cache:
teleport_pos = self.player_tp_cache[player_id]
# 传送玩家
pos_comp.SetPos(teleport_pos)
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "已传送至传送点")
print '已应用玩家传送点'
else:
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "请先设置传送点")
print '该玩家没有设置传送点'
```
我们可以进入游戏查看传送和消息提示情况。
![](./images/11.7_in-game.png)
我们可以看到,传送和消息都和我们所设置的一样正常运作!
我们最后放出完整的代码供大家参考,`modMain.py`如下:
```python
# -*- coding: utf-8 -*-
from mod.common.mod import Mod
import mod.server.extraServerApi as serverApi
@Mod.Binding(name="TeleportPointMod", version="0.0.1")
class TeleportPointMod(object):
def __init__(self):
pass
@Mod.InitServer()
def TeleportPointModServerInit(self):
serverApi.RegisterSystem('TeleportPointMod', 'TeleportPointServerSystem', 'Script_TeleportPointMod.TeleportPointServerSystem.TeleportPointServerSystem')
@Mod.DestroyServer()
def TeleportPointModServerDestroy(self):
pass
@Mod.InitClient()
def TeleportPointModClientInit(self):
pass
@Mod.DestroyClient()
def TeleportPointModClientDestroy(self):
pass
```
`TeleportPointServerSystem.py`如下:
```python
# -*- coding: utf-8 -*-
import mod.server.extraServerApi as serverApi
from mod.server.system.serverSystem import ServerSystem
ServerSystem = serverApi.GetServerSystemCls()
class TeleportPointServerSystem(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerChatEvent", self, self.on_chat)
# 用来暂时缓存玩家的传送点信息,在每次重新开启一次游戏后会被重置
self.player_tp_cache = {}
def on_chat(self, event):
# 获取玩家ID
player_id = event['playerId']
# 获取聊天消息
message = event['message']
if message.startswith('tppoint set'):
pos_comp = serverApi.GetEngineCompFactory().CreatePos(player_id)
teleport_pos = pos_comp.GetFootPos()
# 保存玩家的当前坐标至字典缓存中
self.player_tp_cache[player_id] = teleport_pos
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "已设置传送点")
print '已设置玩家传送点'
if message.startswith('tppoint remove'):
# 判断该玩家是否存有数据
if player_id in self.player_tp_cache:
# 弹出字典中的玩家数据
self.player_tp_cache.pop(player_id)
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "已移除传送点")
print '已移除玩家传送点'
else:
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "请先设置传送点")
print '该玩家没有设置传送点'
if message.startswith('tppoint apply'):
pos_comp = serverApi.GetEngineCompFactory().CreatePos(player_id)
# 判断该玩家是否存有数据
if player_id in self.player_tp_cache:
teleport_pos = self.player_tp_cache[player_id]
# 传送玩家
pos_comp.SetPos(teleport_pos)
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "已传送至传送点")
print '已应用玩家传送点'
else:
msg_comp = serverApi.GetEngineCompFactory().CreateMsg(player_id)
msg_comp.NotifyOneMessage(player_id, "请先设置传送点")
print '该玩家没有设置传送点'
def Destroy(self):
pass
```