diff --git a/client/main.lua b/client/main.lua index 8c67700..1645ae8 100644 --- a/client/main.lua +++ b/client/main.lua @@ -1,11 +1,7 @@ -RegisterNetEvent('esx_service:notifyAllInService') -AddEventHandler('esx_service:notifyAllInService', function(notification, target) - target = GetPlayerFromServerId(target) - if target == PlayerId() then return end +RegisterNetEvent("esx_service:notifyAllInService", function(notifyMessage, src) + local targetPed = GetPlayerPed(GetPlayerFromServerId(src)) + local mugshot, mugshotStr = ESX.Game.GetPedMugshot(targetPed) - local targetPed = GetPlayerPed(target) - local mugshot, mugshotStr = ESX.Game.GetPedMugshot(targetPed) - - ESX.ShowAdvancedNotification(notification.title, notification.subject, notification.msg, mugshotStr, notification.iconType) - UnregisterPedheadshot(mugshot) -end) \ No newline at end of file + ESX.ShowAdvancedNotification(notifyMessage.title, notifyMessage.subject, notifyMessage.msg, mugshotStr, notifyMessage.iconType) + UnregisterPedheadshot(mugshot) +end) diff --git a/fxmanifest.lua b/fxmanifest.lua index f67fb96..ac8c86a 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -4,8 +4,8 @@ game 'gta5' lua54 'yes' description 'A basic duty system for Jobs' -version '1.0' -legacyversion '1.9.1' +version '1.1' +legacyversion '1.11.1' shared_script '@es_extended/imports.lua' diff --git a/server/main.lua b/server/main.lua index 417699a..f4cda52 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,86 +1,276 @@ -local InService = {} -local MaxInService = {} +---@class ServiceNotification +---@field title string +---@field subject string +---@field msg string +---@field iconType number -function GetInServiceCount(name) - local count = 0 +---@param serviceNotification unknown +local function isServiceNotification(serviceNotification) + if type(serviceNotification) ~= "table" then + return false + end + if type(serviceNotification.title) ~= "string" then + return false + end + if type(serviceNotification.subject) ~= "string" then + return false + end + if type(serviceNotification.msg) ~= "string" then + return false + end + if type(serviceNotification.iconType) ~= "number" then + return false + end - for k,v in pairs(InService[name]) do - if v == true then - count = count + 1 - end - end + return true +end + +---@param src number +---@param onDuty boolean +---@param serviceName string +---@return nil +local function setPlayerJobDuty(src, onDuty, serviceName) + local xPlayer = ESX.GetPlayerFromId(src) + if not xPlayer then + return + end + + local currentJob = xPlayer.getJob() + + if currentJob.name ~= serviceName then + return + end + + xPlayer.setJob(currentJob.name, currentJob.grade, onDuty) +end + + +---@class Service +---@field serviceName string +---@field maxPlayers number +---@field players table +---@field new fun(self:Service, serviceName: string, maxPlayers: number): Service +---@field getPlayerCount fun(self:Service): number +---@field getPlayers fun(self:Service): table +---@field addPlayer fun(self:Service, src: number, force:boolean): boolean +---@field removePlayer fun(self:Service, src: number): nil +---@field hasPlayer fun(self:Service, src: number): boolean +---@field notifyAll fun(self:Service, serviceNotification: ServiceNotification, src: number): nil +local Service = {} +Service.__index = Service + +---@type table +local services = {} + +function Service:new(serviceName, maxPlayers) + if services[serviceName] then + return services[serviceName] + end + + local obj = setmetatable({}, self) + obj.serviceName = serviceName + obj.maxPlayers = maxPlayers + obj.players = {} + GlobalState[serviceName] = 0 + + return obj +end + +function Service:getPlayerCount() + return ESX.Table.SizeOf(self.players) +end + +function Service:getPlayers() + return self.players +end + +function Service:addPlayer(src, force) + if self:hasPlayer(src) then + return true + end + + local servicePlayerCount = self:getPlayerCount() + if not force then + if servicePlayerCount >= self.maxPlayers then + return false + end + end + + self.players[src] = true + GlobalState[self.serviceName] = servicePlayerCount + 1 + setPlayerJobDuty(src, true, self.serviceName) - return count + return true end -RegisterServerEvent('esx_service:activateService') -AddEventHandler('esx_service:activateService', function(name, max) - InService[name] = {} - MaxInService[name] = max - GlobalState[name] = GetInServiceCount(name) +function Service:removePlayer(src) + if self:hasPlayer(src) then + self.players[src] = nil + GlobalState[self.serviceName] = self:getPlayerCount() + setPlayerJobDuty(src, false, self.serviceName) + end +end + +function Service:hasPlayer(src) + return self.players[src] or false +end + +function Service:notifyAll(serviceNotification, src) + local targets = {} + for targetSrc, _ in pairs(self.players) do + if src ~= targetSrc then + table.insert(targets, targetSrc) + end + end + + ESX.TriggerClientEvent("esx_service:notifyAllInService", targets, serviceNotification, src) +end + +---@param serviceName string +---@param maxPlayers number +AddEventHandler("esx_service:activateService", function(serviceName, maxPlayers) + if type(serviceName) ~= "string" then + print(("[^3WARNING^7] Attempted To Activate Service With Invalid Name - ^5%s^7"):format(serviceName)) + return + end + if services[serviceName] then + print(("[^3WARNING^7] Attempted To Activate Service That Is Already Active - ^5%s^7"):format(serviceName)) + return + end + if type(maxPlayers) ~= "number" or maxPlayers <= 0 then + print(("[^3WARNING^7] Attempted To Activate Service With Invalid Max Players - ^5%s^7"):format(maxPlayers)) + return + end + + services[serviceName] = Service:new(serviceName, maxPlayers) end) -RegisterServerEvent('esx_service:disableService') -AddEventHandler('esx_service:disableService', function(name) - InService[name][source] = nil - GlobalState[name] = GetInServiceCount(name) +---@param src number +---@param cb function +---@param serviceName string +ESX.RegisterServerCallback("esx_service:enableService", function(src, cb, serviceName) + local service = services[serviceName] + if not service then + print(("[^3WARNING^7] Attempted To Use Inactive Service - ^5%s^7"):format(serviceName)) + return + end + + local servicePlayerCount = service:getPlayerCount() + local success = service:addPlayer(src, false) + + cb(success, service.maxPlayers, servicePlayerCount) end) -RegisterServerEvent('esx_service:notifyAllInService') -AddEventHandler('esx_service:notifyAllInService', function(notification, name) - for k,v in pairs(InService[name]) do - if v == true then - TriggerClientEvent('esx_service:notifyAllInService', k, notification, source) - end - end +---@param serviceName string +RegisterNetEvent("esx_service:disableService", function(serviceName) + ---@type number + local src = source + + local service = services[serviceName] + if not service then + print(("[^3WARNING^7] Attempted To Use Inactive Service - ^5%s^7"):format(serviceName)) + return + end + + service:removePlayer(src) end) -ESX.RegisterServerCallback('esx_service:enableService', function(source, cb, name) - local inServiceCount = GetInServiceCount(name) - - if inServiceCount >= MaxInService[name] then - cb(false, MaxInService[name], inServiceCount) - else - InService[name][source] = true - GlobalState[name] = GetInServiceCount(name) - cb(true, MaxInService[name], inServiceCount) - end +---@param src number +---@param cb function +---@param serviceName string +ESX.RegisterServerCallback("esx_service:isInService", function(src, cb, serviceName) + local service = services[serviceName] + if not service then + print(("[^3WARNING^7] Attempted To Use Inactive Service - ^5%s^7"):format(serviceName)) + return + end + + cb(service:hasPlayer(src)) end) -ESX.RegisterServerCallback('esx_service:isInService', function(source, cb, name) - local isInService = false +---@param src number +---@param cb function +---@param serviceName string +---@param targetSrc number +ESX.RegisterServerCallback("esx_service:isPlayerInService", function(src, cb, serviceName, targetSrc) + if type(targetSrc) ~= "number" then + print(("[^3WARNING^7] Attempted To Get Service With Invalid Target Source - ^5%s^7"):format(targetSrc)) + return + end + + local service = services[serviceName] + if not service then + print(("[^3WARNING^7] Attempted To Use Inactive Service - ^5%s^7"):format(serviceName)) + return + end + + cb(service:hasPlayer(targetSrc)) +end) - if InService[name] ~= nil then - if InService[name][source] then - isInService = true - end - else - print(('[^3WARNING^7] Attempted To Use Inactive Service - ^5%s^7'):format(name)) - end +---@param src number +---@param cb function +---@param serviceName string +ESX.RegisterServerCallback("esx_service:getInServiceList", function(src, cb, serviceName) + local service = services[serviceName] + if not service then + print(("[^3WARNING^7] Attempted To Use Inactive Service - ^5%s^7"):format(serviceName)) + return + end - cb(isInService) + cb(service:getPlayers()) end) -ESX.RegisterServerCallback('esx_service:isPlayerInService', function(source, cb, name, target) - local isPlayerInService = false - local targetXPlayer = ESX.GetPlayerFromId(target) +---@param serviceNotification ServiceNotification +---@param serviceName string +---@param src number +AddEventHandler("esx_service:notifyAllInService", function(serviceNotification, serviceName, src) + if not isServiceNotification(serviceNotification) then + print(("[^3WARNING^7] Attempted To Notify Service With Invalid Notification - ^5%s^7"):format(json.encode(serviceNotification))) + return + end - if InService[name][targetXPlayer.source] then - isPlayerInService = true - end + local service = services[serviceName] + if not service then + print(("[^3WARNING^7] Attempted To Use Inactive Service - ^5%s^7"):format(serviceName)) + return + end - cb(isPlayerInService) + service:notifyAll(serviceNotification, src) end) -ESX.RegisterServerCallback('esx_service:getInServiceList', function(source, cb, name) - cb(InService[name]) +---@param src number +---@param reason string +AddEventHandler("esx:playerDropped", function(src, reason) + for _, service in pairs(services) do + if service:hasPlayer(src) then + service:removePlayer(src) + end + end end) -AddEventHandler('esx:playerDropped', function(playerId, reason) - for k,v in pairs(InService) do - if v[playerId] == true then - v[playerId] = nil - GlobalState[k] = GetInServiceCount(k) - end - end +---@param src number +---@param job table +---@param lastJob table +AddEventHandler("esx:setJob", function(src, job, lastJob) + local lastJobService = services[lastJob.name] + if lastJobService and lastJob.onDuty then + lastJobService:removePlayer(src) + end + + local currentJobService = services[job.name] + if currentJobService and job.onDuty then + currentJobService:addPlayer(src, true) + end +end) + +---@param src number +---@param xPlayer table +---@param isNew boolean +AddEventHandler("esx:playerLoaded", function(src, xPlayer, isNew) + local playerJob = xPlayer.getJob() + local jobService = services[playerJob.name] + + if jobService and playerJob.onDuty then + jobService:addPlayer(src, true) + end end)