feat: unify phone apps with Sky UI

This commit is contained in:
Leon.Schmidt
2026-08-16 15:23:21 +02:00
parent 8d9cdb5d6b
commit 1071b4bde7
62 changed files with 5658 additions and 3349 deletions
+125
View File
@@ -0,0 +1,125 @@
local callbacks = {}
local camera_coord = nil
local camera_target = nil
local camera_created = false
local camera_destroyed = false
local scripted_camera_rendering = false
local vector_meta = {}
vector_meta.__index = vector_meta
function vector_meta.__add(left, right)
return vector3(left.x + right.x, left.y + right.y, left.z + right.z)
end
function vector_meta.__sub(left, right)
return vector3(left.x - right.x, left.y - right.y, left.z - right.z)
end
function vector_meta.__mul(left, right)
if type(left) == "number" then
left, right = right, left
end
return vector3(left.x * right, left.y * right, left.z * right)
end
function vector3(x, y, z)
return setmetatable({ x = x, y = y, z = z }, vector_meta)
end
function RegisterNUICallback(name, callback)
callbacks[name] = callback
end
function RegisterNetEvent() end
function AddEventHandler() end
function TriggerEvent() end
function TriggerServerEvent() end
function SendNUIMessage() end
function CreateThread() end
function Wait() end
function PlayerPedId() return 7 end
function PlayerId() return 8 end
function GetFollowPedCamViewMode() return 1 end
function GetFollowVehicleCamViewMode() return 2 end
function IsRadarHidden() return false end
function DisplayRadar() end
function SetFollowPedCamViewMode() end
function SetFollowVehicleCamViewMode() end
function IsPedInAnyVehicle() return false end
function DisableControlAction() end
function DisablePlayerFiring() end
function HideHudAndRadarThisFrame() end
function GetCurrentResourceName() return "sky_phone" end
function GetEntityCoords()
return vector3(10.0, 20.0, 1.0)
end
function GetPedBoneCoords()
return vector3(10.0, 20.0, 2.7)
end
function GetEntityForwardVector()
return vector3(0.0, 1.0, 0.0)
end
function CreateCam(name, active)
assert(name == "DEFAULT_SCRIPTED_CAMERA" and active, "selfie camera must be created active")
camera_created = true
return 73
end
function DoesCamExist(handle)
return camera_created and not camera_destroyed and handle == 73
end
function SetCamFov() end
function SetCamActive() end
function RenderScriptCams(active)
scripted_camera_rendering = active
end
function SetCamCoord(_, x, y, z)
camera_coord = vector3(x, y, z)
end
function PointCamAtCoord(_, x, y, z)
camera_target = vector3(x, y, z)
end
function DestroyCam(handle)
assert(handle == 73, "the selfie camera handle must be destroyed")
camera_destroyed = true
end
local function response_from(name, data)
local response = nil
callbacks[name](data, function(value)
response = value
end)
return response
end
local function close_enough(actual, expected)
return math.abs(actual - expected) < 0.0001
end
dofile("sky_phone/source/client/camera.lua")
assert(response_from("camera:setActive", { active = true }).success)
assert(response_from("camera:setFacing", { front = true }).success)
assert(camera_created and scripted_camera_rendering, "selfie mode must render a scripted camera")
assert(camera_coord and camera_target, "selfie mode must position and aim the camera")
assert(close_enough(camera_coord.x, 10.0))
assert(close_enough(camera_coord.y, 21.45))
assert(close_enough(camera_coord.z, 2.76))
assert(close_enough(camera_target.x, 10.0))
assert(close_enough(camera_target.y, 20.0))
assert(close_enough(camera_target.z, 2.6))
assert(response_from("camera:setFacing", { front = false }).success)
assert(camera_destroyed and not scripted_camera_rendering, "rear mode must release the selfie camera")
print("Client camera tests passed")
+27 -20
View File
@@ -1,14 +1,9 @@
local disabled_control_group = nil
local enabled_controls = {}
local disabled_controls = {}
local firing_disabled = false
function DisableAllControlActions(group)
disabled_control_group = group
end
function EnableControlAction(group, control, enabled)
assert(group == 0 and enabled, "movement controls must be enabled in the primary input group")
enabled_controls[control] = true
function DisableControlAction(group, control, disabled)
assert(group == 0 and disabled, "phone controls must be disabled in the primary input group")
disabled_controls[control] = true
end
function PlayerId()
@@ -29,6 +24,7 @@ local function resolve(overrides)
call_focus = false,
camera_active = false,
camera_nui_focused = true,
cursor_disabled = false,
is_open = false,
notification_focus = false,
payphone_focus = false,
@@ -66,19 +62,30 @@ assert(
movable_phone.cursor
and movable_phone.focused
and movable_phone.keep_input
and movable_phone.movement_only,
"an open phone must keep only movement input when movement is enabled"
and movable_phone.game_input,
"an open phone must keep GTA input when movement is enabled"
)
SkyPhoneFocus.ApplyMovementOnlyControls()
assert(disabled_control_group == 0, "movement filtering must disable the primary input group")
for _, control in ipairs({ 21, 30, 31, 32, 33, 34, 35 }) do
assert(enabled_controls[control], ("movement control %d must stay enabled"):format(control))
local cursor_disabled_phone = resolve({
allow_movement = true,
cursor_disabled = true,
is_open = true,
})
assert(
not cursor_disabled_phone.cursor
and cursor_disabled_phone.focused
and cursor_disabled_phone.keep_input,
"toggling Alt must release the NUI cursor while preserving phone and GTA input"
)
SkyPhoneFocus.ApplyGameInputControls()
for _, control in ipairs({ 19, 24, 140, 141, 142, 257, 263, 264 }) do
assert(disabled_controls[control], ("phone control %d must remain disabled"):format(control))
end
assert(not enabled_controls[1] and not enabled_controls[2], "look controls must stay disabled")
assert(not enabled_controls[24] and not enabled_controls[25], "combat controls must stay disabled")
assert(not enabled_controls[22], "jump must stay disabled")
assert(firing_disabled, "player firing must remain disabled while the phone is open")
assert(not disabled_controls[1] and not disabled_controls[2], "look controls must stay enabled")
assert(not disabled_controls[21] and not disabled_controls[22], "sprint and jump must stay enabled")
assert(not disabled_controls[30] and not disabled_controls[31], "movement axes must stay enabled")
assert(firing_disabled, "player attacks must remain disabled while the phone is open")
local movable_notification = resolve({ allow_movement = true, notification_focus = true })
assert(
@@ -95,7 +102,7 @@ assert(
not camera_game_input.cursor
and camera_game_input.focused
and camera_game_input.keep_input
and not camera_game_input.movement_only,
and not camera_game_input.game_input,
"camera movement must keep keyboard focus without retaining the NUI cursor"
)