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 (IsEntityDeador health<= 0). The server validates reporter proximity and dedupes via aprocessingDeathflag, then runs the rep loss, loot drop, hit squad, body fade broadcast, and respawn schedule. Server-side health polling is not viable becauseGetEntityHealthon a server-owned ped with no client owner returns 0.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