Configuration
Configuration
Rivo Queue works out of the box. Everything below is optional.
There are three files you can edit:
| File | What it controls |
|---|---|
config/config.lua |
Every setting |
config/theme.lua |
The loading card: banner, icon, colours, buttons |
config/locales/en.lua |
Every message players and admins see |
Restart the resource after changing them. queue reload re-reads tiers only.
Secrets
Tokens are never stored in config.lua. Put them in server.cfg or a separate
cfg file you don't share:
set rivo_queue:panelToken "long-random-value" # admin panel
set rivo_queue:discordToken "your-bot-token" # Discord roles and checks
set rivo_queue:webhookUrl "https://discord.com/api/webhooks/..." # Discord logging
General
| Option | Default | Description |
|---|---|---|
Config.locale |
'en' |
Which file in config/locales/ to use |
Config.debug |
false |
Extra console output for troubleshooting |
Config.consoleInfo |
true |
Print a console line when players queue, get in or leave |
Slots
| Option | Default | Description |
|---|---|---|
Config.reservedSlots |
0 |
Slots only tiers with reservedSlot = true can use |
Config.maxQueueSize |
0 |
Refuse new players once this many are waiting. 0 means unlimited. Tiers with bypassQueue are exempt |
The server size is read from sv_maxClients.
Timing
All values are in seconds unless the name ends in Ms.
| Option | Default | Description |
|---|---|---|
Config.cooldown |
2 |
Short processing delay before a player is queued or let in |
Config.joinDelay |
45 |
After a server boot, hold everyone this long so resources can start. 0 disables |
Config.cardRefreshMs |
1000 |
How often the loading card updates, in milliseconds |
Config.connectingTimeout |
300 |
How long an admitted player has to finish loading before their slot is released |
Config.queueTimeout |
30 |
Remove a waiting player after this long with no network activity (they closed the game) |
Config.deniedHold
How long the "you cannot join" card stays on screen before the connection
closes, per refusal reason. Reasons not listed use default.
| Key | Default |
|---|---|
default |
15 |
ban |
2 |
block |
2 |
throttle |
2 |
alts |
8 |
['queue-full'] |
5 |
Other reasons you can add: identifiers, whitelist, guild, maintenance.
Staged release
Config.stagedRelease controls how players are let in after the startup hold.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Turn staged release on or off |
players |
5 |
Players admitted per window |
everySeconds |
10 |
Length of each window |
durationSeconds |
120 |
How long after joinDelay ends the limit applies |
While it is active, players go through the queue instead of walking straight
in. Tiers with bypassQueue are not limited.
Reconnect grace
Config.grace controls crash recovery.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Turn it on or off |
positionSeconds |
90 |
A waiting player who reconnects within this time gets their old position back |
slotSeconds |
45 |
An admitted player who crashed while loading has their slot held this long |
Ordering
| Option | Default | Description |
|---|---|---|
Config.headLock |
true |
The player first in line can't be pushed back by someone who joins later |
Config.drift
Waiting players gain points over time so nobody waits forever.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Turn it on or off |
pointsPerMinute |
5 |
Points gained per minute of waiting |
maxPoints |
'auto' |
The most drift points a player can gain. 'auto' stops one point below your cheapest tier, so waiting never beats a paying tier. A number sets a fixed cap |
Player UI
Config.ui
| Field | Default | Description |
|---|---|---|
mode |
'card' |
'card' for the Adaptive Card, 'text' for plain text |
showQueueList |
false |
Show a list of players ahead on the card |
maskNames |
true |
Partly hide names in that list, e.g. Kair* |
maxPlayersToDisplay |
10 |
How many names the list shows |
showEstimatedWait |
true |
Show the estimated wait |
brandHoldSeconds |
3 |
Show the "You are in" card for this long to players who didn't have to queue. 0 makes joins instant |
| Option | Default | Description |
|---|---|---|
Config.displayQueueInHostName |
true |
Prefix the server name with the queue size, e.g. [55] My Server |
Admin
| Option | Default | Description |
|---|---|---|
Config.adminAce |
'rivo_queue.admin' |
ACE players need to use the queue command. The console always can |
Config.kickCooldownSeconds |
60 |
How long queue kick blocks a player from reconnecting. 0 disables |
add_ace group.admin rivo_queue.admin allow
Player history
Config.playerHistory keeps one row per player who has connected. The panel's
Users tab and alt detection use it. IP addresses are never stored.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Record players. When off, nothing is stored |
retentionDays |
90 |
Delete a player's history this many days after they were last seen. 0 keeps it forever |
Admin panel
Config.panel controls the web panel at http://your-server-ip:30120/rivo_queue/.
It stays closed until rivo_queue:panelToken is set. See Admin panel.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Serve the panel |
tokenConvar |
'rivo_queue:panelToken' |
Convar holding the token |
rateLimit |
240 |
Requests allowed per address per window |
rateWindowSeconds |
60 |
Length of the rate limit window |
Maintenance
| Option | Default | Description |
|---|---|---|
Config.maintenance.defaultAllowTiers |
{ 'staff' } |
Tiers allowed to connect during queue pause |
Metrics and alerts
| Option | Default | Description |
|---|---|---|
Config.milestones |
{ 25, 50, 100, 200 } |
Queue sizes announced once when reached |
Config.longWaitSeconds |
1800 |
Announce anyone who has waited this long. 0 disables |
Discord webhook
Config.webhook posts events to a Discord channel. Set the URL with therivo_queue:webhookUrl convar, then run queue webhook test.
| Field | Default | Description |
|---|---|---|
enabled |
false |
Turn logging on |
urlConvar |
'rivo_queue:webhookUrl' |
Convar holding the webhook URL |
url |
'' |
Fallback URL if the convar is not set |
username |
'Rivo Queue' |
Name shown on messages |
avatar |
nil |
Avatar image URL |
batchSeconds |
5 |
Messages are grouped and sent this often |
maxBuffered |
200 |
Oldest messages are dropped past this many waiting to send |
events
| Field | Default | What it posts |
|---|---|---|
denial |
true |
Refused connections and alt flags |
admin |
true |
Kicks, bans, priority changes, maintenance |
milestone |
true |
Queue size milestones and long waits |
traffic |
false |
Every queued and admitted player. Busy servers will post a lot |
style
| Field | Default | Description |
|---|---|---|
format |
'v2' |
'v2' for Discord Components V2, 'embed' for classic embeds |
compact |
false |
One line per event instead of a block |
accent |
see config | Accent colour per event kind, as 0xRRGGBB |
icons |
see config | Emoji per event kind. '' hides one |
titles |
{} |
Override a heading, e.g. titles = { denied = 'Refused' } |
thumbnail |
nil |
Image URL shown beside each message |
showIdentifier |
true |
Show the player's identifier under each message |
showTimestamp |
true |
Show a relative time under each message |
footer |
nil |
Extra text added under each message |
separators |
true |
Divider line between heading and body |
Event kinds for accent, icons and titles: denied, flagged, admin,milestone, longWait, queued, admitted.
Environment
| Option | Default | Description |
|---|---|---|
Config.autoStopHardcap |
true |
Stop the hardcap resource on start, since it kicks players the queue is holding |
Identity
| Option | Default | Description |
|---|---|---|
Config.primaryIdentifier |
'license' |
The identifier each player is tracked by |
Config.identifierFallback |
{ 'license2', 'fivem', 'discord', 'steam', 'ip' } |
Used in order if the primary is missing |
Config.requireIdentifiers |
{} |
Refuse players missing any of these, e.g. { 'discord' } |
Messages for discord, steam and license are included. For any other kind,
add an errMissing_<kind> line to your locale file.
Bans
| Option | Default | Description |
|---|---|---|
Config.bans.enabled |
true |
Check the built-in ban list on connect |
txAdmin bans are handled by txAdmin itself before Rivo Queue runs.
Whitelist
Config.whitelist refuses anyone who doesn't pass at least one of its checks.
| Field | Default | Description |
|---|---|---|
enabled |
false |
Turn the whitelist on |
roles |
{} |
Discord role IDs, e.g. { '123456789012345678' }. Needs Config.discord set up |
ace |
'rivo_queue.whitelist' |
Players with this ACE pass |
identifiers |
{} |
Identifiers that pass, e.g. { ['license:abc123'] = true } |
anyPriority |
false |
Anyone with a stored priority row passes |
If Discord can't be reached, players who rely on a role to pass are asked to try
again. Players who pass another way are not affected.
Connection throttle
Config.throttle refuses players who reconnect too many times in a short window.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Turn it on or off |
windowSeconds |
60 |
Length of the window |
maxPerWindow |
10 |
Connection attempts allowed per window |
Alt detection
Config.altDetection looks for one person using several accounts.
| Field | Default | Description |
|---|---|---|
enabled |
false |
Turn it on |
mode |
'flag' |
'flag' logs and marks the player in the panel. 'deny' refuses them |
signals.concurrent |
true |
Two accounts connecting at the same time with the same Discord |
signals.tokens |
true |
Two accounts connecting at the same time with the same hardware |
signals.discord |
true |
A Discord account previously seen with a different license. Needs Config.playerHistory enabled |
Run it in 'flag' mode for a while before switching to 'deny'. Shared PCs and
households can trigger it.
Priority
Config.priorityList
Hardcoded priority by identifier. A number is points, a table sets more fields.
Config.priorityList = {
['license:abc123'] = { points = 10000, label = 'Owner', tier = 'staff' },
['discord:123456789012345678'] = 2500,
}
Config.priorityMode
| Value | Effect |
|---|---|
'sum' (default) |
Add up every matching row |
'max' |
Use only the highest row |
Config.acePriority
Priority from ACE permissions, in the same format.
Config.acePriority = {
['rivo_queue.vip'] = { points = 2500, label = 'VIP', tier = 'vip' },
}
add_ace group.vip rivo_queue.vip allow
Config.txAdmin
txAdmin admins are detected through the ACE txAdmin gives them.
| Field | Default | Description |
|---|---|---|
enabled |
true |
Give txAdmin admins priority |
ace |
'txadmin.menu.viewer' |
The permission to check |
points |
50000 |
Points given |
label |
'Staff' |
Label shown on the card |
tier |
'staff' |
Tier given |
Config.discord
Priority, whitelist and membership checks from your Discord server. Setup steps
are in Installation.
| Field | Default | Description |
|---|---|---|
enabled |
false |
Turn Discord features on |
guildId |
'' |
Your Discord server ID |
tokenConvar |
'rivo_queue:discordToken' |
Convar holding the bot token |
token |
'' |
Fallback token if the convar is not set. Not recommended |
requireInGuild |
false |
Refuse players who are not in your Discord server |
cacheSeconds |
300 |
How long a player's roles are cached |
timeoutMs |
5000 |
Give up on a Discord lookup after this long |
roles |
{} |
Role ID to priority, in the same format as priorityList |
roles = {
['123456789012345678'] = { points = 5000, label = 'Founder', tier = 'founder' },
['234567890123456789'] = 2500,
},
Tiers
Config.tiers lists your tiers, best first. A player gets the best tier named by
any of their priority rows.
| Field | Description |
|---|---|
name |
ID used in priority rows, e.g. 'vip' |
points |
Minimum points for anyone in the tier |
bypassQueue |
Skip the queue whenever a slot they can use is free |
reservedSlot |
Can use Config.reservedSlots |
skipJoinDelay |
Ignore the startup hold |
badge |
Name shown on the card and in the panel |
Config.tiers = {
{ name = 'staff', points = 100000, bypassQueue = true, reservedSlot = true, skipJoinDelay = true, badge = 'Staff' },
{ name = 'founder', points = 25000, reservedSlot = true, badge = 'Founder' },
{ name = 'vip', points = 2500, badge = 'VIP' },
}
Storage
| Option | Default | Description |
|---|---|---|
Config.storage |
'auto' |
'auto' uses MySQL when oxmysql is running, otherwise JSON. 'json' or 'mysql' forces one |
Config.storageFile |
'data/priority.json' |
JSON file for priority rows |
Config.banFile |
'data/bans.json' |
JSON file for bans |
Config.identityFile |
'data/identities.json' |
JSON file for player history |
Config.storageFlushMs |
1000 |
JSON writes are grouped over this many milliseconds |
Config.mysqlTablePrefix |
'rivo_queue_' |
Prefix for the MySQL tables |
Config.mysqlAutoMigrate |
true |
Create the MySQL tables on start. Turn off if your database user can't create tables, and run queue.sql yourself |
Config.pruneIntervalMinutes |
30 |
How often expired rows are deleted. 0 disables |
Theme
config/theme.lua styles the loading card.
| Field | Default | Description |
|---|---|---|
banner |
nil |
Image at the top of the card. nil uses your server's banner_detail convar, false hides it, or set a URL |
icon |
nil |
Small image beside the server name. Must be a public HTTPS URL |
backgroundImage |
nil |
Full card background image |
serverName |
nil |
Name shown on the card. nil uses sv_hostname |
colors |
see file | Text colours: heading, position, muted, good, warning, error |
positionStyle |
'emphasis' |
Background style behind the position number |
buttons |
{} |
Link buttons, e.g. { { label = 'Discord', url = 'https://discord.gg/yourinvite' } } |
credit |
true |
Show a small "powered by Rivo Queue" line |
Loading cards use FiveM's Adaptive Card colours, so colors accepts 'default','dark', 'light', 'accent', 'good', 'warning' or 'attention'.positionStyle accepts 'default', 'emphasis', 'good', 'attention','warning' or 'accent'.
Translations
- Copy
config/locales/en.luato a new file, e.g.de.lua. - Change
Locales['en']toLocales['de']and translate the text. - Set
Config.locale = 'de'.
Keep the {placeholders} as they are. Lines starting with log use %s and%d in a fixed order, so keep those in the same order. Missing lines fall back
to English.