This guide helps customers understand how to integrate cd_garage with other resources for seamless functionality.
Compatible Resources
Compatibility Type
There are multiple ways another resource can be considered compatible with cd_garage. Some methods are easier for customers than others
Built-in (Recommended): This means the resource's creator has already made the necessary changes to ensure compatibility with cd_garage, so you don’t have to do anything.
Creator Docs: This indicates that the creator provides documentation outlining the required changes you need to make for their resource to be 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, only the following modifications are required. This is necessary because most ESX resources typically call these functions to spawn 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.
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, only the following modifications are required:
Vehicles Still Respawn After Deletion?
If vehicles still respawn after being deleted, it’s likely that one of your resources does not use the ESX delete vehicle function. You will need to refer to #PersistentVehicles and add the necessary event to that resource.
To use our built-in vehicle keys feature with official QBCore resources, only the following modifications are required.
This process is much simpler on QBCore compared to ESX, as we have integrated event handlers for the default QBCore qb-vehiclekeys resource into cd_garage, meaning it’s mostly pre-configured.
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, only the following modifications are 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.
To make your phone's garage app compatible with cd_garage, only the following modifications are required. If you use a phone not listed below, these changes may not work for you.
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)
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)
Paid Resources
Keys
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.
To make your phone's garage app compatible with cd_garage, only the following modifications are required. If you use a phone not listed below, these changes may not work for you.
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.