⚙️ 03 — Native Functions

INFO

Le native sono funzioni C/C++ del motore di GTA V esposte a Lua, C# e JS da FiveM. Ogni interazione col gioco — spostare un giocatore, creare un veicolo, mostrare testo — passa attraverso una native.

ObiettivoDettagli
Cosa imparerai- Usare le native di GTA V per interagire col gioco
- Gestire giocatori, veicoli, ped e NPC
- Applicare il pattern Request-Then-Use per modelli e animazioni
PrerequisitiConoscenze base di Lua, completamento file 02

Cosa Sono le Native

Le native sono funzioni C/C++ del motore di GTA V esposte a Lua/C#/JS da FiveM. Ogni azione interagisce col gioco tramite native:

  • Spostare un giocatore → SetEntityCoords
  • Dare un’arma → GiveWeaponToPed
  • Creare un veicolo → CreateVehicle
  • Mostrare testo a schermo → BeginTextCommandDisplayText
flowchart LR
    L[Script Lua] --> N[Chiamata Native]
    N --> C[Citizen Invoker]
    C --> G[GTA V Game Engine]
    G --> R[Resultato]
    R --> L

Dove Trovare le Native

Documentazione ufficiale: docs.fivem.net/natives/

Ogni native ha una pagina con:

  • Nome (es. GetPlayerPed)
  • Hash (es. 0x43A66C31C68491C0)
  • Parametri e tipi
  • Valore di ritorno
  • Esempi di utilizzo

Convenzioni di Nomenclatura

PatternEsempioDescrizione
GetGetEntityCoordsLegge un valore
SetSetEntityCoordsImposta un valore
IsIsPlayerOnlineControlla stato booleano
HasHasEntityBeenDamagedControlla stato
CreateCreateVehicleCrea un’entità
Delete / RemoveDeleteEntityRimuove un’entità
TaskTaskWanderStandardAssegna compito a un ped
RequestRequestModelRichiede caricamento risorsa

Hash delle Native

Internamente, FiveM identifica le native con un hash a 64-bit. Puoi usare hash o nome:

-- Per nome (leggibile)
local coords = GetEntityCoords(ped)
 
-- Per hash (leggermente più veloce)
-- local coords = Citizen.InvokeNative(0x3FEF770D40960D5A, ped)
-- Non serve mai farlo manualmente — il nome è tradotto automaticamente

Gestione Giocatore

Ottenere il ped del giocatore

-- client.lua
Citizen.CreateThread(function()
    while true do
        Citizen.Wait(1000)
 
        local ped = PlayerPedId()
        if ped ~= 0 then
            local salute = GetEntityHealth(ped)
            local armatura = GetPedArmour(ped)
            local maxSalute = GetEntityMaxHealth(ped)
 
            print(string.format(
                "Ped: %d | HP: %d/%d | Armatura: %d",
                ped, salute, maxSalute, armatura
            ))
        end
    end
end)

Posizione e heading

-- client.lua
RegisterCommand("pos", function()
    local ped = PlayerPedId()
    local coords = GetEntityCoords(ped)
    local heading = GetEntityHeading(ped)
 
    print(string.format("Posizione: %.2f, %.2f, %.2f", coords.x, coords.y, coords.z))
    print(string.format("Heading: %.2f", heading))
 
    -- Copia negli appunti
    -- SetClipboard(("{%.6f, %.6f, %.6f}"):format(coords.x, coords.y, coords.z))
end, false)
 
-- Teletrasporto
RegisterCommand("tp", function(source, args)
    local x = tonumber(args[1])
    local y = tonumber(args[2])
    local z = tonumber(args[3])
 
    if x and y and z then
        local ped = PlayerPedId()
        SetEntityCoords(ped, x, y, z, false, false, false, false)
        print("Teletrasportato a", x, y, z)
    else
        print("Uso: /tp x y z")
    end
end, false)

Modellare il giocatore

