champions-of-luneraria/docs/port/U4-NETWORK.md
Martin Stickelbroeck d590fdebeb U4-Nachtrag: Startbildschirm in der Szene, Rückkehr aus der Partie
Befund aus dem Spieltest des U3-Nachtrags: Nichts legte LuneNetPlay in die
Szene. Das Spiel begann direkt in einer Partie, der Startbildschirm aus U4
war unerreichbar, und der Verlassen-Dialog beendete das Spiel statt zum
Hauptmenü zu führen.

- LuneWorldBuilder legt LuneNetPlay auf das Match-Objekt; Szene neu gebaut.
- Das Menü bekommt ein eigenes UIDocument über dem HUD. Vorher hing es an
  keinem Panel, und das HUD hätte es beim ersten Partiestart geleert.
- Rückkehr über „Menü“ → „Zum Menü“: HUD und Aufstellungsflächen weg,
  Sitzung beendet, leere Karte. Die Kamera ruht hinter dem Menü und beginnt
  jede Partie ungedreht. Die Bund-Wahl ist markiert, die Knopfreihe passt
  in die Tafel.
- Tests und Benchmark ohne Startbildschirm (LuneMatchDriver.DirectStart,
  -luneBenchmark); Bot-Partien und Fingerabdrücke unverändert.
- Neu: LuneSmoke (-luneSmoke <Ordner>), Selbsttest eines Players nach
  lune_smoke.gd. StartScreenTests führt ihn im Editor aus.
