champions-of-luneraria/docs/port/U4-NETWORK.md
Martin Stickelbroeck dafcaae5f5 U4-Nachtrag: Bestätigungslauf und Player-Benchmark
Nachgeholt bei offenem Mac auf dem Endstand acf2572; die nächtlichen
Wiederholungsläufe zählen nicht (Mac zugeklappt, nur Wartungs-Wachphasen).

- EditMode 29/29, PlayMode 14/14 in einem Zug (StartScreenTests 26/26,
  Verify 718/0), Fingerabdrücke DCE95C96556F3A1A und 7B8E43AEFC0D60C5
  gleich dem Kern, Szene bei 30, 60, 120 fps und unbegrenzt ebenso.
- Neu gebauter macOS-Player: Selbsttest -luneSmoke wieder 26/26.
- -luneBenchmark behält seine Bot-Partie (Seed 9 ab Runde 21, 116 Einheiten).
  A/B gegen U5.2 (1b31f9b), je drei Läufe abwechselnd: Übersicht 111,0–113,9
  zu 112,5–114,5 fps, Mid nah 145,2–148,9 zu 146,7–150,0 fps, HUD
  0,09–0,11 ms; Mittelwerte 0,3 bzw. 1,1 % auseinander, innerhalb der
  Streuung. Rohdaten in docs/port/logs/u4/benchmark-ab/.

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

13 KiB
Raw Permalink 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 (d590fde), 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. Im Bestätigungslauf mit neu gebautem Player wieder 26/26
EditMode 29/29
PlayMode 14/14 (13 + StartScreenTests), Verify A–I 718/0. Bestätigungslauf auf dem Endstand (acf2572) am 8. Oktober in einem Zug, 307 s
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 (Seed 9 ab Runde 21, bis 116 Einheiten). A/B gegen U5.2 unter gleichen Bedingungen, siehe unten

Leistung (A/B): Je drei Benchmark-Läufe abwechselnd mit einem U5.2-Player (1b31f9b, ohne Nachtrag) und dem Nachtrag-Player (acf2572); zuvor ein verworfener Aufwärmlauf, weil macOS neue Programme beim ersten Start prüft. macOS-Player, Release, Metal, 1920×1080, VSync aus, Mac M5 bei normaler Desktop-Nutzung. Rohdaten logs/u4/benchmark-ab/.

Player Übersicht (Zoom 64) Mid nah (Zoom 22) HUD-Skripte je Bild Einheiten
U5.2 1b31f9b 112,5 / 114,5 / 112,9 fps 146,7 / 150,0 / 147,7 fps 0,088–0,103 ms 116 / 63
U4-Nachtrag acf2572 111,0 / 113,9 / 113,9 fps 145,2 / 148,9 / 145,4 fps 0,090–0,109 ms 116 / 63

Die Mittelwerte liegen 0,3 % (Übersicht) und 1,1 % (Mid nah) auseinander. Das ist weniger als die Streuung zwischen den Läufen eines Players (bis 2,6 %). Im Benchmark baut LuneNetPlay kein Menü und hat keine Bildarbeit. Beide Player liegen unter den U5.2-Zahlen vom 2. Oktober (133 / 180 fps). Der Abstand trifft beide gleich und hängt an der Umgebung. Heute brauchen beide Player in der Übersicht länger als damals: Hauptthread 3,6–3,7 statt 3,1 ms, Render-Thread 4,2–4,5 statt 3,7 ms, Present-Wartezeit 5,3 statt 4,4 ms.

Die nächtlichen Wiederholungsläufe vom 7. auf den 8. Oktober zählen nicht. Der Mac war zugeklappt („Thermal Emergency Sleep“ um 23:35) und wachte nur alle 15 Minuten kurz für Wartung auf. Dabei rissen Echtzeitgrenzen: Bildratenläufe über 600 s, der 120-s-Wächter des Selbsttests und eine Kameraprüfung 0,6 s nach einem Lane-Klick. Der Bestätigungslauf bei geöffnetem Mac ersetzt sie.

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).