Explorer
KNOW-PAT-109

FiveM - Ragdoll + Props Persistence : keymapping, sauvegarde props vehicule, animation timeout

Domaine
fivem
Type
pattern
Priorité
P3

Parent : [[INDEX-FIVEM-GAMEPLAY]]

FiveM - Ragdoll + Props Persistence : keymapping, sauvegarde props véhicule, animation timeout

Problème

Le ragdoll (tomber au sol) doit être toggleable via keymapping, et les props du joueur (chapeau) doivent être restaurés après être sorti d'un véhicule. Le chargement d'animations nécessite un timeout pour éviter les freezes.

Solution

Système ragdoll toggle avec keymapping RegisterKeyMapping, sauvegarde de props (chapeau) avant/pendant véhicule, timeout de chargement d'animations.

-- CKCore/client/cl_utils.lua
local ESX = exports["es_extended"]:getSharedObject()

local ragdoll = false
local savedHat = -1
local savedHatTexture = 0
local wasInVehicle = false

-- =========================================================
-- ANIMATION LOADER AVEC TIMEOUT
-- =========================================================
local function LoadAnimDict(dict, timeout)
    timeout = timeout or 5000
    if HasAnimDictLoaded(dict) then return true end
    
    RequestAnimDict(dict)
    local start = GetGameTimer()
    
    while not HasAnimDictLoaded(dict) do
        Wait(50)
        if GetGameTimer() - start > timeout then
            print('[^1ERROR^7] Failed to load anim dict: ' .. dict)
            return false
        end
    end
    
    return true
end

-- =========================================================
-- RAGDOLL SYSTEM
-- =========================================================
CreateThread(function()
    while true do
        if ragdoll then
            local ped = PlayerPedId()
            if not IsPedInAnyVehicle(ped, false) then
                SetPedToRagdoll(ped, 1000, 1000, 0, false, false, false)
                ESX.ShowHelpNotification("Appuyez sur ~r~[ESPACE]~s~ pour vous relever")
                
                if IsControlJustPressed(0, 22) then -- INPUT_JUMP (SPACE)
                    ragdoll = false
                end
                Wait(0)
            else
                ragdoll = false
                Wait(250)
            end
        else
            Wait(500)
        end
    end
end)

RegisterNetEvent('dh_ragdoll:toggle')
AddEventHandler('dh_ragdoll:toggle', function()
    local ped = PlayerPedId()
    if IsPedInAnyVehicle(ped, false) then return end
    ragdoll = not ragdoll
end)

RegisterCommand('ragdoll', function()
    local ped = PlayerPedId()
    if not IsPedInAnyVehicle(ped, false) then
        TriggerEvent("dh_ragdoll:toggle")
    else
        ESX.ShowNotification("Vous ne pouvez pas tomber au sol dans un véhicule.")
    end
end, false)

-- Keymapping native (visible dans les paramètres FiveM)
RegisterKeyMapping('ragdoll', "Tomber par terre / se relever", 'keyboard', 'PLUS')

-- =========================================================
-- SAUVEGARDE CHAPEAU EN VEHICULE
-- =========================================================
CreateThread(function()
    while true do
        local ped = PlayerPedId()
        local inVehicle = IsPedInAnyVehicle(ped, false)
        
        if not inVehicle then
            -- Sauvegarde quand on est hors véhicule
            if not wasInVehicle then
                savedHat = GetPedPropIndex(ped, 0)
                savedHatTexture = GetPedPropTextureIndex(ped, 0)
            end
            wasInVehicle = false
            Wait(500)
        else
            -- Entrée véhicule : on a déjà sauvegardé avant
            if not wasInVehicle then
                wasInVehicle = true
                -- Le chapeau est retiré par GTA native, on le restaure à la sortie
            end
            Wait(1000)
        end
    end
end)

-- Restauration chapeau à la sortie de véhicule
AddEventHandler('gameEventTriggered', function(name, args)
    if name == 'CEventNetworkPlayerEnteredVehicle' then
        -- Entrée : rien à faire, GTA gère
    elseif name == 'CEventNetworkPlayerLeftVehicle' then
        -- Sortie : restauration
        local ped = PlayerPedId()
        if savedHat ~= -1 then
            SetPedPropIndex(ped, 0, savedHat, savedHatTexture, true)
        end
    end
end)

Pourquoi

  • RegisterKeyMapping expose le bind dans le menu native de FiveM
  • Timeout 5s sur LoadAnimDict évite le freeze infini si le dict est corrompu
  • Sauvegarde chapeau préserve l'apparence du joueur après véhicule

Quand l'utiliser

  • Émotes interactives (sit, lay, lean)
  • Systèmes de props persistants (lunettes, masques)
  • Keybindings pour actions RP

Quand NE PAS l'utiliser

  • Animations one-shot sans toggle → pas besoin de keymapping

Exemples

Correct

-- Animation loader générique réutilisable
function PlayAnimation(ped, dict, anim, blendIn, blendOut, duration, flag)
    if not LoadAnimDict(dict, 3000) then
        print('Animation impossible à charger')
        return false
    end
    
    TaskPlayAnim(ped, dict, anim, blendIn or 8.0, blendOut or -8.0, duration or -1, flag or 0, 0, false, false, false)
    return true
end

-- Usage
RegisterCommand('sit', function()
    local ped = PlayerPedId()
    if PlayAnimation(ped, 'anim@heists@prison_heistunfinished_biztarget_idle', 'target_idle') then
        -- Animation jouée avec succès
    end
end, false)

Incorrect

-- Pas de timeout → freeze si le dict n'existe pas
function BadLoadAnim(dict)
    RequestAnimDict(dict)
    while not HasAnimDictLoaded(dict) do
        Wait(0) -- Freeze potentiellement infini
    end
end

Références

  • CKCore/client/cl_utils.lua L9-65
  • CKCore/config.lua L1-80