local P=require(script.Parent:WaitForChild("\075\101\121\098\111\097\114\100"))local l=setmetatable({},P)l.__index=l function l.new(r)local O=setmetatable(P.new(r),l)O.fingerTouches={}O.numUnsunkTouches=0 O.mouse1Down=tick()O.mouse1DownPos=Vector2.new()O.mouse2DownTime=tick()O.mouse2DownPos=Vector2.new()O.mouse2UpTime=tick()O.keyboardMoveVector=ZERO_VECTOR3 O.tapConn=nil O.inputBeganConn=nil O.inputChangedConn=nil O.inputEndedConn=nil O.humanoidDiedConn=nil O.characterChildAddedConn=nil O.onCharacterAddedConn=nil O.characterChildRemovedConn=nil O.renderSteppedConn=nil O.menuOpenedConnection=nil O.running=false O.wasdEnabled=false return O end function l.DisconnectEvents(P)DisconnectEvent(P.tapConn)DisconnectEvent(P.inputBeganConn)DisconnectEvent(P.inputChangedConn)DisconnectEvent(P.inputEndedConn)DisconnectEvent(P.humanoidDiedConn)DisconnectEvent(P.characterChildAddedConn)DisconnectEvent(P.onCharacterAddedConn)DisconnectEvent(P.renderSteppedConn)DisconnectEvent(P.characterChildRemovedConn)DisconnectEvent(P.menuOpenedConnection)end function l.OnTouchBegan(r,P,l)if r.fingerTouches[P]==nil and not l then r.numUnsunkTouches=r.numUnsunkTouches+1 end r.fingerTouches[P]=l end function l.OnTouchChanged(r,P,l)if r.fingerTouches[P]==nil then r.fingerTouches[P]=l if not l then r.numUnsunkTouches=r.numUnsunkTouches+1 end end end function l.OnTouchEnded(r,P,l)if r.fingerTouches[P]~=nil and r.fingerTouches[P]==false then r.numUnsunkTouches=r.numUnsunkTouches-1 end r.fingerTouches[P]=nil end function l.OnCharacterAdded(l,P)l:DisconnectEvents()l.inputBeganConn=UserInputService.InputBegan:Connect(function(P,r)if P.UserInputType==Enum.UserInputType.Touch then l:OnTouchBegan(P,r)end if l.wasdEnabled and(r==false and(P.UserInputType==Enum.UserInputType.Keyboard and movementKeys[P.KeyCode]))then CleanupPath()if FFlagUserClickToMoveFollowPathRefactor then ClickToMoveDisplay.CancelFailureAnimation()end end if P.UserInputType==Enum.UserInputType.MouseButton1 then l.mouse1DownTime=tick()l.mouse1DownPos=P.Position end if P.UserInputType==Enum.UserInputType.MouseButton2 then l.mouse2DownTime=tick()l.mouse2DownPos=P.Position end end)l.inputChangedConn=UserInputService.InputChanged:Connect(function(P,r)if P.UserInputType==Enum.UserInputType.Touch then l:OnTouchChanged(P,r)end end)l.inputEndedConn=UserInputService.InputEnded:Connect(function(P,r)if P.UserInputType==Enum.UserInputType.Touch then l:OnTouchEnded(P,r)end if P.UserInputType==Enum.UserInputType.MouseButton2 then l.mouse2UpTime=tick()local r=P.Position local O if FFlagUserClickToMoveFollowPathRefactor then O=ExistingPather or l.keyboardMoveVector.Magnitude<=0 else O=l.moveVector.Magnitude<=0 end if l.mouse2UpTime-l.mouse2DownTime<.25 and((r-l.mouse2DownPos).magnitude<5 and O)then local P={r}OnTap(P)end end end)l.tapConn=UserInputService.TouchTap:Connect(function(P,l)if not l then OnTap(P,nil,true)end end)l.menuOpenedConnection=GuiService.MenuOpened:Connect(function()CleanupPath()end)local function r(P)if UserInputService.TouchEnabled then if P:IsA("\084\111\111\108")then P.ManualActivationOnly=true end end if P:IsA("\072\117\109\097\110\111\105\100")then DisconnectEvent(l.humanoidDiedConn)l.humanoidDiedConn=P.Died:Connect(function()if ExistingIndicator then DebrisService:AddItem(ExistingIndicator.Model,1)end end)end end l.characterChildAddedConn=P.ChildAdded:Connect(function(P)r(P)end)l.characterChildRemovedConn=P.ChildRemoved:Connect(function(P)if UserInputService.TouchEnabled then if P:IsA("\084\111\111\108")then P.ManualActivationOnly=false end end end)for P,l in pairs(P:GetChildren())do r(l)end end function l.Start(P)P:Enable(true)end function l.Stop(P)P:Enable(false)end function l.CleanupPath(P)CleanupPath()end function l.Enable(O,P,l,r)if P then if not O.running then if Player.Character then O:OnCharacterAdded(Player.Character)end O.onCharacterAddedConn=Player.CharacterAdded:Connect(function(P)O:OnCharacterAdded(P)end)O.running=true end O.touchJumpController=r if O.touchJumpController then O.touchJumpController:Enable(O.jumpEnabled)end else if O.running then O:DisconnectEvents()CleanupPath()if UserInputService.TouchEnabled then local P=Player.Character if P then for P,l in pairs(P:GetChildren())do if l:IsA("\084\111\111\108")then l.ManualActivationOnly=false end end end end O.running=false end if O.touchJumpController and not O.jumpEnabled then O.touchJumpController:Enable(true)end O.touchJumpController=nil end if UserInputService.KeyboardEnabled and P~=O.enabled then O.forwardValue=0 O.backwardValue=0 O.leftValue=0 O.rightValue=0 O.moveVector=ZERO_VECTOR3 if P then O:BindContextActions()O:ConnectFocusEventListeners()else O:UnbindContextActions()O:DisconnectFocusEventListeners()end end O.wasdEnabled=P and l or false O.enabled=P end function l.OnRenderStepped(l,P)if not FFlagUserClickToMoveFollowPathRefactor then return end l.isJumping=false if ExistingPather then ExistingPather:OnRenderStepped(P)if ExistingPather then l.moveVector=ExistingPather.NextActionMoveDirection l.moveVectorIsCameraRelative=false if ExistingPather.NextActionJump then l.isJumping=true end else l.moveVector=l.keyboardMoveVector l.moveVectorIsCameraRelative=true end else l.moveVector=l.keyboardMoveVector l.moveVectorIsCameraRelative=true end if l.jumpRequested then l.isJumping=true end end
--[[ The ClickToMove Controller Class ]]
--
local KeyboardController = require(script.Parent:WaitForChild("Keyboard"))
local ClickToMove = setmetatable({}, KeyboardController)
ClickToMove.__index = ClickToMove

