# framework bridge

## Overview

The script uses an editable bridge system to support any framework. All framework-specific functions are located in two files:

* `modules/editable_client.lua` - Client-side functions
* `modules/editable_server.lua` - Server-side functions

## Client-Side Bridge

### File: `modules/editable_client.lua`

#### ESX (Default)

```lua
Editable = Editable or {}

function Editable.GetPlayerGroup()
    local xPlayer = ESX.GetPlayerData()
    if xPlayer then
        return xPlayer.job and xPlayer.job.grade_name or 'user'
    end
    return 'user'
end

function Editable.ShowNotification(message)
    ESX.ShowNotification(message)
end

function Editable.GetPlayerName()
    local xPlayer = ESX.GetPlayerData()
    if xPlayer then
        return xPlayer.name or GetPlayerName(PlayerId())
    end
    return GetPlayerName(PlayerId())
end
```

#### QB-Core

```lua
Editable = Editable or {}

local QBCore = exports['qb-core']:GetCoreObject()

function Editable.GetPlayerGroup()
    local PlayerData = QBCore.Functions.GetPlayerData()
    if PlayerData and PlayerData.job then
        return PlayerData.job.grade.name or 'user'
    end
    return 'user'
end

function Editable.ShowNotification(message)
    QBCore.Functions.Notify(message, 'primary')
end

function Editable.GetPlayerName()
    local PlayerData = QBCore.Functions.GetPlayerData()
    if PlayerData and PlayerData.charinfo then
        return PlayerData.charinfo.firstname .. ' ' .. PlayerData.charinfo.lastname
    end
    return GetPlayerName(PlayerId())
end
```

#### OX Core

```lua
Editable = Editable or {}

local Ox = require '@ox_core.lib.init'

function Editable.GetPlayerGroup()
    local player = Ox.GetPlayer()
    if player then
        return player.getGroup() or 'user'
    end
    return 'user'
end

function Editable.ShowNotification(message)
    lib.notify({ description = message })
end

function Editable.GetPlayerName()
    local player = Ox.GetPlayer()
    if player then
        return player.get('name') or GetPlayerName(PlayerId())
    end
    return GetPlayerName(PlayerId())
end
```

#### Standalone

```lua
Editable = Editable or {}

function Editable.GetPlayerGroup()
    -- Implement your own logic
    return 'user'
end

function Editable.ShowNotification(message)
    -- Use native notification
    SetNotificationTextEntry('STRING')
    AddTextComponentString(message)
    DrawNotification(false, false)
end

function Editable.GetPlayerName()
    return GetPlayerName(PlayerId())
end
```

## Server-Side Bridge

### File: `modules/editable_server.lua`

#### ESX (Default)

```lua
Editable = Editable or {}

function Editable.GetPlayerGroup(playerId)
    local xPlayer = ESX.GetPlayerFromId(playerId)
    if xPlayer then
        return xPlayer.getGroup()
    end
    return 'user'
end

function Editable.IsPlayerInGroup(playerId, groups)
    local playerGroup = Editable.GetPlayerGroup(playerId)
    for _, group in ipairs(groups) do
        if playerGroup == group then
            return true
        end
    end
    return false
end

function Editable.GetPlayerName(playerId)
    return GetPlayerName(playerId) or 'Unknown'
end

function Editable.ShowNotification(playerId, message)
    local xPlayer = ESX.GetPlayerFromId(playerId)
    if xPlayer then
        xPlayer.showNotification(message)
    end
end
```

#### QB-Core

```lua
Editable = Editable or {}

local QBCore = exports['qb-core']:GetCoreObject()

function Editable.GetPlayerGroup(playerId)
    local Player = QBCore.Functions.GetPlayer(playerId)
    if Player then
        -- Check if admin/mod via QBCore permissions
        if QBCore.Functions.HasPermission(playerId, 'admin') then
            return 'admin'
        elseif QBCore.Functions.HasPermission(playerId, 'mod') then
            return 'mod'
        end
        return Player.PlayerData.job.grade.name or 'user'
    end
    return 'user'
end

function Editable.IsPlayerInGroup(playerId, groups)
    local playerGroup = Editable.GetPlayerGroup(playerId)
    for _, group in ipairs(groups) do
        if playerGroup == group then
            return true
        end
    end
    -- Also check QBCore permissions
    for _, group in ipairs(groups) do
        if QBCore.Functions.HasPermission(playerId, group) then
            return true
        end
    end
    return false
end

function Editable.GetPlayerName(playerId)
    local Player = QBCore.Functions.GetPlayer(playerId)
    if Player then
        return Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
    end
    return GetPlayerName(playerId) or 'Unknown'
end

function Editable.ShowNotification(playerId, message)
    TriggerClientEvent('QBCore:Notify', playerId, message, 'primary')
end
```

