FIELD MANUAL // Player tools

Origin Multicharacter

Documentation from the supplied script archive. Check your included resource files for the version you install.

Origin Multicharacter

A cinematic character selection, creation and spawn selector for Qbox, QBCore, ESX and standalone servers. One resource replaces qb-multicharacter + qb-spawn, esx_multicharacter, and Qbox's built-in character menu.

Features

Character selection - All of a player's characters stand side by side in the real GTA world, GTA Online style (lineup), with an empty spot for a new one. Small interiors can show one at a time (single) - Someone always stands there: the empty spot gets a stand-in ped. It's solid for a brand-new player's first character and faded next to existing characters (Config.Selection.placeholderPed) - The camera frames the lineup by itself: it works out distance and field of view for any number of characters and any screen shape. It moves closer or turns around when a wall, glass or a building is in the way - Characters only stand on real ground: on narrow or uneven spots the lineup squeezes closer together, and if it still doesn't fit, the scene shows one character at a time instead - Clean, minimal look: each character's name, surname and job sit underneath them, and there's one small action bar at the bottom - Click a character (or its name), use ←/→, and press Enter to play. The camera glides over, the selected character gets a brighter light and waves - Drag to rotate, scroll to zoom - Players can cycle scenes, and the choice is remembered per player - Each player sits in a private routing bucket while choosing - The action bar shows the fields you choose: cash, bank, job, gang, birth date, nationality, phone, playtime, last played - Never a black screen: on joining, the server's loading screen stays up until the scene is ready. If anything fails (a Lua error, a conflicting resource, Qbox's own menu still on, ESX's Config.Multichar off), an error screen says what's wrong and offers Retry and Disconnect. A watchdog catches any step that stops making progress for 45 seconds

Slots - Default slot count, plus per-identifier overrides, ACE permissions, Discord roles (via a bot), database grants (/mc_setslots) and a hook for your own logic (e.g. Tebex) - Locked teaser cards with a link to your store - If a player loses slots, their extra characters stay visible but locked; nothing is deleted

Creation - First and last name, date of birth, gender (the 3D preview updates live), searchable nationality list or free text, a height slider (cm and ft/in), optional backstory, and an optional "I accept the rules" box - An ID card preview fills in as the player types - Validation runs live in the UI, then again on the server, which has the final say. It covers length, allowed characters (accents optional), substring blacklist, reserved words, real calendar dates and age limits. Global unique names are optional - Opens the player's clothing menu afterwards: illenium-appearance, fivem-appearance, qb-clothing, esx_skin, or your own - Starter items: uses the framework's defaults (QBCore Shared.StarterItems, Qbox starterItems) or your own list. Supports ox_inventory, qb-inventory, ps-inventory, lj-inventory and ESX. ID cards get name and date-of-birth metadata

Deletion - Soft delete (default): the character can be recovered with /mc_restore for N days, then is purged automatically. Hard delete is also available - Confirmation by hold-to-delete, by typing the character's name, or both. Has a cooldown and an optional ACE permission

Spawn selector - A drone camera orbits each location. Nearby spots fly over the map; distant ones cut with a quick fade - Simple fade into the world (default) or the GTA "switch" sky transition - New characters start the game right where they stood in the character scene, with no spawn picker (Config.Spawn.newCharacter.spawnInScene). A scene that isn't safe to start in can set spawnHere = false (new characters use Config.Spawn.newCharacter.default, LSIA arrivals) or a vector4 to start them somewhere else, e.g. outside the door. None of the included scenes sets it - Last location (forced automatically if the character was dead, jailed or inside a property), public spawns, job/gang/ACE-restricted spawns, new-only/existing-only spawns - qb-apartments: starter apartment selection for new characters (read from qb-apartments' own config) and a "My apartment" spawn - qb-houses: every owned house as a spawn - Any other housing script plugs in through one hook - Categories, search, thumbnails, and an optional "back to characters" button

