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

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:Test()
	print("BaseCamera:Test()")
end

function BaseCamera:Update(dt)
	warn("BaseCamera:Update() This is a virtual function that should never be getting called.")
	return game.Workspace.CurrentCamera.CFrame, game.Workspace.CurrentCamera.Focus
end

return BaseCamera
