Configuration
Configuration
The inventory keeps its settings in three files inside the resource folder:
micio/config/core.lua: debug output, interface language, the reserved slot rescue.micio/config/grid.lua: grid sizes and durability stacking.micio/config/ui.lua: interface, HUD, holding and giving, renaming, tooltip metadata.
ML Clothing keeps its own two files:
shared/config.lua: clothing slots, bags, armor plates, wear, bag blacklist.shared/invadmin_config.lua: the admin panel.
Every other file of your ox_inventory install keeps working the way it does today, data/ included.
The admin panel has a Settings tab that reads the three inventory files and writes them back without stopping the server. Each key is shown with the one line spec written next to it in the file. A value is accepted only in the type the key already holds, and Language, UI.rarityStyle, UI.Hud.style and UI.Give.consent are offered as closed lists. The file is backed up before every change. The inventory reads these files at start, so restart the resource for a saved value to take effect.
Core
1MicioConfig.Debug = false
2
3MicioConfig.Rescue = {
4 enabled = true,
5 report = true,
6}Debug, defaultfalse. Prints boot and slot rule detail to the server console.Rescue.enabled, defaulttrue. Items sitting in a reserved slot are moved into free grid cells when the character loads, once per character. An item that finds no free cell stays in the slot it was in, and if the pass cannot complete, every item is left where it was saved.Rescue.report, defaulttrue. Prints the capacity comparison at boot.
Grid
1MicioConfig.Grid = {
2 playerCols = 8,
3 playerRows = 4,
4 secondaryCols = 6,
5 dropCols = 6,
6 dropRows = 4,
7 durabilityStackTolerance = 5,
8 durabilityStackPerItem = {},
9}playerCols, default8. Columns in the pocket grid.playerRows, default4. Rows in the pocket grid.secondaryCols, default6. Columns of the right hand panel for shops, vehicle storage and another player. A stash or container sizes itself from its own slot count instead, unless the script that created it set its columns:exports.ox_inventory:RegisterStash(id, label, { slots = 30, cols = 6 }, weight), orexports.ox_inventory:mlSetInventoryCols(id, cols)on a stash you did not register yourself.dropCols, default6. Columns of a bag left on the ground.dropRows, default4. Rows of a bag left on the ground.durabilityStackTolerance, default5. Percentage points two durability values may differ and still stack in one slot.0stacks only identical values.durabilityStackPerItem, default{}. Per item override of the tolerance above, written as['sandwich'] = 25.
Player capacity follows the grid: playerCols times playerRows cells of pocket space, with the reserved slots on top of that count. Size the inventory here rather than with a slot count.
A grid under 8 cells, or a playerCols or playerRows that is not a whole number of at least 1, is refused at boot. A warning names micio/config/grid.lua and 8 by 4 is used instead. The reserved slots sit outside the grid and never constrain it. secondaryCols, dropCols and dropRows fall back to 6, 6 and 4 the same way, without a warning.
Interface
1MicioConfig.UI = {
2 defaultTheme = '#00d4aa',
3 rarityStyle = 'border',
4 enableThemePicker = true,
5 virtualPed = true,
6 stockBadge = false,
7 walkWhileOpen = true,
8 family = 'tactical',
9 families = { 'tactical', 'glass', 'slate' },
10 defaultScale = 100,
11 defaultOpacity = 100,
12 layoutVersion = 1,
13 layoutStudio = false,
14}defaultTheme, default'#00d4aa'. Accent colour a player starts with, any hex value.rarityStyle, default'border'. How rarity shows on a slot. Acceptsborder,fullorglow.enableThemePicker, defaulttrue. Lets each player pick an accent colour. Turn it off to keep everyone ondefaultTheme.virtualPed, defaulttrue. Shows the live character preview next to the inventory. Needs ML Clothing running. Ifox_inventory:virtualPedis already set inserver.cfg, that convar wins and this key is ignored: remove the line to drive the preview from here.stockBadge, defaultfalse. Marks stackable items with a badge on the slot and a line in the tooltip.walkWhileOpen, defaulttrue. Movement keys and sprint stay active while the inventory is open. While a text field has the cursor the keys type.falseholds the player in place.family, default'tactical'. Style family a player starts with.families, default{ 'tactical', 'glass', 'slate' }. Families offered in the settings. Each name is a file inweb/themes/. A saved choice missing from the list falls back tofamily.defaultScale, default100. Interface scale a player starts with, percent.defaultOpacity, default100. Background opacity a player starts with, percent.layoutVersion, default1. Raise it and every player gets the panel positions fromPanelsonce, their own saved positions cleared.layoutStudio, defaultfalse. Adds the layout studio button to the settings. See below.
Default layout
1MicioConfig.UI.Panels = {
2 pockets = { x = 28, y = 3.7 },
3 clothing = { x = 2, y = 4 },
4 weapons = { x = 28, y = 36 },
5 armor = { x = 68, y = 37 },
6 bag = { x = 68, y = 3.7 },
7 secondary = { x = 64.6, y = 55.6 },
8 shop = { x = 64.6, y = 40 },
9 crafting = { x = 64.6, y = 40 },
10 loot = { x = 64.6, y = 55.6 },
11 settings = { x = 40, y = 20 },
12}Top left corner of each panel as a percent of screen width and height, so one layout holds on every resolution. A player who drags a panel keeps that position on their own machine until you raise layoutVersion.
To build the layout in game: set layoutStudio = true, restart the resource, open the settings and press Open next to Layout studio. Every panel appears at once with sample items, the shop and the crafting bench included. Drag them where you want them, set the family, the accent colour, the scale and the opacity from the settings, then press Copy layout. The snippet lands in the clipboard and in the F8 console, with layoutVersion already raised by one. Paste it at the end of micio/config/ui.lua, where it overrides the keys above it, set layoutStudio back to false and restart.
Style families
Three families ship in web/themes/, one CSS file each: tactical.css, dark; glass.css, light and translucent, tinted by the accent colour; slate.css, flat neutral grey with square corners. A family is a set of CSS custom properties on :root[data-family='name'] plus any extra rules. To add one, copy a file under a new name, edit it and add the name to families. The file is loaded at start and on every switch.
Panel and slot backgrounds are computed from the accent colour and the background opacity, starting from the bases the family declares. A base is a grey level from 0 to 255 and an alpha from 0 to 1:
1:root[data-family='glass'] {
2 --fam-tint: 0.18;
3 --fam-bg-primary: 240 0.84;
4 --fam-bg-secondary: 236 0.86;
5 --fam-bg-slot: 255 0.62;
6 --fam-bg-slot-hover: 255 0.9;
7 --fam-bg-slot-empty: 250 0.34;
8 --fam-bg-overlay: 246 0.97;
9}--fam-tint moves each grey toward the accent colour: 0 neutral, 1 the accent itself. The alpha is scaled by the background opacity. --fam-alpha-floor sets the lowest point of that scale, so a light family keeps its text readable at the bottom of the slider: glass uses 0.85. A missing base takes the tactical value.
The tokens every family defines:
Property — What it paints
--surface-1 — Panel backgrounds
--surface-2 — Slots and cards
--surface-3 — Hovered or raised elements
--surface-empty — Empty slots
--line — Hairlines and borders
--line-strong — Borders of hovered or focused elements
--ink — Primary text
--ink-dim — Secondary text
--ink-faint — Placeholder text and disabled controls
--shadow — Shadow colour under floating elements
--backdrop — Full-screen dim behind dialogs
--accent-primary and --accent-rgb come from the player's choice in the settings. Rarity colours, durability gradients and ammo tones are the same in every family.
Screen effects
1MicioConfig.UI.Effects = {
2 enabled = true,
3 blur = false,
4 tint = true,
5 vignette = 0.6,
6}enabled, defaulttrue. Vignette behind the open inventory; the character preview stays clear. Players can switch it off in the settings.blur, defaultfalse.trueblurs the game world while the inventory is open, character preview included. ML Inventory drives the blur itself, soinventory:screenblurcan stayfalse.tint, defaulttrue. Vignette in the player's accent colour instead of black.vignette, default0.6. Edge darkness, 0 to 1.
Keys
1MicioConfig.UI.Keys = {
2 wheel = 'z',
3 hotkeys = { '1', '2', '3', '4', '5' },
4 hud = 'TAB',
5}
6
7MicioConfig.UI.Wheel = {
8 enabled = true,
9}wheel, default'z'. Opens the item wheel. Rebindable per player in the FiveM keybind settings.hotkeys, default{ '1', '2', '3', '4', '5' }. Keys of the five quick slots, in order. Rebindable per player.hud, default'TAB'. Shows the HUD whileHud.modeis'key'. Rebindable per player.Wheel.enabled, defaulttrue.falseremoves the radial wheel and its key. The quick slots and their keys stay.
The keys for the item in hand are under Holding and giving items below. The key that opens the inventory itself belongs to ox_inventory and stays in its inventory:keys convar.
Giving with consent
1MicioConfig.UI.Give = {
2 consent = 'prompt',
3 timeout = 15,
4 distance = 5.0,
5 acceptKey = 'Y',
6 declineKey = 'N',
7}consent, default'prompt'.promptopens a dialog on the receiver's screen with the giver's name, the item image, label and count, and waits for the answer.autohands the item over at once, also when theGiveblock is absent.timeout, default15. Seconds the receiver has to answer. When the time runs out the offer lapses and the giver is told.distance, default5.0. Metres the two players may be apart while an offer is open. Past that the offer is refused before it starts, and an offer already waiting is cancelled and both players are told. Values are held between1.0and50.0.acceptKey, default'Y'. Accepts an offer. Each player can rebind it in the FiveM keybind settings.declineKey, default'N'. Declines an offer. Also rebindable.
The dialog sits in the middle of the screen with an Accept and a Decline button, the countdown, and the two keys printed under the buttons as shortcuts. It works with the inventory closed: the offer takes the mouse cursor while it waits, the player keeps walking and driving, and the cursor goes back to the game as soon as the dialog closes. Escape declines.
Give from the item context menu and the handover of the item in hand both go through this. The server holds the item until the answer arrives, then checks that both players are still connected, still within distance and still holding the same item in the same slot before it moves anything.
After a declined or lapsed offer the giver waits a few seconds before offering again.
While prompt is on, the ox_inventory:giveItem server event is refused: another resource cannot move an item out of a player's pockets without the receiver seeing the offer. Resources that hand out items should use exports.ox_inventory:AddItem instead.
HUD
The HUD is drawn while the inventory is closed: a card for the weapon in slot 1, a slimmer card for slot 2, and the five quick slots of the item wheel. The card of the weapon in hand takes the accent colour and shows magazine and reserve, red with an empty magazine, yellow with no reserve. The other weapon is dimmed. A weapon drawn from any other slot gets its own card while it is in hand. Each quick slot shows the item, its count, its wear and its key.
1MicioConfig.UI.Hud = {
2 enabled = true,
3 style = 'tactical',
4 locked = false,
5 x = 97,
6 y = 96,
7 scale = 100,
8 emptySlots = true,
9 mode = 'always',
10 showSeconds = 5,
11}enabled, defaulttrue. Draws the HUD.style, default'tactical'.tacticaldark cards with a rarity edge,classicrounded cards in the inventory colours,minimalflat,raritycards filled with the rarity colour,glasslight translucent cards. Unknown values fall back totactical.locked, defaultfalse.trueholds every player to the style, position and scale set here.x, default97. Percent of screen width. 60 or more aligns the HUD to its right edge, 40 or less to its left edge, anything between centres it.y, default96. Percent of screen height for the bottom edge of the HUD.scale, default100. Percent, 60 to 140.emptySlots, defaulttrue.falsehides empty quick slots.mode, default'always'.alwayskeeps the HUD on screen.keyshows it forshowSecondsafterKeys.hudor a quick slot key.showSeconds, default5. Seconds on screen inkeymode. A new press restarts the count.
Edit mode closes the inventory and leaves the cursor on the HUD. Drag it, change the style, Enter or Done keeps the layout, Escape restores the previous one.
Holding and giving items
1MicioConfig.UI.Hold = {
2 enabled = true,
3 useKey = 'G',
4 stowKey = 'X',
5 give = true,
6 giveKey = 'H',
7 giveDistance = 2.5,
8 blockControls = {},
9}enabled, defaulttrue. Using an item that has portions takes it into the hand instead of consuming it at once.useKey, default'G'. Takes a portion from the item in hand. Each player can rebind it in the FiveM keybind settings.stowKey, default'X'. Puts the item in hand away.give, defaulttrue. Allows handing the item in hand to a player standing in front.giveKey, default'H'. Starts aiming at the player to hand it to. Also rebindable.giveDistance, default2.5. Metres between the two players for the handover to be accepted.blockControls, default{}. Extra control ids kept dead while an item is in hand. The keys above are already covered.
Renaming
1MicioConfig.UI.Rename = {
2 enabled = true,
3 blacklist = {},
4}enabled, defaulttrue. Lets players give an item their own name from its context menu. Every item is renamable while this is on.blacklist, default{}. Item names players may not rename, written as{ 'water', 'bandage' }.
Tooltip metadata
1MicioConfig.UI.Tooltip = {
2 metadataWhitelist = { 'type', 'registered' },
3 showUnlisted = false,
4 metadataPerItem = {},
5}metadataWhitelist, default{ 'type', 'registered' }. Metadata keys shown in the tooltip. Keys registered through ox_inventory'sdisplayMetadataare added on their own and need no entry here.showUnlisted, defaultfalse.trueshows every metadata key the item carries instead of the list above.metadataPerItem, default{}. Per item override:['note'] = { 'author' }adds keys for that item,trueshows all of them,falseshows none.
These keys are rendered elsewhere in the tooltip and are left out of the metadata list: description, image, imageurl, label, weight, durability, degrade, serial, ammo, components, rotated, source. A key whose value is empty, or is itself a table, is left out as well, whitelisted or not.
Accent colour, interface scale, background opacity, panel positions and the HUD position, style and scale are saved on the player's own machine. The values above are what a player who has changed nothing starts with. Hud.locked takes the HUD back under owner control.
Item fields
Grid size, rarity, category and stack cap are set per item in data/items.lua, and from the item editor in the admin panel.
widthandheight: cells the item takes in the grid. Set both or neither: if either one is missing or is not a number, the item is 1 by 1.grid: shorthand for the two above, written as'2x1'. On ammo, weapon components and tints only the width is taken and the height stays 1.maxstock: how many units fit in one slot. Without it a slot holds any amount of that item.rarity:common,uncommon,rare,epicorlegendary. Defaults tocommon, and drives the slot colour and the rarity sort.category: the tab the item falls into. Defaults tomisc.description: the text under the item name in the tooltip.{key}in the text is replaced with the value of that metadata key, and adescriptionin the item metadata wins over the one in the definition. The text is rendered with**bold**,*italic*, lines starting with-or*as bullets, and line breaks kept.portions: number of servings the item is used in, from 2 to 20. The item goes into the hand instead of being consumed at once, each use takes one serving and applies its share of the item's status effects. Ignored on weapons, ammo, weapon components and tints.use:food,drinkorsmoke. Sets the action label and the wording of the portions line in the tooltip. Without it the kind is read from the status effects the item applies.decayandreturndecay: withdecayset andreturndecaynaming another item, one unit of that item is added to the inventory when the durability timer runs out.
ox_inventory's own item fields keep their meaning, displayMetadata included.
ox_inventory settings
Every inventory: convar you already set keeps its normal meaning.
On qb-core, set setr inventory:framework "qbx" in server.cfg. ox_inventory only accepts esx, nd, ox or qbx in that convar, and reads its database table names from it. With qbx set, qb-core support loads whenever qb-core is running and qbx_core is not. The server prints a warning at boot when qb-core runs with any other value.
The grid is the exception. inventory:slots, inventory:gridcols, inventory:gridrows, inventory:secondarygridcols, inventory:dropcols and inventory:dropslots are written at boot from micio/config/grid.lua, so a line for any of them in server.cfg has no effect.
inventory:imagepath and inventory:screenblur are only given a value when you have not set one: an unset inventory:screenblur is written as false. Setting it true while the character preview is on blurs the preview with the rest of the frame, and the server says so at boot. Pointing inventory:imagepath at a resource that is not on the server is also reported at boot: item icons go missing there and in every other script that reads the convar.
Use setr for a convar the interface reads and set for server only values such as webhooks and loot tables. A client facing convar written with plain set never reaches the client, which then falls back to its built in default with no error anywhere.
Language
The inventory reads its own strings from micio/translations/.
1MicioConfig.Language = 'auto'Language, default'auto'. Follows theox:localeconvar. Set a language code present inmicio/translations/to force one regardless of the convar.
1setr ox:locale "en"ox_inventory's own messages keep coming from its locales/ folder.
ML Clothing reads its in game strings from its own locales/ folder, and 'auto' follows the same convar.
1Config.Language = 'auto'Config.Language, default'auto'. Follows theox:localeconvar, for the in game messages and for the admin panel alike. Set a language code present inlocales/to force one regardless of the convar.
ML Clothing configuration
General
1Config.Debug = falseConfig.Debug, defaultfalse. Prints diagnostic lines to the console. Keep itfalsein production.
Notifications
Each entry toggles one player message. Set an entry to false to suppress it.
1Config.Notifications = {
2 outfit_updated = true,
3 clothing_slot_occupied = true,
4 plate_inserted = true,
5 bag_item_blocked = true,
6}outfit_updated, defaulttrue. Tells the player the worn outfit was saved.clothing_slot_occupied, defaulttrue. Tells the player an item was refused because the clothing slot it belongs to is taken.plate_inserted, defaulttrue. Tells the player an armor plate went into the carrier.bag_item_blocked, defaulttrue. Tells the player an item was refused entry into a bag by the bag blacklist.
Bags
1Config.BagEffect = true
2
3Config.Bag = {
4 DefaultWeight = 5000,
5 DefaultCols = 3,
6 DefaultRows = 3,
7
8 SpeedTable = {
9 { 0, 1.00 },
10 { 5, 0.97 },
11 { 10, 0.93 },
12 { 15, 0.88 },
13 { 18, 0.82 },
14 { 27, 0.75 },
15 { 36, 0.65 },
16 { 40, 0.55 },
17 },
18}Config.BagEffect, defaulttrue. A worn bag slows the player down by the weight it carries.Config.Bag.DefaultWeight, default5000. Bag capacity in grams used when the worn bag drawable has no entry inConfig.BagSizes.Config.Bag.DefaultCols, default3. Columns of the bag grid used with that default weight.Config.Bag.DefaultRows, default3. Rows of the bag grid used with that default weight.Config.Bag.SpeedTable: pairs of{ weight_kg, speed_multiplier }, interpolated linearly from the weight the bag carries.0kg gives full speed,40kg gives0.55.
Bag sizes
1Config.BagSizes = {
2 female = {
3 [111] = { weight = 10000, cols = 4, rows = 4},
4 [125] = { weight = 15000, cols = 6, rows = 4},
5 },
6 male = {
7 [111] = { weight = 15000, cols = 6, rows = 4},
8 [113] = { weight = 10000, cols = 4, rows = 4},
9 },
10}Config.BagSizes: maps the drawable index of the worn bag, per gender, to a stash size. Each entry setsweightin grams,colsandrows. A drawable with no entry falls back toConfig.Bag.DefaultWeightand the default grid. The file ships a long table formaleandfemale. The block above is an extract. Edit, add or remove indices to match your bag models.
Armor plates
1Config.SyncPlatesEveryHit = true
2Config.UseBrokenPlates = true
3Config.BrokenPlateItem = 'brokenplate'
4
5Config.HeavyDrawables = {
6 male = { 12, 13, 15, 18 },
7 female = { 22, 23, 25, 28 },
8}
9
10Config.Plates = {
11 ['heavyplate'] = 50,
12 ['lightplate'] = 25,
13 ['brokenplate'] = 0,
14}Config.SyncPlatesEveryHit, defaulttrue. Plate health is written back on every damage event, so plate wear survives a disconnect at the cost of more frequent writes.Config.UseBrokenPlates, defaulttrue. A plate that reaches zero health becomes the broken plate item.Config.BrokenPlateItem, default'brokenplate'. Item name used for a destroyed plate. It has to be a registered item.Config.HeavyDrawables: vest drawable indices, per gender, that make a plate carrier a heavy carrier. A heavy carrier holds two plates, any other carrier holds one, and the carrier stash is sized to match. Movement is not affected by this list.Config.Plates: maps each plate item name to its armor value. A new plate is created with that value as its health, clamped to 50, so a value above 50 has no extra effect. The armor a carrier grants is the sum of the health of the plates inside it, capped at 100: two 50 point plates in a heavy carrier fill the bar.
Clothing items
1Config.ClothingItems = {
2 hat = { slot = 11, type = 'prop', componentId = 0 },
3 undershirt = { slot = 12, type = 'component', componentId = 8 },
4 jacket = { slot = 13, type = 'component', componentId = 11 },
5 bodyarmor = { slot = 14, type = 'component', componentId = 9 },
6 gloves = { slot = 15, type = 'component', componentId = 3 },
7 pants = { slot = 16, type = 'component', componentId = 4 },
8 shoes = { slot = 17, type = 'component', componentId = 6 },
9 mask = { slot = 18, type = 'component', componentId = 1 },
10 glasses = { slot = 19, type = 'prop', componentId = 1 },
11 earrings = { slot = 20, type = 'prop', componentId = 2 },
12 chain = { slot = 21, type = 'component', componentId = 7 },
13 bracelet = { slot = 22, type = 'prop', componentId = 7 },
14 watch = { slot = 23, type = 'prop', componentId = 6 },
15 bag = { slot = 24, type = 'component', componentId = 5 },
16 decals = { slot = 25, type = 'component', componentId = 10 },
17}Config.ClothingItems: the map from item name to inventory slot and ped component. Each entry has three fields.slot: the inventory slot the item locks into, unique per item. The shipped values run 11 to 25.type:'component'for a ped component,'prop'for a ped prop.componentId: the game component or prop index the item drives.Config.ClothesSlotID,Config.ValidSlotsPerItemandConfig.ComponentMappingare built from this table when the resource loads. Leave them alone.
bodyarmor uses slot 14 and drives the plate carrier. Do not remap it and do not add it to the wear system. Its durability comes from the plates inside it.
Default clothing
1Config.DefaultClothing = {
2 male = {
3 mask = { draw = 0, text = 0 },
4 hat = { draw = -1, text = -1 },
5 pants = { draw = 21, text = 0 },
6 shoes = { draw = 34, text = 0 },
7 },
8 female = {
9 pants = { draw = 15, text = 0 },
10 shoes = { draw = 35, text = 0 },
11 },
12}Config.DefaultClothing: the drawable and texture applied to a clothing slot when its item is removed, per gender.-1clears the component or prop. The file ships an entry for each of the 15 clothing slots in both genders. The block above is an extract.
Plate sync cooldown
1Config.AntiExploit = {
2 ArmorSyncCooldown = 150,
3}ArmorSyncCooldown, default150. Minimum milliseconds between two plate damage reports from the same player. Raise it on a server where players take hits in fast bursts, lower it only if plate wear feels late.
Stash prefixes
1Config.Stash = {
2 PlateCarrierPrefix = 'platecarrier_',
3 BagPrefix = 'playerbag_',
4}Config.Stash.PlateCarrierPrefix, default'platecarrier_'. Identifier prefix for plate carrier stashes.Config.Stash.BagPrefix, default'playerbag_'. Identifier prefix for bag stashes.
Both build unique stash identifiers. Leave them alone unless they collide with another resource, and change them only on a fresh database: existing stashes keep the old identifier.
Bag blacklist
1Config.BagBlacklist = {
2 enabled = true,
3 denyBagInsideBag = true,
4
5 items = {
6 },
7
8 prefixes = {
9 'blueprint_',
10 },
11}enabled, defaulttrue. Master switch for the filter.falseturns it off.denyBagInsideBag, defaulttrue. Refuses a bag item put inside another bag.items, default empty. Exact item names refused entry into a bag.prefixes, default{ 'blueprint_' }. Any item whose name starts with one of these strings is refused.
The filter runs when the item is moved into a bag. A match refuses the move and the item stays where it was. The message the player gets is toggled by Config.Notifications.bag_item_blocked.
Wear and decay
1Config.WearDecay = {
2 Enabled = true,
3 Time = '60m',
4 OnDepleted = 'break',
5 Notify = true,
6
7 Repairable = false,
8 RepairItem = 'repair_kit',
9 RepairCount = 1,
10 RepairAmount = 100,
11
12 Items = {
13 ['antirad_mask'] = {
14 time = '30m',
15 male = {
16 { component = 1, drawable = 244, texture = 0 },
17 { component = 1, drawable = 247, texture = 0 },
18 },
19 },
20 ['antirad_suit'] = {
21 time = '60m',
22 unisex = {
23 { component = 11, drawable = 660, texture = 0 },
24 { component = 11, drawable = 731, texture = 0 },
25 },
26 },
27 },
28}Enabled, defaulttrue. Master switch for the wear system. With it on, the pieces listed underItemslose durability while worn.Time, default'60m'. How long a piece lasts while worn. Takes a number with a unit suffix ('45s','30m','2h','1d') or a plain number, read as minutes. Entries without their owntimeuse this value.OnDepleted, default'break'. What happens at zero durability.'break'keeps the piece worn but broken, giving no protection, and flags it so other resources can react.'remove'takes it off instead.Notify, defaulttrue. Tells the player when a piece breaks.Repairable, defaultfalse. Withfalsea worn piece cannot be repaired with an item and the player equips a fresh one to get the protection back.RepairItem, default'repair_kit'. Item consumed to repair a worn piece.RepairCount, default1. How many of that item a repair consumes.RepairAmount, default100. Durability restored by one repair.Items: the pieces the wear system watches, keyed by a name of your choice. An entry can match by drawable, by item name, or by both. For drawables, listcomponent,drawableandtextureundermale,femaleorunisex. For item names, useitem = 'hazmat_suit', or a list of names. An entry may set its owntime, for example['work_gloves'] = { time = '30m', item = 'work_gloves' }. The repair defaults can be overridden per entry withrepairItem,repairCountandrepairAmount, andrepairItem = falsemakes that piece impossible to repair.
A fuller Items table, with entries matched by drawable, by item name, and with their own repair rules:
1Config.WearDecay.Items = {
2 ['gas_mask'] = {
3 time = '60m',
4 male = { { component = 1, drawable = 247, texture = 0 } },
5 female = { { component = 1, drawable = 247, texture = 0 } },
6 repairItem = 'mask_filter', repairCount = 2, repairAmount = 100,
7 },
8 ['hazmat_suit'] = {
9 time = '2h',
10 item = 'hazmat_suit',
11 repairItem = 'duct_tape', repairCount = 3, repairAmount = 50,
12 },
13 ['work_gloves'] = { time = '30m', item = 'work_gloves' },
14 ['dust_mask'] = { time = '10m', item = 'dust_mask', repairItem = false },
15}Repair happens when a player uses the repair item from the inventory: the most worn piece that uses that item is repaired, repairCount of the item is consumed and repairAmount durability comes back. In the table above a gas mask needs two mask filters, a hazmat suit needs three rolls of duct tape and only gets half its durability back, and a dust mask is thrown away when it breaks. Every repair item has to exist in data/items.lua:
1['repair_kit'] = { label = 'Repair Kit', weight = 500, stack = true, close = true },
2['mask_filter'] = { label = 'Mask Filter', weight = 100, stack = true, close = true },
3['duct_tape'] = { label = 'Duct Tape', weight = 100, stack = true, close = true },A broken piece is exposed to other resources through the ml_clothingBroken state bag, the wear exports and the OnGearBroken and OnGearRepaired hooks, all on the developer page.
An item the wear system manages must not also carry decay or degrade in your items file. Both write the same durability value.
Admin panel
The admin panel reads its own file.
1Config.AdminAce = nil
2Config.Command = 'invadmin'
3Config.OpenKey = nil
4Config.DefaultTheme = 'default'
5Config.MinimizeKey = 'F9'
6Config.ClothingCatalogUrl = 'http://127.0.0.1:3960/api/catalog'Config.AdminAce, defaultnil. An ACE permission that opens the panel. A player holding it passes the admin check. Leftnil, access falls back to the framework admin group.Config.Command, default'invadmin'. The chat command that opens the panel.Config.OpenKey, defaultnil. Key that opens the panel, for example'F7'. Set to a non empty string, a keybind is registered and each player can rebind it. Leftnil, the panel opens by command only.Config.DefaultTheme, default'default'. The panel theme a player starts on.Config.MinimizeKey, default'F9'. Shrinks the open panel to a pill and brings it back.Config.ClothingCatalogUrl, default'http://127.0.0.1:3960/api/catalog'. Endpoint the Clothing tab reads its catalog from. When the URL answers with anything other than a 200 and a JSON body, the Clothing tab shows an empty catalog.
1Config.RateLimit = {
2 list = 500,
3 get = 400,
4 save = 1500,
5 delete = 1500,
6 upload = 1500,
7 playerList = 500,
8 playerGet = 400,
9 playerGive = 800,
10 playerRemove = 800,
11 stashList = 500,
12 stashGet = 400,
13 stashSave = 1500,
14 stashDelete = 1500,
15 weapons = 500,
16 weapon_get = 400,
17 clothingImages = 150,
18 playerImages = 150,
19}Config.RateLimit: cooldown in milliseconds per panel action. Higher values throttle that action harder. The list and get actions run on every navigation, so raising those two is what makes the panel feel unresponsive.
1Config.Editor = {
2 MaxGrid = 5,
3 NamePrefix = 'custom_',
4 MaxImageBytes = 524288,
5}MaxGrid, default5. Largest width or height the item editor accepts.NamePrefix, default'custom_'. Prefix added to the name of an item created in the editor.MaxImageBytes, default524288. Largest item image the editor accepts, in bytes.
1Config.DiscordWebhook = {
2 Default = 'INSERT_WEBHOOK_LINK_HERE',
3 GiveItem = 'INSERT_WEBHOOK_LINK_HERE',
4 RemoveItem = 'INSERT_WEBHOOK_LINK_HERE',
5 ItemEdit = 'INSERT_WEBHOOK_LINK_HERE',
6 ShopEdit = 'INSERT_WEBHOOK_LINK_HERE',
7 InventoryEdit = 'INSERT_WEBHOOK_LINK_HERE',
8 ClothingGive = 'INSERT_WEBHOOK_LINK_HERE',
9}Config.DiscordWebhook: one webhook per action, so each kind of admin action can land in its own channel. An entry left on the placeholder falls back toDefault, and aDefaultleft on the placeholder turns that log off. A value is only used when it starts withhttp.