Conception de l'architecture des tâches de mécanique
Un système de travail de mécanicien est l'une des fonctionnalités les plus populaires et les plus gratifiantes à développer pour un serveur de jeu de rôle FiveM. Contrairement aux simples scripts de réparation qui appellent simplement SetVehicleFixed(), un système mécanique approprié introduit toute une économie de travail avec des rôles spécialisés, des inventaires de pièces et des interactions de joueur à joueur qui stimulent le jeu de rôle. L'architecture doit prendre en compte plusieurs ateliers de mécanique sur la carte, chacun potentiellement détenu par différents groupes de joueurs, avec une hiérarchie de niveaux de travail qui détermine qui peut effectuer quelles réparations. À la base, tu as besoin d'une configuration partagée qui définit les emplacements des ateliers, les services disponibles à chaque niveau, le prix des pièces et les niveaux de travail requis pour débloquer des réparations avancées telles que les échanges de moteurs ou les installations de turbo. Le système doit s'intégrer au cadre de travail existant de ton serveur, qu'il s'agisse de QBCore, ESX ou d'une solution personnalisée, afin que les joueurs entrent et sortent du rôle de mécanicien avec une gestion appropriée des chèques de paie et un suivi de l'état des tâches.
Classements d'emploi et système d'autorisation
Un système de notation à plusieurs niveaux donne de la profondeur à ton travail de mécanicien et encourage les joueurs à gravir les échelons. Commencez par définir des niveaux clairs avec des autorisations spécifiques : un stagiaire peut uniquement être capable de laver les véhicules et de réparer des dommages mineurs à la carrosserie, un mécanicien standard peut gérer les réparations du moteur et le remplacement des pneus, un mécanicien senior débloque le réglage des performances et la peinture au pistolet, et le propriétaire de l'atelier peut gérer les employés et fixer les tarifs des services. Stockez ces définitions de notes dans une configuration partagée afin que le client et le serveur puissent les référencer de manière cohérente. Voici un exemple de configuration qui mappe les notes à leurs services autorisés :
Config.MechanicGrades = {
[0] = {
label = 'Trainee',
services = {'wash', 'body_minor'},
payMultiplier = 0.7
},
[1] = {
label = 'Mechanic',
services = {'wash', 'body_minor', 'body_major', 'engine_repair', 'tire_replace', 'brake_repair'},
payMultiplier = 1.0
},
[2] = {
label = 'Senior Mechanic',
services = {'wash', 'body_minor', 'body_major', 'engine_repair', 'tire_replace',
'brake_repair', 'spray_paint', 'performance_tune', 'turbo_install'},
payMultiplier = 1.3
},
[3] = {
label = 'Shop Owner',
services = 'all',
payMultiplier = 1.5,
canManage = true
}
}
Config.ServicePrices = {
wash = 200,
body_minor = 800,
body_major = 2500,
engine_repair = 3500,
tire_replace = 1200,
brake_repair = 1500,
spray_paint = 5000,
performance_tune = 15000,
turbo_install = 25000
}
Côté serveur, validez toujours la note du joueur avant d'autoriser l'exécution d'un service. Ne faites jamais confiance au client pour signaler quels services sont disponibles, car un tricheur pourrait modifier le NUI pour envoyer n'importe quelle demande de service. Le rappel du serveur doit vérifier le travail actuel du joueur, son niveau scolaire et si le service demandé existe dans la liste de services de son niveau avant de procéder à la réparation.
Mécanique de réparation de véhicules et système de pièces
Des mécanismes de réparation réalistes vont au-delà d’un simple appel natif. Au lieu de réparer instantanément un véhicule, divisez le processus de réparation en étapes qui nécessitent du temps et consomment des pièces de l'inventaire du mécanicien. Lorsqu'un joueur amène sa voiture pour une réparation de moteur, le mécanicien doit avoir les bonnes pièces dans son inventaire personnel ou dans la réserve partagée du magasin. Utilisez un système de barre de progression pour simuler la réparation qui prend du temps, ce qui crée des moments de jeu de rôle naturels où le client attend et interagit avec le mécanicien. La logique de réparation doit cibler des composants spécifiques du véhicule à l'aide de fonctions natives afin que tu puissies réparer le moteur sans réparer les dommages à la carrosserie, ou remplacer les pneus sans affecter la santé du moteur :
local RepairFunctions = {
engine_repair = function(vehicle)
local parts = {'engine_oil', 'spark_plugs', 'coolant'}
if not HasRequiredParts(parts) then
return false, 'Missing required parts'
end
RemovePartsFromInventory(parts)
-- Animate the repair
TaskTurnPedToFaceEntity(PlayerPedId(), vehicle, 1000)
Wait(1000)
if not StartProgressBar('Repairing engine...', 15000, 'mechanic_repair') then
return false, 'Repair cancelled'
end
SetVehicleEngineHealth(vehicle, 1000.0)
SetVehicleEngineOn(vehicle, true, true, false)
return true
end,
body_major = function(vehicle)
local parts = {'body_panel', 'filler_putty', 'paint_primer'}
if not HasRequiredParts(parts) then
return false, 'Missing required parts'
end
RemovePartsFromInventory(parts)
if not StartProgressBar('Repairing body damage...', 20000, 'mechanic_repair') then
return false, 'Repair cancelled'
end
SetVehicleBodyHealth(vehicle, 1000.0)
SetVehicleDeformationFixed(vehicle)
return true
end,
tire_replace = function(vehicle, tireIndex)
local parts = {'tire_set'}
if not HasRequiredParts(parts) then
return false, 'Missing required parts'
end
RemovePartsFromInventory(parts)
if not StartProgressBar('Replacing tire...', 8000, 'mechanic_repair') then
return false, 'Repair cancelled'
end
SetVehicleTyreFixed(vehicle, tireIndex)
return true
end
}
Le système de pièces détachées crée une couche économique supplémentaire sur ton serveur. Stockez les pièces chez les grossistes PNJ ou laissez les joueurs les fabriquer dans des sites industriels. Les ateliers de mécanique peuvent acheter des pièces en gros aux prix de gros et les stocker dans un inventaire partagé, ce qui signifie que le propriétaire de l'atelier doit gérer sa chaîne d'approvisionnement pour assurer le bon fonctionnement de son entreprise. Cette dynamique de l’offre et de la demande ajoute une profondeur considérable à l’expérience de jeu de rôle.
Peinture au pistolet et services cosmétiques
La peinture au pistolet est l'un des services les plus visuellement satisfaisants qu'un atelier de mécanique puisse offrir, et sa bonne mise en œuvre nécessite de travailler avec plusieurs fonctions natives de couleur du véhicule. FiveM fournit des valeurs natives pour les couleurs primaires, secondaires, nacrées, la couleur de la roue et les valeurs RVB personnalisées. Créez une interface utilisateur de sélecteur de couleurs qui permet au mécanicien de sélectionner parmi des couleurs prédéfinies ou de saisir des valeurs RVB personnalisées à un prix plus élevé. Le NUI doit afficher un aperçu en temps réel en appliquant temporairement la couleur au véhicule pendant que le mécanicien parcourt les options. Voici comment gérer l'application de couleur côté serveur une fois que le mécanicien a confirmé le travail de peinture et que le client a payé :
RegisterNetEvent('mechanic:server:applyPaint', function(netId, paintData, customerId)
local src = source
local Mechanic = QBCore.Functions.GetPlayer(src)
local Customer = QBCore.Functions.GetPlayer(customerId)
if not Mechanic or not Customer then return end
if Mechanic.PlayerData.job.name ~= 'mechanic' then return end
local gradeServices = Config.MechanicGrades[Mechanic.PlayerData.job.grade.level].services
if gradeServices ~= 'all' and not TableContains(gradeServices, 'spray_paint') then
return TriggerClientEvent('QBCore:Notify', src, 'Not authorized', 'error')
end
local price = paintData.isCustomRGB and Config.ServicePrices.spray_paint * 1.5
or Config.ServicePrices.spray_paint
if Customer.Functions.RemoveMoney('cash', price, 'mechanic-paint') then
local shopCut = math.floor(price * 0.6)
local mechanicCut = price - shopCut
Mechanic.Functions.AddMoney('cash', mechanicCut, 'mechanic-paint-commission')
AddToShopFunds(Mechanic.PlayerData.job.grade.level >= 3 and src, shopCut)
TriggerClientEvent('mechanic:client:applyPaint', customerId, netId, paintData)
TriggerClientEvent('QBCore:Notify', src, 'Paint applied - earned $' .. mechanicCut, 'success')
TriggerClientEvent('QBCore:Notify', customerId, 'Vehicle painted for $' .. price, 'success')
else
TriggerClientEvent('QBCore:Notify', src, 'Customer cannot afford this', 'error')
end
end)
Au-delà de la peinture de base, envisagez d'ajouter l'application de livrées, l'installation de néons et la teinture de vitres en tant que services cosmétiques distincts. Chaque service doit avoir ses propres exigences en matière de pièces et son propre prix. Les néons, par exemple, nécessitent des kits néon de l'inventaire des pièces et utilisent le SetVehicleNeonLightEnabled et SetVehicleNeonLightsColour autochtones pour appliquer l’effet visuel. Utilisations de la teinture des vitres SetVehicleWindowTint avec différents niveaux de teinte qui pourraient être restreints par les lois locales sur les serveurs, donnant à la police une raison d'arrêter les joueurs pour des teintes illégales.
Améliorations et réglages des performances
Le réglage des performances est l'endroit où les mécaniciens peuvent vraiment briller et gagner le plus d'argent sur le serveur. FiveM fournit de nombreuses modifications natives du véhicule via le SetVehicleMod fonction, qui accepte un type de mod et un index de mod. Les types de mods couvrent les améliorations du moteur (type 11), les freins (type 12), la transmission (type 13), la suspension (type 15), le blindage (type 16) et le turbo (type 18). Chaque type de mod comporte plusieurs niveaux qui améliorent progressivement les performances du véhicule. Créez une interface de réglage qui affiche les mises à niveau disponibles pour le véhicule actuel, le coût de chaque niveau et, idéalement, une comparaison de statistiques montrant les valeurs avant et après pour la vitesse, l'accélération, le freinage et la maniabilité :
function GetAvailableUpgrades(vehicle)
local upgrades = {}
local modTypes = {
{type = 11, label = 'Engine', icon = 'fa-engine'},
{type = 12, label = 'Brakes', icon = 'fa-brake'},
{type = 13, label = 'Transmission', icon = 'fa-gears'},
{type = 15, label = 'Suspension', icon = 'fa-car'},
{type = 16, label = 'Armor', icon = 'fa-shield'},
{type = 18, label = 'Turbo', icon = 'fa-bolt'}
}
SetVehicleModKit(vehicle, 0)
for _, mod in ipairs(modTypes) do
local currentLevel = GetVehicleMod(vehicle, mod.type)
local maxLevel = GetNumVehicleMods(vehicle, mod.type)
local isTurbo = mod.type == 18
table.insert(upgrades, {
type = mod.type,
label = mod.label,
icon = mod.icon,
currentLevel = currentLevel,
maxLevel = isTurbo and 1 or maxLevel,
installed = isTurbo and IsToggleModOn(vehicle, mod.type) or currentLevel >= 0,
price = CalculateUpgradePrice(mod.type, currentLevel + 1)
})
end
return upgrades
end
function ApplyPerformanceUpgrade(vehicle, modType, level)
SetVehicleModKit(vehicle, 0)
if modType == 18 then
ToggleVehicleMod(vehicle, 18, true)
else
SetVehicleMod(vehicle, modType, level, false)
end
end
Les améliorations des performances devraient nécessiter des pièces de grande valeur telles que des kits turbo, des transmissions de course ou des ensembles de freins sportifs. Ces pièces peuvent provenir de fournisseurs spécialisés ou être fabriquées par des joueurs possédant les compétences appropriées, créant ainsi des dépendances croisées qui enrichissent l'économie des serveurs. Validez toujours les demandes de mise à niveau sur le serveur pour empêcher les clients d'appliquer des modifications pour lesquelles ils n'ont pas payé ou pour lesquelles ils n'ont pas les pièces.
Système de facturation et partage des revenus
Un système de facturation propre relie toute l’expérience du mécanicien et gère les transactions financières entre le mécanicien, le client et l’atelier. Lorsqu'un mécanicien effectue un service, générez une facture détaillée répertoriant chaque service effectué et son coût. Présentez la facture au client via une notification ou une fenêtre contextuelle NUI qu'il doit accepter avant que le paiement ne soit traité. Répartissez les revenus entre le mécanicien qui a effectué le travail et le compte professionnel de l'atelier, avec le ratio de répartition configurable par le propriétaire de l'atelier. Voici un système de facturation côté serveur qui gère la création des factures et le traitement des paiements :
local activeInvoices = {}
RegisterNetEvent('mechanic:server:createInvoice', function(customerId, services)
local src = source
local Mechanic = QBCore.Functions.GetPlayer(src)
local Customer = QBCore.Functions.GetPlayer(customerId)
if not Mechanic or not Customer then return end
if Mechanic.PlayerData.job.name ~= 'mechanic' then return end
local totalPrice = 0
local lineItems = {}
for _, service in ipairs(services) do
local price = Config.ServicePrices[service.name]
if price then
totalPrice = totalPrice + price
table.insert(lineItems, {
name = service.label,
price = price
})
end
end
local invoiceId = 'INV-' .. os.time() .. '-' .. math.random(1000, 9999)
activeInvoices[invoiceId] = {
mechanic = src,
customer = customerId,
total = totalPrice,
items = lineItems,
shopId = Mechanic.PlayerData.metadata.currentShop,
timestamp = os.time()
}
TriggerClientEvent('mechanic:client:showInvoice', customerId, invoiceId, lineItems, totalPrice)
end)
RegisterNetEvent('mechanic:server:payInvoice', function(invoiceId)
local src = source
local invoice = activeInvoices[invoiceId]
if not invoice or invoice.customer ~= src then return end
local Customer = QBCore.Functions.GetPlayer(src)
local Mechanic = QBCore.Functions.GetPlayer(invoice.mechanic)
if Customer.Functions.RemoveMoney('cash', invoice.total, 'mechanic-invoice') then
local mechanicShare = math.floor(invoice.total * 0.4)
local shopShare = invoice.total - mechanicShare
if Mechanic then
Mechanic.Functions.AddMoney('cash', mechanicShare, 'mechanic-wage')
TriggerClientEvent('QBCore:Notify', invoice.mechanic,
'Received $' .. mechanicShare .. ' for services', 'success')
end
UpdateShopBalance(invoice.shopId, shopShare)
activeInvoices[invoiceId] = nil
TriggerClientEvent('QBCore:Notify', src, 'Paid $' .. invoice.total, 'success')
else
TriggerClientEvent('QBCore:Notify', src, 'Not enough cash', 'error')
end
end)
Pensez à prendre en charge plusieurs méthodes de paiement, notamment les espèces, les virements bancaires et même la crypto-monnaie si ton serveur dispose d'un système de cryptographie. Suivez toutes les transactions dans un journal de base de données afin que les propriétaires de magasins puissent consulter l'historique de leurs revenus, identifier leurs mécanismes les plus performants et repérer tout modèle de facturation suspect. Ce suivi financier permet également aux systèmes fiscaux et aux interactions gouvernementales de jouer un rôle dans lesquelles l’État peut auditer les ateliers de mécanique.
Gestion des stocks et des stocks de magasin
Chaque atelier de mécanique a besoin d'une réserve commune où les pièces sont stockées et accessibles à tous les employés en service. Intégrez-le au système d'inventaire de ton serveur, qu'il s'agisse de ox_inventory, de qb-inventory ou d'une solution personnalisée, pour créer une réserve spécifique à l'atelier à laquelle seuls les mécaniciens autorisés peuvent accéder. Le propriétaire du magasin devrait avoir la possibilité de commander des pièces auprès d'un fournisseur en gros PNJ, qui déduit l'argent du compte professionnel du magasin et ajoute les pièces à la réserve après un délai de livraison configurable. Ce délai simule la logistique réelle de la chaîne d’approvisionnement et empêche un réapprovisionnement instantané. Suivez l'accès à la cachette dans un journal afin que le propriétaire du magasin puisse voir quels mécaniciens ont pris quelles pièces, évitant ainsi le vol interne. Du côté du client, utilisez une interaction ciblée sur un accessoire spécifique à l'intérieur de l'atelier, comme une armoire à outils ou une étagère de pièces détachées, pour ouvrir la réserve. Combinez la réserve avec un système de fabrication où les mécaniciens peuvent assembler des pièces complexes à partir de matières premières, par exemple en combinant un boîtier de turbo, une turbine et une soupape de décharge dans un kit turbo complet, ajoutant ainsi une autre couche basée sur les compétences au travail.
Dépanneuse et assistance routière
L'extension du métier de mécanicien aux services de dépanneuse et d'assistance routière augmente considérablement l'activité et le potentiel de revenus du métier. Les mécaniciens devraient être capables de vérifier une dépanneuse depuis leur atelier, de se rendre à l'emplacement d'un joueur bloqué, d'attacher le véhicule cassé à l'aide du AttachEntityToEntity natif et remorquez-le jusqu'à l'atelier pour réparation. Implémentez un système de répartition permettant aux joueurs de demander une assistance routière via leur téléphone, ce qui crée un indicateur sur la carte visible par tous les mécaniciens en service. Le premier mécanicien à accepter l'appel obtient le travail et un itinéraire GPS est tracé jusqu'à l'emplacement du client. Pour le système de fixation, calculez les positions de décalage appropriées en fonction du modèle de dépanneuse pour garantir que le véhicule remorqué repose correctement sur le plateau. Ajoutez des frais basés sur la distance au service de remorquage afin que les remorquages plus longs coûtent plus cher au client, incitant les mécaniciens à traiter les appels dans leur région tout en leur permettant d'effectuer des travaux longue distance lucratifs sur toute la carte.
