How do you get predicted Server Position from Client (Client-side Prediction)

I stumbled upon this problem when creating Combat with Client-side Prediction. So in my game you have Client hit registration and Server hit registration.

I’m trying to calculate the HumanoidRootPart’s position on the Server from the Client.

I’ve attempted from creating a part on the Server set the CFrame of that Part to the HumanoidRootPart in a HeartBeat and when that gets replicated to the client it’ll show the ping delayed version of their HumanoidRootPart, but that wasnt reliant. It tend to be inaccurate.

I also made it one on the client where it created a Part and a Heartbeat function it’d task.wait(oneWayPing) (player:GetNetworkPing()) before setting the Part.CFrame to the HumanoidRootPart.CFrame

In this video, Damage is Server, Hit Effects are Client.

Remember there are two Hit Registrations, Client and Server.
Client focuses on Hit Effects (Blood)
Server focuses on Damage.

The first two hits are registered on the server, but not on the client. This is because the Client backed up and it didn’t update to the server in time.

Since I have moved back on the Client the Server doesn’t see this because of lag. It does the damage but because the client backed up in a split second, it doesn’t register effects on client.

The way to sync these two is the Client predicting it’s position on the server and uses that for Hit Effects.


The solution I’m trying to find is calculating HumanoidRootPart.CFrame on the Server using the Client and ping.

5 Likes

My reply might not fully answer your question but I’m giving it a shot. I understand you’re trying to predict the client’s position on the server so you can accurately display client-side effects, such as blood from the sword impact, but why do it like that?

Maybe I’m thinking too simple here, but couldn’t you just tell the client via RemoteEvent when they’ve successfully hit something then do the effects based on the received event?

3 Likes

They would have a delayed response. This is with using Events

The client side prediction reduces the delay by half. So what you see is a reduced version of the delay because the client-side prediction will compensate a little bit for it.

This is with using Client-side Prediction

My inputs have Client-side Prediction so when I click it doesn’t have a delay it does it instantly, same as the effects.

Here is with no Delay Compensation for Hit Registration

1 Like

The combat utilizes Netcode
If you want you can read about it here.

1 Like

Tried making a script; looks like it works but I’m not sure. I multiplied GetNetworkPing by 2 because it was returning half of the ping displayed in the F3 menu but I don’t know if that was necessary.
Local script parented to StarterCharacterScripts

local runService = game:GetService("RunService")
local player = game:GetService("Players").LocalPlayer

local humanoidRootPart = script.Parent:WaitForChild("HumanoidRootPart")
local predictionPart = humanoidRootPart:Clone()
predictionPart.Transparency = 0.5
predictionPart.Anchored = true
predictionPart.CanCollide = false
predictionPart:ClearAllChildren()
predictionPart.Name = "PredictionPart"
predictionPart.Parent = script.Parent

runService.RenderStepped:Connect(function()
	local pingInSeconds = player:GetNetworkPing() * 2
	local predictedPosition = humanoidRootPart.Position + humanoidRootPart.AssemblyLinearVelocity * pingInSeconds
	local predictedOrientation = humanoidRootPart.Orientation + humanoidRootPart.AssemblyAngularVelocity * pingInSeconds
	predictionPart.CFrame = CFrame.new(predictedPosition) * CFrame.Angles(math.rad(predictedOrientation.X), math.rad(predictedOrientation.Y), math.rad(predictedOrientation.Z))
end)

The script predicts where the player will be based on the ping by utilizing the velocity of the player multiplied by the ping in seconds. If the player has a ping of 1000ms (1 second) and a walkspeed of 16 studs/second, the predicted position will be 16 studs in the direction the player is walking because that’s the theoretical distance they will move in 1 second. This isn’t entirely reliable due to many factors. The script has no way of knowing if the player will stop going in that direction, whether or not any physical obstacles are in the way, or if something else changes their position on the server such as the player being knocked in a different direction.

3 Likes

That’s a good attempt. This script you made predicts where you will be in the future based on your ping. Not where you are currently on the Server. The client is always ahead, so the prediction should be behind you instead of in front.

It should look something similar to this, but this isn’t reliant.


In the video it predicts where you are on the Server, but not reliant. If the user’s ping is too high it is totally off prediction.

