# Configuration

## Event to Open Multicharacter:

{% hint style="info" %}
**TriggerClientEvent('zr-multicharacter:start', src)**
{% endhint %}

## Tutorial of how to get the discord token , guild and roles ids :&#x20;

{% embed url="<https://www.youtube.com/watch?v=c_xkk8UMwkk>" %}

<details>

<summary>Files that are configurable</summary>

zr-multicharacter/zr-config/zr-config.lua

zr-multicharacter/zr-config/zr-build-c.lua

zr-multicharacter/zr-config/zr-build-s.lua

</details>

{% hint style="info" %}
To ensure you have everything you need, we are constantly updating our config files.
{% endhint %}

```lua
zr_config.framework = 'QB'  -- We support the following frameworks: 'QB' / 'ESX'
zr_config.QB = 'qb-core'    -- Don't touch
zr_config.ESX = 'es_extended'  -- Don't touch

zr_config.ToggleInterior = true
zr_config.Interior = vector3(-169.286, 486.4938, 137.4436)
zr_config.DefaultSpawn = vector3(-1035.71, -2731.87, 12.86)
zr_config.PlaCoords = vector4(-176.0504, 491.7193, 133.8438, 190.9712)
zr_config.CamCoords = vector4(-176.5, 498.7330, 134.8, 12)
zr_config.EndCoords = vector4(-176.1338, 500.2804, 134.6434, 180)
zr_config.StartCoords = vector4(-179.7581, 499.4727, 134.6435, 281.5096)

zr_config.DefaultModels = {"mp_m_freemode_01","mp_f_freemode_01"}

zr_config.zr_notify = true

zr_config.clothing = 'illenium-appearance' -- 'qb-clothing' or 'illenium-appearance'
zr_config.spawn = 'zr-locations' --  'ps-housing' or 'qb-spawn'


zr_config.default_slots = 1 -- Minimum 1
zr_config.discord_enable = true
-- Token transfered to zr-build-s.lua
zr_config.discord_guild = 1000020530499432448
zr_config.discord_roles = {
    ["1000377003704336476"] = 2, -- Add extra 2 slots if player has this role.
    ["1004486369919373392"] = 1, -- Add extra 1 slot if player has this role.
}

zr_config.EnableDelete = true
zr_config.EnableDeleteByDiscord = false
zr_config.discord_roles_delete_button = {
    ["1000377003704336476"] = true,
    ["1004486369919373392"] = true, 
}

zr_config.Debug = false

zr_config.prefix = 'char'

zr_trans.chinfos = "Character Information."
zr_trans.otinfos = "Other Information."
zr_trans.delete = "Delete character."
zr_trans.deleteconf = "Click again to confirm!"
zr_trans.play = "Play as"
zr_trans.create = "Create new character."
zr_trans.fname = "First Name"
zr_trans.lname = "Last Name"
zr_trans.gender = "Gender"
zr_trans.male = 'MALE'
zr_trans.female = 'FEMALE'
zr_trans.dob = "Birthdate"
zr_trans.job = "Job"
zr_trans.cash = "Cash"
zr_trans.bank = "Bank"
zr_trans.symb = "$"
zr_trans.aslots = "Default slots"
zr_trans.dslots = "Discord slots"

zr_trans.noslots = "You don't have any empty slots!"
zr_trans.deleted = "Character Deleted"
zr_trans.deldiscord = "You must have a discord role to delete your character"
```

{% hint style="info" %}
Open Source part of the script that we do provide in order to make your necessary changes for your server compatibility.
{% endhint %}

{% hint style="warning" %}
Client Side :&#x20;
{% endhint %}

