mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-23 17:18:32 +02:00
A browser-based roguelike synchronized with crypto block timing. A run is a race against the next block: reach the exit before the block lands, or the house wins. The same codebase runs the solo dungeon, the social Tavern, and operator-selected PvP and race rulesets, with separate free and paid leaderboards. Self-hostable under the MIT License. See README.md to run it, docs/ARCHITECTURE.md for the design, and docs/DEPLOY.md to operate an instance.
129 lines
7.5 KiB
Markdown
129 lines
7.5 KiB
Markdown
# Architecture
|
|
|
|
Wowngeon is a provably fair, block-timed roguelike with crypto entry and payouts. A solo run is a
|
|
race against a random block deadline; multiplayer matches run the same engine under a ruleset. The
|
|
game also acts as a multi-chain on-ramp for the Smirk wallet.
|
|
|
|
This page is the index for the architecture docs. Each subsystem has its own page.
|
|
|
|
## System map
|
|
|
|
```
|
|
┌──────────── players (browser) ─────────────┐
|
|
│ index.html · tavern.html · match.html │
|
|
│ html/js/render (render kit) │
|
|
└───────────────┬───────────────┬────────────┘
|
|
Socket.IO │ │ REST (auth, payments, status)
|
|
┌────────────────▼───────────────▼────────────┐
|
|
│ src/network/* socket handlers, chat, │
|
|
│ tavern, match, payments │
|
|
├─────────────────────────────────────────────┤
|
|
game core │ src/game/* dungeon · rulesets · modes │ → RULESETS.md
|
|
money │ src/payments/* providers · wallet-rpc │ → PAYMENTS.md
|
|
cosmetics │ src/multiplayer/entitlements + catalog │ → MONETIZATION.md
|
|
chains │ src/chain/chainProfile.js │ → chain profiles, below
|
|
chat │ src/network/chat/* local + nostr │ → CHAT_AND_NOSTR.md
|
|
└─────────────────────────────────────────────┘
|
|
│ │
|
|
PostgreSQL Wownero/Monero wallet-RPC, BTCPay/checkout gateways
|
|
```
|
|
|
|
`src/index.js` is the composition root: it builds the Express app and Socket.IO server, wires the
|
|
database manager, wallet RPC service, payment config, game mode manager and socket handlers, and
|
|
mounts the REST routes in `src/routes/`.
|
|
|
|
## Subsystem guide
|
|
|
|
| Area | Where | Doc |
|
|
|------|-------|-----|
|
|
| Credits, cosmetic catalog, entitlements | `src/multiplayer/entitlements.js`, `src/services/catalogService.js` | [MONETIZATION.md](MONETIZATION.md) |
|
|
| Chain constants for the five Smirk chains | `src/chain/chainProfile.js` | below |
|
|
| Payment providers and payouts | `src/payments/` | [PAYMENTS.md](PAYMENTS.md) |
|
|
| Rulesets and match engine | `src/game/rulesets/`, `src/multiplayer/MatchEngine.js` | [RULESETS.md](RULESETS.md), [MATCH_MODE.md](MATCH_MODE.md) |
|
|
| Tavern lobby and spectating | `src/network/tavernManager.js`, `src/multiplayer/Room.js` | [TAVERN_AND_MULTIPLAYER.md](TAVERN_AND_MULTIPLAYER.md) |
|
|
| Chat, local and nostr | `src/network/chat/` | [CHAT_AND_NOSTR.md](CHAT_AND_NOSTR.md) |
|
|
| Client render kit and art packs | `html/js/render/` | [RENDER_PACKS.md](RENDER_PACKS.md) |
|
|
| Balance and pacing | `src/sim/`, `src/game/difficultyConfig.js` | [BALANCE_SIM.md](BALANCE_SIM.md), [MULTI_LEVEL.md](MULTI_LEVEL.md) |
|
|
| Deployment and operations | `scripts/deploy/` | [DEPLOY.md](DEPLOY.md), [DEPLOY_INSTANCES.md](DEPLOY_INSTANCES.md), [LOGS_AND_BACKUP.md](LOGS_AND_BACKUP.md) |
|
|
| Financial reconciliation and exports | `src/services/` | [FINANCIAL_RECONCILIATION.md](FINANCIAL_RECONCILIATION.md), [FINANCIAL_EVENT_EXPORT.md](FINANCIAL_EVENT_EXPORT.md) |
|
|
|
|
Optional subsystems are environment-gated and dormant by default: payment gateways register only
|
|
when their `*_URL` / `*_STORE_ID` / `*_API_KEY` trio is set, global nostr chat requires
|
|
`NOSTR_CHAT_ENABLED=true`, and match rooms require `MATCH_ENABLED=true`. With none of those set the
|
|
server runs the native wallet-RPC payment path, local socket chat, and solo play only. The full
|
|
environment template is [`src/.env.example`](../src/.env.example).
|
|
|
|
## Chain profiles
|
|
|
|
`src/chain/chainProfile.js` is the single source of truth for per-chain constants across BTC, LTC,
|
|
XMR, WOW and GRIN: `decimalsFor`, `meanBlockTimeMsFor`, `familyFor` (`monero` / `utxo` /
|
|
`mimblewimble`), `uriSchemeFor` and `atomicDivisor` (BigInt).
|
|
|
|
| Chain | Decimals | Mean block time | Family | URI scheme |
|
|
|-------|----------|-----------------|--------|------------|
|
|
| WOW | 11 | 5 min | monero | `wownero` |
|
|
| XMR | 12 | 2 min | monero | `monero` |
|
|
| BTC | 8 | 10 min | utxo | `bitcoin` |
|
|
| LTC | 8 | 2.5 min | utxo | `litecoin` |
|
|
| GRIN | 9 | 1 min | mimblewimble | `grin` |
|
|
|
|
An unrecognized chain id resolves to a default profile shaped like XMR: 12 decimals, 120000 ms mean
|
|
block time, `monero` family, `monero` URI scheme. Callers therefore never crash on a mis-set
|
|
`CRYPTO_TYPE`. Adding a chain is one entry in the registry plus a family adapter.
|
|
|
|
Money math is exact: `src/money/atomic.js` operates on BigInt atomic units parameterized by
|
|
decimals, never floats.
|
|
|
|
## Game balance and pacing
|
|
|
|
A solo run is bounded by a random deadline drawn from an exponential distribution with mean equal to
|
|
the chain's block time, so the house edge is a convolution of the run-completion distribution with
|
|
block cadence rather than a number that can be set by hand. `src/sim/` drives the real engine with
|
|
headless bots and integrates the deadline out analytically, reporting a measured house win rate per
|
|
preset and per network.
|
|
|
|
`NETWORK_TUNING` in `src/game/difficultyConfig.js` scales dungeon depth to block time. Dungeon size
|
|
and monster behaviour come from the difficulty preset; the per-network entry overrides only the
|
|
level count:
|
|
|
|
| Chain | Levels |
|
|
|-------|--------|
|
|
| GRIN | 1 |
|
|
| XMR | 1 |
|
|
| LTC | 2 |
|
|
| WOW | 2 |
|
|
| BTC | 3 |
|
|
|
|
`NETWORK_TUNING_DISABLED=true` bypasses the override and leaves the preset's own level count in
|
|
place. Descending emits a `game_event`, which the client handles in
|
|
`html/js/network/socketHandlers.js` to surface level progress. See [BALANCE_SIM.md](BALANCE_SIM.md)
|
|
and [MULTI_LEVEL.md](MULTI_LEVEL.md).
|
|
|
|
## Client render kit
|
|
|
|
`html/js/render/` (exposed as `RK`) draws a shared `Scene` model in four techniques: Tiled, ASCII,
|
|
Iso and 3D. Art packs are interchangeable data, a pure-canvas FX layer supplies torch and hazard
|
|
effects, and the pack and technique available to a player come from the operator-owned cosmetic
|
|
catalog. Tiled and ASCII are free; Iso and 3D are premium. See [RENDER_PACKS.md](RENDER_PACKS.md).
|
|
|
|
## Provable fairness
|
|
|
|
`src/game/provablyFair.js` derives each dungeon from a committed seed, `src/game/fairnessVerifier.js`
|
|
exposes verification endpoints, and `src/views/verifyPage.js` renders the public verification page so
|
|
a player can reproduce a dungeon from its published proof.
|
|
|
|
## Conventions
|
|
|
|
- **Game id** is a UUID stored in `games.dungeon_seed`; `games.id` is a serial integer. Match game
|
|
objects with `WHERE dungeon_seed = $N`, never `WHERE id = $N`.
|
|
- **Socket ids are volatile** and change on refresh. Stable identity is the database `user_id` or the
|
|
session, never `socket_id`.
|
|
- **WOW has 11 decimals** (atomic divisor 1e11), unlike Monero's 12.
|
|
- **Cosmetic entitlements are per-pack**, resolved by tier and by lifetime credits purchased in
|
|
`src/multiplayer/entitlements.js`. Buying credits does not by itself unlock premium packs.
|
|
- **Migrations** live in `src/migrations/NNN_*.sql` and run in numeric order.
|
|
- **Tests**: `cd src && npm test` (Jest, `--runInBand`).
|
|
|
|
Source files carry JSDoc for API-level detail; these pages cover the seams between subsystems and
|
|
the operator-facing intent behind them.
|