# ChannelStatus (P10 收尾) —— 频道负载查询(对齐 CServerStateChecker)。 # # var cs := preload("res://net/channel_status.gd").new() # add_child(cs) # cs.query(host, port, func(map): ...) # map: { port:int -> status:int } # # 明文 TCP(无 libsodium):连上任一频道端口 → 发 CG_STATE_CHECKER(0x000F,len 4) → # 跳过其它包直到 GC_RESPOND_CHANNELSTATUS(0x0010) → 读 int32 count → count × {i16 port, u8 status}。 # status:0 关 / 1 正常 / 2 忙 / 3 满(Metin2 约定,非在线人数——那要改服务器)。 extends Node const CG_STATE_CHECKER := 0x000F const GC_RESPOND_CHANNELSTATUS := 0x0010 const STATUS_TEXT := {0: "关闭", 1: "正常", 2: "拥挤", 3: "爆满"} signal done(status_by_port: Dictionary) var _peer: StreamPeerTCP var _cb: Callable var _deadline := 0.0 var _sent := false func query(host: String, port: int, callback: Callable = Callable(), timeout_s := 3.0) -> void: _cb = callback _peer = StreamPeerTCP.new() _sent = false _deadline = _now() + timeout_s if _peer.connect_to_host(host, port) != OK: _finish({}) return set_process(true) func text_for(status: int) -> String: return STATUS_TEXT.get(status, "?") func _now() -> float: return Time.get_ticks_msec() / 1000.0 func _process(_dt: float) -> void: if _peer == null: return _peer.poll() var st := _peer.get_status() if st == StreamPeerTCP.STATUS_ERROR or _now() > _deadline: _finish({}) return if st != StreamPeerTCP.STATUS_CONNECTED: return if not _sent: var req := PackedByteArray() req.resize(4) req.encode_u16(0, CG_STATE_CHECKER) req.encode_u16(2, 4) _peer.put_data(req) _sent = true # 攒够一个包就解析 _try_parse() func _try_parse() -> void: var avail := _peer.get_available_bytes() if avail < 4: return # 逐包扫,跳到 RESPOND_CHANNELSTATUS while _peer.get_available_bytes() >= 4: var head: Array = _peer.get_partial_data(4) if head[0] != OK: return var hb: PackedByteArray = head[1] var header := hb.decode_u16(0) var length := hb.decode_u16(2) if header == GC_RESPOND_CHANNELSTATUS: _read_body() return # 别的包:按 length 跳过剩余(已吃掉 4 字节头) var rest := maxi(0, length - 4) if rest > 0: if _peer.get_available_bytes() < rest: return # 等更多数据(简化:不缓存半包,靠 timeout 兜底) _peer.get_data(rest) func _read_body() -> void: # 已消费 4 字节头;接着 int32 count + count × {i16 port, u8 status} if _peer.get_available_bytes() < 4: return var cnt_r: Array = _peer.get_data(4) var count: int = (cnt_r[1] as PackedByteArray).decode_s32(0) var out := {} for i in count: if _peer.get_available_bytes() < 3: break var rec: PackedByteArray = _peer.get_data(3)[1] out[rec.decode_s16(0)] = rec.decode_u8(2) _finish(out) func _finish(m: Dictionary) -> void: set_process(false) if _peer: _peer.disconnect_from_host() _peer = null done.emit(m) if _cb.is_valid(): _cb.call(m)