local pending_steps = 0 local pending_distance = 0.0 local pending_active_seconds = 0.0 local step_progress = 0.0 local last_coords = nil local last_report_at = GetGameTimer() local function flush_activity() last_report_at = GetGameTimer() local distance_meters = math.floor(pending_distance + 0.5) local active_seconds = math.floor(pending_active_seconds + 0.5) if pending_steps == 0 and distance_meters == 0 and active_seconds == 0 then return end TriggerServerEvent("sky_phone:health:record-activity", { steps = pending_steps, distanceMeters = distance_meters, activeSeconds = active_seconds, }) pending_steps = 0 pending_distance = 0.0 pending_active_seconds = 0.0 end CreateThread(function() while true do Wait(Config.Health.SampleIntervalMs) local ped = PlayerPedId() if DoesEntityExist(ped) then local coords = GetEntityCoords(ped) local is_moving_on_foot = IsPedOnFoot(ped) and not IsPedDeadOrDying(ped, true) and not IsPedFalling(ped) and not IsPedRagdoll(ped) and (IsPedWalking(ped) or IsPedRunning(ped) or IsPedSprinting(ped)) if last_coords and is_moving_on_foot then local delta_x = coords.x - last_coords.x local delta_y = coords.y - last_coords.y local distance = math.sqrt(delta_x * delta_x + delta_y * delta_y) local maximum_sample_distance = Config.Health.MaximumSpeedMetersPerSecond * Config.Health.SampleIntervalMs / 1000.0 if distance >= 0.04 and distance <= maximum_sample_distance then local stride_length = 0.75 if IsPedSprinting(ped) then stride_length = 1.15 elseif IsPedRunning(ped) then stride_length = 1.0 end pending_distance = pending_distance + distance pending_active_seconds = pending_active_seconds + Config.Health.SampleIntervalMs / 1000.0 step_progress = step_progress + distance while step_progress >= stride_length do step_progress = step_progress - stride_length pending_steps = pending_steps + 1 end end end last_coords = coords else last_coords = nil end if GetGameTimer() - last_report_at >= Config.Health.ReportIntervalSeconds * 1000 then flush_activity() end end end) AddEventHandler("playerSpawned", function() last_coords = nil end) AddEventHandler("onResourceStop", function(resource_name) if resource_name == GetCurrentResourceName() then flush_activity() end end) RegisterNUICallback("health:overview", function(data, cb) local result = Bridge.Callbacks.Trigger("sky_phone:health:overview", data or {}) cb(result or { success = false, error = "request_failed" }) end) RegisterNUICallback("health:save-profile", function(data, cb) local result = Bridge.Callbacks.Trigger("sky_phone:health:save-profile", data or {}) cb(result or { success = false, error = "request_failed" }) end) RegisterNetEvent("sky_phone:health:changed", function() SendNUIMessage({ type = "health:changed" }) end)