SDKExample、Godot、GDScript
介绍
该示例使用了 SDK、GDScript
当前示例提供了 GDScript 、Netty、WebSocket、Protobuf 与游戏服务器交互的演示。
该示例主要演示以下几个方面的内容
- ioGame SDK + 代码生成 = 诸多优势。
 - 使用代码生成后的接口文件(action、广播)与服务器交互。
 - 心跳的处理,每次心跳将时间与服务器同步。
 - 交互演示内容包括
- 协议碎片:“基础类型”的参数与返回值。
 - List 类型的参数与返回值。
 - Protobuf 对象类型的参数与返回值。
 
 
示例目录 ./gen/code 中的 action、广播、错误码 ...等交互接口文件由 ioGame 生成。 代码生成可为客户端开发者减少巨大的工作量,并可为客户端开发者屏蔽路由等概念。
SDK 代码生成的几个优势
- 帮助客户端开发者减少巨大的工作量,不需要编写大量的模板代码。
 - 语义明确,清晰。生成的交互代码即能明确所需要的参数类型,又能明确服务器是否会有返回值。这些会在生成接口时就提前明确好。
 - 明确的交互接口,确保了方法的参数类型安全且明确,使我们在编译阶段就能发现潜在问题。 这种做法有效避免了安全隐患,并减少了联调时可能出现的低级错误。
 - 减少服务器与客户端双方对接时的沟通成本,代码即文档。生成的联调代码中有文档与使用示例,方法上的示例会教你如何使用,即使是新手也能做到零学习成本。
 - 帮助客户端开发者屏蔽与服务器交互部分,将更多的精力放在真正的业务上。
 - 为双方联调减少心智负担。联调代码使用简单,与本地方法调用一般丝滑。
 - 抛弃传统面向协议对接的方式,转而使用面向接口方法的对接方式。
 - 当我们的 java 代码编写完成后,我们的文档及交互接口可做到同步更新,不需要额外花时间去维护对接文档及其内容。
 
Example Source Code
see https://github.com/iohao/ioGameSdkGDScriptExampleGodot
快速开始
启动游戏服务器
see https://github.com/iohao/ioGameExamples/tree/main/SdkExample
运行 SdkApplication.java 启动游戏服务器

安装 SDK
当前示例项目已经安装好了相关环境,新项目请自行安装 SDK、GDScript
启动 Godot
Godot Version: 4.4.1

Test
点击按钮会向服务器发送请求,并接收服务器的响应数据。

SDK 设置说明
my_net_config.gd 文件,该配置文件做了以下事情
- 错误码及广播监听相关的加载。
 - IoGameSetting.listen_message_callback:自定义消息监听。
 - socket_init():网络实现的配置、登录。
 - IoGameSetting.start_net: 启动 ioGame Sdk。
 
class_name MyNetConfig
extends RefCounted
static var _socket: MyNetChannel = MyNetChannel.new()
static var current_time_millis: int = 0
static func start_net():
    # biz code init
    GameCode.init()
    Listener.listener_ioGame()
    # --------- IoGameSetting ---------
    var setting := IoGame.IoGameSetting
    setting.enable_dev_mode = true
    setting.set_language(IoGame.IoGameLanguage.Us)
    # message callback. cn: 回调监听
    setting.listen_message_callback = MyListenMessageCallback.new()
    # set socket. cn: 设置网络连接
    setting.net_channel = _socket
    socket_init()
    setting.start_net()
static func poll():
    _socket.poll()
const Common = preload("res://gen/common.gd")
static func socket_init():
    _socket.on_open = func():
        var verify_message := Common.LoginVerifyMessage.new()
        verify_message.set_jwt("1")
        SdkAction.of_login_verify(verify_message, func(result: IoGame.ResponseResult):
                var value := result.get_value(Common.UserMessage) as Common.UserMessage
                print("user: ", value)
        )
static var _heartbeat_message_bytes := IoGame.Proto.ExternalMessage.new().to_bytes()
static var _heartbeat_counter: int = 1
static func send_idle() -> void:
    _heartbeat_counter += 1
    #print("-------- ..HeartbeatMessage {%s}" % [_heartbeat_counter])
    IoGame.IoGameSetting.net_channel.write_and_flush_byte(_heartbeat_message_bytes)
class MyListenMessageCallback extends IoGame.ListenMessageCallback:
    func on_idle_callback(message: Proto.ExternalMessage):
        var data_bytes := message.get_data()
        var long_value := IoGame.Proto.LongValue.new()
        long_value.from_bytes(data_bytes)
        # Synchronize the time of each heartbeat with that of the server.
        # cn: 每次心跳与服务器的时间同步
        MyNetConfig.current_time_millis = long_value.get_value()
class MyNetChannel extends IoGame.SimpleNetChannel:
    var _last_state: WebSocketPeer.State = WebSocketPeer.State.STATE_CLOSED
    var _socket: WebSocketPeer = WebSocketPeer.new()
    var _url: String = "ws://127.0.0.1:10100/websocket"
    var on_open: Callable = func():
        print("on_open")
    var on_connecting: Callable = func():
        print("on_connecting")
    var on_connect_error: Callable = func(error: int):
        print("on_connect_error:", error)
    var on_closing: Callable = func():
        print("on_closing")
    var on_closed: Callable = func():
        print("on_closed")
    func prepare() -> void:
        if _url == null or _url.is_empty():
            _url = IoGame.IoGameSetting.url
        var error: int = _socket.connect_to_url(_url)
        if error != 0:
            on_connect_error.call(error)
            return
        _last_state = _socket.get_ready_state()
    func write_and_flush_byte(bytes: PackedByteArray) -> void:
        _socket.send(bytes)
    func poll() -> void:
        if _socket.get_ready_state() != WebSocketPeer.State.STATE_CLOSED:
            _socket.poll()
        while _socket.get_available_packet_count() > 0:
            var packet := _socket.get_packet()
            var message := IoGame.Proto.ExternalMessage.new()
            message.from_bytes(packet)
            self.accept_message(message)
        var state: WebSocketPeer.State = _socket.get_ready_state()
        if _last_state == state:
            return
        _last_state = state
        match state:
            WebSocketPeer.State.STATE_OPEN:
                on_open.call()
            WebSocketPeer.State.STATE_CONNECTING:
                on_connecting.call()
            WebSocketPeer.State.STATE_CLOSING:
                on_closing.call()
            WebSocketPeer.State.STATE_CLOSED:
                on_closed.call()
            _:
                printerr("Socket Unknown Status.")
Example Source Code Directory
记住,你不需要编写任何交互文件 action、广播、错误码,这些是由 ioGame 服务器生成的,你只需要关注真正的业务逻辑。
下图是 ioGame 游戏服务器的源码,上图中的 GDScript 源码由 ioGame 生成。
;
关于代码生成与使用
click here
如何根据 .proto 生成相关 pb
最后
记住,你不需要编写任何交互文件 action、广播、错误码,这些是由 ioGame 服务器生成的,你只需要关注真正的业务逻辑。