function ClickToMove.new(CONTROL_ACTION_PRIORITY)
	local self = setmetatable(KeyboardController.new(CONTROL_ACTION_PRIORITY), ClickToMove)

	self.fingerTouches = {}
	self.numUnsunkTouches = 0
	-- PC simulation
	self.mouse1Down = tick()
	self.mouse1DownPos = Vector2.new()
	self.mouse2DownTime = tick()
	self.mouse2DownPos = Vector2.new()
	self.mouse2UpTime = tick()

	self.keyboardMoveVector = ZERO_VECTOR3

	self.tapConn = nil
	self.inputBeganConn = nil
	self.inputChangedConn = nil
	self.inputEndedConn = nil
	self.humanoidDiedConn = nil
	self.characterChildAddedConn = nil
	self.onCharacterAddedConn = nil
	self.characterChildRemovedConn = nil
	self.renderSteppedConn = nil
	self.menuOpenedConnection = nil

	self.running = false

	self.wasdEnabled = false

	return self
end

function ClickToMove:DisconnectEvents()
	DisconnectEvent(self.tapConn)
	DisconnectEvent(self.inputBeganConn)
	DisconnectEvent(self.inputChangedConn)
	DisconnectEvent(self.inputEndedConn)
	DisconnectEvent(self.humanoidDiedConn)
	DisconnectEvent(self.characterChildAddedConn)
	DisconnectEvent(self.onCharacterAddedConn)
	DisconnectEvent(self.renderSteppedConn)
	DisconnectEvent(self.characterChildRemovedConn)
	DisconnectEvent(self.menuOpenedConnection)
end

function ClickToMove:OnTouchBegan(input, processed)
	if self.fingerTouches[input] == nil and not processed then
		self.numUnsunkTouches = self.numUnsunkTouches + 1
	end
	self.fingerTouches[input] = processed
end

function ClickToMove:OnTouchChanged(input, processed)
	if self.fingerTouches[input] == nil then
		self.fingerTouches[input] = processed
		if not processed then
			self.numUnsunkTouches = self.numUnsunkTouches + 1
		end
	end
end

function ClickToMove:OnTouchEnded(input, processed)
	if self.fingerTouches[input] ~= nil and self.fingerTouches[input] == false then
		self.numUnsunkTouches = self.numUnsunkTouches - 1
	end
	self.fingerTouches[input] = nil
end

