mirror of
https://github.com/esx-framework/esx_core.git
synced 2026-08-29 01:01:22 +00:00
refactor: swap to oxmysql
ESX officially uses oxmysql with new syntax, so follow suite.
This commit is contained in:
+4
-4
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -19,7 +19,7 @@ shared_scripts {
|
||||
|
||||
server_scripts {
|
||||
'@es_extended/imports.lua',
|
||||
'@mysql-async/lib/MySQL.lua',
|
||||
'@oxmysql/lib/MySQL.lua',
|
||||
'server/*.lua',
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||

|
||||
|
||||
### 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
@@ -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
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user