[Multiplayer BP] Viewport/Mouse Position Per Player Controller?

Hello,

I’m building a Multiplayer Twin Stick Shooter for keyboard and mouse. As the player moves the mouse around, it sways the camera and turns the character to face the mouse. I use Get Viewport Size and Get Mouse Position to accomplish this system which works flawlessly in Single Player. However, as primarily an artist I can’t seem to wrap my head around how to get this working for Multiplayer. I’ve been at this problem for 2 weeks now.

Single Player: SOS - YouTube

I’ve narrowed it down to being a problem with the Player Controller. You can see the issue in the video below:

(I disabled the camera sway here because I was trying to simplify the issue. At the end of this video you can see the simplified blueprint.)

I did some research and learned that I need to create and replicate and then set the variables with RPC then Multicast, but that lead to a bunch of twitching as there was a fight over who’s Player Controller it was or something.

Here’s the blueprint:

I know it’s a lot, but I would really appreciate any feedback, suggestions, or ideas. I’ve been researching this specific issue for so long.

There is one workaround using Set Control Rotation, but it destroys the camera system.

Simply put, I want each player to be able to move their camera and character based on their own mouse position and viewport. I have absolutely no clue how to go about this.

Thank you,

-Metric

Will try help you and tell you the way I did it. Though should mention, mine was made in c++.

First of all, you have to find “aiming point” of each player. You do this only in Player Controller class by finding a point in local Viewport and then deprojecting it from screen to worldspace.

Then, after you got a Vector variable (let’s call it “AimPoint”), it should be replicated to server. And this is the main reason we work with player controller since it’s the only class that is authoritative on client and can replicate variables from Client to Server!
Here you can use RPC, or just set AimPoint to replicate. Can’t really tell which RPC you should use, since I can’t check my PC now, but simple replication should work.
Now on server you got all player controllers each with AimPoint variable containing world coordinate. The tricky part is that you should get those variables from other classes, for example your character class. For this make a call from character to controller that is controling given character and make sure to make that call only on authoritative actor (HasAuthirity node), meaning you get “AimPoint” on server. And then multicast it from server character to all clients with custom multicast event (but be sure to exclude owning client to prevent lag induced jitter). Now you should have individual aiming points for each character.

To summ up:

  1. Collect point AimVector data in Player Controller

  2. Set AimVector variable to replicate

  3. From character make call to controller, get AimVector and put it through multicast event, excluding owning client.

If you struggle with this, I’d be glad to lit it up for you with more examples, but after 23d of december. Cheers!

Thank you.

I believe I understand the first half of your answer, but after several readings I’m still a bit confused about the second half. However what you’ve said so far did help me make some progress.

So far I made a Player Controller Blueprint and put the Blueprint Nodes from the image above into it. [This gets me SO CLOSE][2], but it looks like the Client isn’t telling the Server to update.

I sincerely apologize, but I just can’t quite understand or grasp why that is just yet.

First, I think RPC (Remote Procedure Calls) are the Clients telling the Server to fire an Event (Replicates: Run on Server).

Second, Multicast can only be run on the server and is Replicated to all Clients.

Therefore in theory, when I run RPC > Multicast in the Player Controller Blueprint, I would think it would replicate the results to everyone involved (Both Server and Clients).

I know there’s certain things that exist only on the server (such as GameMode Blueprints, but I’m not sure what else), but Player Controller BP is one of those things that should synchronize between all parties involved I would think?

I’m not exactly sure what is missing in my knowledge to make this all click, but in addition to the dozen video tutorials and forum posts I’ve gone through, I’ll also be going over the Network Compendium by Cedric eXi Neukirchen and Multiplayer in Blueprints | Unreal Engine Documentation to help build my understanding. But that will take time and there’s a lot of information to absorb, so if you or anyone is able to provide some explanation, it would be greatly appreciated.

Edit: I did notice once issue with the Player Controller Blueprints I showed above. When moving around the Character seems to snap it back to the original rotation based on the Pawn (Character / Control?) Rotation. Hmm…

