forked from Simnation/Main
263 lines
5.8 KiB
Lua
263 lines
5.8 KiB
Lua
Debugger = {
|
|
speedBuffer = {},
|
|
speed = 0.0,
|
|
accel = 0.0,
|
|
decel = 0.0,
|
|
toggle = false
|
|
}
|
|
|
|
--[[ Functions ]]--
|
|
function TruncateNumber(value)
|
|
value = value * Config.Precision
|
|
|
|
return (value % 1.0 > 0.5 and math.ceil(value) or math.floor(value)) / Config.Precision
|
|
end
|
|
|
|
function Debugger:Set(vehicle)
|
|
self.vehicle = vehicle
|
|
self:ResetStats()
|
|
|
|
local handlingText = ""
|
|
|
|
-- Loop fields.
|
|
for key, field in pairs(Config.Fields) do
|
|
-- Get field type.
|
|
local fieldType = Config.Types[field.type]
|
|
if fieldType == nil then error("no field type") end
|
|
|
|
-- Get value.
|
|
local value = fieldType.getter(vehicle, "CHandlingData", field.name)
|
|
if type(value) == "vector3" then
|
|
value = ("%s,%s,%s"):format(value.x, value.y, value.z)
|
|
elseif field.type == "float" then
|
|
value = TruncateNumber(value)
|
|
end
|
|
|
|
-- Get input.
|
|
local input = ([[
|
|
<input
|
|
oninput='updateHandling(this.id, this.value)'
|
|
id='%s'
|
|
value=%s
|
|
>
|
|
</input>
|
|
]]):format(key, value)
|
|
|
|
-- Append text.
|
|
handlingText = handlingText..([[
|
|
<div class='tooltip'><span class='tooltip-text'>%s</span><span>%s</span>%s</div>
|
|
]]):format(field.description or "Unspecified.", field.name, input)
|
|
end
|
|
|
|
-- Update text.
|
|
self:Invoke("updateText", {
|
|
["handling-fields"] = handlingText,
|
|
})
|
|
end
|
|
|
|
function Debugger:UpdateVehicle()
|
|
local ped = PlayerPedId()
|
|
local isInVehicle = IsPedInAnyVehicle(ped, false)
|
|
local vehicle = isInVehicle and GetVehiclePedIsIn(ped, false)
|
|
|
|
if self.isInVehicle ~= isInVehicle or self.vehicle ~= vehicle then
|
|
self.vehicle = vehicle
|
|
self.isInVehicle = isInVehicle
|
|
|
|
if isInVehicle and DoesEntityExist(vehicle) then
|
|
self:Set(vehicle)
|
|
end
|
|
end
|
|
end
|
|
|
|
function Debugger:UpdateInput()
|
|
if self.hasFocus then
|
|
DisableControlAction(0, 1)
|
|
DisableControlAction(0, 2)
|
|
end
|
|
end
|
|
|
|
function Debugger:UpdateAverages()
|
|
if not DoesEntityExist(self.vehicle or 0) then return end
|
|
|
|
-- Get the speed.
|
|
local speed = GetEntitySpeed(self.vehicle)
|
|
|
|
-- Speed buffer.
|
|
table.insert(self.speedBuffer, speed)
|
|
|
|
if #self.speedBuffer > 100 then
|
|
table.remove(self.speedBuffer, 1)
|
|
end
|
|
|
|
-- Calculate averages.
|
|
local accel = 0.0
|
|
local decel = 0.0
|
|
local accelCount = 0
|
|
local decelCount = 0
|
|
|
|
for k, v in ipairs(self.speedBuffer) do
|
|
if k > 1 then
|
|
local change = (v - self.speedBuffer[k - 1])
|
|
if change > 0.0 then
|
|
accel = accel + change
|
|
accelCount = accelCount + 1
|
|
else
|
|
decel = accel + change
|
|
decelCount = decelCount + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
accel = accel / accelCount
|
|
decel = decel / decelCount
|
|
|
|
-- Set tops.
|
|
self.speed = math.max(self.speed, speed)
|
|
self.accel = math.max(self.accel, accel)
|
|
self.decel = math.min(self.decel, decel)
|
|
|
|
-- Update text.
|
|
self:Invoke("updateText", {
|
|
["top-speed"] = self.speed * 2.236936,
|
|
["top-accel"] = self.accel * 60.0 * 2.236936,
|
|
["top-decel"] = math.abs(self.decel) * 60.0 * 2.236936,
|
|
})
|
|
end
|
|
|
|
function Debugger:ResetStats()
|
|
self.speed = 0.0
|
|
self.accel = 0.0
|
|
self.decel = 0.0
|
|
self.speedBuffer = {}
|
|
end
|
|
|
|
function Debugger:SetHandling(key, value)
|
|
if not DoesEntityExist(self.vehicle or 0) then return end
|
|
|
|
-- Get field.
|
|
local field = Config.Fields[key]
|
|
if field == nil then error("no field") end
|
|
|
|
-- Get field type.
|
|
local fieldType = Config.Types[field.type]
|
|
if fieldType == nil then error("no field type") end
|
|
|
|
-- Set field.
|
|
fieldType.setter(self.vehicle, "CHandlingData", field.name, value)
|
|
|
|
-- Needed for some values to work.
|
|
ModifyVehicleTopSpeed(self.vehicle, 1.0)
|
|
end
|
|
|
|
function Debugger:CopyHandling()
|
|
local text = ""
|
|
|
|
-- Line writer.
|
|
local function writeLine(append)
|
|
if text ~= "" then
|
|
text = text.."\n\t\t\t"
|
|
end
|
|
text = text..append
|
|
end
|
|
|
|
-- Get vehicle.
|
|
local vehicle = self.vehicle
|
|
if not DoesEntityExist(vehicle) then return end
|
|
|
|
-- Loop fields.
|
|
for key, field in pairs(Config.Fields) do
|
|
-- Get field type.
|
|
local fieldType = Config.Types[field.type]
|
|
if fieldType == nil then error("no field type") end
|
|
|
|
-- Get value.
|
|
local value = fieldType.getter(vehicle, "CHandlingData", field.name, true)
|
|
local nValue = tonumber(value)
|
|
|
|
-- Append text.
|
|
if nValue ~= nil then
|
|
writeLine(("<%s value=\"%s\" />"):format(field.name, field.type == "float" and TruncateNumber(nValue) or nValue))
|
|
elseif field.type == "vector" then
|
|
writeLine(("<%s x=\"%s\" y=\"%s\" z=\"%s\" />"):format(field.name, value.x, value.y, value.z))
|
|
end
|
|
end
|
|
|
|
-- Copy text.
|
|
self:Invoke("copyText", text)
|
|
end
|
|
|
|
function Debugger:Focus(toggle)
|
|
if toggle and not DoesEntityExist(self.vehicle or 0) then return end
|
|
|
|
SetNuiFocus(toggle, toggle)
|
|
SetNuiFocusKeepInput(toggle)
|
|
|
|
self.hasFocus = toggle
|
|
self:Invoke("setFocus", toggle)
|
|
end
|
|
|
|
function Debugger:ToggleOn(toggleData)
|
|
-- if toggle and not DoesEntityExist(self.vehicle or 0) then return end
|
|
|
|
self.toggle = toggleData
|
|
self:Invoke("toggle", toggleData)
|
|
end
|
|
|
|
function Debugger:Invoke(_type, data)
|
|
SendNUIMessage({
|
|
callback = {
|
|
type = _type,
|
|
data = data,
|
|
},
|
|
})
|
|
end
|
|
|
|
--[[ Threads ]]--
|
|
Citizen.CreateThread(function()
|
|
while true do
|
|
Citizen.Wait(1000)
|
|
Debugger:UpdateVehicle()
|
|
end
|
|
end)
|
|
|
|
Citizen.CreateThread(function()
|
|
while true do
|
|
if Debugger.isInVehicle then
|
|
Citizen.Wait(0)
|
|
Debugger:UpdateInput()
|
|
Debugger:UpdateAverages()
|
|
else
|
|
Citizen.Wait(500)
|
|
end
|
|
end
|
|
end)
|
|
|
|
--[[ NUI Events ]]--
|
|
RegisterNUICallback("updateHandling", function(data, cb)
|
|
cb(true)
|
|
Debugger:SetHandling(tonumber(data.key), data.value)
|
|
end)
|
|
|
|
RegisterNUICallback("copyHandling", function(data, cb)
|
|
cb(true)
|
|
Debugger:CopyHandling()
|
|
end)
|
|
|
|
RegisterNUICallback("resetStats", function(data, cb)
|
|
cb(true)
|
|
Debugger:ResetStats()
|
|
end)
|
|
|
|
--[[ Commands ]]--
|
|
RegisterCommand("+vehicleDebug", function()
|
|
if Debugger.toggleOn == false then return end
|
|
Debugger:Focus(not Debugger.hasFocus)
|
|
end, true)
|
|
|
|
RegisterKeyMapping("+vehicleDebug", "Vehicle Debugger", "keyboard", "lmenu")
|
|
|
|
RegisterCommand("vehdebug", function()
|
|
Debugger:ToggleOn(not Debugger.toggleOn)
|
|
Debugger.toggleOn = not Debugger.toggleOn
|
|
end, true)
|