Skip to content

packages/sim ​

The shared simulation: bitECS components and systems on top of Rapier 3D. The same code runs on the server and inside each client for prediction, so it contains no platform code, no clock and no Math.random.

FileWhat
world.tsinitPhysics() (loads the WASM once), createSimWorld(level, rules) (Rapier world + level colliders; every integration parameter: contacts 10 cm ahead, stiffer than Rapier's; setPhysicsSubsteps, the steps a tick is cut into; the game's rules, free roam's by default), destroy
components.tsStructure-of-arrays typed arrays, created per world so several worlds can share a process; a character's flags say whether it is an enemy (hostile) or a police officer (police), which the AI sets
vehicle-classes.tsThe tuning table (and the pursuit tune a vehicle may carry, PURSUIT_TUNE: the police's faster cars): twenty-three classes with a drivetrain and an engine placement, written as deltas of the compact (the taxi, the bus, the ambulance, the fire truck and the garbage truck after the police car, then the pickup, the limo, the delivery scooter, the ice-cream van and the tractor); a class's livery (police, taxi, ambulance, fire) the client paints and its features (light bar, siren, roof sign, ladder) the client lights and sounds; the police car is POLICE_CAR
vehicle.tsSpawn/remove/class switch, the vehicle system (engine, drivetrain, wheelspin, brakes, steering, drift, the siren of a class with one while its driver's input asks, the parking brake of a car nobody has driven since it was spawned or left), pose get/set, reset to the nearest spawn no car or person stands on (vehicleSpotTaken); every simulated car with soft CCD (SOFT_CCD_REACH, world.ts)
character.tsOn-foot avatars: spawn/remove, walk/run (35 km/h at most, FLEE_PACE for a bystander's 30)/jump (the flight keeps its take-off velocity), seating in cars (seats, the driver's input forwarding, the spot at a seat's door and the nearest free one along the car), cover, respawn (personSpotTaken); a knockdown with a reason (a status), the bodies that stay; a character's body (BODIES, Character.body: a person's capsule, or a dog's, low, light and quick; isDog, setBody)
car-hits.tsCars against people on foot, after the physics step, from the speed the car closed at along the contact, less what the person was getting away at (recordApproach before it; running into a car is no hit): a hit above 20 km/h (hurt by the closing speed, knocked down, thrown off the front faster than the car, up onto the bonnet, turning to come down lying), the car slowed by what it hands on; a body down that a car only pushes goes over it (up to clear the roof, slower than the car); a body lying in the road is driven over (setLying).
interaction.tsThe interaction key on foot (interactionOf, the one rule the server acts on and the client's prompt shows: get in, ride along, carjack, pick up, open a container or a trunk, close it, open or shut a door, search a body's pockets or (an NPC) wake it, or Locked; Talk at a contact, Use or Hack at a terminal, Enter code at a keypad door, which raise the interact event the server's missions answer; the closest candidate wins, ties broken by a fixed order) and the item keys (itemSystem: the selected slot, use, drop, a transfer in or out of the open container)
interactables.tsWhat the phone's screens and conversations come from: terminals (a kiosk, a keypad, an ATM, a vending machine on a box of their own, used or hacked) and the contact role of a character (Talk) Shops: a counter (spawnShop, shopStock) whose stock the interaction key opens and a click buys from, for Cash.
items.tsItems as data (ItemDef, the COMMON_ITEMS: key, keycard, package, crate, first-aid kit, cash, the phone, kept in the inventory's last slot, tranquilizer darts, the six weapons (ItemDef.weapon) and their ammunition) and what holds them: inventories (16 slots), crates and lockers (8), trunks (6), items on the ground as pickups without a collider; stacking, counting and taking by tag, locks. Prices (ItemDef.price, DEFAULT_PRICE) and the parking ticket (TICKET_ITEM) a barrier opens for.
loadouts.tsWhat a character starts with and leaves where it dies: a loadout (stacks of items by id, each in the slot it names, giveLoadout), free roam's ARSENAL (the weapons in the slots of their old keys, their ammunition), and the items a mission defined dropped as pickups by whoever dies, where the game's rules say so (dropOnDeath, the server's world alone)
cash.tsCash (GAME_DESIGN §14): one purse per player (SimWorld.cash, by client id) that everything pays into and charges (cashOf, addCash, spendCash, takeCash, setCash); the cash items a player takes count into it, never into a slot (cashTaker).
bank.tsThe bank (GAME_DESIGN §14): a balance beside the Cash that the fines never touch (SimWorld.bank, hashed), and the cash machines (@foi/world’s spots of kind atm): atmAction (pay in the Cash but the $2 fee, or take $100 out), useAtm, atmNear, bankOf, setBank (the client’s copy).
doors.tsThe level's doors: one entity each, a panel on a fixed body swung a quarter turn about its hinge (open either way, its collider with it), locked by a tag or by a keypad's code Gates and barriers (a door's kind): a gate slides aside, a barrier lifts its arm (doorPose); gateSystem, run by the server before each step, opens one for a car within GATE.reach whose driver carries what unlocks it and shuts it once its way has been clear a moment.
locks.tsVehicles' owners (nobody, a player, an NPC, a mission) and locks, keys as items answering to a car's key tag, who opens what, who takes a car for their own (the wheel of nobody's car, a carjack, a pick), PICK's three seconds, the cars' events (unlock, pick, respray, store, take out)
garages.tsThe level's garages: what one offers at the wheel of a car standing still in its bay (a respray, storage, each for its price in cash, the game's over the level's), the respray (the next of eight paints, repaired), storing a car for its player and taking it out again on foot
fuel.tsFilling up at a petrol station’s pumps (spots of kind pump): fuelOffer at the wheel of a car standing still by one, fuelService (the service key 1): the boost full and recharging twice as fast for two minutes (VehicleState.fuelled), for its price in Cash.
spawners.tsThe level's vehicle spawners, run by the server only: a car in every bay (its class or the next of its mix, its owner, locked, its key), the next one once it is gone and the bay is clear
seats.tsWhere a class's seats are (vehicle-seats.json, the models' seat anchors written by npm run models:hulls), each seat's door (the model's doorway: on its flank, the bus's two on the kerb side, the ambulance's at its back; doorwayNear for the client's doors), and how a character gets out at the car's speed over the ground (EXIT, exitMode: step out at 8 km/h or less, bail out up to 35, stay in faster or in the air)
boarding.tsGetting in and out at the doors, players and NPCs alike: on the way to the seat's door and getting in at it, facing it (startBoarding, boardingBeat), stepping out (a moment at the door, facing out), bailing out (the car's velocity, a tumble, hurt by the speed), staying in, the dead put out once the car crawls (leaveVehicle, putOutDead)
carjack.tsWhat the interaction key does to one car (vehicleInteraction: get in, get in as a passenger by the nearest door, carjack, unlock with its key, locked or picked without, nothing at a moving car; interaction.ts weighs it against the rest) and carjacking: the driver pulled out at its door and down, the others out of their own doors, the beat facing the door, the wheel
damage.tsHit points of characters, vehicles and cameras, applyDamage and the hit events (a non-lethal hit never takes the last point, and says so); a wreck's crash hurts the people in it (hurtOccupants)
griefing.tsThe griefing controls: who may hurt whom (mayHurt: the game's playerDamage, rivals sparing a party, the safe zones, a ghost; a dart, a knockout and a stun as much as a shot), the safe zones (no carjack in one), the parties (sameParty), the ghost a player is after respawning (setGhost, ghostTick: collision groups that cars and people pass through) and where a player respawns (setRespawn).; what can be hit (not hidden, not seated, not wrecked)
weapons.tsWeapons as items: the weapon held is the selected slot's (heldWeapon; seated, the pistol carried), ammunition spent a shot at a time out of the inventory (ammoLeft, canFire without it false). Targets on the line of fire (aimTargets, cameras too), shots pitched to them, pistol/shotgun/rifle rays, rockets and grenades (a grenade its own ammunition), blasts, the tranquilizer's darts, the fists (a knockout from behind, a stun from the front); each weapon's noise
nails.tsNail strips laid on the roads (the police's at three stars): entities with a pose and a length, no collider (spawnNailStrip, removeNailStrip, laidStrip); a strip thrown from the kerb unrolls across the road and is reeled in the same way (nailSystem, before the cars; reelNailStrip, isReeledIn), a client's twin kept to the snapshot's length (setNailStrip); the vehicle system pops the tyres crossing one at its height
fire.tsCars on fire and blowing up (the server's world alone, the rule vehicleFire): a car brought low catches fire, burns its fuse (fuseTicks) and blows up in a blast as big as it is (blastSize), lighting the cars beside it, the whole chain its igniter's, killing everyone aboard (a two-wheeler's riders thrown off it, boarding.ts' throwOff); water (water.ts' vehicleInWater) puts a fire out, a blown-up wreck's too, and lights none (isBurning, hasExploded, clearFire)
weather.tsThe room's weather in the simulation: sim.weather (a seed, a climate, a script) read at the clock's minutes every tick into sim.sky (1/64 steps, hashed), and weatherGrip, the share of its grip a tyre keeps on a wet road, in mud or on snow (WEATHER_GRIP: side grip, friction circle and brakes; the engine's traction half the loss); a wreck burns out sooner in a downpour (fire.ts).
pedestrians.tsServer-only walking of the characters nobody owns, from the seeded generator: on the level's pavements (@foi/world) each in its role (PEDESTRIAN_ROLES: a civilian strolls, a commuter goes between two places and waits at the kerb before a crossing, a jogger runs a loop, a shopkeeper keeps to its door), off them wandering the open cross; their flee from gunfire (a shopkeeper ducks inside); range dummies that stand at their posts; the dogs' tick (dogs.ts). Who is out is the crowd's (@foi/ai)
dogs.tsDogs, NPCs of their own (the role dog, a dog's body; spawnDog, dogTick run by the pedestrian system): on a walker's lead (the link kept both ways: walkerOf, dogOf) ranging within its length, sniffing at @foi/world's scents, sitting, the walker its pair (walkerPace); a stray on the pavements; bolting from gunfire and hits, jumping aside from cars; dead where it fell for good. leadWire, decodeLead: its state in a snapshot's spare bytes
sitting.tsSitting on the level’s seats (spots of kind seat, one person each: SimWorld.spotTaken): sitDown (out of the physics, the seat’s pose), sitTick (the breath back to three quarters; up at a movement key or the interaction key), leaveSeat, seatNear, setSitting and benchSeatAt (the client’s copy).
snapshot.tssnapshotEntities: the replicated state of every vehicle, character, door, pickup and container, in the protocol's shape (a vehicle's siren; a character's cls carries a pedestrian's role below ROLE_CLS_BASE and its Character.role, a contact, from it up)
step.tsstepSim: character, vehicle and projectile systems → the velocities going into the step recorded (car-hits.ts) → Rapier's pipeline step, once a tick or as many times as a car closing fast on another body asks for (substeps.ts; without World.step's sweep for soft bodies, which the game never makes) → the cars' hits on people → copy back the poses of what can have moved (not a planted light piece, not a proxy)
substeps.tsHow many physics steps a tick takes: one, unless a car closes on another car, a trailer or a person on foot faster than one step's contacts hold them apart (then up to four): how fast the gap between their nearest points shrinks, with what their spins may add; the pairs found by sweeping the bodies sorted along x, a client's far proxies left out
proxy.tsA client's twins it does not predict (setProxy, the net-client's mirror decides): a kinematic body resting where its snapshot put it, solid and found by rays, passed over by the vehicle and character systems and never integrated, a proxy car without soft CCD; the server never makes one
hash.tshashSimState: the fingerprint compared by the determinism test (inventories, pickups, containers, doors, cars' owners, locks and paints, picking, stored cars and spawners included) The city's state too: the room clock, every player's Cash, the shops' stock, the gates' auto-open and clearance, who is indoors.
breakables.tsThe level's light pieces (placements with a breakable mass): planted on bodies of their own, knocked loose by a car about to hit them with the kinetic energy of a mid-size sedan at 60 km/h or more (LOOSEN_ENERGY, a rig's whole mass behind a trailer's blow; the pieces within its reach looked up on a grid of the ground, its hull cast at each alone), planted again on a reset or at a snapshot's word; isPieceLoose says whether a placement's piece lies loose (a lamp knocked down lights nothing)
status.tsA character's status (awake, stunned, knocked out, asleep, down, dead): incapacitate, a dart's delay (dart, quicker from a head shot), wake, statusSystem (darts that take, loud sounds that wake the sleepers, statuses that run out)
cameras.tsThe level's security cameras: one entity each on a fixed body, swept on a fixed plan of the tick (cameraYaw), on, off or destroyed (setCameraOn, destroyCamera), reset with the level
ladders.tsThe level's ladders: taking one at its foot or its top (climb), up and down it with no gravity, off onto its landing or the ground; jumping or a knockdown lets go (climbStep, letGo).
lifts.tsLifts and escalators: a lift's platform, kinematic, between its stops on a fixed timetable by tick (liftHeight); an escalator's steps carrying whoever stands on them (escalatorVelocity); the ground's own motion for the characters on it (movingGround).
water.tsWater and lava (the level's water): the numbers (WATER: wading over the knees, swimming deeper than the chest, a swimmer's speed and float, a car's flooding depth and drag) and the surface over a point (waterAt); the character system wades, swims and burns (swimStep in character.ts).
sinking.tsCars in water and lava, after each physics step (sinkingSystem): slowed by it, the deeper the more; flooded (wrecked, everyone put out to swim) once their middle sinks 0.6 m under the surface; wrecked by lava at once.
testing.tsShared setup of the unit tests: the core test level, an open flat copy of it, the per-file hooks and stepping helpers

The model is explained in the Driving model guide. vehicle.test.ts pins the driving envelope; determinism.integration.test.ts is the determinism gate.

What a step costs grows with what it simulates: listCharacters and listVehicles keep their sorted lists until one is spawned or removed (the AI asks for them many times a tick), a character's test against the cars it might be stuck in passes over every car whose box cannot reach it before working anything out, and the poses of bodies that cannot have moved are not read back from Rapier. See Performance.