I doubt they will accept a bug report, this is part of core optimizations for development of Fortnite.
Announcement
Collapse
No announcement yet.
Weird replication problem if replicated property set to class default
Collapse
X
-
It does - so I would file a bug report anyway.
Looking through again, I think I can spot a bug which I also ran into and took a while to track down. I've brought this up with Epic on UDN, and the advice I recieved from Epic was to NOT call SetReplicates() in the constructor, and instead set bReplicates = true; directly (also, be sure to call the parents' constructor).
What happened was that SetReplicates() actually adds the actor to the networking system in it's state there and then, but it somehow also caused the system to ignore any deserialized values after that.
I was setting Network Dormancy to DORM_Initial for example, but Replication Graph was adding it in DORM_Awake state (the parents' default value). It took a while to work out why that was happening, but the callstack revealed that the actor was being added to the networking system before it was fully setup and deserialized.
It's stupid I know. My suggestion to Epic was that the block/assert on calls to SetReplicates in the constructor because it can create all kinds of problems, but it doesn't look like they've changed that yet.
---
RPC calls make no sense here, and it's just a recipe for a buggy unmaintanable system if you have to use them to "fix" some other underlying issue, so I agree you shouldn't use them. Properties should be used for anything that determines state.
That being said, sometimes structs with wrapping counters in place of bools can be useful to detect changes you would otherwise miss (e.g, a door opening and closing on same network frame), but that doesn't seem like the issue here. There's nothing wrong with struct replication BTW, it works fine.Last edited by TheJamsh; 10-27-2020, 07:19 AM.Everything @ Stormtide Games - Snr Programmer @ Black Matter Pty.
Twitter - YouTube - Tutorials and Resources: jambax.co.uk
Games: Satellite Command - Hell Let Loose - Project Orion - Eclipse
Marketplace: Sparse Grid Plugin - Export PNG
Comment
-
Originally posted by TheJamsh View PostLooking through again, I think I can spot a bug which I also ran into and took a while to track down. I've brought this up with Epic on UDN, and the advice I recieved from Epic was to NOT call SetReplicates() in the constructor, and instead set bReplicates = true; directly (also, be sure to call the parents' constructor).
What happened was that SetReplicates() actually adds the actor to the networking system in it's state there and then, but it somehow also caused the system to ignore any deserialized values after that.
A nice easy workaround would be if I could just clear the 'cache' that the server replication is using to compare for changes (or force a property cache update). If I could clear it before loading a save game I'm pretty sure it would fix this problem. I've tried ForceNetUpdate, ForcePropertyCompare etc. but none of them seem to do much.
Comment
-
You can try to force a replication once your client has joined. Maybe something like:
Code:if (myActor->GetNetDriver()) { for (UNetConnection* Connection : myActor->GetNetDriver()->ClientConnections) { UActorChannel* Channel = Connection->ActorChannels.FindRef(myActor); if​​​ (Channel != nullptr) Channel->ReplicateActor(); } }
Comment
-
Thanks, BrUnO!
What's the best place to do this on the server? I thought doing it in PostLogin would work, so popped this code in GameModeBase's PostLogin(APlayerController* NewPlayer)
Code:TArray<AActor*>Reps; UGameplayStatics::GetAllActorsOfClass(GetWorld(), AReplicationTest::StaticClass(), Reps); for (auto& Actor : Reps) { if (bDebugPrint) UE_LOG(LogTemp, Display, TEXT("%s [Client %i] AReplicationTest %s (ReplicationTest: %i)"), __FUNCTIONW__, GPlayInEditorID, *Actor->GetName(), Cast<AReplicationTest>(Actor)->ReplicationTest); if (NewPlayer->GetNetDriver()) { for (UNetConnection* Connection : NewPlayer->GetNetDriver()->ClientConnections) { UActorChannel* Channel = Connection->FindActorChannelRef(Actor); if (Channel != nullptr) Channel->ReplicateActor(); } } }
Channel always seems to be nullptr there and so it never gets to the ReplicateActor part.
I also tried in the PlayerController's BeginPlay but this was the same. The only place I could get Channel to be not nullptr is in the Tick (after having been connected for a while), but it still didn't replicate or ever trigger the onRep. I'm guessing it's still assuming the values have't changed and the client has the correct values, and so doesn't replicate?
Comment
-
The `Channel` will be null unless the actor is currently network relevant and non-dormant for that connection (since channels are closed and reopened as actors go in and out of relevancy and dormancy), so it's an unreliable method really.
It's hard to know exactly what's occuring here, but if ForceNetUpdate() and ForcePropertyCompare() don't fix the issue, then the next logical explanation is the Server simply thinks the Client is up-to-date (since all of those functions result in the same thing ultimately). You may be able to drop some breakpoints in RepLayout.cpp to try and get some deeper understanding as to why, but it's going to take some deep digging I suspect.
As another workaround, and something a bit more reliable - my suggestion would be to remove the door actors from the level, and instead create a "Door Spawner" object instead. The Spawner will spawn a new actor at runtime Server-Side, and set properties accordingly. I do this quite a lot in our current game as the different lifetimes of pre-placed actors vs runtime-spawned ones in the networking can create some issues for us, so it's just easier to place a spawner which ensures the same code path is used for all those actors.
BTW - I certainly think it would be worth submitting a bug report with a small repro project to Epic. It might take some time, but if there is an underlying issue they'll be able to fix it quicker. (Also post it here if you do so, I'd be interested to test it out)Everything @ Stormtide Games - Snr Programmer @ Black Matter Pty.
Twitter - YouTube - Tutorials and Resources: jambax.co.uk
Games: Satellite Command - Hell Let Loose - Project Orion - Eclipse
Marketplace: Sparse Grid Plugin - Export PNG
Comment
-
Originally posted by TheJamsh View PostAs another workaround, and something a bit more reliable - my suggestion would be to remove the door actors from the level, and instead create a "Door Spawner" object instead. The Spawner will spawn a new actor at runtime Server-Side, and set properties accordingly. I do this quite a lot in our current game as the different lifetimes of pre-placed actors vs runtime-spawned ones in the networking can create some issues for us, so it's just easier to place a spawner which ensures the same code path is used for all those actors.
Originally posted by TheJamsh View PostAlso post it here if you do so, I'd be interested to test it out)
Contains C++ versions as well as Blueprint (since it happens in both) and some test maps (each containing 3 instances of the replication test actor) to demonstrate the issue:- _0_0_0_to_0_0_0: Editor has values set to 0,0,0 and shows correctly that no replication occurs when the value is set to 0,0,0
- _0_1_2_to_0_1_2: Editor has values set to 0,1,2 and shows correctly that no replication occurs when the value is set to 0,1,2
- _0_1_2_to_0_0_0: Editor has values set to 0,1,2 and shows failed replication on two of the actors when values are set to 0,0,0
- _0_1_2_to_3_4_5: Editor has values set to 0,1,2 and shows correctly that replication occurs when values are set to 3,4,5
BP_ReplicationTest is a blueprint version of the actor which shows that the same replication problem occurs with blueprints.
There's also a folder which demonstrates how it works okay with a delay between setting the ReplicationTests to 0,0,0 in the TestWithDelay folder. I test this using the experimental 'Allow late joining' option. I'll run the server+client 1 and then join a client 2 once the existing server and client have reported their values to the console.
The C++ classes all log to console and I filter with AReplicationTest. BP test prints to screen.Attached Files
Comment
-
I hate to bump, but I just tried this on 4.26 and still having this problem. I submitted a bug report back when I first had this issue.
Is replication just broken in this scenario? How are other people handling things such as the replication of lock status on doors that default to locked (or inventories that don't default to empty and are emptied when the client joins the server)?
Comment
Comment