local J={}J.__index=J function J.new()local F=setmetatable({},J)F.inputBeganConn=nil F.isMouseLocked=false F.savedMouseCursor=nil F.boundKeys={Enum.KeyCode.LeftShift;Enum.KeyCode.RightShift}F.mouseLockToggledEvent=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local P=script:FindFirstChild("\066\111\117\110\100\075\101\121\115")if not P or not P:IsA("\083\116\114\105\110\103\086\097\108\117\101")then if P then P:Destroy()end P=Instance.new("\083\116\114\105\110\103\086\097\108\117\101")P.Name="\066\111\117\110\100\075\101\121\115"P.Value="\076\101\102\116\083\104\105\102\116\044\082\105\103\104\116\083\104\105\102\116"P.Parent=script end if P then P.Changed:Connect(function(J)F:OnBoundKeysObjectChanged(J)end)F:OnBoundKeysObjectChanged(P.Value)end GameSettings.Changed:Connect(function(J)if J=="\067\111\110\116\114\111\108\077\111\100\101"or J=="\067\111\109\112\117\116\101\114\077\111\118\101\109\101\110\116\077\111\100\101"then F:UpdateMouseLockAvailability()end end);(PlayersService.LocalPlayer:GetPropertyChangedSignal("\068\101\118\069\110\097\098\108\101\077\111\117\115\101\076\111\099\107")):Connect(function()F:UpdateMouseLockAvailability()end);(PlayersService.LocalPlayer:GetPropertyChangedSignal("\068\101\118\067\111\109\112\117\116\101\114\077\111\118\101\109\101\110\116\077\111\100\101")):Connect(function()F:UpdateMouseLockAvailability()end)F:UpdateMouseLockAvailability()return F end function J.GetIsMouseLocked(J)return J.isMouseLocked end function J.GetBindableToggleEvent(J)return J.mouseLockToggledEvent.Event end function J.GetMouseLockOffset(J)local F=script:FindFirstChild("\067\097\109\101\114\097\079\102\102\115\101\116")if F and F:IsA("\086\101\099\116\111\114\051\086\097\108\117\101")then return F.Value else if F then F:Destroy()end F=Instance.new("\086\101\099\116\111\114\051\086\097\108\117\101")F.Name="\067\097\109\101\114\097\079\102\102\115\101\116"F.Value=Vector3.new(1.75,0,0)F.Parent=script end if F and F.Value then return F.Value end return Vector3.new(1.75,0,0)end function J.UpdateMouseLockAvailability(J)local F=PlayersService.LocalPlayer.DevEnableMouseLock local P=PlayersService.LocalPlayer.DevComputerMovementMode==Enum.DevComputerMovementMode.Scriptable local T=GameSettings.ControlMode==Enum.ControlMode.MouseLockSwitch local Z=GameSettings.ComputerMovementMode==Enum.ComputerMovementMode.ClickToMove local k=F and(T and(not Z and not P))if k~=J.enabled then J:EnableMouseLock(k)end end function J.OnBoundKeysObjectChanged(F,J)F.boundKeys={}for J in string.gmatch(J,"\091\094\037\115\044\093\043")do for P,T in pairs(Enum.KeyCode:GetEnumItems())do if J==T.Name then F.boundKeys[#F.boundKeys+1]=T break end end end if FFlagPlayerScriptsBindAtPriority then F:UnbindContextActions()F:BindContextActions()end end
--
local MouseLockController = {}
MouseLockController.__index = MouseLockController

function MouseLockController.new()
	local self = setmetatable({}, MouseLockController)
	
	self.inputBeganConn = nil -- Remove with FFlagPlayerScriptsBindAtPriority
	self.isMouseLocked = false
	self.savedMouseCursor = nil
	self.boundKeys = {Enum.KeyCode.LeftShift, Enum.KeyCode.RightShift} -- defaults
	
	self.mouseLockToggledEvent = Instance.new("BindableEvent")
	
	local boundKeysObj = script:FindFirstChild("BoundKeys")
	if (not boundKeysObj) or (not boundKeysObj:IsA("StringValue")) then
		-- If object with correct name was found, but it's not a StringValue, destroy and replace
		if boundKeysObj then
			boundKeysObj:Destroy()
		end
		
		boundKeysObj = Instance.new("StringValue")
		boundKeysObj.Name = "BoundKeys"
		boundKeysObj.Value = "LeftShift,RightShift"
		boundKeysObj.Parent = script
	end
	
	if boundKeysObj then
		boundKeysObj.Changed:Connect(function(value)
			self:OnBoundKeysObjectChanged(value)
		end)
		self:OnBoundKeysObjectChanged(boundKeysObj.Value) -- Initial setup call
	end
	
	-- Watch for changes to user's ControlMode and ComputerMovementMode settings and update the feature availability accordingly
	GameSettings.Changed:Connect(function(property)
		if property == "ControlMode" or property == "ComputerMovementMode" then
			self:UpdateMouseLockAvailability()
		end
	end)
	
	-- Watch for changes to DevEnableMouseLock and update the feature availability accordingly
	PlayersService.LocalPlayer:GetPropertyChangedSignal("DevEnableMouseLock"):Connect(function()
		self:UpdateMouseLockAvailability()
	end)
	
	-- Watch for changes to DevEnableMouseLock and update the feature availability accordingly
	PlayersService.LocalPlayer:GetPropertyChangedSignal("DevComputerMovementMode"):Connect(function()
		self:UpdateMouseLockAvailability()
	end)
	
	self:UpdateMouseLockAvailability()
	
	return self
end

function MouseLockController:GetIsMouseLocked()
	return self.isMouseLocked
end

function MouseLockController:GetBindableToggleEvent()
	return self.mouseLockToggledEvent.Event
end

function MouseLockController:GetMouseLockOffset()
	local offsetValueObj = script:FindFirstChild("CameraOffset")
	if offsetValueObj and offsetValueObj:IsA("Vector3Value") then
		return offsetValueObj.Value
	else
		-- If CameraOffset object was found but not correct type, destroy
		if offsetValueObj then
			offsetValueObj:Destroy()
		end
		offsetValueObj = Instance.new("Vector3Value")
		offsetValueObj.Name = "CameraOffset"
		offsetValueObj.Value = Vector3.new(1.75,0,0) -- Legacy Default Value
		offsetValueObj.Parent = script
	end
	
	if offsetValueObj and offsetValueObj.Value then
		return offsetValueObj.Value
	end
	
	return Vector3.new(1.75,0,0)
end

function MouseLockController:UpdateMouseLockAvailability()
	local devAllowsMouseLock = PlayersService.LocalPlayer.DevEnableMouseLock
	local devMovementModeIsScriptable = PlayersService.LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.Scriptable
	local userHasMouseLockModeEnabled = GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch
	local userHasClickToMoveEnabled =  GameSettings.ComputerMovementMode == Enum.ComputerMovementMode.ClickToMove
	local MouseLockAvailable = devAllowsMouseLock and userHasMouseLockModeEnabled and not userHasClickToMoveEnabled and not devMovementModeIsScriptable
	
	if MouseLockAvailable~=self.enabled then
		self:EnableMouseLock(MouseLockAvailable)
	end
end

function MouseLockController:OnBoundKeysObjectChanged(newValue)
	self.boundKeys = {} -- Overriding defaults, note: possibly with nothing at all if boundKeysObj.Value is "" or contains invalid values
	for token in string.gmatch(newValue,"[^%s,]+") do
		for keyCode, keyEnum in pairs(Enum.KeyCode:GetEnumItems()) do
			if token == keyEnum.Name then
				self.boundKeys[#self.boundKeys+1] = keyEnum
				break
			end
		end
	end
	if FFlagPlayerScriptsBindAtPriority then 
		self:UnbindContextActions()
		self:BindContextActions()
	end
end
