Client
Make sure to check the qb.lua and esx.lua files for examples on how to implement the phone for your framework. They are always up to date with the latest changes.
Step 1: Keep the guard
standalone.lua already opens with this. Leave it as is — it stops the file loading on an ESX or QBCore server:
if Config.Framework ~= "standalone" then
return
endStep 2: Wait for the player to load
How you do this depends on your framework. Block until the character is ready, so the phone doesn't read an empty player:
while not YourFramework.PlayerLoaded do
Wait(500)
endStep 3: Required functions
Eight functions. Each already has a no-op body in standalone.lua — replace them one at a time.
FreamworkNotification
Used to display notifications
function FreamworkNotification(text, notifType, length)
notifType = notifType or "info"
length = length or 5000
print(text, notifType, length)
endGetInventory
Returns the player's items. Used as the fallback for "does the player carry X" when your inventory adapter can't answer, so each entry needs a name field.
function GetInventory()
-- ESX: return Config.Core.PlayerData.inventory
-- QBCore: return Config.Core.Functions.GetPlayerData().items
return {}
endGetClosestPlayer
Finds nearest players
function GetClosestPlayer()
return Config.Core.Game.GetClosestPlayer()
endGetVehiclesInArea
Returns vehicles in the specified area
function GetVehiclesInArea(pos, maxRadius)
return Config.Core.Game.GetVehiclesInArea(pos, maxRadius)
end
GetClosestVehicle
Returns the closest vehicle to the player
function GetClosestVehicle(coord)
return Config.Core.Game.GetClosestVehicle(coord)
endGetPlayersInArea
This function gets all players in the given radius.
function GetPlayersInArea(coord, maxRadius)
return Config.Core.Game.GetPlayersInArea(coord, maxRadius)
endGetPlayerBankBalance
Returns the player's bank money
function GetPlayerBankBalance()
local money = 0
return money
-- Returns the player's bank balance.
-- Uses a promise to handle the asynchronous callback from the server.
--[[
local p = promise.new()
Config.Core.Functions.TriggerCallback('gksphone:server:getPlayerBankBalance', function(balance)
local money = 0
if balance then
money = math.floor(balance * 100) / 100
end
p:resolve(money)
end)
return Citizen.Await(p)
--]]
endVehicleCreate
function VehicleCreate(model, coords, vehicleData)
local createCar = CreateVehicle(model, coords.x, coords.y, coords.z, 0.0, true, false)
SetVehicleOnGroundProperly(createCar)
Config.Core.Game.SetVehicleProperties(createCar, vehicleData?.vehMods)
SetFuel(createCar, vehicleData?.vehMods?.fuelLevel or 100)
GiveKeyCar(createCar)
SetModelAsNoLongerNeeded(model)
return createCar
endStep 4: Required Framework Events
Player load/unload/switching character
For character information when a character is loaded
PlayerData = {}
RegisterNetEvent('esx:playerLoaded', function(data)
PlayerData = data
PlayerData.identifier = PlayerData.identifier -- 'Player identifier'
if PlayerData ~= nil then
if PlayerData.job ~= nil then
JobInfo.job = PlayerData.job.name
JobInfo.job_grade = PlayerData.job.grade
JobInfo.job_label = PlayerData.job.label
JobInfo.job_grade_label = PlayerData.job.grade_label
JobInfo.onDuty = PlayerData.job?.onDuty or false
JobUpdate()
end
end
if not isFirstLoaded then
if Config.AutoOpen then
ForceLoadPhone()
end
end
isFirstLoaded = true
end)When the character logs out, this closes the phone, ends calls, etc.
RegisterNetEvent('esx:onPlayerLogout', function()
Debugprint('esx:onPlayerLogout')
PlayerData = {}
JobInfo.job = ""
JobInfo.job_grade = 0
JobInfo.job_label = ""
JobInfo.job_grade_label = ""
JobInfo.onDuty = false
isFirstLoaded = false
TriggerServerEvent("gksphone:server:playerDropped")
end)
Player Die/handcuffed character
When a character dies or is handcuffed
Cuffed = false
AddEventHandler('esx:onPlayerDeath', function(data)
if PhoneOpen == true then
OpenPhone()
end
PhoneOpenBlock = true
PhoneBlockReason = "You can't use the phone while dead, handcuffed or in last stand."
if Incall then
EndPhoneCall()
end
if MusicData and MusicData[CurrentPlayerId] then
TriggerServerEvent('gksphone:server:musicListen', nil, nil, "pause", nil)
end
end)
AddEventHandler("playerSpawned", function()
PhoneBlockReason = ""
PhoneOpenBlock = false
end)
AddEventHandler("esx:onPlayerSpawn", function()
PhoneBlockReason = ""
PhoneOpenBlock = false
end)
RegisterNetEvent('esx_policejob:handcuff', function()
Cuffed = not Cuffed
if Cuffed then
if PhoneOpen == true then
OpenPhone()
end
PhoneOpenBlock = true
PhoneBlockReason = "You can't use the phone while dead, handcuffed or in last stand."
if Incall then
EndPhoneCall()
end
else
PhoneBlockReason = ""
PhoneOpenBlock = false
end
end)
RegisterNetEvent('esx_policejob:unrestrain', function()
PhoneBlockReason = ""
PhoneOpenBlock = false
end)

