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: in-house queue system #279

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
161 changes: 160 additions & 1 deletion config/server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,164 @@ return {

removeSocietyMoney = function(accountName, payment)
return exports.qbx_management:RemoveMoney(accountName, payment)
end
end,

queue = {
D4isDAVID marked this conversation as resolved.
Show resolved Hide resolved
---Amount of time to wait for remove a player from the queue after disconnecting while waiting.
timeoutSeconds = 30,

---Amount of time to wait for remove a player from the queue after disconnecting when installing server data.
joinTimeoutSeconds = 30,

clockEmojis = {
'🕛',
'🕒',
'🕕',
'🕘',
},

---Queue types from most prioritized to least prioritized.
---The first queue without a predicate function will be used as the default.
---If a player doesn't pass any predicates and a queue without a predicate does not exist they will not be let into the server unless player slots are available.
---@type QueueType[]
queueTypes = {
{ name = 'Priority Queue', color = 'good', predicate = function(source) return source % 2 == 0 --[[HasPermission(source, 'admin')]] end },
D4isDAVID marked this conversation as resolved.
Show resolved Hide resolved
{ name = 'Regular Queue' },
},

---Generator function for the queue adaptive card.
---@param queueType QueueType the queue type the player is in
---@param currentPos integer the current position of the player in the queue
---@param queueSize integer the size of the queue
---@param waitingTime integer in seconds
---@param clockEmoji string
---@return table card queue adaptive card
generateCard = function(queueType, currentPos, queueSize, waitingTime, clockEmoji)
D4isDAVID marked this conversation as resolved.
Show resolved Hide resolved
local serverName = GetConvar('sv_projectName', GetConvar('sv_hostname', 'Server'))
local minutes = math.floor(waitingTime / 60)
local seconds = waitingTime % 60
local timeDisplay = ('%02d:%02d'):format(minutes, seconds)

local progressColumn = {
type = 'Column',
width = 'stretch',
items = {},
}

local progressAmount = 7
local progressColumns = {}

for i = 1, progressAmount + 2 do
progressColumns[i] = table.clone(progressColumn)
progressColumns[i].items = {}
end

progressColumns[1].items[1] = {
type = 'TextBlock',
text = 'Queue',
horizontalAlignment = 'center',
size = 'extralarge',
weight = 'lighter',
color = 'good',
}
for i = 1, progressAmount do
progressColumns[i + 1].items[1] = {
type = 'TextBlock',
text = '•',
horizontalAlignment = 'center',
size = 'extralarge',
weight = 'lighter',
color = 'accent',
}
end
progressColumns[progressAmount + 2].items[1] = {
type = 'TextBlock',
text = 'Server',
horizontalAlignment = 'center',
size = 'extralarge',
weight = 'lighter',
color = 'good',
}

local playerColumn = currentPos == 1 and progressAmount or (progressAmount - math.ceil(currentPos / (queueSize / progressAmount)) + 1)
progressColumns[playerColumn + 1].items[1] = {
type = 'TextBlock',
text = 'You',
horizontalAlignment = 'center',
size = 'extralarge',
weight = 'lighter',
color = 'good',
}

return {
type = 'AdaptiveCard',
version = '1.6',
body = {
{
type = 'TextBlock',
text = 'In Line',
horizontalAlignment = 'center',
size = 'large',
weight = 'bolder',
},
{
type = 'TextBlock',
text = ('Joining %s'):format(serverName),
spacing = 'none',
horizontalAlignment = 'center',
size = 'medium',
weight = 'bolder',
},
{
type = 'ColumnSet',
spacing = 'large',
columns = progressColumns,
},
{
type = 'ColumnSet',
spacing = 'large',
columns = {
{
type = 'Column',
width = 'stretch',
items = {
{
type = 'TextBlock',
text = queueType.name,
color = queueType.color,
size = 'medium',
}
},
},
{
type = 'Column',
width = 'stretch',
items = {
{
type = 'TextBlock',
text = ('%d/%d'):format(currentPos, queueSize),
horizontalAlignment = 'center',
color = 'good',
size = 'medium',
}
},
},
{
type = 'Column',
width = 'stretch',
items = {
{
type = 'TextBlock',
text = ('%s %s'):format(timeDisplay, clockEmoji),
horizontalAlignment = 'right',
size = 'medium',
}
},
},
},
},
},
}
end,
},
}
3 changes: 2 additions & 1 deletion locale/en.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ local Translations = {
tp_error = 'Error While Teleporting.',
connecting_database_timeout = 'Connection to database timed out. (Is the SQL server on?)',
connecting_error = 'An error occurred while connecting to the server. (Check your server console)',
no_match_character_registration = 'Anything other than letters aren\'t allowed, trailing whitespaces aren\'t allowed either and words must start with a capital letter in input fields. You can however add words with spaces inbetween.'
no_match_character_registration = 'Anything other than letters aren\'t allowed, trailing whitespaces aren\'t allowed either and words must start with a capital letter in input fields. You can however add words with spaces inbetween.',
no_queue = 'You were not let in any queue.',
},
success = {
server_opened = 'The server has been opened',
Expand Down
10 changes: 9 additions & 1 deletion server/events.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local serverConfig = require 'config.server'.server
local loggingConfig = require 'config.server'.logging
local logger = require 'modules.logger'
local queue = require 'server.queue'

-- Event Handler

Expand All @@ -19,6 +20,9 @@ AddEventHandler('playerJoining', function()
local src = source --[[@as string]]
local license = GetPlayerIdentifierByType(src, 'license2') or GetPlayerIdentifierByType(src, 'license')
if not license then return end
if queue then
queue.registerPlayerJoined(license)
end
if usedLicenses[license] then
Wait(0) -- mandatory wait for the drop reason to show up
DropPlayer(src, Lang:t('error.duplicate_license'))
Expand Down Expand Up @@ -108,7 +112,11 @@ local function onPlayerConnecting(name, _, deferrals)
-- wait for database to finish
databasePromise:next(function()
deferrals.update(string.format(Lang:t('info.join_server'), name))
deferrals.done()
if not queue then
deferrals.done()
return
end
queue.enqueue(src --[[@as Source]], license, deferrals)
end, function(err)
deferrals.done(Lang:t('error.connecting_error'))
lib.print.error(err)
Expand Down
Loading
Loading