CoreName = nil hasDonePreloading = {} local Countries = json.decode(LoadResourceFile(GetCurrentResourceName(), '/countries.json')) function contains(text, search) return string.find(text, search) ~= nil end function ReqLicense(src) local license = GetPlayerIdentifierByType(src, 'license') for k, v in pairs(Config.Slots.List) do if v.license == license then return v.slot end end end Citizen.CreateThread(function() if GetResourceState('qbx_core') == 'started' then QBX = exports['qbx_core'] CoreName = 'qbx_core' elseif GetResourceState('qb-core') == 'started' then QBCore = exports['qb-core']:GetCoreObject() CoreName = 'qb-core' end print('^2[0r-multicharacterv2]^7 Loaded!') print('^2[0r-multicharacterv2]^7 Core name:'.. CoreName) end) AddEventHandler('QBCore:Server:PlayerLoaded', function(Player) Wait(1000) hasDonePreloading[Player.PlayerData.source] = true end) AddEventHandler('QBCore:Server:OnPlayerUnload', function(src) hasDonePreloading[src] = false end) RegisterNetEvent('0r-multicharacterv2:server:changePlayerBucket') AddEventHandler('0r-multicharacterv2:server:changePlayerBucket', function() SetPlayerRoutingBucket(source, tonumber(source) + 1) end) lib.callback.register('0r-multicharacterv2:server:getSettings', function(source) local src = source local license = GetIdentifier(src) if not license then return Config.Default.Settings end local result = ExecuteSql('SELECT * FROM 0r_multicharacterv2 WHERE identifier = ?', { license }) if result and not result[1] then ExecuteSql('INSERT INTO 0r_multicharacterv2 (identifier, settings, slots) VALUES (?, ?, ?)', { license, json.encode(Config.Default.Settings), Config.Default.Slots }) return Config.Default.Settings end local settings = json.decode(result[1].settings) return settings end) lib.callback.register('0r-multicharacterv2:server:getAvailableSlot', function(source) local src = source local license = GetIdentifier(src) if not license then return end local result = ExecuteSql('SELECT * FROM 0r_multicharacterv2 WHERE identifier = ?', { license }) local otherSlot = 0 if Config.Slots.DiscordPerm.Status then local discordSlot = ReqDiscord(src) if discordSlot then otherSlot = otherSlot + discordSlot end end local licenseSlot = ReqLicense(src) if licenseSlot then otherSlot = otherSlot + licenseSlot end if result and not result[1] then return Config.Default.Slots end return result[1].slots end) lib.callback.register('0r-multicharacterv2:server:checkCharacters', function(source) SetPlayerRoutingBucket(source, source) local license = GetIdentifier(source) if not license then return {} end local playerChars = {} local p = promise.new() ExecuteSql('SELECT * FROM players WHERE license = ?', { license }, function(result) for i = 1, (#result), 1 do result[i].charinfo = json.decode(result[i].charinfo) result[i].money = json.decode(result[i].money) result[i].job = json.decode(result[i].job) playerChars[#playerChars+1] = result[i] end p:resolve(playerChars) end) return { chars = Citizen.Await(p), countries = Countries, } end) lib.callback.register('0r-multicharacterv2:server:playCharacter', function(source, data) local src = source if CoreName == 'qb-core' then if QBCore.Player.Login(src, data.citizenid) then repeat Wait(10) until hasDonePreloading[src] print('^2[0r-multicharacterv2]^7 '..GetPlayerName(src)..' (Citizen ID: '..data.citizenid..') has successfully loaded!') QBCore.Commands.Refresh(src) loadHouseData(src) if Config.SpawnSelector.Skip and not Config.SpawnSelector.Use0Resmon then local coords = json.decode(data.position) TriggerClientEvent('0r-multicharacterv2:client:spawnLastLocation', src, coords, data) elseif not Config.SpawnSelector.Skip and not Config.SpawnSelector.Use0Resmon then Config.SpawnSelector.Open(src, json.decode(data.position)) else TriggerClientEvent('0r-multicharacterv2:client:closeNUIdefault', src, false) end end elseif CoreName == 'qbx_core' then if QBX:Login(src, data.citizenid) then repeat Wait(10) until hasDonePreloading[src] print('^2[0r-multicharacterv2]^7 '..GetPlayerName(src)..' (Citizen ID: '..data.citizenid..') has successfully loaded!') if Config.SpawnSelector.Skip and not Config.SpawnSelector.Use0Resmon then local coords = json.decode(data.position) TriggerClientEvent('0r-multicharacterv2:client:spawnLastLocation', src, coords, data) elseif not Config.SpawnSelector.Skip and not Config.SpawnSelector.Use0Resmon then Config.SpawnSelector.Open(src, json.decode(data.position)) else TriggerClientEvent('0r-multicharacterv2:client:closeNUIdefault', src, false) end end end SetPlayerRoutingBucket(source, Config.Default.Bucket) end) lib.callback.register('0r-multicharacterv2:server:changeSetting', function(source, data) local src = source local license = GetIdentifier(src) if not license then return end local result = ExecuteSql('SELECT * FROM 0r_multicharacterv2 WHERE identifier = ?', { license }) if result and not result[1] then ExecuteSql('INSERT INTO 0r_multicharacterv2 (identifier, settings) VALUES (?, ?)', { license, json.encode(Config.DefaultSettings) }) return end local settings = json.decode(result[1].settings) if data.subhead then settings[data.head][data.subhead][data.body] = data.value elseif data.body then settings[data.head][data.body] = data.value else settings[data.head] = data.value end ExecuteSql('UPDATE 0r_multicharacterv2 SET settings = ? WHERE identifier = ?', { json.encode(settings), license }) end) lib.callback.register('0r-multicharacterv2:server:changeType', function(source, head, data) local src = source local license = GetIdentifier(src) if not license then return end local result = ExecuteSql('SELECT * FROM 0r_multicharacterv2 WHERE identifier = ?', { license }) if result and not result[1] then ExecuteSql('INSERT INTO 0r_multicharacterv2 (identifier, settings) VALUES (?, ?)', { license, json.encode(Config.DefaultSettings) }) return end local settings = json.decode(result[1].settings) if head == 'filter' then settings.filter.type = data end if head == 'particle' then settings.particle.type = data end if head == 'animation' then settings.animations.single = data end if head == 'scenario' then settings.animations.scenario.single = data end if head == 'theme' then settings.color = data end if head == 'background' then settings.coords = data end if head == 'weather' then settings.weather.type = data end if head == 'time' then settings.time.hour = data end ExecuteSql('UPDATE 0r_multicharacterv2 SET settings = ? WHERE identifier = ?', { json.encode(settings), license }) end) lib.callback.register('0r-multicharacterv2:server:createCharacter', function(source, data) local src = source local newData = {} newData.cid = data.cid newData.charinfo = data if CoreName == 'qb-core' then if QBCore.Player.Login(src, false, newData) then repeat Wait(10) until hasDonePreloading[src] print('^2[0r-multicharacterv2]^7 '..GetPlayerName(src)..' has successfully loaded!') QBCore.Commands.Refresh(src) if Config.ApartmentStart then loadHouseData(src) if GetResourceState('0r-apartment-v2') == 'started' then print('^2[0r-multicharacterv2]^7 0R Apartment resource is started!') TriggerClientEvent("0r-multicharacterv2:client:closeNUIdefault", src, false) TriggerClientEvent('0r-multicharacterv2:client:createApartment', src) elseif GetResourceState('qb-apartments') == 'started' then print('^2[0r-multicharacterv2]^7 QB Apartment resource is started!') TriggerClientEvent("0r-multicharacterv2:client:closeNUI", src) TriggerClientEvent('apartments:client:setupSpawnUI', src, newData) else TriggerClientEvent("0r-multicharacterv2:client:closeNUIdefault", src, true) end GiveStarterItems(src) else loadHouseData(src) TriggerClientEvent("0r-multicharacterv2:client:closeNUIdefault", src, true) TriggerEvent('apartments:client:SetHomeBlip', nil) GiveStarterItems(src) end end elseif CoreName == 'qbx_core' then if QBX:Login(src, false, newData) then repeat Wait(10) until hasDonePreloading[src] print('^2[0r-multicharacterv2]^7 '..GetPlayerName(src)..' has successfully loaded!') if Config.ApartmentStart then if GetResourceState('0r-apartment-v2') == 'started' then print('^2[0r-multicharacterv2]^7 0R Apartment resource is started!') TriggerClientEvent("0r-multicharacterv2:client:closeNUIdefault", src, false) TriggerClientEvent('0r-multicharacterv2:client:createApartment', src) else TriggerClientEvent("0r-multicharacterv2:client:closeNUIdefault", src, true) end GiveStarterItems(src) else TriggerClientEvent("0r-multicharacterv2:client:closeNUIdefault", src, true) GiveStarterItems(src) end end end end) lib.callback.register('0r-multicharacterv2:server:openNewSlot', function(source, data) local identifier = GetIdentifier(source) if contains(data, 'tbx') then local slots = ReqTebex(identifier, data) if slots then ExecuteSql('UPDATE 0r_multicharacterv2 SET slots = slots + ? WHERE identifier = ?', { slots, identifier }) end local result = ExecuteSql('SELECT slots FROM `0r_multicharacterv2` WHERE identifier = ?', { identifier }) if result and result[1] then return result[1].slots end else local slots = ReqCode(data) if slots then ExecuteSql('UPDATE 0r_multicharacterv2 SET slots = slots + ? WHERE identifier = ?', { slots, identifier }) end ExecuteSql('DELETE FROM `0r_multicharacterv2-codes` WHERE code = ?', { data }) local result = ExecuteSql('SELECT slots FROM `0r_multicharacterv2` WHERE identifier = ?', { identifier }) if result and result[1] then return result[1].slots end end end)