Variable changes ONLY on the server and not on the client?

Hello.

I have a Weapon class which spawns a projectile. So, the Weapon that spawns the projectile is also the **OWNER **of that projectile.

In the Projectile class I have a pointer to the Weapon



class AWeapon_Projectile* OwnerWeapon;


I set this OwnerWeapon in the PostInitializeComponents() member function (always in the Projectile class)



OwnerWeapon = Cast<AWeapon_Projectile>(GetOwner());


What is the problem?

The problem is that my BeginPlay() function looks like this:



if (Role == ROLE_Authority)
{
	if (OwnerWeapon)
	{
		if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("Owner weapon found!")));
	}

	else
		if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Owner weapon NOT found!")));
}


When I start the game and shoot with that Weapon, the Projectile gets created and the BeginPlay function for that Projectile is called.

In this case, it prints Owner weapon found!

If I try to change the IF-STATEMENT from Role == ROLE_Authority ----> to ----> Role < ROLE_Authority the output when I shoot the Projectile becomes Owner weapon NOT found!

My question is: WHY?

Hi. I looks like you are having a Replication issue. Spawns happen on the server. So the pointer has nothing to point to on the Clients unless you mark the property as Replicated. ROLE_Authority is that of the Listener/Server. Also note, that the Update of the replicated properties in the Super Implementation of PostInitializeComponents (at the Actor level) calls the function to update replicated components.

Any who, here is the documentation for replication:https://wiki.unrealengine.com/Replication I recommend giving that a read.

If anything, I would add the Replicated attribute to the UPROPERTY of the weapon to make sure it is replicated.

Another point is that it may be that the Owner is not replicated to the Clients? Perhaps looking in the C++ Source for GetOwner() in a Component could help.

Another point could be that the PostInitialization is called only on the Server. I know in the Shooter Game Demo C++ code that it is coded in that manner.

Should I replicate the Owner? If yes, why?

Yeah i thought about it too. Maybe an Engine Developer could answer to this [MENTION=3634]Zak M[/MENTION]

No, the PostInitialization is called both on the Server and the Client.

Owner is replicated:



/**
* Owner of this Actor, used primarily for replication (bNetUseOwnerRelevancy & bOnlyRelevantToOwner) and visibility (PrimitiveComponent bOwnerNoSee and bOnlyOwnerSee)
* see SetOwner(), GetOwner()
*/
UPROPERTY(replicated)
AActor* Owner;


  • Did you actually set the Owner when spawning the Bullet? (If yes, where?)
  • Where do you Spawn the Bullet? (Where, which function, Server or Client?)
  • Are you sure the Replication doesn’t take some time and the Variables is just not yet set? (Do that test in the Tick Function and check, if it just took some time)
  • Can you try getting using “GetOwner()” in the BeginPlay instead of “OwnerWeapon”, just to see if the Owner itself is valid?

This setup seems correct to me, and PostInitializeComponents() should be called on both client and server, before BeginPlay(). GetOwner() should also be valid immediate after the component is constructed. Perhaps you missed a Super::PostInitializeComponents() call? I suggest putting a breakpoint in PostInitializeComponent() and seeing why OwnerWeapon is not being assigned.

- Did you actually set the Owner when spawning the Bullet? (If yes, where?)

I set the Owner in the Projectile class PostInitializeComponents() member function (and [MENTION=3634]Zak M[/MENTION] as you can see I call Super::PostInitializeComponents() here)
585cf84ec8ddc9ac848bc6f416cdfb8805431580.jpeg

- Where do you Spawn the Bullet? (Where, which function, Server or Client?)

I spawn the Projectile from the Weapon class, by calling a ServerRPC function (cause I want the projectile to be spawned on the Server)

Sorry, I was talking about ActorComponent’s owner from GetOwner(), not AActor, so my comment was not as relevant.

Replication of Actor’s Owner could be delayed I suppose, but I wouldn’t expect that if it’s set when spawned, as it would be part of the initial replication. You could hook in to OnRep_Owner() as an alternative. Try to debug PostInitializeComponents() and see why it might not be set.

Is there a reason to not pass in the the Owner as part of the initial spawn call (BeginDeferredActorSpawnFromClass)?

Had I done that, what would have changed?

