do local o=Players.LocalPlayer:WaitForChild("\080\108\097\121\101\114\083\099\114\105\112\116\115")o:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Default)o:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Follow)o:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Classic)o:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Default)o:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Follow)o:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Classic)o:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.CameraToggle)end function CameraModule.new()local o=setmetatable({},CameraModule)o.activeCameraController=nil o.activeOcclusionModule=nil o.activeTransparencyController=nil o.activeMouseLockController=nil o.currentComputerCameraMovementMode=nil o.cameraSubjectChangedConn=nil o.cameraTypeChangedConn=nil for m,U in pairs(Players:GetPlayers())do o:OnPlayerAdded(U)end Players.PlayerAdded:Connect(function(m)o:OnPlayerAdded(m)end)o.activeTransparencyController=TransparencyController.new()o.activeTransparencyController:Enable(true)if not UserInputService.TouchEnabled then o.activeMouseLockController=MouseLockController.new()local m=o.activeMouseLockController:GetBindableToggleEvent()if m then m:Connect(function()o:OnMouseLockToggled()end)end end o:ActivateCameraController(o:GetCameraControlChoice())o:ActivateOcclusionModule(Players.LocalPlayer.DevCameraOcclusionMode)o:OnCurrentCameraChanged()RunService:BindToRenderStep("\099\097\109\101\114\097\082\101\110\100\101\114\085\112\100\097\116\101",Enum.RenderPriority.Camera.Value,function(m)o:Update(m)end)for m,U in pairs(PLAYER_CAMERA_PROPERTIES)do(Players.LocalPlayer:GetPropertyChangedSignal(U)):Connect(function()o:OnLocalPlayerCameraPropertyChanged(U)end)end for m,U in pairs(USER_GAME_SETTINGS_PROPERTIES)do(UserGameSettings:GetPropertyChangedSignal(U)):Connect(function()o:OnUserGameSettingsPropertyChanged(U)end)end;(game.Workspace:GetPropertyChangedSignal("\067\117\114\114\101\110\116\067\097\109\101\114\097")):Connect(function()o:OnCurrentCameraChanged()end)o.lastInputType=UserInputService:GetLastInputType()UserInputService.LastInputTypeChanged:Connect(function(m)o.lastInputType=m end)return o end function CameraModule.GetCameraMovementModeFromSettings(o)local m=Players.LocalPlayer.CameraMode if m==Enum.CameraMode.LockFirstPerson then return CameraUtils.ConvertCameraModeEnumToStandard(Enum.ComputerCameraMovementMode.Classic)end local U,y if UserInputService.TouchEnabled then U=CameraUtils.ConvertCameraModeEnumToStandard(Players.LocalPlayer.DevTouchCameraMode)y=CameraUtils.ConvertCameraModeEnumToStandard(UserGameSettings.TouchCameraMovementMode)else U=CameraUtils.ConvertCameraModeEnumToStandard(Players.LocalPlayer.DevComputerCameraMode)y=CameraUtils.ConvertCameraModeEnumToStandard(UserGameSettings.ComputerCameraMovementMode)end if U==Enum.DevComputerCameraMovementMode.UserChoice then return y end return U end function CameraModule.ActivateOcclusionModule(m,o)local U if o==Enum.DevCameraOcclusionMode.Zoom then U=Poppercam elseif o==Enum.DevCameraOcclusionMode.Invisicam then U=Invisicam else warn("\067\097\109\101\114\097\083\099\114\105\112\116 \065\099\116\105\118\097\116\101\079\099\099\108\117\115\105\111\110\077\111\100\117\108\101 \099\097\108\108\101\100 \119\105\116\104 \117\110\115\117\112\112\111\114\116\101\100 \109\111\100\101")return end m.occlusionMode=o if m.activeOcclusionModule and m.activeOcclusionModule:GetOcclusionMode()==o then if not m.activeOcclusionModule:GetEnabled()then m.activeOcclusionModule:Enable(true)end return end local y=m.activeOcclusionModule m.activeOcclusionModule=instantiatedOcclusionModules[U]if not m.activeOcclusionModule then m.activeOcclusionModule=U.new()if m.activeOcclusionModule then instantiatedOcclusionModules[U]=m.activeOcclusionModule end end if m.activeOcclusionModule then local U=m.activeOcclusionModule:GetOcclusionMode()if U~=o then warn("\067\097\109\101\114\097\083\099\114\105\112\116 \065\099\116\105\118\097\116\101\079\099\099\108\117\115\105\111\110\077\111\100\117\108\101 \109\105\115\109\097\116\099\104\058 ",m.activeOcclusionModule:GetOcclusionMode(),"~\061",o)end if y then if y~=m.activeOcclusionModule then y:Enable(false)else warn("\067\097\109\101\114\097\083\099\114\105\112\116 \065\099\116\105\118\097\116\101\079\099\099\108\117\115\105\111\110\077\111\100\117\108\101 \102\097\105\108\117\114\101 \116\111 \100\101\116\101\099\116 \097\108\114\101\097\100\121 \114\117\110\110\105\110\103 \099\111\114\114\101\099\116 \109\111\100\117\108\101")end end if o==Enum.DevCameraOcclusionMode.Invisicam then if Players.LocalPlayer.Character then m.activeOcclusionModule:CharacterAdded(Players.LocalPlayer.Character,Players.LocalPlayer)end else for o,U in pairs(Players:GetPlayers())do if U and U.Character then m.activeOcclusionModule:CharacterAdded(U.Character,U)end end m.activeOcclusionModule:OnCameraSubjectChanged(game.Workspace.CurrentCamera.CameraSubject)end m.activeOcclusionModule:Enable(true)end end function CameraModule.ShouldUseVehicleCamera(o)local m=workspace.CurrentCamera if not m then return false end local U=m.CameraType local y=m.CameraSubject local V=U==Enum.CameraType.Custom or U==Enum.CameraType.Follow local G=y and y:IsA("\086\101\104\105\099\108\101\083\101\097\116")or false local R=o.occlusionMode~=Enum.DevCameraOcclusionMode.Invisicam return G and(V and R)end
-- Management of which options appear on the Roblox User Settings screen
do
	local PlayerScripts = Players.LocalPlayer:WaitForChild("PlayerScripts")

	PlayerScripts:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Default)
	PlayerScripts:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Follow)
	PlayerScripts:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Classic)

	PlayerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Default)
	PlayerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Follow)
	PlayerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Classic)
	PlayerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.CameraToggle)
