Commit Graph

27 Commits

Author SHA1 Message Date
Steven Wroblewski 9f65823f2d Vitrine der Stilproben
Das Startmenü führt zu einer Vitrine, die den gewählten Stil an einer
kleinen Szene zeigt: Fels, toter und lebendiger Boden, Lebensmoos, eine
Ranke, die Steine in eine erwachende Ruine trägt, eine wachsende
Faserpflanze, ein hüpfendes Weidetier und zwei Spielfiguren. Knöpfe,
die Tasten 1 bis 3 und F2 wechseln den Stil, Esc führt zurück ins Menü.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-02 12:27:26 +02:00
Steven Wroblewski 69b642cc60 Eigene Schläge pro Kachel zählen
Als Gast kann die Meldung eines Schlags erst nach dem nächsten Schlag
auf dieselbe Kachel ankommen. Ein Merker pro Kachel ging dabei verloren,
und der brechende Schlag zeigte seine Splitter doch zweimal. Die
Hauptszene zählt ihre noch nicht gemeldeten Schläge deshalb pro Kachel
und vergisst sie, wenn die Welt neu abgeglichen wird.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-02 12:19:01 +02:00
Steven Wroblewski 55c09b0f1f Eigener Schlag zeigt beim Brechen keine zweiten Splitter
Der Kern meldet einen Schlag, der Fels bricht, nur als geänderte Kachel
ohne Spieler. Die Hauptszene merkt sich deshalb die Kacheln ihrer
eigenen Schläge, bis der Kern sie meldet, und zeigt dann keinen zweiten
Splitterwurf. Als Gast kam der zweite eine Rundreise später und sah
wieder verzögert aus. Splitter gibt es nur noch auf Fels, nicht mehr
außerhalb der Karte.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-02 12:04:56 +02:00
Steven Wroblewski d2a7973022 Spielfeld über Art zeichnen
Karte, Figuren und Zielmarke zeichnet jetzt Art. Die Karte zeichnet in
Blöcken von 16 mal 16 Kacheln und nach einem Treffer nur die Blöcke um
die Kachel neu; jede Kachel kennt ihre Nachbarn. Figuren stehen
aufrecht in ihrer Kachel, schreiten und schauen in die Richtung, in die
sie gehen. Der eigene Schlag zeigt seine Splitter sofort, auch als Gast,
und die Namen über fremden Figuren werden in Bildschirmgröße gezeichnet
und bleiben scharf.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-02 11:49:18 +02:00
Steven Wroblewski 9921aba63a Kennungen, Kachelformen und Platzhalter für die Grafik
Jede Grafik auf dem Spielfeld bekommt eine Kennung. Art zeichnet sie im
gewählten Stil oder aus einem Bild gleichen Namens unter game/art.
ArtStyle zeichnet vorerst schlichte Platzhalter. TileShape beschreibt
die Nachbarn einer Kachel, damit Felsmassen außen rund und innen
geschlossen gezeichnet werden können. Die drei Stile Warm, Pastell und
Glimmen gibt es schon mit Namen, noch ohne eigene Zeichnungen.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-02 11:24:45 +02:00
Steven Wroblewski be22e9f358 Abschlusskorrekturen M1c: Schläge der Gäste, Figuren und Fragebogen
- Der Host hält einen Schlag eines Gastes, der während der Abklingzeit
  ankommt, bis zum ersten Takt danach. Übers Internet ging sonst etwa
  jeder fünfte Schlag eines Gastes verloren.
- ENet drosselt die Figuren nie mehr; sonst konnten die Figuren eines
  von zwei Gästen dauerhaft stehen bleiben. Figuren gehen geordnet, und
  eine stille Verbindung gilt nach höchstens acht Sekunden als verloren.
- Positionen, die keine Zahlen sind, und Figuren von Spielern, die
  nicht online sind, werden verworfen.
- Ein Host mit angehaltener Simulation sagt das in der Statuszeile.
- Neue Tests: Schlag während der Abklingzeit, Zielauswahl von NetLink,
  verworfene Figuren, Neuabgleich über die Brücke.
- Der Fragebogen sagt, was jeder Rechner braucht, und die Freigabe in
  der Firewall gehört zum Host. CLAUDE.md beschreibt das Halten der
  Schläge, die Drosselung und die Zeitüberschreitung und ergänzt die
  Vertrauensregel um die Schlüssel.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-02 01:22:36 +02:00
