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