-- client.lua
RegisterCommand("skin", function(source, args)
    local modelName = args[1]
    local model = GetHashKey(modelName)
 
    -- Richiedi il modello
    RequestModel(model)
 
    -- Aspetta che sia caricato
    local timeout = 0
    while not HasModelLoaded(model) and timeout < 100 do
        Citizen.Wait(10)
        timeout = timeout + 1
        RequestModel(model)
    end
 
    if HasModelLoaded(model) then
        SetPlayerModel(PlayerId(), model)
        SetModelAsNoLongerNeeded(model)
        print("Modello cambiato a", modelName)
    else
        print("ERRORE: modello", modelName, "non trovato")
    end
end, false)

Gestione Veicoli

Spawnare un veicolo

-- client.lua
RegisterCommand("veh", function(source, args)
    local modello = args[1]
    if not modello then
        print("Uso: /veh [modello]")
        return
    end
 
    SpawnaVeicolo(modello)
end, false)
 
function SpawnaVeicolo(modello)
    local hash = GetHashKey(modello)
    local ped = PlayerPedId()
    local coords = GetEntityCoords(ped)
    local heading = GetEntityHeading(ped)
 
    RequestModel(hash)
    local timeout = 0
    while not HasModelLoaded(hash) and timeout < 100 do
        Citizen.Wait(10)
        timeout = timeout + 1
        RequestModel(hash)
    end
 
    if HasModelLoaded(hash) then
        local veicolo = CreateVehicle(hash, coords.x, coords.y, coords.z + 2.0, heading, true, false)
        SetPedIntoVehicle(ped, veicolo, -1) -- -1 = posto guida
        SetVehicleEngineOn(veicolo, true, true, false)
        SetModelAsNoLongerNeeded(hash)
 
        print("Veicolo", modello, "spawnato. ID:", veicolo)
    else
        print("ERRORE: modello veicolo", modello, "non valido")
    end
end
 
-- pattern RequestModel unificato
function CaricaModello(hash)
    RequestModel(hash)
    local tentativi = 0
    while not HasModelLoaded(hash) and tentativi < 100 do
        Citizen.Wait(10)
        tentativi = tentativi + 1
        if tentativi % 20 == 0 then
            RequestModel(hash) -- richiedi di nuovo ogni 200ms
        end
    end
    return HasModelLoaded(hash)
end

Modificare un veicolo

-- client.lua
RegisterCommand("mod", function(source, args)
    local ped = PlayerPedId()
    local veicolo = GetVehiclePedIsIn(ped, false)
 
    if veicolo == 0 then
        print("Non sei in un veicolo")
        return
    end
 
    -- Colore primario e secondario
    SetVehicleColours(veicolo, 120, 0) -- rosso / nero
 
    -- Colore extra (cerchi, interni)
    SetVehicleExtraColours(veicolo, 1, 0)
 
    -- Modifiche prestazioni
    SetVehicleModKit(veicolo, 0)
    SetVehicleMod(veicolo, 11, 3, false)   -- motore livello 3
    SetVehicleMod(veicolo, 12, 2, false)   -- freni livello 2
    SetVehicleMod(veicolo, 13, 1, false)   -- trasmissione livello 1
    SetVehicleMod(veicolo, 18, 1, false)   -- turbo
 
    -- Tuning estetico
    SetVehicleMod(veicolo, 0, 1, false)    -- paraurti anteriore
    SetVehicleMod(veicolo, 1, 1, false)    -- paraurti posteriore
    SetVehicleMod(veicolo, 2, 2, false)    -- minigonne laterali
 
    -- Tinted windows
    SetVehicleWindowTint(veicolo, 1)       -- 1 = scuro
 
    -- Neon
    SetVehicleNeonLightEnabled(veicolo, 0, true)
    SetVehicleNeonLightEnabled(veicolo, 1, true)
    SetVehicleNeonLightEnabled(veicolo, 2, true)
    SetVehicleNeonLightEnabled(veicolo, 3, true)
    SetVehicleNeonLightsColour(veicolo, 255, 0, 0) -- rosso
 
    ToggleVehicleMod(veicolo, 22, true)    -- pneumatici da drift
 
    print("Veicolo modificato!")
end, false)

