Config

x-pvp splits its configuration across six files in config/.

FileLoaded onContentDocumented in
config/config.luaSharedGeneral settings, entry points, UI, translations, framework functionsThis page
config/config_server.luaServerDiscord token, killfeed and revive integrationThis page
config/ffa.luaSharedThe 16 FFA mapsGame Modes
config/lobby.luaSharedLobby system: zone, teams, weapons, 9 mapsGame Modes
config/arena.luaSharedBF mode and Air FightGame Modes
config/gungame.luaSharedGungame rounds and weapon levelsGame Modes

Requirements are es_extended and oxmysql. Restart the resource after every change.

General

Config.Debug            = false

Config.ESX              = {
    resource   = "es_extended",
    event      = "esx:getSharedObject",
    use_export = true
}

Config.SpawnProtection  = 1000  -- ms
Config.ScoreBoardInterval = 300 -- seconds

Config.QuitCommand      = "quitpvp"
Config.QuitLobbyCommand = "quitlobby"
OptionDefaultDescription
DebugfalseConsole output while placing maps or debugging. Off in production
ESX.resourcees_extendedName of your ESX resource, in case yours is renamed
ESX.eventesx:getSharedObjectLegacy event used when use_export is off
ESX.use_exporttrueFetches the shared object through the export. Leave on for any current ESX version
SpawnProtection1000Spawn protection after a respawn, in milliseconds
ScoreBoardInterval300Scoreboard refresh interval, in seconds
QuitCommandquitpvpCommand to leave a PvP mode
QuitLobbyCommandquitlobbyCommand to leave a lobby

Routing buckets

Every mode runs in its own dimension so the fights never see each other or the main world.

Config.BaseDimension = 5000 -- FFA: BaseDimension + map index
ModeDimensionSet in
FFA5000 + map index, so 5001 … 5016 for the 16 shipped mapsconfig.lua
Gungame6000 + map indexgungame.lua → baseDimension
BF mode999arena.lua
Air Fight888arena.lua

The ranges must not overlap. Keep enough room between Config.BaseDimension and the Gungame baseDimension for all of your FFA maps.

Entry points, marker and blip

Config.Locations = {
    vec3(-284.0966, -1920.5275, 29.9460)
}

Each vec3 is one place in the world where players can open the PvP menu. Add as many as you like — marker and blip are drawn at every one of them.

Config.Marker = {
    type         = 42,
    move         = false,
    rotate       = false,
    drawDistance = 20.0,
    scale        = vec3(0.5, 0.5, 0.5),
    color        = { r = 255, g = 255, b = 255, a = 50 },
    zoneStyle    = "sphere",
    zoneAlpha    = 0.35,
    zoneColor    = { r = 170, g = 175, b = 180, a = 50 }
}
OptionDefaultDescription
type42GTA marker type
move / rotatefalseBob up and down / spin the marker
drawDistance20.0Distance in metres at which the marker becomes visible
scale0.5 per axisMarker size
colorwhite, a = 50Marker colour and opacity
zoneStylesphereShape used to preview a map's zone
zoneAlpha / zoneColor0.35 / greyTransparency and colour of that preview
Config.Blip = { sprite = 310, color = 1, scale = 0.8, label = "PVP" }

Standard FiveM blip fields — icon id, colour id, size and the name on the map.

Config.Brand = {
    title    = "x-studios",
    subtitle = "pvp",
}

Config.Tabs = {
    ffa        = true,
    lobbys     = true,
    gungame    = true,
    arena      = true,
    scoreboard = true,
    create     = true,
}

Brand is the heading of the menu. Tabs switches whole sections of the UI on and off — set gungame = false and the tab disappears for everyone, which is the clean way to launch with only part of the system.

Config.Images = {
    ffa      = "./images/ffa/",
    lobby    = "./images/lobbys/",
    modes    = "./images/modes/",
    weapons  = "./images/lobbys/weapons/",
    vehicles = "./images/lobbys/cars/",
    fallback = "./images/placeholder.webp",
}

