> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shdevelopment.org/llms.txt
> Use this file to discover all available pages before exploring further.

# sh-vehiclespawner: ACE-Gated Vehicle Spawner for FiveM

> sh-vehiclespawner is a categorized vehicle spawner menu with ACE permissions, per-category access control, and an optional global vehicle whitelist.

sh-vehiclespawner gives your server staff a clean, WarMenu-based in-game menu for spawning vehicles organized into named categories. Every category is gated behind its own ACE permission node, so you can give VIP players access to civilian cars while keeping bikes or emergency vehicles locked to staff. Version 1.0.4 also ships an optional global whitelist that intercepts the `entityCreating` server-side event and cancels any unauthorized spawn — including spawns triggered by vMenu or other third-party spawner resources.

## Requirements

sh-vehiclespawner depends on [warmenu](https://github.com/warxander/warmenu). Ensure `warmenu` is started **before** `sh-vehiclespawner` in your `server.cfg`.

<Warning>
  Do not rename the resource folder. The resource name must remain **`sh-vehiclespawner`** exactly. Renaming it breaks internal asset references and the global whitelist enforcement logic.
</Warning>

## Installation

<Steps>
  <Step title="Download and place the resource">
    Copy the `sh-vehiclespawner` folder into your server's `resources` directory alongside `warmenu`.
  </Step>

  <Step title="Import no SQL — none required">
    sh-vehiclespawner is stateless. There is no database schema to import.
  </Step>

  <Step title="Add to server.cfg">
    ```cfg server.cfg theme={null}
    ensure warmenu
    ensure sh-vehiclespawner
    ```
  </Step>

  <Step title="Configure config.lua">
    Open `sh-vehiclespawner/config.lua` and adjust the values described in the sections below.
  </Step>

  <Step title="Add ACE permission nodes">
    Grant the appropriate ACE nodes to your staff and player groups as shown in the [Permissions](#permissions) section.
  </Step>

  <Step title="Restart the resource">
    Run `refresh` then `restart sh-vehiclespawner` in the server console, or do a full server restart.
  </Step>
</Steps>

## Core Configuration

The table below covers the top-level options in `config.lua`. All values shown are the shipped defaults.

```lua config.lua theme={null}
Config.Debug                   = false  -- Enable debug prints to server console
Config.Keybind                 = 'F7'
Config.MenuTitle               = 'Vehicle Spawner'

-- Menu appearance (RGBA; set to nil to use WarMenu defaults)
Config.MenuBackgroundColor          = {r=0, g=0, b=0, a=160}
Config.MenuTitleColor               = {r=255, g=255, b=255, a=255}
Config.MenuTitleBackgroundColor     = nil   -- Set nil when MenuTitleBackgroundImage is used
Config.MenuTitleBackgroundImage     = {td = 'vehiclespawnmenu', name = 'menubg'}
Config.MenuTextColor                = {r=255, g=255, b=255, a=255}
Config.MenuFocusColor               = {r=255, g=255, b=255, a=100}
Config.MenuFocusTextColor           = {r=0, g=0, b=0, a=255}
Config.MenuWidth                    = nil   -- 0.0–1.0, nil = WarMenu default (~0.23)
Config.MenuX                        = 0.77  -- 0.0 = left edge, 1.0 = right edge

Config.CloseMenuOnVehicleSpawn = true   -- Auto-close the menu after spawning
Config.ReplacePreviousVehicle  = true   -- Delete the last spawned vehicle before spawning a new one
Config.SpawnInsideVehicle      = true   -- Warp the player into the driver seat on spawn
Config.SpawnOffset             = {x = 0.0, y = 5.0, z = 0.0}
Config.SpawnHeadingOffset      = 0.0   -- Additional heading offset in degrees
Config.MaxSpawnDistance        = 50.0  -- Cancel spawn if player moved more than this distance (0 = disabled)
Config.AllowCustomMods         = true  -- Apply mod definitions from Config.Vehicles on spawn
Config.EnableGlobalWhitelist   = true  -- Block whitelisted vehicles spawned from ANY resource

-- Notification system
Config.NotifySystem  = 'sh-notify'  -- 'mythic_notify' | 'ox_lib' | 'sh-notify' | nil (print fallback)
Config.NotifyType    = 'error'
Config.DenyMessage   = "No permission to open menu! Check permissions."
```

<Tip>
  Set `Config.MaxSpawnDistance` to a non-zero value on public or semi-public servers to prevent players from queuing a spawn, moving to a restricted area, and exploiting the teleport.
</Tip>

The menu opens with the **F7** key by default. Players can remap this in the GTA V pause menu under **Settings → Key Bindings → FiveM**.

## Permissions

<Tabs>
  <Tab title="config.lua">
    Enable permission checking and define which ACE node controls each category. Setting a category's permission to `nil` makes that category open to anyone who can open the menu.

    ```lua config.lua theme={null}
    Config.EnablePermissions       = true
    Config.OpenPermission          = 'vehiclespawner.open'
    Config.AllCategoriesPermission = 'vehiclespawner.all'

    Config.CategoryPermissions = {
        cars  = nil,                    -- No permission required for this category
        bikes = 'vehiclespawner.bikes', -- Requires this ACE node
        -- Add entries for any additional categories you define
    }
    ```
  </Tab>

  <Tab title="server.cfg">
    Grant nodes to the relevant groups in `server.cfg`. The example below gives admins full access and VIP players access to the cars category only.

    ```cfg server.cfg theme={null}
    add_ace group.admin vehiclespawner.open  allow
    add_ace group.admin vehiclespawner.all   allow

    add_ace group.vip   vehiclespawner.open  allow
    # cars has nil permission — no extra node needed for VIP to see cars
    ```
  </Tab>
</Tabs>

<Note>
  `vehiclespawner.all` overrides all category-level permission checks. Grant it only to trusted staff who should see every category regardless of individual category nodes.
</Note>

## Defining Vehicles

Vehicles are organized in `Config.Vehicles` as a list of category objects. Each category has a `name` (used as the permission key in `Config.CategoryPermissions`) and a `list` of vehicle entries. The category `name` must match its key in `Config.CategoryPermissions` exactly, or permission checks will not work.

```lua config.lua theme={null}
Config.Vehicles = {
    { name = "cars", list = {
        { label = "Adder", value = "adder", mods = {
            primaryColor   = 12,
            secondaryColor = 12,
            livery         = 0,
            engine         = 3,
            brakes         = 2,
            turbo          = true,
        }},
        { label = "Comet",  value = "comet2", mods = { primaryColor = 147, secondaryColor = 147, engine = 3 } },
        { label = "Elegy",  value = "elegy2", mods = { primaryColor = 0, secondaryColor = 0, suspension = 3 } },
    }},
    { name = "bikes", list = {
        { label = "Bati 801",  value = "bati",     mods = { primaryColor = 88, engine = 3 } },
        { label = "Hakuchou",  value = "hakuchou" },
        { label = "PCJ 600",   value = "pcj",      mods = { primaryColor = 3, secondaryColor = 3 } },
    }},
    -- Add more categories as needed (trucks, planes, etc.)
}
```

The `mods` table is optional per entry. When `Config.AllowCustomMods = true`, every key in `mods` is applied to the vehicle immediately after it spawns.

### Supported Mod Keys

| Key              | Type    | Range / Notes                |
| ---------------- | ------- | ---------------------------- |
| `primaryColor`   | integer | 0 – 159 (GTA color index)    |
| `secondaryColor` | integer | 0 – 159                      |
| `livery`         | integer | 0 = default; varies by model |
| `engine`         | integer | 0 – 3 (stock → race)         |
| `brakes`         | integer | 0 – 2 (stock → race)         |
| `transmission`   | integer | 0 – 2 (stock → race)         |
| `suspension`     | integer | 0 – 3 (stock → lowered race) |
| `turbo`          | boolean | `true` = install turbo       |

## Global Vehicle Whitelist

When `Config.EnableGlobalWhitelist = true`, sh-vehiclespawner registers a server-side `entityCreating` hook. Any time a vehicle entity is about to be created, the hook checks whether the spawning player holds the required ACE permission for that vehicle model. If they do not, the spawn is cancelled — regardless of which resource triggered it.

This means a player with vMenu, a custom spawner, or a Lua executor cannot bypass your whitelist simply by using a different menu.

<Warning>
  The global whitelist applies to **all** resources on the server, not just sh-vehiclespawner. Test your other vehicle-related scripts (mechanic shops, job vehicles, etc.) after enabling this feature to ensure those spawns carry the correct principal or are explicitly excluded in config.
</Warning>

## Notification System

sh-vehiclespawner supports four notification backends. Set `Config.NotifySystem` to one of the following strings, or `nil` to fall back to a console print.

<Accordion title="Supported notification resources">
  | Value             | Resource                                     |
  | ----------------- | -------------------------------------------- |
  | `'mythic_notify'` | mythic\_notify                               |
  | `'ox_lib'`        | ox\_lib                                      |
  | `'sh-notify'`     | sh-notify                                    |
  | `nil`             | Console fallback (no on-screen notification) |
</Accordion>
