Installation Guide

Complete setup guide for oxide-weed including database, item registration, and framework configuration.

Prerequisites

Required Resources

ResourceMinimum VersionPurpose
ox_libv3.0.0+Utility library, locale, callbacks
oxmysqllatestMySQL database operations
community_bridgelatestFramework 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

FrameworkSupport
QBCoreFull
ESXFull
QBX (qbx_core)Full
CustomVia 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_bridge and oxide-weed.

Step 3: Import Database

Import the SQL file into your MySQL database:

sql/install.sql

This creates the following tables:

TablePurpose
drugs_progressionPlayer level and XP tracking (shared across drug resources)
drug_equipmentPlaced equipment (tables, containers, freeze dryers, totes)
drug_plantsActive planted cannabis with growth state and genetics
drug_lampsGrow lamps linked to plants
drug_heatersHeaters linked to drying racks
drug_drying_slotsIndividual bud slots on drying racks and freeze dryers
drug_strainsStrain 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 has water_bottle (different item). You must add water.
  • oxide-weed uses rolling_papers (plural) — stock QBCore has rolling_paper (singular, different item). You must add rolling_papers.
  • oxide-weed uses fertilizer — stock QBCore has weed_nutrition (different item). You must add fertilizer.
  • oxide-weed uses baggy — stock QBCore has cokebaggy, crack_baggy, etc. but no plain baggy. You must add baggy.
  • lighter exists in stock QBCore and can be reused as-is.
  • joint exists in stock QBCore but you should update its weight to 20 and description to 'A rolled joint'.

Item images: Copy all .png files from oxide-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 NameLabelDescription
cannabis_seedCannabis SeedPlantable seed with strain genetics metadata
plant_potPlant PotRequired to plant seeds, returned on harvest
waterWaterBasic water source for plants and containers
fertilizerFertilizerNutrient supply for plants
grow_lampGrow LampPlaceable lamp that accelerates plant growth
weed_tableWeed TablePlaceable table for drying, bagging, packaging, and crossbreeding
weed_heaterHeaterPlaceable heater that speeds up drying
trimming_scissorsTrimming ScissorsUsed to prune dried buds
baggyBaggyEmpty bag for packaging pruned buds
watering_canWatering CanRefillable can for efficient watering (metadata-based)
water_container_smallSmall Water ContainerPlaceable 500-unit water tank
water_container_largeLarge Water ContainerPlaceable 1000-unit water tank
storage_toteStorage TotePlaceable storage container with stash inventory
freeze_dryerFreeze DryerIndustrial drying unit (requires level 7)
growing_manualGrowing ManualOpens an in-game NUI guide
rolling_papersRolling PapersUsed to roll joints
cigarillo_wrapsCigarillo WrapsUsed to roll blunts
lighterLighterRequired for rolling joints and blunts
weed_budWeed BudFresh harvested bud (metadata carries strain/quality)
dried_weed_budDried Weed BudBud after drying on rack
pruned_weed_budPruned Weed BudBud after trimming with scissors
cannabis_leafCannabis LeafByproduct from trimming
pollenPollenCollected from male plants for crossbreeding
weed_1gWeed (1g)Bagged gram of weed
weed_eighthWeed (1/8 oz)Packaged eighth
weed_quarterWeed (1/4 oz)Packaged quarter
weed_halfWeed (1/2 oz)Packaged half ounce
weed_ounceWeed (1 oz)Packaged ounce
jointJointRolled joint, smokable
bluntBluntRolled 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 joint and blunt items do not need to be unique = true. Most inventories handle stacking items with metadata. Setting unique = true would 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 has rolling_paper (singular) — this is a different item. oxide-weed uses rolling_papers (plural). Add it as a new entry.

Note on water: Stock QBCore has water_bottle — this is a different item. oxide-weed uses water as a growing supply. You must add the water entry 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 joint handler. 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.

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_seedstrain_id, strain_name, generation, traits, lineage
  • pollenstrain_id, strain_name, generation, traits
  • weed_bud, dried_weed_bud, pruned_weed_budstrain_id, strain_name, quality, quality_score, generation
  • weed_1g through weed_ounce — Same metadata as buds
  • watering_canwater_level metadata for fill state
  • joint, bluntstrain_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

  1. 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)

  2. Use /weed_kit in-game (requires admin permission) to receive a full set of growing supplies

  3. Use a cannabis seed from your inventory to begin the planting process

  4. 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