function ClassicCamera.SetCameraMovementMode(n,G)BaseCamera.SetCameraMovementMode(n,G)n.isFollowCamera=G==Enum.ComputerCameraMovementMode.Follow n.isCameraToggle=G==Enum.ComputerCameraMovementMode.CameraToggle end function ClassicCamera.Update(G)local n=tick()local Q=n-G.lastUpdate local H=workspace.CurrentCamera local g=H.CFrame local x=H.Focus local m=nil if G.resetCameraAngle then local n=G:GetHumanoidRootPart()if n then m=(n.CFrame*INITIAL_CAMERA_ANGLE).lookVector else m=INITIAL_CAMERA_ANGLE.lookVector end G.resetCameraAngle=false end local T=PlayersService.LocalPlayer local V=G:GetHumanoid()local p=H.CameraSubject local R=p and p:IsA("\086\101\104\105\099\108\101\083\101\097\116")local X=p and p:IsA("\083\107\097\116\101\098\111\097\114\100\080\108\097\116\102\111\114\109")local w=V and V:GetState()==Enum.HumanoidStateType.Climbing if G.lastUpdate==nil or Q>1 then G.lastCameraTransform=nil end if G.lastUpdate then local n=G:UpdateGamepad()if G:ShouldUseVRRotation()then G.rotateInput=G.rotateInput+G:GetVRRotationInput()else local H=math.min(.1,Q)if n~=ZERO_VECTOR2 then G.rotateInput=G.rotateInput+n*H end local g=0 if not(R or X)then g=g+(G.turningLeft and-120 or 0)g=g+(G.turningRight and 120 or 0)end if g~=0 then G.rotateInput=G.rotateInput+Vector2.new(math.rad(g*H),0)end end end local z=G:GetCameraHeight()if G.userPanningTheCamera then tweenSpeed=0 G.lastUserPanCamera=tick()end local b=n-G.lastUserPanCamera<TIME_BEFORE_AUTO_ROTATE local A=G:GetSubjectPosition()if A and(T and H)then local n=G:GetCameraToSubjectDistance()if n<.5 then n=.5 end if G:GetIsMouseLocked()and not G:IsInFirstPerson()then local n=G:CalculateNewLookCFrame(m)local Q=G:GetMouseLockOffset()local H=(Q.X*n.rightVector+Q.Y*n.upVector)+Q.Z*n.lookVector if Util.IsFiniteVector3(H)then A=A+H end else if not G.userPanningTheCamera and G.lastCameraTransform then local n=G:IsInFirstPerson()if(R or X or G.isFollowCamera and w)and(G.lastUpdate and(V and V.Torso))then if n then if G.lastSubjectCFrame and((R or X)and p:IsA("\066\097\115\101\080\097\114\116"))then local n=-Util.GetAngleBetweenXZVectors(G.lastSubjectCFrame.lookVector,p.CFrame.lookVector)if Util.IsFinite(n)then G.rotateInput=G.rotateInput+Vector2.new(n,0)end tweenSpeed=0 end elseif not b then local n=V.Torso.CFrame.lookVector if X then n=p.CFrame.lookVector end tweenSpeed=math.clamp(tweenSpeed+tweenAcceleration*Q,0,tweenMaxSpeed)local H=math.clamp(tweenSpeed*Q,0,1)if G:IsInFirstPerson()and not(G.isFollowCamera and G.isClimbing)then H=1 end local g=Util.GetAngleBetweenXZVectors(n,G:GetCameraLookVector())if Util.IsFinite(g)and math.abs(g)>.0001 then G.rotateInput=G.rotateInput+Vector2.new(g*H,0)end end elseif G.isFollowCamera and(not(n or b)and not VRService.VREnabled)then local n=-(G.lastCameraTransform.p-A)local H=Util.GetAngleBetweenXZVectors(n,G:GetCameraLookVector())local g=.4 if Util.IsFinite(H)and(math.abs(H)>.0001 and math.abs(H)>g*Q)then G.rotateInput=G.rotateInput+Vector2.new(H,0)end end end end if not G.isFollowCamera then local T=VRService.VREnabled if T then x=G:GetVRFocus(A,Q)else x=CFrame.new(A)end local V=x.p if T and not G:IsInFirstPerson()then local Q=A-H.CFrame.p local x=Q.magnitude if x>n or G.rotateInput.x~=0 then local m=math.min(x,n)Q=G:CalculateNewLookVectorVR()*m local T=V-Q local p=H.CFrame.lookVector if G.rotateInput.x~=0 then p=Q end local R=Vector3.new(T.x+p.x,T.y,T.z+p.z)G.rotateInput=ZERO_VECTOR2 g=CFrame.new(T,R)+Vector3.new(0,z,0)end else local Q=G:CalculateNewLookVector(m)G.rotateInput=ZERO_VECTOR2 g=CFrame.new(V-n*Q,V)end else local H=G:CalculateNewLookVector(m)G.rotateInput=ZERO_VECTOR2 if VRService.VREnabled then x=G:GetVRFocus(A,Q)else x=CFrame.new(A)end g=CFrame.new(x.p-n*H,x.p)+Vector3.new(0,z,0)end if FFlagUserCameraToggle then local n=G:GetCameraToggleOffset(Q)x=x+n g=g+n end G.lastCameraTransform=g G.lastCameraFocus=x if(R or X)and p:IsA("\066\097\115\101\080\097\114\116")then G.lastSubjectCFrame=p.CFrame else G.lastSubjectCFrame=nil end end G.lastUpdate=n return g,x end function ClassicCamera.EnterFirstPerson(G)G.inFirstPerson=true G:UpdateMouseBehavior()end function ClassicCamera.LeaveFirstPerson(G)G.inFirstPerson=false G:UpdateMouseBehavior()end return ClassicCamera
-- Movement mode standardized to Enum.ComputerCameraMovementMode values
function ClassicCamera:SetCameraMovementMode(cameraMovementMode)
	BaseCamera.SetCameraMovementMode(self, cameraMovementMode)

	self.isFollowCamera = cameraMovementMode == Enum.ComputerCameraMovementMode.Follow
	self.isCameraToggle = cameraMovementMode == Enum.ComputerCameraMovementMode.CameraToggle
