refactor: swap to oxmysql

ESX officially uses oxmysql with new syntax, so follow suite.
This commit is contained in:
Linden
2022-02-12 05:58:45 +11:00
parent 02352a8e18
commit 72450dfcd6
7 changed files with 74 additions and 101 deletions
+4 -4
View File
@@ -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
+3 -5
View File
@@ -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
+3 -7
View File
@@ -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';
+1 -1
View File
@@ -19,7 +19,7 @@ shared_scripts {
server_scripts {
'@es_extended/imports.lua',
'@mysql-async/lib/MySQL.lua',
'@oxmysql/lib/MySQL.lua',
'server/*.lua',
}
+12 -34
View File
@@ -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 <https://github.com/thelindat/> 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
+7 -7
View File
@@ -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
+44 -43
View File
@@ -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)