Moving the character's pivot forward by 5 studs only moves in one direction, even if you turn the character

Check out CFrame:ToWorldSpace(), it’ll let you edit the CFrame relative to rotation, so no matter the angle it’ll always move forward.

An example would look like

Part.CFrame = Part.CFrame:ToWorldSpace(CFrame.new(0, 0, -5))

Yeah, that didn’t work. I have a feeling its a problem with the loop but I can’t figure out what part of the loop doesn’t work.

What did your new code look like? The loop itself has nothing to do with the position, its gonna be this line.

    ability = function()
		if CheckIfAlive() then
			local s, r = pcall(function()
				sound:Play()
				while sound.IsPlaying do
					torso.CFrame = torso.CFrame:ToWorldSpace(CFrame.new(0, 0, -5))
					task.wait(.125)
				end
			end)
			if not s and r then
				print(r)
			end
		end
	end;

You’re close, but you need to set the entire models CFrame, not just the Torso. Moving only 1 part of the character won’t do anything.

Character:SetPrimaryPartCFrame(Character.PrimaryPart.CFrame:ToWorldSpace(CFrame.new(0, 0, -5)))

didn’t work, also i wanna note that this is a tool

Pivot acts really weirdly on R6 rigs, at least for me. I recommend to set the HumanoidRootPart CFrame instead if you’re using R6. On R15 it works perfectly fine though.

I tried it as you can see above. This seems so simple yet nobody can solve it…

Im not sure if this can help, but in a noclip script i made I used humanoidRootPart.CFrame = CFrame.new(position, position+lookvector)
Hope this can help you.

Edit: Just tried this and it works:

local char = game:GetService("Players").LocalPlayer.Character
local hrp = char:WaitForChild("HumanoidRootPart")

local speed = 10

while true do
	task.wait(0.5)
	hrp.CFrame = CFrame.new(hrp.Position, hrp.Position+ hrp.CFrame.LookVector) * CFrame.new(Vector3.new(0,0,-1) * speed)
end

Didn’t work for me… Am I doing something wrong?

I don’t think you’re doing anything wrong. Are you getting any errors or is it just not moving at all?

No, look at this: a bug - YouTube
When I try to turn the character for it to teleport me in another direction, it doesn’t go in that direction, it keeps going in the same direction.

Heres the full code:

local attackFunc
tool = script.Parent
ability = tool:FindFirstChild("Ability")
rs = game:GetService("ReplicatedStorage")
debris = game:GetService("Debris")
handle = tool.Handle
sound = handle.Sound
plrs = game:GetService("Players")
preId = nil
abilityDb = false -- true
db = false
plr = nil
char = nil
hum = nil
torso = nil

sounds = {
	hit1 = "rbxassetid://7441132956";
	hit2 = "rbxassetid://7441133345";
	hit3 = "rbxassetid://7441133912";
	swing1 = "rbxassetid://8838460866";
	swing2 = "rbxassetid://8838463024";
	swing3 = "rbxassetid://8838463387";
	crush1 = "rbxassetid://7441130752";
	crush2 = "rbxassetid://7441129853";
	crush3 = "rbxassetid://7441129469";
}

function CheckIfAlive()
	local Player = plr
	local Character = char
	local Humanoid = hum
	local Torso = torso
	return (((Player and Player.Parent and Character and Character.Parent and Humanoid and Humanoid.Parent and Humanoid.Health > 0 and Torso and Torso.Parent) and true) or false)
end

config = {
	damage = 20;
	toolDelay = 1;
	abilityDelay = 25;
	ability = function()
		if CheckIfAlive() then
			local s, r = pcall(function()
				sound:Play()
				while sound.IsPlaying do
					torso.CFrame = CFrame.new(torso.Position, torso.Position+ torso.CFrame.LookVector) * CFrame.new(Vector3.new(0,0,-1) * 5)
					task.wait(.125)
				end
			end)
			if not s and r then
				print(r)
			end
		end
	end;
}

--[[
local abilityWait = coroutine.wrap(function()
	task.wait(config.abilityDelay)
	abilityDb = false
end)
abilityWait() ]]

local randomId = math.random(100000, 999999)

local idLoop = coroutine.wrap(function()
	while task.wait(1) do
		local randomGUID = game:GetService("HttpService"):GenerateGUID()
		tool:SetAttribute("ABILITY_ID_"..tostring(randomId), randomGUID)
		local preSet = coroutine.wrap(function()
			task.wait()
			preId = randomGUID
		end)
		preSet()
	end
end)
idLoop()

tool.Equipped:Connect(function()
	char = tool.Parent
	plr = plrs:GetPlayerFromCharacter(char)
	hum = char:FindFirstChildOfClass("Humanoid")
	torso = char:FindFirstChild("Torso") or char:FindFirstChild("HumanoidRootPart")
	local function abilityButton1()
		local plrGui = plr:WaitForChild("PlayerGui")
		local ability = plrGui:WaitForChild("Ability")
		ability.Enabled = true
	end
	abilityButton1()
end)

tool.Unequipped:Connect(function()
	local function abilityButton2()
		local plrGui = plr:WaitForChild("PlayerGui")
		local ability = plrGui:WaitForChild("Ability")
		ability.Enabled = false
	end
	abilityButton2()
end)

