Respawning left the car undrivable. CarManager.spawn() destroys the old car
and builds a new one, but the client's Heartbeat connection survived and kept
driving the DESTROYED car's motors. Because heartbeatConn stayed non-nil, the
cold-start watchdog concluded the chassis was already armed and never armed
the new car - torque stayed at the idle brake value and the car never moved.
Track the seat the live loop is bound to (drivingSeat) and treat the loop as
stale when that seat isn't the one we're sitting in, or its car has left the
workspace. On stale, stop and re-arm against the new car.
Verified: after 4 respawn cycles the car accelerates 49 -> 163 studs/s,
travels 273 studs, stays upright at road level.
The drive loop was armed purely edge-triggered from
humanoid:GetPropertyChangedSignal("SeatPart") plus a one-shot catch-up
applySeat() at init. On cold boot the server seats the player AFTER that
catch-up runs, so the edge is lost, startDriving() never connects, and all
four wheel motors stay at MotorMaxTorque = 0 - the car is completely
undrivable until the player manually gets out and back in.
Replace the one-shot with a 0.5s level-triggered watchdog: if seated in a
DriveSeat with no live heartbeat connection, arm it; if not seated with a
live connection, stop it. Immune to any ordering of bootstrap vs seating.
Verified on cold boot (no manual reseat): all 4 motors uniform, poisoned
torque values restored within 0.6s, car accelerates to MaxSpeed 163 studs/s,
holds it upright, and engine-brakes 163 -> 0.
- New shared Chassis.luau: geometry constants + per-car tuning from stats
- CarManager.buildCarModel rebuilt: prismatic+spring suspension per corner,
servo-hinge steering on front knuckles, motor-hinge driven wheels,
hidden dense ballast for anti-roll; VehicleSeat kept as input device only
- New client ChassisController: drives motors/servos from seat
ThrottleFloat/SteerFloat per Heartbeat; speed-sensitive steering lock;
engine braking on throttle release
- Driver gets network ownership of every unanchored part (constraint
assemblies are separate; missing one causes stuttery physics)
- Docs: MESH_SWAP.md rewritten for shell-on-chassis workflow; ROADMAP updated