Skip to Content
QBCore docs – powered by Nextra 4
ResourcesQB-MultiCharacter

QB-MultiCharacter

QB-MultiCharacter provides a comprehensive character creation and selection system, allowing players to create multiple characters per account and switch between them seamlessly.

📋 Overview

QB-MultiCharacter enables:

  • Multiple Characters - Players can create up to a configurable number of characters
  • Character Selection - Beautiful UI for selecting characters on login
  • Character Creation - Comprehensive character customization system
  • Character Management - Delete, rename, and manage characters
  • Apartment Integration - Automatic apartment assignment for new characters
  • Spawn Selection - Choose where to spawn your character

⚙️ Installation & Setup

Prerequisites

  • QB-Core framework installed
  • QB-Spawn (recommended for spawn selection)
  • QB-Apartments (recommended for automatic apartment assignment)
  • QB-Clothing or qb-appearance (for character customization)

Installation Steps

  1. Download Resource

    git clone https://github.com/qbcore-framework/qb-multicharacter.git
  2. Place in Resources

    resources/ └── [qb]/ └── qb-multicharacter/
  3. Database Setup

    • Import SQL file: /qb-multicharacter/qb-multicharacter.sql
    CREATE TABLE IF NOT EXISTS `player_outfits` ( `id` int(11) NOT NULL AUTO_INCREMENT, `citizenid` varchar(50) DEFAULT NULL, `outfitname` varchar(50) NOT NULL, `model` varchar(50) DEFAULT NULL, `skin` text DEFAULT NULL, `outfitId` varchar(50) NOT NULL, PRIMARY KEY (`id`), KEY `citizenid` (`citizenid`), KEY `outfitId` (`outfitId`) );
  4. Server Configuration

    # server.cfg ensure qb-multicharacter

🔧 Configuration

Main Configuration

-- config.lua Config = Config or {} -- Maximum number of characters per account Config.MaxCharacters = 5 -- Enable character deletion Config.AllowCharacterDeletion = true -- Default spawn location Config.DefaultSpawn = vector4(-1035.71, -2731.87, 12.86, 0.0) -- Enable apartment assignment Config.AssignApartment = true -- Starting money for new characters Config.StartingMoney = { bank = 5000, cash = 500 } -- Character creation settings Config.CharacterCreation = { enableClothing = true, enableApartments = true, enableSpawnSelection = true }

Spawn Locations

-- Configuration for spawn selection Config.Spawns = { ["apartments"] = { coords = vector4(-1037.17, -2738.01, 13.76, 331.47), location = "apartments", label = "Apartments" }, ["motel"] = { coords = vector4(327.56, -205.08, 53.22, 163.5), location = "motel", label = "Motel" }, ["hotel"] = { coords = vector4(-1330.23, -1578.08, 2.61, 214.14), location = "hotel", label = "Hotel" } }

🎮 Player Experience

Character Selection Screen

When players connect, they see:

  • Character List - All created characters with preview
  • Character Info - Name, job, last played, money
  • Character Actions - Play, Delete, Rename
  • Create New - Button to create a new character (if under limit)

Character Creation Process

  1. Basic Information

    • First Name
    • Last Name
    • Date of Birth
    • Gender
    • Nationality
  2. Appearance Customization

    • Face structure
    • Skin tone
    • Hair style and color
    • Eye color
    • Facial features
  3. Clothing Selection

    • Starting outfit
    • Accessories
    • Color variations
  4. Spawn Location

    • Choose starting location
    • Apartment assignment (if enabled)

🔌 API Reference

Server Events

Character Selection

-- When player selects a character RegisterNetEvent('qb-multicharacter:server:loadUserData', function(cData) local src = source local license = QBCore.Functions.GetIdentifier(src, 'license') if QBCore.Player.Login(src, cData.citizenid) then print('Player ' .. cData.citizenid .. ' has successfully loaded') end end)

Character Creation

-- When player creates a new character RegisterNetEvent('qb-multicharacter:server:createCharacter', function(data) local src = source local newData = {} newData.cid = data.cid newData.charinfo = data if QBCore.Player.Login(src, false, newData) then print('New character created: ' .. data.firstname .. ' ' .. data.lastname) end end)

Character Deletion

-- When player deletes a character RegisterNetEvent('qb-multicharacter:server:deleteCharacter', function(citizenid) local src = source local license = QBCore.Functions.GetIdentifier(src, 'license') MySQL.Async.execute('DELETE FROM players WHERE citizenid = ? AND license = ?', { citizenid, license }, function(result) if result.affectedRows > 0 then TriggerClientEvent('QBCore:Notify', src, 'Character deleted successfully', 'success') end end) end)

Client Events

Setup Character Selection

-- Trigger character selection screen RegisterNetEvent('qb-multicharacter:client:setupCharacters', function(characters) SetNuiFocus(true, true) SendNUIMessage({ action = "setupCharacters", characters = characters, maxCharacters = Config.MaxCharacters }) end)

Character Preview

-- Setup character preview RegisterNetEvent('qb-multicharacter:client:previewCharacter', function(charData) if charData and charData.skin then local model = charData.skin.model local skin = json.decode(charData.skin) -- Load character model and apply skin SetupCharacterPreview(model, skin) end end)

🎨 UI Customization

HTML Structure

