Working on UI Logic, will lead to intermediate character creation/selection screen
This commit is contained in:
parent
6352347c4d
commit
22291bf639
8 changed files with 126 additions and 29 deletions
|
|
@ -20,14 +20,6 @@
|
|||
|
||||
### Isolierte Welten auf dem Server
|
||||
|
||||
- Um Physik und Szenen-Bäume sauber zu trennen, wird jede Area auf dem Server in einen eigenen **SubViewport** geladen.
|
||||
- Dies ermöglicht "Multi-World Physics", sodass sich Objekte aus verschiedenen Areas auf dem Server nicht gegenseitig beeinflussen können.
|
||||
|
||||
### Netzwerk-Synchronisation
|
||||
|
||||
- **Visibility Filtering:** `MultiplayerSynchronizer` und `MultiplayerSpawner` werden mit Visibility Filtern versehen. Dadurch wird sichergestellt, dass ein Client nur Updates für die Objekte in seiner eigenen Area erhält.
|
||||
- **Positions-Synchronisation:** Es wird explizit die `position`-Eigenschaft von Nodes synchronisiert, **nicht** `global_position`, um Konflikte mit der SubViewport-Struktur zu vermeiden.
|
||||
|
||||
## 3. Geplante Ordnerstruktur
|
||||
|
||||
Alle Skripte und die dazugehörige Logik sollen thematisch in Unterordnern unter `res://systems/` abgelegt werden:
|
||||
|
|
@ -66,20 +58,16 @@ Alle Skripte und die dazugehörige Logik sollen thematisch in Unterordnern unter
|
|||
Die folgenden Skripte sind als Singletons (Autoloads in Godot) konfiguriert und global verfügbar:
|
||||
|
||||
- **`GameEvents`** (`res://systems/core/game_events.gd`): Zentraler Event-Bus für die Kommunikation zwischen entkoppelten Systemen.
|
||||
- **`NetworkManager`** (`res://systems/network/network_manager.gd`): Verwaltet die gesamte Netzwerklogik, wie das Hosten, Beitreten und die RPC-Kommunikation.
|
||||
- `/data/`: Speicher-Logik, Daten-Wrapper (z.B. für JSON, SQLite).
|
||||
- **`ChatManager`** (`res://systems/network/chat_manager.gd`): Kümmert sich um die Logik des In-Game-Chats.
|
||||
|
||||
## 7. Analyse der existierenden Skripte (Stand: Commit 30b6ade)
|
||||
|
||||
- `/data/`: Speicher-Logik, Daten-Wrapper (z.B. für JSON, SQLite).
|
||||
Dieser Abschnitt beschreibt die Verantwortlichkeiten der zentralen Skripte im Projekt.
|
||||
|
||||
### `/game_root.gd`
|
||||
- **Rolle:** Absoluter Startpunkt des Spiels.
|
||||
- **Verantwortlichkeit:** Hält die Instanz des Hauptmenüs (`main.tscn`). Seine einzige Aufgabe ist es, zu existieren und die initiale Szene zu laden. Die eigentliche Logik wird sofort an die globalen Manager und das UI delegiert.
|
||||
|
||||
### `/systems/core/game_events.gd` (Autoload: `GameEvents`)
|
||||
- **Rolle:** Globaler Event-Bus.
|
||||
- **Verantwortlichkeit:** Dient als zentrale Sammelstelle für Signale, um verschiedene Systeme voneinander zu entkoppeln. Zum Beispiel sendet das UI ein `host_requested` Signal, auf das der `NetworkManager` hört, ohne dass die beiden sich direkt kennen müssen.
|
||||
|
||||
### `/systems/network/network_manager.gd` (Autoload: `NetworkManager`)
|
||||
- **Rolle:** Das Herzstück der gesamten Anwendung.
|
||||
|
|
@ -114,16 +102,14 @@ Dieser Abschnitt beschreibt die Verantwortlichkeiten der zentralen Skripte im Pr
|
|||
|
||||
* **Thinking-Phase:** Analysiere vor der Code-Ausgabe, ob Änderungen die SubViewport-Isolation oder die Server-Autorität beeinflussen könnten.
|
||||
* **Minimaler Eingriff:** Verändere nur angeforderte Logik. Behalte Kommentare und Signal-Strukturen bei.
|
||||
* **Stil:** Schreibe sauberen, performanten GDScript 2.0 Code. Bevorzuge Komposition gegenüber Vererbung.
|
||||
- **Spieler-Spawning:** Koordiniert den komplexen Prozess des Spieler-Spawns. Weist den Client an, eine Szene zu laden (`client_load_area`), wartet auf dessen Bereitschaftsmeldung (`client_ready_to_spawn`) und instanziiert dann den Spieler-Avatar serverseitig in der korrekten Sub-Welt.
|
||||
|
||||
### Technische Details
|
||||
|
||||
Es gibt kein async Keyword, aber await funktioniert trotzdem. => await get_tree().process_frame
|
||||
|
||||
### Dynamische Konfiguration des MultiplayerSynchronizer
|
||||
- **Spieler-Spawning:** Koordiniert den komplexen Prozess des Spieler-Spawns. Weist den Client an, eine Szene zu laden (`client_load_area`), wartet auf dessen Bereitschaftsmeldung (`client_ready_to_spawn`) und instanziiert dann den Spieler-Avatar serverseitig in der korrekten Sub-Welt.
|
||||
|
||||
Die Konfiguration des `MultiplayerSynchronizer` für wiederverwendbare Szenen (wie den Spieler) ist kritisch und muss korrekt gehandhabt werden, um Timing- und Pfad-Probleme zu vermeiden. Die folgenden vier Regeln sind entscheidend:
|
||||
|
||||
1. **Konfiguration nur per Code:** Die Konfiguration muss zur Laufzeit im Code erfolgen, nicht im Editor. Der Editor speichert absolute Pfade, die in einem dynamischen Szenen-Setup (mehrere Welten/Viewports) unbrauchbar sind.
|
||||
|
||||
2. **Ort der Konfiguration: `_ready()`:** Die Logik zur Erstellung der `SceneReplicationConfig` gehört in die `_ready()`-funktion des Skripts, dessen Eigenschaften synchronisiert werden sollen (z.B. `player_controller.gd`).
|
||||
|
|
@ -132,6 +118,8 @@ Die Konfiguration des `MultiplayerSynchronizer` für wiederverwendbare Szenen (w
|
|||
- **Korrekt:** `config.add_property(":sync_position")`
|
||||
- **Falsch:** `config.add_property("sync_position")` oder `config.add_property("..:sync_position")`
|
||||
|
||||
- **Falsch:** `config.add_property("sync_position")` oder `config.add_property("..:sync_position")`
|
||||
|
||||
### Dynamische Konfiguration des MultiplayerSpawner
|
||||
|
||||
- Handhabt nicht nur originäre Objekterzeugung in den Levels, sondern auch Objektaktualisierungen für "Late Joiner"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
[ext_resource type="Script" uid="uid://162cjpb4lac4" path="res://game_root.gd" id="1_xj5yv"]
|
||||
[ext_resource type="PackedScene" uid="uid://bhywhrlwjox6t" path="res://ui/menus/main_menu.tscn" id="2_pjpa4"]
|
||||
[ext_resource type="PackedScene" uid="uid://ca2bhph2k3xpy" path="res://ui/character_select/character_select.tscn" id="3_bxsma"]
|
||||
[ext_resource type="PackedScene" uid="uid://lb6btb6426mi" path="res://ui/account/login.tscn" id="3_lkrbl"]
|
||||
|
||||
[node name="Game_root" type="Node2D" unique_id=1336425327]
|
||||
script = ExtResource("1_xj5yv")
|
||||
|
|
@ -10,4 +11,7 @@ script = ExtResource("1_xj5yv")
|
|||
[node name="MainMenu" parent="." unique_id=1731390780 instance=ExtResource("2_pjpa4")]
|
||||
visible = false
|
||||
|
||||
[node name="Login" parent="." unique_id=1694671237 instance=ExtResource("3_lkrbl")]
|
||||
|
||||
[node name="CharacterSelect" parent="." unique_id=2079351175 instance=ExtResource("3_bxsma")]
|
||||
visible = false
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
class_name CharacterData
|
||||
|
||||
var id: int = -1 # Eindeutige ID (wird später wichtig)
|
||||
var name: String = "New Hero"
|
||||
var id: String = "" # UUID des Charakters
|
||||
var name: String = "Neuer Held"
|
||||
var level: int = 1
|
||||
var area: String = "keuwin_grasland" # Start-Area
|
||||
var area: String = "keuwin_grasland"
|
||||
var position: Vector3 = Vector3.ZERO
|
||||
var testvariable: String = "test"
|
||||
# Hier kommen später noch Inventar, Ausrüstung, etc. hinzu...
|
||||
|
|
|
|||
18
weltenauge/ui/account/login.gd
Normal file
18
weltenauge/ui/account/login.gd
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
extends Control
|
||||
|
||||
@onready var ip_input: TextEdit = $IPInput
|
||||
|
||||
func _on_host_button_pressed() -> void:
|
||||
print("host pressed")
|
||||
GameEvents.host_requested.emit()
|
||||
hide()
|
||||
|
||||
func _on_join_button_pressed():
|
||||
var username = $UsernameLineEdit.text
|
||||
var password = $PasswordLineEdit.text # TODO: Handle Password
|
||||
|
||||
# Hier findet später die Prüfung gegen den Server statt
|
||||
# Im Moment simulieren wir einfach einen erfolgreichen Login
|
||||
#TODO
|
||||
GameEvents.join_requested.emit(ip_input.text)
|
||||
hide()
|
||||
1
weltenauge/ui/account/login.gd.uid
Normal file
1
weltenauge/ui/account/login.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c6yngwnpqsnpi
|
||||
82
weltenauge/ui/account/login.tscn
Normal file
82
weltenauge/ui/account/login.tscn
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
[gd_scene format=3 uid="uid://lb6btb6426mi"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c6yngwnpqsnpi" path="res://ui/account/login.gd" id="1_x74xt"]
|
||||
|
||||
[node name="Login" type="Control" unique_id=1694671237]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
offset_left = 23.0
|
||||
offset_top = 102.0
|
||||
offset_right = 23.0
|
||||
offset_bottom = 102.0
|
||||
script = ExtResource("1_x74xt")
|
||||
|
||||
[node name="IPInput" type="TextEdit" parent="." unique_id=1340335140]
|
||||
custom_minimum_size = Vector2(150, 40)
|
||||
layout_mode = 0
|
||||
offset_left = 375.0
|
||||
offset_top = -70.0
|
||||
offset_right = 525.0
|
||||
offset_bottom = -30.0
|
||||
text = "127.0.0.1"
|
||||
editable = false
|
||||
|
||||
[node name="Join_Button" type="Button" parent="." unique_id=811892478]
|
||||
layout_mode = 0
|
||||
offset_left = 30.0
|
||||
offset_top = 12.0
|
||||
offset_right = 231.0
|
||||
offset_bottom = 43.0
|
||||
text = "Join"
|
||||
|
||||
[node name="Host_Button" type="Button" parent="." unique_id=1465654892]
|
||||
layout_mode = 0
|
||||
offset_left = 313.0
|
||||
offset_top = 11.0
|
||||
offset_right = 530.0
|
||||
offset_bottom = 42.0
|
||||
text = "Host"
|
||||
|
||||
[node name="lb_User" type="Label" parent="." unique_id=1356001317]
|
||||
layout_mode = 0
|
||||
offset_left = 21.0
|
||||
offset_top = -72.0
|
||||
offset_right = 62.0
|
||||
offset_bottom = -49.0
|
||||
text = "User:"
|
||||
|
||||
[node name="lb_User" type="Label" parent="lb_User" unique_id=463394394]
|
||||
layout_mode = 0
|
||||
offset_left = 286.0
|
||||
offset_top = 11.0
|
||||
offset_right = 340.0
|
||||
offset_bottom = 34.0
|
||||
text = "Server:"
|
||||
|
||||
[node name="lb_Password" type="Label" parent="." unique_id=1027088176]
|
||||
layout_mode = 0
|
||||
offset_left = 18.0
|
||||
offset_top = -39.0
|
||||
offset_right = 94.0
|
||||
offset_bottom = -16.0
|
||||
text = "Passwort:"
|
||||
|
||||
[node name="UsernameLineEdit" type="LineEdit" parent="." unique_id=1896094376]
|
||||
layout_mode = 0
|
||||
offset_left = 122.0
|
||||
offset_top = -72.0
|
||||
offset_right = 231.0
|
||||
offset_bottom = -41.0
|
||||
text = "test"
|
||||
|
||||
[node name="PasswordLineEdit" type="LineEdit" parent="." unique_id=214865529]
|
||||
layout_mode = 0
|
||||
offset_left = 121.0
|
||||
offset_top = -38.0
|
||||
offset_right = 230.0
|
||||
offset_bottom = -7.0
|
||||
text = "test"
|
||||
|
||||
[connection signal="pressed" from="Join_Button" to="." method="_on_join_button_pressed"]
|
||||
[connection signal="button_up" from="Host_Button" to="." method="_on_host_pressed"]
|
||||
[connection signal="pressed" from="Host_Button" to="." method="_on_host_button_pressed"]
|
||||
|
|
@ -12,10 +12,12 @@ func _ready():
|
|||
func load_characters():
|
||||
# (Hier kommt die Logik zum Durchsuchen des "user://" Ordners nach JSON-Dateien hin)
|
||||
# (Für den Anfang können wir einfach einen Standard-Charakter erstellen)
|
||||
var data = SaveLoad.load_character()
|
||||
#var data = SaveLoad.load_character()
|
||||
|
||||
var data = null
|
||||
if data == null:
|
||||
data = CharacterData.new()
|
||||
data.id = 1 # Eindeutige ID generieren (später)
|
||||
data.id = "000001" # Eindeutige ID generieren (später)
|
||||
characters = [data]
|
||||
SaveLoad.save_character(data)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -2,12 +2,16 @@ extends Control
|
|||
|
||||
@onready var ip_input: TextEdit = $IPInput
|
||||
|
||||
func _on_host_pressed():
|
||||
func _on_host_button_pressed() -> void:
|
||||
print("host pressed")
|
||||
GameEvents.host_requested.emit()
|
||||
hide()
|
||||
|
||||
func _on_join_pressed():
|
||||
print("join pressed")
|
||||
func _on_join_button_pressed():
|
||||
var username = $UsernameLineEdit.text
|
||||
var password = $PasswordLineEdit.text # TODO: Handle Password
|
||||
|
||||
# Hier findet später die Prüfung gegen den Server statt
|
||||
# Im Moment simulieren wir einfach einen erfolgreichen Login
|
||||
#TODO
|
||||
GameEvents.join_requested.emit(ip_input.text)
|
||||
hide()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue