Skip to Content
QBCore docs – powered by Nextra 4
ResourcesQB-MechanicJob - Vehicle Repair & Tuning System

QB-MechanicJob - Vehicle Repair & Tuning System

The qb-mechanicjob resource provides a comprehensive vehicle repair and tuning system for QBCore servers, featuring mechanic shops, vehicle customization, repair services, and towing operations.

Overview

QB-MechanicJob creates a realistic automotive service experience with vehicle repairs, custom tuning, paint jobs, performance modifications, and complete mechanic shop management. Players can operate as mechanics or customers seeking vehicle services.

Key Features

  • Mechanic Shops: Multiple workshop locations with full service capabilities
  • Vehicle Repairs: Engine, body, and component repair systems
  • Custom Tuning: Performance modifications and upgrades
  • Paint & Liveries: Vehicle customization and visual modifications
  • Towing Service: Flatbed and tow truck operations
  • Parts Inventory: Vehicle parts and supplies management
  • Service Billing: Customer invoicing and payment system
  • Shop Management: Business operations and employee management
  • Vehicle Diagnostics: Damage assessment and repair estimates

Installation

Prerequisites

  • QBCore Framework
  • qb-target (for interaction system)
  • qb-menu (for mechanic menus)
  • qb-input (for service forms)
  • qb-inventory (for vehicle parts)
  • qb-vehiclekeys (for key management)

Installation Steps

  1. Download the Resource
cd resources/[qb] git clone https://github.com/qbcore-framework/qb-mechanicjob.git
  1. Database Setup
-- Mechanic shop tables CREATE TABLE IF NOT EXISTS `mechanic_orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `citizenid` varchar(50) DEFAULT NULL, `mechanic` varchar(50) DEFAULT NULL, `vehicle_plate` varchar(50) DEFAULT NULL, `service_type` varchar(100) DEFAULT NULL, `parts_used` longtext DEFAULT NULL, `total_cost` int(11) DEFAULT 0, `status` varchar(50) DEFAULT 'pending', `created_at` timestamp DEFAULT current_timestamp(), PRIMARY KEY (`id`) ); CREATE TABLE IF NOT EXISTS `mechanic_parts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `shop` varchar(50) DEFAULT NULL, `part_name` varchar(100) DEFAULT NULL, `quantity` int(11) DEFAULT 0, `cost` int(11) DEFAULT 0, `updated_at` timestamp DEFAULT current_timestamp() ON UPDATE current_timestamp(), PRIMARY KEY (`id`) ); CREATE TABLE IF NOT EXISTS `vehicle_modifications` ( `id` int(11) NOT NULL AUTO_INCREMENT, `plate` varchar(50) DEFAULT NULL, `modifications` longtext DEFAULT NULL, `performance_mods` longtext DEFAULT NULL, `last_modified` timestamp DEFAULT current_timestamp() ON UPDATE current_timestamp(), PRIMARY KEY (`id`), UNIQUE KEY `plate` (`plate`) ); CREATE TABLE IF NOT EXISTS `mechanic_invoices` ( `id` int(11) NOT NULL AUTO_INCREMENT, `citizenid` varchar(50) DEFAULT NULL, `shop` varchar(50) DEFAULT NULL, `services` longtext DEFAULT NULL, `amount` int(11) DEFAULT 0, `paid` tinyint(1) DEFAULT 0, `date` timestamp DEFAULT current_timestamp(), PRIMARY KEY (`id`) );
  1. Add Items to qb-core/shared/items.lua
-- Vehicle Parts ['engine_part'] = { ['name'] = 'engine_part', ['label'] = 'Engine Part', ['weight'] = 1000, ['type'] = 'item', ['image'] = 'engine_part.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Engine component for vehicle repairs' }, ['transmission_part'] = { ['name'] = 'transmission_part', ['label'] = 'Transmission Part', ['weight'] = 800, ['type'] = 'item', ['image'] = 'transmission_part.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Transmission component' }, ['brake_pads'] = { ['name'] = 'brake_pads', ['label'] = 'Brake Pads', ['weight'] = 300, ['type'] = 'item', ['image'] = 'brake_pads.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Brake pads for vehicle repair' }, ['tire'] = { ['name'] = 'tire', ['label'] = 'Vehicle Tire', ['weight'] = 2000, ['type'] = 'item', ['image'] = 'tire.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Replacement vehicle tire' }, ['turbo_kit'] = { ['name'] = 'turbo_kit', ['label'] = 'Turbo Kit', ['weight'] = 5000, ['type'] = 'item', ['image'] = 'turbo_kit.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Performance turbo kit upgrade' }
  1. Add Job Configuration to qb-core/shared/jobs.lua
['mechanic'] = { label = 'Mechanic', defaultDuty = true, offDutyPay = false, grades = { ['0'] = { name = 'Apprentice', payment = 50 }, ['1'] = { name = 'Mechanic', payment = 75 }, ['2'] = { name = 'Advanced Mechanic', payment = 100 }, ['3'] = { name = 'Shop Supervisor', payment = 125, isboss = true }, ['4'] = { name = 'Shop Manager', payment = 150, isboss = true } } }
  1. Add to server.cfg
ensure qb-mechanicjob

Ensure qb-mechanicjob loads after qb-core, qb-target, and qb-inventory in your server.cfg

Configuration

Basic Configuration

The main configuration file is located at config.lua:

Config = {} -- General Settings Config.UseTarget = true Config.RepairCost = { body = 1000, engine = 1500, transmission = 1200, brakes = 800, suspension = 900 } -- Mechanic Shop Locations Config.Locations = { ["bennys"] = { label = "Benny's Original Motor Works", coords = vector3(-212.55, -1324.2, 30.89), blip = { sprite = 72, color = 17, scale = 0.8 }, zones = { duty = vector3(-212.55, -1324.2, 30.89), stash = vector3(-222.47, -1329.73, 30.89), vehicle = vector4(-229.47, -1315.39, 30.89, 270.0), lift1 = vector4(-212.0, -1308.0, 31.3, 270.0), lift2 = vector4(-212.0, -1318.0, 31.3, 270.0) } }, ["hayes"] = { label = "Hayes Autos", coords = vector3(-1419.24, -446.58, 35.91), blip = { sprite = 72, color = 17, scale = 0.8 }, zones = { duty = vector3(-1419.24, -446.58, 35.91), stash = vector3(-1413.35, -448.26, 35.91), vehicle = vector4(-1428.46, -455.12, 35.91, 120.0), lift1 = vector4(-1419.0, -450.0, 36.0, 120.0) } } } -- Tow Truck Spawn Points Config.TowSpawns = { [1] = vector4(-229.47, -1315.39, 30.89, 270.0), [2] = vector4(-228.47, -1320.39, 30.89, 270.0) } -- Vehicle Modification Costs Config.ModificationCosts = { engine = { [0] = 0, [1] = 5000, [2] = 10000, [3] = 15000, [4] = 25000 }, brakes = { [0] = 0, [1] = 2500, [2] = 5000, [3] = 7500 }, transmission = { [0] = 0, [1] = 4000, [2] = 8000, [3] = 12000 }, suspension = { [0] = 0, [1] = 3000, [2] = 6000, [3] = 9000, [4] = 12000 }, turbo = 15000, armor = { [0] = 0, [1] = 5000, [2] = 10000, [3] = 15000, [4] = 20000, [5] = 25000 } }

Vehicle Damage System

-- Damage Thresholds Config.DamageSystem = { engine = { threshold = 650.0, repairCost = 1500, parts = {"engine_part"} }, body = { threshold = 800.0, repairCost = 1000, parts = {"body_panel"} }, transmission = { threshold = 700.0, repairCost = 1200, parts = {"transmission_part"} }, brakes = { threshold = 750.0, repairCost = 800, parts = {"brake_pads"} }, tires = { threshold = 900.0, repairCost = 400, parts = {"tire"} } } -- Repair Requirements Config.RepairRequirements = { mechanic_level = { basic = 0, -- Apprentice can do basic repairs advanced = 2, -- Advanced Mechanic for complex repairs custom = 3 -- Supervisor+ for custom modifications }, tools_required = { basic = {"wrench", "screwdriver"}, advanced = {"diagnostic_tool", "hydraulic_jack"}, custom = {"tuning_laptop", "dyno_access"} } }

Parts and Pricing

-- Vehicle Parts Configuration Config.Parts = { ["engine_part"] = { label = "Engine Component", cost = 500, category = "engine", required_skill = 1 }, ["transmission_part"] = { label = "Transmission Component", cost = 400, category = "transmission", required_skill = 1 }, ["brake_pads"] = { label = "Brake Pads", cost = 200, category = "brakes", required_skill = 0 }, ["tire"] = { label = "Performance Tire", cost = 300, category = "tires", required_skill = 0 }, ["turbo_kit"] = { label = "Turbo Kit", cost = 2500, category = "performance", required_skill = 3 } } -- Service Pricing Config.ServicePrices = { oil_change = 150, tire_repair = 100, brake_service = 300, engine_tune = 500, full_service = 800, custom_paint = 1200, performance_tune = 2000 }

API Reference

Client Exports

RepairVehicle

Repair a vehicle with specified components.

-- Repair specific component exports['qb-mechanicjob']:RepairVehicle(vehicle, "engine") -- Repair multiple components exports['qb-mechanicjob']:RepairVehicle(vehicle, {"engine", "body", "brakes"}) -- Full repair exports['qb-mechanicjob']:RepairVehicle(vehicle, "all") -- Parameters: -- vehicle: Vehicle entity -- components: String or table of components to repair

GetVehicleDamage

Get detailed damage information for a vehicle.

local damageInfo = exports['qb-mechanicjob']:GetVehicleDamage(vehicle) -- Returns: -- { -- engine = number (0-1000), -- body = number (0-1000), -- transmission = number (0-1000), -- brakes = number (0-1000), -- tires = table of tire conditions -- }

ModifyVehicle

Apply performance modifications to a vehicle.

-- Apply single modification exports['qb-mechanicjob']:ModifyVehicle(vehicle, "engine", 2) -- Apply multiple modifications exports['qb-mechanicjob']:ModifyVehicle(vehicle, { engine = 2, brakes = 1, suspension = 1, turbo = true }) -- Parameters: -- vehicle: Vehicle entity -- modifications: Modification type and level

Server Exports

CreateServiceOrder

Create a new service order for a customer.

local orderId = exports['qb-mechanicjob']:CreateServiceOrder(data) -- Parameters: -- data: { -- citizenid = string, -- mechanic = string, -- vehicle_plate = string, -- services = table, -- total_cost = number -- }

ProcessPayment

Process payment for mechanic services.

local success = exports['qb-mechanicjob']:ProcessPayment(source, amount, description) -- Parameters: -- source: Player server ID -- amount: Payment amount -- description: Service description

UpdatePartInventory

Update shop part inventory.

exports['qb-mechanicjob']:UpdatePartInventory(shop, partName, quantity) -- Parameters: -- shop: Shop identifier -- partName: Part name -- quantity: Quantity change (+/-)

GetShopInventory

Get current shop inventory.

local inventory = exports['qb-mechanicjob']:GetShopInventory(shop) -- Returns table of parts and quantities

Events

Client Events

-- Vehicle repair started RegisterNetEvent('qb-mechanicjob:client:repairStarted', function(repairType) -- Handle repair start end) -- Vehicle modification applied RegisterNetEvent('qb-mechanicjob:client:modificationApplied', function(modType, level) -- Handle modification end) -- Service order created RegisterNetEvent('qb-mechanicjob:client:orderCreated', function(orderId) -- Handle new order end) -- Payment processed RegisterNetEvent('qb-mechanicjob:client:paymentProcessed', function(amount) -- Handle payment completion end)

Server Events

-- Mechanic on/off duty RegisterNetEvent('qb-mechanicjob:server:dutyToggle', function(onDuty) -- Handle duty status change end) -- Vehicle towed RegisterNetEvent('qb-mechanicjob:server:vehicleTowed', function(plate, location) -- Handle vehicle towing end) -- Parts ordered RegisterNetEvent('qb-mechanicjob:server:orderParts', function(parts, shop) -- Handle parts ordering end) -- Service completed RegisterNetEvent('qb-mechanicjob:server:serviceCompleted', function(orderId, services) -- Handle service completion end)

Usage Examples

Vehicle Repair System

