# Custom Inventory

{% hint style="info" %}
This guide is intended for developers who want to use a custom inventory system that is not natively supported by the phone. You must have basic Lua knowledge to complete these steps.
{% endhint %}

## Custom Inventory Integration Guide

This guide describes how to integrate your custom inventory system with **GKSPHONE v2**.

### 1. Configuration Changes

Tell the phone to use the "custom" inventory setting.

{% stepper %}
{% step %}

### Configuration edit

Open `gksphone/config/config.lua`, find the `Config.Inventory` setting and set it to:

```lua
Config.Inventory = "custom"
```

{% endstep %}
{% endstepper %}

### 2. Server-Side Integration

You need to create a bridge file to handle server-side inventory actions. The phone checks `Config.Inventory`. When set to `"custom"`, the phone expects you to handle the logic. You may need to add your new server script to `fxmanifest.lua` or ensure it's loaded via existing mechanisms.

{% stepper %}
{% step %}

### Create server file

Navigate to `gksphone/server/inventory/` and create `custom.lua` (or modify an existing server script). Ideally, add your custom logic in `gksphone/server/inventory/`.&#x20;
{% endstep %}
{% endstepper %}

The phone expects the following server-side functions to be available (either globally or via the phone calling them). Implement these functions so the phone can interact with your inventory.

#### Required Functions

**SearchPhoneItems(source)**

Searches the player's inventory for the phone item(s). Return a table with item data (or an empty table).

```lua
--- Searches the player's inventory for the specified item.
--- @param source number The player's source ID.
--- @return table item data if found, an empty table otherwise.
function SearchPhoneItems(source)
    local itemData = {}
    -- Your Custom Inventory Logic Here
    -- Example (Pseudo-code):
    -- local playerItems = exports['my-inventory']:GetPlayerItems(source)
    -- for _, item in pairs(playerItems) do
    --     if Config.ItemName[item.name] then
    --         table.insert(itemData, item)
    --     end
    -- end
    return itemData
end
```

**SetItemData(source, item, data)**

Set the metadata of the phone item for a player.

```lua
--- Sets the metadata of an item for a player.
--- @param source number The player's source ID.
--- @param item table The item object (usually returned from SearchPhoneItems).
--- @param data table The metadata table to set.
--- @return boolean True if successful.
function SetItemData(source, item, data)
    -- Your Custom Inventory Logic Here
    -- Example:
    -- exports['my-inventory']:SetMetadata(source, item.slot, data)
    return true
end
```

**UpdateItemData(source, item, datatype, data)**

Update a specific key in the metadata.

```lua
function UpdateItemData(source, item, datatype, data)
    -- Your Custom Inventory Logic Here
    -- Example:
    -- local metadata = item.info or {}
    -- metadata[datatype] = data
    -- exports['my-inventory']:SetMetadata(source, item.slot, metadata)
end
```

**RegisterUsableItem**

Register phone items as usable so they open when clicked. Use your framework's registration method; if unavailable, use the phone-provided wrapper.

```lua
-- Register items defined in Config.ItemName
for itemName, _ in pairs(Config.ItemName) do
    -- Using QBCore or ESX native wrapper usually, 
    -- but for custom inventory, use your inventory's method.
    
    -- Example if using standard ESX/QB wrapper provided by the phone:
    RegisterUsableItem(itemName, function(source, item)
        TriggerClientEvent('gksphone:client:usePhone', source, itemName, item)
    end)
end
```

### 3. Client-Side Integration

If your inventory supports standard ESX/QB item usage events, integration may be automatic. If your inventory uses custom events for adding/removing items, add listeners on the client.

{% stepper %}
{% step %}

### Client file

Navigate to `gksphone/client/inventory/` and create `custom.lua` or modify `client.lua` to listen for your inventory events.
{% endstep %}
{% endstepper %}

#### Handling Item Removal

If the phone item is removed (dropped, used up, etc.), the phone UI should close. Example:

