API Reference

Server exports provided by oxide-weed for integrations.

Server exports provided by oxide-weed, for integrating other resources (selling scripts, MDTs, leaderboards, etc.).

Call them with standard FiveM exports from any server script, as long as oxide-weed is started first:

local level = exports['oxide-weed']:GetPlayerLevel(source)

Progression

GetPlayerLevel(source)

Returns the player's weed level (1–10). Returns 1 if the player has no progression row yet.

local level = exports['oxide-weed']:GetPlayerLevel(source)

GetPlayerRank(source)

Returns the player's master rank past the last level, and its title. The rank is 0 (and the title nil) before the first rank, while master ranks are turned off, or when the player has no character loaded.

local rank, title = exports['oxide-weed']:GetPlayerRank(source)
if rank > 0 then
    print(('%s is %s'):format(GetPlayerName(source), title))   -- e.g. "Master Grower II"
end

GetPlayerProgression(source)

Returns the player's full progression stats, or nil if the player has no valid character loaded.

local progression = exports['oxide-weed']:GetPlayerProgression(source)

Return shape:

{
    level = 1,
    xp = 0,
    currentLevelXp = 0,    -- XP threshold of the current level
    nextLevelXp = 100,     -- XP threshold of the next level (nil at max level)
    totalCreated = 0,
    totalSold = 0,
    unlocks = {            -- what each level opens, as shown on the Grower Profile
        { level = 3, label = 'Crossbreeding', unlocked = false },
        { level = 6, label = 'Green Thumb: your plants lose water and fertilizer 10% slower', kind = 'perk', unlocked = false },
        { level = 7, label = 'Strain: Gelato', kind = 'strain', name = 'Gelato', grade = 'gas', unlocked = false },
        -- ...
    },
    journal = { bestQuality = 0, bestGeneration = 0, harvests = 0 },
    pots = { count = 3, limit = 6 },   -- only while the loose-pot cap is on
}

label is already in the server's language. kind is 'perk', 'strain' or 'pots' for those rows and absent for the rest.

AddXP(source, amount)

Adds weed XP the same way weed's own actions do: the level-up check runs, the player sees the "+XP" pop-up, a level-up shows its banner and fires oxide-weed:server:levelUp, and a new master rank fires oxide-weed:server:rankUp. While Skills mirror is set, the XP is also added to that skill. Whole numbers only; a fraction is rounded. Returns true when XP was added, false if the player is invalid or the amount rounds to nothing. XP added this way doesn't count toward goals.

local ok = exports['oxide-weed']:AddXP(source, 25)

AddSold(source, amount)

Adds to the player's lifetime sold count. Returns true on success, false if the player is invalid or the amount is not a positive number. (oxide-drugselling calls this automatically.)

local ok = exports['oxide-weed']:AddSold(source, 3)

Events

oxide-weed:server:levelUp

A server event fired when a player's weed level goes up, from any XP or an admin command. Listen with AddEventHandler in a server script:

AddEventHandler('oxide-weed:server:levelUp', function(source, level, previousLevel)
    print(('player %d reached weed level %d (was %d)'):format(source, level, previousLevel))
end)

It is not fired when a level goes down (/weed setxp can lower one).

oxide-weed:server:rankUp

A server event fired when a player reaches a new master rank, from any XP or an admin command. It fires only for a player who is online, and whether or not the rank-up message is turned on.

AddEventHandler('oxide-weed:server:rankUp', function(source, rank, previousRank)
    local _, title = exports['oxide-weed']:GetPlayerRank(source)
    print(('player %d reached master rank %d, %s (was %d)'):format(source, rank, title, previousRank))
end)

If one grant crosses several ranks, it fires once, with the highest. It is not fired when a rank goes down.

oxide-weed:server:tentSeized

A server event fired after police seize a grow tent, for records, MDTs or other resources. The tent and its plants are already gone when it fires.

