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!
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.
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.
/**
* 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)
- Where do you Spawn the Bullet? (Where, which function, Server or Client?)
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)?
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!
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?
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.
Having this function code to run whenever the Projectile is spawned, here is the output:
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.
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.