function BaseCamera.ApplyVRTransform(t)if not VRService.VREnabled then return end local N=t.humanoidRootPart and t.humanoidRootPart:FindFirstChild("\082\111\111\116\074\111\105\110\116")if not N then return end local M=game.Workspace.CurrentCamera.CameraSubject local p=M and M:IsA("\086\101\104\105\099\108\101\083\101\097\116")if t.inFirstPerson and not p then local t=VRService:GetUserCFrame(Enum.UserCFrame.Head)local M=t-t.p N.C0=CFrame.new(M:vectorToObjectSpace(t.p))*CFrame.new(0,0,0,-1,0,0,0,0,1,0,1,0)else N.C0=CFrame.new(0,0,0,-1,0,0,0,0,1,0,1,0)end end function BaseCamera.IsInFirstPerson(t)return t.inFirstPerson end function BaseCamera.ShouldUseVRRotation(t)if not VRService.VREnabled then return false end if not t.VRRotationIntensityAvailable and tick()-t.lastVRRotationIntensityCheckTime<1 then return false end local N,M=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)t.VRRotationIntensityAvailable=N and M~=nil t.lastVRRotationIntensityCheckTime=tick()t.shouldUseVRRotation=N and(M~=nil and M~="\083\109\111\111\116\104")return t.shouldUseVRRotation end function BaseCamera.GetVRRotationInput(t)local N=ZERO_VECTOR2 local M,p=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 M then return end local L=t.GamepadPanningCamera or ZERO_VECTOR2 local f=tick()-t.lastVRRotationTime>=t:GetRepeatDelayValue(p)if math.abs(L.x)>=t:GetActivateValue()then if f or not t.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]then local M=1 if L.x<0 then M=-1 end N=N+t:GetRotateAmountValue(p)*M t.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]=true end elseif math.abs(L.x)<t:GetActivateValue()-.1 then t.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]=nil end if t.turningLeft then if f or not t.vrRotateKeyCooldown[Enum.KeyCode.Left]then N=N-t:GetRotateAmountValue(p)t.vrRotateKeyCooldown[Enum.KeyCode.Left]=true end else t.vrRotateKeyCooldown[Enum.KeyCode.Left]=nil end if t.turningRight then if f or not t.vrRotateKeyCooldown[Enum.KeyCode.Right]then N=N+t:GetRotateAmountValue(p)t.vrRotateKeyCooldown[Enum.KeyCode.Right]=true end else t.vrRotateKeyCooldown[Enum.KeyCode.Right]=nil end if N~=ZERO_VECTOR2 then t.lastVRRotationTime=tick()end return N end function BaseCamera.CancelCameraFreeze(N,t)if not t then N.cameraTranslationConstraints=Vector3.new(N.cameraTranslationConstraints.x,1,N.cameraTranslationConstraints.z)end if N.cameraFrozen then N.trackingHumanoid=nil N.cameraFrozen=false end end function BaseCamera.StartCameraFreeze(M,t,N)if not M.cameraFrozen then M.humanoidJumpOrigin=t M.trackingHumanoid=N M.cameraTranslationConstraints=Vector3.new(M.cameraTranslationConstraints.x,0,M.cameraTranslationConstraints.z)M.cameraFrozen=true end end function BaseCamera.OnNewCameraSubject(t)if t.subjectStateChangedConn then t.subjectStateChangedConn:Disconnect()t.subjectStateChangedConn=nil end local N=workspace.CurrentCamera and workspace.CurrentCamera.CameraSubject if t.trackingHumanoid~=N then t:CancelCameraFreeze()end if N and N:IsA("\072\117\109\097\110\111\105\100")then t.subjectStateChangedConn=N.StateChanged:Connect(function(M,p)if VRService.VREnabled and(p==Enum.HumanoidStateType.Jumping and not t.inFirstPerson)then t:StartCameraFreeze(t:GetSubjectPosition(),N)elseif p~=Enum.HumanoidStateType.Jumping and p~=Enum.HumanoidStateType.Freefall then t:CancelCameraFreeze(true)end end)end end function BaseCamera.GetVRFocus(M,t,N)local p=M.LastCameraFocus or t if not M.cameraFrozen then M.cameraTranslationConstraints=Vector3.new(M.cameraTranslationConstraints.x,math.min(1,M.cameraTranslationConstraints.y+.42*N),M.cameraTranslationConstraints.z)end local L if M.cameraFrozen and(M.humanoidJumpOrigin and M.humanoidJumpOrigin.y>p.y)then L=CFrame.new(Vector3.new(t.x,math.min(M.humanoidJumpOrigin.y,p.y+5*N),t.z))else L=CFrame.new((Vector3.new(t.x,p.y,t.z)):lerp(t,M.cameraTranslationConstraints.y))end if M.cameraFrozen then if M.inFirstPerson then M:CancelCameraFreeze()end if M.humanoidJumpOrigin and t.y<M.humanoidJumpOrigin.y-.5 then M:CancelCameraFreeze()end end return L end function BaseCamera.GetRotateAmountValue(N,t)t=t or StarterGui:GetCore("\086\082\082\111\116\097\116\105\111\110\073\110\116\101\110\115\105\116\121")if t then if t=="\076\111\119"then return VR_LOW_INTENSITY_ROTATION elseif t=="\072\105\103\104"then return VR_HIGH_INTENSITY_ROTATION end end return ZERO_VECTOR2 end function BaseCamera.GetRepeatDelayValue(N,t)t=t or StarterGui:GetCore("\086\082\082\111\116\097\116\105\111\110\073\110\116\101\110\115\105\116\121")if t then if t=="\076\111\119"then return VR_LOW_INTENSITY_REPEAT elseif t=="\072\105\103\104"then return VR_HIGH_INTENSITY_REPEAT end end return 0 end function BaseCamera.Update(N,t)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
-- [[ 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:Update(dt)
	error("BaseCamera:Update() This is a virtual function that should never be getting called.", 2)
end

return BaseCamera
