Docs
Rarx Multicharacter cover

Rarx Multicharacter

Rarx Multicharacter

Advanced character selection system for FiveM with loading screen, main menu, and admin panel

  • Qbox
  • QBCore
  • ESX
  • rarx_multicharacter

Rarx Multicharacter Preview

Overview#

RARX Multicharacter is an advanced character selection system for FiveM servers featuring a built-in loading screen, main menu, spawn selector, starter vehicle system, and a full admin panel. The framework is auto-detected at runtime -- no manual configuration needed.

Features#

Character Management

Create, select, and delete characters with configurable slot limits and name validation

Loading Screen

Built-in loading screen with video/image/YouTube backgrounds, music, and rotating tips

Main Menu

Customizable main menu with server branding, rules, controls, stats bar, and video embed

Spawn Selector

Choose spawn location from configurable default spawns, last location, apartments, or housing

Starter Vehicle

Give new characters a starter vehicle from a configurable selection list

Admin Panel

Manage character slots, activate/deactivate characters, perform character kills with backups

Appearance Integration

Works with rarx_clothing, fivem-appearance, illenium-appearance, and bl_appearance

Housing Integration

Supports QB-Apartments, rarx_apartments, 0r_motels, and origen_housing for spawn selection

Requirements#

  • Framework: ESX, QBCore, or QBox (auto-detected)
  • ox_lib
  • oxmysql
  • rarx_lib

Installation#

  1. Install dependencies

    Make sure these resources are installed and running before rarx_multicharacter:

    • oxmysql — database driver
    • ox_lib — runtime library
    • rarx_lib — provided in your Keymaster bundle
    • An appearance system: illenium-appearance, fivem-appearance, rarx_clothing, or bl_appearance
  1. Download & extract

    Download the latest rarx_multicharacter from your Keymaster and extract it into your resources/ folder (e.g. resources/[core]/rarx_multicharacter/).

  2. Import the database

    The install/ folder contains framework-specific SQL files. For ESX, run them in this order:

    SQL
    -- 1. Required for ALL frameworks — multichar slots, character status, CK backups, tracking
    install/general.sql
    
    -- 2. Framework-specific — adds `nat` and `side` columns to your `users` table
    install/esx.sql

    For QBCore/QBox use the matching install/qb.sql or install/qbox.sql.

  1. Edit server.cfg

    On ESX servers, ordering matters. The dependencies must start before es_extended initializes its multichar handlers. Recommended layout:

    server.cfg
    # Core dependencies (oxmysql first, then everything else)
    ensure chat
    ensure hardcap
    ensure oxmysql
    
    # Order-sensitive: ox_lib -> framework -> appearance -> multichar
    ensure ox_lib
    ensure rarx_lib
    ensure es_extended
    ensure illenium-appearance       # or your appearance system
    ensure rarx_multicharacter
    
    # Umbrella ensures (pick up everything else in those folders)
    ensure [core]
    ensure [standalone]
    ensure [esx_addons]

    Set the locale convar for your appearance system, e.g.:

    server.cfg
    setr illenium-appearance:locale "en"
  2. Apply framework-specific setup

    Open the matching tab below — ESX, QBCore or QBox — and follow its steps. The ESX path requires patching es_extended; if you skip it the selector will never open.

  3. Configure & restart

    Edit config.lua to set your branding, slot counts, spawn locations and admin permissions, then perform a full server restart (not just restart rarx_multicharacter). Some settings — especially Config.Multichar in es_extended — are only read at script load.

Framework-Specific Setup#

Disable QBox's built-in character system:

  1. Open qbx_core/config/client.lua

  2. Find useExternalCharacters = false

  3. Change to useExternalCharacters = true

If you are not using rarx_apartments and instead use qb-apartments, add this export to @qb-apartments/client/main.lua:

Lua
exports('GetApartmentsConfig', function()
    return Apartments
end)

1. Remove conflicting resources#

Move (or rename) these resources out of your resources/ folder. They register conflicting commands, deferrals and event handlers that race with rarx_multicharacter:

Resource Why remove
esx_multicharacter Replaced — handles its own selector + spawn flow
esx_skin Replaced by your appearance system (illenium-appearance, fivem-appearance, rarx_clothing, …)
skinchanger Same — appearance system provides the same API
esx_clotheshop / esx_barbershop / esx_accessories Replaced by your appearance system

2. Patch es_extended (REQUIRED on ESX Legacy 1.13.x)#

