431 lines
		
	
	
		
			No EOL
		
	
	
		
			16 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			431 lines
		
	
	
		
			No EOL
		
	
	
		
			16 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
module 'shared/debug'
 | 
						|
module 'shared/resource'
 | 
						|
module 'shared/table'
 | 
						|
module 'shared/utils'
 | 
						|
module 'shared/player'
 | 
						|
 | 
						|
ESX = nil
 | 
						|
Version = resource.version(Bridge.FrameworkName)
 | 
						|
 | 
						|
IsExport, ESX = pcall(function()
 | 
						|
    return exports[Bridge.FrameworkName]:getSharedObject()
 | 
						|
end)
 | 
						|
 | 
						|
if not IsExport then
 | 
						|
    TriggerEvent(Bridge.FrameworkEvent, function(obj) ESX = obj end)
 | 
						|
end
 | 
						|
 | 
						|
Bridge.Debug('Framework', 'ESX', Version)
 | 
						|
 | 
						|
local clientRequests = {}
 | 
						|
TriggerClientCallback = function(source, name, callback, ...)
 | 
						|
    local id = #clientRequests + 1
 | 
						|
    clientRequests[id] = callback
 | 
						|
    TriggerClientEvent(Bridge.Resource .. ':TriggerClientCallback', source, name, id, ...)
 | 
						|
end
 | 
						|
 | 
						|