Gestione Armi

-- client.lua
RegisterCommand("arma", function(source, args)
    local ped = PlayerPedId()
    local nomeArma = args[1] or "WEAPON_PISTOL"
    local munizioni = tonumber(args[2]) or 250
 
    local hash = GetHashKey(nomeArma)
 
    -- Dai l'arma al giocatore
    GiveWeaponToPed(ped, hash, munizioni, false, true)
 
    -- Selezionala automaticamente
    SetCurrentPedWeapon(ped, hash, true)
 
    print("Arma", nomeArma, "data con", munizioni, "colpi")
 
    -- Per tutte le armi disponibili:
    -- WEAPON_PISTOL, WEAPON_ASSAULTRIFLE, WEAPON_CARBINERIFLE,
    -- WEAPON_PUMPSHOTGUN, WEAPON_KNIFE, WEAPON_GRENADE, ecc.
end, false)
 
RegisterCommand("armaop", function()
    local ped = PlayerPedId()
    local hash = GetHashKey("WEAPON_RAILGUN")
    GiveWeaponToPed(ped, hash, 9999, false, true)
    SetPedInfiniteAmmo(ped, true, hash)
end, false)

Gestione Ped (NPC)

-- client.lua
function SpawnaPed(modello, x, y, z, heading)
    local hash = GetHashKey(modello)
 
    if not CaricaModello(hash) then
        print("ERRORE: modello", modello, "non caricato")
        return nil
    end
 
    -- Crea ped come network (true = sincronizzato con server)
    local ped = CreatePed(0, hash, x, y, z, heading, true, true)
    SetModelAsNoLongerNeeded(hash)
 
    -- Rende il ped immune
    SetEntityInvincible(ped, true)
    SetPedCanRagdoll(ped, false)
 
    -- Non fugge
    SetPedFleeAttributes(ped, 0, true)
 
    -- Animazione di default
    TaskStartScenarioInPlace(ped, "WORLD_HUMAN_HANG_OUT_STREET", 0, true)
 
    return ped
end
 
RegisterCommand("npc", function()
    local ped = PlayerPedId()
    local coords = GetEntityCoords(ped)
    local heading = GetEntityHeading(ped)
 
    local npc = SpawnaPed(
        "a_m_y_beach_01",
        coords.x + 3.0, coords.y, coords.z - 1.0,
        heading + 180
    )
 
    if npc then
        print("NPC creato con ID:", npc)
    end
end, false)

Pattern Comuni

Request-Then-Use Pattern

WARNING

Carica sempre i modelli prima di usarli. Creare un’entità senza RequestModel + HasModelLoaded causa crash immediato. Usa un timeout per evitare loop infiniti su modelli mancanti.

Questo pattern si ripete ovunque in FiveM: Richiedi → Aspetta → Usa → Libera.

function CaricaModello(modelHash)
    RequestModel(modelHash)
    local tentativi = 0
    while not HasModelLoaded(modelHash) do
        tentativi = tentativi + 1
        Citizen.Wait(10)
        if tentativi > 500 then -- 5 secondi timeout
            return false
        end
        if tentativi % 25 == 0 then
            RequestModel(modelHash)
        end
    end
    return true
end
 
-- Stesso pattern per animazioni
function CaricaDict(dict)
    RequestAnimDict(dict)
    local tentativi = 0
    while not HasAnimDictLoaded(dict) do
        tentativi = tentativi + 1
        Citizen.Wait(10)
        if tentativi > 500 then return false end
        if tentativi % 25 == 0 then
            RequestAnimDict(dict)
        end
    end
    return true
end
 
-- Stesso pattern per texture / streaming
function CaricaTexture(streamedDict)
    RequestStreamedTextureDict(streamedDict, false)
    local tentativi = 0
    while not HasStreamedTextureDictLoaded(streamedDict) do
        tentativi = tentativi + 1
        Citizen.Wait(10)
        if tentativi > 500 then return false end
        if tentativi % 25 == 0 then
            RequestStreamedTextureDict(streamedDict, false)
        end
    end
    return true
