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 camera_destroyed = false 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.05)) assert(close_enough(camera_coord.z, 2.75)) assert(close_enough(camera_target.x, 10.0)) assert(close_enough(camera_target.y, 20.0)) assert(close_enough(camera_target.z, 2.73)) assert(response_from("camera:setFacing", { front = false }).success) assert(camera_destroyed and not scripted_camera_rendering, "rear mode must release the selfie camera") assert(type(SkyPhoneCamera.EnableWalkable) == "function", "walkable camera enable seam must exist") assert(type(SkyPhoneCamera.DisableWalkable) == "function", "walkable camera disable seam must exist") assert(type(SkyPhoneCamera.SetSelfie) == "function", "selfie camera seam must exist") assert(type(SkyPhoneCamera.ToggleFrozen) == "function", "frozen camera seam must exist") assert(type(SkyPhoneCamera.SetFlashlight) == "function", "flashlight seam must exist") assert(type(SkyPhoneCamera.GetState) == "function", "camera state seam must exist") SkyPhoneCamera.SetFlashlight(true) assert(SkyPhoneCamera.GetState().flashEnabled, "flashlight state must report enabled") SkyPhoneCamera.SetFlashlight(false) assert(not SkyPhoneCamera.GetState().flashEnabled, "flashlight state must report disabled") SkyPhoneCamera.EnableWalkable(true) local walkable_state = SkyPhoneCamera.GetState() assert(walkable_state.walkable, "walkable camera must report enabled") assert(walkable_state.selfie, "walkable camera must preserve selfie mode") assert(walkable_state.active, "walkable camera must open the camera") SkyPhoneCamera.SetSelfie(false) assert(not SkyPhoneCamera.GetState().selfie, "selfie camera must switch back to rear mode") SkyPhoneCamera.ToggleFrozen() SkyPhoneCamera.DisableWalkable() local closed_state = SkyPhoneCamera.GetState() assert(not closed_state.walkable, "walkable camera must report disabled") assert(not closed_state.active, "walkable camera disable must close the camera") print("Client camera tests passed")