204 lines
7.6 KiB
Lua
204 lines
7.6 KiB
Lua
--[[
|
|
https://github.com/alp1x/um-ped-scale
|
|
Main scaling function based off of this script
|
|
|
|
███╗ ██╗ █████╗ ███████╗███████╗ ██████╗ ███████╗██████╗ ███████╗ ██████╗ █████╗ ██╗ ███████╗██████╗
|
|
████╗ ██║██╔══██╗██╔════╝██╔════╝ ██╔══██╗██╔════╝██╔══██╗██╔════╝██╔════╝██╔══██╗██║ ██╔════╝██╔══██╗
|
|
██╔██╗ ██║███████║███████╗███████╗ ██████╔╝█████╗ ██║ ██║███████╗██║ ███████║██║ █████╗ ██████╔╝
|
|
██║╚██╗██║██╔══██║╚════██║╚════██║ ██╔═══╝ ██╔══╝ ██║ ██║╚════██║██║ ██╔══██║██║ ██╔══╝ ██╔══██╗
|
|
██║ ╚████║██║ ██║███████║███████║███████╗██║ ███████╗██████╔╝███████║╚██████╗██║ ██║███████╗███████╗██║ ██║
|
|
╚═╝ ╚═══╝╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚═╝ ╚══════╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝
|
|
|
|
https://discord.gg/nass
|
|
|
|
Please support the development of this script by joining our discord server.
|
|
]]
|
|
|
|
|
|
|
|
local function norm(vec)
|
|
local mag = math.sqrt(vec.x ^ 2 + vec.y ^ 2 + vec.z ^ 2)
|
|
if mag > 0 then
|
|
return vec / mag
|
|
end
|
|
return vec
|
|
end
|
|
|
|
-- Per-ped smoothed Z, keyed by ped entity handle
|
|
local smoothedZ = {}
|
|
|
|
local function applyScaleToEntity(ped, scale)
|
|
local forward, right, upVector, position = GetEntityMatrix(ped)
|
|
|
|
local forwardNorm = norm(forward) * scale
|
|
local rightNorm = norm(right) * scale
|
|
local upNorm = norm(upVector) * scale
|
|
|
|
-- Only look ahead when moving up, cast straight down when descending
|
|
local vel = GetEntityVelocity(ped)
|
|
local isMovingUp = vel.z > 0.1
|
|
local lookAhead = isMovingUp and 0.3 or 0.0
|
|
|
|
local rayStart = vector3(position.x + vel.x * lookAhead, position.y + vel.y * lookAhead, position.z + 2.0)
|
|
local rayEnd = vector3(position.x + vel.x * lookAhead, position.y + vel.y * lookAhead, position.z - 2.5)
|
|
local ray = StartShapeTestRay(rayStart.x, rayStart.y, rayStart.z, rayEnd.x, rayEnd.y, rayEnd.z, 1 | 16, ped, 0)
|
|
local _, hit, groundPos = GetShapeTestResult(ray)
|
|
|
|
-- Fallback: straight down with longer range for flat ground / last step
|
|
if hit ~= 1 then
|
|
local rayStart2 = vector3(position.x, position.y, position.z + 2.0)
|
|
local rayEnd2 = vector3(position.x, position.y, position.z - 5.0)
|
|
local ray2 = StartShapeTestRay(rayStart2.x, rayStart2.y, rayStart2.z, rayEnd2.x, rayEnd2.y, rayEnd2.z, 1 | 16, ped, 0)
|
|
_, hit, groundPos = GetShapeTestResult(ray2)
|
|
end
|
|
|
|
local groundZ
|
|
if hit == 1 then
|
|
groundZ = groundPos.z
|
|
else
|
|
local found, gz = GetGroundZFor_3dCoord(position.x, position.y, position.z, false)
|
|
groundZ = found and gz or position.z
|
|
end
|
|
|
|
local targetZ = groundZ + scale + 0.04
|
|
|
|
local pedKey = tostring(ped)
|
|
if smoothedZ[pedKey] == nil then
|
|
smoothedZ[pedKey] = targetZ
|
|
end
|
|
|
|
if targetZ > smoothedZ[pedKey] then
|
|
-- Going up: snap for large steps, lerp for small ones
|
|
local diff = targetZ - smoothedZ[pedKey]
|
|
if diff > 0.3 then
|
|
smoothedZ[pedKey] = targetZ
|
|
else
|
|
smoothedZ[pedKey] = smoothedZ[pedKey] + diff * 0.3
|
|
end
|
|
else
|
|
-- Going down: always lerp smoothly
|
|
smoothedZ[pedKey] = smoothedZ[pedKey] + (targetZ - smoothedZ[pedKey]) * 0.18
|
|
end
|
|
|
|
SetEntityMatrix(ped,
|
|
forwardNorm.x, forwardNorm.y, forwardNorm.z,
|
|
rightNorm.x, rightNorm.y, rightNorm.z,
|
|
upNorm.x, upNorm.y, upNorm.z,
|
|
position.x, position.y, smoothedZ[pedKey]
|
|
)
|
|
end
|
|
|
|
|
|
local syncedScales = {}
|
|
|
|
-- Resolve the ped that belongs to a server id. Returns 0 when that player is
|
|
-- not currently in scope. IMPORTANT: never fall through to GetPlayerPed(-1),
|
|
-- which returns the LOCAL player's ped and would scale the wrong ped.
|
|
local function getPedForServerId(src)
|
|
local playerIdx = GetPlayerFromServerId(src)
|
|
if playerIdx == -1 then return 0 end
|
|
return GetPlayerPed(playerIdx)
|
|
end
|
|
|
|
RegisterNetEvent('nass_pedscaler:syncCurrentScaling', function(players)
|
|
for k, v in pairs(players) do
|
|
TriggerEvent('nass_pedscaler:syncScale', tonumber(k), v)
|
|
end
|
|
end)
|
|
|
|
RegisterNetEvent('nass_pedscaler:syncScale', function(src, scale)
|
|
if syncedScales[tostring(src)] ~= nil then
|
|
syncedScales[tostring(src)] = nil
|
|
local ped = getPedForServerId(src)
|
|
if ped ~= 0 and DoesEntityExist(ped) then
|
|
applyScaleToEntity(ped, 1.0)
|
|
end
|
|
Wait(100)
|
|
end
|
|
|
|
syncedScales[tostring(src)] = scale
|
|
if scale ~= nil then
|
|
startScale(src, scale)
|
|
else
|
|
local ped = getPedForServerId(src)
|
|
if ped ~= 0 and DoesEntityExist(ped) then
|
|
applyScaleToEntity(ped, 1.0)
|
|
end
|
|
end
|
|
end)
|
|
|
|
function startScale(src, scale)
|
|
CreateThread(function()
|
|
while syncedScales[tostring(src)] ~= nil do
|
|
-- Re-resolve every frame: the target player may not be in scope
|
|
-- yet (e.g. right after joining) and only stream in later.
|
|
local ped = getPedForServerId(src)
|
|
if ped ~= 0 and DoesEntityExist(ped) then
|
|
applyScaleToEntity(ped, scale)
|
|
if Config.scaling.scaleSpeed.enabled then
|
|
SetPedMoveRateOverride(ped, Config.scaling.scaleSpeed.inverse and (1 / scale) or scale)
|
|
end
|
|
end
|
|
|
|
Wait(0)
|
|
end
|
|
end)
|
|
end
|
|
|
|
RegisterNUICallback('slider_updated', function(data, cb)
|
|
local serverId = GetPlayerServerId(PlayerId())
|
|
if syncedScales[tostring(serverId)] ~= nil then
|
|
syncedScales[tostring(serverId)] = nil
|
|
end
|
|
|
|
local playerPed = PlayerPedId()
|
|
if DoesEntityExist(playerPed) then
|
|
applyScaleToEntity(playerPed, data.value)
|
|
end
|
|
|
|
cb('ok')
|
|
end)
|
|
|
|
RegisterNUICallback('save_scale', function(data, cb)
|
|
TriggerServerEvent('nass_pedscaler:syncScale', tonumber(data.scale))
|
|
closeMenu()
|
|
cb('ok')
|
|
end)
|
|
|
|
RegisterNUICallback('close_menu', function(data, cb)
|
|
closeMenu()
|
|
cb('ok')
|
|
end)
|
|
|
|
function closeMenu()
|
|
SetNuiFocus(false, false)
|
|
SendNUIMessage({
|
|
action = "visible",
|
|
data = false
|
|
})
|
|
end
|
|
|
|
RegisterNUICallback('get_config', function(data, cb)
|
|
local serverId = GetPlayerServerId(PlayerId())
|
|
SendNUIMessage({
|
|
action = "config_data",
|
|
data = {
|
|
scaling = Config.scaling,
|
|
currentScale = syncedScales[tostring(serverId)] or 1.0
|
|
}
|
|
})
|
|
cb('ok')
|
|
end)
|
|
|
|
RegisterNUICallback('getLocale', function(data, cb)
|
|
cb(Config.locale)
|
|
end)
|
|
|
|
RegisterNetEvent('nass_pedscaler:openMenu', function()
|
|
SetNuiFocus(true, true)
|
|
SendNUIMessage({
|
|
action = "visible",
|
|
data = true,
|
|
})
|
|
end)
|