Also, another thing:
SpawnActor(...) as a func is the one and only method used to create an actor when not loading them from a level, and takes Location, Rotation, Owner as parameters.
It can optionally take another existing actor as template, but this is almost never used.
SpawnActor calls all spawn events during this function.
When PostNetBeginPlay() is called, the actor already has had it's initially replicated variables set.
#1 This means that whatever replication does to set an actor's initial variables, it can only set Location, Rotation, Owner during spawn.
#2 All other variables have to be set AFTER SpawnActor(...) finishes.
#3 This means PostNetBeginPlay() is called AFTER all other common spawn events.
#4 This also means that PostBeginPlay() is called BEFORE the additional variables are set.
STUFF NOT DEDUCTIBLE THAT NEEDS TESTING==>>>
Are location, rotation, owner set during SpawnActor by replication code? Test using PostBeginPlay()
What happens to Owner (or any other Actor reference) when said actor reference isn't present on the client?
(In short: you receive a Flak Cannon, but it's monster owner isn't on your client... yet)
The 'initial replication' contains a fixed packet which is an encoded Location+Rotation, nothing related to owner.
This is used for spawn (i checked on newer UE's, should be the same on v436)
Theoretically the server knows when said reference isn't present on your client and doesn't mark it as 'replicated', it will delay it's replication until the reference does exist.
There's a problem here, if the reference times out and becomes irrelevant, there's nothing in the server that marks the reference as 'not replicated', so this process only happens once.
(Player becomes irreleveant, his PlayerReplicationInfo loses owner, never regains it)
That's why when you're dealing with replicated actor references you have 2 cases:
You have control of the code of both actors:
Use PostNetBeginPlay() on both to cross-link them, see PlayerReplicationInfo.PostNetBeginPlay() and Pawn.PostNetBeginPlay().
You only have control of the code of one actor:
Store a unique identifier of the target actor, and run a periodic check to re-acquire it, replicate the Identifier and not the reference.
(see sgPlayerData actor in SiegeIV)
An example of advanced crosslinking.
Siege has a 'sgCategoryInfo' actor that contains up to 128 constructibles.
Each constructible (sgBuilding) can have a special rule that limits its availability.
Each special rule is an actor that knows on which contructibles is applied on.
This means the special rule would need to replicate somewhere between 0 and 128 integers to a client right?
Nope, only up to 4, because of bitwise operations compressing the data into 4 integers.
https://github.com/CacoFFF/SiegeIV-UT99 ... oryInfo.uc
https://github.com/CacoFFF/SiegeIV-UT99 ... ildRule.uc
See: MasterSet() in sgBaseBuildRule.
sgCategoryInfo and sgBaseBuildRule have special cross-referencing, idea is to find each other.
If sgCategoryInfo arrives first, it'll fail to find all sgBaseBuildRule not yet received.
If sgBaseBuildRule arrives first, it'll fail to find the sgCategoryInfo.
But since both are coded to find each other, the result will be perfect cross-referencing.
Back to the array, how do we encode the sgBaseBuildRule actor's position(s) in sgCategoryInfo.NetRules?
See sgBaseBuildRule.AppliedOn, each INT has 32 BITS, each BIT is a position, you have 128 positions that can be 0 or 1.
This is simple packed boolean array compression.
Another case of linking:
Rules come in various types, there's additional 'NOT' and 'COMBO' rules that either reverse the result, or demand that all child rules are valid before itself being valid.
The sgBaseBuildRule has a function IsEnabled() that indicates that this rule has been properly initialized and is ready to be used (by client or server).
https://github.com/CacoFFF/SiegeIV-UT99 ... RuleNot.uc
https://github.com/CacoFFF/SiegeIV-UT99 ... leCombo.uc
As you can see, the base sgBaseBuildRule contains all overridable methods needed to make the rule system ignore subclass casting, and the subrules tell the client when replication has been properly finished.
These methods also have a portion of linking themselves, which works by validating a variable the server sends and the actual linking done.
If a combo rules states that there's 3 sub-rules, then the client must find at least 3 rules that identify the combo as it's 'master' rule.
The cross-referencing done here is all based on PostNetBeginPlay() events, you'll find absolutely no periodic checks.
The code will stop working if a rule is deleted, and start working again when replicated by the server a second time.
So crosslinking is secure, doesn't break the client, allows the server to manipulate rules.