function BaseCamera.OnCurrentCameraChanged(Y)if UserInputService.TouchEnabled then if Y.viewportSizeChangedConn then Y.viewportSizeChangedConn:Disconnect()Y.viewportSizeChangedConn=nil end local s=game.Workspace.CurrentCamera if s then Y:OnViewportSizeChanged()Y.viewportSizeChangedConn=(s:GetPropertyChangedSignal("\086\105\101\119\112\111\114\116\083\105\122\101")):Connect(function()Y:OnViewportSizeChanged()end)end end if Y.cameraSubjectChangedConn then Y.cameraSubjectChangedConn:Disconnect()Y.cameraSubjectChangedConn=nil end local s=game.Workspace.CurrentCamera if s then Y.cameraSubjectChangedConn=(s:GetPropertyChangedSignal("\067\097\109\101\114\097\083\117\098\106\101\099\116")):Connect(function()Y:OnNewCameraSubject()end)Y:OnNewCameraSubject()end end function BaseCamera.OnDynamicThumbstickEnabled(Y)if UserInputService.TouchEnabled then Y.isDynamicThumbstickEnabled=true end end function BaseCamera.OnDynamicThumbstickDisabled(Y)Y.isDynamicThumbstickEnabled=false end function BaseCamera.OnGameSettingsTouchMovementModeChanged(Y)if player.DevTouchMovementMode==Enum.DevTouchMovementMode.UserChoice then if UserGameSettings.TouchMovementMode==Enum.TouchMovementMode.DynamicThumbstick or UserGameSettings.TouchMovementMode==Enum.TouchMovementMode.Default then Y:OnDynamicThumbstickEnabled()else Y:OnDynamicThumbstickDisabled()end end end function BaseCamera.OnDevTouchMovementModeChanged(Y)if player.DevTouchMovementMode==Enum.DevTouchMovementMode.DynamicThumbstick then Y:OnDynamicThumbstickEnabled()else Y:OnGameSettingsTouchMovementModeChanged()end end function BaseCamera.OnPlayerCameraPropertyChange(Y)Y:SetCameraToSubjectDistance(Y.currentSubjectDistance)end function BaseCamera.GetCameraHeight(Y)if VRService.VREnabled and not Y.inFirstPerson then return math.sin(VR_ANGLE)*Y.currentSubjectDistance end return 0 end function BaseCamera.InputTranslationToCameraAngleChange(G,Y,s)return Y*s end function BaseCamera.GamepadZoomPress(Y)local s=Y:GetCameraToSubjectDistance()if s>(GAMEPAD_ZOOM_STEP_2+GAMEPAD_ZOOM_STEP_3)/2 then Y:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_2)elseif s>(GAMEPAD_ZOOM_STEP_1+GAMEPAD_ZOOM_STEP_2)/2 then Y:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_1)else Y:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_3)end end function BaseCamera.Enable(s,Y)if s.enabled~=Y then s.enabled=Y if s.enabled then CameraInput.setInputEnabled(true)s.gamepadZoomPressConnection=CameraInput.gamepadZoomPress:Connect(function()s:GamepadZoomPress()end)if player.CameraMode==Enum.CameraMode.LockFirstPerson then s.currentSubjectDistance=.5 if not s.inFirstPerson then s:EnterFirstPerson()end end else CameraInput.setInputEnabled(false)if s.gamepadZoomPressConnection then s.gamepadZoomPressConnection:Disconnect()s.gamepadZoomPressConnection=nil end s:Cleanup()end end end function BaseCamera.GetEnabled(Y)return Y.enabled end function BaseCamera.Cleanup(Y)if Y.subjectStateChangedConn then Y.subjectStateChangedConn:Disconnect()Y.subjectStateChangedConn=nil end if Y.viewportSizeChangedConn then Y.viewportSizeChangedConn:Disconnect()Y.viewportSizeChangedConn=nil end Y.lastCameraTransform=nil Y.lastSubjectCFrame=nil if UserInputService.MouseBehavior~=Enum.MouseBehavior.LockCenter then UserInputService.MouseBehavior=Enum.MouseBehavior.Default end end function BaseCamera.UpdateMouseBehavior(Y)if Y.isCameraToggle then CameraUI.setCameraModeToastEnabled(true)CameraInput.enableCameraToggleInput()CameraToggleStateController(Y.inFirstPerson)else CameraUI.setCameraModeToastEnabled(false)CameraInput.disableCameraToggleInput()if Y.inFirstPerson or Y.inMouseLockedMode then UserGameSettings.RotationType=Enum.RotationType.MovementRelative UserInputService.MouseBehavior=Enum.MouseBehavior.LockCenter else UserGameSettings.RotationType=Enum.RotationType.MovementRelative UserInputService.MouseBehavior=Enum.MouseBehavior.Default end end end function BaseCamera.UpdateForDistancePropertyChange(Y)Y:SetCameraToSubjectDistance(Y.currentSubjectDistance)end function BaseCamera.SetCameraToSubjectDistance(s,Y)local G=s.currentSubjectDistance if player.CameraMode==Enum.CameraMode.LockFirstPerson then s.currentSubjectDistance=.5 if not s.inFirstPerson then s:EnterFirstPerson()end else local G=math.clamp(Y,player.CameraMinZoomDistance,player.CameraMaxZoomDistance)if G<FIRST_PERSON_DISTANCE_THRESHOLD then s.currentSubjectDistance=.5 if not s.inFirstPerson then s:EnterFirstPerson()end else s.currentSubjectDistance=G if s.inFirstPerson then s:LeaveFirstPerson()end end end ZoomController.SetZoomParameters(s.currentSubjectDistance,math.sign(Y-G))return s.currentSubjectDistance end function BaseCamera.SetCameraType(s,Y)s.cameraType=Y end function BaseCamera.GetCameraType(Y)return Y.cameraType end

