İlk commit: Stepstead Godot istemci (4.6 Mobile)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
6a1706051d
346 changed files with 14415 additions and 0 deletions
179
scripts/chat_panel.gd
Normal file
179
scripts/chat_panel.gd
Normal 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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue