diff --git a/weltenauge/PROJEKT_UEBERSICHT.md b/weltenauge/PROJEKT_UEBERSICHT.md index 6a00c36..9d88359 100644 --- a/weltenauge/PROJEKT_UEBERSICHT.md +++ b/weltenauge/PROJEKT_UEBERSICHT.md @@ -2,6 +2,14 @@ "weltenauge" ist ein von Neverwinter Nights (NWN) inspiriertes Multiplayer-Rollenspiel. Das Kernstück ist eine robuste Client/Server-Architektur, die in einer einzigen Godot-Codebase umgesetzt wird. +Dies ist ein "Ewigkeits-Projekt", das nichtkommerziell ist, und +vom Entwickler immer wieder für längere Zeit weggelegt wird. Fokus liegt auf 3D Welten und Weltensimulation. +Dadurch ist es notwendig, dass das gesamte System so modular und +selbsterklärend aufgebaut wird, dass eine Rückkehr zum Projekt nach +langer Pause immer noch machbar ist. Features sind daher soweit einzuschränken, +dass ein absolut Minimaler Prototyp in einem vernünftigen Zeitraum erstellbar wird. +Ausserdem ist Modularität und einfache Testbarkeit Pflicht. + ## 2. Kernkonzepte der Architektur ### Client/Server-Modell diff --git a/weltenauge/systems/network/network_manager.gd b/weltenauge/systems/network/network_manager.gd index c25ef37..84d4c1a 100644 --- a/weltenauge/systems/network/network_manager.gd +++ b/weltenauge/systems/network/network_manager.gd @@ -161,6 +161,7 @@ func _spawn_player_in_world(id, spawn_target_node): var player_scene = load("res://systems/player/player.tscn") var player = player_scene.instantiate() player.name = str(id) + player.get_node("PlayerNameLabel").text = str(id) #player.set_multiplayer_authority(id) player.set_multiplayer_authority(1) diff --git a/weltenauge/systems/player/player.tscn b/weltenauge/systems/player/player.tscn index dcda304..889015c 100644 --- a/weltenauge/systems/player/player.tscn +++ b/weltenauge/systems/player/player.tscn @@ -5,15 +5,16 @@ [sub_resource type="CylinderShape3D" id="CylinderShape3D_ktl23"] +[sub_resource type="SystemFont" id="SystemFont_ktl23"] + [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_fqfg4"] [node name="CharacterBody3D" type="CharacterBody3D" unique_id=682006733 groups=["players"]] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.26067275) script = ExtResource("1_ktl23") interpolation_speed = 5.0 [node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=159496934] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0185384, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0185384, -0.18054307) shape = SubResource("CylinderShape3D_ktl23") [node name="Visuals" type="Node3D" parent="." unique_id=1840405751] @@ -24,6 +25,13 @@ transform = Transform3D(-0.99988204, 0, 0.015358234, 0, 1, 0, -0.015358234, 0, - [node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1343500738] root_node = NodePath("../..") +[node name="PlayerNameLabel" type="Label3D" parent="." unique_id=461683617] +transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 0.73133814, 0) +text = "-label-" +font = SubResource("SystemFont_ktl23") +vertical_alignment = 2 +uppercase = true + [node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=656518492] replication_interval = 0.05 replication_config = SubResource("SceneReplicationConfig_fqfg4") diff --git a/weltenauge/systems/player/player_controller.gd b/weltenauge/systems/player/player_controller.gd index bae3ec7..796c57b 100644 --- a/weltenauge/systems/player/player_controller.gd +++ b/weltenauge/systems/player/player_controller.gd @@ -28,6 +28,7 @@ func _ready(): # 'sync_position': Der Name der Eigenschaft. config.add_property(NodePath(":sync_position")) config.add_property(NodePath(":sync_rotation")) + config.add_property(NodePath("PlayerNameLabel:text")) # Die generierte Konfiguration dem Synchronizer zuweisen. Dies überschreibt alle Editor-Einstellungen. synchronizer.replication_config = config # --- ENDE: Dynamische Replikations-Konfiguration --- @@ -36,6 +37,7 @@ func _ready(): # Wir schalten die automatische Physik-Synchronisation aus set_physics_process(multiplayer.is_server()) + func _physics_process(delta): # Dieser Teil läuft NUR auf dem Server if path.size() > 0: diff --git a/weltenauge/systems/player/tests/test_player_movement.gd b/weltenauge/systems/player/tests/test_player_movement.gd new file mode 100644 index 0000000..9d0a966 --- /dev/null +++ b/weltenauge/systems/player/tests/test_player_movement.gd @@ -0,0 +1,85 @@ +# test_player_movement.gd +extends Node + +#@onready var multiplayer = MultiplayerPeerExtension.new() +var player: CharacterBody3D +var initial_position: Vector3 + +func _ready(): + # 1. Szene laden + var test_scene = load("res://maps/outdoor/grass/keuwin_grasland.tscn").instantiate() + add_child(test_scene) + + # 2. MultiplayerSpawner finden und Player erstellen + var spawner = test_scene.get_node("AreaSpawner") + if not spawner: + printerr("Kein Spawner gefunden!") + queue_free() # Test beenden + + # Test-Spieler erstellen + var player_scene = load("res://systems/player/player.tscn") + player = player_scene.instantiate() + player.name = "TestPlayer" + spawner.get_parent().add_child(player) + + # Initialen Zustand speichern + initial_position = player.global_position + print("Initial position: ", initial_position) + + # 3. Test starten (verzögert, damit alles geladen ist) + call_deferred("start_test") + +func start_test(): + print("Starte Bewegungstest...") + + # Simulieren eines Klicks + var target_position = Vector3(5, 0, 5) # Irgendein Punkt in der Nähe + print("Simuliere Klick auf: ", target_position) + + # Hier MÜSSEN wir den RPC direkt aufrufen. InputEvent geht nicht. + player.request_move.rpc_id(1, target_position) # 1 = Server + + # Auf Bewegung warten (etwas unsauber, aber für den Moment ok) + await get_tree().create_timer(1.0).timeout # Warte 1 Sekunde + + # Ergebnis überprüfen + var new_position = player.global_position + print("Neue Position: ", new_position) + + # Toleranz, da die Bewegung nicht exakt sein muss + var tolerance = 0.5 + if new_position.distance_to(initial_position) > tolerance: + print("Test erfolgreich! Avatar hat sich bewegt.") + else: + printerr("Test fehlgeschlagen! Avatar hat sich nicht bewegt.") + + # Test beenden (optional) + queue_free() + + + +"""Erläuterungen: + +1.) Szene laden: Lädt eine Test-Szene (keuwin_grasland.tscn). Das heisst, diese muss eine Spawner Instanz mit dem Namen AreaSpawner enthalten. +2.) Avatar erzeugen: Sucht den Spawner und erzeugt einen Avatar (keinen Multiplayer, nur lokal für den Test). +3.) Test starten (deferred): Startet den Test in start_test(), um sicherzustellen, dass alles geladen ist. +4.) Simulierter Klick: Sendet den request_move-RPC direkt an den Avatar. +5.) Warten: Wartet 1 Sekunde (eine sehr einfache, blockierende Methode). +6.) Ergebnis prüfen: Vergleicht die neue Position mit der alten. + +Wie man diesen Test benutzt: + +1.) Erstelle eine neue Szene (z.B. test_scene.tscn). +2.) Füge einen Node vom Typ Node als Root hinzu. +3.) Speichere das obige Skript (test_player_movement.gd) im Ordner /systems/player/. +3.) Füge ein Script Node hinzu und weise ihm das Skript test_player_movement.gd zu. +4.) Starte die Szene test_scene.tscn. +5.) Das Skript sollte automatisch ablaufen, die Ergebnisse in der Konsole ausgeben und sich dann selbst beenden. + +Wichtige Einschränkungen: + +Kein echter Multiplayer: Dies ist ein reiner Einzelspieler-Test. Er prüft nur, ob sich der lokale Avatar bewegt. +Blockierendes Warten: Die Verwendung von create_timer(1.0).timeout.await blockiert den Haupt-Thread. Für einen echten Test wäre das schlecht, aber für unseren einfachen Zweck ist es akzeptabel. +Geringe Präzision: Der Toleranzwert von 0.5 bedeutet, dass kleine Bewegungen möglicherweise nicht erkannt werden. +Keine Fehlerbehandlung: Wenn irgendetwas schiefgeht (kein Spawner, keine Szene, falscher Node-Name), bricht der Test einfach ab. +Auch mit diesen Einschränkungen ist dieser Test extrem wertvoll. Er gibt uns eine schnelle und einfache Möglichkeit, um sicherzustellen, dass die grundlegende Click-to-Move-Mechanik weiterhin funktioniert, wenn wir Änderungen am Code vornehmen.""" diff --git a/weltenauge/systems/player/tests/test_player_movement.gd.uid b/weltenauge/systems/player/tests/test_player_movement.gd.uid new file mode 100644 index 0000000..614c559 --- /dev/null +++ b/weltenauge/systems/player/tests/test_player_movement.gd.uid @@ -0,0 +1 @@ +uid://c8p3yn461hle1