Interface - Clean minimal design: thin light type floating over the game with no boxes. Themeable: accent colours, radius, any Google Font, logo, left or right layout - Optional extras, all off or easy to switch off: intro splash, server news cards, ID card preview, social/store links, live player count, background music, native GTA UI sounds - Scales correctly from 720p to 4K and ultrawide - Opens in a normal browser with mock data, so you can theme it without a server (see Browser preview)

Server owner tools - Discord webhook logs for create, delete, restore, select, spawn, relog and slot changes - /relog with a cooldown, an optional ACE permission and a hook - Admin commands, exports and events for other resources - Its own tables are created automatically; no SQL import needed - English, German, French and Spanish; easy to add more

Requirements

  • oxmysql
  • OneSync (standard on modern servers)
  • One of: qbx_core, qb-core, es_extended (Legacy), or nothing (standalone)
  • Optional: a clothing resource (illenium-appearance recommended)

Installation

  1. Drop origin_multicharacter into your resources folder.
  2. Remove or stop the resource this replaces (see your framework below).
  3. Start it after your framework and oxmysql in server.cfg:
ensure oxmysql
ensure qb-core          # or qbx_core / es_extended
ensure illenium-appearance
ensure origin_multicharacter
  1. Join the server. Tables are created automatically on first start.

QBCore

  • Remove qb-multicharacter and qb-spawn.
  • Works with qb-apartments (starter apartments) and qb-houses out of the box.
  • Anything that triggers qb-multicharacter:client:chooseChar still works.

Qbox

  • Required: in qbx_core/config/client.lua set characters.useExternalCharacters = true, then restart the server. While it's false, Qbox opens its own menu at the same time and the two fight over the camera. That's the usual cause of a black screen, so this resource detects it and shows an error telling you what to change.
  • Remove qbx_spawn if you use it.
  • Apartments (qbx_properties): by default (Config.Spawn.properties['qbx_properties'].starter = 'auto'), every character without an apartment gets its starter apartment automatically. The resource writes the same database rows qbx_properties' apartment board would, using apartment option starterApartment from qbx_properties' config/shared.lua. This works whatever qbx_core's characters.startingApartment says, and with it on, Qbox's board (the map with apartment markers) never shows. New characters still spawn where they stand. Owned apartments show up in the spawn picker, and players who logged out inside their apartment are put back inside, the same way qbx_spawn does it. qbx_spawn isn't needed. starter = 'board' leaves it to Qbox's board. starter = false only stops this resource from creating apartments: with qbx_core's characters.startingApartment = true (Qbox's default), qbx_properties' board still shows for every character without one. To have no starter apartments at all, set startingApartment = false in qbx_core.
  • Starter items come from qbx_core's starterItems (config/shared.lua, or config/server.lua on qbx_core older than 1.15) when Config.StarterItems.useFrameworkDefaults = true.

ESX Legacy

  • Remove esx_multicharacter. You don't need esx_identity's registration either, because creation happens here.
  • In es_extended's config set Config.Multichar = true. Newer versions compute it from whether esx_multicharacter is running, so set it to true explicitly.
  • Set Config.ESX.dateFormat to match the format your other scripts expect in users.dateofbirth.
  • Characters use ESX's standard charN:license identifiers, so existing characters show up as they are.

Standalone

  • Nothing else is needed. Characters are stored in origin_characters.
  • Other resources read the active character with exports.origin_multicharacter:GetCharacter(source) or the replicated state bag Player(source).state.character.

The console warns you on start if it finds a conflicting resource or a wrong framework setting.

Configuration

