From 698397fcb20d568953ae285012672ce3805a4ac3 Mon Sep 17 00:00:00 2001 From: Linden Date: Sun, 27 Jun 2021 12:55:54 +1000 Subject: [PATCH 01/64] tweak(client): Move SetupCharacters Server trigger; added locales --- client/main.lua | 7 +++---- locales/cs.lua | 2 ++ locales/de.lua | 2 ++ locales/en.lua | 2 ++ locales/pt.lua | 2 ++ locales/tr.lua | 2 ++ 6 files changed, 13 insertions(+), 4 deletions(-) diff --git a/client/main.lua b/client/main.lua index 0f9384dc..522522b8 100644 --- a/client/main.lua +++ b/client/main.lua @@ -8,8 +8,6 @@ if ESX.GetConfig().Multichar then while not GetResourceState('esx_menu_default') == 'started' do Citizen.Wait(0) end - Citizen.Wait(200) - TriggerServerEvent("esx_multicharacter:SetupCharacters") TriggerEvent("esx_multicharacter:SetupCharacters") break end @@ -38,6 +36,8 @@ if ESX.GetConfig().Multichar then ShutdownLoadingScreen() ShutdownLoadingScreenNui() TriggerEvent('esx:loadingScreenOff') + Citizen.Wait(200) + TriggerServerEvent("esx_multicharacter:SetupCharacters") end) StartLoop = function() @@ -97,7 +97,7 @@ if ESX.GetConfig().Multichar then if Characters[index] then local skin = Characters[index].skin or Config.Default if not Characters[index].model then - if Characters[index].sex == 'Female' then skin.sex = 1 else skin.sex = 0 end + if Characters[index].sex == _('female') then skin.sex = 1 else skin.sex = 0 end end TriggerEvent('skinchanger:loadSkin', skin) end @@ -315,7 +315,6 @@ if ESX.GetConfig().Multichar then AddEventHandler('esx:onPlayerLogout', function() DoScreenFadeOut(0) Spawned = false - TriggerServerEvent("esx_multicharacter:SetupCharacters") TriggerEvent("esx_multicharacter:SetupCharacters") TriggerEvent('esx_skin:resetFirstSpawn') end) diff --git a/locales/cs.lua b/locales/cs.lua index f4ffd7b5..a9734076 100644 --- a/locales/cs.lua +++ b/locales/cs.lua @@ -1,4 +1,6 @@ Locales['cs'] = { + ['male'] = "Muž", + ['female'] = "Žena", ['delete_label'] = "Vymazat %s %s?", ['select_char'] = "Zvolit Postavu", ['create_char'] = "Vytvořit novou postavu", diff --git a/locales/de.lua b/locales/de.lua index 8ffefc6b..654971af 100644 --- a/locales/de.lua +++ b/locales/de.lua @@ -1,4 +1,6 @@ Locales['de'] = { + ['male'] = "Männlich", + ['female'] = "Weiblich", ['delete_label'] = "Lösche %s %s?", ['select_char'] = "Charakter auswählen", ['create_char'] = "Neuen Charakter erstellen", diff --git a/locales/en.lua b/locales/en.lua index 72aa9cbe..f814d78a 100644 --- a/locales/en.lua +++ b/locales/en.lua @@ -1,4 +1,6 @@ Locales['en'] = { + ['male'] = "Male", + ['female'] = "Female", ['delete_label'] = "Delete %s %s?", ['select_char'] = "Select Character", ['create_char'] = "Create new character", diff --git a/locales/pt.lua b/locales/pt.lua index bd83f35e..04b828a3 100644 --- a/locales/pt.lua +++ b/locales/pt.lua @@ -1,4 +1,6 @@ Locales['pt'] = { + ['male'] = "Masculino", + ['female'] = "Feminino", ['delete_label'] = "Eliminar %s %s?", ['select_char'] = "Selecionar personagem", ['create_char'] = "Criar novo personagem", diff --git a/locales/tr.lua b/locales/tr.lua index 6fc35dab..8a3aa060 100644 --- a/locales/tr.lua +++ b/locales/tr.lua @@ -1,4 +1,6 @@ Locales['tr'] = { + ['male'] = "Erkek", + ['female'] = "Kadın", ['delete_label'] = "Sil %s %s?", ['select_char'] = "Karakter Seç", ['create_char'] = "Yeni Karakter Oluştur", From 7acd7bc5a04f52d4b84ab24b4149abe5c127f501 Mon Sep 17 00:00:00 2001 From: Linden Date: Sun, 27 Jun 2021 12:59:08 +1000 Subject: [PATCH 02/64] feat(server): Set VARCHAR(60) automatically; improvements to SQL.ready functions --- fxmanifest.lua | 14 +++++----- server/main.lua | 72 +++++++++++++++++++++---------------------------- 2 files changed, 38 insertions(+), 48 deletions(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index 2916b49e..9ee95603 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'adamant' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.1.1' +version '1.1.2' dependencies { 'es_extended', @@ -10,18 +10,20 @@ dependencies { 'esx_skin' } -shared_script 'config.lua' +shared_scripts { + '@es_extended/locale.lua', + 'locales/*.lua', + 'config.lua' +} server_scripts { '@es_extended/imports.lua', '@mysql-async/lib/MySQL.lua', - 'server/*.lua', + 'server/*.lua' } client_scripts { - '@es_extended/locale.lua', - 'client/main.lua', - 'locales/*.lua', + 'client/*.lua' } ui_page { diff --git a/server/main.lua b/server/main.lua index 09cf277f..c7fd07be 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,30 +1,20 @@ if not ESX then SetTimeout(3000, print('[^3WARNING^7] Unable to start Multicharacter - your version of ESX is not compatible ')) elseif ESX.GetConfig().Multichar == true then - local fetchCharacters = -1 - local IdentifierTables = {} - + local IdentifierTables, Fetch = {}, -1 + -- enter the name of your database here Config.Database = 'es_extended' + -- enter a prefix to prepend to all user identifiers (keep it short) Config.Prefix = 'char' - - RegisterCommand('varchar', function(source) - if source == 0 then - if next(IdentifierTables) == nil then print(' Unable to update your tables - have you defined the correct database?') return end - for _, itable in pairs(IdentifierTables) do - print('Setting `'..itable.table..'` column `'..itable.column..'` to VARCHAR(60)') - MySQL.Sync.execute("ALTER TABLE "..itable.table.." MODIFY COLUMN "..itable.column.." VARCHAR(60)", {}) - end - Citizen.Wait(100) - print(' Updated your tables to use the correct field length - you should remove this command') - end - end, true) - SetupCharacters = function(playerId) - while fetchCharacters == -1 do Citizen.Wait(100) end + local SetupCharacters = function(playerId) + while Fetch == -1 do Citizen.Wait(500) end local identifier = Config.Prefix..'%:'..ESX.GetIdentifier(playerId) - MySQL.Async.fetchAll(fetchCharacters, {'identifier', {identifier} + MySQL.Async.fetchAll(Fetch, { + identifier, + Config.Slots }, function(result) local characters = {} for i=1, #result, 1 do @@ -46,41 +36,43 @@ elseif ESX.GetConfig().Multichar == true then dateofbirth = result[i].dateofbirth, skin = json.decode(result[i].skin) } - if result[i].sex == 'm' then characters[id].sex = 'Male' else characters[id].sex = 'Female' end + if result[i].sex == 'm' then characters[id].sex = _('male') else characters[id].sex = _('female') end end TriggerClientEvent('esx_multicharacter:SetupUI', playerId, characters) end) end - DeleteCharacter = function(playerId, charid) + local DeleteCharacter = function(playerId, charid) local identifier = Config.Prefix..charid..':'..ESX.GetIdentifier(playerId) - for _, itable in pairs(IdentifierTables) do - MySQL.Async.execute("DELETE FROM "..itable.table.." WHERE "..itable.column.." = @identifier", { - ['@identifier'] = identifier + for k, v in pairs(IdentifierTables) do + MySQL.Async.execute("DELETE FROM "..v.table.." WHERE "..v.column.." = ?", { + identifier }) end + print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(playerId), playerId, identifier)) end Citizen.CreateThread(function() MySQL.ready(function () - fetchCharacters = MySQL.Sync.store("SELECT `identifier`, `accounts`, `job`, `job_grade`, `firstname`, `lastname`, `dateofbirth`, `sex`, `skin` FROM `users` WHERE ?? LIKE ?") - - MySQL.Async.fetchAll('SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = @id AND TABLE_SCHEMA = @db', { ['@id'] = "owner", ["@db"] = Config.Database}, function(result) - if result then - for k, v in pairs(result) do - IdentifierTables[#IdentifierTables+1] = {table = v.TABLE_NAME, column = 'owner'} - end + local result = MySQL.Sync.fetchAll('SELECT `TABLE_NAME`, `COLUMN_NAME`, `CHARACTER_MAXIMUM_LENGTH` FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND (COLUMN_NAME = ? OR COLUMN_NAME = ?) ', { + Config.Database, 'identifier', 'owner' + }) + if result then + local varchar, varsize = {}, 0 + for k, v in pairs(result) do + if v.CHARACTER_MAXIMUM_LENGTH < 60 then varchar[v.TABLE_NAME] = v.COLUMN_NAME varsize = varsize+1 end + table.insert(IdentifierTables, {table = v.TABLE_NAME, column = v.COLUMN_NAME}) end - end) - MySQL.Async.fetchAll('SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = @id AND TABLE_SCHEMA = @db', { ['@id'] = "identifier", ["@db"] = Config.Database}, function(result) - if result then - for k, v in pairs(result) do - IdentifierTables[#IdentifierTables+1] = {table = v.TABLE_NAME, column = 'identifier'} + if next(varchar) then + for k, v in pairs(varchar) do + MySQL.Sync.execute("ALTER TABLE "..k.." MODIFY COLUMN "..v.." VARCHAR(60)") end + print(('[^2INFO^7] Attempted to update ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) end - end) + end + if not next(ESX.Jobs) then ESX.Jobs = GetJobs() end + Fetch = MySQL.Sync.store("SELECT `identifier`, `accounts`, `job`, `job_grade`, `firstname`, `lastname`, `dateofbirth`, `sex`, `skin` FROM `users` WHERE identifier LIKE ? LIMIT ?") end) - if not next(ESX.Jobs) then ESX.Jobs = GetJobs() end end) RegisterServerEvent("esx_multicharacter:SetupCharacters") @@ -98,8 +90,6 @@ elseif ESX.GetConfig().Multichar == true then else TriggerEvent('esx:onPlayerJoined', src, Config.Prefix..charid) end - else - -- Trigger Ban Event here to ban individuals trying to use SQL Injections end end) @@ -118,8 +108,6 @@ elseif ESX.GetConfig().Multichar == true then if type(charid) == "number" and string.len(charid) <= 2 then DeleteCharacter(src, charid) SetupCharacters(src) - else - -- Trigger Ban Event here to ban individuals trying to use SQL Injections end end) @@ -133,6 +121,6 @@ elseif ESX.GetConfig().Multichar == true then TriggerEvent('esx:playerLogout', source) end, true) -elseif ESX.GetConfig().Multichar == false then +else SetTimeout(3000, print('[^3WARNING^7] Multicharacter is disabled - please check your ESX configuration')) end From 7332a64ef634ac1247164368d2713b2004dfabb2 Mon Sep 17 00:00:00 2001 From: Linden Date: Sun, 27 Jun 2021 18:05:50 +1000 Subject: [PATCH 03/64] improvements(client): Overhauled most of the character selection and spawning logic --- client/main.lua | 109 ++++++++++++++++++++++-------------------------- fxmanifest.lua | 2 +- 2 files changed, 50 insertions(+), 61 deletions(-) diff --git a/client/main.lua b/client/main.lua index 522522b8..5b859a7d 100644 --- a/client/main.lua +++ b/client/main.lua @@ -13,10 +13,8 @@ if ESX.GetConfig().Multichar then end end) - local cam, cam2 = nil, nil + local canRelog, cam, Spawned = true local Characters = {} - local canRelog = true - local Spawned RegisterNetEvent('esx_multicharacter:SetupCharacters') AddEventHandler('esx_multicharacter:SetupCharacters', function() @@ -42,8 +40,9 @@ if ESX.GetConfig().Multichar then StartLoop = function() hidePlayers = true + MumbleSetVolumeOverride(PlayerId(), 0.0) Citizen.CreateThread(function() - local keys = {18, 27, 172, 173, 176, 177, 187, 188, 191, 201} + local keys = {18, 27, 172, 173, 176, 177, 187, 188, 191, 201, 108, 109} while hidePlayers do DisableAllControlActions(0) for i=1, #keys do @@ -53,31 +52,35 @@ if ESX.GetConfig().Multichar then SetLocalPlayerVisibleLocally(1) SetPlayerInvincible(PlayerId(), 1) Citizen.Wait(3) + local vehicles = GetGamePool('CVehicle') + for i=1, #vehicles do + SetEntityLocallyInvisible(vehicles[i]) + end end + local playerId, playerPed = PlayerId(), PlayerPedId() + MumbleSetVolumeOverride(playerId, -1.0) + SetEntityVisible(playerPed, 1, 0) + SetPlayerInvincible(playerId, 0) + FreezeEntityPosition(playerPed, false) + Citizen.Wait(10000) + canRelog = true end) Citizen.CreateThread(function() - local players, vehicles + local playerPool = {} while hidePlayers do - players = GetActivePlayers() + local players = GetActivePlayers() for i=1, #players do - if players[i] ~= PlayerId() then NetworkConcealPlayer(players[i], true, true) end - end - vehicles = ESX.Game.GetVehicles() - for i=1, #vehicles do - NetworkConcealEntity(vehicles[i], true) + local player = players[i] + if player ~= PlayerId() and not playerPool[player] then + playerPool[player] = true + NetworkConcealPlayer(players[player], true, true) + end end Citizen.Wait(500) end - for i=1, #players do - if players[i] ~= PlayerId() then NetworkConcealPlayer(players[i], false, false) end + for i=1, #playerPool do + NetworkConcealPlayer(playerPool[i], false, false) end - for i=1, #vehicles do - NetworkConcealEntity(vehicles[i], false) - end - SetEntityVisible(PlayerPedId(), 1, 0) - SetPlayerInvincible(PlayerId(), 0) - Citizen.Wait(10000) - canRelog = true end) end @@ -144,10 +147,12 @@ if ESX.GetConfig().Multichar then z = Config.Spawn.z, heading = Config.Spawn.w, model = `mp_m_freemode_01`, - skipFade = false + skipFade = true }, function() exports.spawnmanager:setAutoSpawn(false) canRelog = false + DoScreenFadeIn(400) + while not IsScreenFadedIn() do Citizen.Wait(200) end local playerPed = PlayerPedId() SetPedAoBlobRendering(playerPed, false) SetEntityAlpha(playerPed, 0) @@ -155,8 +160,6 @@ if ESX.GetConfig().Multichar then TriggerEvent('esx_identity:showRegisterIdentity') end) else - DoScreenFadeIn(400) - while not IsScreenFadedIn() do Citizen.Wait(200) end for k,v in pairs(Characters) do if not v.model and v.skin then if v.skin.model then v.model = v.skin.model elseif v.skin.sex == 1 then v.model = `mp_f_freemode_01` else v.model = `mp_m_freemode_01` end @@ -165,6 +168,8 @@ if ESX.GetConfig().Multichar then local label = v.firstname..' '..v.lastname elements[#elements+1] = {label = label, value = v.id} end + DoScreenFadeIn(200) + Citizen.Wait(200) if #elements < Config.Slots then elements[#elements+1] = {label = _('create_char'), value = (#elements+1), new = true} end @@ -184,12 +189,10 @@ if ESX.GetConfig().Multichar then }, function(data, menu) if data.current.action == 'play' then ESX.UI.Menu.CloseAll() - DoScreenFadeOut(300) SendNUIMessage({ action = "closeui" }) TriggerServerEvent('esx_multicharacter:CharacterChosen', data.current.value, false) - Citizen.Wait(300) else local elements2 = {} elements2[1] = {label = _('cancel')} @@ -248,25 +251,19 @@ if ESX.GetConfig().Multichar then RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(playerData, isNew, skin) + DoScreenFadeOut(100) local spawn = playerData.coords - DoScreenFadeOut(0) - Citizen.Wait(300) local playerPed = PlayerPedId() - cam2 = CreateCamWithParams("DEFAULT_SCRIPTED_CAMERA", spawn.x,spawn.y,spawn.z+200, 0.0, 0.0, 0.0, 100.00, false, 0) - PointCamAtCoord(cam2, spawn.x,spawn.y,spawn.z+10) - SetCamActiveWithInterp(cam2, cam, 400, true, true) - - Citizen.Wait(700) - DoScreenFadeIn(500) FreezeEntityPosition(playerPed, true) - SetEntityVisible(playerPed, true, 0) - SetEntityCoords(playerPed, spawn.x, spawn.y, spawn.z, true, false, false, false) + SetEntityCoords(playerPed, spawn.x, spawn.y, spawn.z-1.3, true, false, false, false) + SetEntityHeading(playerPed, spawn.heading) + Citizen.Wait(300) + SetCamActive(cam, false) + RenderScriptCams(0, 0) + DestroyAllCams(true) + DoScreenFadeIn(400) + Citizen.Wait(400) - cam = CreateCamWithParams("DEFAULT_SCRIPTED_CAMERA", spawn.x,spawn.y,spawn.z+10, 0.0, 0.0, 0.0, 100.00, false, 0) - PointCamAtCoord(cam, spawn.x,spawn.y,spawn.z) - SetCamActiveWithInterp(cam, cam2, 1700, true, true) - - PlaySoundFrontend(-1, "Zoom_Out", "DLC_HEIST_PLANNING_BOARD_SOUNDS", 1) if isNew or not skin or #skin == 1 then local sex = skin.sex or 0 if sex == 0 then model = `mp_m_freemode_01` else model = `mp_f_freemode_01` end @@ -280,35 +277,27 @@ if ESX.GetConfig().Multichar then skin = Config.Default skin.sex = sex TriggerEvent('skinchanger:loadSkin', skin, function() - Citizen.CreateThread(function() - playerped = PlayerPedId() - SetPedAoBlobRendering(playerPed, true) - ResetEntityAlpha(playerPed) - Citizen.Wait(1500) - TriggerEvent('esx_skin:openSaveableMenu') - SetEntityHeading(playerPed, spawn.heading) + playerPed = PlayerPedId() + SetPedAoBlobRendering(playerPed, true) + ResetEntityAlpha(playerPed) + TriggerEvent('esx_skin:openSaveableMenu', function() + finished = true end, function() finished = true end) + SetEntityHeading(playerPed, spawn.heading) end) + while not finished do Citizen.Wait(200) end else + local playerPed = PlayerPedId() + SetEntityHeading(playerPed, spawn.heading) TriggerEvent('skinchanger:loadSkin', skin or Characters[Spawned].skin) - Citizen.Wait(1500) + playerPed = PlayerPedId() + SetEntityVisible(playerPed, true, 0) end - Characters = {} TriggerServerEvent('esx:onPlayerSpawn') TriggerEvent('esx:onPlayerSpawn') TriggerEvent('playerSpawned') TriggerEvent('esx:restoreLoadout') - playerPed = PlayerPedId() - FreezeEntityPosition(playerPed, false) - SetEntityHeading(PlayerPed, spawn.heading) - Citizen.Wait(500) - RenderScriptCams(false, true, 500, true, true) - PlaySoundFrontend(-1, "CAR_BIKE_WHOOSH", "MP_LOBBY_SOUNDS", 1) - SetCamActive(cam, false) - DestroyAllCams(true) - DisplayHud(true) - DisplayRadar(true) - hidePlayers = false + Characters, hidePlayers = {}, false end) RegisterNetEvent('esx:onPlayerLogout') diff --git a/fxmanifest.lua b/fxmanifest.lua index 9ee95603..e41f9719 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'adamant' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.1.2' +version '1.2.0' dependencies { 'es_extended', From b081008863bd69f82fad315c419ab9bfc8fe612f Mon Sep 17 00:00:00 2001 From: Linden Date: Sun, 27 Jun 2021 18:05:50 +1000 Subject: [PATCH 04/64] improvements(client): Fix nil value; overhauled most of the character selection and spawning logic --- server/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/main.lua b/server/main.lua index c7fd07be..790e41bc 100644 --- a/server/main.lua +++ b/server/main.lua @@ -60,7 +60,7 @@ elseif ESX.GetConfig().Multichar == true then if result then local varchar, varsize = {}, 0 for k, v in pairs(result) do - if v.CHARACTER_MAXIMUM_LENGTH < 60 then varchar[v.TABLE_NAME] = v.COLUMN_NAME varsize = varsize+1 end + if v.CHARACTER_MAXIMUM_LENGTH and v.CHARACTER_MAXIMUM_LENGTH >= 40 and v.CHARACTER_MAXIMUM_LENGTH < 60 then varchar[v.TABLE_NAME] = v.COLUMN_NAME varsize = varsize+1 end table.insert(IdentifierTables, {table = v.TABLE_NAME, column = v.COLUMN_NAME}) end if next(varchar) then From d6c7e10594395fbf03651c0615c5d6a41e321ec0 Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 28 Jun 2021 18:02:15 +1000 Subject: [PATCH 05/64] improvements(client): Disable spawnmanager auto spawning --- client/main.lua | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/client/main.lua b/client/main.lua index 5b859a7d..4ea6edb5 100644 --- a/client/main.lua +++ b/client/main.lua @@ -2,17 +2,21 @@ ESX = exports['es_extended']:getSharedObject() if ESX.GetConfig().Multichar then Citizen.CreateThread(function() - while NetworkIsPlayerActive(PlayerId()) and not ESX.IsPlayerLoaded() do - Citizen.Wait(5) - DoScreenFadeOut(0) - while not GetResourceState('esx_menu_default') == 'started' do - Citizen.Wait(0) + while not ESX.PlayerLoaded do + Citizen.Wait(0) + if NetworkIsPlayerActive(PlayerId()) then + exports.spawnmanager:setAutoSpawn(false) + DoScreenFadeOut(0) + while not GetResourceState('esx_menu_default') == 'started' do + Citizen.Wait(0) + end + TriggerEvent("esx_multicharacter:SetupCharacters") + break end - TriggerEvent("esx_multicharacter:SetupCharacters") - break end end) + local canRelog, cam, Spawned = true local Characters = {} @@ -86,8 +90,6 @@ if ESX.GetConfig().Multichar then SetupCharacter = function(index) if Spawned == false then - exports.spawnmanager:setAutoSpawn(false) - exports.spawnmanager:forceRespawn() exports.spawnmanager:spawnPlayer({ x = Config.Spawn.x, y = Config.Spawn.y, @@ -104,7 +106,6 @@ if ESX.GetConfig().Multichar then end TriggerEvent('skinchanger:loadSkin', skin) end - exports.spawnmanager:setAutoSpawn(false) end) elseif Characters[index] and Characters[index].skin then if Characters[Spawned] and Characters[Spawned].model then @@ -149,10 +150,9 @@ if ESX.GetConfig().Multichar then model = `mp_m_freemode_01`, skipFade = true }, function() - exports.spawnmanager:setAutoSpawn(false) canRelog = false DoScreenFadeIn(400) - while not IsScreenFadedIn() do Citizen.Wait(200) end + Citizen.Wait(400) local playerPed = PlayerPedId() SetPedAoBlobRendering(playerPed, false) SetEntityAlpha(playerPed, 0) @@ -168,8 +168,8 @@ if ESX.GetConfig().Multichar then local label = v.firstname..' '..v.lastname elements[#elements+1] = {label = label, value = v.id} end - DoScreenFadeIn(200) - Citizen.Wait(200) + DoScreenFadeIn(400) + Citizen.Wait(400) if #elements < Config.Slots then elements[#elements+1] = {label = _('create_char'), value = (#elements+1), new = true} end From f3eb335547bf326dc8567235ac11461b85d482d2 Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 28 Jun 2021 18:54:50 +1000 Subject: [PATCH 06/64] refactor(server): Should be using Async here --- server/main.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/server/main.lua b/server/main.lua index 790e41bc..4a52cac9 100644 --- a/server/main.lua +++ b/server/main.lua @@ -52,11 +52,10 @@ elseif ESX.GetConfig().Multichar == true then print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(playerId), playerId, identifier)) end - Citizen.CreateThread(function() - MySQL.ready(function () - local result = MySQL.Sync.fetchAll('SELECT `TABLE_NAME`, `COLUMN_NAME`, `CHARACTER_MAXIMUM_LENGTH` FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND (COLUMN_NAME = ? OR COLUMN_NAME = ?) ', { - Config.Database, 'identifier', 'owner' - }) + MySQL.ready(function() + MySQL.Async.fetchAll('SELECT `TABLE_NAME`, `COLUMN_NAME`, `CHARACTER_MAXIMUM_LENGTH` FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND (COLUMN_NAME = ? OR COLUMN_NAME = ?) ', { + Config.Database, 'identifier', 'owner' + }, function(result) if result then local varchar, varsize = {}, 0 for k, v in pairs(result) do @@ -69,9 +68,9 @@ elseif ESX.GetConfig().Multichar == true then end print(('[^2INFO^7] Attempted to update ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) end + if not next(ESX.Jobs) then ESX.Jobs = GetJobs() end + Fetch = MySQL.Sync.store("SELECT `identifier`, `accounts`, `job`, `job_grade`, `firstname`, `lastname`, `dateofbirth`, `sex`, `skin` FROM `users` WHERE identifier LIKE ? LIMIT ?") end - if not next(ESX.Jobs) then ESX.Jobs = GetJobs() end - Fetch = MySQL.Sync.store("SELECT `identifier`, `accounts`, `job`, `job_grade`, `firstname`, `lastname`, `dateofbirth`, `sex`, `skin` FROM `users` WHERE identifier LIKE ? LIMIT ?") end) end) From c97daae2a963dd6e5e424d3aaf092e8fcc49549c Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 28 Jun 2021 19:00:17 +1000 Subject: [PATCH 07/64] improvements(client): Hide HUD components while active; refactor --- client/main.lua | 23 +++++++++++++---------- fxmanifest.lua | 2 +- readme.md | 7 +++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/client/main.lua b/client/main.lua index 4ea6edb5..f79c29b5 100644 --- a/client/main.lua +++ b/client/main.lua @@ -32,8 +32,6 @@ if ESX.GetConfig().Multichar then SetCamActive(cam, true) RenderScriptCams(true, false, 1, true, true) ESX.UI.HUD.SetDisplay(0.0) - DisplayHud(false) - DisplayRadar(false) StartLoop() ShutdownLoadingScreen() ShutdownLoadingScreenNui() @@ -55,6 +53,11 @@ if ESX.GetConfig().Multichar then SetEntityVisible(PlayerPedId(), 0, 0) SetLocalPlayerVisibleLocally(1) SetPlayerInvincible(PlayerId(), 1) + ThefeedHideThisFrame() + HideHudComponentThisFrame(11) + HideHudComponentThisFrame(12) + HideHudComponentThisFrame(21) + HideHudAndRadarThisFrame() Citizen.Wait(3) local vehicles = GetGamePool('CVehicle') for i=1, #vehicles do @@ -106,7 +109,10 @@ if ESX.GetConfig().Multichar then end TriggerEvent('skinchanger:loadSkin', skin) end + DoScreenFadeIn(400) + while IsScreenFadedOut() do Citizen.Wait(100) end end) + elseif Characters[index] and Characters[index].skin then if Characters[Spawned] and Characters[Spawned].model then RequestModel(Characters[index].model) @@ -119,15 +125,15 @@ if ESX.GetConfig().Multichar then end TriggerEvent('skinchanger:loadSkin', Characters[index].skin) end - FreezeEntityPosition(PlayerPedId(), true) Spawned = index - SendNUIMessage({ - action = "openui", - character = Characters[index] - }) local playerPed = PlayerPedId() + FreezeEntityPosition(PlayerPedId(), true) SetPedAoBlobRendering(playerPed, true) SetEntityAlpha(playerPed, 255) + SendNUIMessage({ + action = "openui", + character = Characters[Spawned] + }) end RegisterNetEvent('esx_multicharacter:SetupUI') @@ -141,7 +147,6 @@ if ESX.GetConfig().Multichar then SendNUIMessage({ action = "closeui" }) - exports.spawnmanager:forceRespawn() exports.spawnmanager:spawnPlayer({ x = Config.Spawn.x, y = Config.Spawn.y, @@ -168,8 +173,6 @@ if ESX.GetConfig().Multichar then local label = v.firstname..' '..v.lastname elements[#elements+1] = {label = label, value = v.id} end - DoScreenFadeIn(400) - Citizen.Wait(400) if #elements < Config.Slots then elements[#elements+1] = {label = _('create_char'), value = (#elements+1), new = true} end diff --git a/fxmanifest.lua b/fxmanifest.lua index e41f9719..57787aaa 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'adamant' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.2.0' +version '1.2.1' dependencies { 'es_extended', diff --git a/readme.md b/readme.md index c6c5341f..7fa5bfea 100644 --- a/readme.md +++ b/readme.md @@ -9,8 +9,7 @@ - Modify your ESX config with `Config.Multichar = true` - Set your database name for `Config.Database` in server/main.lua - All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry -- Use the `varchar` command from the console to update your SQL tables -- Once you have used the command you should just remove it for sanity's sake + - The resource will attempt to set columns automatically ### Conflicts * The following resources should not be used with ESX Legacy and can result in errors @@ -19,14 +18,14 @@ - fivem-map-skater - fivem-map-hipster - default_spawnpoint - - cui_character (or other resources that modify spawn behaviour) ### Common issues #### Black screen / loading scripts - Download and run all requirements + - Use a fresh spawnmanager as many people alter the code - Ensure none of the conflicting resources are enabled #### mysql-async duplicate entry - - You have not increased the VARCHAR size of your tables (use the command) + - You have not increased the VARCHAR size of the table holding identifiers - usually `owner` or `identifier` #### The menu interface is esx_menu_default - you can use any version if you want a different appearance ![image](https://user-images.githubusercontent.com/65407488/119010385-592a8c80-b9d7-11eb-9aa1-eb7051004843.png) From e7090e6a7d4136032e5a5326d4f9fbbeb98aab8e Mon Sep 17 00:00:00 2001 From: Linden Date: Tue, 29 Jun 2021 19:24:56 +1000 Subject: [PATCH 08/64] fix(client): Enable and and right arrow keys while loop is active Due to hidePlayers now waiting until a skin has been set before disabling, these keys are now required. --- client/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/main.lua b/client/main.lua index f79c29b5..3d7aab44 100644 --- a/client/main.lua +++ b/client/main.lua @@ -44,7 +44,7 @@ if ESX.GetConfig().Multichar then hidePlayers = true MumbleSetVolumeOverride(PlayerId(), 0.0) Citizen.CreateThread(function() - local keys = {18, 27, 172, 173, 176, 177, 187, 188, 191, 201, 108, 109} + local keys = {18, 27, 172, 173, 174, 175, 176, 177, 187, 188, 191, 201, 108, 109} while hidePlayers do DisableAllControlActions(0) for i=1, #keys do From 5dcae7c4c5911aceb2621f688d98c971731aba64 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Fri, 9 Jul 2021 19:39:15 +1000 Subject: [PATCH 09/64] Update readme.md --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 7fa5bfea..7cfa0536 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,5 @@ ### Requirements (ensure you are using the latest) -- [ESX Legacy](https://github.com/esx-framework/es_extended/tree/legacy) +- [ESX Legacy](https://github.com/esx-framework/esx-legacy) - [MySQL Async 3.3.2](https://github.com/brouznouf/fivem-mysql-async/releases/tag/3.3.2) - [ESX Identity](https://github.com/esx-framework/esx_identity) - [ESX Skin](https://github.com/esx-framework/esx_skin) @@ -13,7 +13,7 @@ ### Conflicts * The following resources should not be used with ESX Legacy and can result in errors - - **essentialsmode** + - essentialmode - basic-gamemode - fivem-map-skater - fivem-map-hipster From 861dfcda88217566f5b2e0186b8203eecd841d19 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Wed, 21 Jul 2021 13:30:44 +1000 Subject: [PATCH 10/64] Update main.lua --- server/main.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/main.lua b/server/main.lua index 4a52cac9..f13d9e82 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,5 +1,5 @@ if not ESX then - SetTimeout(3000, print('[^3WARNING^7] Unable to start Multicharacter - your version of ESX is not compatible ')) + SetTimeout(3000, function() print('[^3WARNING^7] Unable to start Multicharacter - your version of ESX is not compatible ') end) elseif ESX.GetConfig().Multichar == true then local IdentifierTables, Fetch = {}, -1 @@ -121,5 +121,5 @@ elseif ESX.GetConfig().Multichar == true then end, true) else - SetTimeout(3000, print('[^3WARNING^7] Multicharacter is disabled - please check your ESX configuration')) + SetTimeout(3000, function() print('[^3WARNING^7] Multicharacter is disabled - please check your ESX configuration') end) end From 5f142f6d1f78d2db6f79c379549761664790668a Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Mon, 26 Jul 2021 20:42:00 +1000 Subject: [PATCH 11/64] chore: Update screenshot in readme --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7cfa0536..35360673 100644 --- a/readme.md +++ b/readme.md @@ -28,7 +28,7 @@ - You have not increased the VARCHAR size of the table holding identifiers - usually `owner` or `identifier` #### The menu interface is esx_menu_default - you can use any version if you want a different appearance -![image](https://user-images.githubusercontent.com/65407488/119010385-592a8c80-b9d7-11eb-9aa1-eb7051004843.png) +![image](https://user-images.githubusercontent.com/65407488/126976325-17cc3241-bb9e-451f-a6ed-610a8ef52fa5.png) ### Relogging - Do not enable this setting if you do not intend to properly set up relog support From 657dcc772828e76fc10e59da764a26756b7c5134 Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 26 Jul 2021 20:46:07 +1000 Subject: [PATCH 12/64] tweak(client): Modify camera behaviour and positioning --- client/main.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/main.lua b/client/main.lua index 3d7aab44..122e5543 100644 --- a/client/main.lua +++ b/client/main.lua @@ -25,12 +25,17 @@ if ESX.GetConfig().Multichar then ESX.PlayerLoaded = false ESX.PlayerData = {} Spawned = false - cam = CreateCamWithParams("DEFAULT_SCRIPTED_CAMERA", Config.Spawn.x, Config.Spawn.y+1.6, Config.Spawn.z+1.3, 0.0, 0.0, 180.0, 100.00, false, 0) - SetEntityCoords(PlayerPedId(), Config.Spawn.x, Config.Spawn.y, Config.Spawn.z, true, false, false, false) - SetEntityHeading(PlayerPedId(), Config.Spawn.w) + cam = CreateCam("DEFAULT_SCRIPTED_CAMERA", true) + local playerPed = PlayerPedId() + SetEntityCoords(playerPed, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z, true, false, false, false) + SetEntityHeading(playerPed, Config.Spawn.w) DoScreenFadeOut(0) SetCamActive(cam, true) RenderScriptCams(true, false, 1, true, true) + + SetCamCoord(cam, Config.Spawn.x, Config.Spawn.y + 1.6, Config.Spawn.z + 1.3) + PointCamAtCoord(cam, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z + 1.3) + ESX.UI.HUD.SetDisplay(0.0) StartLoop() ShutdownLoadingScreen() From 9480853f6a88c2408616f69066986ac37df8a156 Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 26 Jul 2021 20:48:29 +1000 Subject: [PATCH 13/64] improvement: New players now select skin before teleporting to spawn - This also resolves the bug with esx_skin's camera being zoomed in --- client/main.lua | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/client/main.lua b/client/main.lua index 122e5543..84f6b52e 100644 --- a/client/main.lua +++ b/client/main.lua @@ -259,19 +259,7 @@ if ESX.GetConfig().Multichar then RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(playerData, isNew, skin) - DoScreenFadeOut(100) local spawn = playerData.coords - local playerPed = PlayerPedId() - FreezeEntityPosition(playerPed, true) - SetEntityCoords(playerPed, spawn.x, spawn.y, spawn.z-1.3, true, false, false, false) - SetEntityHeading(playerPed, spawn.heading) - Citizen.Wait(300) - SetCamActive(cam, false) - RenderScriptCams(0, 0) - DestroyAllCams(true) - DoScreenFadeIn(400) - Citizen.Wait(400) - if isNew or not skin or #skin == 1 then local sex = skin.sex or 0 if sex == 0 then model = `mp_m_freemode_01` else model = `mp_f_freemode_01` end @@ -291,16 +279,21 @@ if ESX.GetConfig().Multichar then TriggerEvent('esx_skin:openSaveableMenu', function() finished = true end, function() finished = true end) - SetEntityHeading(playerPed, spawn.heading) end) while not finished do Citizen.Wait(200) end - else - local playerPed = PlayerPedId() - SetEntityHeading(playerPed, spawn.heading) - TriggerEvent('skinchanger:loadSkin', skin or Characters[Spawned].skin) - playerPed = PlayerPedId() - SetEntityVisible(playerPed, true, 0) end + DoScreenFadeOut(100) + if not isNew then TriggerEvent('skinchanger:loadSkin', skin or Characters[Spawned].skin) end + Citizen.Wait(300) + local playerPed = PlayerPedId() + FreezeEntityPosition(playerPed, true) + SetEntityCoords(playerPed, spawn.x, spawn.y, spawn.z-1.3, true, false, false, false) + SetEntityHeading(playerPed, spawn.heading) + SetCamActive(cam, false) + RenderScriptCams(false, false, 0, true, true) + cam = nil + DoScreenFadeIn(400) + Citizen.Wait(400) TriggerServerEvent('esx:onPlayerSpawn') TriggerEvent('esx:onPlayerSpawn') TriggerEvent('playerSpawned') From 83bae12c0f56fd48346fd4d7378e192934727fd8 Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 26 Jul 2021 20:59:11 +1000 Subject: [PATCH 14/64] fix: Ensure screenfades last long enough to hide transitions; set local variable for finish (new characters) --- client/main.lua | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/client/main.lua b/client/main.lua index 84f6b52e..9cb30868 100644 --- a/client/main.lua +++ b/client/main.lua @@ -115,7 +115,7 @@ if ESX.GetConfig().Multichar then TriggerEvent('skinchanger:loadSkin', skin) end DoScreenFadeIn(400) - while IsScreenFadedOut() do Citizen.Wait(100) end + repeat Citizen.Wait(200) until not IsScreenFadedOut() end) elseif Characters[index] and Characters[index].skin then @@ -261,6 +261,7 @@ if ESX.GetConfig().Multichar then AddEventHandler('esx:playerLoaded', function(playerData, isNew, skin) local spawn = playerData.coords if isNew or not skin or #skin == 1 then + local finished = false local sex = skin.sex or 0 if sex == 0 then model = `mp_m_freemode_01` else model = `mp_f_freemode_01` end RequestModel(model) @@ -280,20 +281,21 @@ if ESX.GetConfig().Multichar then finished = true end, function() finished = true end) end) - while not finished do Citizen.Wait(200) end + repeat Citizen.Wait(200) until finished end DoScreenFadeOut(100) - if not isNew then TriggerEvent('skinchanger:loadSkin', skin or Characters[Spawned].skin) end - Citizen.Wait(300) + repeat Citizen.Wait(200) until IsScreenFadedOut() + SetCamActive(cam, false) + RenderScriptCams(false, false, 0, true, true) + cam = nil local playerPed = PlayerPedId() FreezeEntityPosition(playerPed, true) SetEntityCoords(playerPed, spawn.x, spawn.y, spawn.z-1.3, true, false, false, false) SetEntityHeading(playerPed, spawn.heading) - SetCamActive(cam, false) - RenderScriptCams(false, false, 0, true, true) - cam = nil - DoScreenFadeIn(400) + if not isNew then TriggerEvent('skinchanger:loadSkin', skin or Characters[Spawned].skin) end Citizen.Wait(400) + DoScreenFadeIn(400) + repeat Citizen.Wait(200) until not IsScreenFadedOut() TriggerServerEvent('esx:onPlayerSpawn') TriggerEvent('esx:onPlayerSpawn') TriggerEvent('playerSpawned') From 9dbe1c5cbe70d9f39bd4e2960ad67e9e7d2ab61e Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 26 Jul 2021 20:59:58 +1000 Subject: [PATCH 15/64] fix: Ensure character is deleted on the server before refreshing client --- server/main.lua | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/server/main.lua b/server/main.lua index f13d9e82..ea74dafa 100644 --- a/server/main.lua +++ b/server/main.lua @@ -44,12 +44,20 @@ elseif ESX.GetConfig().Multichar == true then local DeleteCharacter = function(playerId, charid) local identifier = Config.Prefix..charid..':'..ESX.GetIdentifier(playerId) + local counter = 0 for k, v in pairs(IdentifierTables) do MySQL.Async.execute("DELETE FROM "..v.table.." WHERE "..v.column.." = ?", { identifier - }) + }, function() + counter = counter + 1 + if counter == #IdentifierTables then + print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(playerId), playerId, identifier)) + Citizen.Wait(100) + SetupCharacters(playerId) + end + end) + Citizen.Wait(5) end - print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(playerId), playerId, identifier)) end MySQL.ready(function() @@ -106,7 +114,6 @@ elseif ESX.GetConfig().Multichar == true then local src = source if type(charid) == "number" and string.len(charid) <= 2 then DeleteCharacter(src, charid) - SetupCharacters(src) end end) From 7bf936713533945d0943f6c4001e7215b08c859e Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 26 Jul 2021 21:10:59 +1000 Subject: [PATCH 16/64] tweak: Move fadeout check until after the spawnmanager export --- client/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/main.lua b/client/main.lua index 9cb30868..7c7eff0a 100644 --- a/client/main.lua +++ b/client/main.lua @@ -115,8 +115,8 @@ if ESX.GetConfig().Multichar then TriggerEvent('skinchanger:loadSkin', skin) end DoScreenFadeIn(400) - repeat Citizen.Wait(200) until not IsScreenFadedOut() end) + repeat Citizen.Wait(200) until not IsScreenFadedOut() elseif Characters[index] and Characters[index].skin then if Characters[Spawned] and Characters[Spawned].model then From b5b5f56a2b224f71efdc7d54c25544b04b806e24 Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 26 Jul 2021 21:21:57 +1000 Subject: [PATCH 17/64] Improvement: Set the camera position offset from the entity - Modifying the spawn location would previously require adjusting the camera parameters. - This, along with the previous camera change, ensures the camera is always facing the ped --- client/main.lua | 4 ++-- config.lua | 3 ++- fxmanifest.lua | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client/main.lua b/client/main.lua index 7c7eff0a..242d159d 100644 --- a/client/main.lua +++ b/client/main.lua @@ -29,11 +29,11 @@ if ESX.GetConfig().Multichar then local playerPed = PlayerPedId() SetEntityCoords(playerPed, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z, true, false, false, false) SetEntityHeading(playerPed, Config.Spawn.w) + local offset = GetOffsetFromEntityInWorldCoords(playerPed, 0, 1.7, 0.4) DoScreenFadeOut(0) SetCamActive(cam, true) RenderScriptCams(true, false, 1, true, true) - - SetCamCoord(cam, Config.Spawn.x, Config.Spawn.y + 1.6, Config.Spawn.z + 1.3) + SetCamCoord(cam, offset.x, offset.y, offset.z) PointCamAtCoord(cam, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z + 1.3) ESX.UI.HUD.SetDisplay(0.0) diff --git a/config.lua b/config.lua index a444f660..0dff5211 100644 --- a/config.lua +++ b/config.lua @@ -2,7 +2,8 @@ Config = {} Config.Locale = 'en' Config.Slots = 4 -Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) +Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) -- Sets the location for character selection +-- To set the spawn location for new characters, modify the default value in the `users` SQL table -------------------- -- Do not use unless you are prepared to adjust your resources to correctly reset data diff --git a/fxmanifest.lua b/fxmanifest.lua index 57787aaa..617f933c 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'adamant' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.2.1' +version '1.2.2' dependencies { 'es_extended', From 0ec17f081ec652b4218cf9dddbd420f352e37f39 Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 2 Aug 2021 22:13:36 +1000 Subject: [PATCH 18/64] fix: Close UI when setting up characters; spawn fallback position - If playerData.coords don't exist then there's an issue with that character - Instead of erroring out, spawn them at the character selection area todo: setup default spawn location instead of relying on database --- client/main.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/main.lua b/client/main.lua index 242d159d..87dccc3e 100644 --- a/client/main.lua +++ b/client/main.lua @@ -35,7 +35,7 @@ if ESX.GetConfig().Multichar then RenderScriptCams(true, false, 1, true, true) SetCamCoord(cam, offset.x, offset.y, offset.z) PointCamAtCoord(cam, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z + 1.3) - + ESX.UI.Menu.CloseAll() ESX.UI.HUD.SetDisplay(0.0) StartLoop() ShutdownLoadingScreen() @@ -147,6 +147,7 @@ if ESX.GetConfig().Multichar then Characters = data local elements = {} local Character = next(Characters) + exports.spawnmanager:forceRespawn() if Character == nil then SendNUIMessage({ @@ -259,7 +260,7 @@ if ESX.GetConfig().Multichar then RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(playerData, isNew, skin) - local spawn = playerData.coords + local spawn = playerData.coords or Config.Spawn if isNew or not skin or #skin == 1 then local finished = false local sex = skin.sex or 0 From 248b6e0b92664c40c8a2156770d1a8e688e4b2ad Mon Sep 17 00:00:00 2001 From: Demetrio <15928886+d3rp-jsx@users.noreply.github.com> Date: Mon, 9 Aug 2021 16:54:32 +0200 Subject: [PATCH 19/64] improvement: configurable character deletation (#35) Co-authored-by: d3rp-jsx <15928886+derp-jsx@users.noreply.github.com> --- client/main.lua | 2 +- config.lua | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/client/main.lua b/client/main.lua index 87dccc3e..28e33a4d 100644 --- a/client/main.lua +++ b/client/main.lua @@ -190,7 +190,7 @@ if ESX.GetConfig().Multichar then local elements = {} if not data.current.new then elements[1] = {label = _('char_play'), action = 'play', value = data.current.value} - elements[2] = {label = _('char_delete'), action = 'delete', value = data.current.value} + if Config.CanDelete then elements[2] = {label = _('char_delete'), action = 'delete', value = data.current.value} end ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'choosechar', { title = _('select_char'), align = 'top-left', diff --git a/config.lua b/config.lua index 0dff5211..f1874abf 100644 --- a/config.lua +++ b/config.lua @@ -5,6 +5,8 @@ Config.Slots = 4 Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) -- Sets the location for character selection -- To set the spawn location for new characters, modify the default value in the `users` SQL table +Config.CanDelete = false -- Choose whether or not a user can self-delete its own characters + -------------------- -- Do not use unless you are prepared to adjust your resources to correctly reset data -- Information: https://github.com/thelindat/esx_multicharacter#relogging From 52250d0d495cba7cc569786a1d874faf85e40d7e Mon Sep 17 00:00:00 2001 From: Demetrio <15928886+d3rp-jsx@users.noreply.github.com> Date: Tue, 10 Aug 2021 19:31:30 +0200 Subject: [PATCH 20/64] Dynamic slots (#36) * Removed slots configuration * feature: dynamic slots * fixes + improvements * edited core functionality * added commands for slots management * added commands english locale Co-authored-by: d3rp-jsx <15928886+derp-jsx@users.noreply.github.com> --- client/main.lua | 7 +++--- config.lua | 2 +- esx_multicharacter.sql | 7 ++++++ locales/en.lua | 7 ++++++ server/main.lua | 48 ++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 esx_multicharacter.sql diff --git a/client/main.lua b/client/main.lua index 28e33a4d..15f6b391 100644 --- a/client/main.lua +++ b/client/main.lua @@ -142,9 +142,10 @@ if ESX.GetConfig().Multichar then end RegisterNetEvent('esx_multicharacter:SetupUI') - AddEventHandler('esx_multicharacter:SetupUI', function(data) + AddEventHandler('esx_multicharacter:SetupUI', function(data, slots) DoScreenFadeOut(0) Characters = data + local slots = slots local elements = {} local Character = next(Characters) exports.spawnmanager:forceRespawn() @@ -179,7 +180,7 @@ if ESX.GetConfig().Multichar then local label = v.firstname..' '..v.lastname elements[#elements+1] = {label = label, value = v.id} end - if #elements < Config.Slots then + if #elements < slots then elements[#elements+1] = {label = _('create_char'), value = (#elements+1), new = true} end ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'selectchar', { @@ -228,7 +229,7 @@ if ESX.GetConfig().Multichar then else ESX.UI.Menu.CloseAll() local GetSlot = function() - for i=1, Config.Slots do + for i=1, slots do if not Characters[i] then return i end diff --git a/config.lua b/config.lua index f1874abf..bda8e554 100644 --- a/config.lua +++ b/config.lua @@ -1,7 +1,7 @@ Config = {} Config.Locale = 'en' -Config.Slots = 4 +Config.Slots = 1 Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) -- Sets the location for character selection -- To set the spawn location for new characters, modify the default value in the `users` SQL table diff --git a/esx_multicharacter.sql b/esx_multicharacter.sql new file mode 100644 index 00000000..9495bb5a --- /dev/null +++ b/esx_multicharacter.sql @@ -0,0 +1,7 @@ +CREATE TABLE `multicharacter_slots` ( + `identifier` VARCHAR(60) NOT NULL DEFAULT '' COLLATE 'utf8mb4_unicode_ci', + `slots` INT(11) NOT NULL DEFAULT '1' +) +COLLATE='utf8mb4_unicode_ci' +ENGINE=InnoDB +; diff --git a/locales/en.lua b/locales/en.lua index f814d78a..e61481b0 100644 --- a/locales/en.lua +++ b/locales/en.lua @@ -8,4 +8,11 @@ Locales['en'] = { ['char_delete'] = "Delete this character", ['cancel'] = "Cancel", ['confirm'] = "Confirm", + ['command_setslots'] = "Set multicharacter slots number of a player", + ['command_remslots'] = "Remove multicharacter slots number of a player", + ['command_identifier'] = "Player identifier", + ['command_slots'] = "# of slots", + ['slotsadd'] = "You added %s slots to %s", + ['slotsedit'] = "You set %s slots to %s", + ['slotsrem'] = "You removed slots to %s", } diff --git a/server/main.lua b/server/main.lua index ea74dafa..d8abff13 100644 --- a/server/main.lua +++ b/server/main.lua @@ -12,9 +12,15 @@ elseif ESX.GetConfig().Multichar == true then local SetupCharacters = function(playerId) while Fetch == -1 do Citizen.Wait(500) end local identifier = Config.Prefix..'%:'..ESX.GetIdentifier(playerId) + local slots = MySQL.Sync.fetchScalar("SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?", { + ESX.GetIdentifier(playerId) + }) + if not slots then + slots = Config.Slots + end MySQL.Async.fetchAll(Fetch, { identifier, - Config.Slots + slots }, function(result) local characters = {} for i=1, #result, 1 do @@ -38,7 +44,7 @@ elseif ESX.GetConfig().Multichar == true then } if result[i].sex == 'm' then characters[id].sex = _('male') else characters[id].sex = _('female') end end - TriggerClientEvent('esx_multicharacter:SetupUI', playerId, characters) + TriggerClientEvent('esx_multicharacter:SetupUI', playerId, characters, slots) end) end @@ -123,6 +129,44 @@ elseif ESX.GetConfig().Multichar == true then TriggerEvent('esx:playerLogout', src) end) + ESX.RegisterCommand('setslots', 'admin', function(xPlayer, args, showError) + local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { + args.identifier + }) + + if slots == nil then + MySQL.Async.execute('INSERT INTO `multicharacter_slots` (`identifier`, `slots`) VALUES (?, ?)', { + args.identifier, + args.slots + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsadd', args.slots, args.identifier)) + else + MySQL.Async.execute('UPDATE `multicharacter_slots` SET `slots` = ? WHERE `identifier` = ?', { + args.slots, + args.identifier + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsedit', args.slots, args.identifier)) + end + end, true, {help = _U('command_setslots'), validate = true, arguments = { + {name = 'identifier', help = _U('command_identifier'), type = 'string'}, + {name = 'slots', help = _U('command_slots'), type = 'number'} + }}) + + ESX.RegisterCommand('remslots', 'admin', function(xPlayer, args, showError) + local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { + args.identifier + }) + + if slots ~= nil then + MySQL.Async.execute('DELETE FROM `multicharacter_slots` WHERE `identifier` = ?', { + args.identifier + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsrem', args.identifier)) + end + end, true, {help = _U('command_remslots'), validate = true, arguments = { + {name = 'identifier', help = _U('command_identifier'), type = 'string'} + }}) + RegisterCommand('forcelog', function(source, args, rawCommand) TriggerEvent('esx:playerLogout', source) end, true) From e65a4cb181ffa633dcb271adb9adf3b138fa898e Mon Sep 17 00:00:00 2001 From: Demetrio <15928886+d3rp-jsx@users.noreply.github.com> Date: Wed, 11 Aug 2021 01:33:40 +0200 Subject: [PATCH 21/64] Italian language support + Doc for dynamic slots and minor improvements (#37) * Added Italian language support + usability improvements * cleaner sql file Co-authored-by: d3rp-jsx <15928886+derp-jsx@users.noreply.github.com> --- config.lua | 5 +++++ esx_multicharacter.sql | 9 +++------ locales/it.lua | 18 ++++++++++++++++++ readme.md | 1 + 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 locales/it.lua diff --git a/config.lua b/config.lua index bda8e554..ca56aec7 100644 --- a/config.lua +++ b/config.lua @@ -1,7 +1,12 @@ Config = {} Config.Locale = 'en' +-------------------- +-- This is the default number of slots for EVERY player +-- If you want to manage extra slots for specific players you can do it by using '/setslots' and '/remslots' commands Config.Slots = 1 +-------------------- + Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) -- Sets the location for character selection -- To set the spawn location for new characters, modify the default value in the `users` SQL table diff --git a/esx_multicharacter.sql b/esx_multicharacter.sql index 9495bb5a..86fb2b36 100644 --- a/esx_multicharacter.sql +++ b/esx_multicharacter.sql @@ -1,7 +1,4 @@ CREATE TABLE `multicharacter_slots` ( - `identifier` VARCHAR(60) NOT NULL DEFAULT '' COLLATE 'utf8mb4_unicode_ci', - `slots` INT(11) NOT NULL DEFAULT '1' -) -COLLATE='utf8mb4_unicode_ci' -ENGINE=InnoDB -; + `identifier` VARCHAR(60) NOT NULL, + `slots` INT NOT NULL +); diff --git a/locales/it.lua b/locales/it.lua new file mode 100644 index 00000000..6bae31fb --- /dev/null +++ b/locales/it.lua @@ -0,0 +1,18 @@ +Locales['it'] = { + ['male'] = "Maschio", + ['female'] = "Femmina", + ['delete_label'] = "Cancella %s %s?", + ['select_char'] = "Seleziona Personaggio", + ['create_char'] = "Crea un nuovo personaggio", + ['char_play'] = "Gioca questo personaggio", + ['char_delete'] = "Cancella questo personaggio", + ['cancel'] = "Annulla", + ['confirm'] = "Conferma", + ['command_setslots'] = "Imposta il numero di slot di personaggi di un player", + ['command_remslots'] = "Rimuovi il numero di slot di personaggi di un player", + ['command_identifier'] = "Identifier del giocatore", + ['command_slots'] = "# di slot", + ['slotsadd'] = "Hai aggiunto %s slot a %s", + ['slotsedit'] = "Hai impostato %s slot a %s", + ['slotsrem'] = "Hai rimosso gli slot a %s", +} diff --git a/readme.md b/readme.md index 35360673..ccd8dc76 100644 --- a/readme.md +++ b/readme.md @@ -8,6 +8,7 @@ ### Installation - Modify your ESX config with `Config.Multichar = true` - Set your database name for `Config.Database` in server/main.lua +- Run `esx_multicharacter.sql` into your database - All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry - The resource will attempt to set columns automatically From 5f5b0138f056d1c21a8418f45befa6a911db9dfe Mon Sep 17 00:00:00 2001 From: Demetrio <15928886+d3rp-jsx@users.noreply.github.com> Date: Fri, 20 Aug 2021 16:56:48 +0200 Subject: [PATCH 22/64] feat(chars): enable or disable a specific character of a player (#43) --- client/main.lua | 14 ++++++-- esx_multicharacter.sql | 3 ++ locales/en.lua | 7 ++++ locales/it.lua | 11 ++++-- server/commands.lua | 79 ++++++++++++++++++++++++++++++++++++++++++ server/main.lua | 47 ++----------------------- 6 files changed, 112 insertions(+), 49 deletions(-) create mode 100644 server/commands.lua diff --git a/client/main.lua b/client/main.lua index 15f6b391..e5705d2f 100644 --- a/client/main.lua +++ b/client/main.lua @@ -178,7 +178,11 @@ if ESX.GetConfig().Multichar then end if Spawned == false then SetupCharacter(Character) end local label = v.firstname..' '..v.lastname - elements[#elements+1] = {label = label, value = v.id} + if Characters[k].disabled == 1 then + elements[#elements+1] = {label = label, value = v.id} + else + elements[#elements+1] = {label = label, value = v.id} + end end if #elements < slots then elements[#elements+1] = {label = _('create_char'), value = (#elements+1), new = true} @@ -190,7 +194,11 @@ if ESX.GetConfig().Multichar then }, function(data, menu) local elements = {} if not data.current.new then - elements[1] = {label = _('char_play'), action = 'play', value = data.current.value} + if Characters[data.current.value].disabled == 0 then + elements[1] = {label = _('char_play'), action = 'play', value = data.current.value} + else + elements[1] = {label = _('char_disabled'), value = data.current.value} + end if Config.CanDelete then elements[2] = {label = _('char_delete'), action = 'delete', value = data.current.value} end ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'choosechar', { title = _('select_char'), @@ -203,7 +211,7 @@ if ESX.GetConfig().Multichar then action = "closeui" }) TriggerServerEvent('esx_multicharacter:CharacterChosen', data.current.value, false) - else + elseif data.current.action == 'delete' then local elements2 = {} elements2[1] = {label = _('cancel')} elements2[2] = {label = _('confirm'), value = data.current.value} diff --git a/esx_multicharacter.sql b/esx_multicharacter.sql index 86fb2b36..6aba96ad 100644 --- a/esx_multicharacter.sql +++ b/esx_multicharacter.sql @@ -2,3 +2,6 @@ CREATE TABLE `multicharacter_slots` ( `identifier` VARCHAR(60) NOT NULL, `slots` INT NOT NULL ); + +ALTER TABLE `users` + ADD `disabled` BIT NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/locales/en.lua b/locales/en.lua index e61481b0..b71de307 100644 --- a/locales/en.lua +++ b/locales/en.lua @@ -5,14 +5,21 @@ Locales['en'] = { ['select_char'] = "Select Character", ['create_char'] = "Create new character", ['char_play'] = "Play this character", + ['char_disabled'] = "This character is disabled", ['char_delete'] = "Delete this character", ['cancel'] = "Cancel", ['confirm'] = "Confirm", ['command_setslots'] = "Set multicharacter slots number of a player", ['command_remslots'] = "Remove multicharacter slots number of a player", + ['command_enablechar'] = "Enable a given character of a player", + ['command_disablechar'] = "Disable a given character of a player", + ['command_charslot'] = "Slot number of the character", ['command_identifier'] = "Player identifier", ['command_slots'] = "# of slots", ['slotsadd'] = "You added %s slots to %s", ['slotsedit'] = "You set %s slots to %s", ['slotsrem'] = "You removed slots to %s", + ['charenabled'] = "You enabled character #%s of %s", + ['chardisabled'] = "You disabled character #%s of %s", + ['charnotfound'] = "Character #%s of %s doesn't exist", } diff --git a/locales/it.lua b/locales/it.lua index 6bae31fb..1f2333e5 100644 --- a/locales/it.lua +++ b/locales/it.lua @@ -5,14 +5,21 @@ Locales['it'] = { ['select_char'] = "Seleziona Personaggio", ['create_char'] = "Crea un nuovo personaggio", ['char_play'] = "Gioca questo personaggio", + ['char_disabled'] = "Questo personaggio è disabilitato", ['char_delete'] = "Cancella questo personaggio", ['cancel'] = "Annulla", ['confirm'] = "Conferma", - ['command_setslots'] = "Imposta il numero di slot di personaggi di un player", - ['command_remslots'] = "Rimuovi il numero di slot di personaggi di un player", + ['command_setslots'] = "Imposta il numero di slot di personaggi di un giocatore", + ['command_remslots'] = "Rimuovi il numero di slot di personaggi di un giocatore", + ['command_enablechar'] = "Abilita un personaggio di un giocatore", + ['command_disablechar'] = "Disabilita un personaggio di un giocatore", + ['command_charslot'] = "Numero dello slot del personaggio", ['command_identifier'] = "Identifier del giocatore", ['command_slots'] = "# di slot", ['slotsadd'] = "Hai aggiunto %s slot a %s", ['slotsedit'] = "Hai impostato %s slot a %s", ['slotsrem'] = "Hai rimosso gli slot a %s", + ['charenabled'] = "Hai abilitato il %s° personaggio di %s", + ['chardisabled'] = "Hai disabilitato il %s° personaggio di %s", + ['charnotfound'] = "Il personaggio %s di %s non esiste", } diff --git a/server/commands.lua b/server/commands.lua new file mode 100644 index 00000000..b4fbc2d2 --- /dev/null +++ b/server/commands.lua @@ -0,0 +1,79 @@ +ESX.RegisterCommand('setslots', 'admin', function(xPlayer, args, showError) + local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { + args.identifier + }) + + if slots == nil then + MySQL.Async.execute('INSERT INTO `multicharacter_slots` (`identifier`, `slots`) VALUES (?, ?)', { + args.identifier, + args.slots + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsadd', args.slots, args.identifier)) + else + MySQL.Async.execute('UPDATE `multicharacter_slots` SET `slots` = ? WHERE `identifier` = ?', { + args.slots, + args.identifier + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsedit', args.slots, args.identifier)) + end +end, true, {help = _U('command_setslots'), validate = true, arguments = { + {name = 'identifier', help = _U('command_identifier'), type = 'string'}, + {name = 'slots', help = _U('command_slots'), type = 'number'} +}}) + +ESX.RegisterCommand('remslots', 'admin', function(xPlayer, args, showError) + local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { + args.identifier + }) + + if slots ~= nil then + MySQL.Async.execute('DELETE FROM `multicharacter_slots` WHERE `identifier` = ?', { + args.identifier + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsrem', args.identifier)) + end +end, true, {help = _U('command_remslots'), validate = true, arguments = { + {name = 'identifier', help = _U('command_identifier'), type = 'string'} +}}) + +ESX.RegisterCommand('enablechar', 'admin', function(xPlayer, args, showError) + + local selectedCharacter = 'char'..args.charslot..':'..args.identifier; + + MySQL.Async.execute('UPDATE `users` SET `disabled` = 0 WHERE identifier = ?', { + selectedCharacter + }, function(result) + if result > 0 then + xPlayer.triggerEvent('esx:showNotification', _U('charenabled', args.charslot, args.identifier)) + else + xPlayer.triggerEvent('esx:showNotification', _U('charnotfound', args.charslot, args.identifier)) + end + end) + +end, true, {help = _U('command_enablechar'), validate = true, arguments = { + {name = 'identifier', help = _U('command_identifier'), type = 'string'}, + {name = 'charslot', help = _U('command_charslot'), type = 'number'} +}}) + +ESX.RegisterCommand('disablechar', 'admin', function(xPlayer, args, showError) + + local selectedCharacter = 'char'..args.charslot..':'..args.identifier; + + MySQL.Async.execute('UPDATE `users` SET `disabled` = 1 WHERE identifier = ?', { + selectedCharacter + }, function(result) + if result > 0 then + xPlayer.triggerEvent('esx:showNotification', _U('chardisabled', args.charslot, args.identifier)) + else + xPlayer.triggerEvent('esx:showNotification', _U('charnotfound', args.charslot, args.identifier)) + end + end) + +end, true, {help = _U('command_disablechar'), validate = true, arguments = { + {name = 'identifier', help = _U('command_identifier'), type = 'string'}, + {name = 'charslot', help = _U('command_charslot'), type = 'number'} +}}) + +RegisterCommand('forcelog', function(source, args, rawCommand) + TriggerEvent('esx:playerLogout', source) +end, true) \ No newline at end of file diff --git a/server/main.lua b/server/main.lua index d8abff13..09617693 100644 --- a/server/main.lua +++ b/server/main.lua @@ -40,7 +40,8 @@ elseif ESX.GetConfig().Multichar == true then firstname = result[i].firstname, lastname = result[i].lastname, dateofbirth = result[i].dateofbirth, - skin = json.decode(result[i].skin) + skin = json.decode(result[i].skin), + disabled = result[i].disabled, } if result[i].sex == 'm' then characters[id].sex = _('male') else characters[id].sex = _('female') end end @@ -83,7 +84,7 @@ elseif ESX.GetConfig().Multichar == true then print(('[^2INFO^7] Attempted to update ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) end if not next(ESX.Jobs) then ESX.Jobs = GetJobs() end - Fetch = MySQL.Sync.store("SELECT `identifier`, `accounts`, `job`, `job_grade`, `firstname`, `lastname`, `dateofbirth`, `sex`, `skin` FROM `users` WHERE identifier LIKE ? LIMIT ?") + Fetch = MySQL.Sync.store("SELECT `identifier`, `accounts`, `job`, `job_grade`, `firstname`, `lastname`, `dateofbirth`, `sex`, `skin`, `disabled` FROM `users` WHERE identifier LIKE ? LIMIT ?") end end) end) @@ -129,48 +130,6 @@ elseif ESX.GetConfig().Multichar == true then TriggerEvent('esx:playerLogout', src) end) - ESX.RegisterCommand('setslots', 'admin', function(xPlayer, args, showError) - local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { - args.identifier - }) - - if slots == nil then - MySQL.Async.execute('INSERT INTO `multicharacter_slots` (`identifier`, `slots`) VALUES (?, ?)', { - args.identifier, - args.slots - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsadd', args.slots, args.identifier)) - else - MySQL.Async.execute('UPDATE `multicharacter_slots` SET `slots` = ? WHERE `identifier` = ?', { - args.slots, - args.identifier - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsedit', args.slots, args.identifier)) - end - end, true, {help = _U('command_setslots'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'}, - {name = 'slots', help = _U('command_slots'), type = 'number'} - }}) - - ESX.RegisterCommand('remslots', 'admin', function(xPlayer, args, showError) - local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { - args.identifier - }) - - if slots ~= nil then - MySQL.Async.execute('DELETE FROM `multicharacter_slots` WHERE `identifier` = ?', { - args.identifier - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsrem', args.identifier)) - end - end, true, {help = _U('command_remslots'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'} - }}) - - RegisterCommand('forcelog', function(source, args, rawCommand) - TriggerEvent('esx:playerLogout', source) - end, true) - else SetTimeout(3000, function() print('[^3WARNING^7] Multicharacter is disabled - please check your ESX configuration') end) end From 6925f91a1e52062fd7f72638203233a4be81c26c Mon Sep 17 00:00:00 2001 From: IceCubePiso <33593306+icecubepiso@users.noreply.github.com> Date: Fri, 20 Aug 2021 19:06:47 +0200 Subject: [PATCH 23/64] Update cs.lua (#44) --- locales/cs.lua | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/locales/cs.lua b/locales/cs.lua index a9734076..d309e309 100644 --- a/locales/cs.lua +++ b/locales/cs.lua @@ -3,9 +3,23 @@ Locales['cs'] = { ['female'] = "Žena", ['delete_label'] = "Vymazat %s %s?", ['select_char'] = "Zvolit Postavu", - ['create_char'] = "Vytvořit novou postavu", + ['create_char'] = "Vytvořit Novou Postavu", ['char_play'] = "Hrát za postavu", + ['char_disabled'] = "Tato postava je zakázána!", ['char_delete'] = "Vymazat postavu", ['cancel'] = "Zrušit", ['confirm'] = "Potvrdit", + ['command_setslots'] = "Nastavit slot pro hráče v multicharacteru", + ['command_remslots'] = "Odebrat slot pro hráče v multicharacteru", + ['command_enablechar'] = "Povolit zovlený slot hráči", + ['command_disablechar'] = "Zakázat zvolený slot pro hračé", + ['command_charslot'] = "Číslo slotu", + ['command_identifier'] = "Identifier hráče", + ['command_slots'] = "# ze slotu", + ['slotsadd'] = "Přidal slot %s hráči %s", + ['slotsedit'] = "Nastavil si slot %s hráči %s", + ['slotsrem'] = "Odebral si slot %s", + ['charenabled'] = "Povolol si postavu #%s z %s", + ['chardisabled'] = "Zakázal si postavu #%s z %s", + ['charnotfound'] = "Postava #%s z %s nebyla nalezena/neexistuje", } From 6427a58ac74ba4ee10ccac24660c821c5010601a Mon Sep 17 00:00:00 2001 From: cjosephdc <87730839+cjosephdc@users.noreply.github.com> Date: Wed, 25 Aug 2021 19:38:26 +0800 Subject: [PATCH 24/64] Fix for stuck players (#45) Fix the issue where players get stuck after selecting character --- client/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/main.lua b/client/main.lua index e5705d2f..558e7937 100644 --- a/client/main.lua +++ b/client/main.lua @@ -294,7 +294,7 @@ if ESX.GetConfig().Multichar then repeat Citizen.Wait(200) until finished end DoScreenFadeOut(100) - repeat Citizen.Wait(200) until IsScreenFadedOut() + SetCamActive(cam, false) RenderScriptCams(false, false, 0, true, true) cam = nil From d412efab05d416cdf1020f5d8a456622ba3e7fd2 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Wed, 1 Sep 2021 16:17:05 +1000 Subject: [PATCH 25/64] fix(client)? Maybe resolves issue with concealing players --- client/main.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/main.lua b/client/main.lua index 558e7937..cc3eb09f 100644 --- a/client/main.lua +++ b/client/main.lua @@ -63,7 +63,7 @@ if ESX.GetConfig().Multichar then HideHudComponentThisFrame(12) HideHudComponentThisFrame(21) HideHudAndRadarThisFrame() - Citizen.Wait(3) + Citizen.Wait(0) local vehicles = GetGamePool('CVehicle') for i=1, #vehicles do SetEntityLocallyInvisible(vehicles[i]) @@ -85,13 +85,13 @@ if ESX.GetConfig().Multichar then local player = players[i] if player ~= PlayerId() and not playerPool[player] then playerPool[player] = true - NetworkConcealPlayer(players[player], true, true) + NetworkConcealPlayer(player, true, true) end end Citizen.Wait(500) end - for i=1, #playerPool do - NetworkConcealPlayer(playerPool[i], false, false) + for k in pairs(playerPool) do + NetworkConcealPlayer(k, false, false) end end) end From 1984ef58a541566ef1de4ae5b0e064917d1c91f5 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Fri, 3 Sep 2021 19:46:30 +1000 Subject: [PATCH 26/64] Update readme.md --- readme.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/readme.md b/readme.md index ccd8dc76..dcca296f 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,6 @@ ### Requirements (ensure you are using the latest) - [ESX Legacy](https://github.com/esx-framework/esx-legacy) - [MySQL Async 3.3.2](https://github.com/brouznouf/fivem-mysql-async/releases/tag/3.3.2) -- [ESX Identity](https://github.com/esx-framework/esx_identity) -- [ESX Skin](https://github.com/esx-framework/esx_skin) - [Spawnmanager](https://github.com/citizenfx/cfx-server-data/tree/master/resources/%5Bmanagers%5D/spawnmanager) ### Installation From a1cb26da5d96fe8a132a890bbca9dd7c75e9e36d Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 06:37:34 +1100 Subject: [PATCH 27/64] feat(sql): Setup proper keys and collation - These fields should only be referenced, so index them for faster queries --- esx_multicharacter.sql | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/esx_multicharacter.sql b/esx_multicharacter.sql index 6aba96ad..23c894a5 100644 --- a/esx_multicharacter.sql +++ b/esx_multicharacter.sql @@ -1,7 +1,9 @@ CREATE TABLE `multicharacter_slots` ( - `identifier` VARCHAR(60) NOT NULL, - `slots` INT NOT NULL -); - -ALTER TABLE `users` - ADD `disabled` BIT NOT NULL DEFAULT 0; \ No newline at end of file + `identifier` VARCHAR(60) NOT NULL COLLATE 'utf8mb4_unicode_ci', + `slots` INT(11) NOT NULL, + PRIMARY KEY (`identifier`) USING BTREE, + INDEX `slots` (`slots`) USING BTREE +) +COLLATE='utf8mb4_unicode_ci' +ENGINE=InnoDB +; From 54245704c5571e13a6b2bb0e0b906e9f47acd349 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 08:31:45 +1100 Subject: [PATCH 28/64] fix(sql): Add disabled user column back and change to TINYINT - Accidentaly removed it; change this to TINYINT for consistency --- esx_multicharacter.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esx_multicharacter.sql b/esx_multicharacter.sql index 23c894a5..71049ffa 100644 --- a/esx_multicharacter.sql +++ b/esx_multicharacter.sql @@ -7,3 +7,6 @@ CREATE TABLE `multicharacter_slots` ( COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB ; + +ALTER TABLE `users` + `disabled` TINYINT(1) NULL DEFAULT '0', From a4d7d17251f5d47bd9beb39ebb9aa994ceb21114 Mon Sep 17 00:00:00 2001 From: Demetrio <15928886+d3rp-jsx@users.noreply.github.com> Date: Fri, 15 Oct 2021 23:32:54 +0200 Subject: [PATCH 29/64] Minor fixes and compatibility improvements (#54) --- client/main.lua | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/client/main.lua b/client/main.lua index cc3eb09f..b6fa90d8 100644 --- a/client/main.lua +++ b/client/main.lua @@ -178,11 +178,7 @@ if ESX.GetConfig().Multichar then end if Spawned == false then SetupCharacter(Character) end local label = v.firstname..' '..v.lastname - if Characters[k].disabled == 1 then - elements[#elements+1] = {label = label, value = v.id} - else - elements[#elements+1] = {label = label, value = v.id} - end + elements[#elements+1] = {label = label, value = v.id} end if #elements < slots then elements[#elements+1] = {label = _('create_char'), value = (#elements+1), new = true} @@ -194,10 +190,10 @@ if ESX.GetConfig().Multichar then }, function(data, menu) local elements = {} if not data.current.new then - if Characters[data.current.value].disabled == 0 then - elements[1] = {label = _('char_play'), action = 'play', value = data.current.value} - else + if Characters[data.current.value].disabled then elements[1] = {label = _('char_disabled'), value = data.current.value} + else + elements[1] = {label = _('char_play'), action = 'play', value = data.current.value} end if Config.CanDelete then elements[2] = {label = _('char_delete'), action = 'delete', value = data.current.value} end ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'choosechar', { From ef87a916acab03330c5fa3231cf2919e61ba5de0 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 08:34:14 +1100 Subject: [PATCH 30/64] fix(client): Entity coords should no longer set you into the ground --- client/main.lua | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/client/main.lua b/client/main.lua index b6fa90d8..db5fc7ec 100644 --- a/client/main.lua +++ b/client/main.lua @@ -16,15 +16,14 @@ if ESX.GetConfig().Multichar then end end) - - local canRelog, cam, Spawned = true + local canRelog, cam, spawned = true, nil, nil local Characters = {} RegisterNetEvent('esx_multicharacter:SetupCharacters') AddEventHandler('esx_multicharacter:SetupCharacters', function() ESX.PlayerLoaded = false ESX.PlayerData = {} - Spawned = false + spawned = false cam = CreateCam("DEFAULT_SCRIPTED_CAMERA", true) local playerPed = PlayerPedId() SetEntityCoords(playerPed, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z, true, false, false, false) @@ -97,7 +96,7 @@ if ESX.GetConfig().Multichar then end SetupCharacter = function(index) - if Spawned == false then + if spawned == false then exports.spawnmanager:spawnPlayer({ x = Config.Spawn.x, y = Config.Spawn.y, @@ -117,9 +116,9 @@ if ESX.GetConfig().Multichar then DoScreenFadeIn(400) end) repeat Citizen.Wait(200) until not IsScreenFadedOut() - + elseif Characters[index] and Characters[index].skin then - if Characters[Spawned] and Characters[Spawned].model then + if Characters[spawned] and Characters[spawned].model then RequestModel(Characters[index].model) while not HasModelLoaded(Characters[index].model) do RequestModel(Characters[index].model) @@ -130,14 +129,14 @@ if ESX.GetConfig().Multichar then end TriggerEvent('skinchanger:loadSkin', Characters[index].skin) end - Spawned = index + spawned = index local playerPed = PlayerPedId() FreezeEntityPosition(PlayerPedId(), true) SetPedAoBlobRendering(playerPed, true) SetEntityAlpha(playerPed, 255) SendNUIMessage({ action = "openui", - character = Characters[Spawned] + character = Characters[spawned] }) end @@ -145,7 +144,7 @@ if ESX.GetConfig().Multichar then AddEventHandler('esx_multicharacter:SetupUI', function(data, slots) DoScreenFadeOut(0) Characters = data - local slots = slots + slots = slots local elements = {} local Character = next(Characters) exports.spawnmanager:forceRespawn() @@ -176,9 +175,13 @@ if ESX.GetConfig().Multichar then if not v.model and v.skin then if v.skin.model then v.model = v.skin.model elseif v.skin.sex == 1 then v.model = `mp_f_freemode_01` else v.model = `mp_m_freemode_01` end end - if Spawned == false then SetupCharacter(Character) end + if spawned == false then SetupCharacter(Character) end local label = v.firstname..' '..v.lastname - elements[#elements+1] = {label = label, value = v.id} + if Characters[k].disabled then + elements[#elements+1] = {label = label, value = v.id} + else + elements[#elements+1] = {label = label, value = v.id} + end end if #elements < slots then elements[#elements+1] = {label = _('create_char'), value = (#elements+1), new = true} @@ -190,10 +193,10 @@ if ESX.GetConfig().Multichar then }, function(data, menu) local elements = {} if not data.current.new then - if Characters[data.current.value].disabled then - elements[1] = {label = _('char_disabled'), value = data.current.value} + if not Characters[data.current.value].disabled then + elements[1] = {label = _('char_play'), action = 'play', value = data.current.value} else - elements[1] = {label = _('char_play'), action = 'play', value = data.current.value} + elements[1] = {label = _('char_disabled'), value = data.current.value} end if Config.CanDelete then elements[2] = {label = _('char_delete'), action = 'delete', value = data.current.value} end ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'choosechar', { @@ -218,7 +221,7 @@ if ESX.GetConfig().Multichar then }, function(data, menu) if data.current.value then TriggerServerEvent('esx_multicharacter:DeleteCharacter', data.current.value) - Spawned = false + spawned = false ESX.UI.Menu.CloseAll() else menu.close() @@ -290,15 +293,15 @@ if ESX.GetConfig().Multichar then repeat Citizen.Wait(200) until finished end DoScreenFadeOut(100) - + SetCamActive(cam, false) RenderScriptCams(false, false, 0, true, true) cam = nil local playerPed = PlayerPedId() FreezeEntityPosition(playerPed, true) - SetEntityCoords(playerPed, spawn.x, spawn.y, spawn.z-1.3, true, false, false, false) + SetEntityCoordsNoOffset(playerPed, spawn.x, spawn.y, spawn.z, false, false, false, true) SetEntityHeading(playerPed, spawn.heading) - if not isNew then TriggerEvent('skinchanger:loadSkin', skin or Characters[Spawned].skin) end + if not isNew then TriggerEvent('skinchanger:loadSkin', skin or Characters[spawned].skin) end Citizen.Wait(400) DoScreenFadeIn(400) repeat Citizen.Wait(200) until not IsScreenFadedOut() @@ -312,7 +315,7 @@ if ESX.GetConfig().Multichar then RegisterNetEvent('esx:onPlayerLogout') AddEventHandler('esx:onPlayerLogout', function() DoScreenFadeOut(0) - Spawned = false + spawned = false TriggerEvent("esx_multicharacter:SetupCharacters") TriggerEvent('esx_skin:resetFirstSpawn') end) From ae41811d42fd316bf181dc8a9d76f1dd530cf0bb Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 08:34:34 +1100 Subject: [PATCH 31/64] Delete functions.lua --- server/functions.lua | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 server/functions.lua diff --git a/server/functions.lua b/server/functions.lua deleted file mode 100644 index a1312e0a..00000000 --- a/server/functions.lua +++ /dev/null @@ -1,8 +0,0 @@ -GetJobs = function() - local jobs = {} - while next(jobs) == nil do - Citizen.Wait(250) - jobs = exports['es_extended']:getSharedObject().Jobs - end - return jobs -end \ No newline at end of file From 2164f3db72d97bf82c1d9a9565e02a857640218e Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 08:34:55 +1100 Subject: [PATCH 32/64] style(commands): Indentation --- server/commands.lua | 108 ++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/server/commands.lua b/server/commands.lua index b4fbc2d2..6c0ff047 100644 --- a/server/commands.lua +++ b/server/commands.lua @@ -1,79 +1,79 @@ ESX.RegisterCommand('setslots', 'admin', function(xPlayer, args, showError) - local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { - args.identifier - }) + local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { + args.identifier + }) - if slots == nil then - MySQL.Async.execute('INSERT INTO `multicharacter_slots` (`identifier`, `slots`) VALUES (?, ?)', { - args.identifier, - args.slots - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsadd', args.slots, args.identifier)) - else - MySQL.Async.execute('UPDATE `multicharacter_slots` SET `slots` = ? WHERE `identifier` = ?', { - args.slots, - args.identifier - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsedit', args.slots, args.identifier)) - end + if slots == nil then + MySQL.Async.execute('INSERT INTO `multicharacter_slots` (`identifier`, `slots`) VALUES (?, ?)', { + args.identifier, + args.slots + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsadd', args.slots, args.identifier)) + else + MySQL.Async.execute('UPDATE `multicharacter_slots` SET `slots` = ? WHERE `identifier` = ?', { + args.slots, + args.identifier + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsedit', args.slots, args.identifier)) + end end, true, {help = _U('command_setslots'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'}, - {name = 'slots', help = _U('command_slots'), type = 'number'} + {name = 'identifier', help = _U('command_identifier'), type = 'string'}, + {name = 'slots', help = _U('command_slots'), type = 'number'} }}) ESX.RegisterCommand('remslots', 'admin', function(xPlayer, args, showError) - local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { - args.identifier - }) + local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { + args.identifier + }) - if slots ~= nil then - MySQL.Async.execute('DELETE FROM `multicharacter_slots` WHERE `identifier` = ?', { - args.identifier - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsrem', args.identifier)) - end + if slots ~= nil then + MySQL.Async.execute('DELETE FROM `multicharacter_slots` WHERE `identifier` = ?', { + args.identifier + }) + xPlayer.triggerEvent('esx:showNotification', _U('slotsrem', args.identifier)) + end end, true, {help = _U('command_remslots'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'} + {name = 'identifier', help = _U('command_identifier'), type = 'string'} }}) ESX.RegisterCommand('enablechar', 'admin', function(xPlayer, args, showError) - local selectedCharacter = 'char'..args.charslot..':'..args.identifier; + local selectedCharacter = 'char'..args.charslot..':'..args.identifier; - MySQL.Async.execute('UPDATE `users` SET `disabled` = 0 WHERE identifier = ?', { - selectedCharacter - }, function(result) - if result > 0 then - xPlayer.triggerEvent('esx:showNotification', _U('charenabled', args.charslot, args.identifier)) - else - xPlayer.triggerEvent('esx:showNotification', _U('charnotfound', args.charslot, args.identifier)) - end - end) + MySQL.Async.execute('UPDATE `users` SET `disabled` = 0 WHERE identifier = ?', { + selectedCharacter + }, function(result) + if result > 0 then + xPlayer.triggerEvent('esx:showNotification', _U('charenabled', args.charslot, args.identifier)) + else + xPlayer.triggerEvent('esx:showNotification', _U('charnotfound', args.charslot, args.identifier)) + end + end) end, true, {help = _U('command_enablechar'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'}, - {name = 'charslot', help = _U('command_charslot'), type = 'number'} + {name = 'identifier', help = _U('command_identifier'), type = 'string'}, + {name = 'charslot', help = _U('command_charslot'), type = 'number'} }}) ESX.RegisterCommand('disablechar', 'admin', function(xPlayer, args, showError) - local selectedCharacter = 'char'..args.charslot..':'..args.identifier; + local selectedCharacter = 'char'..args.charslot..':'..args.identifier; - MySQL.Async.execute('UPDATE `users` SET `disabled` = 1 WHERE identifier = ?', { - selectedCharacter - }, function(result) - if result > 0 then - xPlayer.triggerEvent('esx:showNotification', _U('chardisabled', args.charslot, args.identifier)) - else - xPlayer.triggerEvent('esx:showNotification', _U('charnotfound', args.charslot, args.identifier)) - end - end) + MySQL.Async.execute('UPDATE `users` SET `disabled` = 1 WHERE identifier = ?', { + selectedCharacter + }, function(result) + if result > 0 then + xPlayer.triggerEvent('esx:showNotification', _U('chardisabled', args.charslot, args.identifier)) + else + xPlayer.triggerEvent('esx:showNotification', _U('charnotfound', args.charslot, args.identifier)) + end + end) end, true, {help = _U('command_disablechar'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'}, - {name = 'charslot', help = _U('command_charslot'), type = 'number'} + {name = 'identifier', help = _U('command_identifier'), type = 'string'}, + {name = 'charslot', help = _U('command_charslot'), type = 'number'} }}) RegisterCommand('forcelog', function(source, args, rawCommand) - TriggerEvent('esx:playerLogout', source) -end, true) \ No newline at end of file + TriggerEvent('esx:playerLogout', source) +end, true) From 95e9f2bbe881922c487bcf58a69f5298a2d14ad0 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 08:43:51 +1100 Subject: [PATCH 33/64] feat(server): Parse mysql_connection_string for database --- server/main.lua | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/server/main.lua b/server/main.lua index 09617693..d167a5fe 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,13 +1,32 @@ +local function DATABASE() + local connectionString = GetConvar('mysql_connection_string', ''); + if connectionString == '' then + error(connectionString..'\n^1Unable to start Multicharacter - unable to determine database from mysql_connection_string^0', 0) + elseif string.match(connectionString, 'mysql://') then + connectionString = string.sub(connectionString, string.find(connectionString, "/[^/]*$")+1) + return connectionString + else + connectionString = {string.strsplit(';', connectionString)} + for i=1, #connectionString do + local v = connectionString[i] + if v:match('database') then + return v:sub(10, #v) + end + end + end +end + if not ESX then - SetTimeout(3000, function() print('[^3WARNING^7] Unable to start Multicharacter - your version of ESX is not compatible ') end) + error('\n^1WARNING: Unable to start Multicharacter - you must be using ESX Legacy^0') elseif ESX.GetConfig().Multichar == true then - local IdentifierTables, Fetch = {}, -1 - - -- enter the name of your database here - Config.Database = 'es_extended' - + DATABASE = DATABASE() + local DB_TABLES = {} + local FETCH = nil + local PREFIX = 'char' -- enter a prefix to prepend to all user identifiers (keep it short) - Config.Prefix = 'char' + -- if you modify this, you will need to modify es_extended due to an oversight! + -- https://github.com/esx-framework/esx-legacy/blob/main/%5Besx%5D/es_extended/server/classes/player.lua#L17 + -- if Config.Multichar then self.license = 'license'..identifier:sub(identifier:find(':')) else self.license = 'license:'..identifier end local SetupCharacters = function(playerId) while Fetch == -1 do Citizen.Wait(500) end From f46277e2620d5dccdc348f431c1c9256cf3fcee4 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 09:03:31 +1100 Subject: [PATCH 34/64] feat(server): Improve GetJobs function - If using an ESX version with the getter, use it instead for better performance - General refactor and ensure compatibility with oxmysql --- server/main.lua | 53 +++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/server/main.lua b/server/main.lua index d167a5fe..70fdff55 100644 --- a/server/main.lua +++ b/server/main.lua @@ -29,18 +29,15 @@ elseif ESX.GetConfig().Multichar == true then -- if Config.Multichar then self.license = 'license'..identifier:sub(identifier:find(':')) else self.license = 'license:'..identifier end local SetupCharacters = function(playerId) - while Fetch == -1 do Citizen.Wait(500) end - local identifier = Config.Prefix..'%:'..ESX.GetIdentifier(playerId) - local slots = MySQL.Sync.fetchScalar("SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?", { - ESX.GetIdentifier(playerId) - }) - if not slots then - slots = Config.Slots - end - MySQL.Async.fetchAll(Fetch, { - identifier, - slots - }, function(result) + repeat Citizen.Wait(200) until FETCH + local identifier = ESX.GetIdentifier(playerId) + local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { + identifier + }) or Config.Slots + + identifier = PREFIX..'%:'..identifier + + MySQL.Async.fetchAll(FETCH, {identifier, slots}, function(result) local characters = {} for i=1, #result, 1 do local job, grade = result[i].job or 'unemployed', tostring(result[i].job_grade) @@ -49,7 +46,7 @@ elseif ESX.GetConfig().Multichar == true then job = ESX.Jobs[job].label end local accounts = json.decode(result[i].accounts) - local id = tonumber(string.sub(result[i].identifier, #Config.Prefix+1, string.find(result[i].identifier, ':')-1)) + local id = tonumber(string.sub(result[i].identifier, #PREFIX+1, string.find(result[i].identifier, ':')-1)) characters[id] = { id = id, bank = accounts.bank, @@ -69,14 +66,14 @@ elseif ESX.GetConfig().Multichar == true then end local DeleteCharacter = function(playerId, charid) - local identifier = Config.Prefix..charid..':'..ESX.GetIdentifier(playerId) + local identifier = ('%s%s:%s'):format(PREFIX, charid, ESX.GetIdentifier(playerId)) local counter = 0 - for k, v in pairs(IdentifierTables) do + for k, v in pairs(DB_TABLES) do MySQL.Async.execute("DELETE FROM "..v.table.." WHERE "..v.column.." = ?", { identifier }, function() counter = counter + 1 - if counter == #IdentifierTables then + if counter == #DB_TABLES then print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(playerId), playerId, identifier)) Citizen.Wait(100) SetupCharacters(playerId) @@ -87,14 +84,14 @@ elseif ESX.GetConfig().Multichar == true then end MySQL.ready(function() - MySQL.Async.fetchAll('SELECT `TABLE_NAME`, `COLUMN_NAME`, `CHARACTER_MAXIMUM_LENGTH` FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND (COLUMN_NAME = ? OR COLUMN_NAME = ?) ', { - Config.Database, 'identifier', 'owner' + MySQL.Async.fetchAll('SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND (COLUMN_NAME = ? OR COLUMN_NAME = ?) ', { + DATABASE, 'identifier', 'owner' }, function(result) if result then local varchar, varsize = {}, 0 for k, v in pairs(result) do if v.CHARACTER_MAXIMUM_LENGTH and v.CHARACTER_MAXIMUM_LENGTH >= 40 and v.CHARACTER_MAXIMUM_LENGTH < 60 then varchar[v.TABLE_NAME] = v.COLUMN_NAME varsize = varsize+1 end - table.insert(IdentifierTables, {table = v.TABLE_NAME, column = v.COLUMN_NAME}) + table.insert(DB_TABLES, {table = v.TABLE_NAME, column = v.COLUMN_NAME}) end if next(varchar) then for k, v in pairs(varchar) do @@ -102,8 +99,16 @@ elseif ESX.GetConfig().Multichar == true then end print(('[^2INFO^7] Attempted to update ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) end - if not next(ESX.Jobs) then ESX.Jobs = GetJobs() end - Fetch = MySQL.Sync.store("SELECT `identifier`, `accounts`, `job`, `job_grade`, `firstname`, `lastname`, `dateofbirth`, `sex`, `skin`, `disabled` FROM `users` WHERE identifier LIKE ? LIMIT ?") + ESX.Jobs = {} + local function GetJobs() + if ESX.GetJobs then return ESX.GetJobs() + else return exports['es_extended']:getSharedObject().Jobs end + end + repeat + ESX.Jobs = GetJobs() + Citizen.Wait(50) + until next(ESX.Jobs) + FETCH = MySQL.Sync.store("SELECT identifier, accounts, job, job_grade, firstname, lastname, dateofbirth, sex, skin, disabled FROM users WHERE identifier LIKE ? LIMIT ?") end end) end) @@ -121,13 +126,13 @@ elseif ESX.GetConfig().Multichar == true then if isNew then awaitingRegistration[src] = charid else - TriggerEvent('esx:onPlayerJoined', src, Config.Prefix..charid) + TriggerEvent('esx:onPlayerJoined', src, PREFIX..charid) end end end) AddEventHandler('esx_identity:completedRegistration', function(playerId, data) - TriggerEvent('esx:onPlayerJoined', playerId, Config.Prefix..awaitingRegistration[playerId], data) + TriggerEvent('esx:onPlayerJoined', playerId, PREFIX..awaitingRegistration[playerId], data) awaitingRegistration[playerId] = nil end) @@ -150,5 +155,5 @@ elseif ESX.GetConfig().Multichar == true then end) else - SetTimeout(3000, function() print('[^3WARNING^7] Multicharacter is disabled - please check your ESX configuration') end) + assert(nil, '^3WARNING: Multicharacter is disabled - please check your ESX configuration^0') end From d594c5db82aa53090119140502dc48acb0a3a43a Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 09:04:38 +1100 Subject: [PATCH 35/64] chore(manifest): Update versions --- fxmanifest.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index 617f933c..92bd87ad 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,8 @@ -fx_version 'adamant' +fx_version 'cerulean' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.2.2' +version '1.3' +lua54 'yes' dependencies { 'es_extended', @@ -19,7 +20,7 @@ shared_scripts { server_scripts { '@es_extended/imports.lua', '@mysql-async/lib/MySQL.lua', - 'server/*.lua' + 'server/*.lua', } client_scripts { From 749dfd0ec3391b580b451485480224ce862989b2 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 16 Oct 2021 09:05:13 +1100 Subject: [PATCH 36/64] chore(config): Change defaults --- config.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.lua b/config.lua index ca56aec7..f3d9d763 100644 --- a/config.lua +++ b/config.lua @@ -4,13 +4,13 @@ Config.Locale = 'en' -------------------- -- This is the default number of slots for EVERY player -- If you want to manage extra slots for specific players you can do it by using '/setslots' and '/remslots' commands -Config.Slots = 1 +Config.Slots = 4 -------------------- Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) -- Sets the location for character selection -- To set the spawn location for new characters, modify the default value in the `users` SQL table -Config.CanDelete = false -- Choose whether or not a user can self-delete its own characters +Config.CanDelete = true -- Choose whether or not a user can self-delete its own characters -------------------- -- Do not use unless you are prepared to adjust your resources to correctly reset data From 7995739cecd6a3cc68cbec4e6438b87c2317afc9 Mon Sep 17 00:00:00 2001 From: DokaDoka Date: Sat, 16 Oct 2021 10:06:33 +1100 Subject: [PATCH 37/64] fix(sql): fix disabled user column query --- esx_multicharacter.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esx_multicharacter.sql b/esx_multicharacter.sql index 71049ffa..b3a76af7 100644 --- a/esx_multicharacter.sql +++ b/esx_multicharacter.sql @@ -8,5 +8,6 @@ COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB ; -ALTER TABLE `users` - `disabled` TINYINT(1) NULL DEFAULT '0', +ALTER TABLE `users` ADD COLUMN + `disabled` TINYINT(1) NULL DEFAULT '0' +; From 565c5d0e35b2749479b40722d1abe004aff36554 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Mon, 18 Oct 2021 07:33:01 +1100 Subject: [PATCH 38/64] Update readme.md --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index dcca296f..f7f30478 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,9 @@ ### Requirements (ensure you are using the latest) - [ESX Legacy](https://github.com/esx-framework/esx-legacy) -- [MySQL Async 3.3.2](https://github.com/brouznouf/fivem-mysql-async/releases/tag/3.3.2) - [Spawnmanager](https://github.com/citizenfx/cfx-server-data/tree/master/resources/%5Bmanagers%5D/spawnmanager) +- [OxMySQL](https://github.com/overextended/oxmysql/) or [MySQL Async 3.3.2](https://github.com/brouznouf/fivem-mysql-async/releases/tag/3.3.2) + ### Installation - Modify your ESX config with `Config.Multichar = true` - Set your database name for `Config.Database` in server/main.lua From ebae4354cec182d21475bd6bf4d5031f55cbe93a Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 23 Oct 2021 11:58:18 +1100 Subject: [PATCH 39/64] fix(server): Correctly resolve database name for URI connection strings URI-connection strings would incorrectly parse the database name when using additional options as part of the string (i.e. "ESXLegacy?charset=utf8mb4"). Correctly check for these options and match the string accordingly. Also just better pattern matching in general. --- server/main.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server/main.lua b/server/main.lua index 70fdff55..b6eec4d5 100644 --- a/server/main.lua +++ b/server/main.lua @@ -2,9 +2,12 @@ local function DATABASE() local connectionString = GetConvar('mysql_connection_string', ''); if connectionString == '' then error(connectionString..'\n^1Unable to start Multicharacter - unable to determine database from mysql_connection_string^0', 0) - elseif string.match(connectionString, 'mysql://') then - connectionString = string.sub(connectionString, string.find(connectionString, "/[^/]*$")+1) - return connectionString + elseif connectionString:find('mysql://') then + if connectionString:find('?*$') then + return connectionString:match('[^/][%w]*[?$]'):sub(0, -2) + else + return connectionString:match('[^/][%w]*$') + end else connectionString = {string.strsplit(';', connectionString)} for i=1, #connectionString do From 870e1887b0e8d77d1aac23eef29809ef374ecf01 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 23 Oct 2021 11:58:59 +1100 Subject: [PATCH 40/64] Update fxmanifest.lua --- fxmanifest.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index 92bd87ad..7f98c72d 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'cerulean' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.3' +version '1.3.1' lua54 'yes' dependencies { From 8255fa2014715e7c7c0edfc2a2eecfdba86c1225 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Mon, 25 Oct 2021 15:47:57 +1100 Subject: [PATCH 41/64] feat(deferrals): Prevent connection when identifier is in use Only recently came to my attention that this was a concern. Since ESX and identity only check a raw identifier vs a player identifier (which contains a prefix) it doesn't prevent multiple logins. --- server/main.lua | 51 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/server/main.lua b/server/main.lua index b6eec4d5..4c482dd1 100644 --- a/server/main.lua +++ b/server/main.lua @@ -31,9 +31,25 @@ elseif ESX.GetConfig().Multichar == true then -- https://github.com/esx-framework/esx-legacy/blob/main/%5Besx%5D/es_extended/server/classes/player.lua#L17 -- if Config.Multichar then self.license = 'license'..identifier:sub(identifier:find(':')) else self.license = 'license:'..identifier end - local SetupCharacters = function(playerId) + local function GetIdentifier(playerId) + local identifier = 'license:' + for _, v in pairs(GetPlayerIdentifiers(playerId)) do + if string.match(v, identifier) then + identifier = string.gsub(v, identifier, '') + return identifier + end + end + end + + if next(ESX.Players) then + for k, v in pairs(ESX.Players) do + ESX.Players[k] = GetIdentifier(v.source) + end + else ESX.Players = {} end + + local function SetupCharacters(playerId) repeat Citizen.Wait(200) until FETCH - local identifier = ESX.GetIdentifier(playerId) + local identifier = GetIdentifier(playerId) local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { identifier }) or Config.Slots @@ -68,16 +84,29 @@ elseif ESX.GetConfig().Multichar == true then end) end - local DeleteCharacter = function(playerId, charid) - local identifier = ('%s%s:%s'):format(PREFIX, charid, ESX.GetIdentifier(playerId)) + AddEventHandler('playerConnecting', function(playerName, setKickReason, deferrals) + deferrals.defer() + local identifier = GetIdentifier(source) + Citizen.Wait(100) + if ESX.Players[identifier] then + deferrals.done('A player is already connected to the server with this identifier.') + else + ESX.Players[identifier] = true + deferrals.done() + end + end) + + local function DeleteCharacter(playerId, charid) + local identifier = GetIdentifier(playerId) + local character = ('%s%s:%s'):format(PREFIX, charid, identifier) local counter = 0 - for k, v in pairs(DB_TABLES) do + for _, v in pairs(DB_TABLES) do MySQL.Async.execute("DELETE FROM "..v.table.." WHERE "..v.column.." = ?", { - identifier + character }, function() counter = counter + 1 if counter == #DB_TABLES then - print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(playerId), playerId, identifier)) + print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(playerId), playerId, character)) Citizen.Wait(100) SetupCharacters(playerId) end @@ -124,12 +153,12 @@ elseif ESX.GetConfig().Multichar == true then local awaitingRegistration = {} RegisterServerEvent("esx_multicharacter:CharacterChosen") AddEventHandler('esx_multicharacter:CharacterChosen', function(charid, isNew) - local src = source if type(charid) == 'number' and string.len(charid) <= 2 and type(isNew) == 'boolean' then if isNew then - awaitingRegistration[src] = charid + awaitingRegistration[source] = charid else - TriggerEvent('esx:onPlayerJoined', src, PREFIX..charid) + TriggerEvent('esx:onPlayerJoined', source, PREFIX..charid) + ESX.Players[GetIdentifier(source)] = source end end end) @@ -137,10 +166,12 @@ elseif ESX.GetConfig().Multichar == true then AddEventHandler('esx_identity:completedRegistration', function(playerId, data) TriggerEvent('esx:onPlayerJoined', playerId, PREFIX..awaitingRegistration[playerId], data) awaitingRegistration[playerId] = nil + ESX.Players[GetIdentifier(source)] = playerId end) AddEventHandler('playerDropped', function(reason) awaitingRegistration[source] = nil + ESX.Players[GetIdentifier(source)] = nil end) RegisterServerEvent("esx_multicharacter:DeleteCharacter") From 4f3ce99e94eb9b73fdcf70b3bbad7ac8e8b91f93 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Tue, 26 Oct 2021 00:19:49 +1100 Subject: [PATCH 42/64] refactor(config): Remove redundant values from being stored on server --- client/main.lua | 4 +- config.lua | 227 +++++++++++++++++++++++++----------------------- 2 files changed, 118 insertions(+), 113 deletions(-) diff --git a/client/main.lua b/client/main.lua index db5fc7ec..9aa1a919 100644 --- a/client/main.lua +++ b/client/main.lua @@ -7,7 +7,7 @@ if ESX.GetConfig().Multichar then if NetworkIsPlayerActive(PlayerId()) then exports.spawnmanager:setAutoSpawn(false) DoScreenFadeOut(0) - while not GetResourceState('esx_menu_default') == 'started' do + while not GetResourceState('esx_menu_default') == 'started' do Citizen.Wait(0) end TriggerEvent("esx_multicharacter:SetupCharacters") @@ -139,7 +139,7 @@ if ESX.GetConfig().Multichar then character = Characters[spawned] }) end - + RegisterNetEvent('esx_multicharacter:SetupUI') AddEventHandler('esx_multicharacter:SetupUI', function(data, slots) DoScreenFadeOut(0) diff --git a/config.lua b/config.lua index f3d9d763..460c7e44 100644 --- a/config.lua +++ b/config.lua @@ -1,117 +1,122 @@ Config = {} Config.Locale = 'en' --------------------- --- This is the default number of slots for EVERY player --- If you want to manage extra slots for specific players you can do it by using '/setslots' and '/remslots' commands -Config.Slots = 4 --------------------- +if IsDuplicityVersion() then + -- This is the default number of slots for EVERY player + -- If you want to manage extra slots for specific players you can do it by using '/setslots' and '/remslots' commands + Config.Slots = 4 + -------------------- +else + -- Sets the location for the character selection scene + -- To set the spawn location for new characters, modify the default value in the `users` SQL table + Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) + -------------------- -Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) -- Sets the location for character selection --- To set the spawn location for new characters, modify the default value in the `users` SQL table + -- Allows players to delete their characters + Config.CanDelete = true + -------------------- -Config.CanDelete = true -- Choose whether or not a user can self-delete its own characters + -- Do not use unless you are prepared to adjust your resources to correctly reset data + -- Information: https://github.com/thelindat/esx_multicharacter#relogging + Config.Relog = false + -------------------- --------------------- --- Do not use unless you are prepared to adjust your resources to correctly reset data --- Information: https://github.com/thelindat/esx_multicharacter#relogging -Config.Relog = false --------------------- - -Config.Default = { - mom = 21, - dad = 0, - face_md_weight = 50, - skin_md_weight = 50, - nose_1 = 0, - nose_2 = 0, - nose_3 = 0, - nose_4 = 0, - nose_5 = 0, - nose_6 = 0, - cheeks_1 = 0, - cheeks_2 = 0, - cheeks_3 = 0, - lip_thickness = 0, - jaw_1 = 0, - jaw_2 = 0, - chin_1 = 0, - chin_2 = 0, - chin_13 = 0, - chin_4 = 0, - neck_thickness = 0, - hair_1 = 0, - hair_2 = 0, - hair_color_1 = 0, - hair_color_2 = 0, - tshirt_1 = 0, - tshirt_2 = 0, - torso_1 = 0, - torso_2 = 0, - decals_1 = 0, - decals_2 = 0, - arms = 0, - arms_2 = 0, - pants_1 = 0, - pants_2 = 0, - shoes_1 = 0, - shoes_2 = 0, - mask_1 = 0, - mask_2 = 0, - bproof_1 = 0, - bproof_2 = 0, - chain_1 = 0, - chain_2 = 0, - helmet_1 = -1, - helmet_2 = 0, - glasses_1 = 0, - glasses_2 = 0, - watches_1 = -1, - watches_2 = 0, - bracelets_1 = -1, - bracelets_2 = 0, - bags_1 = 0, - bags_2 = 0, - eye_color = 0, - eye_squint = 0, - eyebrows_2 = 0, - eyebrows_1 = 0, - eyebrows_3 = 0, - eyebrows_4 = 0, - eyebrows_5 = 0, - eyebrows_6 = 0, - makeup_1 = 0, - makeup_2 = 0, - makeup_3 = 0, - makeup_4 = 0, - lipstick_1 = 0, - lipstick_2 = 0, - lipstick_3 = 0, - lipstick_4 = 0, - ears_1 = -1, - ears_2 = 0, - chest_1 = 0, - chest_2 = 0, - chest_3 = 0, - bodyb_1 = -1, - bodyb_2 = 0, - bodyb_3 = -1, - bodyb_4 = 0, - age_1 = 0, - age_2 = 0, - blemishes_1 = 0, - blemishes_2 = 0, - blush_1 = 0, - blush_2 = 0, - blush_3 = 0, - complexion_1 = 0, - complexion_2 = 0, - sun_1 = 0, - sun_2 = 0, - moles_1 = 0, - moles_2 = 0, - beard_1 = 0, - beard_2 = 0, - beard_3 = 0, - beard_4 = 0 -} + -- Default appearance for new characters + Config.Default = { + mom = 21, + dad = 0, + face_md_weight = 50, + skin_md_weight = 50, + nose_1 = 0, + nose_2 = 0, + nose_3 = 0, + nose_4 = 0, + nose_5 = 0, + nose_6 = 0, + cheeks_1 = 0, + cheeks_2 = 0, + cheeks_3 = 0, + lip_thickness = 0, + jaw_1 = 0, + jaw_2 = 0, + chin_1 = 0, + chin_2 = 0, + chin_13 = 0, + chin_4 = 0, + neck_thickness = 0, + hair_1 = 0, + hair_2 = 0, + hair_color_1 = 0, + hair_color_2 = 0, + tshirt_1 = 0, + tshirt_2 = 0, + torso_1 = 0, + torso_2 = 0, + decals_1 = 0, + decals_2 = 0, + arms = 0, + arms_2 = 0, + pants_1 = 0, + pants_2 = 0, + shoes_1 = 0, + shoes_2 = 0, + mask_1 = 0, + mask_2 = 0, + bproof_1 = 0, + bproof_2 = 0, + chain_1 = 0, + chain_2 = 0, + helmet_1 = -1, + helmet_2 = 0, + glasses_1 = 0, + glasses_2 = 0, + watches_1 = -1, + watches_2 = 0, + bracelets_1 = -1, + bracelets_2 = 0, + bags_1 = 0, + bags_2 = 0, + eye_color = 0, + eye_squint = 0, + eyebrows_2 = 0, + eyebrows_1 = 0, + eyebrows_3 = 0, + eyebrows_4 = 0, + eyebrows_5 = 0, + eyebrows_6 = 0, + makeup_1 = 0, + makeup_2 = 0, + makeup_3 = 0, + makeup_4 = 0, + lipstick_1 = 0, + lipstick_2 = 0, + lipstick_3 = 0, + lipstick_4 = 0, + ears_1 = -1, + ears_2 = 0, + chest_1 = 0, + chest_2 = 0, + chest_3 = 0, + bodyb_1 = -1, + bodyb_2 = 0, + bodyb_3 = -1, + bodyb_4 = 0, + age_1 = 0, + age_2 = 0, + blemishes_1 = 0, + blemishes_2 = 0, + blush_1 = 0, + blush_2 = 0, + blush_3 = 0, + complexion_1 = 0, + complexion_2 = 0, + sun_1 = 0, + sun_2 = 0, + moles_1 = 0, + moles_2 = 0, + beard_1 = 0, + beard_2 = 0, + beard_3 = 0, + beard_4 = 0 + } +end \ No newline at end of file From c9749c0b4079d8c32a03c7641a665fc06dc04a0c Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Tue, 26 Oct 2021 00:20:59 +1100 Subject: [PATCH 43/64] refactor(server): Remove redundant local values and check result size --- server/main.lua | 76 +++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/server/main.lua b/server/main.lua index 4c482dd1..e6179a71 100644 --- a/server/main.lua +++ b/server/main.lua @@ -31,9 +31,9 @@ elseif ESX.GetConfig().Multichar == true then -- https://github.com/esx-framework/esx-legacy/blob/main/%5Besx%5D/es_extended/server/classes/player.lua#L17 -- if Config.Multichar then self.license = 'license'..identifier:sub(identifier:find(':')) else self.license = 'license:'..identifier end - local function GetIdentifier(playerId) + local function GetIdentifier(source) local identifier = 'license:' - for _, v in pairs(GetPlayerIdentifiers(playerId)) do + for _, v in pairs(GetPlayerIdentifiers(source)) do if string.match(v, identifier) then identifier = string.gsub(v, identifier, '') return identifier @@ -47,40 +47,44 @@ elseif ESX.GetConfig().Multichar == true then end else ESX.Players = {} end - local function SetupCharacters(playerId) - repeat Citizen.Wait(200) until FETCH - local identifier = GetIdentifier(playerId) + local function SetupCharacters(source) + while not FETCH do Citizen.Wait(100) end + local identifier = GetIdentifier(source) local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { identifier }) or Config.Slots - - identifier = PREFIX..'%:'..identifier + identifier = ('%s:%s'):format(PREFIX, identifier) MySQL.Async.fetchAll(FETCH, {identifier, slots}, function(result) - local characters = {} - for i=1, #result, 1 do - local job, grade = result[i].job or 'unemployed', tostring(result[i].job_grade) - if ESX.Jobs[job] and ESX.Jobs[job].grades[grade] then - if job ~= 'unemployed' then grade = ESX.Jobs[job].grades[grade].label else grade = '' end - job = ESX.Jobs[job].label + local characters + if result then + local characterCount = #result + characters = table.create(0, characterCount) + for i=1, characterCount, 1 do + local i = result[i] + local job, grade = i.job or 'unemployed', tostring(i.job_grade) + if ESX.Jobs[job] and ESX.Jobs[job].grades[grade] then + if job ~= 'unemployed' then grade = ESX.Jobs[job].grades[grade].label else grade = '' end + job = ESX.Jobs[job].label + end + local accounts = json.decode(i.accounts) + local id = tonumber(string.sub(i.identifier, #PREFIX+1, string.find(i.identifier, ':')-1)) + characters[id] = { + id = id, + bank = accounts.bank, + money = accounts.money, + job = job, + job_grade = grade, + firstname = i.firstname, + lastname = i.lastname, + dateofbirth = i.dateofbirth, + skin = json.decode(i.skin), + disabled = i.disabled, + sex = i.sex == 'm' and _('male') or _('female') + } end - local accounts = json.decode(result[i].accounts) - local id = tonumber(string.sub(result[i].identifier, #PREFIX+1, string.find(result[i].identifier, ':')-1)) - characters[id] = { - id = id, - bank = accounts.bank, - money = accounts.money, - job = job, - job_grade = grade, - firstname = result[i].firstname, - lastname = result[i].lastname, - dateofbirth = result[i].dateofbirth, - skin = json.decode(result[i].skin), - disabled = result[i].disabled, - } - if result[i].sex == 'm' then characters[id].sex = _('male') else characters[id].sex = _('female') end end - TriggerClientEvent('esx_multicharacter:SetupUI', playerId, characters, slots) + TriggerClientEvent('esx_multicharacter:SetupUI', source, characters, slots) end) end @@ -163,10 +167,10 @@ elseif ESX.GetConfig().Multichar == true then end end) - AddEventHandler('esx_identity:completedRegistration', function(playerId, data) - TriggerEvent('esx:onPlayerJoined', playerId, PREFIX..awaitingRegistration[playerId], data) - awaitingRegistration[playerId] = nil - ESX.Players[GetIdentifier(source)] = playerId + AddEventHandler('esx_identity:completedRegistration', function(source, data) + TriggerEvent('esx:onPlayerJoined', source, PREFIX..awaitingRegistration[source], data) + awaitingRegistration[source] = nil + ESX.Players[GetIdentifier(source)] = source end) AddEventHandler('playerDropped', function(reason) @@ -176,16 +180,14 @@ elseif ESX.GetConfig().Multichar == true then RegisterServerEvent("esx_multicharacter:DeleteCharacter") AddEventHandler('esx_multicharacter:DeleteCharacter', function(charid) - local src = source if type(charid) == "number" and string.len(charid) <= 2 then - DeleteCharacter(src, charid) + DeleteCharacter(source, charid) end end) RegisterServerEvent("esx_multicharacter:relog") AddEventHandler('esx_multicharacter:relog', function() - local src = source - TriggerEvent('esx:playerLogout', src) + TriggerEvent('esx:playerLogout', source) end) else From e3c7e5ce5c2dc1de56d5102dc01f33698a001293 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Tue, 26 Oct 2021 00:53:06 +1100 Subject: [PATCH 44/64] feat(server): Utilise transactions to reduce server load --- fxmanifest.lua | 2 +- server/main.lua | 50 ++++++++++++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index 7f98c72d..992b8ce1 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'cerulean' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.3.1' +version '1.4' lua54 'yes' dependencies { diff --git a/server/main.lua b/server/main.lua index e6179a71..f4137076 100644 --- a/server/main.lua +++ b/server/main.lua @@ -53,7 +53,7 @@ elseif ESX.GetConfig().Multichar == true then local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { identifier }) or Config.Slots - identifier = ('%s:%s'):format(PREFIX, identifier) + identifier = PREFIX..'%:'..identifier MySQL.Async.fetchAll(FETCH, {identifier, slots}, function(result) local characters @@ -100,23 +100,25 @@ elseif ESX.GetConfig().Multichar == true then end end) - local function DeleteCharacter(playerId, charid) - local identifier = GetIdentifier(playerId) - local character = ('%s%s:%s'):format(PREFIX, charid, identifier) - local counter = 0 - for _, v in pairs(DB_TABLES) do - MySQL.Async.execute("DELETE FROM "..v.table.." WHERE "..v.column.." = ?", { - character - }, function() - counter = counter + 1 - if counter == #DB_TABLES then - print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(playerId), playerId, character)) - Citizen.Wait(100) - SetupCharacters(playerId) - end - end) - Citizen.Wait(5) + local function DeleteCharacter(source, charid) + local identifier = ('%s%s:%s'):format(PREFIX, charid, GetIdentifier(source)) + local query = "DELETE FROM ?? WHERE ?? = ?" + local tableCount = #DB_TABLES + local queries = table.create(tableCount, 0) + + for i=1, tableCount do + local v = DB_TABLES[i] + queries[i] = {query = query, values = {v.table, v.column, identifier}} end + + MySQL.Async.transaction(queries, function(result) + if result then + print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(source), source, identifier)) + SetupCharacters(source) + else + print(result) + end + end) end MySQL.ready(function() @@ -130,10 +132,20 @@ elseif ESX.GetConfig().Multichar == true then table.insert(DB_TABLES, {table = v.TABLE_NAME, column = v.COLUMN_NAME}) end if next(varchar) then + local query = "ALTER TABLE ?? MODIFY COLUMN ?? VARCHAR(60)" + local queries = table.create(varsize, 0) + for k, v in pairs(varchar) do - MySQL.Sync.execute("ALTER TABLE "..k.." MODIFY COLUMN "..v.." VARCHAR(60)") + queries[#queries+1] = {query = query, values = {k, v}} end - print(('[^2INFO^7] Attempted to update ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) + + MySQL.Async.transaction(queries, function(result) + if result then + print(('[^2INFO^7] Updated ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) + else + print(('[^2INFO^7] Unable to update ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) + end + end) end ESX.Jobs = {} local function GetJobs() From 3fe1f438df6ccd2d2473fc532e0759324909327a Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Tue, 26 Oct 2021 02:24:06 +1100 Subject: [PATCH 45/64] chore(server): Update error messages and manifest --- fxmanifest.lua | 2 +- server/main.lua | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index 992b8ce1..f39c2340 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'cerulean' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.4' +version '1.4.0' lua54 'yes' dependencies { diff --git a/server/main.lua b/server/main.lua index f4137076..7c3dc1ea 100644 --- a/server/main.lua +++ b/server/main.lua @@ -20,7 +20,7 @@ local function DATABASE() end if not ESX then - error('\n^1WARNING: Unable to start Multicharacter - you must be using ESX Legacy^0') + error('\n^1Unable to start Multicharacter - you must be using ESX Legacy^0') elseif ESX.GetConfig().Multichar == true then DATABASE = DATABASE() local DB_TABLES = {} @@ -114,9 +114,10 @@ elseif ESX.GetConfig().Multichar == true then MySQL.Async.transaction(queries, function(result) if result then print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(source), source, identifier)) + Citizen.Wait(50) SetupCharacters(source) else - print(result) + error('\n^1Transaction failed while trying to delete '..identifier..'^0') end end) end @@ -204,4 +205,4 @@ elseif ESX.GetConfig().Multichar == true then else assert(nil, '^3WARNING: Multicharacter is disabled - please check your ESX configuration^0') -end +end \ No newline at end of file From a9960ef3f5716aa442df84b2b2732cfd3f554977 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Fri, 29 Oct 2021 11:09:30 +1100 Subject: [PATCH 46/64] refactor: move server settings to config Added support for sv_lan to allow use with FxDK. Added support for ESX forks with Config.Identifier --- config.lua | 11 +++++++++++ server/main.lua | 12 +++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/config.lua b/config.lua index 460c7e44..b5af0abc 100644 --- a/config.lua +++ b/config.lua @@ -6,6 +6,17 @@ if IsDuplicityVersion() then -- If you want to manage extra slots for specific players you can do it by using '/setslots' and '/remslots' commands Config.Slots = 4 -------------------- + + -- Text to prepend to each character (char#:identifier) - keep it short + -- if you modify this, you will need to modify es_extended due to an oversight! + -- https://github.com/esx-framework/esx-legacy/blob/main/%5Besx%5D/es_extended/server/classes/player.lua#L17 + -- if Config.Multichar then self.license = 'license'..identifier:sub(identifier:find(':')) else self.license = 'license:'..identifier end + Config.Prefix = 'char' + -------------------- + + -- Default identifier to store for characters - this should always match es_extended (recommended: license) + Config.Identifier = 'license' + else -- Sets the location for the character selection scene -- To set the spawn location for new characters, modify the default value in the `users` SQL table diff --git a/server/main.lua b/server/main.lua index 7c3dc1ea..27f29eb9 100644 --- a/server/main.lua +++ b/server/main.lua @@ -25,14 +25,12 @@ elseif ESX.GetConfig().Multichar == true then DATABASE = DATABASE() local DB_TABLES = {} local FETCH = nil - local PREFIX = 'char' - -- enter a prefix to prepend to all user identifiers (keep it short) - -- if you modify this, you will need to modify es_extended due to an oversight! - -- https://github.com/esx-framework/esx-legacy/blob/main/%5Besx%5D/es_extended/server/classes/player.lua#L17 - -- if Config.Multichar then self.license = 'license'..identifier:sub(identifier:find(':')) else self.license = 'license:'..identifier end + local SLOTS = Config.Slots or 4 + local PREFIX = Config.Prefix or 'char' + local PRIMARY_IDENTIFIER = ESX.GetConfig().Identifier or GetConvar('sv_lan', '') == 'true' and 'ip' or Config.Identifier local function GetIdentifier(source) - local identifier = 'license:' + local identifier = PRIMARY_IDENTIFIER..':' for _, v in pairs(GetPlayerIdentifiers(source)) do if string.match(v, identifier) then identifier = string.gsub(v, identifier, '') @@ -52,7 +50,7 @@ elseif ESX.GetConfig().Multichar == true then local identifier = GetIdentifier(source) local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { identifier - }) or Config.Slots + }) or SLOTS identifier = PREFIX..'%:'..identifier MySQL.Async.fetchAll(FETCH, {identifier, slots}, function(result) From 8402cf423659a6b92182354265a062c3b002950d Mon Sep 17 00:00:00 2001 From: Olvidate <82069828+Olvidate@users.noreply.github.com> Date: Mon, 8 Nov 2021 18:55:42 -0300 Subject: [PATCH 47/64] fix(server): fixed error with identifiers Fixed error when you don't have a identifier, Steam open for example. --- server/main.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/server/main.lua b/server/main.lua index 27f29eb9..eb88b6bc 100644 --- a/server/main.lua +++ b/server/main.lua @@ -90,11 +90,15 @@ elseif ESX.GetConfig().Multichar == true then deferrals.defer() local identifier = GetIdentifier(source) Citizen.Wait(100) - if ESX.Players[identifier] then - deferrals.done('A player is already connected to the server with this identifier.') + if identifier then + if ESX.Players[identifier] then + deferrals.done('A player is already connected to the server with this identifier.') + else + ESX.Players[identifier] = true + deferrals.done() + end else - ESX.Players[identifier] = true - deferrals.done() + deferrals.done("You don't have identifier") end end) @@ -203,4 +207,4 @@ elseif ESX.GetConfig().Multichar == true then else assert(nil, '^3WARNING: Multicharacter is disabled - please check your ESX configuration^0') -end \ No newline at end of file +end From e19f99fdcab8ea3c6af700efb5dcb8b497f90396 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:12:04 +1100 Subject: [PATCH 48/64] refactor(server): update deferral messages --- server/main.lua | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/server/main.lua b/server/main.lua index eb88b6bc..d966d528 100644 --- a/server/main.lua +++ b/server/main.lua @@ -41,14 +41,16 @@ elseif ESX.GetConfig().Multichar == true then if next(ESX.Players) then for k, v in pairs(ESX.Players) do - ESX.Players[k] = GetIdentifier(v.source) + ESX.Players[GetIdentifier(v.source)] = true end else ESX.Players = {} end local function SetupCharacters(source) while not FETCH do Citizen.Wait(100) end local identifier = GetIdentifier(source) - local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { + ESX.Players[identifier] = true + + local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { identifier }) or SLOTS identifier = PREFIX..'%:'..identifier @@ -92,13 +94,12 @@ elseif ESX.GetConfig().Multichar == true then Citizen.Wait(100) if identifier then if ESX.Players[identifier] then - deferrals.done('A player is already connected to the server with this identifier.') + deferrals.done(('A player is already connected to the server with this identifier.\nYour identifier: %s:%s'):format(PRIMARY_IDENTIFIER, identifier) else - ESX.Players[identifier] = true deferrals.done() end else - deferrals.done("You don't have identifier") + deferrals.done(('Unable to retrieve player identifier.\nIdentifier type: %s'):format(PRIMARY_IDENTIFIER) end end) @@ -177,7 +178,7 @@ elseif ESX.GetConfig().Multichar == true then awaitingRegistration[source] = charid else TriggerEvent('esx:onPlayerJoined', source, PREFIX..charid) - ESX.Players[GetIdentifier(source)] = source + ESX.Players[GetIdentifier(source)] = true end end end) @@ -185,7 +186,7 @@ elseif ESX.GetConfig().Multichar == true then AddEventHandler('esx_identity:completedRegistration', function(source, data) TriggerEvent('esx:onPlayerJoined', source, PREFIX..awaitingRegistration[source], data) awaitingRegistration[source] = nil - ESX.Players[GetIdentifier(source)] = source + ESX.Players[GetIdentifier(source)] = true end) AddEventHandler('playerDropped', function(reason) From 2635ce9fbb3138b75d0c6c14ca59c76f54d2f07e Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Thu, 11 Nov 2021 06:28:56 +1100 Subject: [PATCH 49/64] fix(server): added missing symbols --- config.lua | 2 +- server/main.lua | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config.lua b/config.lua index b5af0abc..e7290c3f 100644 --- a/config.lua +++ b/config.lua @@ -29,7 +29,7 @@ else -- Do not use unless you are prepared to adjust your resources to correctly reset data -- Information: https://github.com/thelindat/esx_multicharacter#relogging - Config.Relog = false + Config.Relog = true -------------------- -- Default appearance for new characters diff --git a/server/main.lua b/server/main.lua index d966d528..f411692a 100644 --- a/server/main.lua +++ b/server/main.lua @@ -49,7 +49,7 @@ elseif ESX.GetConfig().Multichar == true then while not FETCH do Citizen.Wait(100) end local identifier = GetIdentifier(source) ESX.Players[identifier] = true - + local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { identifier }) or SLOTS @@ -94,12 +94,12 @@ elseif ESX.GetConfig().Multichar == true then Citizen.Wait(100) if identifier then if ESX.Players[identifier] then - deferrals.done(('A player is already connected to the server with this identifier.\nYour identifier: %s:%s'):format(PRIMARY_IDENTIFIER, identifier) + deferrals.done(('A player is already connected to the server with this identifier.\nYour identifier: %s:%s'):format(PRIMARY_IDENTIFIER, identifier)) else deferrals.done() end else - deferrals.done(('Unable to retrieve player identifier.\nIdentifier type: %s'):format(PRIMARY_IDENTIFIER) + deferrals.done(('Unable to retrieve player identifier.\nIdentifier type: %s'):format(PRIMARY_IDENTIFIER)) end end) From 6c7408b02edaaee7b76e1683253c39ca711ae21e Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Fri, 12 Nov 2021 18:49:13 +1100 Subject: [PATCH 50/64] Update fxmanifest.lua --- fxmanifest.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index f39c2340..503a7fb8 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'cerulean' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.4.0' +version '1.4.1' lua54 'yes' dependencies { From 6a7d0ad56a56c35445464016f80adb2afb90d0b9 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sun, 21 Nov 2021 17:24:09 +1100 Subject: [PATCH 51/64] update readme --- config.lua | 4 +--- readme.md | 11 +++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/config.lua b/config.lua index e7290c3f..503c9cfb 100644 --- a/config.lua +++ b/config.lua @@ -8,9 +8,7 @@ if IsDuplicityVersion() then -------------------- -- Text to prepend to each character (char#:identifier) - keep it short - -- if you modify this, you will need to modify es_extended due to an oversight! - -- https://github.com/esx-framework/esx-legacy/blob/main/%5Besx%5D/es_extended/server/classes/player.lua#L17 - -- if Config.Multichar then self.license = 'license'..identifier:sub(identifier:find(':')) else self.license = 'license:'..identifier end + -- if you change the length, you will need to modify es_extended (refer to the readme) Config.Prefix = 'char' -------------------- diff --git a/readme.md b/readme.md index f7f30478..e4520790 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,15 @@ - All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry - The resource will attempt to set columns automatically +### Changing character prefix +- Each character is created a modified identifier (char#:identifier) +- Due to an oversight, ESX Legacy only supports a prefix with a length of 4 +- If you change the length, refer to https://github.com/esx-framework/esx-legacy/blob/main/%5Besx%5D/es_extended/server/classes/player.lua#L17 +- Modify this line to the following +```lua +if Config.Multichar then self.license = 'license:'..identifier:sub(identifier:find(':'), identifier:len()) else self.license = 'license:'..identifier end +``` + ### Conflicts * The following resources should not be used with ESX Legacy and can result in errors - essentialmode @@ -24,8 +33,6 @@ - Download and run all requirements - Use a fresh spawnmanager as many people alter the code - Ensure none of the conflicting resources are enabled -#### mysql-async duplicate entry - - You have not increased the VARCHAR size of the table holding identifiers - usually `owner` or `identifier` #### The menu interface is esx_menu_default - you can use any version if you want a different appearance ![image](https://user-images.githubusercontent.com/65407488/126976325-17cc3241-bb9e-451f-a6ed-610a8ef52fa5.png) From 150ec165fcd92c5815d952fdf9d67ffdbf9ee625 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sun, 21 Nov 2021 17:26:29 +1100 Subject: [PATCH 52/64] fix(server): clone and wipe the playerlist when restarting the resource Since we're looping through the table, we end up trying to index new values as they are added. --- server/main.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/server/main.lua b/server/main.lua index f411692a..5becd5c1 100644 --- a/server/main.lua +++ b/server/main.lua @@ -40,7 +40,9 @@ elseif ESX.GetConfig().Multichar == true then end if next(ESX.Players) then - for k, v in pairs(ESX.Players) do + local players = table.clone(ESX.Players) + table.wipe(ESX.Players) + for _, v in pairs(players) do ESX.Players[GetIdentifier(v.source)] = true end else ESX.Players = {} end @@ -48,9 +50,9 @@ elseif ESX.GetConfig().Multichar == true then local function SetupCharacters(source) while not FETCH do Citizen.Wait(100) end local identifier = GetIdentifier(source) - ESX.Players[identifier] = true + ESX.Players[identifier] = true - local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { + local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { identifier }) or SLOTS identifier = PREFIX..'%:'..identifier From 874eeef86c10e9fcb188d8520f871879a1ff58bb Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Thu, 2 Dec 2021 01:47:35 +1100 Subject: [PATCH 53/64] fix(server): connection string parser --- fxmanifest.lua | 2 +- server/main.lua | 40 ++++++++++++++++++---------------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/fxmanifest.lua b/fxmanifest.lua index 503a7fb8..f93b5e33 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'cerulean' game 'gta5' description 'https://github.com/thelindat/esx_multicharacter' -version '1.4.1' +version '1.4.2' lua54 'yes' dependencies { diff --git a/server/main.lua b/server/main.lua index 5becd5c1..cb4ad80d 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,28 +1,24 @@ -local function DATABASE() - local connectionString = GetConvar('mysql_connection_string', ''); - if connectionString == '' then - error(connectionString..'\n^1Unable to start Multicharacter - unable to determine database from mysql_connection_string^0', 0) - elseif connectionString:find('mysql://') then - if connectionString:find('?*$') then - return connectionString:match('[^/][%w]*[?$]'):sub(0, -2) - else - return connectionString:match('[^/][%w]*$') - end - else - connectionString = {string.strsplit(';', connectionString)} - for i=1, #connectionString do - local v = connectionString[i] - if v:match('database') then - return v:sub(10, #v) - end - end - end -end - if not ESX then error('\n^1Unable to start Multicharacter - you must be using ESX Legacy^0') elseif ESX.GetConfig().Multichar == true then - DATABASE = DATABASE() + local DATABASE do + local connectionString = GetConvar('mysql_connection_string', ''); + if connectionString == '' then + error(connectionString..'\n^1Unable to start Multicharacter - unable to determine database from mysql_connection_string^0', 0) + elseif connectionString:find('mysql://') then + connectionString = connectionString:sub(9, -1) + DATABASE = connectionString:sub(connectionString:find('/')+1, -1):gsub('[%?]+[%w%p]*$', '') + else + connectionString = {string.strsplit(';', connectionString)} + for i=1, #connectionString do + local v = connectionString[i] + if v:match('database') then + DATABASE = v:sub(10, #v) + end + end + end + end + local DB_TABLES = {} local FETCH = nil local SLOTS = Config.Slots or 4 From d6a56057d8535127065450bddc5c199d57e8457c Mon Sep 17 00:00:00 2001 From: Night Owls Roleplay <85649796+nightowlsrp@users.noreply.github.com> Date: Mon, 13 Dec 2021 22:08:43 -0800 Subject: [PATCH 54/64] removed margin-right to just use "right" value Removed margin-right as "right" handles this usage just fine and margin messes with the actual container. --- html/css/main.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/html/css/main.css b/html/css/main.css index 60090d94..15fb9bc5 100644 --- a/html/css/main.css +++ b/html/css/main.css @@ -25,10 +25,9 @@ body { display:none; position: absolute; top: 50%; - right: 0; + right: 25; transform: translate(0, -50%); background: rgba(0,0,0,0.7); - margin-right: 1.5rem; } .header { From 72450dfcd67dd4db09829cb1ce78bb0542dc314d Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 12 Feb 2022 05:58:45 +1100 Subject: [PATCH 55/64] refactor: swap to oxmysql ESX officially uses oxmysql with new syntax, so follow suite. --- client/main.lua | 8 ++-- config.lua | 8 ++-- esx_multicharacter.sql | 10 ++--- fxmanifest.lua | 2 +- readme.md | 46 ++++++---------------- server/commands.lua | 14 +++---- server/main.lua | 87 +++++++++++++++++++++--------------------- 7 files changed, 74 insertions(+), 101 deletions(-) diff --git a/client/main.lua b/client/main.lua index 9aa1a919..cb10ca8f 100644 --- a/client/main.lua +++ b/client/main.lua @@ -51,7 +51,7 @@ if ESX.GetConfig().Multichar then local keys = {18, 27, 172, 173, 174, 175, 176, 177, 187, 188, 191, 201, 108, 109} while hidePlayers do DisableAllControlActions(0) - for i=1, #keys do + for i = 1, #keys do EnableControlAction(0, keys[i], true) end SetEntityVisible(PlayerPedId(), 0, 0) @@ -64,7 +64,7 @@ if ESX.GetConfig().Multichar then HideHudAndRadarThisFrame() Citizen.Wait(0) local vehicles = GetGamePool('CVehicle') - for i=1, #vehicles do + for i = 1, #vehicles do SetEntityLocallyInvisible(vehicles[i]) end end @@ -80,7 +80,7 @@ if ESX.GetConfig().Multichar then local playerPool = {} while hidePlayers do local players = GetActivePlayers() - for i=1, #players do + for i = 1, #players do local player = players[i] if player ~= PlayerId() and not playerPool[player] then playerPool[player] = true @@ -236,7 +236,7 @@ if ESX.GetConfig().Multichar then else ESX.UI.Menu.CloseAll() local GetSlot = function() - for i=1, slots do + for i = 1, slots do if not Characters[i] then return i end diff --git a/config.lua b/config.lua index 503c9cfb..fe18b776 100644 --- a/config.lua +++ b/config.lua @@ -1,6 +1,9 @@ Config = {} Config.Locale = 'en' +-- Allows players to delete their characters +Config.CanDelete = true + if IsDuplicityVersion() then -- This is the default number of slots for EVERY player -- If you want to manage extra slots for specific players you can do it by using '/setslots' and '/remslots' commands @@ -8,7 +11,6 @@ if IsDuplicityVersion() then -------------------- -- Text to prepend to each character (char#:identifier) - keep it short - -- if you change the length, you will need to modify es_extended (refer to the readme) Config.Prefix = 'char' -------------------- @@ -21,10 +23,6 @@ else Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) -------------------- - -- Allows players to delete their characters - Config.CanDelete = true - -------------------- - -- Do not use unless you are prepared to adjust your resources to correctly reset data -- Information: https://github.com/thelindat/esx_multicharacter#relogging Config.Relog = true diff --git a/esx_multicharacter.sql b/esx_multicharacter.sql index b3a76af7..f19f7610 100644 --- a/esx_multicharacter.sql +++ b/esx_multicharacter.sql @@ -1,13 +1,9 @@ CREATE TABLE `multicharacter_slots` ( - `identifier` VARCHAR(60) NOT NULL COLLATE 'utf8mb4_unicode_ci', + `identifier` VARCHAR(60) NOT NULL, `slots` INT(11) NOT NULL, PRIMARY KEY (`identifier`) USING BTREE, INDEX `slots` (`slots`) USING BTREE -) -COLLATE='utf8mb4_unicode_ci' -ENGINE=InnoDB -; +) ENGINE=InnoDB; ALTER TABLE `users` ADD COLUMN - `disabled` TINYINT(1) NULL DEFAULT '0' -; + `disabled` TINYINT(1) NULL DEFAULT '0'; diff --git a/fxmanifest.lua b/fxmanifest.lua index f93b5e33..0b928219 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -19,7 +19,7 @@ shared_scripts { server_scripts { '@es_extended/imports.lua', - '@mysql-async/lib/MySQL.lua', + '@oxmysql/lib/MySQL.lua', 'server/*.lua', } diff --git a/readme.md b/readme.md index e4520790..fa8c8748 100644 --- a/readme.md +++ b/readme.md @@ -1,24 +1,6 @@ ### Requirements (ensure you are using the latest) - [ESX Legacy](https://github.com/esx-framework/esx-legacy) -- [Spawnmanager](https://github.com/citizenfx/cfx-server-data/tree/master/resources/%5Bmanagers%5D/spawnmanager) - -- [OxMySQL](https://github.com/overextended/oxmysql/) or [MySQL Async 3.3.2](https://github.com/brouznouf/fivem-mysql-async/releases/tag/3.3.2) - -### Installation -- Modify your ESX config with `Config.Multichar = true` -- Set your database name for `Config.Database` in server/main.lua -- Run `esx_multicharacter.sql` into your database -- All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry - - The resource will attempt to set columns automatically - -### Changing character prefix -- Each character is created a modified identifier (char#:identifier) -- Due to an oversight, ESX Legacy only supports a prefix with a length of 4 -- If you change the length, refer to https://github.com/esx-framework/esx-legacy/blob/main/%5Besx%5D/es_extended/server/classes/player.lua#L17 -- Modify this line to the following -```lua -if Config.Multichar then self.license = 'license:'..identifier:sub(identifier:find(':'), identifier:len()) else self.license = 'license:'..identifier end -``` +- [OxMySQL](https://github.com/overextended/oxmysql/releases) ### Conflicts * The following resources should not be used with ESX Legacy and can result in errors @@ -28,13 +10,15 @@ if Config.Multichar then self.license = 'license:'..identifier:sub(identifier:fi - fivem-map-hipster - default_spawnpoint -### Common issues -#### Black screen / loading scripts - - Download and run all requirements - - Use a fresh spawnmanager as many people alter the code - - Ensure none of the conflicting resources are enabled +### Installation +- Modify your ESX config with `Config.Multichar = true` +- Set your database name for `Config.Database` in server/main.lua +- Run `esx_multicharacter.sql` into your database +- All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry + - The resource will attempt to set columns automatically -#### The menu interface is esx_menu_default - you can use any version if you want a different appearance + +#### The menu is esx_menu_default - you can use any version if you want a different appearance ![image](https://user-images.githubusercontent.com/65407488/126976325-17cc3241-bb9e-451f-a6ed-610a8ef52fa5.png) ### Relogging @@ -43,22 +27,16 @@ if Config.Multichar then self.license = 'license:'..identifier:sub(identifier:fi - Add the following events to resources that require support for relogging, or - Add them to [@esx/imports.lua](https://github.com/esx-framework/es_extended/blob/legacy/imports.lua) (and use the imports in your resources) ```lua -RegisterNetEvent('esx:playerLoaded') -AddEventHandler('esx:playerLoaded', function(xPlayer) +RegisterNetEvent('esx:playerLoaded', function(xPlayer) ESX.PlayerData = xPlayer ESX.PlayerLoaded = true end) -RegisterNetEvent('esx:onPlayerLogout') -AddEventHandler('esx:onPlayerLogout', function() +RegisterNetEvent('esx:onPlayerLogout', function() ESX.PlayerLoaded = false ESX.PlayerData = {} end) ``` -- Any threads using ESX.PlayerData in a loop should check if ESX.PlayerLoaded is true - - This ensures the resource does not error after relogging, or while on character selection - - Setup correctly you can break your loops and trigger them again after loading - - Refer to my [boilerplate](https://github.com/thelindat/esx_legacy_boilerplate) for more information and usage examples ### Notes - This resource is not compatible with ExtendedMode or previous versions of ESX @@ -76,7 +54,7 @@ end) ## Notice -Copyright© 2021 Linden and KASH +Copyright © 2021 Linden and KASH This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/server/commands.lua b/server/commands.lua index 6c0ff047..3cfa98d5 100644 --- a/server/commands.lua +++ b/server/commands.lua @@ -1,16 +1,16 @@ ESX.RegisterCommand('setslots', 'admin', function(xPlayer, args, showError) - local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { + local slots = MySQL.scalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { args.identifier }) if slots == nil then - MySQL.Async.execute('INSERT INTO `multicharacter_slots` (`identifier`, `slots`) VALUES (?, ?)', { + MySQL.update('INSERT INTO `multicharacter_slots` (`identifier`, `slots`) VALUES (?, ?)', { args.identifier, args.slots }) xPlayer.triggerEvent('esx:showNotification', _U('slotsadd', args.slots, args.identifier)) else - MySQL.Async.execute('UPDATE `multicharacter_slots` SET `slots` = ? WHERE `identifier` = ?', { + MySQL.update('UPDATE `multicharacter_slots` SET `slots` = ? WHERE `identifier` = ?', { args.slots, args.identifier }) @@ -22,12 +22,12 @@ end, true, {help = _U('command_setslots'), validate = true, arguments = { }}) ESX.RegisterCommand('remslots', 'admin', function(xPlayer, args, showError) - local slots = MySQL.Sync.fetchScalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { + local slots = MySQL.scalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { args.identifier }) if slots ~= nil then - MySQL.Async.execute('DELETE FROM `multicharacter_slots` WHERE `identifier` = ?', { + MySQL.update('DELETE FROM `multicharacter_slots` WHERE `identifier` = ?', { args.identifier }) xPlayer.triggerEvent('esx:showNotification', _U('slotsrem', args.identifier)) @@ -40,7 +40,7 @@ ESX.RegisterCommand('enablechar', 'admin', function(xPlayer, args, showError) local selectedCharacter = 'char'..args.charslot..':'..args.identifier; - MySQL.Async.execute('UPDATE `users` SET `disabled` = 0 WHERE identifier = ?', { + MySQL.update('UPDATE `users` SET `disabled` = 0 WHERE identifier = ?', { selectedCharacter }, function(result) if result > 0 then @@ -59,7 +59,7 @@ ESX.RegisterCommand('disablechar', 'admin', function(xPlayer, args, showError) local selectedCharacter = 'char'..args.charslot..':'..args.identifier; - MySQL.Async.execute('UPDATE `users` SET `disabled` = 1 WHERE identifier = ?', { + MySQL.update('UPDATE `users` SET `disabled` = 1 WHERE identifier = ?', { selectedCharacter }, function(result) if result > 0 then diff --git a/server/main.lua b/server/main.lua index cb4ad80d..a0c13e15 100644 --- a/server/main.lua +++ b/server/main.lua @@ -10,7 +10,7 @@ elseif ESX.GetConfig().Multichar == true then DATABASE = connectionString:sub(connectionString:find('/')+1, -1):gsub('[%?]+[%w%p]*$', '') else connectionString = {string.strsplit(';', connectionString)} - for i=1, #connectionString do + for i = 1, #connectionString do local v = connectionString[i] if v:match('database') then DATABASE = v:sub(10, #v) @@ -48,48 +48,51 @@ elseif ESX.GetConfig().Multichar == true then local identifier = GetIdentifier(source) ESX.Players[identifier] = true - local slots = MySQL.Sync.fetchScalar("SELECT slots FROM multicharacter_slots WHERE identifier = ?", { - identifier - }) or SLOTS + local slots = MySQL.scalar('SELECT slots FROM multicharacter_slots WHERE identifier = ?', { identifier }) or SLOTS identifier = PREFIX..'%:'..identifier - MySQL.Async.fetchAll(FETCH, {identifier, slots}, function(result) - local characters - if result then - local characterCount = #result - characters = table.create(0, characterCount) - for i=1, characterCount, 1 do - local i = result[i] - local job, grade = i.job or 'unemployed', tostring(i.job_grade) - if ESX.Jobs[job] and ESX.Jobs[job].grades[grade] then - if job ~= 'unemployed' then grade = ESX.Jobs[job].grades[grade].label else grade = '' end - job = ESX.Jobs[job].label - end - local accounts = json.decode(i.accounts) - local id = tonumber(string.sub(i.identifier, #PREFIX+1, string.find(i.identifier, ':')-1)) - characters[id] = { - id = id, - bank = accounts.bank, - money = accounts.money, - job = job, - job_grade = grade, - firstname = i.firstname, - lastname = i.lastname, - dateofbirth = i.dateofbirth, - skin = json.decode(i.skin), - disabled = i.disabled, - sex = i.sex == 'm' and _('male') or _('female') - } + local result = MySQL.query.await(FETCH, {identifier, slots}) + local characters + + if result then + local characterCount = #result + characters = table.create(0, characterCount) + + for i = 1, characterCount, 1 do + local v = result[i] + local job, grade = v.job or 'unemployed', tostring(v.job_grade) + + if ESX.Jobs[job] and ESX.Jobs[job].grades[grade] then + if job ~= 'unemployed' then grade = ESX.Jobs[job].grades[grade].label else grade = '' end + job = ESX.Jobs[job].label end + + local accounts = json.decode(v.accounts) + local id = tonumber(string.sub(v.identifier, #PREFIX+1, string.find(v.identifier, ':')-1)) + + characters[id] = { + id = id, + bank = accounts.bank, + money = accounts.money, + job = job, + job_grade = grade, + firstname = v.firstname, + lastname = v.lastname, + dateofbirth = v.dateofbirth, + skin = v.skin and json.decode(v.skin) or {}, + disabled = v.disabled, + sex = v.sex == 'm' and _('male') or _('female') + } end - TriggerClientEvent('esx_multicharacter:SetupUI', source, characters, slots) - end) + end + + TriggerClientEvent('esx_multicharacter:SetupUI', source, characters, slots) end AddEventHandler('playerConnecting', function(playerName, setKickReason, deferrals) deferrals.defer() local identifier = GetIdentifier(source) - Citizen.Wait(100) + if identifier then if ESX.Players[identifier] then deferrals.done(('A player is already connected to the server with this identifier.\nYour identifier: %s:%s'):format(PRIMARY_IDENTIFIER, identifier)) @@ -112,7 +115,7 @@ elseif ESX.GetConfig().Multichar == true then queries[i] = {query = query, values = {v.table, v.column, identifier}} end - MySQL.Async.transaction(queries, function(result) + MySQL.transaction(queries, function(result) if result then print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(source), source, identifier)) Citizen.Wait(50) @@ -163,14 +166,14 @@ elseif ESX.GetConfig().Multichar == true then end) end) - RegisterServerEvent("esx_multicharacter:SetupCharacters") + RegisterNetEvent('esx_multicharacter:SetupCharacters', function() AddEventHandler('esx_multicharacter:SetupCharacters', function() SetupCharacters(source) end) local awaitingRegistration = {} - RegisterServerEvent("esx_multicharacter:CharacterChosen") - AddEventHandler('esx_multicharacter:CharacterChosen', function(charid, isNew) + + RegisterNetEvent('esx_multicharacter:CharacterChosen', function(charid, isNew) if type(charid) == 'number' and string.len(charid) <= 2 and type(isNew) == 'boolean' then if isNew then awaitingRegistration[source] = charid @@ -192,15 +195,13 @@ elseif ESX.GetConfig().Multichar == true then ESX.Players[GetIdentifier(source)] = nil end) - RegisterServerEvent("esx_multicharacter:DeleteCharacter") - AddEventHandler('esx_multicharacter:DeleteCharacter', function(charid) - if type(charid) == "number" and string.len(charid) <= 2 then + RegisterNetEvent('esx_multicharacter:DeleteCharacter', function(charid) + if Config.CanDelete and type(charid) == 'number' and string.len(charid) <= 2 then DeleteCharacter(source, charid) end end) - RegisterServerEvent("esx_multicharacter:relog") - AddEventHandler('esx_multicharacter:relog', function() + RegisterNetEvent('esx_multicharacter:relog', function() TriggerEvent('esx:playerLogout', source) end) From b7c521c8e7856fb8e1ce08c8f006c461bdfb014e Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Sat, 12 Feb 2022 06:03:23 +1100 Subject: [PATCH 56/64] feat(server): database optimisations Limited testing, but works in a fairly clean ESX environment. Sets up foreign keys in the database to allow for easy and optimised character deletion. Foreign keys will only be set where owner and identifier columns exist, the field cannot be NULL and uses VARCHAR. --- server/main.lua | 119 +++++++++++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 42 deletions(-) diff --git a/server/main.lua b/server/main.lua index a0c13e15..5b672bc7 100644 --- a/server/main.lua +++ b/server/main.lua @@ -19,7 +19,7 @@ elseif ESX.GetConfig().Multichar == true then end end - local DB_TABLES = {} + local DB_TABLES = {users = 'identifier'} local FETCH = nil local SLOTS = Config.Slots or 4 local PREFIX = Config.Prefix or 'char' @@ -106,13 +106,13 @@ elseif ESX.GetConfig().Multichar == true then local function DeleteCharacter(source, charid) local identifier = ('%s%s:%s'):format(PREFIX, charid, GetIdentifier(source)) - local query = "DELETE FROM ?? WHERE ?? = ?" - local tableCount = #DB_TABLES - local queries = table.create(tableCount, 0) + local query = 'DELETE FROM %s WHERE %s = ?' + local queries = {} + local count = 0 - for i=1, tableCount do - local v = DB_TABLES[i] - queries[i] = {query = query, values = {v.table, v.column, identifier}} + for table, column in pairs(DB_TABLES) do + count += 1 + queries[count] = {query = query:format(table, column), values = {identifier}} end MySQL.transaction(queries, function(result) @@ -127,47 +127,82 @@ elseif ESX.GetConfig().Multichar == true then end MySQL.ready(function() - MySQL.Async.fetchAll('SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND (COLUMN_NAME = ? OR COLUMN_NAME = ?) ', { - DATABASE, 'identifier', 'owner' - }, function(result) - if result then - local varchar, varsize = {}, 0 - for k, v in pairs(result) do - if v.CHARACTER_MAXIMUM_LENGTH and v.CHARACTER_MAXIMUM_LENGTH >= 40 and v.CHARACTER_MAXIMUM_LENGTH < 60 then varchar[v.TABLE_NAME] = v.COLUMN_NAME varsize = varsize+1 end - table.insert(DB_TABLES, {table = v.TABLE_NAME, column = v.COLUMN_NAME}) - end - if next(varchar) then - local query = "ALTER TABLE ?? MODIFY COLUMN ?? VARCHAR(60)" - local queries = table.create(varsize, 0) + local length = 42 + #PREFIX + local DB_COLUMNS = MySQL.query.await(('SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = "%s" AND DATA_TYPE = "varchar" AND COLUMN_NAME IN (?)'):format(DATABASE, length), { + {'identifier', 'owner'} + }) - for k, v in pairs(varchar) do - queries[#queries+1] = {query = query, values = {k, v}} - end + if DB_COLUMNS then + local FK = MySQL.query.await(('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE = "FOREIGN KEY" AND TABLE_SCHEMA = "%s"'):format(DATABASE)) + local FOREIGN_KEY = {} - MySQL.Async.transaction(queries, function(result) - if result then - print(('[^2INFO^7] Updated ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) - else - print(('[^2INFO^7] Unable to update ^5%s^7 columns to use VARCHAR(60)'):format(varsize)) - end - end) - end - ESX.Jobs = {} - local function GetJobs() - if ESX.GetJobs then return ESX.GetJobs() - else return exports['es_extended']:getSharedObject().Jobs end - end - repeat - ESX.Jobs = GetJobs() - Citizen.Wait(50) - until next(ESX.Jobs) - FETCH = MySQL.Sync.store("SELECT identifier, accounts, job, job_grade, firstname, lastname, dateofbirth, sex, skin, disabled FROM users WHERE identifier LIKE ? LIMIT ?") + for i = 1, #FK do + FOREIGN_KEY[FK[i].TABLE_NAME] = true end - end) + + local columns = {} + local count = 0 + + for i = 1, #DB_COLUMNS do + local v = DB_COLUMNS[i] + + if v?.CHARACTER_MAXIMUM_LENGTH ~= length then + count += 1 + columns[v.TABLE_NAME] = v.COLUMN_NAME + end + end + + if next(columns) then + local query = 'ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(%s)' + local queries = table.create(count, 0) + + for k, v in pairs(columns) do + queries[#queries+1] = {query = query:format(k, v, length)} + end + + if MySQL.transaction.await(queries) then + print(('[^2INFO^7] Updated ^5%s^7 columns to use VARCHAR(%s)'):format(count, length)) + else + print(('[^2INFO^7] Unable to update ^5%s^7 columns to use VARCHAR(%s)'):format(count, length)) + end + end + + for i = 1, #DB_COLUMNS do + local v = DB_COLUMNS[i] + + if not FOREIGN_KEY[v.TABLE_NAME] then + DB_TABLES[v.TABLE_NAME] = v.COLUMN_NAME + + if v.TABLE_NAME ~= 'users' and v.IS_NULLABLE == 'NO' then + MySQL.update(([[ALTER TABLE `%s` + ADD CONSTRAINT `FK_%s_users` FOREIGN KEY (`%s`) REFERENCES `users` (`identifier`) ON UPDATE CASCADE ON DELETE CASCADE]]):format(v.TABLE_NAME, v.TABLE_NAME, v.COLUMN_NAME), function(result) + if result then + print(('[^2INFO^7] Updated ^5"%s.%s"^7 to use FOREIGN_KEY referencing ^5"users.identifier"^7'):format(v.TABLE_NAME, v.COLUMN_NAME)) + end + end) + end + end + end + + ESX.Jobs = {} + + local function GetJobs() + if ESX.GetJobs then + return ESX.GetJobs() + end + return exports.es_extended:getSharedObject().Jobs + end + + repeat + ESX.Jobs = GetJobs() + Citizen.Wait(50) + until next(ESX.Jobs) + + FETCH = 'SELECT identifier, accounts, job, job_grade, firstname, lastname, dateofbirth, sex, skin, disabled FROM users WHERE identifier LIKE ? LIMIT ?' + end end) RegisterNetEvent('esx_multicharacter:SetupCharacters', function() - AddEventHandler('esx_multicharacter:SetupCharacters', function() SetupCharacters(source) end) From fca8927b384713d0cdd8327a2a60f53ba324bd43 Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Mon, 14 Feb 2022 20:18:59 +1100 Subject: [PATCH 57/64] revert(server): foreign keys Can result in some errors. Still keeping the other optimisations from previous commit (namely adjusting all identifier fields to the correct varchar length). --- server/main.lua | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/server/main.lua b/server/main.lua index 5b672bc7..6b3fd4f8 100644 --- a/server/main.lua +++ b/server/main.lua @@ -128,18 +128,11 @@ elseif ESX.GetConfig().Multichar == true then MySQL.ready(function() local length = 42 + #PREFIX - local DB_COLUMNS = MySQL.query.await(('SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = "%s" AND DATA_TYPE = "varchar" AND COLUMN_NAME IN (?)'):format(DATABASE, length), { + local DB_COLUMNS = MySQL.query.await(('SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = "%s" AND DATA_TYPE = "varchar" AND COLUMN_NAME IN (?)'):format(DATABASE, length), { {'identifier', 'owner'} }) if DB_COLUMNS then - local FK = MySQL.query.await(('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE = "FOREIGN KEY" AND TABLE_SCHEMA = "%s"'):format(DATABASE)) - local FOREIGN_KEY = {} - - for i = 1, #FK do - FOREIGN_KEY[FK[i].TABLE_NAME] = true - end - local columns = {} local count = 0 @@ -167,23 +160,6 @@ elseif ESX.GetConfig().Multichar == true then end end - for i = 1, #DB_COLUMNS do - local v = DB_COLUMNS[i] - - if not FOREIGN_KEY[v.TABLE_NAME] then - DB_TABLES[v.TABLE_NAME] = v.COLUMN_NAME - - if v.TABLE_NAME ~= 'users' and v.IS_NULLABLE == 'NO' then - MySQL.update(([[ALTER TABLE `%s` - ADD CONSTRAINT `FK_%s_users` FOREIGN KEY (`%s`) REFERENCES `users` (`identifier`) ON UPDATE CASCADE ON DELETE CASCADE]]):format(v.TABLE_NAME, v.TABLE_NAME, v.COLUMN_NAME), function(result) - if result then - print(('[^2INFO^7] Updated ^5"%s.%s"^7 to use FOREIGN_KEY referencing ^5"users.identifier"^7'):format(v.TABLE_NAME, v.COLUMN_NAME)) - end - end) - end - end - end - ESX.Jobs = {} local function GetJobs() From 67d28ee2682591a44fac7e27786483e4d8e9bece Mon Sep 17 00:00:00 2001 From: CoachYT1 <69034647+CoachYT1@users.noreply.github.com> Date: Mon, 21 Feb 2022 09:17:49 +0100 Subject: [PATCH 58/64] Update readme.md --- readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readme.md b/readme.md index fa8c8748..6e2393c9 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,6 @@ ### Installation - Modify your ESX config with `Config.Multichar = true` -- Set your database name for `Config.Database` in server/main.lua - Run `esx_multicharacter.sql` into your database - All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry - The resource will attempt to set columns automatically @@ -25,7 +24,7 @@ - Do not enable this setting if you do not intend to properly set up relog support - Requires the latest update for ESX Status (prevents multiple status ticks from running) - Add the following events to resources that require support for relogging, or -- Add them to [@esx/imports.lua](https://github.com/esx-framework/es_extended/blob/legacy/imports.lua) (and use the imports in your resources) +- Add them to [@es_extended/imports.lua](https://github.com/esx-framework/esx-legacy/blob/main/[esx]/es_extended/imports.lua) (and use the imports in your resources) ```lua RegisterNetEvent('esx:playerLoaded', function(xPlayer) ESX.PlayerData = xPlayer From 09ce85123d693ddfe54c1bb764b95864418b12b7 Mon Sep 17 00:00:00 2001 From: Dolu <47056777+dolutattoo@users.noreply.github.com> Date: Sat, 12 Mar 2022 03:44:30 +0100 Subject: [PATCH 59/64] fix(server): await player slots --- server/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/main.lua b/server/main.lua index 6b3fd4f8..266c560c 100644 --- a/server/main.lua +++ b/server/main.lua @@ -48,7 +48,7 @@ elseif ESX.GetConfig().Multichar == true then local identifier = GetIdentifier(source) ESX.Players[identifier] = true - local slots = MySQL.scalar('SELECT slots FROM multicharacter_slots WHERE identifier = ?', { identifier }) or SLOTS + local slots = MySQL.scalar.await('SELECT slots FROM multicharacter_slots WHERE identifier = ?', { identifier }) or SLOTS identifier = PREFIX..'%:'..identifier local result = MySQL.query.await(FETCH, {identifier, slots}) From b9232a253303d595e551d769ce558fe570a4fca1 Mon Sep 17 00:00:00 2001 From: Mycroft Date: Wed, 23 Mar 2022 16:04:38 +0000 Subject: [PATCH 60/64] Revert "Feat: Add Official Multicharacter" This reverts commit e6dd5a5f2c11765609582a197c20b3035fc3c264. --- [SQL]/legacy.sql | 14 - [esx]/es_extended/config.lua | 2 +- [esx]/es_extended/fxmanifest.lua | 2 +- [esx]/es_extended/version.json | 4 +- [esx]/esx_identity/fxmanifest.lua | 2 +- [esx]/esx_menu_default/fxmanifest.lua | 2 +- [esx]/esx_menu_dialog/fxmanifest.lua | 2 +- [esx]/esx_menu_list/fxmanifest.lua | 2 +- [esx]/esx_multicharacter/LICENSE.md | 674 ------------------ [esx]/esx_multicharacter/client/main.lua | 335 --------- [esx]/esx_multicharacter/config.lua | 129 ---- .../esx_multicharacter/esx_multicharacter.sql | 9 - [esx]/esx_multicharacter/fxmanifest.lua | 39 - [esx]/esx_multicharacter/html/css/main.css | 70 -- [esx]/esx_multicharacter/html/js/app.js | 35 - [esx]/esx_multicharacter/html/locales/cs.js | 8 - [esx]/esx_multicharacter/html/locales/de.js | 8 - [esx]/esx_multicharacter/html/locales/en.js | 8 - [esx]/esx_multicharacter/html/locales/fr.js | 8 - [esx]/esx_multicharacter/html/locales/pl.js | 8 - [esx]/esx_multicharacter/html/locales/pt.js | 8 - [esx]/esx_multicharacter/html/locales/tr.js | 8 - [esx]/esx_multicharacter/html/ui.html | 24 - [esx]/esx_multicharacter/locales/cs.lua | 25 - [esx]/esx_multicharacter/locales/de.lua | 11 - [esx]/esx_multicharacter/locales/en.lua | 25 - [esx]/esx_multicharacter/locales/it.lua | 25 - [esx]/esx_multicharacter/locales/pt.lua | 11 - [esx]/esx_multicharacter/locales/tr.lua | 11 - [esx]/esx_multicharacter/readme.md | 59 -- [esx]/esx_multicharacter/server/commands.lua | 79 -- [esx]/esx_multicharacter/server/main.lua | 221 ------ [esx]/esx_skin/fxmanifest.lua | 2 +- [esx_addons]/esx_accessories/fxmanifest.lua | 2 +- [esx_addons]/esx_addonaccount/fxmanifest.lua | 2 +- .../esx_addoninventory/fxmanifest.lua | 2 +- [esx_addons]/esx_ambulancejob/fxmanifest.lua | 4 +- [esx_addons]/esx_animations/fxmanifest.lua | 2 +- [esx_addons]/esx_atm/fxmanifest.lua | 2 +- [esx_addons]/esx_bankerjob/fxmanifest.lua | 2 +- [esx_addons]/esx_barbershop/fxmanifest.lua | 2 +- [esx_addons]/esx_basicneeds/fxmanifest.lua | 2 +- [esx_addons]/esx_billing/fxmanifest.lua | 2 +- [esx_addons]/esx_boat/fxmanifest.lua | 2 +- [esx_addons]/esx_clotheshop/fxmanifest.lua | 2 +- [esx_addons]/esx_cruisecontrol/fxmanifest.lua | 2 +- [esx_addons]/esx_datastore/fxmanifest.lua | 2 +- [esx_addons]/esx_dmvschool/fxmanifest.lua | 2 +- [esx_addons]/esx_drugs/fxmanifest.lua | 2 +- [esx_addons]/esx_garage/fxmanifest.lua | 2 +- [esx_addons]/esx_holdup/fxmanifest.lua | 2 +- [esx_addons]/esx_joblisting/fxmanifest.lua | 2 +- [esx_addons]/esx_jobs/fxmanifest.lua | 2 +- [esx_addons]/esx_license/fxmanifest.lua | 2 +- [esx_addons]/esx_lscustom/fxmanifest.lua | 2 +- [esx_addons]/esx_mechanicjob/fxmanifest.lua | 2 +- [esx_addons]/esx_optionalneeds/fxmanifest.lua | 2 +- [esx_addons]/esx_phone/fxmanifest.lua | 2 +- [esx_addons]/esx_policejob/fxmanifest.lua | 2 +- [esx_addons]/esx_property/fxmanifest.lua | 2 +- .../esx_realestateagentjob/fxmanifest.lua | 2 +- [esx_addons]/esx_rpchat/fxmanifest.lua | 2 +- [esx_addons]/esx_service/fxmanifest.lua | 2 +- [esx_addons]/esx_shops/fxmanifest.lua | 2 +- [esx_addons]/esx_sit/fxmanifest.lua | 2 +- [esx_addons]/esx_society/fxmanifest.lua | 2 +- [esx_addons]/esx_status/fxmanifest.lua | 2 +- [esx_addons]/esx_taxijob/fxmanifest.lua | 2 +- [esx_addons]/esx_vehicleshop/fxmanifest.lua | 2 +- [esx_addons]/esx_voice/fxmanifest.lua | 2 +- [esx_addons]/esx_weaponshop/fxmanifest.lua | 2 +- [esx_addons]/esx_whitelist/fxmanifest.lua | 2 +- [esx_addons]/instance/fxmanifest.lua | 2 +- 73 files changed, 50 insertions(+), 1902 deletions(-) delete mode 100644 [esx]/esx_multicharacter/LICENSE.md delete mode 100644 [esx]/esx_multicharacter/client/main.lua delete mode 100644 [esx]/esx_multicharacter/config.lua delete mode 100644 [esx]/esx_multicharacter/esx_multicharacter.sql delete mode 100644 [esx]/esx_multicharacter/fxmanifest.lua delete mode 100644 [esx]/esx_multicharacter/html/css/main.css delete mode 100644 [esx]/esx_multicharacter/html/js/app.js delete mode 100644 [esx]/esx_multicharacter/html/locales/cs.js delete mode 100644 [esx]/esx_multicharacter/html/locales/de.js delete mode 100644 [esx]/esx_multicharacter/html/locales/en.js delete mode 100644 [esx]/esx_multicharacter/html/locales/fr.js delete mode 100644 [esx]/esx_multicharacter/html/locales/pl.js delete mode 100644 [esx]/esx_multicharacter/html/locales/pt.js delete mode 100644 [esx]/esx_multicharacter/html/locales/tr.js delete mode 100644 [esx]/esx_multicharacter/html/ui.html delete mode 100644 [esx]/esx_multicharacter/locales/cs.lua delete mode 100644 [esx]/esx_multicharacter/locales/de.lua delete mode 100644 [esx]/esx_multicharacter/locales/en.lua delete mode 100644 [esx]/esx_multicharacter/locales/it.lua delete mode 100644 [esx]/esx_multicharacter/locales/pt.lua delete mode 100644 [esx]/esx_multicharacter/locales/tr.lua delete mode 100644 [esx]/esx_multicharacter/readme.md delete mode 100644 [esx]/esx_multicharacter/server/commands.lua delete mode 100644 [esx]/esx_multicharacter/server/main.lua diff --git a/[SQL]/legacy.sql b/[SQL]/legacy.sql index f59c0ee1..ae6c1840 100644 --- a/[SQL]/legacy.sql +++ b/[SQL]/legacy.sql @@ -112,19 +112,6 @@ CREATE TABLE `cardealer_vehicles` ( -- -------------------------------------------------------- --- --- Table structure for table `multicharacter_slots` --- - -CREATE TABLE `multicharacter_slots` ( - `identifier` VARCHAR(60) NOT NULL, - `slots` INT(11) NOT NULL, - PRIMARY KEY (`identifier`) USING BTREE, - INDEX `slots` (`slots`) USING BTREE -) ENGINE=InnoDB; - --- -------------------------------------------------------- - -- -- Table structure for table `datastore` -- @@ -514,7 +501,6 @@ CREATE TABLE `users` ( `status` longtext DEFAULT NULL, `is_dead` tinyint(1) DEFAULT 0, `id` int(11) NOT NULL, - `disabled` TINYINT(1) NULL DEFAULT '0', `last_property` varchar(255) DEFAULT NULL ) ENGINE=InnoDB; diff --git a/[esx]/es_extended/config.lua b/[esx]/es_extended/config.lua index d18705bd..6d9f4203 100644 --- a/[esx]/es_extended/config.lua +++ b/[esx]/es_extended/config.lua @@ -18,5 +18,5 @@ Config.EnableDefaultInventory = true -- Display the default Inventory ( F2 ) Config.EnableWantedLevel = false -- Use Normal GTA wanted Level? Config.EnablePVP = true -- Allow Player to player combat -Config.Multichar = true -- Enable support for esx_multicharacter +Config.Multichar = false -- Enable support for esx_multicharacter Config.Identity = true -- Select a characters identity data before they have loaded in (this happens by default with multichar) diff --git a/[esx]/es_extended/fxmanifest.lua b/[esx]/es_extended/fxmanifest.lua index 5fdb4c7b..d25a3e5e 100644 --- a/[esx]/es_extended/fxmanifest.lua +++ b/[esx]/es_extended/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ES Extended' -version '1.6.5' +version '1.6.0' shared_scripts { 'locale.lua', diff --git a/[esx]/es_extended/version.json b/[esx]/es_extended/version.json index 147774cd..9f3db69d 100644 --- a/[esx]/es_extended/version.json +++ b/[esx]/es_extended/version.json @@ -1,5 +1,5 @@ { "version": "legacy", - "commit" : "1.6.5", - "changelog": "\n- Added Official Multicharacter" + "commit" : "1.4.2", + "changelog": "\n- Updated `Car` Command. Fixed some vulnerabilities. Fix SQL. Updated Commands." } diff --git a/[esx]/esx_identity/fxmanifest.lua b/[esx]/esx_identity/fxmanifest.lua index 79254f5e..1c4e4baf 100644 --- a/[esx]/esx_identity/fxmanifest.lua +++ b/[esx]/esx_identity/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Identity' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx]/esx_menu_default/fxmanifest.lua b/[esx]/esx_menu_default/fxmanifest.lua index 7139cca2..64a36d7f 100644 --- a/[esx]/esx_menu_default/fxmanifest.lua +++ b/[esx]/esx_menu_default/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Menu Default' -version '1.6.5' +version '1.6.0' client_scripts { '@es_extended/imports.lua', diff --git a/[esx]/esx_menu_dialog/fxmanifest.lua b/[esx]/esx_menu_dialog/fxmanifest.lua index 3a84362b..1959b086 100644 --- a/[esx]/esx_menu_dialog/fxmanifest.lua +++ b/[esx]/esx_menu_dialog/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Menu Dialog' -version '1.6.5' +version '1.6.0' client_scripts { '@es_extended/imports.lua', diff --git a/[esx]/esx_menu_list/fxmanifest.lua b/[esx]/esx_menu_list/fxmanifest.lua index f267511a..b980e57e 100644 --- a/[esx]/esx_menu_list/fxmanifest.lua +++ b/[esx]/esx_menu_list/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Menu List' -version '1.6.5' +version '1.6.0' client_scripts { '@es_extended/imports.lua', diff --git a/[esx]/esx_multicharacter/LICENSE.md b/[esx]/esx_multicharacter/LICENSE.md deleted file mode 100644 index f288702d..00000000 --- a/[esx]/esx_multicharacter/LICENSE.md +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/[esx]/esx_multicharacter/client/main.lua b/[esx]/esx_multicharacter/client/main.lua deleted file mode 100644 index cb10ca8f..00000000 --- a/[esx]/esx_multicharacter/client/main.lua +++ /dev/null @@ -1,335 +0,0 @@ -ESX = exports['es_extended']:getSharedObject() -if ESX.GetConfig().Multichar then - - Citizen.CreateThread(function() - while not ESX.PlayerLoaded do - Citizen.Wait(0) - if NetworkIsPlayerActive(PlayerId()) then - exports.spawnmanager:setAutoSpawn(false) - DoScreenFadeOut(0) - while not GetResourceState('esx_menu_default') == 'started' do - Citizen.Wait(0) - end - TriggerEvent("esx_multicharacter:SetupCharacters") - break - end - end - end) - - local canRelog, cam, spawned = true, nil, nil - local Characters = {} - - RegisterNetEvent('esx_multicharacter:SetupCharacters') - AddEventHandler('esx_multicharacter:SetupCharacters', function() - ESX.PlayerLoaded = false - ESX.PlayerData = {} - spawned = false - cam = CreateCam("DEFAULT_SCRIPTED_CAMERA", true) - local playerPed = PlayerPedId() - SetEntityCoords(playerPed, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z, true, false, false, false) - SetEntityHeading(playerPed, Config.Spawn.w) - local offset = GetOffsetFromEntityInWorldCoords(playerPed, 0, 1.7, 0.4) - DoScreenFadeOut(0) - SetCamActive(cam, true) - RenderScriptCams(true, false, 1, true, true) - SetCamCoord(cam, offset.x, offset.y, offset.z) - PointCamAtCoord(cam, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z + 1.3) - ESX.UI.Menu.CloseAll() - ESX.UI.HUD.SetDisplay(0.0) - StartLoop() - ShutdownLoadingScreen() - ShutdownLoadingScreenNui() - TriggerEvent('esx:loadingScreenOff') - Citizen.Wait(200) - TriggerServerEvent("esx_multicharacter:SetupCharacters") - end) - - StartLoop = function() - hidePlayers = true - MumbleSetVolumeOverride(PlayerId(), 0.0) - Citizen.CreateThread(function() - local keys = {18, 27, 172, 173, 174, 175, 176, 177, 187, 188, 191, 201, 108, 109} - while hidePlayers do - DisableAllControlActions(0) - for i = 1, #keys do - EnableControlAction(0, keys[i], true) - end - SetEntityVisible(PlayerPedId(), 0, 0) - SetLocalPlayerVisibleLocally(1) - SetPlayerInvincible(PlayerId(), 1) - ThefeedHideThisFrame() - HideHudComponentThisFrame(11) - HideHudComponentThisFrame(12) - HideHudComponentThisFrame(21) - HideHudAndRadarThisFrame() - Citizen.Wait(0) - local vehicles = GetGamePool('CVehicle') - for i = 1, #vehicles do - SetEntityLocallyInvisible(vehicles[i]) - end - end - local playerId, playerPed = PlayerId(), PlayerPedId() - MumbleSetVolumeOverride(playerId, -1.0) - SetEntityVisible(playerPed, 1, 0) - SetPlayerInvincible(playerId, 0) - FreezeEntityPosition(playerPed, false) - Citizen.Wait(10000) - canRelog = true - end) - Citizen.CreateThread(function() - local playerPool = {} - while hidePlayers do - local players = GetActivePlayers() - for i = 1, #players do - local player = players[i] - if player ~= PlayerId() and not playerPool[player] then - playerPool[player] = true - NetworkConcealPlayer(player, true, true) - end - end - Citizen.Wait(500) - end - for k in pairs(playerPool) do - NetworkConcealPlayer(k, false, false) - end - end) - end - - SetupCharacter = function(index) - if spawned == false then - exports.spawnmanager:spawnPlayer({ - x = Config.Spawn.x, - y = Config.Spawn.y, - z = Config.Spawn.z, - heading = Config.Spawn.w, - model = Characters[index].model or `mp_m_freemode_01`, - skipFade = true - }, function() - canRelog = false - if Characters[index] then - local skin = Characters[index].skin or Config.Default - if not Characters[index].model then - if Characters[index].sex == _('female') then skin.sex = 1 else skin.sex = 0 end - end - TriggerEvent('skinchanger:loadSkin', skin) - end - DoScreenFadeIn(400) - end) - repeat Citizen.Wait(200) until not IsScreenFadedOut() - - elseif Characters[index] and Characters[index].skin then - if Characters[spawned] and Characters[spawned].model then - RequestModel(Characters[index].model) - while not HasModelLoaded(Characters[index].model) do - RequestModel(Characters[index].model) - Citizen.Wait(0) - end - SetPlayerModel(PlayerId(), Characters[index].model) - SetModelAsNoLongerNeeded(Characters[index].model) - end - TriggerEvent('skinchanger:loadSkin', Characters[index].skin) - end - spawned = index - local playerPed = PlayerPedId() - FreezeEntityPosition(PlayerPedId(), true) - SetPedAoBlobRendering(playerPed, true) - SetEntityAlpha(playerPed, 255) - SendNUIMessage({ - action = "openui", - character = Characters[spawned] - }) - end - - RegisterNetEvent('esx_multicharacter:SetupUI') - AddEventHandler('esx_multicharacter:SetupUI', function(data, slots) - DoScreenFadeOut(0) - Characters = data - slots = slots - local elements = {} - local Character = next(Characters) - exports.spawnmanager:forceRespawn() - - if Character == nil then - SendNUIMessage({ - action = "closeui" - }) - exports.spawnmanager:spawnPlayer({ - x = Config.Spawn.x, - y = Config.Spawn.y, - z = Config.Spawn.z, - heading = Config.Spawn.w, - model = `mp_m_freemode_01`, - skipFade = true - }, function() - canRelog = false - DoScreenFadeIn(400) - Citizen.Wait(400) - local playerPed = PlayerPedId() - SetPedAoBlobRendering(playerPed, false) - SetEntityAlpha(playerPed, 0) - TriggerServerEvent('esx_multicharacter:CharacterChosen', 1, true) - TriggerEvent('esx_identity:showRegisterIdentity') - end) - else - for k,v in pairs(Characters) do - if not v.model and v.skin then - if v.skin.model then v.model = v.skin.model elseif v.skin.sex == 1 then v.model = `mp_f_freemode_01` else v.model = `mp_m_freemode_01` end - end - if spawned == false then SetupCharacter(Character) end - local label = v.firstname..' '..v.lastname - if Characters[k].disabled then - elements[#elements+1] = {label = label, value = v.id} - else - elements[#elements+1] = {label = label, value = v.id} - end - end - if #elements < slots then - elements[#elements+1] = {label = _('create_char'), value = (#elements+1), new = true} - end - ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'selectchar', { - title = _('select_char'), - align = 'top-left', - elements = elements - }, function(data, menu) - local elements = {} - if not data.current.new then - if not Characters[data.current.value].disabled then - elements[1] = {label = _('char_play'), action = 'play', value = data.current.value} - else - elements[1] = {label = _('char_disabled'), value = data.current.value} - end - if Config.CanDelete then elements[2] = {label = _('char_delete'), action = 'delete', value = data.current.value} end - ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'choosechar', { - title = _('select_char'), - align = 'top-left', - elements = elements - }, function(data, menu) - if data.current.action == 'play' then - ESX.UI.Menu.CloseAll() - SendNUIMessage({ - action = "closeui" - }) - TriggerServerEvent('esx_multicharacter:CharacterChosen', data.current.value, false) - elseif data.current.action == 'delete' then - local elements2 = {} - elements2[1] = {label = _('cancel')} - elements2[2] = {label = _('confirm'), value = data.current.value} - ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'deletechar', { - title = _('delete_label', Characters[data.current.value].firstname, Characters[data.current.value].lastname), - align = 'center', - elements = elements2 - }, function(data, menu) - if data.current.value then - TriggerServerEvent('esx_multicharacter:DeleteCharacter', data.current.value) - spawned = false - ESX.UI.Menu.CloseAll() - else - menu.close() - end - end, function(data, menu) - menu.close() - end) - end - end, function(data, menu) - menu.close() - end) - else - ESX.UI.Menu.CloseAll() - local GetSlot = function() - for i = 1, slots do - if not Characters[i] then - return i - end - end - end - local slot = GetSlot() - TriggerServerEvent('esx_multicharacter:CharacterChosen', slot, true) - TriggerEvent('esx_identity:showRegisterIdentity') - end - end, function(data, menu) - menu.refresh() - end, function(data, menu) - if data.current.new then - local playerPed = PlayerPedId() - SetPedAoBlobRendering(playerPed, false) - SetEntityAlpha(playerPed, 0) - SendNUIMessage({ - action = "closeui" - }) - else - SetupCharacter(data.current.value) - local playerPed = PlayerPedId() - SetPedAoBlobRendering(playerPed, true) - ResetEntityAlpha(playerPed) - end - end) - end - end) - - RegisterNetEvent('esx:playerLoaded') - AddEventHandler('esx:playerLoaded', function(playerData, isNew, skin) - local spawn = playerData.coords or Config.Spawn - if isNew or not skin or #skin == 1 then - local finished = false - local sex = skin.sex or 0 - if sex == 0 then model = `mp_m_freemode_01` else model = `mp_f_freemode_01` end - RequestModel(model) - while not HasModelLoaded(model) do - RequestModel(model) - Citizen.Wait(0) - end - SetPlayerModel(PlayerId(), model) - SetModelAsNoLongerNeeded(model) - skin = Config.Default - skin.sex = sex - TriggerEvent('skinchanger:loadSkin', skin, function() - playerPed = PlayerPedId() - SetPedAoBlobRendering(playerPed, true) - ResetEntityAlpha(playerPed) - TriggerEvent('esx_skin:openSaveableMenu', function() - finished = true end, function() finished = true - end) - end) - repeat Citizen.Wait(200) until finished - end - DoScreenFadeOut(100) - - SetCamActive(cam, false) - RenderScriptCams(false, false, 0, true, true) - cam = nil - local playerPed = PlayerPedId() - FreezeEntityPosition(playerPed, true) - SetEntityCoordsNoOffset(playerPed, spawn.x, spawn.y, spawn.z, false, false, false, true) - SetEntityHeading(playerPed, spawn.heading) - if not isNew then TriggerEvent('skinchanger:loadSkin', skin or Characters[spawned].skin) end - Citizen.Wait(400) - DoScreenFadeIn(400) - repeat Citizen.Wait(200) until not IsScreenFadedOut() - TriggerServerEvent('esx:onPlayerSpawn') - TriggerEvent('esx:onPlayerSpawn') - TriggerEvent('playerSpawned') - TriggerEvent('esx:restoreLoadout') - Characters, hidePlayers = {}, false - end) - - RegisterNetEvent('esx:onPlayerLogout') - AddEventHandler('esx:onPlayerLogout', function() - DoScreenFadeOut(0) - spawned = false - TriggerEvent("esx_multicharacter:SetupCharacters") - TriggerEvent('esx_skin:resetFirstSpawn') - end) - - if Config.Relog then - RegisterCommand('relog', function(source, args, rawCommand) - if canRelog == true then - canRelog = false - TriggerServerEvent('esx_multicharacter:relog') - ESX.SetTimeout(10000, function() - canRelog = true - end) - end - end) - end - -end diff --git a/[esx]/esx_multicharacter/config.lua b/[esx]/esx_multicharacter/config.lua deleted file mode 100644 index fe18b776..00000000 --- a/[esx]/esx_multicharacter/config.lua +++ /dev/null @@ -1,129 +0,0 @@ -Config = {} -Config.Locale = 'en' - --- Allows players to delete their characters -Config.CanDelete = true - -if IsDuplicityVersion() then - -- This is the default number of slots for EVERY player - -- If you want to manage extra slots for specific players you can do it by using '/setslots' and '/remslots' commands - Config.Slots = 4 - -------------------- - - -- Text to prepend to each character (char#:identifier) - keep it short - Config.Prefix = 'char' - -------------------- - - -- Default identifier to store for characters - this should always match es_extended (recommended: license) - Config.Identifier = 'license' - -else - -- Sets the location for the character selection scene - -- To set the spawn location for new characters, modify the default value in the `users` SQL table - Config.Spawn = vector4(-113.7, 565.3, 195.2, 0) - -------------------- - - -- Do not use unless you are prepared to adjust your resources to correctly reset data - -- Information: https://github.com/thelindat/esx_multicharacter#relogging - Config.Relog = true - -------------------- - - -- Default appearance for new characters - Config.Default = { - mom = 21, - dad = 0, - face_md_weight = 50, - skin_md_weight = 50, - nose_1 = 0, - nose_2 = 0, - nose_3 = 0, - nose_4 = 0, - nose_5 = 0, - nose_6 = 0, - cheeks_1 = 0, - cheeks_2 = 0, - cheeks_3 = 0, - lip_thickness = 0, - jaw_1 = 0, - jaw_2 = 0, - chin_1 = 0, - chin_2 = 0, - chin_13 = 0, - chin_4 = 0, - neck_thickness = 0, - hair_1 = 0, - hair_2 = 0, - hair_color_1 = 0, - hair_color_2 = 0, - tshirt_1 = 0, - tshirt_2 = 0, - torso_1 = 0, - torso_2 = 0, - decals_1 = 0, - decals_2 = 0, - arms = 0, - arms_2 = 0, - pants_1 = 0, - pants_2 = 0, - shoes_1 = 0, - shoes_2 = 0, - mask_1 = 0, - mask_2 = 0, - bproof_1 = 0, - bproof_2 = 0, - chain_1 = 0, - chain_2 = 0, - helmet_1 = -1, - helmet_2 = 0, - glasses_1 = 0, - glasses_2 = 0, - watches_1 = -1, - watches_2 = 0, - bracelets_1 = -1, - bracelets_2 = 0, - bags_1 = 0, - bags_2 = 0, - eye_color = 0, - eye_squint = 0, - eyebrows_2 = 0, - eyebrows_1 = 0, - eyebrows_3 = 0, - eyebrows_4 = 0, - eyebrows_5 = 0, - eyebrows_6 = 0, - makeup_1 = 0, - makeup_2 = 0, - makeup_3 = 0, - makeup_4 = 0, - lipstick_1 = 0, - lipstick_2 = 0, - lipstick_3 = 0, - lipstick_4 = 0, - ears_1 = -1, - ears_2 = 0, - chest_1 = 0, - chest_2 = 0, - chest_3 = 0, - bodyb_1 = -1, - bodyb_2 = 0, - bodyb_3 = -1, - bodyb_4 = 0, - age_1 = 0, - age_2 = 0, - blemishes_1 = 0, - blemishes_2 = 0, - blush_1 = 0, - blush_2 = 0, - blush_3 = 0, - complexion_1 = 0, - complexion_2 = 0, - sun_1 = 0, - sun_2 = 0, - moles_1 = 0, - moles_2 = 0, - beard_1 = 0, - beard_2 = 0, - beard_3 = 0, - beard_4 = 0 - } -end \ No newline at end of file diff --git a/[esx]/esx_multicharacter/esx_multicharacter.sql b/[esx]/esx_multicharacter/esx_multicharacter.sql deleted file mode 100644 index f19f7610..00000000 --- a/[esx]/esx_multicharacter/esx_multicharacter.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE `multicharacter_slots` ( - `identifier` VARCHAR(60) NOT NULL, - `slots` INT(11) NOT NULL, - PRIMARY KEY (`identifier`) USING BTREE, - INDEX `slots` (`slots`) USING BTREE -) ENGINE=InnoDB; - -ALTER TABLE `users` ADD COLUMN - `disabled` TINYINT(1) NULL DEFAULT '0'; diff --git a/[esx]/esx_multicharacter/fxmanifest.lua b/[esx]/esx_multicharacter/fxmanifest.lua deleted file mode 100644 index 435f6ba3..00000000 --- a/[esx]/esx_multicharacter/fxmanifest.lua +++ /dev/null @@ -1,39 +0,0 @@ -fx_version 'cerulean' -game 'gta5' -description 'Official Multicharacter System For ESX Legacy' -version '1.6.5' -lua54 'yes' - -dependencies { - 'es_extended', - 'esx_menu_default', - 'esx_identity', - 'esx_skin' -} - -shared_scripts { - '@es_extended/locale.lua', - 'locales/*.lua', - 'config.lua' -} - -server_scripts { - '@es_extended/imports.lua', - '@oxmysql/lib/MySQL.lua', - 'server/*.lua', -} - -client_scripts { - 'client/*.lua' -} - -ui_page { - 'html/ui.html', -} - -files { - 'html/ui.html', - 'html/css/main.css', - 'html/js/app.js', - 'html/locales/*.js', -} diff --git a/[esx]/esx_multicharacter/html/css/main.css b/[esx]/esx_multicharacter/html/css/main.css deleted file mode 100644 index 15fb9bc5..00000000 --- a/[esx]/esx_multicharacter/html/css/main.css +++ /dev/null @@ -1,70 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@300;600&display=swap'); -* { - margin: 0; - padding: 0; - user-select: none; - color: rgb(255, 255, 255); - font-weight: 300; - font-size: 1.6vh; - font-family: Calibri, "Helvetica", san-serif; -} - -html { - overflow: hidden; -} - -p { - margin: 0 !important; -} - -body { - background: transparent; -} - -.main-container { - display:none; - position: absolute; - top: 50%; - right: 25; - transform: translate(0, -50%); - background: rgba(0,0,0,0.7); -} - -.header { - position: absolute; - top: 5%; - left: 50%; - transform: translate(-50%); - font-size: 1.1rem; -} - -.footer { - position: absolute; - bottom: 5%; - left: 50%; - transform: translate(-50%); - font-size: 1.1rem; -} - -.character-box { - display: flex; - right: 0; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; - line-height: 1.4rem; - height: calc(100vh - 6rem); - width: 20rem; - padding: 1rem; - border: 1px rgba(12,12,12,200) solid; - box-shadow: 0px 0px 4px 1px rgba(12,12,12,20); -} - -h1 { - font-family: 'Raleway', sans-serif; - padding-top: 2rem; - display: block; - font-size: 1.3rem; - font-weight: 600; -} diff --git a/[esx]/esx_multicharacter/html/js/app.js b/[esx]/esx_multicharacter/html/js/app.js deleted file mode 100644 index 22b5c92c..00000000 --- a/[esx]/esx_multicharacter/html/js/app.js +++ /dev/null @@ -1,35 +0,0 @@ -var money = Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 0 -}); - -(() => { - Kashacter = {}; - - Kashacter.ShowUI = function(data) { - $('body').css({"display":"block"}); - $('.main-container').css({"display":"block"}); - $('[data-charid=1]').html('

' + `${translate.name} ` + '

' + data.firstname +' '+ data.lastname +'

' + `${translate.job} ` + '

'+ data.job +' '+ data.job_grade +'

' + `${translate.money} ` + '

'+ money.format(data.money) +'

' + `${translate.bank} ` + '

'+ money.format(data.bank) +'

' + `${translate.dob} ` + '

'+ data.dateofbirth +'

' + `${translate.gender} ` + '

'+ data.sex +'

').attr("data-ischar", "true"); - }; - - Kashacter.CloseUI = function() { - $('body').css({"display":"none"}); - $('.main-container').css({"display":"none"}); - $('[data-charid=1]').html('

'); - }; - - window.onload = function(e) { - window.addEventListener('message', function(event) { - switch(event.data.action) { - case 'openui': - Kashacter.ShowUI(event.data.character); - break; - case 'closeui': - Kashacter.CloseUI(); - break; - } - }) - } - -})(); diff --git a/[esx]/esx_multicharacter/html/locales/cs.js b/[esx]/esx_multicharacter/html/locales/cs.js deleted file mode 100644 index cc84dedc..00000000 --- a/[esx]/esx_multicharacter/html/locales/cs.js +++ /dev/null @@ -1,8 +0,0 @@ -const translate = new Object(); - -translate.name = "Jméno"; -translate.job = "Práce"; -translate.bank = "Banka"; -translate.money = "Peníze"; -translate.gender = "Pohlaví"; -translate.dob = "Datum narození"; diff --git a/[esx]/esx_multicharacter/html/locales/de.js b/[esx]/esx_multicharacter/html/locales/de.js deleted file mode 100644 index efd17188..00000000 --- a/[esx]/esx_multicharacter/html/locales/de.js +++ /dev/null @@ -1,8 +0,0 @@ -const translate = new Object(); - -translate.name = "Name"; -translate.job = "Beruf"; -translate.bank = "Bankguthaben"; -translate.money = "Bargeld"; -translate.gender = "Geschlecht"; -translate.dob = "Geburtsdatum"; diff --git a/[esx]/esx_multicharacter/html/locales/en.js b/[esx]/esx_multicharacter/html/locales/en.js deleted file mode 100644 index 125dd3f0..00000000 --- a/[esx]/esx_multicharacter/html/locales/en.js +++ /dev/null @@ -1,8 +0,0 @@ -const translate = new Object(); - -translate.name = "Name"; -translate.job = "Job"; -translate.bank = "Bank"; -translate.money = "Cash"; -translate.gender = "Gender"; -translate.dob = "Date of birth"; diff --git a/[esx]/esx_multicharacter/html/locales/fr.js b/[esx]/esx_multicharacter/html/locales/fr.js deleted file mode 100644 index 597a217d..00000000 --- a/[esx]/esx_multicharacter/html/locales/fr.js +++ /dev/null @@ -1,8 +0,0 @@ -const translate = new Object(); - -translate.name = "Nom"; -translate.job = "Métier"; -translate.bank = "Banque"; -translate.money = "Argent"; -translate.gender = "Sexe"; -translate.dob = "Date de naissance"; diff --git a/[esx]/esx_multicharacter/html/locales/pl.js b/[esx]/esx_multicharacter/html/locales/pl.js deleted file mode 100644 index 07b27356..00000000 --- a/[esx]/esx_multicharacter/html/locales/pl.js +++ /dev/null @@ -1,8 +0,0 @@ -const translate = new Object(); - -translate.name = "imię"; -translate.job = "Zajęcie"; -translate.bank = "Bank"; -translate.money = "Gotówka"; -translate.gender = "Seks"; -translate.dob = "Data urodzenia"; diff --git a/[esx]/esx_multicharacter/html/locales/pt.js b/[esx]/esx_multicharacter/html/locales/pt.js deleted file mode 100644 index c8eca4f8..00000000 --- a/[esx]/esx_multicharacter/html/locales/pt.js +++ /dev/null @@ -1,8 +0,0 @@ -const translate = new Object(); - -translate.name = "Nome"; -translate.job = "Trabalho"; -translate.bank = "Banco"; -translate.money = "Dinheiro"; -translate.gender = "Género"; -translate.dob = "Data de Nascimento"; diff --git a/[esx]/esx_multicharacter/html/locales/tr.js b/[esx]/esx_multicharacter/html/locales/tr.js deleted file mode 100644 index ab820732..00000000 --- a/[esx]/esx_multicharacter/html/locales/tr.js +++ /dev/null @@ -1,8 +0,0 @@ -const translate = new Object(); - -translate.name = "İsim"; -translate.job = "Meslek"; -translate.bank = "Banka"; -translate.money = "Nakit"; -translate.gender = "Cinsiyet"; -translate.dob = "Doğum Tarihi"; diff --git a/[esx]/esx_multicharacter/html/ui.html b/[esx]/esx_multicharacter/html/ui.html deleted file mode 100644 index 7b59ac89..00000000 --- a/[esx]/esx_multicharacter/html/ui.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - -
-
ESX Legacy
-
-

-
-
- -
- - - - - - \ No newline at end of file diff --git a/[esx]/esx_multicharacter/locales/cs.lua b/[esx]/esx_multicharacter/locales/cs.lua deleted file mode 100644 index d309e309..00000000 --- a/[esx]/esx_multicharacter/locales/cs.lua +++ /dev/null @@ -1,25 +0,0 @@ -Locales['cs'] = { - ['male'] = "Muž", - ['female'] = "Žena", - ['delete_label'] = "Vymazat %s %s?", - ['select_char'] = "Zvolit Postavu", - ['create_char'] = "Vytvořit Novou Postavu", - ['char_play'] = "Hrát za postavu", - ['char_disabled'] = "Tato postava je zakázána!", - ['char_delete'] = "Vymazat postavu", - ['cancel'] = "Zrušit", - ['confirm'] = "Potvrdit", - ['command_setslots'] = "Nastavit slot pro hráče v multicharacteru", - ['command_remslots'] = "Odebrat slot pro hráče v multicharacteru", - ['command_enablechar'] = "Povolit zovlený slot hráči", - ['command_disablechar'] = "Zakázat zvolený slot pro hračé", - ['command_charslot'] = "Číslo slotu", - ['command_identifier'] = "Identifier hráče", - ['command_slots'] = "# ze slotu", - ['slotsadd'] = "Přidal slot %s hráči %s", - ['slotsedit'] = "Nastavil si slot %s hráči %s", - ['slotsrem'] = "Odebral si slot %s", - ['charenabled'] = "Povolol si postavu #%s z %s", - ['chardisabled'] = "Zakázal si postavu #%s z %s", - ['charnotfound'] = "Postava #%s z %s nebyla nalezena/neexistuje", -} diff --git a/[esx]/esx_multicharacter/locales/de.lua b/[esx]/esx_multicharacter/locales/de.lua deleted file mode 100644 index 654971af..00000000 --- a/[esx]/esx_multicharacter/locales/de.lua +++ /dev/null @@ -1,11 +0,0 @@ -Locales['de'] = { - ['male'] = "Männlich", - ['female'] = "Weiblich", - ['delete_label'] = "Lösche %s %s?", - ['select_char'] = "Charakter auswählen", - ['create_char'] = "Neuen Charakter erstellen", - ['char_play'] = "Diesen Charakter spielen", - ['char_delete'] = "Diesen Charakter löschen", - ['cancel'] = "Abbrechen", - ['confirm'] = "Bestätigen", -} diff --git a/[esx]/esx_multicharacter/locales/en.lua b/[esx]/esx_multicharacter/locales/en.lua deleted file mode 100644 index b71de307..00000000 --- a/[esx]/esx_multicharacter/locales/en.lua +++ /dev/null @@ -1,25 +0,0 @@ -Locales['en'] = { - ['male'] = "Male", - ['female'] = "Female", - ['delete_label'] = "Delete %s %s?", - ['select_char'] = "Select Character", - ['create_char'] = "Create new character", - ['char_play'] = "Play this character", - ['char_disabled'] = "This character is disabled", - ['char_delete'] = "Delete this character", - ['cancel'] = "Cancel", - ['confirm'] = "Confirm", - ['command_setslots'] = "Set multicharacter slots number of a player", - ['command_remslots'] = "Remove multicharacter slots number of a player", - ['command_enablechar'] = "Enable a given character of a player", - ['command_disablechar'] = "Disable a given character of a player", - ['command_charslot'] = "Slot number of the character", - ['command_identifier'] = "Player identifier", - ['command_slots'] = "# of slots", - ['slotsadd'] = "You added %s slots to %s", - ['slotsedit'] = "You set %s slots to %s", - ['slotsrem'] = "You removed slots to %s", - ['charenabled'] = "You enabled character #%s of %s", - ['chardisabled'] = "You disabled character #%s of %s", - ['charnotfound'] = "Character #%s of %s doesn't exist", -} diff --git a/[esx]/esx_multicharacter/locales/it.lua b/[esx]/esx_multicharacter/locales/it.lua deleted file mode 100644 index 1f2333e5..00000000 --- a/[esx]/esx_multicharacter/locales/it.lua +++ /dev/null @@ -1,25 +0,0 @@ -Locales['it'] = { - ['male'] = "Maschio", - ['female'] = "Femmina", - ['delete_label'] = "Cancella %s %s?", - ['select_char'] = "Seleziona Personaggio", - ['create_char'] = "Crea un nuovo personaggio", - ['char_play'] = "Gioca questo personaggio", - ['char_disabled'] = "Questo personaggio è disabilitato", - ['char_delete'] = "Cancella questo personaggio", - ['cancel'] = "Annulla", - ['confirm'] = "Conferma", - ['command_setslots'] = "Imposta il numero di slot di personaggi di un giocatore", - ['command_remslots'] = "Rimuovi il numero di slot di personaggi di un giocatore", - ['command_enablechar'] = "Abilita un personaggio di un giocatore", - ['command_disablechar'] = "Disabilita un personaggio di un giocatore", - ['command_charslot'] = "Numero dello slot del personaggio", - ['command_identifier'] = "Identifier del giocatore", - ['command_slots'] = "# di slot", - ['slotsadd'] = "Hai aggiunto %s slot a %s", - ['slotsedit'] = "Hai impostato %s slot a %s", - ['slotsrem'] = "Hai rimosso gli slot a %s", - ['charenabled'] = "Hai abilitato il %s° personaggio di %s", - ['chardisabled'] = "Hai disabilitato il %s° personaggio di %s", - ['charnotfound'] = "Il personaggio %s di %s non esiste", -} diff --git a/[esx]/esx_multicharacter/locales/pt.lua b/[esx]/esx_multicharacter/locales/pt.lua deleted file mode 100644 index 04b828a3..00000000 --- a/[esx]/esx_multicharacter/locales/pt.lua +++ /dev/null @@ -1,11 +0,0 @@ -Locales['pt'] = { - ['male'] = "Masculino", - ['female'] = "Feminino", - ['delete_label'] = "Eliminar %s %s?", - ['select_char'] = "Selecionar personagem", - ['create_char'] = "Criar novo personagem", - ['char_play'] = "Selecionar", - ['char_delete'] = "Eliminar personagem", - ['cancel'] = "Cancelar", - ['confirm'] = "Confirmar", -} diff --git a/[esx]/esx_multicharacter/locales/tr.lua b/[esx]/esx_multicharacter/locales/tr.lua deleted file mode 100644 index 8a3aa060..00000000 --- a/[esx]/esx_multicharacter/locales/tr.lua +++ /dev/null @@ -1,11 +0,0 @@ -Locales['tr'] = { - ['male'] = "Erkek", - ['female'] = "Kadın", - ['delete_label'] = "Sil %s %s?", - ['select_char'] = "Karakter Seç", - ['create_char'] = "Yeni Karakter Oluştur", - ['char_play'] = "Bu Karakterle Oyna", - ['char_delete'] = "Bu Karakteri Sil", - ['cancel'] = "İptal", - ['confirm'] = "Onayla", -} diff --git a/[esx]/esx_multicharacter/readme.md b/[esx]/esx_multicharacter/readme.md deleted file mode 100644 index f5879edc..00000000 --- a/[esx]/esx_multicharacter/readme.md +++ /dev/null @@ -1,59 +0,0 @@ - -# Preview - -![image](https://user-images.githubusercontent.com/65407488/126976325-17cc3241-bb9e-451f-a6ed-610a8ef52fa5.png) - -## Installation - -- Modify your ESX config with `Config.Multichar = true` -- All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry - - The resource will attempt to set columns automatically - -### Relogging - -- Do not enable this setting if you do not intend to properly set up relog support -- Requires the latest update for ESX Status (prevents multiple status ticks from running) -- Add the following events to resources that require support for relogging, or -- Add them to [@es_extended/imports.lua](https://github.com/esx-framework/esx-legacy/blob/main/[esx]/es_extended/imports.lua) (and use the imports in your resources) - -```lua -RegisterNetEvent('esx:playerLoaded', function(xPlayer) - ESX.PlayerData = xPlayer - ESX.PlayerLoaded = true -end) - -RegisterNetEvent('esx:onPlayerLogout', function() - ESX.PlayerLoaded = false - ESX.PlayerData = {} -end) -``` - -### Notes - -- Characters are stored in the users table as `char#:license` - if you need to use a different identifier then you need to modify ESX itself -- Character deletion does not require manual entries for the tables to remove -- As characters are stored with unique identifiers, there is no excessive queries being executed - -### Kashacters - -- This project is forked from the [kashacters multicharacter resource](https://github.com/FiveEYZ/esx_kashacter) -- Most of the code has been entirely rewritten -- KASH has given permission for this resource to use his code and the addition of a license -- The license obviously does not apply to previous versions and KASH has stated his resource is free to be used however - -## Notice - -Copyright © 2022 [Linden](https://github.com/thelindat/), ESX-Framework (fournier Brice & Jérémie N'gadi) and KASH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . diff --git a/[esx]/esx_multicharacter/server/commands.lua b/[esx]/esx_multicharacter/server/commands.lua deleted file mode 100644 index 3cfa98d5..00000000 --- a/[esx]/esx_multicharacter/server/commands.lua +++ /dev/null @@ -1,79 +0,0 @@ -ESX.RegisterCommand('setslots', 'admin', function(xPlayer, args, showError) - local slots = MySQL.scalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { - args.identifier - }) - - if slots == nil then - MySQL.update('INSERT INTO `multicharacter_slots` (`identifier`, `slots`) VALUES (?, ?)', { - args.identifier, - args.slots - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsadd', args.slots, args.identifier)) - else - MySQL.update('UPDATE `multicharacter_slots` SET `slots` = ? WHERE `identifier` = ?', { - args.slots, - args.identifier - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsedit', args.slots, args.identifier)) - end -end, true, {help = _U('command_setslots'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'}, - {name = 'slots', help = _U('command_slots'), type = 'number'} -}}) - -ESX.RegisterCommand('remslots', 'admin', function(xPlayer, args, showError) - local slots = MySQL.scalar('SELECT `slots` FROM `multicharacter_slots` WHERE identifier = ?', { - args.identifier - }) - - if slots ~= nil then - MySQL.update('DELETE FROM `multicharacter_slots` WHERE `identifier` = ?', { - args.identifier - }) - xPlayer.triggerEvent('esx:showNotification', _U('slotsrem', args.identifier)) - end -end, true, {help = _U('command_remslots'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'} -}}) - -ESX.RegisterCommand('enablechar', 'admin', function(xPlayer, args, showError) - - local selectedCharacter = 'char'..args.charslot..':'..args.identifier; - - MySQL.update('UPDATE `users` SET `disabled` = 0 WHERE identifier = ?', { - selectedCharacter - }, function(result) - if result > 0 then - xPlayer.triggerEvent('esx:showNotification', _U('charenabled', args.charslot, args.identifier)) - else - xPlayer.triggerEvent('esx:showNotification', _U('charnotfound', args.charslot, args.identifier)) - end - end) - -end, true, {help = _U('command_enablechar'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'}, - {name = 'charslot', help = _U('command_charslot'), type = 'number'} -}}) - -ESX.RegisterCommand('disablechar', 'admin', function(xPlayer, args, showError) - - local selectedCharacter = 'char'..args.charslot..':'..args.identifier; - - MySQL.update('UPDATE `users` SET `disabled` = 1 WHERE identifier = ?', { - selectedCharacter - }, function(result) - if result > 0 then - xPlayer.triggerEvent('esx:showNotification', _U('chardisabled', args.charslot, args.identifier)) - else - xPlayer.triggerEvent('esx:showNotification', _U('charnotfound', args.charslot, args.identifier)) - end - end) - -end, true, {help = _U('command_disablechar'), validate = true, arguments = { - {name = 'identifier', help = _U('command_identifier'), type = 'string'}, - {name = 'charslot', help = _U('command_charslot'), type = 'number'} -}}) - -RegisterCommand('forcelog', function(source, args, rawCommand) - TriggerEvent('esx:playerLogout', source) -end, true) diff --git a/[esx]/esx_multicharacter/server/main.lua b/[esx]/esx_multicharacter/server/main.lua deleted file mode 100644 index 266c560c..00000000 --- a/[esx]/esx_multicharacter/server/main.lua +++ /dev/null @@ -1,221 +0,0 @@ -if not ESX then - error('\n^1Unable to start Multicharacter - you must be using ESX Legacy^0') -elseif ESX.GetConfig().Multichar == true then - local DATABASE do - local connectionString = GetConvar('mysql_connection_string', ''); - if connectionString == '' then - error(connectionString..'\n^1Unable to start Multicharacter - unable to determine database from mysql_connection_string^0', 0) - elseif connectionString:find('mysql://') then - connectionString = connectionString:sub(9, -1) - DATABASE = connectionString:sub(connectionString:find('/')+1, -1):gsub('[%?]+[%w%p]*$', '') - else - connectionString = {string.strsplit(';', connectionString)} - for i = 1, #connectionString do - local v = connectionString[i] - if v:match('database') then - DATABASE = v:sub(10, #v) - end - end - end - end - - local DB_TABLES = {users = 'identifier'} - local FETCH = nil - local SLOTS = Config.Slots or 4 - local PREFIX = Config.Prefix or 'char' - local PRIMARY_IDENTIFIER = ESX.GetConfig().Identifier or GetConvar('sv_lan', '') == 'true' and 'ip' or Config.Identifier - - local function GetIdentifier(source) - local identifier = PRIMARY_IDENTIFIER..':' - for _, v in pairs(GetPlayerIdentifiers(source)) do - if string.match(v, identifier) then - identifier = string.gsub(v, identifier, '') - return identifier - end - end - end - - if next(ESX.Players) then - local players = table.clone(ESX.Players) - table.wipe(ESX.Players) - for _, v in pairs(players) do - ESX.Players[GetIdentifier(v.source)] = true - end - else ESX.Players = {} end - - local function SetupCharacters(source) - while not FETCH do Citizen.Wait(100) end - local identifier = GetIdentifier(source) - ESX.Players[identifier] = true - - local slots = MySQL.scalar.await('SELECT slots FROM multicharacter_slots WHERE identifier = ?', { identifier }) or SLOTS - identifier = PREFIX..'%:'..identifier - - local result = MySQL.query.await(FETCH, {identifier, slots}) - local characters - - if result then - local characterCount = #result - characters = table.create(0, characterCount) - - for i = 1, characterCount, 1 do - local v = result[i] - local job, grade = v.job or 'unemployed', tostring(v.job_grade) - - if ESX.Jobs[job] and ESX.Jobs[job].grades[grade] then - if job ~= 'unemployed' then grade = ESX.Jobs[job].grades[grade].label else grade = '' end - job = ESX.Jobs[job].label - end - - local accounts = json.decode(v.accounts) - local id = tonumber(string.sub(v.identifier, #PREFIX+1, string.find(v.identifier, ':')-1)) - - characters[id] = { - id = id, - bank = accounts.bank, - money = accounts.money, - job = job, - job_grade = grade, - firstname = v.firstname, - lastname = v.lastname, - dateofbirth = v.dateofbirth, - skin = v.skin and json.decode(v.skin) or {}, - disabled = v.disabled, - sex = v.sex == 'm' and _('male') or _('female') - } - end - end - - TriggerClientEvent('esx_multicharacter:SetupUI', source, characters, slots) - end - - AddEventHandler('playerConnecting', function(playerName, setKickReason, deferrals) - deferrals.defer() - local identifier = GetIdentifier(source) - - if identifier then - if ESX.Players[identifier] then - deferrals.done(('A player is already connected to the server with this identifier.\nYour identifier: %s:%s'):format(PRIMARY_IDENTIFIER, identifier)) - else - deferrals.done() - end - else - deferrals.done(('Unable to retrieve player identifier.\nIdentifier type: %s'):format(PRIMARY_IDENTIFIER)) - end - end) - - local function DeleteCharacter(source, charid) - local identifier = ('%s%s:%s'):format(PREFIX, charid, GetIdentifier(source)) - local query = 'DELETE FROM %s WHERE %s = ?' - local queries = {} - local count = 0 - - for table, column in pairs(DB_TABLES) do - count += 1 - queries[count] = {query = query:format(table, column), values = {identifier}} - end - - MySQL.transaction(queries, function(result) - if result then - print(('[^2INFO^7] Player [%s] %s has deleted a character (%s)'):format(GetPlayerName(source), source, identifier)) - Citizen.Wait(50) - SetupCharacters(source) - else - error('\n^1Transaction failed while trying to delete '..identifier..'^0') - end - end) - end - - MySQL.ready(function() - local length = 42 + #PREFIX - local DB_COLUMNS = MySQL.query.await(('SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = "%s" AND DATA_TYPE = "varchar" AND COLUMN_NAME IN (?)'):format(DATABASE, length), { - {'identifier', 'owner'} - }) - - if DB_COLUMNS then - local columns = {} - local count = 0 - - for i = 1, #DB_COLUMNS do - local v = DB_COLUMNS[i] - - if v?.CHARACTER_MAXIMUM_LENGTH ~= length then - count += 1 - columns[v.TABLE_NAME] = v.COLUMN_NAME - end - end - - if next(columns) then - local query = 'ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(%s)' - local queries = table.create(count, 0) - - for k, v in pairs(columns) do - queries[#queries+1] = {query = query:format(k, v, length)} - end - - if MySQL.transaction.await(queries) then - print(('[^2INFO^7] Updated ^5%s^7 columns to use VARCHAR(%s)'):format(count, length)) - else - print(('[^2INFO^7] Unable to update ^5%s^7 columns to use VARCHAR(%s)'):format(count, length)) - end - end - - ESX.Jobs = {} - - local function GetJobs() - if ESX.GetJobs then - return ESX.GetJobs() - end - return exports.es_extended:getSharedObject().Jobs - end - - repeat - ESX.Jobs = GetJobs() - Citizen.Wait(50) - until next(ESX.Jobs) - - FETCH = 'SELECT identifier, accounts, job, job_grade, firstname, lastname, dateofbirth, sex, skin, disabled FROM users WHERE identifier LIKE ? LIMIT ?' - end - end) - - RegisterNetEvent('esx_multicharacter:SetupCharacters', function() - SetupCharacters(source) - end) - - local awaitingRegistration = {} - - RegisterNetEvent('esx_multicharacter:CharacterChosen', function(charid, isNew) - if type(charid) == 'number' and string.len(charid) <= 2 and type(isNew) == 'boolean' then - if isNew then - awaitingRegistration[source] = charid - else - TriggerEvent('esx:onPlayerJoined', source, PREFIX..charid) - ESX.Players[GetIdentifier(source)] = true - end - end - end) - - AddEventHandler('esx_identity:completedRegistration', function(source, data) - TriggerEvent('esx:onPlayerJoined', source, PREFIX..awaitingRegistration[source], data) - awaitingRegistration[source] = nil - ESX.Players[GetIdentifier(source)] = true - end) - - AddEventHandler('playerDropped', function(reason) - awaitingRegistration[source] = nil - ESX.Players[GetIdentifier(source)] = nil - end) - - RegisterNetEvent('esx_multicharacter:DeleteCharacter', function(charid) - if Config.CanDelete and type(charid) == 'number' and string.len(charid) <= 2 then - DeleteCharacter(source, charid) - end - end) - - RegisterNetEvent('esx_multicharacter:relog', function() - TriggerEvent('esx:playerLogout', source) - end) - -else - assert(nil, '^3WARNING: Multicharacter is disabled - please check your ESX configuration^0') -end diff --git a/[esx]/esx_skin/fxmanifest.lua b/[esx]/esx_skin/fxmanifest.lua index 31b095d2..0feb09d3 100644 --- a/[esx]/esx_skin/fxmanifest.lua +++ b/[esx]/esx_skin/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Skin' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_accessories/fxmanifest.lua b/[esx_addons]/esx_accessories/fxmanifest.lua index d2fb53da..6acdf67a 100644 --- a/[esx_addons]/esx_accessories/fxmanifest.lua +++ b/[esx_addons]/esx_accessories/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Accessories' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_addonaccount/fxmanifest.lua b/[esx_addons]/esx_addonaccount/fxmanifest.lua index 7aacd820..8fd979bd 100644 --- a/[esx_addons]/esx_addonaccount/fxmanifest.lua +++ b/[esx_addons]/esx_addonaccount/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Addon Account' -version '1.6.5' +version '1.6.0' server_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_addoninventory/fxmanifest.lua b/[esx_addons]/esx_addoninventory/fxmanifest.lua index 404b109d..c8f0c790 100644 --- a/[esx_addons]/esx_addoninventory/fxmanifest.lua +++ b/[esx_addons]/esx_addoninventory/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Addon Inventory' -version '1.6.5' +version '1.6.0' server_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_ambulancejob/fxmanifest.lua b/[esx_addons]/esx_ambulancejob/fxmanifest.lua index 80444c35..5ff50452 100644 --- a/[esx_addons]/esx_ambulancejob/fxmanifest.lua +++ b/[esx_addons]/esx_ambulancejob/fxmanifest.lua @@ -4,9 +4,9 @@ game 'gta5' description 'ESX Ambulance Job' -version '1.6.5' +version '1.6.0' -c +shared_script '@es_extended/imports.lua' server_scripts { '@oxmysql/lib/MySQL.lua', diff --git a/[esx_addons]/esx_animations/fxmanifest.lua b/[esx_addons]/esx_animations/fxmanifest.lua index 70fd794c..1897459b 100644 --- a/[esx_addons]/esx_animations/fxmanifest.lua +++ b/[esx_addons]/esx_animations/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Animations' -version '1.6.5' +version '1.6.0' client_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_atm/fxmanifest.lua b/[esx_addons]/esx_atm/fxmanifest.lua index 9d6f4325..a464c619 100644 --- a/[esx_addons]/esx_atm/fxmanifest.lua +++ b/[esx_addons]/esx_atm/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Atm' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_bankerjob/fxmanifest.lua b/[esx_addons]/esx_bankerjob/fxmanifest.lua index d4259110..d60a7ca0 100644 --- a/[esx_addons]/esx_bankerjob/fxmanifest.lua +++ b/[esx_addons]/esx_bankerjob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Banker job' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_barbershop/fxmanifest.lua b/[esx_addons]/esx_barbershop/fxmanifest.lua index 3859ec00..a83ae43e 100644 --- a/[esx_addons]/esx_barbershop/fxmanifest.lua +++ b/[esx_addons]/esx_barbershop/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Barber Shop' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_basicneeds/fxmanifest.lua b/[esx_addons]/esx_basicneeds/fxmanifest.lua index 6e5cf251..2088dd2d 100644 --- a/[esx_addons]/esx_basicneeds/fxmanifest.lua +++ b/[esx_addons]/esx_basicneeds/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Basic Needs' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_billing/fxmanifest.lua b/[esx_addons]/esx_billing/fxmanifest.lua index dbfbfdfc..56ef67ca 100644 --- a/[esx_addons]/esx_billing/fxmanifest.lua +++ b/[esx_addons]/esx_billing/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Billing' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_boat/fxmanifest.lua b/[esx_addons]/esx_boat/fxmanifest.lua index 0cb962ea..3a8c8fca 100644 --- a/[esx_addons]/esx_boat/fxmanifest.lua +++ b/[esx_addons]/esx_boat/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Boat' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_clotheshop/fxmanifest.lua b/[esx_addons]/esx_clotheshop/fxmanifest.lua index 41e7a38b..a8dd1b89 100644 --- a/[esx_addons]/esx_clotheshop/fxmanifest.lua +++ b/[esx_addons]/esx_clotheshop/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Clothes Shop' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_cruisecontrol/fxmanifest.lua b/[esx_addons]/esx_cruisecontrol/fxmanifest.lua index c6fa2dee..e92aa300 100644 --- a/[esx_addons]/esx_cruisecontrol/fxmanifest.lua +++ b/[esx_addons]/esx_cruisecontrol/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'CruiseControl System for ESX' -version '1.6.5' +version '1.6.0' dependencies { 'es_extended' diff --git a/[esx_addons]/esx_datastore/fxmanifest.lua b/[esx_addons]/esx_datastore/fxmanifest.lua index aa84426e..4f948458 100644 --- a/[esx_addons]/esx_datastore/fxmanifest.lua +++ b/[esx_addons]/esx_datastore/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Data Store' -version '1.6.5' +version '1.6.0' server_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_dmvschool/fxmanifest.lua b/[esx_addons]/esx_dmvschool/fxmanifest.lua index 726b5d16..433a2fb3 100644 --- a/[esx_addons]/esx_dmvschool/fxmanifest.lua +++ b/[esx_addons]/esx_dmvschool/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX DMV School' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_drugs/fxmanifest.lua b/[esx_addons]/esx_drugs/fxmanifest.lua index 45782bd6..45e910b1 100644 --- a/[esx_addons]/esx_drugs/fxmanifest.lua +++ b/[esx_addons]/esx_drugs/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Drugs' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_garage/fxmanifest.lua b/[esx_addons]/esx_garage/fxmanifest.lua index 28a0dc29..02614ad7 100644 --- a/[esx_addons]/esx_garage/fxmanifest.lua +++ b/[esx_addons]/esx_garage/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Garage' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_holdup/fxmanifest.lua b/[esx_addons]/esx_holdup/fxmanifest.lua index 52619849..1aec4396 100644 --- a/[esx_addons]/esx_holdup/fxmanifest.lua +++ b/[esx_addons]/esx_holdup/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Holdup' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_joblisting/fxmanifest.lua b/[esx_addons]/esx_joblisting/fxmanifest.lua index c5e4bd50..a910652f 100644 --- a/[esx_addons]/esx_joblisting/fxmanifest.lua +++ b/[esx_addons]/esx_joblisting/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Job Listing' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_jobs/fxmanifest.lua b/[esx_addons]/esx_jobs/fxmanifest.lua index 25d637af..8beb059a 100644 --- a/[esx_addons]/esx_jobs/fxmanifest.lua +++ b/[esx_addons]/esx_jobs/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Jobs' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_license/fxmanifest.lua b/[esx_addons]/esx_license/fxmanifest.lua index 9bef90a7..8d907995 100644 --- a/[esx_addons]/esx_license/fxmanifest.lua +++ b/[esx_addons]/esx_license/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX License' -version '1.6.5' +version '1.6.0' server_scripts { '@async/async.lua', diff --git a/[esx_addons]/esx_lscustom/fxmanifest.lua b/[esx_addons]/esx_lscustom/fxmanifest.lua index 19efd417..d6ec6779 100644 --- a/[esx_addons]/esx_lscustom/fxmanifest.lua +++ b/[esx_addons]/esx_lscustom/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX LS Customs' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_mechanicjob/fxmanifest.lua b/[esx_addons]/esx_mechanicjob/fxmanifest.lua index dfc4140a..4d24aeee 100644 --- a/[esx_addons]/esx_mechanicjob/fxmanifest.lua +++ b/[esx_addons]/esx_mechanicjob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Mechanic Job' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_optionalneeds/fxmanifest.lua b/[esx_addons]/esx_optionalneeds/fxmanifest.lua index 2e788e88..f5793a9a 100644 --- a/[esx_addons]/esx_optionalneeds/fxmanifest.lua +++ b/[esx_addons]/esx_optionalneeds/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Optional Needs' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_phone/fxmanifest.lua b/[esx_addons]/esx_phone/fxmanifest.lua index c7f52a52..96733393 100644 --- a/[esx_addons]/esx_phone/fxmanifest.lua +++ b/[esx_addons]/esx_phone/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Phone' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_policejob/fxmanifest.lua b/[esx_addons]/esx_policejob/fxmanifest.lua index 6dd5ac08..60c00cf7 100644 --- a/[esx_addons]/esx_policejob/fxmanifest.lua +++ b/[esx_addons]/esx_policejob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Police Job' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_property/fxmanifest.lua b/[esx_addons]/esx_property/fxmanifest.lua index 0ef6d6e9..dddedcc2 100644 --- a/[esx_addons]/esx_property/fxmanifest.lua +++ b/[esx_addons]/esx_property/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Property' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_realestateagentjob/fxmanifest.lua b/[esx_addons]/esx_realestateagentjob/fxmanifest.lua index 1dbccfd7..5201b2c8 100644 --- a/[esx_addons]/esx_realestateagentjob/fxmanifest.lua +++ b/[esx_addons]/esx_realestateagentjob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Real Estate Job' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_rpchat/fxmanifest.lua b/[esx_addons]/esx_rpchat/fxmanifest.lua index 06774b5d..4d8ae670 100644 --- a/[esx_addons]/esx_rpchat/fxmanifest.lua +++ b/[esx_addons]/esx_rpchat/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX RP Chat' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_service/fxmanifest.lua b/[esx_addons]/esx_service/fxmanifest.lua index 9f49bd78..d271c37c 100644 --- a/[esx_addons]/esx_service/fxmanifest.lua +++ b/[esx_addons]/esx_service/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Service' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_shops/fxmanifest.lua b/[esx_addons]/esx_shops/fxmanifest.lua index fdf23909..9aebaf69 100644 --- a/[esx_addons]/esx_shops/fxmanifest.lua +++ b/[esx_addons]/esx_shops/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Shops' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_sit/fxmanifest.lua b/[esx_addons]/esx_sit/fxmanifest.lua index 2e971618..630b2898 100644 --- a/[esx_addons]/esx_sit/fxmanifest.lua +++ b/[esx_addons]/esx_sit/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Sit' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_society/fxmanifest.lua b/[esx_addons]/esx_society/fxmanifest.lua index 79fe1448..43769fd6 100644 --- a/[esx_addons]/esx_society/fxmanifest.lua +++ b/[esx_addons]/esx_society/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Society' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_status/fxmanifest.lua b/[esx_addons]/esx_status/fxmanifest.lua index 68bd5b3f..d4ebd2c7 100644 --- a/[esx_addons]/esx_status/fxmanifest.lua +++ b/[esx_addons]/esx_status/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Status' -version '1.6.5' +version '1.6.0' lua54 'yes' diff --git a/[esx_addons]/esx_taxijob/fxmanifest.lua b/[esx_addons]/esx_taxijob/fxmanifest.lua index 54e4ea72..b2e67b5f 100644 --- a/[esx_addons]/esx_taxijob/fxmanifest.lua +++ b/[esx_addons]/esx_taxijob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Taxi Job' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_vehicleshop/fxmanifest.lua b/[esx_addons]/esx_vehicleshop/fxmanifest.lua index 82c483c0..f87595e3 100644 --- a/[esx_addons]/esx_vehicleshop/fxmanifest.lua +++ b/[esx_addons]/esx_vehicleshop/fxmanifest.lua @@ -6,7 +6,7 @@ lua54 'yes' description 'ESX Vehicle Shop' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_voice/fxmanifest.lua b/[esx_addons]/esx_voice/fxmanifest.lua index 9ffc0aeb..a8e2697a 100644 --- a/[esx_addons]/esx_voice/fxmanifest.lua +++ b/[esx_addons]/esx_voice/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Voice Controller' -version '1.6.5' +version '1.6.0' client_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_weaponshop/fxmanifest.lua b/[esx_addons]/esx_weaponshop/fxmanifest.lua index 64296bf3..65e74b5e 100644 --- a/[esx_addons]/esx_weaponshop/fxmanifest.lua +++ b/[esx_addons]/esx_weaponshop/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Weapon Shop' -version '1.6.5' +version '1.6.0' shared_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_whitelist/fxmanifest.lua b/[esx_addons]/esx_whitelist/fxmanifest.lua index 6319d5d9..8c6515e6 100644 --- a/[esx_addons]/esx_whitelist/fxmanifest.lua +++ b/[esx_addons]/esx_whitelist/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Whitelist' -version '1.6.5' +version '1.6.0' server_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/instance/fxmanifest.lua b/[esx_addons]/instance/fxmanifest.lua index f5a4b905..57aa044e 100644 --- a/[esx_addons]/instance/fxmanifest.lua +++ b/[esx_addons]/instance/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'Instance' -version '1.6.5' +version '1.6.0' shared_script '@es_extended/imports.lua' From d2c1c6ecd9926c3256e3a6fc2764243f8704b157 Mon Sep 17 00:00:00 2001 From: Mycroft Date: Wed, 23 Mar 2022 16:04:42 +0000 Subject: [PATCH 61/64] Revert "Delete esx_multicharacter" This reverts commit d659a73d182a5febd1e0cfc2b184f2c203693da5. --- [esx_addons]/esx_multicharacter | 1 + 1 file changed, 1 insertion(+) create mode 160000 [esx_addons]/esx_multicharacter diff --git a/[esx_addons]/esx_multicharacter b/[esx_addons]/esx_multicharacter new file mode 160000 index 00000000..02352a8e --- /dev/null +++ b/[esx_addons]/esx_multicharacter @@ -0,0 +1 @@ +Subproject commit 02352a8e18176cb9f369ba608aab66ccf0311fe0 From 1be411b3d1504eab0bd62be2114176cd055c41fd Mon Sep 17 00:00:00 2001 From: Linden <65407488+thelindat@users.noreply.github.com> Date: Wed, 23 Mar 2022 20:34:16 +1100 Subject: [PATCH 62/64] chore: move esx_multicharacter files --- .../esx_multicharacter/LICENSE.md | 0 .../esx_multicharacter/client}/main.lua | 0 .../esx_multicharacter/config.lua | 0 .../esx_multicharacter/esx_multicharacter.sql | 0 .../esx_multicharacter/fxmanifest.lua | 0 .../esx_multicharacter/html}/css/main.css | 0 .../esx_multicharacter/html}/js/app.js | 0 .../esx_multicharacter/html}/locales/cs.js | 0 .../esx_multicharacter/html}/locales/de.js | 0 .../esx_multicharacter/html}/locales/en.js | 0 .../esx_multicharacter/html}/locales/fr.js | 0 .../esx_multicharacter/html}/locales/pl.js | 0 .../esx_multicharacter/html}/locales/pt.js | 0 .../esx_multicharacter/html}/locales/tr.js | 0 .../esx_multicharacter/html}/ui.html | 0 .../esx_multicharacter/locales}/cs.lua | 0 .../esx_multicharacter/locales}/de.lua | 0 .../esx_multicharacter/locales}/en.lua | 0 .../esx_multicharacter/locales}/it.lua | 0 .../esx_multicharacter/locales}/pt.lua | 0 .../esx_multicharacter/locales}/tr.lua | 0 .../esx_multicharacter/readme.md | 144 +++++++++--------- .../esx_multicharacter/server}/commands.lua | 0 .../esx_multicharacter/server}/main.lua | 0 24 files changed, 72 insertions(+), 72 deletions(-) rename LICENSE.md => [esx]/esx_multicharacter/LICENSE.md (100%) rename {client => [esx]/esx_multicharacter/client}/main.lua (100%) rename config.lua => [esx]/esx_multicharacter/config.lua (100%) rename esx_multicharacter.sql => [esx]/esx_multicharacter/esx_multicharacter.sql (100%) rename fxmanifest.lua => [esx]/esx_multicharacter/fxmanifest.lua (100%) rename {html => [esx]/esx_multicharacter/html}/css/main.css (100%) rename {html => [esx]/esx_multicharacter/html}/js/app.js (100%) rename {html => [esx]/esx_multicharacter/html}/locales/cs.js (100%) rename {html => [esx]/esx_multicharacter/html}/locales/de.js (100%) rename {html => [esx]/esx_multicharacter/html}/locales/en.js (100%) rename {html => [esx]/esx_multicharacter/html}/locales/fr.js (100%) rename {html => [esx]/esx_multicharacter/html}/locales/pl.js (100%) rename {html => [esx]/esx_multicharacter/html}/locales/pt.js (100%) rename {html => [esx]/esx_multicharacter/html}/locales/tr.js (100%) rename {html => [esx]/esx_multicharacter/html}/ui.html (100%) rename {locales => [esx]/esx_multicharacter/locales}/cs.lua (100%) rename {locales => [esx]/esx_multicharacter/locales}/de.lua (100%) rename {locales => [esx]/esx_multicharacter/locales}/en.lua (100%) rename {locales => [esx]/esx_multicharacter/locales}/it.lua (100%) rename {locales => [esx]/esx_multicharacter/locales}/pt.lua (100%) rename {locales => [esx]/esx_multicharacter/locales}/tr.lua (100%) rename readme.md => [esx]/esx_multicharacter/readme.md (97%) rename {server => [esx]/esx_multicharacter/server}/commands.lua (100%) rename {server => [esx]/esx_multicharacter/server}/main.lua (100%) diff --git a/LICENSE.md b/[esx]/esx_multicharacter/LICENSE.md similarity index 100% rename from LICENSE.md rename to [esx]/esx_multicharacter/LICENSE.md diff --git a/client/main.lua b/[esx]/esx_multicharacter/client/main.lua similarity index 100% rename from client/main.lua rename to [esx]/esx_multicharacter/client/main.lua diff --git a/config.lua b/[esx]/esx_multicharacter/config.lua similarity index 100% rename from config.lua rename to [esx]/esx_multicharacter/config.lua diff --git a/esx_multicharacter.sql b/[esx]/esx_multicharacter/esx_multicharacter.sql similarity index 100% rename from esx_multicharacter.sql rename to [esx]/esx_multicharacter/esx_multicharacter.sql diff --git a/fxmanifest.lua b/[esx]/esx_multicharacter/fxmanifest.lua similarity index 100% rename from fxmanifest.lua rename to [esx]/esx_multicharacter/fxmanifest.lua diff --git a/html/css/main.css b/[esx]/esx_multicharacter/html/css/main.css similarity index 100% rename from html/css/main.css rename to [esx]/esx_multicharacter/html/css/main.css diff --git a/html/js/app.js b/[esx]/esx_multicharacter/html/js/app.js similarity index 100% rename from html/js/app.js rename to [esx]/esx_multicharacter/html/js/app.js diff --git a/html/locales/cs.js b/[esx]/esx_multicharacter/html/locales/cs.js similarity index 100% rename from html/locales/cs.js rename to [esx]/esx_multicharacter/html/locales/cs.js diff --git a/html/locales/de.js b/[esx]/esx_multicharacter/html/locales/de.js similarity index 100% rename from html/locales/de.js rename to [esx]/esx_multicharacter/html/locales/de.js diff --git a/html/locales/en.js b/[esx]/esx_multicharacter/html/locales/en.js similarity index 100% rename from html/locales/en.js rename to [esx]/esx_multicharacter/html/locales/en.js diff --git a/html/locales/fr.js b/[esx]/esx_multicharacter/html/locales/fr.js similarity index 100% rename from html/locales/fr.js rename to [esx]/esx_multicharacter/html/locales/fr.js diff --git a/html/locales/pl.js b/[esx]/esx_multicharacter/html/locales/pl.js similarity index 100% rename from html/locales/pl.js rename to [esx]/esx_multicharacter/html/locales/pl.js diff --git a/html/locales/pt.js b/[esx]/esx_multicharacter/html/locales/pt.js similarity index 100% rename from html/locales/pt.js rename to [esx]/esx_multicharacter/html/locales/pt.js diff --git a/html/locales/tr.js b/[esx]/esx_multicharacter/html/locales/tr.js similarity index 100% rename from html/locales/tr.js rename to [esx]/esx_multicharacter/html/locales/tr.js diff --git a/html/ui.html b/[esx]/esx_multicharacter/html/ui.html similarity index 100% rename from html/ui.html rename to [esx]/esx_multicharacter/html/ui.html diff --git a/locales/cs.lua b/[esx]/esx_multicharacter/locales/cs.lua similarity index 100% rename from locales/cs.lua rename to [esx]/esx_multicharacter/locales/cs.lua diff --git a/locales/de.lua b/[esx]/esx_multicharacter/locales/de.lua similarity index 100% rename from locales/de.lua rename to [esx]/esx_multicharacter/locales/de.lua diff --git a/locales/en.lua b/[esx]/esx_multicharacter/locales/en.lua similarity index 100% rename from locales/en.lua rename to [esx]/esx_multicharacter/locales/en.lua diff --git a/locales/it.lua b/[esx]/esx_multicharacter/locales/it.lua similarity index 100% rename from locales/it.lua rename to [esx]/esx_multicharacter/locales/it.lua diff --git a/locales/pt.lua b/[esx]/esx_multicharacter/locales/pt.lua similarity index 100% rename from locales/pt.lua rename to [esx]/esx_multicharacter/locales/pt.lua diff --git a/locales/tr.lua b/[esx]/esx_multicharacter/locales/tr.lua similarity index 100% rename from locales/tr.lua rename to [esx]/esx_multicharacter/locales/tr.lua diff --git a/readme.md b/[esx]/esx_multicharacter/readme.md similarity index 97% rename from readme.md rename to [esx]/esx_multicharacter/readme.md index 6e2393c9..c25c77cd 100644 --- a/readme.md +++ b/[esx]/esx_multicharacter/readme.md @@ -1,72 +1,72 @@ -### Requirements (ensure you are using the latest) -- [ESX Legacy](https://github.com/esx-framework/esx-legacy) -- [OxMySQL](https://github.com/overextended/oxmysql/releases) - -### Conflicts -* The following resources should not be used with ESX Legacy and can result in errors - - essentialmode - - basic-gamemode - - fivem-map-skater - - fivem-map-hipster - - default_spawnpoint - -### Installation -- Modify your ESX config with `Config.Multichar = true` -- Run `esx_multicharacter.sql` into your database -- All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry - - The resource will attempt to set columns automatically - - -#### The menu is esx_menu_default - you can use any version if you want a different appearance -![image](https://user-images.githubusercontent.com/65407488/126976325-17cc3241-bb9e-451f-a6ed-610a8ef52fa5.png) - -### Relogging -- Do not enable this setting if you do not intend to properly set up relog support -- Requires the latest update for ESX Status (prevents multiple status ticks from running) -- Add the following events to resources that require support for relogging, or -- Add them to [@es_extended/imports.lua](https://github.com/esx-framework/esx-legacy/blob/main/[esx]/es_extended/imports.lua) (and use the imports in your resources) -```lua -RegisterNetEvent('esx:playerLoaded', function(xPlayer) - ESX.PlayerData = xPlayer - ESX.PlayerLoaded = true -end) - -RegisterNetEvent('esx:onPlayerLogout', function() - ESX.PlayerLoaded = false - ESX.PlayerData = {} -end) -``` - -### Notes -- This resource is not compatible with ExtendedMode or previous versions of ESX -- Legacy, skin, and identity must be updated to at least the minimum commits specified above -- Characters are stored in the users table as `char#:license` - if you need to use a different identifier then you need to modify ESX itself -- Character deletion does not require manual entries for the tables to remove -- As characters are stored with unique identifiers, there is no excessive queries being executed - -### Kashacters -- This project is forked from the [kashacters multicharacter resource](https://github.com/FiveEYZ/esx_kashacter) -- Most of the code has been entirely rewritten -- KASH has given permission for this resource to use his code and the addition of a license -- The license obviously does not apply to previous versions and KASH has stated his resource is free to be used however - - - -## Notice -Copyright © 2021 Linden and KASH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see https://www.gnu.org/licenses. - - -### Thanks to KASH, XxFri3ndlyxX, and all those who have contributed +### Requirements (ensure you are using the latest) +- [ESX Legacy](https://github.com/esx-framework/esx-legacy) +- [OxMySQL](https://github.com/overextended/oxmysql/releases) + +### Conflicts +* The following resources should not be used with ESX Legacy and can result in errors + - essentialmode + - basic-gamemode + - fivem-map-skater + - fivem-map-hipster + - default_spawnpoint + +### Installation +- Modify your ESX config with `Config.Multichar = true` +- Run `esx_multicharacter.sql` into your database +- All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry + - The resource will attempt to set columns automatically + + +#### The menu is esx_menu_default - you can use any version if you want a different appearance +![image](https://user-images.githubusercontent.com/65407488/126976325-17cc3241-bb9e-451f-a6ed-610a8ef52fa5.png) + +### Relogging +- Do not enable this setting if you do not intend to properly set up relog support +- Requires the latest update for ESX Status (prevents multiple status ticks from running) +- Add the following events to resources that require support for relogging, or +- Add them to [@es_extended/imports.lua](https://github.com/esx-framework/esx-legacy/blob/main/[esx]/es_extended/imports.lua) (and use the imports in your resources) +```lua +RegisterNetEvent('esx:playerLoaded', function(xPlayer) + ESX.PlayerData = xPlayer + ESX.PlayerLoaded = true +end) + +RegisterNetEvent('esx:onPlayerLogout', function() + ESX.PlayerLoaded = false + ESX.PlayerData = {} +end) +``` + +### Notes +- This resource is not compatible with ExtendedMode or previous versions of ESX +- Legacy, skin, and identity must be updated to at least the minimum commits specified above +- Characters are stored in the users table as `char#:license` - if you need to use a different identifier then you need to modify ESX itself +- Character deletion does not require manual entries for the tables to remove +- As characters are stored with unique identifiers, there is no excessive queries being executed + +### Kashacters +- This project is forked from the [kashacters multicharacter resource](https://github.com/FiveEYZ/esx_kashacter) +- Most of the code has been entirely rewritten +- KASH has given permission for this resource to use his code and the addition of a license +- The license obviously does not apply to previous versions and KASH has stated his resource is free to be used however + + + +## Notice +Copyright © 2021 Linden and KASH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see https://www.gnu.org/licenses. + + +### Thanks to KASH, XxFri3ndlyxX, and all those who have contributed diff --git a/server/commands.lua b/[esx]/esx_multicharacter/server/commands.lua similarity index 100% rename from server/commands.lua rename to [esx]/esx_multicharacter/server/commands.lua diff --git a/server/main.lua b/[esx]/esx_multicharacter/server/main.lua similarity index 100% rename from server/main.lua rename to [esx]/esx_multicharacter/server/main.lua From 8e82543933b48ec0bd2ebb3dd02eeca65726db2b Mon Sep 17 00:00:00 2001 From: Mycroft Date: Wed, 23 Mar 2022 16:22:46 +0000 Subject: [PATCH 63/64] Version Bump for 1.6.5 --- [SQL]/legacy.sql | 14 +++++ [esx]/es_extended/config.lua | 2 +- [esx]/es_extended/fxmanifest.lua | 2 +- [esx]/es_extended/version.json | 4 +- [esx]/esx_identity/fxmanifest.lua | 2 +- [esx]/esx_menu_default/fxmanifest.lua | 2 +- [esx]/esx_menu_dialog/fxmanifest.lua | 2 +- [esx]/esx_menu_list/fxmanifest.lua | 2 +- [esx]/esx_multicharacter/fxmanifest.lua | 4 +- [esx]/esx_multicharacter/readme.md | 51 +++++++------------ [esx]/esx_skin/fxmanifest.lua | 2 +- [esx_addons]/esx_accessories/fxmanifest.lua | 2 +- [esx_addons]/esx_addonaccount/fxmanifest.lua | 2 +- .../esx_addoninventory/fxmanifest.lua | 2 +- [esx_addons]/esx_ambulancejob/fxmanifest.lua | 2 +- [esx_addons]/esx_animations/fxmanifest.lua | 2 +- [esx_addons]/esx_atm/fxmanifest.lua | 2 +- [esx_addons]/esx_bankerjob/fxmanifest.lua | 2 +- [esx_addons]/esx_barbershop/fxmanifest.lua | 2 +- [esx_addons]/esx_basicneeds/fxmanifest.lua | 2 +- [esx_addons]/esx_billing/fxmanifest.lua | 2 +- [esx_addons]/esx_boat/fxmanifest.lua | 2 +- [esx_addons]/esx_clotheshop/fxmanifest.lua | 2 +- [esx_addons]/esx_cruisecontrol/fxmanifest.lua | 2 +- [esx_addons]/esx_datastore/fxmanifest.lua | 2 +- [esx_addons]/esx_dmvschool/fxmanifest.lua | 2 +- [esx_addons]/esx_drugs/fxmanifest.lua | 2 +- [esx_addons]/esx_garage/fxmanifest.lua | 2 +- [esx_addons]/esx_holdup/fxmanifest.lua | 2 +- [esx_addons]/esx_joblisting/fxmanifest.lua | 2 +- [esx_addons]/esx_jobs/fxmanifest.lua | 2 +- [esx_addons]/esx_license/fxmanifest.lua | 2 +- [esx_addons]/esx_lscustom/fxmanifest.lua | 2 +- [esx_addons]/esx_mechanicjob/fxmanifest.lua | 2 +- [esx_addons]/esx_optionalneeds/fxmanifest.lua | 2 +- [esx_addons]/esx_phone/fxmanifest.lua | 2 +- [esx_addons]/esx_policejob/fxmanifest.lua | 2 +- [esx_addons]/esx_property/fxmanifest.lua | 2 +- .../esx_realestateagentjob/fxmanifest.lua | 2 +- [esx_addons]/esx_rpchat/fxmanifest.lua | 2 +- [esx_addons]/esx_service/fxmanifest.lua | 2 +- [esx_addons]/esx_shops/fxmanifest.lua | 2 +- [esx_addons]/esx_sit/fxmanifest.lua | 2 +- [esx_addons]/esx_society/fxmanifest.lua | 2 +- [esx_addons]/esx_status/fxmanifest.lua | 2 +- [esx_addons]/esx_taxijob/fxmanifest.lua | 2 +- [esx_addons]/esx_vehicleshop/fxmanifest.lua | 2 +- [esx_addons]/esx_voice/fxmanifest.lua | 2 +- [esx_addons]/esx_weaponshop/fxmanifest.lua | 2 +- [esx_addons]/esx_whitelist/fxmanifest.lua | 2 +- [esx_addons]/instance/fxmanifest.lua | 2 +- 51 files changed, 84 insertions(+), 83 deletions(-) diff --git a/[SQL]/legacy.sql b/[SQL]/legacy.sql index ae6c1840..f59c0ee1 100644 --- a/[SQL]/legacy.sql +++ b/[SQL]/legacy.sql @@ -112,6 +112,19 @@ CREATE TABLE `cardealer_vehicles` ( -- -------------------------------------------------------- +-- +-- Table structure for table `multicharacter_slots` +-- + +CREATE TABLE `multicharacter_slots` ( + `identifier` VARCHAR(60) NOT NULL, + `slots` INT(11) NOT NULL, + PRIMARY KEY (`identifier`) USING BTREE, + INDEX `slots` (`slots`) USING BTREE +) ENGINE=InnoDB; + +-- -------------------------------------------------------- + -- -- Table structure for table `datastore` -- @@ -501,6 +514,7 @@ CREATE TABLE `users` ( `status` longtext DEFAULT NULL, `is_dead` tinyint(1) DEFAULT 0, `id` int(11) NOT NULL, + `disabled` TINYINT(1) NULL DEFAULT '0', `last_property` varchar(255) DEFAULT NULL ) ENGINE=InnoDB; diff --git a/[esx]/es_extended/config.lua b/[esx]/es_extended/config.lua index 6d9f4203..d18705bd 100644 --- a/[esx]/es_extended/config.lua +++ b/[esx]/es_extended/config.lua @@ -18,5 +18,5 @@ Config.EnableDefaultInventory = true -- Display the default Inventory ( F2 ) Config.EnableWantedLevel = false -- Use Normal GTA wanted Level? Config.EnablePVP = true -- Allow Player to player combat -Config.Multichar = false -- Enable support for esx_multicharacter +Config.Multichar = true -- Enable support for esx_multicharacter Config.Identity = true -- Select a characters identity data before they have loaded in (this happens by default with multichar) diff --git a/[esx]/es_extended/fxmanifest.lua b/[esx]/es_extended/fxmanifest.lua index d25a3e5e..5fdb4c7b 100644 --- a/[esx]/es_extended/fxmanifest.lua +++ b/[esx]/es_extended/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ES Extended' -version '1.6.0' +version '1.6.5' shared_scripts { 'locale.lua', diff --git a/[esx]/es_extended/version.json b/[esx]/es_extended/version.json index 9f3db69d..4408914d 100644 --- a/[esx]/es_extended/version.json +++ b/[esx]/es_extended/version.json @@ -1,5 +1,5 @@ { "version": "legacy", - "commit" : "1.4.2", - "changelog": "\n- Updated `Car` Command. Fixed some vulnerabilities. Fix SQL. Updated Commands." + "commit" : "1.6.5", + "changelog": "\n- Add ESX Mulitcharacter" } diff --git a/[esx]/esx_identity/fxmanifest.lua b/[esx]/esx_identity/fxmanifest.lua index 1c4e4baf..79254f5e 100644 --- a/[esx]/esx_identity/fxmanifest.lua +++ b/[esx]/esx_identity/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Identity' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx]/esx_menu_default/fxmanifest.lua b/[esx]/esx_menu_default/fxmanifest.lua index 64a36d7f..7139cca2 100644 --- a/[esx]/esx_menu_default/fxmanifest.lua +++ b/[esx]/esx_menu_default/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Menu Default' -version '1.6.0' +version '1.6.5' client_scripts { '@es_extended/imports.lua', diff --git a/[esx]/esx_menu_dialog/fxmanifest.lua b/[esx]/esx_menu_dialog/fxmanifest.lua index 1959b086..3a84362b 100644 --- a/[esx]/esx_menu_dialog/fxmanifest.lua +++ b/[esx]/esx_menu_dialog/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Menu Dialog' -version '1.6.0' +version '1.6.5' client_scripts { '@es_extended/imports.lua', diff --git a/[esx]/esx_menu_list/fxmanifest.lua b/[esx]/esx_menu_list/fxmanifest.lua index b980e57e..f267511a 100644 --- a/[esx]/esx_menu_list/fxmanifest.lua +++ b/[esx]/esx_menu_list/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Menu List' -version '1.6.0' +version '1.6.5' client_scripts { '@es_extended/imports.lua', diff --git a/[esx]/esx_multicharacter/fxmanifest.lua b/[esx]/esx_multicharacter/fxmanifest.lua index 0b928219..435f6ba3 100644 --- a/[esx]/esx_multicharacter/fxmanifest.lua +++ b/[esx]/esx_multicharacter/fxmanifest.lua @@ -1,7 +1,7 @@ fx_version 'cerulean' game 'gta5' -description 'https://github.com/thelindat/esx_multicharacter' -version '1.4.2' +description 'Official Multicharacter System For ESX Legacy' +version '1.6.5' lua54 'yes' dependencies { diff --git a/[esx]/esx_multicharacter/readme.md b/[esx]/esx_multicharacter/readme.md index c25c77cd..f5879edc 100644 --- a/[esx]/esx_multicharacter/readme.md +++ b/[esx]/esx_multicharacter/readme.md @@ -1,59 +1,49 @@ -### Requirements (ensure you are using the latest) -- [ESX Legacy](https://github.com/esx-framework/esx-legacy) -- [OxMySQL](https://github.com/overextended/oxmysql/releases) -### Conflicts -* The following resources should not be used with ESX Legacy and can result in errors - - essentialmode - - basic-gamemode - - fivem-map-skater - - fivem-map-hipster - - default_spawnpoint +# Preview -### Installation -- Modify your ESX config with `Config.Multichar = true` -- Run `esx_multicharacter.sql` into your database -- All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry - - The resource will attempt to set columns automatically - - -#### The menu is esx_menu_default - you can use any version if you want a different appearance ![image](https://user-images.githubusercontent.com/65407488/126976325-17cc3241-bb9e-451f-a6ed-610a8ef52fa5.png) +## Installation + +- Modify your ESX config with `Config.Multichar = true` +- All owner and identifier columns should be set to `VARCHAR(60)` to ensure correct data entry + - The resource will attempt to set columns automatically + ### Relogging + - Do not enable this setting if you do not intend to properly set up relog support - Requires the latest update for ESX Status (prevents multiple status ticks from running) - Add the following events to resources that require support for relogging, or - Add them to [@es_extended/imports.lua](https://github.com/esx-framework/esx-legacy/blob/main/[esx]/es_extended/imports.lua) (and use the imports in your resources) + ```lua RegisterNetEvent('esx:playerLoaded', function(xPlayer) - ESX.PlayerData = xPlayer - ESX.PlayerLoaded = true + ESX.PlayerData = xPlayer + ESX.PlayerLoaded = true end) RegisterNetEvent('esx:onPlayerLogout', function() - ESX.PlayerLoaded = false - ESX.PlayerData = {} + ESX.PlayerLoaded = false + ESX.PlayerData = {} end) ``` ### Notes -- This resource is not compatible with ExtendedMode or previous versions of ESX -- Legacy, skin, and identity must be updated to at least the minimum commits specified above + - Characters are stored in the users table as `char#:license` - if you need to use a different identifier then you need to modify ESX itself - Character deletion does not require manual entries for the tables to remove - As characters are stored with unique identifiers, there is no excessive queries being executed - + ### Kashacters + - This project is forked from the [kashacters multicharacter resource](https://github.com/FiveEYZ/esx_kashacter) - Most of the code has been entirely rewritten - KASH has given permission for this resource to use his code and the addition of a license - The license obviously does not apply to previous versions and KASH has stated his resource is free to be used however - - ## Notice -Copyright © 2021 Linden and KASH + +Copyright © 2022 [Linden](https://github.com/thelindat/), ESX-Framework (fournier Brice & Jérémie N'gadi) and KASH This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -66,7 +56,4 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program. If not, see https://www.gnu.org/licenses. - - -### Thanks to KASH, XxFri3ndlyxX, and all those who have contributed +along with this program. If not, see . diff --git a/[esx]/esx_skin/fxmanifest.lua b/[esx]/esx_skin/fxmanifest.lua index 0feb09d3..31b095d2 100644 --- a/[esx]/esx_skin/fxmanifest.lua +++ b/[esx]/esx_skin/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Skin' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_accessories/fxmanifest.lua b/[esx_addons]/esx_accessories/fxmanifest.lua index 6acdf67a..d2fb53da 100644 --- a/[esx_addons]/esx_accessories/fxmanifest.lua +++ b/[esx_addons]/esx_accessories/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Accessories' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_addonaccount/fxmanifest.lua b/[esx_addons]/esx_addonaccount/fxmanifest.lua index 8fd979bd..7aacd820 100644 --- a/[esx_addons]/esx_addonaccount/fxmanifest.lua +++ b/[esx_addons]/esx_addonaccount/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Addon Account' -version '1.6.0' +version '1.6.5' server_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_addoninventory/fxmanifest.lua b/[esx_addons]/esx_addoninventory/fxmanifest.lua index c8f0c790..404b109d 100644 --- a/[esx_addons]/esx_addoninventory/fxmanifest.lua +++ b/[esx_addons]/esx_addoninventory/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Addon Inventory' -version '1.6.0' +version '1.6.5' server_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_ambulancejob/fxmanifest.lua b/[esx_addons]/esx_ambulancejob/fxmanifest.lua index 5ff50452..763c2c97 100644 --- a/[esx_addons]/esx_ambulancejob/fxmanifest.lua +++ b/[esx_addons]/esx_ambulancejob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Ambulance Job' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_animations/fxmanifest.lua b/[esx_addons]/esx_animations/fxmanifest.lua index 1897459b..70fd794c 100644 --- a/[esx_addons]/esx_animations/fxmanifest.lua +++ b/[esx_addons]/esx_animations/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Animations' -version '1.6.0' +version '1.6.5' client_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_atm/fxmanifest.lua b/[esx_addons]/esx_atm/fxmanifest.lua index a464c619..9d6f4325 100644 --- a/[esx_addons]/esx_atm/fxmanifest.lua +++ b/[esx_addons]/esx_atm/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Atm' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_bankerjob/fxmanifest.lua b/[esx_addons]/esx_bankerjob/fxmanifest.lua index d60a7ca0..d4259110 100644 --- a/[esx_addons]/esx_bankerjob/fxmanifest.lua +++ b/[esx_addons]/esx_bankerjob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Banker job' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_barbershop/fxmanifest.lua b/[esx_addons]/esx_barbershop/fxmanifest.lua index a83ae43e..3859ec00 100644 --- a/[esx_addons]/esx_barbershop/fxmanifest.lua +++ b/[esx_addons]/esx_barbershop/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Barber Shop' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_basicneeds/fxmanifest.lua b/[esx_addons]/esx_basicneeds/fxmanifest.lua index 2088dd2d..6e5cf251 100644 --- a/[esx_addons]/esx_basicneeds/fxmanifest.lua +++ b/[esx_addons]/esx_basicneeds/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Basic Needs' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_billing/fxmanifest.lua b/[esx_addons]/esx_billing/fxmanifest.lua index 56ef67ca..dbfbfdfc 100644 --- a/[esx_addons]/esx_billing/fxmanifest.lua +++ b/[esx_addons]/esx_billing/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Billing' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_boat/fxmanifest.lua b/[esx_addons]/esx_boat/fxmanifest.lua index 3a8c8fca..0cb962ea 100644 --- a/[esx_addons]/esx_boat/fxmanifest.lua +++ b/[esx_addons]/esx_boat/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Boat' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_clotheshop/fxmanifest.lua b/[esx_addons]/esx_clotheshop/fxmanifest.lua index a8dd1b89..41e7a38b 100644 --- a/[esx_addons]/esx_clotheshop/fxmanifest.lua +++ b/[esx_addons]/esx_clotheshop/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Clothes Shop' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_cruisecontrol/fxmanifest.lua b/[esx_addons]/esx_cruisecontrol/fxmanifest.lua index e92aa300..c6fa2dee 100644 --- a/[esx_addons]/esx_cruisecontrol/fxmanifest.lua +++ b/[esx_addons]/esx_cruisecontrol/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'CruiseControl System for ESX' -version '1.6.0' +version '1.6.5' dependencies { 'es_extended' diff --git a/[esx_addons]/esx_datastore/fxmanifest.lua b/[esx_addons]/esx_datastore/fxmanifest.lua index 4f948458..aa84426e 100644 --- a/[esx_addons]/esx_datastore/fxmanifest.lua +++ b/[esx_addons]/esx_datastore/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Data Store' -version '1.6.0' +version '1.6.5' server_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_dmvschool/fxmanifest.lua b/[esx_addons]/esx_dmvschool/fxmanifest.lua index 433a2fb3..726b5d16 100644 --- a/[esx_addons]/esx_dmvschool/fxmanifest.lua +++ b/[esx_addons]/esx_dmvschool/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX DMV School' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_drugs/fxmanifest.lua b/[esx_addons]/esx_drugs/fxmanifest.lua index 45e910b1..45782bd6 100644 --- a/[esx_addons]/esx_drugs/fxmanifest.lua +++ b/[esx_addons]/esx_drugs/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Drugs' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_garage/fxmanifest.lua b/[esx_addons]/esx_garage/fxmanifest.lua index 02614ad7..28a0dc29 100644 --- a/[esx_addons]/esx_garage/fxmanifest.lua +++ b/[esx_addons]/esx_garage/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Garage' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_holdup/fxmanifest.lua b/[esx_addons]/esx_holdup/fxmanifest.lua index 1aec4396..52619849 100644 --- a/[esx_addons]/esx_holdup/fxmanifest.lua +++ b/[esx_addons]/esx_holdup/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Holdup' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_joblisting/fxmanifest.lua b/[esx_addons]/esx_joblisting/fxmanifest.lua index a910652f..c5e4bd50 100644 --- a/[esx_addons]/esx_joblisting/fxmanifest.lua +++ b/[esx_addons]/esx_joblisting/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Job Listing' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_jobs/fxmanifest.lua b/[esx_addons]/esx_jobs/fxmanifest.lua index 8beb059a..25d637af 100644 --- a/[esx_addons]/esx_jobs/fxmanifest.lua +++ b/[esx_addons]/esx_jobs/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Jobs' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_license/fxmanifest.lua b/[esx_addons]/esx_license/fxmanifest.lua index 8d907995..9bef90a7 100644 --- a/[esx_addons]/esx_license/fxmanifest.lua +++ b/[esx_addons]/esx_license/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX License' -version '1.6.0' +version '1.6.5' server_scripts { '@async/async.lua', diff --git a/[esx_addons]/esx_lscustom/fxmanifest.lua b/[esx_addons]/esx_lscustom/fxmanifest.lua index d6ec6779..19efd417 100644 --- a/[esx_addons]/esx_lscustom/fxmanifest.lua +++ b/[esx_addons]/esx_lscustom/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX LS Customs' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_mechanicjob/fxmanifest.lua b/[esx_addons]/esx_mechanicjob/fxmanifest.lua index 4d24aeee..dfc4140a 100644 --- a/[esx_addons]/esx_mechanicjob/fxmanifest.lua +++ b/[esx_addons]/esx_mechanicjob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Mechanic Job' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_optionalneeds/fxmanifest.lua b/[esx_addons]/esx_optionalneeds/fxmanifest.lua index f5793a9a..2e788e88 100644 --- a/[esx_addons]/esx_optionalneeds/fxmanifest.lua +++ b/[esx_addons]/esx_optionalneeds/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Optional Needs' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_phone/fxmanifest.lua b/[esx_addons]/esx_phone/fxmanifest.lua index 96733393..c7f52a52 100644 --- a/[esx_addons]/esx_phone/fxmanifest.lua +++ b/[esx_addons]/esx_phone/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Phone' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_policejob/fxmanifest.lua b/[esx_addons]/esx_policejob/fxmanifest.lua index 60c00cf7..6dd5ac08 100644 --- a/[esx_addons]/esx_policejob/fxmanifest.lua +++ b/[esx_addons]/esx_policejob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Police Job' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_property/fxmanifest.lua b/[esx_addons]/esx_property/fxmanifest.lua index dddedcc2..0ef6d6e9 100644 --- a/[esx_addons]/esx_property/fxmanifest.lua +++ b/[esx_addons]/esx_property/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Property' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_realestateagentjob/fxmanifest.lua b/[esx_addons]/esx_realestateagentjob/fxmanifest.lua index 5201b2c8..1dbccfd7 100644 --- a/[esx_addons]/esx_realestateagentjob/fxmanifest.lua +++ b/[esx_addons]/esx_realestateagentjob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Real Estate Job' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_rpchat/fxmanifest.lua b/[esx_addons]/esx_rpchat/fxmanifest.lua index 4d8ae670..06774b5d 100644 --- a/[esx_addons]/esx_rpchat/fxmanifest.lua +++ b/[esx_addons]/esx_rpchat/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX RP Chat' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_service/fxmanifest.lua b/[esx_addons]/esx_service/fxmanifest.lua index d271c37c..9f49bd78 100644 --- a/[esx_addons]/esx_service/fxmanifest.lua +++ b/[esx_addons]/esx_service/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Service' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_shops/fxmanifest.lua b/[esx_addons]/esx_shops/fxmanifest.lua index 9aebaf69..fdf23909 100644 --- a/[esx_addons]/esx_shops/fxmanifest.lua +++ b/[esx_addons]/esx_shops/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Shops' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_sit/fxmanifest.lua b/[esx_addons]/esx_sit/fxmanifest.lua index 630b2898..2e971618 100644 --- a/[esx_addons]/esx_sit/fxmanifest.lua +++ b/[esx_addons]/esx_sit/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Sit' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_society/fxmanifest.lua b/[esx_addons]/esx_society/fxmanifest.lua index 43769fd6..79fe1448 100644 --- a/[esx_addons]/esx_society/fxmanifest.lua +++ b/[esx_addons]/esx_society/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Society' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_status/fxmanifest.lua b/[esx_addons]/esx_status/fxmanifest.lua index d4ebd2c7..68bd5b3f 100644 --- a/[esx_addons]/esx_status/fxmanifest.lua +++ b/[esx_addons]/esx_status/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Status' -version '1.6.0' +version '1.6.5' lua54 'yes' diff --git a/[esx_addons]/esx_taxijob/fxmanifest.lua b/[esx_addons]/esx_taxijob/fxmanifest.lua index b2e67b5f..54e4ea72 100644 --- a/[esx_addons]/esx_taxijob/fxmanifest.lua +++ b/[esx_addons]/esx_taxijob/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Taxi Job' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_vehicleshop/fxmanifest.lua b/[esx_addons]/esx_vehicleshop/fxmanifest.lua index f87595e3..82c483c0 100644 --- a/[esx_addons]/esx_vehicleshop/fxmanifest.lua +++ b/[esx_addons]/esx_vehicleshop/fxmanifest.lua @@ -6,7 +6,7 @@ lua54 'yes' description 'ESX Vehicle Shop' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' diff --git a/[esx_addons]/esx_voice/fxmanifest.lua b/[esx_addons]/esx_voice/fxmanifest.lua index a8e2697a..9ffc0aeb 100644 --- a/[esx_addons]/esx_voice/fxmanifest.lua +++ b/[esx_addons]/esx_voice/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Voice Controller' -version '1.6.0' +version '1.6.5' client_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_weaponshop/fxmanifest.lua b/[esx_addons]/esx_weaponshop/fxmanifest.lua index 65e74b5e..64296bf3 100644 --- a/[esx_addons]/esx_weaponshop/fxmanifest.lua +++ b/[esx_addons]/esx_weaponshop/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Weapon Shop' -version '1.6.0' +version '1.6.5' shared_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/esx_whitelist/fxmanifest.lua b/[esx_addons]/esx_whitelist/fxmanifest.lua index 8c6515e6..6319d5d9 100644 --- a/[esx_addons]/esx_whitelist/fxmanifest.lua +++ b/[esx_addons]/esx_whitelist/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'ESX Whitelist' -version '1.6.0' +version '1.6.5' server_scripts { '@es_extended/imports.lua', diff --git a/[esx_addons]/instance/fxmanifest.lua b/[esx_addons]/instance/fxmanifest.lua index 57aa044e..f5a4b905 100644 --- a/[esx_addons]/instance/fxmanifest.lua +++ b/[esx_addons]/instance/fxmanifest.lua @@ -4,7 +4,7 @@ game 'gta5' description 'Instance' -version '1.6.0' +version '1.6.5' shared_script '@es_extended/imports.lua' From 003a8efaf106e9414c6f01f05abe69658a97fdb6 Mon Sep 17 00:00:00 2001 From: Mycroft Date: Wed, 23 Mar 2022 16:25:16 +0000 Subject: [PATCH 64/64] Remove Submodule --- [esx_addons]/esx_multicharacter | 1 - 1 file changed, 1 deletion(-) delete mode 160000 [esx_addons]/esx_multicharacter diff --git a/[esx_addons]/esx_multicharacter b/[esx_addons]/esx_multicharacter deleted file mode 160000 index 02352a8e..00000000 --- a/[esx_addons]/esx_multicharacter +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 02352a8e18176cb9f369ba608aab66ccf0311fe0