function BaseCamera:OnCurrentCameraChanged()
	if UserInputService.TouchEnabled then
		if self.viewportSizeChangedConn then
			self.viewportSizeChangedConn:Disconnect()
			self.viewportSizeChangedConn = nil
		end

		local newCamera = game.Workspace.CurrentCamera

		if newCamera then
			self:OnViewportSizeChanged()
			self.viewportSizeChangedConn = newCamera:GetPropertyChangedSignal("ViewportSize"):Connect(function()
				self:OnViewportSizeChanged()
			end)
		end
	end

	-- VR support additions
	if self.cameraSubjectChangedConn then
		self.cameraSubjectChangedConn:Disconnect()
		self.cameraSubjectChangedConn = nil
	end

	local camera = game.Workspace.CurrentCamera
	if camera then
		self.cameraSubjectChangedConn = camera:GetPropertyChangedSignal("CameraSubject"):Connect(function()
			self:OnNewCameraSubject()
		end)
		self:OnNewCameraSubject()
	end
end

function BaseCamera:OnDynamicThumbstickEnabled()
	if UserInputService.TouchEnabled then
		self.isDynamicThumbstickEnabled = true
	end
end

function BaseCamera:OnDynamicThumbstickDisabled()
	self.isDynamicThumbstickEnabled = false
end

function BaseCamera:OnGameSettingsTouchMovementModeChanged()
	if player.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice then
		if (UserGameSettings.TouchMovementMode == Enum.TouchMovementMode.DynamicThumbstick
			or UserGameSettings.TouchMovementMode == Enum.TouchMovementMode.Default) then
			self:OnDynamicThumbstickEnabled()
		else
			self:OnDynamicThumbstickDisabled()
		end
	end
end

function BaseCamera:OnDevTouchMovementModeChanged()
	if player.DevTouchMovementMode == Enum.DevTouchMovementMode.DynamicThumbstick then
		self:OnDynamicThumbstickEnabled()
	else
		self:OnGameSettingsTouchMovementModeChanged()
	end
end

function BaseCamera:OnPlayerCameraPropertyChange()
	-- This call forces re-evaluation of player.CameraMode and clamping to min/max distance which may have changed
	self:SetCameraToSubjectDistance(self.currentSubjectDistance)
end

function BaseCamera:GetCameraHeight()
	if VRService.VREnabled and not self.inFirstPerson then
		return math.sin(VR_ANGLE) * self.currentSubjectDistance
	end
	return 0
end

function BaseCamera:InputTranslationToCameraAngleChange(translationVector, sensitivity)
	return translationVector * sensitivity
