FiveM Mechanic System: Тюнинг, ремонт и профессии с транспортом
Создайте полноценную систему механика для FiveM. Ремонт, тюнинг, эвакуация на штрафстоянку, интерфейсы магазинов и лучшие скрипты механиков для серверов QBCore и ESX.
Agency Scripts
Основатель и ведущий разработчик Agency Scripts
Проектирование архитектуры работы механика
Система работы механика , одна из самых популярных и полезных для разработки функций на FiveM ролевом сервере. В отличие от простых скриптов ремонта, которые просто вызывают SetVehicleFixed() , полноценная система механика вводит целую экономику работы с специализированными ролями, инвентарями запчастей и взаимодействиями между игроками, которые стимулируют ролевую игру. Архитектура должна учитывать несколько автомастерских по карте, каждая из которых может принадлежать разным группам игроков, с иерархией рангов работы, определяющей, кто может выполнять какие ремонты. В основе нужна общая конфигурация, определяющая расположение мастерских, доступные услуги на каждом уровне, цены на запчасти и ранги работы, необходимые для разблокировки сложных ремонтов, таких как замена двигателя или установка турбо. Система должна интегрироваться с существующей системой работы вашего сервера, будь то QBCore, ESX или кастомное решение, чтобы игроки могли отмечаться на работу и уходить с неё с правильной обработкой зарплаты и учётом статуса дежурства.
Грейды работы и система разрешений
Многоуровневая система рангов работы придаёт профессии механика глубину и стимулирует игроков продвигаться по службе. Начните с определения чётких рангов с конкретными правами: стажёр может только мыть машины и ремонтировать мелкие повреждения кузова, обычный механик , чинить двигатель и менять шины, старший механик , настраивать производительность и красить, а владелец мастерской управляет сотрудниками и устанавливает цены на услуги. Храните определения рангов в общей конфигурации, чтобы клиент и сервер использовали их последовательно. Вот пример конфигурации, сопоставляющей ранги с разрешёнными услугами:
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
}
На стороне сервера всегда проверяйте ранг игрока перед выполнением любой услуги. Никогда не доверяйте клиенту сообщать, какие услуги доступны, так как читер может изменить NUI и отправить любой запрос. Серверный callback должен проверять текущую работу игрока, уровень ранга и наличие запрашиваемой услуги в списке услуг этого ранга перед продолжением ремонта.
Механика ремонта транспортных средств и система запчастей
Реалистичная механика ремонта выходит за рамки одного native вызова. Вместо мгновенного ремонта транспортного средства процесс ремонта разбивается на этапы, которые требуют времени и расходуют запчасти из инвентаря механика. Когда игрок приносит машину на ремонт двигателя, механик должен иметь нужные запчасти в личном инвентаре или в общем складе мастерской. Используйте систему прогресс-бара, чтобы симулировать время ремонта, создавая естественные ролевые моменты, когда клиент ждет и взаимодействует с механиком. Логика ремонта должна нацеливаться на конкретные компоненты транспортного средства с помощью native функций, чтобы можно было ремонтировать двигатель без исправления повреждений кузова или менять шины без влияния на здоровье двигателя:
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
}
Система запчастей создаёт дополнительный экономический слой на вашем сервере. Запчасти хранятся у NPC оптовиков или игроки могут изготавливать их на промышленных площадках. Мастерские могут закупать запчасти оптом по оптовым ценам и хранить их в общем инвентаре магазина, что требует от владельца управления цепочкой поставок для бесперебойной работы бизнеса. Эта динамика спроса и предложения добавляет глубину ролевому опыту.
Покраска аэрозолью и косметические услуги
Покраска аэрозолью , одна из самых визуально удовлетворяющих услуг, которые может предложить автомастерская, и для её качественной реализации требуется работа с несколькими нативными функциями цвета транспортного средства. FiveM предоставляет нативы для основного цвета, вторичного цвета, перламутра, цвета колес и пользовательских RGB значений. Создайте UI выбора цвета, который позволит механику выбирать из предустановленных цветов или вводить пользовательские RGB значения за премиальную цену. NUI должен отображать превью в реальном времени, временно применяя цвет к транспортному средству, пока механик просматривает варианты. Вот как обрабатывать серверное применение цвета после подтверждения покраски механиком и оплаты клиентом:
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)
Помимо базовой покраски, рассмотрите возможность добавления нанесения ливреи, установки неоновых огней и тонировки окон как отдельных косметических услуг. Каждая услуга должна иметь свои требования к деталям и ценовую политику. Например, неоновые огни требуют неоновые комплекты из инвентаря деталей и используют SetVehicleNeonLightEnabled и SetVehicleNeonLightsColour natives для применения визуального эффекта. Тонировка окон использует SetVehicleWindowTint с разными уровнями тонировки, которые могут быть ограничены локальными законами сервера, давая полиции повод останавливать игроков за незаконные тонировки.
Улучшения производительности и тюнинг
Настройка производительности , это то, где механики могут действительно проявить себя и заработать большие деньги на сервере. FiveM предоставляет обширные нативы для модификации транспортных средств через SetVehicleMod функция, которая принимает тип мода и индекс мода. Типы модов охватывают улучшения двигателя (тип 11), тормозов (тип 12), трансмиссии (тип 13), подвески (тип 15), брони (тип 16) и турбо (тип 18). Каждый тип мода имеет несколько уровней, которые постепенно улучшают характеристики автомобиля. Создайте интерфейс тюнинга, показывающий доступные улучшения для текущего автомобиля, стоимость каждого уровня и желательно сравнительную статистику до и после по скорости, ускорению, торможению и управляемости:
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
Улучшения производительности должны требовать ценные детали, такие как турбокомплекты, гоночные трансмиссии или спортивные тормозные системы. Эти детали можно получить у специализированных поставщиков или изготовить игрокам с нужными навыками, создавая межпрофильные зависимости, которые обогащают экономику сервера. Всегда проверяйте запросы на улучшения на сервере, чтобы предотвратить применение модификаций, за которые клиент не заплатил или не имеет необходимых деталей.
Система биллинга и распределения доходов
Чистая система выставления счетов связывает весь опыт механика и обрабатывает финансовые операции между механиком, клиентом и мастерской. После завершения услуги механик генерирует детализированный счёт с перечнем выполненных работ и их стоимостью. Счёт показывается клиенту через уведомление или всплывающее окно NUI, которое он должен принять перед оплатой. Доход делится между механиком, выполнившим работу, и бизнес-счётом мастерской, с настраиваемым владельцем магазина соотношением. Вот серверная система выставления счетов, которая обрабатывает создание и оплату счетов:
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)
Рассмотрите поддержку нескольких способов оплаты, включая наличные, банковские переводы и даже криптовалюту, если на вашем сервере есть криптосистема. Отслеживайте все транзакции в базе данных, чтобы владельцы магазинов могли просматривать историю доходов, выявлять лучших механиков и обнаруживать подозрительные схемы оплаты. Это финансовое отслеживание также позволяет реализовать налоговые системы и взаимодействия с государственными ролевыми элементами, где государство может проводить аудит механиков.
Управление инвентарём тайников и магазинов
Каждому автомастерской нужен общий тайник, где хранятся запчасти и к которому имеют доступ все дежурные сотрудники. Интегрируйте с системой инвентаря вашего сервера, будь то ox_inventory, qb-inventory или кастомное решение, чтобы создать тайник, доступный только авторизованным механикам. Владелец мастерской должен иметь возможность заказывать запчасти у NPC оптового поставщика, что списывает деньги с бизнес-счёта мастерской и добавляет запчасти в тайник после настраиваемой задержки доставки. Эта задержка имитирует реальные логистические процессы и предотвращает мгновенное пополнение. Ведите журнал доступа к тайнику, чтобы владелец видел, какие механики брали какие запчасти, предотвращая внутренние кражи. На клиенте используйте взаимодействие с целью на конкретном объекте в мастерской, например, шкаф для инструментов или полка с запчастями, чтобы открыть тайник. Совместите тайник с системой крафта, где механики могут собирать сложные детали из сырья, например, объединять корпус турбины, крыльчатку и wastegate в полный турбо-комплект, добавляя ещё один навык в работу.
Эвакуаторы и дорожная помощь
Расширение работы механика включением услуг эвакуатора и помощи на дороге значительно увеличивает активность и доходность профессии. Механики должны иметь возможность брать эвакуатор из своего магазина, ехать к месту нахождения застрявшего игрока, прикреплять сломанный транспорт с помощью AttachEntityToEntity native и отбуксируйте его обратно в мастерскую для ремонта. Реализуйте систему диспетчеризации, где игроки могут вызвать помощь на дороге через свой телефон, что создаёт метку на карте, видимую всем дежурным механикам. Первый механик, принявший вызов, получает заказ, и на карту рисуется маршрут GPS до места клиента. Для системы крепления рассчитывайте правильные смещения в зависимости от модели эвакуатора, чтобы буксируемый автомобиль сидел правильно на платформе. Добавьте плату за буксировку, зависящую от расстояния, чтобы более длинные буксировки стоили клиенту дороже, стимулируя механиков обслуживать вызовы в своей зоне, но позволяя брать выгодные дальние заказы по всей карте.