Modifiez uniquement config/garages.lua pour une intégration simple. Le fichier est réservé au serveur et regroupe le choix des fournisseurs, les exports personnalisés, les correspondances de champs/états et les adaptations avancées. Redémarrez cdt_admin après modification. Ces réglages ne sont pas enregistrés dans la configuration SQL ni modifiables dans le menu en jeu.
1. Choisir les fournisseurs
Deux choix sont indépendants :
garageProvider: destinations, garage/fourrière, frais et suppression des véhicules actifs.vehicleProvider: registre des propriétaires, lecture et sauvegarde des véhicules.
Valeurs connues : qbx, esx, jg, qs, cd, origen, okok, custom, ou un fournisseur ajouté dans providers. Les noms exacts des ressources sont aussi acceptés. Les intégrations natives et leurs limites sont décrites dans GARAGE_BRIDGE.md.
auto refuse plusieurs garages actifs. Pour les véhicules, il utilise le garage sélectionné s'il déclare une API de lecture, un adaptateur de lecture ou un stockage SQL ; sinon il utilise qbx_vehicles. Une erreur dans un appel personnalisé ne provoque pas un changement silencieux de registre.
Les convars cdt_admin:garages et cdt_admin:vehicles restent prioritaires. Retirez-les pour effectuer le choix uniquement dans le fichier. Qbox utilise par défaut qbx_garages pour les destinations et qbx_vehicles pour le registre. Un garage commercial n'est pas supposé exposer toutes les opérations de propriété et de sauvegarde.
2. Exemple personnalisé
Les noms de ressources et d'exports ci-dessous sont des exemples, à remplacer par les noms et signatures documentés par votre version.
return {
garageProvider='custom',
vehicleProvider='custom',
esxWritable=false,
providers={},
adapters={},
custom={
resource='mon_garage',
vehicleResource='mon_registre', -- Facultatif : sinon la même ressource.
operations={
GetGarages={type='export',name='GetGarages',args={}},
GetPlayerVehicles={type='export',name='GetVehicles',args={'$citizenid'}},
GetPlayerVehicle={type='export',name='GetVehicle',args={'$id','$citizenid'}},
SaveVehicle={type='export',name='SaveVehicle',args={'$entity','$options','$vehicle'}},
SetVehicleGarage={type='export',name='SetGarage',args={'$id','$garage','$providerState','$citizenid'}},
SetVehicleDepotPrice={type='export',name='SetPrice',args={'$id','$price'}},
DeleteVehicle={type='export',name='DeleteVehicle',args={'$entity','$vehicle'}},
},
vehicleFields={id='vehicle_id',citizenid='owner',props='mods',state='status',garage='location'},
vehicleStates={out='outside',stored='parked',impounded='pound'},
garageFields={id='name',label='label',coords='position',type='kind'},
garageTypes={garage='parking',depot='impound'},
garageDefaults={bucket=0},
},
}
Les opérations simples sont exclusivement des exports serveur. Les noms et paramètres sont lus depuis le fichier installé, jamais depuis une requête de l'interface. Une opération à false est désactivée ; une opération absente garde son intégration native lorsqu'elle existe. Aucun événement asynchrone n'est considéré comme une confirmation de sauvegarde ou de déplacement.
Pour remplacer une seule opération d'un fournisseur connu, placez la même structure dans providers :
providers={
jg={operations={
GetPlayerVehicles={type='export',name='GetVehicles',args={'$citizenid'}},
}},
},
Vous pouvez également configurer un catalogue statique custom.garages, au format normalisé {legion={label='Legion',type='garage',bucket=0,accessPoints={{coords={x=1,y=2,z=3,w=0}}}}} si le script n'expose pas ses destinations. Une opération GetGarages explicitement configurée est prioritaire sur ce catalogue statique.
3. Opérations et paramètres
| Opération | Ressource par défaut | Paramètres disponibles |
|---|---|---|
GetGarages | Garage | Aucun |
GetPlayerVehicles | Registre véhicules | $citizenid |
GetPlayerVehicle | Registre véhicules | $id, $citizenid |
SaveVehicle | Registre véhicules | $entity, $options, $vehicle, $id, $citizenid, $plate |
SetVehicleGarage | Garage | $vehicle, $id, $citizenid, $garage, $definition, $state, $providerState |
SetVehicleDepotPrice | Garage | $vehicle, $id, $citizenid, $price |
DeleteVehicle | Garage | $entity, $vehicle, $id, $citizenid, $plate |
CanMove | Garage | $vehicle, $id, $citizenid, $garage, $definition, $price, $isLive |
MatchesEntity | Registre véhicules | $entity, $vehicle, $id, $citizenid, $plate |
$citizenid est l'identifiant de personnage utilisé par le framework : citizenid Qbox ou identifiant de personnage ESX, pas l'identifiant serveur temporaire. Il peut être absent lors d'une lecture interne par identifiant seul. $id peut être numérique ou textuel. $vehicle est la ligne normalisée ; $entity est l'entité serveur active. $options contient notamment les propriétés récupérées du véhicule. $definition est la destination choisie.
Les champs imbriqués sont utilisables, par exemple $options.props, $vehicle.props.plate. Les arguments imbriqués dans des tableaux sont également remplacés. L'ordre et les valeurs nil/false sont conservés. Un nom de paramètre inconnu est refusé. Les fonctions ne sont pas acceptées dans les listes de paramètres simples.
Si un export appartient à une autre ressource, vous pouvez ajouter resource='autre_ressource' dans son opération. Cette ressource doit être réellement démarrée. Pour un retour enveloppé, utilisez resultPath='data' ou resultPath='success' ; ces chemins lisent des clés texte, sans exécuter une expression.
4. Traduire les formats de retour
GetPlayerVehicles doit renvoyer une liste/table de lignes ; GetPlayerVehicle une seule ligne. Chaque ligne normalisée doit avoir un id valide et un citizenid. CDT vérifie de nouveau l'identifiant et le propriétaire, même si l'export ignore les filtres reçus.
vehicleFields associe les champs CDT aux chemins de votre ligne : id, citizenid, props, state, garage, depotPrice, coords, plate, modelName, etc. Les propriétés et coordonnées encodées en JSON sont décodées. Une plaque séparée peut alimenter props.plate.
vehicleStates traduit les valeurs de votre script en états CDT : 0 sorti, 1 rangé, 2 fourrière. Sans mapping, les états de retour doivent déjà être normalisés. Lors du rangement, $state contient l'état CDT, tandis que $providerState contient la valeur correspondante de vehicleStates, ou l'état CDT si aucun mapping n'est configuré.
GetGarages peut renvoyer un dictionnaire normalisé indexé par nom, ou une liste ayant un identifiant. garageFields traduit notamment id, label, coords, type, bucket, depotPrice. Le champ coords devient un point d'accès. garageTypes distingue garage et fourrière ; une classe car/air/sea ne suffit pas à établir cette distinction. garageDefaults fournit les valeurs absentes et garageOverrides adapte des destinations précises.
Ces mappings s'appliquent aux retours des exports personnalisés. Les adaptateurs avancés fournissent directement les formats normalisés décrits dans GARAGE_BRIDGE.md.
5. Confirmer les mutations
SaveVehicle, SetVehicleGarage, SetVehicleDepotPrice, DeleteVehicle, CanMove et MatchesEntity exigent un retour true. Les erreurs, false et l'absence de retour ne sont pas convertis en succès. Un objet {success=true} peut être lu avec resultPath='success'.
SetVehicleGarage doit enregistrer la destination et son état. SaveVehicle doit terminer la sauvegarde avant de retourner. DeleteVehicle doit supprimer réellement l'entité et traiter la persistance/le registre des véhicules sortis de votre fournisseur ; CDT vérifie également que l'entité n'existe plus. Si ces étapes nécessitent plusieurs appels ou une relecture, utilisez un adaptateur avancé.
Les contrôles de permission, service staff, propriétaire, destination et occupants restent effectués par les actions admin. La configuration n'active pas les écritures ESX ou SQL par défaut. Les schémas SQL et règles de cache du fournisseur ne sont pas inventés.
6. Adaptations avancées et distribution
Les fonctions adapters restent dans ce même fichier et sont prioritaires sur les opérations déclaratives et natives. Elles permettent les conversions complexes, les API asynchrones, les contrôles de déplacement et l'audit via InstallAudit. Le stockage SQL explicite déjà prévu dans providers est conservé, avec ses écritures désactivées par défaut.
Tous les fichiers de cette distribution sont exclus de la protection Asset Escrow (escrow_ignore { '**/*' }), y compris config/garages.lua. Ce fichier est réservé au serveur et n'est pas envoyé aux clients.
Après redémarrage, testez avec un staff autorisé et un véhicule de test : liste/propriétaire, destination, sauvegarde, garage/fourrière, frais et refus d'un véhicule occupé. Vérifiez les données persistées, les logs et le retour du véhicule après un redémarrage. Les tests automatisés de CDT ne remplacent pas la validation avec votre version réelle du garage.
