How It Works

How Rivo Queue works

This page explains what happens to a player from the moment they press connect
until they are in the game, and how every setting changes that. Read it once
and the rest of the config will make sense.


1. The connection, step by step

When a player connects, Rivo Queue holds the connection (a FiveM "deferral")
and shows a card on their loading screen. Behind the card, this runs in order:

  1. Identifiers are read. The player is tracked by Config.primaryIdentifier
    (license by default), falling back through Config.identifierFallback.
    No usable identifier means the connection is refused.

  2. Reconnect check. If the same player already has a place in line, or had
    one in the last few seconds, it is carried over (see Reconnect grace).

  3. Gates run. Each gate can refuse the connection. Cheap checks go first so a
    banned player never costs a Discord request.

    Order Gate What it checks
    10 ban The ban list (queue ban add, panel, addBan)
    15 block Temporary blocks left by queue kick
    20 identifiers Config.requireIdentifiers
    30 throttle Too many connection attempts in a short window
    40 whitelist Config.whitelist, when enabled
    45 guild Config.discord.requireInGuild
    50 alts Config.altDetection, when enabled
  4. Player history is recorded for the panel's Users tab
    (Config.playerHistory). Refused players are recorded too.

  5. Processing delay. Config.cooldown seconds.

  6. Priority is resolved from every source (see Priority).

  7. Maintenance check. If maintenance mode is on, only the allowed tiers get
    past this point.

  8. Startup hold. Right after the server boots, everyone waits out
    Config.joinDelay unless their tier has skipJoinDelay.

  9. Queue full check. Config.maxQueueSize, if set.

  10. Admit or queue. The player walks straight in when their tier bypasses the
    queue, or when nobody is waiting and there is a free slot. Everyone else joins
    the queue and sees their position, wait time, estimate and priority.

  11. Admitted. Players who never had to wait see the branded "You are in" card
    for Config.ui.brandHoldSeconds. Then the deferral is released and the game
    starts loading.

  12. Loading. The player now holds a slot while they download and load. When
    they spawn in (playerJoining), the slot becomes a normal player slot.

A player who closes FiveM while waiting is removed after Config.queueTimeout
seconds of silence. A player who is admitted but never finishes loading gives
their slot back after Config.connectingTimeout seconds.


2. Slots

The queue decides who gets in by counting free slots every second:

free = sv_maxClients
     - players online
     - players loading (admitted, not spawned yet)
     - players being admitted this second
     - slots held for crashed players (reconnect grace)
     - Config.reservedSlots          (skipped for tiers with reservedSlot = true)

Counting players who are still loading is what stops the classic queue bug of
admitting 40 people into 30 slots and kicking 10 of them at the loading screen.

queue slots in the console prints exactly these numbers. It is the first thing
to check when the server looks empty but nobody is getting in.

hardcap kicks players as soon as the server is full, which breaks any queue. It
is stopped automatically on start (Config.autoStopHardcap).


3. Priority

Priority is a number of points. More points means further forward.

Sources

Points come from sources. A player can match several at once.

Source Where it comes from
config Config.priorityList, hardcoded identifiers
store Rows saved with queue prio add, the panel, or addPrio (JSON file or MySQL)
discord Config.discord.roles, looked up through your bot
ace Config.acePriority and txAdmin admins (Config.txAdmin)
your own Any resource can add a source with registerPrioritySource (see Developer API)

Rows match on any identifier the player has, so a row saved against
discord:123 still applies to a player tracked by license.

Config.priorityMode decides how matching rows combine: 'sum' adds them,
'max' takes the highest. Stored rows can expire.

Tiers

A row can also name a tier from Config.tiers. The player gets the best tier
named by any of their rows, where "best" means highest in the Config.tiers
list. A tier gives:

Field Effect
points A minimum. A VIP with a 2,500 point tier is worth at least 2,500
bypassQueue Skips the queue whenever a slot they can use is free
reservedSlot Can use the slots held back by Config.reservedSlots
skipJoinDelay Ignores the post-restart hold
badge Name shown on the card and in the panel

4. Order in the queue

Every second the queue is sorted by score, highest first:

score = priority points + time waited bonus
  • Time waited bonus (Config.drift). Every waiting player gains
    pointsPerMinute points per minute. With maxPoints = 'auto' the bonus stops
    one point below your cheapest tier, so a long wait can beat everyone without
    priority but never beats a paying tier.
  • Ties go to whoever joined the queue first.
  • Head lock (Config.headLock). Once a player is first in line, nobody who
    joins later can push them back to second.
  • Admin pins. Moving a player in the panel pins them to that position until
    they get in, leave, or you release the pin. Pins override everything above.

The estimated wait on the card is the average time between recent admissions
multiplied by the player's position.


5. Restarts: startup hold and staged release

After a server boot, every resource needs time to start, and the whole community
tries to connect at once.

  1. Startup hold. For Config.joinDelay seconds everyone is held on a
    "server is starting" card. Restarting only this resource does not trigger it.
  2. Staged release. For Config.stagedRelease.durationSeconds after the hold
    ends, the queue admits at most players people every everySeconds seconds.
    During this window players are not let straight in, they go through the queue
    so priority order is respected. Tiers with bypassQueue still skip it.

6. Reconnect grace

If a player's game crashes while they wait, they do not go to the back.

  • Waiting players who come back within Config.grace.positionSeconds get
    their original queue time back, which puts them back in their old position.
  • Admitted players who crash while loading get their slot held for
    Config.grace.slotSeconds. The held slot counts as taken, and they walk
    straight back in when they reconnect.

Kicked or refused players never get grace.


7. Discord

With a bot token and guild ID set, Discord roles can grant priority, whitelist
access and guild membership checks. Lookups are cached for
Config.discord.cacheSeconds.

When Discord is slow or down:

  • Priority fails open. The player still connects, just without role points
    for that connection. Cached roles keep working through short outages.
  • Whitelist and guild checks fail closed. Letting everyone in would switch
    your whitelist off. Players who pass the whitelist another way (ACE, the
    identifier list) are not affected.
  • Rate limits pause lookups and serve cached roles until Discord allows
    requests again.
  • A rejected token turns Discord features off and logs an error until restart.

8. Storage

Priority rows, bans and player history live in one of two backends:

  • JSON (default when oxmysql is not running): files in data/. Writes are
    batched, and a corrupt file is never overwritten.
  • MySQL (default when oxmysql is running): tables from queue.sql, created
    automatically on first start.

Expired rows are cleaned every Config.pruneIntervalMinutes. Maintenance state
is always kept in data/state.json so it survives a restart.


9. Maintenance mode

queue pause [duration] [reason] or the panel restricts connections to chosen
tiers (Config.maintenance.defaultAllowTiers by default). Players already on the
server are not touched. It persists through restarts and lifts itself when a
duration was given.


10. Logging, metrics and events

  • Console. Config.consoleInfo prints joins, admits and refusals.
    Config.debug prints more.
  • Discord webhook. Four categories you can switch on separately: denial,
    admin, milestone and traffic. Messages are batched and retried on rate
    limits. Player names never ping anyone.
  • Metrics. Counters, peak queue, wait average and p95 per tier, and refusals
    by gate since the last restart. See queue metrics, the panel, or getMetrics.
  • Server events for your own resources: rivo_queue:queued,
    rivo_queue:admitted, rivo_queue:joined, rivo_queue:left,
    rivo_queue:denied, rivo_queue:flagged, rivo_queue:admin and
    rivo_queue:milestone. Payloads are listed in Developer API.

View Rivo Queue