function ControlModule.SelectTouchModule(X)if not UserInputService.TouchEnabled then return nil,false end local N local K=Players.LocalPlayer.DevTouchMovementMode if K==Enum.DevTouchMovementMode.UserChoice then N=movementEnumToModuleMap[UserGameSettings.TouchMovementMode]elseif K==Enum.DevTouchMovementMode.Scriptable then return nil,true else N=movementEnumToModuleMap[K]end return N,true end local function X(X,N)local K=Workspace.CurrentCamera if not K then return N end if X:GetState()==Enum.HumanoidStateType.Swimming then return K.CFrame:VectorToWorldSpace(N)end local V,f local q,s,A,T,Y,G,D,o,B,z,y,b=K.CFrame:GetComponents()if B<1 and B>-1 then V=b f=G else V=T f=-Y*math.sign(B)end local l=math.sqrt(V*V+f*f)return Vector3.new((V*N.x+f*N.z)/l,0,(V*N.z-f*N.x)/l)end function ControlModule.OnRenderStepped(K,N)if K.activeController and(K.activeController.enabled and K.humanoid)then K.activeController:OnRenderStepped(N)local V=K.activeController:GetMoveVector()local f=K.activeController:IsMoveVectorCameraRelative()local q=K:GetClickToMoveController()if K.activeController~=q then if V.magnitude>0 then q:CleanupPath()else q:OnRenderStepped(N)V=q:GetMoveVector()f=q:IsMoveVectorCameraRelative()end end local s=false if K.vehicleController then V,s=K.vehicleController:Update(V,f,K.activeControlModule==Gamepad)end if f then V=X(K.humanoid,V)end K.moveFunction(Players.LocalPlayer,V,false)K.humanoid.Jump=K.activeController:GetIsJumping()or K.touchJumpController and K.touchJumpController:GetIsJumping()end end function ControlModule.OnHumanoidSeated(K,X,N)if X then if N and N:IsA("\086\101\104\105\099\108\101\083\101\097\116")then if not K.vehicleController then K.vehicleController=K.vehicleController.new(CONTROL_ACTION_PRIORITY)end K.vehicleController:Enable(true,N)end else if K.vehicleController then K.vehicleController:Enable(false,N)end end end function ControlModule.OnCharacterAdded(N,X)N.humanoid=X:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")while not N.humanoid do X.ChildAdded:wait()N.humanoid=X:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")end if N.touchGui then N.touchGui.Enabled=true end if N.humanoidSeatedConn then N.humanoidSeatedConn:Disconnect()N.humanoidSeatedConn=nil end N.humanoidSeatedConn=N.humanoid.Seated:Connect(function(X,K)N:OnHumanoidSeated(X,K)end)end function ControlModule.OnCharacterRemoving(N,X)N.humanoid=nil if N.touchGui then N.touchGui.Enabled=false end end
-- Choose current Touch control module based on settings (user, dev)
-- Returns module (possibly nil) and success code to differentiate returning nil due to error vs Scriptable
function ControlModule:SelectTouchModule()
	if not UserInputService.TouchEnabled then
		return nil, false
	end
	local touchModule
	local DevMovementMode = Players.LocalPlayer.DevTouchMovementMode
	if DevMovementMode == Enum.DevTouchMovementMode.UserChoice then
		touchModule = movementEnumToModuleMap[UserGameSettings.TouchMovementMode]
	elseif DevMovementMode == Enum.DevTouchMovementMode.Scriptable then
		return nil, true
	else
		touchModule = movementEnumToModuleMap[DevMovementMode]
	end
	return touchModule, true
end

local function calculateRawMoveVector(humanoid, cameraRelativeMoveVector)
	local camera = Workspace.CurrentCamera
	if not camera then
		return cameraRelativeMoveVector
	end

	if humanoid:GetState() == Enum.HumanoidStateType.Swimming then
		return camera.CFrame:VectorToWorldSpace(cameraRelativeMoveVector)
	end

	local c, s
	local _, _, _, R00, R01, R02, _, _, R12, _, _, R22 = camera.CFrame:GetComponents()
	if R12 < 1 and R12 > -1 then
		-- X and Z components from back vector.
		c = R22
		s = R02
	else
		-- In this case the camera is looking straight up or straight down.
		-- Use X components from right and up vectors.
		c = R00
		s = -R01 * math.sign(R12)
	end
	local norm = math.sqrt(c * c + s * s)
	return Vector3.new(
		(c * cameraRelativeMoveVector.x + s * cameraRelativeMoveVector.z) / norm,
		0,
		(c * cameraRelativeMoveVector.z - s * cameraRelativeMoveVector.x) / norm
	)
end

function ControlModule:OnRenderStepped(dt)
	if self.activeController and self.activeController.enabled and self.humanoid then
		-- Give the controller a chance to adjust its state
		self.activeController:OnRenderStepped(dt)

		-- Now retrieve info from the controller
		local moveVector = self.activeController:GetMoveVector()
		local cameraRelative = self.activeController:IsMoveVectorCameraRelative()

		local clickToMoveController = self:GetClickToMoveController()
		if self.activeController ~= clickToMoveController then
			if moveVector.magnitude > 0 then
				-- Clean up any developer started MoveTo path
				clickToMoveController:CleanupPath()
			else
				-- Get move vector for developer started MoveTo
				clickToMoveController:OnRenderStepped(dt)
				moveVector = clickToMoveController:GetMoveVector()
				cameraRelative = clickToMoveController:IsMoveVectorCameraRelative()
			end
		end

		-- Are we driving a vehicle ?
		local vehicleConsumedInput = false
		if self.vehicleController then
			moveVector, vehicleConsumedInput =
				self.vehicleController:Update(moveVector, cameraRelative, self.activeControlModule == Gamepad)
		end

		-- If not, move the player
		-- Verification of vehicleConsumedInput is commented out to preserve legacy behavior,
		-- in case some game relies on Humanoid.MoveDirection still being set while in a VehicleSeat
		--if not vehicleConsumedInput then
		if cameraRelative then
			moveVector = calculateRawMoveVector(self.humanoid, moveVector)
		end
		self.moveFunction(Players.LocalPlayer, moveVector, false)
		--end

		-- And make them jump if needed
		self.humanoid.Jump = self.activeController:GetIsJumping()
			or (self.touchJumpController and self.touchJumpController:GetIsJumping())
	end
end

function ControlModule:OnHumanoidSeated(active, currentSeatPart)
	if active then
		if currentSeatPart and currentSeatPart:IsA("VehicleSeat") then
			if not self.vehicleController then
				self.vehicleController = self.vehicleController.new(CONTROL_ACTION_PRIORITY)
			end
			self.vehicleController:Enable(true, currentSeatPart)
		end
	else
		if self.vehicleController then
			self.vehicleController:Enable(false, currentSeatPart)
		end
	end
end

function ControlModule:OnCharacterAdded(char)
	self.humanoid = char:FindFirstChildOfClass("Humanoid")
	while not self.humanoid do
		char.ChildAdded:wait()
		self.humanoid = char:FindFirstChildOfClass("Humanoid")
	end

	if self.touchGui then
		self.touchGui.Enabled = true
	end

	if self.humanoidSeatedConn then
		self.humanoidSeatedConn:Disconnect()
		self.humanoidSeatedConn = nil
	end
	self.humanoidSeatedConn = self.humanoid.Seated:Connect(function(active, currentSeatPart)
		self:OnHumanoidSeated(active, currentSeatPart)
	end)
end

function ControlModule:OnCharacterRemoving(char)
	self.humanoid = nil

	if self.touchGui then
		self.touchGui.Enabled = false
	end
end