```lua
-- Example Event Listener
RegisterNetEvent('my-inventory:client:ItemRemoved', function(itemName, count)
    if Config.ItemName[itemName] then
        -- Check if it's the currently active phone
        if PhoneUniqueId and LastItemData and LastItemData.name == itemName then
            -- Calls the phone's internal cleanup function
            ItemPhoneDeleted()
        end
    end
end)
```

#### Handling Item Addition

If a player receives a phone, optionally force an update or open it.

```lua
RegisterNetEvent('my-inventory:client:ItemAdded', function(itemName)
    if Config.ItemName[itemName] then
        -- Optional: Logic when receiving a phone
    end
end)
```

### Checklist

* [x] Set `Config.Inventory = "custom"` in `config.lua`
* [x] Implement `SearchPhoneItems` in server-side script
* [x] Implement `SetItemData` / `UpdateItemData` in server-side script
* [x] Register Usable Items for phone models
* [x] Listen for item removal events on client-side

### Reference Example (Based on ox\_inventory)

If your custom inventory uses export-based methods similar to `ox_inventory`, you can structure your server/client code like the examples below.

#### Server-Side Example (`server/inventory/custom.lua`)

```lua
-- Ensure this code only runs if Config.Inventory is "custom"
if Config.Inventory ~= "custom" then return end

print('[GKSPHONE] Custom Inventory Loaded')

-- 1. SearchPhoneItems
-- Checks if the player has the phone item and returns its data (including slot and metadata)
function SearchPhoneItems(source)
    local src = source
    local itemData = {}
    
    -- Assuming your inventory has a search function like exports.my_inv:Search(source, type, item)
    -- Here we iterate through all configured phone items
    for itemName, _ in pairs(Config.ItemName) do
        -- Example: searching for items in 'slots'
        local foundItems = exports.my_inventory:Search(src, 'slots', itemName)
        if #foundItems > 0 then
            itemData = foundItems
            break -- Return the first valid phone found
        end
    end
    
    return itemData
end

-- 2. SetItemData
-- Updates metadata for a specific item slot
function SetItemData(source, item, data)
    local src = source
    if item and item.slot then
        -- Example: exports.my_inventory:SetMetadata(source, slot, data)
        exports.my_inventory:SetMetadata(src, item.slot, data)
        return true
    end
    return false
end

-- 3. UpdateItemData
-- Updates a SINGLE key within the metadata
function UpdateItemData(source, item, datatype, data)
    local src = source
    local metadata = item.metadata or item.info or {}
    metadata[datatype] = data
    
    -- Re-save the complete metadata object
    exports.my_inventory:SetMetadata(src, item.slot, metadata)
end

-- 4. Register Usable Items
-- This allows the item to open the phone when used from inventory
for itemName, _ in pairs(Config.ItemName) do
    -- Standard ESX/QB registration provided by the phone core usually handles "RegisterUsableItem"
    -- providing you trigger the event:
    RegisterUsableItem(itemName, function(source, item)
        TriggerClientEvent('gksphone:client:usePhone', source, itemName, item)
    end)
end
```

#### Client-Side Example (`client/inventory/custom.lua`)

```lua
if Config.Inventory ~= "custom" then return end

-- 1. Item Usage Export (if your inventory supports client-side use exports)
exports("UsePhoneItem", function(data, itemData)
    -- data contains generic info, itemData contains specific item info (metadata, slot)
    TriggerEvent("gksphone:client:usePhone", data.name, itemData)
end)

-- 2. Check Item Count for Jobs (Optional helper)
function JobCenterHasItem(itemName)
    local count = exports.my_inventory:Search('count', itemName)
    return count > 0
end

-- 3. Listen for Item Events (Added/Removed)
-- This is crucial for closing the phone if the item is removed while open
RegisterNetEvent("my_inventory:client:ItemRemoved", function(item, count)
    -- If the currently open phone is removed, close the interface
    if Config.ItemName[item] then
         if PhoneUniqueId and LastItemData and LastItemData.name == item then
            ItemPhoneDeleted()
        end
    end
end)
```


---

# 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.gkshop.org/gksphone-v2/configuration/custom-inventory-1.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.
