# Installation

## 📦 Installation Instructions for Evo-K9-V3 Script System

To ensure the proper functioning of the Evo-K9-V3 Script System, follow these installation instructions carefully. This system has essential dependencies and setup steps for a smooth experience.

***

### 🛠️ Asset Dependencies

**Mandatory Dependencies:**

* **FiveM Server** (latest recommended)
* **MySQL Database**
* **Framework:**
  * [QB-Core](https://github.com/qbcore-framework/qb-core) (recommended)
  * [es\_extended (ESX Base)](https://github.com/esx-framework/es_extended)
  * QBox
  * Standalone
* **Target System:**
  * [qb-target](https://github.com/BerkieBb/qb-target)
  * [ox\_target](https://github.com/overextended/ox_target)
* **Inventory System:**
  * [qb-inventory](https://github.com/qbcore-framework/qb-inventory)
  * [ox\_inventory](https://github.com/overextended/ox_inventory)
  * qs-inventory
  * tgiaan-inventory

***

### 1️⃣ Download & Place the Resource

* Download Evo-K9-V3 and place it in your server’s resources folder:

  ```
  [FRAMEWORK]/evo-k9-v3/
  ```

***

### 2️⃣ Database Setup

* Run the SQL commands from `database.sql`to set up required tables and columns.\
  Example:

<details>

<summary>Full Database</summary>

```sql
CREATE TABLE IF NOT EXISTS `evo_k9_dogs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `citizenid` varchar(50) NOT NULL,
  `name` VARCHAR(50) NOT NULL DEFAULT 'Unnamed',
  `model` varchar(50) DEFAULT NULL,
  `health` int(11) DEFAULT 200 CHECK (`health` <= 200),
  `hunger` int(11) DEFAULT 100 CHECK (`hunger` <= 100),
  `thirst` int(11) DEFAULT 100 CHECK (`thirst` <= 100),
  `rep` int(11) DEFAULT 0,
  `stamina` int(11) DEFAULT 0 CHECK (`stamina` <= 100),
  `smell` int(11) DEFAULT 0 CHECK (`smell` <= 100),
  `attack` int(11) DEFAULT 0 CHECK (`attack` <= 100),
  `ui_position` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '{"x": 0, "y": 0}' CHECK (json_valid(`ui_position`)),
  `dogid` varchar(20) DEFAULT NULL,
  `outfit` text DEFAULT NULL,
  `animation` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`animation`)),
  `cage` tinyint(1) NOT NULL DEFAULT 0,
  `defence` int(11) DEFAULT 0,
  `intelligence` int(11) DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY `dogid` (`dogid`)
) ENGINE=InnoDB AUTO_INCREMENT=498 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;


CREATE TABLE IF NOT EXISTS `evo_k9_houses` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL DEFAULT 'Unnamed',
  `prop` varchar(64) NOT NULL,
  `coords` text NOT NULL,
  `dog_spawn` text NOT NULL,
  `camera` text NOT NULL,
  `jobs` text NOT NULL,
  `minimumgrade` int(11) NOT NULL DEFAULT 0,
  `created_by` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
```

</details>

> **Tip:** Always back up your database before making changes.

***

### 3️⃣ Install Items in Inventory

* Add these items to your inventory system (qb-inventory/ox\_inventory):

### 🧾 QBCore Inventory Items

<details>

<summary>💡 Click to view usable items for <strong>qb-inventory</strong>:</summary>

```lua
k9glowstick = { 
    name = 'k9glowstick', 
    label = 'Dog Glow Stick', 
    weight = 0, 
    type = 'item', 
    image = 'k9glowstick.png', 
    unique = false, 
    useable = true, 
    shouldClose = true, 
    combinable = nil, 
    description = 'A glow for your k9' 
},

k9weed = { 
    name = 'k9weed', 
    label = 'K9 Weed', 
    weight = 0.5, 
    type = 'item', 
    image = 'k9weed.png', 
    unique = false, 
    useable = true, 
    shouldClose = true, 
    combinable = nil, 
    description = 'Plant weed to train your k9 smell power' 
},

k9revivekit = { 
    name = 'k9revivekit', 
    label = 'Revivekit For K9', 
    weight = 1, 
    type = 'item', 
    image = 'k9revivekit.png', 
    unique = false, 
    useable = true, 
    shouldClose = true, 
    combinable = nil, 
    description = 'Revivekit for your k9 dog' 
},

k9food = { 
    name = 'k9food', 
    label = 'K9 Food', 
    weight = 1, 
    type = 'item', 
    image = 'k9food.png', 
    unique = false, 
    useable = true, 
    shouldClose = true, 
    combinable = nil, 
    description = 'Food For Your K9 Dog' 
},

k9drink = { 
    name = 'k9drink', 
    label = 'K9 Drink', 
    weight = 1, 
    type = 'item', 
    image = 'k9drink.png', 
    unique = false, 
    useable = true, 
    shouldClose = true, 
    combinable = nil, 
    description = 'Drink For Your K9 Dog' 
},

k9flashlight = { 
    name = 'k9flashlight', 
    label = 'K9 Flashlight', 
    weight = 1, 
    type = 'item', 
    image = 'k9flashlight.png', 
    unique = false, 
    useable = true, 
    shouldClose = true, 
    combinable = nil, 
    description = 'A flashlight for your K9 dog' 
},

k9harness = { 
    name = 'k9harness ', 
    label = 'K9 harness', 
    weight = 1, 
    type = 'item', 
    image = 'k9harness.png', 
    unique = false, 
    useable = true, 
    shouldClose = true, 
    combinable = nil, 
    description = 'A harness to carry your K9' 
},
```

</details>

### 🎄 QBCore Inventory Items For Christmas (optional)

<details>

<summary>🎄 Click to view usable items for <strong>qb-inventory</strong>:</summary>

```lua
k9christmasshoe = {
    name = 'k9christmasshoe',
    label = 'K9 Christmas Shoes',
    weight = 0,
    type = 'item',
    image = 'k9christmasshoe.png',
    unique = false,
    useable = true,
    shouldClose = true,
    combinable = nil,
    description = 'Festive shoes for your K9 partner'
},
```

</details>

***

### 📦 Ox Inventory Items

<details>

<summary>💡 Click to view usable items for <strong>ox_inventory</strong>:</summary>

{% code fullWidth="true" %}

```lua
["k9glowstick"] = {
    label = "Dog Glow Stick",
    weight = 0,
    stack = false,
    close = true,
    description = "A glow for your k9",
    client = {
        image = "k9glowstick.png",
    }
},

["k9weed"] = {
    label = "K9 Weed",
    weight = 0.5,
    stack = false,
    close = true,
    description = "Plant weed to train your k9 smell power",
    client = {
        image = "k9weed.png",
    }
},

["k9revivekit"] = {
    label = "Revivekit For K9",
    weight = 1,
    stack = false,
    close = true,
    description = "Revivekit for your k9 dog",
    client = {
        image = "k9revivekit.png",
    }
},

["k9food"] = {
    label = "K9 Food",
    weight = 1,
    stack = false,
    close = true,
    description = "Food For Your K9 Dog",
    client = {
        image = "k9food.png",
    }
},

["k9drink"] = {
    label = "K9 Drink",
    weight = 1,
    stack = false,
    close = true,
    description = "Drink For Your K9 Dog",
    client = {
        image = "k9drink.png",
    }
},

["k9flashlight"] = {
    label = "K9 Flashlight",
    weight = 1,
    stack = false,
    close = true,
    description = "A flashlight for your K9 dog",
    client = {
        image = "k9flashlight.png",
    }
},


["k9harness"] = {
    label = "K9 harness",
    weight = 1,
    stack = false,
    close = true,
    description = "A harness to carry your K9",
    client = {
        image = "k9harness.png",
    }
},
```

{% endcode %}

</details>

### 🎄 Ox Inventory Items For Christmas (optional)

<details>

<summary>🎄 Click to view usable items for <strong>ox_inventory</strong>:</summary>

{% code fullWidth="true" %}

```lua
["k9christmasshoe"] = {
    label = "K9 Christmas Shoes",
    weight = 0,
    stack = false,
    close = true,
    description = "Festive shoes that slip over your K9\'s paws",
    client = {
        event = 'evo-k9:client:toggleChristmasShoes'
    }
},
```

{% endcode %}

</details>

***

### 4️⃣ 🖼️ Images Installation

* In the `evo-k9-v3/images` directory, you’ll find all item images.
* **For qb-inventory:**\
  Copy all images to:

  ```
  qb-inventory/html/images
  ```
* **For ox\_inventory:**\
  Place images in the appropriate `web/images/items` directory.

> **Make sure all image files are correctly placed so they are visible in your inventory UI.**

***

### 5️⃣ 📝 Inventory Integration

* **For ox\_inventory:**\
  Edit `modules/inventory/server.lua` (after `loadInventoryData` function, usually around line 196) to add the new Integration.

<details>

<summary>Click to expand the code for ox_inventory</summary>

```lua
local function evok9getVehicleNetIdByPlate(plate)
    local vehicles = GetAllVehicles()
    for _, vehicle in ipairs(vehicles) do
        local vehiclePlate = GetVehicleNumberPlateText(vehicle)
        if vehiclePlate:find(plate) then
            local netid = NetworkGetNetworkIdFromEntity(vehicle)
            return netid
        end
    end
    return nil
end

---@param data table -- The inventory data, including id, type, and entity information
---@param player table -- The player data (optional)
---@return table | nil -- Returns the list of items or nil if no items found
local function evok9PrintAndReturnInventoryItems(data, player)
    local inventory = setmetatable(Inventory, {
        __call = function(self, inv, player)
            if not inv then
                return self
            elseif type(inv) == 'table' then
                if inv.__index then return inv end

                return not inv.owner and Inventories[inv.id] or loadInventoryData(inv, player)
            end

            return Inventories[inv] or loadInventoryData({ id = inv }, player)
        end
    })(data, player)

    if inventory.items then
        local items = {}

        for slot, item in pairs(inventory.items) do
            table.insert(items, {name = item.name, count = item.count or 1})
        end
        return items
    else
        return nil
    end
end

exports('evok9PrintAndReturnInventoryItems', evok9PrintAndReturnInventoryItems)


---@param plate string -- The plate of the vehicle
---@return table | nil -- Returns the list of items or nil if no items found
local function evok9getVehicleTrunkItemsByPlate(plate)
    local netid = evok9getVehicleNetIdByPlate(plate)
    if netid then
        local data = {
            id = "trunk" .. plate,
            type = "trunk",
            netid = netid,
        }
        
        local items = evok9PrintAndReturnInventoryItems(data)
        if items then
            for _, item in ipairs(items) do
            end
        end
        return items
    else
        return nil
    end
end

exports('evok9getVehicleTrunkItemsByPlate', evok9getVehicleTrunkItemsByPlate)


---@param plate string -- The vehicle plate number
---@return table -- Returns the list of items in the glovebox or nil if not found
local function evok9getVehicleGloveboxItemsByPlate(plate)
    local netid = evok9getVehicleNetIdByPlate(plate)
    if netid then
        local data = {
            id = "glove" .. plate,
            type = "glovebox",
            netid = netid,
        }
        local items = evok9PrintAndReturnInventoryItems(data)

        -- **Print Debug Information**
        if items then
            print("[DEBUG] Glovebox items for vehicle (" .. plate .. "):")
            for _, item in ipairs(items) do
                print("Item:", item.name, "| Count:", item.count)
            end
        else
            print("[ERROR] No items found in the glovebox for plate:", plate)
        end

        return items
    else
        print("[ERROR] Vehicle NetID not found for plate:", plate)
        return nil
    end
end

exports('evok9getVehicleGloveboxItemsByPlate', evok9getVehicleGloveboxItemsByPlate)
```

</details>

* **For qb-inventory:**\
  Edit `server/functions.lua` to add the new Integration.

<details>

<summary>Click to expand the code for <strong>qb-inventory</strong></summary>

<pre class="language-lua"><code class="lang-lua"><strong>--- @param source number The player's server ID.
</strong>--- @param identifier string|nil The identifier of the inventory to open.
--- @param data table|nil Additional data for initializing the inventory.
function evok9CheckInventoryItems(identifier, data)
    if not identifier then
        print("No identifier provided.")
        return nil
    end
​
    if type(identifier) ~= 'string' then
        print("Invalid identifier provided.")
        return nil
    end
​
    local inventory
    if identifier:sub(1, 7) == "player-" then
        local playerId = tonumber(identifier:sub(8))
        local Player = QBCore.Functions.GetPlayer(playerId)
        if Player then
            inventory = Player.PlayerData.items
        else
            print("Player not found.")
            return nil
        end
    else
        inventory = Inventories[identifier]
        if not inventory then
            inventory = InitializeInventory(identifier, data)
        end
        inventory = inventory.items
    end
​
    local formattedInventory = {
        name = identifier,
        label = (inventory and inventory.label) or (data and data.label) or identifier,
        maxweight = (inventory and inventory.maxweight) or (data and data.maxweight) or Config.StashSize.maxweight,
        slots = (inventory and inventory.slots) or (data and data.slots) or Config.StashSize.slots,
        inventory = inventory
    }
​
    if formattedInventory.inventory then
        return formattedInventory.inventory
    else
        print("No items found in inventory: " .. identifier)
        return nil
    end
end
​
exports('evok9CheckInventoryItems', evok9CheckInventoryItems)
​
​
--- @param source number The player's server ID.
--- @param identifier string|nil The identifier of the inventory to open.
--- @param data table|nil Additional data for initializing the inventory.
function evok9CheckPlayerInventoryItems(playerId)
    local Player = QBCore.Functions.GetPlayer(playerId)
    if not Player then
        print("Player not found.")
        return nil
    end
​
    return Player.PlayerData.items
end
​
exports('evok9CheckPlayerInventoryItems', function(playerId)
    return evok9CheckPlayerInventoryItems(playerId)
end)
</code></pre>

</details>

* **For qs-inventory:**\
  Edit `server/custom/misc/evok9.lua` to add the new Integration.

{% hint style="warning" %}
For **qs-inventory**, remove the **first 3 lines** at the top of `server/custom/misc/evok9.lua`.

Those lines check for `evo-k9-v2` and can stop the integration from loading.
{% endhint %}

***

### 6️⃣ ⚙️ Script Configuration

* Open `config.lua` and adjust settings to match your server:

  ```lua
  Config = {
      Framework = 'QB', -- QB, ESX, qbox, standalone
      target = "qb-target", -- qb-target or ox_target
      InventoryType = 'qb-inventory', -- qb-inventory or ox_inventory
      language = 'en', -- Language for localization
      DevMode = false, -- Enable debug mode
  }
  ```
* Adjust shop, training, and other options as needed for your server.

***

### 7️⃣ Add to server.cfg

* Add the resource to your `server.cfg`:

  ```
  ensure evo-k9-v3
  ```

***

### 8️⃣ Change Languages

You can fully customize the script language to fit your preferred localization. All sections are open and editable, allowing you to translate the system to any language you choose.

The language configuration is divided into two main parts:

**1. Backend Language Settings `locales.lua`**

All dynamic text and system notifications are handled here. You can modify this file to update backend language elements:

```
📁 EVO-K9-V3/locales.lua
```

**2. UI Language & Outfit Options `lang.js`**

Text that appears in the user interface is defined in this file. Additionally, this file includes an option to remove or customize the dog outfit:

```
📁 EVO-K9-V3/UI/lang.js
```

🛠️ Feel free to adjust both files to provide a fully localized and personalized experience for your community.

***

## 🏠 Available Maps

* `EVO_K9Facility_Airbase`
* `EVO_K9Facility_WindFarm`

You can only use **one** map at a time!

### 🛠 Setup

1. **Choose Your Map**\
   Open `config.lua` and select the map you want to use.
2. **Edit or Remove a Map**\
   If you want to change ped positions or fully remove a map:
   * Delete the map folder you don’t need.
   * Remove the related lines from `fxmanifest.lua`.

***

### 📌 Final Steps

* Double-check all dependencies are installed and configured.
* Make sure all images and items are added to your inventory system.
* Run the SQL scripts and verify your database tables.
* Start your server and enjoy your new K9 companion!

***

## **🐾 K9 Not Spawning – Troubleshooting Guide**

* You must have an active license or a maximum player slot of 8 for the dog to spawn.
* Redownload the script from Keymaster, as sometimes it doesn't download completely.
* Check if any anti-cheat is blocking the K9 from spawning.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://evo-development.gitbook.io/evo-development-docs/products/evo-k9-v3/installation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
