# SLEEK MULTI CHARACTER

{% embed url="<https://youtu.be/-N8wP8xNJEg?si=kOl1-JzfvlhXgUJf>" %}

{% hint style="danger" %}
To use this script, you also need the **FORGE-CHARCREATOR**, both are purchased together so you should have no problem installing them together.
{% endhint %}

{% hint style="success" %}
This script is compatible with **ESX**, **QB, QBOX** and **Illenium**.
{% endhint %}

{% hint style="success" %}
This script is compatible with **Quasar Inventory**, **QB Inventory and OX Inventory**.
{% endhint %}

**INSTALLATION GUIDE**

{% tabs %}
{% tab title="ESX" %}

#### **1️⃣ Download & Extract**

* Download **forge-multicharacter.pack.zip** from **KEYMASTER**.
* Unzip it and place the **forge-multicharacter** folder inside your server's `resources` directory.

**2️⃣ Add to Server Startup**

* Open your **server.cfg** and add the following line:

  ```plaintext
  ensure forge-multicharacter
  ```
* **Do not rename the folder**—it must remain as `forge-multicharacter`, or the resource will not work properly.
* Ensure it is placed **just below your core resources** for proper loading.

**3️⃣ Remove Conflicting Scripts**

* **Delete or remove** any other MultiCharacter script you previously installed, such as **esx\_multicharacter**.
* If you are using **ESX + Illenium**, you must also **remove the following scripts**:
  * `esx_skin`
  * `skinchanger`
* ⚠ **If you are using ESX + Default, do NOT delete these scripts.**

**4️⃣ Enable MultiCharacter in ESX\_Extended**

* In **es\_extended**, replace the MultiCharacter setting with:

  ```lua
  GetResourceState("forge-multicharacter") ~= "missing"
  ```

  * ✅ **This must be enabled even if you are using only one character slot.**
  * It should look like the **screenshot** provided.

**5️⃣ Install SQL Database**

* You **must install the correct SQL file**, as there is **one version for ESX and another for QB-Core**.
* Ensure you import the correct database structure for your framework.

**6️⃣ Role-Based Character Access (Optional)**