I’m not sure if this video helps diagnose the problem or not, but I’ve moved to Casting to the Player Controller and getting the Rotation variable that I want to use to set the Relative Rotation of the Player Character’s Mesh. The same issue occurs that I mention in my Edit above.

I’ve tried to break down what you said in your original post but I get caught up around the tricky part.

Also, what does Calling mean? Is that the same as Casting?

Thank you,

-Metric

Each Player Controlle exists in two places: Server and only Owning Client. Thus on your machine you got your Player Controller that is controlling your character. Other characters are being controlled either through net command or something like net controller, I’m not sure and that is not so important.

Server, on the other hand, has all Player Controllers (which are non authoritative btw). So when any player makes something on his side (client side) player controller can replicate from client side, to server side. That is very important property of Player Controller class.

You are absolurtely correct about multicast, it should be called from server (well, authoritative side to be precise), in that case it’ll be called on every object copy, that exist through multiplayer session (if you call multicast on client it’ll work only on that client, btw). But, as Player Controllers do not exist through all clients (only owner and server), you should call your multicast from other class, like character that is replicated.

So now, you have all Player Controllets on server, each has recieved a Vector from a client it is tied to. Each controller has a corresponding character. You have two options:

  1. From character you call multicast and set new Vector variable in your Character, that is going to be your aiming point.

  2. You set replicated Vector variable in character and set it with Server function in you Character.

To both multicast and Server functions you should pass your coordinate from Player Controller, both those functions should be in Character and be called from character (I assume in tick).

In terms of blueprints calling would be connecting node in a line for execution. In your case the blue multicast and blue RPC nodes are being called.

On the graph above RPC is not reaching cliens since it’s being called only on owner. I assume you are testing with “dedicated” flag off and when you are rotating character in server window it replicates, but in client window it is not.

What you should do:
In your Character class get player controller, get your rotator from player controller.
Then add multicast function which will set your charactets rotation (all in Character) and call it in tick of your character, passing rotator that you got from player controller.

When you have a chance, I would love to see how you would accomplish this in blueprints.

For now, I found a workaround solution after lots of testing

257174-hardfought.png

The main thing I’m doing differently now is that I’m using Set Control Rotation which seems to replicate over the network no problem. This destroys the camera system I had, so I had to find a workaround for that too.

I’m getting and setting the variables I need in the Player Controller BP:

Then in the Player Character BP I’m getting the variables I need (None of them are replicated) and setting the Control Rotation and the Camera Location using World Location instead of Relative.

There are some new issues with this method of using World Location instead of Relative Location.

I found that the ConvertMouseLocationToWorldSpace node did not give the coordinates I needed. It only had a gradient from about 20 to -20 units when moving my mouse from one side of the screen to the other. Whereas if I moved my character the same distance, it was actually closer to 200 to -200 units. That meant that the averaged offset of the camera was only about 10 units which was basically not noticeable at all.

So instead I used Hit Result Under Cursor by Channel, but if your mouse ever goes off a cliff or to the top of a building it’ll cause some jitter. I tried to counter that by using camera lag and will soon incorporate RInterp To like in my original BP. Additionally, adding an invisible box between the player and the camera that the Hit Result Under Cursor by Channel will collide with will fix any jumping issues as long as there isn’t a building or wall higher than the invisible box.

Again, I would love to see how you would tackle this, but I will mark this as solved.

Thank you again,

-Metric

[Result][4]

Sure, I’m ready to help just need to get home from vacation, I’m only having my smartphone here with me. :slight_smile:

We have progressed pretty far with our shooter, applying all the same character rotation torwards cursor and camera shift, I’d be happy to give you some advice.

I will definitely look forward to your example. It may be much more efficient or better than what I’m doing now. That is if you want to still want to. Currently the janky solution I have right now is working if nothing else, and that was mostly derived from your help. So again, thank you.

Thank you so so much Noowai. Ive been stuck on this for days, you saved me so much time and all. I fixed it with you example explaining it. Thank you