From a4f4da621f44d630882ba23fc6074dbf5ea96d30 Mon Sep 17 00:00:00 2001 From: Linden Date: Mon, 17 May 2021 20:33:25 +1000 Subject: [PATCH] feat(legacy/multichar): Added support for esx_multicharacter; applied minor changes to spawning --- client/main.lua | 50 +++++++++---- config.lua | 1 + server/classes/player.lua | 7 +- server/main.lua | 149 ++++++++++++++++++++++++++++++-------- 4 files changed, 158 insertions(+), 49 deletions(-) diff --git a/client/main.lua b/client/main.lua index c62cab8b..3524c5cb 100644 --- a/client/main.lua +++ b/client/main.lua @@ -1,8 +1,9 @@ local isPaused, isDead, pickups = false, false, {} Citizen.CreateThread(function() - while NetworkIsPlayerActive(PlayerId()) do + while NetworkIsPlayerActive(PlayerId()) and not Config.Multichar do Citizen.Wait(5) + DoScreenFadeOut(500) TriggerServerEvent('esx:onPlayerJoined') break end @@ -42,25 +43,42 @@ AddEventHandler('esx:playerLoaded', function(playerData, isNew) }) end - exports.spawnmanager:spawnPlayer({ - x = playerData.coords.x, - y = playerData.coords.y, - z = playerData.coords.z + 0.25, - heading = playerData.coords.heading, - model = `mp_m_freemode_01`, - skipFade = false - }, function() - TriggerEvent('esx:onPlayerSpawn') - TriggerEvent('playerSpawned') -- compatibility with old scripts, will be removed soon. - TriggerEvent('esx:restoreLoadout') - + if Config.Multichar then + TriggerEvent('esx_multicharacter:SpawnCharacter', playerData.coords, isNew, playerData.skin) Citizen.Wait(4000) + else + exports.spawnmanager:spawnPlayer({ + x = playerData.coords.x, + y = playerData.coords.y, + z = playerData.coords.z + 0.25, + heading = playerData.coords.heading, + model = `mp_m_freemode_01`, + skipFade = true + }, function() + TriggerEvent('esx:onPlayerSpawn') + TriggerEvent('playerSpawned') -- compatibility with old scripts + TriggerEvent('esx:restoreLoadout') + end) + Citizen.Wait(1000) + if isNew then + if playerData.skin.sex == 0 then + TriggerEvent('skinchanger:loadDefaultModel', true) + else + TriggerEvent('skinchanger:loadDefaultModel', false) + end + elseif playerData.skin then TriggerEvent('skinchanger:loadSkin', playerData.skin) end ShutdownLoadingScreen() ShutdownLoadingScreenNui() + TriggerEvent('esx:loadingScreenOff') + DoScreenFadeIn(500) FreezeEntityPosition(ESX.PlayerData.ped, false) - StartServerSyncLoops() - end) - TriggerEvent('esx:loadingScreenOff') -- compatibility with old scripts, will be removed soon. + end + StartServerSyncLoops() +end) + +RegisterNetEvent('esx:onPlayerLogout') +AddEventHandler('esx:onPlayerLogout', function() + ESX.PlayerLoaded = false end) RegisterNetEvent('esx:setMaxWeight') diff --git a/config.lua b/config.lua index 89fbb379..194cd219 100644 --- a/config.lua +++ b/config.lua @@ -18,3 +18,4 @@ 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 -- Requires esx_multicharacter diff --git a/server/classes/player.lua b/server/classes/player.lua index 64d6c1f9..148210b4 100644 --- a/server/classes/player.lua +++ b/server/classes/player.lua @@ -14,8 +14,9 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, self.variables = {} self.weight = weight self.maxWeight = Config.MaxWeight + if Config.Multichar then self.license = 'license'..string.sub(identifier, 6) else self.license = 'license:'..identifier end - ExecuteCommand(('add_principal identifier.license:%s group.%s'):format(self.identifier, self.group)) + ExecuteCommand(('add_principal identifier.%s group.%s'):format(self.license, self.group)) self.triggerEvent = function(eventName, ...) TriggerClientEvent(eventName, self.source, ...) @@ -66,9 +67,9 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, end self.setGroup = function(newGroup) - ExecuteCommand(('remove_principal identifier.license:%s group.%s'):format(self.identifier, self.group)) + ExecuteCommand(('remove_principal identifier.%s group.%s'):format(self.license, self.group)) self.group = newGroup - ExecuteCommand(('add_principal identifier.license:%s group.%s'):format(self.identifier, self.group)) + ExecuteCommand(('add_principal identifier.%s group.%s'):format(self.license, self.group)) end self.getGroup = function() diff --git a/server/main.lua b/server/main.lua index df1a7e18..b82382b3 100644 --- a/server/main.lua +++ b/server/main.lua @@ -3,47 +3,41 @@ Citizen.CreateThread(function() SetGameType('ESX Roleplay') end) +local awaitingRegistration = {} RegisterNetEvent('esx:onPlayerJoined') -AddEventHandler('esx:onPlayerJoined', function() - if not ESX.Players[source] then - onPlayerJoined(source) - end -end) +if Config.Multichar then + AddEventHandler('esx_identity:completedRegistration', function(playerId, data) + awaitingRegistration[playerId] = data + end) + AddEventHandler('esx:onPlayerJoined', function(src, char, isNew) + if not ESX.Players[src] then + onPlayerJoined(src, char, isNew) + end + end) +else + AddEventHandler('esx:onPlayerJoined', function() + if not ESX.Players[source] then + onPlayerJoined(source) + end + end) +end -function onPlayerJoined(playerId) +function onPlayerJoined(playerId, char, isNew) local identifier = ESX.GetIdentifier(playerId) + if char then identifier = 'char'..char..':'..identifier end if identifier then if ESX.GetPlayerFromIdentifier(identifier) then DropPlayer(playerId, ('there was an error loading your character!\nError code: identifier-active-ingame\n\nThis error is caused by a player on this server who has the same identifier as you have. Make sure you are not playing on the same Rockstar account.\n\nYour Rockstar identifier: %s'):format(identifier)) + elseif Config.Multichar and isNew then + createESXPlayer(identifier, playerId) else MySQL.Async.fetchScalar('SELECT 1 FROM users WHERE identifier = @identifier', { ['@identifier'] = identifier }, function(result) if result then loadESXPlayer(identifier, playerId, false) - else - local accounts = {} - - for account,money in pairs(Config.StartingAccountMoney) do - accounts[account] = money - end - - if IsPlayerAceAllowed(playerId, "command") then - print(('^2[INFO] ^0 Player ^5%s ^0Has been granted admin permissions via ^5Ace Perms.^7'):format(playerId)) - defaultGroup = "admin" - else - defaultGroup = "user" - end - - MySQL.Async.execute('INSERT INTO users (`accounts`, `identifier`, `group`) VALUES (@accounts, @identifier, @group)', { - ['@accounts'] = json.encode(accounts), - ['@identifier'] = identifier, - ['@group'] = defaultGroup - }, function(rowsChanged) - loadESXPlayer(identifier, playerId, true) - end) - end + else createESXPlayer(identifier, playerId) end end) end else @@ -51,6 +45,51 @@ function onPlayerJoined(playerId) end end +function createESXPlayer(identifier, playerId) + local accounts = {} + + for account,money in pairs(Config.StartingAccountMoney) do + accounts[account] = money + end + + if IsPlayerAceAllowed(playerId, "command") then + print(('^2[INFO] ^0 Player ^5%s ^0Has been granted admin permissions via ^5Ace Perms.^7'):format(playerId)) + defaultGroup = "admin" + else + defaultGroup = "user" + end + + if not Config.Multichar then + MySQL.Async.execute('INSERT INTO users (`accounts`, `identifier`, `group`) VALUES (@accounts, @identifier, @group)', { + ['@accounts'] = json.encode(accounts), + ['@identifier'] = identifier, + ['@group'] = defaultGroup + }, function(rowsChanged) + loadESXPlayer(identifier, playerId, true) + end) + else + local data + awaitingRegistration[playerId] = true + while true do + Citizen.Wait(250) + if awaitingRegistration[playerId] ~= true then data = awaitingRegistration[playerId] break end + end + awaitingRegistration[playerId] = nil + MySQL.Async.execute('INSERT INTO users (`accounts`, `identifier`, `group`, `firstname`, `lastname`, `dateofbirth`, `sex`, `height`) VALUES (@accounts, @identifier, @group, @firstname, @lastname, @dateofbirth, @sex, @height)', { + ['@accounts'] = json.encode(accounts), + ['@identifier'] = identifier, + ['@group'] = defaultGroup, + ['@firstname'] = data.firstname, + ['@lastname'] = data.lastname, + ['@dateofbirth'] = data.dateofbirth, + ['@sex'] = data.sex, + ['@height'] = data.height, + }, function(rowsChanged) + loadESXPlayer(identifier, playerId, true) + end) + end +end + AddEventHandler('playerConnecting', function(name, setCallback, deferrals) deferrals.defer() local playerId = source @@ -81,7 +120,13 @@ function loadESXPlayer(identifier, playerId, isNew) } table.insert(tasks, function(cb) - MySQL.Async.fetchAll('SELECT accounts, job, job_grade, `group`, loadout, position, inventory FROM users WHERE identifier = @identifier', { + local query + if Config.Multichar then + query = 'SELECT `accounts`, `job`, `job_grade`, `group`, `loadout`, `position`, `inventory`, `skin`, `firstname`, `lastname`, `dateofbirth`, `sex`, `height` FROM `users` WHERE identifier = @identifier' + else + query = 'SELECT `accounts`, `job`, `job_grade`, `group`, `loadout`, `position`, `inventory`, `skin` FROM `users` WHERE identifier = @identifier' + end + MySQL.Async.fetchAll(query, { ['@identifier'] = identifier }, function(result) local job, grade, jobObject, gradeObject = result[1].job, tostring(result[1].job_grade) @@ -203,6 +248,25 @@ function loadESXPlayer(identifier, playerId, isNew) userData.coords = {x = -269.4, y = -955.3, z = 31.2, heading = 205.8} end + -- Skin + if result[1].skin and result[1].skin ~= '' then + userData.skin = json.decode(result[1].skin) + elseif userData.sex then + if userData.sex == 'f' then userData.skin = {sex=1} else userData.skin = {sex=0} end + end + + -- Identity + if Config.Multichar then + if result[1].firstname and result[1].firstname ~= '' then + userData.firstname = result[1].firstname + userData.lastname = result[1].lastname + userData.playerName = userData.firstname..' '..userData.lastname + if result[1].dateofbirth then userData.dateofbirth = result[1].dateofbirth end + if result[1].sex then userData.sex = result[1].sex end + if result[1].height then userData.height = result[1].height end + end + end + cb() end) end) @@ -210,6 +274,15 @@ function loadESXPlayer(identifier, playerId, isNew) Async.parallel(tasks, function(results) local xPlayer = CreateExtendedPlayer(playerId, identifier, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, userData.loadout, userData.playerName, userData.coords) ESX.Players[playerId] = xPlayer + + if Config.Multichar and userData.firstname then + xPlayer.set('firstName', userData.firstname) + xPlayer.set('lastName', userData.lastname) + if userData.dateofbirth then xPlayer.set('dateofbirth', userData.dateofbirth) end + if userData.sex then xPlayer.set('sex', userData.sex) end + if userData.height then xPlayer.set('height', userData.height) end + end + TriggerEvent('esx:playerLoaded', playerId, xPlayer, isNew) xPlayer.triggerEvent('esx:playerLoaded', { @@ -220,7 +293,8 @@ function loadESXPlayer(identifier, playerId, isNew) job = xPlayer.getJob(), loadout = xPlayer.getLoadout(), maxWeight = xPlayer.getMaxWeight(), - money = xPlayer.getMoney() + money = xPlayer.getMoney(), + skin = userData.skin }, isNew) xPlayer.triggerEvent('esx:createMissingPickups', ESX.Pickups) @@ -250,6 +324,21 @@ AddEventHandler('playerDropped', function(reason) end end) +if Config.Multichar then + AddEventHandler('esx:playerLogout', function(playerId) + local xPlayer = ESX.GetPlayerFromId(playerId) + awaitingRegistration[playerId] = nil + if xPlayer then + TriggerEvent('esx:playerDropped', playerId, reason) + + ESX.SavePlayer(xPlayer, function() + ESX.Players[playerId] = nil + end) + end + TriggerClientEvent("esx:onPlayerLogout", playerId) + end) +end + RegisterNetEvent('esx:updateCoords') AddEventHandler('esx:updateCoords', function(coords) local xPlayer = ESX.GetPlayerFromId(source)