- Tests: EditMode 29/29, PlayMode 14/14 (StartScreenTests 26/26), Verify
  718/0, Fingerabdrücke DCE95C96556F3A1A und 7B8E43AEFC0D60C5 unverändert.
  macOS-Player: Selbsttest 26/26, Bilder in
  docs/port/screenshots/u4/startbildschirm/. Ein zusammenhängender
  PlayMode-Lauf auf dem Endstand und ein Player-Benchmark stehen aus, weil
  der Mac zugeklappt schlief (siehe U4-NETWORK.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:37:51 +02:00

12 KiB
Raw Blame History

U4 · Netzwerk

Stand: 2. Oktober 2026 · fertig (luneraria/u4 = 769e622). Nachtrag vom 7. Oktober 2026: Startbildschirm in der Szene (unten).

Es wurde keine neue Architektur erfunden. Übertragen ist der M4-Umfang (lune_session.gd, Protokoll 4), serverautoritativ:

  • Clients senden Absichten.
  • Der Host berechnet Gold, Käufe, Kampf, Schaden, Besitz, Boss und Sieg.

Umsetzung

Baustein Ort Inhalt
LuneSession Assets/Luneraria/Core/Net/LuneSession.cs autoritative Sitzung (Port von lune_session.gd): Rollen, Sitze, Lobby, Hallo/Beitritt/Wiedereinstieg, Befehle, Bereit, Kampfbeginn, Momentaufnahmen, Abrechnung, Revanche, Disconnect
NetModel Assets/Luneraria/Core/Net/NetModel.cs Sitzungsmodelle (Lobby, öffentlicher Zustand, Einheitenätzeze, Rahmen) und ILuneNetLink
LuneLoopback Assets/Luneraria/Core/Net/LuneLoopback.cs In-Prozess-Transport für die Protokoll- und Mehr-Runden-Tests
LuneWire Assets/Luneraria/Net/LuneWire.cs Codierung der Nachrichten (Art + Payload, Cursor-Codec) und der Kampfrahmen
LuneTcp Assets/Luneraria/Net/LuneTcp.cs TCP-Transport (Ersatz für ENet): ein Socket je Gast, zuverlässige Nachrichten und Rahmen, Pump auf dem Spielthread
LuneMainMenu Assets/Luneraria/UI/Game/LuneMainMenu.cs Startbildschirm: Allein spielen, Hosten, Beitreten, Bund, Lane, Name, Adresse, Port
LuneNetPlay Assets/Luneraria/UI/Game/LuneNetPlay.cs Schale um Sitzung und Transport (Port von lune_main.gd): Menü, Partie, Rückkehr, Revanche. Seit dem Nachtrag legt LuneWorldBuilder sie in die Szene
LuneSmoke Assets/Luneraria/UI/Game/LuneSmoke.cs Selbsttest eines Players über den Startbildschirm (nach lune_smoke.gd), -luneSmoke <Ordner>; Nachtrag
LuneGame Assets/Luneraria/UI/Game/LuneGame.cs Befehle, Rückgängig und Bereit gehen im Netzspiel über die Sitzung; Gast zeigt nur Host-Rahmen

Offline ist ein lokaler Host mit Bot-Plätzen (LuneSession.HostOffline). Hosten und Beitreten nutzen LuneTcp mit LuneWire. Peer 1 ist der Host; freie Plätze bleiben Bots.

Erfasster M4-Umfang

Funktion Verhalten in der Referenz im Port
Rollen offline (lokaler Host mit Bot-Plätzen), Host (ENet-Server, bis 5 Gäste), Gast erfüllt (offline, Host, Gast; TCP statt ENet)
Sechs Plätze ein Peer genau ein Platz; freie Plätze spielen Bots; Lobbyeinträge mit Name, Bereit, Bot erfüllt
Beitritt Hallo mit Protokollversion und Name; falsche Version wird abgelehnt; Namen gekürzt (24 Zeichen); volle Partie abgelehnt erfüllt
Private Planung ein Gast sendet Befehle für seinen Platz; fremde Plätze werden abgelehnt (Spoof-Schutz); der Zustand enthält nur den eigenen Entwurf erfüllt
Bereit nach Bereit ist die Planung verbindlich; alle bereit → Kampf; Bots planen einmal je Runde erfüllt
Kampfsynchronisation Kampfbeginn mit Einheitenätzen und Gebäude-HP; alle 0,05 s neue Einheiten und ein Frame (13 Werte je Einheit, ungeordnet-zuverlässig); Gast interpoliert, verspätete Frames werden verworfen erfüllt (Rahmen mit Serial; späte Frames verworfen)
Abrechnung Host sendet den öffentlichen Zustand nach dem Kampf erfüllt
Disconnect Platz geht an einen Bot, der in der Planung sofort plant; niemals Kernverlust erfüllt
Wiedereinstieg gleicher Name, solange der Platz bot-gehalten ist → Platz zurück, volle Synchronisation erfüllt
Übernahme ein neuer Mensch verwirft den unbestätigten Bot-Entwurf und muss selbst bereit melden erfüllt
Revanche Host startet neu, Plätze bleiben erfüllt
Hostverlust Gast kehrt mit Meldung ins Menü zurück erfüllt
Tests test_lune_net 43 Prüfungen, net_rounds.py Loopback mit zwei Prozessen 12 Prüfungen erfüllt: NetSuite 43/43, NetRoundsSuite 12/12 (In-Prozess-Loopback statt zwei Prozesse)

Prüfung

Test Ergebnis
NetSuite (Port von test_lune_net.gd) 43/43: Sitzplatzbesitz und Spoof, veraltete Befehle, Doppelkauf, fremde UID, Disconnect ohne Kernschaden, sechs Plätze und Phasen, Hallo und Wiedereinstieg, Bot-Übernahme und einmaliges Bot-Planen, Bereit verbindlich und Privatsphäre der Entwürfe
NetRoundsSuite (Port von net_rounds.py) 12/12: Host und Gast spielen 5 Runden, Prüfsummen nach jeder Abrechnung gleich, Gast rechnet 0 Kampfschritte und erhält Rahmen, Gast A trennt im Kampf von Runde 2, Bot übernimmt, Gast B kehrt mit demselben Namen auf denselben Sitz zurück
LuneWireTests Round-trip von Befehlen, öffentlichem Zustand (inkl. Entwurf, Hero, Buchungen), Einheitenätzen, Rahmen, Lobby und Optionen
EditMode gesamt 29/29 (Kern 9 inkl. NetProtocol und NetRounds, Wire 4, Integration 2, UI-Modell 12, Bildraten 4)
PlayMode gesamt 13/13 (Szene, Vertical Function Test, Capture, Verify A–I, UI-Toolkit-Probe); Bildwerkzeuge und Spieltest Explicit
Kerntests .NET 457/457 (75 + 91 + 73 + 157 + 6 + 43 + 12)
Fingerabdrücke der Bot-Partien unverändert DCE95C96556F3A1A, 7B8E43AEFC0D60C5

Das Loopback der Mehr-Runden-Partie läuft im Prozess mit zwei LuneSession-Instanzen und LuneLoopback (Nachrichten synchron in Sende-Reihenfolge). Damit sind Protokoll, Prüfsummen, Übernahme und Wiedereinstieg abgedeckt; eine echte Zwei-Prozess-Partie über Sockets bleibt eine optionale Erweiterung.

Abnahme U4

Vorgabe Stand
Rollen offline / Host / Gast erfüllt
Sechs Plätze, ein Peer ein Platz, freie Plätze Bots erfüllt
Beitritt mit Protokollprüfung, Namenskürzung, volle Partie abgelehnt erfüllt
Private Planung, Spoof-Schutz, nur eigener Entwurf im Zustand erfüllt
Bereit verbindlich, alle bereit → Kampf, Bots einmal je Runde erfüllt
Kampfsynchronisation (Beginn, neue Einheiten, Rahmen 20/s, späte Frames verworfen) erfüllt
Abrechnung mit öffentlichem Zustand erfüllt
Disconnect → Bot, kein Kernverlust erfüllt
Wiedereinstieg über den Namen erfüllt
Übernahme verwirft den Bot-Entwurf erfüllt
Revanche durch den Host erfüllt
Hostverlust → Meldung und Rückkehr ins Menü erfüllt
Mindestumfang: Ready, private Planung, Bot-Übernahme, Wiedereinstieg, Snapshots, Revanche, Disconnect, sechs Plätze erfüllt
Tests 43 + 12 erfüllt

Nachtrag: Startbildschirm in der Szene (7. Oktober 2026)

Zweig luneraria/u4-nachtrag, aufgesetzt auf luneraria/u5.2 (1b31f9b, mit dem U3-Nachtrag).

Befund aus dem Spieltest des U3-Nachtrags: Nichts legte LuneNetPlay in die Szene. G1_Map.unity enthielt die Komponente nicht, LuneWorldBuilder fügte sie nicht hinzu, und es gab keinen Bootstrap. Das Spiel begann deshalb direkt in einer Partie (LuneGame.Start startet sie, wenn Net fehlt), und der Startbildschirm war unerreichbar. Der Verlassen-Dialog versprach das Hauptmenü, beendete aber das Spiel.

Beim Einbinden zeigten sich zwei weitere Fehler. Sie hätten den Startbildschirm auch mit der Komponente in der Szene verborgen:

  • LuneNetPlay.Start legte ein UIDocument ohne PanelSettings an und hängte das Menü an kein Panel.
  • Das HUD übernimmt das UIDocument des Match-Objekts und leert es bei jedem Partiestart (LuneHud.Init). Ein Menü dort wäre mit der ersten Partie verschwunden.

Behebung:

Teil Änderung
Szene LuneWorldBuilder legt LuneNetPlay auf das Match-Objekt neben LuneGame, LuneMatchDriver, LuneMatchView und LuneBenchmark, mit Verweisen auf Spielcontroller, Treiber, Ansicht, Kamera und UI-Assets. Szene neu gebaut
Menüfläche eigenes UIDocument (Objekt „Menu“) mit eigenen PanelSettings, über dem HUD (Sortierung 20 über 10). Die Wurzel nimmt keine Klicks, ein verborgenes Menü lässt das HUD frei
Start Spielcontroller und Treiber warten. Die Kamera steht in der Übersicht still, denn die Felder Name und Adresse nehmen W, A, S, D, Q und E
Partie „Allein spielen“, Hosten und Beitreten wie in U4. Jede Partie beginnt mit ungedrehter Kamera; Godot legt dafür je Partie ein neues Spielobjekt an
Rückkehr „Menü“ → „Zum Menü“: HUD und Aufstellungsflächen verschwinden, der Spielcontroller ruht, die Sitzung endet. Der Treiber hält eine neue Partie, die nie läuft; die Karte ist leer wie beim Start
Bund-Wahl Glutpakt und Wurzelbund zeigen die Wahl wie die Lane-Knöpfe; vorher fehlte die Markierung
Menübreite Die vier Aktionsknöpfe brauchen etwa 650 px und ragten bei höchstens 640 px über den Rahmen (erstes Player-Bild); die Tafel darf jetzt 760 px breit werden
Verlassen-Dialog mit Startbildschirm „ZUM MENÜ“; ohne ihn (Tests, Benchmark) sagt der Dialog, dass das Spiel endet, und der Knopf heißt „BEENDEN“

Tests und Benchmark ohne Startbildschirm: LuneMatchDriver.DirectStart (die beiden Szenenlader der Tests setzen ihn) und -luneBenchmark (LuneBenchmark.Running) halten LuneNetPlay heraus. Dann startet LuneGame die Partie der Szene wie vor U4, und die Fingerabdrücke der Bot-Partien bleiben gleich.

Selbsttest im Player (nach lune_smoke.gd, ergänzt um die Rückkehr): <Player> -luneSmoke <Ordner> drückt die echten Knöpfe (LuneButton.Click; Godots Selbsttest löst pressed aus) und prüft im Player auch, dass jeder Knopf in seiner Mitte zuoberst liegt. Jeder Schritt wird vom Bildschirm fotografiert. Am Ende schreibt der Test report.json und beendet sich mit 0 (bestanden) oder 1. Ablauf: Startbildschirm → „Allein spielen“ → Planung → „Startaufstellung“ und „Bereit“ → Kampf → „Menü“ → „Zum Menü“ → Startbildschirm → zweite Partie.

Prüfung:

Prüfung Ergebnis
StartScreenTests (PlayMode, neu) 26/26 Prüfungen im Editor (Selbsttest ohne Bilder)
macOS-Player, -luneSmoke 26/26 in 10,8 s (Release, Metal, 1920×1080). Bilder screenshots/u4/startbildschirm/, Bericht logs/u4/smoke-macos.json, Protokoll logs/u4/smoke-macos-log.txt
EditMode 29/29
PlayMode 14/14 (13 + StartScreenTests), Verify A–I 718/0. Zu den Läufen siehe unten
Fingerabdrücke der Bot-Partien Seed 2 DCE95C96556F3A1A (12.690 Schritte), Seed 9 ab Runde 21 7B8E43AEFC0D60C5 (4.195 Schritte): gleich dem Kern und unverändert, in der Szene auch bei 30, 60, 120 fps und unbegrenzt
Benchmark -luneBenchmark LuneNetPlay bleibt aus, die Bot-Partie bleibt (Code; die Szenentests nehmen denselben Weg ohne Startbildschirm). Ein Player-Lauf steht aus

Zu den PlayMode-Läufen: Der erste vollständige Lauf (7. Oktober, 23:28) ergab 14/14. Ihm fehlte nur die Menübreite, eine Layoutzeile, die kein Test liest. Danach wurde der Mac zugeklappt. Er ging in den Ruhezustand („Thermal Emergency Sleep“ um 23:35) und wachte nur noch alle 15 Minuten kurz für Wartung auf. Drei weitere Läufe auf dem Endstand liefen nur in diesen Wachphasen; jeder Test bestand darin mindestens einmal. Der Lauf vom 8. Oktober (05:14) ergab 12/14, mit Bildraten und Vertical Function Test; F_Input und StartScreenTests bestanden in den Läufen davor und danach. Fehlschläge gab es nur an Echtzeitgrenzen, wenn der Mac dazwischen schlief: Bildratenläufe über 600 s, der 120-s-Wächter des Selbsttests und eine Kameraprüfung 0,6 s nach einem Lane-Klick. Ein zusammenhängender Lauf auf dem Endstand bei geöffnetem Mac steht aus.

Bekannte Grenzen

  • Transport: TCP statt ENet. Kampfrahmen laufen auf demselben Socket und werden über die Serial verworfen (wie unreliable_ordered). Unter Paketverlust kann TCP Head-of-Line-Blocking erzeugen; für eine Internetpartie wäre ein unzuverlässiger Kanal wie bei ENet der nächste Schritt.
  • Zwei-Prozess-Loopback (net_rounds.py) ist als In-Prozess-Test umgesetzt (NetRoundsSuite). Ein Sockets-Lauf über zwei Player ist optional.
  • Windows auf x64-Hardware und Netz über mehrere Rechner sind nicht gemessen (Build-Module fehlen, siehe U1.5-UNITY.md).
  • Hauptmenü ist der Startbildschirm mit Offline/Hosten/Beitreten; das erweiterte Menü der Referenz (Emblem, Version, erweiterte Optionen, 3D-Bühne) ist vereinfacht. Bis zum Nachtrag vom 7. Oktober 2026 war er nicht in der Szene. F1, M und F11 wirken erst in der Partie; in der Referenz auch im Menü.
  • „Menü“ im HUD fragt vor der Rückkehr (Dialog aus U3); Godot kehrt sofort zurück.
  • Kein Audio-Netzwerk und keine Lobby-Chat-Nachrichten (waren nicht Teil des M4-Mindestumfangs).