İlk commit: Stepstead Godot istemci (4.6 Mobile)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jts 2026-07-11 11:31:35 +03:00
commit 6a1706051d
346 changed files with 14415 additions and 0 deletions

117
autoload/ws_client.gd Normal file
View file

@ -0,0 +1,117 @@
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\"}")