structura foldere
mutat kq- folders in un singur folder [kq]
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,27 @@
|
||||
# KQ_DYNO INSTALLATION GUIDE
|
||||
|
||||
This guide will provide step-by-step instructions on how to install and set up the KQ_DYNO script for FiveM.
|
||||
|
||||
## Step 1:
|
||||
After downloading the script, unzip the folder and place it in the `resources` directory on your FiveM server.
|
||||
|
||||
## Step 2:
|
||||
Open the `config.lua` file in the script folder and make sure that the correct framework is enabled.
|
||||
|
||||
## Step 3:
|
||||
After the config file has been set up, add the script to your `server.cfg` file. Make sure that it's added **after** your framework of choice, so that it loads and starts properly.
|
||||
|
||||
## Step 4:
|
||||
Configure your dyno locations in the `config.lua` file
|
||||
|
||||
## Done
|
||||
Enjoy the script
|
||||
|
||||
|
||||
## Extra info
|
||||
To restart the script. Use our custom `/kq_dyno_restart` command. Simply restarting or ensuring it will cause you to crash
|
||||
due to the custom props being unloaded from the memory.
|
||||
|
||||
https://kuzquality.com/
|
||||
|
||||
https://discord.gg/fZsyam7Rvz
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
-- Triggered when player starts a dyno run
|
||||
function OnDynoStart(dynoKey)
|
||||
|
||||
end
|
||||
|
||||
-- Triggered when the dyno run is fully finished
|
||||
function OnDynoFinish(dynoKey)
|
||||
|
||||
end
|
||||
@@ -0,0 +1,448 @@
|
||||
|
||||
function GetVehicleStats(veh)
|
||||
if not Config.dynoFormula then
|
||||
return GetVehicleStatsVanilla(veh)
|
||||
end
|
||||
|
||||
if Config.dynoFormula == 'highperformance1' then
|
||||
return GetVehicleStatsAlternative(veh)
|
||||
end
|
||||
|
||||
if Config.dynoFormula == 'highperformance2' then
|
||||
return GetVehicleStatsAlternative2(veh)
|
||||
end
|
||||
|
||||
if Config.dynoFormula == 'highperformance3' then
|
||||
return GetVehicleStatsAlternative3(veh)
|
||||
end
|
||||
|
||||
return GetVehicleStatsVanilla(veh)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function GetVehicleStatsVanilla(veh)
|
||||
return UseCache('vehStats' .. veh, function()
|
||||
local fInitialDriveForce = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveForce')
|
||||
local fDriveInertia = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveInertia')
|
||||
local fInitialDriveMaxFlatVel = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveMaxFlatVel')
|
||||
local fMass = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fMass')
|
||||
local nInitialDriveGears = GetVehicleHandlingFloat(veh, 'CHandlingData', 'nInitialDriveGears')
|
||||
|
||||
local fDriveBiasFront = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveBiasFront')
|
||||
|
||||
|
||||
local drivetrainLoss = 0.1 -- awd
|
||||
if fDriveBiasFront >= 0.85 then
|
||||
drivetrainLoss = 0.13 -- fwd
|
||||
end
|
||||
if fDriveBiasFront <= 0.15 then
|
||||
drivetrainLoss = 0.2 -- rwd
|
||||
end
|
||||
|
||||
local wheelPower = GetWheelPower(veh)
|
||||
|
||||
if IsVehicleFwd(veh) then
|
||||
wheelPower = wheelPower * fDriveBiasFront
|
||||
else
|
||||
wheelPower = wheelPower * (1 - fDriveBiasFront)
|
||||
end
|
||||
|
||||
local rpm = GetVehicleCurrentRpm(veh)
|
||||
|
||||
local maxRpm = ((math.min(161.0, fInitialDriveMaxFlatVel) / nInitialDriveGears / 30) * 8500) * 0.95
|
||||
local realRpm = math.floor(rpm * maxRpm)
|
||||
|
||||
local torque = math.floor((fInitialDriveForce * fMass) * (realRpm / maxRpm)
|
||||
+ (wheelPower * 40)
|
||||
* (math.min(4.0, math.max(0.7, (fMass / 1700) ^ 3)))
|
||||
)
|
||||
|
||||
local hpMultiplier = 0.95
|
||||
if fInitialDriveMaxFlatVel >= 150 then
|
||||
hpMultiplier = 1.0
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 159 then
|
||||
hpMultiplier = 1.1
|
||||
torque = math.floor(torque * 1.05)
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 159.5 then
|
||||
hpMultiplier = 1.15
|
||||
torque = math.floor(torque * 1.15)
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 164.0 then
|
||||
hpMultiplier = 1.05
|
||||
torque = math.floor(torque * 1.1)
|
||||
end
|
||||
|
||||
local hp = math.abs(math.floor(DiminishingReturns(
|
||||
((torque / 1.356) * (rpm * maxRpm) / 5252)
|
||||
* fDriveInertia
|
||||
* (math.min(160.0, fInitialDriveMaxFlatVel) / 150)
|
||||
* wheelPower
|
||||
* (1 - drivetrainLoss)
|
||||
* hpMultiplier
|
||||
* (math.min(2.0, math.max(0.95, fMass / 1400)))
|
||||
)))
|
||||
|
||||
local torqueInUnits = torque
|
||||
|
||||
if UsingFtLbs() then
|
||||
torqueInUnits = torque / 1.356
|
||||
end
|
||||
|
||||
return hp, torqueInUnits, realRpm, rpm
|
||||
end, 50)
|
||||
end
|
||||
|
||||
|
||||
function GetVehicleStatsAlternative(veh)
|
||||
return UseCache('vehStats' .. veh, function()
|
||||
local fInitialDriveForce = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveForce')
|
||||
local fDriveInertia = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveInertia')
|
||||
local fInitialDriveMaxFlatVel = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveMaxFlatVel')
|
||||
local fMass = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fMass')
|
||||
local nInitialDriveGears = GetVehicleHandlingFloat(veh, 'CHandlingData', 'nInitialDriveGears')
|
||||
|
||||
local fDriveBiasFront = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveBiasFront')
|
||||
|
||||
|
||||
local drivetrainLoss = 0.1 -- awd
|
||||
if fDriveBiasFront >= 0.85 then
|
||||
drivetrainLoss = 0.13 -- fwd
|
||||
end
|
||||
if fDriveBiasFront <= 0.15 then
|
||||
drivetrainLoss = 0.2 -- rwd
|
||||
end
|
||||
|
||||
local wheelPower = GetWheelPower(veh)
|
||||
|
||||
if IsVehicleFwd(veh) then
|
||||
wheelPower = wheelPower * fDriveBiasFront
|
||||
else
|
||||
wheelPower = wheelPower * (1 - fDriveBiasFront)
|
||||
end
|
||||
|
||||
local rpm = GetVehicleCurrentRpm(veh)
|
||||
|
||||
local maxRpm = ((math.min(161.0, fInitialDriveMaxFlatVel) / nInitialDriveGears / 30) * 8500) * 0.95
|
||||
local realRpm = math.floor(rpm * maxRpm)
|
||||
|
||||
local torque = math.floor((fInitialDriveForce * fMass) * (realRpm / maxRpm)
|
||||
+ (wheelPower * 40)
|
||||
* (math.min(4.0, math.max(0.7, (fMass / 1700) ^ 3)))
|
||||
)
|
||||
|
||||
local hpMultiplier = 0.95
|
||||
if fInitialDriveMaxFlatVel >= 150 then
|
||||
hpMultiplier = 1.0
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 159 then
|
||||
hpMultiplier = 1.1
|
||||
torque = math.floor(torque * 1.05)
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 159.5 then
|
||||
hpMultiplier = 1.15
|
||||
torque = math.floor(torque * 1.15)
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 164.0 then
|
||||
hpMultiplier = 1.05
|
||||
torque = math.floor(torque * 1.1)
|
||||
end
|
||||
|
||||
local hp = math.abs(math.floor(DiminishingReturns(
|
||||
((torque / 1.356) * (rpm * maxRpm) / 5252)
|
||||
* fDriveInertia
|
||||
* math.min(1.1, wheelPower)
|
||||
* (1 - drivetrainLoss)
|
||||
* hpMultiplier
|
||||
* (math.min(2.0, math.max(0.95, fMass / 1400)))
|
||||
)))
|
||||
|
||||
local torqueInUnits = torque
|
||||
|
||||
if UsingFtLbs() then
|
||||
torqueInUnits = torque / 1.356
|
||||
end
|
||||
|
||||
return hp, torqueInUnits, realRpm, rpm
|
||||
end, 50)
|
||||
end
|
||||
|
||||
function GetVehicleStatsAlternative2(veh)
|
||||
return UseCache('vehStats' .. veh, function()
|
||||
local fInitialDriveForce = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveForce')
|
||||
local fDriveInertia = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveInertia')
|
||||
local fInitialDriveMaxFlatVel = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveMaxFlatVel')
|
||||
local fMass = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fMass')
|
||||
local nInitialDriveGears = GetVehicleHandlingFloat(veh, 'CHandlingData', 'nInitialDriveGears')
|
||||
|
||||
local fDriveBiasFront = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveBiasFront')
|
||||
|
||||
|
||||
local drivetrainLoss = 0.1 -- awd
|
||||
if fDriveBiasFront >= 0.85 then
|
||||
drivetrainLoss = 0.13 -- fwd
|
||||
end
|
||||
if fDriveBiasFront <= 0.15 then
|
||||
drivetrainLoss = 0.2 -- rwd
|
||||
end
|
||||
|
||||
local wheelPower = GetWheelPower(veh)
|
||||
|
||||
if IsVehicleFwd(veh) then
|
||||
wheelPower = wheelPower * fDriveBiasFront
|
||||
else
|
||||
wheelPower = wheelPower * (1 - fDriveBiasFront)
|
||||
end
|
||||
|
||||
local rpm = GetVehicleCurrentRpm(veh)
|
||||
|
||||
local maxRpm = ((math.min(161.0, fInitialDriveMaxFlatVel) / nInitialDriveGears / 30) * 8500) * 0.95
|
||||
local realRpm = math.floor(rpm * maxRpm)
|
||||
|
||||
local torque = math.floor(((fInitialDriveForce * 0.5) * fMass) * (realRpm / maxRpm)
|
||||
+ (math.min(3.0, wheelPower))
|
||||
* (math.min(4.0, math.max(0.7, (fMass / 1700) ^ 3)))
|
||||
)
|
||||
|
||||
local hpMultiplier = 0.95
|
||||
if fInitialDriveMaxFlatVel >= 150 then
|
||||
hpMultiplier = 1.0
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 159 then
|
||||
hpMultiplier = 1.1
|
||||
torque = math.floor(torque * 1.05)
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 159.5 then
|
||||
hpMultiplier = 1.15
|
||||
torque = math.floor(torque * 1.15)
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 164.0 then
|
||||
hpMultiplier = 1.05
|
||||
torque = math.floor(torque * 1.1)
|
||||
end
|
||||
|
||||
local hp = math.abs(math.floor(DiminishingReturns(
|
||||
((torque / 1.356) * (rpm * maxRpm) / 5252)
|
||||
* fDriveInertia
|
||||
* (math.min(160.0, fInitialDriveMaxFlatVel) / 250)
|
||||
* math.min(2.0, wheelPower)
|
||||
* (1 - drivetrainLoss)
|
||||
* hpMultiplier
|
||||
* (math.min(2.0, math.max(0.95, fMass / 1400)))
|
||||
)))
|
||||
|
||||
local torqueInUnits = torque
|
||||
|
||||
if UsingFtLbs() then
|
||||
torqueInUnits = torque / 1.356
|
||||
end
|
||||
|
||||
return hp, torqueInUnits, realRpm, rpm
|
||||
end, 50)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function GetVehicleStatsAlternative3(veh)
|
||||
return UseCache('vehStats' .. veh, function()
|
||||
local fInitialDriveForce = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveForce')
|
||||
local fDriveInertia = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveInertia')
|
||||
local fInitialDriveMaxFlatVel = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fInitialDriveMaxFlatVel')
|
||||
local fMass = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fMass')
|
||||
local nInitialDriveGears = GetVehicleHandlingFloat(veh, 'CHandlingData', 'nInitialDriveGears')
|
||||
|
||||
local fDriveBiasFront = GetVehicleHandlingFloat(veh, 'CHandlingData', 'fDriveBiasFront')
|
||||
|
||||
|
||||
local drivetrainLoss = 0.1 -- awd
|
||||
if fDriveBiasFront >= 0.85 then
|
||||
drivetrainLoss = 0.13 -- fwd
|
||||
end
|
||||
if fDriveBiasFront <= 0.15 then
|
||||
drivetrainLoss = 0.2 -- rwd
|
||||
end
|
||||
|
||||
local wheelPower = GetWheelPower(veh)
|
||||
|
||||
if IsVehicleFwd(veh) then
|
||||
wheelPower = wheelPower * fDriveBiasFront
|
||||
else
|
||||
wheelPower = wheelPower * (1 - fDriveBiasFront)
|
||||
end
|
||||
|
||||
local rpm = GetVehicleCurrentRpm(veh)
|
||||
|
||||
local maxRpm = ((math.min(161.0, fInitialDriveMaxFlatVel) / nInitialDriveGears / 35) * 8500) * 0.95
|
||||
local realRpm = math.floor(rpm * maxRpm)
|
||||
|
||||
local torque = math.floor(((fInitialDriveForce * 0.4) * fMass) * (realRpm / maxRpm)
|
||||
+ (math.min(2.0, wheelPower / 2))
|
||||
* (math.min(4.0, math.max(0.7, (fMass / 1700) ^ 3)))
|
||||
)
|
||||
|
||||
local hpMultiplier = 0.95
|
||||
if fInitialDriveMaxFlatVel >= 150 then
|
||||
hpMultiplier = 1.0
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 159 then
|
||||
hpMultiplier = 1.1
|
||||
torque = math.floor(torque * 1.05)
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 159.5 then
|
||||
hpMultiplier = 1.15
|
||||
torque = math.floor(torque * 1.15)
|
||||
end
|
||||
if fInitialDriveMaxFlatVel >= 164.0 then
|
||||
hpMultiplier = 1.05
|
||||
torque = math.floor(torque * 1.1)
|
||||
end
|
||||
|
||||
local hp = math.abs(math.floor(DiminishingReturns(
|
||||
((torque / 1.356) * (rpm * maxRpm) / 5252)
|
||||
* fDriveInertia
|
||||
* math.min(2.0, wheelPower / 2)
|
||||
* (1 - drivetrainLoss)
|
||||
* hpMultiplier
|
||||
* (math.min(2.0, math.max(0.95, fMass / 1400)))
|
||||
)))
|
||||
|
||||
local torqueInUnits = torque
|
||||
|
||||
if UsingFtLbs() then
|
||||
torqueInUnits = torque / 1.356
|
||||
end
|
||||
|
||||
return hp, torqueInUnits, realRpm, rpm
|
||||
end, 50)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function GetWheelPower(veh)
|
||||
local power = 0
|
||||
for i = 0 , GetVehicleNumberOfWheels(veh) - 1 do
|
||||
power = power + GetVehicleWheelPower(veh, i) * (GetVehicleWheelTireColliderSize(veh, i) * 2 + 0.15)
|
||||
end
|
||||
return power
|
||||
end
|
||||
|
||||
function DiminishingReturns(x)
|
||||
return x * (1 - (math.min(0.3, (x + 100) / 2400) - 0.05))
|
||||
end
|
||||
|
||||
|
||||
function UsingFtLbs()
|
||||
return Config.torqueUnits == 'lb-ft' or Config.torqueUnits == 'lbs' or Config.torqueUnits == 'ft-lb'
|
||||
end
|
||||
|
||||
function GetTorqueUnit()
|
||||
if UsingFtLbs() then
|
||||
return L('lb-ft')
|
||||
end
|
||||
return L('nm')
|
||||
end
|
||||
|
||||
function IsPlayerUnreachable()
|
||||
local playerPed = PlayerPedId()
|
||||
return IsPedRagdoll(playerPed) or IsEntityDead(playerPed)
|
||||
end
|
||||
|
||||
|
||||
function KeybindTip(message)
|
||||
SetTextComponentFormat("STRING")
|
||||
AddTextComponentString(message)
|
||||
EndTextCommandDisplayHelp(0, 0, 0, 200)
|
||||
end
|
||||
|
||||
-- This function is responsible for all the tooltips displayed on top right of the screen, you could
|
||||
-- replace it with a custom notification etc.
|
||||
function Notify(message)
|
||||
SetTextComponentFormat("STRING")
|
||||
AddTextComponentString(message)
|
||||
EndTextCommandDisplayHelp(0, 0, 0, -1)
|
||||
end
|
||||
|
||||
RegisterNetEvent('kq_dyno:client:notify')
|
||||
AddEventHandler('kq_dyno:client:notify', function(message)
|
||||
Notify(message)
|
||||
end)
|
||||
|
||||
function PlayAnim(dict, anim, flag, duration)
|
||||
Citizen.CreateThread(function()
|
||||
RequestAnimDict(dict)
|
||||
local timeout = 0
|
||||
while not HasAnimDictLoaded(dict) do
|
||||
Citizen.Wait(50)
|
||||
timeout = timeout + 1
|
||||
if timeout > 100 then
|
||||
return
|
||||
end
|
||||
end
|
||||
TaskPlayAnim(PlayerPedId(), dict, anim, 1.5, 1.0, duration or -1, flag or 1, 0, false, false, false)
|
||||
RemoveAnimDict(dict)
|
||||
end)
|
||||
end
|
||||
|
||||
function DrawDynoMarker(dyno)
|
||||
DrawMarker(43, dyno.coords + vector3(0.0, 0.0, -1.0), 0.0, 0.0, 0.0, 0.0, 0.0, dyno.heading, 2.5, 1.0, 0.5, 40, 110, 250, 30, 0, 0, 0, 0)
|
||||
end
|
||||
|
||||
function CanPerformDynoTests(dynoKey)
|
||||
return UseCache('CanPerformDynoTests' .. dynoKey, function()
|
||||
local dyno = Config.dynos[dynoKey]
|
||||
|
||||
return (not Config.jobWhitelist.enabled or (not PLAYER_JOB or not dyno.jobs or Contains(dyno.jobs, PLAYER_JOB)))
|
||||
end, 5000)
|
||||
end
|
||||
|
||||
-- Keybinds display
|
||||
buttons = nil
|
||||
keybinds = {}
|
||||
|
||||
function AddKeybindDisplay(key, label)
|
||||
buttons = nil
|
||||
|
||||
table.insert(keybinds, {
|
||||
key = '~' .. key .. '~',
|
||||
label = label,
|
||||
})
|
||||
|
||||
buttons = RequestScaleformMovie("INSTRUCTIONAL_BUTTONS")
|
||||
while not HasScaleformMovieLoaded(buttons) do
|
||||
Wait(0)
|
||||
end
|
||||
|
||||
BeginScaleformMovieMethod(buttons, "CLEAR_ALL")
|
||||
EndScaleformMovieMethod()
|
||||
|
||||
for k, keybind in pairs(keybinds) do
|
||||
BeginScaleformMovieMethod(buttons, "SET_DATA_SLOT")
|
||||
ScaleformMovieMethodAddParamInt(k - 1)
|
||||
ScaleformMovieMethodAddParamPlayerNameString(keybind.key)
|
||||
PushScaleformMovieMethodParameterString(keybind.label)
|
||||
EndScaleformMovieMethod()
|
||||
end
|
||||
|
||||
BeginScaleformMovieMethod(buttons, "DRAW_INSTRUCTIONAL_BUTTONS")
|
||||
EndScaleformMovieMethod()
|
||||
end
|
||||
|
||||
function ClearKeybinds()
|
||||
buttons = nil
|
||||
keybinds = {}
|
||||
end
|
||||
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
local sleep = 500
|
||||
|
||||
if buttons ~= nil then
|
||||
sleep = 1
|
||||
DrawScaleformMovieFullscreen(buttons, 255, 255, 255, 255, 0)
|
||||
end
|
||||
Citizen.Wait(sleep)
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,31 @@
|
||||
if Config.esxSettings.enabled then
|
||||
ESX = nil
|
||||
|
||||
if Config.esxSettings.useNewESXExport then
|
||||
ESX = exports['es_extended']:getSharedObject()
|
||||
else
|
||||
Citizen.CreateThread(function()
|
||||
while ESX == nil do
|
||||
TriggerEvent('esx:getSharedObject', function(obj)
|
||||
ESX = obj
|
||||
end)
|
||||
Citizen.Wait(0)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
while ESX == nil or ESX.GetPlayerData().job == nil do
|
||||
Citizen.Wait(10)
|
||||
end
|
||||
|
||||
ESX.PlayerData = ESX.GetPlayerData()
|
||||
PLAYER_JOB = ESX.PlayerData.job.name
|
||||
end)
|
||||
|
||||
RegisterNetEvent('esx:setJob')
|
||||
AddEventHandler('esx:setJob', function(job)
|
||||
ESX.PlayerData.job = job
|
||||
PLAYER_JOB = job.name
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
if Config.qbSettings.enabled then
|
||||
QBCore = exports['qb-core']:GetCoreObject()
|
||||
|
||||
if QBCore.Functions.GetPlayerData() and QBCore.Functions.GetPlayerData().job then
|
||||
PLAYER_JOB = QBCore.Functions.GetPlayerData().job.name
|
||||
end
|
||||
|
||||
RegisterNetEvent('QBCore:Client:OnPlayerLoaded')
|
||||
AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
|
||||
PLAYER_JOB = QBCore.Functions.GetPlayerData().job.name
|
||||
end)
|
||||
|
||||
|
||||
RegisterNetEvent('QBCore:Client:OnJobUpdate')
|
||||
AddEventHandler('QBCore:Client:OnJobUpdate', function(JobInfo)
|
||||
PLAYER_JOB = JobInfo.name
|
||||
end)
|
||||
end
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,315 @@
|
||||
Config = {}
|
||||
|
||||
Config.debug = false
|
||||
|
||||
--- If you're testing the script and editing the values DO NOT simply restart the script. As this script is using custom models (dynos)
|
||||
--- it will crash if you just restart it. Instead use the `/kq_dyno_restart` command. It will safely restart the script without causing you to crash
|
||||
|
||||
|
||||
--- SETTINGS FOR ESX
|
||||
Config.esxSettings = {
|
||||
enabled = false,
|
||||
-- Whether or not to use the new ESX export method
|
||||
useNewESXExport = true,
|
||||
}
|
||||
|
||||
--- SETTINGS FOR QBCORE
|
||||
Config.qbSettings = {
|
||||
enabled = true,
|
||||
}
|
||||
|
||||
|
||||
--- BASIC
|
||||
|
||||
-- Torque units | 'nm' or 'lb-ft'
|
||||
Config.torqueUnits = 'nm'
|
||||
|
||||
|
||||
--- Horsepower and torque calculation formula
|
||||
-- If you're not using vanilla or vanilla-like handling:
|
||||
-- Try out different formulas and see what works best for your server.
|
||||
|
||||
-- 'vanilla' = Perfect setup for vanilla handling as well as handling files obeying the principles of vanilla GTA
|
||||
|
||||
-- 'highperformance1' = Good for servers using handling files which result in faster vehicles
|
||||
-- 'highperformance2' = Good for servers using handling files which result in faster vehicles (extra)
|
||||
-- 'highperformance3' = Good for servers using handling files which result in faster vehicles (extra)
|
||||
---------------------------------------------
|
||||
Config.dynoFormula = 'vanilla'
|
||||
|
||||
|
||||
|
||||
--- FRAMEWORK OPTIONS (MAKE SURE TO ENABLE YOUR FRAMEWORK IF USING ONE) <!>
|
||||
Config.jobWhitelist = {
|
||||
enabled = true,
|
||||
-- To configure the jobs, set them on each dyno individually
|
||||
}
|
||||
|
||||
|
||||
-- Time it takes for the screens to turn off after a dyno run (in seconds)
|
||||
Config.screenTimeout = 30
|
||||
|
||||
-- Whether to display the dyno sheet on the screen as UI
|
||||
Config.displaySheetOnScreen = true
|
||||
|
||||
-- Determines the location of the dyno sheet
|
||||
Config.screenSheetOffset = {
|
||||
x = 0.84,
|
||||
y = 0.833,
|
||||
}
|
||||
|
||||
-- Dynos setup
|
||||
-- coords = vector3 of the dyno location
|
||||
-- heading = heading of the dyno
|
||||
-- model = model defined in Config.dynoModels (By leaving this out, you will create a dyno without a model. Useful for MLOs with built-in dynos)
|
||||
-- displays = table of displays
|
||||
-- displayCoords = vector3 of the display location
|
||||
-- displayTilt = angle of the display tilt,
|
||||
-- displayHeading = heading of the display
|
||||
-- displayType = display defined in Config.displayTypes
|
||||
-- jobs = Table of jobs which are allowed to use the dyno (false or nil to allow everyone to use it)
|
||||
Config.dynos = {
|
||||
['bennys'] = {
|
||||
coords = vector3(-214.28, -1318.14, 30.9),
|
||||
heading = 180.0,
|
||||
|
||||
model = 'default_purple',
|
||||
|
||||
displays = {
|
||||
{
|
||||
displayCoords = vector3(-217.4, -1318.92, 32.55),
|
||||
displayHeading = 90.0,
|
||||
displayTilt = 3.0,
|
||||
displayType = 'wall_tv_2',
|
||||
},
|
||||
{
|
||||
displayCoords = vector3(-211.5, -1320.6, 30.89),
|
||||
displayHeading = 250.0,
|
||||
displayType = 'stand',
|
||||
}
|
||||
},
|
||||
|
||||
jobs = { 'mechanic' },
|
||||
},
|
||||
['lsc_harmony'] = {
|
||||
coords = vector3(1182.66, 2636.5, 37.78),
|
||||
heading = 0.0,
|
||||
|
||||
model = 'default_blue',
|
||||
|
||||
displays = {
|
||||
{
|
||||
displayCoords = vector3(1182.66, 2634.6, 39.3),
|
||||
displayHeading = 180.0,
|
||||
displayType = 'wall_tv',
|
||||
},
|
||||
},
|
||||
|
||||
jobs = { 'mechanic' },
|
||||
},
|
||||
['lsc_airport'] = {
|
||||
coords = vector3(-1164.45, -2018.8, 13.18),
|
||||
heading = 315.0,
|
||||
|
||||
model = 'default_red',
|
||||
|
||||
displays = {
|
||||
{
|
||||
displayCoords = vector3(-1164.3, -2014.53, 14.13),
|
||||
displayHeading = 45.0,
|
||||
displayType = 'wall_tv',
|
||||
},
|
||||
},
|
||||
|
||||
jobs = { 'mechanic' },
|
||||
},
|
||||
['import_export_garage'] = {
|
||||
coords = vector3(980.2, -3002.11, -39.65),
|
||||
heading = 90.0,
|
||||
|
||||
model = 'default_blue',
|
||||
|
||||
displays = {
|
||||
{
|
||||
displayCoords = vector3(978.5, -2999.35, -39.62),
|
||||
displayHeading = 0.0,
|
||||
displayType = 'stand',
|
||||
},
|
||||
},
|
||||
|
||||
jobs = { 'mechanic' },
|
||||
},
|
||||
--['no_model_liberty_walk_mlo'] = {
|
||||
-- coords = vector3(1148.40, -792.69, 57.5),
|
||||
-- heading = 90.0,
|
||||
--
|
||||
-- displays = {
|
||||
-- {
|
||||
-- displayCoords = vector3(1148.29, -795.0, 58.35),
|
||||
-- displayHeading = 190.0,
|
||||
-- displayType = 'monitor',
|
||||
-- },
|
||||
-- },
|
||||
--
|
||||
-- jobs = nil,
|
||||
--},
|
||||
}
|
||||
|
||||
|
||||
-- This is just used to fill the default dynos with their rollers
|
||||
Config.baseRollers = {
|
||||
{
|
||||
prop = 'kq_dyno_roller',
|
||||
rotation = vector3(0.0, 90.0, 0.0),
|
||||
offset = vector3(0.18, 0.6, -0.08),
|
||||
direction = -1,
|
||||
side = 1,
|
||||
},
|
||||
{
|
||||
prop = 'kq_dyno_roller',
|
||||
rotation = vector3(0.0, 90.0, 0.0),
|
||||
offset = vector3(-0.18, 0.6, -0.08),
|
||||
direction = -1,
|
||||
side = 1,
|
||||
},
|
||||
|
||||
{
|
||||
prop = 'kq_dyno_roller',
|
||||
rotation = vector3(0.0, 90.0, 0.0),
|
||||
offset = vector3(0.18, -1.18, -0.08),
|
||||
direction = -1,
|
||||
side = 2,
|
||||
},
|
||||
{
|
||||
prop = 'kq_dyno_roller',
|
||||
rotation = vector3(0.0, 90.0, 0.0),
|
||||
offset = vector3(-0.18, -1.18, -0.08),
|
||||
direction = -1,
|
||||
side = 2,
|
||||
},
|
||||
}
|
||||
|
||||
-- Dyno models
|
||||
Config.dynoModels = {
|
||||
['default_yellow'] = {
|
||||
base = 'kq_dyno2_yellow',
|
||||
textureVariation = 0,
|
||||
heading = -90.0,
|
||||
offset = vector3(0.0, 0.0, -0.04),
|
||||
rollers = Config.baseRollers,
|
||||
},
|
||||
['default_red'] = {
|
||||
base = 'kq_dyno2_red',
|
||||
textureVariation = 0,
|
||||
heading = -90.0,
|
||||
offset = vector3(0.0, 0.0, -0.04),
|
||||
rollers = Config.baseRollers,
|
||||
},
|
||||
['default_purple'] = {
|
||||
base = 'kq_dyno2_purple',
|
||||
textureVariation = 0,
|
||||
heading = -90.0,
|
||||
offset = vector3(0.0, 0.0, -0.04),
|
||||
rollers = Config.baseRollers,
|
||||
},
|
||||
['default_green'] = {
|
||||
base = 'kq_dyno2_green',
|
||||
textureVariation = 0,
|
||||
heading = -90.0,
|
||||
offset = vector3(0.0, 0.0, -0.04),
|
||||
rollers = Config.baseRollers,
|
||||
},
|
||||
['default_gray'] = {
|
||||
base = 'kq_dyno2_gray',
|
||||
textureVariation = 0,
|
||||
heading = -90.0,
|
||||
offset = vector3(0.0, 0.0, -0.04),
|
||||
rollers = Config.baseRollers,
|
||||
},
|
||||
['default_blue'] = {
|
||||
base = 'kq_dyno2_blue',
|
||||
textureVariation = 0,
|
||||
heading = -90.0,
|
||||
offset = vector3(0.0, 0.0, -0.04),
|
||||
rollers = Config.baseRollers,
|
||||
},
|
||||
['basic'] = {
|
||||
base = 'kq_dyno',
|
||||
textureVariation = 0,
|
||||
heading = -90.0,
|
||||
offset = vector3(0.0, 0.0, 0.0),
|
||||
rollers = {
|
||||
{
|
||||
prop = 'kq_dyno_roller',
|
||||
rotation = vector3(0.0, 90.0, 0.0),
|
||||
offset = vector3(0.18, 0.9, -0.08),
|
||||
direction = -1,
|
||||
side = 1,
|
||||
},
|
||||
{
|
||||
prop = 'kq_dyno_roller',
|
||||
rotation = vector3(0.0, 90.0, 0.0),
|
||||
offset = vector3(-0.18, 0.9, -0.08),
|
||||
direction = -1,
|
||||
side = 1,
|
||||
},
|
||||
|
||||
{
|
||||
prop = 'kq_dyno_roller',
|
||||
rotation = vector3(0.0, 90.0, 0.0),
|
||||
offset = vector3(0.18, -0.9, -0.08),
|
||||
direction = -1,
|
||||
side = 2,
|
||||
},
|
||||
{
|
||||
prop = 'kq_dyno_roller',
|
||||
rotation = vector3(0.0, 90.0, 0.0),
|
||||
offset = vector3(-0.18, -0.9, -0.08),
|
||||
direction = -1,
|
||||
side = 2,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
-- Display types
|
||||
-- prop = prop of the display
|
||||
-- offset = offset of the display (texture, not the prop)
|
||||
-- heading = heading of the display (texture, not the prop)
|
||||
-- size = size of the display
|
||||
Config.displayTypes = {
|
||||
['stand'] = {
|
||||
prop = 'prop_cs_tv_stand',
|
||||
offset = vector3(0.529, -0.08, 1.01),
|
||||
heading = 180.0,
|
||||
size = vector2(1.098, 0.54),
|
||||
},
|
||||
['monitor'] = {
|
||||
prop = 'prop_tv_flat_03',
|
||||
offset = vector3(0.35, -0.01, 0.025),
|
||||
heading = 180.0,
|
||||
size = vector2(0.7, 0.4),
|
||||
},
|
||||
['wall_tv'] = {
|
||||
prop = 'prop_tv_flat_01',
|
||||
offset = vector3(1.07, -0.06, -0.12),
|
||||
heading = 180.0,
|
||||
size = vector2(2.14, 1.2),
|
||||
},
|
||||
['wall_tv_2'] = {
|
||||
prop = 'xm_prop_x17_tv_flat_01',
|
||||
offset = vector3(0.798, -0.046, 0.152),
|
||||
heading = 180.0,
|
||||
size = vector2(1.5, 0.832),
|
||||
},
|
||||
}
|
||||
|
||||
-- https://docs.fivem.net/docs/game-references/controls/
|
||||
-- Use the input index for the "input" value
|
||||
Config.keybinds = {
|
||||
start = {
|
||||
label = 'E',
|
||||
name = 'INPUT_PICKUP',
|
||||
input = 38,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
-- Discord webhook options
|
||||
Config.webhook = {
|
||||
enabled = false, -- Whether to send the dyno sheets to the discord webhook
|
||||
|
||||
-- To get the Discord webhook link, right click on a channel > Edit channel > Integrations > Webhooks > View webhooks > New webhook
|
||||
url = 'YOUR_WEBHOOK_URL_HERE',
|
||||
|
||||
-- Here you can add webhooks for specific dynos. Based on the dyno key/index name (same as in config.lua)
|
||||
dynoSpecific = {
|
||||
['bennys'] = 'DYNO_SPECIFIC_WEBHOOK_URL_HERE', -- remove this line if you don't want to use a dyno specific webhooks
|
||||
},
|
||||
|
||||
-- Replace this with the name of your server or a title you want on your dyno sheets
|
||||
title = 'Red Valley - DynoTech',
|
||||
|
||||
-- Whether to include certain parts of the users info in the webhook messages
|
||||
includeUserName = true,
|
||||
includeSteamId = true,
|
||||
|
||||
color = 16723456,
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
fx_version 'cerulean'
|
||||
games { 'gta5' }
|
||||
lua54 'yes'
|
||||
|
||||
author 'KuzQuality | Kuzkay'
|
||||
description 'Car dyno by KuzQuality'
|
||||
version '1.4.0'
|
||||
|
||||
ui_page 'html/blank.html'
|
||||
|
||||
data_file 'DLC_ITYP_REQUEST' 'stream/kq_dyno_props.ytyp'
|
||||
|
||||
files {
|
||||
'html/js/jquery.js',
|
||||
'html/js/chart.js',
|
||||
'html/js/chartjs-annotation.js',
|
||||
'html/js/html2canvas.js',
|
||||
'html/blank.html',
|
||||
'html/index.html',
|
||||
}
|
||||
--
|
||||
-- Server
|
||||
--
|
||||
|
||||
server_scripts {
|
||||
'config.lua',
|
||||
'config_server.lua',
|
||||
'locale.lua',
|
||||
'server/server.lua',
|
||||
'server/editable/editable.lua',
|
||||
}
|
||||
|
||||
--
|
||||
-- Client
|
||||
--
|
||||
|
||||
client_scripts {
|
||||
'config.lua',
|
||||
'locale.lua',
|
||||
'client/editable/api.lua',
|
||||
'client/functions.lua',
|
||||
'client/cache.lua',
|
||||
'client/client.lua',
|
||||
'client/spawning.lua',
|
||||
'client/display.lua',
|
||||
'client/editable/client.lua',
|
||||
'client/editable/esx.lua',
|
||||
'client/editable/qb.lua',
|
||||
}
|
||||
|
||||
escrow_ignore {
|
||||
'config.lua',
|
||||
'config_server.lua',
|
||||
'locale.lua',
|
||||
'client/editable/*.lua',
|
||||
'server/editable/*.lua',
|
||||
}
|
||||
|
||||
dependency '/assetpacks'
|
||||
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<body style="background-color: transparent;">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,228 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="js/jquery.js"></script>
|
||||
<script src="js/chart.js"></script>
|
||||
<script src="js/chartjs-annotation.js"></script>
|
||||
<script src="js/html2canvas.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="chart">
|
||||
<canvas id="chart"></canvas>
|
||||
<span class="watermark">Dyno Technology by KuzQuality.com</span>
|
||||
<span class="title" id="title"></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(() => {
|
||||
let times = [];
|
||||
|
||||
let localeSet = false;
|
||||
let title = '';
|
||||
let peakHp = 'Peak HP';
|
||||
let peakTorque = 'Peak Torque';
|
||||
let torqueUnit = 'nm';
|
||||
|
||||
window.addEventListener('message', ({data}) => {
|
||||
if (data.event === 'update') {
|
||||
if (times.length > 600) {
|
||||
times.shift();
|
||||
}
|
||||
times.push({
|
||||
rpm: event.data.rpm,
|
||||
hp: event.data.hp,
|
||||
torque: event.data.torque,
|
||||
});
|
||||
|
||||
setChart();
|
||||
|
||||
if (!localeSet) {
|
||||
setLocale(data);
|
||||
}
|
||||
}
|
||||
if (data.event === 'capture-image') {
|
||||
captureImage(data.dynoKey);
|
||||
}
|
||||
});
|
||||
|
||||
function setLocale(data) {
|
||||
localeSet = true;
|
||||
|
||||
title = data.title;
|
||||
peakHp = data.peakHp;
|
||||
peakTorque = data.peakTorque;
|
||||
torqueUnit = data.torqueUnit;
|
||||
$('#title').html(title);
|
||||
}
|
||||
|
||||
function captureImage(dynoKey) {
|
||||
$('.chart').addClass('screenshot');
|
||||
$('.watermark').addClass('screenshot');
|
||||
$('.title').addClass('screenshot');
|
||||
html2canvas(document.querySelector(".chart")).then(canvas => {
|
||||
const base64 = canvas.toDataURL();
|
||||
fetch(`https://kq_dyno/SaveDynoImage`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({img: base64, dynoKey}),
|
||||
});
|
||||
|
||||
$('.chart').removeClass('screenshot');
|
||||
$('.watermark').removeClass('screenshot');
|
||||
$('.title').removeClass('screenshot');
|
||||
});
|
||||
}
|
||||
|
||||
function setChart() {
|
||||
const chart = Chart.getChart("chart");
|
||||
|
||||
// If the chart exists, destroy it
|
||||
if (chart) {
|
||||
chart.destroy();
|
||||
}
|
||||
|
||||
const xValues = times.map(({ rpm, hp, torque }) => rpm);
|
||||
const hpValues = times.map(({ rpm, hp, torque }) => parseInt(hp));
|
||||
const torqueValues = times.map(({ rpm, hp, torque }) => parseInt(torque));
|
||||
|
||||
const ctx = document.getElementById('chart').getContext('2d');
|
||||
|
||||
Chart.defaults.font.size = 33;
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: xValues,
|
||||
datasets: [
|
||||
{
|
||||
data: hpValues,
|
||||
label: 'Horsepower',
|
||||
borderColor: 'red',
|
||||
fill: false
|
||||
},
|
||||
{
|
||||
data: torqueValues,
|
||||
label: 'Torque',
|
||||
borderColor: 'blue',
|
||||
fill: false
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
animation: false,
|
||||
elements: {
|
||||
point: {
|
||||
radius: 1
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
display: true,
|
||||
min: 0,
|
||||
max: Math.ceil(Math.max(Math.max(...torqueValues), Math.max(...hpValues)) * 1.1),
|
||||
gridLines: {
|
||||
color: 'rgba(255,255,255,0.3)'
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'category',
|
||||
title: 'RPM',
|
||||
display: true,
|
||||
clip: true,
|
||||
ticks: {
|
||||
stepSize: 500, // Set the step size to 500
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
annotation: {
|
||||
annotations: [
|
||||
{
|
||||
type: 'line',
|
||||
mode: 'horizontal',
|
||||
scaleID: 'y',
|
||||
value: Math.max(...hpValues), // Set the value to where you want the line
|
||||
borderColor: 'red', // Color of the line
|
||||
borderWidth: 2, // Width of the line
|
||||
borderDash: [20],
|
||||
label: {
|
||||
display: true,
|
||||
content: peakHp + ' ' + Math.max(...hpValues), // Set the label content
|
||||
enabled: true, // Show the label
|
||||
position: '45%', // Position of the label ('start', 'center', or 'end')
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'line',
|
||||
mode: 'horizontal',
|
||||
scaleID: 'y',
|
||||
value: Math.max(...torqueValues), // Set the value to where you want the line
|
||||
borderColor: 'blue', // Color of the line
|
||||
borderWidth: 2, // Width of the line
|
||||
borderDash: [20],
|
||||
label: {
|
||||
display: true,
|
||||
content: peakTorque + ' ' + Math.max(...torqueValues) + ' ' + torqueUnit, // Set the label content
|
||||
enabled: true, // Show the label
|
||||
position: '15%', // Position of the label ('start', 'center', or 'end')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html {
|
||||
background-color: rgb(240, 240, 240);
|
||||
}
|
||||
|
||||
.chart {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.chart.screenshot {
|
||||
padding-top: 600px;
|
||||
height: 1280px;
|
||||
width: 1280px;
|
||||
}
|
||||
|
||||
.watermark.screenshot {
|
||||
bottom: -550px !important;
|
||||
}
|
||||
|
||||
.watermark {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
font-size: 22px;
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-family: Tahoma, sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: rgba(148, 19, 19, 1);
|
||||
font-size: 30px;
|
||||
position: absolute;
|
||||
bottom: 45px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-family: Tahoma, sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.title.screenshot {
|
||||
bottom: 130px !important;
|
||||
font-size: 64px !important;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
|
||||
Locale = {
|
||||
['lb-ft'] = 'lb-ft',
|
||||
['nm'] = 'nm',
|
||||
['Press ~{INPUT}~ to start the dyno test'] = 'Apasa ~{INPUT}~ pentru a incepe testul dyno',
|
||||
['~r~This vehicle is FWD biased. Turn it around'] = '~r~Acest vehicul este cu tractiune fata. Intoarce-l',
|
||||
['~r~This vehicle is RWD biased. Turn it around'] = '~r~Acest vehicul este cu tractiune spate. Intoarce-l',
|
||||
['~r~The vehicle isn\'t aligned correctly'] = '~r~Vehiculul nu este aliniat corect',
|
||||
['~r~You are not allowed to perform dyno tests'] = '~r~Nu ai permisiunea sa efectuezi teste dyno',
|
||||
|
||||
['Peak HP'] = 'HP Maxim',
|
||||
['Peak torque'] = 'Cuplu Maxim',
|
||||
|
||||
-- Webhooks
|
||||
['Vehicle'] = 'Vehicul',
|
||||
['License plate'] = 'Numar de inmatriculare',
|
||||
['Date'] = 'Data',
|
||||
['User'] = 'Utilizator',
|
||||
['Dyno performance report'] = 'Raport de performanta dyno',
|
||||
|
||||
-- Display
|
||||
['KuzQuality - DynoTech'] = 'Red Valley - DynoTech',
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
function GetDiscordDescription(model, license, player)
|
||||
local description = '- **' .. L('Vehicle') .. '**: ' .. model ..
|
||||
'\n- **' .. L('License plate') .. '**: ' .. license ..
|
||||
'\n- **' .. L('Date') .. '**: '.. os.date("%A, %m %B %Y - %H:%M")
|
||||
|
||||
if Config.webhook.includeUserName then
|
||||
description = description .. '\n\n'.. L('User') .. ': ' .. GetPlayerName(player)
|
||||
end
|
||||
if Config.webhook.includeSteamId then
|
||||
if not Config.webhook.includeUserName then
|
||||
description = description .. '\n'
|
||||
end
|
||||
description = description .. '\n*' .. GetIdentifier(player) .. '*'
|
||||
end
|
||||
|
||||
return description
|
||||
end
|
||||
|
||||
function GetIdentifier(player)
|
||||
for k, v in ipairs(GetPlayerIdentifiers(player)) do
|
||||
if string.match(v, 'license:') then
|
||||
return v:gsub('license:', '')
|
||||
end
|
||||
end
|
||||
return ''
|
||||
end
|
||||
|
||||
RegisterCommand('kq_dyno_restart', function(source)
|
||||
TriggerClientEvent('kq_dyno:client:prepareRestart', -1, source)
|
||||
end, true)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user