Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(groups): Add group management functionality #668

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions client/groups.lua
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
local jobs = require 'shared.jobs'
local gangs = require 'shared.gangs'

---@return table<string, Job>
function GetJobs()
return jobs
return lib.callback.await('qbx_core:server:getJobs')
end

exports('GetJobs', GetJobs)

---@return table<string, Gang>
function GetGangs()
return gangs
return lib.callback.await('qbx_core:server:getGangs')
end

exports('GetGangs', GetGangs)

---@param name string
---@return Job?
function GetJob(name)
local jobs = lib.callback.await('qbx_core:server:getJobs')
return jobs[name]
end

Expand All @@ -26,15 +24,8 @@ exports('GetJob', GetJob)
---@param name string
---@return Gang?
function GetGang(name)
local gangs = lib.callback.await('qbx_core:server:getGangs')
return gangs[name]
end

exports('GetGang', GetGang)

RegisterNetEvent('qbx_core:client:onJobUpdate', function(jobName, job)
jobs[jobName] = job
end)

RegisterNetEvent('qbx_core:client:onGangUpdate', function(gangName, gang)
gangs[gangName] = gang
end)
68 changes: 68 additions & 0 deletions server/groups.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,28 @@ GroupType = {
GANG = 'gang'
}

---@type boolean
local managementEnabled = GetConvar('qbx:enableGroupManagement', 'false') == 'true'

---@type table<string, Job>
local jobs = require 'shared.jobs'

---@type table<string, Gang>
local gangs = require 'shared.gangs'

local storage = require 'server.storage.groups'

if managementEnabled then
CreateThread(function()
storage.createGroupsTable()

local jobData = storage.fetchJobs()
local gangData = storage.fetchGangs()
CreateJobs(jobData)
CreateGangs(gangData)
end)
end

for name in pairs(jobs) do
if name ~= name:lower() then
lib.print.error(('jobs.lua contains a job name with capital letters: %s'):format(name))
Expand Down Expand Up @@ -216,3 +232,55 @@ local function removeGangGrade(name, grade)
end

exports('RemoveGangGrade', removeGangGrade)

---Update job data with persistence
---@param name string
---@param data Job
local function updateJob(name, data)
if not managementEnabled then
lib.print.error('Job management not enabled')
return
end
if not jobs[name] then
lib.print.error('Job must exist to update. Not found:', name)
return
end
if data.defaultDuty == nil then data.defaultDuty = jobs[name].defaultDuty end
if data.offDutyPay == nil then data.offDutyPay = jobs[name].offDutyPay end
if data.label == nil then data.label = jobs[name].label end
if data.type == nil then data.type = jobs[name].type end
storage.updateGroup(name, GroupType.JOB, data)
jobs[name] = data
TriggerEvent('qbx_core:server:onJobUpdate', name, jobs[name])
TriggerClientEvent('qbx_core:client:onJobUpdate', -1, name, jobs[name])
end

exports('UpdateJob', updateJob)

---Update gang data with persistence
---@param name string
---@param data Gang
local function updateGang(name, data)
if not managementEnabled then
lib.print.error('Gang management not enabled')
return
end
if not gangs[name] then
lib.print.error('Gang must exist to update. Not found:', name)
return
end
storage.updateGroup(name, GroupType.GANG, data)
gangs[name] = data
TriggerEvent('qbx_core:server:onGangUpdate', name, gangs[name])
TriggerClientEvent('qbx_core:client:onGangUpdate', -1, name, gangs[name])
end

exports('UpdateGang', updateGang)

lib.callback.register('qbx_core:server:getJobs', function()
return jobs
end)

lib.callback.register('qbx_core:server:getGangs', function()
return gangs
end)
93 changes: 93 additions & 0 deletions server/storage/groups.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
local function createGroupsTable()
MySQL.query.await([[
CREATE TABLE IF NOT EXISTS `groups` (
`name` varchar(255) NOT NULL UNIQUE,
`type` varchar(10) NOT NULL,
`label` varchar(255) NOT NULL,
`defaultDuty` tinyint(1) DEFAULT 1,
`offDutyPay` tinyint(1) DEFAULT 0,
`grades` LONGTEXT DEFAULT NULL,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
]])
end

---Update / insert group data
---@param name string
---@param groupType GroupType
---@param data Job|Gang
local function updateGroup(name, groupType, data)
if data.grades and table.type(data.grades) == 'hash' then
local _grades = {}
for k, v in pairs(data.grades) do
if not tonumber(k) then goto skip end
_grades[tonumber(k)] = v
::skip::
end
data.grades = _grades
end
MySQL.query([[
INSERT INTO `groups` (name, type, label, defaultDuty, offDutyPay, grades)
VALUES (@name, @type, @label, @defaultDuty, @offDutyPay, @grades)
ON DUPLICATE KEY UPDATE
`type` = @type, `label` = @label, `defaultDuty` = @defaultDuty, `offDutyPay` = @offDutyPay, `grades` = @grades
]], {
name = name,
type = groupType,
label = data.label,
defaultDuty = data.defaultDuty,
offDutyPay = data.offDutyPay,
grades = data.grades and json.encode(data.grades),
})
end

local function convertGrades(gangJson)
local _grades = json.decode(gangJson)
local grades = {}
for k, v in pairs(_grades) do
grades[tonumber(("%d"):format(k))] = v
end
return grades
end

---Fetch job data
---@return table<string, Job>
local function fetchJobs()
local results = MySQL.query.await("SELECT * FROM `groups` WHERE `type` = 'job'")
local jobData = {}

for i = 1, #results do
jobData[results[i].name] = {
label = results[i].label,
type = results[i].type,
defaultDuty = results[i].defaultDuty == 1,
offDutyPay = results[i].offDutyPay == 1,
grades = results[i].grades and convertGrades(results[i].grades) or {},
}
end

return jobData
end

---Fetch gang data
---@return table<string, Gang>
local function fetchGangs()
local results = MySQL.query.await("SELECT * FROM `groups` WHERE `type` = 'gang'")
local gangData = {}

for i = 1, #results do
gangData[results[i].name] = {
label = results[i].label,
grades = results[i].grades and convertGrades(results[i].grades) or {},
}
end

return gangData
end

return {
createGroupsTable = createGroupsTable,
updateGroup = updateGroup,
fetchJobs = fetchJobs,
fetchGangs = fetchGangs,
}