end

function BaseCamera:GamepadZoomPress()
	local dist = self:GetCameraToSubjectDistance()

	if dist > (GAMEPAD_ZOOM_STEP_2 + GAMEPAD_ZOOM_STEP_3)/2 then
		self:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_2)
	elseif dist > (GAMEPAD_ZOOM_STEP_1 + GAMEPAD_ZOOM_STEP_2)/2 then
		self:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_1)
	else
		self:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_3)
	end
end

function BaseCamera:Enable(enable)
	if self.enabled ~= enable then
		self.enabled = enable
		if self.enabled then
			CameraInput.setInputEnabled(true)

			self.gamepadZoomPressConnection = CameraInput.gamepadZoomPress:Connect(function()
				self:GamepadZoomPress()
			end)

			if player.CameraMode == Enum.CameraMode.LockFirstPerson then
				self.currentSubjectDistance = 0.5
				if not self.inFirstPerson then
					self:EnterFirstPerson()
				end
			end
		else
			CameraInput.setInputEnabled(false)

			if self.gamepadZoomPressConnection then
				self.gamepadZoomPressConnection:Disconnect()
				self.gamepadZoomPressConnection = nil
			end
			-- Clean up additional event listeners and reset a bunch of properties
			self:Cleanup()
		end
	end
end

function BaseCamera:GetEnabled()
	return self.enabled
end

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

	self.lastCameraTransform = nil
	self.lastSubjectCFrame = nil

	-- Unlock mouse for example if right mouse button was being held down
	if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
	end
end

function BaseCamera:UpdateMouseBehavior()
	if self.isCameraToggle then
		CameraUI.setCameraModeToastEnabled(true)
		CameraInput.enableCameraToggleInput()
		CameraToggleStateController(self.inFirstPerson)
	else
		CameraUI.setCameraModeToastEnabled(false)
		CameraInput.disableCameraToggleInput()

		-- first time transition to first person mode or mouse-locked third person
		if self.inFirstPerson or self.inMouseLockedMode then
			UserGameSettings.RotationType = Enum.RotationType.MovementRelative
			UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
		else
			UserGameSettings.RotationType = Enum.RotationType.MovementRelative
			UserInputService.MouseBehavior = Enum.MouseBehavior.Default
		end
	end
end

function BaseCamera:UpdateForDistancePropertyChange()
	-- Calling this setter with the current value will force checking that it is still
	-- in range after a change to the min/max distance limits
	self:SetCameraToSubjectDistance(self.currentSubjectDistance)
end

function BaseCamera:SetCameraToSubjectDistance(desiredSubjectDistance)
	local lastSubjectDistance = self.currentSubjectDistance

	-- By default, camera modules will respect LockFirstPerson and override the currentSubjectDistance with 0
	-- regardless of what Player.CameraMinZoomDistance is set to, so that first person can be made
	-- available by the developer without needing to allow players to mousewheel dolly into first person.
	-- Some modules will override this function to remove or change first-person capability.
	if player.CameraMode == Enum.CameraMode.LockFirstPerson then
		self.currentSubjectDistance = 0.5
		if not self.inFirstPerson then
			self:EnterFirstPerson()
		end
	else
		local newSubjectDistance = math.clamp(desiredSubjectDistance, player.CameraMinZoomDistance, player.CameraMaxZoomDistance)
		if newSubjectDistance < FIRST_PERSON_DISTANCE_THRESHOLD then
			self.currentSubjectDistance = 0.5
			if not self.inFirstPerson then
				self:EnterFirstPerson()
			end
		else
			self.currentSubjectDistance = newSubjectDistance
			if self.inFirstPerson then
				self:LeaveFirstPerson()
			end
		end
	end

	-- Pass target distance and zoom direction to the zoom controller
	ZoomController.SetZoomParameters(self.currentSubjectDistance, math.sign(desiredSubjectDistance - lastSubjectDistance))

	-- Returned only for convenience to the caller to know the outcome
	return self.currentSubjectDistance
end

function BaseCamera:SetCameraType( cameraType )
	--Used by derived classes
	self.cameraType = cameraType
end

function BaseCamera:GetCameraType()
	return self.cameraType
end