```lua
function zr_multichar_show_public()
	-- Trigger Custom Functions/Events when display menu.
end

function zr_multichar_hide_public()
	-- Trigger Custom Functions/Events when hide menu.
end

function zr_setup_skin(zr_data)
    DeleteEntity(zr_current_char)
    if (zr_config.framework=='QB') then -- QBcore
        if zr_data ~= nil then
            QBcore.Functions.TriggerCallback('zr-multicharacter:getSkinData', function(zr_model, zr_skin)
				if (zr_config.clothing=='qb-clothing') then
					zr_model = zr_model ~= nil and tonumber(zr_model) or false
				end
				if zr_model ~= nil then
					CreateThread(function()
						zr_skin = json.decode(zr_skin)
						zr_multichar_loadModel(zr_model)
						zr_current_char = CreatePed(2, zr_model, zr_config.StartCoords.x, zr_config.StartCoords.y, zr_config.StartCoords.z, zr_config.StartCoords.w, false, true)
						if (zr_config.clothing=='qb-clothing') then
							TriggerEvent('qb-clothing:client:loadPlayerClothing', zr_skin, zr_current_char)
						elseif (zr_config.clothing=='illenium-appearance') then
							exports['illenium-appearance']:setPedAppearance(zr_current_char, zr_skin)
						end
						zr_animate_character(zr_current_char)
					end)
				else
					CreateThread(function()				
						zr_model = GetHashKey(zr_config.DefaultModels[math.random(1, #zr_config.DefaultModels)])
						zr_multichar_loadModel(zr_model)
						zr_current_char = CreatePed(2, zr_model, zr_config.StartCoords.x, zr_config.StartCoords.y, zr_config.StartCoords.z, zr_config.StartCoords.w, false, true)	
						zr_animate_character(zr_current_char)
					end)
				end
			end, zr_data.citizenid)
        else
            CreateThread(function()
                local zr_model = GetHashKey(zr_config.DefaultModels[1])
                zr_multichar_loadModel(zr_model)
                zr_current_char = CreatePed(2, zr_model, zr_config.StartCoords.x, zr_config.StartCoords.y, zr_config.StartCoords.z, zr_config.StartCoords.w, false, true)	
				zr_animate_character(zr_current_char)
            end)
        end
    else -- ESX
		if zr_data ~= nil then
			local zr_pedtype = "mp_f_freemode_01"
			local zr_skin = zr_config.DefaultSkins["f"]
			zr_skin.sex = 1
			if zr_data.sex == nil then 
				zr_pedtype = "mp_m_freemode_01"
				if zr_pedtype == "mp_m_freemode_01" then 
					zr_skin = zr_config.DefaultSkins["m"]
					zr_skin.sex = 0
				end
			else
				if zr_data.sex == "m" then 
					zr_pedtype = "mp_m_freemode_01"
					zr_skin = zr_config.DefaultSkins["m"]
					zr_skin.sex = 0
				end  
			end
			zr_model = GetHashKey(zr_pedtype)
			if zr_model ~= nil then
				CreateThread(function()
					exports.spawnmanager:spawnPlayer({x = zr_config.StartCoords.x,y = zr_config.StartCoords.y,z = zr_config.StartCoords.z,heading = zr_config.StartCoords.w,model = ped,skipFade = true
					}, function()
						if zr_data.skin then 
							zr_multichar_loadModel(zr_model)
							SetPlayerModel(PlayerId(), zr_model)
							SetModelAsNoLongerNeeded(zr_model)
							TriggerEvent('skinchanger:loadSkin', zr_data.skin)
						else
							TriggerEvent('skinchanger:loadSkin', zr_skin)
						end
					end)
					Wait(500)
					zr_animate_character(PlayerPedId())
				end)
			end
		end         
    end
end

if (zr_config.framework=='ESX') then
    RegisterNetEvent('esx:playerLoaded')
	AddEventHandler('esx:playerLoaded', function(zr_playerdata, zr_isnew, zr_skin)
		local zr_spawn = zr_playerdata.coords or zr_config.DefaultSpawn
		if zr_isnew or not zr_skin or #zr_skin == 1 then
			local done = false
			local zr_gender = zr_playerdata.sex -- local zr_gender = 'm' (https://github.com/zaphosting/esx_12)
			zr_skin = zr_config.DefaultSkins[zr_gender]
			zr_skin.sex = zr_gender == "m" and 0 or 1 
			if zr_skin.sex == 0 then zr_model = zr_config.DefaultModels[1] else zr_model = zr_config.DefaultModels[2] end
			zr_multichar_loadModel(zr_model)
			SetPlayerModel(PlayerId(), zr_model)
			SetModelAsNoLongerNeeded(zr_model)
			TriggerEvent('skinchanger:loadSkin', zr_skin, function()
                TriggerEvent('esx_skin:openSaveableMenu', function()
                    done = true end, function() done = true
                end)
			end)
			repeat Wait(200) until done
		end
		DoScreenFadeOut(100)
		SetEntityCoordsNoOffset(PlayerPedId(), zr_spawn.x, zr_spawn.y, zr_spawn.z, false, false, false, true)
		SetEntityHeading(PlayerPedId(), zr_spawn.heading)
		if not zr_isnew then TriggerEvent('skinchanger:loadSkin', zr_skin) end
		Wait(400)
		DoScreenFadeIn(400)
		repeat Wait(200) until not IsScreenFadedOut()
		TriggerServerEvent('esx:onPlayerSpawn')
		TriggerEvent('esx:onPlayerSpawn')
		TriggerEvent('playerSpawned')
		TriggerEvent('esx:restoreLoadout')
		FreezeEntityPosition(PlayerPedId(), false)
		zr_multichar_esx_hideplayers = false
		zr_multichar_esx_loops_stop()
	end)

	RegisterNetEvent('esx:onPlayerLogout')
	AddEventHandler('esx:onPlayerLogout', function()
		DoScreenFadeOut(0)
		TriggerEvent('esx_skin:resetFirstSpawn')
	end)
end


function zr_identity_notify(zr_msg)
    if (zr_config.zr_notify) then
        exports['zr-notify']:zr_notify('info', zr_msg, 5000, 'info', 'right')
    else
        if (zr_config.framework=='QB') then
            QBcore.Functions.Notify(zr_msg, "info")
		else
			ESX.ShowNotification(zr_msg, "info", 3000)
        end
    end
end
```

