Esempio Completo: Risorsa Arma Custom con ESX + OX
INFO
Risorsa completa che integra un’arma custom (M4A1 Tactical) con ESX, ox_inventory, ox_target e ox_lib.
| Obiettivo | Dettagli |
|---|---|
| Cosa imparerai | • Struttura completa di una risorsa FiveM • Integrare arma custom con ESX + OX stack • Configurare shop, acquisti e notifiche end-to-end |
| Prerequisiti | • Aver completato le guide 02-07 • Un’arma custom pronta con file .ydr/.ytd • ox_lib, ox_inventory, ox_target installati |
Struttura
weapon_m4a1/
├── fxmanifest.lua
├── config.lua
├── client.lua
├── server.lua
└── stream/ ← File dell'arma custom
├── w_m4a1.ydr
├── w_m4a1_fp.ydr
├── w_m4a1.ytd
├── w_m4a1.weaponlayouts.meta
├── w_m4a1.weaponanimations.meta
└── w_m4a1.weaponpickups.meta
NOTE
Gli item (arma + munizioni) si definiscono in
ox_inventory/data/weapons.lua, non in questa risorsa. Vedi sezione “items.lua” più sotto.
fxmanifest.lua
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
author 'TuoNome'
description 'M4A1 Tactical - ESX + OX Integration'
version '1.0.0'
shared_scripts {
'@ox_lib/init.lua',
'@es_extended/imports.lua',
'config.lua'
}
client_scripts {
'client.lua'
}
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server.lua'
}
files {
'stream/*.meta'
}
data_file 'WEAPON_INFO_FILE' 'stream/*.weaponlayouts.meta'
data_file 'WEAPON_ANIMATIONS_FILE' 'stream/*.weaponanimations.meta'
data_file 'WEAPON_PICKUP_FILE' 'stream/*.weaponpickups.meta'config.lua
-- config.lua
Config = Config or {}
Config.Debug = false
-- Arma
Config.WeaponName = 'WEAPON_M4A1_CUSTOM'
Config.WeaponLabel = 'M4A1 Tactical'
Config.WeaponHash = 'w_m4a1'
-- Prezzi
Config.WeaponPrice = 5000
Config.AmmoPrice = 50 -- Per 30 proiettili
-- Munizioni
Config.AmmoType = 'ammo-rifle'
Config.DefaultAmmo = 120
-- Negozio
Config.ShopCoords = vector3(250.0, -150.0, 29.5)items.lua
WARNING
In ox_inventory armi e munizioni non si registrano con export a runtime (
RegisterWeapon/RegisterItemnon esistono). Si definiscono nei fileox_inventory/data/weapons.luaeox_inventory/data/items.lua. Questo fileitems.luaqui sotto non serve: l’esempio reale è la voce da aggiungere nei data file.
-- ox_inventory/data/weapons.lua (aggiungi alla tabella Weapons)
['WEAPON_M4A1_CUSTOM'] = {
label = 'M4A1 Tactical',
weight = 2500,
durability = 0.02,
ammoname = 'ammo-rifle',
},
-- ox_inventory/data/weapons.lua (aggiungi alla tabella Ammo)
['ammo-rifle'] = {
label = '5.56x45',
weight = 4,
},NOTE
Se preferisci non toccare i file di ox_inventory (che gli update sovrascrivono), tieni un backup o usa un modulo di merge. L’importante è che gli item siano nel
data/prima che la risorsa parta.
E il file items.lua nella tua risorsa lo puoi eliminare dalla struttura e dal server_scripts: il ruolo è coperto dai data file di ox_inventory.
client.lua
-- client.lua
local ESX = exports['es_extended']:getSharedObject()
-- Crea lo shop con ox_target
CreateThread(function()
exports.ox_target:addBoxZone({
coords = Config.ShopCoords,
size = vec3(2.0, 2.0, 2.0),
rotation = 0,
debug = Config.Debug,
options = {
{
name = 'open_weapon_shop',
icon = 'fa-solid fa-gun',
label = 'Apriti Armeria',
onSelect = function()
openWeaponShop()
end,
distance = 2.5,
}
}
})
end)
function openWeaponShop()
lib.registerContext({
id = 'weapon_shop',
title = 'Armeria',
options = {
{
title = Config.WeaponLabel,
description = 'Fucile d\'assalto - ' .. Config.WeaponPrice .. '$',
icon = 'fa-solid fa-gun',
onSelect = function()
TriggerServerEvent('m4a1:buyWeapon')
end
},
{
title = 'Munizioni 5.56mm',
description = '30 proiettili - ' .. Config.AmmoPrice .. '$',
icon = 'fa-solid fa-bullseye',
onSelect = function()
TriggerServerEvent('m4a1:buyAmmo', 30)
end
},
{
title = 'Chiudi',
icon = 'fa-solid fa-xmark',
}
}
})
lib.showContext('weapon_shop')
end
-- Le notifiche arrivano dal server con exports.ox_lib:notify (vedi server.lua)
-- Sul client basta chiamare lib.notify(...) per notifiche locali.
-- Comando di debug (se Config.Debug = true)
if Config.Debug then
RegisterCommand('givem4', function()
TriggerServerEvent('m4a1:giveWeapon')
end, false)
endWARNING
Il comando di debug
givem4è accessibile a tutti i giocatori quandoConfig.Debug = true. Non abilitarlo in produzione o aggiungi un controllo ACL.
server.lua
-- server.lua
local ESX = exports['es_extended']:getSharedObject()
-- Acquisto arma
RegisterNetEvent('m4a1:buyWeapon')
AddEventHandler('m4a1:buyWeapon', function()
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return end
-- Controlla se ha già l'arma
if exports.ox_inventory:Search(source, 'count', Config.WeaponName) > 0 then
exports.ox_lib:notify(source, { title = 'Armeria', description = 'Hai già questa arma!', type = 'error' })
return
end
-- Controlla soldi
if xPlayer.getAccount('money').money >= Config.WeaponPrice then
xPlayer.removeAccountMoney('money', Config.WeaponPrice)
-- ox_inventory crea l'arma come item con le munizioni nel metadata
exports.ox_inventory:AddItem(source, Config.WeaponName, 1, { ammo = Config.DefaultAmmo })
exports.ox_lib:notify(source, { title = 'Armeria', description = Config.WeaponLabel .. ' acquistato per ' .. Config.WeaponPrice .. '$', type = 'success' })
else
exports.ox_lib:notify(source, { title = 'Armeria', description = 'Non hai abbastanza denaro! Servono ' .. Config.WeaponPrice .. '$', type = 'error' })
end
end)
-- Acquisto munizioni
RegisterNetEvent('m4a1:buyAmmo')
AddEventHandler('m4a1:buyAmmo', function(amount)
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return end
amount = tonumber(amount) or 30
local price = Config.AmmoPrice * math.ceil(amount / 30)
if xPlayer.getAccount('money').money >= price then
xPlayer.removeAccountMoney('money', price)
-- Aggiunge munizioni come item separato
exports.ox_inventory:AddItem(source, Config.AmmoType, amount)
exports.ox_lib:notify(source, { title = 'Armeria', description = amount .. ' munizioni acquistate per ' .. price .. '$', type = 'success' })
else
exports.ox_lib:notify(source, { title = 'Armeria', description = 'Non hai abbastanza denaro!', type = 'error' })
end
end)
-- Comando debug
RegisterNetEvent('m4a1:giveWeapon')
AddEventHandler('m4a1:giveWeapon', function()
local xPlayer = ESX.GetPlayerFromId(source)
if xPlayer then
exports.ox_inventory:AddItem(source, Config.WeaponName, 1, { ammo = Config.DefaultAmmo })
exports.ox_lib:notify(source, { title = 'Debug', description = Config.WeaponLabel .. ' ricevuta!', type = 'success' })
end
end)
-- All'avvio
AddEventHandler('onResourceStart', function(resourceName)
if GetCurrentResourceName() == resourceName then
print('^2[M4A1] Risorsa pronta! weapon=' .. Config.WeaponName)
end
end)Come Usare
TIP
Procedura di deploy:
- Crea l’arma custom (segui Modulo 03 - Armi Custom)
- Metti i file .ydr/.ytd/.meta in stream/
- Copia questa risorsa in resources/weapon_m4a1
- Aggiungi ensure weapon_m4a1 in server.cfg
- Riavvia il server
- Vai allo shop alle coordinate Config.ShopCoords
- Interagisci con E → compra l’arma
QUESTION
Riflessione: Quali altri eventi potresti aggiungere? Esempio: notifica quando l’arma si rompe (durabilità = 0), sistema di upgrade, o vendita dell’arma.
Verifica
- L’arma si vede nel negozio di ox_inventory
- L’acquisto scala i soldi
- L’arma appare nell’inventario
- Puoi equipaggiarla e sparare
- Le munizioni si consumano
- ox_target mostra l’opzione al punto giusto
TIP
✅ Modulo Integrazione ESX + OX completato!
Torna alla: Indice Generale