Networking; Replicating Turret Rotation + Double Input Issue

I’m working on a project where I have a tank which needs to be controlled by separate players. For example, one player controls the driving and another player controls the turret and shooting.

So far it’s all been going well, but I’ve had a lot of problems figuring out how to accomplish this. As of now, the entire tank consists of 2 (separate) pawns - the hull along with the tracks and all necessary stuff to drive around and the turret, which is what I’m having issues with.

Since I couldn’t figure out a way to have it all in one pawn yet have 2 players possess it, I attach them to one another and I’ve gotten that to work over network - but now I’m trying to make it so the other player can move the turret around and have it synchronized.

As of now I have this;

Very basic setup for rotation as you can see. However, both players can control the turret and I can’t figure out how to solve this.

So let’s say Player 1 is the driver and Player 2 is the gunner. If Player 1 looks around, the turret will still rotate on his screen - which it shouldn’t. If Player 2 looks around, it’ll behave as intended*(though not yet replicated)*.

Basically, I don’t want Player 1 to be able to rotate the turret on his end.

Any pointers as to what would be the best way to replicate this would also be welcome. I’m not a newcomer to client and server interaction and understand the concept behind it - however, the way UE4 requires you to do it can be very confusing at times. But I’m sure I’ll get used to it.

So any help would be greatly appreciated!

Ok, first of all we need to make sure that we are talking about the same setup:

You need the following setup (based on my knowledge) to get this to work:

1- Tank needs to be a Pawn and have all the logic, which is needed to control it, in itself

2- Turret needs to be a Pawn, too, and also have all the logic, which is needed to control it, in itself

(With this, you make sure that you split the controls and don’t have to manage everything in one class.)

3- You don’t want a DefaultPawn in your GameMode! Because that one is spawned and possessed, when a Player connects. You need to do this by hand:

4- Use the “OnPostLogin” function of the GameMode to Spawn the Tank for the first Player (simple Int Variable to count or a FlipFlop) and use the passed PlayerController to possess it. GameMode is ServerSide only, so this is replicated and should just work. Same goes for the Turret, but you want to make sure that you save the Tank Pawn in a variable (Inside of the GameMode), so you can attach it to the Tank.

(You could also spawn a combined “pack” of Tank and Turret directly. You can add “ChildActors” as components, which you could do in the Tank and then assign the Turret Class to it.)

5- Now we can start talking about Replicating the Movement

So if this is your setup, (can differ a bit), and each Pawn has its own Input, we can start replicating.
Make sure both Pawns are actually set to Replicate and ReplicateMovement in the Default Class Settings.

Now you need to remember, that “EventTick” is called on Server and Client. If you don’t use a DedicatedServer Setup, the first Player will be the ListenHost, which means he’s the Server AND a Client.

(Which means, if you, by any chance, let the first Player control the Turret, it will be replicated.)

So, we don’t want to use the EventTick like that. Now i need to know:

Is this a 2D TopDown Game?

Because you are getting the 2D Mouse Position on Screen.

Not focusing on the actual input you need, you need to do it somehow like this:

In your InputSettings of the Project, create Inputs for the MouseMovement. The Template Project
mostly have the setup. You need “AxisMapping” for the Mouse.

These events can be found by the same name in the Turret Pawn then. They are constantly called
and will pass a float value that is 0.0f until you move the mouse up/down, or for the second axis, left/right.

These Events are LOCAL. Means they will only be called by the Local Player who possess the Turret.
That means Player1 can’t use them for now. But now you need replication.

So you want to setup the Movement that it works for Player2 locally. Even if you replicate, you want to have the Player2 get the Input directly applied, since he would notice a lag if not.

Now you add so called “RPCs”, which can be used to transfer a call to the Server version of an Actor.
To create then, add a “CustomEvent” and in its settings, set it to “RunOnServer”.

(It’s important to note, that RPCs only run on the Server OR on ClientOwned Actors. PlayerController or a possessed PlayerCharacter(Pawn), are client controlled, so we are good to go.)

The RunOnServer RPC needs the Float Value that the Mouse Event passes. And then, you just do the same stuff on the Server again. So you do it twice. Once on the Client, to prevent Lag and one on the Server to replicate it.

