LB-Phone Setup
kartik-properties includes support for LB-Phone's Home Application. This allows players to manage their owned, leased, and key-held properties, invite or remove keyholders, navigate to their properties, and remotely toggle door locks directly from their phone.
Official Integration Notice: Official out-of-the-box support for kartik-properties is coming soon directly in an upcoming update of LB-Phone. In the meantime, follow the straightforward setup guide below.
Features Supported
- 🏠 Property Directory: Lists all citizen-owned properties, rented/leased units, and properties where the player holds keys.
- 🔑 Key Management: Grant keys to nearby or online players directly through the phone.
- 🚫 Revoke Keys: Remove keyholders in real-time with instant synchronization.
- 🔒 Remote Door Lock: Lock and unlock property doors remotely from the app.
- 📍 GPS Navigation: Set a waypoint directly to the property's physical entrance.
⚙️ Installation & Setup
Step 1: Configure LB-Phone Auto-Detection
Open lb-phone/shared/functions.lua and add "kartik-properties" to the end of the houseScripts auto-detection array:
local houseScripts = {
"loaf_housing",
"qb-houses",
"qs-housing",
"vms_housing",
"rtx_housing",
"kartik-properties"
}Ensure Config.HouseScript in lb-phone/config/config.lua is set to "auto" (to auto-detect) or set it manually to "kartik-properties":
Config.HouseScript = "kartik-properties"Step 2: Create Client Bridge File
Create the file: lb-phone/client/apps/framework/home/kartik-properties.lua and paste the following code:
if Config.HouseScript ~= "kartik-properties" then
return
end
RegisterNUICallback("Home", function(data, cb)
local action, houseData = data.action, data.houseData
debugprint("kartik-properties - Home:" .. (action or ""))
if action == "getHomes" then
TriggerCallback("home:getOwnedHouses", cb)
elseif action == "removeKeyholder" then
TriggerCallback("home:removeKeyholder", cb, houseData.id, data.identifier)
elseif action == "addKeyholder" then
TriggerCallback("home:addKeyholder", cb, houseData.id, tonumber(data.source))
elseif action == "toggleLocked" then
TriggerCallback("home:toggleLocked", cb, houseData.id)
elseif action == "setWaypoint" then
if houseData.coords then
SetNewWaypoint(houseData.coords.x, houseData.coords.y)
end
cb(true)
end
end)Step 3: Create Server Bridge File
Create the file: lb-phone/server/apps/framework/home/kartik-properties.lua and paste the following code:
if Config.HouseScript ~= "kartik-properties" then
return
end
RegisterCallback("home:getOwnedHouses", function(source)
local identifier = GetIdentifier(source)
if not identifier then return {} end
local housingData = exports['kartik-properties']:GetPlayerHousingData(identifier)
if not housingData then return {} end
local formatted = {}
for i = 1, #housingData do
local h = housingData[i]
local keyholders = {}
if h.keyholders then
for _, kh in ipairs(h.keyholders) do
if kh.identifier ~= h.owner then
keyholders[#keyholders + 1] = {
identifier = kh.identifier,
name = kh.name
}
end
end
end
formatted[#formatted + 1] = {
label = h.label,
id = h.houseId,
uniqueId = h.houseId,
coords = h.coords,
locked = h.locked,
keyholders = keyholders,
price = h.price or 0
}
end
return formatted
end)
RegisterCallback("home:removeKeyholder", function(source, houseId, targetCid)
local revokedByCid = GetIdentifier(source)
if not revokedByCid then return false end
local propData = exports['kartik-properties']:GetPropertyHousingData(tonumber(houseId))
if not propData then return false end
-- Safeguard: Owner cannot remove themselves, and only the owner or the keyholder themselves can revoke a key
if targetCid == propData.owner then
return false
end
if revokedByCid ~= propData.owner and revokedByCid ~= targetCid then
return false
end
local res = exports['kartik-properties']:RevokeHousingKey(tonumber(houseId), targetCid, revokedByCid)
if not res or not res.success then
return false
end
-- Return updated keyholders
local updatedPropData = exports['kartik-properties']:GetPropertyHousingData(tonumber(houseId))
local keyholders = {}
if updatedPropData and updatedPropData.keyholders then
for _, kh in ipairs(updatedPropData.keyholders) do
if kh.identifier ~= updatedPropData.owner then
keyholders[#keyholders + 1] = {
identifier = kh.identifier,
name = kh.name
}
end
end
end
return keyholders
end)
RegisterCallback("home:addKeyholder", function(source, houseId, targetSource)
local targetCid = GetIdentifier(targetSource)
local grantedByCid = GetIdentifier(source)
if not targetCid or not grantedByCid then return false end
local propData = exports['kartik-properties']:GetPropertyHousingData(tonumber(houseId))
if not propData then return false end
-- Safeguard: target must not be the owner, and only the owner can add keyholders
if targetCid == propData.owner or grantedByCid ~= propData.owner then
return false
end
local res = exports['kartik-properties']:GrantHousingKey(tonumber(houseId), targetCid, grantedByCid)
if not res or not res.success then
return false
end
-- Return updated keyholders
local updatedPropData = exports['kartik-properties']:GetPropertyHousingData(tonumber(houseId))
local keyholders = {}
if updatedPropData and updatedPropData.keyholders then
for _, kh in ipairs(updatedPropData.keyholders) do
if kh.identifier ~= updatedPropData.owner then
keyholders[#keyholders + 1] = {
identifier = kh.identifier,
name = kh.name
}
end
end
end
return keyholders
end)
RegisterCallback("home:toggleLocked", function(source, houseId)
local propData = exports['kartik-properties']:GetPropertyHousingData(tonumber(houseId))
if not propData then return false end
local newLockedState = not propData.locked
exports['kartik-properties']:SetPropertyLocked(tonumber(houseId), newLockedState)
return newLockedState
end)Step 4: Ensure Startup Order in server.cfg
Make sure kartik-properties starts before lb-phone:
ensure kartik-properties
ensure lb-phone