292 lines
9.6 KiB
Lua
Raw Normal View History

2025-04-07 01:41:12 +00:00
local config = require 'config.client'
---client uses key fob to toggle the door locks
---@param vehicle number The entity number of the vehicle.
local function toggleLock(vehicle)
if not vehicle then return end
local vehicleConfig = GetVehicleConfig(vehicle)
if vehicleConfig.noLock or vehicleConfig.shared then return end
if GetIsVehicleAccessible(vehicle) then
lib.playAnim(cache.ped, 'anim@mp_player_intmenu@key_fob@', 'fob_click', 3.0, 3.0, -1, 49)
--- if the statebag is out of sync, rely on it as the source of truth and sync the client to the statebag's value
local stateBagValue = Entity(vehicle).state.doorslockstate
if GetVehicleDoorLockStatus(vehicle) ~= stateBagValue then
SetVehicleDoorsLocked(vehicle, stateBagValue)
end
local lockstate = (GetVehicleDoorLockStatus(vehicle) % 2) + 1
TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), lockstate)
exports.qbx_core:Notify(locale(lockstate == 2 and 'notify.vehicle_locked' or 'notify.vehicle_unlocked'))
qbx.playAudio({ audioName = 'Remote_Control_Fob', audioRef = 'PI_Menu_Sounds', source = vehicle })
SetVehicleLights(vehicle, 2)
Wait(250)
SetVehicleLights(vehicle, 1)
Wait(200)
SetVehicleLights(vehicle, 0)
Wait(300)
ClearPedTasks(cache.ped)
else
exports.qbx_core:Notify(locale('notify.no_keys'), 'error')
end
end
---if the player does not have ignition access to the vehicle:
---check whether to give keys if engine is on
---disable the engine and listen for search keys if applicable to the vehicle
local function onEnteringDriverSeat()
local vehicle = cache.vehicle
EngineBind:disable(false)
CreateThread(function()
while cache.seat == -1 do
if IsControlJustPressed(0, 23) then -- vehicle enter/leave input
EngineBind:disable(true)
end
Wait(0)
end
end)
local vehicleConfig = GetVehicleConfig(vehicle)
if vehicleConfig.shared then return end
local isVehicleAccessible = GetIsVehicleAccessible(vehicle)
if isVehicleAccessible then return end
local isVehicleRunning = GetIsVehicleEngineRunning(vehicle)
if config.getKeysWhenEngineIsRunning and isVehicleRunning then
lib.print.debug("giving keys because engine is running")
TriggerServerEvent('qbx_vehiclekeys:server:playerEnteredVehicleWithEngineOn', VehToNet(vehicle))
return
end
lib.print.debug("player does not have access to vehicle ignition. Disabling engine.")
SetVehicleNeedsToBeHotwired(vehicle, false)
CreateThread(function()
while not isVehicleAccessible and cache.seat == -1 do
SetVehicleEngineOn(vehicle, false, true, true)
DisableControlAction(0, 71, true)
Wait(0)
isVehicleAccessible = GetIsVehicleAccessible(vehicle)
end
if lib.progressActive() then
lib.cancelProgress()
end
DisableKeySearch()
end)
if vehicleConfig.findKeysChance ~= 0.0 then
EnableKeySearch()
end
end
lib.onCache('seat', function(newSeat)
if newSeat ~= -1 then return end
Wait(0) -- needed to update cache.seat
onEnteringDriverSeat()
end)
lib.onCache('vehicle', function(vehicle)
if not vehicle then return end
SetVehicleKeepEngineOnWhenAbandoned(vehicle, config.keepEngineOnWhenAbandoned)
end)
-----------------------
------ Key Binds ------
-----------------------
local togglelocksBind
togglelocksBind = lib.addKeybind({
name = 'togglelocks',
description = locale('info.toggle_locks'),
defaultKey = 'L',
onPressed = function()
togglelocksBind:disable(true)
local vehicle = lib.getClosestVehicle(GetEntityCoords(cache.ped), config.vehicleMaximumLockingDistance, true)
toggleLock(vehicle)
Wait(1000)
togglelocksBind:disable(false)
end
})
local function toggleEngine(vehicle)
if not GetIsVehicleAccessible(vehicle) then return end
local engineOn = GetIsVehicleEngineRunning(vehicle)
local vehicleModel = GetEntityModel(vehicle)
local vehicleClass = GetVehicleClass(vehicle)
local anim = config.anims.toggleEngine.model[vehicleModel]
or config.anims.toggleEngine.class[vehicleClass]
or config.anims.toggleEngine.default
if next(anim) then
lib.playAnim(cache.ped, anim.dict, anim.clip, 8.0, 8.0,-1, 48, 0)
Wait(0)
CreateThread(function()
while IsEntityPlayingAnim(cache.ped, anim.dict, anim.clip, 3) do
if IsControlJustPressed(0, 23) then -- enter/exit vehicle input
ClearPedTasks(cache.ped)
return
end
Wait(0)
end
end)
--- aethestic wait so that the engine toggles when the player appears to touch the button/key
Wait(anim.delay or 0)
end
if cache.vehicle then
SetVehicleEngineOn(vehicle, not engineOn, false, true)
end
end
EngineBind = lib.addKeybind({
name = 'toggleengine',
description = locale('info.engine'),
defaultKey = config.keySearchBind,
onPressed = function()
if cache.seat == -1 then
EngineBind:disable(true)
toggleEngine(cache.vehicle)
Wait(1000)
EngineBind:disable(false)
end
end
})
-----------------------
---- Client Events ----
-----------------------
local isTakingKeys = false
RegisterNetEvent('QBCore:Client:VehicleInfo', function(data)
if not LocalPlayer.state.isLoggedIn or data.event ~= 'Entering' then return end
local vehicleConfig = GetVehicleConfig(data.vehicle)
if vehicleConfig.noLock or isTakingKeys then return end
isTakingKeys = true
local driver = GetPedInVehicleSeat(data.vehicle, -1)
if driver ~= 0 and IsEntityDead(driver) and not (vehicleConfig.carjackingImmune or IsPedAPlayer(driver)) then
TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', data.netId, 1)
if lib.progressCircle({
duration = 2500,
label = locale('progress.takekeys'),
position = 'bottom',
useWhileDead = false,
canCancel = true,
disable = {
car = true,
},
}) then
TriggerServerEvent('qbx_vehiclekeys:server:tookKeys', VehToNet(data.vehicle))
end
end
isTakingKeys = false
end)
RegisterNetEvent('lockpicks:UseLockpick', function(isAdvanced)
local vehicle = cache.vehicle
if vehicle then
if GetKeySearchEnabled() then
DisableKeySearch()
Hotwire(vehicle, isAdvanced)
EnableKeySearch()
else
Hotwire(vehicle, isAdvanced)
end
else
LockpickDoor(isAdvanced)
end
end)
RegisterNetEvent('qbx_vehiclekeys:client:OnLostKeys', function()
if cache.seat == -1 then
onEnteringDriverSeat()
end
end)
for _, info in pairs(config.sharedKeys) do
if info.enableAutolock then
lib.onCache('vehicle', function (vehicle)
local leftVehicle = cache.vehicle
if not vehicle and leftVehicle then
local isShared = AreKeysJobShared(leftVehicle)
local isAutolockEnabled = config.sharedKeys[QBX.PlayerData.job.name]?.enableAutolock
if isShared and isAutolockEnabled then
TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(leftVehicle), 2)
end
end
end)
break
end
end
qbx.entityStateHandler('doorslockstate', function(entity, _, value)
if entity == 0 then return end
SetVehicleDoorsLocked(entity, value)
end)
AddEventHandler('onResourceStart', function(resourceName)
if (GetCurrentResourceName() ~= resourceName) then return end
if cache.seat == -1 then
onEnteringDriverSeat()
end
end)
---Checks the vehicle is always locked at spawn.
---@param vehicle number The entity number of the vehicle.
---@param isDriven boolean
---@return boolean `true` if the vehicle is locked, `false` otherwise.
local function getIsVehicleInitiallyLocked(vehicle, isDriven)
local vehicleConfig = GetVehicleConfig(vehicle)
local vehicleLockedChance = isDriven
and vehicleConfig.spawnLockedIfDriven
or vehicleConfig.spawnLockedIfParked
if type(vehicleLockedChance) == 'number' then
return math.random() < vehicleLockedChance
else
return vehicleLockedChance == true
end
end
local function onVehicleAttemptToEnter(vehicle)
if Entity(vehicle).state.doorslockstate then return end
local ped = GetPedInVehicleSeat(vehicle, -1)
if IsPedAPlayer(ped) then return end
local isLocked = not GetVehicleConfig(vehicle).noLock and getIsVehicleInitiallyLocked(vehicle, ped and ped ~= 0)
local lockState = isLocked and 2 or 1
SetVehicleDoorsLocked(vehicle, lockState)
TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), lockState)
end
local isLoggedIn = false
local function playerEnterVehLoop()
CreateThread(function()
while isLoggedIn do
local vehicle = GetVehiclePedIsTryingToEnter(cache.ped)
if vehicle ~= 0 then
onVehicleAttemptToEnter(vehicle)
end
Wait(100)
end
end)
end
CreateThread(function()
if LocalPlayer.state.isLoggedIn then
playerEnterVehLoop()
end
end)
AddStateBagChangeHandler('isLoggedIn', ('player:%s'):format(cache.serverId), function(_, _, value)
isLoggedIn = value
if not value then return end
playerEnterVehLoop()
end)