Migrating From N4 Queue

Migrating from n4_queue

Short version: rename the resource in your scripts, import one table, delete the
old folder.

The four read exports and addPrio and removePrio keep n4's names and
signatures, so scripts that already call the queue keep working after a
find-and-replace.


1. Your scripts

-- before
local size = exports['n4_queue']:queueSize()

-- after
local size = exports['rivo_queue']:queueSize()

Unchanged in name, arguments, and return shape:

Export Note
queueList() Adds tier and score to each row. Existing fields are unchanged.
queueSize() Identical.
connectingList() Identical shape, keyed by identifier.
connectingSize() Identical.
addPrio(identifier, points, category?) Identical. An optional fourth table argument adds label, tier, and expiry.
removePrio(id) Returns true/false rather than a result object.

removePrio is the one behaviour difference. n4 returned a database result you
would check with result.affectedRows; this returns a boolean:

-- before
local result = exports['n4_queue']:removePrio(id)
if result.affectedRows > 0 then … end

-- after
if exports['rivo_queue']:removePrio(id) then … end

2. Your priority data

If you used n4 with a database

n4's table is queue with (id, identifier, points, category).

Start rivo_queue once so it creates its tables (or run queue.sql), then:

INSERT INTO `rivo_queue_priority`
    (`identifier`, `points`, `category`, `created_at`, `created_by`)
SELECT `identifier`, `points`, `category`, UNIX_TIMESTAMP(), 'n4-import'
FROM `queue`;

Every row carries over. n4 has no labels, tiers, or expiry, so those columns
stay empty and you can fill them in later.

Keep the old queue table until you have confirmed the import. Nothing reads it.

If you did not use a database

Your priority came from Discord roles only. Copy the role IDs and point values
from n4's prioRoles into Config.discord.roles:

-- n4
prioRoles = {
    { label = 'VIP',   roleId = 111111111111111111, points = 2500 },
    { label = 'Staff', roleId = 222222222222222222, points = 5000 },
}

-- rivo_queue
Config.discord.roles = {
    ['111111111111111111'] = { points = 2500, label = 'VIP',   tier = 'vip'   },
    ['222222222222222222'] = { points = 5000, label = 'Staff', tier = 'staff' },
}

Note the role ID is a string key here, not a number field. Discord IDs are
64-bit and Lua numbers are doubles, so a snowflake stored as a number loses
precision and stops matching.


3. Your config

n4 Rivo Queue
joinDelay Config.joinDelay (same meaning)
cooldown Config.cooldown (same meaning)
displayQueueInHostName Config.displayQueueInHostName
maxPlayersToDisplay Config.ui.maxPlayersToDisplay, and set Config.ui.showQueueList = true
consoleInfo Config.consoleInfo
stackPrio = true Config.priorityMode = 'sum'
stackPrio = false Config.priorityMode = 'max'
discord.enabled Config.discord.enabled
discord.requireIdentifier Config.requireIdentifiers = { 'discord' }
discord.requireInGuild Config.discord.requireInGuild
discord.whitelist + whitelistRoleId Config.whitelist.enabled + Config.whitelist.roles = { '…' }
discord.botToken convar rivo_queue:discordToken
discord.guildId Config.discord.guildId
prioRoles Config.discord.roles

Two differences to watch for:

The queue list is off by default. n4 always shows the first N players. Here
it is opt-in, and names are masked when it is on. Set
Config.ui.showQueueList = true for the old behaviour.

The whitelist takes a list of roles, not a single one. It also accepts ACE
permissions, an identifier list, and "anyone with stored priority". Passing any
one of them is enough. Your single whitelistRoleId becomes a one-element list.


4. Swap them

  1. Stop the server.
  2. Remove ensure n4_queue, add ensure rivo_queue.
  3. Delete or move the n4_queue folder so it cannot start by accident.
  4. Start, and watch for [rivo_queue] storage: … in the console.
  5. Run queue slots and queue status to confirm.

What you gain immediately

Without configuring anything beyond the above:

  • Priority rows can expire (expiresAt in addPrio's options table, or days in queue prio add and the panel).
  • A player who crashes mid-queue keeps their position for 90 seconds.
  • Nobody at the front of the queue gets bumped by a late donator.
  • queue list, queue kick, queue ban, queue pause from the console.
  • Metrics: average and p95 wait, admits per hour, refusals by reason.
  • The admin panel, once you set a token.

What to look at next

  • Tiers (Config.tiers). Points decide order; tiers decide who follows
    different rules. Give staff bypassQueue so they skip the queue entirely.
  • Reserved slots (Config.reservedSlots). Hold back a few slots that only
    a reserved tier can use.
  • Webhook logging (Config.webhook). Bans, whitelist refusals, admin
    actions, and queue milestones in a Discord channel.

View Rivo Queue