It is definitely a topic that takes some time to wrap your head around and I won’t be able to do it justice here in a few paragraphs. This is something you’ll need to really put some time into to make sure that you grasp the concepts as it’s critical to any multiplayer endeavor with unreal or any other game engine for that matter.
Here are some good resources on the topic.
An Unreal Engine Blog – An Unreal Engine Blog (cedric-neukirchen.net)
Multiplayer in Unreal Engine: How to Understand Network Replication - YouTube
With that being said, let’s focus for a minute on what you have going on and hopefully I can relay the information in a way that’s meaningful. Keep in mind that I’m intentionally keeping this as focused on your issue as possible. You will find there are usually a couple of ways to solve a problem. My intent here is to offer a glimpse into what a typical design patter for something like this might look like.
First, everything you’re attempting to do can be done inside the pawn/character, including the search for the nearest player. From what I can see it looks like you might have put that out to a blueprint function library is that correct? Not that it’s complex by any means but initially start simple. If you find you need the function elsewhere then you can move it to a BFL.
Next, be careful with what you put on tick. All to often you see people adopt design patterns that rely on that over well thought out execution flows. Don’t get me wrong, some times it’s unavoidable. When to use it and not becomes more apparent with more experience. Everything you have on tick at the moment should be put elsewhere.
Now, a bit about your specific problem and how it relates to replication. I’m going to assume for a second that you’re running a listen server where one player is the host and the other is the client. Under this scenario, once play has begun the host version of the game (the server) will have the following:
- A Pawn/Character possessed/controlled by Player1 which we’ll refer to as SPawnA (S for server)
- A Pawn/Character possessed/controlled by Player2 which we’ll refer to as SPawnB (S for server)
On the client you will have the following
- A Pawn/Character possessed/controlled by Player1 which we’ll refer to as CPawnA (C for client)
- A Pawn/Character possessed/controlled by Player2 which we’ll refer to as CPawnB (C for client)
Keep in mind this is the tip of the iceberg as there are of course and gamemode, gamestate, playerstate, etc. that are all available but we’re going to focus on the things that matter to your scenario at the moment so you’re not drinking from the fire hose.
So, while playing on the host/server you are Player1 controlling SPawnA. While playing on the client your are Player2 controlling CPawnB. The general idea is that anything Player1 does with it’s pawn on the host, gets replicated and played back down on the client. Anything Player2 does with it’s pawn on the client, gets replicated and played back on the host. I can not stress enough how simplified a view this is and how much is hidden from you, but let’s move on.
Ok, from here, whenever I consider the execution flow I prefer to think of things from the client’s perspective as this usually pertains to the server as well but not vice versa so let’s start there. So the client (Player2) wants to kill the nearest player. He presses a key which fires a chain of execution in CPawnB. Right now you’re finding the nearest player on the client side and attempting to change it’s health. While this works locally for the client, the server has no idea what has just happened, why? The simple answer is that the client does not have the authority over the game, the server does. So anything you change on the client, unless explicitly replicated upstream, has no effect on the server. Let’s make it have an effect. In order for this to work, you want the “GetNearestPlayer” function to run from the server version of CPawnB (SPawnB). So how do we do that? With a server reliable RPC. Create a custom event in your character graph and set it to “Run On Server” and check the reliable flag. This will tell unreal that this event needs to be run on the server AND we need a guarantee that it is going to fire (reliable). Then, move the BP nodes that you currently have following “InputAction Kill” over to this new event, and hook the inputaction up to a call to your newly created event. So the execution flow looks something like “InputAction Kill” → “NewCustomEvent” and “NewCustomEvent” → “GetNearestPlayer” → etc.
Right so, in the spirit of KISS (Keep It Simple Stupid), let’s stop there and I want you to do that…with a slight twist. Instead of setting the health to 0, simply call “DestroyActor”, making sure you connect up the return from the cast to the “Target” pin…you don’t want to destroy self. This will allow you to test what you’ve done so far. If executed properly you should, from either the server or the client, be able to hit the kill key and it will make the opposing pawn disappear on both the server and the client version of the games.
Let me know how that goes, and we can move on from there. If you run into issues, make sure to post your new nodes/connections. Oh, and one last thing, move that GetNearestCharacter function over to your character BP. It will simplify it slightly in that you can simply check to see if for loop array element (which is a character) equals “self”. That will explicitely exclude the calling character and get rid of the check for 0 distance.
Good luck!!