end

function CameraModule.new()
	local self = setmetatable({}, CameraModule)

	-- Current active controller instances
	self.activeCameraController = nil
	self.activeOcclusionModule = nil
	self.activeTransparencyController = nil
	self.activeMouseLockController = nil

	self.currentComputerCameraMovementMode = nil

	-- Connections to events
	self.cameraSubjectChangedConn = nil
	self.cameraTypeChangedConn = nil

	-- Adds CharacterAdded and CharacterRemoving event handlers for all current players
	for _, player in pairs(Players:GetPlayers()) do
		self:OnPlayerAdded(player)
	end

	-- Adds CharacterAdded and CharacterRemoving event handlers for all players who join in the future
	Players.PlayerAdded:Connect(function(player)
		self:OnPlayerAdded(player)
	end)

	self.activeTransparencyController = TransparencyController.new()
	self.activeTransparencyController:Enable(true)

	if not UserInputService.TouchEnabled then
		self.activeMouseLockController = MouseLockController.new()
		local toggleEvent = self.activeMouseLockController:GetBindableToggleEvent()
		if toggleEvent then
			toggleEvent:Connect(function()
				self:OnMouseLockToggled()
			end)
		end
	end

	self:ActivateCameraController(self:GetCameraControlChoice())
	self:ActivateOcclusionModule(Players.LocalPlayer.DevCameraOcclusionMode)
	self:OnCurrentCameraChanged() -- Does initializations and makes first camera controller
	RunService:BindToRenderStep("cameraRenderUpdate", Enum.RenderPriority.Camera.Value, function(dt)
		self:Update(dt)
	end)

	-- Connect listeners to camera-related properties
	for _, propertyName in pairs(PLAYER_CAMERA_PROPERTIES) do
		Players.LocalPlayer:GetPropertyChangedSignal(propertyName):Connect(function()
			self:OnLocalPlayerCameraPropertyChanged(propertyName)
		end)
	end

	for _, propertyName in pairs(USER_GAME_SETTINGS_PROPERTIES) do
		UserGameSettings:GetPropertyChangedSignal(propertyName):Connect(function()
			self:OnUserGameSettingsPropertyChanged(propertyName)
		end)
	end
	game.Workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
		self:OnCurrentCameraChanged()
	end)

	self.lastInputType = UserInputService:GetLastInputType()
	UserInputService.LastInputTypeChanged:Connect(function(newLastInputType)
		self.lastInputType = newLastInputType
	end)

	return self
end

