Implement per-school save functionality by introducing a dedicated save directory and updating the school management system to support loading and saving school states. Revise documentation to reflect these changes, including updates to the architecture and design documents, and enhance the API for reloading schools from disk. Update tests to ensure proper functionality of the new save and reload features.
This commit is contained in:
@@ -11,7 +11,7 @@ way; this file is *how to work in them*.
|
||||
| schools, the game clock, game rules | `src/HSchool.Simulation` |
|
||||
| the menu API (list, create, delete) | `src/HSchool.Server/Api` **and** `docs/protocol.md` |
|
||||
| what the socket carries | `src/HSchool.Protocol` **and** `src/HSchool.Client/src/net/protocol.ts` **and** `docs/protocol.md` |
|
||||
| connection handling, the loop | `src/HSchool.Server` |
|
||||
| connection handling, workers, saves | `src/HSchool.Server` |
|
||||
| what runs locally | `src/HSchool.AppHost/AppHost.cs` |
|
||||
| screens, dialogs, formatting, UI language | `src/HSchool.Client/src` |
|
||||
|
||||
@@ -59,9 +59,11 @@ say so explicitly in the change description.
|
||||
`docs/protocol.md` change in the same commit. A layout change bumps
|
||||
`ProtocolConstants.Version` / `PROTOCOL_VERSION`. Tests on both sides assert byte offsets —
|
||||
if one of them has to change, so do the other two.
|
||||
3. **Only the loop thread touches a `School` or the `SchoolRegistry`.** Everything inbound goes
|
||||
through `GameCommandQueue`; menu reads use the immutable state the loop publishes; everything
|
||||
outbound goes through the per-client outbox. No locks around the registry, no `Task.Run` into it.
|
||||
3. **Only a school's worker thread touches that `School` or its `World`.** The supervisor
|
||||
owns the mailbox table and never calls into a world. Create/delete/name suggestions go
|
||||
through `GameCommandQueue`; open/close/running/speed go to that school's mailbox; menu
|
||||
reads use the snapshots workers publish; everything outbound goes through the per-client
|
||||
outbox. No locks around a school, no `Task.Run` into it.
|
||||
4. **The simulation knows nothing about the network.** `HSchool.Simulation` must not reference
|
||||
ASP.NET Core, sockets or logging infrastructure. It stays testable without a host.
|
||||
5. **Fixed timestep.** The clock advances by `SimulationOptions.FixedDeltaTime`, never by
|
||||
@@ -103,8 +105,11 @@ say so explicitly in the change description.
|
||||
- Server wiring, endpoints and the WebSocket belong in `tests/HSchool.AppHost.Tests`. That suite
|
||||
shares one AppHost across all tests (`AppHostFixture`) — keep it that way, booting per test costs
|
||||
about ten seconds each.
|
||||
- Those tests also share one server, so schools survive between them: start each test by clearing
|
||||
the list (`SchoolApiTests.ResetAsync`) instead of assuming it is empty.
|
||||
- Those tests also share one server, so schools survive between them (and now on disk too):
|
||||
start each test by clearing the list (`SchoolApiTests.ResetAsync`) instead of assuming it
|
||||
is empty. Reset deletes through the API, which deletes the save files. Headless AppHost
|
||||
sets `HSchool:AllowSaveReload` so tests can `POST /api/dev/reload-schools` without killing
|
||||
the shared fixture.
|
||||
- The screens have no unit tests — a DOM environment would cost a dependency the project does not
|
||||
have. Verify UI changes by running the app. Dictionaries and date formatting are covered in
|
||||
Vitest (`i18n/strings.test.ts`, `format/gameTime.test.ts`).
|
||||
@@ -125,8 +130,8 @@ say so explicitly in the change description.
|
||||
- **Game dates are UTC on the wire and UTC when formatted.** A `DateTime` bound from configuration
|
||||
arrives as `Kind=Unspecified`, serializes without a `Z`, and the browser then reads it in its own
|
||||
time zone — `SimulationOptions.DefaultStartDate` forces the kind for exactly that reason.
|
||||
- `PeriodicTimer` does not catch up on its own. The accumulator in `GameLoopService` does, capped
|
||||
at 5 steps — do not "simplify" it away.
|
||||
- `PeriodicTimer` does not catch up on its own. The accumulator in each `SchoolWorker` does,
|
||||
capped at 5 steps — do not "simplify" it away.
|
||||
- Every school runs whether or not a connection is watching it, so anything you hang off the tick
|
||||
runs six times over once six schools exist. `OpenSchool` only subscribes to clock frames.
|
||||
- The menu polls `GET /api/schools` once a second and patches its cards in place. Rebuilding the
|
||||
|
||||
Reference in New Issue
Block a user