function BaseCamera.ApplyVRTransform(k)if not VRService.VREnabled then return end local A=k.humanoidRootPart and k.humanoidRootPart:FindFirstChild("\082\111\111\116\074\111\105\110\116")if not A then return end local S=game.Workspace.CurrentCamera.CameraSubject local X=S and S:IsA("\086\101\104\105\099\108\101\083\101\097\116")if k.inFirstPerson and not X then local k=VRService:GetUserCFrame(Enum.UserCFrame.Head)local S=k-k.p A.C0=CFrame.new(S:vectorToObjectSpace(k.p))*CFrame.new(0,0,0,-1,0,0,0,0,1,0,1,0)else A.C0=CFrame.new(0,0,0,-1,0,0,0,0,1,0,1,0)end end function BaseCamera.IsInFirstPerson(k)return k.inFirstPerson end function BaseCamera.ShouldUseVRRotation(k)if not VRService.VREnabled then return false end if not k.VRRotationIntensityAvailable and tick()-k.lastVRRotationIntensityCheckTime<1 then return false end local A,S=pcall(function()return StarterGui:GetCore("\086\082\082\111\116\097\116\105\111\110\073\110\116\101\110\115\105\116\121")end)k.VRRotationIntensityAvailable=A and S~=nil k.lastVRRotationIntensityCheckTime=tick()k.shouldUseVRRotation=A and(S~=nil and S~="\083\109\111\111\116\104")return k.shouldUseVRRotation end function BaseCamera.GetVRRotationInput(k)local A=ZERO_VECTOR2 local S,X=pcall(function()return StarterGui:GetCore("\086\082\082\111\116\097\116\105\111\110\073\110\116\101\110\115\105\116\121")end)if not S then return end local c=k.GamepadPanningCamera or ZERO_VECTOR2 local D=tick()-k.lastVRRotationTime>=k:GetRepeatDelayValue(X)if math.abs(c.x)>=k:GetActivateValue()then if D or not k.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]then local S=1 if c.x<0 then S=-1 end A=A+k:GetRotateAmountValue(X)*S k.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]=true end elseif math.abs(c.x)<k:GetActivateValue()-.1 then k.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]=nil end if k.turningLeft then if D or not k.vrRotateKeyCooldown[Enum.KeyCode.Left]then A=A-k:GetRotateAmountValue(X)k.vrRotateKeyCooldown[Enum.KeyCode.Left]=true end else k.vrRotateKeyCooldown[Enum.KeyCode.Left]=nil end if k.turningRight then if D or not k.vrRotateKeyCooldown[Enum.KeyCode.Right]then A=A+k:GetRotateAmountValue(X)k.vrRotateKeyCooldown[Enum.KeyCode.Right]=true end else k.vrRotateKeyCooldown[Enum.KeyCode.Right]=nil end if A~=ZERO_VECTOR2 then k.lastVRRotationTime=tick()end return A end function BaseCamera.CancelCameraFreeze(A,k)if not k then A.cameraTranslationConstraints=Vector3.new(A.cameraTranslationConstraints.x,1,A.cameraTranslationConstraints.z)end if A.cameraFrozen then A.trackingHumanoid=nil A.cameraFrozen=false end end function BaseCamera.StartCameraFreeze(S,k,A)if not S.cameraFrozen then S.humanoidJumpOrigin=k S.trackingHumanoid=A S.cameraTranslationConstraints=Vector3.new(S.cameraTranslationConstraints.x,0,S.cameraTranslationConstraints.z)S.cameraFrozen=true end end function BaseCamera.OnNewCameraSubject(k)if k.subjectStateChangedConn then k.subjectStateChangedConn:Disconnect()k.subjectStateChangedConn=nil end local A=workspace.CurrentCamera and workspace.CurrentCamera.CameraSubject if k.trackingHumanoid~=A then k:CancelCameraFreeze()end if A and A:IsA("\072\117\109\097\110\111\105\100")then k.subjectStateChangedConn=A.StateChanged:Connect(function(S,X)if VRService.VREnabled and(X==Enum.HumanoidStateType.Jumping and not k.inFirstPerson)then k:StartCameraFreeze(k:GetSubjectPosition(),A)elseif X~=Enum.HumanoidStateType.Jumping and X~=Enum.HumanoidStateType.Freefall then k:CancelCameraFreeze(true)end end)end end function BaseCamera.GetVRFocus(S,k,A)local X=S.LastCameraFocus or k if not S.cameraFrozen then S.cameraTranslationConstraints=Vector3.new(S.cameraTranslationConstraints.x,math.min(1,S.cameraTranslationConstraints.y+.42*A),S.cameraTranslationConstraints.z)end local c if S.cameraFrozen and(S.humanoidJumpOrigin and S.humanoidJumpOrigin.y>X.y)then c=CFrame.new(Vector3.new(k.x,math.min(S.humanoidJumpOrigin.y,X.y+5*A),k.z))else c=CFrame.new((Vector3.new(k.x,X.y,k.z)):lerp(k,S.cameraTranslationConstraints.y))end if S.cameraFrozen then if S.inFirstPerson then S:CancelCameraFreeze()end if S.humanoidJumpOrigin and k.y<S.humanoidJumpOrigin.y-.5 then S:CancelCameraFreeze()end end return c end function BaseCamera.GetRotateAmountValue(A,k)k=k or StarterGui:GetCore("\086\082\082\111\116\097\116\105\111\110\073\110\116\101\110\115\105\116\121")if k then if k=="\076\111\119"then return VR_LOW_INTENSITY_ROTATION elseif k=="\072\105\103\104"then return VR_HIGH_INTENSITY_ROTATION end end return ZERO_VECTOR2 end function BaseCamera.GetRepeatDelayValue(A,k)k=k or StarterGui:GetCore("\086\082\082\111\116\097\116\105\111\110\073\110\116\101\110\115\105\116\121")if k then if k=="\076\111\119"then return VR_LOW_INTENSITY_REPEAT elseif k=="\072\105\103\104"then return VR_HIGH_INTENSITY_REPEAT end end return 0 end function BaseCamera.Update(A,k)error("\066\097\115\101\067\097\109\101\114\097\058\085\112\100\097\116\101\040\041 \084\104\105\115 \105\115 \097 \118\105\114\116\117\097\108 \102\117\110\099\116\105\111\110 \116\104\097\116 \115\104\111\117\108\100 \110\101\118\101\114 \098\101 \103\101\116\116\105\110\103 \099\097\108\108\101\100\046",2)end return BaseCamera


function BaseCamera:ApplyVRTransform()
	if not VRService.VREnabled then
		return
	end

	--we only want this to happen in first person VR
	local rootJoint = self.humanoidRootPart and self.humanoidRootPart:FindFirstChild("RootJoint")
	if not rootJoint then
		return
	end

	local cameraSubject = game.Workspace.CurrentCamera.CameraSubject
	local isInVehicle = cameraSubject and cameraSubject:IsA("VehicleSeat")

	if self.inFirstPerson and not isInVehicle then
		local vrFrame = VRService:GetUserCFrame(Enum.UserCFrame.Head)
		local vrRotation = vrFrame - vrFrame.p
		rootJoint.C0 = CFrame.new(vrRotation:vectorToObjectSpace(vrFrame.p)) * CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
	else
		rootJoint.C0 = CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
	end
end

function BaseCamera:IsInFirstPerson()
	return self.inFirstPerson
end

function BaseCamera:ShouldUseVRRotation()
	if not VRService.VREnabled then
		return false
	end

	if not self.VRRotationIntensityAvailable and tick() - self.lastVRRotationIntensityCheckTime < 1 then
		return false
	end

	local success, vrRotationIntensity = pcall(function() return StarterGui:GetCore("VRRotationIntensity") end)
	self.VRRotationIntensityAvailable = success and vrRotationIntensity ~= nil
	self.lastVRRotationIntensityCheckTime = tick()

	self.shouldUseVRRotation = success and vrRotationIntensity ~= nil and vrRotationIntensity ~= "Smooth"

	return self.shouldUseVRRotation
end

function BaseCamera:GetVRRotationInput()
	local vrRotateSum = ZERO_VECTOR2
	local success, vrRotationIntensity = pcall(function() return StarterGui:GetCore("VRRotationIntensity") end)

	if not success then
		return
	end

	local vrGamepadRotation = self.GamepadPanningCamera or ZERO_VECTOR2
	local delayExpired = (tick() - self.lastVRRotationTime) >= self:GetRepeatDelayValue(vrRotationIntensity)

	if math.abs(vrGamepadRotation.x) >= self:GetActivateValue() then
		if (delayExpired or not self.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]) then
			local sign = 1
			if vrGamepadRotation.x < 0 then
				sign = -1
			end
			vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity) * sign
			self.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = true
		end
	elseif math.abs(vrGamepadRotation.x) < self:GetActivateValue() - 0.1 then
		self.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = nil
	end
	if self.turningLeft then
		if delayExpired or not self.vrRotateKeyCooldown[Enum.KeyCode.Left] then
			vrRotateSum = vrRotateSum - self:GetRotateAmountValue(vrRotationIntensity)
			self.vrRotateKeyCooldown[Enum.KeyCode.Left] = true
		end
	else
		self.vrRotateKeyCooldown[Enum.KeyCode.Left] = nil
	end
	if self.turningRight then
		if (delayExpired or not self.vrRotateKeyCooldown[Enum.KeyCode.Right]) then
			vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity)
			self.vrRotateKeyCooldown[Enum.KeyCode.Right] = true
		end
	else
		self.vrRotateKeyCooldown[Enum.KeyCode.Right] = nil
	end

	if vrRotateSum ~= ZERO_VECTOR2 then
		self.lastVRRotationTime = tick()
	end

	return vrRotateSum
