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.
-- 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/3Ordena 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 endPista
source primero, guard del jugador, precio de Config, y solo entregas si RemoveMoney devuelve true.
Completa el guard que comprueba que el jugador existe antes de tocar su dinero.
local Player = QBCore.Functions.GetPlayer(src)if not then return endPista
GetPlayer puede devolver nil si el jugador no está cargado; córtalo ahí.
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:
local precio = precioDe(itemName)if not precio then return endif Player.Functions.RemoveMoney('cash', precio, 'tienda-247') then Player.Functions.AddItem(itemName, 1)endReescrí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:
