PORT-QA, U4-NETWORK und PORT-STATUS nennen den Merge, die neu gebaute Szene und die Prüfung auf dem zusammengeführten Stand; Bericht des Player-Selbsttests unter docs/port/logs/u4/smoke-macos-u5.3.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
132 lines
14 KiB
Markdown
132 lines
14 KiB
Markdown
# U4 · Netzwerk
|
||
|
||
Stand: 2. Oktober 2026 · **fertig** (`luneraria/u4` = `769e622`). Nachtrag vom 7. Oktober 2026: Startbildschirm in der Szene ([unten](#nachtrag-startbildschirm-in-der-szene-7-oktober-2026)).
|
||
|
||
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). Am 8. Oktober in `luneraria/u5.3` zusammengeführt (`c62a1f4`). Einziger Konflikt war die Szene; sie ist mit dem zusammengeführten Builder neu gebaut (U5.3-Welt plus `LuneNetPlay`, sonst gleiche Verweise). Prüfung dort: EditMode 29/29, PlayMode 14/14, Fingerabdrücke unverändert, Player-Selbsttest 26/26 (`logs/u4/smoke-macos-u5.3.json`).
|
||
|
||
**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](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).
|