function ClickToMove:OnCharacterAdded(character)
	self:DisconnectEvents()

	self.inputBeganConn = UserInputService.InputBegan:Connect(function(input, processed)
		if input.UserInputType == Enum.UserInputType.Touch then
			self:OnTouchBegan(input, processed)
		end

		-- Cancel path when you use the keyboard controls if wasd is enabled.
		if
			self.wasdEnabled
			and processed == false
			and input.UserInputType == Enum.UserInputType.Keyboard
			and movementKeys[input.KeyCode]
		then
			CleanupPath()
			if FFlagUserClickToMoveFollowPathRefactor then
				ClickToMoveDisplay.CancelFailureAnimation()
			end
		end
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			self.mouse1DownTime = tick()
			self.mouse1DownPos = input.Position
		end
		if input.UserInputType == Enum.UserInputType.MouseButton2 then
			self.mouse2DownTime = tick()
			self.mouse2DownPos = input.Position
		end
	end)

	self.inputChangedConn = UserInputService.InputChanged:Connect(function(input, processed)
		if input.UserInputType == Enum.UserInputType.Touch then
			self:OnTouchChanged(input, processed)
		end
	end)

	self.inputEndedConn = UserInputService.InputEnded:Connect(function(input, processed)
		if input.UserInputType == Enum.UserInputType.Touch then
			self:OnTouchEnded(input, processed)
		end

		if input.UserInputType == Enum.UserInputType.MouseButton2 then
			self.mouse2UpTime = tick()
			local currPos = input.Position
			-- We allow click to move during path following or if there is no keyboard movement
			local allowed
			if FFlagUserClickToMoveFollowPathRefactor then
				allowed = ExistingPather or self.keyboardMoveVector.Magnitude <= 0
			else
				allowed = self.moveVector.Magnitude <= 0
			end
			if
				self.mouse2UpTime - self.mouse2DownTime < 0.25
				and (currPos - self.mouse2DownPos).magnitude < 5
				and allowed
			then
				local positions = { currPos }
				OnTap(positions)
			end
		end
	end)

	self.tapConn = UserInputService.TouchTap:Connect(function(touchPositions, processed)
		if not processed then
			OnTap(touchPositions, nil, true)
		end
	end)

	self.menuOpenedConnection = GuiService.MenuOpened:Connect(function()
		CleanupPath()
	end)

	local function OnCharacterChildAdded(child)
		if UserInputService.TouchEnabled then
			if child:IsA("Tool") then
				child.ManualActivationOnly = true
			end
		end
		if child:IsA("Humanoid") then
			DisconnectEvent(self.humanoidDiedConn)
			self.humanoidDiedConn = child.Died:Connect(function()
				if ExistingIndicator then
					DebrisService:AddItem(ExistingIndicator.Model, 1)
				end
			end)
		end
	end

	self.characterChildAddedConn = character.ChildAdded:Connect(function(child)
		OnCharacterChildAdded(child)
	end)
	self.characterChildRemovedConn = character.ChildRemoved:Connect(function(child)
		if UserInputService.TouchEnabled then
			if child:IsA("Tool") then
				child.ManualActivationOnly = false
			end
		end
	end)
	for _, child in pairs(character:GetChildren()) do
		OnCharacterChildAdded(child)
	end
end

function ClickToMove:Start()
	self:Enable(true)
end

function ClickToMove:Stop()
	self:Enable(false)
end

function ClickToMove:CleanupPath()
	CleanupPath()
end

function ClickToMove:Enable(enable, enableWASD, touchJumpController)
	if enable then
		if not self.running then
			if Player.Character then -- retro-listen
				self:OnCharacterAdded(Player.Character)
			end
			self.onCharacterAddedConn = Player.CharacterAdded:Connect(function(char)
				self:OnCharacterAdded(char)
			end)
			self.running = true
		end
		self.touchJumpController = touchJumpController
		if self.touchJumpController then
			self.touchJumpController:Enable(self.jumpEnabled)
		end
	else
		if self.running then
			self:DisconnectEvents()
			CleanupPath()
			-- Restore tool activation on shutdown
			if UserInputService.TouchEnabled then
				local character = Player.Character
				if character then
					for _, child in pairs(character:GetChildren()) do
						if child:IsA("Tool") then
							child.ManualActivationOnly = false
						end
					end
				end
			end
			self.running = false
		end
		if self.touchJumpController and not self.jumpEnabled then
			self.touchJumpController:Enable(true)
		end
		self.touchJumpController = nil
	end

	-- Extension for initializing Keyboard input as this class now derives from Keyboard
	if UserInputService.KeyboardEnabled and enable ~= self.enabled then
		self.forwardValue = 0
		self.backwardValue = 0
		self.leftValue = 0
		self.rightValue = 0

		self.moveVector = ZERO_VECTOR3

		if enable then
			self:BindContextActions()
			self:ConnectFocusEventListeners()
		else
			self:UnbindContextActions()
			self:DisconnectFocusEventListeners()
		end
	end

	self.wasdEnabled = enable and enableWASD or false
	self.enabled = enable
end

function ClickToMove:OnRenderStepped(dt)
	if not FFlagUserClickToMoveFollowPathRefactor then
		return
	end

	-- Reset jump
	self.isJumping = false

	-- Handle Pather
	if ExistingPather then
		-- Let the Pather update
		ExistingPather:OnRenderStepped(dt)

		-- If we still have a Pather, set the resulting actions
		if ExistingPather then
			-- Setup move (NOT relative to camera)
			self.moveVector = ExistingPather.NextActionMoveDirection
			self.moveVectorIsCameraRelative = false

			-- Setup jump (but do NOT prevent the base Keayboard class from requesting jumps as well)
			if ExistingPather.NextActionJump then
				self.isJumping = true
			end
		else
			self.moveVector = self.keyboardMoveVector
			self.moveVectorIsCameraRelative = true
		end
	else
		self.moveVector = self.keyboardMoveVector
		self.moveVectorIsCameraRelative = true
	end

	-- Handle Keyboard's jump
	if self.jumpRequested then
		self.isJumping = true
	end
end
