The only way right now is it to interrupt the entering task, like you do when you hold movement keys as a player during jacking. If you set the "backwards" control state after jacking starts, you can do this.
The current implementation of jacking is very lacking in this aspect. If jacking is aborted for one of many reasons, the server doesn't know how far the jacker is, ie. if he physically pulled out the jacked ped yet, so it relies on the jacker to abort properly. But for peds, if the syncer changes the jacking isn't aborted properly and the jacker will be warped into the car. This is something I plan on improving, and also add a client and server event for when jacking physically starts, as it could be useful in many scripts.
-- onClientPedJacked: when a ped/player has been actually jacked from a vehicle by the local player or syncing ped.
-- Source: ped that got jacked
-- 1st parameter: ped that jacked the other ped
addEvent("onClientPedJacked", false)
local ENTER_RESPONSE_TIMEOUT = 600 -- Time for server to ack our entry request and we start entering otherwise we consider it declined
-- Sub tasks to indicate we are actually jacking now
local PED_JACK_TASKS = {
["TASK_SIMPLE_CAR_SHUFFLE"] = true, -- Jacking through passenger seat
["TASK_SIMPLE_CAR_QUICK_DRAG_PED_OUT"] = true,
["TASK_SIMPLE_CAR_SLOW_DRAG_PED_OUT"] = true,
["TASK_SIMPLE_CAR_GET_IN"] = true, -- Jumping on a bike from the front
}
local timerData = {}
local getPedTask = getPedTask
local isElement = isElement
local getVehicleController = getVehicleController
local function stopEnterVehicleTimer()
timerData[sourceTimer] = nil
killTimer(sourceTimer)
end
local function onEnterVehicleFrame()
if not isElement(timerData[sourceTimer].jackingPed) then
return stopEnterVehicleTimer()
end
local pedTaskComplex, pedTaskSimple = getPedTask(timerData[sourceTimer].jackingPed, "primary", 3)
if not pedTaskComplex then
pedTaskComplex = ""
end
if pedTaskComplex:sub(1, 22) ~= "TASK_COMPLEX_ENTER_CAR" then
if timerData[sourceTimer].enterTaskActive then
return stopEnterVehicleTimer()
else
if getTickCount() - timerData[sourceTimer].enterTick > ENTER_RESPONSE_TIMEOUT then
return stopEnterVehicleTimer()
end
end
return
end
timerData[sourceTimer].enterTaskActive = true
if PED_JACK_TASKS[pedTaskSimple] then
triggerEvent("onClientPedJacked", timerData[sourceTimer].jackedPed, timerData[sourceTimer].jackingPed)
return stopEnterVehicleTimer()
end
if not isElement(timerData[sourceTimer].veh) then
return stopEnterVehicleTimer()
end
if not isElement(timerData[sourceTimer].jackedPed) then
return stopEnterVehicleTimer()
end
if getVehicleController(timerData[sourceTimer].veh) ~= timerData[sourceTimer].jackedPed then
return stopEnterVehicleTimer()
end
end
local function onClientVehicleStartEnter(jackingPed, seat, door)
if jackingPed ~= localPlayer and not isElementSyncer(jackingPed) then return end
if seat ~= 0 then return end
local jackedPed = getVehicleController(source)
if not jackedPed then return end
for k,v in ipairs(timerData) do
if v.jackingPed == ped then return end
end
local timer = setTimer(onEnterVehicleFrame, 0, 0)
timerData[timer] = {
enterTick = getTickCount(),
jackingPed = jackingPed,
jackedPed = jackedPed,
veh = source,
enterTaskActive = false,
}
end
addEventHandler("onClientVehicleStartEnter", root, onClientVehicleStartEnter)
You can use above snippet, "onClientPedJacked" triggers when ped is physically getting jacked by local player or syncing ped. Set control state "backwards" when this event triggers, and release it again when the ped is no longer entering (see TASK_COMPLEX_ENTER_CAR in the snippet above). Let me know if you need an example for that.