Por que o ChatGPT escreve scripts FiveM quebrados (e como corrigir)

8 min de leitura

  • chatgpt fivem
  • ia fivem lua
  • skills

O ChatGPT escreve scripts FiveM quebrados porque aprendeu FiveM em posts de fórum e repositórios do GitHub que cobrem dez anos de APIs em mudança, sem nenhuma forma de saber qual versão você roda. O resultado é código que mistura chamadas de ESX e QBCore, usa natives que não existem, coloca queries de banco de dados no client e confia em todo valor que um jogador envia. A solução não é um prompt melhor. É dar ao modelo a documentação real da sua stack em um formato que ele lê antes de escrever: uma skill.

Os seis padrões de falha em Lua de FiveM escrito por IA

Depois de revisar muitos recursos gerados por IA, os mesmos seis erros aparecem em quase todos. Se você aprender a identificá-los, consegue revisar um script em minutos.

1. Natives inventados

O modelo viu milhares de nomes de natives, então consegue gerar nomes novos e plausíveis. GetVehicleOwner(vehicle), SetPlayerJob(source, 'police'), IsPedInAnyOwnedVehicle. Nenhum deles existe. Natives reais seguem a nomenclatura de docs.fivem.net/natives, e um native que não está nessa página não é um native.

O sinal: um native que faz exatamente a coisa de alto nível que você pediu. Natives reais são de baixo nível. Não existe native para “dono de um veículo” porque propriedade é um conceito do framework armazenado no seu banco de dados, não na engine do jogo.

2. APIs de QBCore, Qbox e ESX misturadas

Peça um script para QBCore e muitas vezes vai aparecer um ESX.GetPlayerFromId no meio, ou QBCore.Functions.GetPlayer ao lado de exports.qbx_core:GetPlayer. O modelo não sabe que são três frameworks diferentes com três objetos de jogador diferentes. Ele sabe que tudo é “código de roleplay FiveM” e mistura.

Antes e depois, para um evento de servidor que paga um jogador:

-- Saída da IA: chamada ESX dentro de um recurso QBCore
RegisterNetEvent('myjob:pay', function(amount)
    local xPlayer = ESX.GetPlayerFromId(source)
    xPlayer.addMoney(amount)
end)
-- Corrigido para QBCore, com a recompensa decidida no servidor
local QBCore = exports['qb-core']:GetCoreObject()

RegisterNetEvent('myjob:pay', function()
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end
    local reward = Config.Reward -- nunca confie em um valor enviado pelo client
    Player.Functions.AddMoney('cash', reward, 'myjob-payout')
end)

Repare na segunda correção desse exemplo: o original aceitava amount vindo do client. Esse é o padrão de falha cinco, e os dois costumam chegar juntos.

3. Código de client onde deveria ser server (e o contrário)

O FiveM roda dois ambientes Lua. O client roda no PC do jogador e pode desenhar UI, tocar animações e ler o ped local. O servidor guarda o banco de dados, o dinheiro e a verdade. Modelos de IA borram essa linha o tempo todo:

  • MySQL.query no client.lua. Impossível; o oxmysql é um recurso exclusivo do servidor. E vazaria sua string de conexão se funcionasse.
  • TriggerClientEvent chamado de um script client. Isso é uma função de servidor.
  • GetPlayerName(source) no client, onde source não existe.
  • DrawText ou lib.notify no servidor, onde não há tela para desenhar.

O sinal: um único main.lua fazendo tudo. Recursos de verdade separam client/ e server/, e o fxmanifest.lua diz qual arquivo é qual.

4. Campos do fxmanifest faltando ou errados

Um manifest que o modelo escreve de memória costuma ficar assim:

resource_manifest_version '44febabe-d386-4d18-afbe-5e627f4af937'
client_script 'client.lua'
server_script 'server.lua'

Esse é o formato de 2018. Ainda carrega, mas desativa silenciosamente o Lua 5.4 e os recursos mais novos do manifest. A forma atual é:

fx_version 'cerulean'
game 'gta5'
lua54 'yes'

shared_script '@ox_lib/init.lua'
client_script 'client.lua'
server_scripts {
    '@oxmysql/lib/MySQL.lua',
    'server.lua'
}

As omissões mais comuns são lua54 'yes' (o script então falha em <const> ou divisão inteira), o shared script @ox_lib/init.lua (toda chamada lib. vira “attempt to index a nil value (global ‘lib’)”) e @oxmysql/lib/MySQL.lua (mesmo erro, agora com MySQL).

5. Eventos de servidor que confiam no client

Este é o que faz servidores serem roubados. Um modelo escreve:

RegisterNetEvent('shop:buy', function(item, price)
    local Player = QBCore.Functions.GetPlayer(source)
    Player.Functions.RemoveMoney('cash', price)
    Player.Functions.AddItem(item, 1)
end)

Qualquer jogador com um menu de cheat pode disparar shop:buy com ('weapon_pistol', 0). O handler do evento precisa buscar o item em uma config do lado do servidor, pegar o preço de lá, verificar se o jogador pode pagar e recusar qualquer outra coisa. A skill fivem-security tem o checklist completo, mas a versão curta é: o client pede, o servidor decide.

RegisterNetEvent('shop:buy', function(itemName)
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    local item = Config.Items[itemName]
    if not Player or not item then return end
    if Player.PlayerData.money.cash < item.price then return end
    if Player.Functions.RemoveMoney('cash', item.price, 'shop-purchase') then
        Player.Functions.AddItem(itemName, 1)
    end
end)