end

function BaseCamera:CancelCameraFreeze(keepConstraints)
	if not keepConstraints then
		self.cameraTranslationConstraints = Vector3.new(self.cameraTranslationConstraints.x, 1, self.cameraTranslationConstraints.z)
	end
	if self.cameraFrozen then
		self.trackingHumanoid = nil
		self.cameraFrozen = false
	end
end

function BaseCamera:StartCameraFreeze(subjectPosition, humanoidToTrack)
	if not self.cameraFrozen then
		self.humanoidJumpOrigin = subjectPosition
		self.trackingHumanoid = humanoidToTrack
		self.cameraTranslationConstraints = Vector3.new(self.cameraTranslationConstraints.x, 0, self.cameraTranslationConstraints.z)
		self.cameraFrozen = true
	end
end

function BaseCamera:OnNewCameraSubject()
	if self.subjectStateChangedConn then
		self.subjectStateChangedConn:Disconnect()
		self.subjectStateChangedConn = nil
	end

	local humanoid = workspace.CurrentCamera and workspace.CurrentCamera.CameraSubject
	if self.trackingHumanoid ~= humanoid then
		self:CancelCameraFreeze()
	end
	if humanoid and humanoid:IsA("Humanoid") then
		self.subjectStateChangedConn = humanoid.StateChanged:Connect(function(oldState, newState)
			if VRService.VREnabled and newState == Enum.HumanoidStateType.Jumping and not self.inFirstPerson then
				self:StartCameraFreeze(self:GetSubjectPosition(), humanoid)
			elseif newState ~= Enum.HumanoidStateType.Jumping and newState ~= Enum.HumanoidStateType.Freefall then
				self:CancelCameraFreeze(true)
			end
		end)
	end
end

function BaseCamera:GetVRFocus(subjectPosition, timeDelta)
	local lastFocus = self.LastCameraFocus or subjectPosition
	if not self.cameraFrozen then
		self.cameraTranslationConstraints = Vector3.new(self.cameraTranslationConstraints.x, math.min(1, self.cameraTranslationConstraints.y + 0.42 * timeDelta), self.cameraTranslationConstraints.z)
	end

	local newFocus
	if self.cameraFrozen and self.humanoidJumpOrigin and self.humanoidJumpOrigin.y > lastFocus.y then
		newFocus = CFrame.new(Vector3.new(subjectPosition.x, math.min(self.humanoidJumpOrigin.y, lastFocus.y + 5 * timeDelta), subjectPosition.z))
	else
		newFocus = CFrame.new(Vector3.new(subjectPosition.x, lastFocus.y, subjectPosition.z):lerp(subjectPosition, self.cameraTranslationConstraints.y))
	end

	if self.cameraFrozen then
		-- No longer in 3rd person
		if self.inFirstPerson then -- not VRService.VREnabled
			self:CancelCameraFreeze()
		end
		-- This case you jumped off a cliff and want to keep your character in view
		-- 0.5 is to fix floating point error when not jumping off cliffs
		if self.humanoidJumpOrigin and subjectPosition.y < (self.humanoidJumpOrigin.y - 0.5) then
			self:CancelCameraFreeze()
		end
	end

	return newFocus
end

function BaseCamera:GetRotateAmountValue(vrRotationIntensity)
	vrRotationIntensity = vrRotationIntensity or StarterGui:GetCore("VRRotationIntensity")
	if vrRotationIntensity then
		if vrRotationIntensity == "Low" then
			return VR_LOW_INTENSITY_ROTATION
		elseif vrRotationIntensity == "High" then
			return VR_HIGH_INTENSITY_ROTATION
		end
	end
	return ZERO_VECTOR2
end

function BaseCamera:GetRepeatDelayValue(vrRotationIntensity)
	vrRotationIntensity = vrRotationIntensity or StarterGui:GetCore("VRRotationIntensity")
	if vrRotationIntensity then
		if vrRotationIntensity == "Low" then
			return VR_LOW_INTENSITY_REPEAT
		elseif vrRotationIntensity == "High" then
			return VR_HIGH_INTENSITY_REPEAT
		end
	end
	return 0
end

function BaseCamera:Update(dt)
	error("BaseCamera:Update() This is a virtual function that should never be getting called.", 2)
end

return BaseCamera
