跳到主要内容

SDK、GDScript

介绍​

GDScript SDK 适用于使用 GDScript 的 Godot 项目。

GDScript SDK 提供了与服务器交互的简单封装,内部使用 Protobuf 数据协议通信。 配合上代码生成能避免编写大量的模板代码, 从而帮助客户端开发者减少巨大的工作量。

安装​

通过 AssetLib 搜索 ooGame 并下载 An



点击 Install 按钮,将 sdk 安装到 addons 插件目录中。 An



安装后 addons 目录会多出 sdk 相关文件 An

An

SDK 设置​

添加一个 my_net_config.gd 文件,用于配置 sdk 相关内容

class_name MyNetConfig
extends RefCounted

static var _socket: MyNetChannel = MyNetChannel.new()
static var current_time_millis: int = 0

static func start_net():
# --------- 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()


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.")

如何生成 .proto​

生成 .proto 需要使用 godobuf 库, 下面做一些简单的安装演示,更详细的安装说明可到该库上阅读 README.md 内容。

下载 godobuf 库到本地

git clone https://github.com/oniksan/godobuf.git

将 addons/protobuf 目录复制到项目的 addons 目录中。

An



现在,Godot 工具中目录如下

gds_p2

启用 godobuf 插件 An



现在,会多出 Godobuf tab,通过此 tab 开发者将 .proto 转换为 .gd 文件

gds_p4

Input protobuf file: 选择你想编译的 .proto Output GDScript file: 是 .proto 编译后的输出目录。

注意,编译后 proto 文件一定要放在 gen 目录下。 An



./gen/code 目录中的 action、广播、错误码 ...等交互接口文件由 框架生成。 代码生成可为客户端开发者减少巨大的工作量,代码使用简单,与本地方法调用一般丝滑。

gds_p6

处理错误码​

以下分别展示了 callback、async await 两种编码风格对于错误的处理。

SdkAction 由框架生成。

func int_func():
print("-------- OnIntValue --------")
var value: int = 1

# code style: callback.
SdkAction.of_int_value(value, func(result: IoGame.ResponseResult):
result.log(result.get_int())
).on_error(func(result: IoGame.ResponseResult):
var error_code := result.get_response_status()
print("error_code: ", error_code)
print("error_info: ", result.get_error_info())
)

# code style: async await.
var _result := await SdkAction.of_await_int_value(value)
if _result.success():
_result.log(_result.get_int())
else:
var error_code := _result.get_response_status()
print("error_code: ", error_code)
print("error_info: ", _result.get_error_info())

注意事项​

获取网络数据

see https://docs.godotengine.org/en/stable/tutorials/networking/websocket.html#using-websocket-in-godot

需要在 _process(_delta) 方法中调用 MyNetConfig.poll() 方法,接收网络数据

extends Node
...
func _ready():
MyNetConfig.start_net()

func _process(_delta):
# cn: 接收网络数据
# Call this in _process or _physics_process.
# Data transfer, and signals emission will only happen when calling this function.
MyNetConfig.poll()