Serious shot replication problem [video]

You have to set up a replicated variable and update it when there is input or on every ticket. I suggest input as to not slow down client ticks; this is also how I replicate the yaw.

Check out this post here.

To be honest I had the idea to replicate the Yaw thanks to that post that I already saw times ago.

The problem is that I must find a way to actually TELL everyone my current Camera Yaw.

Also the Pitch? Or only the Yaw?

He says:

Yes, but how can I replicate those?

For the Pitch and the Yaw I have these two functions in my Character



void AMyCharacter::AddYawInput(float value)
{
	AddControllerYawInput(value);
}

void AMyCharacter::AddPitchInput(float value)
{
	AddControllerPitchInput(value);
}


I think it’s just the yaw that doesn’t get replicated, but you can do both to make sure.

In your MyCharacter, you need to create two variables that are replicated, let’s call them ClientPitch and ClientYaw.

I know you are doing it in C++ but if you look at this image you can see how it works in Blueprints. This only shows pitch, but you can do it for yaw too.

Okay, the top-side of the Blueprint is pretty clear to me.

I don’t quite understand what SetPinch function does. I see it’s only called on the Server and updates the Pitch value. But what is that stuff in between?

If you can tell me, It’d be nice =)

The second function, SetPitch, takes the current pitch, turns it into a Rotator, gets the Rotator difference between the Actor rotation and the Control rotation and uses those two rotators in an RInterp To function. It then takes that result, grabs the pitch of that rotator and makes sure it is between -90 and 90 and sets the Pitch.

Essentially it is just using the old pitch and the new rotation of the character to create the new pitch.

The SetPitch function is actually called on both the client and the server.

Although, I do think I changed this in my own project because variable replication is only from server to client. I think I just call the Server Look Up RPC to set pitch no matter what and not call it locally. Sorry, I’m not at my home computer so I would have more information for you.

Hard to say for sure without seeing the ServerStartFire, but on the client you’re calling a server function and then drawing a debug point for a HitResult. That HitResult wasn’t updated by the client, but it is updated (I presume) after the server does the shot and then replicates it back. So you’re drawing whatever happened the last time the server replicated it down, each time you shoot on the client, which is why you see a shot behind.

Yes, we were able to figure that out. The problem he is having now is he is trying to draw the raycasts on both the client and the server, but since yaw or pitch isn’t replicated, the client always sees the server as shooting straight forward despite the server looking down.

Pawn GetBaseAimRotation() should include remote view pitch. There is actually a RemoteViewPitch variable replicated from the server to the client, but it’s not exposed to Blueprints… It’s also a byte value that would have to be remapped. GetBaseAimRotation() takes care of that though.

You could also add your own replicated rotator if necessary. Controller->ControlRotation would be a good candidate.

And I’m surprised that the Engine doesn’t do that automatically.

I haven’t look at that in a while, but yeah it’s not ideal. GetBaseAimRotation() and RemoteViewPitch is quite old and seems like it is trying to balance not replicating very much versus trying to provide something useful. It probably falls short of being very helpful.

That said it is pretty simple to replicate the rotation you need.

@ [MENTION=3634]Zak M[/MENTION]

Ok I’ve “translated” the Blueprint that Toxin sent me in C++

Pitch is a Replicated variable. But it stands there, how do I say that that Pitch is the Pitch everyone must see for my Character?

Also, is the Algorithm of SetPitch the same for SetYaw? Maybe changing the MakeRot/BreakRot node so that the Yaw input is filled rather than Pitch.

I think it’s easier to do this in PreReplication personally. This is what Pawn does:



void APawn::PreReplication( IRepChangedPropertyTracker & ChangedPropertyTracker )
{
	Super::PreReplication( ChangedPropertyTracker );

	if (Role == ROLE_Authority && GetController())
	{
		SetRemoteViewPitch(GetController()->GetControlRotation().Pitch);
	}
}

void APawn::SetRemoteViewPitch(float NewRemoteViewPitch)
{
	// Compress pitch to 1 byte
	NewRemoteViewPitch = FRotator::ClampAxis(NewRemoteViewPitch);
	RemoteViewPitch = (uint8)(NewRemoteViewPitch * 255.f/360.f);
}


You probably want a similar setup but without the clamping to byte stuff. Interping might make more sense on the client, and interping from current to target each frame would be smoother.

For Yaw, if your actor rotates to match Yaw, you don’t need to do anything because ActorRotation.Yaw == ControlRotation.Yaw. Otherwise you can do something similar as above.

Thank you for the suggestion, but there you introduce more stuff to my mind I’ve never seen and made my Engine crash.
I decided not to take that way.

I’ve found a simpler solution on the AnswersHub that says:

The Blueprint he provides is way simpler than @ but at the end the question is always the same:

once I set Pitch/Yaw variables to the new values, how do I tell all the clients those variables’ values? (so that they get the current character rotation correctly?)

Assuming those are replicated variables, they are automatically broadcast to all clients. So then you’d want to use them anywhere you want to do a trace that is relevant. I’d probably make a helper function that is like GetAimRotation() that reads those values to put together a rotation you’d use for traces.

Yeah, I’m at my home computer for right now and I see what I have done.

My SetPitch function is the same so what I do is do the RInterpTo on the client so the Pitch variable is updated locally and then I tell the server to update the Pitch variable so everyone else knows what that client’s pitch is.

I do this so that the animation blueprint knows what to do in the AimOffset when the client needs to render another client’s offset.

I don’t know if this is the correct way to do it, but it works for me so that’s why I kept it.

I don’t have a SetYaw so I don’t think you need to worry about Yaw.

So, if you want your C++ code to match my blueprint, your SetPitch function is not an RPC, it’s just a regular function. And then you would pass the Pitch into the RPC and set the Pitch.

I think your code would look like this:

Don’t mind the squiggles, I just coded in a file that doesn’t have the right information for Intellisense.

That code should work. However the Server should already have an accurate ControlRotation for all PlayerControllers of remote players, so it might not be necessary. CharacterMovementComponent already sends that client->server.

The issue to solve is usually how to get the other simulated remote players on the client to have a an accurate rotation. Presumably you solve that with a replicated Pitch value. Simply copying that in a Tick as gedamial has done should be sufficient. Really you could probably just have a replicated copy of ControlRotation (RemoteControlRotation) on your Pawn/Character, and be done. This avoids the other assumptions that ControlRotation is equal to ActorRotation in Yaw and Roll, which is usually true but not always. For instance if you let a character physically face one direction but the camera is in a “free-look” mode (ie 3rd person camera), ControlRotation.Yaw != ActorRotation.Yaw.

Thanks for the continued responses, this is giving me some good items to consider for cleanup and documentation in the future.

Why do you change the Pitch twice, one for the client and one for server? Shouldn’t you do it once on the Server?

Also, the question is always the same

Yes, they are replicated.

I need those values to make all clients now that is my CURRENT value for the Pitch and the Yaw.
So it must work for everything (animations, also) not just for tracing.

I must find a way to tell everyone that they should rely on the Pitch/Yaw variables, and not on the default values the Character has

When the variable is updated on the server, since it is replicated, all of the clients will know.

Zak M is right, you should make a GetAimRotation function and use that to get the End Plug of your trace. In your code you have the RotXVector as the PlayerRotation.Vector(), but it should be GetAimRotation().Vector() (or however it’s done in C++). This way it will use the replicated Pitch.

Alright guys, I got it work!

As Toxin said, I just needed to set the StartPlug to the Character->GetBaseAimRotation().Vector() to make the shot go wherever the player is looking at.

The thing that left me surprised, is that it works also without replicating anything! How is that possible?

Why the guy right here ends up by replicating the values?

Am I missing a step or it’s just fine as I did? Could I face problems in the future? Maybe with animations? :confused:
[MENTION=3634]Zak M[/MENTION]

Is GetBaseAimRotation your own function?

And why do you say it works without replicating? Aren’t you updating the replicated pitch value on tick?