-- Client-side repair process RegisterNetEvent('qb-mechanicjob:client:startRepair', function(repairType) local player = QBCore.Functions.GetPlayerData() if player.job.name == "mechanic" and player.job.onduty then local vehicle = QBCore.Functions.GetClosestVehicle() local requiredParts = Config.DamageSystem[repairType].parts -- Check if mechanic has required parts for i = 1, #requiredParts do local hasPart = QBCore.Functions.HasItem(requiredParts[i]) if not hasPart then QBCore.Functions.Notify("Missing required part: " .. requiredParts[i], "error") return end end -- Start repair animation and progress QBCore.Functions.Progressbar("vehicle_repair", "Repairing " .. repairType .. "...", 10000, false, true, { disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true, }, { animDict = "mini@repair", anim = "fixing_a_ped", }, { model = "prop_tool_box_04", bone = 57005, coords = vector3(0.4, 0.0, 0.0), rotation = vector3(0.0, 0.0, 0.0), }, {}, function() -- Repair completed TriggerServerEvent('qb-mechanicjob:server:repairVehicle', VehToNet(vehicle), repairType) end) end end) -- Server-side repair handler RegisterNetEvent('qb-mechanicjob:server:repairVehicle', function(netId, repairType) local src = source local player = QBCore.Functions.GetPlayer(src) local vehicle = NetworkGetEntityFromNetworkId(netId) if player.PlayerData.job.name == "mechanic" then local repairCost = Config.RepairCost[repairType] or 500 local requiredParts = Config.DamageSystem[repairType].parts -- Remove required parts from inventory for i = 1, #requiredParts do player.Functions.RemoveItem(requiredParts[i], 1) end -- Apply repair to vehicle if repairType == "engine" then SetVehicleEngineHealth(vehicle, 1000.0) elseif repairType == "body" then SetVehicleBodyHealth(vehicle, 1000.0) elseif repairType == "brakes" then SetVehicleBrake(vehicle, false) end TriggerClientEvent('QBCore:Notify', src, repairType .. ' repaired successfully!', 'success') end end)

Vehicle Modification System

-- Performance tuning interface RegisterNetEvent('qb-mechanicjob:client:openTuningMenu', function() local vehicle = QBCore.Functions.GetClosestVehicle() if not vehicle then return end local tuningMenu = { { header = "Vehicle Tuning", isMenuHeader = true }, { header = "Engine Upgrade", txt = "Improve engine performance", params = { event = "qb-mechanicjob:client:upgradeEngine", args = {vehicle = vehicle} } }, { header = "Brake System", txt = "Upgrade brake system", params = { event = "qb-mechanicjob:client:upgradeBrakes", args = {vehicle = vehicle} } }, { header = "Suspension", txt = "Modify suspension", params = { event = "qb-mechanicjob:client:upgradeSuspension", args = {vehicle = vehicle} } }, { header = "Turbo Kit", txt = "Install turbo kit - $" .. Config.ModificationCosts.turbo, params = { event = "qb-mechanicjob:client:installTurbo", args = {vehicle = vehicle} } } } exports['qb-menu']:openMenu(tuningMenu) end) -- Engine upgrade implementation RegisterNetEvent('qb-mechanicjob:client:upgradeEngine', function(data) local vehicle = data.vehicle local currentLevel = GetVehicleMod(vehicle, 11) -- Engine mod local nextLevel = currentLevel + 1 if nextLevel <= 4 then local cost = Config.ModificationCosts.engine[nextLevel] QBCore.Functions.TriggerCallback('qb-mechanicjob:server:canAfford', function(canAfford) if canAfford then SetVehicleMod(vehicle, 11, nextLevel, false) TriggerServerEvent('qb-mechanicjob:server:payForMod', cost, 'Engine Upgrade Level ' .. nextLevel) else QBCore.Functions.Notify("Insufficient funds for upgrade", "error") end end, cost) else QBCore.Functions.Notify("Engine already at maximum level", "error") end end)

Towing Service

-- Tow truck operations RegisterNetEvent('qb-mechanicjob:client:towVehicle', function() local player = QBCore.Functions.GetPlayerData() if player.job.name == "mechanic" and player.job.onduty then local towTruck = GetVehiclePedIsIn(PlayerPedId(), false) local towModel = GetEntityModel(towTruck) -- Check if player is in a tow truck if towModel == GetHashKey("flatbed") or towModel == GetHashKey("towtruck") then local targetVehicle = QBCore.Functions.GetClosestVehicle() if targetVehicle then QBCore.Functions.Progressbar("towing_vehicle", "Attaching vehicle to tow truck...", 8000, false, true, { disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true, }, { animDict = "mini@repair", anim = "fixing_a_ped", }, {}, {}, function() AttachEntityToEntity(targetVehicle, towTruck, 0, 0.0, -2.5, 1.0, 0.0, 0.0, 0.0, false, false, false, false, 2, true) QBCore.Functions.Notify("Vehicle attached to tow truck", "success") end) else QBCore.Functions.Notify("No vehicle nearby to tow", "error") end else QBCore.Functions.Notify("You need to be in a tow truck", "error") end end end)

Troubleshooting

Common Issues

Vehicle Repairs Not Working

-- Check vehicle entity validity if not DoesEntityExist(vehicle) then print("Vehicle entity does not exist") return end -- Verify repair permissions local player = QBCore.Functions.GetPlayerData() if player.job.name ~= "mechanic" or not player.job.onduty then print("Player not authorized for repairs") return end

Modification Costs Not Updating

  • Verify modification cost configuration in config.lua
  • Check if vehicle model supports specific modifications
  • Ensure proper database table structure for tracking modifications

Parts Inventory Issues

-- Debug parts inventory RegisterCommand('checkparts', function() local inventory = exports['qb-mechanicjob']:GetShopInventory('bennys') for part, quantity in pairs(inventory) do print(part .. ": " .. quantity) end end)

Debug Commands

-- Repair vehicle instantly (admin only) /fixveh -- Add mechanic parts to inventory /givepart [part_name] [quantity] -- Check vehicle modification levels /checkmods -- Toggle mechanic duty /mechduty

Performance Optimization

  1. Damage Calculations: Optimize vehicle damage checking frequency
  2. Part Inventory: Cache inventory data to reduce database queries
  3. Vehicle Spawning: Implement proper vehicle cleanup and pooling

Always test vehicle modifications and repairs thoroughly to ensure they work correctly with your server’s vehicle system.

Last updated on