Serious shot replication problem [video]


I’m making a Multiplayer FPS game and I’ve just started making the part of the Weapons and of the shots.

Having a Client and a Server, this is what happens when both shoot in the game:

Calmly, let’s analyze this together.

Part 1: The Server shoots
The Server shoots the first shot: only the Server can see it.
The Server shoots the second shot: now also the Client can see it.

Part 2: The Client shoots
The Client shoots the first shot: only the Server can see it.
The Client shoots the second shot: now also the Client can see it.

As you notice, the Client looks a bit retarded (no, not offending him)

I’ve uploaded a video on YouTube that shows better the issue:

As you can see at 1:01, the Server sees the Client’s shots in the correct location!

How do I draw those DebugPoints?

When the Weapon shoots, I call the Trace function on the Server side (A new, community-hosted Unreal Engine Wiki - Announcements - Unreal Engine Forums).

After the trace, the Server calls a NetMulticast RPC function which shows red DebugPoints if the Server and blue DebugPoints if the Client:

Some tags: @eXi @TheJamsh

New information that will probably make easier to find the issue: I am printing a DebugMessage everytime someone shoots.
The DebugMessage contains the X and Y coordinates of the HitResult.

After shooting multiple times both on the Server and on the Client, I notice that the HitResult on the client is always 0!

I think this has something to do with network lag.

When you call that Multicast, the Client hasn’t updated the HitResult variable yet. That’s why it always lags behind 1 shot, and why some people use OnRep_Notify instead of a Multicast, especially if that multicast uses a recently updated variable.

If you don’t want to use OnRep_Notify, you will have to actually pass that HitResult through the Multicast, instead of it being a replicated variable.

I’m mainly a Blueprints guy but if I had to guess what that would look like in C++ it would be this:

void AWeapon::MarkDecal_Implementation(HitResult *hr)
if (Role == ROLE_Authority)
DrawDebugPoint(GetWorld(), hr.ImpactPoint, 20.0f, FColor::Red, true);
DrawDebugPoint(GetWorld(), hr.ImpactPoint, 20.0f, FColor::Blue, true);

The question is can you do this in C++? I know you can pass parameters through Multicast events in Blueprints.

I tried passing the HitResult as const reference to the MultiCast function, but I get always the exact same problem.

If I wanted to use a OnRep_Notify variable, how should I do it?

I mean, i set the FHitResult variable like this:

UPROPERTY(ReplicatedUsing = OnRep_HitResult)
	FHitResult HitResult;

	void OnRep_HitResult();

And then? In the OnRep_HitResult() function what should be put? :confused:

And this is the Weapon->StartFire() function that gets called by the Character when he presses the LeftMouseButton:

With the hope the bug comes out :frowning:

In the OnRep_HitResult function, do the DrawDebugPoint. The function will only be called when the variable is updated. And this way, the client should know what the updated hit result is before it tries to draw the point.

Ok now the Server isn’t able to see his own DebugPoints, while the Client can see both his DebugPoints and those of the Server.

Why isn’t the Server able to see anything?

Oh, according to, the OnRep doesn’t get called on the server. So you will have to have the server call it’s own DrawDebugPoint in your StartFire function. Make sure only the server calls the DrawDebugPoint in your StartFire function so the Client doesn’t draw two points.

@ToxinGaming okay I’ve called the OnRep_HitResult() on the server… dunno if it’s a good pratice but it works! thanks very much dude!

Glad you were able to get it working. Now I have to figure out my own networking issues :stuck_out_tongue:

I’d help you, but unfortunately I’m very noob with UE Networking

Yeah, I’d also consider myself a noob at UE networking. I’m almost considering switching over to Photon and getting out of UE’s built-in networking, because I would at least have a more available customer support.

I do this consistently whenever I change a replicated variable on the server: change the value and call OnRep manually. Its most convenient when you have logic that has to be run on both server and client.

@ToxinGaming hey man, look at this

I have a Crosshair in my game, and I want every shot to go there (at the center of the screen). In fact, if you see the screenshots below, this doesn’t happen


