Probar los hooks
Esta página explica cómo comprobar que tus hooks funcionan antes de ponerlos en producción: cómo ver dispararse cada uno, los comandos de prueba incluidos, cómo acortar los tiempos y una lista con todos los hooks.
Preparar el servidor
Sección titulada «Preparar el servidor»-
Activa los comandos de prueba en
config.lua:Config.Debug = trueEsto activa
/markettesty/marketdebug. Los dos funcionan solo para administradores. -
Hazte administrador en
server.cfg(o añade tu identificador aConfig.Admin.Identifiers):server.cfg add_ace group.admin marketplace.admin allowadd_principal identifier.license:TU_LICENCIA group.admin -
Opcional: registra cada hook con su duración en la consola:
Config.HandlerRuntime = {Debug = true,-- deja el resto como está} -
Reinicia el recurso después de cada cambio en
config.luaohandlers.lua:Ventana de terminal ensure sl-marketplaceLa consola debería mostrar
handlers API ready. Si dicethe handlers API is incomplete, se ha renombrado o borrado algún hook (ver/markethandlers validate).
Dos jugadores en un mismo PC
Sección titulada «Dos jugadores en un mismo PC»Muchos hooks necesitan dos jugadores (un comprador y un vendedor, un atracador y un comprador). Puedes abrir un segundo cliente de FiveM en el mismo PC con la opción de arranque -cl2:
- Crea un acceso directo a
FiveM.exey añade-cl2al final de Destino. - Abre FiveM normalmente y después abre el acceso directo: arranca un segundo cliente con su propia identidad.
- Conecta los dos a tu servidor de pruebas (
localhost:30120).
1. Registrar todos los hooks
Sección titulada «1. Registrar todos los hooks»Pega este bloque al final del todo de server/handlers.lua. Envuelve cada hook para que muestre su nombre y su data completo en la consola del servidor, y después ejecuta tu código como siempre (los guards siguen bloqueando exactamente igual).
-- ─── SOLO PARA PRUEBAS: muestra cada hook. Bórralo antes de ir a producción. ───local function printable(value, depth) depth = depth or 0 local kind = type(value) if kind == 'vector2' or kind == 'vector3' or kind == 'vector4' then return tostring(value) end if kind ~= 'table' then return value end if depth > 5 then return '...' end local out = {} for k, v in pairs(value) do out[k] = printable(v, depth + 1) end return outend
for name, original in pairs(Handlers) do Handlers[name] = function(data) print(('^3[hook] %s^7\n%s'):format(name, json.encode(printable(data), { indent = true }))) return original(data) endendReinicia el recurso y haz cualquier cosa en el marketplace: cada hook aparece con sus datos, por ejemplo:
[hook] OnSaleCompleted{ "buyerName": "Ruben", "item": "bread", "basePrice": 50, "grossPaid": 50, "deliveryMode": "mailbox", "stage": "settled", ...}2. Registrar todos los eventos de cliente
Sección titulada «2. Registrar todos los eventos de cliente»Pega esto al final de client/handlers.lua. Los prints aparecen en la consola F8 del jugador que recibe cada evento.
-- ─── SOLO PARA PRUEBAS: muestra cada evento de cliente. Bórralo antes de ir a producción. ───local EVENTS = { 'onPurchaseCompleted', 'onDeliveryArrived', 'onDeliveryResult', 'onAuctionWon', 'onSaleMade', 'onInPersonTradeCompleted', 'onListingCreated', 'onListingCancelled', 'onListingBumped', 'onBidPlaced', 'onOutbid', 'onMailboxClaimed', 'onMessageReceived', 'onRefundStatusChanged', 'onInPersonTradeStarted', 'onInPersonMeetUpdated', 'onInPersonTradeCancelled', 'onDeliveryRobbed', 'onSkillCheckStarted', 'onSkillCheckPhase', 'onSkillCheckFinished',}
local function printable(value, depth) depth = depth or 0 local kind = type(value) if kind == 'vector2' or kind == 'vector3' or kind == 'vector4' then return tostring(value) end if kind ~= 'table' then return value end if depth > 5 then return '...' end local out = {} for k, v in pairs(value) do out[k] = printable(v, depth + 1) end return outend
for _, name in ipairs(EVENTS) do AddEventHandler('sl-marketplace:' .. name, function(data) print(('[client event] %s %s'):format(name, json.encode(printable(data)))) end)end/markethandlers
Sección titulada «/markethandlers»Diagnóstico de los hooks incluido en el script. Funciona desde la consola del servidor o en el juego para administradores. Se activa con Config.HandlerRuntime.EnableDiagnosticsCommand (activado por defecto); el nombre es Config.HandlerRuntime.DiagnosticsCommand.
| Comando | Qué muestra |
|---|---|
/markethandlers |
Resumen: llamadas totales, correctas, errores, bloqueos de guards y llamadas lentas |
/markethandlers all |
Una línea por hook: llamadas, errores, bloqueos, llamadas lentas, tiempo medio y máximo |
/markethandlers errors |
Solo los hooks con errores, llamadas lentas o que faltan |
/markethandlers validate |
Comprueba que los 38 hooks existen y son funciones. Lista los que faltan, los no válidos y los que sobran |
/markethandlers reset |
Pone los contadores a cero |
Ejemplo de salida de all:
[sl-marketplace][handler diagnostics] OnSaleCompleted lifecycle calls=3 ok=3 errors=0 denials=0 slow=0 avg=0.33ms max=1ms[sl-marketplace][handler diagnostics] CanBuyListing guard calls=4 ok=4 errors=0 denials=1 slow=0 avg=0.25ms max=1msUna buena rutina: reset, haz la acción que quieres probar, all. El hook que esperas debería tener calls=1; si sube errors, la consola de arriba muestra el error y su traceback.
/markettest
Sección titulada «/markettest»Comandos para probar los hooks tú solo, sin un segundo jugador. Necesitan Config.Debug = true y permisos de administrador; se ejecutan en el juego (no desde la consola).
| Comando | Qué hace |
|---|---|
/markettest help |
Muestra cómo se usa |
/markettest listing [modo] [tipo] [objeto] [precio] [cantidad] |
Crea un anuncio de un vendedor de prueba (un jugador ficticio) para que puedas comprarlo o pujar tú mismo |
/markettest grant [dinero] [objeto] [cantidad] |
Te da dinero y/o objetos |
/markettest clean |
Borra el vendedor de prueba y todos sus anuncios |
Para listing:
| Parámetro | Valores | Por defecto |
|---|---|---|
modo |
mailbox, meetup, npc |
mailbox |
tipo |
fixed, auction, blind, dutch, bundle |
fixed |
objeto |
Cualquier nombre de objeto | bread |
precio |
Precio (nunca por debajo de Config.MinPrice) |
10 |
cantidad |
Cantidad | 1 |
Las subastas de prueba (auction, blind) terminan a los 5 minutos. Ejemplos:
/markettest grant 5000/markettest listing mailbox fixed bread 50 -> cómpralo: CanBuyListing, OnSaleCompleted/markettest listing npc fixed water 100 -> cómpralo: furgoneta de reparto, OnDeliveryCompleted/markettest listing mailbox auction bread 100 -> puja y espera 5 min: OnAuctionEnded/markettest listing mailbox dutch bread 1000 -> cómpralo: OnSaleCompleted con listingType dutch/markettest cleanAcortar los tiempos
Sección titulada «Acortar los tiempos»Algunos hooks solo se disparan después de un tiempo. En el servidor de pruebas, baja temporalmente estos valores:
| Para probar | Cambia | Valor de prueba |
|---|---|---|
| Caducidad de tus propias subastas | Config.Auction.MinDurationMinutes |
1 |
| Bajadas de precio holandesas | Config.Auctions.Dutch.MinIntervalMinutes |
1 |
| Caducidad de inversas y trueques | Créalos con la duración más corta | — |
timeout del repartidor |
Config.Gameplay.NPCDelivery.DeliveryTimeout |
30 |
| Tiempo límite del intercambio en persona | Config.InPersonTrade.TimeoutMinutes |
2 |
| Caducidad de la propuesta de encuentro | Config.InPersonTrade.MeetRequestTimeoutSeconds |
30 |
| Abandonar la zona de encuentro | Config.InPersonTrade.AbandonTimeoutSeconds |
15 |
| Subir anuncios varias veces | Config.RateLimits.bump |
{ max = 10, window = 60 } |
Hay dos tiempos que no se pueden acortar desde config.lua: los anuncios caducados y las subastas terminadas se revisan cada 30 segundos, y la aprobación automática de reembolsos (AutoApproveAfterHours) se revisa cada hora.
Probar un guard
Sección titulada «Probar un guard»Haz que bloquee todo, comprueba el mensaje y vuelve a poner tu lógica:
Handlers.CanPlaceBid = function(data) print(('[test] %s de %s: $%s (mínimo $%s)'):format(data.action, data.bidderName, data.amount, data.minimumBid)) return false, 'Prueba: las pujas están bloqueadas'endLo que deberías ver: el mensaje Prueba: las pujas están bloqueadas en el juego, tu línea en la consola, que no cambia nada (no se reserva dinero), y que /markethandlers all muestra denials=1 en CanPlaceBid.
Prueba también el caso de fallo: haz que el guard lance un error (error('boom')). La acción tiene que quedar bloqueada y la consola tiene que mostrar el error con su traceback. Eso confirma que una integración rota nunca dejará pasar acciones (salvo que pongas GuardFailurePolicy = 'allow').
Lista de comprobación
Sección titulada «Lista de comprobación»Cada hook, cómo lanzarlo y si puedes hacerlo tú solo.
Guards del servidor
Sección titulada «Guards del servidor»| Hook | Cómo lanzarlo | ¿Solo? |
|---|---|---|
CanCreateListing |
Publica un anuncio desde el marketplace | Sí |
CanBuyListing |
Compra un anuncio (/markettest listing) |
Sí |
CanPlaceBid |
Puja, o fija un máximo automático, en una subasta de prueba | Sí |
CanCancelListing |
Cancela uno de tus anuncios | Sí |
CanCreateBarterProposal |
Envía una propuesta a un anuncio de trueque / contraoferta | 2 jugadores |
CanAcceptBarterProposal |
Acepta una propuesta de trueque o una contraoferta | 2 jugadores |
CanConfirmInPersonTrade |
Confirma un intercambio en persona | 2 jugadores |
CanRequestRefund |
Pide un reembolso de una compra | 2 jugadores |
Hooks del servidor
Sección titulada «Hooks del servidor»| Hook | Cómo lanzarlo | ¿Solo? |
|---|---|---|
OnSaleCompleted |
Compra un anuncio de prueba | Sí |
OnAuctionEnded |
Puja en una subasta de prueba y espera 5 min | Sí |
OnReverseOfferAccepted |
Acepta una oferta en tu subasta inversa | 2 jugadores |
OnListingCreated |
Publica desde el marketplace | Sí |
OnListingExpired |
Subasta de prueba sin pujas, espera 5 min | Sí |
OnListingCancelled |
Cancela un anuncio (y desde /marketadmin) |
Sí |
OnListingBumped |
Sube un anuncio | Sí |
OnBidPlaced |
Puja en una subasta de prueba | Sí |
OnProxyBidSet |
Fija un máximo automático | Sí |
OnDeliveryCompleted |
Compra un anuncio de prueba npc y espera a la furgoneta |
Sí |
OnDeliveryFailed |
Destruye la furgoneta, o desconéctate durante el reparto | Sí |
OnDeliveryRobbed |
Atraca la furgoneta de reparto de otro jugador | 2 jugadores |
OnInPersonTradeCompleted |
Completa un intercambio en persona | 2 jugadores |
OnInPersonTradeCancelled |
Cancela un intercambio en persona | 2 jugadores |
OnMeetupStatusChanged |
Propón / acepta un punto de encuentro en el chat | 2 jugadores |
OnBarterProposalCreated |
Envía una propuesta de trueque | 2 jugadores |
OnBarterProposalStatusChanged |
Acepta, contraoferta o rechaza una propuesta | 2 jugadores |
OnRefundRequested |
Pide un reembolso | 2 jugadores |
OnRefundApproved |
Aprueba un reembolso (o fuérzalo en /marketadmin) |
2 jugadores |
OnRefundRejected |
Rechaza un reembolso | 2 jugadores |
OnPlayerRated |
Valora a un vendedor después de comprarle | 2 jugadores |
OnMessageSent |
Envía un mensaje en un anuncio | 2 jugadores |
OnFavoriteChanged |
Marca un anuncio como favorito | Sí |
OnFollowChanged |
Sigue a un vendedor | 2 jugadores |
OnWishlistChanged |
Añade un objeto a tu lista de deseos | Sí |
OnReportCreated |
Reporta un anuncio | Sí |
OnProfileCreated |
Crea tu tienda por primera vez | Sí |
OnProfileUpdated |
Edita tu perfil | Sí |
OnMailboxClaimed |
Recoge un objeto o dinero del buzón | Sí |
OnAdminAction |
Cancela, bloquea, desbloquea, resuelve un reporte o fuerza un reembolso en /marketadmin |
Sí |
Eventos de cliente
Sección titulada «Eventos de cliente»| Evento | Lo recibe | ¿Solo? |
|---|---|---|
onPurchaseCompleted |
Comprador | Sí |
onSaleMade |
Vendedor | 2 jugadores |
onAuctionWon |
Ganador | Sí |
onListingCreated, onListingCancelled, onListingBumped |
Vendedor | Sí |
onBidPlaced |
Quien puja | Sí |
onOutbid |
El que iba ganando | 2 jugadores |
onMailboxClaimed |
Quien recoge | Sí |
onMessageReceived |
Destinatario | 2 jugadores |
onRefundStatusChanged |
Comprador y vendedor | 2 jugadores |
onDeliveryArrived, onDeliveryResult |
Comprador | Sí |
onDeliveryRobbed |
Atracador | 2 jugadores |
onInPersonTradeStarted, onInPersonMeetUpdated, onInPersonTradeCompleted, onInPersonTradeCancelled |
Los dos | 2 jugadores |
onSkillCheckStarted, onSkillCheckPhase, onSkillCheckFinished |
Atracador | 2 jugadores |
Problemas frecuentes
Sección titulada «Problemas frecuentes»Mi hook no se dispara nunca.
Comprueba que el nombre es exactamente el del archivo original (mayúsculas incluidas) y que has reiniciado el recurso. /markethandlers validate lista los hooks que faltan o se han renombrado. En los eventos de cliente, comprueba que el texto del evento empieza por sl-marketplace:.
Después de editar un guard se bloquea todo.
Tu guard lanza un error, y los guards fallan cerrados. La consola del servidor muestra [sl-marketplace][handlers][ERROR] CanXxx: con el traceback.
La consola dice Slow execution: 250 ms.
Un hook tardó más que SlowWarningMs. Mueve el trabajo lento (peticiones HTTP, consultas grandes) dentro de un CreateThread(function() ... end) en el hook, y nunca lo hagas en un guard.
No me llega un evento de cliente.
Casi todos van a un solo jugador (ver Eventos de cliente). Los eventos del vendedor no se disparan para el vendedor de /markettest, porque nunca está conectado.
/markettest dice Config.Debug is disabled.
Pon Config.Debug = true y reinicia el recurso. Acuérdate de volver a ponerlo en false en producción.