<!-- Character selection interface --> <div class="character-selection"> <div class="character-list"> <!-- Character cards --> </div> <div class="character-actions"> <button id="play-character">Play</button> <button id="delete-character">Delete</button> <button id="create-character">Create New</button> </div> </div>

CSS Styling

/* Custom styling for character selection */ .character-selection { background: linear-gradient(45deg, #1a1a1a, #2d2d2d); font-family: 'Roboto', sans-serif; } .character-card { background: rgba(255, 255, 255, 0.1); border-radius: 10px; padding: 20px; margin: 10px; transition: all 0.3s ease; } .character-card:hover { background: rgba(255, 255, 255, 0.2); transform: translateY(-5px); }

JavaScript Events

// Handle character selection $(document).on('click', '.character-card', function() { const cid = $(this).data('cid'); selectCharacter(cid); }); // Handle character creation $(document).on('click', '#create-character', function() { $.post('https://qb-multicharacter/createCharacter', JSON.stringify({ firstname: $('#firstname').val(), lastname: $('#lastname').val(), birthdate: $('#birthdate').val(), gender: $('#gender').val(), nationality: $('#nationality').val() })); });

🏠 Integration Examples

With QB-Apartments

-- Automatically assign apartment to new character RegisterNetEvent('qb-multicharacter:server:createCharacter', function(data) local src = source if QBCore.Player.Login(src, false, data) then -- Assign default apartment if Config.AssignApartment then TriggerEvent('qb-apartments:server:CreateApartment', src, 'apartment1') end end end)

With QB-Spawn

-- Integrate with spawn selection exports['qb-spawn']:openUI(function(coords, location) TriggerServerEvent('qb-multicharacter:server:setSpawnLocation', coords, location) end)

With QB-Clothing

-- Character appearance customization RegisterNetEvent('qb-multicharacter:client:openCreator', function() TriggerEvent('qb-clothing:client:openCreator', function(skin) TriggerServerEvent('qb-multicharacter:server:saveCharacterSkin', skin) end) end)

💾 Database Schema

Characters Table

-- Enhanced player data for multicharacter ALTER TABLE `players` ADD COLUMN `last_updated` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; -- Character metadata CREATE TABLE IF NOT EXISTS `character_meta` ( `id` int(11) NOT NULL AUTO_INCREMENT, `citizenid` varchar(50) NOT NULL, `meta_key` varchar(100) NOT NULL, `meta_value` longtext, PRIMARY KEY (`id`), KEY `citizenid` (`citizenid`), KEY `meta_key` (`meta_key`) );

Player Outfits

-- Character outfit storage CREATE TABLE IF NOT EXISTS `player_outfits` ( `id` int(11) NOT NULL AUTO_INCREMENT, `citizenid` varchar(50) DEFAULT NULL, `outfitname` varchar(50) NOT NULL, `model` varchar(50) DEFAULT NULL, `skin` text DEFAULT NULL, `outfitId` varchar(50) NOT NULL, PRIMARY KEY (`id`), KEY `citizenid` (`citizenid`) );

🛡️ Security Features

Character Validation

-- Validate character data before creation local function ValidateCharacterData(data) if not data.firstname or data.firstname == '' then return false, 'First name is required' end if not data.lastname or data.lastname == '' then return false, 'Last name is required' end if string.len(data.firstname) > 50 then return false, 'First name too long' end return true, 'Valid' end

Anti-Exploitation

-- Prevent character spam creation local characterCreationCooldown = {} RegisterNetEvent('qb-multicharacter:server:createCharacter', function(data) local src = source local license = QBCore.Functions.GetIdentifier(src, 'license') -- Check cooldown if characterCreationCooldown[license] and characterCreationCooldown[license] > GetGameTimer() then return TriggerClientEvent('QBCore:Notify', src, 'Please wait before creating another character', 'error') end -- Set cooldown (30 seconds) characterCreationCooldown[license] = GetGameTimer() + 30000 -- Continue with character creation end)

⚡ Performance Tips

Optimization

-- Cache character data to reduce database queries local characterCache = {} local function GetCharacterData(license) if characterCache[license] then return characterCache[license] end local result = MySQL.Sync.fetchAll('SELECT * FROM players WHERE license = ?', {license}) characterCache[license] = result return result end -- Clear cache on character update AddEventHandler('qb-multicharacter:server:characterUpdated', function(license) characterCache[license] = nil end)

❓ Troubleshooting

Common Issues

Issue: Characters not loading

-- Check database connection and table structure MySQL.ready(function() local result = MySQL.Sync.fetchAll('SHOW TABLES LIKE "players"') if #result == 0 then print('ERROR: Players table does not exist!') end end)

Issue: UI not showing

-- Check NUI callbacks RegisterNUICallback('closeUI', function(data, cb) SetNuiFocus(false, false) cb('ok') end)

Issue: Character creation fails

-- Add detailed error logging TriggerServerEvent('qb-multicharacter:server:createCharacter', data, function(success, message) if not success then print('Character creation failed: ' .. message) end end)

Debug Commands

-- Admin commands for debugging QBCore.Commands.Add('getcharacters', 'Get player characters', { {name = 'license', help = 'Player license'} }, true, function(source, args) local characters = GetCharacterData(args[1]) print(json.encode(characters, {indent = true})) end, 'admin')

📚 Additional Resources

Last updated on