System Simulation Patterns¶
Purpose¶
This document describes the shared technical approach that keeps all major game systems authoritative, scalable, and cheap enough to run on Cloudflare.
Core Pattern¶
The game should be command-driven and timer-driven.
- the client sends intent
- the server validates prerequisites
- the server stores authoritative state
- time passes
- the server settles the outcome when a timer completes or the player checks in
Command Model¶
Every mutating action should be represented as a command such as:
- start expedition
- place market order
- plant crop
- deliver resources to town
- bid on auction
- post player contract
Commands should validate actor state, permissions, resource costs, and location rules before any write is committed.
Safe Retry Rule¶
Every command should carry a unique request key so that retries do not duplicate rewards, purchases, shipments, or contract payouts.
State Ownership¶
Use a clear ownership boundary for mutable state:
- one expedition coordinator per active expedition or group mission
- one market coordinator per exchange
- one town coordinator per settlement
- one guild coordinator per guild treasury and permissions
This keeps race conditions local and debuggable.
Storage Split¶
D1¶
Use for relational persistence, historical records, and reporting-friendly data.
Durable Objects¶
Use for serialized coordination and short-lived in-memory active state.
KV¶
Use for read-heavy cached projections like public town status, codex summaries, and map board views.
R2¶
Use for static SVG assets, sound, and large immutable content bundles.
Timer Model¶
All long actions should be stored as job records with:
- actor
- action type
- start time
- next wake time
- expected end time
- seed
- current phase
This model works for expeditions, crop growth, shipments, town projects, and contract expiration.
The same model should be used for dynamic event instances and their resolution windows.
Event Director Pattern¶
Dynamic world events should be evaluated locally, not by one giant world scan.
Recommended approach:
- each town or area coordinator maintains compact local condition scores
- an evaluation pass runs on a fixed cadence
- eligible event templates are weighted by local state
- a small number of events are spawned or advanced
- results feed back into town, route, resource, and market state
This preserves dynamism without breaking the cost model.
Event Log Pattern¶
For important systems, write append-only event rows instead of only overwriting final totals.
This is especially valuable for:
- currency movement
- item transfers
- expedition outcomes
- town reserve changes
- tax application
- auction settlement
Read Model Pattern¶
Player interfaces should read from summarized projections where possible.
Examples:
- town status panel reads a town summary
- market overview reads regional price snapshots
- codex reads player and guild knowledge summaries
- event board reads active local and regional event summaries
This keeps the UI fast without compromising authoritative writes.
Failure Recovery¶
Every timer-driven system needs replay-safe settlement. If a Worker retries or a coordinator wakes twice, the system should detect that settlement already happened and return the same result instead of duplicating state changes.
Settlement Tick Architecture¶
There are two distinct settlement mechanisms. They are not the same thing and must not be conflated.
Per-Expedition Settlement (Continuous)¶
Expedition outcomes settle independently of any global clock. This is not the daily tick.
Trigger: The expedition coordinator Durable Object sets an alarm for the expedition's computed end time at the moment the expedition launches. When the alarm fires, the coordinator settles the outcome and writes results back to D1. If the player checks in before the alarm fires and the end time has already passed, the coordinator settles immediately on check-in.
Effect: Expedition results, rewards, injury records, skill events, and supply consumption are written on settlement. Town reserve contributions from deliveries and contract completions are staged for the daily tick to consolidate.
Retry safety: The coordinator marks the expedition as settled before dispatching writebacks. A second alarm or check-in after settlement is a no-op.
Daily Global Tick (Scheduled)¶
All world-state simulation that does not belong to a specific expedition runs on a single daily tick.
Trigger: Cloudflare Cron Trigger on a dedicated Worker, scheduled at 00:00 UTC every day. The trigger interval is daily (0 0 * * *). It cannot be shortened without a deliberate architecture decision — do not add per-hour world simulation without evaluating the D1 write volume implications.
Dispatch model: The global tick Worker does not run all simulation itself. It reads the list of active towns, regions, and markets from D1, then sends a task message to each relevant coordinator Durable Object (one per town, one per market region). Each coordinator runs its own simulation pass and writes its own state. The global tick Worker is a dispatcher, not a simulator.
Order of operations within the daily tick:
| Step | System | What Happens |
|---|---|---|
| 1 | Market cleanup | Expired sell orders, buy orders, and auctions are closed; refunds issued via escrow release |
| 2 | Town simulation | Each town consumes reserves, applies production, processes staged deliveries from settled expeditions, and updates health bands |
| 3 | Board regeneration | Town coordinators emit new board offer generation requests based on updated town state and shortfall priorities |
| 4 | Creature escalation | Each region coordinator evaluates creature grade promotions based on unkilled-tick counters |
| 5 | Event director evaluation | Each town and region coordinator evaluates dynamic event eligibility and advances active event instances |
| 6 | Skill event aggregation | Pending cross-system skill events (teaching session grants, guild certification credits) are applied to character skill records |
| 7 | Notification dispatch | Players with advance-pending skills, completed caravan legs, expiring contracts, or market settlements receive notifications |
Steps 1–7 are independent within each coordinator — a town coordinator does not wait for another town to finish. Failures in one coordinator do not block others. The global tick Worker does not retry failed coordinator dispatches automatically; coordinator alarms handle their own recovery.
Settlement tick for game calendar: The game calendar advances one day per daily tick. Season changes occur on tick-driven day counts defined in seasons-and-weather.md. Creature migration windows open and close on tick counts, not real-world dates.
What Belongs Where¶
| System | Settlement Type |
|---|---|
| Expedition outcome, rewards, injuries | Per-expedition (continuous) |
| Skill events from expeditions | Per-expedition |
| Town reserve changes from deliveries | Staged; consolidated in daily tick step 2 |
| Market order expiry | Daily tick step 1 |
| Board offer refresh | Daily tick step 3 |
| Creature escalation | Daily tick step 4 |
| Dynamic event progression | Daily tick step 5 |
| Cross-skill and teaching grants | Daily tick step 6 |
| Game calendar and season advance | Daily tick |
| Caravan leg arrival | Per-expedition (coordinator alarm at arrival time) |
| Auction close | Triggered by auction end time (DO alarm), not daily tick |
Why This Matters¶
The same technical pattern should drive combat, farming, market settlement, town demand, and logistics. Reusing one clear backend model is what keeps the game maintainable.