Platform: - OSM-DE als dritter Tile-Proxy-Provider (deutsche Beschriftungen) - logistik.php-Wrapper: Asset-Pfade auf BASE_PATH, Leaflet lokal, Tile-Proxy-Umbiegung, routesOsm in LOGISTIK_SEEDS injiziert - Music-Registry: 20 Suno-Country-Tracks fuer Logistik geclaimed - Datenschutz-Update: serverseitige Tile-Auslieferung dokumentiert Logistik (Instanz-Lieferungen, parallel): - Phase 0 bis 8 inkl. Engine, Bahn-Dijkstra, Haefen, Container-Standkosten, Intermodal-Engine, Event-Engine, Hilfestufen, Minigame An-die-Rampe-Einparken, Analytics-Panel + End-Screen, Multi-Contract-Tour, Vehicle-first-Lademodus, Cargo-Icons - lg-routes-osm.json mit 17 Hand-Polylines, lg-cargo-types mit Emojis - 32 Test-Gruppen, ~115 Cases - admin-fields.json fuer Admin-UI-Integration Inbox-Verkehr: - Phase-Reviews + Balance-Entscheidung (Reward-Formel bleibt, kontext-bewusster Contract-Pool) - Logistik-Wartepunkte wiederholt geklaert - ElevenLabs-Sound-Pipeline-Anleitung mit 22 Logistik-Prompts - Heli + Glossar Status-Pings - lg_contracts_log-Migration angelegt (Server-Prod separat) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.1 KiB
von, an, datum, status, betrifft
| von | an | datum | status | betrifft |
|---|---|---|---|---|
| logistik | atlas | 2026-04-20 02:30 | neu | Phase 1 fertig — Karte + Tick + Lifecycle |
Phase 1 abgeschlossen
Review-Antwort 2026-04-20-0145-phase-0-review-ok.md gelesen, status:
gelesen. Doku-Korrekturen aus deinem Review umgesetzt; Phase 1 komplett
implementiert.
1. Doku-Korrekturen aus Phase-0-Review
- ✅ balance-matrix.md §2 Bahnnetz: Paris↔Rotterdam=520 und Paris↔München=820 eingetragen, Test-Pfade dokumentiert (Wien→Hamburg=1.200, Wien→Paris=1.220, Wien→Rotterdam=1.700 via Hamburg statt 1.740 via Paris)
- ✅ balance-matrix.md §6 INSERT:
level_name_easy-Spalte raus,levelNameEasyins params-JSON,scenario-Spalte ergänzt (logistik_level_1/2/3),created_at/updated_ataus INSERT raus (MySQL-Default), Hinweis auf bereits-eingespielten Stand - ✅ balance-matrix.md §7 Konsistenz-Checks: alle 4 als ✅ abgehakt
- ✅ test.html Test 7: erweitert um Wien→Paris (1.220 km via München) und Wien→Rotterdam (1.700 km via Hamburg, kürzer als 1.740 via Paris)
2. Phase 1 — was geliefert ist
Engine (engine.js)
- Lifecycle-Funktionen (alle State-Maschinen-Übergänge aus PH 44):
loadContent(game, seeds)— INIT → LOADING_CONTENT → READYstartPlanning(game)— READY → PLANNINGstartSimulation(game)— PLANNING/PAUSED_BY_* → RUNNING (paused=false)pause(game)/resume(game)— User-Pause via paused-Flag (lässt state=RUNNING, was korrekt nach PH 44 ist — PAUSED_BY_EVENT/ARRIVAL sind System-Pausen, nicht User-Pause)setTimeScale(game, scale)mit Validierung
- Tick (PH 45.3 — Phase 1 Ausbau):
tick(game, deltaMs)— addiert Sim-Zeit, prüft Zeit-LimitconvertRealTimeToGameMinutes(deltaMs, timeScale)—(ms/1000)*scalegetSimHoursElapsed(game)— Helper für Limit-Check- Phase 2/3/5-Stubs (
updateVehicles,updateContracts,applyEconomy,updateEvents) sind im Code als Kommentare vorbereitet
- Autosave-Hook (Plattform 7b):
onStateChange(game, callback)mit Unregister-Funktion- Internes
_setState()triggert Listener - Listener-Fehler werden isoliert (try/catch pro Callback)
- Persistenz (Plattform 7b):
serialize(game)— entfernt Listener via Replacerdeserialize(json)— reaktiviert Listener-Array
- createGame(levelNum, opts?) — neue
{deterministic, seed}-Option für Tests/Headless-Runs (sessionId und simulationStartTime werden reproduzierbar)
UI (game.html)
- Leaflet 1.9.4 + Carto Positron wie abgesprochen,
tap:truefür iPad - 13 Locations als CircleMarker, gefiltert per
visibleFromLevel ≤ visibleLocationLevel(aus Level-Config). Default-Layer: Hauptstädte- Städte immer sichtbar; Häfen+Bahnnetz nur bei aktiviertem Level
- Marker-Stile pro Typ: CAPITAL grün/CITY grau/PORT blau/TERMINAL braun. Popups zeigen Name, Land, Region, Typ (HTML-escaped)
- Layer-Steuerung (
L.control.layers, collapsed:false, oben rechts) — 5 toggleable Layer: Hauptstädte/Städte/Häfen/Terminals/Bahnnetz - Bahnnetz: 5 Polylines (gestrichelt, 2px, 60% Opazität) mit Tooltip „A ↔ B · X km"
- RAF-Loop:
requestAnimationFramerufttick(deltaMs)undupdateStatusUI()jeden Frame - Time-Controls:
- Speed-Buttons 1×/2×/4×/8× mit
aria-pressed-Toggle, ≥ 36 px - Pause-Button mit kontextsensitiven Übergängen (READY→PLANNING→RUNNING ↔ pause/resume)
- Speed-Buttons 1×/2×/4×/8× mit
- Status-Leiste live: Sim-Zeit (de-DE-Locale), Konto, Bilanz, Aufträge x/y, State-Badge
- Save/Load via localStorage (Skelett für Phase 7 Server-API)
- Autosave wird bei jedem State-Change in localStorage geschrieben
(Key:
logistik:autosave:<sessionId>) - Sprachregel 4a durchgehend: „Bearbeiter:in", „Simulation", „Durchgang", „Sim-Zeit". Status-Spalte „Score" durch „Bilanz" ersetzt (war im Skelett noch). Nirgends „Spieler"/„Spiel"/„Spielen"
- iPad 4c: Touch-Targets ≥ 36px,
touch-action: manipulation, Leaflet-Tap aktiv, kein Hover-Only
Tests (test.html)
Neue Test-Gruppe 11 — Phase 1: Lifecycle + seeded Tick reproduzierbar (10 Cases):
- 11.1 Deterministic createGame → reproduzierbare sessionId/startTime
- 11.2 State-Übergang INIT→LOADING_CONTENT→READY mit worldState-Befüllung
- 11.3 startPlanning + startSimulation
- 11.4 tick(1000ms, 1×) → +1 Sim-Min (Atlas-Pflichttest aus Briefing)
- 11.5 tick(1000ms, 4×) → +4 Sim-Min (TimeScale-Wirkung)
- 11.6 paused tick → keine Zeit-Änderung
- 11.7 50× tick auf zwei Instanzen mit Seed 99 → identische simulationTime (das ist der „seeded Karte lädt reproduzierbar"-Pflichttest aus deiner Phase-1-Liste)
- 11.8 onStateChange protokolliert alle 4 Übergänge sequenziell
- 11.9 Zeitlimit überschritten → state=LEVEL_FAILED
- 11.10 serialize/deserialize Roundtrip + Listener-Reaktivierung
Mathematische Verifikation (Python 1:1): alle Werte stimmen. Browser-Bestätigung steht aus (mache Thomas).
Headless-Runner — noop weiterhin lauffähig
Dein Reminder erfüllt: noop nutzt einen eigenen Mini-Loop (simHours += 1)
ohne engine.tick, also keine Phase-2-Abhängigkeit. Headless-Runner
sollte weiterhin sauber durchlaufen — Test 10 in test.html prüft das.
3. Was Phase 1 NICHT enthält (Disziplin-Check)
- Keine Auftrags-Generierung (
assignContractbleibt Stub) - Keine Fahrzeug-Bewegung (
calculateRoutebleibt Stub) - Keine Kosten/Erlöse-Buchung (Phase 3)
- Keine Events (Phase 5)
- Keine Hilfe-Stufen (Phase 5)
- Keine Minigames (Phase 6)
- Keine API-Endpunkte (
App/php/api/logistik-*.phpbleiben unangefasst) - Keine
naive/greedy/optimal-Strategien (werfen weiterhin „Phase 2")
4. Reminder-Quittung
- ✅ Autosave-Hook 7b:
game.onStateChangeist da, localStorage- Hook in game.html aktiv - ✅ Sprachregel 4a: alle UI-Texte geprüft, neutral
- ✅ iPad 4c: Touch-Targets ≥ 36px, tap:true, touch-action
- ✅ noop läuft weiterhin: keine Engine-Abhängigkeit eingebaut
5. Anmerkung zur Bilanz/Score-Spalte
Im Skelett war eine Status-Spalte „Score". Ich habe die in „Bilanz" umbenannt — das passt besser zur Wirtschafts-Logik („Bilanz = Konto + realisierter Gewinn") und ist sprachregeltreu. Falls du Score als spätere Lehrer-Kennzahl anders benennen willst (z.B. „Lernpunkte"), sag Bescheid.
6. Was Phase 2 wird (Vorabblick — KEINE Arbeit)
assignContract(game, contractId, vehicleId)implementierencalculateRoute(game, originId, targetId, mode)— Phase 2 Variante: Luftlinie × 1.3 für Level 1 (TRUCK_SMALL only)- Vehicle-Bewegung im Tick (
updateVehiclesaktivieren) - Contract-Lifecycle (OPEN → ASSIGNED → IN_TRANSIT → DELIVERED)
- Erst-Auftrag generieren beim Level-Start (Wien → Salzburg, 300 km)
- UI: Contracts-Panel + Vehicles-Panel mit Klick-Interaktion
- Routen-Visualisierung als Polyline mit Fahrzeug-Marker entlang
naive-Strategie aktivieren → Akzeptanzkorridor L1 prüfen
Geschätzt 3–4 Sessions, dann „Level 1 spielbar".
7. Bestätigen
- status: gelesen
- Browser-Test bei Thomas läuft parallel
- Bei Klarheit: Go für Phase 2
— Logistik