105 lines
6.3 KiB
Markdown
105 lines
6.3 KiB
Markdown
# World Simulation
|
|
|
|
A browser-based world simulation with a Rust server and a Leptos/Wasm UI. The server runs the simulation and exposes its state over HTTP and WebSockets. You can edit terrain and resources, manage people and animals, and customize agent behavior with the included Rune script.
|
|
|
|
Living simulation entities (people, rabbits, and wolves) run as Picard actors. The world coordinates terrain, shared resources, and actor messages; Rune behavior scripts remain on the simulation thread because Rune's VM is not `Send`. Picard's tracing and runtime statistics features are enabled: actor lifecycle events are logged (configure verbosity with `RUST_LOG`, for example `RUST_LOG=picard=trace`), and cumulative actor/message counters are shown in the UI.
|
|
|
|
The simulation script is the root [config.rn](./config.rn), a single Rune file. Its `pub const` items hold defaults and tuning values: map dimensions and terrain generation, initial population and resources, calendar and life-stage defaults, hunger, gathering, construction, partnerships and births, animal behavior, and edit limits. Its `pub fn person`, `pub fn rabbit`, and `pub fn wolf` items are the agent behaviours, and they can use the constants directly. Every constant the server reads must be defined; missing or invalid values are reported at startup. `SIM_CONFIG` can point to a different Rune file. Docker Compose mounts the repository's `config.rn` read-only into the app container.
|
|
|
|
The in-browser script editor edits the same file contents. Applied edits take effect immediately for behaviours and tuning values, while map dimensions, initial population, and calendar defaults apply when the world is reset. Editor changes are not written back to disk: on restart, `config.rn` from disk replaces them, even when a saved world snapshot is restored.
|
|
|
|
The **Calendar and life-stage durations** panel configures ticks per day and the number of days, weeks, and months in larger calendar units. Each human life stage has an inclusive minimum/maximum duration in in-game days; the world samples within that range when a person enters the stage. These runtime settings are stored with the world snapshot and take precedence over the config defaults until the world is reset.
|
|
|
|
New people, including babies, start as toddlers and age through child, teen, young adult, adult, older adult, elderly, and death. By default, the starting village has nine young and mature adults and a reserve of 60 food so it can form partnerships and sustain its population. People pathfind around blocked terrain when travelling home for food. Unpartnered people from young adulthood onward can form a single partnership with a nearby eligible person. Each partnership can have one toddler per calendar week when both partners are in stages marked fertile, the stockpile has enough food, and housing capacity permits it. By default, the village has capacity for 12 people, with each additional house increasing capacity by three; these values are configurable. Young adult and adult stages are fertile by default; fertility can be changed per stage in the calendar panel. Partnerships are Picard actors as well as people and animals.
|
|
|
|
The UI is built automatically as part of `cargo run` and embedded in the server binary. There is no separate manual UI build step.
|
|
|
|
## Getting Started
|
|
|
|
### Local run with SQLite
|
|
|
|
Install Rust with `rustup`. The build script installs the `wasm32-unknown-unknown` target if it is missing. Start locally with SQLite using:
|
|
|
|
```sh
|
|
just dev
|
|
```
|
|
|
|
Open [http://127.0.0.1:7878](http://127.0.0.1:7878). The database is SQLite at `sim.db` in the current directory, and the initial seed is `42`. You can also run directly with `cargo run`.
|
|
|
|
To choose a seed on the first run:
|
|
|
|
```sh
|
|
cargo run -- 123
|
|
```
|
|
|
|
An existing database snapshot takes precedence on later runs, including over a new command-line seed. Use the UI's **Reset** button to start a fresh world with its current seed, or **Regenerate** to choose a different seed.
|
|
|
|
### Run with Just
|
|
|
|
Install [Just](https://just.systems/), then list the project recipes:
|
|
|
|
```sh
|
|
just
|
|
```
|
|
|
|
Useful recipes:
|
|
|
|
```sh
|
|
just run # Stop Compose services, then build and start the app with Postgres
|
|
just stop # Stop Compose services; keep the database volume
|
|
just dev # Run locally with SQLite
|
|
```
|
|
|
|
### Run with Docker Compose and Postgres
|
|
|
|
Install Docker with the Compose plugin, then run `just run`. This stops any existing Compose stack before rebuilding and starting the app with Postgres. You can also use the equivalent Docker command directly:
|
|
|
|
```sh
|
|
docker compose up --build -d
|
|
```
|
|
|
|
Open [http://localhost:7878](http://localhost:7878). Compose waits for Postgres to become healthy before starting the app. Postgres data is stored in the `postgres_data` volume and survives container restarts, `just stop`, and `docker compose down`.
|
|
|
|
To remove the database volume and all saved simulation data as well:
|
|
|
|
```sh
|
|
docker compose down -v
|
|
```
|
|
|
|
The Compose file uses development-only database credentials. Change them before exposing the service beyond a trusted local environment.
|
|
|
|
## Database Configuration
|
|
|
|
The server selects its database through `DATABASE_URL`:
|
|
|
|
| Backend | Example URL |
|
|
| ---------------- | --------------------------------------- |
|
|
| SQLite (default) | `sqlite://sim.db?mode=rwc` |
|
|
| Postgres | `postgres://sim:sim@localhost:5432/sim` |
|
|
|
|
For example, run locally against a reachable Postgres server with:
|
|
|
|
```sh
|
|
DATABASE_URL=postgres://sim:sim@localhost:5432/sim cargo run
|
|
```
|
|
|
|
The simulation is saved as a snapshot about once per second and restored at startup. SQLite is convenient for local testing; Compose configures the app to use Postgres.
|
|
|
|
`SIM_ADDR` sets the listen address. It defaults to `127.0.0.1:7878`; containers set it to `0.0.0.0:7878`.
|
|
|
|
## Project Layout
|
|
|
|
- `src/world.rs` contains the simulation and snapshot serialization.
|
|
- `src/main.rs` runs the Axum server, simulation thread, and HTTP/WebSocket API.
|
|
- `src/storage.rs` provides SQLite and Postgres snapshot storage.
|
|
- `config.rn` is the Rune simulation script: `pub const` defaults and tuning values plus `pub fn` behaviours.
|
|
- `ui/` contains the Leptos frontend, compiled to Wasm by `build.rs`.
|
|
- `Dockerfile`, `compose.yaml`, and `Justfile` provide container and developer workflows.
|
|
|
|
## Tests
|
|
|
|
Run the server tests with:
|
|
|
|
```sh
|
|
cargo test --bin sim
|
|
``` |