Steven Wroblewski 84e786e531 Zwei-Instanzen-Test unabhängig von der Startzeit, Bot endet immer
Die Uhr des Hosts wartet jetzt auf den Gast. So kann ein langsamer Start
des zweiten Prozesses die Takte bis zum Vergleich nicht mehr verbrauchen.
Der Bot endet auch dann, wenn er seinen Bericht nicht schreiben kann,
und überlebt den Test nie. Ein leeres --storage= führt ihn nicht mehr in
den Ordner des Spielers. Ein neuer Test prüft, dass der Bot ohne
schreibbaren Bericht mit Exit-Code 1 endet.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 23:24:10 +02:00
Steven Wroblewski acce1ed435 Zwei Instanzen im Gleichschritt
Ein Test startet einen zweiten Godot-Prozess als Gast. Der Gast tritt
über das Netzwerk bei und schlägt Stein, beide Welten enden im selben
Zustand, ohne Abgleich unterwegs. Damit ist die Prüffrage von
Meilenstein 1 Teil der automatischen Prüfungen.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 22:49:41 +02:00
Steven Wroblewski bfd237fd5c Defekte Sitzung gibt Mitspieler frei, nur echte Gäste beenden die Pause
Hält der Kern mit einem internen Fehler an, schließt ein Host seine Welt
für Gäste, und ein Gast kehrt ins Menü zurück, statt dass die anderen
ohne Nachricht warten. Eine Pause endet erst, wenn der Host einen Gast
angenommen hat, nicht schon bei einer bloßen Verbindung. So kann ein
Gast nicht mehr in einer pausierten Welt festhängen, wenn der Host
zwischen Verbindung und Gruß pausiert. Eine Pause lässt sich immer
beenden. Meldungen, die nach dem Ende einer Sitzung im selben Stapel
folgen, bleiben unbeachtet. Vier neue Tests decken das ab.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 22:33:10 +02:00
Steven Wroblewski 53ef02ae75 Spielen allein, als Host oder als Gast
Die Hauptszene beginnt mit dem Startmenü oder mit dem Direktstart aus
der Befehlszeile. Gäste sehen die Welt des Hosts und die Figuren aller
Spieler. Nur der Host speichert, Pause gibt es nur ohne Gäste, Laden
nur beim Spielen allein. Ablehnungen, Abbrüche und Abgleiche erscheinen
als Meldung, und ein Spielstand, der sich gerade nicht lesen lässt,
bleibt unangetastet.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 22:03:42 +02:00
Steven Wroblewski d2da661452 Startmenü, fremde Figuren und Statuszeile
Das Startmenü fragt nach dem Namen und bietet allein spielen, die Welt
öffnen oder beitreten. Die Figuren der anderen Spieler gleiten zu ihrer
neuesten Position und tragen ihren Namen. Die Anzeige füllt Werte in
Meldungen ein und hat eine Statuszeile. Die Texte für Menü und Netzwerk
gibt es auf Deutsch und Englisch.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 21:40:57 +02:00
Steven Wroblewski 51cd4572a8 Gesperrte Einstellungen nicht überschreiben
Wer eine Einstellung ändert, liest die Einstellungsdatei jetzt an
derselben Stelle wie Schlüssel und Speicherstand. Ist sie gerade nicht
lesbar, etwa weil ein anderes Programm sie hält, bleibt sie unverändert,
statt nur mit dem neuen Wert überschrieben zu werden. Von einer
beschädigten Datei bleibt, was Godot lesen konnte. Ein neuer Test deckt
die gehaltene Datei ab. Der Parameter von set_player_name heißt jetzt
new_name, damit er die Methode player_name nicht verdeckt.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 21:23:49 +02:00
Steven Wroblewski d5debc5bcb Profile, Startoptionen und vorsichtiges Lesen
Die Befehlszeile wählt ein Profil, einen Namen und einen Direktstart.
Zwei Fenster auf einem Rechner sind so zwei Spieler. Ein Schlüssel oder
Spielstand, der sich gerade nicht lesen lässt, wird nicht mehr ersetzt.
Name und zuletzt genutzte Adresse bleiben gespeichert.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 20:57:03 +02:00
Steven Wroblewski a43ce66a89 Nichts an schließende oder fehlende Verbindungen senden
NetLink merkt sich die Verbindungen, die es gerade schließt, und
schickt ihnen nichts mehr. Pakete an alle oder an alle außer einem gehen
einzeln an die offenen Verbindungen, statt Godot ein Ziel zu nennen, das
es nicht mehr gibt. Beides löste sonst Fehler in Godot aus, etwa wenn
der Host Figuren weiterreicht, während er einen abgelehnten Gast
hinauswirft. Ein neuer Test mit zwei Gästen deckt das ab.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 20:27:07 +02:00
Steven Wroblewski 0917450014 Verbindung über ENet
NetLink verbindet Host und Gäste über ENet: Nachrichten des Kerns
zuverlässig und in Reihenfolge, Positionen der Figuren unzuverlässig.
Eine Verbindung schließt erst, wenn wartende Nachrichten draußen sind.
SessionLink trägt die Nachrichten einer Sitzung über die Verbindung und
reicht Positionen weiter. Die Tests verbinden zwei Seiten über die
Loopback-Schnittstelle.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 19:53:04 +02:00
Steven Wroblewski 6c7c5bffc2 Panik-Test ohne globalen Hook, begrenzte Gast-Schleifen
Der Test einer Panik im Kern tauscht den globalen Panik-Hook nicht mehr
aus. Das war unnötig, weil der Testläufer die Meldung einer erwarteten
Panik ohnehin zurückhält, und es konnte Meldungen anderer, gleichzeitig
scheiternder Tests verschlucken. Die Gast-Schleifen in den GDScript-Tests
der Brücke laufen höchstens so oft, wie Takte warten, damit ein
abgewichener Gast den Testlauf nicht anhält.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 19:41:38 +02:00
Steven Wroblewski 2faa3ccce3 Brücke für Host und Gast
GwSession führt eine Sitzung als Host oder als Gast und reicht die
Nachrichten des Kerns an GDScript weiter. Nur der Host speichert. Die
Behandlung interner Fehler liegt jetzt in einem reinen Rust-Teil und hat
einen Test, und das Ereignis join_refused nennt den Schlüssel.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 19:20:34 +02:00
Steven Wroblewski bc34bc61f7 Tests: Speichern beim Schließen und automatisches Speichern
Beides setzt Konzept 9 um („automatisch in festen Abständen“, Speichern
beim Schließen), und beides ließ sich entfernen, ohne dass ein Test
rot wurde.