AddEventHandler('oxide-weed:server:tentSeized', function(data)
    print(('officer %s seized tent %s (%s) owned by %s, with %d plants'):format(
        tostring(data.officer.source), tostring(data.tentId), data.tier, tostring(data.ownerCharId), #data.plants))
    for _, plant in ipairs(data.plants) do
        print(('  %s, quality %s'):format(tostring(plant.name), tostring(plant.quality)))
    end
end)

data fields:

FieldTypeDescription
tentIdnumberThe tent's id
tierstringThe tent size: 'grow_box', 'grow_tent' or 'grow_tent_large' (or your own size's key)
ownerCharIdstringThe character identifier of the player who placed it
coordsvector3Where the tent stood
bucketnumberIts routing bucket
plantstableOne row per plant that was in it: { plantId, strainId, name, quality }. strainId is the strain hash, name the strain name the plant showed, quality its 0–100 score
officertable{ source, charId } of the officer who seized it

Sales from oxide-drugselling

While oxide-drugselling runs, oxide-weed listens to its server event oxide-drugselling:drugSold. Each weed sale adds its units to that strain's sold count in the seller's Grower Profile (strain mastery) and counts toward the seller's sale goals. For a signature strain, it also builds the strain's reputation by the sale's xpUnits (the grams sold), or by its item count when the event doesn't carry xpUnits. The strain comes from the sale's metaKey, which starts with the strain id, and the grade from the part after it. Only the event raised by oxide-drugselling itself is counted, so another script can't add sales by raising it. The sale's XP is still paid by oxide-drugselling through AddXP; a finished goal adds its own XP.

Plants

GetPlantCount(source)

Returns how many active plants the player owns.

local count = exports['oxide-weed']:GetPlantCount(source)

GetAllPlants()

Returns every active plant on the server, keyed by plant id.

local plants = exports['oxide-weed']:GetAllPlants()

Each entry:

{
    type = 'cannabis_seed',
    strain = 'og_kush',
    strain_name = 'OG Kush',
    coords = vector3(0.0, 0.0, 0.0),
    water = 50,
    fertilizer = 50,
    lastStage = 1,
    quality = 50,
    gender = 'female',
    generation = 1,
    placedBy = 'char:123',   -- character identifier
    bucket = 0,              -- routing bucket
}

GetPlantData(plantId)

Returns detailed live data for one plant, or nil if the id is invalid or the plant no longer exists.

local plant = exports['oxide-weed']:GetPlantData(plantId)

Return shape:

{
    type = 'cannabis_seed',
    strain = 'og_kush',
    strain_name = 'OG Kush',
    coords = vector3(0.0, 0.0, 0.0),
    water = 50,
    fertilizer = 50,
    currentStage = 2,        -- computed live, including lamp/trait speed-ups
    totalStages = 4,
    quality = 62,
    gender = 'female',
    generation = 1,
    traits = {},             -- the 10 genetics traits
    placedBy = 'char:123',
    bucket = 0,
}

Genetics

GetStrainData(strainHash)

Looks up a strain in the genetics registry by its hash (found on item metadata as strain_id). Returns nil for unknown hashes.

local strain = exports['oxide-weed']:GetStrainData(strainHash)

Return shape:

{
    strain_name = 'OG Kush',
    traits = { potency = 35, thc = 25, --[[ ... ]] },
    base_quality = 65,
    required_level = 2,
    registered_by = nil,   -- the character identifier that registered it as a signature strain, or nil
    reputation = 0,        -- a signature strain's reputation, 0 to SignatureStrains.reputation.max; may have decimals
    name_key = nil,        -- a signature strain's name in lower case, as names are compared; nil otherwise
}

oxide-drugselling uses this for trait-based price bonuses; it's also the hook for custom pricing, effects, or sale logic. For a signature strain, strain_name is its registered name.

PriceFor(metadata)

The price multiplier oxide-drugselling's export_multiplier modifier asks for (see Configuration). For an item of a registered signature strain, it returns 1 plus the strain's price bonus, up to 1.15 at full reputation with the defaults, and one detail line for the sell panel. For anything else, or while signature strains are turned off, it returns 1.0 and no details.

local multiplier, details = exports['oxide-weed']:PriceFor(item.metadata)

Parameters:

NameTypeDescription
metadatatableThe item's metadata. Only strain_id is read

Returns: number multiplier, and table|nil details: one { label, value, bonus, color, type } row when there is a bonus. label is "Signature" in the server's language, value the strain's reputation tier, and bonus the bonus as a share (0.15 = 15%).

You don't need to call this yourself; adding the modifier row to oxide-drugselling is enough.

Smoking

IsPlayerSmoking(source)

Returns true while the player has an active smoking effect session.

local smoking = exports['oxide-weed']:IsPlayerSmoking(source)

Settings

Settings live in the database and are normally edited in game with /weed settings (see Admin). These exports let another resource read or change them programmatically.

GetSetting(key)

Returns the current live value of a top-level setting key (e.g. 'Store', 'PlantSettings', 'Strains'). Keys match the Config.* names in Configuration.

local store = exports['oxide-weed']:GetSetting('Store')
print(store.items[1].price)

SetSetting(key, value)

Replaces a setting's value: applies it live, saves it to the database, pushes it to every player, and re-runs anything that depends on it (NPCs re-spawn, item handlers re-register, wild plants re-seed). The value must be the whole value for that key — read it with GetSetting, modify, and write it back.

local settings = exports['oxide-weed']:GetSetting('PlantSettings')
settings.waterDecayRate = 0.5
exports['oxide-weed']:SetSetting('PlantSettings', settings)

UseHudAccent and SceneAnims are config-file only (see Configuration - General Settings), so SetSetting refuses them.

Warning: this export is not permission-checked — it trusts the calling resource. Values are not validated the way the in-game menu validates them, so keep the same shape and value ranges the config files use.