Explorer
KNOW-PAT-100

FiveM - Native HeadBlendData Manipulation : extraction et restauration via InvokeNative

Domaine
fivem
Type
pattern
Priorité
P2

Parent : [[INDEX-FIVEM-GAMEPLAY]]

FiveM - Native HeadBlendData Manipulation : extraction et restauration via InvokeNative

Problème

Lorsqu'un joueur équipe/retire un masque ou change d'accessoire, les données de blend de la tête (visage, peau, traits) peuvent être perdues ou corrompues par certains natives GTA.

Solution

Extraction des données de blend de tête via Citizen.InvokeNative et PointerValueIntInitialized, stockage temporaire, et restauration manuelle après changement d'accessoires.

local function getHeadBlendData(ped)
    local tbl = {
        Citizen.InvokeNative(0x2746BD9D88C5C5D0, ped,
            Citizen.PointerValueIntInitialized(0),
            Citizen.PointerValueIntInitialized(0),
            Citizen.PointerValueIntInitialized(0),
            Citizen.PointerValueIntInitialized(0),
            Citizen.PointerValueIntInitialized(0),
            Citizen.PointerValueIntInitialized(0),
            Citizen.PointerValueIntInitialized(0),
            Citizen.PointerValueIntInitialized(0),
            Citizen.PointerValueIntInitialized(0)
        )
    }

    return {
        shapeFirst = tbl[1],
        shapeSecond = tbl[2],
        shapeThird = tbl[3],
        skinFirst = tbl[4],
        skinSecond = tbl[5],
        skinThird = tbl[6],
        shapeMix = tbl[7],
        skinMix = tbl[8],
        thirdMix = tbl[9]
    }
end

-- Sauvegarde avant changement
local savedBlendData = nil

RegisterNetEvent('mask:equip')
AddEventHandler('mask:equip', function(maskIndex)
    local ped = PlayerPedId()
    
    -- Sauvegarde uniquement si c'est un freemode model
    if IsFreemodeModel(ped) then
        savedBlendData = getHeadBlendData(ped)
    end
    
    -- Application du masque
    SetPedComponentVariation(ped, 1, maskIndex, 0, 2)
    
    -- Restauration après un court délai (le native de masque peut écraser)
    Wait(100)
    if savedBlendData then
        SetPedHeadBlendData(ped,
            savedBlendData.shapeFirst,
            savedBlendData.shapeSecond,
            savedBlendData.shapeThird,
            savedBlendData.skinFirst,
            savedBlendData.skinSecond,
            savedBlendData.skinThird,
            savedBlendData.shapeMix,
            savedBlendData.skinMix,
            savedBlendData.thirdMix,
            false
        )
    end
end)

local function IsFreemodeModel(ped)
    local model = GetEntityModel(ped)
    return model == GetHashKey('mp_m_freemode_01') or model == GetHashKey('mp_f_freemode_01')
end

Pourquoi

  • SetPedComponentVariation pour le masque peut réinitialiser le blend
  • Citizen.InvokeNative(0x2746BD9D88C5C5D0) est GetPedHeadBlendData (native non exposée en Lua)
  • PointerValueIntInitialized permet de récupérer les valeurs passées par référence

Quand l'utiliser

  • Scripts d'accessoires (masques, lunettes, chapeaux)
  • Systèmes de chirurgie esthétique / barbier
  • Sauvegarde/restauration d'apparence complète

Quand NE PAS l'utiliser

  • Si vous utilisez un système de skins complet (qb-clothing, illenium-appearance) qui gère déjà le blend

Exemples

Correct

-- Wrapper avec timeout pour éviter les boucles infinies
local function safeGetHeadBlendData(ped, maxAttempts)
    maxAttempts = maxAttempts or 50
    local attempts = 0
    local data
    
    repeat
        data = getHeadBlendData(ped)
        attempts = attempts + 1
        Wait(10)
    until data.shapeFirst ~= 0 or attempts >= maxAttempts
    
    return data
end

Incorrect

-- Invocation directe sans PointerValue → crash ou valeurs incorrectes
local blend = Citizen.InvokeNative(0x2746BD9D88C5C5D0, ped, 0, 0, 0, 0, 0, 0, 0, 0, 0)
-- Les 0 ne sont pas des pointeurs initialisés → données corrompues

Références

  • mask-fix/client.lua L26-58
  • GTA V Native DB : GET_PED_HEAD_BLEND_DATA