Exports & API
hz_lib expose 140+ exports utilisables depuis n'importe quelle ressource. Tous les exports sont disponibles vía exports['hz_lib'].
Meta / Detection
-- Client & server
local Bridge = exports['hz_lib']:GetBridge() -- full Bridge table (advanced usage)
local framework = exports['hz_lib']:GetDetectedFramework() -- 'esx', 'qbcore', 'qbox', etc.
local inventory = exports['hz_lib']:GetDetectedInventory() -- 'ox_inventory', etc.
-- Client only
local notify = exports['hz_lib']:GetDetectedNotifications() -- 'ox_lib', etc.
local dispatch = exports['hz_lib']:GetDetectedDispatch() -- 'cd_dispatch', etc.
local target = exports['hz_lib']:GetDetectedTarget() -- 'ox_target', etc.
local menu = exports['hz_lib']:GetDetectedMenu() -- 'ox_lib', 'qb-menu', etc.
-- Server only
local banking = exports['hz_lib']:GetDetectedBanking() -- 'qb-banking', 'hz_banking', 'none', etc.
Framework
Client
-- Get current player job
local job = exports['hz_lib']:GetPlayerJob()
-- Get full player data
local data = exports['hz_lib']:GetPlayerData()
Server
-- Get player info
local job = exports['hz_lib']:GetPlayerJob(source)
local data = exports['hz_lib']:GetPlayerData(source)
local charId = exports['hz_lib']:GetPlayerCharId(source)
local name = exports['hz_lib']:GetPlayerName(source)
-- Money
local canPay = exports['hz_lib']:CanAfford(source, 500)
exports['hz_lib']:AddMoney(source, 500, 'bank')
exports['hz_lib']:RemoveMoney(source, 500, 'cash')
-- Job queries
local cops = exports['hz_lib']:GetPlayersWithJob({'police', 'sheriff'}, 0)
-- Usable items
exports['hz_lib']:RegisterUsableItem('phone', function(source)
-- player used the item
end)
Inventaire (Server)
-- Check items
local count = exports['hz_lib']:GetItemCount(source, 'bread')
local itemData = exports['hz_lib']:GetItemData(source, 'bread')
local has = exports['hz_lib']:HasItem(source, 'bread', 1)
local canFit = exports['hz_lib']:CanCarry(source, 'bread', 5)
-- Add / Remove
exports['hz_lib']:AddItem(source, 'bread', 5)
exports['hz_lib']:RemoveItem(source, 'bread', 1)
exports['hz_lib']:AddItemToFit(source, 'bread', 5) -- Only add if can carry
-- Stash
exports['hz_lib']:OpenStash(source, 'my_stash', 'My Stash', 50, 100000)
local content = exports['hz_lib']:GetStashContent('my_stash')
Desde la v1.2.0, GetItemData(source, item, meta) devuelve un objeto con ese nombre cuyos metadatos contienen cada clave y valor de meta, o nil si ninguno coincide:
local card = exports['hz_lib']:GetItemData(source, 'id_card', { citizenid = 'ABC12345' })
if not card then
-- el jugador no lleva esa tarjeta en concreto
end
- ox_inventory, qb-inventory y el inventario nativo de QBCore recorren todas las pilas del objeto; ps, qs, codem, origen, tgiann, core y ak47 comprueban la pila que el inventario devuelve primero.
- El inventario nativo de ESX no guarda metadatos, así que una búsqueda con
metadevuelvenil.GetItemDatatambién devuelvenilcuando el jugador no tiene el objeto,RemoveItemdevuelvefalsecuando no tiene suficientes yAddItemdevuelvefalsecon un objeto desconocido.
Banca / Sociedad (Server)
El dinero de una cuenta de sociedad (la cuenta del jefe de un trabajo o de una banda), enviado al banco configurado en HZBridge.Banking.
local balance = exports['hz_lib']:GetSocietyMoney('mechanic')
exports['hz_lib']:AddSocietyMoney('mechanic', 500, 'Repair')
local paid = exports['hz_lib']:RemoveSocietyMoney('mechanic', 200, 'Parts') -- false if refused
-- Can the detected bank really read balances and take money?
local supports = exports['hz_lib']:GetBankingSupports() -- { get = true|false, remove = true|false }
Algunos bancos solo permiten añadir dinero. Cuando supports.get o supports.remove es false, un saldo de 0 o un false de RemoveSocietyMoney significa "no compatible", no "vacío". Con HZBridge.Banking = 'none', añadir y retirar devuelven false y el saldo es 0.
Notifications
Client
exports['hz_lib']:Notify('Item added!', 'success', 3000)
Server
-- Notify one player
exports['hz_lib']:NotifyPlayer(source, 'Welcome!', 'info', 5000)
-- Notify all players
exports['hz_lib']:NotifyAll('Server restart in 5 minutes', 'warning', 10000)
Types : 'info', 'success', 'warning', 'error'
Dispatch (Client)
exports['hz_lib']:SendDispatch({
title = 'Robbery in progress',
message = '10-90 at Fleeca Bank',
coords = GetEntityCoords(PlayerPedId()),
jobs = {'police'},
blip = { sprite = 161, color = 1, scale = 1.0 },
})
Target (Client)
-- Add target to entity
exports['hz_lib']:AddTargetEntity(entity, {
{ label = 'Open', icon = 'fas fa-door-open', action = function(e) end },
})
-- Add target to zone
exports['hz_lib']:AddTargetZone('my_zone', {
coords = vector3(0, 0, 0),
size = vec3(2.0, 2.0, 2.0), -- box size, optional (default 2 x 2 x 2)
rotation = 0.0, -- optional
options = { { label = 'Interact', action = function() end } },
})
-- Add target to model
exports['hz_lib']:AddTargetModel('prop_vendmach_01', {
{ label = 'Buy drink', icon = 'fas fa-coffee', action = function() end },
})
-- Remove
exports['hz_lib']:RemoveTarget('my_zone')
Menú / UI (Client)
Menú contextuel
-- Quick: register + show in one call
exports['hz_lib']:ContextMenu('my_menu', 'My Menu', {
{
title = 'Option 1',
description = 'Description here',
icon = 'fas fa-star',
onSelect = function(args) print('selected!') end,
},
{
title = 'Sub Menu',
menu = 'my_submenu', -- Opens another registered context
},
})
-- Or register and show separately
exports['hz_lib']:RegisterContext({
id = 'my_menu',
title = 'My Menu',
options = { --[[ ... ]] },
})
exports['hz_lib']:ShowContext('my_menu')
-- Hide / Query
exports['hz_lib']:HideContext()
local openId = exports['hz_lib']:GetOpenContext()
Dialogue de saisie
local result = exports['hz_lib']:InputDialog('Enter Details', {
{ type = 'input', label = 'Name', placeholder = 'John Doe', required = true },
{ type = 'number', label = 'Amount', default = 100 },
{ type = 'select', label = 'Type', options = {
{ value = 'a', label = 'Option A' },
{ value = 'b', label = 'Option B' },
}},
})
if result then
local name, amount, type = result[1], result[2], result[3]
end
Dialogue d'alerte
local response = exports['hz_lib']:AlertDialog({
header = 'Confirm Action',
content = 'Are you sure you want to proceed?',
centered = true,
cancel = true,
})
if response == 'confirm' then
-- User confirmed
end
TextUI
exports['hz_lib']:ShowTextUI('[E] Interact', {
position = 'right-center',
icon = 'fas fa-hand-pointer',
})
exports['hz_lib']:HideTextUI()
local isOpen = exports['hz_lib']:IsTextUIOpen()
Barre de progression
local completed = exports['hz_lib']:ProgressBar({
duration = 5000,
label = 'Crafting...',
canCancel = true,
disable = { move = true, combat = true },
anim = { dict = 'mini@repair', clip = 'fixing_a_player' },
})
if completed then
-- Finished
else
-- Cancelled
end
-- Circle variant
local done = exports['hz_lib']:ProgressCircle({ duration = 3000, label = 'Loading...' })
-- Query / Cancel
local active = exports['hz_lib']:IsProgressActive()
exports['hz_lib']:CancelProgress()
Menú liste
exports['hz_lib']:RegisterMenu({
id = 'my_list',
title = 'Select Item',
options = {
{ label = 'Item 1', description = 'First item' },
{ label = 'Item 2', description = 'Second item' },
},
}, function(selected, scrollIndex, args)
print('Selected index:', selected)
end)
exports['hz_lib']:ShowMenu('my_list')
exports['hz_lib']:HideMenu()
Tout fermer
exports['hz_lib']:CloseAllMenus() -- Close any open menu/context/input/alert/progress
Callbacks
Server
-- Register a server callback
exports['hz_lib']:RegisterCallback('myResource:getData', function(source, arg1, arg2)
return { money = 1000, name = 'John' }
end)
-- Call a client callback from server
local result = exports['hz_lib']:TriggerClientCallback(source, 'myResource:clientCheck')
Client
-- Call a server callback (blocking)
local data = exports['hz_lib']:TriggerCallback('myResource:getData', arg1, arg2)
print(data.money) -- 1000
-- Register a client callback
exports['hz_lib']:RegisterClientCallback('myResource:clientCheck', function()
return GetEntityCoords(PlayerPedId())
end)
Minijeux (Client)
-- Progress with coordinates
local success = exports['hz_lib']:MinigameProgress(coords, 5000, {
label = 'Searching...',
})
-- Sequence minigame
local passed = exports['hz_lib']:SequenceMinigame(coords, 5, {
label = 'Enter code',
})
-- Skill check
local passed = exports['hz_lib']:SkillCheck('medium', {'w', 'a', 's', 'd'})
Diálogo con NPC (Client)
Una caja de diálogo en la parte inferior de la pantalla para hablar con un NPC. La frase del NPC se escribe, al ritmo de su voz si pasas duration, y luego aparecen hasta cuatro opciones numeradas. Mientras está abierta, la cámara encuadra al NPC por encima del hombro del jugador, el NPC mueve los labios al hablar y ambos personajes se miran. El HUD se oculta, y el menú de pausa, el combate y el movimiento quedan bloqueados hasta que se cierra.
El jugador elige con las teclas 1 a 4, las flechas y Enter, o con el ratón. Enter (o un clic en la frase) muestra la frase completa de golpe. Escape cierra la caja. Los indicadores de teclas siguen HZBridge.Locale ('en' o 'fr').
| Export | Parámetros | Devuelve |
|---|---|---|
OpenDialogue | (data) | id del diálogo, o nil, 'busy' / nil, 'invalid' |
SayDialogue | (id, data) | boolean |
CloseDialogue | (id?) | boolean |
IsDialogueOpen | () | boolean |
SelectDialogue | (id, optionId) | boolean |
local dialogueId
dialogueId = exports['hz_lib']:OpenDialogue({
ped = ped, -- el NPC que habla
name = 'Rosa Ortiz',
role = 'Mechanic',
text = 'Hey. What can I do for you?',
duration = 1900, -- duración de la línea de voz que reproduces (ms), opcional
options = {
{ id = 'repair', label = 'Repair my car' },
{ id = 'leave', label = 'Never mind', close = true },
},
onSelect = function(optionId)
if optionId == 'repair' then
exports['hz_lib']:SayDialogue(dialogueId, {
text = 'That will be $250. Deal?',
options = {
{ id = 'pay', label = 'Deal', close = true },
{ id = 'no', label = 'Too expensive', close = true },
},
})
elseif optionId == 'pay' then
TriggerServerEvent('my_garage:repair')
end
end,
onClose = function(reason)
-- 'select', 'escape', 'replaced', 'closed', 'too_far' o 'stopped'
end,
})
if not dialogueId then
-- el diálogo de otro recurso está en pantalla
end
Campos de OpenDialogue (SayDialogue acepta los mismos, salvo ped y camera):
| Campo | Por defecto | Descripción |
|---|---|---|
ped | — | El NPC que habla. Sin él: ni cámara ni control de distancia |
name | — | Nombre mostrado como título |
role | — | Línea pequeña sobre el nombre. false en SayDialogue la quita |
text | — | La frase del NPC |
duration | ritmo de lectura | Duración de la línea de voz en ms: el texto se escribe exactamente en ese tiempo |
options | ninguna | Hasta 4 { id, label, close? }, visibles cuando la frase termina de escribirse. close = true cierra la caja tras elegir |
camera | true | Encuadrar al NPC. false mantiene la cámara de juego |
focus | true | El teclado y el ratón van a la caja. false = solo visualización, sin entrada |
talk | true | false = hz_lib no mueve los labios del NPC (si tu recurso lo anima por su cuenta) |
maxDistance | 4.0 | Distancia al NPC, en metros, a partir de la cual el diálogo se cierra |
onSelect | — | function(optionId, dialogueId), llamada en cada elección |
onClose | — | function(reason), llamada una vez al terminar el diálogo |
| Motivo | Cuándo |
|---|---|
'select' | El jugador eligió una opción con close = true |
'escape' | El jugador pulsó Escape |
'replaced' | Tu recurso abrió un nuevo diálogo |
'closed' | Llamaste a CloseDialogue |
'too_far' | El jugador se alejó más de maxDistance, el NPC desapareció, o el NPC o el jugador murió |
'stopped' | Tu recurso (o hz_lib) se detuvo |
- Un solo diálogo en pantalla a la vez. Un nuevo
OpenDialoguede tu recurso reemplaza el tuyo. El diálogo de otro recurso nunca se sustituye: recibesnil, 'busy'. SayDialogueyCloseDialoguesolo actúan sobre tu propio diálogo; sinid, se aplican a él.- Opción con
close = true: primero vuelven la cámara, el HUD y los controles, luegoonSelecty despuésonClose('select'). Así puedes abrir tu propio menú desdeonSelect. - Opción sin
close: responde conSayDialoguedesdeonSelect. Si no lo haces, vuelven las mismas opciones. Una frase enviada conoptions = {}(o sin opciones) no muestra ninguna opción. nameyroleomitidos enSayDialoguese mantienen.- hz_lib no reproduce ninguna voz: reproduce tú la línea de voz del NPC y pasa su duración en
duration. Los sonidos del menú del juego acompañan el paso del ratón, la elección y Escape. SelectDialogue(id, optionId)elige una opción en lugar del jugador (escenas guionizadas, tutoriales): la fila se muestra seleccionada un instante y luego se ejecuta exactamente como la elección de un jugador. Devuelvefalsemientras la frase se escribe, o con un id u opción desconocidos.- Sin cámara cuando el jugador está en un vehículo, o cuando la cámara de otro script ya está activa. Si hay una pared detrás del hombro del jugador, se usa otro ángulo.
- Los textos se muestran tal cual: tradúcelos en tu recurso. Un error en tus callbacks se muestra en la consola F8 sin romper el diálogo.
Seguimiento de objetivos (Client)
Muestra los pasos de un trabajo o una misión en la pantalla del jugador: un título y luego cada paso con su estado. El paso en curso puede llevar una línea de detalle, un contador y una barra de progreso. Lo dibuja hz_lib: todos los scripts HZ comparten el mismo aspecto, los colores de tu tema y un único lugar en pantalla.
| Export | Parámetros | Devuelve |
|---|---|---|
SetObjectives | (id, { kicker?, title, steps }) | boolean |
UpdateObjective | (id, stepId, patch) | boolean |
ClearObjectives | (id) | boolean |
-- Crea (o reemplaza) el seguimiento 'delivery' de tu recurso
exports['hz_lib']:SetObjectives('delivery', {
kicker = 'Delivery',
title = 'Objectives',
steps = {
{ id = 'load', text = 'Load the truck', detail = 'Warehouse 3, Elysian Island', value = 0, max = 12, unit = 'crates', state = 'current' },
{ id = 'drop', text = 'Deliver to Grove Street', state = 'todo' },
},
})
-- Progreso y luego el paso siguiente
exports['hz_lib']:UpdateObjective('delivery', 'load', { value = 5 })
exports['hz_lib']:UpdateObjective('delivery', 'load', { state = 'done' })
exports['hz_lib']:UpdateObjective('delivery', 'drop', { state = 'current' })
-- Trabajo terminado
exports['hz_lib']:ClearObjectives('delivery')
Campos de un paso:
| Campo | Tipo | Descripción |
|---|---|---|
id | string | Identificador del paso, usado por UpdateObjective |
text | string | Texto del paso |
state | string | 'todo' (por defecto), 'current' o 'done' |
detail | string | Segunda línea, visible solo bajo el paso en curso |
value | number | Contador a la derecha del paso |
max | number | Con value: muestra value / max y una barra en el paso en curso |
unit | string | Unidad tras el contador (L, crates…) |
UpdateObjectivefusionapatchen un paso (value,state,text,detail…). Devuelvefalsesi el seguimiento o el paso no existe.- Los identificadores pertenecen a tu recurso: dos recursos pueden usar
'delivery'sin conflicto. Varios seguimientos se apilan en una misma columna. - Cinco líneas como máximo: primero se van los pasos terminados más antiguos; si no basta, cuatro pasos y una línea
+N. - Los textos se muestran tal cual: tradúcelos en tu recurso.
- El seguimiento se oculta mientras el menú de pausa o el mapa están abiertos, y desaparece cuando tu recurso se detiene.
- Cuando hz_lib se reinicia, lanza el evento de cliente
hz_lib:objectives:ready: vuelve a enviar tus seguimientos desde ahí.
AddEventHandler('hz_lib:objectives:ready', function()
if onJob then exports['hz_lib']:SetObjectives('delivery', currentTracker) end
end)
Por defecto, la lista aparece a la izquierda de la pantalla. Puedes moverla en /hzpanel > Appearance > Objectives tracker: Screen side (left o right) y Height (% desde arriba, 26 por defecto). Sube la altura si la lista tapa otro elemento del HUD.
Admin Panel (Server)
-- Ouvre le panneau d'administration centralise pour un joueur (meme effet que taper /hzpanel).
-- Le second argument preselectionne optionnellement l'onglet d'un module.
exports['hz_lib']:OpenPanel(source)
exports['hz_lib']:OpenPanel(source, 'hz_weather')
Consultez le guide Panneau d'administration pour le DSL de schema, les types de champ et l'enregistrement de vues.
Theme (Server & Client)
L'onglet Apparence du panneau d'administration ecrit un theme partage unique utilise par chaque NUI HZ. Les ressources peuvent lire le theme actuel de maniere synchrone, ou s'abonner aux mises a jour en direct.
Server
-- Get the current effective theme (accent + surfaces + gradient mode + radii + fonts).
local theme = exports['hz_lib']:GetTheme()
-- Subscribe to admin changes server-side.
AddEventHandler('HZ-Bridge:theme:updated', function(theme)
-- theme: { preset, accent, accentHi, gold, surface, subpanel, tint,
-- gradientMode, radiusNone, radiusXs, radiusSm, ..., radiusXl,
-- fontDisplay, fontBody, fontNumber,
-- fonts = { display, body, number, href } }
end)
Client
-- Live updates from the admin panel.
RegisterNetEvent('HZ-Bridge:theme:updated', function(theme)
SendNUIMessage({ action = 'theme', data = theme })
end)
-- Pull the current theme on resource start so first paint is themed.
TriggerServerEvent('HZ-Bridge:theme:request')
Le serveur repond vía TriggerClientEvent('HZ-Bridge:theme:updated', src, theme) donc le meme handler s'execute pour la synchronisation initiale et les mises a jour en direct.