* If you want to use **role-based character access**, you need to:
  * **Create a** [**Discord bot**](https://discord.com/login?redirect_to=%2Fdevelopers%2Fapplications) and add it to your Discord server.
  * Properly configure the **bot token and guild ID** in the config.
  * Follow the linked [**tutorial** ](/codeforge/sleek-series/sleek-multi-character/discord-integration.md)for setting up role-based access.
* **Bot configuration & Discord integration** must be set up in:
  * `sv_config.lua` (first step)
  * `config.lua` (final adjustments)

**7️⃣ Clear Cache & Restart Server**

* **Clear the cache** of both your server and your FiveM client.
* **Restart your entire server** with `forge-multicharacter` **properly ensured** in your `server.cfg`.

🚀 Once installed, everything should be working smoothly!
{% endtab %}

{% tab title="QB" %}

#### **1️⃣ Download & Extract**

* Download **forge-multicharacter.pack.zip** from **KEYMASTER**.
* Unzip it and place the **forge-multicharacter** folder inside your server's `resources` directory.

**2️⃣ Add to Server Startup**

* Open your **server.cfg** and add the following line:

  ```plaintext
  ensure forge-multicharacter
  ```
* **Do not rename the folder**—it must remain as `forge-multicharacter`, or the resource will not function correctly.
* Ensure it is placed **just below your core resources** for proper loading.

**3️⃣ Remove Conflicting Scripts**

* **Delete or remove** any other MultiCharacter script you previously installed, such as **qb-multicharacter**.

**4️⃣ If Using QB-Core + Illenium**

* Navigate to the following file:

  ```
  illenium-appearance/client/framework/esx/compatibility.lua
  ```
* **At line 1** *(this may vary depending on your version, so it’s best to search for the function directly)*, **comment out or remove**:

  ```lua
  if not Framework.ESX() then return end
  ```

**5️⃣ Install SQL Database**

* You **must install the correct SQL file**, as there is **one version for ESX and another for QB-Core**.
* Ensure you import the correct database structure for your framework.

**6️⃣ Role-Based Character Access (Optional)**

* If you want to use **role-based character access**, you need to:
  * **Create a** [**Discord bot**](https://discord.com/login?redirect_to=%2Fdevelopers%2Fapplications) and add it to your Discord server.
  * Properly configure the **bot token and guild ID** in the config.
  * Follow the linked [**tutorial** ](/codeforge/sleek-series/sleek-multi-character/discord-integration.md)for setting up role-based access.
* **Bot configuration & Discord integration** must be set up in:
  * `sv_config.lua` (first step)
  * `config.lua` (final adjustments)

**7️⃣ Required Step for QB-Clothing Users (One-Time Only)**

If you're using `qb-clothing`, you **must** add the following block of code to ensure full compatibility with all Forge scripts that rely on skin handling.

> ⚠️ **Note:** This is a **common requirement** for all Forge scripts using `skin`. You only need to add this **once**—do **not** repeat it for each script.

📂 **File to edit:**

```
qb-clothing/client/main.lua
```

📌 **Add this block of code:**

```lua
RegisterNetEvent('qb-clothing:setSkinData', function(key, index, texture)
    skinData[key] = skinData[key] or {}
    skinData[key].item = index
    skinData[key].texture = texture
end)

RegisterNetEvent('qb-clothing:saveSkin', function()
    SaveSkin()
end)

AddEventHandler('qb-clothing:client:getSkin', function(cb)
    cb(skinData)
end)
```

💡 **Tip:** Place this code at the **bottom** of the file or next to other event handlers.\
It’s essential for proper integration between Forge scripts and the QB-Clothing system.

**8️⃣ Clear Cache & Restart Server**

* **Clear the cache** of both your server and your FiveM client.
* **Restart your entire server** with `forge-multicharacter` **properly ensured** in your `server.cfg`.

🚀 Once installed, everything should be working smoothly!
{% endtab %}

{% tab title="QBOX" %}
**1️⃣ Important Notes**

* This script **works with QB functions**, but **requires additional modifications** to work with **QBOX**.
* You **must select the QB framework** and **follow all QB setup steps**, plus the **additional changes** for QBOX detailed below.

***

**2️⃣ Download & Extract**

* Download **forge-multicharacter.pack.zip** from **KEYMASTER**.
* Unzip it and place the **forge-multicharacter** folder inside your server's `resources` directory.

***

**3️⃣ Add to Server Startup**

* Open your **server.cfg** and add the following line:

  ```plaintext
  ensure forge-multicharacter
  ```
* **Do not rename the folder**—it must remain as `forge-multicharacter`, or the resource will not function correctly.
* Ensure it is placed **just below your core resources** for proper loading.

***

**4️⃣ Remove Conflicting Scripts**

* **Delete or remove** any other MultiCharacter script you previously installed, such as **qbox-multicharacter**.

If you're using the **default character system from QBOX**, make sure to enable external character support:

1. Go to:\
   `qbx_core/config/client.lua`
2. Find the line:

   ```lua
   useExternalCharacters = false
   ```
3. Change it to:

   ```lua
   useExternalCharacters = true
   ```

⚠️ **Important:**\
If you don’t enable this setting, **our script will not work properly**.

***

**5️⃣ If Using QBOX-Core + Illenium**

* Navigate to the following file:

  ```lua
  illenium-appearance/client/framework/esx/compatibility.lua
  ```
* **At line 1** *(this may vary depending on your version, so it’s best to search for the function directly)*, **comment out or remove**:

  ```lua
  if not Framework.ESX() then return end
  ```

***

**6️⃣ Modify QBOX-Core to Ensure Compatibility**

* You **must add a function** to your **QBOX core** for proper citizen ID generation.
* Open:

  ```
  qbox_core > bridge > qb > server > player.lua
  ```
* **Add the following function**:

  ```lua
  function playerObj.CreateCitizenId()
      return exports['qbx_core']:GenerateUniqueIdentifier('citizenid')
  end
  ```
* ✅ This change **ensures that QBOX correctly generates Citizen IDs** for new characters.

***

**7️⃣ If You Still Have Issues**

* **Modify the primary identifier in forge-multicharacter.**
* Open:

  ```lua
  forge-multicharacter/server/frameworks/QB.lua
  ```
* **Change `license` to `license2`** inside the function:

  ```lua
  ST.QB:PRIMARY_IDENTIFIER()
  ```

***

**8️⃣ Install SQL Database**

* You **must install the correct SQL file**, as there is **one version for ESX and another for QB/QBOX**.
* Ensure you import the correct database structure for your framework.

***

**9️⃣ Role-Based Character Access (Optional)**

* If you want to use **role-based character access**, you need to:
  * **Create a Discord bot** and add it to your Discord server.
  * Properly configure the **bot token and guild ID** in the config.
  * Follow the linked **tutorial** for setting up role-based access.
* **Bot configuration & Discord integration** must be set up in:
  * `sv_config.lua` (first step)
  * `config.lua` (final adjustments)

***

**🔟 Clear Cache & Restart Server**

* **Clear the cache** of both your server and your FiveM client.
* **Restart your entire server** with `forge-multicharacter` **properly ensured** in your `server.cfg`.

🚀 Once installed and properly configured, everything should work smoothly!
{% endtab %}
{% endtabs %}

**CONFIG**

The following will explain all the settings, one of the most important things that I recommend you spend a few minutes to understand in order to offer your users the best possible experience.

In addition, inside CLIENT and SERVER you will have the files related to the frameworks, where you will have many open ESX and QB functions for you to adapt them to your framework needs.

<figure><img src="/files/B4jwzJLxEilwiwnhPlcA" alt=""><figcaption></figcaption></figure>

{% tabs %}
{% tab title="CONFIG" %}
{% hint style="warning" %}
If you use the latest update of the script it **will automatically detect everything regarding Framework, Skin Manager and Identifier**. <mark style="color:red;">Don't touch anything where it says</mark> <mark style="color:red;"></mark><mark style="color:red;">**"You don't need to touch this".**</mark>
{% endhint %}

{% code lineNumbers="true" %}

```lua
Config = {}
Config.MULTICHAR = {}
Config.UI = {}
Config.UI.color = {}

--  ██████╗ ██████╗ ███╗   ██╗███████╗██╗ ██████╗ ██╗   ██╗██████╗  █████╗ ████████╗██╗ ██████╗ ███╗   ██╗
-- ██╔════╝██╔═══██╗████╗  ██║██╔════╝██║██╔════╝ ██║   ██║██╔══██╗██╔══██╗╚══██╔══╝██║██╔═══██╗████╗  ██║
-- ██║     ██║   ██║██╔██╗ ██║█████╗  ██║██║  ███╗██║   ██║██████╔╝███████║   ██║   ██║██║   ██║██╔██╗ ██║
-- ██║     ██║   ██║██║╚██╗██║██╔══╝  ██║██║   ██║██║   ██║██╔══██╗██╔══██║   ██║   ██║██║   ██║██║╚██╗██║
-- ╚██████╗╚██████╔╝██║ ╚████║██║     ██║╚██████╔╝╚██████╔╝██║  ██║██║  ██║   ██║   ██║╚██████╔╝██║ ╚████║
--  ╚═════╝ ╚═════╝ ╚═╝  ╚═══╝╚═╝     ╚═╝ ╚═════╝  ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝
                                                                                                       
Config.DEBUG = true -- This will activate debug mode, with a bunch of LOGs on F8 that will corroborate the script's operation. Enable it only in necessary cases

-- GENERAL:
Config.framework =  GetResourceState('es_extended') == "started" and "ESX" or GetResourceState('qb-core') == "started" and "QB" or "CUSTOM" -- You don't need to touch this
Config.resource = nil -- nil => default resource name, normally you don't need to change this value, only if you are using a custom ESX or QB version with a different resource name than 'es_extended' or 'qb-core'
--[[
    ~id~        = character id (ESX) / citizenid (QBCore)
    ~license~   = license identifier
    ~steam~     = steam identifier
    ~discord~   = discord identifier 

    default:
        ESX: 'char~id~:~license~'
        QB:  '~id~'
]]
Config.Prefix = 'char' -- You don't need to touch this
Config.identifier = Config.framework == 'ESX' and 'char~id~:~license~' or '~id~' -- You don't need to touch this
Config.useIllenium = (GetResourceState("illenium-appearance") == "started" and true or false) -- You don't need to touch this
Config.lowPerformanceMode = false -- If you put true here. All UI animations will be removed, so there's no possible LAG. This lowers the aesthetics and beauty of the system
Config.particles = true -- If you put false here, it means there will be no particles or dark background. If you think it looks too dark when creating a character, set it to false here. This lowers the aesthetics and beauty of the system
Config.allowLogout = true -- if true, the player is allowed to logout, whithout having to quit and rejoin
Config.relogCommand = "relog" -- The command that can be used to do relog/logout
Config.relogAdmin = false -- if true, only admins can use the relog admin command on other players or themselves
Config.relogAdminCommand = "rp" -- Admin command to force relog on other players. Only if relogAdmin is true
Config.addSlotsCommand = "addslots" -- The command that can be used to add slots

--Dimensions that should not be used selecting the character.
---Dimension 0 is locked by default since this is the default server dimension with the city and players should not be visible during character selection.
Config.lockedDimensions = {
    0, --- default server dimension
}

-- INTERFACE:
Config.UI.volume = 30 -- 0 - 100
Config.UI.color.primary = "0, 224, 255" -- primary UI color
Config.UI.color.secondary = "49, 175, 212" -- secondary UI color
Config.UI.color.hover = "0, 150, 196" -- hover UI color
-- DISCORD ROLES

Config.noDiscordSlots = 3   -- amount of slots unlocked, when no discord bot is connected.
Config.MULTICHAR.slots = { -- Each discord role will access the number of slots you want
    {
        groupId = "your-groupId",
        name = "Premium",
        slots = 3
    },
    {
        groupId = "your-groupId",
        name = "Premium+",
        slots = 4
    },
    {
        groupId = "1233795374641189018",
        name = "Member",
        slots = 2
    },
}
Config.MULTICHAR.buy_new_slot_url = "https://discord.gg/my-server" -- Add the invitation link to your discord. When you want to purchase a new slot, this one will be opened
-- CHARACTER SETTINGS
Config.MULTICHAR.Animations = { -- When you select a character, the character will make an animation from this list 
    {
        animation   = "gestures@f@standing@casual gesture_hello",
        time        = 1000
    },
    {
        animation   = "gestures@m@standing@casual gesture_hello",
        time        = 1000
    },
    {
        animation   = "gestures@m@standing@fat gesture_hello",
        time        = 1000
    }
}
Config.MULTICHAR.canDelete = true -- If true players are allowed to delete their characters. If false, they can only be deleted from the database
Config.MULTICHAR.spawn = vector4(-284.2856, 562.4627, 172.9182, 19.9895) -- The position, where the player will be while in the menu
-- TRANSLATES
Config.language = "en"
Language = {}
Language.en = {
    ['delete_character']    = "DELETE CHARACTER",
    ['playtime']            = "PLAYTIME",
    ['play']                = "PLAY",
    ['yes']                 = "YES",
    ['no']                  = "NO",
    ['you_sure']           = "ARE YOU SURE?",
    ['deleted']             = "Character deleted !",
    ['last_spawn']          = "Here is some information about this character the last spawn point was at ~lsp~", -- ~lsp~ = The players last location (Street [crossing Street])
    ['ls_citizien']         = "Los Santos - Citizien",
    ['gender']              = "Gender",
    ['gender_male']         = "MALE",
    ['gender_female']       = "FEMALE",
    ['job']                 = "JOB",
    ['create_char']         = "CREATE A NEW CHARACTER",
    ['free']                = "FREE",
    ['create']              = "CREATE",
    ['buy_slot']            = "BUY A NEW CHARACTER SLOT",
    ['please_restart']      = "To do this, you must perform a full restart.",
    ['charcard_gender']     = "GENDER",
    ['cash']                = "CASH",
    ['bank']                = "BANK",
    ['nationality']         = "NATIONALITY",
    ['select']              = "SELECT",
    ['please_wait']          = "PLEASE WAIT..."
}

Language.de = {
    ['delete_character']    = "CHARACTER LÖSCHEN",
    ['playtime']            = "SPIELZEIT",
    ['play']                = "SPIELEN",
    ['yes']                 = "JA",
    ['no']                  = "NEIN",
    ['you_sure']           = "BIST DU DIR SICHER?",
    ['deleted']             = "Character gelöscht!",
    ['last_spawn']          = "Hier sind ein paar information über den character. Die letze position war bei ~lsp~", -- ~lsp~ = The players last location (Street [crossing Street])
    ['ls_citizien']         = "Los Santos - Bürger",
    ['gender']              = "Gender",
    ['gender_male']         = "MÄNNLICH",
    ['gender_female']       = "WEIBLICH",
    ['job']                 = "BERUF",
    ['create_char']         = "NEUEN CHARACTER ERSTELLEN",
    ['free']                = "FREI",
    ['create']              = "ERSTELLEN",
    ['buy_slot']            = "NEUEN SLOT KAUFEN",
    ['please_restart']      = "Um diese aktion auszuführen, musst du dein spiel neu starten.",
    ['charcard_gender']     = "GESCHLECHT",
    ['cash']                = "BARGELD",
    ['bank']                = "BANK",
    ['nationality']         = "NATIONALITÄT",
    ['select']              = "AUSWÄHLEN",
    ['pease_wait']          = "BITTE WARTE..."
}
```

{% endcode %}
{% endtab %}

{% tab title="SV\_CONFIG" %}

```lua
Config.bot = { -- Add your discord bot information. This detects whether a player has the necessary role to access a slot or not. More information in the documentation
    guild = "your-guild",
    token = "your-token",
    use = false              -- set this to false if you don't want to use the discord bot
}
```

{% endtab %}

{% tab title="OPEN" %}

```lua
Open = {}

Open.client = {}

---Called, when the player clicked on play. This should open the spawn menu, if exists.<br>
---Scripts using ESX or QBCore default functions, are included by default.
function Open.client:openSpawnMenu() end

---Should call an export on the hud to hide the hud
---@param bool boolean if set to true, the hud should be hidden, if not the hud should be visible
function Open.client:hideHud(bool) end

---Forces the UI to stay hidden or not<br>
---can be used with `exports["forge-multicharacter"]:forceHide(true)` or `exports["forge-multicharacter"]:forceHide(false)`
---@param hide boolean if set to true the UI will be hidden, if not the UI will be visible, IF the UI would be visibile in the current situation
exports("forceHide", function(hide)
    UI.forceHide(hide)
end)
```

{% endtab %}

{% tab title="SQL" %}
**QB**

{% code overflow="wrap" %}

```sql
ALTER TABLE `players` ADD `playtime` BIGINT NOT NULL DEFAULT '0' AFTER `last_updated`;

CREATE TABLE additionalSlots (
    `identifier` VARCHAR(64) NOT NULL,
    `slots` INT NOT NULL DEFAULT 0,
    PRIMARY KEY (`identifier`)
);
```

{% endcode %}

**ESX**

{% code overflow="wrap" %}

```sql
ALTER TABLE `users` ADD `playtime` BIGINT NOT NULL DEFAULT '0' AFTER `pincode`;
ALTER TABLE `users` ADD `nationality` VARCHAR(50) DEFAULT 'UNKNOWN' AFTER `playtime`;

CREATE TABLE additionalSlots (
    `identifier` VARCHAR(64) NOT NULL,
    `slots` INT NOT NULL DEFAULT 0,
    PRIMARY KEY (`identifier`)
);
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="success" %}
**If you want to edit the aesthetics or design. You have the HTML open so you can modify the style and everything as you want.**

The script is **RESPONSIVE** for all resolutions as well.
{% 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://codeforge.gitbook.io/codeforge/sleek-series/sleek-multi-character.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.
