Files
h-school/README.md
T
Leonid Pershin e2e7d30701 Tighten layer graph tests and document npm test typecheck.
Content and People/Schedule/Ai now fail the same way if they grow a game-layer edge the projects.md graph forbids; README matches the tsc-then-vitest script from phase 57.
2026-08-20 14:04:35 +03:00

156 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# h-school
Base for a school-management game: an authoritative .NET server that owns the saves and their
in-game calendars, a TypeScript client that renders the menus, and .NET Aspire tying them together
for local runs and integration tests.
What exists today is the shell around a game: a main menu of schools, a creation form, and a
school screen with a running game clock. People already walk, dress, take lessons and talk.
## Stack
| Layer | Choice |
| --- | --- |
| Server | .NET 10, ASP.NET Core |
| Simulation | [Arch](https://github.com/genaray/Arch) ECS, fixed 20 Hz tick |
| Transport | REST for the menu, raw WebSocket + binary protocol for the clock |
| Client | TypeScript, Vite, plain DOM |
| Orchestration | .NET Aspire 13 |
| Tests | xUnit v3, Vitest, `Aspire.Hosting.Testing` |
## Prerequisites
- [.NET SDK 10](https://dotnet.microsoft.com/download) (`global.json` pins the 10.0.1xx band)
- [Node.js](https://nodejs.org/) 22.12 or newer
- Optional: the Aspire CLI (`dotnet tool install -g aspire.cli`) if you prefer `aspire run`
## Run everything
```bash
dotnet run --project src/HSchool.AppHost
```
On Windows `run-aspire.ps1` does the same (`run-aspire.cmd` forwards to it and can be
double-clicked). On Ubuntu `./run-aspire.sh`. Both check that the .NET SDK and Node are on
PATH first and pass any arguments through (`--launch-profile http`). A second launch with no
C# changes skips MSBuild; `--rebuild` forces a build.
The Aspire dashboard opens with two resources: `server` (ASP.NET Core) and `client` (Vite dev
server on port **5173**).
## Share with friends on Tailscale
For a dev session over your tailnet, expose only the Vite client — not the game server (5180),
Aspire dashboard (15180), or SwarmUI.
`run-aspire.ps1` / `run-aspire.sh` run `tailscale serve --bg 5173` before the AppHost when
`tailscale` is on PATH and connected. If Tailscale is missing, offline, or `serve` fails, the script prints a
warning and continues with local access only (`http://localhost:5173`). When Serve is up, it
prints the HTTPS client URL next to the local one; the Aspire dashboard stays on localhost.
Pass `--no-tailscale` to skip Serve entirely. You can also run the command yourself once per
boot if you start with `dotnet run --project src/HSchool.AppHost` instead.
Friends on the same tailnet open `https://<your-machine>.<tailnet>.ts.net`. The page, REST API
and game WebSocket all go through Vites proxy on one origin; Kestrel stays on localhost.
Change `HSchool:AlphaPassword` from the repo default before sharing the link. Optional: set
`HSCHOOL_TAILSCALE_SERVE=1` in the client process environment if you want Vite HMR through Serve
(`wss` on port 443); gameplay works without it.
Do **not** add port 5180 or the Aspire dashboard to `tailscale serve`.
## What you can do
- **Main menu** — every school as a card with its name and its current in-game date and time,
ticking live. Deleting one asks for confirmation first. The footer switches the UI between
Russian and English; the choice is remembered in the browser.
- **Create a school** — type a name or roll a random one, pick a start date (3 April 2012, 06:00
by default). When the player has filled their school slots the create button is disabled and
says why.
- **Inside a school** — the date, time and weekday of the game calendar, play/pause and the
×½ ×1 ×2 ×5 ×10 speed buttons, plus a way back to the menu.
Time runs at 1 game minute per real second at ×1. **Every school runs on its own**, whether or
not you are inside it — the menu cards keep counting. Only the pause button stops a school, and it
stays paused (the card says so) until you press play again.
Schools are written under `saves/` on the server. Restarting the process brings them back.
## Run the pieces separately
```bash
dotnet run --project src/HSchool.Server
```
```bash
npm --prefix src/HSchool.Client run dev
```
Without Aspire the client falls back to `http://localhost:5180` for its `/api` and `/ws` proxy,
which matches the server's launch profile.
## Tests
```bash
dotnet test
```
- `tests/HSchool.Architecture.Tests` — layer bans (Arch, ASP.NET, sockets, wall-clock) for
Protocol through Simulation. No host.
- `tests/HSchool.Protocol.Tests` — wire-format round-trips and byte layouts.
- `tests/HSchool.Content.Tests` — JSONC catalog, inheritance, patches, map connectivity. No host.
- `tests/HSchool.Simulation.Tests` — the game clock, school load/create, and the school registry, no host involved.
- `tests/HSchool.AppHost.Tests` — boots the real Aspire graph, drives the menu API and the
WebSocket clock. Runs headless (`--HSchool:Headless=true`), so no Node install is needed.
```bash
npm --prefix src/HSchool.Client test
```
`npm test` runs `tsc -b` then Vitest (codec, calendar formatting, RU/EN dictionaries). A duplicate
key in `strings.ts` fails typecheck without `npm run build`. `test:watch` is Vitest only.
## Layout
```
src/
HSchool.Protocol/ binary wire format (shared contract with the client)
HSchool.Content/ JSONC defs, patches, map validation
HSchool.Simulation/ schools, the game clock, the Arch ECS world
HSchool.Server/ ASP.NET Core host, menu API, WebSocket, workers
HSchool.Server/mods/ pack folders; `core` is always on
HSchool.ServiceDefaults/ Aspire telemetry, health checks, resilience
HSchool.AppHost/ Aspire orchestration
HSchool.Client/ Vite + TypeScript UI
tests/
docs/
architecture.md how the pieces fit together
protocol.md the HTTP API and the wire format, byte by byte
AGENTS.md working agreements for humans and coding agents
```
## Configuration
Simulation tunables live under the `Simulation` section of
`src/HSchool.Server/appsettings.json`:
| Key | Default | Meaning |
| --- | --- | --- |
| `TickRate` | 20 | fixed simulation steps per second |
| `MaxSchools` | 2 | how many schools each player may own |
| `GameMinutesPerRealSecond` | 1 | game minutes per real second at ×1 |
| `DefaultStartDate` | `2012-03-31T06:00:00` | prefilled start of a new school |
| `SavesDirectory` | `saves` | per-school JSON files |
| `ModsDirectory` | `mods` | pack folders; `core` is required |
| `SaveIntervalSeconds` | 30 | rare clock snapshot; not every tick |
| `MinSaveIntervalMilliseconds` | 1000 | shortest gap between saves caused by pause or speed |
| `MonthlyPayrollCap` | 100000 | monthly payroll the player may commit; hires and assignments that would exceed it are rejected |
| `SchoolWeekDays` | 5 | working days from Monday (5 is MonFri; 6 adds Saturday) |
| `MaxDecisionsPerTick` | 64 | presence decisions processed per tick; overflow waits |
## What is deliberately missing
No authentication, no action execution, and the create dialog does not yet pick mods or edit the
map — every new school gets the vanilla `core` layout. Each of these has a seam described in
[`docs/architecture.md`](docs/architecture.md).