Guia FiveM

Como criar Scripts Lua para FiveM

Guia prático para criar seu primeiro resource em Lua: estrutura, client vs server, comandos, eventos e exemplos que você consegue testar no FXServer. Conteúdo alinhado à documentação oficial de Scripting in Lua e ao tutorial Creating Your First Script .

O que você precisa saber antes

  • FiveM usa uma Lua 5.4 modificada (CfxLua) — arquivos com extensão .lua
  • Servidor FiveM já rodando (FXServer) com pasta resources
  • Editor de texto (VS Code recomendado)
  • Base estável ajuda, mas este guia funciona mesmo sem QBCore — se ainda não tem servidor, veja Windows + QBCore

O que é um resource

Um resource é uma pasta com arquivos que o servidor pode start, stop e restart individualmente. Cada script personalizado costuma ser um resource próprio.

Estrutura recomendada para iniciantes:

resources/[local]/meu_primeiro_script/
  fxmanifest.lua
  client.lua
  server.lua
  shared/config.lua   (opcional)

Pastas entre colchetes como [local] só organizam; o nome do resource é a pasta interna (meu_primeiro_script).

1. Criar o fxmanifest.lua

Sem o manifest o FiveM não detecta o resource. Exemplo mínimo (standalone, não é gametype):

fx_version 'cerulean'
game 'gta5'

author 'Seu Nome'
description 'Meu primeiro script em Lua'
version '1.0.0'

shared_script 'shared/config.lua'

client_script 'client.lua'
server_script 'server.lua'
  • fx_version — use uma versão atual (ex.: cerulean) para recursos novos
  • game 'gta5' — indica GTA V / FiveM
  • client_script / server_script — o que cada lado carrega

Client × server (regra de ouro)

  • Client: teclas, markers, animação, natives de jogo (posição do ped, criar veículo localmente para teste, UI)
  • Server: dinheiro, itens, permissões, banco de dados, o que precisa ser a “fonte da verdade”

Cada jogador roda uma cópia do client no PC dele. Variáveis do client não são compartilhadas entre players. Para ações entre jogadores ou recompensas, use o server + eventos.

2. Exemplo prático: comando /ola

No client.lua:

RegisterCommand('ola', function()
    TriggerEvent('chat:addMessage', {
        args = { 'DEVELOPERWHS', 'Olá! Seu primeiro script Lua está rodando.' }
    })
end, false)

-- Sugestão no chat ao digitar /
TriggerEvent('chat:addSuggestion', '/ola', 'Mostra uma mensagem de boas-vindas')

No console do FXServer:

refresh
ensure meu_primeiro_script

Entre no servidor, abra o chat (T) e digite /ola. Depois de editar o código, use restart meu_primeiro_script — não precisa fechar o jogo.

3. Exemplo prático: /coords (útil no dia a dia)

Script client simples para copiar coordenadas ao montar markers, spawns e pontos de job:

RegisterCommand('coords', function()
    local ped = PlayerPedId()
    local coordenadas = GetEntityCoords(ped)
    local heading = GetEntityHeading(ped)

    print(('vector4(%.2f, %.2f, %.2f, %.2f)'):format(
        coordenadas.x,
        coordenadas.y,
        coordenadas.z,
        heading
    ))

    TriggerEvent('chat:addMessage', {
        args = {
            'Coords',
            ('X: %.2f | Y: %.2f | Z: %.2f | H: %.2f'):format(
                coordenadas.x,
                coordenadas.y,
                coordenadas.z,
                heading
            )
        }
    })
end, false)

Aqui entram dois conceitos da runtime Lua : vectors (posição com .x, .y, .z) e natives como PlayerPedId e GetEntityCoords.

4. Exemplo: client + server com evento

O jogador pede algo no client; o server decide se aceita. Padrão essencial para qualquer script de emprego ou recompensa.

client.lua — tecla E perto de um ponto:

local pontoEntrega = vector3(215.76, -810.12, 30.73)
local distanciaMaxima = 2.0

CreateThread(function()
    while true do
        local espera = 1000
        local ped = PlayerPedId()
        local coordenadas = GetEntityCoords(ped)
        local distancia = #(coordenadas - pontoEntrega)

        if distancia < 10.0 then
            espera = 0
            DrawMarker(
                2,
                pontoEntrega.x, pontoEntrega.y, pontoEntrega.z,
                0.0, 0.0, 0.0,
                0.0, 0.0, 0.0,
                0.3, 0.3, 0.3,
                56, 189, 248, 180,
                false, true, 2, false, nil, nil, false
            )

            if distancia < distanciaMaxima then
                BeginTextCommandDisplayHelp('STRING')
                AddTextComponentSubstringPlayerName('Pressione ~INPUT_CONTEXT~ para entregar')
                EndTextCommandDisplayHelp(0, false, true, -1)

                if IsControlJustReleased(0, 38) then -- E
                    TriggerServerEvent('meu_primeiro_script:entregar')
                end
            end
        end

        Wait(espera)
    end
end)

server.lua — valida distância e dá a recompensa no server:

local pontoEntrega = vector3(215.76, -810.12, 30.73)

RegisterNetEvent('meu_primeiro_script:entregar', function()
    local sourceId = source
    local ped = GetPlayerPed(sourceId)
    local coordenadas = GetEntityCoords(ped)
    local distancia = #(coordenadas - pontoEntrega)

    if distancia > 5.0 then
        print(('[meu_primeiro_script] jogador %s longe demais'):format(sourceId))
        return
    end

    -- Aqui entraria dinheiro/item via QBCore, ox_inventory, etc.
    TriggerClientEvent('chat:addMessage', sourceId, {
        args = { 'Entrega', 'Entrega concluída! (+exemplo)' }
    })
end)

Note o Wait(espera) dinâmico: longe do ponto o loop dorme 1s; perto usa 0 só enquanto precisa desenhar o marker. Isso reduz lag.

5. Hashes com crase (backtick)

Em CfxLua você pode gerar hash em tempo de compilação com `nome` — zero custo em runtime (documentado em Scripting in Lua ):

RequestModel(`adder`)

if GetEntityModel(veiculo) == `buzzard` then
    print('É um Buzzard.')
end

6. Exports (um resource falando com outro)

Defina um export no seu script e chame de outro resource:

-- no seu resource
exports('DizerOla', function(nome)
    print('Olá, ' .. tostring(nome) .. '!')
end)

-- em outro resource
exports.meu_primeiro_script:DizerOla('mundo')

No QBCore, a maior parte da integração (player, money, job) passa por exports e callbacks do framework — não reinventar inventário do zero.

Checklist rápido ao criar um script

  1. Pasta + fxmanifest.lua
  2. refresh + ensure nome_do_resource
  3. Comando ou marker funciona no client
  4. Ação sensível (dinheiro/item) validada no server
  5. Nome de eventos com prefixo do resource (evita conflito)
  6. resmon 1 sem idle absurdo

Segurança e performance

  • Nunca confie em preço, quantidade ou job enviados só pelo client
  • Valide distância e permissão no server antes de pagar/dar item
  • Evite Wait(0) o tempo todo sem necessidade
  • Prefira loops com espera maior quando o jogador está longe
  • Não exponha eventos de admin sem ACE / permissão

Próximos passos

Com o básico de resource, comando, evento e export, você já consegue prototipar jobs simples. Para aprofundar: natives, NUI (HTML/CSS/JS) e State Bags na documentação Cfx.re .

Se a base ainda não está organizada, veja como criar uma base QBCore . Fundamentos da linguagem: como programar em Lua . Mais tutoriais no blog — e scripts prontos em WH Emotes , Phone e Smugglers .