Vanilla es_extended auto-detects multichar mode by looking for a resource named esx_multicharacter. Because you've replaced it with rarx_multicharacter, the lookup returns missing and the server silently falls back to single-character mode — the selector never opens.

Two small edits are required:

2a. es_extended/shared/config/main.lua — force-enable multichar mode:

Lua
-- BEFORE
Config.Multichar = GetResourceState("esx_multicharacter") ~= "missing"

-- AFTER
Config.Multichar = true

2b. es_extended/client/main.lua — always disable the default spawnmanager (not only when multichar is off):

Lua
-- BEFORE
CreateThread(function()
    while not Config.Multichar do
        Wait(100)
        if NetworkIsPlayerActive(ESX.playerId) then
            ESX.DisableSpawnManager()
            DoScreenFadeOut(0)
            Wait(500)
            TriggerServerEvent("esx:onPlayerJoined")
            break
        end
    end
end)

-- AFTER
CreateThread(function()
    while not NetworkIsPlayerActive(ESX.playerId) do
        Wait(100)
    end
    ESX.DisableSpawnManager()

    if not Config.Multichar then
        DoScreenFadeOut(0)
        Wait(500)
        TriggerServerEvent("esx:onPlayerJoined")
    end
end)

Without this, the default cfx spawnmanager auto-spawns the ped and calls ShutdownLoadingScreen() before Rarx can open its selector — you'll see the loadscreen close to a black void with no menu.

3. Add provides {} to your appearance system#

Other ESX addons (esx_accessories, esx_ambulancejob, etc.) declare esx_skin as a hard dependency. After removing esx_skin, your server will refuse to start them unless your appearance system advertises that name. For illenium-appearance, edit its fxmanifest.lua:

Lua
provides {
  "esx_skin",
  "skinchanger",
}

4. Character prefix (ESX only)#

ESX characters are stored as PREFIX + slot : identifier (e.g. char1:license:abc…, char2:license:abc…). The prefix is set by Config.ESX.PREFIX (default "char") and is used everywhere identifiers are parsed — slot extraction, admin commands and saving.

5. Restart the server#

Do a full server restart, not just restart rarx_multicharacter — Config.Multichar is read at es_extended script load and won't pick up a hot-reload of only the multichar resource.

Verifying the install#

After restarting the server, connect once and check both consoles for these signals. They confirm each stage of the boot completed correctly.

  1. Server console (txAdmin live or fxserver.log)

    You should see, in this order:

    Text
    [oxmysql] Database server connection established!
    [es_extended] [INFO] ESX Legacy 1.13.5 initialized!
    [resources] Started resource rarx_multicharacter

    On player connect:

    Text
    [hardcap] Connecting: <name>
    [es_extended] [INFO] Player "<firstname lastname>" has connected to the server. ID: <n>

    If es_extended never prints "initialized!" something is wrong with oxmysql or your jobs table.

  2. Client (F8)

    On connect, you should see the rarx loadscreen, then the character selector with your existing characters (or a "Create character" slot if none exist). No black-screen-with-floating-menu, no infinite loadscreen.

    Enable Config.Debug = true in rarx_multicharacter/config.lua for extra [rarx_multicharacter] lines that trace every step.

  3. Database

    Pick an existing test character and inspect its users row:

    SQL
    SELECT identifier, firstname, lastname, sex, height,
           LENGTH(skin) AS skin_len, LEFT(position, 60) AS position
    FROM users WHERE identifier LIKE 'char%';

    You should see one row per character, with identifier prefixed char1:, char2:, etc., a populated skin (illenium appearance JSON) and a saved position. If skin_len = 0, illenium's save callback didn't fire — see the troubleshooting section.

Clean reset (re-test from scratch)#

If you need to wipe a test player and start over (for example after fixing a half-broken install):

SQL
-- Replace <license> with the hex after `license:` from your identifier
DELETE FROM users WHERE identifier LIKE 'char%:<license>';
DELETE FROM playerskins WHERE citizenid LIKE '%<license>%';
DELETE FROM player_outfits WHERE citizenid LIKE '%<license>%';
DELETE FROM multicharacter_slots WHERE identifier LIKE '%<license>%';
DELETE FROM multicharacter_character_status WHERE citizenid LIKE '%<license>%';

Reconnect — you'll be back at the "Create character" prompt.

Configuration#

Language#

The language is set via the rarx-lang convar in your server.cfg, shared across all RARX resources:

server.cfg
setr rarx-lang "en"

Available languages: en (English) and es (Spanish). To add another, copy translates/en.lua and translate the strings inside it.

UI Appearance#

