Skip to content

组件调用 ​

上一节我们学了事件系统——事件告诉你「发生了什么」。但光知道发生了什么还不够,我们需要做出改变:给玩家物品、修改血量、传送位置、播放特效……这些都要靠组件。

事件 = 监听游戏中的变化;组件 = 操作游戏中的数据。

你将学到

  • 组件的创建方式: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)            # 设置血量为 10

AttrType 枚举

血量、速度、攻击力等属性通过数值常量区分:

值属性范围
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
        )

测试 ​

  1. 运行游戏,进入存档
  2. 检查血条——20 颗心(最大血量 40)
  3. 检查背包——钻石剑 + 16 个面包
  4. 查看日志——输出玩家 ID 和出生位置

事件 + 组件 = Mod 开发范式 ​

到这里你已经掌握了 Mod SDK 的核心开发范式:

监听事件(知道发生了什么)
    │
    ▼
在回调函数中调用组件(做出改变)
    │
    ▼
游戏状态更新

所有的 Mod 逻辑都是这个模式的变体:

需求监听什么事件调用什么组件
玩家加入时给装备AddServerPlayerEventCreateItem → SpawnItemToPlayerInv
玩家死亡时传送到出生点PlayerDieEventCreatePos → SetPos
方块被破坏时生成粒子DestroyBlockEventCreateParticle(客户端)
生物受伤时减半伤害PlayerAttackEntityEvent修改 args["damage"]
右键方块打开商店 UIServerBlockUseEventNotifyToClient → 客户端创建 UI

小结 ​

要点说明
创建组件GetEngineCompFactory().CreateXxx(entityId)
实体组件传入 entityId(玩家、生物、物品实体的 ID)
世界组件传入 levelId(serverApi.GetLevelId())
服务端组件Item、Attr、Pos、Dimension、Game、Block 等
客户端组件Model、Particle、Camera 等
开发范式监听事件 → 回调中调用组件 → 修改游戏状态

接下来我们将学习自定义事件与通信——让客户端和服务端之间传递消息。