XyraLScripts
Installation guide

Multicharacter

A cinematic character selector with identity dossiers, saved appearance previews, job animations, map-camera spawn picking and configurable slots.

Requirements

Required

  • qbx_core or qb-core
  • oxmysql

Optional

  • An appearance resource, if you want saved clothing and first-character setup — illenium-appearance, fivem-appearance and qb-clothing are supported out of the box.
  • qbx_apartments or qb-apartments, if you want starting apartments.

Installation

  1. Put XS-MultiCharacter in your resources folder.
  2. Add ensure XS-MultiCharacter to server.cfg, after the framework, oxmysql, and your appearance and apartment resources.
  3. Disable the multicharacter resource that came with your framework. QBCore servers should stop or remove qb-multicharacter.
  4. Qbox servers also need this in qbx_core/config/client.lua:
    useExternalCharacters = true
  5. Check the three files in config/ before starting.

The two tables are created automatically by default. If you turn automatic table creation off, import sql/XS-CriminalTablet_multichar.sql yourself.

Configuration

Config is split across three files so the client and server halves stay separate:

  • config/shared.lua — character rules, first-time setup, spawn locations.
  • config/client.lua — scene, cameras, animations, integrations, UI style.
  • config/server.lua — slots, appearance table, dossier fields, cooldowns.
  • locales/en.lua — every player-facing line.
  • integrations/ — the adapters. Edit here for a renamed or custom resource.

The resource validates its own config at startup. Bad framework names, duplicate spawn IDs, missing coords, unsafe appearance table names and invalid slot settings are printed as CONFIG ERROR before anything else runs.

Character slots

Default and maximum slot counts live in config/server.lua. A player always gets the highest value they qualify for, and the result is clamped to the configured maximum.

By ACE:

add_ace group.supporter XS-CriminalTablet.slots.6 allow
add_ace group.vip XS-CriminalTablet.slots.8 allow

By license, for a fixed override:

identifiers = {
    ['license:abc123'] = 8
}

Or from another resource at runtime:

exports['XS-MultiCharacter']:RegisterSlotProvider(function(source, currentSlots)
    if IsPlayerAceAllowed(source, 'myserver.founder') then
        return 10
    end
end)

Spawns and permissions

Spawn locations sit in config/shared.lua under their categories. Empty categories hide themselves, last location has its own configurable category, and anything without one falls back to defaultCategory.

Restrict a location by adding a permission table:

permission = {
    jobs = { police = 0, ambulance = 2 },
    ace = 'XS-CriminalTablet.spawn.pillbox'
}

Passing any listed rule grants access by default. Add requireAll = true when a character must pass every rule. The available checks are jobs, gangs, citizenids and ace.

The server re-checks the permission when a spawn is actually picked. Hiding a button in the interface is never treated as security.

Saved appearances

The default query expects the common layout:

playerskins: id, citizenid, model, skin, active

If your appearance resource renamed its table or columns, change Config.Server.Appearance. SQL identifiers are validated before any query is built, so a bad name fails loudly at startup rather than at runtime.

The client adapter is chosen automatically. Force it in Config.Client.Integrations.appearance if more than one clothing resource happens to be installed.

Dossier and activity

The standard dossier covers identity, occupation, position, affiliation, phone, nationality, account number and money, each toggleable in the client config. Simple extra fields go in the server config:

metadataFields = {
    { key = 'callsign', label = 'Callsign' }
}

Other resources can contribute calculated values without editing XS-MultiCharacter:

exports['XS-MultiCharacter']:RegisterDossierProvider(function(source, citizenid, playerRow, dossier)
    return { { label = 'Reputation', value = 'Trusted' } }
end)

Activity tracking records previous selection time, total playtime, the date tracking began and the last saved district. Playtime is written on unload, disconnect or resource stop — there is no repeating save query. Turn it off in Config.Server.Activity, or keep collecting and just hide it with Config.Client.UI.showActivity.

Admin slot manager

Grant the ACE:

add_ace group.admin XS-CriminalTablet.multichar.admin allow

Then /charslots opens the manager, showing online players, current character count, effective slots and any persistent overrides. The direct form also works:

/charslots 12 8
/charslots 12 reset

Changing an override does not log the target out or reopen their selector. The new limit applies the next time their character list loads.

Before going live

  • Test the full new-character flow against the exact appearance and apartment versions your server runs.
  • Test one existing male and one existing female character to confirm the saved appearance query matches your table.
  • Check every camera location for interiors or map assets only your server loads.
  • Keep spawn IDs unique — duplicates are reported at startup.
  • Grant XS-CriminalTablet.multichar.admin only to staff who should manage persistent slot limits.
  • Do not start the old multicharacter resource beside this one.

Updating

Replace the whole folder rather than individual files, then restart. A partial upload tends to surface as unrelated-looking errors elsewhere. Review the config files after any update — new options are added there rather than hard-coded.

Troubleshooting

Two character selectors open at once

The framework’s own multicharacter resource is still running. Stop or remove qb-multicharacter on QBCore. On Qbox, also set useExternalCharacters = true in qbx_core/config/client.lua — without it, Qbox keeps handling character selection itself.

Characters load with default clothing instead of their saved appearance

The appearance query does not match your table. The default expects playerskins with id, citizenid, model, skin, active. Point Config.Server.Appearance at whatever your clothing resource actually uses.

The console prints CONFIG ERROR on start

That is the startup validator, and it names the problem. It catches bad framework names, duplicate spawn IDs, missing coordinates, unsafe appearance table names and invalid slot settings. Fix the value it names and restart.

A spawn location is missing from the list

Either its category is empty and has been hidden automatically, or the character failed the location’s permission rules. Check the permission table on that location, and remember requireAll = true means every rule must pass rather than any one of them.

The apartment and clothing menus open over each other

The standard Qbox and QBCore apartment resources open clothing themselves after an apartment is picked, so XS-MultiCharacter leaves that handoff alone. If you use a custom apartment event that does not do this, set Config.FirstCharacter.apartments.opensClothingAfterSelection to false and XS-MultiCharacter will run the clothing-first fallback instead.

How do I let a player switch character without reconnecting?

You cannot. The resource deliberately does not expose an event or command that logs a player out and reopens character selection — that path is a common source of duplicated player state. Lifecycle events are available for integrations, but none of them force a re-select.

Support

Found a bug? Open an issue. Need setup help? Join the Discord — check this guide first, it usually has the answer.