Lua
Config.Ui = {
    bannedWords = {'badword1', 'badword2'},
    maxBirthYear = 2015,
    minBirthYear = 1900,
    maxCharSlots = 5,       -- Total slots displayed
    allowCharSlots = 1,     -- Default unlocked slots
    hideKeyBind = "L",
    delKeyBind = "Delete",
    delAllowed = false,     -- Allow players to delete characters
    primaryColor = "#c94f4f",
    secondaryColor = "#c94f4f",
    logoUrl = "https://your-logo-url.png",
    nationalities = {
        ['United States'] = true,
        ['Spain'] = true,
        -- ... add/remove countries as needed
    },
}

Color Scheme#

Lua
Config.Colors = {
    primary = '#c94f4f',
    secondary = '#1a1a1a',
}

Character Info Display#

Lua
Config.Characters = {
    -- Fields shown on character cards
    -- Available: 'name', 'job', 'cash', 'bank', 'phone', 'nationality', 'dob'
    displayInfo = { 'name', 'job' },
}

Spawn System#

Lua
Config.SpawnSystem = {
    enabled = true,
    useRandomBucket = true,    -- Prevents player overlap during selection
    forceDefaultBucket = 0,    -- Bucket when entering the world

    ui = {
        showLastLocation = true,
        animatedTransition = true,
    },

    defaultSpawns = {
        {
            name = "LS Airport",
            coords = vector4(-1035.63, -2735.84, 20.17, 330.49),
            icon = 'fa-plane',
            description = "Los Santos International Airport"
        },
    },
}

Starter Vehicle#

Lua
Config.StarterVehicle = {
    enabled = true,
    showSelector = true,   -- Show UI selector (false = random from list)
    garage = 'garaje_central',
    vehicles = {
        { model = 'panto', label = 'Panto' },
        { model = 'blista', label = 'Blista' },
        { model = 'faggio2', label = 'Faggio Sport' },
    }
}

Loading Screen#

Lua
Config.Loading = {
    enabled = true,  -- Set to false to disable the custom loading screen
    background = {
        type = 'video',  -- 'video' | 'image' | 'youtube'
        url = 'https://your-video-url.mp4',
    },
    music = {
        enabled = true,
        type = 'mp3',    -- 'mp3' | 'youtube'
        url = 'https://your-music-url.mp3',
        volume = 0.5,
    },
    logo = 'https://your-logo-url.png',
    tips = {
        'Welcome to the server!',
        'Use /help for available commands',
    },
    tipInterval = 5,
}
Lua
Config.Menu = {
    serverName = 'Your Server',
    serverSlogan = 'Your best roleplay experience',

    features = {
        { icon = 'fa-coins', text = 'Realistic Economy' },
        { icon = 'fa-car', text = 'Custom Vehicles' },
    },

    -- Navbar sections
    sections = {
        { id = 'home', label = 'HOME', isDefault = true },
        { id = 'rules', label = 'RULES', items = { ... } },
        { id = 'controls', label = 'CONTROLS', items = { ... } },
        { id = 'discord', label = 'DISCORD', isExternalLink = true, url = 'https://discord.gg/...' },
    },

    stats = {
        { type = 'players', label = 'PLAYERS ONLINE', icon = 'fa-users' },
        { type = 'uptime', label = 'UPTIME', icon = 'fa-clock' },
        { type = 'staff', label = 'STAFF ONLINE', icon = 'fa-user-shield' },
    },
}

Apartment Integration#

Lua
Config.Apartments = {
    disableQBApartment = false,
    enableQBApartmentSpawns = true,
    showApartmentsToExisting = true,
    enable0rMotels = false,
    enableOrigenHousing = false,
}

Commands#

Slot Management#

Command Description
/setslots [identifier] [amount] Assign unlocked character slots to a player
/removeslots [identifier] Reset player slots to default

Example:

Text
/setslots steam:12345678 5

Character Management (ESX)#

Command Description
/disablecharacter [identifier] [slot] Disable access to a specific slot
/enablecharacter [identifier] [slot] Enable access to a specific slot

Character Management (QBCore / QBox)#

Command Description
/disablecharacter [citizenid] Disable a character profile
/enablecharacter [citizenid] Enable a character profile

Other Commands#

Command Description
/logout Return to character selection (only registered when Config.logoutCmd = true)
/relog Return to character selection — QBox only
/multicharadmin Open the admin panel (requires permissions; command name set by Config.AdminSystem.command)

Admin Panel#

The admin panel provides full character management capabilities with Discord webhook logging.

