Scripting

Guía de ox_inventory: cómo instalarlo y agregar items

Aprende a instalar ox_inventory y a agregar items personalizados: campos de items.lua, imágenes, items usables, metadata y errores comunes en FiveM.

· 12 min de lectura

ox_inventory es el inventario por slots de Overextended, el equipo detrás de ox_lib y ox_target. Reemplaza los sistemas de items, inventario y armas que trae tu framework con un solo resource que maneja inventarios de jugadores, stashes, shops, maleteros, guanteras y drops, y valida en el servidor cada movimiento de items. Es el inventario por defecto en Qbox y una mejora muy popular en ESX.

En esta guía vemos qué soporta ox_inventory, cómo instalarlo y, sobre todo, cómo agregar items en ox_inventory: los campos de data/items.lua, las imágenes de los items, cómo hacer un item usable, cómo dar items desde código, la metadata y los errores con los que más te vas a topar.

Versión corta: instala oxmysql y ox_lib, descarga el release ox_inventory.zip, configura inventory:framework en server.cfg e inícialo justo después de tu framework. Para agregar un item, defínelo en data/items.lua, pon un <item_name>.png en web/images/, reinicia y dalo con exports.ox_inventory:AddItem(source, 'item_name', 1).

Qué soporta ox_inventory

ox_inventory se comunica con tu framework mediante un bridge, que eliges con la convar inventory:framework. Los frameworks con soporte oficial son:

FrameworkValor de la convarNotas
ox_coreoxEl framework propio de Overextended
ESX LegacyesxRequiere ESX Legacy 1.6.0 o superior. También es el valor por defecto si no configuras la convar
QboxqbxQbox está construido alrededor de ox_inventory
ND Corend

QBCore no está en la lista. El release actual solo trae bridges para ox, ESX, Qbox y ND. Si usas QBCore y quieres ox_inventory, lo más práctico es pasarte a Qbox, que corre la mayoría de los scripts de QBCore con su propio bridge. Revisa Qbox vs QBCore vs ESX para ver los pros y contras.

Tampoco hay modo standalone. Sin un framework soportado, tienes que escribir tu propio módulo de bridge, algo que la documentación describe como posible pero sin soporte.

Ten en cuenta también que ox_inventory trata las armas como items y no usa loadouts. Los scripts que dependen del comportamiento del inventario por defecto del framework, como esx_shops o esx_trunkinventory, van a chocar con él.

Cómo instalar ox_inventory

Necesitas un servidor con OneSync activado y dos dependencias:

  • oxmysql para la base de datos
  • ox_lib para la UI, los callbacks y utilidades

ox_target es opcional, pero recomendado para shops y stashes con zonas de interacción.

  1. Descarga ox_inventory.zip desde el último release en GitHub. No uses la descarga "Source code"; no incluye la UI compilada.
  2. Extráelo en tu carpeta resources de modo que la carpeta se llame ox_inventory.
  3. Configura la convar del framework y el orden de inicio en server.cfg:
setr inventory:framework "qbx"   # or "esx", "ox", "nd"

start oxmysql
start ox_lib
start qbx_core      # your framework
start ox_target
start ox_inventory

La configuración va en convars, no en un archivo de config. Las primeras que vas a tocar:

setr inventory:slots 50          # player inventory slots
setr inventory:weight 30000      # max carry weight, in grams
setr inventory:target true       # use ox_target for shops and stashes
setr inventory:keys ["F2", "K", "TAB"]

¿Vienes de ESX? Arranca el servidor una vez y ejecuta convertinventory esx en la consola del servidor para convertir los inventarios de los jugadores, luego reinicia. Si tu base de datos de ESX tiene una tabla items, ox_inventory copia a data/items.lua los items que todavía no conoce y te pide reiniciar.

Si estás armando un servidor desde cero, Cómo crear un servidor de FiveM te explica primero txAdmin y los recipes de framework.

