1
0
Fork 0
forked from Simnation/Main
Main/resources/[jobs]/[mechanic]/jg-mechanic/framework/cl-functions.lua
2025-08-13 21:00:13 +02:00

388 lines
No EOL
14 KiB
Lua

---@param text string
function Framework.Client.ShowTextUI(text)
if (Config.DrawText == "auto" and GetResourceState("jg-textui") == "started") or Config.DrawText == "jg-textui" then
exports["jg-textui"]:DrawText(text)
elseif (Config.DrawText == "auto" and GetResourceState("ox_lib") == "started") or Config.DrawText == "ox_lib" then
exports["ox_lib"]:showTextUI(text, {
position = "left-center"
})
elseif (Config.DrawText == "auto" and GetResourceState("okokTextUI") == "started") or Config.DrawText == "okokTextUI" then
exports["okokTextUI"]:Open(text, "lightblue", "left")
elseif (Config.DrawText == "auto" and GetResourceState("ps-ui") == "started") or Config.DrawText == "ps-ui" then
exports["ps-ui"]:DisplayText(text, "primary")
elseif Config.Framework == "QBCore" then
exports["qb-core"]:DrawText(text)
else
error("You do not have a notifications system set up!")
end
end
function Framework.Client.HideTextUI()
if (Config.DrawText == "auto" and GetResourceState("jg-textui") == "started") or Config.DrawText == "jg-textui" then
exports["jg-textui"]:HideText()
elseif (Config.DrawText == "auto" and GetResourceState("ox_lib") == "started") or Config.DrawText == "ox_lib" then
exports["ox_lib"]:hideTextUI()
elseif (Config.DrawText == "auto" and GetResourceState("okokTextUI") == "started") or Config.DrawText == "okokTextUI" then
exports["okokTextUI"]:Close()
elseif (Config.DrawText == "auto" and GetResourceState("ps-ui") == "started") or Config.DrawText == "ps-ui" then
exports["ps-ui"]:HideText()
elseif Config.Framework == "QBCore" then
exports["qb-core"]:HideText()
else
error("You do not have a notifications system set up!")
end
end
---@param msg string
---@param type? "success" | "warning" | "error"
---@param time? number
function Framework.Client.Notify(msg, type, time)
type = type or "success"
time = time or 5000
if (Config.Notifications == "auto" and GetResourceState("ox_lib") == "started") or Config.Notifications == "ox_lib" then
exports["ox_lib"]:notify({
title = "Mechanic",
description = msg,
type = type
})
elseif (Config.Notifications == "auto" and GetResourceState("okokNotify") == "started") or Config.Notifications == "okokNotify" then
exports["okokNotify"]:Alert("Mechanic", msg, time, type)
elseif (Config.Notifications == "auto" and GetResourceState("ps-ui") == "started") or Config.Notifications == "ps-ui" then
exports["ps-ui"]:Notify(msg, type, time)
elseif (Config.Notifications == "auto" and GetResourceState("nox_notify") == "started") or Config.Notifications == "nox_notify" then
TriggerEvent("nox_notify:showClientNotify", "Mechanic", msg, type, time)
else
if Config.Framework == "QBCore" then
return QBCore.Functions.Notify(msg, type, time)
elseif Config.Framework == "Qbox" then
exports.qbx_core:Notify(msg, type, time)
elseif Config.Framework == "ESX" then
return ESX.ShowNotification(msg, type)
end
end
end
RegisterNetEvent("jg-mechanic:client:notify", function(...)
Framework.Client.Notify(...)
end)
---@param toggle boolean
function Framework.Client.ToggleHud(toggle)
if GetResourceState("jg-hud") == "started" then
exports["jg-hud"]:toggleHud(toggle)
return
end
DisplayHud(toggle)
DisplayRadar(toggle)
end
---@param text string | false
---@param duration? number
---@param cb function Code to run when progress bar completes successfully
---@param cbCancelled? function Code to run if the progress bar is cancelled
function Framework.Client.ProgressBar(text, duration, anim, prop, cb, cbCancelled)
if Config.ProgressBar == "auto" or Config.ProgressBar == "ox-bar" or Config.ProgressBar == "ox-circle" then
if (Config.ProgressBar == "ox-bar" and lib.progressBar or lib.progressCircle)({
duration = duration or 5000,
label = text or "",
useWhileDead = false,
canCancel = true,
anim = not anim and {} or {
dict = anim.dict,
clip = anim.name
},
prop = not prop and {} or {
model = GetHashKey(prop.model),
bone = prop.bone,
pos = prop.coords,
rot = prop.rotation
},
}) then cb() elseif cbCancelled then cbCancelled() end
elseif Config.ProgressBar == "qb" then
QBCore.Functions.Progressbar(text or "", text, duration, false, true, {
disableMovement = false,
disableCarMovement = false,
disableMouse = false,
disableCombat = true,
}, not anim and {} or {
animDict = anim.dict,
anim = anim.name
}, not prop and {} or {
model = GetHashKey(prop.model),
bone = prop.bone,
coords = prop.coords,
rotation = prop.rotation
}, {}, cb(), cbCancelled and cbCancelled() or false)
end
end
---@param cb function Code to run when skill check is completed successfully
---@param cbFailed function Code to run if the skill check is failed
function Framework.Client.SkillCheck(cb, cbFailed)
if not Config.UseSkillbars then
return Framework.Client.ProgressBar("", Config.ProgressBarDuration or 10000, false, false, cb, cbFailed)
end
local attempts, maxFails = 0, Config.MaximumSkillCheckAttempts or 3
if Config.SkillCheck == "auto" or Config.SkillCheck == "ox" then
repeat
success = lib.skillCheck(Config.SkillCheckDifficulty, Config.SkillCheckInputs)
if not success then
attempts += 1
if attempts == maxFails then return cbFailed() end
Framework.Client.Notify(Locale.skillCheckFailed:format(maxFails - attempts), "error")
end
Wait(success and 100 or 2000)
until success
return cb()
elseif Config.SkillCheck == "qb" and GetResourceState("qb-skillbar") == "started" then
local Skillbar = exports["qb-skillbar"]:GetSkillbarObject()
Skillbar.Start({
duration = math.random(5000, 10000),
pos = math.random(10, 30),
width = math.random(10, 20),
}, function()
cb()
end, function()
cbFailed()
end)
else
error("Config.SkillCheck is invalid or no skill check resource is available!")
end
end
-- Get a nice vehicle label from either QBCore shared or GTA natives
---@param model string | number
function Framework.Client.GetVehicleLabel(model)
if type(model) == "string" then
if Config.Framework == "QBCore" and QBCore.Shared.Vehicles then
local vehShared = QBCore.Shared.Vehicles[model]
if vehShared then
return vehShared.brand .. " " .. vehShared.name
end
end
if Config.Framework == "Qbox" and exports.qbx_core:GetVehiclesByName() then
local vehShared = exports.qbx_core:GetVehiclesByName()[model]
if vehShared then
return vehShared.brand .. " " .. vehShared.name
end
end
end
local hash = type(model) == "string" and joaat(model) or model
local makeName = GetMakeNameFromVehicleModel(hash)
local modelName = GetDisplayNameFromVehicleModel(hash)
local label = GetLabelText(makeName) .. " " .. GetLabelText(modelName)
if makeName == "CARNOTFOUND" or modelName == "CARNOTFOUND" then
label = tostring(model)
else
if GetLabelText(modelName) == "NULL" and GetLabelText(makeName) == "NULL" then
label = (makeName or "") .. " " .. (modelName or "")
elseif GetLabelText(makeName) == "NULL" then
label = GetLabelText(modelName)
end
end
return label
end
---@param model string | number
function Framework.Client.GetVehicleValue(model)
local hash = type(model) == "string" and joaat(model) or model
-- Base game value (handling file)
local vehicleValue = GetVehicleModelValue(hash)
if type(model) == "string" then
if Config.Framework == "QBCore" and QBCore.Shared.Vehicles then
local vehShared = QBCore.Shared.Vehicles[model]
if vehShared and vehShared.price then
vehicleValue = vehShared.price
end
end
if Config.Framework == "Qbox" and exports.qbx_core:GetVehiclesByName() then
local vehShared = exports.qbx_core:GetVehiclesByName()[model]
if vehShared and vehShared.price then
vehicleValue = vehShared.price
end
end
end
-- If you're using jg-dealerships, this would be the most accurate vehicle value
if GetResourceState("jg-dealerships") == "started" then
local price = lib.callback.await("jg-mechanic:server:dealerships-vehicle-value", false, hash)
if price then vehicleValue = price end
end
return vehicleValue or 50000 -- fallback value of 50000, I guess the average price of a car?
end
---@param vehicle integer
---@return string|false plate
function Framework.Client.GetPlate(vehicle)
local plate = GetVehicleNumberPlateText(vehicle)
if not plate or plate == nil or plate == "" then return false end
if GetResourceState("brazzers-fakeplates") == "started" then
local originalPlate = lib.callback.await("jg-mechanic:server:brazzers-get-plate-from-fakeplate", false, plate)
if originalPlate then plate = originalPlate end
end
local trPlate = string.gsub(plate, "^%s*(.-)%s*$", "%1")
return trPlate
end
---Add exports for third party deformation & repair scripts
---@param vehicle integer
function Framework.Client.RepairVehicle(vehicle)
SetVehicleUndriveable(vehicle, false)
WashDecalsFromVehicle(vehicle, 1.0)
SetVehicleEngineHealth(vehicle, 1000.0)
SetVehicleBodyHealth(vehicle, 1000.0)
SetVehiclePetrolTankHealth(vehicle, 1000.0)
SetVehicleDirtLevel(vehicle, 0.0)
SetVehicleDeformationFixed(vehicle)
SetVehicleFixed(vehicle)
if GetResourceState("VehicleDeformation") == "started" then
exports["VehicleDeformation"]:FixVehicleDeformation(vehicle)
end
--* Add more exports for repair scripts here... feel free to let us know them in Discord so we can add them by default in future updates!
end
--
-- Player
--
function Framework.Client.GetPlayerData()
if Config.Framework == "QBCore" then
return QBCore.Functions.GetPlayerData()
elseif Config.Framework == "Qbox" then
return exports.qbx_core:GetPlayerData()
elseif Config.Framework == "ESX" then
return ESX.GetPlayerData()
end
end
---@param type "cash" | "bank" | "money"
function Framework.Client.GetBalance(type)
if Config.Framework == "QBCore" then
return QBCore.Functions.GetPlayerData().money[type]
elseif Config.Framework == "Qbox" then
return exports.qbx_core:GetPlayerData().money[type]
elseif Config.Framework == "ESX" then
if type == "cash" then type = "money" end
for i, acc in pairs(ESX.GetPlayerData().accounts) do
if acc.name == type then
return acc.money
end
end
return 0
end
end
---@return {name: string, label: string, grade: string} | {}
function Framework.Client.GetPlayerJob()
local player = Framework.Client.GetPlayerData()
if not player or not player.job then return {} end
if Config.Framework == "QBCore" or Config.Framework == "Qbox" then
return {
name = player.job.name,
label = player.job.label,
grade = player.job.grade.level
}
elseif Config.Framework == "ESX" then
return {
name = player.job.name,
label = player.job.label,
grade = player.job.grade
}
end
return {}
end
---@param mechanicId string
function Framework.Client.GetPlayerJobDuty(mechanicId)
if not Config.MechanicLocations[mechanicId] then return false end
local onDuty = lib.callback.await("jg-mechanic:server:is-on-duty", false, mechanicId)
if Config.Framework == "QBCore" or Config.Framework == "Qbox" then
local player = Framework.Client.GetPlayerData()
if not player or not player.job then return false end
onDuty = player.job.onduty
end
return onDuty
end
---@param toggle boolean
function Framework.Client.ToggleJobDuty(toggle)
lib.callback.await("jg-mechanic:server:toggle-duty", false, toggle)
end
--
-- Sound (uses native audio, switch to your preferred sound script if you'd like)
--
---@param soundName string
---@param coords vector3
function Framework.Client.PlaySound(soundName, coords)
if Config.DisableSound then return false end
lib.requestAudioBank("audiodirectory/jg_mechanic")
local soundId = GetSoundId()
PlaySoundFromCoord(soundId, soundName, coords.x, coords.y, coords.z, "special_soundset", true, 7.5, false)
CreateThread(function()
while not HasSoundFinished(soundId) do Wait(1) end
ReleaseSoundId(soundId)
ReleaseNamedScriptAudioBank("audiodirectory/jg_mechanic")
end)
return soundId
end
--
-- Stashes
--
---@param stashId string
---@param stashName string
function Framework.Client.OpenInventoryStash(stashId, stashName)
if (Config.Inventory == "auto" and GetResourceState("ox_inventory") == "started") or Config.Inventory == "ox_inventory" then
exports.ox_inventory:openInventory("stash", stashId)
elseif (Config.Inventory == "auto" and GetResourceState("qb-inventory") == "started") or Config.Inventory == "qb-inventory" then
TriggerServerEvent("jg-mechanic:server:open-inventory-stash", stashId, stashName)
elseif (Config.Inventory == "auto" and GetResourceState("qs-inventory") == "started") or Config.Inventory == "qs-inventory" then
exports["qs-inventory"]:RegisterStash(stashName, 50, 50000000)
elseif (Config.Inventory == "auto" and GetResourceState("codem-inventory") == "started") or Config.Inventory == "codem-inventory" then
TriggerServerEvent("codem-inventory:server:openstash", stashId, 15, 15000, stashName)
elseif (Config.Inventory == "auto" and GetResourceState("tgiann-inventory") == "started") or Config.Inventory == "tgiann-inventory" then
exports["tgiann-inventory"]:OpenInventory("stash", stashId, { maxweight = 50000, slots = 50 })
else
error("Error: Invalid inventory system set in config.")
end
end
---@param soundId integer|false
function Framework.Client.StopSound(soundId)
if not soundId or Config.DisableSound then return false end
if not soundId then return end
StopSound(soundId)
end