Access Control#

Lua
Config.AdminSystem = {
    enable = true,
    useAcePermissions = true,
    acePermission = 'qbcore.god',   -- QBCore / QBox only — see the per-framework note below
    adminIdentifiers = {
        '123456789',                -- Discord ID (with or without 'discord:' prefix)
        'steam:110000123456789',    -- Steam HEX
        -- 'license:abc123',        -- License
        -- 'fivem:12345',           -- FiveM ID
    },
    command = 'multicharadmin',
}

Both ACE permissions and identifier-based access work in parallel -- if either matches, access is granted.

Features#

  • Slot Management -- Grant or remove character slots per player
  • Character Activation/Deactivation -- Disable or re-enable character profiles with required reasons
  • Character Kill (CK) -- Permanently remove characters with automatic backup creation
  • Discord Webhooks -- Log all admin actions to separate Discord channels

Webhook Configuration#

Lua
Config.AdminSystem.webhooks = {
    enable = true,
    setSlots = 'https://discord.com/api/webhooks/...',
    characterStatus = 'https://discord.com/api/webhooks/...',
    characterKill = 'https://discord.com/api/webhooks/...',
    general = 'https://discord.com/api/webhooks/...',
}

Appearance Systems#

The script integrates with these appearance resources for character display during selection:

  • rarx_clothing (recommended)
  • illenium-appearance
  • fivem-appearance
  • bl_appearance
  • origen_clothing
  • qb-clothing

The system auto-detects which appearance resource is running and uses it automatically. No manual configuration needed.

Anticheat Compatibility#

This resource uses natives during character selection and spawn that may trigger false positives in anticheats. Below are the exact events and the natives they execute, so you can whitelist them.

Character Selection#

Event:rarx_multicharacter:client:openMenu
Native Target Reason
FreezeEntityPosition(ped, true) PlayerPedId + preview peds Hold player and character peds in place during selection
SetEntityInvincible(ped, true) PlayerPedId + preview peds Prevent death from metabolism/environment while idle on selection screen
NetworkSetEntityInvisibleToNetwork(ped, true) PlayerPedId Hide real player ped from other clients
SetEntityLocallyInvisible(ped) PlayerPedId (every frame) Keep player ped invisible locally

Spawn#

Events:

  • rarx_multicharacter:client:spawnDefault
  • rarx_multicharacter:client:spawnInApartment
  • rarx_multicharacter:client:spawnInFirstApartment
Native When Reason
FreezeEntityPosition(ped, true) Spawn start Briefly freeze while coordinates are applied
FreezeEntityPosition(ped, false) ~1 second later Release player for normal movement
SetEntityInvincible(ped, false) Spawn start Restore normal damage
NetworkSetEntityInvisibleToNetwork(ped, false) Spawn start Make player visible to network again
SetEntityVisible(ped, true) Spawn start Make ped visible after teleport

Summary#

Detection Type Triggered By Duration
God mode (invincible) rarx_multicharacter:client:openMenu Only during selection screen
Freeze openMenu + spawn events Selection screen + ~1s during spawn
Invisibility rarx_multicharacter:client:openMenu Only during selection screen

Troubleshooting#

Characters not loading

Verify the database was imported correctly and that oxmysql is started before this resource.

Blank/invisible characters

Ensure your appearance system (rarx_clothing, illenium-appearance, etc.) is started and working correctly.

Admin panel not accessible

Check that your identifier is correctly added to Config.AdminSystem.adminIdentifiers or that you have the correct ACE permission.

Spawn selector not showing

Verify Config.SpawnSystem.enabled = true and that character positions are configured in Config.chars.

QBox characters not working

Ensure useExternalCharacters = true is set in qbx_core/config/client.lua.

Starter vehicles not appearing

Check that Config.StarterVehicle.enabled = true and that the vehicle models exist in your server.

Admin panel not detecting ACE permissions

QBCore / QBox: grant the ACE in server.cfg and make sure it matches Config.AdminSystem.acePermission:

server.cfg
add_ace identifier.discord:123456789 qbcore.god allow

ESX: the qbcore.god ACE doesn't exist on ESX. Add the admin to Config.AdminSystem.adminIdentifiers, or point acePermission at an ACE you actually grant (e.g. group.admin). Both ACE and identifier-based access work in parallel.

[ESX] Loadscreen ends but the selector never appears

Symptoms: the loadscreen closes to a black screen and nothing happens, or F8 shows NetworkIsSessionStarted, triggering server:openMenu followed by silence on the server console.