Cómo agregar un item personalizado

Todo item tiene que estar definido en ox_inventory/data/items.lua antes de poder existir en cualquier inventario. El archivo retorna una tabla: la key es el spawn name del item (por convención, en minúsculas y sin espacios) y el valor son las opciones del item.

Cómo se arma un item de ox_inventory

El item válido más simple:

['gold_ring'] = {
    label = 'Anillo de oro',
    weight = 20,
},

Campos del item

Estos son los campos documentados para data/items.lua. El peso va en gramos.

CampoTipoQué hace
labelstringNombre que se muestra. Obligatorio
weightnumberPeso de una unidad, en gramos
stackbooleanPonlo en false para que el item no se apile en un slot
closebooleanPonlo en false para que el inventario siga abierto después de usarlo
descriptionstringTexto que aparece en el tooltip del item
consumenumberCuántos se quitan al usarlo. Por defecto 1. Un decimal como 0.2 quita 20% de durabilidad en su lugar. 0 no quita nada
degradenumberMinutos hasta que el item se degrada por completo
decaybooleanBorra el item cuando la durabilidad llega a 0
allowArmedbooleanPermite usarlo con un arma en la mano
clienttableOpciones de uso del lado del cliente (abajo)
servertableOpciones del lado del servidor, principalmente export
buttonstableAcciones extra en el menú contextual del clic derecho, cada una con label y action(slot)

La tabla client controla lo que pasa del lado del jugador cuando usa el item:

CampoQué hace
usetimeDuración de la barra de progreso en milisegundos
anim{ dict = '...', clip = '...' } que se reproduce durante la barra de progreso
propProp adjunto: model, pos, rot, y opcionalmente bone y rotOrder
disableControles desactivados durante el uso: move, car, combat, mouse, sprint
cancelPermite que el jugador cancele la barra de progreso
exportExport del cliente que se llama al usarlo, con el formato 'resourceName.exportName'
eventEvento del cliente que se dispara después de usarlo
statusCambios de status después de usarlo (hambre, sed y similares)
add / removeFunciones que se llaman cuando el jugador gana o pierde el item, y reciben el nuevo total

Un ejemplo completo

Aquí tienes una bebida energética que reproduce una animación de tomar con una lata en la mano y después da un pequeño boost de velocidad al correr. Está basada en el item sprunk que viene con ox_inventory.

['energy_drink'] = {
    label = 'Bebida energética',
    weight = 350,
    stack = true,
    close = true,
    description = 'Corre un poco más rápido por un rato.',
    client = {
        anim = { dict = 'mp_player_intdrink', clip = 'loop_bottle' },
        prop = {
            model = `prop_ld_can_01`,
            pos = vec3(0.01, 0.01, 0.06),
            rot = vec3(5.0, 5.0, -180.5)
        },
        usetime = 2500,
        export = 'my_items.energy_drink',
    },
},

El prop tiene que ser un modelo que el juego pueda cargar. Si quieres una lata o herramienta personalizada en la mano del jugador, primero tienes que hacerle stream; Props personalizados para FiveM explica cómo.

Imágenes de los items

Las imágenes de los items van en ox_inventory/web/images/, con el nombre exacto de la key del item:

Un ícono de inventario generado con la herramienta de imágenes de BLDR

ox_inventory/web/images/energy_drink.png

