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 meta devuelve nil. GetItemData también devuelve nil cuando el jugador no tiene el objeto, RemoveItem devuelve false cuando no tiene suficientes y AddItem devuelve false con 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').

ExportParámetrosDevuelve
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):

CampoPor defectoDescripció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
durationritmo de lecturaDuración de la línea de voz en ms: el texto se escribe exactamente en ese tiempo
optionsningunaHasta 4 { id, label, close? }, visibles cuando la frase termina de escribirse. close = true cierra la caja tras elegir
cameratrueEncuadrar al NPC. false mantiene la cámara de juego
focustrueEl teclado y el ratón van a la caja. false = solo visualización, sin entrada
talktruefalse = hz_lib no mueve los labios del NPC (si tu recurso lo anima por su cuenta)
maxDistance4.0Distancia 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
Motivos de cierre:
MotivoCuá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 OpenDialogue de tu recurso reemplaza el tuyo. El diálogo de otro recurso nunca se sustituye: recibes nil, 'busy'.
  • SayDialogue y CloseDialogue solo actúan sobre tu propio diálogo; sin id, se aplican a él.
  • Opción con close = true: primero vuelven la cámara, el HUD y los controles, luego onSelect y después onClose('select'). Así puedes abrir tu propio menú desde onSelect.
  • Opción sin close: responde con SayDialogue desde onSelect. Si no lo haces, vuelven las mismas opciones. Una frase enviada con options = {} (o sin opciones) no muestra ninguna opción.
  • name y role omitidos en SayDialogue se 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. Devuelve false mientras 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.

ExportParámetrosDevuelve
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:

CampoTipoDescripción
idstringIdentificador del paso, usado por UpdateObjective
textstringTexto del paso
statestring'todo' (por defecto), 'current' o 'done'
detailstringSegunda línea, visible solo bajo el paso en curso
valuenumberContador a la derecha del paso
maxnumberCon value: muestra value / max y una barra en el paso en curso
unitstringUnidad tras el contador (L, crates…)
  • UpdateObjective fusiona patch en un paso (value, state, text, detail…). Devuelve false si 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.