Confusing server side lag

I have an issue with my server side knockback system, it works fine on npcs, however I noticed that when the knockback is applied to a player all other players see an extremely delayed version. this sort of makes sense if the velocity was applied on the client, however its on the server.


local function PhysicsOwnership(Attacker, Victim)
	local pl1 = players:GetPlayerFromCharacter(Victim)
	if pl1 == nil then
		local pl2 = players:GetPlayerFromCharacter(Attacker)
		
		if pl2 then return pl2, "Attacker player"
			
		else
			return nil, "No player"
		end
		
	else
		return pl1, "Victim player"
	end
end


function Knockback.Knockback(Character, Target, Distance, Lifetime)
	Lifetime = Lifetime or 0.3

	local plr, result = PhysicsOwnership(Character, Target)

	local CharacterRoot = Character:FindFirstChild("HumanoidRootPart")
	local Root = Target:FindFirstChild("HumanoidRootPart")

	local BodyVelocity = Instance.new("BodyVelocity")
	BodyVelocity.MaxForce = Vector3.new(80000, 0, 80000)
	BodyVelocity.Velocity = CharacterRoot.CFrame.LookVector * Distance
	BodyVelocity.Parent = Root

	task.delay(Lifetime, function()
		if BodyVelocity then
			BodyVelocity:Destroy()
		end
	end)
	
	

		

	return BodyVelocity
	
	
end

try applying the velocity on the players client because Roblox replicates characters physics to the server smoothly (which is why flying exploits work)

you can achieve this using a RemoteEvent also, maybe look into LinearVelocity because BodyVelocity is deprecated.

1 Like

This is happening because player characters are owned by the client. When you add a bodymover on the server it won’t appear active until it replicates to the client and then streams to the server from the client.

RemoteEvents are the way to go for this like the person above me has stated. Similarly, LinearVelocity is the more modern equivalent of BodyVelocity, though you will need an Attachment for that to work.

1 Like

Hello again, as you can see from the video the knockback is inconsistent even when i fire it to the client. I used body velocity, but I also tested it with linear velocity and received little difference. basically on the server script it checks if the victim is a player if it is then it fires a remote to handle the knockback on the client.

Server side script


local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local debris = game:GetService("Debris")
local players = game:GetService("Players")

local Knockbackremote = ReplicatedStorage.Client.Remotes.KnockBack


local Cache




local function PhysicsOwnership(Attacker, Victim)
	local pl1 = players:GetPlayerFromCharacter(Victim)
	if pl1 == nil then
		local pl2 = players:GetPlayerFromCharacter(Attacker)
		
		if pl2 then return pl2, "Attacker player"
			
		else
			return nil, "No player"
		end
		
	else
		return pl1, "Victim player"
	end
end



local Knockback = {}


function Knockback.Knockback(Character, Target, Distance, Lifetime)
	Lifetime = Lifetime or 0.3

	local plr, result = PhysicsOwnership(Character, Target)

	local CharacterRoot = Character:FindFirstChild("HumanoidRootPart")
	local Root = Target:FindFirstChild("HumanoidRootPart")

	if result == "Attacker player" then

		Root:SetNetworkOwner(plr)
		
		RunService.Heartbeat:Wait()

		Knockbackremote:FireClient(plr, Character, Target, Distance, Lifetime)

		task.delay(Lifetime + 0.15, function()
			Root:SetNetworkOwner(nil)

		end)

	elseif result == "Victim player" then
		Knockbackremote:FireClient(plr,Character, Target, Distance, Lifetime, tick())

	elseif result == "No player" then

		local BodyVelocity = Instance.new("BodyVelocity")
		BodyVelocity.MaxForce = Vector3.new(80000, 0, 80000)
		BodyVelocity.Velocity = CharacterRoot.CFrame.LookVector * Distance
		BodyVelocity.Parent = Root

		task.delay(Lifetime, function()
			if BodyVelocity then
				BodyVelocity:Destroy()
			end
		end)

		return BodyVelocity
	end
	
	
end



function Knockback.Init(ModulesCache)
	Cache = ModulesCache
end

function Knockback.Start()

end



return Knockback

Client side

local Knockbackremote = game.ReplicatedStorage.Client.Remotes.KnockBack


Knockbackremote.OnClientEvent:Connect(function(Character, Target, Distance, Lifetime)
	local BodyVelocity = Instance.new("BodyVelocity")
	BodyVelocity.MaxForce = Vector3.new(80000, 0, 80000)
	BodyVelocity.Velocity = Character.HumanoidRootPart.CFrame.LookVector * Distance
	BodyVelocity.Parent = Target.HumanoidRootPart

	task.delay(Lifetime or 0.2, function()
		BodyVelocity:Destroy()
		BodyVelocity = nil
	end)

	return BodyVelocity
	
end)

You could try doing client side prediction. Essentially applying the knockback animation on the attacking player’s client as it’s registered on the attacking client.

This roblox doc about client prediction may help you: Server authority model | Documentation - Roblox Creator Hub