Lo que tienes que saber:

  • Usa PNG. La UI arma la ruta como <name>.png, y el fxmanifest.lua del resource solo incluye web/images/*.png. Un .webp o .jpg no va a cargar.
  • Tamaño: las imágenes que vienen con ox_inventory son de 100 x 100 píxeles con fondo transparente. Usa ese tamaño para que se vea todo consistente.
  • Los nombres distinguen mayúsculas y minúsculas en hosts Linux. Energy_Drink.png no es energy_drink.png.
  • Puedes cambiar la ruta base con la convar inventory:imagepath si alojas las imágenes en otro lugar.

Si no tienes un ícono, el generador de imágenes de BLDR puede crear uno a partir de un prompt de texto; pide un solo objeto con fondo transparente y después redimensiónalo a 100 x 100.

Cómo hacer un item usable

ox_inventory te da tres formas de ejecutar código cuando se usa un item. Elige una por item.

1. Export del cliente (la que recomienda la documentación)

Configura client.export en el item y después define ese export en tu propio resource. Tu función recibe los datos del item y el slot, decide si el item se puede usar y le devuelve el control a ox_inventory con useItem. Esa llamada corre las validaciones del servidor, reproduce la barra de progreso, la animación y el prop, y quita el item.

-- my_items/client.lua
exports('energy_drink', function(data, slot)
    if IsPedInAnyVehicle(cache.ped, false) then
        return lib.notify({ type = 'error', description = 'No mientras manejas' })
    end

    exports.ox_inventory:useItem(data, function(data)
        if not data then return end

        SetRunSprintMultiplierForPlayer(cache.playerId, 1.2)
        lib.notify({ description = 'Te sientes acelerado' })

        SetTimeout(30000, function()
            SetRunSprintMultiplierForPlayer(cache.playerId, 1.0)
        end)
    end)
end)

La tabla cache viene de ox_lib, así que agrega shared_script '@ox_lib/init.lua' al fxmanifest.lua de tu resource. Si useItem devuelve nil en data, el servidor rechazó el uso y el item no se consume.

2. Export del servidor

En su lugar, configura server.export = 'my_items.energy_drink' y el export se llama en el servidor con un nombre de evento. Devuelve false durante usingItem para bloquear el uso.

-- my_items/server.lua
exports('energy_drink', function(event, item, inventory, slot, data)
    if event == 'usingItem' then
        -- validaciones antes de usarlo; devuelve false para cancelar
    end

    if event == 'usedItem' then
        -- el item se usó y se consumió
    end
end)

3. Items usables del framework

Si un item no tiene opciones de uso en client, ni server.export, ni valor de consume, ox_inventory le pasa el uso a tu framework. El código que ya tienes sigue funcionando:

  • ESX: ESX.RegisterUsableItem('energy_drink', function(source) ... end)
  • Qbox: exports.qbx_core:CreateUseableItem('energy_drink', function(source, item) ... end)

La documentación aclara que el sistema integrado es más seguro y te da la barra de progreso, las animaciones y los props gratis, así que para items nuevos mejor usa las opciones 1 o 2.

Cómo dar y quitar items

Todos los cambios de items pasan en el servidor. Primero revisa la capacidad y después agrega:

local ox_inventory = exports.ox_inventory

local function giveEnergyDrink(source, count)
    if not ox_inventory:CanCarryItem(source, 'energy_drink', count) then
        return false
    end

    local success, response = ox_inventory:AddItem(source, 'energy_drink', count)
    if not success then
        print(('AddItem failed: %s'):format(response))
    end

    return success
end

AddItem devuelve false más un motivo como invalid_item (el item no está en items.lua), invalid_count o invalid_inventory.

Otros exports del servidor que vas a usar todo el tiempo:

ExportPara qué sirve
RemoveItem(inv, item, count, metadata, slot)Quitar items
GetItemCount(inv, itemName, metadata)Contar cuántos tiene un jugador
Search(inv, 'count', items)Contar varios items en una sola llamada
CanCarryItem(inv, item, count, metadata)Revisar peso y slots libres

El argumento inv acepta el server id de un jugador, el id de un stash o una tabla con id y owner.

Metadata

La metadata permite que una sola definición de item se comporte como muchos items distintos. Es una tabla que va pegada a cada slot y se pasa como cuarto argumento de AddItem:

exports.ox_inventory:AddItem(source, 'gold_ring', 1, {
    label = 'Anillo de oro grabado',
    description = 'Para M, por siempre.',
    engraving = 'M + J',
})

Algunas keys son especiales: label, weight, description, image (un nombre de archivo en la carpeta de imágenes, sin .png) e imageurl sobrescriben lo que ve el jugador, y type aparece en la esquina del tooltip. Cualquier otra key se guarda y tus scripts la pueden leer. Para mostrar keys personalizadas en el tooltip, llama el export del cliente exports.ox_inventory:displayMetadata({ engraving = 'Grabado' }).

Los items con degrade reciben automáticamente un valor durability en la metadata.

Shops y stashes, en resumen

Los shops se definen en data/shops.lua con un nombre, una lista inventory de entradas { name = 'item', price = 10 }, y locations o targets. También puedes registrarlos en runtime desde el servidor con exports.ox_inventory:RegisterShop(name, data), aunque los shops creados en runtime no tienen blips ni zonas de target.

Los stashes se registran en el servidor y se abren en el cliente:

-- servidor
exports.ox_inventory:RegisterStash('mechanic_parts', 'Piezas de mecánico', 50, 100000, false, { mechanic = 0 })

-- cliente
exports.ox_inventory:openInventory('stash', 'mechanic_parts')

Los argumentos son id, label, slots, peso máximo, owner y groups. Un owner en true le da a cada jugador su propia copia; false crea un solo stash compartido.

Errores comunes y cómo arreglarlos

SíntomaCausa probable
UI has not been builtDescargaste el source code. Usa el asset ox_inventory.zip del release
No such export ... in resource ox_inventoryox_inventory no pudo arrancar (revisa la consola justo arriba), o tu script inicia antes que él
El item no muestra imagenEl archivo no es .png, el nombre no coincide con la key del item o cambian las mayúsculas
AddItem devuelve invalid_itemError de tipeo en el nombre del item, o editaste items.lua sin reiniciar
El item no hace nada al usarloNo hay client.export, server.export ni handler de item usable del framework registrado, o el nombre del export no coincide con 'resource.export'
Se pierde el contenido de stashes o maleteros al reiniciarEl servidor se mató en vez de reiniciarse desde txAdmin. Los inventarios se guardan cada 5 minutos, en los reinicios de txAdmin y con el comando de consola saveinv
Inventario de ESX vacío después del cambioNo se ejecutó convertinventory esx, o no se reinició el servidor después

Confirma también que inventory:framework coincida con tu framework. El valor por defecto es esx, así que un servidor Qbox sin la convar va a fallar de formas bastante confusas.

Escribe scripts de items más rápido

La mayoría de los items personalizados siguen el mismo patrón: una entrada en items.lua, una imagen y un export de cliente o servidor con el efecto. El generador de scripts de BLDR conoce Qbox, QBCore, ESX, ox_lib, ox_target y ox_inventory, así que puedes describir un item y su efecto y obtener Lua que usa useItem y las llamadas correctas del framework desde el principio.

Preguntas frecuentes

¿ox_inventory funciona con QBCore?

No de forma oficial. El release actual soporta ox_core, ESX, Qbox y ND Core. Los servidores QBCore que quieren ox_inventory normalmente se pasan a Qbox, que mantiene funcionando la mayoría de los scripts de QBCore con su bridge de compatibilidad.

¿Tengo que reiniciar el servidor después de agregar un item?

Sí. data/items.lua se lee cuando arranca ox_inventory, así que los items nuevos o modificados solo aparecen después de reiniciar.

¿Dónde pongo los items en Qbox?

En ox_inventory/data/items.lua, igual que en cualquier otro framework. Qbox usa ox_inventory como su sistema de items, así que no hay un archivo aparte de shared items que editar.

¿Puedo hacer un item que abra su propio almacenamiento, como una mochila?

Sí. En ox_inventory se llaman containers. Define el item con stack = false y después configura sus slots y peso máximo en modules/items/containers.lua o con el export del servidor setContainerProperties.

Sigue leyendo