This is the code I’ve been using:

void AWeapon::OnRep_HitResult()
	// Storing the Location and Rotation of the Character
	FRotator PlayerRotation = MyOwner->GetControlRotation();
	FVector RotXVector = PlayerRotation.Vector();

	// START PLUG 77 is the Camera's Z value)
	FVector StartPlug = FVector(MyOwner->GetActorLocation().X, MyOwner->GetActorLocation().Y, MyOwner->GetActorLocation().Z + 77);

	// END PLUG 	
	int32 distance = 2500; // Maximum distance of the trace
	FVector EndPlug = (RotXVector * distance) + StartPlug;

	// Draws the red debug line
	DrawDebugLine(GetWorld(), StartPlug, EndPlug, FColor(255, 0, 0), true, -1, 0, 0.7f);

where MyOwner is simply the Actor Owner of the Weapon, which is Replicated using RepNotify

Any tip?

Instead of doing the raycast from MyOwner (the pawn), you can do it from your Follow Camera. The follow camera should be a component of MyOwner, so I think you can just change it all your MyOwner references to MyOwner->FollowCamera. I’m not sure if that is the right syntax since I don’t code much in C++ (I’m more of a C# guy since I use that at work).

I did as you suggested: start the raycast from the camera. This is the code

	// Storing the Location and Rotation of the Character
	FRotator PlayerRotation = MyOwner->MainCamera->GetComponentRotation();
	FVector RotXVector = PlayerRotation.Vector();

	FVector StartPlug = FVector(MyOwner->MainCamera->GetComponentLocation().X, 

	// END PLUG 	
	int32 distance = 2500; // Maximum distance of the trace
	FVector EndPlug = (RotXVector * distance) + StartPlug;

	// Draws the red debug line
	DrawDebugLine(GetWorld(), StartPlug, EndPlug, FColor(255, 0, 0), true, -1, 0, 0.7f);

The problem is that both the client and server see their own RayCast well, but not the other ones:

The Server here sees the client that shot a RayCast in front of him (not even in front of him, since the RayCast seems to start form the EAR of the character!)
Instead, the Character didn’t shot there, he shot on the ground.

It’s like the camera positition/rotation are not replicated.

By the way, all I want to do is to address the shot to the Crosshair (center of the screen) wherever the shot come from (Weapon Socket, etc…)

Oh it doesn’t matter, I satisfied even with a theoretical explanation =)

Yeah sorry I know more about 3rd person than 1st person.

If you want to do the cast from your weapon to the center of your screen, the start would be from MyOwner then I guess. But then end would be the follow camera World Transform plus the distance you want to go.

As an example here is my raycast that just does 10000 units in front of the 3rd person camera (it is also in Blueprints):

Start Vector:


End Vector:

FollowCamera->GetWorldTransform().Location + (FollowCamera->GetWorldTransform().Rotation->GetForwardVector() * 10000)

I kind of used the LineTrace detailed out on this page, except I don’t use the Find Look At Rotation and those other transforms. But I think those would be useful to you if you wanted to figure out the transform from your weapon.

Okay, that helped, but there seems to be a replication problem.
Both client and server can see their OWN RayCast well.
But they can’t see well the other’s RayCast**

I shoot at the ground with the Server, but the Client sees the Server shooting in front of him

They can’t see the other’s raycast at all, or is do they just the other’s raycast incorrectly?

Based on your last picture it doesn’t even look like they see each other’s raycast at all.

My first check would be if you are calling the AWeapon::OnRep_HitResult function on both the client and the server.

Second, I don’t believe yaw is replicated at all, that’s just part of the engine. You can set up the replication yourself though.

I’ll check back here later if I come up with any ideas.

Of course both the Client and the Server can see the RayCast. In the picture above, the Server shoots on the ground and the Client sees Server’s raycast as If he shot in front of him.
So it’s a problem of location/position/direction of the Camera.

Note that this happens for both the players. So it’s not a problem of the Client himself. Also the Server sees Client’s RayCast badly.

If that is the problem, my question is how?