6. Chamadas de banco de dados desatualizadas

Tutoriais antigos usavam mysql-async e ghmattimysql. Servidores modernos rodam oxmysql. O modelo escreve alegremente MySQL.Async.fetchAll('SELECT * FROM users WHERE identifier = @id', {['@id'] = id}, function(result) ... end). O oxmysql manteve uma camada de compatibilidade para esses nomes por um tempo, mas a API atual e documentada é:

local rows = MySQL.query.await('SELECT * FROM users WHERE identifier = ?', { identifier })
local id = MySQL.insert.await('INSERT INTO vehicles (owner, plate) VALUES (?, ?)', { owner, plate })

Depender dos nomes legados significa que seu script quebra no dia em que a camada de compatibilidade for removida, e pirâmides de callback são mais difíceis de revisar de qualquer forma. A skill oxmysql documenta as variantes await e as chamadas MySQL.prepare e MySQL.transaction que o modelo raramente usa corretamente.

Por que insistir no prompt não resolve

Você pode colocar “use QBCore, não ESX” em todo prompt e o modelo ainda vai escorregar, porque o problema é o que ele aprendeu, não o que você pediu. Ele não tem memória confiável de qual assinatura de QBCore.Functions.* é a atual, quais funções lib. existem ou o que MySQL.query.await retorna. Correções no prompt competem com milhares de exemplos desatualizados nos dados de treinamento.

O que funciona é colocar a referência correta na frente do modelo no momento em que ele escreve. É isso que uma skill é.

A solução: dê ao modelo documentação real com skills

Uma skill é uma pasta com um arquivo SKILL.md no topo e arquivos de referência ao lado. O SKILL.md descreve o que a skill cobre e quando usá-la. Os arquivos de referência guardam a API de verdade: assinaturas de função, nomes de eventos, trechos de manifest, erros comuns e suas correções.

Agentes como Claude Code e Cursor leem as descrições dos SKILL.md no início de uma sessão e, quando o seu pedido combina com uma delas, carregam a skill completa no contexto antes de escrever código. Então, quando você pede uma loja para QBCore, o modelo lê Player.Functions.AddItem, Player.PlayerData.money e o padrão de validação do lado do servidor a partir da referência, não da memória.

Instalar as nossas leva um minuto:

  1. Abra a página de skills de FiveM e baixe as da sua stack. Para a maioria dos servidores, são fivem-basics, oxlib, oxmysql e esx-framework ou qbcore-framework.
  2. Descompacte cada uma na pasta de skills que a sua ferramenta usa (.claude/skills/ para Claude Code, .cursor/rules/ para Cursor, .github/instructions/ para Copilot). As notas de instalação em cada página de skill têm os caminhos atuais.
  3. Inicie uma sessão nova e pergunte “quais skills de FiveM você tem carregadas?” para confirmar.

Daí em diante, o modelo escreve MySQL.query.await porque é o que a referência diz, e coloca o manuseio de dinheiro no servidor porque a skill de segurança mandou.

Checklist de revisão para recursos FiveM escritos por IA

Mesmo com as skills carregadas, revise todo recurso antes de dar ensure. Dez verificações, em ordem:

  1. Todo native existe no docs.fivem.net.
  2. Só um framework é referenciado, e é o seu.
  3. Nenhuma chamada de banco de dados, dinheiro ou inventário no client.lua.
  4. O fxmanifest.lua tem fx_version 'cerulean', game 'gta5' e lua54 'yes' quando necessário.
  5. @ox_lib/init.lua e @oxmysql/lib/MySQL.lua estão declarados se o código os usa.
  6. Todo handler de evento no servidor valida source e os argumentos.
  7. Preços, recompensas e nomes de itens vêm da config do servidor, nunca do evento.
  8. Chamadas de banco de dados usam MySQL.*.await ou callbacks com placeholders ?, nunca concatenação de string.
  9. Loops de Citizen.Wait(0) só rodam enquanto precisam (um while true do Wait(0) que desenha um marker pelo mapa inteiro é um bug de frame time esperando para acontecer).
  10. Nenhum TriggerClientEvent(-1, ...) para coisas que só um jogador deveria ver.

Dez minutos com essa lista pegam a maior parte do que um menu de cheat encontraria por você.

Perguntas frequentes

O ChatGPT consegue escrever um script FiveM funcional?

Sim, para recursos pequenos e independentes com instruções claras, e com muito mais confiabilidade quando tem skills ou documentação no contexto. Ele sofre com qualquer coisa que dependa de uma versão específica de framework ou de um recurso pago que nunca viu.

Isso acontece com Claude, Copilot e Gemini também?

Sim. Todos os grandes modelos de linguagem compartilham o mesmo problema de dados de treinamento: exemplos desatualizados de FiveM em muitos sabores incompatíveis. Os modelos diferem em quão bem seguem a documentação que você dá a eles, e é por isso que as skills ajudam em todos.

Uma skill é a mesma coisa que uma regra do Cursor ou um system prompt?

Quase. Uma regra do Cursor ou um CLAUDE.md é uma instrução curta que está sempre ativa. Uma skill é carregada só quando é relevante e pode trazer vários arquivos de referência, então ela guarda uma referência de API completa sem inflar todos os prompts. Nossas skills vêm como SKILL.md mais referências e podem ser colocadas em qualquer um dos dois mecanismos.

Adicione estas skills ao Cursor, VS Code ou Claude Code para que a IA conheça as APIs reais citadas neste artigo.