第一个服务端脚本
在前文中,我们完成了服务端脚本注册,本篇将讲解服务端系统类的基本用法,并完成一个简易功能。
什么是系统类?
BaseSystem
是 ModSdk 提供的基础系统类,开发者可以通过它实现游戏中的核心脚本逻辑,例如注册和监听游戏事件
、广播事件
等。结合 serverApi
,可以轻松(?)开发出丰富多样的玩法功能。
什么是游戏事件?
在 Minecraft 的 Mod 开发中,游戏事件是游戏运行过程中触发的特定行为或状态变化。例如,玩家加入游戏、方块被破坏、生物受到伤害等,都是常见的游戏事件。
通过监听这些事件,开发者可以在特定的时机执行自定义逻辑,从而实现丰富的游戏功能。例如:
- 在玩家加入时发送欢迎消息。
- 当特定方块被破坏时生成奖励物品。
- 在生物受到伤害时触发特殊效果。
事件监听的基本流程
注册事件监听器
使用系统类方法ListenForEvent
注册一个事件监听器,指定需要监听的事件类型以及回调函数
。实现事件处理逻辑
在事件触发时,回调函数
将被自动触发,并拿到相关的事件信息(如果存在),例如生物死亡事件可以拿到谁死亡了,是谁击杀的。
示例代码
以下是一个简单的服务端事件监听示例,监听玩家攻击生物的事件并输出日志:
# -*- coding: utf-8 -*-
import mod.server.extraServerApi as serverApi
ServerSystem = serverApi.GetServerSystemCls() # 获取服务端系统基类
# 定义MyServer类
class MyServer(ServerSystem):
def __init__(self, namespace, systemName):
# ServerSystem基类接收两个参数 描述当前系统被注册的命名空间以及系统名(modMain.py中的注册)
ServerSystem.__init__(self, namespace, systemName)
# 获取原版MC引擎的命名空间和系统名
mcNamespace, mcSystemName = serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName()
# 注册PlayerAttackEntityEvent事件监听(游戏关闭时所有的监听会被自动取消,因此不需要开发者考虑回收问题)
self.ListenForEvent(mcNamespace, mcSystemName, "PlayerAttackEntityEvent", self, self.PlayerAttackEntityEvent)
def PlayerAttackEntityEvent(self, args={}):
playerId = args["playerId"]
victimId = args["victimId"]
print("玩家: {} 命中了 {}".format(playerId, victimId))
接口讲解
接口 | 描述 | 返回类型 |
---|---|---|
serverApi.GetEngineNamespace | 获取引擎命名空间(原版命名空间) | str |
serverApi.GetEngineSystemName | 获取引擎系统名(原版系统名) | str |
ServerSystem::ListenForEvent | 监听特定游戏事件,注册回调方法 | None |
ListenForEvent参数
描述 | 类型 |
---|---|
监听的命名空间 | str |
监听的系统名 | str |
监听的事件名 | str |
系统来源(固定self) | BaseSystem |
绑定回调方法,必须是系统来源(及self)下的方法 | function |
快速查阅:游戏API与事件,您可以在此处看到所有开放的游戏事件以及回调参数。
关于监听
事件监听除了监听原版游戏事件
外还能监听其他MOD自定义的事件
,因此需要命名空间+系统名区分指定监听谁。
编写服务端脚本
运行上述示例代码,游戏中玩家命中生物将在mcs控制台
中输出对应的日志 (请确保按照上文modMain.py
中注册它)。
为示例代码添加具体功能
通过事件触发的时机以及事件参数
结合serverApi
实现具体游戏功能。
# -*- coding: utf-8 -*-
import mod.server.extraServerApi as serverApi
ServerSystem = serverApi.GetServerSystemCls()
class MyServer(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
mcNamespace, mcSystemName = serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName()
self.ListenForEvent(mcNamespace, mcSystemName, "PlayerAttackEntityEvent", self, self.PlayerAttackEntityEvent)
# PlayerAttackEntityEvent事件的参数且看下文
def PlayerAttackEntityEvent(self, args={}):
playerId = args["playerId"]
victimId = args["victimId"]
# GetEngineTypeStr接口 获取实体英文标识符(与JSON中的定义一致)
comp = serverApi.GetEngineCompFactory().CreateEngineType(victimId)
if comp.GetEngineTypeStr() == "minecraft:zombie":
print("玩家: {} 命中了僵尸({})".format(playerId, victimId))
# Hurt接口 对指定实体造成指定伤害
# 此处将对玩家造成3点伤害 实现玩家攻击僵尸自动受到反伤
comp = serverApi.GetEngineCompFactory().CreateHurt(playerId)
comp.Hurt(3, serverApi.GetMinecraftEnum().ActorDamageCause.EntityAttack, victimId, None, False)
自此,玩家在攻击到僵尸时将受到反伤害,攻击其他生物则无事发生。
补充
部分API接口可能需要用到levelId,该数据可通过 serverApi.GetLevelId()
获取。
引用接口/事件
接口 | 描述 |
---|---|
GetEngineTypeStr | 获取实体的类型名称(英文标识符) |
Hurt | 设置实体伤害(造成伤害) |
PlayerAttackEntityEvent | 【事件】当玩家攻击生物时触发 |
关于实体ID
请注意区分运行时entityId
与JSON标识符的区别,每个生物在游戏中都有唯一的实体ID作为描述信息(描述CPP实体对象引用)对生物的操作离不开实体ID。
说明
由于网易ModSdk早年的工厂设计滥用,导致接口极难记忆,建议只记住有什么,需要用到时再去官网API文档搜索并CV。
总结
基本MOD开发逻辑如下:
- 注册游戏事件监听,在您需要的时机执行代码。
- 判断事件参数,筛选条件。
- 结合游戏API作出处理。