Skip to main content
The Crafting component provides a flexible system for creating crafting benches where players can combine items to create new ones. Supports recipes, cooldowns, restrictions, and schematics.

Overview

Access via COMPONENTS.Crafting (server-side only).

Crafting Benches

Register custom crafting locations

Recipes

Define item combination recipes

Cooldowns

Per-bench, per-recipe cooldowns

Restrictions

Job, reputation, item requirements
Server-Side Only: All crafting operations must be performed on the server for security.

Crafting Benches

RegisterBench

Register a crafting bench with recipes and restrictions. Syntax:
COMPONENTS.Crafting:RegisterBench(id, label, targeting, location, restrictions, recipes, canUseSchematics)
Parameters:
NameTypeRequiredDescription
idstringYesUnique bench identifier
labelstringYesDisplay name of the bench
targetingbooleanYesShow in targeting/interaction menu
locationvector3NoBench coordinates (if physical location)
restrictionstableNoAccess restrictions {job, rep, items}
recipestableYesTable of recipe definitions
canUseSchematicsbooleanNoAllow schematic recipes (default: false)
Recipe Structure:
{
    result = {
        name = "lockpick",  -- Item to create
        count = 1           -- Quantity created
    },
    items = {               -- Required materials
        { name = "steel", count = 2 },
        { name = "plastic", count = 1 }
    },
    time = 5000,           -- Crafting duration (ms)
    cooldown = 3600,       -- Recipe cooldown (seconds, optional)
    level = 1,             -- Required crafting level (optional)
    durability = {         -- Random durability range (optional)
        min = 20000,
        max = 40000
    }
}
Example:
-- Server side - Register mechanic workbench
COMPONENTS.Crafting:RegisterBench(
    'mechanic_workbench',
    'Mechanic Workbench',
    true,
    vector3(123.45, -678.90, 30.00),
    {
        job = {
            { id = 'mechanic', onDuty = true }
        }
    },
    {
        repair_kit = {
            result = {
                name = 'repairkit',
                count = 1
            },
            items = {
                { name = 'steel', count = 5 },
                { name = 'plastic', count = 3 },
                { name = 'rubber', count = 2 }
            },
            time = 10000,
            cooldown = 1800  -- 30 minute cooldown
        },
        advanced_repair_kit = {
            result = {
                name = 'advrepairkit',
                count = 1
            },
            items = {
                { name = 'steel', count = 10 },
                { name = 'plastic', count = 5 },
                { name = 'electronics', count = 2 }
            },
            time = 15000,
            cooldown = 3600,  -- 1 hour cooldown
            level = 3  -- Requires mechanic level 3
        }
    },
    false  -- Cannot use schematics
)
Restrictions Structure:
{
    job = {
        { id = 'mechanic', onDuty = true },
        { id = 'engineer', onDuty = false }
    },
    rep = {
        { id = 'mechanic_rep', level = 5 }
    },
    items = {
        { name = 'wrench', count = 1 }  -- Must have in inventory
    }
}

AddRecipeToBench

Add a recipe to an existing bench. Syntax:
COMPONENTS.Crafting:AddRecipeToBench(benchId, recipeId, recipe)
Parameters:
NameTypeRequiredDescription
benchIdstringYesBench identifier
recipeIdstringYesUnique recipe ID
recipetableYesRecipe definition
Example:
-- Server side - Add new recipe to existing bench
COMPONENTS.Crafting:AddRecipeToBench(
    'mechanic_workbench',
    'turbo_kit',
    {
        result = {
            name = 'turbo',
            count = 1
        },
        items = {
            { name = 'steel', count = 15 },
            { name = 'aluminum', count = 10 },
            { name = 'electronics', count = 5 }
        },
        time = 30000,
        cooldown = 7200,
        level = 5
    }
)

Crafting Operations

Craft.Start

Start crafting an item (called internally by framework). Syntax:
COMPONENTS.Crafting.Craft:Start(crafter, bench, result, qty)
Parameters:
NameTypeRequiredDescription
crafternumberYesCharacter SID
benchstringYesBench identifier
resultstringYesRecipe ID to craft
qtynumberYesQuantity to craft
Returns:
TypeDescription
table{error, message} if failed, or craft result data
Example:
-- Server side - Handle craft request
RegisterServerEvent('crafting:server:StartCraft', function(benchId, recipeId, quantity)
    local src = source
    local player = Fetch:Source(src)

    if not player then return end

    local char = player:GetData('Character')
    if not char then return end

    local stateId = char:GetData('SID')

    -- Start crafting
    local result = COMPONENTS.Crafting.Craft:Start(stateId, benchId, recipeId, quantity)

    if result.error then
        TriggerClientEvent('mythic-notifications:client:Send', src, {
            message = result.message,
            type = 'error'
        })
    else
        TriggerClientEvent('mythic-notifications:client:Send', src, {
            message = 'Crafting started',
            type = 'success'
        })
    end
end)

Complete Examples

Gun Crafting Bench

-- Server side - Illegal gun crafting bench
COMPONENTS.Crafting:RegisterBench(
    'gun_bench',
    'Weapon Workbench',
    true,
    vector3(1234.56, -789.01, 50.00),
    {
        rep = {
            { id = 'underground', level = 10 }  -- Requires underground reputation
        },
        items = {
            { name = 'weapon_license', count = 1 }  -- Must have license
        }
    },
    {
        craft_pistol = {
            result = {
                name = 'weapon_pistol',
                count = 1
            },
            items = {
                { name = 'pistol_frame', count = 1 },
                { name = 'pistol_barrel', count = 1 },
                { name = 'gun_spring', count = 2 },
                { name = 'gun_screws', count = 5 }
            },
            time = 25000,
            cooldown = 3600,
            durability = {
                min = 15000,
                max = 25000
            }
        },
        craft_smg = {
            result = {
                name = 'weapon_smg',
                count = 1
            },
            items = {
                { name = 'smg_frame', count = 1 },
                { name = 'smg_barrel', count = 1 },
                { name = 'gun_spring', count = 3 },
                { name = 'gun_screws', count = 8 },
                { name = 'electronics', count = 1 }
            },
            time = 40000,
            cooldown = 7200,
            level = 5,
            durability = {
                min = 20000,
                max = 35000
            }
        }
    },
    false
)

Drug Processing Bench

-- Server side - Drug processing table
COMPONENTS.Crafting:RegisterBench(
    'drug_processing',
    'Processing Table',
    true,
    vector3(987.65, -432.10, 20.00),
    nil,  -- No restrictions
    {
        process_coke = {
            result = {
                name = 'coke_bag',
                count = 10
            },
            items = {
                { name = 'coke_brick', count = 1 },
                { name = 'cutting_agent', count = 2 }
            },
            time = 15000,
            cooldown = 600  -- 10 minute cooldown
        },
        process_meth = {
            result = {
                name = 'meth_bag',
                count = 15
            },
            items = {
                { name = 'meth_brick', count = 1 }
            },
            time = 20000,
            cooldown = 900  -- 15 minute cooldown
        },
        bag_weed = {
            result = {
                name = 'weed_bag',
                count = 20
            },
            items = {
                { name = 'weed_oz', count = 1 },
                { name = 'plastic_bag', count = 20 }
            },
            time = 10000,
            cooldown = 300  -- 5 minute cooldown
        }
    },
    false
)

Advanced Electronics Bench

-- Server side - Electronics workbench with job requirement
COMPONENTS.Crafting:RegisterBench(
    'electronics_bench',
    'Electronics Workbench',
    true,
    vector3(456.78, -123.45, 35.00),
    {
        job = {
            { id = 'electronics', onDuty = true }
        }
    },
    {
        craft_phone = {
            result = {
                name = 'phone',
                count = 1
            },
            items = {
                { name = 'phone_parts', count = 1 },
                { name = 'electronics', count = 3 },
                { name = 'battery', count = 1 }
            },
            time = 12000
        },
        craft_radio = {
            result = {
                name = 'radio',
                count = 1
            },
            items = {
                { name = 'radio_parts', count = 1 },
                { name = 'electronics', count = 2 },
                { name = 'antenna', count = 1 }
            },
            time = 10000
        },
        craft_laptop = {
            result = {
                name = 'laptop',
                count = 1
            },
            items = {
                { name = 'laptop_shell', count = 1 },
                { name = 'motherboard', count = 1 },
                { name = 'electronics', count = 5 },
                { name = 'battery', count = 2 }
            },
            time = 30000,
            cooldown = 1800,
            level = 3
        }
    },
    false
)

Food Preparation Station

-- Server side - Kitchen/cooking station
COMPONENTS.Crafting:RegisterBench(
    'cooking_station',
    'Cooking Station',
    true,
    vector3(234.56, -876.54, 30.00),
    {
        job = {
            { id = 'burger_shot', onDuty = true },
            { id = 'restaurant', onDuty = true }
        }
    },
    {
        cook_burger = {
            result = {
                name = 'burger',
                count = 1
            },
            items = {
                { name = 'raw_beef', count = 1 },
                { name = 'bun', count = 1 },
                { name = 'lettuce', count = 1 },
                { name = 'tomato', count = 1 }
            },
            time = 5000
        },
        cook_fries = {
            result = {
                name = 'fries',
                count = 1
            },
            items = {
                { name = 'potato', count = 2 },
                { name = 'oil', count = 1 }
            },
            time = 3000
        },
        make_soda = {
            result = {
                name = 'soda',
                count = 1
            },
            items = {
                { name = 'cup', count = 1 },
                { name = 'syrup', count = 1 }
            },
            time = 2000
        }
    },
    false
)

