[{"data":1,"prerenderedAt":2941},["ShallowReactive",2],{"/docs/jobs/mechanicjob/reference/garage-integration":3,"/docs/jobs/mechanicjob/reference/garage-integration-surround":2930,"/docs/jobs/mechanicjob/reference/garage-integration-implemented-suggestions":2940},{"id":4,"title":5,"body":6,"description":2921,"extension":2922,"head":2923,"implementedSuggestions":2923,"meta":2924,"navigation":1436,"path":2925,"schemaOrg":2923,"seo":2926,"sitemap":2927,"stem":2928,"__hash__":2929},"docs/1.docs/0.jobs/2.mechanicjob/4.reference/4.garage-integration.md","Garage Integration",{"type":7,"value":8,"toc":2888},"minimark",[9,14,18,34,37,48,52,55,93,96,111,122,126,143,147,150,160,163,208,211,226,231,235,240,243,249,252,286,289,293,296,302,305,331,341,344,368,371,415,418,422,425,456,463,492,500,503,545,548,578,582,585,605,612,616,619,621,627,629,656,659,662,686,691,694,729,732,734,763,765,793,796,834,838,848,854,865,869,875,878,922,928,934,938,945,1050,1053,1087,1091,1097,1125,1128,1174,1177,1180,1217,1228,1326,1329,1333,1339,2175,2178,2184,2187,2250,2256,2317,2320,2360,2363,2380,2384,2387,2401,2404,2451,2454,2472,2475,2488,2492,2495,2512,2515,2518,2522,2525,2528,2555,2558,2562,2565,2585,2588,2667,2676,2680,2683,2701,2710,2713,2718,2722,2725,2773,2776,2808,2812,2815,2847,2853,2857,2884],[10,11,13],"h2",{"id":12},"what-this-guide-solves","What this guide solves",[15,16,17],"p",{},"A garage saves vehicle tuning in four steps:",[19,20,21,25,28,31],"ol",{},[22,23,24],"li",{},"The garage reads the properties of the live vehicle.",[22,26,27],{},"The server stores the properties as JSON.",[22,29,30],{},"The garage reads that JSON when the vehicle is spawned.",[22,32,33],{},"The client applies the properties to the spawned vehicle.",[15,35,36],{},"Most garages already call the central QBCore or ESX functions for steps 1 and 4. The cleanest\nintegration is therefore to make those two framework functions use exactly the same implementation\nas Sky. Compatible garages then receive the same property table without editing every getter and\nsetter.",[15,38,39,43,44,47],{},[40,41,42],"code",{},"qb-garages"," still needs an additional fix: some versions try to save properties through a\n",[40,45,46],{},"qb-mechanicjob"," event that does not exist when Sky Mechanic Job is installed. The complete fix for\nthat is included below.",[10,49,51],{"id":50},"two-separate-types-of-saved-tuning","Two separate types of saved tuning",[15,53,54],{},"Sky Mechanic Job and the garage use separate storage locations:",[56,57,58,71],"table",{},[59,60,61],"thead",{},[62,63,64,68],"tr",{},[65,66,67],"th",{},"Storage",[65,69,70],{},"What it contains",[72,73,74,83],"tbody",{},[62,75,76,80],{},[77,78,79],"td",{},"Garage vehicle column",[77,81,82],{},"GTA properties such as paint, wheels, performance mods, extras, neon, windows, and damage",[62,84,85,90],{},[77,86,87],{},[40,88,89],{},"sky_mechanic_vehicle_tuning.properties",[77,91,92],{},"Mechanic-specific features such as Stancer, custom handling, Nitro, anti-lag, two-step, and Engine Sounds",[15,94,95],{},"The normal garage columns are usually:",[97,98,99,105],"ul",{},[22,100,101,102],{},"QBCore: ",[40,103,104],{},"player_vehicles.mods",[22,106,107,108],{},"ESX: ",[40,109,110],{},"owned_vehicles.vehicle",[112,113,116],"callout",{"color":114,"icon":115},"warning","i-lucide-triangle-alert",[15,117,118,119,121],{},"Do not replace ",[40,120,89],{}," with the garage column. Both storage\nlocations are required and have different purposes.",[10,123,125],{"id":124},"before-you-start","Before you start",[19,127,128,131,134,137,140],{},[22,129,130],{},"Back up the framework client file.",[22,132,133],{},"Back up the garage resource.",[22,135,136],{},"Back up the owned-vehicle database table.",[22,138,139],{},"Check whether your server uses QBCore or ESX.",[22,141,142],{},"Complete only the matching framework section below.",[10,144,146],{"id":145},"the-source-of-truth","The source of truth",[15,148,149],{},"The complete Sky implementation is stored in:",[151,152,158],"pre",{"className":153,"code":155,"language":156,"meta":157},[154],"language-text","sky_base/config/vehicle_functions.lua\n","text","",[40,159,155],{"__ignoreMap":157},[15,161,162],{},"The two source functions are:",[151,164,168],{"className":165,"code":166,"language":167,"meta":157,"style":157},"language-lua shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","Functions.Vehicle.GetVehicleProperties(vehicle)\nFunctions.Vehicle.SetVehicleProperties(vehicle, props)\n","lua",[40,169,170,193],{"__ignoreMap":157},[171,172,175,179,183,186,190],"span",{"class":173,"line":174},"line",1,[171,176,178],{"class":177},"sTEyZ","Functions.",[171,180,182],{"class":181},"sBMFI","Vehicle",[171,184,185],{"class":177},".",[171,187,189],{"class":188},"s2Zo4","GetVehicleProperties",[171,191,192],{"class":177},"(vehicle)\n",[171,194,196,198,200,202,205],{"class":173,"line":195},2,[171,197,178],{"class":177},[171,199,182],{"class":181},[171,201,185],{"class":177},[171,203,204],{"class":188},"SetVehicleProperties",[171,206,207],{"class":177},"(vehicle, props)\n",[15,209,210],{},"Whenever Sky adds or changes a property, synchronize the contents of these two functions with the\nmatching framework functions.",[15,212,213,214,217,218,221,222,225],{},"The two property functions intentionally contain no ",[40,215,216],{},"Sky.*",", ",[40,219,220],{},"QBCore.*",", or ",[40,223,224],{},"ESX.*"," calls. They\nreceive the raw vehicle entity, just like the QBCore and ESX functions. Their inner contents are\ntherefore framework-neutral and can be copied unchanged without an adapter.",[112,227,228],{"color":114,"icon":115},[15,229,230],{},"Do not copy only selected mod fields. The complete function contents must stay synchronized so\npaint, damage, wheels, tyres, windows, extras, neon, xenon, liveries, and framework-compatible\naliases use the same schema.",[10,232,234],{"id":233},"qbcore-connect-the-central-functions-to-sky","QBCore: connect the central functions to Sky",[236,237,239],"h3",{"id":238},"step-1-open-the-correct-file","Step 1: Open the correct file",[15,241,242],{},"Open:",[151,244,247],{"className":245,"code":246,"language":156,"meta":157},[154],"qb-core/client/functions.lua\n",[40,248,246],{"__ignoreMap":157},[15,250,251],{},"Search for:",[151,253,255],{"className":165,"code":254,"language":167,"meta":157,"style":157},"function QBCore.Functions.GetVehicleProperties(vehicle)\n",[40,256,257],{"__ignoreMap":157},[171,258,259,263,266,268,271,273,275,279,283],{"class":173,"line":174},[171,260,262],{"class":261},"s7zQu","function",[171,264,265],{"class":188}," QBCore",[171,267,185],{"class":177},[171,269,270],{"class":188},"Functions",[171,272,185],{"class":177},[171,274,189],{"class":188},[171,276,278],{"class":277},"sMK4o","(",[171,280,282],{"class":281},"sHdIc","vehicle",[171,284,285],{"class":277},")\n",[15,287,288],{},"The original function is long and reads every vehicle property with GTA natives.",[236,290,292],{"id":291},"step-2-synchronize-the-getter","Step 2: Synchronize the getter",[15,294,295],{},"Open these files next to each other:",[151,297,300],{"className":298,"code":299,"language":156,"meta":157},[154],"Source: sky_base/config/vehicle_functions.lua\nTarget: qb-core/client/functions.lua\n",[40,301,299],{"__ignoreMap":157},[15,303,304],{},"In the Sky file, find:",[151,306,308],{"className":165,"code":307,"language":167,"meta":157,"style":157},"function Functions.Vehicle.GetVehicleProperties(vehicle)\n",[40,309,310],{"__ignoreMap":157},[171,311,312,314,317,319,321,323,325,327,329],{"class":173,"line":174},[171,313,262],{"class":261},[171,315,316],{"class":188}," Functions",[171,318,185],{"class":177},[171,320,182],{"class":188},[171,322,185],{"class":177},[171,324,189],{"class":188},[171,326,278],{"class":277},[171,328,282],{"class":281},[171,330,285],{"class":277},[15,332,333,334,337,338,185],{},"Copy everything inside that function, but do not copy its first ",[40,335,336],{},"function ..."," line or its final\nclosing ",[40,339,340],{},"end",[15,342,343],{},"In QBCore, delete the old contents of:",[151,345,346],{"className":165,"code":254,"language":167,"meta":157,"style":157},[40,347,348],{"__ignoreMap":157},[171,349,350,352,354,356,358,360,362,364,366],{"class":173,"line":174},[171,351,262],{"class":261},[171,353,265],{"class":188},[171,355,185],{"class":177},[171,357,270],{"class":188},[171,359,185],{"class":177},[171,361,189],{"class":188},[171,363,278],{"class":277},[171,365,282],{"class":281},[171,367,285],{"class":277},[15,369,370],{},"Paste the copied Sky function contents directly into it. The resulting structure is:",[151,372,375],{"className":165,"code":373,"filename":374,"language":167,"meta":157,"style":157},"function QBCore.Functions.GetVehicleProperties(vehicle)\n    -- Paste the complete contents of\n    -- Functions.Vehicle.GetVehicleProperties(vehicle) here.\nend\n","qb-core/client/functions.lua",[40,376,377,397,403,409],{"__ignoreMap":157},[171,378,379,381,383,385,387,389,391,393,395],{"class":173,"line":174},[171,380,262],{"class":261},[171,382,265],{"class":188},[171,384,185],{"class":177},[171,386,270],{"class":188},[171,388,185],{"class":177},[171,390,189],{"class":188},[171,392,278],{"class":277},[171,394,282],{"class":281},[171,396,285],{"class":277},[171,398,399],{"class":173,"line":195},[171,400,402],{"class":401},"sHwdD","    -- Paste the complete contents of\n",[171,404,406],{"class":173,"line":405},3,[171,407,408],{"class":401},"    -- Functions.Vehicle.GetVehicleProperties(vehicle) here.\n",[171,410,412],{"class":173,"line":411},4,[171,413,414],{"class":261},"end\n",[15,416,417],{},"Both functions now use the same parameter name and the same raw vehicle entity.",[236,419,421],{"id":420},"step-3-synchronize-the-setter","Step 3: Synchronize the setter",[15,423,424],{},"In the same file, search for:",[151,426,428],{"className":165,"code":427,"language":167,"meta":157,"style":157},"function QBCore.Functions.SetVehicleProperties(vehicle, props)\n",[40,429,430],{"__ignoreMap":157},[171,431,432,434,436,438,440,442,444,446,448,451,454],{"class":173,"line":174},[171,433,262],{"class":261},[171,435,265],{"class":188},[171,437,185],{"class":177},[171,439,270],{"class":188},[171,441,185],{"class":177},[171,443,204],{"class":188},[171,445,278],{"class":277},[171,447,282],{"class":281},[171,449,450],{"class":277},",",[171,452,453],{"class":281}," props",[171,455,285],{"class":277},[15,457,458,459,462],{},"In ",[40,460,461],{},"sky_base/config/vehicle_functions.lua",", find:",[151,464,466],{"className":165,"code":465,"language":167,"meta":157,"style":157},"function Functions.Vehicle.SetVehicleProperties(vehicle, props)\n",[40,467,468],{"__ignoreMap":157},[171,469,470,472,474,476,478,480,482,484,486,488,490],{"class":173,"line":174},[171,471,262],{"class":261},[171,473,316],{"class":188},[171,475,185],{"class":177},[171,477,182],{"class":188},[171,479,185],{"class":177},[171,481,204],{"class":188},[171,483,278],{"class":277},[171,485,282],{"class":281},[171,487,450],{"class":277},[171,489,453],{"class":281},[171,491,285],{"class":277},[15,493,494,495,497,498,185],{},"Copy everything inside that function, excluding its first ",[40,496,336],{}," line and its final closing\n",[40,499,340],{},[15,501,502],{},"Delete the old contents of the QBCore setter and paste the Sky contents directly into it:",[151,504,506],{"className":165,"code":505,"filename":374,"language":167,"meta":157,"style":157},"function QBCore.Functions.SetVehicleProperties(vehicle, props)\n    -- Paste the complete contents of\n    -- Functions.Vehicle.SetVehicleProperties(vehicle, props) here.\nend\n",[40,507,508,532,536,541],{"__ignoreMap":157},[171,509,510,512,514,516,518,520,522,524,526,528,530],{"class":173,"line":174},[171,511,262],{"class":261},[171,513,265],{"class":188},[171,515,185],{"class":177},[171,517,270],{"class":188},[171,519,185],{"class":177},[171,521,204],{"class":188},[171,523,278],{"class":277},[171,525,282],{"class":281},[171,527,450],{"class":277},[171,529,453],{"class":281},[171,531,285],{"class":277},[171,533,534],{"class":173,"line":195},[171,535,402],{"class":401},[171,537,538],{"class":173,"line":405},[171,539,540],{"class":401},"    -- Functions.Vehicle.SetVehicleProperties(vehicle, props) here.\n",[171,542,543],{"class":173,"line":411},[171,544,414],{"class":261},[15,546,547],{},"Every compatible resource that calls these QBCore functions now uses the same property logic:",[151,549,551],{"className":165,"code":550,"language":167,"meta":157,"style":157},"QBCore.Functions.GetVehicleProperties(vehicle)\nQBCore.Functions.SetVehicleProperties(vehicle, props)\n",[40,552,553,566],{"__ignoreMap":157},[171,554,555,558,560,562,564],{"class":173,"line":174},[171,556,557],{"class":177},"QBCore.",[171,559,270],{"class":181},[171,561,185],{"class":177},[171,563,189],{"class":188},[171,565,192],{"class":177},[171,567,568,570,572,574,576],{"class":173,"line":195},[171,569,557],{"class":177},[171,571,270],{"class":181},[171,573,185],{"class":177},[171,575,204],{"class":188},[171,577,207],{"class":177},[236,579,581],{"id":580},"step-4-do-not-change-the-qbcore-manifest","Step 4: Do not change the QBCore manifest",[15,583,584],{},"Do not add this:",[151,586,588],{"className":165,"code":587,"language":167,"meta":157,"style":157},"dependency \"sky_base\"\n",[40,589,590],{"__ignoreMap":157},[171,591,592,595,598,602],{"class":173,"line":174},[171,593,594],{"class":188},"dependency",[171,596,597],{"class":277}," \"",[171,599,601],{"class":600},"sfazB","sky_base",[171,603,604],{"class":277},"\"\n",[15,606,607,608,611],{},"to ",[40,609,610],{},"qb-core/fxmanifest.lua",". Sky Base already needs QBCore, so adding the reverse dependency would\ncreate a circular manifest dependency.",[10,613,615],{"id":614},"esx-connect-the-central-functions-to-sky","ESX: connect the central functions to Sky",[236,617,239],{"id":618},"step-1-open-the-correct-file-1",[15,620,242],{},[151,622,625],{"className":623,"code":624,"language":156,"meta":157},[154],"es_extended/client/functions.lua\n",[40,626,624],{"__ignoreMap":157},[15,628,251],{},[151,630,632],{"className":165,"code":631,"language":167,"meta":157,"style":157},"function ESX.Game.GetVehicleProperties(vehicle)\n",[40,633,634],{"__ignoreMap":157},[171,635,636,638,641,643,646,648,650,652,654],{"class":173,"line":174},[171,637,262],{"class":261},[171,639,640],{"class":188}," ESX",[171,642,185],{"class":177},[171,644,645],{"class":188},"Game",[171,647,185],{"class":177},[171,649,189],{"class":188},[171,651,278],{"class":277},[171,653,282],{"class":281},[171,655,285],{"class":277},[236,657,292],{"id":658},"step-2-synchronize-the-getter-1",[15,660,661],{},"Copy the complete inner contents of:",[151,663,664],{"className":165,"code":307,"language":167,"meta":157,"style":157},[40,665,666],{"__ignoreMap":157},[171,667,668,670,672,674,676,678,680,682,684],{"class":173,"line":174},[171,669,262],{"class":261},[171,671,316],{"class":188},[171,673,185],{"class":177},[171,675,182],{"class":188},[171,677,185],{"class":177},[171,679,189],{"class":188},[171,681,278],{"class":277},[171,683,282],{"class":281},[171,685,285],{"class":277},[15,687,688,689,185],{},"from ",[40,690,461],{},[15,692,693],{},"Delete the old contents of the ESX getter and paste the copied contents directly:",[151,695,698],{"className":165,"code":696,"filename":697,"language":167,"meta":157,"style":157},"function ESX.Game.GetVehicleProperties(vehicle)\n    -- Paste the complete Sky getter contents here.\nend\n","es_extended/client/functions.lua",[40,699,700,720,725],{"__ignoreMap":157},[171,701,702,704,706,708,710,712,714,716,718],{"class":173,"line":174},[171,703,262],{"class":261},[171,705,640],{"class":188},[171,707,185],{"class":177},[171,709,645],{"class":188},[171,711,185],{"class":177},[171,713,189],{"class":188},[171,715,278],{"class":277},[171,717,282],{"class":281},[171,719,285],{"class":277},[171,721,722],{"class":173,"line":195},[171,723,724],{"class":401},"    -- Paste the complete Sky getter contents here.\n",[171,726,727],{"class":173,"line":405},[171,728,414],{"class":261},[236,730,421],{"id":731},"step-3-synchronize-the-setter-1",[15,733,251],{},[151,735,737],{"className":165,"code":736,"language":167,"meta":157,"style":157},"function ESX.Game.SetVehicleProperties(vehicle, props)\n",[40,738,739],{"__ignoreMap":157},[171,740,741,743,745,747,749,751,753,755,757,759,761],{"class":173,"line":174},[171,742,262],{"class":261},[171,744,640],{"class":188},[171,746,185],{"class":177},[171,748,645],{"class":188},[171,750,185],{"class":177},[171,752,204],{"class":188},[171,754,278],{"class":277},[171,756,282],{"class":281},[171,758,450],{"class":277},[171,760,453],{"class":281},[171,762,285],{"class":277},[15,764,661],{},[151,766,767],{"className":165,"code":465,"language":167,"meta":157,"style":157},[40,768,769],{"__ignoreMap":157},[171,770,771,773,775,777,779,781,783,785,787,789,791],{"class":173,"line":174},[171,772,262],{"class":261},[171,774,316],{"class":188},[171,776,185],{"class":177},[171,778,182],{"class":188},[171,780,185],{"class":177},[171,782,204],{"class":188},[171,784,278],{"class":277},[171,786,282],{"class":281},[171,788,450],{"class":277},[171,790,453],{"class":281},[171,792,285],{"class":277},[15,794,795],{},"Delete the old ESX setter contents, then use:",[151,797,799],{"className":165,"code":798,"filename":697,"language":167,"meta":157,"style":157},"function ESX.Game.SetVehicleProperties(vehicle, props)\n    -- Paste the complete Sky setter contents here.\nend\n",[40,800,801,825,830],{"__ignoreMap":157},[171,802,803,805,807,809,811,813,815,817,819,821,823],{"class":173,"line":174},[171,804,262],{"class":261},[171,806,640],{"class":188},[171,808,185],{"class":177},[171,810,645],{"class":188},[171,812,185],{"class":177},[171,814,204],{"class":188},[171,816,278],{"class":277},[171,818,282],{"class":281},[171,820,450],{"class":277},[171,822,453],{"class":281},[171,824,285],{"class":277},[171,826,827],{"class":173,"line":195},[171,828,829],{"class":401},"    -- Paste the complete Sky setter contents here.\n",[171,831,832],{"class":173,"line":405},[171,833,414],{"class":261},[236,835,837],{"id":836},"step-4-do-not-change-the-esx-manifest","Step 4: Do not change the ESX manifest",[15,839,840,841,844,845,847],{},"Do not make ",[40,842,843],{},"es_extended"," depend on ",[40,846,601],{},". Keep the normal start direction:",[151,849,852],{"className":850,"code":851,"language":156,"meta":157},[154],"es_extended → sky_base → garage\n",[40,853,851],{"__ignoreMap":157},[15,855,856,857,860,861,864],{},"Normal ESX garages that already use ",[40,858,859],{},"ESX.Game.GetVehicleProperties"," and\n",[40,862,863],{},"ESX.Game.SetVehicleProperties"," now use Sky automatically.",[10,866,868],{"id":867},"qbcore-additional-qb-garages-fix","QBCore: additional qb-garages fix",[15,870,871,872,874],{},"Changing the central QBCore getter and setter is not enough for affected ",[40,873,42],{}," versions.",[15,876,877],{},"Some versions contain this call while parking:",[151,879,881],{"className":165,"code":880,"language":167,"meta":157,"style":157},"TriggerServerEvent(\n    \"qb-mechanicjob:server:SaveVehicleProps\",\n    QBCore.Functions.GetVehicleProperties(vehicle)\n)\n",[40,882,883,891,905,918],{"__ignoreMap":157},[171,884,885,888],{"class":173,"line":174},[171,886,887],{"class":188},"TriggerServerEvent",[171,889,890],{"class":177},"(\n",[171,892,893,896,899,902],{"class":173,"line":195},[171,894,895],{"class":277},"    \"",[171,897,898],{"class":600},"qb-mechanicjob:server:SaveVehicleProps",[171,900,901],{"class":277},"\"",[171,903,904],{"class":177},",\n",[171,906,907,910,912,914,916],{"class":173,"line":405},[171,908,909],{"class":177},"    QBCore.",[171,911,270],{"class":181},[171,913,185],{"class":177},[171,915,189],{"class":188},[171,917,192],{"class":177},[171,919,920],{"class":173,"line":411},[171,921,285],{"class":177},[15,923,924,925,927],{},"That event belongs to a different Mechanic Job resource. Sky Mechanic Job does not provide it, so\nthe event goes nowhere and ",[40,926,104],{}," remains outdated.",[15,929,930,931,933],{},"The following steps make ",[40,932,42],{}," save the JSON itself.",[236,935,937],{"id":936},"step-1-configure-the-property-column","Step 1: Configure the property column",[15,939,940,941,944],{},"Open ",[40,942,943],{},"qb-garages/config.lua"," and add:",[151,946,948],{"className":165,"code":947,"filename":943,"language":167,"meta":157,"style":157},"Config.VehiclePropertiesStorage = {\n    table = \"player_vehicles\",\n    column = \"mods\",\n    plateColumn = \"plate\",\n    ownerColumn = \"citizenid\",\n    ownerField = \"citizenid\"\n}\n",[40,949,950,964,981,997,1013,1030,1044],{"__ignoreMap":157},[171,951,952,955,958,961],{"class":173,"line":174},[171,953,954],{"class":177},"Config.",[171,956,957],{"class":181},"VehiclePropertiesStorage",[171,959,960],{"class":277}," =",[171,962,963],{"class":177}," {\n",[171,965,966,969,972,974,977,979],{"class":173,"line":195},[171,967,968],{"class":177},"    table ",[171,970,971],{"class":277},"=",[171,973,597],{"class":277},[171,975,976],{"class":600},"player_vehicles",[171,978,901],{"class":277},[171,980,904],{"class":177},[171,982,983,986,988,990,993,995],{"class":173,"line":405},[171,984,985],{"class":177},"    column ",[171,987,971],{"class":277},[171,989,597],{"class":277},[171,991,992],{"class":600},"mods",[171,994,901],{"class":277},[171,996,904],{"class":177},[171,998,999,1002,1004,1006,1009,1011],{"class":173,"line":411},[171,1000,1001],{"class":177},"    plateColumn ",[171,1003,971],{"class":277},[171,1005,597],{"class":277},[171,1007,1008],{"class":600},"plate",[171,1010,901],{"class":277},[171,1012,904],{"class":177},[171,1014,1016,1019,1021,1023,1026,1028],{"class":173,"line":1015},5,[171,1017,1018],{"class":177},"    ownerColumn ",[171,1020,971],{"class":277},[171,1022,597],{"class":277},[171,1024,1025],{"class":600},"citizenid",[171,1027,901],{"class":277},[171,1029,904],{"class":177},[171,1031,1033,1036,1038,1040,1042],{"class":173,"line":1032},6,[171,1034,1035],{"class":177},"    ownerField ",[171,1037,971],{"class":277},[171,1039,597],{"class":277},[171,1041,1025],{"class":600},[171,1043,604],{"class":277},[171,1045,1047],{"class":173,"line":1046},7,[171,1048,1049],{"class":177},"}\n",[15,1051,1052],{},"Only change these values if your owned-vehicle table uses different names:",[97,1054,1055,1060,1066,1072,1078],{},[22,1056,1057,1059],{},[40,1058,56],{},": owned-vehicle table",[22,1061,1062,1065],{},[40,1063,1064],{},"column",": JSON property column",[22,1067,1068,1071],{},[40,1069,1070],{},"plateColumn",": plate column",[22,1073,1074,1077],{},[40,1075,1076],{},"ownerColumn",": database owner column",[22,1079,1080,1083,1084],{},[40,1081,1082],{},"ownerField",": matching value in ",[40,1085,1086],{},"Player.PlayerData",[236,1088,1090],{"id":1089},"step-2-read-the-properties-before-parking","Step 2: Read the properties before parking",[15,1092,940,1093,1096],{},[40,1094,1095],{},"qb-garages/client.lua"," and find:",[151,1098,1100],{"className":165,"code":1099,"language":167,"meta":157,"style":157},"local function DepositVehicle(veh, data)\n",[40,1101,1102],{"__ignoreMap":157},[171,1103,1104,1107,1110,1113,1115,1118,1120,1123],{"class":173,"line":174},[171,1105,1106],{"class":277},"local",[171,1108,1109],{"class":261}," function",[171,1111,1112],{"class":188}," DepositVehicle",[171,1114,278],{"class":277},[171,1116,1117],{"class":281},"veh",[171,1119,450],{"class":277},[171,1121,1122],{"class":281}," data",[171,1124,285],{"class":277},[15,1126,1127],{},"Directly after the plate is read, add:",[151,1129,1131],{"className":165,"code":1130,"language":167,"meta":157,"style":157},"local plate = QBCore.Functions.GetPlate(veh)\nlocal vehicle_properties = QBCore.Functions.GetVehicleProperties(veh)\n",[40,1132,1133,1155],{"__ignoreMap":157},[171,1134,1135,1137,1140,1142,1145,1147,1149,1152],{"class":173,"line":174},[171,1136,1106],{"class":277},[171,1138,1139],{"class":177}," plate ",[171,1141,971],{"class":277},[171,1143,1144],{"class":177}," QBCore.",[171,1146,270],{"class":181},[171,1148,185],{"class":177},[171,1150,1151],{"class":188},"GetPlate",[171,1153,1154],{"class":177},"(veh)\n",[171,1156,1157,1159,1162,1164,1166,1168,1170,1172],{"class":173,"line":195},[171,1158,1106],{"class":277},[171,1160,1161],{"class":177}," vehicle_properties ",[171,1163,971],{"class":277},[171,1165,1144],{"class":177},[171,1167,270],{"class":181},[171,1169,185],{"class":177},[171,1171,189],{"class":188},[171,1173,1154],{"class":177},[15,1175,1176],{},"Because the central QBCore getter was synchronized above, this call now produces the same property\ntable as Sky.",[15,1178,1179],{},"Remove the complete old event:",[151,1181,1183],{"className":165,"code":1182,"language":167,"meta":157,"style":157},"TriggerServerEvent(\n    \"qb-mechanicjob:server:SaveVehicleProps\",\n    QBCore.Functions.GetVehicleProperties(veh)\n)\n",[40,1184,1185,1191,1201,1213],{"__ignoreMap":157},[171,1186,1187,1189],{"class":173,"line":174},[171,1188,887],{"class":188},[171,1190,890],{"class":177},[171,1192,1193,1195,1197,1199],{"class":173,"line":195},[171,1194,895],{"class":277},[171,1196,898],{"class":600},[171,1198,901],{"class":277},[171,1200,904],{"class":177},[171,1202,1203,1205,1207,1209,1211],{"class":173,"line":405},[171,1204,909],{"class":177},[171,1206,270],{"class":181},[171,1208,185],{"class":177},[171,1210,189],{"class":188},[171,1212,1154],{"class":177},[171,1214,1215],{"class":173,"line":411},[171,1216,285],{"class":177},[15,1218,1219,1220,1223,1224,1227],{},"Pass ",[40,1221,1222],{},"vehicle_properties"," as the final argument of the existing ",[40,1225,1226],{},"canDeposit"," callback:",[151,1229,1231],{"className":165,"code":1230,"language":167,"meta":157,"style":157},"QBCore.Functions.TriggerCallback(\n    \"qb-garages:server:canDeposit\",\n    function(can_deposit)\n        -- Keep the existing garage code here.\n    end,\n    plate,\n    data.type,\n    data.indexgarage,\n    1,\n    vehicle_properties\n)\n",[40,1232,1233,1246,1257,1269,1274,1281,1286,1296,1306,1315,1321],{"__ignoreMap":157},[171,1234,1235,1237,1239,1241,1244],{"class":173,"line":174},[171,1236,557],{"class":177},[171,1238,270],{"class":181},[171,1240,185],{"class":177},[171,1242,1243],{"class":188},"TriggerCallback",[171,1245,890],{"class":177},[171,1247,1248,1250,1253,1255],{"class":173,"line":195},[171,1249,895],{"class":277},[171,1251,1252],{"class":600},"qb-garages:server:canDeposit",[171,1254,901],{"class":277},[171,1256,904],{"class":177},[171,1258,1259,1262,1264,1267],{"class":173,"line":405},[171,1260,1261],{"class":261},"    function",[171,1263,278],{"class":277},[171,1265,1266],{"class":281},"can_deposit",[171,1268,285],{"class":277},[171,1270,1271],{"class":173,"line":411},[171,1272,1273],{"class":401},"        -- Keep the existing garage code here.\n",[171,1275,1276,1279],{"class":173,"line":1015},[171,1277,1278],{"class":261},"    end",[171,1280,904],{"class":177},[171,1282,1283],{"class":173,"line":1032},[171,1284,1285],{"class":177},"    plate,\n",[171,1287,1288,1291,1294],{"class":173,"line":1046},[171,1289,1290],{"class":177},"    data.",[171,1292,1293],{"class":181},"type",[171,1295,904],{"class":177},[171,1297,1299,1301,1304],{"class":173,"line":1298},8,[171,1300,1290],{"class":177},[171,1302,1303],{"class":181},"indexgarage",[171,1305,904],{"class":177},[171,1307,1309,1313],{"class":173,"line":1308},9,[171,1310,1312],{"class":1311},"sbssI","    1",[171,1314,904],{"class":177},[171,1316,1318],{"class":173,"line":1317},10,[171,1319,1320],{"class":177},"    vehicle_properties\n",[171,1322,1324],{"class":173,"line":1323},11,[171,1325,285],{"class":177},[15,1327,1328],{},"Keep the existing fuel, damage, vehicle deletion, outside-vehicle, and notification code.",[236,1330,1332],{"id":1331},"step-3-add-the-server-side-storage-helpers","Step 3: Add the server-side storage helpers",[15,1334,940,1335,1338],{},[40,1336,1337],{},"qb-garages/server.lua",". Add this block above the callback registrations:",[151,1340,1342],{"className":165,"code":1341,"filename":1337,"language":167,"meta":157,"style":157},"local function getVehiclePropertiesStorage(Player)\n    local storage = Config.VehiclePropertiesStorage\n    local identifiers = {\n        storage.table,\n        storage.column,\n        storage.plateColumn,\n        storage.ownerColumn,\n        storage.ownerField\n    }\n\n    for _, identifier in ipairs(identifiers) do\n        if type(identifier) ~= \"string\" or not identifier:match(\"^[%w_]+$\") then\n            error((\"Invalid Config.VehiclePropertiesStorage identifier: %s\"):format(tostring(identifier)))\n        end\n    end\n\n    local owner = Player.PlayerData[storage.ownerField]\n    if not owner then\n        error((\"PlayerData.%s is unavailable for vehicle property persistence\"):format(storage.ownerField))\n    end\n\n    return storage, owner\nend\n\nlocal function saveVehicleProperties(Player, plate, properties)\n    if type(properties) ~= \"table\" then return false end\n\n    local storage, owner = getVehiclePropertiesStorage(Player)\n    properties.plate = plate\n\n    local query = (\"UPDATE `%s` SET `%s` = ? WHERE `%s` = ? AND `%s` = ?\"):format(\n        storage.table,\n        storage.column,\n        storage.plateColumn,\n        storage.ownerColumn\n    )\n    local affected_rows = MySQL.update.await(query, {\n        json.encode(properties),\n        plate,\n        owner\n    })\n\n    if affected_rows > 0 then return true end\n\n    -- MySQL can report zero affected rows when the stored JSON is already identical.\n    local exists_query = (\"SELECT 1 FROM `%s` WHERE `%s` = ? AND `%s` = ? LIMIT 1\"):format(\n        storage.table,\n        storage.plateColumn,\n        storage.ownerColumn\n    )\n    return MySQL.scalar.await(exists_query, { plate, owner }) ~= nil\nend\n\nlocal function loadVehicleProperties(Player, plate)\n    local storage, owner = getVehiclePropertiesStorage(Player)\n    local query = (\"SELECT `%s` AS properties FROM `%s` WHERE `%s` = ? AND `%s` = ? LIMIT 1\"):format(\n        storage.column,\n        storage.table,\n        storage.plateColumn,\n        storage.ownerColumn\n    )\n    local row = MySQL.single.await(query, { plate, owner })\n\n    if not row or not row.properties then return {} end\n\n    return json.decode(row.properties) or {}\nend\n",[40,1343,1344,1360,1376,1387,1396,1404,1412,1420,1427,1432,1438,1458,1511,1541,1547,1553,1558,1582,1594,1621,1626,1631,1640,1645,1650,1676,1706,1711,1726,1739,1744,1770,1779,1788,1797,1805,1811,1835,1847,1853,1859,1865,1870,1893,1898,1904,1929,1938,1947,1954,1959,1981,1986,1991,2011,2024,2048,2057,2066,2075,2082,2087,2109,2114,2142,2147,2170],{"__ignoreMap":157},[171,1345,1346,1348,1350,1353,1355,1358],{"class":173,"line":174},[171,1347,1106],{"class":277},[171,1349,1109],{"class":261},[171,1351,1352],{"class":188}," getVehiclePropertiesStorage",[171,1354,278],{"class":277},[171,1356,1357],{"class":281},"Player",[171,1359,285],{"class":277},[171,1361,1362,1365,1368,1370,1373],{"class":173,"line":195},[171,1363,1364],{"class":277},"    local",[171,1366,1367],{"class":177}," storage ",[171,1369,971],{"class":277},[171,1371,1372],{"class":177}," Config.",[171,1374,1375],{"class":181},"VehiclePropertiesStorage\n",[171,1377,1378,1380,1383,1385],{"class":173,"line":405},[171,1379,1364],{"class":277},[171,1381,1382],{"class":177}," identifiers ",[171,1384,971],{"class":277},[171,1386,963],{"class":177},[171,1388,1389,1392,1394],{"class":173,"line":411},[171,1390,1391],{"class":177},"        storage.",[171,1393,56],{"class":181},[171,1395,904],{"class":177},[171,1397,1398,1400,1402],{"class":173,"line":1015},[171,1399,1391],{"class":177},[171,1401,1064],{"class":181},[171,1403,904],{"class":177},[171,1405,1406,1408,1410],{"class":173,"line":1032},[171,1407,1391],{"class":177},[171,1409,1070],{"class":181},[171,1411,904],{"class":177},[171,1413,1414,1416,1418],{"class":173,"line":1046},[171,1415,1391],{"class":177},[171,1417,1076],{"class":181},[171,1419,904],{"class":177},[171,1421,1422,1424],{"class":173,"line":1298},[171,1423,1391],{"class":177},[171,1425,1426],{"class":181},"ownerField\n",[171,1428,1429],{"class":173,"line":1308},[171,1430,1431],{"class":177},"    }\n",[171,1433,1434],{"class":173,"line":1317},[171,1435,1437],{"emptyLinePlaceholder":1436},true,"\n",[171,1439,1440,1443,1446,1449,1452,1455],{"class":173,"line":1323},[171,1441,1442],{"class":261},"    for",[171,1444,1445],{"class":177}," _, identifier ",[171,1447,1448],{"class":261},"in",[171,1450,1451],{"class":188}," ipairs",[171,1453,1454],{"class":177},"(identifiers) ",[171,1456,1457],{"class":261},"do\n",[171,1459,1461,1464,1467,1470,1473,1475,1478,1481,1484,1487,1490,1493,1496,1498,1500,1503,1505,1508],{"class":173,"line":1460},12,[171,1462,1463],{"class":261},"        if",[171,1465,1466],{"class":188}," type",[171,1468,1469],{"class":177},"(identifier) ",[171,1471,1472],{"class":277},"~=",[171,1474,597],{"class":277},[171,1476,1477],{"class":600},"string",[171,1479,1480],{"class":277},"\" ",[171,1482,1483],{"class":277},"or",[171,1485,1486],{"class":277}," not",[171,1488,1489],{"class":181}," identifier",[171,1491,1492],{"class":177},":",[171,1494,1495],{"class":188},"match",[171,1497,278],{"class":177},[171,1499,901],{"class":277},[171,1501,1502],{"class":600},"^[%w_]+$",[171,1504,901],{"class":277},[171,1506,1507],{"class":177},") ",[171,1509,1510],{"class":261},"then\n",[171,1512,1514,1517,1520,1522,1525,1527,1530,1533,1535,1538],{"class":173,"line":1513},13,[171,1515,1516],{"class":188},"            error",[171,1518,1519],{"class":177},"((",[171,1521,901],{"class":277},[171,1523,1524],{"class":600},"Invalid Config.VehiclePropertiesStorage identifier: %s",[171,1526,901],{"class":277},[171,1528,1529],{"class":177},"):",[171,1531,1532],{"class":188},"format",[171,1534,278],{"class":177},[171,1536,1537],{"class":188},"tostring",[171,1539,1540],{"class":177},"(identifier)))\n",[171,1542,1544],{"class":173,"line":1543},14,[171,1545,1546],{"class":261},"        end\n",[171,1548,1550],{"class":173,"line":1549},15,[171,1551,1552],{"class":261},"    end\n",[171,1554,1556],{"class":173,"line":1555},16,[171,1557,1437],{"emptyLinePlaceholder":1436},[171,1559,1561,1563,1566,1568,1571,1574,1577,1579],{"class":173,"line":1560},17,[171,1562,1364],{"class":277},[171,1564,1565],{"class":177}," owner ",[171,1567,971],{"class":277},[171,1569,1570],{"class":177}," Player.",[171,1572,1573],{"class":181},"PlayerData",[171,1575,1576],{"class":177},"[storage.",[171,1578,1082],{"class":181},[171,1580,1581],{"class":177},"]\n",[171,1583,1585,1588,1590,1592],{"class":173,"line":1584},18,[171,1586,1587],{"class":261},"    if",[171,1589,1486],{"class":277},[171,1591,1565],{"class":177},[171,1593,1510],{"class":261},[171,1595,1597,1600,1602,1604,1607,1609,1611,1613,1616,1618],{"class":173,"line":1596},19,[171,1598,1599],{"class":188},"        error",[171,1601,1519],{"class":177},[171,1603,901],{"class":277},[171,1605,1606],{"class":600},"PlayerData.%s is unavailable for vehicle property persistence",[171,1608,901],{"class":277},[171,1610,1529],{"class":177},[171,1612,1532],{"class":188},[171,1614,1615],{"class":177},"(storage.",[171,1617,1082],{"class":181},[171,1619,1620],{"class":177},"))\n",[171,1622,1624],{"class":173,"line":1623},20,[171,1625,1552],{"class":261},[171,1627,1629],{"class":173,"line":1628},21,[171,1630,1437],{"emptyLinePlaceholder":1436},[171,1632,1634,1637],{"class":173,"line":1633},22,[171,1635,1636],{"class":261},"    return",[171,1638,1639],{"class":177}," storage, owner\n",[171,1641,1643],{"class":173,"line":1642},23,[171,1644,414],{"class":261},[171,1646,1648],{"class":173,"line":1647},24,[171,1649,1437],{"emptyLinePlaceholder":1436},[171,1651,1653,1655,1657,1660,1662,1664,1666,1669,1671,1674],{"class":173,"line":1652},25,[171,1654,1106],{"class":277},[171,1656,1109],{"class":261},[171,1658,1659],{"class":188}," saveVehicleProperties",[171,1661,278],{"class":277},[171,1663,1357],{"class":281},[171,1665,450],{"class":277},[171,1667,1668],{"class":281}," plate",[171,1670,450],{"class":277},[171,1672,1673],{"class":281}," properties",[171,1675,285],{"class":277},[171,1677,1679,1681,1683,1686,1688,1690,1692,1694,1697,1700,1703],{"class":173,"line":1678},26,[171,1680,1587],{"class":261},[171,1682,1466],{"class":188},[171,1684,1685],{"class":177},"(properties) ",[171,1687,1472],{"class":277},[171,1689,597],{"class":277},[171,1691,56],{"class":600},[171,1693,1480],{"class":277},[171,1695,1696],{"class":261},"then",[171,1698,1699],{"class":261}," return",[171,1701,1702],{"class":277}," false",[171,1704,1705],{"class":261}," end\n",[171,1707,1709],{"class":173,"line":1708},27,[171,1710,1437],{"emptyLinePlaceholder":1436},[171,1712,1714,1716,1719,1721,1723],{"class":173,"line":1713},28,[171,1715,1364],{"class":277},[171,1717,1718],{"class":177}," storage, owner ",[171,1720,971],{"class":277},[171,1722,1352],{"class":188},[171,1724,1725],{"class":177},"(Player)\n",[171,1727,1729,1732,1734,1736],{"class":173,"line":1728},29,[171,1730,1731],{"class":177},"    properties.",[171,1733,1008],{"class":181},[171,1735,960],{"class":277},[171,1737,1738],{"class":177}," plate\n",[171,1740,1742],{"class":173,"line":1741},30,[171,1743,1437],{"emptyLinePlaceholder":1436},[171,1745,1747,1749,1752,1754,1757,1759,1762,1764,1766,1768],{"class":173,"line":1746},31,[171,1748,1364],{"class":277},[171,1750,1751],{"class":177}," query ",[171,1753,971],{"class":277},[171,1755,1756],{"class":177}," (",[171,1758,901],{"class":277},[171,1760,1761],{"class":600},"UPDATE `%s` SET `%s` = ? WHERE `%s` = ? AND `%s` = ?",[171,1763,901],{"class":277},[171,1765,1529],{"class":177},[171,1767,1532],{"class":188},[171,1769,890],{"class":177},[171,1771,1773,1775,1777],{"class":173,"line":1772},32,[171,1774,1391],{"class":177},[171,1776,56],{"class":181},[171,1778,904],{"class":177},[171,1780,1782,1784,1786],{"class":173,"line":1781},33,[171,1783,1391],{"class":177},[171,1785,1064],{"class":181},[171,1787,904],{"class":177},[171,1789,1791,1793,1795],{"class":173,"line":1790},34,[171,1792,1391],{"class":177},[171,1794,1070],{"class":181},[171,1796,904],{"class":177},[171,1798,1800,1802],{"class":173,"line":1799},35,[171,1801,1391],{"class":177},[171,1803,1804],{"class":181},"ownerColumn\n",[171,1806,1808],{"class":173,"line":1807},36,[171,1809,1810],{"class":177},"    )\n",[171,1812,1814,1816,1819,1821,1824,1827,1829,1832],{"class":173,"line":1813},37,[171,1815,1364],{"class":277},[171,1817,1818],{"class":177}," affected_rows ",[171,1820,971],{"class":277},[171,1822,1823],{"class":177}," MySQL.",[171,1825,1826],{"class":181},"update",[171,1828,185],{"class":177},[171,1830,1831],{"class":188},"await",[171,1833,1834],{"class":177},"(query, {\n",[171,1836,1838,1841,1844],{"class":173,"line":1837},38,[171,1839,1840],{"class":177},"        json.",[171,1842,1843],{"class":188},"encode",[171,1845,1846],{"class":177},"(properties),\n",[171,1848,1850],{"class":173,"line":1849},39,[171,1851,1852],{"class":177},"        plate,\n",[171,1854,1856],{"class":173,"line":1855},40,[171,1857,1858],{"class":177},"        owner\n",[171,1860,1862],{"class":173,"line":1861},41,[171,1863,1864],{"class":177},"    })\n",[171,1866,1868],{"class":173,"line":1867},42,[171,1869,1437],{"emptyLinePlaceholder":1436},[171,1871,1873,1875,1877,1880,1883,1886,1888,1891],{"class":173,"line":1872},43,[171,1874,1587],{"class":261},[171,1876,1818],{"class":177},[171,1878,1879],{"class":277},">",[171,1881,1882],{"class":1311}," 0",[171,1884,1885],{"class":261}," then",[171,1887,1699],{"class":261},[171,1889,1890],{"class":277}," true",[171,1892,1705],{"class":261},[171,1894,1896],{"class":173,"line":1895},44,[171,1897,1437],{"emptyLinePlaceholder":1436},[171,1899,1901],{"class":173,"line":1900},45,[171,1902,1903],{"class":401},"    -- MySQL can report zero affected rows when the stored JSON is already identical.\n",[171,1905,1907,1909,1912,1914,1916,1918,1921,1923,1925,1927],{"class":173,"line":1906},46,[171,1908,1364],{"class":277},[171,1910,1911],{"class":177}," exists_query ",[171,1913,971],{"class":277},[171,1915,1756],{"class":177},[171,1917,901],{"class":277},[171,1919,1920],{"class":600},"SELECT 1 FROM `%s` WHERE `%s` = ? AND `%s` = ? LIMIT 1",[171,1922,901],{"class":277},[171,1924,1529],{"class":177},[171,1926,1532],{"class":188},[171,1928,890],{"class":177},[171,1930,1932,1934,1936],{"class":173,"line":1931},47,[171,1933,1391],{"class":177},[171,1935,56],{"class":181},[171,1937,904],{"class":177},[171,1939,1941,1943,1945],{"class":173,"line":1940},48,[171,1942,1391],{"class":177},[171,1944,1070],{"class":181},[171,1946,904],{"class":177},[171,1948,1950,1952],{"class":173,"line":1949},49,[171,1951,1391],{"class":177},[171,1953,1804],{"class":181},[171,1955,1957],{"class":173,"line":1956},50,[171,1958,1810],{"class":177},[171,1960,1962,1964,1966,1969,1971,1973,1976,1978],{"class":173,"line":1961},51,[171,1963,1636],{"class":261},[171,1965,1823],{"class":177},[171,1967,1968],{"class":181},"scalar",[171,1970,185],{"class":177},[171,1972,1831],{"class":188},[171,1974,1975],{"class":177},"(exists_query, { plate, owner }) ",[171,1977,1472],{"class":277},[171,1979,1980],{"class":277}," nil\n",[171,1982,1984],{"class":173,"line":1983},52,[171,1985,414],{"class":261},[171,1987,1989],{"class":173,"line":1988},53,[171,1990,1437],{"emptyLinePlaceholder":1436},[171,1992,1994,1996,1998,2001,2003,2005,2007,2009],{"class":173,"line":1993},54,[171,1995,1106],{"class":277},[171,1997,1109],{"class":261},[171,1999,2000],{"class":188}," loadVehicleProperties",[171,2002,278],{"class":277},[171,2004,1357],{"class":281},[171,2006,450],{"class":277},[171,2008,1668],{"class":281},[171,2010,285],{"class":277},[171,2012,2014,2016,2018,2020,2022],{"class":173,"line":2013},55,[171,2015,1364],{"class":277},[171,2017,1718],{"class":177},[171,2019,971],{"class":277},[171,2021,1352],{"class":188},[171,2023,1725],{"class":177},[171,2025,2027,2029,2031,2033,2035,2037,2040,2042,2044,2046],{"class":173,"line":2026},56,[171,2028,1364],{"class":277},[171,2030,1751],{"class":177},[171,2032,971],{"class":277},[171,2034,1756],{"class":177},[171,2036,901],{"class":277},[171,2038,2039],{"class":600},"SELECT `%s` AS properties FROM `%s` WHERE `%s` = ? AND `%s` = ? LIMIT 1",[171,2041,901],{"class":277},[171,2043,1529],{"class":177},[171,2045,1532],{"class":188},[171,2047,890],{"class":177},[171,2049,2051,2053,2055],{"class":173,"line":2050},57,[171,2052,1391],{"class":177},[171,2054,1064],{"class":181},[171,2056,904],{"class":177},[171,2058,2060,2062,2064],{"class":173,"line":2059},58,[171,2061,1391],{"class":177},[171,2063,56],{"class":181},[171,2065,904],{"class":177},[171,2067,2069,2071,2073],{"class":173,"line":2068},59,[171,2070,1391],{"class":177},[171,2072,1070],{"class":181},[171,2074,904],{"class":177},[171,2076,2078,2080],{"class":173,"line":2077},60,[171,2079,1391],{"class":177},[171,2081,1804],{"class":181},[171,2083,2085],{"class":173,"line":2084},61,[171,2086,1810],{"class":177},[171,2088,2090,2092,2095,2097,2099,2102,2104,2106],{"class":173,"line":2089},62,[171,2091,1364],{"class":277},[171,2093,2094],{"class":177}," row ",[171,2096,971],{"class":277},[171,2098,1823],{"class":177},[171,2100,2101],{"class":181},"single",[171,2103,185],{"class":177},[171,2105,1831],{"class":188},[171,2107,2108],{"class":177},"(query, { plate, owner })\n",[171,2110,2112],{"class":173,"line":2111},63,[171,2113,1437],{"emptyLinePlaceholder":1436},[171,2115,2117,2119,2121,2123,2125,2127,2130,2133,2135,2137,2140],{"class":173,"line":2116},64,[171,2118,1587],{"class":261},[171,2120,1486],{"class":277},[171,2122,2094],{"class":177},[171,2124,1483],{"class":277},[171,2126,1486],{"class":277},[171,2128,2129],{"class":177}," row.",[171,2131,2132],{"class":181},"properties",[171,2134,1885],{"class":261},[171,2136,1699],{"class":261},[171,2138,2139],{"class":177}," {} ",[171,2141,414],{"class":261},[171,2143,2145],{"class":173,"line":2144},65,[171,2146,1437],{"emptyLinePlaceholder":1436},[171,2148,2150,2152,2155,2158,2161,2163,2165,2167],{"class":173,"line":2149},66,[171,2151,1636],{"class":261},[171,2153,2154],{"class":177}," json.",[171,2156,2157],{"class":188},"decode",[171,2159,2160],{"class":177},"(row.",[171,2162,2132],{"class":181},[171,2164,1507],{"class":177},[171,2166,1483],{"class":277},[171,2168,2169],{"class":177}," {}\n",[171,2171,2173],{"class":173,"line":2172},67,[171,2174,414],{"class":261},[15,2176,2177],{},"The update checks both the plate and the owner. A player therefore cannot overwrite another\nplayer's vehicle by submitting its plate.",[236,2179,2181,2182],{"id":2180},"step-4-save-inside-candeposit","Step 4: Save inside ",[40,2183,1226],{},[15,2185,2186],{},"Find:",[151,2188,2190],{"className":165,"code":2189,"language":167,"meta":157,"style":157},"QBCore.Functions.CreateCallback(\n    \"qb-garages:server:canDeposit\",\n    function(source, cb, plate, vehicle_type, garage, state)\n",[40,2191,2192,2205,2215],{"__ignoreMap":157},[171,2193,2194,2196,2198,2200,2203],{"class":173,"line":174},[171,2195,557],{"class":177},[171,2197,270],{"class":181},[171,2199,185],{"class":177},[171,2201,2202],{"class":188},"CreateCallback",[171,2204,890],{"class":177},[171,2206,2207,2209,2211,2213],{"class":173,"line":195},[171,2208,895],{"class":277},[171,2210,1252],{"class":600},[171,2212,901],{"class":277},[171,2214,904],{"class":177},[171,2216,2217,2219,2221,2224,2226,2229,2231,2233,2235,2238,2240,2243,2245,2248],{"class":173,"line":405},[171,2218,1261],{"class":261},[171,2220,278],{"class":277},[171,2222,2223],{"class":281},"source",[171,2225,450],{"class":277},[171,2227,2228],{"class":281}," cb",[171,2230,450],{"class":277},[171,2232,1668],{"class":281},[171,2234,450],{"class":277},[171,2236,2237],{"class":281}," vehicle_type",[171,2239,450],{"class":277},[171,2241,2242],{"class":281}," garage",[171,2244,450],{"class":277},[171,2246,2247],{"class":281}," state",[171,2249,285],{"class":277},[15,2251,2252,2253,2255],{},"Add ",[40,2254,2132],{}," as the final parameter:",[151,2257,2259],{"className":165,"code":2258,"language":167,"meta":157,"style":157},"QBCore.Functions.CreateCallback(\n    \"qb-garages:server:canDeposit\",\n    function(source, cb, plate, vehicle_type, garage, state, properties)\n",[40,2260,2261,2273,2283],{"__ignoreMap":157},[171,2262,2263,2265,2267,2269,2271],{"class":173,"line":174},[171,2264,557],{"class":177},[171,2266,270],{"class":181},[171,2268,185],{"class":177},[171,2270,2202],{"class":188},[171,2272,890],{"class":177},[171,2274,2275,2277,2279,2281],{"class":173,"line":195},[171,2276,895],{"class":277},[171,2278,1252],{"class":600},[171,2280,901],{"class":277},[171,2282,904],{"class":177},[171,2284,2285,2287,2289,2291,2293,2295,2297,2299,2301,2303,2305,2307,2309,2311,2313,2315],{"class":173,"line":405},[171,2286,1261],{"class":261},[171,2288,278],{"class":277},[171,2290,2223],{"class":281},[171,2292,450],{"class":277},[171,2294,2228],{"class":281},[171,2296,450],{"class":277},[171,2298,1668],{"class":281},[171,2300,450],{"class":277},[171,2302,2237],{"class":281},[171,2304,450],{"class":277},[171,2306,2242],{"class":281},[171,2308,450],{"class":277},[171,2310,2247],{"class":281},[171,2312,450],{"class":277},[171,2314,1673],{"class":281},[171,2316,285],{"class":277},[15,2318,2319],{},"After ownership has been confirmed, but before the vehicle is marked as parked, add:",[151,2321,2323],{"className":165,"code":2322,"language":167,"meta":157,"style":157},"if not saveVehicleProperties(Player, plate, properties) then\n    cb(false)\n    return\nend\n",[40,2324,2325,2339,2351,2356],{"__ignoreMap":157},[171,2326,2327,2330,2332,2334,2337],{"class":173,"line":174},[171,2328,2329],{"class":261},"if",[171,2331,1486],{"class":277},[171,2333,1659],{"class":188},[171,2335,2336],{"class":177},"(Player, plate, properties) ",[171,2338,1510],{"class":261},[171,2340,2341,2344,2346,2349],{"class":173,"line":195},[171,2342,2343],{"class":188},"    cb",[171,2345,278],{"class":177},[171,2347,2348],{"class":277},"false",[171,2350,285],{"class":177},[171,2352,2353],{"class":173,"line":405},[171,2354,2355],{"class":261},"    return\n",[171,2357,2358],{"class":173,"line":411},[171,2359,414],{"class":261},[15,2361,2362],{},"The order must be:",[19,2364,2365,2368,2371,2374,2377],{},[22,2366,2367],{},"Confirm ownership.",[22,2369,2370],{},"Save the property JSON.",[22,2372,2373],{},"Mark the vehicle as parked.",[22,2375,2376],{},"Return success to the client.",[22,2378,2379],{},"Delete the live vehicle on the client.",[236,2381,2383],{"id":2382},"step-5-load-the-configured-property-column","Step 5: Load the configured property column",[15,2385,2386],{},"Find the server callback:",[151,2388,2390],{"className":165,"code":2389,"language":167,"meta":157,"style":157},"\"qb-garages:server:spawnvehicle\"\n",[40,2391,2392],{"__ignoreMap":157},[171,2393,2394,2396,2399],{"class":173,"line":174},[171,2395,901],{"class":277},[171,2397,2398],{"class":600},"qb-garages:server:spawnvehicle",[171,2400,604],{"class":277},[15,2402,2403],{},"Get the QBCore player at the beginning:",[151,2405,2407],{"className":165,"code":2406,"language":167,"meta":157,"style":157},"local Player = exports[\"qb-core\"]:GetPlayer(source)\nif not Player then return end\n",[40,2408,2409,2437],{"__ignoreMap":157},[171,2410,2411,2413,2416,2418,2421,2423,2426,2428,2431,2434],{"class":173,"line":174},[171,2412,1106],{"class":277},[171,2414,2415],{"class":177}," Player ",[171,2417,971],{"class":277},[171,2419,2420],{"class":177}," exports[",[171,2422,901],{"class":277},[171,2424,2425],{"class":600},"qb-core",[171,2427,901],{"class":277},[171,2429,2430],{"class":177},"]:",[171,2432,2433],{"class":188},"GetPlayer",[171,2435,2436],{"class":177},"(source)\n",[171,2438,2439,2441,2443,2445,2447,2449],{"class":173,"line":195},[171,2440,2329],{"class":261},[171,2442,1486],{"class":277},[171,2444,2415],{"class":177},[171,2446,1696],{"class":261},[171,2448,1699],{"class":261},[171,2450,1705],{"class":261},[15,2452,2453],{},"Load the configured property column:",[151,2455,2457],{"className":165,"code":2456,"language":167,"meta":157,"style":157},"local vehicle_properties = loadVehicleProperties(Player, plate)\n",[40,2458,2459],{"__ignoreMap":157},[171,2460,2461,2463,2465,2467,2469],{"class":173,"line":174},[171,2462,1106],{"class":277},[171,2464,1161],{"class":177},[171,2466,971],{"class":277},[171,2468,2000],{"class":188},[171,2470,2471],{"class":177},"(Player, plate)\n",[15,2473,2474],{},"Return it with the spawned network ID and plate:",[151,2476,2478],{"className":165,"code":2477,"language":167,"meta":157,"style":157},"cb(net_id, vehicle_properties, plate)\n",[40,2479,2480],{"__ignoreMap":157},[171,2481,2482,2485],{"class":173,"line":174},[171,2483,2484],{"class":188},"cb",[171,2486,2487],{"class":177},"(net_id, vehicle_properties, plate)\n",[236,2489,2491],{"id":2490},"step-6-keep-the-normal-qbcore-setter","Step 6: Keep the normal QBCore setter",[15,2493,2494],{},"When the client receives the spawned vehicle, it should use:",[151,2496,2498],{"className":165,"code":2497,"language":167,"meta":157,"style":157},"QBCore.Functions.SetVehicleProperties(vehicle, props)\n",[40,2499,2500],{"__ignoreMap":157},[171,2501,2502,2504,2506,2508,2510],{"class":173,"line":174},[171,2503,557],{"class":177},[171,2505,270],{"class":181},[171,2507,185],{"class":177},[171,2509,204],{"class":188},[171,2511,207],{"class":177},[15,2513,2514],{},"Do not replace this call in every garage. The central QBCore setter already contains the same\nimplementation as Sky.",[15,2516,2517],{},"Keep the garage's existing fuel, keys, engine state, visual damage, warp, and outside-vehicle code.",[10,2519,2521],{"id":2520},"esx-garages","ESX garages",[15,2523,2524],{},"After changing the two central ESX functions, most ESX garages need no client modification.",[15,2526,2527],{},"Confirm that the garage:",[19,2529,2530,2536,2542,2547,2550],{},[22,2531,2532,2533,2535],{},"Uses ",[40,2534,859],{}," while parking.",[22,2537,2538,2539,185],{},"Encodes the complete returned table with ",[40,2540,2541],{},"json.encode",[22,2543,2544,2545,185],{},"Stores it in ",[40,2546,110],{},[22,2548,2549],{},"Reads and decodes the same column while spawning.",[22,2551,2532,2552,2554],{},[40,2553,863],{}," after the vehicle exists.",[15,2556,2557],{},"If all five points are already true, no garage code needs to be changed.",[10,2559,2561],{"id":2560},"custom-garages-that-bypass-the-framework","Custom garages that bypass the framework",[15,2563,2564],{},"Some garages use their own adapter functions instead of the central framework functions. Common\nnames are:",[151,2566,2568],{"className":165,"code":2567,"language":167,"meta":157,"style":157},"CL.GetVehicleProperties\nCL.SetVehicleProperties\n",[40,2569,2570,2578],{"__ignoreMap":157},[171,2571,2572,2575],{"class":173,"line":174},[171,2573,2574],{"class":177},"CL.",[171,2576,2577],{"class":181},"GetVehicleProperties\n",[171,2579,2580,2582],{"class":173,"line":195},[171,2581,2574],{"class":177},[171,2583,2584],{"class":181},"SetVehicleProperties\n",[15,2586,2587],{},"When possible, make the adapter call the synchronized framework functions:",[151,2589,2591],{"className":165,"code":2590,"language":167,"meta":157,"style":157},"CL.GetVehicleProperties = function(vehicle)\n    return QBCore.Functions.GetVehicleProperties(vehicle)\nend\n\nCL.SetVehicleProperties = function(vehicle, props)\n    QBCore.Functions.SetVehicleProperties(vehicle, props)\nend\n",[40,2592,2593,2609,2623,2627,2631,2651,2663],{"__ignoreMap":157},[171,2594,2595,2597,2599,2601,2603,2605,2607],{"class":173,"line":174},[171,2596,2574],{"class":177},[171,2598,189],{"class":188},[171,2600,960],{"class":277},[171,2602,1109],{"class":261},[171,2604,278],{"class":277},[171,2606,282],{"class":281},[171,2608,285],{"class":277},[171,2610,2611,2613,2615,2617,2619,2621],{"class":173,"line":195},[171,2612,1636],{"class":261},[171,2614,1144],{"class":177},[171,2616,270],{"class":181},[171,2618,185],{"class":177},[171,2620,189],{"class":188},[171,2622,192],{"class":177},[171,2624,2625],{"class":173,"line":405},[171,2626,414],{"class":261},[171,2628,2629],{"class":173,"line":411},[171,2630,1437],{"emptyLinePlaceholder":1436},[171,2632,2633,2635,2637,2639,2641,2643,2645,2647,2649],{"class":173,"line":1015},[171,2634,2574],{"class":177},[171,2636,204],{"class":188},[171,2638,960],{"class":277},[171,2640,1109],{"class":261},[171,2642,278],{"class":277},[171,2644,282],{"class":281},[171,2646,450],{"class":277},[171,2648,453],{"class":281},[171,2650,285],{"class":277},[171,2652,2653,2655,2657,2659,2661],{"class":173,"line":1032},[171,2654,909],{"class":177},[171,2656,270],{"class":181},[171,2658,185],{"class":177},[171,2660,204],{"class":188},[171,2662,207],{"class":177},[171,2664,2665],{"class":173,"line":1046},[171,2666,414],{"class":261},[15,2668,2669,2670,2672,2673,2675],{},"For an ESX garage, use ",[40,2671,859],{}," and ",[40,2674,863],{}," instead.\nIf the adapter supports both frameworks, select the matching pair in its existing framework branch.",[10,2677,2679],{"id":2678},"updates-and-maintenance","Updates and maintenance",[15,2681,2682],{},"Framework and Sky updates can make the copies different again. After updating QBCore, ESX, or Sky:",[19,2684,2685,2689,2692,2695,2698],{},[22,2686,940,2687,185],{},[40,2688,461],{},[22,2690,2691],{},"Open the framework client functions file next to it.",[22,2693,2694],{},"Compare both getter bodies.",[22,2696,2697],{},"Compare both setter bodies.",[22,2699,2700],{},"Copy the Sky contents again when anything differs.",[15,2702,2703,2704,2707,2708,185],{},"No ",[40,2705,2706],{},"self"," adapter is needed. Sky, QBCore, and ESX all pass the raw vehicle entity as ",[40,2709,282],{},[15,2711,2712],{},"The actual property implementation remains configurable in:",[151,2714,2716],{"className":2715,"code":155,"language":156,"meta":157},[154],[40,2717,155],{"__ignoreMap":157},[10,2719,2721],{"id":2720},"step-by-step-test","Step-by-step test",[15,2723,2724],{},"Use one owned test vehicle:",[19,2726,2727,2736,2739,2742,2745,2758,2761,2764,2767,2770],{},[22,2728,2729,2730,2732,2733,185],{},"Start the framework, ",[40,2731,601],{},", the garage, and ",[40,2734,2735],{},"sky_mechanicjob",[22,2737,2738],{},"Take the vehicle out.",[22,2740,2741],{},"Change an obvious value such as paint, wheels, or an engine upgrade.",[22,2743,2744],{},"Park the vehicle.",[22,2746,2747,2748],{},"Check the database:\n",[97,2749,2750,2754],{},[22,2751,101,2752],{},[40,2753,104],{},[22,2755,107,2756],{},[40,2757,110],{},[22,2759,2760],{},"Confirm that the JSON contains the plate and changed mod values.",[22,2762,2763],{},"Take the vehicle out again.",[22,2765,2766],{},"Confirm that the tuning was restored.",[22,2768,2769],{},"Restart the server.",[22,2771,2772],{},"Retrieve the vehicle and verify it again.",[15,2774,2775],{},"Then test:",[97,2777,2778,2781,2784,2787,2790,2793,2796,2799,2802,2805],{},[22,2779,2780],{},"custom and standard paint",[22,2782,2783],{},"wheels and custom tyres",[22,2785,2786],{},"performance upgrades",[22,2788,2789],{},"extras",[22,2791,2792],{},"neon and xenon",[22,2794,2795],{},"windows, doors, and tyre state",[22,2797,2798],{},"livery",[22,2800,2801],{},"Stancer",[22,2803,2804],{},"Nitro, anti-lag, and two-step",[22,2806,2807],{},"Engine Sound",[10,2809,2811],{"id":2810},"if-tuning-is-still-missing","If tuning is still missing",[15,2813,2814],{},"Check these points in order:",[19,2816,2817,2820,2823,2826,2829,2832,2838,2844],{},[22,2818,2819],{},"Does the framework getter still match the Sky getter contents?",[22,2821,2822],{},"Does the garage JSON column change while parking?",[22,2824,2825],{},"Is the database update restricted by plate and owner?",[22,2827,2828],{},"Does the spawn callback read the same JSON column?",[22,2830,2831],{},"Does the framework setter still match the Sky setter contents?",[22,2833,2834,2835,2837],{},"Does ",[40,2836,601],{}," start after the framework and before the garage?",[22,2839,2834,2840,2843],{},[40,2841,2842],{},"sky_mechanic_vehicle_tuning"," contain a row for the exact plate?",[22,2845,2846],{},"Does another script apply old properties after the framework setter?",[15,2848,2849,2850,2852],{},"If normal paint and wheels are missing, inspect the framework and garage property flow. If only\nStancer, Nitro, anti-lag, or Engine Sound is missing, inspect\n",[40,2851,89],{}," and the exact plate value.",[10,2854,2856],{"id":2855},"related-pages","Related pages",[97,2858,2859,2866,2872,2878],{},[22,2860,2861],{},[2862,2863,2865],"a",{"href":2864},"../features/tuning-and-orders","Tuning and Orders",[22,2867,2868],{},[2862,2869,2871],{"href":2870},"../features/vehicle-systems","Vehicle Systems",[22,2873,2874],{},[2862,2875,2877],{"href":2876},"../setup/configuration","Configuration",[22,2879,2880],{},[2862,2881,2883],{"href":2882},"../troubleshooting","Troubleshooting",[2885,2886,2887],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":157,"searchDepth":174,"depth":195,"links":2889},[2890,2891,2892,2893,2894,2900,2906,2915,2916,2917,2918,2919,2920],{"id":12,"depth":195,"text":13},{"id":50,"depth":195,"text":51},{"id":124,"depth":195,"text":125},{"id":145,"depth":195,"text":146},{"id":233,"depth":195,"text":234,"children":2895},[2896,2897,2898,2899],{"id":238,"depth":405,"text":239},{"id":291,"depth":405,"text":292},{"id":420,"depth":405,"text":421},{"id":580,"depth":405,"text":581},{"id":614,"depth":195,"text":615,"children":2901},[2902,2903,2904,2905],{"id":618,"depth":405,"text":239},{"id":658,"depth":405,"text":292},{"id":731,"depth":405,"text":421},{"id":836,"depth":405,"text":837},{"id":867,"depth":195,"text":868,"children":2907},[2908,2909,2910,2911,2913,2914],{"id":936,"depth":405,"text":937},{"id":1089,"depth":405,"text":1090},{"id":1331,"depth":405,"text":1332},{"id":2180,"depth":405,"text":2912},"Step 4: Save inside canDeposit",{"id":2382,"depth":405,"text":2383},{"id":2490,"depth":405,"text":2491},{"id":2520,"depth":195,"text":2521},{"id":2560,"depth":195,"text":2561},{"id":2678,"depth":195,"text":2679},{"id":2720,"depth":195,"text":2721},{"id":2810,"depth":195,"text":2811},{"id":2855,"depth":195,"text":2856},"Connect the central QBCore or ESX vehicle-property functions to Sky and fix tuning persistence in qb-garages.","md",null,{},"/docs/jobs/mechanicjob/reference/garage-integration",{"title":5,"description":2921},{"loc":2925},"1.docs/0.jobs/2.mechanicjob/4.reference/4.garage-integration","Mzivyi_AgbqYoiTO5E2IeSsMhSTeQSvwcRZy92X9tgo",[2931,2936],{"title":2932,"path":2933,"stem":2934,"description":2935,"children":-1},"Exports","/docs/jobs/mechanicjob/reference/exports","1.docs/0.jobs/2.mechanicjob/4.reference/3.exports","Client and server exports provided by the Sky Mechanic Job resource.",{"title":2883,"path":2937,"stem":2938,"description":2939,"children":-1},"/docs/jobs/mechanicjob/troubleshooting","1.docs/0.jobs/2.mechanicjob/5.troubleshooting","Diagnose common installation, permission, workshop, inventory, tablet, and persistence problems.",[],1784983894374]