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.
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.
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
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.