Lockpicking Tools Bench

-- Server side - Criminal tools bench
COMPONENTS.Crafting:RegisterBench(
    'tools_bench',
    'Tool Making Bench',
    true,
    vector3(567.89, -234.56, 25.00),
    {
        rep = {
            { id = 'criminal', level = 3 }
        }
    },
    {
        craft_lockpick = {
            result = {
                name = 'lockpick',
                count = 1
            },
            items = {
                { name = 'metal_scrap', count = 2 },
                { name = 'plastic', count = 1 }
            },
            time = 8000,
            durability = {
                min = 5,
                max = 15
            }
        },
        craft_advanced_lockpick = {
            result = {
                name = 'adv_lockpick',
                count = 1
            },
            items = {
                { name = 'metal_scrap', count = 4 },
                { name = 'plastic', count = 2 },
                { name = 'electronics', count = 1 }
            },
            time = 15000,
            cooldown = 1800,
            level = 5,
            durability = {
                min = 15,
                max = 30
            }
        },
        craft_thermite = {
            result = {
                name = 'thermite',
                count = 1
            },
            items = {
                { name = 'aluminum_powder', count = 3 },
                { name = 'iron_oxide', count = 2 },
                { name = 'magnesium', count = 1 }
            },
            time = 20000,
            cooldown = 3600,
            level = 8
        }
    },
    false
)

Client Integration

Opening Crafting Bench

-- Client side - Trigger bench from targeting/interaction
AddEventHandler('crafting:client:OpenBench', function(data)
    local benchId = data.benchId

    -- Request bench data from server
    COMPONENTS.Callbacks:ServerCallback('crafting:server:GetBench', benchId, function(benchData)
        if benchData then
            -- Open crafting UI
            SendNUIMessage({
                type = 'OPEN_CRAFTING',
                data = benchData
            })
        else
            COMPONENTS.Notification:Error('Cannot access this bench')
        end
    end)
end)

-- Client side - Request craft
RegisterNUICallback('Crafting:Craft', function(data, cb)
    -- data = { benchId, recipeId, quantity }
    TriggerServerEvent('crafting:server:StartCraft', data.benchId, data.recipeId, data.quantity)
    cb(true)
end)

Cooldown Management

Cooldowns are automatically managed by the framework. They are stored in the database and persist across restarts. Cooldown Features:
  • Per-recipe cooldowns
  • Stored in database (crafting_cooldowns table)
  • Automatic cleanup of expired cooldowns
  • Admin commands to clear cooldowns
Admin Command:
-- Server side - Admin can remove cooldowns
RegisterCommand('clearcraftcd', function(source, args)
    local player = Fetch:Source(source)

    if not player or not player.Permissions:IsAdmin() then
        return
    end

    local benchId = args[1]
    local recipeId = args[2]

    -- Remove cooldown (internal function)
    RemoveCraftingCooldown(source, benchId, recipeId)
end, false)

Best Practices

Balanced Recipes

-- ✅ GOOD - Balanced crafting times and cooldowns
{
    craft_basic_item = {
        result = { name = 'lockpick', count = 1 },
        items = {
            { name = 'metal', count = 2 }
        },
        time = 5000,  -- 5 seconds (reasonable)
        cooldown = 300  -- 5 minutes (prevents spam)
    }
}

-- ❌ BAD - Unbalanced
{
    craft_op_item = {
        result = { name = 'super_gun', count = 100 },  -- Too many
        items = {
            { name = 'plastic', count = 1 }  -- Too cheap
        },
        time = 100,  -- Too fast
        cooldown = nil  -- No cooldown = spam
    }
}

Security

//GOOD - Restrict powerful items
COMPONENTS.Crafting:RegisterBench(
    'weapons_bench',
    'Illegal Weapons',
    true,
    location,
    {
        rep = { { id = 'criminal', level = 10 } },  -- High requirement
        items = { { name = 'weapon_license', count = 1 } }
    },
    recipes,
    false
)

//BAD - No restrictions on powerful items
COMPONENTS.Crafting:RegisterBench(
    'weapons_bench',
    'Free Weapons',
    true,
    location,
    nil,  -- Anyone can use!
    recipes,
    false
)

Item Balance

//GOOD - Reasonable material costs
{
    items = {
        { name = 'steel', count = 5 },
        { name = 'plastic', count = 3 },
        { name = 'electronics', count = 1 }
    }
}

//BAD - Unrealistic costs
{
    items = {
        { name = 'plastic', count = 1 }  -- Making assault rifle from 1 plastic
    }
}

Next Steps

Recipe IDs: Use descriptive recipe IDs like craft_pistol instead of recipe1. Makes debugging and admin management easier.
Cooldowns Persist: Cooldowns are stored in the database and survive server restarts. Plan cooldown durations carefully for game balance.