Replication for UI/Health comp

I’m new to replication and multiplayer so maybe im missing something simple here. I have a HUD that on startup spawns the characters UI and makes a reference to it call “Main widget ref”.

Then once selecting team and spawning FirstPersonCharacterBP in it runs a on event begin play to a RPC Server - to RPC Owning Client to give my players their team tag and attempting to give my HUD widget ref a ref to the first person character that has the health comp inside it. (as seen in photo 2)

It reads nothing from the first person var inside the HUD widget. I feel like my health comp should be on the character BP and i feel like my UI setup works best when spawned on HUD But not getting the results i need from this setup, is this structured wrong?

there are a few issues here,

the server RPC can fire before the Player has loaded therefore being missed. Do you even need the server RPC? can you use BeginPlay on the LocalPlayer?

you Widget is marked as replicated but widgets are local only so they dont replicate, is it setup correctly on client? does it pass the valid check?

Dont use GetPlayerController(x) in multiplayer, its probably fine here but can break in future.

I dont see your health anywhere but things like health should be RepNotify not RPC.

Check your Tags, you Tag is replicated but the Tags array isnt, although if its the inbuild Tags im not sure how they work in multiplayer, i’d suggest creating a struct for ‘playerstate’ ie Name/Team etc and repnotify that

This ^^^^

Health, stats, team, etc should be in the PlayerState for multiplayer.

On the characters autonomous proxy use begin play to call up to the controller. From PC you can get the player state natively. Fire off server RPCs relating to health stats from the PS.

On the receiving side have the authority proxy call the GS, GM etc as needed. Setting values happens on the authority end.

Health in the PS should be a Rep notify. This will create an onrep health function. Use that function to update UI etc.

As far as setting teams this should be handled by the GM via on post login.

On post login provides a ref to the controller. Use that red to get the PlayerState and set the team. You can use an onrep here as well. Helps if teams can be changed later. Use the onrep function to update team colors, UI etc.

The advice above is right and you should follow it, but nobody’s said why your current graph reads nothing, and I think it’s worth knowing because it’s a trap you’ll keep hitting until you’ve seen it once.

Your Client RPC is almost certainly being thrown away.

You’re firing this from the character’s BeginPlay. On the server, the order inside RestartPlayer is:

SpawnDefaultPawnFor()   <- pawn spawns, BeginPlay runs here
Possess()               <- controller takes the pawn, ownership established

BeginPlay happens before Possess. So at the moment your RPC_S_Startup_Info runs on the server, that character has no owning connection yet. “Replicated To Owning Client” with no owning client doesn’t queue or retry, it just gets dropped. No warning, no log, nothing.

That’s why you see no error and no result. The RPC isn’t failing, it’s going nowhere.

Same thing on the client side if BeginPlay beats the Controller being replicated in, a server RPC from an unowned pawn gets discarded too.

Quick way to confirm before you change anything: put a print on the first node of RPC_C_Startup_Info. If it never prints, that’s your answer.

The second thing, in your HUD graph

Your Create Character UI Widget node has the Owning Player pin empty. Fill it in with Get Owning Player Controller. Left empty it can resolve to something you didn’t expect, and anything in the widget that calls GetOwningPlayer later will come back null, which gives you exactly the “reads nothing” symptom again but from a different direction.

Why the PlayerState advice fixes this and not just because it’s tidier

The useful way to think about it is this. RPCs are order dependent. They fire once, at one moment, and if the thing on the other end isn’t ready, that’s it, you’ve lost it. You end up writing IsValid checks everywhere, and your IsValid on Main Widget Ref is doing exactly that, it’s quietly swallowing the failure with no retry path.

RepNotify is order independent. The value replicates, and whenever it lands the OnRep runs, whether that’s before or after your HUD exists. You stop racing.

So put health and team on the PlayerState as RepNotify variables, and have the UI read from there. PlayerState is replicated to everyone and it exists before the pawn does, so the timing problem disappears instead of being worked around.

For the UI, rather than pushing a reference into the widget from outside, pull from inside it. GetOwningPlayer, then PlayerState, then cast. Do it in an OnRep and in the widget’s Construct, so whichever happens last fills it in. That way you don’t care about the order at all.

On the tags

Worth adding to what Auran131 said, Actor Tags are not replicated. You’re AddUnique-ing on the owning client only, so the server and every other client has an empty Tags array on that character. If anything server side ever checks that tag it’ll never find it. A replicated enum or a small struct on the PlayerState is what you want.

One last practical note

If you do keep any RPC flow for something else later, drive it from PossessedBy on the server and OnRep_Controller on the client rather than BeginPlay. Those fire after ownership exists, which is the whole problem here.

your client RPC dies before it runs. beginplay on the character fires before possess on the server, so at that moment there is no owning connection yet and a client bound RPC gets thrown away with no warning. ask for the player state from the controller instead and read health as a repnotify there, then let the onrep update teh widget. player state exists for every player on every machine so the ref is always valid. you can also try Blueprint Object Replication, a replication plugin for Unreal Engine that keeps per player stats in objects on a component with rep notifies instead of hand wired RPCs: https://www.fab.com/listings/e26dcf07-7c78-4e67-8e56-272cf6df8021