#### OX Core

```lua
Editable = Editable or {}

local Ox = require '@ox_core.lib.server'

function Editable.GetPlayerGroup(playerId)
    local player = Ox.GetPlayer(playerId)
    if player then
        return player.getGroup() or 'user'
    end
    return 'user'
end

function Editable.IsPlayerInGroup(playerId, groups)
    local playerGroup = Editable.GetPlayerGroup(playerId)
    for _, group in ipairs(groups) do
        if playerGroup == group then
            return true
        end
    end
    return false
end

function Editable.GetPlayerName(playerId)
    local player = Ox.GetPlayer(playerId)
    if player then
        return player.get('name') or GetPlayerName(playerId)
    end
    return GetPlayerName(playerId) or 'Unknown'
end

function Editable.ShowNotification(playerId, message)
    TriggerClientEvent('ox_lib:notify', playerId, { description = message })
end
```

#### Standalone

```lua
Editable = Editable or {}

function Editable.GetPlayerGroup(playerId)
    -- Implement your own ACE permission check
    if IsPlayerAceAllowed(playerId, 'admin') then
        return 'admin'
    elseif IsPlayerAceAllowed(playerId, 'mod') then
        return 'mod'
    end
    return 'user'
end

function Editable.IsPlayerInGroup(playerId, groups)
    local playerGroup = Editable.GetPlayerGroup(playerId)
    for _, group in ipairs(groups) do
        if playerGroup == group then
            return true
        end
    end
    return false
end

function Editable.GetPlayerName(playerId)
    return GetPlayerName(playerId) or 'Unknown'
end

function Editable.ShowNotification(playerId, message)
    TriggerClientEvent('chat:addMessage', playerId, {
        args = { 'SYSTEM', message }
    })
end
```

## Function Reference

### Client Functions

| Function                             | Description                         | Returns  |
| ------------------------------------ | ----------------------------------- | -------- |
| `Editable.GetPlayerGroup()`          | Get current player's group/rank     | `string` |
| `Editable.ShowNotification(message)` | Display notification to player      | `void`   |
| `Editable.GetPlayerName()`           | Get current player's character name | `string` |

### Server Functions

| Function                                       | Description                             | Returns   |
| ---------------------------------------------- | --------------------------------------- | --------- |
| `Editable.GetPlayerGroup(playerId)`            | Get player's group/rank                 | `string`  |
| `Editable.IsPlayerInGroup(playerId, groups)`   | Check if player is in any of the groups | `boolean` |
| `Editable.GetPlayerName(playerId)`             | Get player's character name             | `string`  |
| `Editable.ShowNotification(playerId, message)` | Send notification to player             | `void`    |

## Group System

The group system is used for:

{% stepper %}
{% step %}

### Command Restrictions

Limiting commands to specific groups.
{% endstep %}

{% step %}

### Name Colors

Different colors for different groups.
{% endstep %}

{% step %}

### Report Routing

Sending reports to admin groups.
{% endstep %}
{% endstepper %}

### Example Group Colors

```lua
GroupRoles = {
    ['admin'] = 'rgba(255, 0, 0, 0.85)',      -- Red for admins
    ['mod'] = 'rgba(255, 165, 0, 0.85)',      -- Orange for mods
    ['helper'] = 'rgba(0, 255, 0, 0.85)',     -- Green for helpers
    ['vip'] = 'rgba(255, 215, 0, 0.85)',      -- Gold for VIPs
    ['user'] = 'rgba(255, 255, 255, 0.85)'    -- White for regular users
}
```

## Modifying fxmanifest.lua

If you change from ESX to another framework, update `fxmanifest.lua`:

### ESX (Default)

```lua
shared_scripts {
    '@es_extended/imports.lua',
    '@ox_lib/init.lua',
}
```

### QB-Core

```lua
shared_scripts {
    '@qb-core/shared/locale.lua',
    '@ox_lib/init.lua',
}
```

### OX Core

```lua
shared_scripts {
    '@ox_lib/init.lua',
}
```

### Standalone

```lua
shared_scripts {
    '@ox_lib/init.lua',
}
```

## Next Steps

* [📤 Exports](https://scriptlock.gitbook.io/script-lock-docs/resources/chat-system/exports) - Available exports
* [📋 Logs Configuration](https://scriptlock.gitbook.io/script-lock-docs/resources/chat-system/logs) - Discord logging
* [🗺️ Localization](https://scriptlock.gitbook.io/script-lock-docs/resources/chat-system/localization) - Language settings