Cause: Config.Multichar is false on the server side, so es_extended skips registering the esx:onPlayerJoined handler and the default spawnmanager auto-spawn handler stays active and races the multichar flow.

Fix: apply both edits in the ESX install Step 2 (Config.Multichar = true + unconditional ESX.DisableSpawnManager()), then do a full server restart.

[ESX] Server console shows ESX present but ESX.Jobs empty and the selector never returns chars

Symptoms: server console prints OpenMenu(N) entering GetAllChars... and then hangs. Eventually oxmysql may print Duplicate entry 'char1:...' for key 'PRIMARY' when the player tries to create.

Cause: the script reads ESX.Jobs directly from the cross-VM snapshot returned by getSharedObject — that snapshot is stale and never reflects the table populated later by RefreshJobs(). The init loop spins forever.

Fix (in rarx_multicharacter/server/framework.lua, inside the if isESX then MySQL.ready(function() ... end) block):

Replace the repeat ... until ESX and next(ESX.Jobs) ... isDatabaseConnected = true block with:

Lua
if not ESX then
    ESX = exports["es_extended"]:getSharedObject()
end
if ESX and ESX.GetJobs then
    ESX.Jobs = ESX.GetJobs()  -- blocks until Core.JobsLoaded
end
isDatabaseConnected = true

ESX.GetJobs() is a cross-VM call that internally waits for Core.JobsLoaded and returns the live jobs table.

[ESX] After illenium customization the screen stays black with the menu floating on top

Cause: the multichar NUI is still loaded with its black overlay behind the illenium menu; illenium's NUI clicks are not reaching the customization callbacks because rarx never hid its own NUI.

Fix: in rarx_multicharacter/client/framework.lua, inside the isUsingIlleniumAppearance branch of the new-character flow, hide rarx NUI before opening illenium and load the default skin first (matches the native esx_multicharacter order):

Lua
SendNUIMessage({ action = 'hide' })
SendNUIMessage({ action = 'hideBlackOverlay' })

TriggerEvent("esx_skin:resetFirstSpawn")
TriggerEvent("skinchanger:loadSkin", skin, function()
    local ped = PlayerPedId()
    SetPedAoBlobRendering(ped, true)
    ResetEntityAlpha(ped)
    DoScreenFadeIn(600)

    TriggerEvent("esx_skin:openSaveableMenu", function()
        finished = true
    end, function()
        finished = true
    end)
end)
[ESX] After saving in illenium the world doesn't render / player stuck underground

Cause: for new characters the script spawned the ped at the secret creator-studio interior (z = -90) and forgot to teleport it to a real spawn location after illenium completes.

Fix: in rarx_multicharacter/client/framework.lua, in the post-illenium block (where isUsingIlleniumAppearance or isUsingFivemAppearance is true), always set coords on new characters and stream the destination:

Lua
local target = spawn
if isNew then
    local realSpawns = Config.SpawnSystem and Config.SpawnSystem.defaultSpawns
    if realSpawns and #realSpawns > 0 and realSpawns[1].coords then
        target = realSpawns[1].coords
    elseif Config.DefaultSpawn and Config.DefaultSpawn.z > -50.0 then
        target = Config.DefaultSpawn
    else
        target = vector4(-1035.63, -2735.84, 20.17, 330.49) -- LSIA fallback
    end
end
SetEntityCoords(ped, target.x, target.y, target.z, false, false, false, false)
SetEntityHeading(ped, target.w or target.heading or 0.0)
RequestCollisionAtCoord(target.x, target.y, target.z)
NewLoadSceneStart(target.x, target.y, target.z, target.x, target.y, target.z, 50.0, 0)
local t = 0
while not IsNewLoadSceneLoaded() and t < 100 do Wait(50) t = t + 1 end
NewLoadSceneStop()
[ESX] Returning character logs in but stays on a black screen

Cause: the fallback path for existing ESX characters (esx:playerLoaded with isNew=false and a saved skin) calls DoScreenFadeOut(0) and esxSpawnPlayer(skin, spawn) but never calls DoScreenFadeIn, so the screen stays black after the spawn completes.

Fix: at the end of the fallback (just before PostSpawnPlayer()), add a fade-in and clear the leftover rarx NUI overlay:

Lua
SendNUIMessage({ action = 'hide' })
SendNUIMessage({ action = 'hideBlackOverlay' })
-- ... existing esxSpawnPlayer / skinchanger / restoreLoadout calls ...
Wait(1000)
DoScreenFadeIn(800)
PostSpawnPlayer()