I’m developing a multiplayer racing game in mainly c++ and some blueprints. I have a problem regarding the inputs.
Problem I have occurs when I either play it in packaged project or when I launch the game through PowerShell. In editor, everything works as it should.
I’ve been banging my head against this problem for a while and tried about every suggestion I’ve found even remotely reminding of the problem I have.
Some info about my project.
I use 2 controllers for input. Menus and lobby use MenuController( FInputModeUIOnly ) and then there is PlayerController which is used in the actual game (FInputModeGameOnly) .
Players control pawn vehicles(blueprint) that derive from c++ class
Movement is done by using custom movement component and movement replication
Three different GameModes used. MenuGameMode, LobbyGameMode and PlayGameMode.
In short:
In Editor : Host and client controls work as they should.
Packaged Project: Host controls not working.
Project launch through PowerShell: Host controls not working, tested inputs by UE_LOG and they seem to fire
when button is pushed. Client controls work as intended.
So if anyone has an idea what to try next or why is this happening in my project , please give me a helping hand.
Really hard to diagnose the problem without seeing the code. Have you tested whether the host receives input at all (whether the input even reaches your movement code)? You can test this by either logging or attaching a debugger to the standalone game. Does the problem occur when starting a stand-alone game from the editor as well? You say you use a custom movement component and custom replication. If your input actually arrives in the movement component my money would be on a bug in your movement code. Remember that stand-alone games usually run on a much higher framerate than within the editor (which is capped to 120 by default). People often write movement logic that suddenly breaks with high framerate because they only test in the editor.
I know it is super hard to help out without seeing the project and I thank everyone who spends their valuable time to help out.
Grim I’ll go through your suggestions.
Yes, the problem occurs in standalone game too (launched from editor)
I’ve already been using debugger but apparently in the wrong place. I’ve done what you’ve suggested and tried to Log out the GetRemoteRole() in my VehicleMovementReplication class. What I’ve discovered is that the client logs out his role but the host says nothing… nothing at all. Which I guess means that the problem might be somewhere in the movement or in the replication of it.
I’ll keep on trucking and try to figure out what is breaking the chain.
Thanks again Grim for your insight, it helped me a lot! If you come up with any new suggestions please give me a nudge
I don’t know if they fixed this in more recent versions but GetRemoteRole() has/used to have an inconsistency between editor and stand-alone (autonomous and simulated proxy being switched around for clients). Maybe that is your problem. I have stopped using it altogether because of that. You can replace GetRemoteRole() with a combination of GetLocalRole() and IsLocallyControlled().
Ok, I’ll looking into that. I can now almost say for certain that the problem lies in my replication component or movement component. I’m trying to think right now how IsLocallyControlled() is going to fit into my code.
Any idea how to use IsLocallyControlled() in movement component class? Right now I check the role like this if (GetOwner()->GetLocalRole() == ROLE_AutonomousProxy || GetOwner()->GetRemoteRole() == ROLE_SimulatedProxy)
Also, I have a weird feeling that my spawning of playercontrollers aren’t working right. When I launch the game in Editor it only shows one PlayerController in the Outliner. Shouldn’t there be as many controllers as there are players? I’ve done a helper function that takes and adds incoming player in PostLogin to an array of controllers. When I loop that in game it shows that there are as many controllers that there are players connected but outliner shows only one controller…
Right now I check the role like this
if (GetOwner()->GetLocalRole() ==
ROLE_AutonomousProxy ||
GetOwner()->GetRemoteRole() ==
ROLE_SimulatedProxy)
That in itself could be the problem because firstly as I said GetRemoteRole() is probably still inconsistent and also very confusing because what should it even logically return when called on a remotely controlled pawn on the server? If there is more than 1 client connected it has both an autonomous proxy and at least one simulated proxy as remote role. However, this code would logically be the same as GetLocalRole() == ROLE_AutonomousProxy || GetLocalRole() == ROLE_Authority && IsLocallyControlled() for a 2 player server-client scenario. For more players you would have to clarify where you actually want to run this code because of the aforesaid ambiguity.
I have a weird feeling that my
spawning of playercontrollers aren’t
working right.
In a multiplayer game, only the server has all player controllers. Clients only have their own player controller locally. But when playing in editor, you should see the server state of the world in the outliner (so all player controllers). What do you mean when you say “spawning” player controllers? I don’t think that’s even possible. Player controllers are assigned to clients and every client only has one. There is usually no need to maintain an array of them, you have access to all of them on the server and clients should have no interest in other people’s controllers.
Thank you for the reply and making things more clear
My pawn functionality is made out of 3 classes. The pawn class itself, movement component and movement replication component. The code provided was from the movement component class. And what I understood the IsLocallyControlled() can’t be used directly from there because it isn’t a pawn. Did I get that right’? Might be a way to use it throught casting? GetOwner()-> IsLocallyControlled() doesn’t work at least. So what would be the best way to implement IsLocallyControlled() function in a non-pawn class?
Right now I need to figure out what is wrong with the movement component because that doesn’t work right. Sometimes everyone can move and sometimes they can’t. Input still fires but nothing moves. Except the client in 2 player situation.
Let me clarify the player controller problem. With spawning controllers I meant that when they connect to a server they should be assigned with one. And I also know that you might not need to store them but what I did for testing’s sake, I’ve stored them into an array to see in game that there really is as many controllers as there are players. But in editor outliner, there is always only one controller…
My movement class doesn’t inherit from UPawnMovementComponent so that is not an option. I will use the casting way to do it. I think it’s weird too that the controllers won’t show up but I’ll tackle this as soon as I get back home. And yes I’ve been logging the whole time and used the debugger. I just need to go through my code and logic. One way of course is to start a new project and attach my old project piece by piece into it…
I left out the objects for brevity. IsLocallyControlled() is a member of APawn so you need a pointer to your pawn class and call the function on that. You can do that by casting the return value of GetOwner() to APawn: Cast<APawn>(GetOwner()). If your components inherit from UPawnMovementComponent you can also use the PawnOwner variable of that class: PawnOwner->IsLocallyControlled()
It is weird that you don’t see the controllers in the outliner but again, this is hard to diagnose without seeing the whole code. It also sounds like you have problems in multiple places and networking is not a trivial problem. The best advice I can give you is to log as much as possible (also printing the net role and object name so you know what gets called where) and then narrow down the problems.
I went and changed the if-statement in my MovementComponent as Grim suggested to
if (GetOwner()->GetLocalRole() == ROLE_AutonomousProxy || GetOwner()->GetLocalRole() == ROLE_Authority && Cast(GetOwner())->IsLocallyControlled())
And lo and behold, it started working. Now the inputs work in editor, standalone and launched from powershell. So it seems that is solved? Inputs work even with more than 2 player situations. Still I don’t see more than 1 player controller in the world outliner but still my array is filled with the correct number of controllers. I just don’t get it.
But now I’ll tackle the replication because that is not working now
I got everything working. With Grims help I’ve managed to get the movement working by adding the if-statement he suggested →
if (GetOwner()->GetLocalRole() == ROLE_AutonomousProxy || GetOwner()->GetLocalRole() == ROLE_Authority && Cast(GetOwner())->IsLocallyControlled());
And my replication problem solved by adding following if-statement to my code →
if (GetOwner()->GetRemoteRole() == ROLE_SimulatedProxy || Cast(GetOwner())->IsLocallyControlled());
So the only question that still stands is the question of my controllers in World Outliner but the original question has been answered so thank you very much Grim for your help.