RivalityFX
RivalityFX is a modular PvP arena engine for FiveM (GTA V, Lua 5.4). It's a platform: it runs several PvP game modes at once — round-based duels, deathmatch, battle royale — each in its own isolated match, and you customize or extend it without touching the core.
This documentation has two paths:
- Run a server — deploy on Linux, configure and operate it, and (optionally) sell VIP + cosmetic packs. Start here if you're hosting RivalityFX.
- Create for it — build and distribute game modes, maps, ped skins, outfits, weapon wraps, and load screens against the stable, public SDK. Start here if you're a creator extending it.
The rest of this page explains what the engine is — useful background for both paths, and the foundation the SDK builds on.
What the engine is
The engine owns the generic machinery, and nothing else:
- Scene instances — one scene is one running match, bound to one mode.
- Routing buckets — each scene gets its own bucket, so matches never collide.
- Arenas — the one match container: players open or join an arena of a mode, which fills and auto-launches into a scene (no ready-check). A persistent arena recycles after each match; a player-created one closes when it empties.
- Tick loop — drives every scene (a built-in driver, or your custom
tick). - Kill / death dispatch — killfeed, spectate, and your mode's hooks.
- Default scoreboard + match HUD — rendered for two-team modes for free.
- Lobby snapshot — the live list of modes and scenes the menu reads.
- Built-in rules runtime — declarative
rulesblocks: elimination rounds, deathmatch, and zone control, with no gameplay code.
The engine owns no game rules. Round length, win conditions, teams, and loadouts come from your mode; maps come from the shared battleground pool (the battlegrounds a mode draws from — distinct from the Arena match container above), which a mode can also ship its own map into (see the battleground SDK).
The mod model
A mode is a separate resource — a different Lua VM from the engine — so it
can be shipped, versioned, and sold on its own. A mode depends on both sdk (the
contract/registry) and engine (the runtime), and registers a plain-data
descriptor with the SDK (exports.sdk:registerMode), which the engine mirrors
and runs:
-- [modes]/mode_xxx/server/main.lua
CreateThread(function()
while GetResourceState('sdk') ~= 'started' do Wait(100) end
exports.sdk:registerMode(MODE) -- MODE is a plain Lua table
end)Because a descriptor is plain data, the simplest mode you can ship — the 1v1
Duel — contains no functions at all: just its structure (teamCount ×
perTeam), win condition, loadouts, and a declarative rules block. That is the
floor, not the ceiling. A mode grows along a value ladder, and you only pay
for the rung you need:
- A
rulespreset — zero code. The Duel isstructure = 'rounds'with a best-of win condition; the built-in rules runtime composes it into a full match. Its value is design — loadouts, pacing, the arenas it draws from — not lines of Lua. - A
rulescomposition — still zero code.rulesis a device system, not a fixed menu. Add thezonesdevice and the same machine becomes King of the Hill, Domination, or Hardpoint: a genuinely different mode, still pure data. New devices (triggers, sequencers, spawners) widen what data alone can express. - An imperative escape hatch — your own code. When a mode needs logic the
devices don't cover (Gun Game, Escort, Infection…), it ships a
tickloop, a registered nativedriver, or per-event hooks (onKill, …). These are real function references that run inside the mode's VM; the SDK registry drops a mode automatically if its owning resource stops, so a dead hook is never called. See Hooks and Choosing how to drive a mode.
Plain data is a deliberate strength, not a limitation: a descriptor is validated
against a versioned contract (apiVersion), serializable, and carries no arbitrary
code into the engine — so a mode is safe to distribute and to load. You drop to a
tick/driver only when the declarative surface genuinely runs out.
The golden rule
One scene = one mode = one routing bucket.
Two matches can therefore never share a bucket, which gives you natural isolation:
two duels (or two different modes) cannot interfere with each other. This
requires routingBuckets = true in the engine config — it is on by default
and must stay on. See the lobby contract and the
internal buckets notes.
Where to go next
Running a server — the operator / server-owner path
- Deploy on Linux — from an empty VM to a live server.
- Server configuration — the
server.cfgfile, every convar, ACE, secrets. - Operations & ranked — grant ranks, the
/rfxcommands, running ranked play. - Configuration recipes — copy-paste setups for common server shapes.
- Selling VIP & packs — monetize without pay-to-win (Tebex + VIP).
Creating & extending — the creator path
- Creating for RivalityFX — the hub: modes, maps, skins, outfits, weapon wraps, load screens, and how to ship/sell them.
- Getting started — scaffold, register, run, and test a mode.
- Build your first mode — a full end-to-end walkthrough.
- Choosing how to drive a mode — a
rulesblock vs a customtickvs a registered nativedriver. - Mode API reference