- Schließen: Die Hauptszene bekommt NOTIFICATION_WM_CLOSE_REQUEST. Danach
  meldet ein SaveStore im selben Ordner einen Spielstand und genau eine
  Aufzeichnung.
- Automatisch: Die Hauptszene läuft per _run_tick bis zum Takt vor
  AUTOSAVE_TICKS, ohne Bilder abzuwarten. Bis dahin gibt es keinen
  Spielstand, einen Takt später gibt es einen.

Entfernt man das Speichern beim Schließen, schlägt der erste Test fehl;
entfernt man das automatische Speichern in _run_tick, der zweite. Ohne
das Schreiben der Aufzeichnung beim Schließen schlägt der erste ebenfalls
fehl.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 13:26:30 +02:00
Steven Wroblewski dff213cc61 Testdateien: Löschen nur unter user://tests, Altlasten räumen, Wortlaut
user://tests liegt im echten Benutzerordner des Spiels, neben Spielstand,
Schlüssel und Aufzeichnungen des Spielers. TestFiles.remove_dir löschte
jeden Pfad, den es bekam; ein falsches Argument hätte echte Spielerdateien
gelöscht. Tests, die früh mit einem Laufzeitfehler abbrachen, ließen ihren
Ordner zurück (es lagen 15 solche Ordner im Benutzerordner).

- remove_dir vereinfacht den Pfad (simplify_path) und verweigert alles,
  was nicht user://tests oder darunter liegt, mit push_error und ohne zu
  löschen. Die Wurzel steht in der Konstante TestFiles.ROOT, die auch
  temporary_dir benutzt.
- run_tests.gd entfernt user://tests zu Beginn von _run_all, vor dem
  Fehlerzähler, aber nur wenn der Ordner existiert, weil Godot beim
  Auflisten eines fehlenden Ordners einen Fehler meldet.
- CLAUDE.md sagt jetzt, dass die Tests unter user://tests schreiben und
  nie die echten Dateien des Spielers anfassen.

Das Verweigern wurde einmal von Hand geprüft, mit einem Wegwerfskript auf
selbst angelegten Ordnern: Ohne Schutz löschte remove_dir sie, mit Schutz
bleiben sie samt Datei stehen und es erscheint ein Fehler, auch für einen
Geschwisterordner user://tests_probe und für user://tests/../…. Danach
waren die 15 Altlasten verschwunden und die Ausgabe fehlerfrei, auch ohne
vorhandenen Ordner user://tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 13:23:01 +02:00
Steven Wroblewski 400556134f Testläufer meldet einen Fehler, wenn kein Test lief
quit(1 if failed > 0 else 0) beendete einen Lauf mit "0 passed, 0 failed"
mit Code 0, zum Beispiel nachdem der Testordner umbenannt wurde oder alle
Tests falsch benannt waren. Die Prüfliste sah dann grün aus, ohne etwas
geprüft zu haben.