{% hint style="warning" %}
Server Side :
{% endhint %}

```lua
-- Discord Token Moved to Server Side
zr_config.discord_token = "Discord_Token_Here"  

if (zr_config.framework=='QB') then
    QBcore.Functions.CreateCallback("zr-multicharacter:getSkinData", function(_, cb, cid)
        if (zr_config.clothing=='qb-clothing') then
            local zr_data = MySQL.query.await('SELECT * FROM playerskins WHERE citizenid = ? AND active = ?', {cid, 1})
            if zr_data[1] ~= nil then
                cb(zr_data[1].model, zr_data[1].skin)
            else
                cb(nil)
            end
        elseif (zr_config.clothing=='illenium-appearance') then
            local zr_data = MySQL.query.await('SELECT * FROM playerskins WHERE citizenid = ? AND active = ?', {cid, 1})
            if zr_data[1] ~= nil then
                cb(zr_data[1].model, zr_data[1].skin)
            else
                cb(nil)
            end
        end
    end)

    function zr_custom_spawn_menu(zr_source, zr_data)
        if (zr_config.spawn=='ps-housing') then
            TriggerClientEvent('ps-housing:client:setupSpawnUI', zr_source, zr_data)
        else
            TriggerClientEvent('apartments:client:setupSpawnUI', zr_source, zr_data)
        end
    end

    QBcore.Commands.Add("logout", 'logout', {}, false, function(source)
        local src = source
        QBcore.Player.Logout(src)
        TriggerClientEvent('zr-multicharacter:start', src)
    end, "admin")
end


if (zr_config.framework=='ESX') then
    zr_dbtablesesx = {users = 'identifier'}

    function zr_custom_spawn_menu(zr_source)
        -- Spawn menu trigger here! 
    end 

    RegisterCommand('relog', function(source)
        TriggerClientEvent('zr-multicharacter:start', source)
        TriggerEvent('esx:playerLogout', source)
    end)
end
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0bugscripts.gitbook.io/0bugscripts/zbug-scripts/zbug-multicharacter/configuration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
