RivalityFX Docsrivalityfx.com ↗

Getting started

This page takes you from an empty folder to a running mode. For a deeper, rules-and-all walkthrough see Build your first mode.

Prerequisites

  • A FiveM server already running the engine resource and its dependencies (ui, spawnmanager, lobby, baseevents).
  • routingBuckets left at its default (true) in engine/shared/config.lua. This is required — see the golden rule.

1. Create the resource

A mode is just a resource that depends on both sdk (the contract/registry) and engine (the runtime). The minimum is a manifest and one server script.

[modes]/mode_mygame/
├── fxmanifest.lua
└── server/
    └── main.lua

fxmanifest.lua:

fx_version 'cerulean'
game 'gta5'
 
author 'You'
description 'mode: My Game'
version '0.1.0'
 
dependencies { 'sdk', 'engine' }
 
-- The SDK's shared helpers + descriptor builder + LuaCATS types, included into your
-- VM so the descriptor below validates at load and your editor autocompletes it.
shared_scripts {
    '@sdk/shared/kit.lua',         -- validation primitives the contract uses (load first)
    '@sdk/shared/criteria.lua',    -- the criterion contract `defineMode` delegates to (required)
    '@sdk/shared/descriptor.lua',  -- defineMode + the RfxMode types
}
 
server_script 'server/main.lua'

The dependencies { 'sdk', 'engine' } line guarantees both the SDK (the contract/registry) and the engine (the runtime) are present.

2. Write the descriptor

The descriptor is a plain Lua table wrapped in defineMode — which validates it at load (a malformed descriptor aborts here with a precise message, not silently at runtime) and fills defaults. A mode declares its structure (teamCount × perTeam — teams are anonymous, no names/colors/models) and a declarative rules block that runs on the engine's rules runtime — no functions required.

-- [modes]/mode_mygame/server/main.lua
local MODE = defineMode{
    id        = 'mygame',                            -- must be unique across all modes
    apiVersion = 1,                                  -- descriptor contract version you target
    label     = 'My Game',
    teamCount = 2,                                   -- 2 anonymous teams...
    perTeam   = 2,                                   -- ...of 2 players (2v2)
    minToStart = 1,                                  -- 1 per team starts the round
    maxRound  = 5,                                   -- best of: first to 5 round wins
    -- Behaviour: a declarative `rules` block, auto-run on the engine's rules runtime.
    rules = {
        structure = 'rounds',                        -- elimination rounds
        phases    = { live = 150, post = 5 },
        roundEnd  = { 'elimination', 'timeLimit' },  -- team wipe OR the live timer ends a round
        win       = { roundWins = 5 },
    },
    -- The kit is symmetric (same for every combatant).
    armor   = 100,
    loadout = { { 'WEAPON_CARBINERIFLE', 150 }, { 'WEAPON_PISTOL', 100 } },
}

Maps are not part of the mode: battlegrounds from the shared pool declare a modes.mygame block (spawn arrays indexed by team number) — see the battleground SDK. See the Mode descriptor reference for every field, its type, default, and scope.

3. Register it

Wait until the SDK resource has started, then register the descriptor with the SDK — which the engine mirrors and runs. The SDK tags the descriptor with your resource name automatically, and drops the mode if your resource stops.

CreateThread(function()
    while GetResourceState('sdk') ~= 'started' do Wait(100) end
    exports.sdk:registerMode(MODE)
end)

4. Run it

Add the resource to your server.cfg (after the SDK and the engine) and start the server:

ensure sdk
ensure engine
ensure mode_mygame

On a successful registration the SDK prints:

[sdk] mode registered: mygame (My Game) from mode_mygame

5. Test it in-game

  1. Connect. You spawn in the lobby (bucket 0).
  2. Press M to open the main menu (NUI).
  3. Pick My Game in the mode rail — it opens the mode's cover (hero, live badges, your record). Hit Play casual to reach the casual arena browser, then create an arena (pick map / loadout / best-of) or join an open one. (Ranked slots, if any, are joined straight from the cover.)
  4. Bring in enough clients to fill it (or, as an admin with rfx_lab on, run /rfx lab start to force a solo round). The arena auto-launches the moment it's full — there's no ready-up — and the round opens live immediately: on a battleground with ground spawns (all the base duel arenas) each player starts standing on their spot; on one with only areas, they parachute in.
  5. Press Esc → Leave (or /leave) to return to the lobby.

If your mode never appears in the menu, check the server console for the mode registered line and confirm dependencies { 'sdk', 'engine' } is in your manifest.

Next steps