stepstead-client/autoload/ws_client.gd
jts 6a1706051d İlk commit: Stepstead Godot istemci (4.6 Mobile)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 11:31:35 +03:00

117 lines
3.3 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Node
## Canlı multiplayer istemcisi — diğer oyuncuların pozisyonlarını WebSocket ile alır.
## Sunucu eventleri: online_list (sadece bağlanınca), player_joined, player_moved,
## player_left, pong. Kopunca 5 sn'de bir yeniden bağlanır.
signal player_joined(p: Dictionary)
signal player_moved(p: Dictionary)
signal player_left(char_id: int)
signal online_list(players: Array)
signal chat_received(msg: Dictionary)
signal chat_history(messages: Array) # global geçmiş (bağlanınca)
signal local_chat_history(messages: Array) # bulunulan lokasyonun geçmişi (istek üzerine)
signal connection_changed(is_connected: bool)
const PING_INTERVAL := 25.0 # sunucu presence TTL 120sn, ping ile yenilenir
const RECONNECT_DELAY := 5.0
var _ws: WebSocketPeer = null
var _open := false
var _ping_accum := 0.0
var _reconnect_accum := 0.0
var _should_run := false
func start() -> void:
if _should_run:
return
_should_run = true
_connect_ws()
func stop() -> void:
_should_run = false
if _ws != null:
_ws.close()
_ws = null
if _open:
_open = false
connection_changed.emit(false)
func _connect_ws() -> void:
if Auth.token == "":
return
var url := Config.get_api_base().replace("https://", "wss://").replace("http://", "ws://") + "/ws?token=" + Auth.token
_ws = WebSocketPeer.new()
var err := _ws.connect_to_url(url)
if err != OK:
push_warning("WS bağlantı hatası: %d" % err)
_ws = null
_ping_accum = 0.0
func _process(delta: float) -> void:
if not _should_run:
return
if _ws == null:
_reconnect_accum += delta
if _reconnect_accum >= RECONNECT_DELAY:
_reconnect_accum = 0.0
_connect_ws()
return
_ws.poll()
var state := _ws.get_ready_state()
if state == WebSocketPeer.STATE_OPEN:
if not _open:
_open = true
connection_changed.emit(true)
while _ws.get_available_packet_count() > 0:
_handle_packet(_ws.get_packet().get_string_from_utf8())
_ping_accum += delta
if _ping_accum >= PING_INTERVAL:
_ping_accum = 0.0
_ws.send_text("{\"type\":\"ping\"}")
elif state == WebSocketPeer.STATE_CLOSED:
_ws = null
_reconnect_accum = 0.0
if _open:
_open = false
connection_changed.emit(false)
func _handle_packet(text: String) -> void:
var json := JSON.new()
if json.parse(text) != OK:
return
if not (json.data is Dictionary):
return
var msg: Dictionary = json.data
match str(msg.get("type", "")):
"online_list":
var players: Array = msg.get("players", [])
online_list.emit(players)
"player_joined":
player_joined.emit(msg)
"player_moved":
player_moved.emit(msg)
"player_left":
player_left.emit(int(msg.get("char_id", 0)))
"chat":
chat_received.emit(msg)
"chat_history":
var messages: Array = msg.get("messages", [])
if str(msg.get("channel", "global")) == "local":
local_chat_history.emit(messages)
else:
chat_history.emit(messages)
"pong":
pass
func send_chat(text: String, channel: String = "global") -> void:
if _ws == null or _ws.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
var trimmed := text.strip_edges()
if trimmed == "":
return
_ws.send_text(JSON.stringify({"type": "chat", "text": trimmed, "channel": channel}))
func request_local_history() -> void:
if _ws == null or _ws.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
_ws.send_text("{\"type\":\"get_local_history\"}")