# Editable files preview

{% hint style="success" %}
This script is customizable, you can preview files you have access to below.
{% endhint %}

## Main files

{% hint style="info" %}
These are the main files you can edit to customize this resource
{% endhint %}

<details>

<summary>client/cl_editable.lua</summary>

```lua
---------------------------------------------------------------------------------
--   _____       _                    _____          _                         --
--  |  __ \     (_)                  / ____|        | |                        --
--  | |__) |__   _  ___   ___   _ __ | |      ___   __| |  ___                 --
--  |  ___/ _ \ | |/ __| / _ \ | '_ \| |     / _ \ / _` | / _ \                --
--  | |  | (_) || |\__ \| (_) || | | | |____| (_) | (_| ||  __/                --
--  |_|   \___/ |_||___/ \___/ |_| |_|\_____|\___/ \__,_| \___|                --
--                                                                             --
--  © PoisonCode                                                               --
---------------------------------------------------------------------------------
--  Discord:       https://discord.gg/rNJ8cHXCsN                               --
--  Tebex:         https://tebex.poisoncode.com                                --
--  Docs:          https://docs.poisoncode.com                                 --
---------------------------------------------------------------------------------


RegisterCommand("collections", function(source, args)
    showUI(not IsUiDisplayed)
end)


exports('openCollections', function()
    showUI(not IsUiDisplayed)
end)


RegisterNetEvent('pc_collections:client:openCollections', function()
    showUI(not IsUiDisplayed)
end)
```

</details>

<details>

<summary>server/sv_editable.lua</summary>

```lua
COLLECTIONS_CACHE = {}
Database = {}

---------------------------------------------------------------------------------
--   _____       _                    _____          _                         --
--  |  __ \     (_)                  / ____|        | |                        --
--  | |__) |__   _  ___   ___   _ __ | |      ___   __| |  ___                 --
--  |  ___/ _ \ | |/ __| / _ \ | '_ \| |     / _ \ / _` | / _ \                --
--  | |  | (_) || |\__ \| (_) || | | | |____| (_) | (_| ||  __/                --
--  |_|   \___/ |_||___/ \___/ |_| |_|\_____|\___/ \__,_| \___|                --
--                                                                             --
--  © PoisonCode                                                               --
---------------------------------------------------------------------------------
--  Discord:       https://discord.gg/rNJ8cHXCsN                               --
--  Tebex:         https://tebex.poisoncode.com                                --
--  Docs:          https://docs.poisoncode.com                                 --
---------------------------------------------------------------------------------

-- ====================================================================================================== --
-- ------------------------------------------- DATABASE ------------------------------------------------- --
-- ====================================================================================================== --

function Database.Init()
    if Config.Database == "oxmysql" and GetResourceState('oxmysql') ~= 'started' then
        print("^1[ERROR] oxmysql defined in config but not started. Switching to JSON.^0")
        Config.Database = "json"
    end

    if Config.Database == "json" then
        local loadFile = LoadResourceFile(GetCurrentResourceName(), "./server/data.json")
        if loadFile then
            COLLECTIONS_CACHE = json.decode(loadFile)
        else
            COLLECTIONS_CACHE = {}
        end
    end
end


---@param PID string Player Unique Identifier
---@param collectionName string|nil Collection name to get count for
---@return number|table 
function Database.GetLimitCounts(PID, collectionName)
    if Config.Database == "oxmysql" then
        if not collectionName then
            local result = {}
            local response = MySQL.prepare.await('SELECT collection, count FROM `collections` WHERE `player_id` = ?', {PID})
            if response then
                if #response == 0 and response.collection then response = {response} end
                for _, row in ipairs(response) do
                    result[row.collection] = row.count
                end
            end
            return result
        else
            return MySQL.prepare.await('SELECT count FROM `collections` WHERE `player_id` = ? AND `collection` = ?', {PID, collectionName}) or 0
        end
    else
        if not COLLECTIONS_CACHE[PID] then return (collectionName and 0 or {}) end
        if collectionName then
            return COLLECTIONS_CACHE[PID][collectionName] or 0
        else
            return COLLECTIONS_CACHE[PID]
        end
    end
end


---@param PID string Player Unique Identifier
---@param collectionName string
function Database.IncrementLimit(PID, collectionName)
    if Config.Database == "oxmysql" then
        MySQL.prepare.await('INSERT INTO collections (player_id, collection, count) VALUES (?,?,1) ON DUPLICATE KEY UPDATE count = count + 1', {PID, collectionName})
    else
        if not COLLECTIONS_CACHE[PID] then COLLECTIONS_CACHE[PID] = {} end
        COLLECTIONS_CACHE[PID][collectionName] = (COLLECTIONS_CACHE[PID][collectionName] or 0) + 1
        SaveResourceFile(GetCurrentResourceName(), "./server/source/data.json", json.encode(COLLECTIONS_CACHE), -1)
    end
end

-- ====================================================================================================== --
-- --------------------------------------------- OTHER -------------------------------------------------- --
-- ====================================================================================================== --

---@param player player Player source id
---@return string Unique Player identifier
function GetPlayerUID(player)
    if Config.Framework == "ESX" then
        return Bridge.GetPlayer(player).identifier
    elseif Config.Framework == "QBCore" or Config.Framework == "QBox" then
        return Bridge.GetPlayer(player).PlayerData.citizenid
    elseif Config.Framework == "ox_core" then
        return Bridge.GetPlayer(player).charId
    end
end


RegisterNetEvent('pc_collections:server:openCollections', function(target)
    TriggerClientEvent('pc_collections:client:openCollections', target)
end)


exports('openCollections', function(target)
    TriggerClientEvent('pc_collections:client:openCollections', target)
end)
```

</details>

<details>

<summary>config.lua</summary>

```lua
Config = {}
Locales = {}
Bridge = {}
---------------------------------------------------------------------------------
--   _____       _                    _____          _                         --
--  |  __ \     (_)                  / ____|        | |                        --
--  | |__) |__   _  ___   ___   _ __ | |      ___   __| |  ___                 --
--  |  ___/ _ \ | |/ __| / _ \ | '_ \| |     / _ \ / _` | / _ \                --
--  | |  | (_) || |\__ \| (_) || | | | |____| (_) | (_| ||  __/                --
--  |_|   \___/ |_||___/ \___/ |_| |_|\_____|\___/ \__,_| \___|                --
--                                                                             --
--  © PoisonCode                                                               --
---------------------------------------------------------------------------------
--  Discord:       https://discord.gg/rNJ8cHXCsN                               --
--  Tebex:         https://tebex.poisoncode.com                                --
--  Docs:          https://docs.poisoncode.com                                 --
---------------------------------------------------------------------------------

-- ====================================================================================================== --
-- ---------------------------------------- BRIDGE SETTINGS --------------------------------------------- --
-- ====================================================================================================== --

Config.Framework = "ESX" -- "ESX" / "QBCore" / "QBox" / "ox_core"
Config.InventorySystem = "ox_inventory" -- "ox_inventory" / "ESX" / "QBCore" / "QBox" (ox_core has to use ox_inventory)
Config.Database = "oxmysql" -- "oxmysql" / "json" -- we recommend using oxmysql, you have to setup the database table using the provided SQL file.
Config.Notifications = "pc_notifications" -- pc_notifications / "custom"

-- ====================================================================================================== --
-- -------------------------------------------- GENERAL ------------------------------------------------- --
-- ====================================================================================================== --

Config.Locale = "en" -- Set your language here -- available languages: en 

Config.Debug = false -- Enable debug messages

Config.ShowClaimLimits = true -- Show claim limits in the UI
Config.ShowRewardIcons = true -- Show reward icons in the UI, if disabled only names will be shown

-- ====================================================================================================== --
-- -------------------------------------------- SKILLS -------------------------------------------------- --
-- ====================================================================================================== --
--   For this section to work, you need pc_skills resource: https://tebex.poisoncode.com/scripts/skills   --
-- ====================================================================================================== --

Config.UseSkillSystem = true -- Enable skill system integration
Config.SkillName = "skill1" -- Skill name from the skill system 

-- ====================================================================================================== --
-- ------------------------------------------ COLLECTIONS ----------------------------------------------- --
-- ====================================================================================================== --

Config.Collections = {

    ["collection1"] = { -- Collection name
        order = 1, -- Order in the list
        label = "Example collection 1", -- Collection name
        limit = false, -- Limit how many times player can complete this collection, set to false for unlimited
        items = { -- Items required to complete this collection
            {name = "bread", label = "Bread", count = 2},
        },
        reward = { -- Items rewarded for completing this collection
            {name = "money", label = "Cash", count = 500},
        },
        -- pc_skills integration, this will only work if Config.pc_skills.enabled is set to true
        lvl = 1, -- Level required to unlock this collection, only works if Config.pc_skills.enabled is set to true
        rewardXP = 200, -- Experience points rewarded for completing this collection, only works if Config.pc_skills.enabled is set to true
    },

    ["collection2"] = {
        order = 2,
        label = "Example collection 2",
        limit = 1,
        items = {
            {name = "weed", label = "Weed", count = 5},
            {name = "glove", label = "Gloves", count = 2},
            {name = "mask1", label = "Mask", count = 1},
        },
        reward = {
            {name = "armour", label = "Bulletproof vest", count = 1},
            {name = "weapon_pistol", label = "Pistol", count = 1},
        },
        lvl = 1,
        rewardXP = 10,
    },

    ["collection3"] = {
        order = 3,
        label = "Example collection 3",
        limit = 1,
        items = {
            {name = "carrot", label = "Carrot", count = 1},
            {name = "eggplant", label = "Eggplant", count = 1},
            {name = "Pepper", label = "Pepper", count = 1},
        },
        reward = {
            {name = "money", label = "Cash", count = 20000},
        },
        lvl = 5,
        rewardXP = 20,
    },

    ["collection4"] = {
        order = 4,
        label = "Example collection 4",
        limit = 2,
        items = {
            {name = "bread", label = "Bread", count = 1},
            {name = "bread", label = "Bread", count = 1},
            {name = "bread", label = "Bread", count = 1},
            {name = "bread", label = "Bread", count = 1},
            {name = "bread", label = "Bread", count = 1},
            {name = "water", label = "Water", count = 1},
            {name = "water", label = "Water", count = 1},
            {name = "water", label = "Water", count = 1},
            {name = "water", label = "Water", count = 1},
            {name = "water", label = "Water", count = 1},
        },
        reward = {
            {name = "usb_black", label = "USB stick", count = 2},
        },
        lvl = 3,
        rewardXP = 20,
    },

        ["collection5"] = {
        order = 5,
        label = "Example collection 5",
        limit = 3,
        items = {
            {name = "advancedkit", label = "Repair kit", count = 1},
            {name = "ziptie", label = "Ziptie", count = 5},
        },
        reward = {
            {name = "internals", label = "Parts", count = 2},
        },
        lvl = 3,
        rewardXP = 100,
    },
    
}
```

</details>

## Bridge module

{% hint style="info" %}
Bridge module is used to provide compatibility with different frameworks, inventory systems and much more, you can see which system are supported and if you have sufficient knowledge - add a new one.
{% endhint %}

<details>

<summary>server/framework.lua</summary>

```lua
if Config.Framework ~= "ESX" or Framework then return end

Framework = exports["es_extended"]:getSharedObject() or nil
if not Framework then
  TriggerEvent('esx:getSharedObject', function(library) 
    Framework = library or nil
  end)
end

Bridge.GetPlayer = Framework.GetPlayerFromId

if Framework and Bridge.GetPlayer then
  print("Loaded ESX framework")
end
```

</details>

<details>

<summary>server/inventory.lua</summary>

```lua
if Config.Framework ~= "ox_core" or Framework then return end

if not Ox then
    print("Ox_Core framework not found, make sure it's uncommented in fxmanifest.")
end

Bridge.GetPlayer = Ox.GetPlayerFromUserId

if not Config.InventorySystem == "ox_inventory" then
    print("You cannot use ox_core framework without ox_inventory, please check your Configuration.")
    Config.InventorySystem = "ox_inventory"
end

if Ox and Bridge.GetPlayer and Config.InventorySystem == "ox_inventory" then
    print("Loaded ox_core framework")
end

```

</details>

<details>

<summary>server/notifications.lua</summary>

```lua
if Config.Framework ~= "QBCore" or Framework then return end

Framework = exports["qb-core"]:GetCoreObject() or nil

Bridge.GetPlayer = Framework.Functions.GetPlayer

if Framework and Bridge.GetPlayer then
    print("Loaded QBCore framework")
end
```

</details>

{% hint style="info" %}
If you encounter any problems during configuration, you can create a support ticket on our discord.
{% endhint %}


---

# 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://docs.poisoncode.com/group-1/copy-of-pc_collections/editable-files-preview.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.