Der Läufer endet jetzt auch mit Code 1, wenn kein Test bestanden wurde.
Der Doc-Kommentar sagt das. Einmal von Hand geprüft: Mit einem Dateifilter,
den keine Testdatei erfüllt, meldete der alte Läufer 0 passed, 0 failed
mit Code 0, der neue endet mit Code 1.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 13:21:31 +02:00
Steven Wroblewski 842213c574 Spielstand bleibt erhalten, wenn das letzte Umbenennen scheitert
SaveStore.write_save verschob die geprüfte Temporärdatei direkt auf
world.grw. Godot löscht unter Windows ein vorhandenes Ziel, bevor es die
Datei verschiebt. Scheiterte die Verschiebung, zum Beispiel weil ein
Virenscanner world.grw.tmp festhielt, war der vorige Spielstand schon weg.

Jetzt wird der vorige Stand zuerst nach world.grw.bak verschoben, dann
rückt die Temporärdatei nach. Scheitert das, kommt der Stand aus der
Sicherung zurück; nach Erfolg wird die Sicherung gelöscht. Bleibt nach
einem Absturz zwischen den beiden Verschiebungen nur world.grw.bak übrig,
holt SaveStore sie beim Öffnen des Ordners zurück.

Neue Tests: ein offenes Handle auf world.grw.tmp, eine blockierte
Sicherung, die Wiederherstellung aus der Sicherung und dass eine
Sicherung einen vorhandenen Stand nie ersetzt.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 13:16:02 +02:00
Steven Wroblewski 754d7f1e92 Speichern meldet Fehler und schützt unbrauchbare Stände
Lässt sich ein unbrauchbarer Spielstand nicht beiseitelegen, bleibt das
Speichern gesperrt, bis ein Stand erfolgreich geladen wird; so wird er
nie überschrieben. Ein gescheitertes automatisches Speichern zeigt
SAVE_FAILED, und jedes gescheiterte Speichern wird protokolliert.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 12:15:05 +02:00
Steven Wroblewski 68483c648e Darstellung und Hauptszene
Die Hauptszene verbindet Kern, Karte, Figur, Anzeige und Dateien:
fester Takt, Laufen, Stein schlagen in Reichweite, Speichern mit F5,
Laden mit F9, Pause mit Esc, automatisches Speichern alle zwei Minuten
und beim Schließen. Die Karte erscheint in Platzhalterfarben, bis in
M1d ein Stil gewählt ist. Ein Werkzeug macht Bildschirmfotos ohne
Handarbeit.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 11:53:51 +02:00
Steven Wroblewski 3761966303 SaveStore prüft jeden Schreibvorgang
Ein Speicherstand ersetzt den vorigen nur noch, wenn er vollständig
geschrieben und zurückgelesen wurde. Ein nicht gespeicherter
Spielerschlüssel wird gemeldet, und set_aside_save meldet, wenn nichts
verschoben wurde.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 11:42:31 +02:00
Steven Wroblewski ccf9813c80 Texte, Tasten und Dateien
Alle Texte stehen in einer Tabelle mit Deutsch und Englisch, die das
Spiel zur Laufzeit liest. Die Tasten werden in Code angelegt, nach
physischer Position. SaveStore verwaltet den Spielerschlüssel dieser
Installation, schreibt den Speicherstand über eine temporäre Datei,
legt unbrauchbare Stände beiseite und behält die zehn neuesten
Aufzeichnungen.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 11:26:12 +02:00
Steven Wroblewski 2607df8a97 Takt und Bewegung der Figur
TickClock rechnet Bildzeit in Takte um und holt nach einem Ruckler
höchstens fünf Takte auf. GridMotion bewegt einen Körper über das
Kachelraster und lässt ihn an Wänden entlanggleiten. Die Figur läuft
fünf Felder pro Sekunde, außerhalb des Gleichschritts.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 11:11:52 +02:00
Steven Wroblewski bd0f588714 Brücke zu Godot und Godot-Projekt
Die GDExtension grovewright-bridge gibt den Kern als Klasse GwSession
an GDScript weiter: Befehle einreihen, einen Takt ausführen, Karte und
Inventar lesen, speichern, laden, aufzeichnen. Eine Panik im Kern macht
die Sitzung defekt, statt einen guten Speicherstand zu überschreiben.
Das Godot-Projekt bekommt einen Testläufer, der auch Laufzeitfehler als
Fehlschlag zählt.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-01 10:46:23 +02:00