Exports & Events
Exports, callbacks, state bags, and events for integrating with oxide-blackmarket.
Reference for integrating with oxide-blackmarket.
oxide-blackmarket uses Callback = olink.callback internally. Client callback usage assumes your resource already has access to the same o-link callback object.
Server Exports
Active dealers (multi-dealer)
Several dealers are active at once. These return the live set.
local dealers = exports['oxide-blackmarket']:GetActiveDealers()
-- dealers = { { id, netId, coords, spawnIndex }, ... }
local nearest = exports['oxide-blackmarket']:GetNearestDealer(vector3(x, y, z))
-- nearest = { id, netId, coords, distance } | nilReturns:
GetActiveDealers() -> table— a list of{ id = number, netId = number, coords = vector3, spawnIndex = number }, one per currently active dealer (empty list if none)GetNearestDealer(coords) -> table|nil— the active dealer closest tocoordsas{ id, netId, coords, distance }, ornilif none are active /coordsis missing
Dealer state (single-dealer, back-compat)
These predate the multi-dealer system and resolve to the first active dealer (use GetActiveDealers / GetNearestDealer for full awareness).
local netId = exports['oxide-blackmarket']:GetDealerNetId()
local coords = exports['oxide-blackmarket']:GetDealerCoords()
local spawnCoords = exports['oxide-blackmarket']:GetDealerSpawnCoords()
local active = exports['oxide-blackmarket']:IsDealerActive()
local valid = exports['oxide-blackmarket']:IsDealerValid()Returns:
GetDealerNetId() -> number|nil— first active dealer's network idGetDealerCoords() -> vector3|nil— first active dealer's live coordsGetDealerSpawnCoords() -> vector3|nil— first active dealer's configured spawn coordsIsDealerActive() -> boolean— true if at least one dealer is activeIsDealerValid() -> boolean— true if at least one dealer is active
Stock
Each dealer keeps its own stock pool, tracked per catalog entry. An entry id has the form 'tier:index' (e.g. '3:6' = tier 3, sixth entry). Entries can share an item name (e.g. the printer_usb blueprints) while keeping separate stock pools. The stock exports aggregate across all active dealers by item name.
local stock = exports['oxide-blackmarket']:GetDealerStock()
local qty = exports['oxide-blackmarket']:GetItemStock('weapon_pistol')
local ok = exports['oxide-blackmarket']:UpdateDealerStock('weapon_pistol', -1)Returns:
GetDealerStock() -> table—{ [itemName] = count }, summed across every active dealerGetItemStock(itemNameOrEntryId) -> number— an item name returns the total across all dealers and all entries with that name; an entry id returns that entry's total across all dealersUpdateDealerStock(itemNameOrEntryId, amount) -> boolean— acts on the first active dealer. An entry id updates that entry directly; with an item name, positive amounts restock the first matching entry and negative amounts drain matching entries in catalog order
Reputation
local rep = exports['oxide-blackmarket']:GetPlayerReputation(source)
local ok1 = exports['oxide-blackmarket']:SetPlayerReputation(source, 500)
local ok2 = exports['oxide-blackmarket']:AddPlayerReputation(source, 50)
local ok3 = exports['oxide-blackmarket']:RemovePlayerReputation(source, 100)
local ok4 = exports['oxide-blackmarket']:AddReputationWithNotify(source, 50)
local ok5 = exports['oxide-blackmarket']:RemoveReputationWithNotify(source, 100)Returns:
GetPlayerReputation(source) -> numberSetPlayerReputation(source, amount) -> booleanAddPlayerReputation(source, amount) -> booleanRemovePlayerReputation(source, amount) -> booleanAddReputationWithNotify(source, amount) -> booleanRemoveReputationWithNotify(source, amount) -> boolean
Settings
Configuration is stored in the oxide_settings database table (see Configuration). These read and write it at runtime, keyed by the top-level config name without the Config. prefix.
local dealerCount = exports['oxide-blackmarket']:GetSetting('DealerCount')
local ok = exports['oxide-blackmarket']:SetSetting('DealerCount', 5)Returns:
GetSetting(key) -> any— the current (database-backed) value of that settingSetSetting(key, value) -> boolean— updates the setting live: applies it on the server immediately, saves it to the database, and syncs it to clients. The change persists across restarts. (Editing the database row directly instead needs a resource restart to take effect.)
Client Exports
Dealer and menu state
local entity = exports['oxide-blackmarket']:GetDealerEntity()
local active = exports['oxide-blackmarket']:IsDealerActive()
local inMenu = exports['oxide-blackmarket']:IsInMenu()
exports['oxide-blackmarket']:SetInMenu(true)Returns:
GetDealerEntity() -> number|nil— the entity handle of the nearest streamed-in dealer pedIsDealerActive() -> boolean— true if any dealer ped is currently streamed inIsInMenu() -> boolean— true while a shop NUI is open
UI
exports['oxide-blackmarket']:OpenShopUI(shopData)
exports['oxide-blackmarket']:CloseShopUI()
exports['oxide-blackmarket']:UpdateShopUI('updateStock', { id = '2:2', item = 'weapon_pistol', stock = 5 })
local isShopOpen = exports['oxide-blackmarket']:IsShopOpen()
local isNuiOpen = exports['oxide-blackmarket']:IsNUIOpen()Returns:
IsShopOpen() -> booleanIsNUIOpen() -> boolean
Player state
local loggedIn = exports['oxide-blackmarket']:IsLoggedIn()
local isPolice = exports['oxide-blackmarket']:IsPlayerPolice()Returns:
IsLoggedIn() -> booleanIsPlayerPolice() -> boolean
Server Callbacks
oxide-blackmarket:server:GetReputation
Callback.Trigger('oxide-blackmarket:server:GetReputation', function(data)
print(data.rep, data.tier, data.tierName)
end)Return shape:
{
rep = number,
tier = number,
tierName = string
}oxide-blackmarket:server:IsPlayerPolice
Callback.Trigger('oxide-blackmarket:server:IsPlayerPolice', function(isPolice)
print(isPolice)
end)Returns boolean.
State Bags
oxide-blackmarket:dealer
Replicated entity state bag set on each active dealer ped. Its value is the dealer's id (a small number) while the ped is a live dealer; it is cleared (set to nil) when the ped dies or is deleted. Clients identify each dealer via this bag rather than a captured entity reference, since out-of-scope clients only resolve the entity when it streams into their scope. With multiple dealers active, the id distinguishes one from another.
-- Client: check if a ped is a dealer, and which one
local dealerId = Entity(entity).state['oxide-blackmarket:dealer']
if dealerId then
-- this ped is dealer `dealerId`
end
-- React to stream-in / stream-out
AddStateBagChangeHandler('oxide-blackmarket:dealer', nil, function(bagName, _, value)
local entity = GetEntityFromStateBagName(bagName)
-- value == dealerId on spawn/stream-in, nil on despawn/stream-out/death
end)Client Events
Dealer
oxide-blackmarket:client:SpawnHitSquad(coords)oxide-blackmarket:client:DealerBodyFade(netId)— server-driven body fade triggered by the death flow
Reputation
oxide-blackmarket:client:TierChanged(newTier, newTierName)oxide-blackmarket:client:TierUp(tierName)oxide-blackmarket:client:TierDown(tierName)oxide-blackmarket:client:ReputationLost()
Shop
oxide-blackmarket:client:OpenShop(shopData)oxide-blackmarket:client:TransactionResult(success, message, updateData)
shopData contains:
{
playerRep = number,
playerTier = number,
tierName = string,
playerCash = number,
buyInventory = table, -- entries: { id, item, label, price, stock, info, category }
sellInventory = table, -- entries: { item, label, count, sellPrice, repGain, category }
enableTiers = boolean,
dealerNetId = number, -- which dealer this shop is open against; echoed back on buy/sell
}buyInventory[n].id is the catalog entry id ('tier:index') used to identify the entry in purchases and stock updates. sellInventory[n].sellPrice is the current market price (after saturation). The category on each entry is the heading it's grouped under in the UI.
Loot
oxide-blackmarket:client:SpawnLoot(coords, lootId)oxide-blackmarket:client:RemoveLootBag(lootId)oxide-blackmarket:client:LootCollected()
Pager
oxide-blackmarket:client:PagerSending(duration)— plays the texting animation and progress bar fordurationms while the reply is pendingoxide-blackmarket:client:PagerResult(success, payload)
Pager result behavior:
- On success,
payloadis a table{ detail = string, waypoint = boolean, coords = vector3 }.detailis'area','street', or'exact'(set by the player's tier viaConfig.PagerIntel); the client composes the anonymous tip email from it and drops a map waypoint whenwaypointis true. - On failure,
payloadis a message string.
Server Events
Every dealer-facing server event carries the dealer's netId so the server knows which of the active dealers the client means.
Dealer and arrest
TriggerServerEvent('oxide-blackmarket:server:DealerKilled', netId)
TriggerServerEvent('oxide-blackmarket:server:DealerSurrendered', netId, state)
TriggerServerEvent('oxide-blackmarket:server:DeliverDealer', netId, dropOffIndex)Notes:
DealerKilledis fired by the in-scope client that owns the ped at the moment of death. The server validates reporter proximity, dedupes duplicate reports, then runs the rep loss, loot drop, hit squad, body fade broadcast, and respawn schedule.DealerSurrendered(netId, state)reports whether the dealer's hands are up (state = true) or he's broken free (state = false). It controls the reduced police society payout if the dealer is killed while surrendered.DeliverDealer(netId, dropOffIndex)finalizes a transport arrest (it replaces the old instantArrestDealerevent). The client fires it when the officer's vehicle reaches a drop-off; the server re-validates that the caller is police, is withinConfig.DropOffRadiusofConfig.ArrestDropOffs[dropOffIndex], and has the dealer present, then pays the reward (or funds the oxide-police department treasury) and despawns the dealer.
Shop
TriggerServerEvent('oxide-blackmarket:server:RequestShop', netId)
TriggerServerEvent('oxide-blackmarket:server:Purchase', netId, entryId, quantity)
TriggerServerEvent('oxide-blackmarket:server:Sell', netId, itemName, quantity)Notes:
- All three are scoped to the dealer identified by
netId, so purchases and sales draw from and affect that specific dealer's stock. Purchasetakes the catalog entry id fromshopData.buyInventory('tier:index'). A plain item name is also accepted and resolves to the first catalog entry with that name within the player's tier — fine for unique item names, ambiguous for duplicates likeprinter_usb.Sellprices at the current market rate and is subject to the optional daily sell cap.
Loot
TriggerServerEvent('oxide-blackmarket:server:CollectLoot', lootId)Integration Examples
Grant blackmarket rep from another resource
RegisterNetEvent('my-heist:server:completed', function()
local src = source
exports['oxide-blackmarket']:AddReputationWithNotify(src, 100)
end)Check whether a dealer is currently up
local function getDealerLocation()
if not exports['oxide-blackmarket']:IsDealerValid() then
return nil
end
return exports['oxide-blackmarket']:GetDealerCoords()
endUse current dealer stock in another script
local function canBuyFromDealer(itemName, quantity)
return exports['oxide-blackmarket']:GetItemStock(itemName) >= quantity
end