That’s “all”, so try to accomplish this step by step and if you run into problems, please post a screenshot of the setup at this point and ask (:

Cheers!

Hey, thanks for the detailed reply!

That’s pretty much how it all is setup at the moment, they’re both 2 different pawns with their own inputs. Just that the turret is attached to the hull.

I’m getting both of those via the Level BP and pass them onto my GameMode. This is where I then attach the turret to the hull and have each player possess one part. Currently it’s setup in such a way that the player hosting the game will be the driver, the player joining handles the turret.

Maybe not the best way to set it up, and it will get messy if I intend to have more than one tank. But so far it’s just to serve as a prototype, so that’s fine.

I tried the method you described, using input axises, however they only work for the listen client - for the other client it wouldn’t work at all and always return 0.0. Whether this was a bug or me using it wrong, I don’t know.

The reason I get 2D mouse is because I was initially trying to set the cursor to the center of the screen with every tick since games tend to do this and then just check if the cursor has move left/right/up or down for aiming.

See this video; - YouTube for an example of what I mean. There are 2 green squares, one’s always at the center and the other is the cursor.

However I wasn’t able to achieve this since I couldn’t figure out how to set the mouse position to a custom one. I know there’s a function for it but it has no exec pin - so I was rather confused as to what to do with it.

Movement of the tank is already replicated, however the rotation of the turret is not*(yet)*. Last I looked at it, I need to fiddle around with replicating variables.

And I’ll probably replace aiming the turret with some camera stuff rather than raw input at a later stage.

With that “EventPostLogin” setup, you are possessing the Hull and the Turret with Player 1. A Sequence Node will call 0, then 1 etc.

Also, yes using the LevelBlueprint might not be the best method. You could just spawn them in the GameMode.

How about you do something like this:

Remove the Turret from the Map again and spawn it runtime:

OnPostLogin Function that handles new Players (even the Server that hosts)

http://puu.sh/olIE7/092d6fa716.jpg

Spawn the Tank (TankSpawnTransform is just 0,0,0 in Location and Rotation and 1,1,1 in Scale)

http://puu.sh/olK2w/559fa82d39.jpg

Spawn the Turret (We attach the Turret to the Tank, so the SpawnLocation is not important)

http://puu.sh/olK5Q/ed1aa26bc7.png

Variables were created on the fly. No replication for them, cause not needed and GameMode only exists on Server anyway:

http://puu.sh/olK7r/ebd9f22929.png

Now for your Turret Movement Problem. Here is a really simple setup to replicated the Pitch and Yaw Rotation of the Turret Mesh to everyone else:

LeftRight Movement with Comments:

http://puu.sh/olKJk/4164f6effb.jpg

UpDown Movement without Comments, since it’s similar:

http://puu.sh/olKLZ/13f8ca8a8e.jpg

Result of the Turret Rotation Replication with 2 Players (Server and Client) + one extra Player to show that it’s actually replicating to everyone. Server is in the upper left corner. Controlling Client 1 in the lower middle and the additional Client2 in the upper right corner. The grey Block is the Turret and the other thing beneath that is the Tank body. As you can see, the grey block is turned left up on all 3 screens.

http://puu.sh/olKNZ/a1d232ea24.jpg

That makes so much more sense… And god bless you for showing me the increment and Switch on Int nodes - those will make my life so much easier in the future! I’ve set it up like you did, however, I’m getting an error when I try and attach the turret to my tank.

Accessed None trying to read property TankRef from function: 'ExecuteUbergraph_MyGameMode' from node: AttachActorToComponent in graph: EventGraph in object: MyGameMode

Could the problem be due to the fact that the hull uses a separate controller? What I did was cast to the needed controller when the first player has logged in in order to possess the tank.

Edit:

May be worth to mention that neither of the possessing works. The tank is spawned at 0, 0, 0 despite me specifying a certain location for it to be spawned at - which is in the transform variable.

Player 1’s camera is inside the turret*(camera of the turret is above the turret itself)* and Player 2’s camera is just below the terrain itself.

The error you are getting is due to the TankRef Reference Variable being empty.

This only happens if the Spawning fails.

So i guess the CollisionHandlingOverride just needs to be set to AlwaysSpawn (in the Spawn Actor Node of the Tank).

You don’t need to cast the Controller. The Possess function is a PlayerController function and the passed NewPlayer reference is already a PlayerController.

Are you sure that nothing is blocked the cameras? Set the SpringArm of your Camera to not doing a Collision Check. Can be done in its option when selecting the SpringArm. If you don’t yet use one for your Camera, then you should do that now.

What do you mean with “separate Controller”? Sure it’s a separated one. Each Player has its own PlayerController. That’s what represents the Player after all.

God damnit I overlook things so easily, yeah that solved the problem. I should’ve realized since I had the exact same issue earlier - and solved it the same way.

The issue with input persists, however. Mouse input does not work at all, it always return 0.0 no matter how much I move my mouse about. What’s rather peculiar however is that using the analog sticks of a gamepad works perfectly fine.

Edit:

Use mouse for Touch is disabled, still trying to figure out what’s causing this.

Do you, by any chance, have a mouse event somewhere else that consumes input? If you click on such a Input Node in the EventGraph, you can set Consume Input via a bool. Maybe someone steals the input of it? PlayerController or so?

Hmm, yeah I had some mouse inputs in the parent BP of the tank’s hull for camera management and it seems that was interrupting it. I figured it would be fine since it uses a different controller BP.

https://streamable.com/dskb

Thanks for all the help, you’re awesome! :smiley:

eXi, I finally discovered this post after Eight Billion hours of searching and coding and trying everything to get my Tank Turret to work. When I set it up just now, and at long last the turret rotated correctly in network play correctly I just had to groan with joy. You have the best Kung Fu! Endless Thanks!!! - YouTube

link text