Skip to content

基本跨端通信

在 Minecraft Mod 开发中,跨端通信是实现客户端与服务端交互的核心功能。通过跨端通信接口,开发者可以在不同端之间传递事件和数据,从而实现复杂的游戏逻辑。

常用跨端通信接口

以下是常用的跨端通信接口及其功能描述:

  • NotifyToClient
    服务端向指定客户端发送事件,用于单个玩家的定向通信。

  • NotifyToServer
    客户端向服务器发送事件,用于客户端向服务端传递数据或请求。

  • NotifyToMultiClients
    服务端向多个指定客户端批量发送事件,用于群体通信。

  • BroadcastToAllClient
    服务端向所有客户端广播事件,用于全局通信。

服务端向客户端发送消息

编写服务端发送逻辑

下文将演示使用NotifyToClient发送消息到指定客户端。

python
# -*- 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)
    
    def PlayerAttackEntityEvent(self, args={}):
        playerId = args["playerId"]
        victimId = args["victimId"]
        # 在玩家命中生物时发送一个通信到客户端
        # 参数: (玩家ID, 自定义事件名, dict参数表)
        self.NotifyToClient(playerId, "playerAttackEntity", {"targetId": victimId})

编写客户端接收逻辑

客户端需要定义并注册回调处理函数(监听),以便在接收到消息后处理业务。

python
# -*- coding: utf-8 -*-
# 客户端
import mod.client.extraClientApi as clientApi
ClientSystem = clientApi.GetClientSystemCls()

class MyClient(ClientSystem):
    def __init__(self, namespace, systemName):
        ClientSystem.__init__(self, namespace, systemName)
        # 使用ListenForEvent监听指定服务端的指定事件(命名空间:test,系统名:ser1)
        self.ListenForEvent("test", "ser1", "playerAttackEntity", self, self.serPlayerAttackEntity)

    def serPlayerAttackEntity(self, args):
        # args包含了服务端传递的信息(仅支持py基本数据类型)
        print("你命中了:{}".format(args["targetId"]))

说明

广播默认没有环境隔离,需要指定命名空间,系统名区分。也可以用于跨MOD联动(虽然有其他方案)。

客户端向服务端发送消息

服务端向客户端发送消息类似,同样是使用广播+监听组合完成。

编写客户端发送逻辑

客户端需要定义并注册回调处理函数(监听),以便在接收到消息后处理业务。

python
# -*- coding: utf-8 -*-
# 客户端
import mod.client.extraClientApi as clientApi
ClientSystem = clientApi.GetClientSystemCls()
playerId = clientApi.GetLocalPlayerId()

class MyClient(ClientSystem):
    def __init__(self, namespace, systemName):
        ClientSystem.__init__(self, namespace, systemName)
        mcNamespace, mcSystemName = clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName()
        self.ListenForEvent(mcNamespace, mcSystemName, "ClientJumpButtonReleaseEvent", self, self.ClientJumpButtonReleaseEvent)

    def ClientJumpButtonReleaseEvent(self, _={}):
        # 当玩家跳跃时发送跳跃信息到服务端 (注:在高版本中客户端广播会自动携带当前playerId,因此可以不需要传递自己的id,此处仅作参考)
        self.NotifyToServer("playerJumpRelease", {"clPlayerId": playerId})

编写服务端接收逻辑

python
# -*- coding: utf-8 -*-
# 服务端
import mod.server.extraServerApi as serverApi
ServerSystem = serverApi.GetServerSystemCls()
levelId = serverApi.GetLevelId()

class MyServer(ServerSystem):
    def __init__(self, namespace, systemName):
        ServerSystem.__init__(self, namespace, systemName)
        self.ListenForEvent("test", "cli1", "playerJumpRelease", self, self.playerJumpRelease)
    
    def playerJumpRelease(self, args={}):
        playerId = args["clPlayerId"]
        # 杀死玩家,不许跳不许停
        comp = serverApi.GetEngineCompFactory().CreateGame(levelId)
        comp.KillEntity(playerId)

注意

若开发网络型MOD逻辑,不要相信客户端传递的任何数据,请在服务端二次校验。

关于性能问题

跨端通信会立即发送数据包,高频的广播会导致性能大幅度下降(在网络环境),请控制发包频率。

总结

跨端通信是 Minecraft Mod 开发中不可或缺的一部分,通过合理使用通信接口,可以实现客户端与服务端之间的高效交互。

需要注意的是,跨端通信的频率应尽量控制,以避免性能问题。同时,服务端应对客户端传递的数据进行严格校验(在重要数据场景),确保逻辑安全性。

通过以上内容的学习,开发者可以掌握基本的跨端通信方法,为实现复杂的游戏逻辑打下基础。

Released under the BSD3 License