F5 StudioF5 Studio
Skip to main content

Permissions

F5 Combat HUD has two independent access systems, and they answer different questions:

SystemQuestionWhereEnforced by
F5Cfg.ModeratorAcesWho may moderate the marketplace?config/features.luaThe server, on every moderation call
F5Cfg.SectionOverridesWhat does this group's menu show?config/features.luaThe menu only

Everything else — which features exist at all — is configuration, not permission.

Marketplace Moderators

config/features.lua
F5Cfg.ModeratorAces = {
'command.combathud_admin',
'god',
'admin',
'mod',
}

A player who matches any entry gets the Moderation tab inside the marketplace: hiding and unhiding listings, deleting them, and banning or unbanning players from the marketplace.

How an entry is matched

Each entry is tried three ways, and any one of them is enough:

  1. As a bare ACE — IsPlayerAceAllowed(src, 'admin')
  2. As the ACE group.<entry>group.admin
  3. On ESX, against the group the player carries on their character — xPlayer.getGroup() == 'admin'

That is what makes one list work on all three frameworks. god, admin and mod are QBCore's own admin groups, admin is also the ESX group and the QBox group.admin ACE — so existing staff already qualify whichever framework you run.

mod is deliberately broad on QBCore

Because entries are also matched as group.<entry>, listing 'mod' grants moderation to the ACE principal group.mod as well as to the QBCore group. Drop 'mod' from the list if marketplace moderation should stay above that rank.

A permission of this resource's own

command.combathud_admin exists for someone who moderates the marketplace without being a server admin:

server.cfg
add_ace group.moderator command.combathud_admin allow

Then add the players to that group:

server.cfg
add_principal identifier.license:110000112345678 group.moderator

Framework examples

QBCore / QBox — reuse your existing admin groups

Nothing to do. god, admin and mod are already in the list, and both frameworks expose them as group.<name> ACEs.

To grant a custom group instead:

server.cfg
add_ace group.helper command.combathud_admin allow
ESX — the group on the character

ESX stores the group on the character (users.group), and the bridge asks xPlayer.getGroup() before falling back to ACEs. A player whose group is admin matches the shipped list with no server.cfg changes at all.

For a custom ESX group, add the group name to the list:

config/features.lua
F5Cfg.ModeratorAces = {
'command.combathud_admin',
'god', 'admin', 'mod',
'superadmin', -- matched against xPlayer.getGroup() and the ACE group.superadmin
}

The tab is not the permission

marketplaceModerate — the flag that shows the tab — is EnableMarketplace and <player is a moderator>. But the tab being visible is never what grants the power: every moderation call re-runs the same check on the server before it touches the database. A modified NUI that forces the tab open gets a refusal on every button.

Moderation is also unavailable to everyone when F5Cfg.EnableMarketplace = false, regardless of ACEs.

Per-Group Menu Overrides

SectionOverrides changes what the menu shows a given group. It is empty out of the box:

config/features.lua
F5Cfg.SectionOverrides = {
-- trial = {
-- customImage = false, rainbow = false, glow = false,
-- },
}

A key matches the ACE group.<key> — and, on ESX, the group on the player's character. The example above hides the custom image, rainbow and glow sections from anyone in group.trial.

Use it to take away, never to give

Overrides rewrite one thing only: the payload that decides what the menu shows this player. The server's validators and the HUD's own render gates both read the global config and never see a group's payload. So:

  • Granting a group a section that is globally disabled gives them a visible panel whose values are pinned or wiped on the next save.
  • Taking a section away from a group hides the controls, but anything they had already switched on keeps rendering. To actually switch a feature off, switch it off globally.

What you can override

KeyHides
rainbowCrosshair → Rainbow mode
glowCrosshair → Glow
dynamicCrosshair → Dynamic spread
aimingVisibilityCrosshair → ADS visibility
customImageCrosshair → Custom image
animatedCrosshair → Animation
hpColorCrosshair → HP-based colour
killstreakScoreboard → Killstreak announcement and thresholds
killstreakCounterScoreboard → Live streak counter
kdHudScoreboard → K/D display
kdHudPresetsScoreboard → K/D preset grid
killFeedScoreboard → Kill feed
killFeedPresetsScoreboard → Kill feed preset grid
dragPositionScoreboard → Drag-to-position
publishMarketplace → publish / update / unpublish
publishCustomImageMarketplace → publishing a custom-image crosshair
applyMarketplace → applying someone else's listing
likesMarketplace → likes
authorProfileMarketplace → author profile
searchMarketplace → search
sortMarketplace → sorting
tagsMarketplace → tag filter

The whole-feature flags can be overridden the same way — EnableCrosshair, EnableEffects, EnableScoreboard, EnableMarketplace, EnableHitmarker, EnableHitParticles, EnableDamageNumbers, EnableKillmarker, EnableHeadshotMarker, EnableHitDirection, EnableKillFlash, EnableKillstreak, EnableKDHud, EnableKillFeed, EnableWeaponCrosshairs — again only for hiding, never for granting.

Five sections cannot be overridden

presets, style, parameters, colors and preview have no override mapping. Writing them into a group's table does nothing — the menu keeps showing them. Switch them off globally in CrosshairSections / EffectsSections instead.

Any key the override system does not recognise is named at startup, so a typo is not silent:

[f5_combathud][config-validator] WARN: F5Cfg.SectionOverrides.trial.rainbwo is not a known section or Enable* flag — it will be ignored
Only false closes a section

Override values are used exactly as written and are never type-checked. customImage = false hides the section; customImage = 0, = 'no' or = nil all leave it open. Write the boolean.

killstreak, kdHud and killFeed address the Scoreboard sections — the configurator panels. The Enable* keys address the tab-level flags the payload is built from. Neither stops the feature rendering: what the HUD draws is decided by the global config, not by a group's payload.

Overriding a tab does not fold its sections

Turning off a tab for a group hides the tab, but the sections inside it are separate keys. If you want a group to lose the Scoreboard tab and have its sections stay hidden should you re-enable the tab later, list each key:

config/features.lua
F5Cfg.SectionOverrides = {
trial = {
EnableScoreboard = false,
killstreak = false,
kdHud = false,
killFeed = false,
},
}

One player, two groups

When a player is in two groups that set the same key, the winner is undefined — the tables are merged in whatever order Lua walks them. Put the union in a single group instead of relying on precedence.

When Changes Take Effect

The feature payload is built per player when their character loads, and the client asks for it exactly once per session. There is no polling.

You changedThe player sees it
A file in config/After a resource restart, on their next character load
An ACE or a groupOn their next reconnect — not after a timeout
Integration hook

The client listens for f5_combathud:client:configChanged. Nothing inside the resource ever fires it — it exists so another resource of yours can push a refresh without a relog:

TriggerClientEvent('f5_combathud:client:configChanged', source)

The player's menu then re-fetches its payload. The server caches that payload for 30 seconds per player, so fire the event a moment after the change rather than in the same tick.

Audit Trail

When a player's client sends data for a section that is switched off — a modified NUI, or settings saved before you disabled the section — the server discards it and writes a row into f5_combathud_admin_audit with the action policy_strip and the actor system. Moderation actions are recorded there as well.

The table is write-only in game: nothing in the menu ever reads it. See Database → Audit.

See Also