Panneau d'administration
HZ-Bridge embarque un panneau d'administration centralise dans lequel chaque module HZ-Script se branche. Au lieu que chaque script fournisse sa propre commande + interface pour la config, tout est regroupe derriere un seul /hzpanel accessible aux admins. Le panneau construit automatiquement un editeur type pour chaque champ de config declare dans le bridge_schema.lua de chaque module.
Ouvrir le panneau
En jeu (chat, console F8 ou raccourci clavier) :
/hzpanel
- Console seulement (F8 serveur) —
/hzpaneldepuis la console serveur n'ouvre pas le NUI. Tapez-le depuis le jeu. - Necessite la permission ACE configuree sous
HZBridge.Panel.AcePermission(defautadmin) — voir Configuration des permissions ci-dessous. - Appuyez sur
Escapeou cliquez sur le bouton fermer pour quitter. Les sessions sont protegees par token et expirent apresHZBridge.Panel.SessionTokenTtlMs(5 min par defaut) — rouvrez pour rafraichir.
-- server export — ouvre le panneau pour src et preselectionne le module nomme
exports['HZ-Bridge']:OpenPanel(src, 'HZ-Weather')
Configuration des permissions
Le panneau est protege par le noeud ACE canonique admin de FXServer. Deux lignes dans server.cfg sont requises :
add_principal identifier.license:YOUR_LICENSE group.admin
add_ace group.admin admin allow
Remplacez YOUR_LICENSE par la licence du joueur de votre serveur (visible en tapant /hzpanel une fois — la sortie console de l'echec affiche tous vos identifiants + un bloc pret a copier-coller avec votre licence deja interpolee).
Vous pouvez coller les deux lignes directement dans la console serveur pour corriger immediatement — aucun redemarrage requis. Si vous les mettez dans server.cfg, redemarrez FXServer (ou relancez exec server.cfg) pour les charger.
add_ace group.admin command allow dans server.cfg mais pas add_ace group.admin admin allow. Le menu admin de qb-core utilise sa table DB qbcore_admins plutot que le noeud ACE canonique admin, donc la ligne est absente. Presque chaque ticket de permission HZ-Bridge vient de la — ajoutez la seconde ligne et c'est regle.Le probe framework se rabat sur les tables admin de qb-core / qbx_core / ESX / ox_core si la verification ACE echoue. Donc un joueur marque comme admin dans votre table qbcore_admins peut ouvrir le panneau meme sans la configuration ACE. Mais ACE est la methode recommandee car elle est agnostique au framework et auditable en un seul endroit.
Si la verification echoue, la console serveur affiche :
- Le noeud ACE exact verifie
- Tous vos identifiants joueur
- Une matrice de probe ACE (quels noeuds sont accordes, lesquels ne le sont pas)
- Les deux lignes exactes
add_principal+add_acea copier-coller, avec votre licence deja interpolee
command.hzpanel n'accorde PAS le panneau. Une erreur courante est d'essayer add_ace identifier.X command.hzpanel allow. Ce noeud n'est pas utilise par HZ-Bridge — la verification porte sur l'AcePermission configure (defaut admin), pas sur le nom de la commande.Noeud ACE personnalise
Si vous ne voulez pas utiliser le noeud canonique admin (par ex. vous voulez qu'un sous-ensemble specifique du staff ouvre le panneau sans leur donner toutes les autres commandes admin), configurez un noeud personnalise dans config.lua :
HZBridge.Panel.AcePermission = 'hzbridge.panel.admin'
Puis dans server.cfg :
add_principal identifier.license:YOUR_LICENSE group.hzbridge.staff
add_ace group.hzbridge.staff hzbridge.panel.admin allow
Le fallback (quand AcePermission est nil ou '') est 'admin' — aligne sur le defaut de config depuis v1.1.1. Les versions anterieures utilisaient 'HZ-Bridge.admin' comme fallback, ce qui etait un ecart documente et bloquait les clients qui n'avaient que l'ACE canonique admin accorde. Mettez a jour vers v1.1.1 si vous etes concerne.
Ce que vous pouvez modifier
Le panneau decouvre automatiquement chaque ressource qui embarque un fichier bridge_schema.lua a sa racine. A partir de HZ-Bridge v1.1.0, les modules suivants fournissent un schema et s'integrent au panneau :
| Module | Ce que vous pouvez ajuster |
|---|---|
| HZ-Bridge | Theme global — accent, surfaces, mode gradient, echelle arrondis |
| HZ-Weather | Zones (editeur + carte), previsions, heure, saisons, evenements, config |
| HZ-Television | Chaines, valeurs par defaut, options de performance |
| HZ-AudioMixer | Volumes par defaut par categorie, overrides de profil par joueur |
bridge_schema.lua — voir la section DSL de schema ci-dessous.
Le DSL de schema
Le bridge_schema.lua de chaque module est un petit DSL Lua qui declare la config que le panneau expose. Le DSL s'execute dans un environnement sandbox (pas de _G, pas de io brut, sous-ensembles restreints de string / table / math) donc un schema buggue ou malveillant ne peut pas casser le serveur.
Exemple minimal
-- resources/your-script/bridge_schema.lua
module('your-script', {
schemaVersion = 1,
label = { en = 'Your Script', fr = 'Ton script' },
}, function()
section('general', {
label = { en = 'General', fr = 'Général' },
}, function()
field('Enabled', 'boolean', {
default = true,
label = { en = 'Enabled', fr = 'Activé' },
description = {
en = 'Master on/off switch for the script.',
fr = 'Interrupteur global du script.',
},
})
field('PlayerLimit', 'number', {
default = 32, min = 1, max = 256, step = 1,
label = { en = 'Max concurrent players', fr = 'Joueurs simultanés max' },
})
end)
end)
C'est tout — ouvrez /hzpanel, l'onglet "Your Script" apparait avec deux champs types, les changements de valeur sont ecrits sur disque et diffuses a chaque client abonne.
Types de champ
| Type | Rendu | Notes |
|---|---|---|
boolean | Interrupteur toggle | |
number | Saisie numerique avec min / max / step | Variante curseur quand step <= 1 et plage bornee |
string | Saisie texte, pattern + maxLength optionnels | |
enum | Liste deroulante (choix unique) | Choix via choices = { 'a', 'b', 'c' } |
enum-multi | Multi-selection contrainte (chips toggle) | Nouveau en v1.1.0 — stocke en list |
color | Selecteur de couleur hex | Valide en #RRGGBB |
keybind | Capture de raccourci (touche + modificateurs) | |
list | Saisie de tags (ajout/suppression libre) | |
list | Editeur de table inline avec colonnes itemSchema | |
vehicle-list | Grille de selection de vehicules | Remplie automatiquement depuis GetAllVehicleModels() |
weapon-list | Grille de selection d'armes | Catalogue statique, fourni sous web/src/data/weapons.ts |
action | Bouton qui declenche un evenement serveur | Utilisez pour des declencheurs type "Appliquer preset" / "Reset" |
enum-action | Liste deroulante d'actions | |
view | Composant React personnalise pleine largeur | Registre sous web/src/views/ |
Sections, groupes, onglets
section(id, { label, tab, dependsOn }, body)— regroupement visuel dans un onglet de module.tabest l'id du sous-onglet (declare viamodule(name, { tabs = { ... } })).dependsOn = { field = 'X', equals = true }replie la section quand la condition parente est fausse.group(id, { label }, body)— groupe repliable inline dans une section.field(id, type, opts)— un seul champ.optssupportedefault,description,requiresRestart,deprecated,hidden,dependsOn, plus les extras specifiques au type.invariant(sectionId, fn)— validation inter-champs. S'execute a chaque tentative de sauvegarde. Retournenil(ok) ou une chaine (message d'erreur).migrations({ [N] = function(values) ... end })— incrementezschemaVersionet fournissez une migration pour reecrire les anciennes valeurs sauvegardees.
Vues personnalisees
Si vous avez besoin d'une interface plus specifique que ce que le renderer de formulaire type peut produire (un editeur de carte, un graphique, un calendrier...), declarez un champ view et enregistrez le composant React :
-- bridge_schema.lua
field('ZonesEditor', 'view', {
component = 'HZ-Weather:ZoneEditor',
events = {
upsertZone = 'hz_weather:admin:upsertZone',
deleteZone = 'hz_weather:admin:deleteZone',
},
})
// web/src/views/HZ-Weather/index.tsx
import { registerView } from '../registry'
import { ZoneEditor } from './ZoneEditor'
registerView('HZ-Weather:ZoneEditor', ZoneEditor)
HZ-Weather fournit six vues comme implementations de reference : Map, ZoneEditor, Events, Forecast, SeasonsPanel, TimePanel.
Cascade de theme (Apparence)
L'onglet Apparence dans HZ-Bridge centralise les tokens visuels que chaque NUI HZ partage. Un seul changement retinte HZ-Weather, HZ-AudioMixer, HZ-Television en direct — sans redemarrage. Les nouveaux scripts qui se branchent heritent automatiquement de la cascade tant que leur NUI lit les variables CSS canoniques --hz-*.
Axes que vous controlez
| Axe | Cles | Effet | |
|---|---|---|---|
| Accent | accent / accentHi / gold | Trio signature Vice (rose / rose vif / dore). Presets : Vice, Industrial. | |
| Surfaces | surface / subpanel / tint | Panneau exterieur / sous-panneau interieur / teinte hover. RGB seulement — l'opacite est decidee par chaque consommateur. Presets : Surfaces Vice, Surfaces Neutres. | |
| Mode gradient | gradientMode = 'gradient' \ | 'solid' | solid aplatit chaque gradient d'accent en remplissage plat — rendu plus calme / style outil bureautique. |
| Arrondis | radiusNone / Xs / Sm / Md / Lg / Xl | Echelle de coins a six niveaux. Presets : Sharp (0/2/4/6/8/10), Soft (0/3/6/8/12/16), Round (0/4/8/12/16/20), Industrial (0/0/2/2/4/4). |
Comment les modules le consomment
Le payload complet est diffuse a chaque fois que l'admin sauvegarde :
-- server (any resource)
AddEventHandler('HZ-Bridge:theme:updated', function(theme)
-- theme: { preset, accent, accentHi, gold, surface, subpanel, tint,
-- gradientMode, radiusNone, radiusXs, radiusSm, ..., radiusXl }
end)
-- client
RegisterNetEvent('HZ-Bridge:theme:updated', function(theme)
SendNUIMessage({ action = 'theme', data = theme })
end)
Dans votre NUI, ecrivez chaque cle comme variable CSS sur :root (par ex. --hz-accent-rgb, --hz-surface-rgb, --hz-radius-md). Les composants referencent les variables via rgb(var(--hz-accent-rgb) / 0.45) / var(--hz-radius-md) donc la cascade est automatique.
Obtenez le theme actuel de maniere synchrone au demarrage :
local theme = exports['HZ-Bridge']:GetTheme()
Ou demandez-le via TriggerServerEvent('HZ-Bridge:theme:request') — le serveur repond avec TriggerClientEvent('HZ-Bridge:theme:updated', src, theme).
hz-fivem-ui sous examples/theme-cascade-boilerplate.md.Securite + audit
- Schemas sandbox — Le DSL s'execute sans
io,os,debugbruts, et avec une bibliotheque standard restreinte. Unbridge_schema.luabuggue peut echouer au chargement (logue) mais ne peut pas crasher le serveur. - Ecritures rate-limitees — defaut
10 ecritures par 5spar source. Configurable viaHZBridge.Panel.RateLimitWrites/RateLimitWindowMs. - Tokens de session — chaque ouverture du panneau emet un token ephemere ; les tokens expires recoivent un nouveau bootstrap a la prochaine requete.
- Pipeline de validation — chaque sauvegarde passe par la validation de type de champ, les verifications optionnelles
pattern/min/max, puis les fonctionsinvariantau niveau section avant que la valeur n'atterrisse sur disque. - Log d'audit — chaque sauvegarde acceptee ecrit une ligne dans le fichier d'audit rotatif (
data/audit-YYYY-MM-DD.log). Les fichiers rotatifs plus anciens queHZBridge.Panel.AuditRetentionDays(defaut 90) sont supprimes au demarrage. Passez a 365 si vous avez besoin de retention RGPD. - Ecritures atomiques — la config effective par module est ecrite dans
data/via tmpfile + rename. Les ecritures en attente utilisent.json data/et sont commitees de maniere atomique lors d'une sauvegarde reussie..pending.json - Verification ACE par source a chaque action — pas seulement a l'ouverture du panneau. Un admin dont les droits sont revoques ne peut pas continuer a editer sur un panneau deja ouvert.
Reference
- Source du DSL de schema :
modules/panel/schema_dsl.lua - API serveur :
modules/panel/api_server.lua - Module theme :
modules/panel/theme.lua - Panneau React :
web/src/App.tsx - Config effective + en attente :
data/(atomique) +.json data/(en cours).pending.json - Audit :
data/audit-YYYY-MM-DD.log
