Exportaciones de FiveM en Lua: exports('name', fn) y 'No such export'

Cómo definir y llamar a exportaciones en Lua de FiveM, los estilos de exportaciones en fxmanifest y server_exports, y cómo reparar errores 'No such export' causados por el orden de inicio o el lado incorrecto.

Un script llama a otro y la consola responde:

text
No such export getCount in resource my_inventory

Este artículo muestra cómo se definen y llaman las exportaciones en Lua, las dos formas de declararlas, y las razones habituales por las que aparece ese error.

Definir una exportación

Una exportación permite que un recurso ofrezca una función a los demás. La forma simple es la función exports dentro de un script:

lua
-- my_inventory/server/main.lua
local function getCount(source, item)
    -- ...
    return 5
end

exports('getCount', getCount)

También puedes pasar la función en línea:

lua
exports('getCount', function(source, item)
    return 5
end)

Eso es todo. No hay nada que añadir a fxmanifest.lua, y la exportación existe en cualquier lado que ejecute el script: ponlo en un script del servidor y es una exportación del servidor, ponlo en un script del cliente y es una exportación del cliente.

El estilo del manifiesto

Los recursos más antiguos declaran exportaciones en fxmanifest.lua y definen una función global simple con el mismo nombre:

lua
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

server_exports { 'getCount' }
exports { 'getOwnedCount' }
lua
-- server script
function getCount(source, item)
    return 5
end
  • exports { … } enumera las exportaciones del cliente.
  • server_exports { … } enumera las exportaciones del servidor.

Esto sigue funcionando, y muchos recursos de ESX y QBCore lo usan. Los dos estilos no entran en conflicto, así que un recurso puede mezclarlos. Para código nuevo, exports('name', fn) es más simple porque la función y la exportación viven juntas, y no puedes olvidar una línea en el manifiesto. Recuerda que fxmanifest.lua es el nombre del manifiesto actual: ve fxmanifest vs __resource.lua.

Llamar a una exportación

Desde cualquier otro recurso en el mismo lado:

lua
local count = exports['my_inventory']:getCount(source, 'water')

Las versiones de punto y dos puntos son lo mismo, siempre que el nombre sea un identificador Lua válido:

lua
local count = exports.my_inventory:getCount(source, 'water')

Usa la forma de corchete cuando el nombre del recurso tiene un guión, como exports['qb-core']:GetCoreObject(). La llamada es sincrónica: devuelve el valor de la función, y puede producir si la función espera.

Consejo: los argumentos y valores de retorno viajan entre recursos, así que las tablas se copian. Cambiar una tabla que obtuviste de una exportación no cambia los datos propios del otro recurso. Las funciones dentro de una tabla devuelta aún funcionan, ya que vuelven a llamar al propietario.

Por qué obtienes «No such export»

text
No such export getCount in resource my_inventory

Comprueba estos, en este orden:

  1. El recurso no se ha iniciado. Abre la consola y ejecuta ensure my_inventory. Si falla al iniciar, arregla eso primero.
  2. Se inició después del llamador. La exportación solo existe una vez que el propietario ha cargado sus scripts. Ve start order in server.cfg y pon el propietario arriba de los scripts que lo usan.
  3. El nombre está mal escrito. Los nombres de exportación distinguen mayúsculas de minúsculas: getCount y GetCount son diferentes.
  4. Lado incorrecto. Un script del servidor no puede llamar a una exportación del cliente, y viceversa. El error se ve igual.
  5. La exportación se declara pero falta la función. Con el estilo de manifiesto, server_exports { 'getCount' } necesita una función global llamada getCount en el servidor. Una función local no cuenta.
  6. El propietario falló o se detuvo. Si se bloqueó en un error de script, o lo detuviste, sus exportaciones se fueron hasta que se ejecute de nuevo. Lee su salida de inicio en la consola.

Para las versiones del mundo real de este error, ve No such export GetSharedObject in resource es_extended y QBCore is nil: GetCoreObject.

Haz el orden seguro con dependencias

No dependas solo del orden de las líneas de ensure. Declara la dependencia en el manifiesto del script que llama a la exportación:

lua
dependency 'my_inventory'

FiveM entonces inicia my_inventory primero, y se niega a iniciar tu recurso si falta, con un mensaje más claro (could not find dependency).

Manejo de un recurso faltante con elegancia

Si otro recurso es opcional, comprueba su estado antes de llamarlo:

lua
if GetResourceState('my_inventory') == 'started' then
    local count = exports.my_inventory:getCount(source, 'water')
end

GetResourceState devuelve una cadena como started, stopped, starting o missing. Es la forma limpia de soportar una integración opcional sin un error de consola.

Llamar a tus propias exportaciones

Un recurso puede llamar a sus propias exportaciones también, con su propio nombre: exports['my_inventory']:getCount(...). Para una función que solo se usa dentro del recurso, una función local normal es más rápida y simple. Las exportaciones son para el límite entre recursos.

Una palabra sobre rendimiento

Cada llamada cruza entre dos recursos, así que es más lenta que una llamada de función normal. No llames a una exportación en un bucle apretado por fotograma si puedes leer el valor una vez y mantenerlo. Llamar a una exportación un par de veces por segundo está bien.

Lista de verificación

Síntoma Solución
No such export x in resource y Inicia y, y ponlo antes del llamador en server.cfg
Funciona en el servidor, falla en el cliente Define la exportación en un script del cliente también, o llámala desde el servidor
Exportación de estilo manifiesto faltante Define una función global con el mismo nombre que la entrada del manifiesto
La capitalización del nombre difiere Coincide con la ortografía exacta
El nombre del recurso tiene un guión exports['my-resource']:name()
La integración opcional spammea la consola Comprueba GetResourceState('x') == 'started' primero

Respuestas rápidas

¿Cómo llamo a una exportación desde otro recurso?

Usa exports['resource_name']:exportName(args) o exports.resource_name:exportName(args). El otro recurso debe estar iniciado y debe definir esa exportación en el mismo lado (cliente o servidor).

¿Todavía necesito exportaciones en fxmanifest.lua?

No con exports('name', fn): registra la exportación desde el script mismo. Las listas exports {} y server_exports {} en el manifiesto son el estilo más antiguo, donde una función global se expone por nombre.

¿Por qué funciona una exportación en el cliente pero no en el servidor?

Las exportaciones del cliente y servidor son separadas. Una exportación definida en un script del cliente solo existe en el cliente, y una definida en un script del servidor solo en el servidor.

Scripts que evitan este problema

Item Creator V2Crea items usables con animaciones, props, efectos y más — sin escribir código.Ver script →Mic PhoneUn móvil plegable que se abre en tablet y llega al móvil real del jugador.Ver script →Shop CreatorCrea una tienda en menos de un minuto — dueños, empleados, caja fuerte y atracos.Ver script →

Sigue leyendo