> For the complete documentation index, see [llms.txt](https://unknown-development.gitbook.io/unknown-development/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://unknown-development.gitbook.io/unknown-development/scripts/unknown_recycle.md).

# unknown\_recycle

<mark style="color:$info;">Are you searching for a realistic and rewarding civilian job for your FiveM server? Look no further!</mark>\ <mark style="color:$info;">Our Recycle Job system delivers a modern and immersive working experience designed for long-term roleplay.</mark>

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>Buy yours now</td><td><a href="https://unknown-development.tebex.io/package/recycle">https://unknown-development.tebex.io/package/recycle</a></td></tr><tr><td>Checkout all our scripts</td><td><a href="https://unknown-development.tebex.io/category/3172823">https://unknown-development.tebex.io/category/3172823</a></td></tr></tbody></table>

## Showcase

YT video here

## Config

{% tabs %}
{% tab title="config.lua" %}

```lua
Config = {}

-- Framework
Config.Framework = 'qb' -- 'esx', 'qb', 'qbox'

-- Inventory
Config.Inventory = 'ox_inventory' -- 'ox_inventory', 'qb-inventory', or 'esx' (ESX native inventory)

-- Target
Config.Target = 'ox_target' -- 'ox_target', 'qb-target', 'bt-target'

-- Minigame (OPTIONAL, only if Config.UseMinigames = true)
Config.Minigame = 'bl_ui' -- 'bl_ui', 'devhub_hackingMinigames', 'devhub_minigames', 'ox_lib', 'ps-ui' (DON'T FORGET TO CONFIGURE MINIGAME SETTINGS IN SHARED/MINIGAMES.LUA)

-- Progress bar
Config.ProgressBar = 'ox_lib_circle' -- 'ox_lib_bar', 'ox_lib_circle', 'qb-core', 'unknown_ui' (UNRELEASED...), 'progressBars'

-- Notification
Config.Notify = 'ox_lib' -- 'ox_lib', 'qb-core', 'esx', 'unknown_ui' (UNRELEASED...), 'okokNotify'

-- Locale
Config.Locale = 'en' -- 'en', 'lt'

-- Blip settings
Config.Blip = {
    enable = true,
    coords = vector3(-349.9062, -1542.6182, 27.7235),
    sprite = 467,
    color = 2,
    scale = 0.9,
    label = "Recycle Center",
}

-- Sorting locations (DO NOT CHANGE)
Config.SortingLocations = {
    {
        coords = vector3(-351.5346, -1546.4781, 27.5572),
        radius = 0.3,
    },
    {
        coords = vector3(-351.5483, -1545.0939, 27.5572),
        radius = 0.3,
    },
    {
        coords = vector3(-351.5702, -1543.6439, 27.5572),
        radius = 0.3,
    },
    {
        coords = vector3(-351.4867, -1542.2240, 27.5572),
        radius = 0.3,
    },
    {
        coords = vector3(-351.5028, -1540.7899, 27.5572),
        radius = 0.3,
    },
    {
        coords = vector3(-351.4832, -1539.3816, 27.5572),
        radius = 0.3,
    },
    {
        coords = vector3(-351.4916, -1538.0209, 27.5572),
        radius = 0.3,
    },
}

-- Sorting items
Config.SortableItems = {
    ["plastic"] = {
        name = "plastic",
        label = "Plastic",
        processingTime = 10000, -- ms
        animations = {
            dict = "mini@repair",
            clip = "fixing_a_ped"
        },
        inputs = {
            {item = "plastic", amount = 1}
        },
        outputs = {
            {item = "phone", minAmount = 1, maxAmount = 3, chance = 0},
            {item = "lockpick", minAmount = 1, maxAmount = 2, chance = 0}
        }
    },
    ["phone"] = {
        name = "phone",
        label = "Phone",
        processingTime = 15000,
        animations = {
            dict = "mini@repair",
            clip = "fixing_a_ped"
        },
        inputs = {
            {item = "phone", amount = 1}
        },
        outputs = {
            {item = "iron", minAmount = 1, maxAmount = 2, chance = 80},
            {item = "aluminum", minAmount = 1, maxAmount = 2, chance = 60},
            {item = "copper", minAmount = 1, maxAmount = 1, chance = 40}
        }
    },
    ["paper"] = {
        name = "paper",
        label = "Paper",
        processingTime = 8000,
        animations = {
            dict = "mini@repair",
            clip = "fixing_a_ped"
        },
        inputs = {
            {item = "paper", amount = 1}
        },
        outputs = {
            {item = "paper_sorted", minAmount = 2, maxAmount = 4, chance = 90},
            {item = "money", minAmount = 100, maxAmount = 500, chance = 10}
        }
    }
}

-- Markers (NOT RECOMMENDED TO CHANGE)
Config.Marker = {
    type = 6,
    size = vector3(0.5, 0.5, 0.5),
    color = {r = 255, g = 255, b = 255, a = 200},
    drawDistance = 15.0
}

Config.UseMinigames = true

-- Debug
Config.Debug = false
```

{% endtab %}

{% tab title="shared/framework.lua" %}

```lua
Framework = {}

function Framework:GetCurrent()
    if Config.Framework == 'esx' and GetResourceState('es_extended') == 'started' then
        return 'esx'
    elseif Config.Framework == 'qb' and GetResourceState('qb-core') == 'started' then
        return 'qb'
    elseif Config.Framework == 'qbox' and GetResourceState('qbx_core') == 'started' then
        return 'qbox'
    end
    return nil
end

function Framework:GetPlayerData(source)
    local framework = self:GetCurrent()
    
    if framework == 'esx' then
        local ESX = exports['es_extended']:getSharedObject()
        local xPlayer = ESX.GetPlayerFromId(source)
        return {
            source = source,
            identifier = xPlayer.identifier,
            inventory = xPlayer.inventory
        }
    elseif framework == 'qb' then
        local QBCore = exports['qb-core']:GetCoreObject()
        local Player = QBCore.Functions.GetPlayer(source)
        return {
            source = source,
            identifier = Player.PlayerData.citizenid,
            inventory = Player.PlayerData.items
        }
    elseif framework == 'qbox' then
        local Player = exports['qbx_core']:GetPlayer(source)
        return {
            source = source,
            identifier = Player.PlayerData.citizenid,
            inventory = Player.PlayerData.items
        }
    end
    return nil
end

function Framework:HasItem(source, itemName, amount)
    amount = amount or 1
    
    if Config.Inventory == 'ox_inventory' then
        local count = exports.ox_inventory:Search(source, 'count', itemName)
        return count >= amount, count
    elseif Config.Inventory == 'qb-inventory' then
        return exports['qb-inventory']:HasItem(source, itemName, amount)
    elseif Config.Inventory == 'esx' then
        local ESX = exports['es_extended']:getSharedObject()
        local xPlayer = ESX.GetPlayerFromId(source)
        local item = xPlayer.getInventoryItem(itemName)
        if item and item.count >= amount then
            return true, item.count
        end
    end
    
    return false, 0
end

function Framework:RemoveItem(source, itemName, amount)
    if Config.Inventory == 'ox_inventory' then
        return exports.ox_inventory:RemoveItem(source, itemName, amount)
    elseif Config.Inventory == 'qb-inventory' then
        return exports['qb-inventory']:RemoveItem(source, itemName, amount, false, false, 'unknown_recycle:RemoveSortedItem')
    elseif Config.Inventory == 'esx' then
        local ESX = exports['es_extended']:getSharedObject()
        local xPlayer = ESX.GetPlayerFromId(source)
        return xPlayer.removeInventoryItem(itemName, amount)
    end
end

function Framework:AddItem(source, itemName, amount)
    if Config.Inventory == 'ox_inventory' then
        return exports.ox_inventory:AddItem(source, itemName, amount)
    elseif Config.Inventory == 'qb-inventory' then
        return exports['qb-inventory']:AddItem(source, itemName, amount, false, false, 'unknown_recycle:GiveSortedItem')
    elseif Config.Inventory == 'esx' then
        local ESX = exports['es_extended']:getSharedObject()
        local xPlayer = ESX.GetPlayerFromId(source)
        return xPlayer.addInventoryItem(itemName, amount)
    end

end

function Framework:CanCarryItem(source, itemName, amount)
    if Config.Inventory == 'ox_inventory' then
        return exports.ox_inventory:CanCarryItem(source, itemName, amount)
    elseif Config.Inventory == 'qb-inventory' then
        return exports['qb-inventory']:CanAddItem(source, itemName, amount)
    elseif Config.Inventory == 'esx' then
        local ESX = exports['es_extended']:getSharedObject()
        local xPlayer = ESX.GetPlayerFromId(source)
        return xPlayer.CanCarryItem(itemName, amount)
    end
    return true
end

return Framework
```

{% endtab %}

{% tab title="shared/minigames.lua" %}

```lua
function StartMinigame(callback)
    if Config.Minigame == 'ox_lib' and GetResourceState('ox_lib') == 'started' then
        local success = lib.skillCheck({'easy', 'easy', 'easy'}, {'w', 'a', 's', 'd'})
        if callback then callback(success) end
        return success
        
    elseif Config.Minigame == 'bl_ui' and GetResourceState('bl_ui') == 'started' then
        local success = exports['bl_ui']:RapidLines(2, 70, 3)
        if callback then callback(success) end
        return success
        
    elseif Config.Minigame == 'devhub_hackingMinigames' and GetResourceState('devhub_hackingMinigames') == 'started' then
        local success = exports['devhub_hackingMinigames']:startMinigame('morse', 60)
        if callback then callback(success) end
        return success

    elseif Config.Minigame == 'devhub_minigames' and GetResourceState('devhub_minigames') == 'started' then
        local success = exports['devhub_minigames']:startMinigame("minigame_2", "medium")
        if callback then callback(success) end
        return success
    
    elseif Config.Minigame == 'ps-ui' and GetResourceState('ps-ui') == 'started' then
        local success = exports['ps-ui']:Thermite(10, 5, 3) -- Time, Gridsize, IncorrectBlocks
        if callback then callback(success) end
        return success
    end

end
```

{% endtab %}

{% tab title="shared/notify.lua" %}

```lua
function Notify(source, message, type)
    if not source or source == 0 then
        -- Client-side
        if Config.Notify == 'ox_lib' and GetResourceState('ox_lib') == 'started' then
            lib.notify({
                title = 'Recycle',
                description = message,
                type = type or 'inform'
            })
        elseif Config.Notify == 'qb-core' and GetResourceState('qb-core') == 'started' then
            local QBCore = exports['qb-core']:GetCoreObject()
            if type == 'error' then
                QBCore.Functions.Notify(message, 'error')
            elseif type == 'success' then
                QBCore.Functions.Notify(message, 'success')
            else
                QBCore.Functions.Notify(message, 'primary')
            end
        elseif Config.Notify == 'esx' and GetResourceState('es_extended') == 'started' then
            local ESX = exports['es_extended']:getSharedObject()
            ESX.ShowNotification(message)
        elseif Config.Notify == 'unknown_ui' and GetResourceState('unknown_ui') == 'started' then
            exports['unknown_ui']:showNotify(type, 'Recycle', message, 5000, "#4CAF50", "fa-solid fa-recycle")
        elseif Config.Notify == 'okokNotify' and GetResourceState('okokNotify') == 'started' then
            exports['okokNotify']:Alert('Recycle', message, 5000, type or 'info', true)
        else
            -- Fallback GTA notification
            BeginTextCommandThefeedPost('STRING')
            AddTextComponentSubstringPlayerName(message)
            EndTextCommandThefeedPostTicker(true, true)
        end
    else
        -- Server-side
        if Config.Notify == 'ox_lib' then
            TriggerClientEvent('ox_lib:notify', source, {
                description = message,
                type = type or 'inform'
            })
        elseif Config.Notify == 'qb-core' then
            TriggerClientEvent('QBCore:Notify', source, message, type or 'primary')
        elseif Config.Notify == 'esx' then
            TriggerClientEvent('esx:showNotification', source, message)
        elseif Config.Notify == 'unknown_ui' then
            TriggerClientEvent('unknown_ui:notify:show', source, type, 'Recycle', message, 5000, "#4CAF50", "fa-solid fa-recycle")
        elseif Config.Notify == 'okokNotify' then
            TriggerClientEvent('okokNotify:Alert', source, 'Recycle', message, 5000, type or 'info', true)
        end
    end
end

function LNotify(source, key, type, ...)
    local locale = Locales[Config.Locale] or Locales['en']
    local message = locale[key] or key
    
    if ... then
        local args = {...}
        message = message:gsub('%%s', function()
            return table.remove(args, 1) or '%s'
        end)
    end
    
    Notify(source, message, type)
end
```

{% endtab %}

{% tab title="shared/progressbar.lua" %}

```lua
function ProgressBar(source, label, duration, options)
    options = options or {}
        -- Client-side
        if Config.ProgressBar == 'ox_lib_bar' and GetResourceState('ox_lib') == 'started' then
            if lib.progressBar({
                duration = duration,
                label = label,
                useWhileDead = options.useWhileDead or false,
                canCancel = options.canCancel or true,
                disable = options.disable or {
                    car = true,
                    move = true,
                    combat = true
                },
                anim = options.anim or {},
                onCancel = options.onCancel,
                onFinish = options.onFinish
            }) then
                return true
            else
                if options.onCancel then options.onCancel() end
                return false
            end
        elseif Config.ProgressBar == 'ox_lib_circle' and GetResourceState('ox_lib') == 'started' then
            if lib.progressCircle({
                duration = duration,
                position = 'bottom',
                label = label,
                useWhileDead = options.useWhileDead or false,
                canCancel = options.canCancel or true,
                disable = options.disable or {
                    car = true,
                    move = true,
                    combat = true
                },
                anim = options.anim or {},
                onCancel = options.onCancel,
                onFinish = options.onFinish
            }) then
                return true
            else
                if options.onCancel then options.onCancel() end
                return false
            end
            
        elseif Config.ProgressBar == 'qb-core' and GetResourceState('qb-core') == 'started' then
            local QBCore = exports['qb-core']:GetCoreObject()
            QBCore.Functions.Progressbar('recycle_progress', label, duration, false, true, {
                disableMovement = true,
                disableCarMovement = true,
                disableMouse = false,
                disableCombat = true,
            }, options.anim or {}, {}, {}, function()
                if options.onFinish then options.onFinish() end
            end, function()
                if options.onCancel then options.onCancel() end
            end)
            return true

        elseif Config.ProgressBar == 'unknown_ui' and GetResourceState('unknown_ui') == 'started' then
            exports['unknown_ui']:showProgress({
                icon = "fa-solid fa-spinner fa-spin",
                duration = duration,
                label = label,
                canCancel = true,
                disable = {
                    move = true,
                    attack = true
                },
                anim = options.anim or {},
            })
            Wait(duration)
            return true
            
        elseif Config.ProgressBar == 'progressBars' and GetResourceState('progressBars') == 'started' then
            exports['progressBars']:startUI(duration, label)
            Wait(duration)
            return true
            
        else
            -- Fallback progress bar
            local startTime = GetGameTimer()
            while GetGameTimer() - startTime < duration do
                Wait(0)
                local elapsed = GetGameTimer() - startTime
                local progress = elapsed / duration
                
                SetTextFont(4)
                SetTextScale(0.5, 0.5)
                SetTextColour(255, 255, 255, 255)
                SetTextOutline()
                BeginTextCommandDisplayText("STRING")
                AddTextComponentSubstringPlayerName(label)
                EndTextCommandDisplayText(0.5, 0.9)
                
                DrawRect(0.5, 0.95, 0.2, 0.03, 0, 0, 0, 150)
                DrawRect(0.5, 0.95, 0.2 * progress, 0.025, 255, 255, 255, 200)
                
                if IsControlJustPressed(0, 200) then -- ESC pressed
                    return false
                end
            end
        return true
    end
end
```

{% endtab %}
{% endtabs %}

## Locales

{% tabs %}
{% tab title="locales/locales.lua" %}

```lua
Locales = {
    ['en'] = {
        -- Notifications
        ['already_sorting'] = 'You are already sorting items!',
        ['starting_sorting'] = 'Starting sorting process...',
        ['sorting_failed'] = 'Sorting failed!',
        ['processing_items'] = 'Processing %s...',
        ['sorting_cancelled'] = 'Sorting cancelled!',
        ['sorting_completed'] = 'Sorting completed successfully!',
        ['no_sortable_items'] = 'You don\'t have any items that can be sorted!',
        ['not_enough_items'] = 'You don\'t have enough items!',
        ['inventory_full'] = 'Your inventory is full!',
        ['inventory_full_items'] = 'Cannot carry: %s',
        ['sorting_results'] = 'Sorting results:\n%s',
        ['no_output'] = 'Sorting produced no results!',
        ['player_not_found'] = 'Player not found!',
        ['invalid_item'] = 'Invalid item!',
        ['location_in_use'] = 'This location is already in use by another player!',
        
        -- Dialogs & Menus
        ['select_item_to_sort'] = 'Select Item to Sort',
        ['item_amount_desc'] = 'Available: %s',
        ['sorting_amount'] = 'Sorting Amount',
        ['select_amount'] = 'Select amount to sort (max: %s)',
        ['sorting_duration_calc'] = 'Processing time per item: %s sec | Max amount: %s | Total max time: %s sec',
        ['cancel'] = 'Cancel',
        ['cancel_desc'] = 'Go back',
        
        -- Target
        ['start_sorting'] = 'Start Sorting'
    },
    
    ['lt'] = {
        -- Notifications
        ['already_sorting'] = 'Jau vykdote rūšiavimą!',
        ['starting_sorting'] = 'Pradedamas rūšiavimo procesas...',
        ['sorting_failed'] = 'Rūšiavimas nepavyko!',
        ['processing_items'] = 'Apdorojama %s...',
        ['sorting_cancelled'] = 'Rūšiavimas atšauktas!',
        ['sorting_completed'] = 'Rūšiavimas sėkmingai užbaigtas!',
        ['no_sortable_items'] = 'Neturite daiktų, kuriuos galima rūšiuoti!',
        ['not_enough_items'] = 'Neturite pakankamai daiktų!',
        ['inventory_full'] = 'Jūsų inventorius pilnas!',
        ['inventory_full_items'] = 'Negalima nešioti: %s',
        ['sorting_results'] = 'Rūšiavimo rezultatai:\n%s',
        ['no_output'] = 'Rūšiavimas nedavė jokių rezultatų!',
        ['player_not_found'] = 'Žaidėjas nerastas!',
        ['invalid_item'] = 'Netinkamas daiktas!',
        ['location_in_use'] = 'Ši vieta jau naudojama kito žaidėjo!',
        
        -- Dialogs & Menus
        ['select_item_to_sort'] = 'Pasirinkite daiktą rūšiavimui',
        ['item_amount_desc'] = 'Turimas kiekis: %s',
        ['sorting_amount'] = 'Rūšiavimo kiekis',
        ['select_amount'] = 'Pasirinkite kiekį rūšiavimui (maks.: %s)',
        ['sorting_duration_calc'] = 'Apdorojimo laikas vienam: %s sec | Maks. kiekis: %s | Bendras laikas maks.: %s sec',
        ['cancel'] = 'Atšaukti',
        ['cancel_desc'] = 'Grįžti atgal',
        
        -- Target
        ['start_sorting'] = 'Pradėti rūšiavimą'
    }
}
```

{% 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:

```
GET https://unknown-development.gitbook.io/unknown-development/scripts/unknown_recycle.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.
