Config
x-pvp splits its configuration across six files in config/.
| File | Loaded on | Content | Documented in |
|---|---|---|---|
config/config.lua | Shared | General settings, entry points, UI, translations, framework functions | This page |
config/config_server.lua | Server | Discord token, killfeed and revive integration | This page |
config/ffa.lua | Shared | The 16 FFA maps | Game Modes |
config/lobby.lua | Shared | Lobby system: zone, teams, weapons, 9 maps | Game Modes |
config/arena.lua | Shared | BF mode and Air Fight | Game Modes |
config/gungame.lua | Shared | Gungame rounds and weapon levels | Game 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"
| Option | Default | Description |
|---|---|---|
Debug | false | Console output while placing maps or debugging. Off in production |
ESX.resource | es_extended | Name of your ESX resource, in case yours is renamed |
ESX.event | esx:getSharedObject | Legacy event used when use_export is off |
ESX.use_export | true | Fetches the shared object through the export. Leave on for any current ESX version |
SpawnProtection | 1000 | Spawn protection after a respawn, in milliseconds |
ScoreBoardInterval | 300 | Scoreboard refresh interval, in seconds |
QuitCommand | quitpvp | Command to leave a PvP mode |
QuitLobbyCommand | quitlobby | Command 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
| Mode | Dimension | Set in |
|---|---|---|
| FFA | 5000 + map index, so 5001 … 5016 for the 16 shipped maps | config.lua |
| Gungame | 6000 + map index | gungame.lua → baseDimension |
| BF mode | 999 | arena.lua |
| Air Fight | 888 | arena.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 }
}
| Option | Default | Description |
|---|---|---|
type | 42 | GTA marker type |
move / rotate | false | Bob up and down / spin the marker |
drawDistance | 20.0 | Distance in metres at which the marker becomes visible |
scale | 0.5 per axis | Marker size |
color | white, a = 50 | Marker colour and opacity |
zoneStyle | sphere | Shape used to preview a map's zone |
zoneAlpha / zoneColor | 0.35 / grey | Transparency 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.
Menu
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,
}
| Option | Default | Description |
|---|---|---|
OwnKillfeed | true | Uses the killfeed built into x-pvp. Set false if another resource already draws one |
maxItems | 5 | Maximum entries on screen at once |
lifetime | 6000 | How 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.
| Function | Purpose |
|---|---|
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
| Function | Description |
|---|---|
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.