How do I Prevent Server Authority rollback to snap my character positivo back on a Double Junp ability?

I made a script that enables DoubleJump if the player has an item, which can stack for more doublejumps.

It works, but because I want the game to use Server Authority, and I made the jump action replicate to the server, the character snaps back to the server position when jumping. Here’s a video showing the Issue:

Is there a way to make this double jump smoother while still having the server authority?
Here’s the code I made:

Client Code

UIS.InputBegan:Connect(function(input,process)
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if input.KeyCode == Enum.KeyCode.Space then
			if char.Humanoid.Health > 0 then
				local runStats = char:FindFirstChild("Stats")
				if runStats then
					if char.Humanoid.FloorMaterial == Enum.Material.Air then
						local charges = char:FindFirstChild("ClientDoubleJumpCharges")
						if not charges then
							charges = Instance.new("IntValue")
							charges.Name = "ClientDoubleJumpCharges"
							charges.Parent = char
						end
						local doubleJumpItem = runStats.Inventory:FindFirstChild("7")
						if doubleJumpItem and doubleJumpItem.Value > charges.Value then
							charges.Value+=1
							char.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
							local realShot = game.ReplicatedStorage.Remote.Events.DoubleJump:FireServer()
							
						end
						char.Humanoid:GetPropertyChangedSignal("FloorMaterial"):Once(function()
							if charges then charges.Value = 0 end
						end)
					end
				end
			end
		end
	end
end

Server Code

game.ReplicatedStorage.Remote.Events.DoubleJump.OnServerEvent:Connect(function(player)
	local char = player.Character
	if char and workspace:IsAncestorOf(char) and char.Humanoid.Health > 0 then
		local runStats = char:FindFirstChild("Stats")
		if runStats then
			local char = player.Character
			if char then
				local runStats = char:FindFirstChild("Stats")
				if runStats then
					if char.Humanoid.FloorMaterial == Enum.Material.Air then
						local charges = char:FindFirstChild("DoubleJumpCharges")
						if not charges then
							charges = Instance.new("IntValue")
							charges.Name = "DoubleJumpCharges"
							charges.Parent = char
						end
						local doubleJumpItem = runStats.Inventory:FindFirstChild("7")
						if doubleJumpItem and doubleJumpItem.Value > charges.Value then
							char.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
							charges.Value+=1
						end
						char.Humanoid:GetPropertyChangedSignal("FloorMaterial"):Once(function()
							if charges then charges.Value = 0 end
						end)
					end
				end
			end
		end
	end
end)

Instead of using Remote Events, use the Input Action System, and create your system under BindToSimulation.

Using IAS, you can create an InputContext which contains an InputAction, which you can use to detect the double jump action. Use however many InputBindings under this InputAction to connect this action to any key or button that you want.

And then under BindToSimulation, on both the server and the client, get the current value of this action, and use it to determine if the user has requested a double jump action, and if they did, apply the action.

These methods allow you to achieve a synchronized character state on both the server and the client with minimal mispredictions.

More information can be found in here:

If you need examples, I have created some under this documentation, with more to come:

1 Like

It worked Perfectly with this code, but only in Studio test. When I actually play It skill gives the rollback Flicker, even If a bit less common
Client Side

local charContexts = player:WaitForChild("InputContexts"):WaitForChild("CharacterContext")
local jumpAction = charContexts:WaitForChild("JumpAction")
jumpAction.Pressed:Connect(function()
	if char.Humanoid.Health > 0 then
		local runStats = char:FindFirstChild("Stats")
		if runStats then
			if char.Humanoid.FloorMaterial == Enum.Material.Air then
				local charges = char:FindFirstChild("ClientDoubleJumpCharges")
				if not charges then
					charges = Instance.new("IntValue")
					charges.Name = "ClientDoubleJumpCharges"
					charges.Parent = char
				end
				local doubleJumpItem = runStats.Inventory:FindFirstChild("7")
				if doubleJumpItem and doubleJumpItem.Value > charges.Value then
					charges.Value+=1
					char.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
					local realShot = game.ReplicatedStorage.Remote.Events.DoubleJump:FireServer()
				end
				char.Humanoid:GetPropertyChangedSignal("FloorMaterial"):Once(function()
					if charges then charges.Value = 0 end
				end)
			end
		end
	end
end)

Server Code

game.Players.PlayerAdded:Connect(function(player)
	local stat = script.Stats:Clone()
	stat.Parent = player
	local charContexts = player:WaitForChild("InputContexts"):WaitForChild("CharacterContext")
	local jumpAction = charContexts:WaitForChild("JumpAction")
	jumpAction.Pressed:Connect(function()
		local char = player.Character
		if char and char.Humanoid.Health > 0 then
			local runStats = char:FindFirstChild("Stats")
			if runStats then
				if char.Humanoid.FloorMaterial == Enum.Material.Air then
					local charges = char:FindFirstChild("DoubleJumpCharges")
					if not charges then
						charges = Instance.new("IntValue")
						charges.Name = "DoubleJumpCharges"
						charges.Parent = char
					end
					local doubleJumpItem = runStats.Inventory:FindFirstChild("7")
					if doubleJumpItem and doubleJumpItem.Value > charges.Value then
						charges.Value+=1
						char.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
					end
					char.Humanoid:GetPropertyChangedSignal("FloorMaterial"):Once(function()
						if charges then charges.Value = 0 end
					end)
				end
			end
		end
	end)
end)