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) | 
