> For the complete documentation index, see [llms.txt](https://uniqers-scripts-docs.gitbook.io/uniqers-scripts-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://uniqers-scripts-docs.gitbook.io/uniqers-scripts-docs/uniqers-trunk.md).

# uniqers-trunk

How to install and all exports infos.

<figure><img src="https://1436200110-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZO8XqahJMWr9lDZTL9c1%2Fuploads%2F3DlMad5vj80kuzEOVHFq%2FAdvanced_trunk_system_script_thu%E2%80%A6_2K_20261011180950.jpg?alt=media&amp;token=2db8bfbb-2008-4356-a6c5-e45f5d40667c" alt=""><figcaption></figcaption></figure>

## uniqers-trunk: Advanced Vehicle Trunk for FiveM

See exactly what is inside a trunk. Every item a player puts in becomes a real 3D prop that sits on the trunk floor, and every player around sees the same thing in the same spot. Players place items by hand with real physics, hide inside trunks, cover pickup beds with tarps, pick locked trunks with a pin-tumbler minigame and store outfits. It all runs with any framework, inventory, target, garage and dispatch script.

* **Frameworks:** QBCore, Qbox, ESX, ND\_Core, ox\_core, standalone (auto-detected)
* **Inventories:** works with every inventory (see Inventory compatibility)
* **Interaction:** ox\_target, qb-target or the built-in 3D text prompts (no target needed)
* **Languages:** English, Turkish, German, French, Spanish
* **Performance:** steady **0.00 ms** resmon: idle, with a loaded trunk and with the tarp on (details)

***

### Table of contents

1. Requirements
2. Installation
3. How it works
4. Configuration
5. Owned vehicles only
6. Garages
7. Hiding in the trunk
8. Lockpicking and police alerts
9. Tarps and the tarp shop
10. Outfits
11. Item props and amount tiers
12. Admin panel
13. Addon vehicles
14. Inventory compatibility
15. Exports and events
16. Performance
17. FAQ and troubleshooting

***

### Requirements

|                      |                                                                                          |
| -------------------- | ---------------------------------------------------------------------------------------- |
| **OneSync**          | Required (Legacy or Infinity)                                                            |
| **Framework**        | QBCore, Qbox, ESX, ND\_Core, ox\_core, or none                                           |
| **Database**         | oxmysql or mysql-async *recommended*. Without one, data is kept in JSON files in `data/` |
| **screenshot-basic** | Optional, only for vehicle photos in the admin panel                                     |
| **Target**           | Optional: ox\_target or qb-target. Without one, 3D text prompts are used                 |

There is no SQL file to import. Every table the script needs is created on the first start.

***

### Installation

1. Put the `uniqers-trunk` folder into your `resources` folder.
2. Add it to `server.cfg` **after** your framework, database, inventory and target:

   ```cfg
   ensure oxmysql
   ensure qb-core            # or es_extended / qbx_core / ND_Core / ox_core
   ensure ox_inventory       # your inventory
   ensure ox_target          # optional
   ensure uniqers-trunk
   ```
3. Give your admins access to the admin panel:

   ```cfg
   add_ace group.admin uniqers.admin allow
   ```

   Framework admin groups (`admin`, `superadmin`, `god`) also work, see `Config.Admin.Groups`.
4. Open `config/config.lua` and choose your language:

   ```lua
   Config.Locale = 'en'   -- 'en' | 'tr' | 'de' | 'fr' | 'es'
   ```
5. Restart the server. The console prints what was detected:

   ```
   [uniqers-trunk] Framework: qb
   [uniqers-trunk] Inventory: ox_inventory | storage: ox | player: ox
   [uniqers-trunk] Lockpick alert: ps-dispatch
   ```

That is all. No items have to be added to your inventory, and no other resource has to be edited.

***

***

### Configuration

All settings are in `config/`. Every option has an English comment next to it.

| File                    | What is in it                                                                                                            |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `config/config.lua`     | General settings, open mode, placement, police, webhooks, storage, garages, tarp, hiding, admin, HUD, capacity per class |
| `config/items.lua`      | Which prop is shown for which item, amount tiers                                                                         |
| `config/vehicles.lua`   | Per-vehicle overrides, front trunks, blacklist, job-restricted vehicles                                                  |
| `config/lockpick.lua`   | Lockpick minigame, difficulty levels, police alerts / dispatch                                                           |
| `config/outfits.lua`    | Outfit system                                                                                                            |
| `config/animations.lua` | Put / take animations, highlight, item labels                                                                            |
| `locales/*.lua`         | All texts in five languages                                                                                              |

#### The most used options

```lua
Config.Framework  = 'auto'     -- 'auto' | 'esx' | 'qb' | 'qbx' | 'nd' | 'ox' | 'none'
Config.Inventory  = 'auto'     -- 'auto' | 'ox_inventory' | 'qb-inventory' | 'qs-inventory' | 'builtin'
Config.Target     = 'auto'     -- 'auto' | 'ox_target' | 'qb-target' | 'drawtext'
Config.Appearance = 'auto'     -- 'auto' | 'native' | 'illenium-appearance' | 'fivem-appearance' | 'qb-clothing' | 'skinchanger'

Config.OpenMode   = 'focus'    -- 'focus': camera + custom UI | 'inventory': opens the inventory stash
Config.ShowProps  = 'lid'      -- 'always' | 'lid' | 'open'
Config.CheckLock  = true       -- locked vehicles cannot be opened
Config.RenderDistance = 20.0   -- props are visible within this distance

Config.CapacityMode = 'both'   -- 'weight' | 'slots' | 'both'
Config.TrunkSpace = {          -- per vehicle class: slots, weight (grams), size
    [1] = { enabled = true, slots = 30, weight = 60000, size = vector3(1.00, 0.75, 0.40) },  -- Sedans
    -- ...
}

Config.HUD.Accent = '#FDCB02'  -- main UI color for the whole interface
```

#### Open modes

* **`'focus'` (default):** the camera frames the trunk and the player works with the mouse. Hover an item to highlight it, click it for a menu (take, move, wear, inspect), press **+** to put something in. A 3D HUD shows weight and slots, and small cards above each prop show the item names.
* **`'inventory'`:** the classic way. The inventory's stash opens, and the props still appear in the trunk.

#### Placing items

With `Config.Placement.Mode = 'free'` the item appears as a ghost that follows the mouse. Physics is solved while you move it. The ghost already shows the exact pose the item will rest in, it turns green only when it really fits, and one click puts it there.

| Key                             | Action                                        |
| ------------------------------- | --------------------------------------------- |
| Mouse wheel                     | Rotate (hold **SHIFT** for fine steps)        |
| **R**                           | Stand the item upright / lay it down          |
| **CTRL** + wheel, **+** / **-** | Zoom toward the item                          |
| **W A S D** / arrows            | Move the view around long beds and box trucks |
| Middle mouse                    | Reset the view                                |
| **F**                           | Inspect mode                                  |

Items sit on the real surface of the items below them. If the support is too narrow they tip or slide, and when the item underneath is taken the one on top settles down. Items never float and never disappear: when the floor is full they go to the next layer.

***

### Owned vehicles only

`Config.Storage.NonOwnedMode` decides what happens with vehicles that are not owned by anyone (NPC cars, stolen street cars):

| Value        | Behaviour                                                                                     |
| ------------ | --------------------------------------------------------------------------------------------- |
| `'persist'`  | Every vehicle has a normal, permanent trunk (default)                                         |
| `'session'`  | Non-owned vehicles have a trunk, but it is wiped on server restart                            |
| `'disabled'` | **Only owned vehicles have a trunk.** Non-owned vehicles cannot be opened, searched or picked |

With `'disabled'` you choose what still works on non-owned vehicles:

```lua
Config.Storage = {
    NonOwnedMode = 'disabled',
    NonOwnedAllow = {
        Hide  = true,   -- players can still hide inside the trunk
        Cover = true,   -- the bed can still be covered with a tarp
    },
}
```

Ownership is checked on the server by plate, in `player_vehicles` (QBCore / Qbox) or `owned_vehicles` (ESX). If your garage uses another table, set `OwnedTable` and `OwnedColumn`. The result is cached on the vehicle (state bag), so each vehicle is checked only once, not every frame while a target menu is open. A vehicle bought after it was checked shows as owned within 30 seconds.

***

### Garages

The trunk follows the **plate**, so it works with every garage script without any edits (qb-garages, jg-advancedgarages, cd\_garage, okokGarage, esx\_garage and others): anything that spawns the vehicle again with its plate.

When any script spawns a vehicle, its plate is looked up and the items, the position of every prop and the tarp come back right away. When a vehicle is deleted (parked), anyone looking into that trunk is closed out and a player hiding inside climbs out.

```lua
Config.Garage = {
    Enabled    = true,   -- restore props and tarp when a vehicle spawns
    SaveCover  = true,   -- keep the tarp across server restarts
    EjectHider = true,   -- a hiding player climbs out when the vehicle is parked
}
```

For a custom garage the exports below give a cleaner hand-off (optional):

```lua
-- client
exports['uniqers-trunk']:VehicleStoring(vehicle)   -- before DeleteEntity
exports['uniqers-trunk']:VehicleSpawned(vehicle)   -- after the vehicle and its props are set

-- server
exports['uniqers-trunk']:VehicleStored(netIdOrEntity)
exports['uniqers-trunk']:VehicleSpawned(netIdOrEntity)
```

If a script changes plates (fake plates, plate changers), call `exports['uniqers-trunk']:MoveTrunk(oldPlate, newPlate)` and the trunk moves with it.

***

### Hiding in the trunk

Players can climb into any trunk that fits a person (sedans, SUVs, vans, pickup beds, box trucks). The size is measured from the real trunk of each vehicle, and there must be room between the items.

* The character walks to the back, opens the lid and climbs in. A low trunk is entered from behind, a high bed is climbed onto. The animation adapts to every vehicle.
* Inside: **E** gets out, **H** cracks the lid open to look outside. On an open bed **H** pulls the tarp back a little at the head.
* A locked trunk cannot be opened from inside. Holding **H** kicks it open (`KickOpen`).
* On an open bed a tarp is pulled over automatically (`AutoTarp`).
* Anyone who opens the trunk sees the hider and can pull them out.
* If the vehicle is parked or destroyed, the hider is ejected.

Everything is in `Config.Hide`.

***

### Lockpicking and police alerts

A locked trunk shows **Pick Trunk Lock** when the player has the lockpick item (`Config.Lockpick.Item`, empty = no item needed).

The minigame is a cutaway pin-tumbler lock with springs, driver pins and key pins. Hold the tension, find the binding pin and lift it to the shear line until it clicks. Spool pins false-set, serrated pins give fake clicks, too much tension wears the pick and an overset pin has to be dropped.

```lua
Config.Lockpick = {
    Item       = 'lockpick',
    Picks      = 3,
    Difficulty = 'medium',     -- 'easy' | 'medium' | 'hard' | 'expert' | 'class'
    ClassLevel = { [7] = 'expert', [6] = 'hard', ... },  -- used with 'class'
}
```

A broken lock stays broken for everyone (state bag) until a mechanic repairs it (`RepairTrunkLock` export).

#### Built-in dispatch support

`Config.Lockpick.Alert.Dispatch = 'auto'` finds your dispatch script and sends the alert to it:

| Dispatch        |                                                         |
| --------------- | ------------------------------------------------------- |
| ps-dispatch     | ✔                                                       |
| cd\_dispatch    | ✔                                                       |
| qs-dispatch     | ✔                                                       |
| rcore\_dispatch | ✔                                                       |
| tk\_dispatch    | ✔                                                       |
| codem-dispatch  | ✔                                                       |
| lb-tablet (MDT) | ✔                                                       |
| none of them    | built-in alert: notification + flashing blip for `Jobs` |
| anything else   | `Dispatch = 'custom'` and your own function             |

```lua
Alert = {
    Enabled  = true,
    Chance   = 0.5,                 -- 50% of attempts call the police
    Dispatch = 'auto',
    Jobs     = { 'police', 'sheriff' },
    Code     = '10-60',
    Custom   = function(src, data)
        -- data = { coords, plate, jobs, code, title, message, blip = { sprite, colour, scale, time } }
    end,
},
```

The server event `uniqers-trunk:lockpickAlert` (src, coords, plate) is also triggered on every alert.

#### Police search

Police jobs (`Config.Police.Jobs`) get a **Search Trunk** option. With `ReadOnly = true` they can only look and cannot take items. `BypassLock = true` lets them open locked trunks.

***

### Tarps and the tarp shop

Pickup and flatbed beds are open, so anyone can see what is in them. A tarp hides the contents.

* **The resource's own streamed tarp model** with straps, stitched edges and rings. It is attached to the vehicle and sized to the cargo by a size animation, so it costs nothing per frame, parked or driving.
* Items under the tarp are not loaded at all, so nobody can see or reach them.
* **Tarp shop** (trunk screen → TARP): free plain colors, ready-made designs (camo, desert, urban, carbon, stripes, plaid) and **custom tarps from any image link**. The server finds the image on the page (imgur, prnt.sc, Pinterest and others).
* Bought tarps belong to the player and can be used on every vehicle.
* If the vehicle explodes, the tarp burns and the props disappear. The items are kept.

Prices, accounts and limits are in `Config.Cover.Shop`.

***

### Outfits

Outfits do not need an inventory item.

* **Store outfit:** the clothes come off the character (left in underwear), and a folded clothes prop is placed in the trunk where the player wants it. The player names the outfit.
* **Wear:** puts the outfit on and removes it from the trunk. If the player is dressed, they are asked first. Undressing and dressing are animated, and the camera shows the character from the front.
* Clicking an outfit shows its parts (top, pants, shoes...) with images.
* The new look is saved to your clothing script: illenium-appearance, fivem-appearance, qb-clothing, skinchanger (esx\_skin), or native.

Everything is in `config/outfits.lua`.

***

### Item props and amount tiers

* **Automatic props:** weapons use their real world model. Other items are matched by keyword (`Config.PropByKeyword`), and everything else gets `Config.DefaultProp`.
* **Your own mapping:** `config/items.lua`, or in game with `/trunkitems`.
* **Amount tiers:** an item can change its prop with the amount. Money goes from a single banknote to a stack, a pile and a cash case. Ammo goes from a small pack to a crate. Tiers can be edited in the admin panel too.
* Items are laid down naturally (the thinnest side up), and items that can stand on their own base stay upright.

```lua
Config.Items = {
    ['water']  = { model = 'prop_ld_flow_bottle', stack = true },
    ['cash']   = { tiers = {
        { min = 1,       model = 'p_banknote_onedollar_s' },
        { min = 10000,   model = 'hei_prop_heist_cash_pile' },
        { min = 5000000, model = 'prop_cash_case_01' },
    } },
}
```

***

### Admin panel

`/trunkadmin` opens one panel for everything (needs the `uniqers.admin` ace or an admin group).

| Tab          | What you can do                                                                                                                                                |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **VEHICLES** | Every vehicle on the server and the state of its trunk data. Filter vehicles without data, take photos                                                         |
| **STUDIO**   | One vehicle's trunk: trunk yes / no, door, box, floor area, raised parts (wheel arches, steps), camera, capacity, extras                                       |
| **ITEMS**    | Which prop is shown for which item, amount tiers, prop images. **CATALOG** lists every prop in the game that fits in a trunk (\~13,800) with images and search |
| **CLOTHES**  | The clothing catalog with names and images used for outfit parts, including addon clothes                                                                      |

The studio spawns a private copy of the vehicle in its own dimension (only you see it), with daylight and lights. Settings are saved on the server (`data/admin_data.json`) and apply to everyone right away. Your config files are not touched.

| Command        |                                                    |
| -------------- | -------------------------------------------------- |
| `/trunkadmin`  | Admin panel                                        |
| `/trunkitems`  | Admin panel on the ITEMS tab                       |
| `/trunkdebug`  | Studio of the nearest vehicle                      |
| `/trunkarea`   | Studio + draw the trunk area by hand               |
| `/trunkstudio` | Prints your position to use as the studio location |
| `/covertrunk`  | Cover / uncover the nearest bed                    |
| `/storeoutfit` | Store the outfit you wear (trunk open)             |

All command names can be changed in the config.

***

***

### Inventory compatibility

| Inventory                                                                                             | Where the trunk is stored                               |
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| ox\_inventory                                                                                         | ox stash                                                |
| qb-inventory (new, 2024+)                                                                             | qb's own trunk storage                                  |
| qb-inventory (old), ps-inventory, lj-inventory, jpr-inventory                                         | `stashitems`                                            |
| qs-inventory                                                                                          | qs stash                                                |
| **Everything else:** codem, origen, core\_inventory, tgiann, ak47, jaksam, chezza, mf, ESX default... | **Built-in storage** (own table, created automatically) |

With built-in storage the items are taken from and given to the player through the framework (`AddItem` / `addInventoryItem`), which every inventory supports. Item images are found automatically for most inventories. If yours does not show any, set `Config.ItemImages = 'nui://your_inventory/html/images/%s.png'`.

#### The inventory's own trunk key

qb-inventory and ox\_inventory open **their own** trunk when TAB is pressed behind a vehicle. With `Config.InventoryTrunk.TakeOver = true` that key opens the uniqers-trunk trunk instead, so there are never two separate trunks. The glovebox and the normal inventory stay the same. With qb-inventory, `Share = true` keeps the contents in qb's own trunk storage, so items players already had are not lost.

***

### Exports and events

```lua
-- server
exports['uniqers-trunk']:GetTrunkItems(plate)
exports['uniqers-trunk']:AddTrunkItem(plate, item, count)
exports['uniqers-trunk']:GetStashId(plate)
exports['uniqers-trunk']:IsHidingInTrunk(src)
exports['uniqers-trunk']:KickFromTrunk(src)
exports['uniqers-trunk']:IsTrunkLockBroken(netId)
exports['uniqers-trunk']:BreakTrunkLock(netId)
exports['uniqers-trunk']:RepairTrunkLock(netId)
exports['uniqers-trunk']:VehicleStored(netIdOrEntity)
exports['uniqers-trunk']:VehicleSpawned(netIdOrEntity)
exports['uniqers-trunk']:GetTrunkSnapshot(plate)
exports['uniqers-trunk']:ApplyTrunkSnapshot(plate, snapshot)
exports['uniqers-trunk']:MoveTrunk(oldPlate, newPlate)
exports['uniqers-trunk']:ClearTrunk(plate)
exports['uniqers-trunk']:IsTrunkCovered(plate)
exports['uniqers-trunk']:SetTrunkCovered(plate, true, 'khaki')

-- client
exports['uniqers-trunk']:VehicleStoring(vehicle)
exports['uniqers-trunk']:VehicleSpawned(vehicle)

-- close the trunk UI of a player from another resource
TriggerClientEvent('unq_trunk:forceClose', src)

-- server event you can listen to (every lockpick police alert)
AddEventHandler('uniqers-trunk:lockpickAlert', function(src, coords, plate) end)

-- server events you can trigger instead of the garage exports
TriggerEvent('uniqers-trunk:vehicleStored', netIdOrEntityOrPlate)
TriggerEvent('uniqers-trunk:vehicleSpawned', netIdOrEntityOrPlate)
```

#### Discord webhooks

`Config.Webhook` logs lock breaks, police searches, custom tarp purchases (who and which image link) and players hiding in or being pulled out of trunks.

***

### Performance

Measured with resmon in game:

| Situation                                   | resmon      |
| ------------------------------------------- | ----------- |
| Idle (no trunk in use)                      | **0.00 ms** |
| Next to a loaded trunk (item props visible) | **0.00 ms** |
| Next to a loaded, covered (tarp) bed        | **0.00 ms** |
| Driving a loaded, covered pickup            | **0.00 ms** |
| Using the trunk screen (camera, cards, HUD) | 0.16 ms     |

The script is built for big servers:

* **No networked entities.** Props are local objects. The server only sends data.
* **Nothing runs when nothing happens.** Idle loops are taken out of the scheduler completely and wake up only when something happens (a trunk opens, a placement or hide starts, a vehicle with trunk data comes close). Away from trunks the only work left is one vehicle scan every 2 seconds. Per-frame work only happens while a trunk is open in front of you.
* **State bag reads are cached** and refreshed by change handlers, so target menus that check options every frame do not touch the network layer.
* **Props are created over several frames** (8 per frame), so a full truck bed never causes a hitch, and the work is cancelled safely when you drive away.
* **The server syncs only open trunks**, slows down when the contents do not change, and syncs instantly through the ox\_inventory `swapItems` hook.
* **Duplicate pushes are skipped:** a vehicle is not updated again when its contents and tarp are the same.
* **Ownership and stash reads are cached**, so there are no repeated database queries.
* **Zero-cost tarp.** GTA resets the scale of attached props, so a scaled tarp normally has to be moved by the script every frame (\~0.03 ms while driving). This tarp is a skinned model attached to the vehicle; its size comes from a size animation (5 cm steps), so there is no per-frame work, parked or driving.

Settings that matter on very busy servers:

```lua
Config.RenderDistance = 20.0            -- lower = fewer props around you
Config.MaxVisibleProps = 60             -- props per trunk
Config.ShowProps = 'lid'                -- 'open' draws props only while a trunk is used
Config.ShowOpenTrunks.MaxPerScan = 6    -- open beds asked per scan
Config.Cover.Mode = 'model'             -- keep the model tarp ('poly' costs more)
```

Measure with `resmon`: idle, with a trunk open, and next to covered pickups.

***

### FAQ and troubleshooting

**Items float or sink on an addon vehicle.** Run the addon vehicle scanner, or set the floor in `/trunkadmin` → STUDIO.

**"This inventory does not support this action."** The item is usually not defined in your inventory's item list. Inventories silently reject unknown items. Add the item to your inventory.

**Two different trunks on the same vehicle.** Keep `Config.InventoryTrunk.TakeOver = true` (qb-inventory / ox\_inventory). With the old qb-inventory, ps, lj or qs-inventory, turn off that inventory's own trunk key in its config.

**A garage vehicle comes back with an empty trunk.** The garage must spawn the vehicle with the same plate (all common garages do). If you use `NonOwnedMode = 'session'` or `'disabled'`, set `Config.Storage.OwnedTable` when your garage does not use `player_vehicles` / `owned_vehicles`.

**The trunk of a vehicle does not open.** Check `Config.TrunkSpace[class].enabled`, `Config.Blacklist`, `Config.JobRestricted` and `Config.CheckLock`. With `Config.Debug = true` the reason is printed in F8.

**Which language / color?** `Config.Locale` and `Config.HUD.Accent`. Every text is in `locales/`.

***

Support & Updates:

Encountered a bug or need help configuring a custom framework? Join our community!

## Support & Updates & Questions

<div align="left"><figure><img src="https://1436200110-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZO8XqahJMWr9lDZTL9c1%2Fuploads%2F6U1vJg05XehtFcmGXsMW%2F3670325.png?alt=media&amp;token=603ba3cd-283e-42c5-a0e2-13d33fefb5bd" alt="https://discord.gg/MyrGhbf9tM" width="128"><figcaption></figcaption></figure></div>

\
<https://discord.gg/MyrGhbf9tM>
