Kartik Scripts

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

On this page