Files
val-blog/ai-agent-living/godot/scripts/bridge_client.gd
T

153 lines
3.4 KiB
GDScript

extends Node
# Bridge 客户端 - 连接 Godot 和 OpenClaw
signal action_received(action: Dictionary)
signal state_synced(state: Dictionary)
signal connected_to_bridge()
signal disconnected_from_bridge()
@export var bridge_url: String = "ws://127.0.0.1:8765"
@export var reconnect_interval: float = 5.0
@export var auto_connect: bool = false # 默认不自动连接
var socket: WebSocketPeer
var is_connected: bool = false
var reconnect_timer: float = 0.0
func _ready():
# 作为全局单例
name = "BridgeClient"
print("BridgeClient initialized, auto_connect = ", auto_connect)
if auto_connect:
_connect_to_bridge()
func _process(delta):
if socket:
_socket_poll()
elif reconnect_timer > 0:
reconnect_timer -= delta
if reconnect_timer <= 0:
_connect_to_bridge()
func _connect_to_bridge():
print("Connecting to OpenClaw Bridge at ", bridge_url)
socket = WebSocketPeer.new()
var err = socket.connect_to_url(bridge_url)
if err != OK:
print("Failed to connect: ", err)
_schedule_reconnect()
return
# 设置状态
is_connected = false
func _socket_poll():
socket.poll()
var state = socket.get_ready_state()
match state:
WebSocketPeer.STATE_CONNECTING:
pass # 正在连接
WebSocketPeer.STATE_OPEN:
if not is_connected:
is_connected = true
print("Connected to OpenClaw Bridge!")
emit_signal("connected_to_bridge")
_send_hello()
# 处理收到的消息
while socket.get_available_packets() > 0:
var packet = socket.get_packet()
var message_str = packet.get_string_from_utf8()
_parse_message(message_str)
WebSocketPeer.STATE_CLOSING:
pass # 正在关闭
WebSocketPeer.STATE_CLOSED:
if is_connected:
is_connected = false
print("Disconnected from Bridge")
emit_signal("disconnected_from_bridge")
socket = null
_schedule_reconnect()
func _schedule_reconnect():
reconnect_timer = reconnect_interval
print("Will reconnect in ", reconnect_interval, " seconds...")
func _send_hello():
send_command({
"type": "hello",
"client": "godot",
"agent_id": "val",
"timestamp": Time.get_unix_time_from_system()
})
func _parse_message(message_str: String):
var json = JSON.new()
var err = json.parse(message_str)
if err != OK:
print("Failed to parse JSON: ", message_str)
return
var message = json.get_data()
if typeof(message) != TYPE_DICTIONARY:
print("Invalid message format")
return
var msg_type = message.get("type", "")
match msg_type:
"action_sequence":
# 解析动作序列
var actions = message.get("actions", [])
for action in actions:
emit_signal("action_received", action)
"state_sync":
# 同步Agent状态
emit_signal("state_synced", message.get("state", {}))
"heartbeat":
# 响应心跳
send_command({"type": "heartbeat_ack", "timestamp": Time.get_unix_time_from_system()})
"error":
print("Bridge error: ", message.get("error", "Unknown error"))
_:
print("Unknown message type: ", msg_type)
func send_command(command: Dictionary) -> bool:
if not is_connected or not socket:
# 静默处理,不打印警告
return false
var json_str = JSON.stringify(command)
var err = socket.send_text(json_str)
if err != OK:
print("Failed to send command: ", err)
return false
return true
func request_state_sync():
send_command({
"type": "request_state_sync",
"agent_id": "val"
})
func close_connection():
if socket:
socket.close()
is_connected = false