Refactor world simulation and API to enhance world state management; introduce StoredWorldDto for internal bookkeeping, improve synchronization between simulation and API data, and implement new simulation options for idle and catch-up behavior. Update documentation to reflect changes in data structures and API endpoints.
This commit is contained in:
@@ -113,6 +113,11 @@ them without reworking the data model.
|
||||
| `DELETE /api/worlds/{id}` | Remove a world and its chunks |
|
||||
| `GET /api/climates` | The climate catalogue for the create form, with the latitude band each preset is the default for |
|
||||
|
||||
`state.json` and the API do not share a type. `StoredWorldDto` holds what the simulation needs to resume — the
|
||||
last tick stamp and the drifting pressure systems — and `WorldSummaryDto` holds what clients see. The only way
|
||||
from one to the other is `ToSummary()`, so a new endpoint cannot publish the internals by forgetting to strip
|
||||
them; the wire type has no field that could carry them.
|
||||
|
||||
Generation takes tens of seconds — mostly waiting on Overpass — so `POST` returns straight away and the client
|
||||
polls for status. Only one generation runs at a time, to stay a good citizen on the shared Overpass mirrors.
|
||||
The number of worlds that may exist at once is capped by `WorldStorage:MaxConcurrentWorlds` (today that means
|
||||
@@ -136,6 +141,13 @@ The drifting systems are persisted in `state.json` so a restart resumes the sky
|
||||
than a game day away and the model rolls a fresh sky for the season instead — stepping days of drift in one
|
||||
jump is not a simulation, it is a teleport.
|
||||
|
||||
Time does not run without limit while nobody is here. A world banks at most `Simulation:MaxCatchUpGameHours`
|
||||
of in-world time per step, so a host that was down for a week wakes its worlds a day older rather than years.
|
||||
Worlds nobody is looking at also tick lazily, on `Simulation:IdleTickSeconds` instead of every pass. That
|
||||
costs no accuracy — a step is driven by the wall time since *that* world last ticked, so one long step and
|
||||
fifty short ones land on the same game time — and reading a world brings it current before answering, which
|
||||
keeps the work proportional to how much anyone is actually watching.
|
||||
|
||||
Snow is the one part of the weather with memory. Everything else is a function of the current instant, but
|
||||
you cannot tell how deep the snow lies without knowing what the sky did for the last few days, so it is
|
||||
integrated as the world ticks and stored alongside the pressure systems. A world created in a Siberian
|
||||
@@ -210,6 +222,10 @@ usual dissolve instead of a special case. The page chrome follows via a `data-th
|
||||
|
||||
- `WorldStorage:RootDirectory` — where generated worlds go (default `data/worlds`)
|
||||
- `WorldStorage:MaxConcurrentWorlds` — how many worlds may exist at once (default `8`)
|
||||
- `Simulation:MaxCatchUpGameHours` — in-world time a world may bank per step, so downtime does not cost years
|
||||
(default `24`; `0` removes the limit)
|
||||
- `Simulation:IdleAfterSeconds` — how long after the last request a world stops counting as watched (default `20`)
|
||||
- `Simulation:IdleTickSeconds` — tick spacing for unwatched worlds (default `5`)
|
||||
- `Osm:Endpoints` — Overpass mirrors, tried in order
|
||||
- `Osm:CacheDirectory` — raw Overpass responses (default `data/osm-cache`)
|
||||
- `Osm:QueryTimeoutSeconds` / `Osm:RequestTimeoutSeconds` — server-side and client-side budgets
|
||||
|
||||
Reference in New Issue
Block a user