I’m trying to set up the very basics of multiplayer and I can’t figure out what’s wrong. I had this working at one point and I’m totally at a loss as to what could be the problem.
In my game mode’s OnPostLogin event, I am spawning a character and using Possess on the controller to possess that pawn. I added a 1s delay after spawning the character, because I know that seems to be necessary (less than 1 second should be enough from what I’ve seen). I then also use Enable Input on the controller.
Over on the controlle’s OnPossess event, I am setting a variable that stores the character that is possessed, but for some reason, this variable always ends up as None for the client. Why is that? Isn’t the controller owned by the client and should be getting the character without a problem? The result of this is the client is just stuck staring at the sky, though their character is spawned fine. They can’t move the character since I placed checks throughout my controller to only execute input actions when the character is valid. What am I missing here? I’ve tried force-setting the character with custom events that run in every way possible; run on owning client, run on server, multicast. I’ve tried using a RepNotify event on a boolean called “PawnPossed” that then sets the character variable, still no go.
Thank you for writing back! This issue has been frustrating me for a week or two. Last night I moved some of the logic from the game mode to the player controller, mainly the spawn logic, as I read it’s better practice to not handle that within the game mode. The one step I’m missing that’s driving me insane is that the OnPossess node for the controller only executes on the server, and even if I call a run on client event there, passing it the character pawn that is spawned, it doesn’t execute at all! It completely bypasses that node and I don’t understand why.
I am storing the character variable (or trying to) so that I can easily verify that it is valid any time the user hits a key; I read that is good practice. The editor spits out a bunch of errors if the character isn’t valid otherwise, because the inputs attempt to execute things on the character of course.
In the game mode settings, I have the default character set to none because that causes duplicate pawns to be spawned. I don’t want the game mode to immediately spawn a character for the players by default when they join (I want to eventually let the player select a player class, etc.)
I really wish this forum would let you just paste screenshots in from the clipboard.
Here is the OnPostLogin in my game mode. It simply adds the controller to an array (incomplete, but just doing this to use it later for scoreboard/etc.) and then calls a custom OnPostLogin on the controller client-side:
The client-side OnPostLogin in the controller then simply calls a RequestSpawn event on the server (I intend to do further stuff here like allow the player to choose their player class, etc). RequestSpawn finds the best spawn point and spawns the character (this all works, as I can see the character spawn in the server’s preview), tells the controller to possess it, and then “tries” to execute the SetPossessedPawn event on the client to set the character variable. This is I think the missing key here; why isn’t that event being executed properly on the client??? The possession node is working, because if I print (from the server) the controller and controlled pawn’s object names, they are printed fine.
Edit: I just tried throwing in the “Handle Starting New Player” event in the game mode and I may be getting closer. The client’s camera is now at least with the character but still have no control over it, and can’t see the server’s character walking around (so strange). What’s the difference between OnPostLogin and Handle Starting New Player?
Going absolutely nuts here. I set up an Event Tick on my controller to check if the controlled pawn is valid. When I look at the debug flow from the server, the controlled pawn shows correctly, but from the client, it shows as None. The client is clearly not possessing the pawn correctly on their controller. My head hurts…
Well, I’m clueless as to why but this is working now. I disabled the Component Replicates option on the component I have on my character for inventory, and that took care of the problem. Seriously don’t understand why it was the problem, but it was. I don’t necessarily need it to replicate since the only time other players’ inventories are relevant (once killed and being looted), the server will handle retrieving it and making it visible in the UI, and only the server can manage the inventory too. The inventory component BP is set to replicate itself, so I don’t get why setting it to replicate on the character broke this. Is it trying to “double” replicate or something?
After banging my head against this for hours and hours, I came to a solution that is clean enough and works. Here’s an explanation of what my issue was:
In the Player Controller, on Event Possessed, I set a reference to my pawn like so:
However, when a client Joins the Session, the Event Possessed does not fire on the client as Unreal only lets this occur on the server (don’t ask me why). Thus, I created a custom twin of the EventPossessed, and called it on begin play on remote only, meaning the custom possession event will only fire on the client.