Folders the UI loads its pictures from, relative to frontend/. The image field of a map or mode is the file name inside the matching folder — a map with image = "rooftop" uses frontend/images/ffa/rooftop.webp. Anything missing falls back to placeholder.webp.

Weapons

Config.Weapons = {
    [`weapon_pistol`]     = {
        `COMPONENT_PISTOL_CLIP_02`
    },
    [`weapon_pistol_mk2`] = {
        `COMPONENT_AT_PI_COMP`,
        `COMPONENT_PISTOL_MK2_CLIP_02`,
        `COMPONENT_AT_PI_RAIL`,
    },
    [`weapon_pistol50`]   = {
        `COMPONENT_PISTOL50_CLIP_02`
    }
}

The default loadout every FFA player gets. The key is the weapon hash, the value is the list of attachments handed out with it — the backtick notation is Lua 5.4 hash syntax, which the resource enables with lua54 "yes".

Individual FFA maps can override this with their own weapons table; see FFA.

Killfeed

Config.OwnKillfeed = true

Config.Killfeed = {
    maxItems = 5,
    lifetime = 6000,
}
OptionDefaultDescription
OwnKillfeedtrueUses the killfeed built into x-pvp. Set false if another resource already draws one
maxItems5Maximum entries on screen at once
lifetime6000How long an entry stays, in milliseconds

If you run x_sync, its killfeed is fed separately through the server functions — see Killfeed integration.

Language

Config.Locale = "de"

Config.Translations = {
    ["de"] = {
        notReady  = "Bitte warte einen Moment",
        ffaJoined = "Du bist der FFA Map %s beigetreten",
        …
    }
}

Config.Locale picks the active table. To switch to English, add an ["en"] table with the same keys and point Config.Locale at it:

Config.Locale = "en"

Config.Translations = {
    ["de"] = { … },
    ["en"] = {
        notReady        = "Please wait a moment",
        cannotUse       = "You cannot use the PvP system right now",
        noCars          = "You cannot use cars in PvP",
        ffaJoined       = "You joined the FFA map %s",
        ffaLeft         = "You left the FFA map %s",
        bfJoined        = "You joined the BF mode",
        bfLeft          = "You left the BF mode",
        bfNoVehicle     = "The vehicle could not be provided",
        airJoined       = "You joined the Air Fight",
        airLeft         = "You left the Air Fight",
        lobbyJoined     = "You joined the lobby of %s",
        lobbyLeft       = "You left the lobby of %s",
        lobbyWinner     = "The lobby is over. Team %s won",
        lobbyDraw       = "The lobby is over. Nobody won (draw).",
        weaponsBack     = "You got %s weapon%s back",
        garageBusy      = "The parking spot is occupied",
        garageSpawned   = "You took out a %s",
        garageFailed    = "The vehicle could not be taken out",
        garageHelp      = "Take out vehicle",
        forceExit       = "You were kicked from the %s automatically because a restart is coming up",
    }
}

Every %s is filled in at runtime — keep them in place and in the same order. Gungame carries its own strings in gungame.lua under Config.Gungame.locales.

Framework functions

Config.Functions is the layer between x-pvp and the rest of your server. The defaults are wired for x_hud with an ESX fallback.

FunctionPurpose
Notify(message)Normal notification
Announce(message)Prominent announcement, e.g. a round result. Falls back to Notify
HelpNotify(message)One-off help text
ToggleHelpNotify(state, message)Shows or hides the persistent "press E" hint
OnRespawn()Runs after a respawn inside PvP
CanJoin()Decides whether the player may enter PvP
UIOpened() / UIClosed()Empty hooks that fire with the menu

Notifications

Config.Functions.Notify = function(message)
    if GetResourceState("x_hud") == "started" then
        local ok = pcall(function()
            exports["x_hud"]:showNotify("info", "PVP", message, 5000)
        end)
        if ok then return end
    end

    if ESX and ESX.ShowNotification then
        ESX.ShowNotification(message, "info", 5000, "PVP")
    end
