Der Bot rief einen neuen Monat aus, obwohl im Spiel keiner war. Zwei Fehler, die zusammen genau das ergeben: statsLesen las die Uhrzeit als `Number(server.dayTime) || 0`. Eine Antwort ohne dayTime — Server startet neu, Proxy schiebt eine Fehlerseite dazwischen, XML halb geschrieben — wurde damit zu 0. Und tagUmgeschlagen prueft auf `jetzt < vorher`. Null ist kleiner als jeder Vortagswert, also sah jede kaputte Antwort wie Mitternacht aus. Beides behoben: fehlt die Angabe, ist sie jetzt null und nicht 0 — "weiss nicht" ist kein Tageswechsel. Und ein Wechsel muss die Form eines echten Mitternachtssprungs haben: vom spaeten Abend in den fruehen Morgen, beide Werte innerhalb eines Tages. Ein Zappeln um ein paar Minuten faellt jetzt durch. Eine Antwort ohne Uhrzeit ueberschreibt ausserdem den letzten guten Stand nicht mehr, sonst ginge der echte Sprung danach verloren. Beim Nachmessen zeigte sich, dass meine Doku an der Stelle falsch war: dayTime ist nicht live, sondern ein Schnappschuss. Fuenf Abrufe ueber zwei Minuten mit einem Spieler online ergaben denselben Wert (37028620) — der Server schreibt das XML im "Web API Interval" neu, hier alle 360 Sekunden. Steht jetzt richtig in docs/ls-feed.md, samt dem verbleibenden Restrisiko: ein Serverneustart setzt die Uhr auf den gespeicherten Stand zurueck und kann in seltenen Faellen einen Monat zu viel zaehlen. Geprueft: echter Sprung, normaler Tagesverlauf, Erstlauf, fehlende Angabe als 0/null/NaN, kleiner Ruecksprung, Ruecksprung am Vormittag, unsinnige Groessen, und dass eine fehlende dayTime im XML als null ankommt statt als 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.6 KiB
Was ein LS-Server über sich verrät
Aufgeschrieben, damit die Frage „können wir nicht auch …" nicht dreimal gestellt wird. Alles hier ist an einem echten FS25-Server (1.21.0.0) geprüft, nicht aus der Dokumentation abgeschrieben — die schweigt zu den Einzelheiten.
Die Endpunkte
Alle brauchen ?code=<Zugangs-Code>. Der Code steht in der Abfrage-URL, die
der Hoster ausgibt; der Port ist nicht immer 8080.
| Endpunkt | Grösse | Inhalt |
|---|---|---|
dedicated-server-stats.xml |
~49 KB | Server, Spieler, Mods, Parzellen, Felder, Fahrzeuge |
dedicated-server-stats-map.jpg |
51 KB – 1,5 MB | Luftbild, size= 512…4096, quality= 1…100 |
dedicated-server-savegame.html?file=careerSavegame |
~20 KB | Einstellungen, Geld, Spielzeit, Modliste |
dedicated-server-savegame.html?file=vehicles |
~39 KB | jedes Fahrzeug mit Preis, farmId, Betriebsstunden |
dedicated-server-savegame.html?file=economy |
~305 KB | Preiskurve je Fruchtart über zwölf Perioden |
Andere Dateinamen antworten mit 204 und leerem Rumpf. Geprüft und nicht
verfügbar: farms, farmland, farmlands, fields, field, items,
placeables, environment, sales, players, production, productions,
missions, densityMapHeight, treePlants, growth, weeds, fillTypes.
Was in der Statusabfrage steht
<Server version="1.21.0.0" mapSize="4096" mapName="…" dayTime="46057948">
<Slots capacity="4" numUsed="3">
<Player isUsed="true" isAdmin="true" uptime="128" x="…" y="…" z="…">Name</Player>
</Slots>
<Mods> <Mod name="…" author="…" version="…">Titel</Mod> <!-- 110x -->
<Farmlands><Farmland id="1" owner="0" area="22.3" price="1340352" x="…" z="…"/>
<Fields> <Field id="1" x="…" z="…" isOwned="false"/>
<Vehicles> <Vehicle name="…" type="…" x="…" z="…" fillTypes="…" fillLevels="…" isAIActive="false"/>
owner ist die Hof-Nummer, nicht der Spielername. Welcher Spieler zu
welchem Hof gehört, steht in keinem Endpunkt — deshalb die Zuordnung im Panel.
Koordinaten
x nach rechts, z nach unten, und die Welt läuft von -mapSize bis
+mapSize — also doppelt so weit, wie der Name vermuten lässt.
Das ist die Stelle, an der man zweimal falsch abbiegt:
-mapSize/2 … +mapSize/2 wirkt naheliegend und sieht auf den ersten Blick
sogar richtig aus, weil die Parzellen zueinander stimmen. Tatsächlich zieht es
jede Parzelle um Faktor zwei vom Mittelpunkt weg, und am Ende liegen die
Felder im Wald.
Ein Test, der die Koordinaten auf ihre eigene Bounding-Box normiert, merkt das nicht — er prüft nur die Anordnung und besteht bei jedem Maßstab.
Woran man es festmacht
Viele Karten tragen eingebrannte Marken H1…H8 mit einer Legende, welche
Parzelle das ist (131 H1, 132 H2, …). Das sind acht kostenlose Passpunkte.
Mit dem richtigen Maßstab liegen die Parzellen-Schwerpunkte unter 15 px von
ihrer Marke entfernt, gemessen auf einem 1024er Bild; mit dem falschen rund
200 px. Der Unterschied ist so deutlich, dass eine einzige Prüfung reicht.
Was es nicht gibt
Welche Frucht auf einem Feld steht und wie weit sie ist. Das liegt in
densityMap_fruits.gdm, einer Binärdatei ohne öffentliche Spezifikation, die
nur im kompletten Savegame-ZIP steckt — und das lädt man über die
Admin-Oberfläche, nicht über den Code.
Daran ändert auch kein Mod etwas. Crop Growth Stage
Info und Additional
Field Info berechnen
genau diese Werte, sind aber reine HUD-Overlays: Lua, modDesc.xml, ein Icon —
nichts, was eine Datei schreibt oder einen Port öffnet.
Bestätigt durch die Konkurrenz. Keiner dieser Bots zeigt Feldfrüchte, obwohl einer davon Geld kostet:
- GamePuls — kommerziell, mit Premium-Stufe
- Farm Sim Game — gehostet
- IceEagle132
- DJWoodZ
- cloudmaker97
Der aktuelle Monat. Er steht in keinem Endpunkt.
playTime aus dem Savegame taugt nicht dafür: die Datei wird nur beim
Autosave geschrieben und hinkt bis zu einer Viertelstunde hinterher. Über zwei
Stunden gemessen stieg playTime um 50, während die Spieluhr 18,7 Stunden
weiterlief — daraus lässt sich nichts rechnen.
dayTime in der Statusabfrage zählt Millisekunden seit Tagesbeginn und ist
die brauchbarste Uhr im Feed — aber auch nur ein Schnappschuss. Der Server
schreibt das XML im „Web API Interval" neu, dazwischen steht derselbe Wert.
Gemessen: fünf Abrufe über zwei Minuten, ein Spieler online, alle identisch
(dayTime=37028620).
Bei plannedDaysPerPeriod = 1 ist jeder Rücksprung um Mitternacht ein
Monatswechsel. Also: Monat einmal im Panel eintragen, danach zählt der Bot an
dieser Uhr selbst weiter. Steht der Server leer, steht auch die Spielzeit — und
der Monat bleibt richtigerweise stehen.
Ein Rücksprung ist nicht automatisch Mitternacht. Wer einfach auf
jetzt < vorher prüft, ruft bei jeder kaputten Antwort einen neuen Monat aus:
eine fehlende dayTime wird schnell zu 0, und 0 ist kleiner als jeder
Vortagswert. Ein echter Wechsel geht vom späten Abend in den frühen Morgen —
also beide Werte prüfen, nicht nur ihre Differenz.
Bleibt ein Restrisiko: ein Serverneustart lädt den Spielstand und setzt die Uhr auf den gespeicherten Zeitpunkt zurück. Fällt der zufällig in den frühen Morgen, während vorher später Abend gemessen wurde, zählt der Bot einen Monat zu viel. Dann im Panel den richtigen eintragen — von da an läuft es weiter.
Die zwölf Perioden sind übrigens schlicht Monate: EARLY_SPRING ist März,
EARLY_AUTUMN September.
growthMode sagt, ob überhaupt etwas wächst (2 = pausiert). Auf die
Preise hat das keinen Einfluss — die Kurve hängt am Monat, nicht am Wachstum.
Fallstricke
- Parzellen haben nur Schwerpunkt und Fläche, keine Umrisse. Die Karte zeichnet flächengleiche Kreise. Bei langen schmalen Feldern sieht man das.
- Die Modliste steht vor den Parzellen. Wer nur die ersten Zeilen anschaut, hält den Feed für eine reine Statusabfrage.
- Spargel sprengt jede Preisliste. Er schwankt zwischen 26 und 7540 € und verdrängt nach Schwankungsbreite sortiert jede echte Feldfrucht. Deshalb arbeitet die Preisliste mit einer Auswahl statt mit einem Ranking.
- Das Luftbild als PNG ist zehnmal so gross wie nötig — 2,5 MB statt 250 KB. Es ist ein Foto, also JPEG.