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>
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>
Der Kommentar an dig_at sagte, der Kern prüfe alles außer der
Abklingzeit. Das stimmt nicht: Der Kern prüft Abklingzeit, Feld,
Gelände, Werkzeugstufe und freien Platz, aber nicht die Reichweite. Die
prüft nur die Hülle (in _update_marker und _try_dig), weil die Figuren
außerhalb des Gleichschritts laufen und der Kern ihren Ort nicht kennt.
Der Plan für M1c darf sich nicht darauf verlassen. Der Kommentar nennt
jetzt, was der Aufrufer und was der Kern prüft.
AUTOSAVE_TICKS wiederholte mit 2400 die Taktrate von 20 pro Sekunde. Die
Konstante wird jetzt als zwei Minuten aus GwSession.TICKS_PER_SECOND
abgeleitet; GDScript nimmt das in einer const an und rechnet 2400.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>