This guide walks a FiveM builder through creating a server-authoritative QBCore hunting job. It includes a short implementation plan, assumptions, complete destination-labelled files, installation steps, validation and anti-cheat notes, and quick next steps so you can ship a safe hunting script.
Implementation plan
Short plan (do these in order):
- Decide scope: free-for-all hunting or job-locked. Configure animal spawn points and sell/pelt items in config.lua.
- Create resource manifest and server/client scripts. Use server events for all state changes: giving/removing items, paying money.
- Integrate interaction (qb-target or keybind) on client; call server events for authoritative actions.
- Test with multiple players, check item integrity, and apply anti-spam/cooldowns on server.
Assumptions & framework dependencies
Assumptions: you use QBCore v1/v2 style exports (exports['qb-core']:GetCoreObject()). The guide avoids inventory API specifics beyond common functions: QBCore.Functions.GetPlayer, Player.Functions.AddItem, Player.Functions.RemoveItem, and Player.Functions.AddMoney. If you use ox_inventory or a different core, adapt those calls accordingly. Optional: qb-target for interaction targets.
Destination-labelled files
Place these files inside a resource folder named qb-hunting. The list below is complete for a minimal, secure hunting job.
fxmanifest.lua
fx_version 'cerulean'
games {'gta5'}
author 'Your Name'
description 'QBCore Hunting Job'
version '1.0.0'
shared_scripts {
'config.lua'
}
client_scripts {
'client/main.lua'
}
server_scripts {
'server/main.lua'
}
dependencies {
'qb-core'
}
config.lua
Config = {}
-- Toggle whether only players with a specific job can sell pelts
Config.RequireJob = false
Config.AllowedJob = 'hunter' -- only used if RequireJob = true
-- Prices per pelt item
Config.Prices = {
['pelt_rabbit'] = 50,
['pelt_deer'] = 250,
['pelt_bear'] = 800
}
-- Sell ped/coords -- simple single location example
Config.SellLocation = { x = 2442.0, y = 4969.0, z = 41.35 }
-- Server-side cooldown (ms) per player to prevent spam
Config.SellCooldown = 1500
server/main.lua
local QBCore = exports['qb-core']:GetCoreObject()
local lastSell = {} -- source -> timestamp
RegisterNetEvent('qb-hunting:server:SellPelt', function(peltItem)
local src = source
local now = os.time() * 1000
if lastSell[src] and (now - lastSell[src]) < Config.SellCooldown then
TriggerClientEvent('QBCore:Notify', src, 'Please wait before selling again', 'error')
return
end
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
if Config.RequireJob and Player.PlayerData.job.name ~= Config.AllowedJob then
TriggerClientEvent('QBCore:Notify', src, 'Your job cannot sell these pelts', 'error')
return
end
local item = Player.Functions.GetItemByName(peltItem)
if not item then
TriggerClientEvent('QBCore:Notify', src, 'You have no pelts to sell', 'error')
return
end
local price = Config.Prices[peltItem] or 0
if price <= 0 then
TriggerClientEvent('QBCore:Notify', src, 'This pelt cannot be sold', 'error')
return
end
-- Remove exactly one pelt, server-side authoritative
local removed = Player.Functions.RemoveItem(peltItem, 1, false)
if removed then
Player.Functions.AddMoney('cash', price, 'hunting-pelt-sell')
TriggerClientEvent('QBCore:Notify', src, 'Sold pelt for $' .. price, 'success')
lastSell[src] = now
else
TriggerClientEvent('QBCore:Notify', src, 'Failed to remove pelt', 'error')
end
end)
client/main.lua
local QBCore = exports['qb-core']:GetCoreObject()
-- Example: direct sell interaction at a fixed coord (also support qb-target externally)
Citizen.CreateThread(function()
while true do
local sleep = 2000
local ped = PlayerPedId()
local pCoords = GetEntityCoords(ped)
local dist = #(pCoords - vector3(Config.SellLocation.x, Config.SellLocation.y, Config.SellLocation.z))
if dist < 3.0 then
sleep = 5
-- show prompt (use your notification/UI) and listen for keypress
-- For brevity we use a simple key check
if IsControlJustReleased(0, 38) then -- E
-- open a sell menu or attempt to sell a default item
-- In real use, show player's pelts and select item to sell
TriggerServerEvent('qb-hunting:server:SellPelt', 'pelt_deer')
end
end
Citizen.Wait(sleep)
end
end)
Installation & where files belong
- Create folder resources/[local]/qb-hunting
- Drop the files above into that folder with the same filenames.
- Start the resource in server.cfg:
ensure qb-hunting - If you use qb-target, add target models or add an export in
client/main.luato register the sell spot.
Validation, security and anti-cheat notes
- Never give money or remove items on the client. All state changes happen in server/main.lua.
- Validate Player existence with
QBCore.Functions.GetPlayerand check the real inventory withPlayer.Functions.GetItemByName. - Use cooldowns (Config.SellCooldown) and optionally server-side rate limits to stop automated farming.
- Do not trust client-sent prices or counts; derive prices from server-side Config.Prices and remove items server-side.
- If you integrate with a police or economy system, add logs and export events for auditing.
| Checklist | Why it matters |
|---|---|
| Server-only money/item changes | Prevents spoofing and duping |
| Cooldown per player | Mitigates rapid automated sells |
| Job checks (optional) | Supports roleplay rules and monetization |
| qb-target integration | Better UX than a keybind loop |
| Test with multiple players | Find race conditions and concurrency issues |
Testing and validation steps
- Start the server and join as two players to test concurrency.
- Try selling without a pelt (should be denied).
- Give a pelt via your server admin tools or a spawn command, then sell and confirm money arrival in server logs.
- Attempt to spam sell to ensure cooldown and removal logic hold.
- Check resource logs for unexpected errors and tighten error handling.
Next practical steps
Improve realism by spawning animal entities client-side and dropping progressive pelt types. Add a butcher minigame client-side (only triggers a server event when completed), track pelt quality in item metadata, and provide NPC buyers with dynamic prices. For workflow acceleration, consider generating plan files and tests using a scripting workspace like Stellar AI — start at https://trystellarai.com/app to prototype resource structure and tests. When you publish or iterate, keep the spec and tests with the resource; Stellar AI can help with iteration at https://trystellarai.com/app. For articles and deeper design patterns see the engineering posts on the Stellar blog: https://trystellarai.com/blog.