FiveM crafting system: ox_inventory benches and custom crafting
Build crafting on FiveM: ox_inventory crafting benches in data/crafting.lua with ingredients and zones, a custom server-checked recipe, and anti-dupe tips.
Crafting means a player turns some items into another item. You can use the crafting benches built into ox_inventory, or write your own recipe in a script. This article shows both, and then the checks that keep players from duplicating items.
ox_inventory crafting benches
Open ox_inventory/data/crafting.lua. It returns a list of benches. Each bench has a list of craftable items and a place in the world:
return {
{
items = {
{
name = 'lockpick',
ingredients = {
scrap_metal = 5,
plastic = 2,
},
duration = 5000,
count = 1,
},
{
name = 'bandage',
ingredients = {
cloth = 2,
},
duration = 3000,
},
},
points = {
vec3(1087.3, -3099.4, -39.0),
},
},
}What each field does:
| Field | Meaning |
|---|---|
name |
The item that is produced |
ingredients |
Item names and the count of each one needed |
duration |
Crafting time in milliseconds |
count |
How many of the result you get per craft |
points |
Coordinates where the bench can be used |
zones |
Box zones for ox_target, as an alternative to points |
Everything named in name or ingredients must exist in data/items.lua. See adding items to ox_inventory. Restart ox_inventory after editing the file.
Tip: an ingredient value below 1 does not consume the item, it uses that fraction of its durability. A value of
0.1on a tool with durability uses ten percent of it.
Zones instead of points
A zone is a box the player can target:
zones = {
{
coords = vec3(1087.3, -3099.4, -39.0),
size = vec3(1.5, 1.0, 1.0),
distance = 1.5,
rotation = 45.0,
},
},Zones need ox_target to be running. Look at the examples in your copy of data/crafting.lua for the exact fields of your version, as the format changes between releases. For restricting a bench to a job, ox_inventory also reads groups on the bench, the same idea as in ox_inventory stashes.
A custom recipe with server checks
If you want your own rules, such as a skill level, a cost or a progress bar of your own, write the recipe in your script and let ox_inventory only handle the items. The important part is that the server does everything:
-- server.lua
local crafting = {}
local recipe = {
result = 'lockpick',
ingredients = { scrap_metal = 5, plastic = 2 },
}
lib.callback.register('my_script:craft', function(source)
if crafting[source] then return false end
crafting[source] = true
local ok = false
-- 1. check every ingredient
local hasAll = true
for item, count in pairs(recipe.ingredients) do
if exports.ox_inventory:Search(source, 'count', item) < count then
hasAll = false
break
end
end
-- 2. check the player can carry the result
if hasAll and exports.ox_inventory:CanCarryItem(source, recipe.result, 1) then
-- 3. remove, then add
local removed = {}
local allRemoved = true
for item, count in pairs(recipe.ingredients) do
if exports.ox_inventory:RemoveItem(source, item, count) then
removed[item] = count
else
allRemoved = false
break
end
end
if allRemoved and exports.ox_inventory:AddItem(source, recipe.result, 1) then
ok = true
else
-- give back what was removed
for item, count in pairs(removed) do
exports.ox_inventory:AddItem(source, item, count)
end
end
end
crafting[source] = nil
return ok
end)The client asks, plays the progress bar, and only reads the answer:
-- client.lua
if lib.progressBar({ duration = 5000, label = 'Crafting' }) then
local ok = lib.callback.await('my_script:craft', false)
lib.notify({ description = ok and 'Crafted' or 'Missing items', type = ok and 'success' or 'error' })
endFor the callback and notification functions, see server callbacks on ESX, QBCore and ox_lib.
Anti-dupe tips
Crafting is a classic place for item duplication, because items are removed and added in two steps. Keep these rules:
- Server only. The server checks ingredients and gives the result. The client sends "I want to craft recipe X", never counts or item names it made up.
- Check, then remove, then add. Never add the result before the removal succeeded. If the add fails, give the ingredients back.
- One craft at a time. A flag per player, like
crafting[source]above, stops a spammed event from running the recipe several times in parallel. - Check
CanCarryItemfirst. A full inventory is the usual reasonAddItemfails, and the player would lose the ingredients. - Check the distance. If the recipe belongs to a bench, compare the player's coordinates to the bench on the server.
- Clear state on drop. Reset the flag when a player leaves, so a disconnect in the middle does not lock the recipe.
AddEventHandler('playerDropped', function()
crafting[source] = nil
end)For more on protecting events, see securing server events.
Checklist
| Symptom | Fix |
|---|---|
| Bench not appearing | Edit data/crafting.lua, then restart ox_inventory |
| Recipe errors on start | An item in name or ingredients is missing from data/items.lua |
| Zone does nothing | ox_target must be running, and the zone fields must match your version |
| Ingredients lost, no result | Check CanCarryItem first and refund when AddItem fails |
| Items duplicated | Move the whole recipe to the server, add a one-at-a-time flag |
| Craft works from far away | Check the player's distance to the bench on the server |
Quick answers
How do I add a crafting bench to ox_inventory?
Add an entry to ox_inventory/data/crafting.lua with items (each with ingredients and duration) and either points or zones for where the bench stands. Restart ox_inventory.
Can a recipe use part of an item's durability?
Yes. An ingredient value below 1 uses that fraction of the durability of an item that has it, rather than consuming the item.
How do I stop players from duplicating items while crafting?
Do the whole recipe on the server: check the ingredients, remove them, then add the result, and refuse to start a second craft while one is running for that player.
Scripts that skip this problem
Item Creator V2Create usable items with animations, props, effects and more β without writing code.View script β
Shop CreatorBuild a shop in under a minute β owners, employees, vaults and robberies included.View script β
Quest CreatorA visual editor for quests and NPC dialogues, built node by node in game.View script β