This release introduces a phone break-and-repair system — phones can now be damaged (e.g. while swimming) and repaired at NPCs around the map. It also brings better payphone defaults, several bridge improvements (target retry mechanism, new notify event), Cupid UI polish, and assorted bug fixes across music, V app login, and item checks for broken phones.
Config.Phone.item.can_phone_break. Phones break when swimming, and repair NPCs with blips are placed around the map. Players bring a broken phone item to an NPC to fix it.server/open/functions.lua now respects the broken metadata flag when checking whether a player has a phone, preventing broken phones from being used.These files are not encrypted. Review the changes below — you may need to manually apply updates to your server's config files.
bridge/client/notify.lua+RegisterNetEvent("okokPhone:Client:notify", function(data)
+ Notify(data)
+end)
bridge/client/target.lua-local target = {}
+local target = {}
+
+local registrations = {}
+local pendingRegistrations = {}
+local retryingRegistrations = false
----@param models string[]
----@param label string
----@param cb fun(entity: number)
----@param distance number
-function target.addModels(models, label, cb, distance)
+local function getRegistrationKey(models, label)
+ local keys = {}
+ for i, model in ipairs(models) do
+ keys[i] = tostring(model)
+ end
+ return ("%s:%s"):format(table.concat(keys, "|"), label)
+end
+
+local function addModelsNow(models, label, cb, distance)
if GetResourceState("ox_target") == "started" then
exports.ox_target:addModel(models, {
distance = distance,
@@ -14,6 +22,7 @@ function target.addModels(models, label, cb, distance)
cb(data.entity)
end
})
+ return true
elseif GetResourceState("qb-target") == "started" then
exports["qb-target"]:AddTargetModel(models, {
options = {
@@ -28,16 +37,90 @@ function target.addModels(models, label, cb, distance)
},
distance = distance
})
+ return true
+ end
+
+ return false
+end
+
+local function retryPendingRegistrations()
+ if retryingRegistrations then return end
+ retryingRegistrations = true
+
+ CreateThread(function()
+ while next(pendingRegistrations) do
+ for key, data in pairs(pendingRegistrations) do
+ if addModelsNow(data.models, data.label, data.cb, data.distance) then
+ pendingRegistrations[key] = nil
+ end
+ end
+
+ if next(pendingRegistrations) then
+ Wait(1000)
+ end
+ end
+
+ retryingRegistrations = false
+ end)
+end
+
+AddEventHandler("onClientResourceStart", function(resource)
+ if resource ~= "ox_target" and resource ~= "qb-target" then return end
+
+ for key, data in pairs(registrations) do
+ if addModelsNow(data.models, data.label, data.cb, data.distance) then
+ pendingRegistrations[key] = nil
+ end
end
+end)
+
+---@param models string[]
+---@param label string
+---@param cb fun(entity: number)
+---@param distance number
+function target.addModels(models, label, cb, distance)
+ local key = getRegistrationKey(models, label)
+ registrations[key] = {
+ models = models,
+ label = label,
+ cb = cb,
+ distance = distance
+ }
+
+ if addModelsNow(models, label, cb, distance) then return true end
+
+ pendingRegistrations[key] = registrations[key]
+ retryPendingRegistrations()
+ return false
end
---@param models string[]
function target.cleanupModels(models)
+ for key, data in pairs(registrations) do
+ if data.models == models then
+ registrations[key] = nil
+ end
+ end
+
+ for key, data in pairs(pendingRegistrations) do
+ if data.models == models then
+ pendingRegistrations[key] = nil
+ end
+ end
+
if GetResourceState("ox_target") == "started" then
exports.ox_target:removeModel(models)
- elseif GetResourceState("qb-target") == "started" then
+ end
+
+ if GetResourceState("qb-target") == "started" then
exports["qb-target"]:RemoveTargetModel(models)
end
end
+function target.addLocalEntity(entity, data)
+ if GetResourceState("ox_target") == "started" then
+ exports.ox_target:addLocalEntity(entity, data)
+ end
+end
+
return target
client/open/phone_repairs.lua