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'.

lua
-- 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/3
Ordena el código

Ordena 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) end
if xPlayer.getAccount('bank').money < cantidad then return cb(false) end
if not cantidad or cantidad < 1 then return cb(false) end
local 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.

Rellena los huecos

Completa el movimiento de un ingreso ya validado: efectivo → banco.

1-- Ingresar: cash -> bank (ya validado)
2xPlayer.(cantidad)
3xPlayer.('bank', cantidad)
Pista

Quitas efectivo con removeMoney y lo sumas a la cuenta 'bank' con addAccountMoney.

Corrige el error

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:

1ESX.RegisterServerCallback('cajero:retirar', function(source, cb, cantidad)
2 local xPlayer = ESX.GetPlayerFromId(source)
3 cantidad = tonumber(cantidad)
4 xPlayer.removeAccountMoney('bank', cantidad)
5 xPlayer.addMoney(cantidad)
6 cb(true)
7end)

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:

¿Qué tal esta lección?