Commands#
Crafting Creator registers one command for staff. Players need none: benches are opened by walking up to them.
Command | Where | Description |
|---|---|---|
| In game | Opens the creator: the list of benches made in game, with create, edit and delete. Bound to |
The key is a FiveM key mapping, so each player can rebind it under Settings → Key Bindings → FiveM. Changing Config.OpenCreatorKey only changes the default for players who have never had the mapping.
Debug commands#
With Config.Debug = true, a few more client commands exist for tuning how a bench looks. None of them save anything — copy the values you like into config/main.lua.
Command | Description |
|---|---|
| With a bench open, moves the camera and the showcased item relative to the bench prop. The six numbers are the |
| Puts the showcase camera on the first bench of |
| Changes the spotlight over the bench. |
| Moves the spotlight and the point it aims at. |
| Previews a weapon tint on the showcased weapon. |
Debug mode also registers developer test commands on the server that write directly into
crafting_queue, and prints every action to the console. Use it on a test server, and keepConfig.Debug = falsein production.
Server Hooks#
Crafting Creator has no exports for gameplay; scripts plug into it from the server, through four hooks in server/custom/hooks.lua and the events further down. The hooks are where a skill or perk script changes a craft — a faster craft for a skilled player, a material saved, a bonus item — and the safe place to award its own XP. An error inside a hook is caught and printed; it never breaks the craft.
ModifyCraft — change duration, materials, output or XP
Runs every time a craft is about to start, and also when the recipe list is shown (data.preview = true), so the window displays the modified time and materials. Return a table with only what you want to change, or nil for the recipe as written.
function CraftingHooks.ModifyCraft(source, data)
-- data.tableId, data.itemName, data.amount requested amount
-- data.duration seconds per item
-- data.ingredients TOTAL materials for this craft { iron = 20, ... }
-- data.earn, data.price, data.level
-- data.preview true while the list is shown, nothing taken yet
-- data.mode 'queue' | 'proximity'
-- your skill script's own export
local perk = exports['my-skills']:GetLevel(source, 'crafting') or 0
if perk < 5 then return end
return {
duration = math.floor(data.duration * 0.8), -- 20% faster
ingredients = { -- one iron saved
iron = math.max(0, (data.ingredients.iron or 0) - 1),
},
outputAmount = not data.preview and data.amount + 1 or nil, -- one extra
}
endReturn field | Rule |
|---|---|
| Seconds per item, whole number, 0 or more. |
| Totals for the whole craft. Can only go down, never above the recipe; ingredients you leave out stay as they are. |
| Items delivered. Never below the amount requested. If the inventory has no room for the bonus, the requested amount is delivered instead. |
| Crafting XP per item, 0 or more. |
The limits are enforced after your hook runs, so a mistake can never make a craft cost more than the recipe or deliver less than was paid for.
OnCraftStarted
After the money and materials are taken and the craft is running.
function CraftingHooks.OnCraftStarted(source, payload)
-- payload.queueId, payload.tableId, payload.item, payload.amount,
-- payload.outputAmount, payload.duration, payload.ingredients, payload.mode
endOnCraftCollected — the safe place to award XP
Only after the item is in the player's inventory and the queue entry or proximity session is consumed. It never fires for a cancel, a refund, a failed delivery or a second click on the same item.
function CraftingHooks.OnCraftCollected(source, payload)
-- payload.amount items delivered (with any bonus)
-- payload.requestedAmount items the player asked for
-- payload.earn crafting XP awarded
exports['pn-skills']:AddXp(source, 'crafting', payload.amount)
endOnCraftCancelled
A proximity craft that ended without delivering. Never award XP here.
function CraftingHooks.OnCraftCancelled(source, payload)
-- payload.item, payload.amount, payload.reason, payload.mode
endServer Events#
The same moments are also fired as server events, so another resource can listen without touching Crafting Creator's files:
Event | Arguments | When |
|---|---|---|
|
| A craft has started. |
|
| An item was delivered. The event to award XP from. |
|
| A proximity craft was cancelled or refunded. |
|
| A craft is being prepared, after |
-- server side of any resource
AddEventHandler('qs-crafting:server:craftCollected', function(source, payload)
if payload.item == 'weapon_pistol' then
print(('%s crafted %d pistol(s) at bench %s'):format(
GetPlayerName(source), payload.amount, payload.tableId))
end
end)Arguments passed to another resource are copies. Listening to
modifyCraftfrom outside tells you what a craft will be, but changingmodsthere has no effect — to change a craft, useCraftingHooks.ModifyCraft.
The payload#
Field | Meaning |
|---|---|
| The queue entry's number in queue mode; a session id string in proximity mode. |
| The bench: a number for benches made in the creator, the |
| The item name being crafted. |
| Requested on start and cancel; delivered on collect. |
| Planned output on start; the original request on collect. |
| On start: seconds per item and the materials actually taken. |
| On collect: the crafting XP awarded. |
|
|
| On cancel — see below. |
Reading a Player's Crafting Level#
Each player's level is kept in a replicated state bag, crafting_skill, readable from any resource on either side — useful for a job that only hires skilled crafters, or a shop that shows the level:
-- server
local skill = Player(source).state.crafting_skill
-- { level = 7, xp = 120, xpToNextLevel = 1139 }
if skill and skill.level >= 10 then
-- ...
end
-- client
local skill = LocalPlayer.state.crafting_skillIt is set when the player loads and updated every time they earn XP. Treat it as read-only: the level is saved from Crafting Creator's own XP, so writing to the state bag from another script is not stored.
Cancel Reasons#
payload.reason on craftCancelled says why a proximity craft did not deliver. In every case the refund in Config.CraftingProgression.CancelRefund has already been given.
Reason | Means |
|---|---|
| The player cancelled the progress circle. |
| They moved further than |
| The craft finished but the item did not fit in their inventory. |
| They left the server mid-craft. |
|
|