I **need **a pointer to the Projectile’s owner (the Weapon who spawned it) so that I call functions from it.

Nothing major, only that PostActorCreated() would be called without the Owner being set, but that may not be an issue. Just saying that it’s preferable to avoid subtle issues like that, if you already know the owner when you are spawning.

I’m interested in the results of debugging (PostInitializeCompoents and OnRep_Owner) as I suggested. Also of course make sure that the AWeapon_Projectile and Projectile class are set to replicate (bReplicates = true or SetReplicates(true)).

Yes both classes are set up to replicate.
**
So to summarize everything:**

I spawn a projectile from my AWeapon_Projectile (the implementation can be seen in the screenshot above ServerStartFire_Implementation)
So the projectile is spawned on the server (to avoid cheaters).

Once it’s spawned, the PostInitializeComponents() function is called on the Projectile class. My version of that function can also be seen above.

For the implementation of the Projectile class I took a leaf out of the ShooterGame example. The ShooterGame has this PostInitializeComponents() function implementation:

The** PostInitializeComponents()** is called both on the Client and the Server so the OwnerWeapon variable should be succeffully set for both… or maybe not for the simple reason I’m spawning it on the server? Mhm… confused…

ALSO, NOTICE THAT the ShooterGame PostInitializeComponents() function just gets the Owner of the variable and puts it in temporary variable. In my case, the OwnerWeapon is a variable that belongs to the class!

For the Weapon class it was different:

a55483621a44e74bd72bb21a1c2f62b543fbab51.jpeg

I set the Pawn who is owning the Weapon. When the Pawn dies, the weapon could be picked by another player so the Owner changes.

With a projectile… the owner doesn’t change.

UPDATE:

Doing the same with the projectile, now it works** both for the Client and the Server!**

Anyway, I still don’t understand:** how was I blocking the OwnerWeapon pointer to be replicated to the clients**?. Is that because I was setting the Owner in a ServerRPC call and I needed a RepNotify?

Sorry, by “doing the same”, you mean using a rep notify instead of PostInitializeComponents()?

I set the OwnerWeapon variable the same I did with the MyOwner in the Weapon class



/* owner weapon */
UPROPERTY(Transient, ReplicatedUsing = OnRep_OwnerWeapon)
	class AWeapon_Projectile* OwnerWeapon;	
UFUNCTION()
	void OnRep_OwnerWeapon();





void AProjectile::OnRep_OwnerWeapon()
{
	if (OwnerWeapon)
		SetOwner(OwnerWeapon);

	else
	{
		if (Role == ROLE_Authority)
			SetOwner(NULL);
	}
}


Thanks, I’m going to loop in some of the networking team to see why the old setup didn’t work.

Not sure if your case is the same as mine. For mine, i had to make sure that GetOwner exist before i can use them. It threw up tons of errors when i didnt quote it in my constructor of my ActorComponent (spawned dynamically by NewObject function in my Character). Kinda weird though if a spawned object doesnt have its owner.



// constructor of a newly spawned ActorComponent
if ( GetOwner() )
        OwnerWeapon = Cast<AWeapon_Projectile>(GetOwner());
        //  OwnerWeapon = GetOwner(); // or this, both work with one being safety cast while another is not. 


I can’t remember off the top of my head, but I’m not sure if the Owner and other properties / variables are replicated down to clients as soon as the object is spawned. Mind you if that was the case then ROLE wouldn’t have replicated down either… so IDK.

@TheJamsh
Another question here:

Look at my Projectile::PostInitializeComponents()

38bff6992548bc274973ca6ae76661e8d35e4c68.jpeg

Having this function code to run whenever the Projectile is spawned, here is the output:

2a127d991b1672d621b7a88a25b0abd4c04d766a.jpeg

As you can see from the DebugMessages, the Server GOT the OwnerWeapon while the Client didn’t.

Is it a matter of time?

Because If I do the same check in the OnImpact() function (hence, when the projectile explodes, after a couple of seconds), then also the Client will receive that variable.

I got some clarification from the network team:

On clients, serialization of network properties happens after PostInitializeComponents(), but before BeginPlay(). So moving the caching and use of GetOwner() to BeginPlay() should work here.

I requested that they update the docs to make this more clear. Also you can just use the OnRep_ approach that appears to be working.

That’s interesting. Thanks Zak!