ESX es nil: cómo arreglar esx:getSharedObject en ESX Legacy

¿Te sale attempt to index a nil value (global 'ESX')? El antiguo evento esx:getSharedObject ya no existe en ESX Legacy. Aquí tienes el arreglo de una línea y qué hacer con los scripts que no puedes editar.

Arrancas el servidor, abres la consola F8 y ahí está:

text
SCRIPT ERROR: @my_script/client/main.lua:12: attempt to index a nil value (global 'ESX')

O su gemelo en el lado del servidor, attempt to index a nil value (upvalue 'ESX'). El script está bien, ESX está funcionando y aun así ESX es nil. Es el error de ESX más común que existe, y casi siempre tiene la misma causa.

Por qué ESX es nil

Los scripts de ESX antiguos obtienen el objeto ESX así:

lua
ESX = nil

TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)

Ese evento era la forma en que ESX 1.1 y 1.2 repartían su objeto compartido. ESX Legacy lo marcó como obsoleto, y las versiones actuales ya no responden a él. El script lanza el evento, nadie contesta, y ESX se queda en nil hasta que la primera línea que lo usa peta.

Lo verás sobre todo con scripts escritos hace años o copiados de tutoriales antiguos.

El arreglo: pídeselo directamente a es_extended

Sustituye esas líneas por el export que ofrece ESX Legacy:

lua
ESX = exports['es_extended']:getSharedObject()

Funciona igual en el cliente y en el servidor. Hazlo en todos los archivos que usen ESX. Si el script también tenía un bucle de espera como este, bórralo; el export responde al instante:

lua
-- old code: remove it
Citizen.CreateThread(function()
    while ESX == nil do
        TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
        Citizen.Wait(0)
    end
end)

Aún más fácil: imports.lua

es_extended trae un pequeño archivo que te prepara ESX. Añádelo al fxmanifest.lua del script:

lua
fx_version 'cerulean'
game 'gta5'
lua54 'yes'

shared_script '@es_extended/imports.lua'

client_scripts { 'client/*.lua' }
server_scripts { 'server/*.lua' }

Ahora todos los archivos de cliente y de servidor tienen un ESX global, y en el cliente ESX.PlayerData se mantiene actualizado cuando cambian el trabajo y el dinero del jugador. Puedes borrar del todo las líneas de getSharedObject.

Consejo: usa un solo método por script. O el export al principio de cada archivo, o imports.lua en el manifest; mezclar los dos funciona, pero solo añade ruido.

¿Sigue siendo nil? Revisa el orden de arranque

Si ya usas el export y ESX sigue siendo nil, o te sale No such export getSharedObject in resource es_extended, el script está arrancando antes que es_extended. El orden lo decide tu server.cfg:

cfg
ensure oxmysql
ensure ox_lib
ensure es_extended
ensure [esx]

ensure my_script

Dos cosas más que revisar en la consola del servidor, desde el principio del todo:

  • es_extended arrancó sin errores. Si falla (un mysql_connection_string incorrecto, falta oxmysql), todos los scripts que dependen de él fallan también.
  • La carpeta se llama de verdad es_extended. Una copia renombrada o duplicada rompe el nombre del export, y en Linux el nombre distingue entre mayúsculas y minúsculas.

Explicamos ese error en detalle en No such export getSharedObject in resource es_extended.

Datos del jugador en el cliente

Los scripts antiguos también leen al jugador así:

lua
-- old
ESX.GetPlayerData()
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer) PlayerData = xPlayer end)

Eso sigue funcionando en ESX Legacy, con un detalle: espera a que el jugador esté cargado antes de leer el trabajo o el dinero al arrancar.

lua
CreateThread(function()
    while not ESX.IsPlayerLoaded() do Wait(250) end
    local job = ESX.GetPlayerData().job
    print(('job: %s (%s)'):format(job.name, job.grade))
end)

RegisterNetEvent('esx:setJob', function(job)
    -- the job changed: refresh whatever shows it
end)

Con imports.lua, ESX.PlayerData.job se mantiene actualizado sin que hagas nada.

Scripts que no puedes editar

Si el script está encriptado (escrow) y sigue usando el evento antiguo, no puedes cambiar su código. Por orden de preferencia:

  1. Pídele una actualización a su autor. Cualquier script que se siga vendiendo para ESX debería usar el export.
  2. Responde tú mismo al evento antiguo desde ESX. En es_extended, añade esto a un archivo de servidor y a uno de cliente:
lua
AddEventHandler('esx:getSharedObject', function(cb)
    cb(ESX)
end)

Cuidado: esto es un parche al propio es_extended. Al actualizar ESX se sobrescribe, así que tendrás que volver a añadirlo después de cada actualización. Úsalo como solución temporal, no como el arreglo definitivo.

Checklist rápida

Síntoma Solución
attempt to index a nil value (global 'ESX') Sustituye TriggerEvent('esx:getSharedObject'…) por exports['es_extended']:getSharedObject()
Sigue siendo nil después del cambio Arranca es_extended antes que el script en server.cfg
No such export getSharedObject es_extended no ha arrancado, ha fallado o tiene otro nombre
ESX.PlayerData.job es nil al arrancar Espera primero a ESX.IsPlayerLoaded()
Script encriptado con el evento antiguo Pídeselo al autor; mientras tanto, responde al evento desde es_extended

Respuestas rápidas

¿Por qué ESX es nil en mi script?

El script pide ESX con la antigua llamada TriggerEvent('esx:getSharedObject'), a la que ESX Legacy ya no responde. Sustitúyela por ESX = exports['es_extended']:getSharedObject(), o añade shared_script '@es_extended/imports.lua' al fxmanifest.

¿Tengo que cambiar tanto los archivos de cliente como los de servidor?

Sí. Todos los archivos que usan ESX necesitan el objeto, en el cliente y en el servidor. La línea de imports.lua en el fxmanifest los cubre todos de una vez.

¿Y si el script está encriptado (escrow) y no puedo editarlo?

Primero pídele una actualización a su autor. Como último recurso puedes responder al evento antiguo desde es_extended, pero tendrás que volver a añadirlo cada vez que actualices ESX.

Scripts que evitan este problema

Advanced BoostingBoosting de vehículos desde una tablet: contratos de clase D a S+, crews y cola en vivo.Ver script →Item Creator V2Crea items usables con animaciones, props, efectos y más — sin escribir código.Ver script →Shop CreatorCrea una tienda en menos de un minuto — dueños, empleados, caja fuerte y atracos.Ver script →

Sigue leyendo