FiveM机械师系统:调校、维修与车辆职业
构建完整的 FiveM 机械师系统。维修、调校、扣押拖车、商店 UI 以及适用于 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发送任意服务请求。服务器回调应检查玩家当前职业、等级以及请求服务是否存在于该等级的服务列表中,然后再执行修理。
车辆维修机制和零件系统
真实的维修机制超越单一的 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批发商处备货,或让玩家在工业地点制造。修理店可批量购买零件以批发价存入共享库存,店主需管理供应链以保持业务顺畅。此供需动态极大丰富了角色扮演体验。
喷漆和美容服务
喷漆是机械车间提供的最具视觉满足感的服务之一,良好的实现需要使用多个车辆颜色 native 函数。FiveM 提供了主色、次色、珠光色、轮毂颜色和自定义 RGB 值的 natives。构建一个颜色选择器 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 function,接受改装类型和改装索引。改装类型包括发动机升级(类型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订购零件,扣除店铺营业账户资金,并在可配置的交货延迟后将零件添加到仓库。此延迟模拟现实供应链物流,防止即时补货。记录仓库访问日志,店主可查看哪些机械师取走了哪些零件,防止内部盗窃。客户端通过在店铺内特定道具(如工具柜或零件架)上的目标交互打开仓库。将仓库与制作系统结合,机械师可用原材料组装复杂零件,例如将涡轮壳体、叶轮和废气旁通阀组合成完整涡轮套件,为工作增添技能层次。
拖车与路边援助
扩展机械师职业,包含拖车和路边援助服务,大幅提升职业活跃度和收入潜力。机械师应能从店铺借出拖车,驱车前往遇险玩家位置,使用 AttachEntityToEntity native,将其拖回修理店。实现调度系统,玩家可通过手机请求道路救援,地图上为所有值班机械师创建标记。第一个接受呼叫的机械师获得任务,并绘制 GPS 路线到客户位置。对于连接系统,根据拖车模型计算正确的偏移位置,确保被拖车辆正确放置在平板上。对拖车服务添加基于距离的费用,距离越长费用越高,激励机械师优先处理本区域呼叫,同时仍允许他们接收跨地图的高利润长途任务。