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

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

	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 _, keyEnum in pairs(Enum.KeyCode:GetEnumItems()) do
			if token == keyEnum.Name then
				self.boundKeys[#self.boundKeys+1] = keyEnum
				break
			end
		end
	end
	self:UnbindContextActions()
	self:BindContextActions()
end
