Actions = {} Actions._index = Actions Actions.inVehicle = false Actions.enteringVehicle = false Actions.inPauseMenu = false Actions.currentWeapon = false function Actions:GetSeatPedIsIn() for i = -1, 16 do if GetPedInVehicleSeat(self.vehicle, i) == ESX.PlayerData.ped then return i end end return -1 end function Actions:GetVehicleData() if not DoesEntityExist(self.vehicle) then return end local vehicleModel = GetEntityModel(self.vehicle) local displayName = GetDisplayNameFromVehicleModel(vehicleModel) local netId = NetworkGetEntityIsNetworked(self.vehicle) and VehToNet(self.vehicle) or self.vehicle local plate = GetVehicleNumberPlateText(self.vehicle) return displayName, netId, plate end function Actions:SetVehicleStatus() ESX.SetPlayerData("vehicle", self.vehicle) ESX.SetPlayerData("seat", self.seat) end function Actions:TrackPedCoordsOnce() CreateThread(function() while not ESX.IsPlayerLoaded() do Wait(250) end ESX.PlayerData.coords = nil setmetatable(ESX.PlayerData, { __index = function(_, key) if key ~= "coords" then return end local coords = GetEntityCoords(ESX.PlayerData.ped) return coords end }) end) end function Actions:TrackPed() local playerPed = ESX.PlayerData.ped local newPed = PlayerPedId() if playerPed ~= newPed then ESX.SetPlayerData("ped", newPed) TriggerEvent("esx:playerPedChanged", newPed) if Config.EnableDebug then print("[DEBUG] Player ped changed:", newPed) end end end function Actions:TrackPauseMenu() local isActive = IsPauseMenuActive() if isActive ~= self.inPauseMenu then self.inPauseMenu = isActive TriggerEvent("esx:pauseMenuActive", isActive) if Config.EnableDebug then print("[DEBUG] Pause menu active:", isActive) end end end function Actions:EnterVehicle() self.seat = GetSeatPedIsTryingToEnter(ESX.PlayerData.ped) local _, netId, plate = self:GetVehicleData() self.enteringVehicle = true TriggerEvent("esx:enteringVehicle", self.vehicle, plate, self.seat, netId) TriggerServerEvent("esx:enteringVehicle", plate, self.seat, netId) self:SetVehicleStatus() if Config.EnableDebug then print("[DEBUG] Entering vehicle:", self.vehicle, plate, self.seat, netId) end end function Actions:ResetVehicleData() self.enteringVehicle = false self.vehicle = false self.seat = false self.inVehicle = false self:SetVehicleStatus() end function Actions:EnterAborted() self:ResetVehicleData() TriggerEvent("esx:enteringVehicleAborted") TriggerServerEvent("esx:enteringVehicleAborted") if Config.EnableDebug then print("[DEBUG] Entering vehicle aborted") end end function Actions:WarpEnter() self.enteringVehicle = false self.inVehicle = true self.seat = self:GetSeatPedIsIn() local displayName, netId, plate = self:GetVehicleData() self:SetVehicleStatus() TriggerEvent("esx:enteredVehicle", self.vehicle, plate, self.seat, displayName, netId) TriggerServerEvent("esx:enteredVehicle", plate, self.seat, displayName, netId) if Config.EnableDebug then print("[DEBUG] Entered vehicle:", self.vehicle, plate, self.seat, displayName, netId) end end function Actions:ExitVehicle() local currentVehicle = GetVehiclePedIsIn(ESX.PlayerData.ped, false) if currentVehicle ~= self.vehicle or ESX.PlayerData.dead then local displayName, netId, plate = self:GetVehicleData() TriggerEvent("esx:exitedVehicle", self.vehicle, plate, self.seat, displayName, netId) TriggerServerEvent("esx:exitedVehicle", plate, self.seat, displayName, netId) if Config.EnableDebug then print("[DEBUG] Exited vehicle:", self.vehicle, plate, self.seat, displayName, netId) end self:ResetVehicleData() end end function Actions:TrackVehicle() if not self.inVehicle and not ESX.PlayerData.dead then local tempVehicle = GetVehiclePedIsTryingToEnter(ESX.PlayerData.ped) if DoesEntityExist(tempVehicle) and not self.enteringVehicle then self.vehicle = tempVehicle self:EnterVehicle() elseif not DoesEntityExist(tempVehicle) and not IsPedInAnyVehicle(ESX.PlayerData.ped, true) and self.enteringVehicle then self:EnterAborted() elseif IsPedInAnyVehicle(ESX.PlayerData.ped, false) then self.vehicle = GetVehiclePedIsIn(ESX.PlayerData.ped, false) self:WarpEnter() end elseif self.inVehicle then self:ExitVehicle() self:TrackSeat() end end function Actions:TrackSeat() if not self.inVehicle then return end local newSeat = self:GetSeatPedIsIn() if newSeat ~= self.seat then self.seat = newSeat ESX.SetPlayerData("seat", self.seat) TriggerEvent("esx:vehicleSeatChanged", self.seat) if Config.EnableDebug then print("[DEBUG] Vehicle seat changed:", self.seat) end end end function Actions:TrackWeapon() ---@type number|false local newWeapon = GetSelectedPedWeapon(ESX.PlayerData.ped) newWeapon = newWeapon ~= `WEAPON_UNARMED` and newWeapon or false if newWeapon ~= self.currentWeapon then self.currentWeapon = newWeapon ESX.SetPlayerData("weapon", self.currentWeapon) TriggerEvent("esx:weaponChanged", self.currentWeapon) if Config.EnableDebug then print("[DEBUG] Weapon changed:", self.currentWeapon) end end end function Actions:SlowLoop() CreateThread(function() while ESX.PlayerLoaded do self:TrackPauseMenu() self:TrackVehicle() self:TrackWeapon() Wait(500) end end) end function Actions:PedLoop() CreateThread(function() while ESX.PlayerLoaded do self:TrackPed() Wait(0) end end) end function Actions:Init() self:SlowLoop() self:PedLoop() self:TrackPedCoordsOnce() end Actions:Init()