end

Giocare un’animazione

TIP

Usa ClearPedTasks(ped) per fermare qualsiasi animazione in corso. Per animazioni che devono partire sempre da capo, chiamala prima di TaskPlayAnim.

-- client.lua
RegisterCommand("balla", function()
    local ped = PlayerPedId()
 
    if CaricaDict("anim@mp_player_intcelebrationmale@air_shuffle") then
        TaskPlayAnim(ped, "anim@mp_player_intcelebrationmale@air_shuffle",
            "air_shuffle", 8.0, -8.0, -1, 49, 0, false, false, false)
    end
end, false)
 
RegisterCommand("stopanim", function()
    local ped = PlayerPedId()
    ClearPedTasks(ped)
end, false)

Rilevare input giocatore

-- client.lua
Citizen.CreateThread(function()
    while true do
        Citizen.Wait(0)
 
        -- Tasto E premuto?
        if IsControlJustPressed(0, 38) then -- 38 = E
            local ped = PlayerPedId()
            local coords = GetEntityCoords(ped)
 
            -- Controlla se vicino a un veicolo
            local veicolo = GetClosestVehicle(coords.x, coords.y, coords.z, 3.0, 0, 71)
            if veicolo ~= 0 then
                print("Vicino a veicolo", veicolo, "— premi E per entrare")
            end
 
            -- Controlla se vicino a un ped
            local pedTarget = GetClosestPed(coords.x, coords.y, coords.z, 3.0, true, true)
            if pedTarget ~= 0 and pedTarget ~= ped then
                print("Vicino a NPC", pedTarget)
            end
        end
    end
end)
 
-- Lista tasti comuni:
-- 38 = E       | 51 = E (alternativo)
-- 24 = SPACE   | 22 = INVIO
-- 36 = CTRL    | 21 = SHIFT
-- 201 = SU     | 208 = GIÙ
-- 203 = SINISTRA | 205 = DESTRA

Text UI (aiuto a schermo)

-- client.lua
function DrawText3D(x, y, z, testo)
    local onScreen, _x, _y = World3dToScreen2d(x, y, z)
    local scale = 0.35
 
    if onScreen then
        SetTextScale(0.0, scale)
        SetTextFont(4)
        SetTextProportional(1)
        SetTextColour(255, 255, 255, 215)
        SetTextEntry("STRING")
        SetTextCentre(true)
        AddTextComponentString(testo)
        DrawText(_x, _y)
 
        -- Sfondo
        local larghezza = string.len(testo) * 0.007
        DrawRect(_x, _y + 0.012, larghezza, 0.028, 0, 0, 0, 150)
    end
end
 
Citizen.CreateThread(function()
    while true do
        Citizen.Wait(0)
        local ped = PlayerPedId()
        local coords = GetEntityCoords(ped)
 
        -- Mostra testo sopra la testa del giocatore
        DrawText3D(coords.x, coords.y, coords.z + 1.0, "Giocatore: " .. GetPlayerName(PlayerId()))
    end
end)

QUESTION

Riflessione: Stai chiamando native in loop che potrebbero essere evitate? GetEntityCoords e PlayerPedId sono economiche, ma chiamate come RequestModel in loop senza controllo possono impattare le performance.

Best Practices

RegolaPerché
Usa sempre RequestModel + HasModelLoadedCreare un’entità senza caricarla prima = crash
Timeout sui caricamentiModello mancante = loop infinito
SetModelAsNoLongerNeeded dopo l’usoLibera memoria
Controlla che un’entità esistaDoesEntityExist(id) prima di usarla
Non chiamare native inutilmente nei loopUsa Wait(N) più alto quando possibile
Preferisci versioni native con nomePiù leggibili, stesso costo
Usa i delegati di controlloIsControlJustPressed per input, non polling su variabili

TIP

Prossimo passo: 04 - Esport e Import


Torna alla: Indice Generale