end

All three notification functions follow the same pattern: try x_hud, fall back to ESX. Replace the body with your own system and nothing else in the resource changes.

Respawn cleanup

Config.Functions.OnRespawn = function()
    if ESX and ESX.SetPlayerData then
        ESX.SetPlayerData("dead", false)
    end

    if GetResourceState("esx_ambulancejob") == "started" then
        TriggerServerEvent("esx_ambulancejob:setDeathStatus", false)
    end

    TriggerEvent("esx:onPlayerSpawn")

    ClearTimecycleModifier()
    ClearExtraTimecycleModifier()
    SetPedMotionBlur(PlayerPedId(), false)
    AnimpostfxStopAll()
end

Clears the death state after a PvP respawn. The four native calls at the end remove the death screen effects — keep them even when you replace the framework part, otherwise players run around with a grey filter over the screen.

Join check

Config.Functions.CanJoin = function()
    if IsPedDeadOrDying(PlayerPedId(), false) then
        return false, "Du kannst das PvP System nicht verwenden, während du tot bist"
    end

    return true
end

Returns true to let the player in, or false plus a reason that is shown to them. This is the place for your own rules — a weapon ban, a jail check, a cooldown:

Config.Functions.CanJoin = function()
    if IsPedDeadOrDying(PlayerPedId(), false) then
        return false, "You cannot use the PvP system while you are dead"
    end

    if LocalPlayer.state.jailed then
        return false, "Not while you are in jail"
    end

    return true
end

Countdown sounds

Config.Countdown = {
    start = { name = "CHECKPOINT_PERFECT", set = "HUD_MINI_GAME_SOUNDSET" },
    tick  = { name = "Beep_Red",           set = "DLC_HEIST_HACKING_SNAKE_SOUNDS" },
    go    = { name = "Beep_Green",         set = "DLC_HEIST_HACKING_SNAKE_SOUNDS" },
}

The three sounds of a round countdown: when it starts, on every tick, and on go. Any GTA sound name with its sound set works.

Server config

config/config_server.lua holds everything that must not reach the client.

ConfigServer.DiscordToken = ""

Bot token used to load the profile pictures in the lobby HUD. Leave it empty and the HUD simply shows no avatars.

A bot token is a credential. Never paste it into a ticket, a screenshot or a public repository. If it leaks, reset it in the Discord developer portal.

Killfeed integration

ConfigServer.Functions.AddPlayerToKillfeed = function(dimIdent, src)
    if GetResourceState("x_sync") ~= "started" then return end

    pcall(function()
        exports["x_sync"]:addPlayer(dimIdent, src)
    end)
end

Registers a player with the x_sync killfeed when they enter a mode; RemovePlayerFromKillfeed(src) takes them out again when they leave. Both check whether x_sync is running, so they are safe to leave in place even without it.

Avatars and revive

ConfigServer.Functions.GetAvatar = function(identifier)
    return nil
end

ConfigServer.Functions.RevivePlayer = function(src)
    TriggerClientEvent("esx_ambulancejob:revive", src)
end
FunctionDescription
GetAvatar(identifier)Return an image URL to override the Discord avatar, or nil to keep the Discord one
RevivePlayer(src)Called when somebody leaves PvP while dead. Point it at your own ambulance job if you are not on esx_ambulancejob

Theming

The look of the menu lives outside the Lua config, in frontend/css/config.css — 168 lines of CSS variables. Change the values, keep the names:

:root {
    --header-text: #FFFFFF;
    --tab-background: rgba(255, 255, 255, 0.05);
    --create-background: radial-gradient(111.79% 675.46% at 50% 50%, #00FF4D 0%, rgba(116, 116, 116, 0) 100%);
    --create-shadow-color: #00FF4D;
    …
}

--background is a stack of radial glows over a dark base, and the accent green of the create button comes from --create-background, --create-border-color and --create-shadow-color.