๐ ๏ธ Configuration
โ๏ธ Configuration
Shared Configuration (configs/shared.lua)
Development Mode
Shared.DevelopmentMode = false- DevelopmentMode: Enables development/debug features. The
/craftingadmincommand does not require this to be enabled โ it is available to admins at all times.
๐ก๏ธ Admin Command โ /craftingadmin
Admin-only command. This command is available to all players with admin permissions. No additional configuration (such as DevelopmentMode) is required.
What is /craftingadmin?
The /craftingadmin command opens the in-game Admin Panel, a powerful, real-time configuration editor that lets server administrators manage the entire crafting system without touching any configuration files.
Step-by-Step Usage
- Join the server as an admin
- Open chat and run
/craftingadmin - The Admin Panel UI will open, make your changes live
- Save the configuration and restart script!
Permissions
The command checks the player's permission level through devhub_lib. Only players recognised as admins by the configured framework (ESX group admin/superadmin, QBCore god/admin, etc.) can execute /craftingadmin. All other players will receive an access-denied notification.
Permission handling is managed by devhub_lib. Refer to the Admin System documentation to configure admin groups for your framework.
Categories Configuration
Shared.Categories = {
["all"] = {
label = "All",
icon = "fa-solid fa-layer-group",
order = 0
},
["weapons"] = {
label = "Weapons",
icon = "fa-solid fa-gun",
order = 1
},
["tools"] = {
label = "Tools",
icon = "fa-solid fa-wrench",
order = 2
},
}- label: Display name shown in the UI dropdown
- icon: FontAwesome icon class for the category
- order: Sort order in the category list (lower = first)
Blueprints Configuration
Shared.Blueprints = {
["devhub_pistol"] = {
label = "Pistol Blueprint",
description = "Basic sidearm blueprint for close-range combat.",
img = "https://example.com/pistol_bp.webp",
rarity = "common",
hidden = false,
items = {
{ name = "devhub_metal_scrap", amount = 3 },
{ name = "devhub_steel_plate", amount = 2 },
},
customUnlock = {
{
label = "Complete the 'Rookie Training' mission",
icon = "fa-solid fa-user-graduate",
handler = function(source)
-- Custom logic to check unlock condition
return true -- Return true if condition met
end
},
}
},
}| Property | Type | Description |
|---|---|---|
label | string | Display name of the blueprint |
description | string | Description text shown in tooltip |
img | string | URL to blueprint image |
rarity | string | Rarity tier: common, uncommon, rare, epic, legendary |
hidden | boolean | If true, shows as "???" until unlocked |
items | table | Array of required items to craft the blueprint |
customUnlock | table | Optional custom conditions for unlocking |
Crafts Configuration
Shared.Crafts = {
["weapons_crafts"] = {
{
uid = "pistol_standard_01",
ingredients = {
{ name = "devhub_steel_plate", amount = 3 },
{ name = "devhub_spring_mechanism", amount = 2 },
},
maxQuantity = -1, -- -1 = unlimited
time = 15, -- Crafting time in seconds
result = {
name = "weapon_pistol",
amount = 1,
},
blueprint = "devhub_pistol", -- Optional: requires this blueprint
category = "weapons",
prop = "w_pi_pistol", -- Optional: 3D preview prop
rarity = "common",
},
},
}| Property | Type | Description |
|---|---|---|
uid | string | Unique identifier for the recipe |
ingredients | table | Array of required materials with name and amount |
maxQuantity | number | Maximum craftable at once (-1 = unlimited) |
time | number | Crafting duration in seconds |
result | table | Output item name and amount |
blueprint | string | Optional blueprint requirement |
category | string | Category key for filtering |
prop | string | Optional 3D prop model for preview |
rarity | string | Rarity tier for visual styling |
Crafting Stations Configuration
Shared.Craftings = {
{
id = "weapon_crafting",
label = "Weapon Crafting",
craftsId = "weapons_crafts", -- References Shared.Crafts key
queueSize = {
amount = 5,
custom = function(source)
-- Custom queue size logic (e.g., VIP gets more slots)
return nil -- Return nil to use default amount
end
},
coords = vector4(934.45, -1522.09, 30.08, -179.32),
prop = "gr_prop_gr_bench_02a",
camera = {
x = 934.49,
y = -1520.90,
z = 31.49,
lookAtX = 934.56,
lookAtY = -1525.89,
lookAtZ = 31.58,
},
attachmentsEnabled = true,
blip = {
name = "Weapon Crafting",
sprite = 566,
size = 0.8,
color = 5,
},
},
}| Property | Type | Description |
|---|---|---|
id | string | Unique identifier for the station |
label | string | Display name in UI |
craftsId | string | Key referencing Shared.Crafts recipe group |
queueSize.amount | number | Default queue slots |
queueSize.custom | function | Optional function for dynamic queue size |
coords | vector4 | World position and heading |
prop | string | 3D prop model name |
camera | table | Camera position and lookAt coordinates |
attachmentsEnabled | boolean | Enable weapon attachment tab at this station |
blip | table | Optional map blip configuration |
Community Projects Configuration
Shared.CommunityProjects = {
{
id = "community_project_1",
label = "New Vehicle Fleet",
description = "Help us add new vehicles to the server!",
img = "https://example.com/project.webp",
order = 0,
items = {
{ name = "devhub_metal_scrap", amount = 1200 },
{ name = "devhub_spring_mechanism", amount = 600 },
{ name = "devhub_electronic_chip", amount = 500 },
},
},
}| Property | Type | Description |
|---|---|---|
id | string | Unique identifier for the project |
label | string | Project display name |
description | string | Project description text |
img | string | URL to project image |
order | number | Display order (lower = first) |
items | table | Required materials with target amounts |
Weapon Attachments Configuration
Weapon attachments are configured in individual files under configs/attachments/. Each weapon has its own configuration file.
-- configs/attachments/WEAPON_ASSAULTRIFLE.lua
Shared.WeaponAttachments["WEAPON_ASSAULTRIFLE"] = {
label = "Assault Rifle",
itemName = "weapon_assaultrifle",
attachments = {
["suppressor"] = {
{ name = "COMPONENT_AT_AR_SUPP_02", label = "Suppressor", itemName = "attachment_suppressor" },
},
["scope"] = {
{ name = "COMPONENT_AT_SCOPE_MACRO", label = "Macro Scope", itemName = "attachment_scope_macro" },
{ name = "COMPONENT_AT_SCOPE_MEDIUM", label = "Medium Scope", itemName = "attachment_scope_medium" },
},
["clip"] = {
{ name = "COMPONENT_ASSAULTRIFLE_CLIP_01", label = "Default Clip" },
{ name = "COMPONENT_ASSAULTRIFLE_CLIP_02", label = "Extended Clip", itemName = "attachment_extended_clip" },
},
["grip"] = {
{ name = "COMPONENT_AT_AR_AFGRIP", label = "Grip", itemName = "attachment_grip" },
},
["flashlight"] = {
{ name = "COMPONENT_AT_AR_FLSH", label = "Flashlight", itemName = "attachment_flashlight" },
},
["tint"] = {
{ name = "TINT_NORMAL", label = "Black" },
{ name = "TINT_GREEN", label = "Green", itemName = "tint_green" },
{ name = "TINT_GOLD", label = "Gold", itemName = "tint_gold" },
-- ... more tints
},
}
}| Property | Type | Description |
|---|---|---|
label | string | Weapon display name |
itemName | string | Inventory item name for the weapon |
attachments | table | Categories of available attachments |
name | string | GTA component/tint name |
label | string | Attachment display name |
itemName | string | Optional: inventory item required (if omitted, attachment is free) |
Client Configuration (configs/client.lua)
UI Settings
Config.ClickSoundVolume = 0.3- ClickSoundVolume: Volume level for UI click sounds (0.0 to 1.0)
Blueprint Display
Config.HideLockedHiddenBlueprints = falsetrue= Items requiring hidden blueprints are completely hidden until unlockedfalse= Items are shown but blueprint displays as "???" until unlocked
Feature Toggles
Config.CommunityProjectsEnabled = true- CommunityProjectsEnabled: Enable/disable the Community Projects tab
Client Functions (Hooks)
Config.OpenFunctions = {
["CanOpenCrafting"] = function(stationId)
-- Called before opening crafting menu
-- Return true to allow, false to deny
-- Example: check if player is dead, in vehicle, etc.
return true
end,
["OnCraftingOpened"] = function(stationId)
-- Called when crafting menu opens
end,
["OnCraftingClosed"] = function(stationId)
-- Called when crafting menu closes
end,
["OnCraftStart"] = function(stationId, recipeId, amount)
-- Called when player starts crafting
end,
}| Function | Parameters | Description |
|---|---|---|
CanOpenCrafting | stationId | Validate if player can open crafting (return boolean) |
OnCraftingOpened | stationId | Hook when crafting UI opens |
OnCraftingClosed | stationId | Hook when crafting UI closes |
OnCraftStart | stationId, recipeId, amount | Hook when craft begins |
Server Configuration (configs/server.lua)
Server Functions (Hooks)
Config.ServerFunctions = {
["OnCraftStart"] = function(source, stationId, recipeId, amount)
-- Called when player starts crafting (server-side)
end,
["CanCraft"] = function(source, stationId, recipeId, amount)
-- Custom validation before crafting starts
-- Return true to allow, false to deny
return true
end,
["OnAttachmentsApplied"] = function(source, weaponModel, weaponSlot, attachmentsApplied)
-- Called when player applies attachments to a weapon
-- attachmentsApplied = array of {category, component, label}
end,
["CanUnlockBlueprint"] = function(source, blueprintId)
-- Custom validation before unlocking a blueprint
-- Return true to allow, false to deny
return true
end,
["OnBlueprintUnlocked"] = function(source, blueprintId)
-- Called when player successfully unlocks a blueprint
end,
["OnCraftCompleted"] = function(source, stationId, recipeId, amount, resultItem, resultAmount)
-- Called when a craft finishes (timer reaches 0), before the player claims it
-- resultItem = item name, resultAmount = total amount to be given
end,
["CanClaimItem"] = function(source, stationId, recipeId, amount, resultItem, resultAmount)
-- Custom validation before claiming a finished craft
-- Return true to allow, false to deny
return true
end,
["OnItemClaimed"] = function(source, stationId, recipeId, amount, resultItem, resultAmount)
-- Called after the player successfully claims a crafted item
end,
}| Function | Parameters | Description |
|---|---|---|
OnCraftStart | source, stationId, recipeId, amount | Server-side hook when crafting starts |
CanCraft | source, stationId, recipeId, amount | Validate craft permission (return boolean) |
OnAttachmentsApplied | source, weaponModel, weaponSlot, attachmentsApplied | Hook when attachments are saved |
CanUnlockBlueprint | source, blueprintId | Validate blueprint unlock (return boolean) |
OnBlueprintUnlocked | source, blueprintId | Hook when blueprint is unlocked |
OnCraftCompleted | source, stationId, recipeId, amount, resultItem, resultAmount | Hook when craft timer finishes (before claim) |
CanClaimItem | source, stationId, recipeId, amount, resultItem, resultAmount | Validate claim permission (return boolean) |
OnItemClaimed | source, stationId, recipeId, amount, resultItem, resultAmount | Hook when player claims crafted item |
Community Project Completion Event
AddEventHandler("devhub_crafting:server:communityProjectCompleted", function(projectId, projectData)
-- Triggered when a community project reaches 100%
-- Use this to give rewards, send announcements, etc.
-- Example: Give reward to all online players
local players = GetPlayers()
for _, playerId in ipairs(players) do
-- exports['your_core']:GiveItem(playerId, 'reward_item', 10)
end
-- Example: Server-wide announcement
TriggerClientEvent('chat:addMessage', -1, {
color = {0, 255, 0},
args = {"Community", "Project '" .. projectData.label .. "' completed!"}
})
end)Skill Tree Configuration (configs/skillTree.lua)
Enable Skill Tree
The skill tree integration requires devhub_skillTree resource. Enable in shared.lua:
Shared.SkillTreeEnabled = true -- Add this to shared.luaSkill Category
Shared.SkillsCategory = {
skill = 'crafting',
title = 'Crafting'
}- skill: Internal identifier for the skill category
- title: Display name in skill tree UI
Skills List
Shared.SkillsList = {
["crafting"] = {
{
uid = "skill_7",
index = 7,
title = "Fast Crafting",
icon = "fas fa-bolt",
img = "https://upload.devhub.gg/dh_upload/crafting/crafting.png",
description = "Reduces crafting time by 5%.",
points = 1,
effect = 5,
lines = { rightBottom = false },
},
{
uid = "skill_28",
index = 28,
title = "Double Craft",
icon = "fas fa-clone",
img = "https://upload.devhub.gg/dh_upload/crafting/crafting.png",
description = "5% chance to receive double crafted items.",
points = 1,
effect = 5,
lines = { bottom = false, rightTop = false, top = false, left = false },
},
-- ... more skills
}
}| Property | Type | Description |
|---|---|---|
uid | string | Unique skill identifier |
index | number | Grid position in skill tree |
title | string | Skill display name |
icon | string | FontAwesome icon class |
img | string | Skill icon image URL |
description | string | Skill description text |
points | number | Skill points required to unlock |
effect | number | Effect value (e.g., percentage) |
lines | table | Connection lines to adjacent skills |
unLockable | boolean | If true, skill cannot be unlocked (decorative node) |
Available Skill Types
- Fast Crafting: Reduces crafting time by X%
- Double Craft: X% chance to receive double items
- Experience Boost: Gain X% more XP
- Rare Drop Chance: Increases rare item drop by X%
- Material Preservation: X% chance to not consume materials
- Blueprint Access: Unlocks specific weapon blueprints
Rarity Colors Reference
-- Used throughout the script for visual styling
local rarities = {
["common"] = "#C0C0C0", -- Silver
["uncommon"] = "#00FF00", -- Green
["rare"] = "#00D4FF", -- Cyan
["epic"] = "#8A5BFF", -- Purple
["legendary"] = "#FFA500" -- Orange
}Configuration Best Practices
- Backup configs: Always backup configuration files before making changes
- Unique IDs: Ensure all
uid,id, and key names are unique across configs - Test incrementally: Change one setting at a time and test thoroughly
- Balance crafting times: Set appropriate times based on item value/rarity
- Blueprint progression: Design blueprint unlock paths that encourage gameplay
- Queue sizes: Balance queue slots with server economy (VIP perks, etc.)
- Attachment items: Decide which attachments require items vs. free (default clips)
- Community projects: Set realistic material goals based on player population
- Image URLs: Use reliable image hosting