Custom frameworks & inventories
vns-core is built so that support for a new system is added in one file, once, and every VNS script picks it up automatically. This page is aimed at developers.
How adapters work
Each supported system lives in its own module file:
vns-core/
└── modules/
├── framework/ esx.lua, qbcore.lua, qbox.lua
├── inventory/ ox_inventory.lua, qb-inventory.lua, qs-inventory.lua,
│ origen_inventory.lua, codem-inventory.lua,
│ tgiann-inventory.lua, core_inventory.lua, esx_inventory.lua
└── target/ ox_target.lua, qb-target.lua, qtarget.lua
Every file in these folders is loaded automatically (the manifest includes
modules/framework/*.lua, modules/inventory/*.lua and
modules/target/*.lua). Each module registers itself as a candidate:
VNSCore.Register('inventory', {
name = 'my_inventory', -- the value used in Config.Inventory
priority = 10, -- higher wins when several are running
resource = 'my_inventory', -- resource name checked for auto-detection
build = build, -- function returning the adapter table
})
The category is 'framework', 'inventory' or 'target'. Per category,
vns-core then picks:
- the candidate whose
namematches the value forced inconfig.lua, or - when the option is
'auto', the highest-priority candidate whoseresourceis started.
The stock priorities are: QBox 20, QBCore 10, ESX 10; ox_inventory 20, other inventories 10, ESX built-in inventory 1; ox_target 20, qb-target 10, qtarget 10.
build() runs on both the client and the server. Use IsDuplicityVersion()
inside it to define the server-side and client-side functions separately, as
the stock modules do.
Adding your own inventory
- Copy the existing adapter closest to yours to
modules/inventory/my_inventory.lua. For most custom inventories that isqb-inventory.lua. -
Implement the functions using your inventory's exports.
Server side
Function Returns AddItem(source, item, count, metadata)trueon successRemoveItem(source, item, count, metadata)trueon successGetItemCount(source, item)number HasItem(source, item, count)boolean GetItemLabel(item)label string (return itemif unknown)RegisterStash(stashId, label, slots, weight)nothing (can be empty if your inventory creates stashes on open) OpenStashServer(source, stashId, opts)nothing. opts={ label, slots, weight }StashHasItems(stashId)boolean CanCarryItem(source, item, count)(optional)boolean. Treated as trueif missingGetPlayerItems(source)(optional){ [name] = { name, label, count } }GetAllItems()(optional){ [name] = { name, label } }. If missing, the framework's shared item list is usedClient side
Function Returns GetItemCount(item)number HasItem(item, count)boolean OpenStash(stashId, opts)nothing OpenLocalStash(stashId)(optional)nothing. Called when the server fires vns-core:client:openLocalStash, for inventories whose stash UI has to be opened from the clientIf your inventory has no client-side count export, do what the stock modules do:
lib.callback.await('vns-core:server:getItemCount', false, item). If opening a stash has to start on the server, triggervns-core:server:openStashfromOpenStash, which calls yourOpenStashServer. -
Change
nameandresourcein theVNSCore.Registercall at the bottom. - Restart. Either set
Config.Inventory = 'my_inventory'or let auto-detection find it (give it a priority above 20 if ox_inventory is also running).
Adding a framework
Copy modules/framework/qbcore.lua (or esx.lua) and implement:
- Both sides:
GetPlayerData(source)(client: no argument) returning{ source, identifier, name, job = { name, label, grade, gradeLabel, isboss, onduty } },GetPlayerJob(source),IsPlayerBoss(source). - Client:
GetMoney(moneyType). - Server:
GetMoney,AddMoney,RemoveMoney(source, moneyType, amount),RegisterUsableItem(item, callback),GetNameByIdentifier(identifier),GetMetadata(source, key),GetSharedItems(),CreateJob,DeleteJob,UpdateJob,SetPlayerJob,SetDuty,GiveVehicle(source, model, plate),GetOwnedVehicles(source),PlateExists(plate).
Functions a script doesn't need can be left out. vns-core checks for them and
returns a safe default (nil, 0, false or an empty table) when they are
missing.
vns-core also needs to know when a character has loaded. It polls
GetPlayerData() until it returns an identifier, so a correct
GetPlayerData is enough.
Adding a target system
Copy modules/target/qb-target.lua and implement, on the client:
AddSphereZone(opts), AddBoxZone(opts), RemoveZone(zoneId),
AddEntityTarget(entity, options) and RemoveEntityTarget(entity). The
option and zone shapes are listed in the Exports reference.
On the server the adapter can return an empty table.
The bridge from a script's side
Scripts import @vns-core/shared/bridge.lua and call everything through the
VNS table, for example VNS.HasItem(source, 'wood', 5) or
VNS.Notify(source, { title = 'Base', description = 'Saved', type = 'success' }).
Encrypted VNS scripts keep their open bridge files readable
(client/client_open.lua / server/server_open.lua, or
client/open_client.lua / server/open_server.lua in Base Building). That is
where those calls are made, so you can always see and adjust how a script
talks to your server. See the Exports reference for every
function.
Warning
Keep a copy of your custom adapter file when updating vns-core. Updates replace the folder and don't know about your file; put it back after updating.