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:


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.sqlto set up required tables and columns. Example:

Full Database (Run this if you're using Evo-K9 for the first time)
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;
Use this if you already used Evo-K9 v2 and don’t want to lose your data.
CREATE TABLE `evo_k9_houses` (
  `id` INT AUTO_INCREMENT PRIMARY KEY,
  `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 NOT NULL DEFAULT 0,
  `created_by` VARCHAR(64) NOT NULL
);


ALTER TABLE evo_k9_dogs
ADD COLUMN defence INT DEFAULT 0,
ADD COLUMN intelligence INT DEFAULT 0;

UPDATE evo_k9_dogs
SET
    animation = IF(animation IS NULL OR animation = 'null', '{}', animation),
    defence = IF(defence IS NULL, 0, defence),
    intelligence = IF(intelligence IS NULL, 0, intelligence),
    ui_position = IF(ui_position IS NULL OR JSON_VALID(ui_position) = 0, '{"x":"normal","y":"Down"}', ui_position);

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

💡 Click to view usable items for qb-inventory:
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' 
},

📦 Ox Inventory Items

💡 Click to view usable items for ox_inventory:
["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",
    }
},

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 items.

Click to expand the code for ox_inventory
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)
  • For qb-inventory: Edit server/functions.lua to add the new items.

Click to expand the code for qb-inventory
--- @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 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)

6️⃣ ⚙️ Script Configuration

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

    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.


📌 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.

Last updated