2026-04-14 17:41:39 +02:00

325 lines
10 KiB
Lua

local stateTimerConstants = {4.0, 2.0}
CreateThread(function()
while true do
Wait(100)
local ped = PlayerPedId()
local vehicle = GetVehiclePedIsIn(ped, false)
if not DoesEntityExist(vehicle) then
Wait(1000)
goto continue
end
local vehicleModel = GetEntityModel(vehicle)
if not Config.FlatBedModels[vehicleModel] then
Wait(1000)
goto continue
end
local bedNet = Entity(vehicle).state.bedProp
if bedNet then
Wait(1000)
goto continue
end
TriggerServerEvent('gs_flatbed:CreateBedEntity', NetworkGetNetworkIdFromEntity(vehicle))
Wait(1000)
::continue::
end
end)
RegisterNetEvent('gs_flatbed:AttachBedToVehicle')
AddEventHandler('gs_flatbed:AttachBedToVehicle', function(vehicleNetId, bedNetId)
local startTime = GetGameTimer()
while (not NetworkDoesNetworkIdExist(bedNetId) and GetGameTimer()-startTime < 1000) do
Wait(10)
end
-- If something went wrong and the entity is not networked, retry.
if (not NetworkDoesNetworkIdExist(bedNetId)) then
TriggerServerEvent('gs_flatbed:DeleteBedEntity', vehicleNetId, bedNetId)
return
end
local flatbedVehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
local bedEntity = NetworkGetEntityFromNetworkId(bedNetId)
while (not DoesEntityExist(bedEntity)) do
Wait(10)
end
local stateCoords = GetFlatbedStatePositions(flatbedVehicle)
AttachEntityToEntity(
bedEntity,
flatbedVehicle,
GetEntityBoneIndexByName(flatbedVehicle, 'chassis'),
stateCoords[0].pos[1],
stateCoords[0].pos[2],
stateCoords[0].pos[3],
stateCoords[0].rot[1],
stateCoords[0].rot[2],
stateCoords[0].rot[3],
0,
0,
1,
0,
0,
1
)
-- If something went wrong and the entity is not attached to the vehicle, retry.
if (not IsEntityAttachedToEntity(bedEntity, flatbedVehicle)) then
TriggerServerEvent('gs_flatbed:DeleteBedEntity', vehicleNetId, bedNetId)
end
end)
RegisterNetEvent('gs_flatbed:LowerFlatbedClient')
AddEventHandler('gs_flatbed:LowerFlatbedClient', function(vehicleNetId)
local flatbedVehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
LowerFlatbed(flatbedVehicle)
end)
RegisterNetEvent('gs_flatbed:RaiseFlatbedClient')
AddEventHandler('gs_flatbed:RaiseFlatbedClient', function(vehicleNetId)
local flatbedVehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
RaiseFlatbed(flatbedVehicle)
end)
RegisterNetEvent('gs_flatbed:AttachVehicleClient')
AddEventHandler('gs_flatbed:AttachVehicleClient', function(vehicleNetId, vehicleToAttachNetId)
local flatbedVehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
local vehicleToAttach = NetworkGetEntityFromNetworkId(vehicleToAttachNetId)
AttachVehicle(flatbedVehicle, vehicleToAttach)
end)
RegisterNetEvent('gs_flatbed:DetachVehicleClient')
AddEventHandler('gs_flatbed:DetachVehicleClient', function(vehicleToAttachNetId)
local vehicleToAttach = NetworkGetEntityFromNetworkId(vehicleToAttachNetId)
DetachVehicle(vehicleToAttach)
end)
function LowerFlatbed(flatbedVehicle)
-- Return if the flatbed does not have a bed or it is moving
if not DoesFlatbedHaveBedAndNotMoving(flatbedVehicle) then return end
-- Get the positions of the bed states.
local stateCoords = GetFlatbedStatePositions(flatbedVehicle)
-- Flatbed is now moving
Entity(flatbedVehicle).state:set('bedMoving', true, true)
local bedNet = Entity(flatbedVehicle).state.bedProp
local bedEntity = NetworkGetEntityFromNetworkId(bedNet)
-- Start moving
PlaySoundEffect(flatbedVehicle)
local LERP_VALUE = 0.0
local state = 0
local moveTick = CreateThread(function()
while true do
-- If the final state is reached, stop
if state == 2 then
Entity(flatbedVehicle).state:set('bedLowered', true, true)
Entity(flatbedVehicle).state:set('bedMoving', false, true)
ReleaseSoundEffect()
return
end
-- Calculate the new offset coords
local offsetPos = {}
local offsetRot = {}
for i = 1, 3 do
offsetPos[i] = lerp(stateCoords[state].pos[i], stateCoords[state + 1].pos[i], LERP_VALUE)
offsetRot[i] = lerp(stateCoords[state].rot[i], stateCoords[state + 1].rot[i], LERP_VALUE)
end
AttachEntityToEntity(
bedEntity,
flatbedVehicle,
GetEntityBoneIndexByName(flatbedVehicle, 'chassis'),
offsetPos[1],
offsetPos[2],
offsetPos[3],
offsetRot[1],
offsetRot[2],
offsetRot[3],
0,
0,
1,
0,
0,
1
)
-- Calculate the new leap value
LERP_VALUE = LERP_VALUE + (1.0 * GetFrameTime()) / stateTimerConstants[state + 1]
if LERP_VALUE >= 1.0 then
LERP_VALUE = 0.0
state = state + 1
end
Wait(0)
end
end)
end
function RaiseFlatbed(flatbedVehicle)
-- Return if the flatbed does not have a bed or it is moving
if not DoesFlatbedHaveBedAndNotMoving(flatbedVehicle) then return end
-- Get the positions of the bed states.
local stateCoords = GetFlatbedStatePositions(flatbedVehicle)
-- Flatbed is now moving
Entity(flatbedVehicle).state:set('bedMoving', true, true)
local bedNet = Entity(flatbedVehicle).state.bedProp
local bedEntity = NetworkGetEntityFromNetworkId(bedNet)
-- Start moving
PlaySoundEffect(flatbedVehicle)
local LERP_VALUE = 0.0
local state = 2
local moveTick = CreateThread(function()
while true do
-- If the final state is reached, stop
if state == 0 then
Entity(flatbedVehicle).state:set('bedLowered', false, true)
Entity(flatbedVehicle).state:set('bedMoving', false, true)
ReleaseSoundEffect()
return
end
-- Reset the offset coords
local offsetPos = {}
local offsetRot = {}
-- Calculate the new offset coords
for i = 1, 3 do
offsetPos[i] = lerp(stateCoords[state].pos[i], stateCoords[state - 1].pos[i], LERP_VALUE)
offsetRot[i] = lerp(stateCoords[state].rot[i], stateCoords[state - 1].rot[i], LERP_VALUE)
end
AttachEntityToEntity(
bedEntity,
flatbedVehicle,
GetEntityBoneIndexByName(flatbedVehicle, 'chassis'),
offsetPos[1],
offsetPos[2],
offsetPos[3],
offsetRot[1],
offsetRot[2],
offsetRot[3],
0,
0,
1,
0,
0,
1
)
-- Calculate the new leap value
LERP_VALUE = LERP_VALUE + (1.0 * GetFrameTime()) / stateTimerConstants[state]
if LERP_VALUE >= 1.0 then
LERP_VALUE = 0.0
state = state - 1
end
Wait(0)
end
end)
end
function lerp(start, finish, amount)
return (1 - amount) * start + amount * finish
end
function AttachVehicle(flatbedVehicle, vehicleToAttach)
-- Check if vehicleToAttach exists
if not DoesEntityExist(vehicleToAttach) then return end
-- Return if the flatbed does not have a bed or it is moving
if not DoesFlatbedHaveBedAndNotMoving(flatbedVehicle) then return end
-- Get the bed from the flatbed
local bedNet = Entity(flatbedVehicle).state.bedProp
local bedToAttachTo = NetworkGetEntityFromNetworkId(bedNet)
-- Determine the rotations
local vehicleRotation = GetEntityRotation(vehicleToAttach, 2)
local bedRotation = GetEntityRotation(bedToAttachTo, 2)
-- Determine the rotation offset
local rotationOffsetZ = vehicleRotation.z - bedRotation.z
-- Determine the positions
local vehicleCoords = GetEntityCoords(vehicleToAttach)
local bedOffsetCoords = GetOffsetFromEntityGivenWorldCoords(bedToAttachTo, vehicleCoords.x, vehicleCoords.y, vehicleCoords.z)
-- Attach the vehicle
AttachEntityToEntity(
vehicleToAttach,
bedToAttachTo,
0,
bedOffsetCoords.x,
bedOffsetCoords.y,
bedOffsetCoords.z + 0.025,
0.0, -- xRot
0.0, -- yRot
rotationOffsetZ, -- zRot
0, -- p9
0, -- useSoftPinning
false, -- collision
false, -- isPed
2, -- rotationOrder
true -- syncRot
)
end
function DetachVehicle(vehicleToDetach)
-- Check if vehicleToDetach exists
if not DoesEntityExist(vehicleToDetach) then return end
-- Update the flatbed and detach entity
DetachEntity(vehicleToDetach, false, true)
SetVehicleOnGroundProperly(vehicleToDetach)
end
function DoesFlatbedHaveBedAndNotMoving(vehicle)
local hasBed = Entity(vehicle).state.bedProp ~= nil
local isMoving = Entity(vehicle).state.bedMoving
return hasBed and not isMoving
end
local soundId = nil
function PlaySoundEffect(entity)
if soundId ~= nil then
StopSound(soundId)
ReleaseSoundId(soundId)
end
soundId = GetSoundId()
local audioName = 'OPENING'
local audioRef = 'DOOR_GARAGE'
PlaySoundFromEntity(soundId, audioName, entity, audioRef, false, false);
end
function ReleaseSoundEffect()
if soundId == nil then
return
end
StopSound(soundId)
ReleaseSoundId(soundId)
soundId = nil
end
function GetFlatbedStatePositions(entity)
if not DoesEntityExist(entity) then return end
local vehicleModel = GetEntityModel(entity)
if (not Config.FlatBedModels[vehicleModel]) then return end
local stateCoords = Config.FlatBedModels[vehicleModel]
return stateCoords
end