Skip to content

Commit

Permalink
feat: in-house queue system
Browse files Browse the repository at this point in the history
  • Loading branch information
D4isDAVID committed Dec 13, 2023
1 parent c1323a6 commit 2e7c56c
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 3 deletions.
6 changes: 4 additions & 2 deletions 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.',
already_in_queue = 'You are already in queue.',
},
success = {
server_opened = 'The server has been opened',
Expand Down Expand Up @@ -58,7 +59,8 @@ local Translations = {
gender = 'Sex',
birth_date = 'Birth Date',
select_gender = 'Select your gender...',
confirm_delete = 'Are you sure you wish to delete this character?'
confirm_delete = 'Are you sure you wish to delete this character?',
in_queue = '🐌 You are %{queuePos}/%{queueSize} in queue.',
},
command = {
tp = {
Expand Down
7 changes: 6 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 Down Expand Up @@ -108,7 +109,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 queue then
queue.awaitPlayerQueue(src --[[@as Source]], license, deferrals)
else
deferrals.done()
end
end, function(err)
deferrals.done(Lang:t('error.connecting_error'))
lib.print.error(err)
Expand Down
109 changes: 109 additions & 0 deletions server/queue.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
if GetConvar('qbx:enablequeue', 'true') == 'false' then return end

-- Disable hardcap because it kicks the player when the server is full

---@param resource string
AddEventHandler('onResourceStarting', function(resource)
if resource == 'hardcap' then
lib.print.info('Preventing hardcap from starting...')
CancelEvent()
end
end)

if GetResourceState('hardcap'):find('start') then
lib.print.info('Stopping hardcap...')
StopResource('hardcap')
end

-- Queue code

local maxPlayers = GlobalState.MaxPlayers

local queueSize = 0
---@type table<string, integer> player license to queue position map
local playerPositions = {}

---Map of licenses of players that passed the queue and are downloading server content.
---@type table<string, true>
local joiningPlayers = {}
local joiningPlayerCount = 0

---@param license string
local function addPlayerJoining(license)
if not joiningPlayers[license] then
joiningPlayerCount += 1
end
joiningPlayers[license] = true
end

---@param license string
local function removePlayerJoining(license)
if joiningPlayers[license] then
joiningPlayerCount -= 1
end
joiningPlayers[license] = nil
end

---@param license string
local function enqueue(license)
queueSize += 1
playerPositions[license] = queueSize
end

---@param license string
local function dequeue(license)
local pos = playerPositions[license]

queueSize -= 1
playerPositions[license] = nil

-- decrease the positions of players who are after the current player in queue
for k, v in pairs(playerPositions) do
if v > pos then
playerPositions[k] -= 1
end
end
end

---@param source Source
---@param license string
---@param deferrals Deferrals
local function awaitPlayerQueue(source, license, deferrals)
if playerPositions[license] then
deferrals.done(Lang:t('error.already_in_queue'))
return
end

enqueue(license)

-- wait until the player disconnected or until there are available slots and the player is first in queue
while DoesPlayerExist(source --[[@as string]]) and ((GetNumPlayerIndices() + joiningPlayerCount) >= maxPlayers or playerPositions[license] > 1) do
deferrals.update(Lang:t('info.in_queue', {
queuePos = playerPositions[license],
queueSize = queueSize,
}))

Wait(1000)
end

-- if the player disconnected while waiting in queue
if not DoesPlayerExist(source --[[@as string]]) then
dequeue(license)
return
end

addPlayerJoining(license)
dequeue(license)
deferrals.done()

-- wait until the player finally joins or disconnects while installing server content
-- this may result in waiting ~2 additional minutes if the player disconnects as FXServer will think that the player exists
while DoesPlayerExist(source --[[@as string]]) do
Wait(1000)
end
removePlayerJoining(license)
end

return {
awaitPlayerQueue = awaitPlayerQueue,
}

0 comments on commit 2e7c56c

Please sign in to comment.