end

function ClassicCamera:Update()
	local now = tick()
	local timeDelta = now - self.lastUpdate

	local camera = workspace.CurrentCamera
	local newCameraCFrame = camera.CFrame
	local newCameraFocus = camera.Focus

	local overrideCameraLookVector = nil
	if self.resetCameraAngle then
		local rootPart = self:GetHumanoidRootPart()
		if rootPart then
			overrideCameraLookVector = (rootPart.CFrame * INITIAL_CAMERA_ANGLE).lookVector
		else
			overrideCameraLookVector = INITIAL_CAMERA_ANGLE.lookVector
		end
		self.resetCameraAngle = false
	end

	local player = PlayersService.LocalPlayer
	local humanoid = self:GetHumanoid()
	local cameraSubject = camera.CameraSubject
	local isInVehicle = cameraSubject and cameraSubject:IsA("VehicleSeat")
	local isOnASkateboard = cameraSubject and cameraSubject:IsA("SkateboardPlatform")
	local isClimbing = humanoid and humanoid:GetState() == Enum.HumanoidStateType.Climbing

	if self.lastUpdate == nil or timeDelta > 1 then
		self.lastCameraTransform = nil
	end

	if self.lastUpdate then
		local gamepadRotation = self:UpdateGamepad()

		if self:ShouldUseVRRotation() then
			self.rotateInput = self.rotateInput + self:GetVRRotationInput()
		else
			-- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from
			local delta = math.min(0.1, timeDelta)

			if gamepadRotation ~= ZERO_VECTOR2 then
				self.rotateInput = self.rotateInput + (gamepadRotation * delta)
			end

			local angle = 0
			if not (isInVehicle or isOnASkateboard) then
				angle = angle + (self.turningLeft and -120 or 0)
				angle = angle + (self.turningRight and 120 or 0)
			end

			if angle ~= 0 then
				self.rotateInput = self.rotateInput + Vector2.new(math.rad(angle * delta), 0)
			end
		end
	end

	local cameraHeight = self:GetCameraHeight()

	-- Reset tween speed if user is panning
	if self.userPanningTheCamera then
		tweenSpeed = 0
		self.lastUserPanCamera = tick()
	end

	local userRecentlyPannedCamera = now - self.lastUserPanCamera < TIME_BEFORE_AUTO_ROTATE
	local subjectPosition = self:GetSubjectPosition()

	if subjectPosition and player and camera then
		local zoom = self:GetCameraToSubjectDistance()
		if zoom < 0.5 then
			zoom = 0.5
		end

		if self:GetIsMouseLocked() and not self:IsInFirstPerson() then
			-- We need to use the right vector of the camera after rotation, not before
			local newLookCFrame = self:CalculateNewLookCFrame(overrideCameraLookVector)

			local offset = self:GetMouseLockOffset()
			local cameraRelativeOffset = offset.X * newLookCFrame.rightVector
				+ offset.Y * newLookCFrame.upVector
				+ offset.Z * newLookCFrame.lookVector

			--offset can be NAN, NAN, NAN if newLookVector has only y component
			if Util.IsFiniteVector3(cameraRelativeOffset) then
				subjectPosition = subjectPosition + cameraRelativeOffset
			end
		else
			if not self.userPanningTheCamera and self.lastCameraTransform then
				local isInFirstPerson = self:IsInFirstPerson()

				if
					(isInVehicle or isOnASkateboard or (self.isFollowCamera and isClimbing))
					and self.lastUpdate
					and humanoid
					and humanoid.Torso
				then
					if isInFirstPerson then
						if
							self.lastSubjectCFrame
							and (isInVehicle or isOnASkateboard)
							and cameraSubject:IsA("BasePart")
						then
							local y = -Util.GetAngleBetweenXZVectors(
								self.lastSubjectCFrame.lookVector,
								cameraSubject.CFrame.lookVector
							)
							if Util.IsFinite(y) then
								self.rotateInput = self.rotateInput + Vector2.new(y, 0)
							end
							tweenSpeed = 0
						end
					elseif not userRecentlyPannedCamera then
						local forwardVector = humanoid.Torso.CFrame.lookVector
						if isOnASkateboard then
							forwardVector = cameraSubject.CFrame.lookVector
						end

						tweenSpeed = math.clamp(tweenSpeed + tweenAcceleration * timeDelta, 0, tweenMaxSpeed)

						local percent = math.clamp(tweenSpeed * timeDelta, 0, 1)
						if self:IsInFirstPerson() and not (self.isFollowCamera and self.isClimbing) then
							percent = 1
						end

						local y = Util.GetAngleBetweenXZVectors(forwardVector, self:GetCameraLookVector())
						if Util.IsFinite(y) and math.abs(y) > 0.0001 then
							self.rotateInput = self.rotateInput + Vector2.new(y * percent, 0)
						end
					end
				elseif
					self.isFollowCamera
					and (not (isInFirstPerson or userRecentlyPannedCamera) and not VRService.VREnabled)
				then
					-- Logic that was unique to the old FollowCamera module
					local lastVec = -(self.lastCameraTransform.p - subjectPosition)

					local y = Util.GetAngleBetweenXZVectors(lastVec, self:GetCameraLookVector())

					-- This cutoff is to decide if the humanoid's angle of movement,
					-- relative to the camera's look vector, is enough that
					-- we want the camera to be following them. The point is to provide
					-- a sizable dead zone to allow more precise forward movements.
					local thetaCutoff = 0.4

					-- Check for NaNs
					if Util.IsFinite(y) and math.abs(y) > 0.0001 and math.abs(y) > thetaCutoff * timeDelta then
						self.rotateInput = self.rotateInput + Vector2.new(y, 0)
					end
				end
			end
		end

		if not self.isFollowCamera then
			local VREnabled = VRService.VREnabled

			if VREnabled then
				newCameraFocus = self:GetVRFocus(subjectPosition, timeDelta)
			else
				newCameraFocus = CFrame.new(subjectPosition)
			end

			local cameraFocusP = newCameraFocus.p
			if VREnabled and not self:IsInFirstPerson() then
				local vecToSubject = (subjectPosition - camera.CFrame.p)
				local distToSubject = vecToSubject.magnitude

				-- Only move the camera if it exceeded a maximum distance to the subject in VR
				if distToSubject > zoom or self.rotateInput.x ~= 0 then
					local desiredDist = math.min(distToSubject, zoom)
					vecToSubject = self:CalculateNewLookVectorVR() * desiredDist
					local newPos = cameraFocusP - vecToSubject
					local desiredLookDir = camera.CFrame.lookVector
					if self.rotateInput.x ~= 0 then
						desiredLookDir = vecToSubject
					end
					local lookAt = Vector3.new(newPos.x + desiredLookDir.x, newPos.y, newPos.z + desiredLookDir.z)
					self.rotateInput = ZERO_VECTOR2

					newCameraCFrame = CFrame.new(newPos, lookAt) + Vector3.new(0, cameraHeight, 0)
				end
			else
				local newLookVector = self:CalculateNewLookVector(overrideCameraLookVector)
				self.rotateInput = ZERO_VECTOR2
				newCameraCFrame = CFrame.new(cameraFocusP - (zoom * newLookVector), cameraFocusP)
			end
		else -- is FollowCamera
			local newLookVector = self:CalculateNewLookVector(overrideCameraLookVector)
			self.rotateInput = ZERO_VECTOR2

			if VRService.VREnabled then
				newCameraFocus = self:GetVRFocus(subjectPosition, timeDelta)
			else
				newCameraFocus = CFrame.new(subjectPosition)
			end
			newCameraCFrame = CFrame.new(newCameraFocus.p - (zoom * newLookVector), newCameraFocus.p)
				+ Vector3.new(0, cameraHeight, 0)
		end

		if FFlagUserCameraToggle then
			local toggleOffset = self:GetCameraToggleOffset(timeDelta)
			newCameraFocus = newCameraFocus + toggleOffset
			newCameraCFrame = newCameraCFrame + toggleOffset
		end

		self.lastCameraTransform = newCameraCFrame
		self.lastCameraFocus = newCameraFocus
		if (isInVehicle or isOnASkateboard) and cameraSubject:IsA("BasePart") then
			self.lastSubjectCFrame = cameraSubject.CFrame
		else
			self.lastSubjectCFrame = nil
		end
	end

	self.lastUpdate = now
	return newCameraCFrame, newCameraFocus
end

function ClassicCamera:EnterFirstPerson()
	self.inFirstPerson = true
	self:UpdateMouseBehavior()
end

function ClassicCamera:LeaveFirstPerson()
	self.inFirstPerson = false
	self:UpdateMouseBehavior()
end

return ClassicCamera
