Fundamentals: your first resource in QBCore · Lesson 3/5 · 9 min

Client vs Server: the key mental model

The client runs on the player's PC (untrusted); the server is the authority. They communicate through events.

This is THE concept that separates a secure script from a sieve. Client code runs on each player's PC: anyone can tamper with it. Server code runs on your machine: it's the single source of truth. In QBCore this is just as critical as in ESX.

Golden rule: anything that grants money, items or an advantage is DECIDED and EXECUTED on the server. The client only asks; never trust what it sends.

Talking between client and server: events

lua
-- CLIENT: asks the server to pay out a salary
RegisterCommand('sueldo', function()
  TriggerServerEvent('taxi:server:cobrarSueldo')
end)

-- SERVER: decides and executes (authority)
RegisterNetEvent('taxi:server:cobrarSueldo', function()
  local src = source -- ID of the player that triggered the event
  print(('Player %s asked for their salary'):format(src))
end)

Client → Server

  • TriggerServerEvent('name', ...): the client notifies the server.
  • TriggerClientEvent('name', targetId, ...): the server notifies a client.
  • RegisterNetEvent('name', fn): registers and listens to a network event (modern syntax).
  • source (server only): the ID of the player that triggered the event.

Recommended naming convention in QBCore: resource:client:action and resource:server:action (the core's own events follow QBCore:Client:... and QBCore:Server:...). That way you know at a glance where each event lives.

Practice what you learned

0/3
Test

Regla de oro del modelo cliente-servidor: ¿dónde se decide y ejecuta todo lo que da dinero, items o ventaja?

Ordena el código

Ordena el flujo de un comando /sueldo que el cliente pide y el servidor atiende.

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

RegisterCommand('sueldo', function()
end)
RegisterNetEvent('taxi:server:cobrarSueldo', function()
TriggerServerEvent('taxi:server:cobrarSueldo')
local src = source
end)
Pista

Primero el comando del cliente que dispara el evento, y luego el servidor que lo escucha con RegisterNetEvent.

Rellena los huecos

Completa la línea del cliente que avisa al servidor para cobrar el sueldo.

1RegisterCommand('sueldo', function()
2 ('taxi:server:cobrarSueldo')
3end)
Pista

Es la función con la que el cliente dispara un evento que corre en el servidor.

Challenge: code it yourself

Make a /hola command on the client that fires an event to the server, and have the server print the player's ID to the console.

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

RegisterCommand in client.lua → TriggerServerEvent; RegisterNetEvent in server.lua using source.

Escribe aquí tu solución:

How was this lesson?