# <img src="/images/gunrack.webp" /> Weapon storage
Documentation relating to the jo_gunrack.

:::: tabs
::: tab BUY
[Buy the script](https://jumpon-studios.com/fivem/weapon-storage)
:::

::: tab PREVIEW
<iframe width="560" height="315" src="https://www.youtube.com/embed/wN7W2RE8r4M?si=o_3URKrSNJNL9wKc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
:::
::::

## 1. Installation
Be sure you installed the required dependencies :
- For ESX : [ox_target](https://github.com/overextended/ox_target/tree/main)
- For QBCore : qb_target

To install jo_gunrack:
- Drag and drop the resource into your resources folder
  - jo_gunrack 
- Add this ensure in your server.cfg
  - `ensure jo_gunrack`
Congratulation, the **Weapon storage** script is ready to be used!

## 2. Usage
Go to one of the locations to see the weapon storage. Press the 3rd eye key to interact with it.

## 3. Script configuration
The configuration file is `config.lua` in the resource root. **Do not edit this file directly** as your changes may be lost during updates. Instead, use `overwriteConfig.lua` to store your customizations.

- **`config.lua`** - Default configuration maintained by developers. **Do not modify this file.**
- **`overwriteConfig.lua`** - This is where you place only the values you want to override.

### How to customize the configuration

1. Open `jo_gunrack/overwriteConfig.lua`
2. Find the value you want to change in `config.lua` (e.g., `Config.language`)
3. Copy only that line into `overwriteConfig.lua`
4. Edit the copied value to your liking

The script loads `config.lua` first, then `overwriteConfig.lua` overwrites only the values you redefine. This ensures your customizations are preserved when updating the script.

`jo_gunrack/shared/config.lua`

```lua
-------------------------------
-- DOCUMENTATION : https://docs.jumpon-studios.com/
--------------------------------

-------------------------------------------
-- DON'T EDIT THIS FILE
-- TO OVERWRITE CONFIG VALUE, USE overwriteConfig.lua file instead
-------------------------------------------
Config = {}
Config.equipWeaponWhenTook = true --auto equip of weapon when pick up
Config.distanceSpawnGunrack = 50.0 --distance to spawn the weapon storage

Config.commands = {
  configurator = {
    name = 'createGunRack', --use false to turn off
    group = 'admin'
  },
  clip_configurator = {
    name = 'configClipGunRack', --use false to turn off
    group = 'admin'
  }
}

-- Fix of untargetable weapon
-- ! use weapon model in LOWERCASE !
-- <bugged_weapon_model> = '<native_weapon_model>'
-- Use a native weapon with the same shape
Config.fixUntargetableWeapon = {}

Config.gunrackModels = {
  ["xm_prop_xm_gunlocker_01a"] = {
    racks = {
      [1] = {offset = vec3(-0.32, -0.22, 0.36), rotation = vec3(-90, 0.0, 0.0), size = "small", autoAdjustDimension = "y"},
      [2] = {offset = vec3(-0.03, -0.220, 0.36), rotation = vec3(-90, 0.0, 0.0), size = "small", autoAdjustDimension = "y"},
      [3] = {offset = vec3(-0.396, 0.04, 0.796), rotation = vec3(0.0, -70, 90), size = "big", autoAdjustDimension = false},
      [4] = {offset = vec3(-0.286, 0.04, 0.796), rotation = vec3(0.0, -70, 90), size = "big", autoAdjustDimension = false},
      [5] = {offset = vec3(-0.175, 0.04, 0.796), rotation = vec3(0.0, -70, 90), size = "big", autoAdjustDimension = false},
      [6] = {offset = vec3(-0.055, 0.04, 0.796), rotation = vec3(0.0, -70, 90), size = "big", autoAdjustDimension = false},
      [7] = {offset = vec3(0.055, 0.04, 0.796), rotation = vec3(0.0, -70, 90), size = "big", autoAdjustDimension = false},
      [8] = {offset = vec3(-0.25, 0.0, 1.325), rotation = vec3(-90,0,25), size = "small", autoAdjustDimension = "y"},
      [9] = {offset = vec3(0.0, 0.0, 1.325), rotation = vec3(-90,0,25), size = "small", autoAdjustDimension = "y"},
      [10] = {offset = vec3(0.25, 0.0, 1.325), rotation = vec3(-90,0,25), size = "small", autoAdjustDimension = "y"},
    },
    sizeLimits = {
      {size='small',max = 0.4},
      {size='big',max = 9999},
    }
  },
  ['prop_cs_gunrack'] = {
    racks = {
      [1] = {offset = vec3(-0.58,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [2] = {offset = vec3(-0.45,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [3] = {offset = vec3(-0.32,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [4] = {offset = vec3(-0.19,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [5] = {offset = vec3(-0.07,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [6] = {offset = vec3(0.06,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [7] = {offset = vec3(0.195,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [8] = {offset = vec3(0.325,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [9] = {offset = vec3(0.455,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
      [10] = {offset = vec3(0.58,0.05,-0.3), rotation = vec3(0.0,-90,90), size="all", autoAdjustDimension = "x"},
    },
    sizeLimits = {
      {size="all",max=9999}
    }
  },
  ['jo_wall_rack'] = {
    allowCollide = true,
    modelSize = vec2(1.0,1.0),
    isSlotable = true,
    gapBetweenWeapon = vec2(0.05,0.05),
    weaponRotation = vec3(0,0,0),
    offset = vec3(0,0.0,0)
  },
  ['jo_gunrack_unique'] = {
    allowCollide = true,
    modelSize = vec2(0.113,0),
    offset = vec3(0,0,0),
    racks = {
      [1] = {offset = vec3(0.06,-0.15,0.05), rotation = vec3(0.0,-90,270), size="all", autoAdjustDimension = "x"},
    },
    sizeLimits = {
      {size="all",max=9999}
    }
  }
}

Config.gunracks = {
  {
    model = "xm_prop_xm_gunlocker_01a", --"xm_prop_xm_gunlocker_01a"/"prop_cs_gunrack"
    id = "police1", --must be unique
    location = vec3(461.9, -981.1, 29.69),
    rotation = vec3(0,0,-90),
  },
  {
    model = "prop_cs_gunrack",
    id = "rack",
    location = vec3(459.067,-983.292,30.045),
    rotation = vec3(0,0,180.000),
  },
  {
    model = "jo_wall_rack",
    id = "policeWall1",
    location = vec3(457.533,-978.800,30.00),
    rotation = vec3(0,0,0),
    size = vec2(3,2),
  },
  {
    model = "jo_gunrack_unique",
    id = "policeRack3",
    location = vec3(455.135,-978.778,29.688),
    rotation = vec3(0,0,0.000),
    size = vec2(13,1),
  }
}

exports('getConfig', function()
  return Config
end)
```

`jo_gunrack/shared/lang.lua`

```lua
-------------------------------------------
-- DON'T EDIT THIS FILE
-- TO TRANSLATE THE SCRIPT, USE overwriteLang.lua file instead
-------------------------------------------
Lang = {}

Lang.ammo = "Ammunition"
Lang.gunrack = "Gunrack"
Lang.invalidItem = "Item invalid"
Lang.inventoryFull = "Your inventory is full"
Lang.noFreeRack = "No free rack for this weapon"
Lang.notOwner = "You are not the owner of this weapon"
Lang.quality = "Quality"
Lang.seeInformation = "See information"
Lang.serie = "Serie"
Lang.storeAWeapon = "Store a weapon"
Lang.takeAWeapon = 'Take a weapon'
Lang.takeIt = "Take it"
Lang.takeWeaponLabel = 'Take %s'
Lang.weaponStored = "%s is stored"
Lang.weaponTook = "%s is took"
Lang.notAllowed = "You are not allowed to use this command"
```

## 4. Know issues
:::details No such export isActive in resource ox_target
My update of ox_target is in waiting of approval by the OX team. To wait the integration in the main script, you can use my edit : [ox_target](https://github.com/KadDarem/ox_target/tree/isactive-export).<br>
You can find the 3 lines I added here : [the pull request](https://github.com/overextended/ox_target/pull/133/commits/6573d595b86fc41d9bc815795f6ae4ab3bcc3852)
:::

## 5. For developers

### Exports

#### `[Shared]` Get script configuration
exports to get the script configuration
```lua
exports.jo_gunrack:getConfig()

```

### Filters

[Filters](/DeveloperResources/filters) are the new way to modify data used by the script. These filters are fired at a specific point in time during the execution of the script. But contrary to events, filters are **synchronous**. 

- Syntax: 
```lua
-- @param <actionName> - name of the action
-- @param <argumentList> - list of arguments which are passed
exports.jo_gunrack:RegisterFilter(<actionName>, function(variable)
  -- Add your new data here
	return variable -- Don't forget to return the value
end)
```

#### `[Client]` Limits gun adding
Fires before the player add a weapon into the weapon storage
```lua
-- @param canAdd - boolean : true if can add a weapon
-- @param gunrackId - int : unique identifier of the weapon storage
-- @param rackId - int : number of the rack where the weapon is
exports.jo_gunrack:RegisterFilter('canAddWeapon', function(canAdd, gunrackId, rackId)
	return canAdd
end)

```
#### `[Client]` Limits gun grabbing
Fires before the player takes a weapon stored in the weapon storage
```lua
-- @param isOwner - boolean : true if the player is the owner of the weapon
-- @param gunrackId - int : unique identifier of the weapon storage
-- @param rackId - int : number of the rack where the weapon is
exports.jo_gunrack:RegisterFilter('canTakeWeapon', function(isOwner, gunrackId, rackId)
	return isOwner
end)

```
