stepstead-client/scripts/chat_panel.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

179 lines
5.4 KiB
GDScript
Raw 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 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)