No Owning Connection for "Player 2"'s ClientController
So, this is probably something stupid that I'm just not wrapping my head around, but I've got really baffling behavior in my example application that I haven't been able to figure out. This isn't just a C++ problem, since it includes Blueprint as well, but I suspect that if I were trying to do what I'm doing with Blueprint in C++, I'd get the same outcome.
I'm working with an example game that is very simple - there's a widget object generated in the level script that creates a button and two score counters (one for "my score" and one for "their score"). When a player clicks the button in their client, they increment their score by one and both clients should update to reflect the change in scores. However, the behavior I'm seeing when I test is that one of the clients can increment score while the other can't, instead generating a warning:
So here's what I'm doing. On my player controller, I've got the following function:
The UI itself is scripted in Blueprint because the whole point of this example game was to explore how easy it was to let designers handle UI in Blueprint while actual game logic happens on the C++ side. I've got a single widget that contains the whole UI (all three elements of it), with the following logic for constructing itself and actually responding to a button press:
So I'm starting two clients and a separate server on my machine for test purposes. I've arbitrarily chosen to label the one that starts directly in editor Player 1 and the one that opens in a new editor window Player 2. When Player 1 clicks the button, everything works. When Player 2 clicks the button I get the "No owning connection for actor NEPlayerController_0" warning and nothing happens (which, since the server isn't executing the function, makes sense). Can anyone tell me what I've done wrong?
asked Jul 06 '18 at 02:13 AM in C++ Programming
So, it turns out that I had a bunch of problems in here. Because documentation leaves a lot to be desired in this space, I'm gonna go ahead and explain a few of them in hopes that the next poor bastard who runs into this problem has a better go of it.
1) I was creating my widgets in the level script, which appears to have caused this issue. I'm not entirely certain why, but it appears that the widget was created in both viewports, but when I tried to get player controller 0 or my owning player, the function was returning client 1's client controller. I fixed this by initializing the widget in the client controller in an
2) I was calling a net multicast function on the client controller. This is, apparently, a really, really bad idea, since each client contains each client controller, so I was calling the function multiple times on each machine, resulting in very strange behavior. This one took me forever to figure out. I was able to move the function into a new default pawn class to fix the matter.
3) I was sending a player ID from the client to the server, when I could have simply extracted the same information on the server side, because the client controller I was called from was replicated anyway and knew which client it was on. I ended up sending a player object back to the client from the server on score change and having the widget test whether the player in question was its owner. No generation of a UUID necessary. Of course, I could have also just used the pre-existing net ID. That said, using the controller itself to determine who sent the RPC is ultimately more secure (not that a game about pressing a button really needs to be secure), since the ownership of the connection makes it impossible for non-owning controllers to simply fake which ID was their's.
I hope that if anyone else stumbled into this particularly thorny maze that you found this helpful, since I was entirely lost for a week working on what was ultimately a silly set of mistakes on my part. But, hey, what's explicit documentation good for anyway?
Follow this question
Once you sign in you will be able to subscribe for any updates here