Customization
The files of nx_hud you can read and edit. Configs, data, inventory gameplay, payment methods, framework bridges, the HUD's data adapters and translations, with a worked example of a custom payment method.
Most of nx_hud is escrowed, but the parts a server owner adapts stay
plain Lua and JSON in every release. This page lists them and what each
one holds. For options that only take a value, see
Configuration. For changes made from
your own resource instead of in these files, see
Exports.
Edits take effect at the next full server restart. Keep a copy of the files you change, and carry your changes across when you update.
The readable files
| Path | What it holds |
|---|---|
config/*.lua | The five config files. See Configuration. |
data/*.lua | Items, weapons, shops, stashes, crafting, vehicles, evidence lockers, licences and animations. |
inventory/custom/client.lua | Item effects, who can be searched, the give animation, distances and the drop bag. |
inventory/custom/server.lua | Payment methods, weapon serial numbers and default loot. |
inventory/bridge/** | The inventory's framework bridges (ESX, Qbox) and their contract. |
target/bridge/** | Targeting's framework adapters (ESX, Qbox) and their contract. |
bridge/client/*.lua | Where the HUD reads status, money, fuel, the seatbelt and weapon ammo. |
inventory/server/45_give.lua | Giving an item to another player. |
inventory/server/64_vehicles.lua | Trunks and gloveboxes: sizes, owned vehicles and loot in unowned ones. |
inventory/server/66_dumpsters.lua | Dumpsters. |
inventory/server/70_shops.lua | Shops: their instances, stock, prices and the purchase. |
inventory/server/72_payments.lua | How a purchase is paid: methods, resolvers, price modifiers. |
inventory/client/60_shops.lua | Shop and bench markers, targets, shopkeepers, blips and the openers. |
inventory/server/78_licenses.lua | Buying licences. |
inventory/server/80_commands.lua | The admin inventory commands. |
inventory/server/88_compat.lua | convertinventory and what ox_inventory keeps for old scripts. |
server/vehicle.lua | Indicator sync for a driver who is not the vehicle's network owner. |
target/client/70_defaults.lua | The built-in vehicle door options of targeting. |
compat/ui/80_esx.lua | Showing ESX's own notifications and prompts in the HUD. |
compat/ui/81_sharedprefs.lua | Per-player preferences that several scripts share. |
compat/core/server/60_txadmin.lua | txAdmin announcements and warnings shown as notifications. |
inventory/locales/*.json, target/locales/*.json, compat/locales/*.json | Translations. |
init.lua, compat/abi.lua and compat/imports/** are readable too,
because other resources load them when they include @ox_lib/init.lua.
They are ox_lib's modules: leave them as they are.
Data files
The files in data/ use ox_inventory's formats, so data you already have
works, and nxinv migrate apply copies yours across (see
Installation). The starter files
open with a comment that describes their shape.
nx_hud reads a few extra fields:
- Shops (
data/shops.lua): apaymentfield on a shop sets how its items are paid for. Give it one name (payment = 'bank') to fix the payment, or a list (payment = { 'money', 'bank' }) to let the player pick in the shop. The first name in the list is the default. Shops without apaymentusepayments.choicesfromconfig/inventory.lua(cash or card out of the box). Acurrencyfield on an item names an item or a payment method. It wins over the shop'spayment, unless it is one of the names in the list, in which case the player can still pick. - Licences (
data/licenses.lua): acurrencyorpaymentfield sets what the licence is paid with. Before anything is charged, the player confirms the price and how it's paid (see Buying a licence). - Crafting (
data/crafting.lua): recipes takechance,hideChance,failResult,requiresandresultMetadata. The bench shows the chance and what a recipe still needs. See Recipe fields. - Items (
data/items.lua):accessorymakes an item wearable,backpackmakes a worn bag,armoura plate carrier andplatean armour plate (see Wearable items).carrymakes the character carry the item in their hands (see Carrying items).
Wearable items
An item with an accessory field can be worn. While worn it sits in its
gear slot, next to the pockets (see
Worn gear). The sockets it can go
on are set in NxInventory.accessories.sockets: back, vest, watch
(the left wrist) and bracelet (the right wrist) out of the box.
One socket. socket names it, and male and female give the
clothing numbers:
['watch_classic'] = { label = 'Classic Watch', weight = 100, stack = false,
accessory = { socket = 'watch', male = { drawable = 0, texture = 0 }, female = { drawable = 0, texture = 0 } } },Several sockets. sockets lists each socket the item fits, each with
its own clothing numbers. One bracelet item then goes on either wrist:
['bracelet_bangles_red'] = { label = 'Red Bangles', weight = 60, stack = false,
accessory = { sockets = {
watch = { male = { drawable = 40, texture = 3 }, female = { drawable = 29, texture = 3 } },
bracelet = { male = { drawable = 8, texture = 3 }, female = { drawable = 15, texture = 3 } },
} } },- Using the item, or wearing it from code with
setWorn(source, slot, true), puts it on the first free socket. When all of them are taken, it replaces the item on the first one. Using a worn item takes it off. An item that has a use of its own (a weapon, ammo, an item that is used up, or a usable item of your framework) keeps that use, and is worn from its menu. - "First" follows
NxInventory.accessories.order: with the default, the left wrist, then the right. Addorder = { 'bracelet', 'watch' }inside an item'saccessoryto change the order for that item. - The item's menu offers each socket ("Put on left wrist", "Put on right wrist"), and the player can drag it onto either gear slot.
- A worn item remembers its socket, so it is on the same wrist after a relog.
A socket entry can be true instead of a table to use the accessory's
own male and female numbers. sockets can also be a list,
{ { socket = 'watch', male = {...} }, { socket = 'bracelet', ... } },
whose order is then the item's order.
Looks. male is used for the male freemode ped and any other model,
female for the female freemode ped. A look keyed by a model name, such
as ['a_m_y_hipster_01'] = { drawable = 2, texture = 0 }, is used for
that model. A flat { drawable, texture } in place of male and
female fits every model. An accessory table in the item's metadata
wins over the item's own, so one item name can come in many looks.
Bags and vests. On the back socket, backpack = { slots, maxWeight, bonus } makes a bag with its own grid. While it is worn,
bonus (by default its maxWeight) is added to what the pockets hold,
and it cannot come off while the pockets would then be over their limit.
On the vest socket, armour = { plates = n } makes a plate carrier
that takes items with plate = { armour = n }. See
Armour plates.
['backpack'] = { label = 'Backpack', weight = 5000, stack = false, close = false,
accessory = { socket = 'back', male = { drawable = 45, texture = 0 }, female = { drawable = 45, texture = 0 } },
backpack = { slots = 15, maxWeight = 25000, bonus = 25000 } },
['heavypc'] = { label = 'Heavy Bulletproof Vest', weight = 1500, stack = false, consume = 0,
accessory = { socket = 'vest', male = { drawable = 4, texture = 0 }, female = { drawable = 4, texture = 0 } },
armour = { plates = 2 } },
['heavyplate'] = { label = 'Heavy Plate', weight = 500, stack = false, plate = { armour = 50 } },inventory/custom/client.lua
The client side of the inventory's gameplay, in the NxInventoryClient
table.
keepOpen: how far a player can walk from an open stash, drop, trunk or searched player before it closes. A stash or shop that sets its own distance uses that instead.pickupRadius: the inventory key opens the closest drop, stash, shop or bench within this distance.drop: the bag model a drop shows when drop props are on. Theinventory:dropmodelconvar wins over it.giveAnim: the animation played when a player gives an item.falseplays none.searchableAnimsandcanBeSearched(ped, info): when other players may search this player. By default that is a dead, downed or cuffed player, or one with their hands up. Police can search anyone. A server resource can take this decision over withsetSearchCheck.effects: what using an item does, keyed by item name. They run only for items indata/items.luawith noclient.exportorclient.eventof their own. Shipped effects:bandage,armour,parachute,phone(npwd) andclothing.
An effect receives (itemDef, item, slot, inv). inv holds helpers:
| Helper | What it does |
|---|---|
inv.use(itemDef, onUsed) | Use the item up through the server, then run onUsed. Skip it and nothing is used up. |
inv.notify(text, type) | Show a notification. |
inv.text(key, fallback) | A string from the inventory's locale files. |
inv.loadModel(model) | Load a model before you use it. |
inv.warn(msg), inv.error(msg) | Write to the client console. |
inv.wearParachuteBag(ped) | Put the parachute bag on the ped. |
-- inventory/custom/client.lua
E.energydrink = function(itemDef, item, slot, inv)
inv.use(itemDef, function()
SetRunSprintMultiplierForPlayer(PlayerId(), 1.2)
inv.notify('You feel awake', 'success')
end)
endOther resources can override any of this at runtime with
registerItemEffect,
setStealCheck,
addOpenGate and
addUseGate.
inventory/custom/server.lua
The server side, in the NxInventoryCustom table. Two helper tables are
ready at the top of the file:
Inv:count(inv, item),remove(inv, item, count)andadd(inv, item, count).Framework:balance,removeandaddfor a player's money that the framework keeps outside the inventory, as in(src, account, amount, reason), andsociety,societyRemoveandsocietyAddfor a society account, as in(name, amount, reason).hasJob(src, job, minGrade)says whether the player holds a job at that grade or above. ESX and Qbox answer them through the framework bridge.
Payment methods
itemPayment: how a purchase paid with an item is checked and taken. This is ox_inventory's behaviour.'bank': paying by card from the player's bank account. The shop calls it "Card" and shows the bank balance.'society:*': a society account, for example'society:police'. Only members of that job can pay with it. SetSOCIETY_MIN_GRADEabove the method to the boss grade if only bosses should spend company money. On ESX it isesx_addonaccount'ssociety_<name>. On Qbox it is Renewed-Banking's account. With another banking script, fill ingetSociety,removeSocietyandaddSocietyat the bottom ofinventory/bridge/qbx/server.lua.resolvePayment: commented out. Uncomment it to choose the payment per purchase, for example cash first and the bank when the cash is short.
Every method gets (src, amount, ctx). The fields of ctx are listed
under Payments. Besides canAfford,
charge and refund, a method can have:
balance(src, ctx): the amount the player has. The shop shows it next to the method and limits the amount a player can buy by it. Without it, the shop shows only the label and the purchase decides.allowed(src, ctx): returnfalseand a reason to keep the method from this player. It drops out of the player's choices, and items priced only in it are locked with the reason.prefixandsuffix: how an amount reads. Both left out gives$1,000.prefix = '', suffix = ' chips'gives1,000 chips.
In the shop, the player switches between the shop's methods with Q and E, or by clicking the method at the bottom left. The last choice is remembered for every shop that takes it.
Serial numbers and loot
serial(code): a new weapon's serial number.codeis set for service weapons ('POL') andnilotherwise.vehicleLootanddumpsterLoot: the loot rows used when theinventory:vehiclelootandinventory:dumpsterlootconvars are not set. A row is{ item, min, max, chance }, with the chance in percent (80 when left out).
Worked example: a card with a fee
Cash or card works out of the box: bank is the card, and every shop
without a payment offers both. This example adds a second card that
charges the bank account plus a 2 % fee, and puts it in one shop.
1. Register the method at the end of the payments section of
inventory/custom/server.lua, below the 'society:*' method:
-- currency = 'card': the bank account, plus a 2 % card fee
local CARD_FEE = 0.02
local function withFee(amount) return math.ceil(amount * (1 + CARD_FEE)) end
Custom.registerPaymentMethod('card', {
label = 'Card, 2% fee',
balance = function(src) return Framework.balance(src, 'bank') end,
canAfford = function(src, amount) return (Framework.balance(src, 'bank') or 0) >= withFee(amount) end,
charge = function(src, amount, ctx) return Framework.remove(src, 'bank', withFee(amount), ctx.reason) end,
refund = function(src, amount, ctx) return Framework.add(src, 'bank', withFee(amount), ctx.reason) end,
})amount is the purchase total, so the fee is worked out per purchase.
refund gives the whole charge back if the goods cannot be placed, for
example when the player's pockets are full.
2. Use it in a shop in data/shops.lua. List it in the shop's
payment so players can pick it, and set currency on an item to make
an exception:
corner_store = {
name = 'Corner store',
payment = { 'money', 'card' },
blip = { id = 52, colour = 69, scale = 0.7 },
inventory = {
{ name = 'water', price = 4 },
{ name = 'sandwich', price = 9 },
{ name = 'coffee', price = 5, currency = 'money' }, -- cash only
},
-- locations and targets as before
},3. Restart the whole server. In the shop the player sees
Card, 2% fee with their bank balance and can switch to it with
Q / E. Prices show without the fee, so the label is
where players learn about it. Purchase messages read $9 (Card, 2% fee).
The same method works for a licence in data/licenses.lua:
{ name = 'weapon', coords = vec3(14.20, -1106.10, 29.80), price = 4000, currency = 'card' },Buying a licence
At a licence counter, E opens a confirmation first, so no money moves on a single key press. It names the licence, the price after any licence price modifier, the payment method and, when known, the balance: "Buy the Weapon licence for $2,000 by Card?" with "Balance: $8,500" underneath. Cash prices show what the player is carrying instead. Nothing is charged until the player presses Buy, and Cancel (or Esc) walks away.
When the purchase can't go ahead, the player is told why instead of seeing a dialog:
| Situation | What the player sees |
|---|---|
| Already has the licence | "You already have the Weapon licence" |
| Can't afford it | "You can not afford the Weapon licence ($2,000)" |
The method isn't available to them (its allowed said no) | "You can not pay for the Weapon licence: " followed by the method's reason |
A buyLicense hook refused | "You can not buy the Weapon licence right now" |
The server checks everything again when the player confirms, so a
balance that changed in the meantime is still caught. The new texts are the
nx_licence_* keys in inventory/locales/.
To register the method from your own resource instead, call
exports.nx_hud:registerPaymentMethod
with the same table. The Framework helpers exist only inside
inventory/custom/server.lua, so take the money through your banking
script's exports there.
Inventory framework bridges
inventory/bridge/ holds one folder per framework, each with a
client.lua and a server.lua: esx and qbx. The bridge that runs is
the one named by the inventory:framework convar. It attaches when its
framework starts and detaches when it stops.
inventory/bridge/_interface.lua is the contract. Its header lists every
function a bridge can provide: player data and groups, boss checks, the
framework's usable items, licences, money outside the inventory
(getMoney, removeMoney, addMoney), society accounts
(getSociety, removeSociety, addSociety), owned vehicles and
inventory conversion. Every field is optional. A missing one falls back
to ox_inventory's default, and a payment method that needs a missing
money function refuses the purchase and says so in the console.
To support a framework of your own, write
inventory/bridge/<name>/client.lua and server.lua against that file,
set inventory:framework to <name>, and add both files to
fxmanifest.lua. The manifest names each bridge file one by one,
because FiveM's file patterns do not match a wildcard folder:
-- fxmanifest.lua
client_scripts {
-- ...
'inventory/bridge/esx/client.lua',
'inventory/bridge/qbx/client.lua',
'inventory/bridge/mycore/client.lua', -- add
-- ...
}
server_scripts {
-- ...
'inventory/bridge/esx/server.lua',
'inventory/bridge/qbx/server.lua',
'inventory/bridge/mycore/server.lua', -- add
-- ...
}nxinv bridge in the server console shows which bridge is selected and
whether it is attached.
Targeting framework adapters
target/bridge/ works the same way for targeting, client side only:
target/bridge/_interface.lua is the contract, and esx/client.lua and
qbx/client.lua answer the job, gang and item checks of target options.
A new adapter is target/bridge/<name>/client.lua, added to
client_scripts in fxmanifest.lua next to the other two. Without an
adapter, targeting still works, but options limited to a job or gang
show for everyone.
The HUD's data adapters
bridge/client/ is where the HUD reads its numbers. 00_core.lua
describes the contract at the top.
10_framework.lua: hunger, thirst, stress and money for Qbox, QBCore and ESX (throughesx_status).20_fuel.lua: the fuel scriptsConfig.fuel = 'auto'looks for, in order, and how each one is read.30_seatbelt.lua: the seatbelt scriptsConfig.seatbelt = 'auto'follows, and how each one is read.40_ammo.lua: what the weapon pill shows for a weapon whose rounds a script keeps itself. Scripts register withregisterAmmoReader.
To add a fuel script that is not on the list, add an entry to ADAPTERS
and its name to ORDER in 20_fuel.lua:
['my_fuel'] = { read = export('my_fuel', 'GetFuel') }, -- the export answers 0 to 100A seatbelt script goes into SCRIPTS in 30_seatbelt.lua:
{ res = 'my_seatbelt', read = function() return exports.my_seatbelt:IsBuckled() == true end },If you write the fuel or seatbelt script yourself, registering it from
that script with
registerFuelReader or
registerSeatbeltReader
keeps your change out of nx_hud's files. /hud bridge in F8 prints
which adapters answer.
Gameplay modules
These files carry ox_inventory's behaviour for one feature each. They are readable so you can see exactly what happens, and change it when your server needs something else:
45_give.lua: giving to another player. The range isNxInventory.rules.giveRange; both players must be in the same routing bucket whilestrict.sameBucketGiveis on.64_vehicles.lua: trunks and gloveboxes. Sizes come fromdata/vehicles.lua; unowned vehicles get random loot whileinventory:randomlootis on.66_dumpsters.lua: dumpsters. Their size isNxInventory.rules.dumpster, and they are never saved.70_shops.lua: shops. Opening one, its stock and prices, and a purchase in order: checks, thebuyItemhook, the charge and the goods.72_payments.lua: payment methods, resolvers and price modifiers. Prefer the exports andinventory/custom/server.lua; change this file only for what they cannot do.client/60_shops.lua: the client side of shops, benches and licence counters: markers, targets, shopkeeper peds, blips and the openers.78_licenses.lua: buying a licence at its counter, through the payment methods and thebuyLicensehook.80_commands.lua: the admin commands and their ACE groups. See Commands.88_compat.lua:convertinventoryand the callbacks old scripts still call.
The client and HUD files in the same group:
server/vehicle.lua: lets a driver who is not the vehicle's network owner set the indicators. Only the driver may, at most ten times a second.target/client/70_defaults.lua: the six built-in vehicle door options.compat/ui/80_esx.lua: showsesx_notifyandesx_textuicalls in the HUD while those resources are stopped (Compat.esx).compat/ui/81_sharedprefs.lua: shared preferences other scripts read.compat/core/server/60_txadmin.lua: txAdmin announcements, direct messages and restart warnings as notifications, and warnings as an alert dialog. Off unlesssetr ox:txAdminNotifications 1, and each one only while txAdmin hides its own version.
Translations
nx_hud ships in ten languages: English (en), Suomi (fi), Deutsch
(de), Français (fr), Português do Brasil (pt-br), Español (es),
Türkçe (tr), Nederlands (nl), Italiano (it) and Polski (pl). That
covers the HUD and its settings sheet, notifications, menus and dialogs,
the inventory with its shops, crafting and licences, and targeting.
- Set the server's language with
Compat.localeinconfig/compat.lua. Asetr ox:localeline inserver.cfgoverrides it. - Each player can switch their own language in the
/ox_libsettings menu.setr ox:userLocales 0turns that off, so everyone sees the server's language. - A line missing from a translation falls back to English.
| Folder | Covers | Ships with |
|---|---|---|
compat/locales/ | The HUD, its settings sheet, notifications, menus and dialogs | The ten languages above. The ox_lib basics (Confirm, Cancel, the settings menu) also come in 26 more. |
inventory/locales/ | The inventory, shops, crafting and licences | The ten languages above |
target/locales/ | Targeting | The ten languages above |
To add a language, copy en.json to <code>.json in each folder and
translate the values. Keep the keys and any %s as they are. Spotted a
wrong translation, or need another language? Tell us on Discord.
Configuration
Every option in config/hud.lua, config/compat.lua, config/inventory.lua, config/target.lua and config/settings.lua for nx_hud, plus the ox convars it reads.
Exports
The nx_hud API for other resources. HUD visibility, status, fuel, seatbelt and ammo readers, player settings, inventory gates and item effects, worn gear, payment methods, shop prices, crafting benches, combine recipes and the new hook events.