> For the complete documentation index, see [llms.txt](https://docs.acura.gg/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.acura.gg/redm/ad_mining/unlocked-files.md).

# Unlocked Files

## Client Side

<details>

<summary><code>cl_framework.lua</code></summary>

{% code lineNumbers="true" %}

```lua
Framework = {}

TriggerEvent("getCore", function(core)
    Framework.Core = core
end)

Framework.Callback = function(event, cb, args)
    Framework.Core.RpcCall(event, cb, args)
end

Framework.Notify = function(message, duration)
    Framework.Core.NotifyRightTip(message, duration)
end
```

{% endcode %}

</details>

## Server Side

{% tabs %}
{% tab title="sv\_framework.lua" %}
{% code lineNumbers="true" %}

```lua
Framework = {}

TriggerEvent("getCore", function(core)
    Framework.Core = core
end)

Framework.Notify = function(source, message, duration)
    Framework.Core.NotifyRightTip(source, message, duration)
end

Framework.AddCallback = function(event, cb)
    Framework.Core.addRpcCallback(event, cb)
end

Framework.GetItemLabel = function(itemName, cb)
    exports["vorp_inventory"]:getItemDB(itemName, function(item)
        cb(item and item.label or nil)
    end)
end

Framework.GetItemById = function(source, itemId, cb)
    exports["vorp_inventory"]:getItemByMainId(source, itemId, function(item)
        if item then
            cb({
                name = item.name,
                label = item.label,
                count = item.count,
                metadata = item.metadata,
                id = item.mainid or item.id
            })
        else
            cb(nil)
        end
    end)
end

Framework.getItemByName = function(source, itemName, cb)
    exports["vorp_inventory"]:getItemByName(source, itemName, function(item)
        if cb then
            if item then
                cb({
                    name = item.name,
                    label = item.label,
                    count = item.count,
                    metadata = item.metadata,
                    id = item.mainid or item.id
                })
            else
                cb(nil)
            end
        end
    end)
end

Framework.SetItemMetadata = function(source, itemId, metadata)
    exports["vorp_inventory"]:setItemMetadata(source, itemId, metadata, nil)
end

Framework.RegisterItem = function(itemName, cb)
    exports["vorp_inventory"]:registerUsableItem(itemName, function(data)
        cb({
            source = data.source,
            itemId = data.item.mainid or data.item.id,
            metadata = data.item.metadata
        })
    end)
end

Framework.CloseInventory = function(source)
    TriggerClientEvent("vorp_inventory:CloseInv", source)
end

Framework.GetCharacterName = function(source, cb)
    local character = Framework.Core.getUser(source).getUsedCharacter
    cb(character.firstname .. ' ' .. character.lastname)
end

Framework.GetMoney = function(source, cb)
    local character = Framework.Core.getUser(source).getUsedCharacter
    cb(character.money)
end

Framework.RemoveMoney = function(source, amount)
    local character = Framework.Core.getUser(source).getUsedCharacter
    character.removeCurrency(0, amount)
end

Framework.AddMoney = function(source, amount)
    local character = Framework.Core.getUser(source).getUsedCharacter
    character.addCurrency(0, amount)
end

Framework.CanCarryItem = function(source, itemName, amount, cb)
    exports["vorp_inventory"]:canCarryItem(source, itemName, amount, function(canCarry)
        cb(canCarry)
    end)
end

Framework.AddItem = function(source, itemName, amount, cb)
    exports["vorp_inventory"]:addItem(source, itemName, amount or 1, {}, function(added)
        if cb then cb(added) end
    end)
end

Framework.RemoveItem = function(source, itemName, itemCount)
    -- Function must return true / false if item has been removed or not
    return exports["vorp_inventory"]:subItem(source, itemName, itemCount or 1)
end

Framework.GetInventoryItems = function(source, cb)
    exports["vorp_inventory"]:getUserInventoryItems(source, function(inventory)
        local items = {}

        for index, item in pairs(inventory) do
            items[index] = {
                name = item.name,
                count = item.count
            }
        end

        cb(items)
    end)
end

RegisterNetEvent("vorpinventory:serverDropItem", function(itemName, itemId, _, __)
    local _source = source
    ItemDropped(_source, itemName, itemId)
end)
```

{% endcode %}
{% endtab %}

{% tab title="sv\_callbacks.lua" %}

```lua
Framework.AddCallback("ad_mining:server:getJob", function(source, cb, args)
    if Framework.Core.getUser(source) then
        local character = Framework.Core.getUser(source).getUsedCharacter
        cb(character.job)
    end
end)

Framework.AddCallback("ad_mining:server:getInventory", function(source, cb, args)
    exports["vorp_inventory"]:getUserInventoryItems(source, function(inventory)
        cb(inventory)
    end)
end)

Framework.AddCallback("ad_mining:server:hasItem", function(src, cb, args)
    Framework.getItemByName(src, args.item, function(item)
        cb({
            has = not not item and (not args.amount or item.count >= args.amount),
            count = item and item.count or 0
        })
    end)
end)

Framework.AddCallback("ad_mining:server:getItemLabel", function(source, cb, args)
    if Config.ItemLabels[args.itemName] then -- Cache item labels
        cb(Config.ItemLabels[args.itemName])
    else
        Framework.GetItemLabel(args.itemName, function(itemLabel)
            cb(itemLabel and itemLabel or nil)
            if itemLabel then Config.ItemLabels[args.itemName] = itemLabel end
        end)
    end
end)
```

{% endtab %}

{% tab title="sv\_itemlabels.lua" %}

```lua
local function FetchItemLabel(itemName, err)
    if Config.ItemLabels[itemName] then return end -- Cache item labels

    Framework.GetItemLabel(itemName, function(itemLabel)
        if itemLabel then Config.ItemLabels[itemName] = itemLabel
        else err() end
    end)
end

CreateThread(function()
    for index, traderData in ipairs(Config.MineTraders) do
        for itemName, _ in pairs(traderData.buyItems) do
            FetchItemLabel(itemName, function()
                print("^1[ad_mining] ^7Invalid item found for [BUY] trader", index, ", item name:", itemName)
            end)
        end

        for itemName, _ in pairs(traderData.sellItems) do
            FetchItemLabel(itemName, function()
                print("^1[ad_mining] ^7Invalid item found for [SELL] trader", index, ", item name:", itemName)
            end)
        end
    end

    for _, pointData in pairs(Config.MinePoints) do
        for _, pointItems in pairs(pointData.items) do
            if type(pointItems) == "table" then
                for _, itemName in pairs(pointItems) do
                    FetchItemLabel(itemName, function()
                        print("^1[ad_mining] ^7Invalid item found for mine point:", pointData.name, ", item name:", itemName)
                    end)
                end
            else
                FetchItemLabel(pointItems, function()
                    print("^1[ad_mining] ^7Invalid item found for mine point:", pointData.name, ", item name:", pointItems)
                end)
            end
        end

        for index, data in pairs(pointData.levels) do
            if data.ores then
                for itemName, _ in pairs(data.ores) do
                    FetchItemLabel(itemName, function()
                        print("^1[ad_mining] ^7Invalid item found for [LEVELS] mine point", pointData.name, ", level:", index, ", item name:", itemName)
                    end)
                end
            end
        end
    end

    for _, modData in pairs(Config.ModificationItems) do
        FetchItemLabel(modData.name, function()
            print("^1[ad_mining] ^7Invalid item found for modification item:", modData.name)
        end)
    end

    for _, itemData in pairs(Config.ExoticItems) do
        FetchItemLabel(itemData.name, function()
            print("^1[ad_mining] ^7Invalid item found for exotic item:", itemData.name)
        end)
    end

    for index, stationData in pairs(Config.ModStations) do
        for itemName, _ in pairs(stationData.repair.itemsPerDurability) do
            FetchItemLabel(itemName, function()
                Config.ModStations[index].repair.itemsPerDurability[itemName] = nil
                print("^1[ad_mining] ^7Invalid item found for [REPAIR] mod station", index, ", item name:", itemName)
            end)
        end
    end
end)

```

{% endtab %}

{% tab title="sv\_rarities.lua" %}

```lua
Config.Rarities = {}
Config.Rarities.Lucky = {}
Config.Rarities.Order = {
    {rarity = "exotic", weight = 0.2},
    {rarity = "legendary", weight = 2},
    {rarity = "ultrarare", weight = 3},
    {rarity = "rare5", weight = 5},
    {rarity = "rare10", weight = 10},
    {rarity = "rare15", weight = 15},
    {rarity = "rare20", weight = 20},
    {rarity = "common30", weight = 30},
    {rarity = "common50", weight = 50},
    {rarity = "common70", weight = 70},
    {rarity = "guaranteed", weight = 100}
}

CreateThread(function()
    for _, orderData in pairs(Config.Rarities.Order) do
        local addedWeight = 0
        if orderData.weight >= 1 and orderData.weight < 100 then
            addedWeight = math.random(Config.Default.luckyWeight.min, Config.Default.luckyWeight.max)
        end

        table.insert(Config.Rarities.Lucky, {
            rarity = orderData.rarity,
            weight = orderData.weight + addedWeight
        })
    end
end)

Config.Rarities.GenerateRarity = function(allowedRarities, lucky)
    local filteredItems = {}
    local totalWeight = 0

    for _, item in ipairs(lucky and Config.Rarities.Lucky or Config.Rarities.Order) do
        if allowedRarities[item.rarity] then
            table.insert(filteredItems, item)
            totalWeight = totalWeight + item.weight
        end
    end

    if #filteredItems == 0 then
        return nil -- No valid rarities found
    end

    math.randomseed(os.time() + math.random(999999)) -- Seed based off time to make it actually random
    local randomNumber = math.random() -- Generate a random number between 0 and 1
    local accumulatedWeight = 0

    for _, item in ipairs(filteredItems) do
        accumulatedWeight = accumulatedWeight + (item.weight / totalWeight) -- Adjust weight to be relative to the totalWeight

        if randomNumber <= accumulatedWeight then
            return item.rarity
        end
    end
end

Config.Rarities.GetAllowedRarities = function(items)
    local allowedRarities = {}
    for rarity,_ in pairs(items) do
        allowedRarities[rarity] = true
    end
    return allowedRarities
end

Config.Rarities.CombineLabels = function(itemArray)
    local result = {}
    for item, count in pairs(itemArray) do
        table.insert(result, count .. "x " .. Config.ItemLabels[item])
    end

    local combinedResult = table.concat(result, ", ")

    local lastCommaIndex = combinedResult:find(", [^,]*$") -- Find the last comma and anything after it
    if lastCommaIndex then
        combinedResult = combinedResult:sub(1, lastCommaIndex - 1) .. " & " .. combinedResult:sub(lastCommaIndex + 2)
    end

    return combinedResult
end

local CombineNames = function(itemArray)
    local itemCounts = {}

    for _, item in ipairs(itemArray) do
        if itemCounts[item] then
            itemCounts[item] = itemCounts[item] + 1
        else
            itemCounts[item] = 1
        end
    end

    return itemCounts
end

Config.Rarities.GenerateItems = function(source, pointIndex, lucky)
    local pickaxeId = Player(source).state['mining:pickaxeId']
    local minePoint = Config.MinePoints[pointIndex]
    local results = {}

    CreateThread(function()
        FetchEquippedModItemsWithHandle(source, pickaxeId, nil, "maxItems", function(modItems)
            local items = minePoint.items
            local maxItems = minePoint.maxItems

            for _, modItem in pairs(modItems) do
                maxItems = modItem.handles.maxItems(modItem.modData, modItem.count, maxItems)
            end

            local rAmount = math.random(maxItems)
            for i=1, rAmount do
                local rarity = Config.Rarities.GenerateRarity(Config.Rarities.GetAllowedRarities(items))
                local item = type(items[rarity]) == "string" and items[rarity] or items[rarity][math.random(1, #items[rarity])]

                table.insert(results, item)
            end
        end)
    end)

    local cc = 0
    while #results == 0 do Wait(100); cc = cc + 1; if cc > 250 then break end end

    return results, CombineNames(results)
end
```

{% endtab %}

{% tab title="sv\_sql.lua" %}

```lua
CreateThread(function()
    Wait(5000)

    local itemsToInsert = {}
    local insertedItems = {}

    for _, modData in pairs(Config.ModificationItems) do
        table.insert(itemsToInsert, {
            name = modData.name,
            label = modData.label,
            desc = modData.description
        })
    end

    for _, itemData in pairs(Config.ExoticItems) do
        table.insert(itemsToInsert, {
            name = itemData.name,
            label = itemData.label,
            desc = itemData.description
        })
    end

    -- Insert journal into database
    table.insert(itemsToInsert, {
        name = Config.MiningJournal.name,
        label = Config.MiningJournal.label,
        desc = Config.MiningJournal.description,
        limit = 1,
        usable = 1
    })

    for _, itemData in pairs(itemsToInsert) do
        exports["vorp_inventory"]:getItemDB(itemData.name, function(data)
            if not data then
                exports.oxmysql:execute("INSERT INTO items (`item`, `label`, `limit`, `can_remove`, `type`, `usable`, `desc`) VALUES (@item, @label, @limit, @can_remove, @type, @usable, @desc)", {
                    ['item'] = itemData.name,
                    ['label'] = itemData.label,
                    ['limit'] = itemData.limit or 3,
                    ['can_remove'] = 1,
                    ['type'] = 'item_standard',
                    ['usable'] = itemData.usable or 0,
                    ['desc'] = itemData.desc
                }, function()
                    table.insert(insertedItems, itemData.name)
                    print("^3[ad_mining] ^7Inserted item into database:", itemData.name)
                end)
            end
        end)
    end

    Wait(500)

    if #insertedItems > 0 then
        print("^3█████╗ ██████╗          ███╗   ███╗██╗███╗  ██╗██╗███╗  ██╗ ██████╗ ")
        print("^3██╔══██╗██╔══██╗        ████╗ ████║██║████╗ ██║██║████╗ ██║██╔════╝ ")
        print("^3███████║██║  ██║        ██╔████╔██║██║██╔██╗██║██║██╔██╗██║██║  ██╗ ")
        print("^3██╔══██║██║  ██║        ██║╚██╔╝██║██║██║╚████║██║██║╚████║██║  ╚██╗")
        print("^3██║  ██║██████╔╝ █████╗ ██║ ╚═╝ ██║██║██║ ╚███║██║██║ ╚███║╚██████╔╝")
        print("^3╚═╝  ╚═╝╚═════╝  ╚════╝ ╚═╝     ╚═╝╚═╝╚═╝  ╚══╝╚═╝╚═╝  ╚══╝ ╚═════╝ ")
        print("^3████████████████████████████████████████████████████████████████████╗")
        print("^3╚═══════════════════════════════════════════════════════════════════╝")
        print("^3[ad_mining] ^7Successfully inserted " .. #insertedItems .. " items into database, please restart the server to load the items ingame.")
    end
end)
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.acura.gg/redm/ad_mining/unlocked-files.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
