Need help on my client side movement script

Hi, I want to make a secure custom movement. I created a momentum based movement inside a local script every calculation in on a local script and I’m scared that exlpoiters may modify that script.

This is the script

local Players = game:GetService("Players")
local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local player = Players.LocalPlayer

-- Variabili che devono essere ripristinate quando il personaggio cambia
local character, humanoid, root, gyro
local isSliding = false

local activeKeys = {}

local Animation = script.Slide

local AnimationPlay

-- Funzione per inizializzare il movimento per un nuovo personaggio
local function setupCharacter(newCharacter)
	character = newCharacter
	humanoid = character:WaitForChild("Humanoid")
	root = character:WaitForChild("HumanoidRootPart")

	humanoid:ChangeState(Enum.HumanoidStateType.Physics)
	humanoid.AutoRotate = false

	if gyro then gyro:Destroy() end
	gyro = Instance.new("BodyGyro")
	gyro.Parent = root
	gyro.MaxTorque = Vector3.new(1_000_000, 1_000_000, 1_000_000)
	gyro.P = 10_000
	gyro.CFrame = CFrame.new(root.Position, root.Position + workspace.CurrentCamera.CFrame.LookVector)
end

player.CharacterAdded:Connect(setupCharacter)
if player.Character then setupCharacter(player.Character) end

local jumpPower = 550
local maxSpeed = 55
local slideSpeed = 1000
local slideDuration = 0.5
local slideTime = 0

local moveInput = Vector3.zero
local initialSlideDirection = Vector3.zero

local inputMap = {
	[Enum.KeyCode.W] = Vector3.new(0, 0, -1),
	[Enum.KeyCode.S] = Vector3.new(0, 0, 1),
	[Enum.KeyCode.A] = Vector3.new(-1, 0, 0),
	[Enum.KeyCode.D] = Vector3.new(1, 0, 0),
}

local function slideAnimation()

	AnimationPlay = character.Humanoid:LoadAnimation(Animation)
	AnimationPlay:Play()
	humanoid.HipHeight = .1
	humanoid.HipHeight = 2

end

local function isOnGround()
	if not root then return false end
	local rayOrigin = root.Position
	local rayDirection = Vector3.new(0, -(humanoid.HipHeight + 3), 0)

	local params = RaycastParams.new()
	params.FilterDescendantsInstances = {character}
	params.FilterType = Enum.RaycastFilterType.Exclude

	local result = workspace:Raycast(rayOrigin, rayDirection, params)
	return result ~= nil
end

local function updateMoveInput()
	moveInput = Vector3.zero
	for keyCode, pressed in pairs(activeKeys) do
		if pressed and inputMap[keyCode] then
			moveInput += inputMap[keyCode]
		end
	end
end

UIS.InputBegan:Connect(function(input, processed)
	if processed then return end
	if inputMap[input.KeyCode] then
		activeKeys[input.KeyCode] = true
	end

	if input.KeyCode == Enum.KeyCode.LeftShift and not isSliding and root and root.AssemblyLinearVelocity.Magnitude > 10 and isOnGround() then
		isSliding = true
		slideTime = 0
		initialSlideDirection = root.AssemblyLinearVelocity.Unit

		slideAnimation()

		print("Scivolata iniziata!")
	end
end)

UIS.InputEnded:Connect(function(input)
	if inputMap[input.KeyCode] then
		activeKeys[input.KeyCode] = nil
	end
end)

UIS.WindowFocusReleased:Connect(function()
	activeKeys = {}
	moveInput = Vector3.zero
end)

RunService.RenderStepped:Connect(function(dt)
	if not root then return end
	updateMoveInput()

	local cam = workspace.CurrentCamera
	local currentVel = root.AssemblyLinearVelocity

	if not isSliding then
		local direction = cam.CFrame:VectorToWorldSpace(moveInput)
		direction = Vector3.new(direction.X, 0, direction.Z).Unit

		if direction.Magnitude > 0 then
			local targetVel = direction * maxSpeed
			local newVel = Vector3.new(
				math.clamp(currentVel.X + (targetVel.X - currentVel.X) * dt * 10, -maxSpeed, maxSpeed),
				currentVel.Y,
				math.clamp(currentVel.Z + (targetVel.Z - currentVel.Z) * dt * 10, -maxSpeed, maxSpeed)
			)

			root.AssemblyLinearVelocity = newVel
		end
	else
		local slideDirection = initialSlideDirection + Vector3.new(moveInput.X, 0, moveInput.Z) * 0.2
		slideDirection = slideDirection.Unit

		local targetVel = slideDirection * slideSpeed
		local momentumDelta = targetVel - currentVel
		local newVel = currentVel + momentumDelta * dt
		newVel = newVel * 0.9

		root.AssemblyLinearVelocity = newVel

		slideTime += dt
		if slideTime >= slideDuration or not isOnGround() then
			isSliding = false
			AnimationPlay:Stop()

			print("Scivolata finita!")
		end
	end
end)

-- Salto
UIS.InputBegan:Connect(function(input, processed)
	if input.KeyCode == Enum.KeyCode.Space and isOnGround() then
		if isSliding then
			root:ApplyImpulse(Vector3.new(0, jumpPower * 1.25, 0))
		else
			root:ApplyImpulse(Vector3.new(0, jumpPower, 0))
		end
	end
end)

RunService.RenderStepped:Connect(function()
	if root and gyro then
		local cam = workspace.CurrentCamera
		local lookVector = cam.CFrame.LookVector
		local up = Vector3.new(0, 1, 0)
		gyro.CFrame = CFrame.lookAt(root.Position, root.Position + Vector3.new(lookVector.X, 0, lookVector.Z), up)
	end
end)

RunService.RenderStepped:Connect(function()
	if root and isOnGround() then
		local planarVel = Vector3.new(root.AssemblyLinearVelocity.X, 0, root.AssemblyLinearVelocity.Z)
		local damped = planarVel * 0.9
		root.AssemblyLinearVelocity = Vector3.new(damped.X, root.AssemblyLinearVelocity.Y, damped.Z)
	end
end)

The comments are in italian, if you are intrested.

How do i make this movemnt script secure, so no one can modify it, elimate it, or change is values?

I tried making the movement script on the server script, but I have no idea how to do that.

Can you help me find a solution how to fix this, or maybe a tutorial, anticheat, or something like that? Should I put everything on a server script?
Appriciate all the help.
Sorry for the bad english!

You can check this, it implements server-sided movement, or you could wait until aurorascripts release
And for the “no one can change its values” you either make the server do the movement (as linked above) or make it verify every position the client sends is not exploited

1 Like

Here is the testing place for that module: Chickynoid v2.0 beta - Roblox

1 Like

Thank you for the help <3! Have a nice day!