Ressources FiveM¶
medusa-changing-rooms possède les commandes et la logique de placement/édition des vestiaires.
medusa-admin expose leur surface World Edit et transmet au terminal NUI une liste de commandes
filtrée par permissions pour l'autocomplétion.
medusa-entity-placement centralise les prévisualisations de PNJ et props. medusa-world-props possède
la synchronisation et les commandes des objets libres persistants ; medusa-admin ne fournit que leur
surface World Edit.
medusa-inventory possède l'inventaire joueur, sa NUI et les raccourcis de barre rapide. Il résout le
personnage via medusa-player-utils et délègue toute persistance/concurrence à l'API.
medusa-hud possède l'unique NUI d'affichage permanent. Les ressources métier lui transmettent
leurs états par événements client locaux : les buffs alimentent la pile supérieure droite et le
système temps/météo alimente l'inlay date/heure inférieur droit.
Au démarrage, entrypoint.sh parcourt le manifeste construit dans l'image et remplace chaque
ressource [local] du volume persistant par sa copie embarquée. Une reconstruction déploie donc
aussi les modifications et suppressions de fichiers des nouvelles ressources, sans dépendre d'une
liste manuelle qui pourrait devenir incomplète. Les ressources tierces restent synchronisées selon
leurs règles dédiées.
Sorties du terminal F9¶
medusa-admin est le consommateur unique de l'événement medusa:terminal:output. Une commande
cliente publie localement avec TriggerEvent; une commande serveur cible son joueur avec
emitNet. Le payload contient message, un prefix court et un kind parmi output, success,
warning ou error. Le client borne le préfixe à 24 caractères et le message à 4096 caractères,
puis transmet la ligne à la NUI, même si F9 est fermé afin de conserver l'historique de session.
Les messages administratifs historiques passent par le même writer. medusa-commands y publie
les deux formats de /coords, tandis que medusa-core utilise un helper commun pour les résultats
de /characters et /mycharacter. Toute nouvelle commande Medusa qui produit un résultat texte
doit publier sur ce canal ; les interfaces ouvertes par une commande restent leur propre résultat.
medusa-admin¶
La NUI medusa-admin sépare data-admin-section (navigation principale) et data-admin-view
(sous-section). selectAdminSection filtre les onglets selon le domaine et les permissions déjà
calculées ; selectAdminView n'affiche qu'un workspace ingame-<view>-view et ne rafraîchit que le
module actif. Les magasins, vestiaires et objets persistants ne partagent donc plus un conteneur
World Edit empilé. Ajouter un module consiste à déclarer sa section, son onglet, sa vue et ses
métadonnées sans modifier la géométrie générale du panneau.
La sous-navigation utilise un conteneur admin-subnav-track horizontal borné par deux contrôles
précédent/suivant. Le track accepte le défilement natif tactile/trackpad, convertit la molette
verticale en déplacement horizontal lorsqu’il reste du contenu, et gère Gauche/Droite ainsi que
Début/Fin au clavier. selectAdminView replace l’onglet actif dans la zone visible ; les flèches
sont désactivées aux extrémités et l’animation respecte prefers-reduced-motion. Les onglets cachés
par permission ne participent pas à la largeur navigable.
Le shell visuel utilise une grille à trois zones : rail principal, rail secondaire et workspace.
Ses fonds restent confinés au châssis et la racine admin demeure transparente. Les règles AR/VR
communes sont normatives dans .agents/AGENTS.md afin que les futures NUI restent cohérentes avec
medusa-clothing-shops et medusa-inventory.
La NUI expose openAdminAction, un dialogue asynchrone unique qui construit ses champs avec les
API DOM, applique la validation HTML et retourne soit les valeurs saisies, soit null après
annulation. Toutes les actions anciennement basées sur confirm ou prompt passent par ce composant.
medusa-admin isole le panneau NUI, le terminal, les outils visuels World Edit et toutes les commandes administratives. Son client possède exclusivement les key mappings et callbacks NUI administratifs. Son serveur réautorise chaque action et appelle l’API interne via medusa-core.
medusa-moderation reste propriétaire du cycle de connexion et du contexte chargé depuis Discord. Il expose uniquement getAdminProfile(source) et listAdminProfiles() au resource admin. Cette frontière évite de dupliquer l’authentification et permet d’ajouter de nouveaux modules au panneau sans modifier le parcours joueur. medusa-admin est démarré après medusa-moderation dans server.cfg.template et synchronisé comme resource local par entrypoint.sh.
Les exports JavaScript sont enregistrés avec global.exports, conformément au runtime FiveM. Les deux resources possèdent un fichier .resource-version : sa progression force entrypoint.sh à remplacer les copies persistées lors d’un déploiement, évitant qu’un nouveau medusa-admin soit associé à une ancienne copie de medusa-moderation.
Le payload ShowID provient de listAdminProfiles() et conserve highest_role. Le client medusa-admin rend séparément l’identité Discord, le personnage actif et ce rôle sans recalculer la hiérarchie côté client.
La commande /car crée le véhicule avec CreateVehicleServerSetter dans medusa-admin/server.js,
l’affecte au routing bucket du joueur et active le mode orphelin persistant. Le client reçoit
uniquement l’identifiant réseau, attend sa réplication puis place le joueur au volant. Ce flux est
compatible avec le verrouillage OneSync strict appliqué par medusa-world-control : aucune entité
réseau n’est créée côté client.
La commande /delv est autorisée côté serveur avec ADMIN_ALLOW_DELETE_VEHICLE. Le client
parcourt le pool CVehicle, sans exclure les véhicules détruits, et retient l'entité la plus proche
à 10 mètres au maximum. Il demande brièvement le contrôle réseau, marque l'entité comme mission,
puis appelle DeleteVehicle et DeleteEntity en secours. Un résultat n'est accepté par le serveur
que pendant la fenêtre ouverte par la commande ; l'audit vehicle.delete utilise la plaque comme
cible et conserve également la distance et l'identifiant réseau.
La commande /tpm est autorisée côté serveur avec ADMIN_ALLOW_TPM, puis le client recherche le
blip waypoint de type 8. Sans blip, il renvoie un échec explicite. Sinon, il téléporte le ped ou
son véhicule après recherche progressive du sol et chargement des collisions. Le résultat et les
coordonnées finales reviennent au serveur pour le message utilisateur et l’audit
player.teleport_waypoint ; le serveur revalide la permission avant de les accepter.
La commande /tpc est protégée séparément par ADMIN_ALLOW_TPC. Le serveur analyse la chaîne
vec3(x, y, z) ou trois nombres, refuse les valeurs non finies et conserve la destination pendant
15 secondes. Le client téléporte le ped ou son véhicule après demande de collision. Le résultat
est corrélé à la demande en attente et l'audit player.teleport_coordinates reprend exclusivement
les coordonnées validées et conservées côté serveur.
Les ressources sont classées dans [local], [maps], [mods] et [vehicles]. Les ressources
locales implémentent la connexion API, la whitelist, l'accueil, la modération, les commandes, le
loading screen, la création/personnalisation, les magasins de vêtements, les tatouages, le spawn
et les utilitaires joueurs.
Personnages et apparence¶
fivem-appearance reste la release amont originale v1.3.1. L'interface Medusa vit dans
medusa-character-customization et appelle les callbacks amont afin que les palettes cheveux,
reflets, yeux et overlays soient appliquées correctement. medusa-player-utils centralise la
correspondance entre source FiveM, compte connecté et personnage actif.
La création initiale et /customization utilisent l'interface locale ; les apparences enregistrées
continuent d'être chargées avec les exports amont. Les demandes de recustomisation hors ligne sont
persistées côté API.
Magasins de vêtements¶
medusa-clothing-shops lit ses positions, modèle/scénario de conseillère, distances et blip depuis
son config.json. Chaque magasin inscrit un ped géré dans medusa-interactions, sans marqueur au
sol. Un MarkerTypeVerticalCylinder turquoise signale le ped à 20 mètres par défaut, avant le
popup. Sa boucle de dessin ne s'exécute que pendant le ciblage du ped. Le magasin ouvre
medusa-character-customization avec uniquement components et props activés.
L'éditeur conserve un snapshot du ped : annuler ou rencontrer une erreur API restaure ce snapshot.
Le NUI sans focus et les notifications appartiennent désormais à medusa-interactions, afin que le
même langage puisse être réutilisé pour toute entité ou position.
Le bloc popup du config.json des magasins définit l'intégralité des textes, avec surcharge
possible dans chaque entrée de shops.
Le contexte medusaMode = "clothing-shop" transmis à medusa-character-customization sélectionne
les titres, confirmations, télémétrie et libellés vestimentaires. Les deux ressources possèdent un
marqueur de version afin que l'entrypoint propage le redesign dans le volume persistant.
medusa-clothing-shops possède aussi une page NUI transparente dédiée à la cabine VR. Le client
l'affiche juste avant l'ouverture de l'éditeur et la masque dans son callback, quelle que soit
l'issue. Aucun z-index NUI n'est imposé : la pile de focus FiveM conserve l'éditeur interactif au
premier plan. pointer-events: none empêche la couche décorative de capturer une entrée. Les
couleurs et libellés proviennent de vrOverlay dans
le config.json du magasin. Les racines HTML, body et overlay imposent un fond RGBA totalement
transparent ; les cadres n'emploient aucun inset sombre susceptible de teinter la vue GTA. Aucun
fichier de medusa-character-customization n'est modifié.
medusa-changing-rooms reste lui aussi isolé : il réutilise uniquement les exports d'application de
composants/accessoires et le gestionnaire d'interactions. Il ne charge ni ne modifie le NUI, le
client ou la configuration de medusa-clothing-shops.
L'appel de l'export d'ouverture est protégé par pcall. Si l'export manque ou lève une erreur,
la ressource ferme la surcouche, libère son verrou editorOpen, journalise la cause dans la console
client et affiche une notification au joueur ; une tentative suivante reste donc possible.
L'inscription de chaque magasin utilise aussi lockOnAction = true dans medusa-interactions.
L'appui sur E suspend donc globalement le scan, le marker, le popup et les nouvelles entrées avant
l'ouverture de l'éditeur. L'inscription contient un clientEvent et un payload.shopIndex, jamais
un callback Lua non sérialisable. Le gestionnaire local résout le magasin puis libère le verrou via
l'export releaseInteraction(id, reason) après sauvegarde, annulation ou erreur.
Le drapeau temporaire debug du magasin ajoute les traces F8
[medusa-clothing-shops][DEBUG] suivantes : interaction_event, open_requested,
snapshot_captured, vr_overlay, editor_export_call, editor_export_returned et
editor_callback. Si la dernière apparaît immédiatement avec appearance=false, c'est l'éditeur
qui se referme ; si editor_export_failed apparaît, son message contient la cause Lua. L'absence
de interaction_event situe le problème avant le magasin, dans le gestionnaire d'interactions.
À l'enregistrement, le serveur résout le personnage actif avec medusa-player-utils, valide la forme
des composants et props, puis appelle :
PATCH /internal/v1/characters/{character_id}/state
{ "clothing": { "components": [...], "props": [...] } }
PostgreSQL conserve la tenue dans characters.clothing. medusa-spawn la réapplique après
l'apparence à chaque session. Aucun accès direct à la base n'est effectué par la ressource.
Contenu et monde¶
medusa-loading-screencharge sa configuration viaLOADSCREEN_CONFIG_URL.medusa-spawnfournit le point d'apparition de secours.bob74_iplest embarqué en version2.6.1.- les véhicules validés résident individuellement sous
[vehicles]. realistichandlingbyTairaremplace le handling des véhicules vanilla.
Synchronisation du volume¶
Au démarrage, l'entrypoint copie les ressources embarquées absentes dans fivem_resources. Les
ressources versionnées par le projet sont remplacées lorsque leur marqueur change ; les ressources
externes inconnues sont préservées. Les dépendances amont gérées disposent de règles séparées.
Les façades pinées lc_utils et lc_fuel sont toujours remplacées depuis l’image, avant le fallback
d’installation cp -Rn, car leur contrat doit évoluer atomiquement avec medusa-energy. Sans cette
règle, une ancienne copie conservée dans le volume désactive volontairement toutes les stations au
contrôle de compatibilité.
Véhicules enregistrés¶
medusa-vehicles est chargé après le cœur, les interactions, l'inventaire, les groupes et la
banque, puis avant medusa-admin. Il maintient la correspondance UUID ↔ entité réseau et publie
des state bags de corrélation ; l'API reste seule autoritaire pour la clé, le propriétaire et la
serrure. Au premier reconcile d'un démarrage de ressource, l'API force les véhicules actifs dans
un état verrouillé et la ressource les recrée moteur coupé depuis la dernière position sûre.
medusa-admin conserve actorPayload en discord_role_ids pour ses contrats historiques, mais
toutes les routes internes du domaine véhicules utilisent vehicleActorPayload en
actor_role_ids. Le placement serrurier ferme F10, attend la mutation API, puis déclenche la
resynchronisation des Peds et le message de résultat sans rouvrir automatiquement le panneau.
Les actions F10 GPS et SE TP passent par l'export serveur
medusa-vehicles.locateRegistered, qui exige une entité active dans le bucket de l'administrateur.
GPS appelle SetNewWaypoint avec les coordonnées serveur. SE TP réutilise l'événement client de
/tpc, place le Ped ou son véhicule quatre mètres à côté de la cible, charge les collisions et
n'audite qu'un résultat corrélé. restoreRegistered calcule DEVANT MOI depuis le Ped serveur,
refuse les occupants et sérialise la restauration par UUID.