RegisterNetEvent(Bridge.Resource .. ':ClientCallback', function(requestId, ...)
 | 
						|
    if clientRequests[requestId] then
 | 
						|
        clientRequests[requestId](...)
 | 
						|
        clientRequests[requestId] = nil
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
AddEventHandler(Bridge.FrameworkPrefix .. ':playerLoaded', function(playerId, xPlayer)
 | 
						|
    local player = Database.prepare('SELECT `gang`, `gang_grade`, `metadata` FROM `users` WHERE identifier = ?', { xPlayer.getIdentifier() })
 | 
						|
    local gang = player.gang
 | 
						|
    local grade = tostring(player.gang_grade)
 | 
						|
    local gangObject = {}
 | 
						|
    local gradeObject = {}
 | 
						|
 | 
						|
    if Framework.DoesGangExist(gang, grade) then
 | 
						|
        gangObject, gradeObject = ESX.Gangs[gang], ESX.Gangs[gang].grades[grade]
 | 
						|
    else
 | 
						|
        if Bridge.DebugMode then print(('[^3WARNING^7] Ignoring invalid gang for ^5%s^7 [gang: ^5%s^7, grade: ^5%s^7]'):format(xPlayer.getIdentifier(), gang, grade)) end
 | 
						|
        gang, grade = 'none', '0'
 | 
						|
        gangObject, gradeObject = ESX.Gangs[gang], ESX.Gangs[gang].grades[grade]
 | 
						|
    end
 | 
						|
 | 
						|
    local gangData = {}
 | 
						|
    gangData.name = gangObject.name
 | 
						|
    gangData.label = gangObject.label
 | 
						|
 | 
						|
    gangData.grade = tonumber(grade)
 | 
						|
    gangData.grade_name = gradeObject.name
 | 
						|
    gangData.grade_label = gradeObject.label
 | 
						|
 | 
						|
    local stateBag = Player(playerId).state
 | 
						|
    stateBag:set("gang", gangData, true)
 | 
						|
    stateBag:set("duty", false, true)
 | 
						|
 | 
						|
    local metadata = pcall(xPlayer.getMeta)
 | 
						|
    if not metadata then
 | 
						|
        stateBag:set("metadata", json.decode(player.metadata), true)
 | 
						|
    end
 | 
						|
 | 
						|
    pcall(Framework.OnPlayerLoaded, xPlayer.source)
 | 
						|
end)
 | 
						|
 | 
						|
AddEventHandler('playerDropped', function()
 | 
						|
    local src = source
 | 
						|
    local xPlayer = ESX.GetPlayerFromId(src)
 | 
						|
    if xPlayer then
 | 
						|
        local metadata = pcall(xPlayer.getMeta)
 | 
						|
        if not metadata then
 | 
						|
            Database.prepare('UPDATE `users` SET `metadata` = ? WHERE `identifier` = ?', { json.encode(xPlayer.get('metadata')), xPlayer.getIdentifier() })
 | 
						|
        end
 | 
						|
    end
 | 
						|
    TriggerClientEvent(Bridge.FrameworkPrefix .. ':playerLogout', src)
 | 
						|
    pcall(Framework.OnPlayerUnload, src)
 | 
						|
end)
 | 
						|
 | 
						|
AddEventHandler(Bridge.FrameworkPrefix .. ':playerLogout', function(playerId)
 | 
						|
    local xPlayer = ESX.GetPlayerFromId(playerId)
 | 
						|
    if xPlayer then
 | 
						|
        local metadata = pcall(xPlayer.getMeta)
 | 
						|
        if not metadata then
 | 
						|
            Database.prepare('UPDATE `users` SET `metadata` = ? WHERE `identifier` = ?', { json.encode(xPlayer.get('metadata')), xPlayer.getIdentifier() })
 | 
						|
        end
 | 
						|
    end
 | 
						|
    pcall(Framework.OnPlayerUnload, playerId)
 | 
						|
end)
 | 
						|
 | 
						|
AddEventHandler(Bridge.FrameworkPrefix .. ':setJob', function()
 | 
						|
    pcall(Framework.OnJobUpdate, source)
 | 
						|
end)
 | 
						|
 | 
						|
AddStateBagChangeHandler('duty', nil, function(bagName, _, value)
 | 
						|
    local playerId = GetPlayerFromStateBagName(bagName)
 | 
						|
    pcall(Framework.OnJobDutyUpdate, playerId)
 | 
						|
end)
 | 
						|
 | 
						|
AddStateBagChangeHandler('gang', nil, function(bagName, _, gang)
 | 
						|
    local playerId = GetPlayerFromStateBagName(bagName)
 | 
						|
    local Player = Framework.GetPlayer(playerId)
 | 
						|
    if not Player then return end
 | 
						|
    if not gang.name or not gang.grade then return end
 | 
						|
    Database.prepare('UPDATE `users` SET gang = ?, gang_grade = ? WHERE identifier = ?', { gang.name, gang.grade, Player.Identifier})
 | 
						|
    pcall(Framework.OnGangUpdate, playerId)
 | 
						|
end)
 | 
						|
 | 
						|
Framework.CreateCallback = function(name, cb)
 | 
						|
    ESX.RegisterServerCallback(name, cb)
 | 
						|
end
 | 
						|
 | 
						|
Framework.TriggerCallback = function(source, name, cb, ...)
 | 
						|
    local success = pcall(ESX.TriggerClientCallback, source, name, cb, ...)
 | 
						|
    if not success then
 | 
						|
        TriggerClientCallback(source, name, cb, ...)
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
Framework.CreateUseableItem = function(name, cb)
 | 
						|
    ESX.RegisterUsableItem(name, cb)
 | 
						|
end
 | 
						|
 | 
						|
Framework.GetPlayer = function(source)
 | 
						|
    local src = source
 | 
						|
    local xPlayer = ESX.GetPlayerFromId(src)
 | 
						|
    if not xPlayer then return nil end
 | 
						|
    local self = table.deepclone(Framework.Player)
 | 
						|
    ---@cast self Player
 | 
						|
    local PlayerJob = xPlayer.getJob()
 | 
						|
    local PlayerGang = Player(src).state.gang
 | 
						|
    self.source = xPlayer.source
 | 
						|
    self.Identifier = xPlayer.getIdentifier()
 | 
						|
    self.Name = GetPlayerName(src)
 | 
						|
    self.Firstname = xPlayer.get('firstName')
 | 
						|
    self.Lastname = xPlayer.get('lastName')
 | 
						|
    self.DateOfBirth = xPlayer.get('dateofbirth') or '01/01/2000'
 | 
						|
    self.Gender = xPlayer.get("sex") or "m"
 | 
						|
    self.Job.Name = PlayerJob.name
 | 
						|
    self.Job.Label = PlayerJob.label
 | 
						|
    self.Job.Duty = xPlayer.get('duty')
 | 
						|
    self.Job.Boss = PlayerJob.grade_name == 'boss' and true or false
 | 
						|
    self.Job.Grade.Name = PlayerJob.grade_label
 | 
						|
    self.Job.Grade.Level = PlayerJob.grade
 | 
						|
    if type(PlayerGang) == "table" then
 | 
						|
        self.Gang.Name = PlayerGang.name
 | 
						|
        self.Gang.Label = PlayerGang.label
 | 
						|
        self.Gang.Boss = PlayerGang.grade_name == 'boss' and true or false
 | 
						|
        self.Gang.Grade.Name = PlayerGang.grade_label
 | 
						|
        self.Gang.Grade.Level = PlayerGang.grade
 | 
						|
    end
 | 
						|
    local getmeta, metadata = pcall(xPlayer.getMeta)
 | 
						|
    self.Metadata = (getmeta and metadata or (Player(self.source).state.metadata or {}))
 | 
						|
 | 
						|
    self.SetJob = function(job, grade)
 | 
						|
        if not ESX.DoesJobExist(job, grade) then return false end
 | 
						|
        xPlayer.setJob(job, grade)
 | 
						|
        return true
 | 
						|
    end
 | 
						|
 | 
						|
    self.SetGang = function(gang, grade)
 | 
						|
        grade = tostring(grade)
 | 
						|
        if not Framework.DoesGangExist(gang, grade) then return false end
 | 
						|
        local gangObject, gradeObject = ESX.Gangs[gang], ESX.Gangs[gang].grades[grade]
 | 
						|
        local gangData = {}
 | 
						|
        gangData.name = gangObject.name
 | 
						|
        gangData.label = gangObject.label
 | 
						|
        gangData.grade = tonumber(grade)
 | 
						|
        gangData.grade_name = gradeObject.name
 | 
						|
        gangData.grade_label = gradeObject.label
 | 
						|
        Player(self.source).state:set("gang", gangData, true)
 | 
						|
        return true
 | 
						|
    end
 | 
						|
 | 
						|
    self.AddMoney = function (type, amount)
 | 
						|
        if type == 'cash' then type = 'money' end
 | 
						|
        local current = self.GetMoney(type)
 | 
						|
        xPlayer.addAccountMoney(type, amount)
 | 
						|
        return self.GetMoney(type) == current + amount
 | 
						|
    end
 | 
						|
 | 
						|
    self.RemoveMoney = function(type, amount)
 | 
						|
        if type == 'cash' then type = 'money' end
 | 
						|
        local current = self.GetMoney(type)
 | 
						|
        if current < amount then return false end
 | 
						|
        xPlayer.removeAccountMoney(type, amount)
 | 
						|
        return self.GetMoney(type) == current - amount
 | 
						|
    end
 | 
						|
 | 
						|
    self.GetMoney = function(type)
 | 
						|
        if type == 'cash' then type = 'money' end
 | 
						|
        return xPlayer.getAccount(type)?.money
 | 
						|
    end
 | 
						|
 | 
						|
    self.GetStatus = function(key)
 | 
						|
        local p = promise.new()
 | 
						|
        TriggerEvent('esx_status:getStatus', src, key, function(status)
 | 
						|
            p:resolve(Framework.Round(status.percent, 0))
 | 
						|
        end)
 | 
						|
        return Citizen.Await(p)
 | 
						|
    end
 | 
						|
 | 
						|
    self.SetStatus = function(key, value)
 | 
						|
        TriggerClientEvent("esx_status:set", src, key, (value * 10000))
 | 
						|
    end
 | 
						|
 | 
						|
    self.GetMetaData = function(key)
 | 
						|
        if not key then
 | 
						|
            local success, result = pcall(xPlayer.getMeta)
 | 
						|
            if success then return result end
 | 
						|
            if not success then return Player(self.source).state.metadata or {} end
 | 
						|
        else
 | 
						|
            local success, result = pcall(xPlayer.getMeta, key)
 | 
						|
            if success then return result end
 | 
						|
            if not success then return Player(self.source).state.metadata[key] or nil end
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    self.SetMetaData = function(key, value)
 | 
						|
        local success, result = pcall(xPlayer.setMeta, key, value)
 | 
						|
        if not success then
 | 
						|
            local metadata = Player(self.source).state.metadata or {}
 | 
						|
            metadata[key] = value
 | 
						|
            Player(self.source).state:set("metadata", metadata, true)
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    self.HasLicense = function(name)
 | 
						|
        return (Database.scalar('SELECT 1 FROM `user_licenses` WHERE `type` = ? AND `owner` = ?', { name, self.Identifier }) ~= nil)
 | 
						|
    end
 | 
						|
 | 
						|
    self.GetLicenses = function()
 | 
						|
        local p = promise.new()
 | 
						|
        Database.query('SELECT `type` FROM `user_licenses` WHERE `owner` = ?', { self.Identifier }, function(result)
 | 
						|
            local licenses = {}
 | 
						|
            for i = 1, #result do
 | 
						|
                licenses[result[i].type] = true
 | 
						|
            end
 | 
						|
            p:resolve(licenses)
 | 
						|
        end)
 | 
						|
        return Citizen.Await(p)
 | 
						|
    end
 | 
						|
 | 
						|
    self.AddLicense = function(name)
 | 
						|
        TriggerEvent('esx_license:addLicense', src, name)
 | 
						|
    end
 | 
						|
 | 
						|
    self.RemoveLicense = function(name)
 | 
						|
        Database.prepare('DELETE FROM `user_licenses` WHERE `type` = ? AND `owner` = ?', { name, self.Identifier })
 | 
						|
    end
 | 
						|
 | 
						|
    return self
 | 
						|
end
 | 
						|
 | 
						|
Framework.GetPlayerByIdentifier = function(identifier)
 | 
						|
    return Framework.GetPlayer(ESX.GetPlayerFromIdentifier(identifier)?.source)
 | 
						|
end
 | 
						|
 | 
						|
Framework.DoesJobExist = function(job, grade)
 | 
						|
    return ESX.DoesJobExist(job, grade)
 | 
						|
end
 | 
						|
 | 
						|
Framework.DoesGangExist = function(gang, grade)
 | 
						|
    grade = tostring(grade)
 | 
						|
    if gang and grade then
 | 
						|
        if ESX.Gangs[gang] and ESX.Gangs[gang].grades[grade] then
 | 
						|
            return true
 | 
						|
        else
 | 
						|
            return false
 | 
						|
        end
 | 
						|
    end
 | 
						|
    return false
 | 
						|
end
 | 
						|
 | 
						|
Framework.RegisterSociety = function(name, type)
 | 
						|
    if type ~= 'job' and type ~= 'gang' then error('Society Type Must Be Job Or Gang', 0) return end
 | 
						|
    local society_data_name = ('society_%s'):format(name)
 | 
						|
 | 
						|
    Database.scalar('SELECT `name` FROM `addon_account` WHERE `name` = ?', { society_data_name }, function(addon_account)
 | 
						|
        if not addon_account then
 | 
						|
            Database.insert('INSERT IGNORE INTO `addon_account` (`name`, `label`, `shared`) VALUES (?, ?, ?)', { society_data_name, Framework.FirstToUpper(name), 1})
 | 
						|
        end
 | 
						|
    end)
 | 
						|
 | 
						|
    Database.scalar('SELECT `account_name` FROM `addon_account_data` WHERE `account_name` = ?', { society_data_name }, function(addon_account_data)
 | 
						|
        if not addon_account_data then
 | 
						|
            Database.insert('INSERT IGNORE INTO `addon_account_data` (`account_name`, `money`) VALUES (?, ?)', { society_data_name, 0 })
 | 
						|
        end
 | 
						|
    end)
 | 
						|
    
 | 
						|
    TriggerEvent('esx_addonaccount:refreshAccounts')
 | 
						|
    TriggerEvent('esx_society:registerSociety', name, Framework.FirstToUpper(name), society_data_name, society_data_name, society_data_name, { type = 'public' })
 | 
						|
end
 | 
						|
 | 
						|
Framework.SocietyGetMoney = function(name, type)
 | 
						|
    if type ~= 'job' and type ~= 'gang' then error('Society Type Must Be Job Or Gang', 0) return 0 end
 | 
						|
    local p = promise.new()
 | 
						|
    local society_name = ('society_%s'):format(name)
 | 
						|
    TriggerEvent('esx_addonaccount:getSharedAccount', society_name, function(account)
 | 
						|
        p:resolve(account.money)
 | 
						|
    end)
 | 
						|
    return Citizen.Await(p)
 | 
						|
end
 | 
						|
 | 
						|
Framework.SocietyAddMoney = function(name, type, amount)
 | 
						|
    if type ~= 'job' and type ~= 'gang' then error('Society Type Must Be Job Or Gang', 0) return false end
 | 
						|
    local p = promise.new()
 | 
						|
    local society_name = ('society_%s'):format(name)
 | 
						|
    TriggerEvent('esx_addonaccount:getSharedAccount', society_name, function(account)
 | 
						|
        if account and amount > 0 then
 | 
						|
            account.addMoney(amount)
 | 
						|
            p:resolve(true)
 | 
						|
        else
 | 
						|
            p:resolve(false)
 | 
						|
        end
 | 
						|
    end)
 | 
						|
    return Citizen.Await(p)
 | 
						|
end
 | 
						|
 | 
						|
Framework.SocietyRemoveMoney = function(name, type, amount)
 | 
						|
    if type ~= 'job' and type ~= 'gang' then error('Society Type Must Be Job Or Gang', 0) return false end
 | 
						|
    local p = promise.new()
 | 
						|
    local society_name = ('society_%s'):format(name)
 | 
						|
    TriggerEvent('esx_addonaccount:getSharedAccount', society_name, function(account)
 | 
						|
        if account and amount > 0 and account.money >= amount then
 | 
						|
            account.removeMoney(amount)
 | 
						|
            p:resolve(true)
 | 
						|
        else
 | 
						|
            p:resolve(false)
 | 
						|
        end
 | 
						|
    end)
 | 
						|
    return Citizen.Await(p)
 | 
						|
end
 | 
						|
 | 
						|
Framework.Notify = function(source, message, type, length)
 | 
						|
    TriggerClientEvent(Bridge.FrameworkPrefix .. ':showNotification', source, message, type, length)
 | 
						|
end
 | 
						|
 | 
						|
Framework.IsPlayerDead = function(source)
 | 
						|
    local p = promise.new()
 | 
						|
    Framework.TriggerCallback(source, Bridge.Resource .. ':bridge:IsPlayerDead', function(isDead)
 | 
						|
        p:resolve(isDead)
 | 
						|
    end)
 | 
						|
    return Citizen.Await(p)
 | 
						|
end
 | 
						|
 | 
						|
Framework.HasPermission = function(source, permission)
 | 
						|
    local xPlayer = ESX.GetPlayerFromId(source)
 | 
						|
    if type(permission) == "string" then
 | 
						|
        return xPlayer.getGroup() == permission
 | 
						|
    elseif type(permission) == "table" then
 | 
						|
        for _, perm in pairs(permission) do
 | 
						|
            if xPlayer.getGroup() == perm then
 | 
						|
                return true
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
    return false
 | 
						|
end
 | 
						|
 | 
						|
Citizen.CreateThreadNow(function()
 | 
						|
    ESX.Gangs = {}
 | 
						|
    local success, result = pcall(Database.scalar, 'SELECT 1 FROM gangs')
 | 
						|
    if not success then
 | 
						|
        Database.query([[CREATE TABLE IF NOT EXISTS `gangs` (
 | 
						|
	        `name` varchar(50) NOT NULL,
 | 
						|
            `label` varchar(50) DEFAULT NULL,
 | 
						|
            PRIMARY KEY (`name`)
 | 
						|
        )]])
 | 
						|
    end
 | 
						|
 | 
						|
    local success, result = pcall(Database.scalar, 'SELECT 1 FROM gang_grades')
 | 
						|
    if not success then
 | 
						|
        Database.query([[CREATE TABLE IF NOT EXISTS `gang_grades` (
 | 
						|
	        `id` int(11) NOT NULL,
 | 
						|
            `gang_name` varchar(50) DEFAULT NULL,
 | 
						|
            `grade` int(11) NOT NULL,
 | 
						|
            `name` varchar(50) NOT NULL,
 | 
						|
            `label` varchar(50) NOT NULL,
 | 
						|
            PRIMARY KEY (`id`)
 | 
						|
        )]])
 | 
						|
    end
 | 
						|
 | 
						|
    local success, result = pcall(Database.scalar, 'SELECT gang FROM users')
 | 
						|
    if not success then
 | 
						|
        Database.query("ALTER TABLE `users` ADD COLUMN `gang` varchar(20) DEFAULT 'none' AFTER job_grade")
 | 
						|
    end
 | 
						|
 | 
						|
    local success, result = pcall(Database.scalar, 'SELECT gang_grade FROM users')
 | 
						|
    if not success then
 | 
						|
        Database.query('ALTER TABLE `users` ADD COLUMN `gang_grade` int(11) DEFAULT 0 AFTER gang')
 | 
						|
    end
 | 
						|
 | 
						|
    local success, gangs = pcall(Database.query, 'SELECT * FROM gangs')
 | 
						|
    if success then
 | 
						|
        for _, v in ipairs(gangs) do
 | 
						|
            ESX.Gangs[v.name] = v
 | 
						|
            ESX.Gangs[v.name].grades = {}
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    local success, gang_grades = pcall(Database.query, 'SELECT * FROM gang_grades')
 | 
						|
    if success then
 | 
						|
        for _, v in ipairs(gang_grades) do
 | 
						|
            if ESX.Gangs[v.gang_name] then
 | 
						|
                ESX.Gangs[v.gang_name].grades[tostring(v.grade)] = v
 | 
						|
            else
 | 
						|
                if Bridge.DebugMode then print(('[^3WARNING^7] Ignoring gang grades for ^5"%s"^0 due to missing gang'):format(v.gang_name)) end
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    for _, v in pairs(ESX.Gangs) do
 | 
						|
        if next(v.grades) == nil then
 | 
						|
            ESX.Gangs[v.name] = nil
 | 
						|
            if Bridge.DebugMode then print(('[^3WARNING^7] Ignoring gang ^5"%s"^0 due to no gang grades found'):format(v.name)) end
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    ESX.Gangs['none'] = {
 | 
						|
        label = 'No Gang Affiliaton',
 | 
						|
        grades = { ['0'] = { grade = 0, label = 'None' } }
 | 
						|
    }
 | 
						|
 | 
						|
    local success, result = pcall(Database.scalar, 'SELECT metadata FROM users')
 | 
						|
    if not success then
 | 
						|
        Database.query("ALTER TABLE `users` ADD COLUMN `metadata` LONGTEXT NULL DEFAULT NULL AFTER loadout")
 | 
						|
    end
 | 
						|
end) |