Proyecto final: tu primer cajero (ATM) · Lección 3/4 · 11 min
El servidor: ingresar y retirar (validado)
El corazón del cajero: callbacks que comprueban el saldo y mueven el dinero, con anti-spam.
Aquí está lo importante: TODO el dinero se mueve en el servidor, validando que el jugador tiene lo que dice. El cliente solo pide 'ingresa 100' o 'retira 50'.
-- server.lua
local ultimo = {}
local function antiSpam(src)
local ahora = GetGameTimer()
if ultimo[src] and (ahora - ultimo[src]) < 500 then return false end
ultimo[src] = ahora
return true
end
-- Consultar saldo
ESX.RegisterServerCallback('cajero:saldo', function(source, cb)
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return cb(0, 0) end
cb(xPlayer.getMoney(), xPlayer.getAccount('bank').money)
end)
-- Ingresar (cash -> bank)
ESX.RegisterServerCallback('cajero:ingresar', function(source, cb, cantidad)
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer or not antiSpam(source) then return cb(false) end
cantidad = tonumber(cantidad)
if not cantidad or cantidad < 1 then return cb(false) end
if xPlayer.getMoney() < cantidad then return cb(false) end -- ¿tiene el efectivo?
xPlayer.removeMoney(cantidad)
xPlayer.addAccountMoney('bank', cantidad)
cb(true)
end)
-- Retirar (bank -> cash)
ESX.RegisterServerCallback('cajero:retirar', function(source, cb, cantidad)
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer or not antiSpam(source) then return cb(false) end
cantidad = tonumber(cantidad)
if not cantidad or cantidad < 1 then return cb(false) end
if xPlayer.getAccount('bank').money < cantidad then return cb(false) end -- ¿tiene saldo?
xPlayer.removeAccountMoney('bank', cantidad)
xPlayer.addMoney(cantidad)
cb(true)
end)server.lua
Cuenta los blindajes: jugador existe, anti-spam, cantidad es número y positiva, y TIENE el dinero antes de moverlo. Sin uno de esos checks, un tramposo te vacía el banco. cb() en todos los caminos (módulo de callbacks).
Practica lo aprendido
0/3Ordena las comprobaciones del servidor ANTES de mover el dinero en un retiro.
Coloca las líneas en el orden correcto con las flechas.
if not xPlayer or not antiSpam(source) then return cb(false) endif xPlayer.getAccount('bank').money < cantidad then return cb(false) endif not cantidad or cantidad < 1 then return cb(false) endlocal xPlayer = ESX.GetPlayerFromId(source)cantidad = tonumber(cantidad)Pista
Primero el jugador y el anti-spam, luego convertir la cantidad, validarla, y por último comprobar el saldo.
Completa el movimiento de un ingreso ya validado: efectivo → banco.
-- Ingresar: cash -> bank (ya validado)xPlayer.(cantidad)xPlayer.('bank', cantidad)Pista
Quitas efectivo con removeMoney y lo sumas a la cuenta 'bank' con addAccountMoney.
Este callback de retirar mueve el dinero SIN comprobar el saldo del banco. Un tramposo te vacía la cuenta. Añade la comprobación.
Este código tiene un fallo:
ESX.RegisterServerCallback('cajero:retirar', function(source, cb, cantidad) local xPlayer = ESX.GetPlayerFromId(source) cantidad = tonumber(cantidad) xPlayer.removeAccountMoney('bank', cantidad) xPlayer.addMoney(cantidad) cb(true)end)Reescríbelo corregido:
Pista
Antes de mover el dinero: if xPlayer.getAccount('bank').money < cantidad then return cb(false) end.
Reto: prográmalo tú
Añade un límite máximo de retirada por operación (p. ej. 5000€) leído de Config.
Escríbelo tú en tu editor (VS Code) y pruébalo en tu servidor. Aquí se aprende haciéndolo, no copiando.
Ver pista
Tras validar la cantidad: if cantidad > Config.MaxRetiro then return cb(false) end.
Escribe aquí tu solución:
