2026-04-14 17:41:39 +02:00

230 lines
9.3 KiB
Lua

if Config.Framework == 'esx' or Config.Framework == 'oldesx' then
Citizen.CreateThread(function()
while Core == nil do
Wait(0)
end
ESXStarterItem = {
[1] = {item = 'water', amount = 2},
[2] = {item = 'phone', amount = 1},
}
RegisterCallback('m-multichar-server-GetCharacters', function(source, cb)
-- Nur logout triggern wenn Spieler wirklich geladen ist (verhindert common.lua:20 nil error)
local existingPlayer = Core.GetPlayerFromId(source)
if existingPlayer then
TriggerEvent('esx:playerLogout', tonumber(source))
end
SetPlayerRoutingBucket(source, tonumber(source))
identifier = Config.Prefix .. '%:' .. Core.GetIdentifier(source)
if not identifier then
DropPlayer(source, "We can't find your license id!")
return
end
local chars = {}
local result = ExecuteSql('SELECT * FROM users WHERE identifier LIKE "%' .. identifier .. '%"')
for i = 1, (#result), 1 do
result[i].charinfo = {}
result[i].charinfo = {
firstname = result[i].firstname,
lastname = result[i].lastname,
birthdate = result[i].dateofbirth,
nationality = result[i].nationality or 'UNKOWN',
phone = result[i].phone_number or "000-000",
}
result[i].money = {}
result[i].money = {
cash = json.decode(result[i].accounts).money or 0,
bank = json.decode(result[i].accounts).bank or 0
}
result[i].esxjobName = result[i].job
result[i].job = {
name = result[i].esxjobName or 'unemployed',
grade = result[i].job_grade,
jobname = result[i].esxjobName or 'unemployed'
}
result[i].esxjobName2 = result[i].job2
result[i].job2 = {
name = result[i].esxjobName2 or 'None',
grade = result[i].job_grade or 0,
jobname = result[i].esxjobName2 or 'unemployed'
}
playersData[result[i].identifier] = tonumber(result[i].playtime)
local totalPlayedTime = SecondsToClock(tonumber(result[i].playtime))
result[i].playtime = totalPlayedTime
table.insert(chars, result[i])
end
cb(chars)
end)
RegisterCallback("m-multichar:server:getSkin", function(source, cb, cid)
local src = source
local result = ExecuteSql('SELECT skin FROM users WHERE identifier = "' .. cid .. '"')
if result[1] ~= nil then
cb(result[1].skin)
else
cb(nil)
end
end)
RegisterCallback('m-multichar-server-DeleteCharacter', function(source, cb, citizenid)
local query = 'DELETE FROM %s WHERE %s = ?'
local queries = {}
local count = 0
for table, column in pairs(Config.DeleteTable) do
count += 1
queries[count] = { query = query:format(table, column), values = { citizenid } }
end
MySQL.transaction(queries, function(result)
if result then
print(('[^2INFO^7] Player ^5%s %s^7 has deleted a character ^5(%s)^7'):format(GetPlayerName(source),
source, citizenid))
Wait(50)
cb(true)
else
error('\n^1Transaction failed while trying to delete ' .. citizenid .. '^0')
cb(false)
end
end)
end)
Core.RegisterCommand('logout', Config.LoutOutPermission, function(xPlayer, args, showError)
if not xPlayer then return end
local source = xPlayer.source
TriggerEvent("m-multichar-server-Relog", source)
end, true,
{
help = 'LOGOUT Commnad',
validate = true,
})
end)
-- Hilfsfunktion: Warten bis License-Identifier verfügbar
-- WICHTIG: Muss immer aus einem Citizen.CreateThread heraus aufgerufen werden!
local function WaitForLicenseIdentifier(src)
local attempts = 0
repeat
Wait(300)
attempts = attempts + 1
local ids = GetPlayerIdentifiers(src)
for _, id in ipairs(ids) do
if string.sub(id, 1, 8) == "license:" then
return true
end
end
until attempts >= 15
print('[codem-multicharacter] WARN: Kein License-Identifier für Source ' .. tostring(src) .. ' nach 15 Versuchen')
return false
end
LoadPlayer = function(source)
local src = source
local ts = 0
while not Core.GetPlayerFromId(src) and ts < 1000 do
ts += 1
Wait(0)
end
local xPlayer = Core.GetPlayerFromId(src)
if not xPlayer then
print('[codem-multicharacter] WARN: Player ' .. src .. ' not found after timeout in LoadPlayer')
return false
end
local ply = Player(src).state
if not ply then return false end
local identifier = xPlayer.identifier
if identifier then
ply:set('identifier', identifier, true)
end
return true
end
RegisterServerEvent("m-multichar-server-CreateChar", function(data)
local src = source
Citizen.CreateThread(function()
-- Warten bis License-Identifier sicher verfügbar
WaitForLicenseIdentifier(src)
data.cid = tonumber(data.cid) + 1
if data.gender == 0 then
data.sex = "m"
else
data.sex = "f"
end
data.dateofbirth = data.birthdate
TriggerEvent('esx:onPlayerJoined', src, Config.Prefix .. data.cid, data)
LoadPlayer(tonumber(src))
local ply = Core.GetPlayerFromId(src)
if not ply then
print('[codem-multicharacter] WARN: GetPlayerFromId nil nach CreateChar für Source ' .. tostring(src))
return
end
local identifier = ply.identifier or 'unknown'
if Config.Framework == 'esx' or Config.Framework == 'oldesx' then
ExecuteSql('UPDATE users SET nationality = "' .. data.nationality .. '" WHERE identifier = "' .. identifier .. '"')
end
PlayTimeLogin(identifier)
SetPlayerRoutingBucket(src, Config.DefaultBucket)
TriggerClientEvent("m-multichar:client:closeNUIdefault", src)
end)
end)
RegisterServerEvent("m-multichar-server-LoadPlayer", function(data)
local src = source
Citizen.CreateThread(function()
-- Warten bis License-Identifier sicher verfügbar
WaitForLicenseIdentifier(src)
local _, _, number = string.find(data.identifier, Config.Prefix .. "(%d+)")
TriggerClientEvent("m-multichar:client:closeNUIdefault", src)
SetPlayerRoutingBucket(src, Config.DefaultBucket)
TriggerEvent('esx:onPlayerJoined', src, Config.Prefix .. number, nil)
LoadPlayer(src)
PlayTimeLogin(data.identifier)
print('^2[codem-multichacter]^7 ' .. GetPlayerName(src) .. ' (Identifier: ' ..
data.identifier .. ') has succesfully loaded!')
end)
end)
RegisterNetEvent("m-multichar-server-Relog", function(source, srcc)
source = source or srcc
-- Nil-safe: nur logout wenn Spieler wirklich existiert
local player = Core.GetPlayerFromId(source)
if player then
TriggerEvent('esx:playerLogout', source)
end
TriggerClientEvent('m-multichar-client-Load', source)
local actuallTime = os.time()
if source == nil then return end
if player == nil then return end
local identifier = player.identifier
if identifier == nil then return end
if (playersData[identifier] ~= nil and playersDataActuall[identifier] ~= nil) then
local time = tonumber(actuallTime - playersDataActuall[identifier])
local timeFormatted = SecondsToClock(time)
local timeAll = time + playersData[identifier]
local timeAllFormatted = SecondsToClock(timeAll)
if Config.Framework == 'esx' or Config.Framework == 'oldesx' then
ExecuteSql('UPDATE users SET playtime = "' .. timeAll .. '" WHERE identifier = "' .. identifier .. '"')
elseif Config.Framework == 'qb' or Config.Framework == 'oldqb' then
ExecuteSql('UPDATE players SET playtime = "' .. timeAll .. '" WHERE citizenid = "' .. identifier .. '"')
end
playersData[identifier] = timeAll
end
end)
RegisterServerEvent("m-multichar-server-StarterItems")
AddEventHandler("m-multichar-server-StarterItems", function()
local src = source
local xPlayer = Core.GetPlayerFromId(src)
if not xPlayer then return end
for _, v in pairs(ESXStarterItem) do
AddItem(src, v.item, v.amount, false)
end
end)
end