Requirements
dd_lib detects at boot whether vorp_core, rsg-core or neither is running and routes every identity, money and notification call accordingly. Three deployments are supported.
dd_lib and dd_shellkit are free and MIT licensed. Both are fully open and editable, nothing in them is encrypted. Grab the zip from the releases page of each and drop the folder into your resources directory.
dd_lib
config/overrides.lua, where you can re-point any of those calls at your own resources.dd_shellkit
Alt-held cursor mode plus the right-click player context menu the trade flow uses. If you already run dd_hud, dd_shellkit stays passive.Installation
Download
Extract
resources/ directory. The exact bracket folders do not matter, the load order in server.cfg does.Copy your item icons
dd_inventory/img/items/, named after the item.Delete the old inventory
resources/[VORP]/vorp_inventory/ folder, or resources/[rsg]/rsg-inventory/. Keep a backup zip somewhere outside resources/ if you like. Most servers need nothing else here - if a resource then refuses to start, see “If a script still expects the old inventory” below.Set the load order
server.cfg, after your framework core if you run one, and before any resource that consumes the inventory.Restart
If a script still expects the old inventory
Skip this on a standalone server, there is no old inventory to miss. Everyexports.vorp_inventory:* call, and on RSG every exports['rsg-inventory']:* call, is answered by DD Inventory, so scripts keep working. Two things still look for the name of the deleted resource, and both only matter once you have deleted the folder:
- a manifest line
dependencies { 'vorp_inventory' }, which stops that resource from starting at all - a runtime check
GetResourceState('vorp_inventory') == 'started', which makes that script quietly skip its inventory path
vorp_fishing/fxmanifest.lua, remove 'vorp_inventory' from its dependencies block and it starts again. The same applies to any open script with that check, on either framework.
If you cannot edit the script - an encrypted or escrowed paid resource, for example - copy extras/vorp_inventory/ out of this download into resources/[VORP]/, or extras/rsg-inventory/ into resources/[rsg]/. It is a single manifest with no scripts and no files, and it exists only so the name resolves. Nothing to rename, nothing to configure.
Third-party UIs with hardcoded image paths
VORP only in practice:vorp_menu and vorp_stores, or another UI that shows item images, hardcode the old image URL and need a one-line path change from nui://vorp_inventory/html/img/items/ to nui://dd_inventory/img/items/. On RSG, rsg-inventory, rsg-core and rsg-weapons resolve item images relatively and need no change; only your own scripts that hardcode nui://rsg-inventory/html/images/ do.
vorp_stores/client/client.lua has one occurrence, vorp_menu/html/js/app.js has two. Any other custom UI that loads item images the same way needs the same one-liner.
server.cfg load order
Place this block after your framework core, if you run one, and before any resource that consumes the inventory (stores, banking, housing, stables, jobs, your own scripts):dd_lib must be loaded before anything that uses the bridge, dd_shellkit must exist before the inventory registers its panel, and the placeholder, if you needed one, must start before the scripts whose dependency checks it resolves.
First boot
There is no manual SQL to run. On the first start DD Inventory creates all of its tables (inventories, inventory_rights, item_definitions, item_instances, inventory_audit, character_currency, account_sigils) with CREATE TABLE IF NOT EXISTS. What happens next depends on the detected framework.
items table, and inserts every name that does not yet exist as an item definition - carrying over label, description, stack limit (-1/unlimited becomes 100), type, weight and the usable flag. Existing DD Inventory definitions are never overwritten, so the import is safe to let run on every boot. The vorp compatibility layer is not gated on the detected framework, so this import is attempted everywhere. On a database with no items table it logs items table not found - skipping VORP item import and moves on, which is the normal line on a standalone or RSG server.
Running without a framework
DD Inventory runs on a bare FXServer, withDDLib.framework detected as standalone. Everything that is purely inventory logic works unchanged. Four consequences follow from there being no framework to ask, and all four are worth planning for before you open the server.
Set currencyMode to native
Set currencyMode to native
currencyMode = 'framework' every balance reads as zero, and every credit or debit returns a failure code (FRAMEWORK_ADD_FAILED) rather than an error you would notice. Set currencyMode = 'native' and the cash and gold balances live in DD Inventory’s own character_currency table, where they behave exactly as on a framework server. The account-wide premium balance is unaffected either way, it is always DD Inventory-owned.One identity per account
One identity per account
DDLibOverrides['identity.charId'] at it (see Framework overrides) and multiple characters work normally.No character-selection signal
No character-selection signal
dd_lib has no standalone branch for the character lifecycle: it hooks vorp:SelectedCharacter on VORP and RSGCore:Server:PlayerLoaded on RSG, and on standalone there is no equivalent event to hook. The client gates the open keybind on an active session, and on standalone that session is only marked active by the replay DD Inventory runs a couple of seconds after the resource starts, for players who are connected at that moment. Players who connect later are not covered by that replay.Two ways around it, both server-side: trigger dd_inventory:client:sessionActive towards a player once your own spawn or character flow has finished, or drive the whole lifecycle from your own resource. There is no override key for this hook today.Empty item catalogue and notifications
Empty item catalogue and notifications
item_definitions starts empty and /dd_give answers Unknown item until you populate it. Register definitions from your own resource with exports.dd_inventory:registerItemDefinition({ ... }), documented in the developer reference, or insert the rows directly.Notifications fall back to chat:addMessage, which reaches the player on a default FXServer chat resource and does nothing at all if you removed chat. Point DDLibOverrides['notify'] at your own notification resource.Player controls
Configuration
Everything you configure lives in theconfig/ folder: config/config.lua holds the global DDInvConfig, config/language.lua holds every piece of player-facing text. Both files - along with the framework compat shim and the NUI host indirection - are escrow-ignored and stay fully readable and editable after purchase.
Slots, weight and grid
carriedWeight / maxWeight. speedPenalty is a percentage, blockSprint additionally disables sprinting. Add, remove or re-tune tiers freely, just keep the ranges contiguous.
dd_buffcore-style export surface). Without one installed nothing breaks: the weight bar and all limits still work, only the movement debuff is skipped.openKey is a Windows virtual-key code, not a RedM control hash: the key is polled with IsRawKeyDown. The codes you are most likely to want:
0x01-0xFF is refused at start with a console warning and falls back to I, so a mistyped config never leaves your players without an inventory key.
The same code is registered with the panel host, so the key also closes the inventory while the interface has focus. That part covers the letters, the digits, F1-F12, the arrow keys, TAB, ENTER, SPACE, BACKSPACE and ESC. A code outside that set still opens the inventory from the game world, it just cannot close it again from inside the panel, and the console says so once at start.
To confirm what the key resolved to, from a client script:
Currency mode
'framework' mode, because the framework wallet is only addressable through a connected player object. getCharacterCurrency reports zero for an offline character and addCurrency returns PLAYER_OFFLINE rather than guessing.
Currencies
The three config keys (breakdust, seamshards, sigils) are internal identifiers used by the export API and the database columns. No player ever sees a key - every visible detail comes from the label and icon you set here.
breakdustis the cash wallet. In'framework'mode this is the framework’s money: VORP currency0, or rsg-core’scashaccount.seamshardsis the gold wallet. In'framework'mode this is the framework’s gold: VORP currency1, or rsg-core’sgoldaccount. RSG’sbloodmoneyis a separate currency and is deliberately never used as a gold stand-in. rsg-core also rejects fractional amounts ongold, so round before crediting if your VORP setup deals in fractions.sigilsis the account-wide premium balance, owned by DD Inventory itself (account_sigilstable) in both modes and on every framework, and shared across all of a player’s characters. It is keyed on the account license rather than a character, which is why it is the default currency for slot purchases: it works identically on VORP, RSG and standalone.iconselects a built-in inline SVG:'dollar','gold'or'sigil'.enabled = falsehides that currency everywhere - currency bar, trade window, bank controls. Omittingenabledmeans enabled.
Slot purchase tiers
Prices are inslotPurchaseCurrency.
Rarities
The list order is the ascending prestige order, and it is also the NUI’s sort priority. Rename labels, change colours, remove entries or add your own keys.key must match the value stored in the rarity column of DD Inventory’s item_definitions, and on VORP also in the rarity column DD Inventory adds to the items table. An item with an unlisted rarity falls back to the first entry’s styling. Assign rarities live with /dd_setrarity <item> <key>, list the valid keys with /dd_rarities.
Sort priority and trade
maxDistance is enforced on the server, so a modified client cannot trade across the map. It is checked when the trade window is requested, once a second for as long as it stays open, and one last time immediately before the items change hands. Walk out of range and the trade cancels itself for both players with a message. Set it to 0 to switch the distance check off entirely.
To see what the server measures, for example when a player reports a trade cancelling on its own:
Bind types and bind restrictions
bind_on_equip item becomes bound when your gear or equipment resource calls exports.dd_inventory:setItemBound(itemId) on first equip.
Framework overrides
Every framework call DD Inventory makes goes throughdd_lib, and every one of them can be replaced without touching DD Inventory itself. This is how you run a custom notification, economy or identity system, and it is also how you drive DD Inventory from a core that is neither VORP nor RSG. Leave a key at nil to keep the built-in behaviour for the detected framework, so you can override one call and leave the rest alone. Reroute the bridge in @dd_lib/config/overrides.lua:
identity.charId, identity.charName, identity.license, money.add, money.remove, money.get, money.onChanged, notify, log - all documented inside the file itself. money.remove must return false when the player cannot pay, because DD Inventory reads that boolean to decide whether a purchase went through.
dd_inventory:client:sessionActive towards the player itself.Language
Every player-facing string - notifications, admin command feedback and all UI text - lives inconfig/language.lua. English and German ship out of the box:
DDLanguage = '' to follow a server-wide setting instead, so all your DD resources switch together:
Translations['en'] = { ... } block, rename the key to your language code, and translate the values only. Keys must stay identical across blocks, and every %s / %d placeholder must be kept in the same order. Keys with a dot in them (trade.accept, tooltip.label_weight) are the ones shipped to the UI.
config/config.lua. Item labels come from your items database table.Admin commands
All commands are registered throughox_lib and gated by the ace object command.<name>, granted to the principal group.admin on first boot. Grant it to anyone else with add_ace <principal> command.<name> allow in server.cfg. All of them work from the server console, RCON and txAdmin as well as in-game; when run from the console the reply is printed to the console instead of being sent as an in-game notification.
/additem, /giveitem, /setjob, RSG’s equivalents) keep working unchanged, because DD Inventory answers the inventory exports they call. It does not replace or remove any of them.
/dd_give and /dd_remove
/dd_give and /dd_remove
/dd_give fails with Unknown item: <name> if no item_definitions row exists for that name. Every grant is written to the audit log with a correlation id./dd_transfer
/dd_transfer
item_instances.item_id) into another inventory id. Useful for recovering items that ended up in a stash or bank the owner can no longer reach./dd_setrarity
/dd_setrarity
item_definitions.rarity and, on a VORP install, the framework’s own items.rarity column, so the change survives the item re-import that runs on every boot.Unknown rarity keys are allowed - you may add your own keys to DDInvConfig.rarities later. The command then prints a warning and the NUI falls back to default styling for that item until the key is configured. Error replies: MISSING_ITEM_NAME, MISSING_RARITY_KEY, ITEM_NOT_FOUND./dd_rarities
/dd_rarities
/dd_setrarity expects./dd_debug
/dd_debug
Optional client debug commands
Optional client debug commands
DDInvConfig.enableTestTui = true, a text-mode debug UI registers the extra client commands /dd_invtui, /dd_invtui_close, /dd_invtui_refresh, /dd_invtui_select, /dd_invtui_use, /dd_invtui_drop, /dd_invtui_move. Leave enableTestTui = false in production.Restarting and updating
- Restart in dependency order:
dd_libthendd_shellkitthendd_inventory. - Restarting
dd_shellkitalone is safe - the inventory detects the reloaded shell and re-registers its panel and keybind automatically. - Updating DD Inventory itself:
restart dd_inventoryis enough. Schema migrations and the item import are idempotent and re-run safely on every start.
Troubleshooting
Item images are missing, everything shows a placeholder letter
Item images are missing, everything shows a placeholder letter
dd_inventory/img/items/ - redo the icon copy step and restart dd_inventory (new files also need a refresh first). In third-party UIs such as vorp_menu or vorp_stores: those hardcode the old path nui://vorp_inventory/html/img/items/..., which no longer resolves once the original resource is deleted - apply the one-line path change above.An item does nothing when I right-click it
An item does nothing when I right-click it
is_usable in item_definitions, which is imported from VORP’s usable column or RSG’s useable field. Second, something has to handle the use: a registerUsableItem callback on VORP, a CreateUseableItem callback on RSG, or a server-side handler registered via registerItemUseHandler on any framework. With neither, the use is allowed but nothing happens.A new item I added to the framework's item table does not appear
A new item I added to the framework's item table does not appear
dd_inventory and watch for the VORP item import: N imported line, or its RSG equivalent. Existing definitions are never overwritten, so if you edited an item that was already imported, change it in item_definitions or use registerItemDefinition. On standalone there is no import at all and registerItemDefinition is the only route.Every currency shows zero and payments quietly fail
Every currency shows zero and payments quietly fail
currencyMode is still on 'framework' and there is no framework wallet to read. Set it to 'native'. On VORP and RSG the same symptom for a single character usually means the character is offline, which is reported as PLAYER_OFFLINE rather than guessed at.Standalone: pressing I does nothing for players who joined after the server started
Standalone: pressing I does nothing for players who joined after the server started
dd_inventory starts. Trigger dd_inventory:client:sessionActive towards the player from your own spawn flow. See Running without a framework.My weapons behave slightly differently than before
My weapons behave slightly differently than before
A player's slots shrank and items are stuck in grey slots
A player's slots shrank and items are stuck in grey slots
slotPurchaseCurrency warning at boot
slotPurchaseCurrency warning at boot
Nothing opens when I press I
Nothing opens when I press I
dd_shellkit is started (or dd_hud, if you run it - it takes over as shell), and that openKey in config/config.lua is not colliding with another resource’s bind.Support
Discord support
config/config.lua, and the exact steps to reproduce.