fix(client): re-arm chassis when the drive loop is bound to a stale car
CI / quality (push) Failing after 47s
CI / quality (push) Failing after 47s
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.
This commit is contained in:
@@ -29,6 +29,11 @@ local ChassisController = {}
|
||||
|
||||
local heartbeatConn: RBXScriptConnection? = nil
|
||||
local seatedConn: RBXScriptConnection? = nil
|
||||
-- The seat the live heartbeatConn is bound to. On respawn the old car is
|
||||
-- destroyed and a new one spawned; the connection stays alive but drives the
|
||||
-- DESTROYED car's motors. Tracking the seat lets the watchdog notice that the
|
||||
-- loop is stale and re-arm against the new car.
|
||||
local drivingSeat: VehicleSeat? = nil
|
||||
|
||||
local function findCarModel(seat: VehicleSeat): Model?
|
||||
local model = seat:FindFirstAncestorOfClass("Model")
|
||||
@@ -70,6 +75,7 @@ local function startDriving(seat: VehicleSeat)
|
||||
return
|
||||
end
|
||||
|
||||
drivingSeat = seat
|
||||
heartbeatConn = RunService.Heartbeat:Connect(function()
|
||||
local throttle = seat.ThrottleFloat
|
||||
local steer = seat.SteerFloat
|
||||
@@ -106,6 +112,7 @@ local function stopDriving()
|
||||
heartbeatConn:Disconnect()
|
||||
heartbeatConn = nil
|
||||
end
|
||||
drivingSeat = nil
|
||||
end
|
||||
|
||||
function ChassisController.init()
|
||||
@@ -141,7 +148,15 @@ function ChassisController.init()
|
||||
local seated = seatPart
|
||||
and seatPart:IsA("VehicleSeat")
|
||||
and seatPart.Name == Chassis.SEAT_NAME
|
||||
if seated and not heartbeatConn then
|
||||
-- A live connection bound to a different seat (or to a car that
|
||||
-- has since been destroyed) is STALE: it keeps driving the old
|
||||
-- car's motors, so heartbeatConn stays non-nil and the new car
|
||||
-- never gets armed. Re-arm whenever the bound seat isn't the
|
||||
-- one we're actually sitting in, or its car left the world.
|
||||
local stale = heartbeatConn ~= nil
|
||||
and (drivingSeat ~= seatPart or not seatPart:IsDescendantOf(workspace))
|
||||
if seated and (not heartbeatConn or stale) then
|
||||
stopDriving()
|
||||
startDriving(seatPart :: VehicleSeat)
|
||||
elseif not seated and heartbeatConn then
|
||||
stopDriving()
|
||||
|
||||
Reference in New Issue
Block a user