Installation Guide
Complete setup guide for oxide-weed including database, item registration, and framework configuration.
Prerequisites
Required Resources
| Resource | Minimum Version | Purpose |
|---|---|---|
| ox_lib | v3.0.0+ | Utility library, locale, callbacks |
| oxmysql | latest | MySQL database operations |
| community_bridge | latest | Framework abstraction layer |
Community Bridge is available for download in our Discord server. Make sure you have the latest version installed before proceeding.
Community Bridge automatically detects and bridges your framework (QBCore, ESX, QBX, etc.), target system, inventory system, phone system, and notification system. No manual configuration is needed for these.
Supported Frameworks
| Framework | Support |
|---|---|
| QBCore | Full |
| ESX | Full |
| QBX (qbx_core) | Full |
| Custom | Via community_bridge |
Installation Steps
Step 1: Download the Resource
Extract oxide-weed to your resources directory:
resources/
└── [oxide]/
└── oxide-weed/
Step 2: Add to Server Config
Add to your server.cfg — dependency order matters:
QBCore:
ensure ox_lib
ensure oxmysql
ensure qb-core
ensure qb-inventory # or your inventory resource
ensure community_bridge
ensure oxide-weed
ESX:
ensure ox_lib
ensure oxmysql
ensure es_extended
ensure ox_inventory # or your inventory resource
ensure community_bridge
ensure oxide-weed
QBX:
ensure ox_lib
ensure oxmysql
ensure qbx_core
ensure ox_inventory # or your inventory resource
ensure community_bridge
ensure oxide-weed
Your framework core and inventory resource must load before
community_bridgeandoxide-weed.
Step 3: Import Database
Import the SQL file into your MySQL database:
sql/install.sql
This creates the following tables:
| Table | Purpose |
|---|---|
drugs_progression | Player level and XP tracking (shared across drug resources) |
drug_equipment | Placed equipment (tables, containers, freeze dryers, totes) |
drug_plants | Active planted cannabis with growth state and genetics |
drug_lamps | Grow lamps linked to plants |
drug_heaters | Heaters linked to drying racks |
drug_drying_slots | Individual bud slots on drying racks and freeze dryers |
drug_strains | Strain registry mapping trait hashes to names and metadata |
The drugs_progression table uses a shared schema. If you run other Oxide drug resources (future meth, coke, etc.), they share this table with different drug column values.
Step 4: Register Items
You must register all items in your framework's item database. See the framework-specific sections below.
Step 5: Configure Settings
Review and customize shared/config.lua and shared/config/*.lua. See Configuration for all options.
Item Registration
Important Notes
Existing items: Some items below (e.g.,
lighter) may already exist in your server. If an item with the exact same name is already registered, you do not need to add it again. However, be aware of these common mismatches on stock QBCore/ESX servers:
- oxide-weed uses
water— stock QBCore haswater_bottle(different item). You must addwater.- oxide-weed uses
rolling_papers(plural) — stock QBCore hasrolling_paper(singular, different item). You must addrolling_papers.- oxide-weed uses
fertilizer— stock QBCore hasweed_nutrition(different item). You must addfertilizer.- oxide-weed uses
baggy— stock QBCore hascokebaggy,crack_baggy, etc. but no plainbaggy. You must addbaggy.lighterexists in stock QBCore and can be reused as-is.jointexists in stock QBCore but you should update itsweightto20anddescriptionto'A rolled joint'.
Item images: Copy all
.pngfiles fromoxide-weed/item images/to your inventory's image directory:
- QBCore (qb-inventory):
qb-inventory/html/images/- ESX (ox_inventory):
ox_inventory/web/images/
Required Items
| Item Name | Label | Description |
|---|---|---|
cannabis_seed | Cannabis Seed | Plantable seed with strain genetics metadata |
plant_pot | Plant Pot | Required to plant seeds, returned on harvest |
water | Water | Basic water source for plants and containers |
fertilizer | Fertilizer | Nutrient supply for plants |
grow_lamp | Grow Lamp | Placeable lamp that accelerates plant growth |
weed_table | Weed Table | Placeable table for drying, bagging, packaging, and crossbreeding |
weed_heater | Heater | Placeable heater that speeds up drying |
trimming_scissors | Trimming Scissors | Used to prune dried buds |
baggy | Baggy | Empty bag for packaging pruned buds |
watering_can | Watering Can | Refillable can for efficient watering (metadata-based) |
water_container_small | Small Water Container | Placeable 500-unit water tank |
water_container_large | Large Water Container | Placeable 1000-unit water tank |
storage_tote | Storage Tote | Placeable storage container with stash inventory |
freeze_dryer | Freeze Dryer | Industrial drying unit (requires level 7) |
growing_manual | Growing Manual | Opens an in-game NUI guide |
rolling_papers | Rolling Papers | Used to roll joints |
cigarillo_wraps | Cigarillo Wraps | Used to roll blunts |
lighter | Lighter | Required for rolling joints and blunts |
weed_bud | Weed Bud | Fresh harvested bud (metadata carries strain/quality) |
dried_weed_bud | Dried Weed Bud | Bud after drying on rack |
pruned_weed_bud | Pruned Weed Bud | Bud after trimming with scissors |
cannabis_leaf | Cannabis Leaf | Byproduct from trimming |
pollen | Pollen | Collected from male plants for crossbreeding |
weed_1g | Weed (1g) | Bagged gram of weed |
weed_eighth | Weed (1/8 oz) | Packaged eighth |
weed_quarter | Weed (1/4 oz) | Packaged quarter |
weed_half | Weed (1/2 oz) | Packaged half ounce |
weed_ounce | Weed (1 oz) | Packaged ounce |
joint | Joint | Rolled joint, smokable |
blunt | Blunt | Rolled blunt, smokable |
QBCore Item Registration
Step 1: Copy item images
Copy all .png files from oxide-weed/item images/ to qb-inventory/html/images/.
Step 2: Update existing joint item
Find the existing joint entry in qb-core/shared/items.lua (in the Drugs section) and update it:
joint = {
name = 'joint', label = 'Joint',
weight = 20, type = 'item',
image = 'joint.png',
unique = false, useable = true,
shouldClose = true,
description = 'A rolled joint',
},
Note on unique: The
jointandbluntitems do not need to beunique = true. Most inventories handle stacking items with metadata. Settingunique = truewould prevent joints from stacking.
Step 3: Add new items
Add these to qb-core/shared/items.lua. The existing lighter can be reused — do not add a duplicate.
Note on
rolling_papers: Stock QBCore hasrolling_paper(singular) — this is a different item. oxide-weed usesrolling_papers(plural). Add it as a new entry.
Note on
water: Stock QBCore haswater_bottle— this is a different item. oxide-weed useswateras a growing supply. You must add thewaterentry below.
-- oxide-weed Items
-- Growing supplies
cannabis_seed = {
name = 'cannabis_seed', label = 'Cannabis Seed',
weight = 10, type = 'item', image = 'cannabis_seed.png',
unique = false, useable = true, shouldClose = true,
description = 'A cannabis seed with genetic potential',
},
plant_pot = {
name = 'plant_pot', label = 'Plant Pot',
weight = 500, type = 'item', image = 'plant_pot.png',
unique = false, useable = false, shouldClose = true,
description = 'A pot for growing plants',
},
water = {
name = 'water', label = 'Water',
weight = 100, type = 'item', image = 'water_bottle.png',
unique = false, useable = false, shouldClose = true,
description = 'Clean water',
},
fertilizer = {
name = 'fertilizer', label = 'Fertilizer',
weight = 200, type = 'item', image = 'fertilizer.png',
unique = false, useable = false, shouldClose = true,
description = 'Plant nutrients',
},
-- Equipment
grow_lamp = {
name = 'grow_lamp', label = 'Grow Lamp',
weight = 1000, type = 'item', image = 'grow_lamp.png',
unique = false, useable = true, shouldClose = true,
description = 'Accelerates plant growth',
},
weed_table = {
name = 'weed_table', label = 'Weed Table',
weight = 2000, type = 'item', image = 'weed_table.png',
unique = false, useable = true, shouldClose = true,
description = 'Processing table for drying and packaging',
},
weed_heater = {
name = 'weed_heater', label = 'Heater',
weight = 1500, type = 'item', image = 'weed_heater.png',
unique = false, useable = true, shouldClose = true,
description = 'Speeds up bud drying',
},
watering_can = {
name = 'watering_can', label = 'Watering Can',
weight = 300, type = 'item', image = 'watering_can.png',
unique = true, useable = true, shouldClose = true,
description = 'Refillable watering can',
},
water_container_small = {
name = 'water_container_small',
label = 'Small Water Container',
weight = 1000, type = 'item',
image = 'water_container_small.png',
unique = false, useable = true, shouldClose = true,
description = 'Small water storage tank',
},
water_container_large = {
name = 'water_container_large',
label = 'Large Water Container',
weight = 2000, type = 'item',
image = 'water_container_large.png',
unique = false, useable = true, shouldClose = true,
description = 'Large water storage tank',
},
storage_tote = {
name = 'storage_tote', label = 'Storage Tote',
weight = 1000, type = 'item', image = 'storage_tote.png',
unique = false, useable = true, shouldClose = true,
description = 'Portable storage container',
},
freeze_dryer = {
name = 'freeze_dryer', label = 'Freeze Dryer',
weight = 5000, type = 'item', image = 'freeze_dryer.png',
unique = false, useable = true, shouldClose = true,
description = 'Industrial freeze drying unit',
},
-- Processing supplies
trimming_scissors = {
name = 'trimming_scissors', label = 'Trimming Scissors',
weight = 100, type = 'item',
image = 'trimming_scissors.png',
unique = false, useable = true, shouldClose = true,
description = 'For trimming dried buds',
},
baggy = {
name = 'baggy', label = 'Baggy',
weight = 10, type = 'item', image = 'baggy.png',
unique = false, useable = false, shouldClose = true,
description = 'Empty plastic bag',
},
growing_manual = {
name = 'growing_manual', label = 'Growing Manual',
weight = 50, type = 'item', image = 'growing_manual.png',
unique = false, useable = true, shouldClose = true,
description = 'A guide to cannabis cultivation',
},
rolling_papers = {
name = 'rolling_papers', label = 'Rolling Papers',
weight = 10, type = 'item', image = 'rolling_papers.png',
unique = false, useable = true, shouldClose = true,
description = 'For rolling joints',
},
cigarillo_wraps = {
name = 'cigarillo_wraps', label = 'Cigarillo Wraps',
weight = 10, type = 'item', image = 'cigarillo_wraps.png',
unique = false, useable = true, shouldClose = true,
description = 'For rolling blunts',
},
-- Product items
weed_bud = {
name = 'weed_bud', label = 'Weed Bud',
weight = 50, type = 'item', image = 'weed_bud.png',
unique = false, useable = false, shouldClose = true,
description = 'Fresh cannabis bud',
},
dried_weed_bud = {
name = 'dried_weed_bud', label = 'Dried Weed Bud',
weight = 40, type = 'item', image = 'dried_weed_bud.png',
unique = false, useable = false, shouldClose = true,
description = 'Dried cannabis bud',
},
pruned_weed_bud = {
name = 'pruned_weed_bud', label = 'Pruned Weed Bud',
weight = 30, type = 'item', image = 'pruned_weed_bud.png',
unique = false, useable = false, shouldClose = true,
description = 'Trimmed cannabis bud',
},
cannabis_leaf = {
name = 'cannabis_leaf', label = 'Cannabis Leaf',
weight = 10, type = 'item', image = 'cannabis_leaf.png',
unique = false, useable = false, shouldClose = true,
description = 'Trimming byproduct',
},
pollen = {
name = 'pollen', label = 'Pollen',
weight = 10, type = 'item', image = 'pollen.png',
unique = false, useable = false, shouldClose = true,
description = 'Cannabis pollen for crossbreeding',
},
-- Packaged weed
weed_1g = {
name = 'weed_1g', label = 'Weed (1g)',
weight = 20, type = 'item', image = 'weed_1g.png',
unique = false, useable = false, shouldClose = true,
description = 'Bagged gram of weed',
},
weed_eighth = {
name = 'weed_eighth', label = 'Weed (1/8 oz)',
weight = 60, type = 'item', image = 'weed_eighth.png',
unique = false, useable = false, shouldClose = true,
description = 'Packaged eighth of weed',
},
weed_quarter = {
name = 'weed_quarter', label = 'Weed (1/4 oz)',
weight = 120, type = 'item', image = 'weed_quarter.png',
unique = false, useable = false, shouldClose = true,
description = 'Packaged quarter of weed',
},
weed_half = {
name = 'weed_half', label = 'Weed (1/2 oz)',
weight = 240, type = 'item', image = 'weed_half.png',
unique = false, useable = false, shouldClose = true,
description = 'Packaged half ounce of weed',
},
weed_ounce = {
name = 'weed_ounce', label = 'Weed (1 oz)',
weight = 480, type = 'item', image = 'weed_ounce.png',
unique = false, useable = false, shouldClose = true,
description = 'Packaged ounce of weed',
},
-- Smokables
blunt = {
name = 'blunt', label = 'Blunt',
weight = 25, type = 'item', image = 'blunt.png',
unique = false, useable = true, shouldClose = true,
description = 'A rolled blunt',
},
Step 4: Remove old joint handler from qb-smallresources
oxide-weed registers its own joint/blunt useable item handlers with trait-based effects. The default QBCore joint handler in qb-smallresources will conflict.
In qb-smallresources/server/consumables.lua, find and comment out or remove the joint handler:
-- Removed for oxide-weed
-- QBCore.Functions.CreateUseableItem('joint', function(source, item)
-- ...
-- end)
In qb-smallresources/client/consumables.lua, find and comment out or remove the UseJoint event handler:
-- Removed for oxide-weed
-- RegisterNetEvent('consumables:client:UseJoint', function()
-- ...
-- end)
Important: Only remove the
jointhandler. Leave all other drug consumable handlers untouched.
Step 5: qb-drugs overlap (optional)
oxide-weed includes its own NPC street selling system. If you also run qb-drugs, its weed corner-selling entries use different item names so the two systems can coexist. If you want to consolidate weed selling to oxide-weed only, remove the weed entries from qb-drugs/config.lua.
Step 6: Fix metadata display in qb-inventory (optional)
qb-inventory displays all metadata fields in item tooltips by default. This means internal fields like strain_id, quality_score, effects, and traits will show as raw data. oxide-weed includes a display table in its metadata that defines which fields should be shown to the player.
Edit qb-inventory/html/app.js and find the generateTooltipContent method. Replace the metadata rendering block:
if (
item.info &&
Object.keys(item.info).length > 0 &&
item.info.display !== false
) {
if (
item.info.display &&
typeof item.info.display === "object"
) {
for (const [key, value] of
Object.entries(item.info.display)
) {
content += '<div class="tooltip-info">'
+ '<span class="tooltip-info-key">'
+ this.formatKey(key) + ':</span> '
+ value + '</div>';
}
} else {
for (const [key, value] of
Object.entries(item.info)
) {
if (key !== "description" && key !== "display") {
let valueStr = value;
if (key === "attachments") {
valueStr = Object.keys(value).length > 0
? "true" : "false";
}
content += '<div class="tooltip-info">'
+ '<span class="tooltip-info-key">'
+ this.formatKey(key) + ':</span> '
+ valueStr + '</div>';
}
}
}
}
This change is backwards-compatible — items without a display table will continue to show all metadata as before.
Note: This is only needed for qb-inventory. ox_inventory handles metadata display differently.
Step 7: Fix metadata-based stacking in qb-inventory (recommended)
qb-inventory stacks items by name only — it does not compare metadata when deciding whether to combine items. This means different strains with the same item name will merge into one slot, losing metadata.
oxide-weed relies on metadata-aware stacking: items with the same name but different metadata should occupy separate slots.
Edit qb-inventory/server/functions.lua:
1. Add helper functions after the existing GetFirstSlotByItem function:
local function MetadataMatch(a, b)
a = a or {}
b = b or {}
if a == b then return true end
for k, v in pairs(a) do
if b[k] ~= v then return false end
end
for k in pairs(b) do
if a[k] == nil then return false end
end
return true
end
function GetFirstSlotByItemAndMeta(items, itemName, info)
if not items then return end
local lowerName = itemName:lower()
local hasInfo = info and next(info) ~= nil
for slot, item in pairs(items) do
if item.name:lower() == lowerName then
if not hasInfo then
return tonumber(slot)
end
if MetadataMatch(info, item.info) then
return tonumber(slot)
end
end
end
return nil
end
2. Update the AddItem function — find this block:
if not itemInfo.unique then
slot = slot or GetFirstSlotByItem(inventory, item)
Replace with:
if not itemInfo.unique then
slot = slot or GetFirstSlotByItemAndMeta(inventory, item, info)
Note: This is only needed for qb-inventory. ox_inventory already compares metadata when stacking.
ESX Item Registration (ox_inventory)
Add these to your ox_inventory/data/items.lua. Skip any items that already exist (e.g., water, lighter).
['cannabis_seed'] = {
label = 'Cannabis Seed',
weight = 10,
stack = true,
close = true,
description = 'A cannabis seed with genetic potential',
},
['plant_pot'] = {
label = 'Plant Pot',
weight = 500,
stack = true,
close = true,
description = 'A pot for growing plants',
},
['fertilizer'] = {
label = 'Fertilizer',
weight = 200,
stack = true,
close = true,
description = 'Plant nutrients',
},
['grow_lamp'] = {
label = 'Grow Lamp',
weight = 1000,
stack = true,
close = true,
description = 'Accelerates plant growth',
},
['weed_table'] = {
label = 'Weed Table',
weight = 2000,
stack = true,
close = true,
description = 'Processing table for drying and packaging',
},
['weed_heater'] = {
label = 'Heater',
weight = 1500,
stack = true,
close = true,
description = 'Speeds up bud drying',
},
['trimming_scissors'] = {
label = 'Trimming Scissors',
weight = 100,
stack = true,
close = true,
description = 'For trimming dried buds',
},
['baggy'] = {
label = 'Baggy',
weight = 10,
stack = true,
close = true,
description = 'Empty plastic bag',
},
['watering_can'] = {
label = 'Watering Can',
weight = 300,
stack = false,
close = true,
description = 'Refillable watering can',
},
['water_container_small'] = {
label = 'Small Water Container',
weight = 1000,
stack = true,
close = true,
description = 'Small water storage tank',
},
['water_container_large'] = {
label = 'Large Water Container',
weight = 2000,
stack = true,
close = true,
description = 'Large water storage tank',
},
['storage_tote'] = {
label = 'Storage Tote',
weight = 1000,
stack = true,
close = true,
description = 'Portable storage container',
},
['freeze_dryer'] = {
label = 'Freeze Dryer',
weight = 5000,
stack = true,
close = true,
description = 'Industrial freeze drying unit',
},
['growing_manual'] = {
label = 'Growing Manual',
weight = 50,
stack = true,
close = true,
description = 'A guide to cannabis cultivation',
},
['rolling_papers'] = {
label = 'Rolling Papers',
weight = 10,
stack = true,
close = true,
description = 'For rolling joints',
},
['cigarillo_wraps'] = {
label = 'Cigarillo Wraps',
weight = 10,
stack = true,
close = true,
description = 'For rolling blunts',
},
['lighter'] = {
label = 'Lighter',
weight = 50,
stack = true,
close = true,
description = 'A disposable lighter',
},
['weed_bud'] = {
label = 'Weed Bud',
weight = 50,
stack = true,
close = true,
description = 'Fresh cannabis bud',
},
['dried_weed_bud'] = {
label = 'Dried Weed Bud',
weight = 40,
stack = true,
close = true,
description = 'Dried cannabis bud',
},
['pruned_weed_bud'] = {
label = 'Pruned Weed Bud',
weight = 30,
stack = true,
close = true,
description = 'Trimmed cannabis bud',
},
['cannabis_leaf'] = {
label = 'Cannabis Leaf',
weight = 10,
stack = true,
close = true,
description = 'Trimming byproduct',
},
['pollen'] = {
label = 'Pollen',
weight = 10,
stack = true,
close = true,
description = 'Cannabis pollen for crossbreeding',
},
['weed_1g'] = {
label = 'Weed (1g)',
weight = 20,
stack = true,
close = true,
description = 'Bagged gram of weed',
},
['weed_eighth'] = {
label = 'Weed (1/8 oz)',
weight = 60,
stack = true,
close = true,
description = 'Packaged eighth of weed',
},
['weed_quarter'] = {
label = 'Weed (1/4 oz)',
weight = 120,
stack = true,
close = true,
description = 'Packaged quarter of weed',
},
['weed_half'] = {
label = 'Weed (1/2 oz)',
weight = 240,
stack = true,
close = true,
description = 'Packaged half ounce of weed',
},
['weed_ounce'] = {
label = 'Weed (1 oz)',
weight = 480,
stack = true,
close = true,
description = 'Packaged ounce of weed',
},
['joint'] = {
label = 'Joint',
weight = 20,
stack = true,
close = true,
description = 'A rolled joint',
},
['blunt'] = {
label = 'Blunt',
weight = 25,
stack = true,
close = true,
description = 'A rolled blunt',
},
Item Metadata Notes
Several items carry metadata that must be preserved through inventory operations:
- cannabis_seed —
strain_id,strain_name,generation,traits,lineage - pollen —
strain_id,strain_name,generation,traits - weed_bud, dried_weed_bud, pruned_weed_bud —
strain_id,strain_name,quality,quality_score,generation - weed_1g through weed_ounce — Same metadata as buds
- watering_can —
water_levelmetadata for fill state - joint, blunt —
strain_name,quality,quality_score,effects
The only item that should be unique = true is watering_can, which tracks a per-item water_level fill state. All other metadata items should be unique = false and rely on metadata-aware stacking.
Framework Setup
oxide-weed uses community_bridge for all framework interactions. No framework-specific configuration is needed beyond registering items. The bridge handles:
- Usable item registration
- Inventory add/remove/check operations
- Cash balance management (for store and scientist)
- Job checking (for police count in selling)
- Notification delivery
Verification
-
Start your server and check the console for:
[oxide-weed] Strain registry loaded [oxide-weed] Equipment loaded [oxide-weed] Plants loaded [oxide-weed] oxide-weed initialized(Debug messages only appear when
Config.Debug = true) -
Use
/weed_kitin-game (requires admin permission) to receive a full set of growing supplies -
Use a cannabis seed from your inventory to begin the planting process
-
Visit The Germinator store (default location near the docks) to verify the shop NUI opens
Next Steps
- Features — Understand every gameplay mechanic in detail
- Configuration — Customize all settings for your server
- Admin — Learn the admin commands for testing and management