Final project: a 24/7 store with QBCore · Lesson 3/4 · 11 min

The server: validated purchase

The heart of the store: a callback (or event) that checks the price from Config, charges and delivers.

Here's the important part: the server receives ONLY the item name, looks up its price in Config, checks that the player has money, charges and delivers. With anti-spam to prevent abuse.

lua
-- server.lua
local QBCore = exports['qb-core']:GetCoreObject()
local ultimo = {}

local function precioDe(itemName)
  for _, p in ipairs(Config.Productos) do
    if p.item == itemName then return p.precio end
  end
  return nil
end

RegisterNetEvent('tienda:server:comprar', function(itemName)
  local src = source
  local Player = QBCore.Functions.GetPlayer(src)
  if not Player then return end

  -- anti-spam
  local ahora = GetGameTimer()
  if ultimo[src] and (ahora - ultimo[src]) < 500 then return end
  ultimo[src] = ahora

  -- price from the SERVER
  local precio = precioDe(itemName)
  if not precio then return end -- item is not in the catalog

  -- charge (RemoveMoney validates the balance and returns true/false)
  if Player.Functions.RemoveMoney('cash', precio, 'tienda-247') then
    Player.Functions.AddItem(itemName, 1)
    TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[itemName], 'add')
    QBCore.Functions.Notify(src, 'Purchased', 'success')
  else
    QBCore.Functions.Notify(src, 'You don\'t have enough cash', 'error')
  end
end)

server.lua

Count the safeguards: player exists, anti-spam, the item is in Config (valid price), and RemoveMoney checks the balance before delivering. Without one of those checks, a cheater walks off with free items.

Practice what you learned

0/3
Ordena el código

Ordena el evento de compra del servidor: obtener jugador, anti-spam, precio desde Config, cobrar y entregar.

Coloca las líneas en el orden correcto con las flechas.

local Player = QBCore.Functions.GetPlayer(src)
local precio = precioDe(itemName)
Player.Functions.AddItem(itemName, 1)
end)
RegisterNetEvent('tienda:server:comprar', function(itemName)
if Player.Functions.RemoveMoney('cash', precio, 'tienda-247') then
if not Player then return end
end
local src = source
if not precio then return end
Pista

source primero, guard del jugador, precio de Config, y solo entregas si RemoveMoney devuelve true.

Rellena los huecos

Completa el guard que comprueba que el jugador existe antes de tocar su dinero.

1local Player = QBCore.Functions.GetPlayer(src)
2if not then return end
Pista

GetPlayer puede devolver nil si el jugador no está cargado; córtalo ahí.

Corrige el error

Este evento entrega el item sin comprobar que existe en QBCore.Shared.Items, así que un item mal escrito en Config rompe el inventario. Añade esa validación antes de cobrar.

Este código tiene un fallo:

1local precio = precioDe(itemName)
2if not precio then return end
3if Player.Functions.RemoveMoney('cash', precio, 'tienda-247') then
4 Player.Functions.AddItem(itemName, 1)
5end

Reescríbelo corregido:

Pista

Comprueba QBCore.Shared.Items[itemName] justo después de validar el precio y antes de RemoveMoney.

Challenge: code it yourself

Add a limit: don't allow a purchase if the item doesn't exist in QBCore.Shared.Items (item misspelled in Config).

Write it yourself in your editor (VS Code) and test it on your server. You learn here by doing it, not by copying.

See hint

if not QBCore.Shared.Items[itemName] then return end before RemoveMoney.

Escribe aquí tu solución:

How was this lesson?