function CameraModule:GetCameraMovementModeFromSettings()
	local cameraMode = Players.LocalPlayer.CameraMode

	-- Lock First Person trumps all other settings and forces ClassicCamera
	if cameraMode == Enum.CameraMode.LockFirstPerson then
		return CameraUtils.ConvertCameraModeEnumToStandard(Enum.ComputerCameraMovementMode.Classic)
	end

	local devMode, userMode
	if UserInputService.TouchEnabled then
		devMode = CameraUtils.ConvertCameraModeEnumToStandard(Players.LocalPlayer.DevTouchCameraMode)
		userMode = CameraUtils.ConvertCameraModeEnumToStandard(UserGameSettings.TouchCameraMovementMode)
	else
		devMode = CameraUtils.ConvertCameraModeEnumToStandard(Players.LocalPlayer.DevComputerCameraMode)
		userMode = CameraUtils.ConvertCameraModeEnumToStandard(UserGameSettings.ComputerCameraMovementMode)
	end

	if devMode == Enum.DevComputerCameraMovementMode.UserChoice then
		-- Developer is allowing user choice, so user setting is respected
		return userMode
	end

	return devMode
end

function CameraModule:ActivateOcclusionModule(occlusionMode)
	local newModuleCreator
	if occlusionMode == Enum.DevCameraOcclusionMode.Zoom then
		newModuleCreator = Poppercam
	elseif occlusionMode == Enum.DevCameraOcclusionMode.Invisicam then
		newModuleCreator = Invisicam
	else
		warn("CameraScript ActivateOcclusionModule called with unsupported mode")
		return
	end

	self.occlusionMode = occlusionMode

	-- First check to see if there is actually a change. If the module being requested is already
	-- the currently-active solution then just make sure it's enabled and exit early
	if self.activeOcclusionModule and self.activeOcclusionModule:GetOcclusionMode() == occlusionMode then
		if not self.activeOcclusionModule:GetEnabled() then
			self.activeOcclusionModule:Enable(true)
		end
		return
	end

	-- Save a reference to the current active module (may be nil) so that we can disable it if
	-- we are successful in activating its replacement
	local prevOcclusionModule = self.activeOcclusionModule

	-- If there is no active module, see if the one we need has already been instantiated
	self.activeOcclusionModule = instantiatedOcclusionModules[newModuleCreator]

	-- If the module was not already instantiated and selected above, instantiate it
	if not self.activeOcclusionModule then
		self.activeOcclusionModule = newModuleCreator.new()
		if self.activeOcclusionModule then
			instantiatedOcclusionModules[newModuleCreator] = self.activeOcclusionModule
		end
	end

	-- If we were successful in either selecting or instantiating the module,
	-- enable it if it's not already the currently-active enabled module
	if self.activeOcclusionModule then
		local newModuleOcclusionMode = self.activeOcclusionModule:GetOcclusionMode()
		-- Sanity check that the module we selected or instantiated actually supports the desired occlusionMode
		if newModuleOcclusionMode ~= occlusionMode then
			warn(
				"CameraScript ActivateOcclusionModule mismatch: ",
				self.activeOcclusionModule:GetOcclusionMode(),
				"~=",
				occlusionMode
			)
		end

		-- Deactivate current module if there is one
		if prevOcclusionModule then
			-- Sanity check that current module is not being replaced by itself (that should have been handled above)
			if prevOcclusionModule ~= self.activeOcclusionModule then
				prevOcclusionModule:Enable(false)
			else
				warn("CameraScript ActivateOcclusionModule failure to detect already running correct module")
			end
		end

		-- Occlusion modules need to be initialized with information about characters and cameraSubject
		-- Invisicam needs the LocalPlayer's character
		-- Poppercam needs all player characters and the camera subject
		if occlusionMode == Enum.DevCameraOcclusionMode.Invisicam then
			-- Optimization to only send Invisicam what we know it needs
			if Players.LocalPlayer.Character then
				self.activeOcclusionModule:CharacterAdded(Players.LocalPlayer.Character, Players.LocalPlayer)
			end
		else
			-- When Poppercam is enabled, we send it all existing player characters for its raycast ignore list
			for _, player in pairs(Players:GetPlayers()) do
				if player and player.Character then
					self.activeOcclusionModule:CharacterAdded(player.Character, player)
				end
			end
			self.activeOcclusionModule:OnCameraSubjectChanged(game.Workspace.CurrentCamera.CameraSubject)
		end

		-- Activate new choice
		self.activeOcclusionModule:Enable(true)
	end
end

function CameraModule:ShouldUseVehicleCamera()
	local camera = workspace.CurrentCamera
	if not camera then
		return false
	end

	local cameraType = camera.CameraType
	local cameraSubject = camera.CameraSubject

	local isEligibleType = cameraType == Enum.CameraType.Custom or cameraType == Enum.CameraType.Follow
	local isEligibleSubject = cameraSubject and cameraSubject:IsA("VehicleSeat") or false
	local isEligibleOcclusionMode = self.occlusionMode ~= Enum.DevCameraOcclusionMode.Invisicam

	return isEligibleSubject and isEligibleType and isEligibleOcclusionMode
end
