Links

Resource Integration

A guide to help customers understand how to make cd_garage compatible with other resources.

Compatible Resources

Compatibility Type
There is multiple ways another resource can be considered compatible with cd_garage. Some are easier for the customer than others.
Built-in (recommended) - This means the resource's creator has already made the changes to their resource to make it compatible with cd_garage, so you don’t have to.
Creator Docs - This means the creator provides documentation for the required changes you need to make to make their resource compatible with cd_garage.
Resource Name
Compatibility Type
lb-phone
Built-in
okok-vehicleshop
Creator Docs
gksphone
Built-in
cdev-vehcleshop
Built-in

ESX Resources

Keys

To use our built-in vehicle keys feature with official ESX resources, these are the only modifications required because most ESX resources usually call these functions to spawn in vehicles.
Still don't recieve keys? If you don't receive keys to a vehicle, most likely, one of your resources does not use any of the ESX spawn vehicle functions, so you will need to refer to #VehicleKeys and add the event to that resource.
es_extended (server)
es_extended (client)
Click this link to view the code on GitHub: ex_extended/server/onesync.lua
Add the 2 line's of code exactly as seen in the screenshot below.
Wait(100)
TriggerClientEvent('cd_garage:AddKeys', xPlayer.id, GetVehicleNumberPlateText(createdVehicle))
Click this link to view the code on GitHub: ex_extended/client/functions.lua
Add the line of code exactly as seen in the screenshot below.
TriggerEvent('cd_garage:AddKeys', exports['cd_garage']:GetPlate(vehicle))

Job Garages

