How Integrations Work#
Vending Machine Creator never talks to your framework or inventory directly. Each one is reached through a small bridge file outside escrow, and the right bridge is picked at start from the resources already running.
Layer | Supported | Used for |
|---|---|---|
Framework |
| Money, giving and taking items, identifiers, names, jobs and admin checks. Required. |
Inventory |
| The item list and pictures in the creator and the owner's panel. Required. |
Database |
| Placed machines, owners, stock and earnings. Required. |
Text UI |
| Styled |
HUD |
| Hidden, with the minimap, while the creator or the owner's panel is open. Other HUDs stay on screen; the minimap is always hidden. |
Phone |
| The VendGo app. Without it, machines are only used in person. |
Police dispatch | Any, through | Robbery alerts. Out of the box: a notification and a blip for the jobs in |
Money and items always go through the framework bridge. The inventory bridge only supplies the item list and the pictures, so when a product is not given, the framework's own item list is the place to look.
Overriding Detection#
Both detection maps are at the top of config/main.lua. Detection returns the first started resource it meets, and the maps have no fixed order — so with two inventories running at once, which one is picked is not guaranteed. Set the value by hand instead:
-- Auto, the default: whatever is started wins.
Config.Framework = DependencyCheck(frameworks) or 'standalone'
Config.Inventory = DependencyCheck(inventories) or 'standalone'
-- Manual: skip detection entirely.
Config.Framework = 'qb' -- esx · qb
Config.Inventory = 'ox' -- ox · qs · qb · tgiann · codem · origenA core or inventory renamed on your server is not found under its usual name. Add it to the map with the bridge it should use — ['my-core'] = 'qb' — and it is detected like the original. Detection only sees resources that are already started, so anything you want found must be above ensure qs-vendingmachine-creator in server.cfg.
Item Pictures#
The pictures in the creator's product list and the owner's panel come from the inventory bridge, which points at the inventory's own image folder:
Inventory | Image path |
|---|---|
| The |
|
|
|
|
|
|
|
|
|
|
Moved your images somewhere else? Change the path at the top of server/custom/inventory/<inventory>.lua — or, for ox_inventory, the convar.
Notifications#
Messages such as "You received Cola" or "Your inventory is full" are shown as the script's own toasts, styled like its panels. They all pass through one function in custom/client.lua — the server sends its messages to it too — so replacing its body moves every notification to your own system:
-- custom/client.lua
function Notification(msg, type) -- type: 'info' · 'error' · 'success'
lib.notify({ description = msg, type = type })
endPolice Dispatch#
AlertPolice(src, machine) in custom/server.lua runs when a robbery starts and the alert chance comes up. Out of the box it sends a notification and a flashing blip to every online player whose job is in Config.Robbery.alert.jobs. Replace its body to send the alert to your dispatch resource instead:
-- custom/server.lua
function AlertPolice(src, machine)
local coords = machine.coords -- x, y, z of the machine
local label = machine.label -- its name, e.g. 'Drink Machine'
-- src is the thief's server id
-- call your dispatch resource here
endThe on/off switch and the chance stay in Config.Robbery.alert, so they keep working with your dispatch. An error inside the function is caught and printed — a broken dispatch never stops the robbery.
Adding a Framework#
A framework that is not on the list takes one folder and one line. Nothing else in the resource refers to a framework by name.
Copy the closest bridge
Copy
custom/qb/— orcustom/esx/— tocustom/<name>/. It holds aclient.luaand aserver.lua, each returning a table of functions.Change the calls inside
Fill each function with your core's own calls. The full list, with what each must return, is in
types.lua(ServerFrameworkandClientFramework).lua -- custom/mycore/server.lua local framework = {} function framework:getIdentifier(source) ... end function framework:getAccountMoney(source, account) ... end function framework:removeAccountMoney(source, account, amount) ... end -- true when paid function framework:addItem(source, item, count) ... end -- true when given -- ...the rest of ServerFramework return frameworkRegister it for detection
Add your core to the
frameworksmap inconfig/main.lua. The value is the folder name:['my_core'] = 'mycore'.
Adding an Inventory#
Copy the closest bridge
Copy
server/custom/inventory/qb.luatoserver/custom/inventory/<name>.lua.Change the guard, the path and the list
The first line keeps the file asleep unless it is the chosen inventory.
formatItemListreturns every item with its name, label and full picture address.lua if Config.Inventory ~= 'myinv' then return end sv_inventory.imagePath = 'nui://my-inventory/html/images/' function sv_inventory:formatItemList() -- { [name] = { name = ..., label = ..., image = self.imagePath .. 'cola.png' } } endRegister it for detection
Add it to the
inventoriesmap inconfig/main.luawith the value from the guard:['my-inventory'] = 'myinv'.
If that is more than you want to take on, open a ticket with the name of the resource.
Languages#
41 translations ship in locales/: ar · bg · bn · ca · cs · da · de · el · en · es · et · fa · fi · fr · he · hi · hr · hu · id · it · ja · ko · lt · lv · ms · nl · no · pl · pt · ro · ru · sk · sl · sv · sw · th · tr · uk · ur · vi · zh. Set Config.Locale to the file name.
To add another, copy en.json to the new code, translate it and set the locale to that code. Any key missing from a translation — at any depth — is filled in from English, so an older translation keeps working after an update. A locale whose file does not exist falls back to English with a warning in the console.



