FiveM drug system design: gathering, processing and selling safely

How to design a FiveM drug system: gathering and processing with server-side item checks, rate limits, selling to NPCs safely, police alerts and balancing payouts.

The symptom: players have thousands of drugs in minutes, sell the same item to the same NPC forever, or earn ten times what a job pays with no police alert at all.

A drug system has three stages: gather, process and sell. All three follow the same rule: the client asks, the server checks and decides. This article shows the checks and the balance questions that matter.

The three stages

Stage What happens What the server must check
Gather Player picks a plant, mines a resource Location, cooldown, a rate limit
Process Raw items become a finished product The player has the items, is at the process spot
Sell Product turns into money or dirty money The item, the buyer, the price, the cooldown

Each stage consumes or creates items, so the safe design uses your inventory's server functions. The item creation side is in adding items to ox_inventory.

Server-side item checks

Never trust a client that says "I have 10 of this". Ask the inventory on the server, remove the inputs, then add the outputs, in one place:

lua
-- server
RegisterNetEvent('drugs:process', function()
    local src = source
    if not isNearProcessor(src) then return end   -- distance check on the server

    local count = exports.ox_inventory:GetItemCount(src, 'weed_leaf')
    if count < 3 then return end

    if exports.ox_inventory:RemoveItem(src, 'weed_leaf', 3) then
        exports.ox_inventory:AddItem(src, 'weed_bag', 1)
    end
end)

Remove first, add second, and only add when the removal succeeded. If you add first, a player who spams the event can keep the output and lose nothing. Check for canCarryItem before adding if players can be full.

Rate limits

Even a legitimate event can be abused by firing it from a loop. Give each action a minimum delay per player, kept on the server:

lua
local lastAction = {}

local function rateLimited(src, key, ms)
    local now = GetGameTimer()
    lastAction[src] = lastAction[src] or {}
    if lastAction[src][key] and now - lastAction[src][key] < ms then
        return true
    end
    lastAction[src][key] = now
    return false
end

Set the delay a bit under what the real action takes, so honest players are never blocked. Remember to clear lastAction[src] on playerDropped so the table does not grow forever. Gathering should also be limited by location: a plant that exists in one field must not be pickable from anywhere.

Selling to NPCs safely

Selling to pedestrians is the most abused part, because the client picks the ped. Add the option with your target library on the client, for example on all peds:

lua
-- client (ox_target)
exports.ox_target:addGlobalPed({
    {
        label = 'Offer drugs',
        icon = 'fa-solid fa-cannabis',
        distance = 2.0,
        canInteract = function(entity)
            return not IsPedAPlayer(entity) and not IsEntityDead(entity)
        end,
        onSelect = function(data)
            TriggerServerEvent('drugs:sell', 'weed_bag')
        end,
    },
})

Targeting basics are in adding ox_target zones. Notice that the client sends only the item name. Everything else is decided on the server:

lua
RegisterNetEvent('drugs:sell', function(item)
    local src = source
    local price = Config.Prices[item]
    if not price then return end                      -- only allowed items
    if rateLimited(src, 'sell', 4000) then return end -- cooldown between deals

    if exports.ox_inventory:RemoveItem(src, item, 1) then
        local payout = math.random(price.min, price.max)
        exports.ox_inventory:AddItem(src, 'black_money', payout)
    end
end)

The price comes from the server config, never from the client. The item name should be checked against an allowed list, because a client could send any name. Add a random chance that the NPC refuses or reports you. If the sale needs the player to be in a zone or at night only, check that on the server too. The black_money item name depends on your setup; see money types.

Police alerts

Risk is what makes drugs interesting. Alert the police on a chance, from the server, with the location of the deal:

  • A percentage chance on every sale (for example a small chance that the NPC calls the police).
  • A larger chance when fewer deals have been made in a quiet area, or when many deals happen in the same spot.
  • A required minimum of on-duty officers for selling and processing, counted on the server, as in setting up a police job.

If you use a phone app for deals, orders and meeting points should still be created and checked on the server.

Drug Dealer AppStreet sales as an lb-phone app: zones, NPC buyers, levels and police alerts.from €18.15View script β†’

Balancing payouts

Balance in numbers, not in feeling:

  1. Time one full loop (gather, process, sell) and count how many minutes it takes.
  2. Compute money per hour: payout times loops per hour.
  3. Compare it with your best legal job's paycheck. Drugs may pay more, because of the risk, but a factor of two or three is plenty.
  4. Add friction: processing time, item weight, a limited number of sales per NPC, a cooldown per location.

Then watch the money in your database after a week and adjust. The method is in balancing your server economy.

Checklist

Symptom Fix
Infinite items Check location, remove inputs first and rate limit on the server
Client sets the price Take prices from the server config only
Sells any item as drugs Check the item name against an allowed list
Same NPC buys forever Add a cooldown per player and per ped or location
Drugs pay too much Compare money per hour with a normal job
No police reaction Alert on a chance, from the server

Quick answers

Why do players get unlimited drugs?

The gather or process event runs on the server without checking location, time or limits, so a modified client can fire it in a loop. Add the checks and a rate limit on the server.

How do I let players sell drugs to NPCs?

Add a target option to pedestrians on the client, then let the server check the item, the distance, a cooldown and the price before it pays. The client only asks.

How do I balance drug payouts?

Work out the money per hour a player can earn and compare it with a normal job. Drugs can pay more because of the risk, but not so much that nobody does anything else.

Scripts that skip this problem

Drug Dealer AppStreet sales as an lb-phone app: zones, NPC buyers, levels and police alerts.View script β†’Item Creator V2Create usable items with animations, props, effects and more β€” without writing code.View script β†’Pawn Shop AppA player-to-player pawn market inside lb-phone.View script β†’

Keep reading