To use our built-in job garage feature with official ESX resources, these are the only modifications required.
esx_policejob (personal owned)
esx_policejob (society owned)
Click this link to view the code on GitHub: esx_policejob/server/main.lua
REPLACE the line of code exactly as seen in the screenshot below.
MySQL.insert('INSERT INTO owned_vehicles (owner, vehicle, plate, type, job_personalowned, `stored`) VALUES (?, ?, ?, ?, ?, ?)', { xPlayer.identifier, json.encode(vehicleProps), vehicleProps.plate, type, xPlayer.job.name, true},
Click this link to view the code on GitHub: esx_policejob/server/main.lua
REPLACE the line of code exactly as seen in the screenshot below.
MySQL.insert('INSERT INTO owned_vehicles (owner, vehicle, plate, type, job, `stored`) VALUES (?, ?, ?, ?, ?, ?)', { xPlayer.job.name, json.encode(vehicleProps), vehicleProps.plate, type, xPlayer.job.name, true},

Boat & Air Garages

To use our built-in boat & air garages feature with official ESX resources, these are the only modifications required.
esx_boat
Click this link to view the code on GitHub: esx_boat/client/main.lua
Add the line of code exactly as seen in the screenshot below.
TriggerEvent('cd_garage:UpdateGarageType')

Persistent Vehicle

To use our built-in persistent vehicle feature with official ESX resources, these are the only modifications required.
Vehicles still respawn when deleting them? If vehicles still respawn when deleting them, most likely, one of your resources does not use the ESX delete vehicle function, so you will need to refer to #PersistentVehicles and add the event to that resource.
es_extended
Click this link to view the code on GitHub: es_extended/client/functions.lua
Add the line of code exactly as seen in the screenshot below.
TriggerServerEvent('cd_garage:RemovePersistentVehicles', exports['cd_garage']:GetPlate(vehicle))

QBCore Resources

Keys

To use our built-in vehicle keys feature with official QBCore resources, these are the only modifications required.
This process is much simpler on QBCore compared to ESX because we have added event handlers for the default QBCore qb-vehiclekeys resource into cd_garage, meaning its mostly pre-configured.
qb-core
Click this link to view the code on GitHub: qb-core/client/events.lua
REPLACE the line’s of code exactly as seen in the screenshot below.
if GetResourceState('cd_garage') == 'started' and plate then
hasKeys = exports['cd_garage']:DoesPlayerHaveKeys(plate)
end

Boat & Air Garages

To use our built-in boat & air garages feature with official QBCore resources, these are the only modifications required.
qb-vehicleshop
Click this link to view the code on GitHub: qb-vehicleshop/client/main.lua
Add the line of code exactly as seen in the screenshot below.
TriggerEvent('cd_garage:UpdateGarageType')

Persistent Vehicle

To use our built-in persistent vehicle feature with official QBCore resources, these are the only modifications required.
Vehicles still respawn when deleting them? If vehicles still respawn when deleting them, most likely, one of your resources does not use the QBCore delete vehicle function, so you will need to refer to #PersistentVehicles and add the event to that resource.
qb-core
Click this link to view the code on GitHub: qb-core/client/functions.lua
Add the line of code exactly as seen in the screenshot below.
TriggerServerEvent('cd_garage:RemovePersistentVehicles', exports['cd_garage']:GetPlate(vehicle))

Garage Phone Apps

To make your phones garage app compatible with cd_garage, these are the only modifications required. If you use a phone thats not listed below, these changes may not work for you.
qb-phone
renewed qb-phone
Click this link to view the code on GitHub: qb-phone/server/main.lua
Replace this whole function.
QBCore.Functions.CreateCallback('qb-phone:server:GetPhoneData', function(source, cb)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if Player ~= nil then
local PhoneData = {
Applications = {},
PlayerContacts = {},
MentionedTweets = {},
Chats = {},
Hashtags = {},
Invoices = {},
Garage = {},
Mails = {},
Adverts = {},
CryptoTransactions = {},
Tweets = {},
Images = {},
InstalledApps = Player.PlayerData.metadata["phonedata"].InstalledApps
}
PhoneData.Adverts = Adverts
local result = MySQL.query.await('SELECT * FROM player_contacts WHERE citizenid = ? ORDER BY name ASC', {Player.PlayerData.citizenid})
if result[1] ~= nil then
for _, v in pairs(result) do
v.status = GetOnlineStatus(v.number)
end
PhoneData.PlayerContacts = result
end
local invoices = MySQL.query.await('SELECT * FROM phone_invoices WHERE citizenid = ?', {Player.PlayerData.citizenid})
if invoices[1] ~= nil then
for _, v in pairs(invoices) do
local Ply = QBCore.Functions.GetPlayerByCitizenId(v.sender)
if Ply ~= nil then
v.number = Ply.PlayerData.charinfo.phone
else
local res = MySQL.query.await('SELECT * FROM players WHERE citizenid = ?', {v.sender})
if res[1] ~= nil then
res[1].charinfo = json.decode(res[1].charinfo)
v.number = res[1].charinfo.phone
else
v.number = nil
end
end
end
PhoneData.Invoices = invoices
end
local garageresult = MySQL.query.await('SELECT * FROM player_vehicles WHERE citizenid = ?', {Player.PlayerData.citizenid})
if garageresult[1] ~= nil then
for _, v in pairs(garageresult) do
local vehicleModel = v.vehicle
if QBCore.Shared.Vehicles[vehicleModel] then
v.garage = v.garage_id
v.vehicle = QBCore.Shared.Vehicles[vehicleModel].name
v.brand = QBCore.Shared.Vehicles[vehicleModel].brand
end
end
PhoneData.Garage = garageresult
end
local messages = MySQL.query.await('SELECT * FROM phone_messages WHERE citizenid = ?', {Player.PlayerData.citizenid})
if messages ~= nil and next(messages) ~= nil then
PhoneData.Chats = messages
end
if AppAlerts[Player.PlayerData.citizenid] ~= nil then
PhoneData.Applications = AppAlerts[Player.PlayerData.citizenid]
end
if MentionedTweets[Player.PlayerData.citizenid] ~= nil then
PhoneData.MentionedTweets = MentionedTweets[Player.PlayerData.citizenid]
end
if Hashtags ~= nil and next(Hashtags) ~= nil then
PhoneData.Hashtags = Hashtags
end
local Tweets = MySQL.query.await('SELECT * FROM phone_tweets WHERE `date` > NOW() - INTERVAL ? hour', {Config.TweetDuration})
if Tweets ~= nil and next(Tweets) ~= nil then
PhoneData.Tweets = Tweets
TWData = Tweets
end
local mails = MySQL.query.await('SELECT * FROM player_mails WHERE citizenid = ? ORDER BY `date` ASC', {Player.PlayerData.citizenid})
if mails[1] ~= nil then
for k, _ in pairs(mails) do
if mails[k].button ~= nil then
mails[k].button = json.decode(mails[k].button)
end
end
PhoneData.Mails = mails
end
local transactions = MySQL.query.await('SELECT * FROM crypto_transactions WHERE citizenid = ? ORDER BY `date` ASC', {Player.PlayerData.citizenid})
if transactions[1] ~= nil then
for _, v in pairs(transactions) do
PhoneData.CryptoTransactions[#PhoneData.CryptoTransactions+1] = {
TransactionTitle = v.title,
TransactionMessage = v.message
}
end
end
local images = MySQL.query.await('SELECT * FROM phone_gallery WHERE citizenid = ? ORDER BY `date` DESC',{Player.PlayerData.citizenid})
if images ~= nil and next(images) ~= nil then
PhoneData.Images = images
end
cb(PhoneData)
end
end)
Click this link to view the code on GitHub: qb-phone/server/garage.lua
Replace this whole function.
QBCore.Functions.CreateCallback('qb-phone:server:GetGarageVehicles', function(source, cb)
local Player = QBCore.Functions.GetPlayer(source)
local Vehicles = {}
local vehdata
local result = exports.oxmysql:executeSync('SELECT * FROM player_vehicles WHERE citizenid = ?', {Player.PlayerData.citizenid})
if result[1] then
for _, v in pairs(result) do
local VehicleData = QBCore.Shared.Vehicles[v.vehicle]
local VehicleGarage = "None"
local enginePercent = round(v.engine / 10, 0)
local bodyPercent = round(v.body / 10, 0)
VehicleGarage = v.garage_id
local VehicleState = "In"
if v.in_garage ~= true then
VehicleState = "Out"
end
if v.impound ~= 0 then
VehicleState = "Impounded"
end
if VehicleData["brand"] then
vehdata = {
fullname = VehicleData["brand"] .. " " .. VehicleData["name"],
brand = VehicleData["brand"],
model = VehicleData["name"],
plate = v.plate,
garage = VehicleGarage,
state = VehicleState,
fuel = v.fuel,
engine = enginePercent,
body = bodyPercent,
paymentsleft = v.paymentsleft
}
else
vehdata = {
fullname = VehicleData["name"],
brand = VehicleData["name"],
model = VehicleData["name"],
plate = v.plate,
garage = VehicleGarage,
state = VehicleState,
fuel = v.fuel,
engine = enginePercent,
body = bodyPercent,
paymentsleft = v.paymentsleft
}
end
Vehicles[#Vehicles+1] = vehdata
end
cb(Vehicles)
else
cb(nil)
end
end)

Keys

okok-vehicleshop
You can find this event in [okok-vehicleshop/sv_utils.lua] (approx; line 72).
Add the line of code exactly as seen in the screenshot below.
TriggerClientEvent('cd_garage:AddKeys', _source, vehicleProps.plate:match( "^%s*(.-)%s*$" ))

Boat & Air Garages

okok-vehicleshop
You can find this event in [okok-vehicleshop/sv_utils.lua] (approx; line 68).
Add the line of code exactly as seen in the screenshot below.
TriggerClientEvent('cd_garage:UpdateGarageType', source)

Garage Phone Apps

To make your phones garage app compatible with cd_garage, these are the only modifications required.
lb-phone
gksphone
lb-phone comes pre-configured to work with cd_garage, so no modifications are required.
gksphone comes pre-configured to work with cd_garage, so no modifications are required.