
Rarx Multicharacter
Rarx Multicharacter
Advanced character selection system for FiveM with loading screen, main menu, and admin panel
- Qbox
- QBCore
- ESX
rarx_multicharacter

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#
Create, select, and delete characters with configurable slot limits and name validation
Built-in loading screen with video/image/YouTube backgrounds, music, and rotating tips
Customizable main menu with server branding, rules, controls, stats bar, and video embed
Choose spawn location from configurable default spawns, last location, apartments, or housing
Give new characters a starter vehicle from a configurable selection list
Manage character slots, activate/deactivate characters, perform character kills with backups
Works with rarx_clothing, fivem-appearance, illenium-appearance, and bl_appearance
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#
Install dependencies
Download & extract
Download the latest
rarx_multicharacterfrom your Keymaster and extract it into yourresources/folder (e.g.resources/[core]/rarx_multicharacter/).Import the database
The
install/folder contains framework-specific SQL files. For ESX, run them in this order:-- 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.sqlFor QBCore/QBox use the matching
install/qb.sqlorinstall/qbox.sql.
Edit server.cfg
On ESX servers, ordering matters. The dependencies must start before
es_extendedinitializes its multichar handlers. Recommended layout:# 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.:
setr illenium-appearance:locale "en"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.Configure & restart
Edit
config.luato set your branding, slot counts, spawn locations and admin permissions, then perform a full server restart (not justrestart rarx_multicharacter). Some settings — especiallyConfig.Multicharines_extended— are only read at script load.
Framework-Specific Setup#
Disable QBox's built-in character system:
-
Open
qbx_core/config/client.lua -
Find
useExternalCharacters = false -
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:
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:
-- BEFORE
Config.Multichar = GetResourceState("esx_multicharacter") ~= "missing"
-- AFTER
Config.Multichar = true2b. es_extended/client/main.lua — always disable the default spawnmanager (not only when multichar is off):
-- 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:
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.
Server console (txAdmin live or
fxserver.log)You should see, in this order:
[oxmysql] Database server connection established! [es_extended] [INFO] ESX Legacy 1.13.5 initialized! [resources] Started resource rarx_multicharacterOn player connect:
[hardcap] Connecting: <name> [es_extended] [INFO] Player "<firstname lastname>" has connected to the server. ID: <n>If
es_extendednever prints "initialized!" something is wrong withoxmysqlor your jobs table.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 = trueinrarx_multicharacter/config.luafor extra[rarx_multicharacter]lines that trace every step.Database
Pick an existing test character and inspect its
usersrow: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
identifierprefixedchar1:,char2:, etc., a populatedskin(illenium appearance JSON) and a savedposition. Ifskin_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):
-- 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:
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#
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#
Config.Colors = {
primary = '#c94f4f',
secondary = '#1a1a1a',
}Character Info Display#
Config.Characters = {
-- Fields shown on character cards
-- Available: 'name', 'job', 'cash', 'bank', 'phone', 'nationality', 'dob'
displayInfo = { 'name', 'job' },
}Spawn System#
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#
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#
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,
}Main Menu#
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#
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:
/setslots steam:12345678 5Character 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#
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#
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:spawnDefaultrarx_multicharacter:client:spawnInApartmentrarx_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.
Loading screen shows wrong logo
The loading screen runs before Lua scripts load, so it reads from ui/loadingConfig.js instead of config.lua. Edit both files with the same logo URL. You must restart the server (not just ensure) for loading screen changes to take effect.
Admin panel not detecting ACE permissions
QBCore / QBox: grant the ACE in server.cfg and make sure it matches Config.AdminSystem.acePermission:
add_ace identifier.discord:123456789 qbcore.god allowESX: 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:
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 = trueESX.GetJobs() is a cross-VM call that internally waits for Core.JobsLoaded and returns the live jobs table.
[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:
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:
SendNUIMessage({ action = 'hide' })
SendNUIMessage({ action = 'hideBlackOverlay' })
-- ... existing esxSpawnPlayer / skinchanger / restoreLoadout calls ...
Wait(1000)
DoScreenFadeIn(800)
PostSpawnPlayer()