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

1368 lines
46 KiB
Lua

---@return boolean
---@diagnostic disable-next-line: duplicate-set-field
function ESX.IsPlayerLoaded()
return ESX.PlayerLoaded
end
---@return table
function ESX.GetPlayerData()
return ESX.PlayerData
end
---@param name string
---@param func function
---@return nil
function ESX.SecureNetEvent(name, func)
local invoker = GetInvokingResource()
local invokingResource = invoker and invoker ~= 'unknown' and invoker or 'es_extended'
if not invokingResource then
return
end
if not Core.Events[invokingResource] then
Core.Events[invokingResource] = {}
end
local event = RegisterNetEvent(name, function(...)
if source == '' then
return
end
local success, result = pcall(func, ...)
if not success then
error(("%s"):format(result))
end
end)
local eventIndex = #Core.Events[invokingResource] + 1
Core.Events[invokingResource][eventIndex] = event
end
local addonResourcesState = {
['esx_progressbar'] = GetResourceState('esx_progressbar') ~= 'missing',
['esx_notify'] = GetResourceState('esx_notify') ~= 'missing',
['esx_textui'] = GetResourceState('esx_textui') ~= 'missing',
['esx_context'] = GetResourceState('esx_context') ~= 'missing',
}
local function IsResourceFound(resource)
return addonResourcesState[resource] or error(('Resource [^5%s^1] is Missing!'):format(resource))
end
function ESX.DisableSpawnManager()
if GetResourceState("spawnmanager") == "started" then
exports.spawnmanager:setAutoSpawn(false)
end
end
---@param items string | table The item(s) to search for
---@param count? boolean Whether to return the count of the item as well
---@return table | number
function ESX.SearchInventory(items, count)
local item
if type(items) == 'string' then
item, items = items, {items}
end
local data = {}
for i = 1, #ESX.PlayerData.inventory do
local e = ESX.PlayerData.inventory[i]
for ii = 1, #items do
if e.name == items[ii] then
data[table.remove(items, ii)] = count and e.count or e
break
end
end
if #items == 0 then
break
end
end
return not item and data or data[item]
end
---@param key string Table key to set
---@param val any Value to set
---@return nil
function ESX.SetPlayerData(key, val)
local current = ESX.PlayerData[key]
ESX.PlayerData[key] = val
if key ~= "loadout" then
if type(val) == "table" or val ~= current then
TriggerEvent("esx:setPlayerData", key, val, current)
end
end
end
---@param freeze boolean Whether to freeze the player
---@return nil
function Core.FreezePlayer(freeze)
local ped = PlayerPedId()
SetPlayerControl(ESX.playerId, not freeze, 0)
if freeze then
SetEntityCollision(ped, false, false)
FreezeEntityPosition(ped, true)
else
SetEntityCollision(ped, true, true)
FreezeEntityPosition(ped, false)
end
end
---@param skin table Skin data to set
---@param coords table Coords to spawn the player at
---@param cb function Callback function
---@return nil
function ESX.SpawnPlayer(skin, coords, cb)
local p = promise.new()
TriggerEvent("skinchanger:loadSkin", skin, function()
p:resolve()
end)
Citizen.Await(p)
RequestCollisionAtCoord(coords.x, coords.y, coords.z)
local playerPed = PlayerPedId()
local timer = GetGameTimer()
Core.FreezePlayer(true)
SetEntityCoordsNoOffset(playerPed, coords.x, coords.y, coords.z, false, false, true)
SetEntityHeading(playerPed, coords.heading)
RequestCollisionAtCoord(coords.x, coords.y, coords.z)
while not HasCollisionLoadedAroundEntity(playerPed) and (GetGameTimer() - timer) < 5000 do
Wait(0)
end
NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, coords.heading, 0, true)
TriggerEvent('playerSpawned', coords)
cb()
end
---@param message string
---@param length? number Timeout in milliseconds
---@param options? ProgressBarOptions
---@return boolean Success Whether the progress bar was successfully created or not
function ESX.Progressbar(message, length, options)
return IsResourceFound('esx_progressbar') and exports['esx_progressbar']:Progressbar(message, length, options)
end
function ESX.CancelProgressbar()
return IsResourceFound('esx_progressbar') and exports['esx_progressbar']:CancelProgressbar()
end
---@param message string The message to show
---@param notifyType? string The type of notification to show
---@param length? number The length of the notification
---@param title? string The title of the notification
---@param position? string The position of the notification
---@return nil
function ESX.ShowNotification(message, notifyType, length, title, position)
return IsResourceFound('esx_notify') and exports['esx_notify']:Notify(notifyType or "info", length or 5000, message, title, position)
end
function ESX.TextUI(...)
return IsResourceFound('esx_textui') and exports['esx_textui']:TextUI(...)
end
---@return nil
function ESX.HideUI()
return IsResourceFound('esx_textui') and exports['esx_textui']:HideUI()
end
---@param sender string
---@param subject string
---@param msg string
---@param textureDict string
---@param iconType integer
---@param flash boolean
---@param saveToBrief? boolean
---@param hudColorIndex? integer
---@return nil
function ESX.ShowAdvancedNotification(sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex)
AddTextEntry("esxAdvancedNotification", msg)
BeginTextCommandThefeedPost("esxAdvancedNotification")
if hudColorIndex then
ThefeedSetNextPostBackgroundColor(hudColorIndex)
end
EndTextCommandThefeedPostMessagetext(textureDict, textureDict, false, iconType, sender, subject)
EndTextCommandThefeedPostTicker(flash, saveToBrief == nil or saveToBrief)
end
---@param msg string The message to show
---@param thisFrame? boolean Whether to show the message this frame
---@param beep? boolean Whether to beep
---@param duration? number The duration of the message
---@return nil
function ESX.ShowHelpNotification(msg, thisFrame, beep, duration)
AddTextEntry("esxHelpNotification", msg)
if thisFrame then
DisplayHelpTextThisFrame("esxHelpNotification", false)
else
BeginTextCommandDisplayHelp("esxHelpNotification")
EndTextCommandDisplayHelp(0, false, beep == nil or beep, duration or -1)
end
end
---@param msg string The message to show
---@param coords table The coords to show the message at
---@return nil
function ESX.ShowFloatingHelpNotification(msg, coords)
AddTextEntry("esxFloatingHelpNotification", msg)
SetFloatingHelpTextWorldPosition(1, coords.x, coords.y, coords.z)
SetFloatingHelpTextStyle(1, 1, 2, -1, 3, 0)
BeginTextCommandDisplayHelp("esxFloatingHelpNotification")
EndTextCommandDisplayHelp(2, false, false, -1)
end
---@param msg string The message to show
---@param time number The duration of the message
---@return nil
function ESX.DrawMissionText(msg, time)
ClearPrints()
BeginTextCommandPrint('STRING')
AddTextComponentSubstringPlayerName(msg)
EndTextCommandPrint(time, true)
end
---@param str string The string to hash
---@return string The hashed string
function ESX.HashString(str)
return ('~INPUT_%s~'):format(('%x'):format(joaat(str) & 0x7fffffff + 2 ^ 31):upper())
end
function ESX.OpenContext(...)
return IsResourceFound('esx_context') and exports['esx_context']:Open(...)
end
function ESX.PreviewContext(...)
return IsResourceFound('esx_context') and exports['esx_context']:Preview(...)
end
function ESX.CloseContext(...)
return IsResourceFound('esx_context') and exports['esx_context']:Close(...)
end
function ESX.RefreshContext(...)
return IsResourceFound('esx_context') and exports['esx_context']:Refresh(...)
end
---@param command_name string The command name
---@param label string The label to show
---@param input_group string The input group
---@param key string The key to bind
---@param on_press function The function to call on press
---@param on_release? function The function to call on release
function ESX.RegisterInput(command_name, label, input_group, key, on_press, on_release)
local command = on_release and '+' .. command_name or command_name
RegisterCommand(command, on_press, false)
Core.Input[command_name] = ESX.HashString(command)
if on_release then
RegisterCommand('-' .. command_name, on_release, false)
end
RegisterKeyMapping(command, label or '', input_group or 'keyboard', key or '')
end
---@param menuType string
---@param open function The function to call on open
---@param close function The function to call on close
function ESX.UI.Menu.RegisterType(menuType, open, close)
ESX.UI.Menu.RegisteredTypes[menuType] = {
open = open,
close = close,
}
end
---@class ESXMenu
---@field type string
---@field namespace string
---@field resourceName string
---@field name string
---@field data table
---@field submit? function
---@field cancel? function
---@field change? function
---@field close function
---@field update function
---@field refresh function
---@field setElement function
---@field setElements function
---@field setTitle function
---@field removeElement function
---@param menuType string
---@param namespace string
---@param name string
---@param data table
---@param submit? function
---@param cancel? function
---@param change? function
---@param close? function
---@return ESXMenu
function ESX.UI.Menu.Open(menuType, namespace, name, data, submit, cancel, change, close)
---@class ESXMenu
local menu = {}
menu.type = menuType
menu.namespace = namespace
menu.resourceName = (GetInvokingResource() or "Unknown")
menu.name = name
menu.data = data
menu.submit = submit
menu.cancel = cancel
menu.change = change
menu.close = function()
ESX.UI.Menu.RegisteredTypes[menuType].close(namespace, name)
for i = 1, #ESX.UI.Menu.Opened, 1 do
if ESX.UI.Menu.Opened[i] then
if ESX.UI.Menu.Opened[i].type == menuType and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then
ESX.UI.Menu.Opened[i] = nil
end
end
end
if close then
close()
end
end
menu.update = function(query, newData)
for i = 1, #menu.data.elements, 1 do
local match = true
for k, v in pairs(query) do
if menu.data.elements[i][k] ~= v then
match = false
end
end
if match then
for k, v in pairs(newData) do
menu.data.elements[i][k] = v
end
end
end
end
menu.refresh = function()
ESX.UI.Menu.RegisteredTypes[menuType].open(namespace, name, menu.data)
end
menu.setElement = function(i, key, val)
menu.data.elements[i][key] = val
end
menu.setElements = function(newElements)
menu.data.elements = newElements
end
menu.setTitle = function(val)
menu.data.title = val
end
menu.removeElement = function(query)
for i = 1, #menu.data.elements, 1 do
for k, v in pairs(query) do
if menu.data.elements[i] then
if menu.data.elements[i][k] == v then
table.remove(menu.data.elements, i)
break
end
end
end
end
end
ESX.UI.Menu.Opened[#ESX.UI.Menu.Opened + 1] = menu
ESX.UI.Menu.RegisteredTypes[menuType].open(namespace, name, data)
return menu
end
---@param menuType string
---@param namespace string
---@param name string
---@param cancel? boolean Should the close be classified as a cancel
---@return nil
function ESX.UI.Menu.Close(menuType, namespace, name, cancel)
for i = 1, #ESX.UI.Menu.Opened, 1 do
if ESX.UI.Menu.Opened[i] then
if ESX.UI.Menu.Opened[i].type == menuType and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then
if not cancel then
ESX.UI.Menu.Opened[i].close()
else
local menu = ESX.UI.Menu.Opened[i]
ESX.UI.Menu.RegisteredTypes[menu.type].close(menu.namespace, menu.name)
if type(menu.cancel) ~= "nil" then
menu.cancel(menu.data, menu)
end
end
ESX.UI.Menu.Opened[i] = nil
end
end
end
end
---@param cancel? boolean Should the close be classified as a cancel
---@return nil
function ESX.UI.Menu.CloseAll(cancel)
for i = 1, #ESX.UI.Menu.Opened, 1 do
if ESX.UI.Menu.Opened[i] then
if not cancel then
ESX.UI.Menu.Opened[i].close()
else
local menu = ESX.UI.Menu.Opened[i]
ESX.UI.Menu.RegisteredTypes[menu.type].close(menu.namespace, menu.name)
if type(menu.cancel) ~= "nil" then
menu.cancel(menu.data, menu)
end
end
ESX.UI.Menu.Opened[i] = nil
end
end
end
---@param menuType string
---@param namespace string
---@param name string
---@return ESXMenu | nil
function ESX.UI.Menu.GetOpened(menuType, namespace, name)
for i = 1, #ESX.UI.Menu.Opened, 1 do
if ESX.UI.Menu.Opened[i] then
if ESX.UI.Menu.Opened[i].type == menuType and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then
return ESX.UI.Menu.Opened[i]
end
end
end
end
---@return ESXMenu[]
function ESX.UI.Menu.GetOpenedMenus()
return ESX.UI.Menu.Opened
end
ESX.UI.Menu.IsOpen = ESX.UI.Menu.GetOpened
---@param add boolean Whether the item is being added or removed
---@param item string The item to show
---@param count number How many of the item to show
---@return nil
function ESX.UI.ShowInventoryItemNotification(add, item, count)
SendNUIMessage({
action = "inventoryNotification",
add = add,
item = item,
count = count,
})
end
---@param ped integer The ped to get the mugshot of
---@param transparent? boolean Whether the mugshot should be transparent
function ESX.Game.GetPedMugshot(ped, transparent)
if not DoesEntityExist(ped) then
return
end
local mugshot = transparent and RegisterPedheadshotTransparent(ped) or RegisterPedheadshot(ped)
while not IsPedheadshotReady(mugshot) do
Wait(0)
end
return mugshot, GetPedheadshotTxdString(mugshot)
end
---@param entity integer The entity to get the coords of
---@param coords table | vector3 | vector4 The coords to teleport the entity to
---@param cb? function The callback function
function ESX.Game.Teleport(entity, coords, cb)
if DoesEntityExist(entity) then
RequestCollisionAtCoord(coords.x, coords.y, coords.z)
while not HasCollisionLoadedAroundEntity(entity) do
Wait(0)
end
SetEntityCoords(entity, coords.x, coords.y, coords.z, false, false, false, false)
SetEntityHeading(entity, coords.w or coords.heading or 0.0)
end
if cb then
cb()
end
end
---@param object integer | string The object to spawn
---@param coords table | vector3 The coords to spawn the object at
---@param cb? function The callback function
---@param networked? boolean Whether the object should be networked
---@return integer | nil
function ESX.Game.SpawnObject(object, coords, cb, networked)
local model = type(object) == "number" and object or joaat(object)
ESX.Streaming.RequestModel(model)
local obj = CreateObject(model, coords.x, coords.y, coords.z, networked == nil or networked, false, true)
return cb and cb(obj) or obj
end
---@param object integer | string The object to spawn
---@param coords table | vector3 The coords to spawn the object at
---@param cb? function The callback function
---@return nil
function ESX.Game.SpawnLocalObject(object, coords, cb)
ESX.Game.SpawnObject(object, coords, cb, false)
end
---@param vehicle integer The vehicle to delete
---@return nil
function ESX.Game.DeleteVehicle(vehicle)
SetEntityAsMissionEntity(vehicle, true, true)
DeleteVehicle(vehicle)
end
---@param object integer The object to delete
---@return nil
function ESX.Game.DeleteObject(object)
SetEntityAsMissionEntity(object, false, true)
DeleteObject(object)
end
---@param vehicleModel integer | string The vehicle to spawn
---@param coords table | vector3 The coords to spawn the vehicle at
---@param heading number The heading of the vehicle
---@param cb? fun(vehicle: number) The callback function
---@param networked? boolean Whether the vehicle should be networked
---@return number? vehicle
function ESX.Game.SpawnVehicle(vehicleModel, coords, heading, cb, networked)
if cb and not ESX.IsFunctionReference(cb) then
error("Invalid callback function")
end
local model = type(vehicleModel) == "number" and vehicleModel or joaat(vehicleModel)
local vector = type(coords) == "vector3" and coords or vec(coords.x, coords.y, coords.z)
local isNetworked = networked == nil or networked
local playerCoords = GetEntityCoords(ESX.PlayerData.ped)
if not vector or not playerCoords then
return
end
local dist = #(playerCoords - vector)
if dist > 424 then -- Onesync infinity Range (https://docs.fivem.net/docs/scripting-reference/onesync/)
local executingResource = GetInvokingResource() or "Unknown"
return error(("Resource ^5%s^1 Tried to spawn vehicle on the client but the position is too far away (Out of onesync range)."):format(executingResource))
end
local promise = not cb and promise.new()
CreateThread(function()
local modelHash = ESX.Streaming.RequestModel(model)
if not modelHash then
if promise then
promise:reject(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model))
return
end
error(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model))
end
local vehicle = CreateVehicle(model, vector.x, vector.y, vector.z, heading, isNetworked, true)
if networked then
local id = NetworkGetNetworkIdFromEntity(vehicle)
SetNetworkIdCanMigrate(id, true)
SetEntityAsMissionEntity(vehicle, true, true)
end
SetVehicleHasBeenOwnedByPlayer(vehicle, true)
SetVehicleNeedsToBeHotwired(vehicle, false)
SetModelAsNoLongerNeeded(model)
SetVehRadioStation(vehicle, "OFF")
RequestCollisionAtCoord(vector.x, vector.y, vector.z)
while not HasCollisionLoadedAroundEntity(vehicle) do
Wait(0)
end
if promise then
promise:resolve(vehicle)
elseif cb then
cb(vehicle)
end
end)
if promise then
return Citizen.Await(promise)
end
end
---@param vehicle integer The vehicle to spawn
---@param coords table | vector3 The coords to spawn the vehicle at
---@param heading number The heading of the vehicle
---@param cb? function The callback function
---@return nil
function ESX.Game.SpawnLocalVehicle(vehicle, coords, heading, cb)
ESX.Game.SpawnVehicle(vehicle, coords, heading, cb, false)
end
---@param vehicle integer The vehicle to check
---@return boolean
function ESX.Game.IsVehicleEmpty(vehicle)
return GetVehicleNumberOfPassengers(vehicle) == 0 and IsVehicleSeatFree(vehicle, -1)
end
---@return table
function ESX.Game.GetObjects() -- Leave the function for compatibility
return GetGamePool("CObject")
end
---@param onlyOtherPeds? boolean Whether to exlude the player ped
---@return table
function ESX.Game.GetPeds(onlyOtherPeds)
local pool = GetGamePool("CPed")
if onlyOtherPeds then
local myPed = ESX.PlayerData.ped
for i = 1, #pool do
if pool[i] == myPed then
table.remove(pool, i)
break
end
end
end
return pool
end
---@return table
function ESX.Game.GetVehicles() -- Leave the function for compatibility
return GetGamePool("CVehicle")
end
---@param onlyOtherPlayers? boolean Whether to exclude the player
---@param returnKeyValue? boolean Whether to return the key value pair
---@param returnPeds? boolean Whether to return the peds
---@return table
function ESX.Game.GetPlayers(onlyOtherPlayers, returnKeyValue, returnPeds)
local players = {}
local active = GetActivePlayers()
for i = 1, #active do
local currentPlayer = active[i]
local ped = GetPlayerPed(currentPlayer)
if DoesEntityExist(ped) and ((onlyOtherPlayers and currentPlayer ~= ESX.playerId) or not onlyOtherPlayers) then
if returnKeyValue then
players[currentPlayer] = ped
else
players[#players + 1] = returnPeds and ped or currentPlayer
end
end
end
return players
end
---@param coords? table | vector3 The coords to get the closest object to
---@param modelFilter? table The model filter
---@return integer, integer
function ESX.Game.GetClosestObject(coords, modelFilter)
return ESX.Game.GetClosestEntity(ESX.Game.GetObjects(), false, coords, modelFilter)
end
---@param coords? table | vector3 The coords to get the closest ped to
---@param modelFilter? table The model filter
---@return integer, integer
function ESX.Game.GetClosestPed(coords, modelFilter)
return ESX.Game.GetClosestEntity(ESX.Game.GetPeds(true), false, coords, modelFilter)
end
---@param coords? table | vector3 The coords to get the closest player to
---@return integer, integer
function ESX.Game.GetClosestPlayer(coords)
return ESX.Game.GetClosestEntity(ESX.Game.GetPlayers(true, true), true, coords, nil)
end
---@param coords? table | vector3 The coords to get the closest vehicle to
---@param modelFilter? table The model filter
---@return integer, integer
function ESX.Game.GetClosestVehicle(coords, modelFilter)
return ESX.Game.GetClosestEntity(ESX.Game.GetVehicles(), false, coords, modelFilter)
end
---@param entities table The entities to search through
---@param isPlayerEntities boolean Whether the entities are players
---@param coords table | vector3 The coords to search from
---@param maxDistance number The max distance to search within
---@return table
local function EnumerateEntitiesWithinDistance(entities, isPlayerEntities, coords, maxDistance)
local nearbyEntities = {}
if coords then
coords = vector3(coords.x, coords.y, coords.z)
else
local playerPed = ESX.PlayerData.ped
coords = GetEntityCoords(playerPed)
end
for k, entity in pairs(entities) do
local distance = #(coords - GetEntityCoords(entity))
if distance <= maxDistance then
nearbyEntities[#nearbyEntities + 1] = isPlayerEntities and k or entity
end
end
return nearbyEntities
end
---@param coords table | vector3 The coords to search from
---@param maxDistance number The max distance to search within
---@return table
function ESX.Game.GetPlayersInArea(coords, maxDistance)
return EnumerateEntitiesWithinDistance(ESX.Game.GetPlayers(true, true), true, coords, maxDistance)
end
---@param coords table | vector3 The coords to search from
---@param maxDistance number The max distance to search within
---@return table
function ESX.Game.GetVehiclesInArea(coords, maxDistance)
return EnumerateEntitiesWithinDistance(ESX.Game.GetVehicles(), false, coords, maxDistance)
end
---@param coords table | vector3 The coords to search from
---@param maxDistance number The max distance to search within
---@return boolean
function ESX.Game.IsSpawnPointClear(coords, maxDistance)
return #ESX.Game.GetVehiclesInArea(coords, maxDistance) == 0
end
---@param shape integer The shape to get the test result from
---@return boolean, table, table, integer, integer
function ESX.Game.GetShapeTestResultSync(shape)
local handle, hit, coords, normal, material, entity
repeat
handle, hit, coords, normal, material, entity = GetShapeTestResultIncludingMaterial(shape)
Wait(0)
until handle ~= 1
return hit, coords, normal, material, entity
end
---@param depth number The depth to raycast
---@vararg any The arguments to pass to the shape test
---@return table, boolean, table, table, integer, integer
function ESX.Game.RaycastScreen(depth, ...)
local world, normal = GetWorldCoordFromScreenCoord(.5, .5)
local origin = world + normal
local target = world + normal * depth
return target, ESX.Game.GetShapeTestResultSync(StartShapeTestLosProbe(origin.x, origin.y, origin.z, target.x, target.y, target.z, ...))
end
---@param entities table The entities to search through
---@param isPlayerEntities boolean Whether the entities are players
---@param coords? table | vector3 The coords to search from
---@param modelFilter? table The model filter
---@return integer, integer
function ESX.Game.GetClosestEntity(entities, isPlayerEntities, coords, modelFilter)
local closestEntity, closestEntityDistance, filteredEntities = -1, -1, nil
if coords then
coords = vector3(coords.x, coords.y, coords.z)
else
local playerPed = ESX.PlayerData.ped
coords = GetEntityCoords(playerPed)
end
if modelFilter then
filteredEntities = {}
for currentEntityIndex = 1, #entities do
if modelFilter[GetEntityModel(entities[currentEntityIndex])] then
filteredEntities[#filteredEntities + 1] = entities[currentEntityIndex]
end
end
end
for k, entity in pairs(filteredEntities or entities) do
local distance = #(coords - GetEntityCoords(entity))
if closestEntityDistance == -1 or distance < closestEntityDistance then
closestEntity, closestEntityDistance = isPlayerEntities and k or entity, distance
end
end
return closestEntity, closestEntityDistance
end
---@return integer | nil, vector3 | nil
function ESX.Game.GetVehicleInDirection()
local _, hit, coords, _, _, entity = ESX.Game.RaycastScreen(5, 10, ESX.PlayerData.ped)
if hit and IsEntityAVehicle(entity) then
return entity, coords
end
end
---@param vehicle integer The vehicle to get the properties of
---@return table | nil
function ESX.Game.GetVehicleProperties(vehicle)
if not DoesEntityExist(vehicle) then
return
end
---@type number | number[], number | number[]
local colorPrimary, colorSecondary = GetVehicleColours(vehicle)
local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle)
local dashboardColor = GetVehicleDashboardColor(vehicle)
local interiorColor = GetVehicleInteriorColour(vehicle)
if GetIsVehiclePrimaryColourCustom(vehicle) then
colorPrimary = { GetVehicleCustomPrimaryColour(vehicle) }
end
if GetIsVehicleSecondaryColourCustom(vehicle) then
colorSecondary = { GetVehicleCustomSecondaryColour(vehicle) }
end
local hasCustomXenonColor, customXenonColorR, customXenonColorG, customXenonColorB = GetVehicleXenonLightsCustomColor(vehicle)
local customXenonColor = nil
if hasCustomXenonColor then
customXenonColor = { customXenonColorR, customXenonColorG, customXenonColorB }
end
local extras = {}
for extraId = 0, 20 do
if DoesExtraExist(vehicle, extraId) then
extras[tostring(extraId)] = IsVehicleExtraTurnedOn(vehicle, extraId)
end
end
local doorsBroken, windowsBroken, tyreBurst = {}, {}, {}
local numWheels = tostring(GetVehicleNumberOfWheels(vehicle))
local TyresIndex = { -- Wheel index list according to the number of vehicle wheels.
["2"] = { 0, 4 }, -- Bike and cycle.
["3"] = { 0, 1, 4, 5 }, -- Vehicle with 3 wheels (get for wheels because some 3 wheels vehicles have 2 wheels on front and one rear or the reverse).
["4"] = { 0, 1, 4, 5 }, -- Vehicle with 4 wheels.
["6"] = { 0, 1, 2, 3, 4, 5 }, -- Vehicle with 6 wheels.
}
if TyresIndex[numWheels] then
for _, idx in pairs(TyresIndex[numWheels]) do
tyreBurst[tostring(idx)] = IsVehicleTyreBurst(vehicle, idx, false)
end
end
for windowId = 0, 7 do -- 13
RollUpWindow(vehicle, windowId) --fix when you put the car away with the window down
windowsBroken[tostring(windowId)] = not IsVehicleWindowIntact(vehicle, windowId)
end
local numDoors = GetNumberOfVehicleDoors(vehicle)
if numDoors and numDoors > 0 then
for doorsId = 0, numDoors do
doorsBroken[tostring(doorsId)] = IsVehicleDoorDamaged(vehicle, doorsId)
end
end
return {
model = GetEntityModel(vehicle),
doorsBroken = doorsBroken,
windowsBroken = windowsBroken,
tyreBurst = tyreBurst,
tyresCanBurst = GetVehicleTyresCanBurst(vehicle),
plate = ESX.Math.Trim(GetVehicleNumberPlateText(vehicle)),
plateIndex = GetVehicleNumberPlateTextIndex(vehicle),
bodyHealth = ESX.Math.Round(GetVehicleBodyHealth(vehicle), 1),
engineHealth = ESX.Math.Round(GetVehicleEngineHealth(vehicle), 1),
tankHealth = ESX.Math.Round(GetVehiclePetrolTankHealth(vehicle), 1),
fuelLevel = ESX.Math.Round(GetVehicleFuelLevel(vehicle), 1),
dirtLevel = ESX.Math.Round(GetVehicleDirtLevel(vehicle), 1),
color1 = colorPrimary,
color2 = colorSecondary,
pearlescentColor = pearlescentColor,
wheelColor = wheelColor,
dashboardColor = dashboardColor,
interiorColor = interiorColor,
wheels = GetVehicleWheelType(vehicle),
windowTint = GetVehicleWindowTint(vehicle),
xenonColor = GetVehicleXenonLightsColor(vehicle),
customXenonColor = customXenonColor,
neonEnabled = { IsVehicleNeonLightEnabled(vehicle, 0), IsVehicleNeonLightEnabled(vehicle, 1), IsVehicleNeonLightEnabled(vehicle, 2), IsVehicleNeonLightEnabled(vehicle, 3) },
neonColor = table.pack(GetVehicleNeonLightsColour(vehicle)),
extras = extras,
tyreSmokeColor = table.pack(GetVehicleTyreSmokeColor(vehicle)),
modSpoilers = GetVehicleMod(vehicle, 0),
modFrontBumper = GetVehicleMod(vehicle, 1),
modRearBumper = GetVehicleMod(vehicle, 2),
modSideSkirt = GetVehicleMod(vehicle, 3),
modExhaust = GetVehicleMod(vehicle, 4),
modFrame = GetVehicleMod(vehicle, 5),
modGrille = GetVehicleMod(vehicle, 6),
modHood = GetVehicleMod(vehicle, 7),
modFender = GetVehicleMod(vehicle, 8),
modRightFender = GetVehicleMod(vehicle, 9),
modRoof = GetVehicleMod(vehicle, 10),
modRoofLivery = GetVehicleRoofLivery(vehicle),
modEngine = GetVehicleMod(vehicle, 11),
modBrakes = GetVehicleMod(vehicle, 12),
modTransmission = GetVehicleMod(vehicle, 13),
modHorns = GetVehicleMod(vehicle, 14),
modSuspension = GetVehicleMod(vehicle, 15),
modArmor = GetVehicleMod(vehicle, 16),
modTurbo = IsToggleModOn(vehicle, 18),
modSmokeEnabled = IsToggleModOn(vehicle, 20),
modXenon = IsToggleModOn(vehicle, 22),
modFrontWheels = GetVehicleMod(vehicle, 23),
modCustomFrontWheels = GetVehicleModVariation(vehicle, 23),
modBackWheels = GetVehicleMod(vehicle, 24),
modCustomBackWheels = GetVehicleModVariation(vehicle, 24),
modPlateHolder = GetVehicleMod(vehicle, 25),
modVanityPlate = GetVehicleMod(vehicle, 26),
modTrimA = GetVehicleMod(vehicle, 27),
modOrnaments = GetVehicleMod(vehicle, 28),
modDashboard = GetVehicleMod(vehicle, 29),
modDial = GetVehicleMod(vehicle, 30),
modDoorSpeaker = GetVehicleMod(vehicle, 31),
modSeats = GetVehicleMod(vehicle, 32),
modSteeringWheel = GetVehicleMod(vehicle, 33),
modShifterLeavers = GetVehicleMod(vehicle, 34),
modAPlate = GetVehicleMod(vehicle, 35),
modSpeakers = GetVehicleMod(vehicle, 36),
modTrunk = GetVehicleMod(vehicle, 37),
modHydrolic = GetVehicleMod(vehicle, 38),
modEngineBlock = GetVehicleMod(vehicle, 39),
modAirFilter = GetVehicleMod(vehicle, 40),
modStruts = GetVehicleMod(vehicle, 41),
modArchCover = GetVehicleMod(vehicle, 42),
modAerials = GetVehicleMod(vehicle, 43),
modTrimB = GetVehicleMod(vehicle, 44),
modTank = GetVehicleMod(vehicle, 45),
modWindows = GetVehicleMod(vehicle, 46),
modLivery = GetVehicleMod(vehicle, 48) == -1 and GetVehicleLivery(vehicle) or GetVehicleMod(vehicle, 48),
modLightbar = GetVehicleMod(vehicle, 49),
}
end
---@param vehicle integer The vehicle to set the properties of
---@param props table The properties to set
---@return nil
function ESX.Game.SetVehicleProperties(vehicle, props)
if not DoesEntityExist(vehicle) then
return
end
local colorPrimary, colorSecondary = GetVehicleColours(vehicle)
local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle)
SetVehicleModKit(vehicle, 0)
if props.tyresCanBurst ~= nil then
SetVehicleTyresCanBurst(vehicle, props.tyresCanBurst)
end
if props.plate ~= nil then
SetVehicleNumberPlateText(vehicle, props.plate)
end
if props.plateIndex ~= nil then
SetVehicleNumberPlateTextIndex(vehicle, props.plateIndex)
end
if props.bodyHealth ~= nil then
SetVehicleBodyHealth(vehicle, props.bodyHealth + 0.0)
end
if props.engineHealth ~= nil then
SetVehicleEngineHealth(vehicle, props.engineHealth + 0.0)
end
if props.tankHealth ~= nil then
SetVehiclePetrolTankHealth(vehicle, props.tankHealth + 0.0)
end
if props.fuelLevel ~= nil then
SetVehicleFuelLevel(vehicle, props.fuelLevel + 0.0)
end
if props.dirtLevel ~= nil then
SetVehicleDirtLevel(vehicle, props.dirtLevel + 0.0)
end
if props.color1 ~= nil then
if type(props.color1) == "table" then
SetVehicleCustomPrimaryColour(vehicle, props.color1[1], props.color1[2], props.color1[3])
else
SetVehicleColours(vehicle, props.color1, colorSecondary)
end
end
if props.color2 ~= nil then
if type(props.color2) == "table" then
SetVehicleCustomSecondaryColour(vehicle, props.color2[1], props.color2[2], props.color2[3])
else
SetVehicleColours(vehicle, props.color1 or colorPrimary, props.color2)
end
end
if props.pearlescentColor ~= nil then
SetVehicleExtraColours(vehicle, props.pearlescentColor, wheelColor)
end
if props.interiorColor ~= nil then
SetVehicleInteriorColor(vehicle, props.interiorColor)
end
if props.dashboardColor ~= nil then
SetVehicleDashboardColor(vehicle, props.dashboardColor)
end
if props.wheelColor ~= nil then
SetVehicleExtraColours(vehicle, props.pearlescentColor or pearlescentColor, props.wheelColor)
end
if props.wheels ~= nil then
SetVehicleWheelType(vehicle, props.wheels)
end
if props.windowTint ~= nil then
SetVehicleWindowTint(vehicle, props.windowTint)
end
if props.neonEnabled ~= nil then
SetVehicleNeonLightEnabled(vehicle, 0, props.neonEnabled[1])
SetVehicleNeonLightEnabled(vehicle, 1, props.neonEnabled[2])
SetVehicleNeonLightEnabled(vehicle, 2, props.neonEnabled[3])
SetVehicleNeonLightEnabled(vehicle, 3, props.neonEnabled[4])
end
if props.extras ~= nil then
for extraId, enabled in pairs(props.extras) do
extraId = tonumber(extraId)
if extraId then
SetVehicleExtra(vehicle, extraId, not enabled)
end
end
end
if props.neonColor ~= nil then
SetVehicleNeonLightsColour(vehicle, props.neonColor[1], props.neonColor[2], props.neonColor[3])
end
if props.xenonColor ~= nil then
SetVehicleXenonLightsColor(vehicle, props.xenonColor)
end
if props.customXenonColor ~= nil then
SetVehicleXenonLightsCustomColor(vehicle, props.customXenonColor[1], props.customXenonColor[2], props.customXenonColor[3])
end
if props.modSmokeEnabled ~= nil then
ToggleVehicleMod(vehicle, 20, true)
end
if props.tyreSmokeColor ~= nil then
SetVehicleTyreSmokeColor(vehicle, props.tyreSmokeColor[1], props.tyreSmokeColor[2], props.tyreSmokeColor[3])
end
if props.modSpoilers ~= nil then
SetVehicleMod(vehicle, 0, props.modSpoilers, false)
end
if props.modFrontBumper ~= nil then
SetVehicleMod(vehicle, 1, props.modFrontBumper, false)
end
if props.modRearBumper ~= nil then
SetVehicleMod(vehicle, 2, props.modRearBumper, false)
end
if props.modSideSkirt ~= nil then
SetVehicleMod(vehicle, 3, props.modSideSkirt, false)
end
if props.modExhaust ~= nil then
SetVehicleMod(vehicle, 4, props.modExhaust, false)
end
if props.modFrame ~= nil then
SetVehicleMod(vehicle, 5, props.modFrame, false)
end
if props.modGrille ~= nil then
SetVehicleMod(vehicle, 6, props.modGrille, false)
end
if props.modHood ~= nil then
SetVehicleMod(vehicle, 7, props.modHood, false)
end
if props.modFender ~= nil then
SetVehicleMod(vehicle, 8, props.modFender, false)
end
if props.modRightFender ~= nil then
SetVehicleMod(vehicle, 9, props.modRightFender, false)
end
if props.modRoof ~= nil then
SetVehicleMod(vehicle, 10, props.modRoof, false)
end
if props.modRoofLivery ~= nil then
SetVehicleRoofLivery(vehicle, props.modRoofLivery)
end
if props.modEngine ~= nil then
SetVehicleMod(vehicle, 11, props.modEngine, false)
end
if props.modBrakes ~= nil then
SetVehicleMod(vehicle, 12, props.modBrakes, false)
end
if props.modTransmission ~= nil then
SetVehicleMod(vehicle, 13, props.modTransmission, false)
end
if props.modHorns ~= nil then
SetVehicleMod(vehicle, 14, props.modHorns, false)
end
if props.modSuspension ~= nil then
SetVehicleMod(vehicle, 15, props.modSuspension, false)
end
if props.modArmor ~= nil then
SetVehicleMod(vehicle, 16, props.modArmor, false)
end
if props.modTurbo ~= nil then
ToggleVehicleMod(vehicle, 18, props.modTurbo)
end
if props.modXenon ~= nil then
ToggleVehicleMod(vehicle, 22, props.modXenon)
end
if props.modFrontWheels ~= nil then
SetVehicleMod(vehicle, 23, props.modFrontWheels, props.modCustomFrontWheels)
end
if props.modBackWheels ~= nil then
SetVehicleMod(vehicle, 24, props.modBackWheels, props.modCustomBackWheels)
end
if props.modPlateHolder ~= nil then
SetVehicleMod(vehicle, 25, props.modPlateHolder, false)
end
if props.modVanityPlate ~= nil then
SetVehicleMod(vehicle, 26, props.modVanityPlate, false)
end
if props.modTrimA ~= nil then
SetVehicleMod(vehicle, 27, props.modTrimA, false)
end
if props.modOrnaments ~= nil then
SetVehicleMod(vehicle, 28, props.modOrnaments, false)
end
if props.modDashboard ~= nil then
SetVehicleMod(vehicle, 29, props.modDashboard, false)
end
if props.modDial ~= nil then
SetVehicleMod(vehicle, 30, props.modDial, false)
end
if props.modDoorSpeaker ~= nil then
SetVehicleMod(vehicle, 31, props.modDoorSpeaker, false)
end
if props.modSeats ~= nil then
SetVehicleMod(vehicle, 32, props.modSeats, false)
end
if props.modSteeringWheel ~= nil then
SetVehicleMod(vehicle, 33, props.modSteeringWheel, false)
end
if props.modShifterLeavers ~= nil then
SetVehicleMod(vehicle, 34, props.modShifterLeavers, false)
end
if props.modAPlate ~= nil then
SetVehicleMod(vehicle, 35, props.modAPlate, false)
end
if props.modSpeakers ~= nil then
SetVehicleMod(vehicle, 36, props.modSpeakers, false)
end
if props.modTrunk ~= nil then
SetVehicleMod(vehicle, 37, props.modTrunk, false)
end
if props.modHydrolic ~= nil then
SetVehicleMod(vehicle, 38, props.modHydrolic, false)
end
if props.modEngineBlock ~= nil then
SetVehicleMod(vehicle, 39, props.modEngineBlock, false)
end
if props.modAirFilter ~= nil then
SetVehicleMod(vehicle, 40, props.modAirFilter, false)
end
if props.modStruts ~= nil then
SetVehicleMod(vehicle, 41, props.modStruts, false)
end
if props.modArchCover ~= nil then
SetVehicleMod(vehicle, 42, props.modArchCover, false)
end
if props.modAerials ~= nil then
SetVehicleMod(vehicle, 43, props.modAerials, false)
end
if props.modTrimB ~= nil then
SetVehicleMod(vehicle, 44, props.modTrimB, false)
end
if props.modTank ~= nil then
SetVehicleMod(vehicle, 45, props.modTank, false)
end
if props.modWindows ~= nil then
SetVehicleMod(vehicle, 46, props.modWindows, false)
end
if props.modLivery ~= nil then
SetVehicleMod(vehicle, 48, props.modLivery, false)
SetVehicleLivery(vehicle, props.modLivery)
end
if props.windowsBroken ~= nil then
for k, v in pairs(props.windowsBroken) do
if v then
k = tonumber(k)
if k then
RemoveVehicleWindow(vehicle, k)
end
end
end
end
if props.doorsBroken ~= nil then
for k, v in pairs(props.doorsBroken) do
if v then
k = tonumber(k)
if k then
SetVehicleDoorBroken(vehicle, k, true)
end
end
end
end
if props.tyreBurst ~= nil then
for k, v in pairs(props.tyreBurst) do
if v then
k = tonumber(k)
if k then
SetVehicleTyreBurst(vehicle, k, true, 1000.0)
end
end
end
end
end
---@param coords vector3 | table coords to get the closest pickup to
---@param text string The text to display
---@param size? number The size of the text
---@param font? number The font of the text
---@return nil
function ESX.Game.Utils.DrawText3D(coords, text, size, font)
local vector = type(coords) == "vector3" and coords or vec(coords.x, coords.y, coords.z)
local camCoords = GetFinalRenderedCamCoord()
local distance = #(vector - camCoords)
size = size or 1
font = font or 0
local scale = (size / distance) * 2
local fov = (1 / GetGameplayCamFov()) * 100
scale = scale * fov
SetTextScale(0.0, 0.55 * scale)
SetTextFont(font)
SetTextProportional(true)
SetTextColour(255, 255, 255, 215)
BeginTextCommandDisplayText("STRING")
SetTextCentre(true)
AddTextComponentSubstringPlayerName(text)
SetDrawOrigin(vector.x, vector.y, vector.z, 0)
EndTextCommandDisplayText(0.0, 0.0)
ClearDrawOrigin()
end
---@param account string Account name (money/bank/black_money)
---@return table|nil
function ESX.GetAccount(account)
for i = 1, #ESX.PlayerData.accounts, 1 do
if ESX.PlayerData.accounts[i].name == account then
return ESX.PlayerData.accounts[i]
end
end
return nil
end
function ESX.ShowInventory()
if not Config.EnableDefaultInventory then
return
end
exports.esx_inventory:ShowInventory()
end
RegisterNetEvent('esx:showNotification', ESX.ShowNotification)
RegisterNetEvent('esx:showAdvancedNotification', ESX.ShowAdvancedNotification)
RegisterNetEvent('esx:showHelpNotification', ESX.ShowHelpNotification)
AddEventHandler("onResourceStop", function(resourceName)
for i = 1, #ESX.UI.Menu.Opened, 1 do
if ESX.UI.Menu.Opened[i] then
if ESX.UI.Menu.Opened[i].resourceName == resourceName or ESX.UI.Menu.Opened[i].namespace == resourceName then
ESX.UI.Menu.Opened[i].close()
ESX.UI.Menu.Opened[i] = nil
end
end
end
end)
-- Credits to txAdmin for the list.
local mismatchedTypes = {
[`airtug`] = "automobile", -- trailer
[`avisa`] = "submarine", -- boat
[`blimp`] = "heli", -- plane
[`blimp2`] = "heli", -- plane
[`blimp3`] = "heli", -- plane
[`caddy`] = "automobile", -- trailer
[`caddy2`] = "automobile", -- trailer
[`caddy3`] = "automobile", -- trailer
[`chimera`] = "automobile", -- bike
[`docktug`] = "automobile", -- trailer
[`forklift`] = "automobile", -- trailer
[`kosatka`] = "submarine", -- boat
[`mower`] = "automobile", -- trailer
[`policeb`] = "bike", -- automobile
[`ripley`] = "automobile", -- trailer
[`rrocket`] = "automobile", -- bike
[`sadler`] = "automobile", -- trailer
[`sadler2`] = "automobile", -- trailer
[`scrap`] = "automobile", -- trailer
[`slamtruck`] = "automobile", -- trailer
[`Stryder`] = "automobile", -- bike
[`submersible`] = "submarine", -- boat
[`submersible2`] = "submarine", -- boat
[`thruster`] = "heli", -- automobile
[`towtruck`] = "automobile", -- trailer
[`towtruck2`] = "automobile", -- trailer
[`tractor`] = "automobile", -- trailer
[`tractor2`] = "automobile", -- trailer
[`tractor3`] = "automobile", -- trailer
[`trailersmall2`] = "trailer", -- automobile
[`utillitruck`] = "automobile", -- trailer
[`utillitruck2`] = "automobile", -- trailer
[`utillitruck3`] = "automobile", -- trailer
}
---@param model number|string
---@return string | boolean
function ESX.GetVehicleTypeClient(model)
model = type(model) == "string" and joaat(model) or model
if not IsModelInCdimage(model) then
return false
end
if not IsModelAVehicle(model) then
return false
end
if mismatchedTypes[model] then
return mismatchedTypes[model]
end
local vehicleType = GetVehicleClassFromName(model)
local types = {
[8] = "bike",
[11] = "trailer",
[13] = "bike",
[14] = "boat",
[15] = "heli",
[16] = "plane",
[21] = "train",
}
return types[vehicleType] or "automobile"
end
ESX.GetVehicleType = ESX.GetVehicleTypeClient