Build first lobby browser UI
This commit is contained in:
@@ -14,6 +14,7 @@ Der aktuelle Stand ist bewusst ein technischer Prototyp. Es ist noch keine ferti
|
||||
- Brotatos Run-Szene wird per Script-Extension beobachtet.
|
||||
- Run-Start, Spieler-Spawn und einfache Player-Snapshots werden geloggt bzw. fuer P2P-Versand vorbereitet.
|
||||
- Das Brogether-Modal ist standardmaessig versteckt und kann ueber das Hauptmenue oder `F5` geoeffnet werden.
|
||||
- Die UI enthaelt einen ersten Lobby-Browser, Lobby-Erstellung mit optionalem Passwort und einen Wartebereich mit Spielerkacheln.
|
||||
|
||||
## Was noch nicht fertig ist
|
||||
|
||||
@@ -54,6 +55,11 @@ Danach Brotato komplett neu starten.
|
||||
|
||||
Brogether ist im Spiel standardmaessig unsichtbar. Im Hauptmenue gibt es einen neuen `BROGETHER`-Button; alternativ oeffnet `F5` das Brogether-Modal. Das Modal pausiert das Spiel wie Brotatos eigenes F8-Feedback-Fenster und kann mit `Escape`, `F5` oder dem Close-Button wieder geschlossen werden.
|
||||
|
||||
Im Modal gibt es jetzt zwei Bereiche:
|
||||
|
||||
- Lobby-Browser: zeigt gefundene Brogether-Lobbys mit Name, Host, Spielerzahl und Passwortstatus.
|
||||
- Wartebereich: zeigt die Spieler in der aktuellen Lobby als Kacheln mit Steam-Namen und statischem Initialen-Avatar.
|
||||
|
||||
## Debug-Tasten
|
||||
|
||||
```text
|
||||
@@ -65,7 +71,7 @@ F10 Ping senden
|
||||
F11 Lokalen Loopback-Test starten
|
||||
```
|
||||
|
||||
Das Brogether-Modal enthaelt Buttons fuer Host, Join, Leave, Ping und Loopback. Es ist fuer die naechsten Zwei-Client-Tests gedacht und ersetzt die meisten Hotkey-Aktionen.
|
||||
Das Brogether-Modal enthaelt Buttons fuer Host, Join, Leave und Ping. Es ist fuer die naechsten Zwei-Client-Tests gedacht und ersetzt die meisten Hotkey-Aktionen. Passwort-Lobbys sind aktuell eine Mod-seitige Zugangskontrolle: die Lobby bleibt sichtbar, der Join-Button prueft aber das Passwort, bevor Brogether beitritt.
|
||||
|
||||
Brogether schreibt ein eigenes Log nach:
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ Danach Brotato ueber Steam starten. Die Mod sollte im Mod-Menue auftauchen.
|
||||
|
||||
Brogether selbst bleibt danach unsichtbar, bis es geoeffnet wird. Im Hauptmenue fuegt die Mod einen `BROGETHER`-Button hinzu. Alternativ oeffnet `F5` dasselbe Modal. Das Modal verhaelt sich bewusst wie Brotatos F8-Feedback-Fenster: es pausiert, legt sich ueber das Spiel und kann mit `Escape`, `F5` oder `Close` geschlossen werden.
|
||||
|
||||
Die UI hat jetzt einen ersten Lobby-Browser. Dort kann man Lobbys suchen, eine Lobby mit optionalem Passwort erstellen und einer ausgewaehlten Lobby beitreten. Nach Host/Join wechselt Brogether in einen Wartebereich mit Steam-Namen und statischen Initialen-Avataren fuer die Lobby-Spieler.
|
||||
|
||||
## Debug-Hotkeys im Spiel
|
||||
|
||||
- `F5`: Brogether-Modal ein-/ausblenden
|
||||
|
||||
@@ -2,10 +2,16 @@ extends Node
|
||||
|
||||
const MOD_ID := "Brogether-Brogether"
|
||||
const LOG_PATH := "user://brogether.log"
|
||||
const BROGETHER_VERSION := "0.1.0"
|
||||
const MAX_LOBBY_MEMBERS := 2
|
||||
|
||||
var steam = null
|
||||
var lobby_id := 0
|
||||
var lobby_members := []
|
||||
var available_lobbies := []
|
||||
var selected_lobby_id := 0
|
||||
var pending_lobby_name := ""
|
||||
var pending_lobby_password_hash := ""
|
||||
var steam_id := 0
|
||||
var is_host := false
|
||||
var packet_sequence := 0
|
||||
@@ -16,6 +22,18 @@ var panel: PanelContainer = null
|
||||
var panel_status_label: Label = null
|
||||
var panel_log_label: Label = null
|
||||
var panel_default_focus: Control = null
|
||||
var browser_view: Control = null
|
||||
var lobby_view: Control = null
|
||||
var lobby_list_container: VBoxContainer = null
|
||||
var lobby_empty_label: Label = null
|
||||
var lobby_name_input: LineEdit = null
|
||||
var lobby_password_input: LineEdit = null
|
||||
var lobby_password_check: CheckBox = null
|
||||
var join_password_input: LineEdit = null
|
||||
var selected_lobby_label: Label = null
|
||||
var lobby_members_container: GridContainer = null
|
||||
var lobby_title_label: Label = null
|
||||
var lobby_detail_label: Label = null
|
||||
var status_time_left := 0.0
|
||||
var restore_paused_value := false
|
||||
var restore_focus_control = null
|
||||
@@ -82,7 +100,7 @@ func _input(event: InputEvent) -> void:
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
|
||||
func create_lobby() -> void:
|
||||
func create_lobby(password: String = "", lobby_name: String = "") -> void:
|
||||
if steam == null:
|
||||
_log("cannot create lobby: Steam singleton missing")
|
||||
return
|
||||
@@ -90,20 +108,27 @@ func create_lobby() -> void:
|
||||
_log("already in lobby %s" % lobby_id)
|
||||
_update_debug_panel()
|
||||
return
|
||||
pending_lobby_name = lobby_name.strip_edges()
|
||||
if pending_lobby_name.empty():
|
||||
pending_lobby_name = "%s's Brogether Lobby" % _get_persona_name(steam_id)
|
||||
pending_lobby_password_hash = _hash_password(password)
|
||||
var lobby_type := 2
|
||||
_log("creating public dev lobby")
|
||||
steam.call("createLobby", lobby_type, 2)
|
||||
_log("creating lobby '%s'" % pending_lobby_name)
|
||||
steam.call("createLobby", lobby_type, MAX_LOBBY_MEMBERS)
|
||||
|
||||
|
||||
func find_lobbies() -> void:
|
||||
if steam == null:
|
||||
_log("cannot find lobbies: Steam singleton missing")
|
||||
return
|
||||
available_lobbies.clear()
|
||||
selected_lobby_id = 0
|
||||
_update_lobby_browser()
|
||||
if steam.has_method("addRequestLobbyListStringFilter"):
|
||||
steam.call("addRequestLobbyListStringFilter", "brogether", "1", 0)
|
||||
if steam.has_method("addRequestLobbyListDistanceFilter"):
|
||||
steam.call("addRequestLobbyListDistanceFilter", 2)
|
||||
_log("requesting lobby list")
|
||||
_log("refreshing lobby browser")
|
||||
steam.call("requestLobbyList")
|
||||
|
||||
|
||||
@@ -125,6 +150,7 @@ func leave_lobby() -> void:
|
||||
lobby_id = 0
|
||||
lobby_members.clear()
|
||||
is_host = false
|
||||
_show_browser_view()
|
||||
_update_debug_panel()
|
||||
|
||||
|
||||
@@ -253,10 +279,14 @@ func _on_lobby_created(connect: int, created_lobby_id: int) -> void:
|
||||
is_host = true
|
||||
_log("created lobby %s" % lobby_id)
|
||||
steam.call("setLobbyJoinable", lobby_id, true)
|
||||
steam.call("setLobbyData", lobby_id, "name", "Brogether")
|
||||
steam.call("setLobbyData", lobby_id, "name", pending_lobby_name)
|
||||
steam.call("setLobbyData", lobby_id, "brogether", "1")
|
||||
steam.call("setLobbyData", lobby_id, "version", "0.1.0")
|
||||
steam.call("setLobbyData", lobby_id, "version", BROGETHER_VERSION)
|
||||
steam.call("setLobbyData", lobby_id, "max_players", str(MAX_LOBBY_MEMBERS))
|
||||
steam.call("setLobbyData", lobby_id, "has_password", "1" if not pending_lobby_password_hash.empty() else "0")
|
||||
steam.call("setLobbyData", lobby_id, "password_hash", pending_lobby_password_hash)
|
||||
_refresh_lobby_members()
|
||||
_show_lobby_view()
|
||||
_update_debug_panel()
|
||||
|
||||
|
||||
@@ -270,17 +300,66 @@ func _on_lobby_joined(joined_lobby_id: int, _permissions: int, _locked: bool, re
|
||||
is_host = steam.has_method("getLobbyOwner") and int(steam.call("getLobbyOwner", lobby_id)) == steam_id
|
||||
_log("joined lobby %s as %s with %s member(s)" % [lobby_id, "host" if is_host else "client", lobby_members.size()])
|
||||
_send_p2p_packet(0, {"type": "handshake", "from": steam_id})
|
||||
_show_lobby_view()
|
||||
_update_debug_panel()
|
||||
|
||||
|
||||
func _on_lobby_match_list(lobbies: Array) -> void:
|
||||
_log("found %s lobby candidate(s)" % lobbies.size())
|
||||
available_lobbies.clear()
|
||||
for candidate in lobbies:
|
||||
var candidate_id := int(candidate)
|
||||
if steam.has_method("getLobbyData") and steam.call("getLobbyData", candidate_id, "brogether") == "1":
|
||||
join_lobby(candidate_id)
|
||||
return
|
||||
_log("no Brogether lobby found")
|
||||
available_lobbies.append(_get_lobby_summary(candidate_id))
|
||||
_log("found %s Brogether lobby candidate(s)" % available_lobbies.size())
|
||||
_update_lobby_browser()
|
||||
|
||||
|
||||
func _get_lobby_summary(target_lobby_id: int) -> Dictionary:
|
||||
var member_count := 0
|
||||
var max_members := MAX_LOBBY_MEMBERS
|
||||
if steam != null and steam.has_method("getNumLobbyMembers"):
|
||||
member_count = int(steam.call("getNumLobbyMembers", target_lobby_id))
|
||||
if steam != null and steam.has_method("getLobbyMemberLimit"):
|
||||
max_members = int(steam.call("getLobbyMemberLimit", target_lobby_id))
|
||||
var owner_id := 0
|
||||
if steam != null and steam.has_method("getLobbyOwner"):
|
||||
owner_id = int(steam.call("getLobbyOwner", target_lobby_id))
|
||||
return {
|
||||
"id": target_lobby_id,
|
||||
"name": _get_lobby_data(target_lobby_id, "name", "Brogether Lobby"),
|
||||
"owner_id": owner_id,
|
||||
"owner_name": _get_persona_name(owner_id),
|
||||
"member_count": member_count,
|
||||
"max_members": max_members,
|
||||
"has_password": _get_lobby_data(target_lobby_id, "has_password", "0") == "1",
|
||||
"password_hash": _get_lobby_data(target_lobby_id, "password_hash", ""),
|
||||
"version": _get_lobby_data(target_lobby_id, "version", "")
|
||||
}
|
||||
|
||||
|
||||
func _get_lobby_data(target_lobby_id: int, key: String, fallback: String = "") -> String:
|
||||
if steam == null or not steam.has_method("getLobbyData"):
|
||||
return fallback
|
||||
var value = steam.call("getLobbyData", target_lobby_id, key)
|
||||
if value == null:
|
||||
return fallback
|
||||
var text := str(value)
|
||||
return fallback if text.empty() else text
|
||||
|
||||
|
||||
func _get_persona_name(target_steam_id: int) -> String:
|
||||
if target_steam_id == 0:
|
||||
return "Unknown"
|
||||
if steam != null and steam.has_method("getFriendPersonaName"):
|
||||
var persona := str(steam.call("getFriendPersonaName", target_steam_id))
|
||||
if not persona.empty():
|
||||
return persona
|
||||
return str(target_steam_id)
|
||||
|
||||
|
||||
func _hash_password(password: String) -> String:
|
||||
var clean := password.strip_edges()
|
||||
return "" if clean.empty() else str(clean.hash())
|
||||
|
||||
|
||||
func _on_lobby_chat_update(this_lobby_id: int, _changed_id: int, _making_change_id: int, _chat_state: int) -> void:
|
||||
@@ -308,11 +387,9 @@ func _refresh_lobby_members() -> void:
|
||||
var member_count := int(steam.call("getNumLobbyMembers", lobby_id))
|
||||
for index in range(member_count):
|
||||
var member_id := int(steam.call("getLobbyMemberByIndex", lobby_id, index))
|
||||
var persona := str(member_id)
|
||||
if steam.has_method("getFriendPersonaName"):
|
||||
persona = steam.call("getFriendPersonaName", member_id)
|
||||
lobby_members.append({"steam_id": member_id, "name": persona})
|
||||
lobby_members.append({"steam_id": member_id, "name": _get_persona_name(member_id)})
|
||||
_log("members: %s" % lobby_members)
|
||||
_update_lobby_room()
|
||||
_update_debug_panel()
|
||||
|
||||
|
||||
@@ -452,72 +529,441 @@ func _create_debug_panel() -> void:
|
||||
panel.anchor_right = 0.5
|
||||
panel.anchor_top = 0.5
|
||||
panel.anchor_bottom = 0.5
|
||||
panel.margin_left = -260
|
||||
panel.margin_right = 260
|
||||
panel.margin_top = -170
|
||||
panel.margin_bottom = 170
|
||||
panel.margin_left = -430
|
||||
panel.margin_right = 430
|
||||
panel.margin_top = -300
|
||||
panel.margin_bottom = 300
|
||||
panel.pause_mode = Node.PAUSE_MODE_PROCESS
|
||||
panel.visible = false
|
||||
|
||||
var style: StyleBoxFlat = StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.08, 0.09, 0.1, 0.96)
|
||||
style.border_color = Color(0.55, 0.58, 0.62, 1.0)
|
||||
style.set_border_width_all(1)
|
||||
style.set_corner_radius_all(3)
|
||||
style.content_margin_left = 18
|
||||
style.content_margin_right = 18
|
||||
style.content_margin_top = 16
|
||||
style.content_margin_bottom = 16
|
||||
panel.add_stylebox_override("panel", style)
|
||||
panel.add_stylebox_override("panel", _make_panel_style(Color(0.075, 0.08, 0.09, 0.98), Color(0.55, 0.58, 0.62, 1.0), 18))
|
||||
|
||||
var box: VBoxContainer = VBoxContainer.new()
|
||||
box.name = "Content"
|
||||
box.add_constant_override("separation", 10)
|
||||
box.add_constant_override("separation", 12)
|
||||
panel.add_child(box)
|
||||
|
||||
var header: HBoxContainer = HBoxContainer.new()
|
||||
header.add_constant_override("separation", 10)
|
||||
box.add_child(header)
|
||||
|
||||
var title: Label = Label.new()
|
||||
title.text = "BROGETHER"
|
||||
title.align = Label.ALIGN_CENTER
|
||||
title.rect_min_size = Vector2(220, 28)
|
||||
title.add_color_override("font_color", Color(1, 1, 1, 1))
|
||||
box.add_child(title)
|
||||
header.add_child(title)
|
||||
|
||||
panel_status_label = Label.new()
|
||||
panel_status_label.text = "Steam: ..."
|
||||
panel_status_label.align = Label.ALIGN_RIGHT
|
||||
panel_status_label.autowrap = true
|
||||
box.add_child(panel_status_label)
|
||||
panel_status_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
header.add_child(panel_status_label)
|
||||
|
||||
var grid: GridContainer = GridContainer.new()
|
||||
grid.columns = 2
|
||||
grid.add_constant_override("hseparation", 6)
|
||||
grid.add_constant_override("vseparation", 6)
|
||||
box.add_child(grid)
|
||||
var close_button: Button = Button.new()
|
||||
close_button.text = "X"
|
||||
close_button.rect_min_size = Vector2(42, 34)
|
||||
close_button.connect("pressed", self, "close_debug_panel")
|
||||
header.add_child(close_button)
|
||||
|
||||
panel_default_focus = _add_panel_button(grid, "Host", "create_lobby")
|
||||
_add_panel_button(grid, "Join", "find_lobbies")
|
||||
_add_panel_button(grid, "Leave", "leave_lobby")
|
||||
_add_panel_button(grid, "Ping", "send_ping")
|
||||
_add_panel_button(grid, "Loopback", "run_loopback_test")
|
||||
_add_panel_button(grid, "Close", "close_debug_panel")
|
||||
var separator: HSeparator = HSeparator.new()
|
||||
box.add_child(separator)
|
||||
|
||||
browser_view = HBoxContainer.new()
|
||||
browser_view.name = "LobbyBrowser"
|
||||
browser_view.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
browser_view.add_constant_override("separation", 14)
|
||||
box.add_child(browser_view)
|
||||
|
||||
var browser_column: VBoxContainer = VBoxContainer.new()
|
||||
browser_column.rect_min_size = Vector2(390, 410)
|
||||
browser_column.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
browser_column.add_constant_override("separation", 8)
|
||||
browser_view.add_child(browser_column)
|
||||
|
||||
var browser_title: Label = Label.new()
|
||||
browser_title.text = "LOBBY BROWSER"
|
||||
browser_title.add_color_override("font_color", Color(0.92, 0.96, 1.0, 1.0))
|
||||
browser_column.add_child(browser_title)
|
||||
|
||||
var browser_hint: Label = Label.new()
|
||||
browser_hint.text = "Offene Brogether-Lobbys werden hier angezeigt."
|
||||
browser_hint.autowrap = true
|
||||
browser_column.add_child(browser_hint)
|
||||
|
||||
var scroll: ScrollContainer = ScrollContainer.new()
|
||||
scroll.rect_min_size = Vector2(390, 300)
|
||||
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
browser_column.add_child(scroll)
|
||||
|
||||
lobby_list_container = VBoxContainer.new()
|
||||
lobby_list_container.add_constant_override("separation", 6)
|
||||
scroll.add_child(lobby_list_container)
|
||||
|
||||
lobby_empty_label = Label.new()
|
||||
lobby_empty_label.text = "Noch keine Lobbys geladen."
|
||||
lobby_empty_label.autowrap = true
|
||||
lobby_list_container.add_child(lobby_empty_label)
|
||||
|
||||
var refresh_button: Button = Button.new()
|
||||
refresh_button.text = "Refresh"
|
||||
refresh_button.rect_min_size = Vector2(390, 36)
|
||||
refresh_button.connect("pressed", self, "find_lobbies")
|
||||
browser_column.add_child(refresh_button)
|
||||
|
||||
var action_column: VBoxContainer = VBoxContainer.new()
|
||||
action_column.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
action_column.add_constant_override("separation", 10)
|
||||
browser_view.add_child(action_column)
|
||||
|
||||
var create_box: PanelContainer = PanelContainer.new()
|
||||
create_box.add_stylebox_override("panel", _make_panel_style(Color(0.105, 0.11, 0.12, 0.95), Color(0.28, 0.31, 0.34, 1.0), 12))
|
||||
action_column.add_child(create_box)
|
||||
|
||||
var create_content: VBoxContainer = VBoxContainer.new()
|
||||
create_content.add_constant_override("separation", 8)
|
||||
create_box.add_child(create_content)
|
||||
|
||||
var create_title: Label = Label.new()
|
||||
create_title.text = "LOBBY ERSTELLEN"
|
||||
create_content.add_child(create_title)
|
||||
|
||||
lobby_name_input = LineEdit.new()
|
||||
lobby_name_input.placeholder_text = "Lobbyname"
|
||||
lobby_name_input.rect_min_size = Vector2(360, 34)
|
||||
create_content.add_child(lobby_name_input)
|
||||
|
||||
lobby_password_check = CheckBox.new()
|
||||
lobby_password_check.text = "Passwort verwenden"
|
||||
create_content.add_child(lobby_password_check)
|
||||
|
||||
lobby_password_input = LineEdit.new()
|
||||
lobby_password_input.placeholder_text = "Passwort"
|
||||
lobby_password_input.secret = true
|
||||
lobby_password_input.rect_min_size = Vector2(360, 34)
|
||||
create_content.add_child(lobby_password_input)
|
||||
|
||||
var host_button: Button = Button.new()
|
||||
host_button.text = "Host Lobby"
|
||||
host_button.rect_min_size = Vector2(360, 38)
|
||||
host_button.connect("pressed", self, "_create_lobby_from_ui")
|
||||
create_content.add_child(host_button)
|
||||
panel_default_focus = host_button
|
||||
|
||||
var join_box: PanelContainer = PanelContainer.new()
|
||||
join_box.add_stylebox_override("panel", _make_panel_style(Color(0.105, 0.11, 0.12, 0.95), Color(0.28, 0.31, 0.34, 1.0), 12))
|
||||
action_column.add_child(join_box)
|
||||
|
||||
var join_content: VBoxContainer = VBoxContainer.new()
|
||||
join_content.add_constant_override("separation", 8)
|
||||
join_box.add_child(join_content)
|
||||
|
||||
var join_title: Label = Label.new()
|
||||
join_title.text = "AUSGEWAEHLTE LOBBY"
|
||||
join_content.add_child(join_title)
|
||||
|
||||
selected_lobby_label = Label.new()
|
||||
selected_lobby_label.text = "Keine Lobby ausgewaehlt."
|
||||
selected_lobby_label.autowrap = true
|
||||
selected_lobby_label.rect_min_size = Vector2(360, 58)
|
||||
join_content.add_child(selected_lobby_label)
|
||||
|
||||
join_password_input = LineEdit.new()
|
||||
join_password_input.placeholder_text = "Passwort, falls noetig"
|
||||
join_password_input.secret = true
|
||||
join_password_input.rect_min_size = Vector2(360, 34)
|
||||
join_content.add_child(join_password_input)
|
||||
|
||||
var join_button: Button = Button.new()
|
||||
join_button.text = "Join Lobby"
|
||||
join_button.rect_min_size = Vector2(360, 38)
|
||||
join_button.connect("pressed", self, "_join_selected_lobby_from_ui")
|
||||
join_content.add_child(join_button)
|
||||
|
||||
lobby_view = VBoxContainer.new()
|
||||
lobby_view.name = "LobbyRoom"
|
||||
lobby_view.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
lobby_view.add_constant_override("separation", 12)
|
||||
lobby_view.visible = false
|
||||
box.add_child(lobby_view)
|
||||
|
||||
lobby_title_label = Label.new()
|
||||
lobby_title_label.text = "WARTEBEREICH"
|
||||
lobby_title_label.add_color_override("font_color", Color(0.92, 0.96, 1.0, 1.0))
|
||||
lobby_view.add_child(lobby_title_label)
|
||||
|
||||
lobby_detail_label = Label.new()
|
||||
lobby_detail_label.text = "Noch nicht in einer Lobby."
|
||||
lobby_detail_label.autowrap = true
|
||||
lobby_view.add_child(lobby_detail_label)
|
||||
|
||||
lobby_members_container = GridContainer.new()
|
||||
lobby_members_container.columns = 2
|
||||
lobby_members_container.add_constant_override("hseparation", 10)
|
||||
lobby_members_container.add_constant_override("vseparation", 10)
|
||||
lobby_members_container.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
lobby_view.add_child(lobby_members_container)
|
||||
|
||||
var lobby_actions: HBoxContainer = HBoxContainer.new()
|
||||
lobby_actions.add_constant_override("separation", 8)
|
||||
lobby_view.add_child(lobby_actions)
|
||||
|
||||
_add_panel_button(lobby_actions, "Ping", "send_ping")
|
||||
_add_panel_button(lobby_actions, "Leave", "leave_lobby")
|
||||
_add_panel_button(lobby_actions, "Browser", "_show_browser_view")
|
||||
|
||||
panel_log_label = Label.new()
|
||||
panel_log_label.text = "Ready"
|
||||
panel_log_label.autowrap = true
|
||||
panel_log_label.rect_min_size = Vector2(480, 78)
|
||||
panel_log_label.rect_min_size = Vector2(820, 44)
|
||||
box.add_child(panel_log_label)
|
||||
|
||||
status_layer.add_child(panel)
|
||||
_show_browser_view()
|
||||
_update_debug_panel()
|
||||
|
||||
|
||||
func _add_panel_button(parent: Control, label: String, method_name: String) -> Button:
|
||||
var button: Button = Button.new()
|
||||
button.text = label
|
||||
button.rect_min_size = Vector2(236, 34)
|
||||
button.rect_min_size = Vector2(130, 36)
|
||||
button.connect("pressed", self, method_name)
|
||||
parent.add_child(button)
|
||||
return button
|
||||
|
||||
|
||||
func _make_panel_style(bg: Color, border: Color, margin: int) -> StyleBoxFlat:
|
||||
var style: StyleBoxFlat = StyleBoxFlat.new()
|
||||
style.bg_color = bg
|
||||
style.border_color = border
|
||||
style.set_border_width_all(1)
|
||||
style.set_corner_radius_all(3)
|
||||
style.content_margin_left = margin
|
||||
style.content_margin_right = margin
|
||||
style.content_margin_top = margin
|
||||
style.content_margin_bottom = margin
|
||||
return style
|
||||
|
||||
|
||||
func _create_lobby_from_ui() -> void:
|
||||
var password := ""
|
||||
if lobby_password_check != null and lobby_password_check.pressed and lobby_password_input != null:
|
||||
password = lobby_password_input.text
|
||||
var display_name := ""
|
||||
if lobby_name_input != null:
|
||||
display_name = lobby_name_input.text
|
||||
create_lobby(password, display_name)
|
||||
|
||||
|
||||
func _join_selected_lobby_from_ui() -> void:
|
||||
if selected_lobby_id == 0:
|
||||
_log("select a lobby before joining")
|
||||
return
|
||||
var summary: Dictionary = _get_selected_lobby_summary()
|
||||
if summary.has("has_password") and bool(summary["has_password"]):
|
||||
var entered := ""
|
||||
if join_password_input != null:
|
||||
entered = join_password_input.text
|
||||
if _hash_password(entered) != str(summary.get("password_hash", "")):
|
||||
_log("wrong or missing lobby password")
|
||||
return
|
||||
join_lobby(selected_lobby_id)
|
||||
|
||||
|
||||
func _show_browser_view() -> void:
|
||||
if browser_view != null:
|
||||
browser_view.visible = true
|
||||
if lobby_view != null:
|
||||
lobby_view.visible = false
|
||||
_update_lobby_browser()
|
||||
|
||||
|
||||
func _show_lobby_view() -> void:
|
||||
if browser_view != null:
|
||||
browser_view.visible = false
|
||||
if lobby_view != null:
|
||||
lobby_view.visible = true
|
||||
_update_lobby_room()
|
||||
|
||||
|
||||
func _update_lobby_browser() -> void:
|
||||
if lobby_list_container == null:
|
||||
return
|
||||
_clear_children(lobby_list_container)
|
||||
if available_lobbies.empty():
|
||||
lobby_empty_label = Label.new()
|
||||
lobby_empty_label.text = "Keine Brogether-Lobbys gefunden.\nErstelle eine neue Lobby oder druecke Refresh."
|
||||
lobby_empty_label.autowrap = true
|
||||
lobby_empty_label.rect_min_size = Vector2(360, 80)
|
||||
lobby_list_container.add_child(lobby_empty_label)
|
||||
else:
|
||||
for summary_data in available_lobbies:
|
||||
var summary: Dictionary = summary_data
|
||||
var button: Button = Button.new()
|
||||
button.text = _format_lobby_summary(summary)
|
||||
button.rect_min_size = Vector2(360, 74)
|
||||
button.connect("pressed", self, "_on_lobby_row_pressed", [int(summary["id"])])
|
||||
lobby_list_container.add_child(button)
|
||||
_update_selected_lobby_label()
|
||||
|
||||
|
||||
func _format_lobby_summary(summary: Dictionary) -> String:
|
||||
var lock_text := "PASSWORT" if bool(summary.get("has_password", false)) else "OFFEN"
|
||||
return "%s\n%s/%s Spieler | %s | Host: %s" % [
|
||||
str(summary.get("name", "Brogether Lobby")),
|
||||
str(summary.get("member_count", 0)),
|
||||
str(summary.get("max_members", MAX_LOBBY_MEMBERS)),
|
||||
lock_text,
|
||||
str(summary.get("owner_name", "Unknown"))
|
||||
]
|
||||
|
||||
|
||||
func _on_lobby_row_pressed(target_lobby_id: int) -> void:
|
||||
selected_lobby_id = target_lobby_id
|
||||
_update_selected_lobby_label()
|
||||
|
||||
|
||||
func _update_selected_lobby_label() -> void:
|
||||
if selected_lobby_label == null:
|
||||
return
|
||||
var summary: Dictionary = _get_selected_lobby_summary()
|
||||
if summary.empty():
|
||||
selected_lobby_label.text = "Keine Lobby ausgewaehlt."
|
||||
return
|
||||
var password_text := "Passwort noetig" if bool(summary.get("has_password", false)) else "Kein Passwort"
|
||||
selected_lobby_label.text = "%s\n%s/%s Spieler\n%s" % [
|
||||
str(summary.get("name", "Brogether Lobby")),
|
||||
str(summary.get("member_count", 0)),
|
||||
str(summary.get("max_members", MAX_LOBBY_MEMBERS)),
|
||||
password_text
|
||||
]
|
||||
|
||||
|
||||
func _get_selected_lobby_summary() -> Dictionary:
|
||||
for summary_data in available_lobbies:
|
||||
var summary: Dictionary = summary_data
|
||||
if int(summary.get("id", 0)) == selected_lobby_id:
|
||||
return summary
|
||||
return {}
|
||||
|
||||
|
||||
func _update_lobby_room() -> void:
|
||||
if lobby_members_container == null:
|
||||
return
|
||||
_clear_children(lobby_members_container)
|
||||
if lobby_id == 0:
|
||||
if lobby_title_label != null:
|
||||
lobby_title_label.text = "WARTEBEREICH"
|
||||
if lobby_detail_label != null:
|
||||
lobby_detail_label.text = "Noch nicht in einer Lobby."
|
||||
return
|
||||
var lobby_name: String = _get_lobby_data(lobby_id, "name", "Brogether Lobby")
|
||||
var password_text := "mit Passwort" if _get_lobby_data(lobby_id, "has_password", "0") == "1" else "ohne Passwort"
|
||||
if lobby_title_label != null:
|
||||
lobby_title_label.text = lobby_name.to_upper()
|
||||
if lobby_detail_label != null:
|
||||
lobby_detail_label.text = "Wartebereich %s | %s/%s Spieler | %s" % [str(lobby_id), lobby_members.size(), MAX_LOBBY_MEMBERS, password_text]
|
||||
for member in lobby_members:
|
||||
_add_member_card(member)
|
||||
var empty_slot_count: int = max(0, MAX_LOBBY_MEMBERS - lobby_members.size())
|
||||
for empty_slot in range(empty_slot_count):
|
||||
_add_empty_member_slot(empty_slot)
|
||||
|
||||
|
||||
func _add_member_card(member: Dictionary) -> void:
|
||||
var card: PanelContainer = PanelContainer.new()
|
||||
card.rect_min_size = Vector2(390, 128)
|
||||
card.add_stylebox_override("panel", _make_panel_style(Color(0.12, 0.13, 0.14, 0.96), Color(0.32, 0.36, 0.39, 1.0), 10))
|
||||
lobby_members_container.add_child(card)
|
||||
|
||||
var row: HBoxContainer = HBoxContainer.new()
|
||||
row.add_constant_override("separation", 12)
|
||||
card.add_child(row)
|
||||
|
||||
var avatar: PanelContainer = PanelContainer.new()
|
||||
avatar.rect_min_size = Vector2(74, 74)
|
||||
avatar.add_stylebox_override("panel", _make_panel_style(_avatar_color(int(member.get("steam_id", 0))), Color(0.72, 0.76, 0.8, 1.0), 4))
|
||||
row.add_child(avatar)
|
||||
|
||||
var initials: Label = Label.new()
|
||||
initials.text = _initials(str(member.get("name", "?")))
|
||||
initials.align = Label.ALIGN_CENTER
|
||||
initials.valign = Label.VALIGN_CENTER
|
||||
initials.rect_min_size = Vector2(66, 66)
|
||||
initials.add_color_override("font_color", Color(1, 1, 1, 1))
|
||||
avatar.add_child(initials)
|
||||
|
||||
var text_box: VBoxContainer = VBoxContainer.new()
|
||||
text_box.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_child(text_box)
|
||||
|
||||
var name_label: Label = Label.new()
|
||||
name_label.text = str(member.get("name", "Unknown"))
|
||||
name_label.add_color_override("font_color", Color(0.95, 0.97, 1.0, 1.0))
|
||||
text_box.add_child(name_label)
|
||||
|
||||
var id_label: Label = Label.new()
|
||||
id_label.text = "Steam %s" % str(member.get("steam_id", 0))
|
||||
text_box.add_child(id_label)
|
||||
|
||||
var role_label: Label = Label.new()
|
||||
role_label.text = "Host" if int(member.get("steam_id", 0)) == _current_lobby_owner() else "Player"
|
||||
text_box.add_child(role_label)
|
||||
|
||||
|
||||
func _add_empty_member_slot(_index: int) -> void:
|
||||
var card: PanelContainer = PanelContainer.new()
|
||||
card.rect_min_size = Vector2(390, 128)
|
||||
card.add_stylebox_override("panel", _make_panel_style(Color(0.09, 0.095, 0.105, 0.72), Color(0.2, 0.22, 0.24, 1.0), 10))
|
||||
lobby_members_container.add_child(card)
|
||||
|
||||
var label: Label = Label.new()
|
||||
label.text = "Freier Platz"
|
||||
label.align = Label.ALIGN_CENTER
|
||||
label.valign = Label.VALIGN_CENTER
|
||||
label.rect_min_size = Vector2(360, 96)
|
||||
card.add_child(label)
|
||||
|
||||
|
||||
func _current_lobby_owner() -> int:
|
||||
if steam != null and lobby_id != 0 and steam.has_method("getLobbyOwner"):
|
||||
return int(steam.call("getLobbyOwner", lobby_id))
|
||||
return steam_id if is_host else 0
|
||||
|
||||
|
||||
func _initials(display_name: String) -> String:
|
||||
var clean := display_name.strip_edges()
|
||||
if clean.empty():
|
||||
return "?"
|
||||
var result := ""
|
||||
var parts := clean.split(" ", false)
|
||||
for part in parts:
|
||||
if result.length() >= 2:
|
||||
break
|
||||
if str(part).length() > 0:
|
||||
result += str(part).substr(0, 1).to_upper()
|
||||
if result.empty():
|
||||
result = clean.substr(0, 1).to_upper()
|
||||
return result
|
||||
|
||||
|
||||
func _avatar_color(value: int) -> Color:
|
||||
var colors: Array = [
|
||||
Color(0.25, 0.45, 0.82, 1.0),
|
||||
Color(0.68, 0.35, 0.72, 1.0),
|
||||
Color(0.25, 0.58, 0.48, 1.0),
|
||||
Color(0.74, 0.44, 0.28, 1.0)
|
||||
]
|
||||
var color_index: int = int(abs(value)) % colors.size()
|
||||
return colors[color_index]
|
||||
|
||||
|
||||
func _clear_children(parent: Node) -> void:
|
||||
for child in parent.get_children():
|
||||
parent.remove_child(child)
|
||||
child.queue_free()
|
||||
|
||||
|
||||
func toggle_debug_panel() -> void:
|
||||
if panel != null and panel.visible:
|
||||
close_debug_panel()
|
||||
@@ -535,6 +981,10 @@ func open_debug_panel() -> void:
|
||||
dim_background.visible = true
|
||||
panel.visible = true
|
||||
set_process_input(true)
|
||||
if lobby_id != 0:
|
||||
_show_lobby_view()
|
||||
else:
|
||||
_show_browser_view()
|
||||
if panel_default_focus != null and is_instance_valid(panel_default_focus):
|
||||
panel_default_focus.call_deferred("grab_focus")
|
||||
_update_debug_panel("Panel opened")
|
||||
|
||||
Reference in New Issue
Block a user