组件调用
上一节我们学了事件系统——事件告诉你「发生了什么」。但光知道发生了什么还不够,我们需要做出改变:给玩家物品、修改血量、传送位置、播放特效……这些都要靠组件。
事件 = 监听游戏中的变化;组件 = 操作游戏中的数据。
你将学到
- 组件的创建方式:
GetEngineCompFactory().CreateXxx(entityId) - 常用服务端组件(物品、属性、位置、方块、游戏规则)
- 常用客户端组件(模型、特效、相机)
- 组件中的 Get 和 Set 方法
- 完整实战:玩家加入时设置血量和给予初始物品
什么是组件
组件是引擎封装好的功能接口集合。每个组件负责一个领域:
| 组件 | 职责 | 举例 |
|---|---|---|
| Item 组件 | 物品操作 | 给予物品、获取背包、修改耐久 |
| Attr 组件 | 属性操作 | 获取/设置血量、速度、攻击力 |
| Pos 组件 | 位置操作 | 获取/设置坐标、传送 |
| Dimension 组件 | 维度操作 | 切换维度、传送到下界 |
| Block 组件 | 方块操作 | 获取方块信息、放置/破坏方块 |
| Game 组件 | 游戏规则 | 设置游戏模式、执行命令 |
| Model 组件 | 模型渲染 | 切换模型、播放动画(客户端) |
| Particle 组件 | 粒子特效 | 播放/停止粒子(客户端) |
创建组件
所有组件通过工厂方法创建:
python
# 服务端
import mod.server.extraServerApi as serverApi
comp = serverApi.GetEngineCompFactory().CreateXxx(entityId)
# 客户端
import mod.client.extraClientApi as clientApi
comp = clientApi.GetEngineCompFactory().CreateXxx(entityId)其中 CreateXxx 中的 Xxx 就是组件名称。entityId 是你要操作的实体 ID。
常见的工厂方法
| 工厂方法 | 所属端 | 说明 |
|---|---|---|
CreateItem(entityId) | 服务端 | 物品/背包操作 |
CreateAttr(entityId) | 两端 | 引擎属性(血量、速度等) |
CreateModAttr(entityId) | 两端 | 自定义属性(自动同步,见 S2) |
CreatePos(entityId) | 服务端 | 位置和坐标 |
CreateDimension(entityId) | 服务端 | 维度切换 |
CreateBlockInfo(levelId) | 服务端 | 方块信息查询 |
CreateGame(levelId) | 服务端 | 游戏规则和命令 |
CreateModel(entityId) | 客户端 | 模型渲染 |
CreateParticle(entityId) | 客户端 | 粒子特效 |
CreateCamera(entityId) | 客户端 | 相机控制 |
levelId 是什么
部分组件(如方块、游戏规则)不针对某个实体,而是针对整个世界。此时传入 levelId:
python
levelId = serverApi.GetLevelId()
comp = serverApi.GetEngineCompFactory().CreateGame(levelId)组件的 Get 和 Set
大部分组件都遵循 Get + Set 的模式:
python
# 获取玩家当前血量
comp = serverApi.GetEngineCompFactory().CreateAttr(playerId)
health = comp.GetAttrValue(0) # 0 = AttrType.HEALTH
print "当前血量: %s" % health
# 设置玩家血量为 10
comp.SetAttrValue(0, 10) # 设置血量为 10AttrType 枚举
血量、速度、攻击力等属性通过数值常量区分:
| 值 | 属性 | 范围 |
|---|---|---|
0 | 生命值(HEALTH) | 0~20 |
1 | 移动速度(SPEED) | 0~正无穷 |
2 | 攻击力(DAMAGE) | 1~正无穷 |
4 | 饥饿值(HUNGER) | 0~20 |
5 | 饱和度(SATURATION) | 0~20 |
6 | 伤害吸收(ABSORPTION) | 0~16 |
12 | 护甲值(ARMOR) | — |
完整枚举参见 API 枚举值文档。
常用服务端组件详解
Item 组件——物品操作
python
comp = serverApi.GetEngineCompFactory().CreateItem(playerId)| 方法 | 说明 |
|---|---|
SpawnItemToPlayerInv(itemDict, playerId) | 给予玩家物品 |
GetPlayerItem(posType, slotPos) | 获取玩家指定槽位的物品 |
SetPlayerAllItems(itemsDictMap) | 批量设置玩家背包 |
GetEntityItem(posType, slotPos) | 获取生物指定槽位的物品 |
itemDict 格式:
python
itemDict = {
"itemName": "minecraft:diamond_sword", # 物品标识符
"count": 1, # 数量
"auxValue": 0 # 附加值
}
comp.SpawnItemToPlayerInv(itemDict, playerId)Pos 组件——位置操作
python
comp = serverApi.GetEngineCompFactory().CreatePos(entityId)| 方法 | 说明 |
|---|---|
GetPos() | 获取实体坐标,返回 (x, y, z) |
GetFootPos() | 获取实体脚底坐标 |
SetPos(pos) | 设置实体坐标(传送) |
SetFootPos(pos) | 设置实体脚底坐标 |
python
# 获取玩家位置
pos = comp.GetPos()
print "位置: %s, %s, %s" % (pos[0], pos[1], pos[2])
# 传送到坐标 (100, 70, 200)
comp.SetPos((100, 70, 200))Game 组件——游戏规则和命令
python
levelId = serverApi.GetLevelId()
comp = serverApi.GetEngineCompFactory().CreateGame(levelId)| 方法 | 说明 |
|---|---|
SetGameRulesInfoServer(rulesDict) | 设置游戏规则 |
SetCommand(command, playerId=None) | 执行命令 |
python
# 执行命令:给所有玩家 10 个绿宝石
comp.SetCommand("/give @a emerald 10")
# 设置游戏规则
comp.SetGameRulesInfoServer({
"keep_inventory": True,
"mob_griefing": False
})Dimension 组件——维度传送
python
comp = serverApi.GetEngineCompFactory().CreateDimension(entityId)| 方法 | 说明 |
|---|---|
ChangePlayerDimension(dimensionId, pos) | 传送玩家到指定维度和坐标 |
ChangeEntityDimension(dimensionId, pos) | 传送非玩家实体(不能用于玩家) |
玩家 vs 实体
传送玩家必须用 ChangePlayerDimension,传送非玩家实体用 ChangeEntityDimension。两者不可互换。
常用客户端组件
Camera 组件——相机控制
python
comp = clientApi.GetEngineCompFactory().CreateCamera(playerId)可以锁定相机角度、设置远近裁剪面、添加相机运动器等。
Model 组件——模型操作
python
comp = clientApi.GetEngineCompFactory().CreateModel(entityId)可以切换实体模型、设置材质、控制动画播放。
Particle 组件——粒子特效
python
comp = clientApi.GetEngineCompFactory().CreateParticle(entityId)可以创建和控制原版粒子特效。
客户端组件只能在 ClientSystem 中使用
和事件一样,客户端组件只在客户端生效。不要在 ServerSystem 中调用 clientApi 的组件。
实战:玩家加入时设置属性和给予物品
将事件(S3)和组件(本节)结合起来——监听玩家加入事件,设置初始血量并给予起始装备:
python
# -*- coding: utf-8 -*-
import mod.server.extraServerApi as serverApi
ServerSystem = serverApi.GetServerSystemCls()
class TomatoIslandServerSystem(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
self.ListenEvents()
def ListenEvents(self):
self.ListenForEvent(
serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"AddServerPlayerEvent",
self,
self.OnPlayerJoin
)
def OnPlayerJoin(self, args):
playerId = args["id"]
# 1. 设置最大血量为 40(20 颗心)
attrComp = serverApi.GetEngineCompFactory().CreateAttr(playerId)
attrComp.SetAttrMaxValue(0, 40) # 0 = HEALTH
attrComp.SetAttrValue(0, 40) # 回满血
# 2. 给予初始装备
itemComp = serverApi.GetEngineCompFactory().CreateItem(playerId)
itemComp.SpawnItemToPlayerInv(
{"itemName": "minecraft:diamond_sword", "count": 1, "auxValue": 0},
playerId
)
itemComp.SpawnItemToPlayerInv(
{"itemName": "minecraft:bread", "count": 16, "auxValue": 0},
playerId
)
# 3. 打印日志
posComp = serverApi.GetEngineCompFactory().CreatePos(playerId)
pos = posComp.GetPos()
print "====== 玩家 %s 加入,位置: %s ======" % (playerId, pos)
def Destroy(self):
self.UnListenForEvent(
serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"AddServerPlayerEvent",
self,
self.OnPlayerJoin
)测试
- 运行游戏,进入存档
- 检查血条——20 颗心(最大血量 40)
- 检查背包——钻石剑 + 16 个面包
- 查看日志——输出玩家 ID 和出生位置
事件 + 组件 = Mod 开发范式
到这里你已经掌握了 Mod SDK 的核心开发范式:
监听事件(知道发生了什么)
│
▼
在回调函数中调用组件(做出改变)
│
▼
游戏状态更新所有的 Mod 逻辑都是这个模式的变体:
| 需求 | 监听什么事件 | 调用什么组件 |
|---|---|---|
| 玩家加入时给装备 | AddServerPlayerEvent | CreateItem → SpawnItemToPlayerInv |
| 玩家死亡时传送到出生点 | PlayerDieEvent | CreatePos → SetPos |
| 方块被破坏时生成粒子 | DestroyBlockEvent | CreateParticle(客户端) |
| 生物受伤时减半伤害 | PlayerAttackEntityEvent | 修改 args["damage"] |
| 右键方块打开商店 UI | ServerBlockUseEvent | NotifyToClient → 客户端创建 UI |
小结
| 要点 | 说明 |
|---|---|
| 创建组件 | GetEngineCompFactory().CreateXxx(entityId) |
| 实体组件 | 传入 entityId(玩家、生物、物品实体的 ID) |
| 世界组件 | 传入 levelId(serverApi.GetLevelId()) |
| 服务端组件 | Item、Attr、Pos、Dimension、Game、Block 等 |
| 客户端组件 | Model、Particle、Camera 等 |
| 开发范式 | 监听事件 → 回调中调用组件 → 修改游戏状态 |
接下来我们将学习自定义事件与通信——让客户端和服务端之间传递消息。