File What it controls
config/config.lua Slots, creation rules, deletion, selection, relog, spawning, appearance, starter items, logs, interface/theme
config/scenes.lua Where characters are shown
config/spawns.lua Spawn locations
editable/server.lua Server hooks: gate actions, extra slots, extra spawns, reactions
editable/client.lua Client hooks: notifications, HUD/weather-sync toggles, custom clothing menu
locales/*.lua All text, both in-game and in the UI

Scenes

Every scene is built around one anchor, vector4(x, y, z, heading). Characters stand on it facing heading, and the camera places itself automatically. In a lineup, characters stand side by side on the ground, closer together on uneven ground. The camera backs off far enough to fit them all, and if a wall or railing is in the way it moves closer, widens, or films from the other side.

Four scenes are included, all one character at a time. New characters start right where they stand:

id Where Mode
yellowjackbar (default) Inside the Yellow Jack, by the BEER sign, standing idle single
forum Forum Drive, Strawberry, leaning on a graffiti garage door single
janitor The Janitor's apartment, standing idle single
clubhouse The Lost MC clubhouse bar, sitting on the booth (rpemotes' sitchair) single

Other modes: lineup (everyone side by side, GTA Online style) and seats (everyone seated on chairs the scene places, seen from a fixed camera). The comments at the top of config/scenes.lua list every option.

To build your own scene: 1. Set Config.Debug = true, stand where the characters should stand, and face the way they should face, towards the camera. 2. Run /mc_coords and paste the printed vector4 as anchor. 3. Optionally add time, weather, timecycle, spacing, camera overrides, or entities (vehicles or props placed relative to the anchor).

Slots

Config.Slots = {
    default = 3, max = 8,
    identifiers = { ['license:...'] = 6 },
    ace = { { permission = 'origin.slots.vip', slots = 5 } },
    discord = { enabled = true, guildId = '...', roles = { ['roleId'] = 4 } },
}
  • ACE: add_ace group.vip origin.slots.vip allow
  • Discord: set origin_mc_discord_token "BOT_TOKEN" in server.cfg. The bot needs to be in your guild with the Server Members intent.
  • Database: /mc_setslots <server id | identifier> <slots>
  • Custom: Hooks.GetSlots(src, owner, current) in editable/server.lua

Spawn restrictions

{ id = 'mrpd', label = 'Mission Row PD', category = 'job', icon = 'shield',
  coords = vector4(428.23, -984.28, 29.76, 3.5),
  jobs = { police = 0 }, onDuty = false, gangs = nil, ace = nil, newOnly = false, existingOnly = false, snap = false }

Other housing scripts

Return spawns from Hooks.GetExtraSpawns in editable/server.lua. event is fired on the client after the teleport:

function Hooks.GetExtraSpawns(src, character, isNew)
    local list = {}
    for _, house in ipairs(MySQL.query.await('SELECT id, label, x, y, z FROM my_houses WHERE owner = ?', { character.citizenid })) do
        list[#list + 1] = {
            id = 'myhousing:' .. house.id, label = house.label, category = 'property', icon = 'home',
            coords = vector4(house.x, house.y, house.z, 0.0),
            event = 'myhousing:client:enter', args = { house.id },
        }
    end
    return list
end

Theme

Config.UI.theme = { accent = '#5aa9ff', accent2 = '#a78bfa', radius = 8, glass = 0.88, font = 'Barlow', displayFont = 'Barlow Condensed' }
Config.UI.layout = 'left' -- or 'right'

accent2 is the second stop of every gradient, so pick a colour that pairs with accent. Any Google Font name works.

Commands

Command Who What
/relog players Back to character selection (name, cooldown and ACE are configurable)
/mc_setslots <id\|identifier> <n> ACE command.mc_setslots Grant slots (stored in the database)
/mc_restore <key> ACE command.mc_restore Restore a soft-deleted character (citizenid, charN:license, or sa:id)
/mc_open <id> ACE command.mc_open Send a player back to character selection
/mc_purge ACE command.mc_purge Remove expired soft-deleted characters now
/mc_coords everyone, only with Config.Debug Print your position as a vector4
add_ace group.admin command.mc_setslots allow
add_ace group.admin command.mc_restore allow
add_ace group.admin command.mc_open allow
add_ace group.admin command.mc_purge allow

Developer API

Server exports

exports.origin_multicharacter:GetSlots(src)                  -- number
exports.origin_multicharacter:SetSlots(srcOrIdentifier, n)
exports.origin_multicharacter:Relog(src, bypassChecks)       -- bypassChecks defaults to true
exports.origin_multicharacter:IsInSelection(src)             -- boolean
exports.origin_multicharacter:GetPlaytime(src)               -- seconds on the current character
exports.origin_multicharacter:GetIdentityExtra(charKey)      -- { height, backstory, nationality }
exports.origin_multicharacter:RegisterSpawn({ id, label, coords, category, icon, jobs, ... })
exports.origin_multicharacter:RemoveSpawn(id)
-- standalone only
exports.origin_multicharacter:GetCharacter(src)
exports.origin_multicharacter:GetCharacterId(src)

Client exports

exports.origin_multicharacter:IsInSelection()
exports.origin_multicharacter:Relog()

Server events (AddEventHandler) - origin_multicharacter:server:characterCreated (src, character) - origin_multicharacter:server:characterSelected (src, character) - origin_multicharacter:server:characterDeleted (src, character, mode) - origin_multicharacter:server:playerSpawned (src, character, isNew) - Standalone: origin_multicharacter:server:characterLoaded / :characterUnloaded

Client events - origin_multicharacter:client:spawned (character, spawnId, isNew)

Event names are prefixed with the resource name, so renaming the folder renames them.

Browser preview

Serve the resource folder over HTTP and open the page:

cd origin_multicharacter
npx serve .            # or: python -m http.server
# open http://localhost:3000/web/index.html

Query options: ?view=create, ?view=spawn, ?chars=0 (a brand-new player), ?intro=1, ?news=1, ?idcard=1, ?layout=right, ?accent=%23f97316.

A browser can't render GTA, so the preview puts plain outlines where the characters stand. In game, the real world and your real characters take their place.

Security

  • The server is the only authority. The client sends a character key or spawn id, and the server checks it against the list it built for that player. Unknown keys, other players' characters, locked characters and spawn ids that weren't offered are all refused.
  • Requests are serialized per player, so double-clicks and spam can't run overlapping logins or deletes. Creation, deletion and relog have cooldowns.
  • Private data (identifiers, database keys) never leaves the server.
  • Names and backstories are sanitized on the server; the UI escapes everything it renders.

Troubleshooting

  • An error screen appears instead of the selection: it names the step that failed. "Check for conflicts" means another character resource is running, or Qbox's own menu is still on. "Load characters from the server" means the server side didn't answer: look at the server console. Anything else: press F8 and look for red origin_multicharacter lines.
  • Qbox shows its own menu as well, or the screen stays black: set characters.useExternalCharacters = true in qbx_core/config/client.lua and restart the server (a resource restart isn't enough).
  • Characters stand in a bad spot or the camera clips: switch scenes with the scenery button, or set Config.Selection.scene to another id. For your own spot, see Scenes.
  • ESX character doesn't load, or "Config.Multichar = false" on screen: set Config.Multichar = true in es_extended's config. Write it literally: newer versions compute it from whether esx_multicharacter is running, which turns it off once you remove that resource.
  • "This resource started before your framework": in server.cfg, ensure your framework (qbx_core, qb-core or es_extended) before origin_multicharacter.
  • Which version is installed? The server console prints origin_multicharacter <version> on start, and fxmanifest.lua has the same version.
  • Weather/time flicker in scenes: pause your weather sync in Editable.OnOpen (qb-weathersync and cd_easytime are handled already).
  • Stuck on the clothing camera with no menu: press F8. Errors like Cannot read properties of undefined (reading 'masks') from illenium-appearance mean it got an incomplete menu config; 1.1.2 always sends the full one. Other errors from your clothing resource: try Config.Appearance.provider set to the resource name, or 'none'.
  • Clothing menu opens twice with qb-apartments: some qb-apartments/qb-interior setups open the clothing menu themselves for new characters. Set Config.Appearance.newCharacter = false.