CI / quality (push) Successful in 1m18s
Daikoku Futo PA becomes the hub (Tokyo Xtreme Racer structure): park, pick a
mode, drive out the exit gate to start the run, pull back into the PA to end it.
Modes:
- CRUISE free roam, banks session + lifetime kilometres
- DUEL gap-based battle: hold 350 studs for 3s to win
- TIME ATTACK solo flying lap, 4 sector splits, saved personal best
New shared modules:
- Circuit.luau one source of truth for loop geometry. progressOf(pos) gives
lap distance, which drives lap detection, sectors and duel gaps
alike, so the map and gameplay can never drift apart.
- Modes.luau mode definitions + duel/time-attack tuning constants
Server-authoritative throughout: ModeManager samples the car real position on
Heartbeat and the client never reports distance, lap time or gap. Teleport and
respawn jumps are rejected from distance accumulation.
ProfileTemplate v3 adds DistanceStuds, BestLapTime, BestSectors, DuelsWon and
DuelsLost; ProfileStore Reconcile migrates existing saves.
Rename: repo, wally package, local dir and stale NAS asset paths all move off
the old fnf-sim name. NAS folder was already 0-tokyo-wangan-racing, so those
doc paths were broken before this.
106 lines
4.1 KiB
Markdown
106 lines
4.1 KiB
Markdown
# Tokyo Wangan Racing
|
|
|
|
A Roblox game where you cruise a neon Tokyo expressway at night in cool cars —
|
|
starting with a real 1993 Mazda RX-7. The driving feel comes first; everything
|
|
else layers on top of it. See `docs/ROADMAP.md` for what comes next.
|
|
|
|
**Status:** Playable. Spawn → drive → switch cars → respawn, plus the full
|
|
three-mode Wangan loop. CI green on a self-hosted Gitea runner. Built code-first
|
|
— nothing to hand-build in Studio.
|
|
|
|
## The Daikoku loop (how you play)
|
|
|
|
Daikoku Futo PA is the hub, exactly like Tokyo Xtreme Racer. You are never
|
|
"joining a match" — you park, pick how you want to run, and drive out.
|
|
|
|
```
|
|
IN THE PA ──► pick a mode ──► cross the exit gate ──► RUNNING
|
|
▲ │
|
|
└──────────────── pull back into the PA ─────────────────┘
|
|
```
|
|
|
|
| Mode | 日本語 | What it is |
|
|
|---|---|---|
|
|
| **CRUISE** | 流し | Free roam. Bank kilometres, meet other drivers. Rivals can pull alongside and challenge you. |
|
|
| **DUEL** | バトル | Hunt rivals. First to open a ~350-stud gap and *hold* it for 3s wins. No laps, no checkpoints — who breaks first. |
|
|
| **TIME ATTACK** | タイムアタック | Solo flying lap with 4 sector splits and a saved personal best. Rivals can't interrupt you. |
|
|
|
|
Cruise and Duel both allow challenges, so a cruise can turn into a battle
|
|
organically — pull alongside someone and the prompt appears for both of you.
|
|
Time Attack deliberately opts out so a hot lap is never ruined.
|
|
|
|
Kilometres, lap times and duel records all persist via ProfileStore.
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
Toolchain is managed by [Rokit](https://github.com/rojo-rbx/rokit). With Rokit on
|
|
your `PATH`:
|
|
|
|
```bash
|
|
rokit install # rojo, wally, selene, stylua at pinned versions
|
|
wally install # restores ProfileStore into ServerPackages/
|
|
```
|
|
|
|
| Tool | Purpose |
|
|
|---|---|
|
|
| rojo | Sync/build code ↔ Roblox place |
|
|
| wally | Package manager (ProfileStore) |
|
|
| selene | Static analysis / linter |
|
|
| stylua | Code formatter |
|
|
|
|
## Build & run
|
|
|
|
```bash
|
|
rojo build --output build.rbxl # standalone place file to open in Studio
|
|
# OR live-sync into an open Studio place (install the Rojo Studio plugin):
|
|
rojo serve
|
|
```
|
|
|
|
In Studio press **Play**. You spawn on the expressway in your car. Bottom bar:
|
|
**CARS** (switch car) and **RESPAWN** (re-spawn if you flip). The RX-7 only
|
|
appears for allowlisted accounts.
|
|
|
|
## Quality gates (CI enforces these on every push)
|
|
|
|
```bash
|
|
stylua --check src/ # formatting
|
|
selene src/ # lint
|
|
rojo build --output build.rbxl # must compile
|
|
```
|
|
|
|
CI runs on a self-hosted **Gitea Actions** runner on UNRAID-1 (Ubuntu 24.04 job
|
|
container — rojo's binary needs glibc 2.39). Workflow: `.gitea/workflows/ci.yml`.
|
|
|
|
---
|
|
|
|
## Architecture (server-authoritative)
|
|
|
|
Clients **request**, the server **decides**. The RX-7 allowlist and anti-cheat
|
|
are server-side.
|
|
|
|
```
|
|
ReplicatedStorage/Shared GameConfig, Cars, ProfileTemplate, Remotes
|
|
ServerScriptService/Server init.server + managers (below)
|
|
ServerScriptService/ServerPackages ProfileStore (Wally)
|
|
StarterPlayerScripts/Client init.client (HUD + car picker)
|
|
```
|
|
|
|
| Module | Responsibility |
|
|
|---|---|
|
|
| `DataManager` | Wraps **ProfileStore** — session locking, reconcile, Studio mock. Remembers your last car. |
|
|
| `CarManager` | Spawns the equipped car (VehicleSeat-driven placeholder) and enforces the RX-7 allowlist. |
|
|
| `MapBuilder` | Procedurally builds the expressway, spawn pad, neon pylons, kill walls. |
|
|
| `AntiCheat` | Movement sanity check (speed/teleport) — a speed bump, not a fortress. |
|
|
|
|
The RX-7 demo-lock: `GameConfig.RX7AllowedUserIds` holds the owner's + son's
|
|
Roblox UserIds; only they can select/drive the RX-7 (enforced in `CarManager` and
|
|
the `EquipCar` remote).
|
|
|
|
## Replacing the placeholder RX-7 with the real mesh
|
|
|
|
One function changes: `CarManager.buildCarModel`. Full step-by-step in
|
|
`docs/MESH_SWAP.md`. Reference photos live on the NAS at
|
|
`unraid-1:/mnt/user/data/yy-roblox-games/0-tokyo-wangan-racing/001-1993 Mazda RX-7/`.
|