tool.Activated:Connect(function()
	if not db and CheckIfAlive() then
		db = true
		local Anim = Instance.new("StringValue")
		Anim.Name = "toolanim"
		Anim.Value = "Slash"
		Anim.Parent = tool
		local randomSwingSound = math.random(1, 3)
		if randomSwingSound == 1 then
			sound.SoundId = sounds.swing1
		elseif randomSwingSound == 2 then
			sound.SoundId = sounds.swing2
		elseif randomSwingSound == 3 then
			sound.SoundId = sounds.swing3
		end
		sound:Play()
		local plrsHit = {}
		attackFunc = handle.Touched:Connect(function(part)
			local s, r = pcall(function()
				if part.Parent and part.Parent:IsA("Model") and part.Parent:FindFirstChildOfClass("Humanoid") and #plrsHit <= 0 then
					local otherChar = part.Parent
					local otherPlr = plrs:GetPlayerFromCharacter(otherChar)
					if not otherPlr or otherPlr.UserId ~= plr.UserId then
						local otherHum = otherChar:FindFirstChild("Humanoid")
						if otherHum.Health > 0 then
							local otherHrp = otherChar.PrimaryPart
							if (otherHum.Health - config.damage) > 0 then
								local randomHitSound = math.random(1, 3)
								if randomHitSound == 1 then
									sound.SoundId = sounds.hit1
								elseif randomHitSound == 2 then
									sound.SoundId = sounds.hit2
								elseif randomHitSound == 3 then
									sound.SoundId = sounds.hit3
								end
							elseif (otherHum.Health - config.damage) <= 0 then
								plr.leaderstats.Kills.Value += 1
								local randomCrushSound = math.random(1, 3)
								if randomCrushSound == 1 then
									sound.SoundId = sounds.crush1
								elseif randomCrushSound == 2 then
									sound.SoundId = sounds.crush2
								elseif randomCrushSound == 3 then
									sound.SoundId = sounds.crush3
								end
							end
							local soundClone = sound:Clone()
							soundClone.Parent = otherHrp
							soundClone:Play()
							local soundCoro = coroutine.wrap(function()
								soundClone.Ended:Wait()
								soundClone:Destroy()
							end)
							soundCoro()
							plrsHit[#plrsHit+1] = otherChar.Name
							plr.leaderstats.Hits.Value += 1
							otherHum.Health -= config.damage
						end
					end
				end
			end)
		end)
		task.wait(config.toolDelay)
		attackFunc:Disconnect()
		table.clear(plrsHit)
		if Anim then 
			Anim:Destroy() 
		end
		db = false
	end
end)

if ability then
	ability.OnServerEvent:Connect(function(plr, id)
		if tostring(id) == tostring(tool:GetAttribute("ABILITY_ID_"..randomId)) or tostring(id) == tostring(preId) then
			if not abilityDb then
				abilityDb = true
				local abilityCoro = coroutine.wrap(function()
					config.ability()
				end)
				abilityCoro()
				task.wait(config.abilityDelay)
				abilityDb = false
			end
		end
	end)
end

tool.GetIfReady.OnServerInvoke = function()
	if abilityDb then
		return false
	else
		return true
	end
end

Is this a localscript or a serverscript? Because I noticed that in the video you’re turning your camera with shiftlock, which the server might not detect (idk)

Edit: I tried it my code on a serverscript and i still worked so idk.

You’re probably right, its a serverscript. How do I fix this? Can I perhaps use a RemoteFunction to get the player’s orientation on the client and transfer it to the server?

I don’t actually think that it mattered if it was a serverscript for updating the position, but this should really be done entirely on the client. Theres no reason to handle this on the server, as the client is perfectly capable of repositioning the character with humanoidRootPart or Torso.

The problem is that its hard to replicate whats happening on the server side of the tool onto the client.

Not really. Its actually much better to handle tools on the client. Heres an example of a very simple localscript that does this just fine:

local lplr = game:GetService("Players").LocalPlayer
task.wait(0.1)
local tool = script.Parent
local sound = script.Sound

local speed = 10

tool.Activated:Connect(function()
	if lplr.Character == nil then
		return
	end
	local hrp = lplr.Character:FindFirstChild("HumanoidRootPart")
	if hrp == nil then
		return
	end
	sound.Playing = true
	while sound.IsPlaying do
		task.wait(0.5)
		hrp.CFrame = CFrame.new(hrp.Position, hrp.Position + hrp.CFrame.LookVector) * CFrame.new(Vector3.new(0,0,-1) * speed)
	end
end)

I can’t transfer a 200 line server script to a local script.

Not all of your script needs to be a localscript. Just handling the player using the tool needs to be done on the client and detected by the server with remotes. I still would handle the player movement on the client even though it might work with remotes on the server. Of course it’s entirely up to you if you feel like converting the handling to the client; don’t do it if you don’t feel up to it. I think I have given a perfectly fine solution though, so you can mark my answer as the solution and close this topic or keep waiting for a new solution. Regardless of your choice, I wish you a good rest of your day/evening.