2 Likes

How are you doing the hitboxes? Also if you were to use the server-client way use an unreliable event instread.

1 Like

It uses Client-side Prediction, so the combat runs parallel on the Server and Client.

Hitboxes are Calculated on the Server and Client. Server focuses on damage, Client focuses on visual effects. Unreliable events would have delayed feedback on high ping players. As seen from a clip above.

The Client and Server are not meant to talk to each other as much. When they do it’s correction and rollback. Here is the Server and Client shared code

They would have to not talk to each other using events as soon as the server registers a hit. If they did it would provide significant delay. So they would have to predict each other.

function SwordCore:_registerHit(settings)
	local character = self.Character
	local humanoidRootPart: Part = character:FindFirstChild("HumanoidRootPart")
	
	if humanoidRootPart then
		settings = settings or {
			Radius = 9.5,
			Angle = math.rad(150),
			RadiusAngleDecay = 1.05
		}
		
		local radius = settings.Radius
		
		local dotProductAngle = mathCos(settings.Angle)
		
		local humanoidRootPartCFrame = humanoidRootPart.CFrame
		local originPosition, lookVector = humanoidRootPartCFrame.Position, humanoidRootPartCFrame.LookVector
		
		local dotProduct = lookVector.Dot
		local characters = collectionService:GetTagged("Character")
		
		local radiusAngleDecay = settings.RadiusAngleDecay
		
		local targets = {}
		for i = 1, #characters do
			local target = characters[i]
			if target == character then continue end
			
			local targetHumanoidRootPart = target:FindFirstChild("HumanoidRootPart")
			if targetHumanoidRootPart then
				local difference = (targetHumanoidRootPart.Position - originPosition)
				local distance = difference.Magnitude
				if distance < radius then
					local targetProduct = dotProduct(lookVector, difference.Unit)
					if targetProduct > dotProductAngle and distance < radius/(mathAcos(targetProduct) * radiusAngleDecay) then
						targets[#targets + 1] = target
					end
				end
			end
		end
		
		if #targets > 0 then
			if isServer then
				self:_damageTargets(targets, 15)
			else
				VisualEffects.Character:Emit("SwordBleed", targets, self.Sounds.Hit)
				VisualEffects.Character:PlayAnimation(targets, self.Animations.Hit)
			end
		end
	end
end

What the combat input (similar) looks like as a flowchart from Netcode - Wikipedia

Would this be okay? Also the particles might be delayed because I’m bad at making particles.
robloxapp-20240702-1027024.wmv (387.8 KB)
(sorry for bad quality and incorrect format)

Also here’s the file if you want to see it. I rushed it so it’s not really organized. Basically I did client (input) → server which used a raycast hitbox module → client (effects)
SwordTest.rbxl (98.0 KB)

1 Like

This goes against Client-side Prediction Netcode. What you made is a problem that every game has.
Input’s should not be processed through the server.

These clips both have players on 2000 ping (2 seconds lag)

This is an example of the same technique you used but on High Ping


This is an example using Client-side Prediction to fix this issue


The problem I’m trying to solve is getting the HumanoidRootPart’s CFrame on the Server using the Client. The Client has to predict where It is on the Server which is ping second behind it’s actual character. It’s networking that i’m trying to solve.

1 Like

Can you show an example when you’re actually hitting something? The videos are just showing the animations which can just be moved to the client. I see what you mean though, sorry for the misunderstanding.

1 Like

This is the first clip of this post

It shows a person attacking, then backing up.

The problem is that the Client and Server have different HumanoidRootPart positions, this is because it takes times to send information from Client to Server (Network Ownership)

The Client backed up, before it registered the hit. So it didnt play the effects.
The Server didn’t get the memo in time so it registered the hit and did the damage.

You cannot use ordinary Event’s to address this issue, because they take time to send messages.


This here is an example using Events (Half Server Combat)

This here is an example using Client-side Prediction (Netcode) [Parallel Server and Client Combat]


The problem is in the First clip where when you move too much on the client, the server is delayed and doesn’t get the memo of the character movement in time.

1 Like

Here is another example

Both players have 100+ ping, but are still synced with no delay. This is because of Client-side Prediction. The Hitboxes are inaccurate because they are calculated on the Server and Client (Client-side Prediction) The Client moves their humanoidrootpart in that 0.1 second time frame. The server within that 0.1 second time frame, hasnt seen the client moved yet because of their ping. It takes time to send information. So the problem is that the Client needs to predict where it is on the server.

I don’t think you understand. The Combat is mainly Client. If you modify the Server it wont change the clients, unless the Server fires events to update its client to the server (Server Reconciliation). If an exploiter were to exploit the client combat, they cannot because the server will not tell the other clients to update their screens.

There’s two combat classes. Client (You) and Server (Server) If you do something on the client, it’ll do it on the client. then send a message to the server while your still doing it. If you’re not allowed to then it’ll revert that movement. If you are the Server will try to copy and sync with you. This helps people with high ping. The combat CANNOT be exploited because if you try to do something your not, YOU have the copy of the server’s combat. So if the server tries to copy you but it cannot because of some arguments. Then it’ll revert you.


You don’t see this type of combat in other games because it is difficult to implement.

High difficulty, high reward.

I remind again, its client based combat with server validation (CLIENT SIDE PREDICTION) (NETCODE)


IT IS A NETWORKING ISSUE NOT A SKILL ISSUE (IM A VERY EXPERIENCED DEVELOPER)

2 Likes

All animations are already client-sided. Nothing you see is Server-sided. The server hides everything and only validates information. Mainly because it is (CLIENT-SIDE PREDICTION)

I repeat CLIENT-SIDE PREDICTION. There Server only validates information because that’s the most optimized thing it can do. The other clients worry about syncing and visuals.

I remind, you cannot use ordinary server combat code (What every game uses, IT DOESNT BENEFIT HIGH PING/LAG PLAYERS)

I have custom animation replication. So if an exploiter were to play an animation without permission it gets blocked by the other clients NOT THE SERVER other clients. It doesn’t get blocked by the server because it can be used for Anti-cheat/Punishment/Flagging


Almost every game uses Server-based combat. Mine uses Client-side prediction, this helps players with high ping not feel like they are on high ping. Very big companies use this technique such as Triple A Games (AAA).

Server-based combat means, animations is played on the server, server controls and does calculations while the client only sends inputs.

Client-side Prediction is where when the Combat is both ran on the Server and Client and they will sync each other up. If the client Attacks, the server validates then Attacks (Not shown) then sends other clients to Attack on their screen and sync.

2 Likes

Ah I see. I was just trying to take the lazy way out. Sorry for wasting your time and good luck. I’ll let you know if I find anything :wink:

I found this:

1 Like

What’s the latency of the client? If I’m reading things correctly, it seems most of the clips are taken with 400+ ping, which honestly, I think is a lost cause.

1 Like

In the 2nd latest reply i sent above with a clip shows two players with 100 ping. It shows the differences in hit reg. damage and visual

1 Like

I created a really accurate version of what I’m looking for.
I just have to apply Server Reconciliation to it.

Here is the code if anyone wants it.

local players = game:GetService("Players")
local runService = game:GetService("RunService")

local player = players.LocalPlayer
local character = player.Character

local humanoidRootPart = character:WaitForChild("HumanoidRootPart") :: Part

local clientPredictionRootPart = Instance.new("Part")
clientPredictionRootPart.Name = "ClientPredictionRootPart"
clientPredictionRootPart.Anchored = true
clientPredictionRootPart.CanCollide = false
clientPredictionRootPart.CanTouch = false
clientPredictionRootPart.CanQuery = false
clientPredictionRootPart.EnableFluidForces = false
clientPredictionRootPart.Massless = true
clientPredictionRootPart.Locked = true
clientPredictionRootPart.Material = Enum.Material.SmoothPlastic
clientPredictionRootPart.Color = Color3.new(1, 0, 0)
clientPredictionRootPart.Size = Vector3.new(2, 2, 1)
clientPredictionRootPart.CastShadow = false
clientPredictionRootPart.Parent = character

local taskWait = task.wait
runService.Heartbeat:Connect(function()
	local savedCFrame = humanoidRootPart.CFrame

	local ping = player:GetNetworkPing()
	taskWait(ping * 2)
	
	clientPredictionRootPart.CFrame = savedCFrame
end)
5 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.