mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-29 05:02:32 +00:00
734f4651cb
Co-authored-by: DerEchteAlec <alec.schitzkat@luwan.io>
267 lines
9.0 KiB
Lua
267 lines
9.0 KiB
Lua
local camera_state = nil
|
|
|
|
local function server_prepare(action, data)
|
|
local request = {
|
|
action = action,
|
|
propertyId = data and data.propertyId,
|
|
target = data and data.target,
|
|
identifier = data and data.identifier,
|
|
}
|
|
return Bridge.Callbacks.Trigger("sky_phone:housing:prepare", request)
|
|
end
|
|
|
|
local function suspend_phone()
|
|
TriggerEvent("sky_phone:client:setSuspended", true)
|
|
TriggerEvent("sky_phone:animation:phone", false)
|
|
SendNUIMessage({ type = "app:suspend" })
|
|
end
|
|
|
|
local function resume_phone()
|
|
SendNUIMessage({ type = "app:resume" })
|
|
TriggerEvent("sky_phone:client:setSuspended", false)
|
|
TriggerEvent("sky_phone:animation:phone", true)
|
|
end
|
|
|
|
local function stop_camera(resume)
|
|
local state = camera_state
|
|
if not state then
|
|
return
|
|
end
|
|
camera_state = nil
|
|
RenderScriptCams(false, true, 350, true, true)
|
|
if state.camera and DoesCamExist(state.camera) then
|
|
DestroyCam(state.camera, false)
|
|
end
|
|
ClearFocus()
|
|
SetNightvision(state.night_vision)
|
|
if DoesEntityExist(state.ped) then
|
|
FreezeEntityPosition(state.ped, state.frozen)
|
|
end
|
|
if resume ~= false then
|
|
resume_phone()
|
|
end
|
|
end
|
|
|
|
local function camera_number(value, fallback)
|
|
local number = tonumber(value)
|
|
if not number or number ~= number or number == math.huge or number == -math.huge then
|
|
return fallback
|
|
end
|
|
return number
|
|
end
|
|
|
|
local function run_camera(provider_name, camera_data)
|
|
if camera_state or type(camera_data) ~= "table"
|
|
or type(camera_data.coords) ~= "table"
|
|
or type(camera_data.rotation) ~= "table"
|
|
then
|
|
return
|
|
end
|
|
local coords = {
|
|
x = camera_number(camera_data.coords.x),
|
|
y = camera_number(camera_data.coords.y),
|
|
z = camera_number(camera_data.coords.z),
|
|
}
|
|
local rotation = {
|
|
x = camera_number(camera_data.rotation.x),
|
|
y = camera_number(camera_data.rotation.y, 0.0),
|
|
z = camera_number(camera_data.rotation.z),
|
|
}
|
|
if not coords.x or not coords.y or not coords.z or not rotation.x or not rotation.z then
|
|
Bridge.Debug("error", "[sky_phone] Rejected invalid housing camera data.")
|
|
return
|
|
end
|
|
|
|
local config = Config.Housing.Camera
|
|
local ped = PlayerPedId()
|
|
local camera = CreateCamWithParams(
|
|
"DEFAULT_SCRIPTED_CAMERA",
|
|
coords.x,
|
|
coords.y,
|
|
coords.z,
|
|
rotation.x,
|
|
rotation.y,
|
|
rotation.z,
|
|
config.FieldOfView,
|
|
true,
|
|
2
|
|
)
|
|
if not camera or camera == 0 then
|
|
Bridge.Debug("error", "[sky_phone] Failed to create housing camera.")
|
|
return
|
|
end
|
|
|
|
camera_state = {
|
|
camera = camera,
|
|
frozen = IsEntityPositionFrozen(ped),
|
|
night_vision = GetUsingnightvision(),
|
|
ped = ped,
|
|
provider = provider_name,
|
|
}
|
|
suspend_phone()
|
|
FreezeEntityPosition(ped, true)
|
|
SetFocusArea(coords.x, coords.y, coords.z, 0.0, 0.0, 0.0)
|
|
SetCamActive(camera, true)
|
|
RenderScriptCams(true, true, 350, true, true)
|
|
|
|
local maximum_left = camera_number(camera_data.maximumLeft)
|
|
local maximum_right = camera_number(camera_data.maximumRight)
|
|
local night_vision = camera_state.night_vision
|
|
local resume_after_camera = false
|
|
local close_phone_after_camera = false
|
|
while camera_state and camera_state.camera == camera do
|
|
Wait(0)
|
|
DisableAllControlActions(0)
|
|
if IsDisabledControlJustPressed(0, config.ExitControl) then
|
|
resume_after_camera = true
|
|
break
|
|
end
|
|
if IsPedDeadOrDying(ped, true) or GetResourceState(provider_name) ~= "started" then
|
|
close_phone_after_camera = true
|
|
break
|
|
end
|
|
|
|
local camera_rotation = GetCamRot(camera, 2)
|
|
local next_x = camera_rotation.x
|
|
local next_z = camera_rotation.z
|
|
if IsDisabledControlPressed(0, config.LeftControl)
|
|
and (not maximum_left or next_z < maximum_left)
|
|
then
|
|
next_z = next_z + config.RotateSpeed
|
|
elseif IsDisabledControlPressed(0, config.RightControl)
|
|
and (not maximum_right or next_z > maximum_right)
|
|
then
|
|
next_z = next_z - config.RotateSpeed
|
|
end
|
|
if IsDisabledControlPressed(0, config.UpControl) then
|
|
next_x = math.min(85.0, next_x + config.RotateSpeed)
|
|
elseif IsDisabledControlPressed(0, config.DownControl) then
|
|
next_x = math.max(-85.0, next_x - config.RotateSpeed)
|
|
end
|
|
if next_x ~= camera_rotation.x or next_z ~= camera_rotation.z then
|
|
SetCamRot(camera, next_x, camera_rotation.y, next_z, 2)
|
|
end
|
|
|
|
local field_of_view = GetCamFov(camera)
|
|
if IsDisabledControlJustPressed(0, config.ZoomInControl) then
|
|
SetCamFov(camera, math.max(config.MinimumFieldOfView, field_of_view - 3.0))
|
|
elseif IsDisabledControlJustPressed(0, config.ZoomOutControl) then
|
|
SetCamFov(camera, math.min(config.MaximumFieldOfView, field_of_view + 3.0))
|
|
end
|
|
if IsDisabledControlJustPressed(0, config.NightVisionControl) then
|
|
night_vision = not night_vision
|
|
SetNightvision(night_vision)
|
|
end
|
|
end
|
|
stop_camera(resume_after_camera)
|
|
if close_phone_after_camera then
|
|
TriggerEvent("sky_phone:client:forceClose")
|
|
end
|
|
end
|
|
|
|
RegisterNetEvent("sky_phone:device:invalidated", function()
|
|
stop_camera(false)
|
|
end)
|
|
|
|
RegisterNUICallback("housing:overview", function(data, cb)
|
|
if type(data) ~= "table" then
|
|
cb({ success = false, error = "invalid_request" })
|
|
return
|
|
end
|
|
local result = Bridge.Callbacks.Trigger("sky_phone:housing:overview", {})
|
|
if type(result) == "table" and result.success and type(result.data) == "table" then
|
|
local properties, error_code = Bridge.Housing.EnrichOverview(
|
|
result.data.provider,
|
|
result.data.properties
|
|
)
|
|
if not properties then
|
|
cb({ success = false, error = error_code or "provider_error" })
|
|
return
|
|
end
|
|
result.data.properties = properties
|
|
end
|
|
cb(type(result) == "table" and result or { success = false, error = "request_failed" })
|
|
end)
|
|
|
|
AddEventHandler("sky_phone:client:nuiReady", function()
|
|
if camera_state then
|
|
suspend_phone()
|
|
end
|
|
end)
|
|
|
|
RegisterNUICallback("housing:key-candidates", function(data, cb)
|
|
if type(data) ~= "table" or type(data.propertyId) ~= "string" then
|
|
cb({ success = false, error = "invalid_request" })
|
|
return
|
|
end
|
|
local result = server_prepare("key_candidates", data)
|
|
cb(type(result) == "table" and result or { success = false, error = "request_failed" })
|
|
end)
|
|
|
|
RegisterNUICallback("housing:command", function(data, cb)
|
|
if type(data) ~= "table" or type(data.action) ~= "string" or type(data.propertyId) ~= "string" then
|
|
cb({ success = false, error = "invalid_request" })
|
|
return
|
|
end
|
|
local actions = {
|
|
grant_key = true,
|
|
open_cctv = true,
|
|
revoke_key = true,
|
|
set_waypoint = true,
|
|
toggle_lock = true,
|
|
}
|
|
if not actions[data.action] then
|
|
cb({ success = false, error = "invalid_action" })
|
|
return
|
|
end
|
|
|
|
local prepared = server_prepare(data.action, data)
|
|
if type(prepared) ~= "table" or not prepared.success or type(prepared.data) ~= "table" then
|
|
cb(type(prepared) == "table" and prepared or { success = false, error = "request_failed" })
|
|
return
|
|
end
|
|
if data.action == "set_waypoint" then
|
|
local coords = prepared.data.coords
|
|
if coords == nil then
|
|
local success, error_code = Bridge.Housing.Execute(
|
|
prepared.data.provider,
|
|
data.action,
|
|
prepared.data
|
|
)
|
|
cb(success and { success = true }
|
|
or { success = false, error = error_code or "invalid_coordinates" })
|
|
return
|
|
end
|
|
|
|
local x = type(coords) == "table" and camera_number(coords.x) or nil
|
|
local y = type(coords) == "table" and camera_number(coords.y) or nil
|
|
if not x or not y then
|
|
cb({ success = false, error = "invalid_coordinates" })
|
|
return
|
|
end
|
|
SetNewWaypoint(x + 0.0, y + 0.0)
|
|
cb({ success = true })
|
|
return
|
|
end
|
|
if data.action == "open_cctv" then
|
|
if type(prepared.data.camera) ~= "table" or type(prepared.data.provider) ~= "string" then
|
|
cb({ success = false, error = "cctv_unavailable" })
|
|
return
|
|
end
|
|
cb({ success = true })
|
|
CreateThread(function()
|
|
run_camera(prepared.data.provider, prepared.data.camera)
|
|
end)
|
|
return
|
|
end
|
|
|
|
local success, error_code = Bridge.Housing.Execute(prepared.data.provider, data.action, prepared.data)
|
|
cb(success and { success = true } or { success = false, error = error_code or "provider_rejected" })
|
|
end)
|
|
|
|
AddEventHandler("onResourceStop", function(resource_name)
|
|
if resource_name == GetCurrentResourceName() and camera_state then
|
|
stop_camera(false)
|
|
end
|
|
end)
|