Hello forum! I am having issues while scripting my volleyball game. In my game, there is a server ball and a client ball. The server uses Heartbeat to move the ball, while the client uses Renderstepped. The problem is that the server and the client have different deltatimes, meaning that the frames of the lerp are not synchronized. This may not seem like a big issue, but there are instances where the client ball goes over the net but the server ball hits the net and vice versa. Currently, I am using a raycast to detect if the net is in front of the ball, but due to frame inconsistencies, this method isn’t very reliable.
I have thought about making a part that follows the path the ball will take and detect if the part touches the net, but I’m not sure how I would do that.
Any possible solutions are appreciated! Thank you!
Hi Kilp,
These issues are common, and I believe the most adopted solution is giving authority to either the client, or the server.
There will almost always be a gap in the server heartbeat and client framerate, it’s a lot of factors like hardware, running software, and game optimization.
Therefore, giving one side (usually the server) the authority and right to decide the outcome of any inconsistencies is usually the go to.
You might’ve already experienced this in fighting games, when you see a move that you should’ve landed but didn’t, or landed a move when they were nowhere near you. This is a combination of latency, and server authority.
So in this case, I would just trust the server, and have it replicate the accurate position of the ball to all the clients. It might look a bit funky on the client, but it’ll be more fair and function better that way.
Could we see how you are doing the “movement” both in the server and the client?
Are you moving the ball in the server, but doing the rendering on the client?
I would like to make it as smooth as possible on the client though
Are you incorporating the deltatime into the lerp?
Yes I am (texttextetexttexttetxtetxtetxt)
Im moving it on both the server and the client
May I see how you incorporate it?
How does that work exactly – could we see code? (like what @guy56890 said)
Sure
Server script:
con = runs.Heartbeat:Connect(function(dt)
stillupd = true
i +=dt/data.increaseval local suc, err = pcall(function()
if not data.ball or data.ball:GetAttribute("CanUpdateLerp") == false then con:Disconnect() end
end)
if not suc then
print(err)
con:Disconnect()
end
if data.ball:GetAttribute("LerpID") ~= lerpid then print("discon");con:Disconnect() return end
if (data.ball.Position - data.c2.p).Magnitude < 3 then con:Disconnect() return end
local rayparams = RaycastParams.new()
rayparams.CollisionGroup = "ServerBall"
rayparams.IgnoreWater = true
local rayres = workspace:Raycast(data.ball.Position, data.ball.CFrame.LookVector * 3,rayparams )
if rayres and rayres.Instance then
if rayres.Instance.Name == "Net" then
if not netcon then
c1 = data.ball.CFrame
netcon = runs.Heartbeat:Connect(function()
local succ, err = pcall(function()
if data.ball == nil or data.ball:GetAttribute("CanUpdateLerp")== false then netcon:Disconnect(); con:Disconnect() return end
end)
if not succ then
netcon:Disconnect()
end
if data.ball:GetAttribute("LerpId") ~= lerpid then netcon:Disconnect(); con:Disconnect() return end
if (Vector3.new(data.ball.Position.X, data.ball.Position.Y, 0) - Vector3.new(c2.X, c2.Y, 0) ).Magnitude < 3 then netcon:Disconnect(); con:Disconnect() return end
data.ball.CFrame = CFrame.new(c1:Lerp(c2, i * 2).X, c1:Lerp(c2, i *2).Y, rayres.Instance.Position.Z - char.HumanoidRootPart.CFrame.LookVector.Z * 2)
end)
return
end
end
end
if not netcon then
data.ball.CFrame = CFrame.lookAlong(data.c1:Lerp(data.c2, i *5 ).p, data.ball:GetAttribute("LastLV"))
end
end)
Client:
con = runs.Heartbeat:Connect(function(dt)
stillupd = true
i += dt/increase
if ball.Parent.Parent == nil or ball.Parent:GetAttribute("CanUpdateLerp") == false or ball:GetAttribute("LerpID") ~= lerpid then con:Disconnect(); print(ball.Parent:GetAttribute("CanUpdateLerp")) return end
if (ball.Position - c2.p).Magnitude < 3 then ball:SetAttribute("LerpID", nil);con:Disconnect(); return end
local rayparams = RaycastParams.new()
rayparams.CollisionGroup = "ServerBall"
rayparams.IgnoreWater = true
local rayres = workspace:Raycast(ball.Position, ball.CFrame.LookVector * 3,rayparams ) or workspace:Raycast(char.HumanoidRootPart.Position, frontraycast, rayparams)
if (rayres and rayres.Instance) then
if rayres.Instance.Name == "Net" then
if not netcon then
c1 = ball.CFrame
netcon = runs.RenderStepped:Connect(function()
if ball.Parent:GetAttribute("CanUpdateLerp")== false then netcon:Disconnect() return end
if (Vector3.new(ball.Position.X, ball.Position.Y, 0) - Vector3.new(c2.X, c2.Y, 0) ).Magnitude < 3 then netcon:Disconnect() return end
ball.CFrame = CFrame.new(c1:Lerp(c2, i *2).X, c1:Lerp(c2, i*2).Y, rayres.Instance.Position.Z - char.HumanoidRootPart.CFrame.LookVector.Z * 2)
end)
end
end
return
end
if not netcon then
ball.CFrame = CFrame.lookAlong(c1:Lerp(c2, i * 5).p, lv)
end
end)
Also heres a video of the issue:
https://gyazo.com/7ec1769eaef355e80a92e30ec07db609
Could you explain to me what I’m looking at here?
Basically the server ball is detected on the client, the client hits the client ball, then the server ball is sent to the server, the server hits the ball, and finally the server ball is sent to all the other clients and they hit the client ball. Th server ball is the parent to the client ball, buit every client has a different client ball.
So what are all the uh, different colors of balls?
The red one is the server ball and the fully visible one is the client ball
This seems also to maybe be an issue with the raycast. It could be that one frame, they raycast doesn’t hit anything, however the next frame it’ll have skipped over it during the speed, and therefore the raycast wouldve been ineffective.
It could also be that you have the client calculations done on Heartbeat, instead of RenderStepped. This results in the object being moved after all the physics calculations have been done, and perhaps moving it to RenderStepped would provide a more desirable outcome.
I dont think thats the problem because I only just changed it to heartbeat to see if it would fix my problem, which it didnt
I also think thats what the issue is
I ended up fixing it by raycasting on the client right before the lerp starts and if nothing is detected on that raycast, the server takes over completely. I also made it so that you cant hit the ball if it is behind you, even if it is in the hitbox. There are still some minor issues, but the main ones are gone for the most part.