İ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

179
scripts/chat_panel.gd Normal file
View file

@ -0,0 +1,179 @@
extends PanelContainer
## Sohbet paneli — kod ile kurulur (tscn'de yok), WsClient chat sinyallerini dinler.
## hud.gd oluşturup HUD CanvasLayer'ına ekler. Node adı "ChatPanel" (world.gd blokaj kontrolü).
const MAX_ROWS := 60
const PANEL_HEIGHT := 480.0
var _list: VBoxContainer
var _scroll: ScrollContainer
var _input: LineEdit
var _tab_global: Button
var _tab_local: Button
## Aktif kanal: "global" | "local". Mesajlar kanal başına bellekte tutulur,
## sekme değişince yeniden çizilir.
var _channel := "global"
var _msgs := {"global": [], "local": []}
func _ready() -> void:
name = "ChatPanel"
visible = false
_build_ui()
WsClient.chat_received.connect(_on_chat)
WsClient.chat_history.connect(_on_history)
WsClient.local_chat_history.connect(_on_local_history)
# Lokasyon değişince yerel geçmiş bayatlar
GameState.traveled.connect(func(_p: Dictionary) -> void:
_msgs["local"] = []
if visible and _channel == "local":
WsClient.request_local_history())
func _build_ui() -> void:
set_anchors_preset(Control.PRESET_BOTTOM_WIDE)
offset_top = -PANEL_HEIGHT
offset_left = 8
offset_right = -8
offset_bottom = -8
var sb := StyleBoxFlat.new()
sb.bg_color = Color(0.08, 0.1, 0.13, 0.95)
sb.set_corner_radius_all(10)
add_theme_stylebox_override("panel", sb)
var margin := MarginContainer.new()
margin.add_theme_constant_override("margin_left", 12)
margin.add_theme_constant_override("margin_right", 12)
margin.add_theme_constant_override("margin_top", 8)
margin.add_theme_constant_override("margin_bottom", 8)
add_child(margin)
var vbox := VBoxContainer.new()
vbox.add_theme_constant_override("separation", 6)
margin.add_child(vbox)
var top := HBoxContainer.new()
var title := Label.new()
title.text = "💬 Sohbet"
title.add_theme_font_size_override("font_size", 18)
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
top.add_child(title)
_tab_global = Button.new()
_tab_global.text = "🌍 Genel"
_tab_global.toggle_mode = true
_tab_global.button_pressed = true
_tab_global.pressed.connect(func() -> void: _switch_channel("global"))
top.add_child(_tab_global)
_tab_local = Button.new()
_tab_local.text = "📍 Burada"
_tab_local.toggle_mode = true
_tab_local.pressed.connect(func() -> void: _switch_channel("local"))
top.add_child(_tab_local)
var close_btn := Button.new()
close_btn.text = ""
close_btn.pressed.connect(func() -> void: visible = false)
top.add_child(close_btn)
vbox.add_child(top)
_scroll = ScrollContainer.new()
_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
vbox.add_child(_scroll)
_list = VBoxContainer.new()
_list.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_list.add_theme_constant_override("separation", 4)
_scroll.add_child(_list)
var bottom := HBoxContainer.new()
bottom.add_theme_constant_override("separation", 8)
_input = LineEdit.new()
_input.placeholder_text = "Mesaj yaz…"
_input.max_length = 300
_input.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_input.text_submitted.connect(func(_t: String) -> void: _send())
bottom.add_child(_input)
var send_btn := Button.new()
send_btn.text = "Gönder"
send_btn.pressed.connect(_send)
bottom.add_child(send_btn)
vbox.add_child(bottom)
func open() -> void:
visible = true
if _channel == "local" and (_msgs["local"] as Array).is_empty():
WsClient.request_local_history()
_scroll_to_bottom()
_input.grab_focus()
func _switch_channel(ch: String) -> void:
_channel = ch
_tab_global.button_pressed = ch == "global"
_tab_local.button_pressed = ch == "local"
_input.placeholder_text = "Mesaj yaz…" if ch == "global" else "Buradakilere yaz…"
if ch == "local":
WsClient.request_local_history()
_rerender()
func _send() -> void:
var msg := _input.text.strip_edges()
if msg == "":
return
WsClient.send_chat(msg, _channel)
_input.text = ""
_input.grab_focus()
func _on_history(messages: Array) -> void:
_msgs["global"] = messages.duplicate()
if _channel == "global":
_rerender()
func _on_local_history(messages: Array) -> void:
_msgs["local"] = messages.duplicate()
if _channel == "local":
_rerender()
func _on_chat(msg: Dictionary) -> void:
var ch := str(msg.get("channel", "global"))
if not _msgs.has(ch):
return
var arr: Array = _msgs[ch]
arr.append(msg)
while arr.size() > MAX_ROWS:
arr.pop_front()
if ch == _channel:
_append_row(msg)
while _list.get_child_count() > MAX_ROWS:
var oldest := _list.get_child(0)
_list.remove_child(oldest)
oldest.queue_free()
_scroll_to_bottom()
func _rerender() -> void:
for c in _list.get_children():
c.queue_free()
for m in (_msgs[_channel] as Array):
if m is Dictionary:
_append_row(m)
_scroll_to_bottom()
func _append_row(msg: Dictionary) -> void:
var own: bool = int(msg.get("char_id", 0)) == int(GameState.character.get("id", -1))
var row := RichTextLabel.new()
row.bbcode_enabled = true
row.fit_content = true
row.scroll_active = false
row.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var name_color := "#7ee08a" if own else "#e0c060"
row.text = "[color=%s]%s:[/color] %s" % [
name_color,
str(msg.get("name", "?")).replace("[", ""),
str(msg.get("text", "")).replace("[", ""),
]
_list.add_child(row)
func _scroll_to_bottom() -> void:
if not visible:
return
await get_tree().process_frame
_scroll.scroll_vertical = int(_scroll.get_v_scroll_bar().max_value)