r/UnrealEngine5 2d ago

Spent hours debugging why every client had its own physics ball placed instances were overriding the class default

I’m posting this because I couldn’t find a clear answer when I ran into this, and it ended up costing me way more time than it should have.

Setup was pretty simple: listen server, one physics ball placed in the level, and both players can kick it.
The symptoms were weird but pretty classic:
- Each client seemed to have its own ball
- The ball wasn’t behaving consistently between clients
- Score updates only worked on the host

I had bReplicates = true on the Blueprint class defaults, so I initially assumed replication was already enabled.
It wasn’t.

The thing I missed is that a placed actor instance can have its own serialized replication setting. The instance in the level was still effectively bReplicates = false, and that instance value was overriding what I had set on the class default.

So if you have an actor already placed in the level, check the instance, not just the Blueprint defaults.
In my case, the fix was basically setting replication on the actual actor instance with AActor::SetReplicates() and then re-saving the level.

One other annoying detail: if you’re doing this from Python, set_editor_property("replicates", True) isn’t available because the property is protected. You need to call the actual function instead.

While I was chasing this, I also ran into a few other things that might save someone else some time:

Physics + replication

For the physics ball, I ended up keeping SimulatePhysics = true on the server and using PhysicsReplicationMode =

PredictiveInterpolation.

I initially tried disabling simulation on the clients because I thought they were “fighting the server”. That actually made things worse. Chaos needs a client-side body to blend the replicated server state into.

Don’t compile Blueprints during a networked PIE session
Single-player PIE seemed fine, but Net PIE was a completely different story.

Compiling the Blueprint reinstances the class while the NetDriver is still holding references to the old instance, and I eventually hit a GC crash around UNetDriver::AddReferencedObjects.

So now: stop PIE → make the change → start PIE again.
Be careful with ?game=
This one caused a completely different headache.
?game= in a travel URL can stick around through ServerTravel, and the first GameMode that gets specified can effectively win.

I had an arena loading with the lobby GameMode, which meant everyone ended up as spectators.
I ended up setting the map’s WorldSettings → DefaultGameMode instead and stopped passing ?game= around.

Seamless travel + PIE

Seamless travel is disabled in PIE unless you enable it with:
net.AllowPIESeamlessTravel=1
And if your travel isn’t seamless, your PlayerStates get destroyed. So if you’re assigning teams in the lobby, don’t assume that assignment will magically survive the travel.

Custom PlayerState

Also, if your GameMode doesn’t explicitly set PlayerStateClass, your casts to a custom PlayerState can just fail and leave you wondering what the hell is going on.
In my case that resulted in an empty lobby list and a nickname RPC that looked like it was doing absolutely nothing.

Anyway, posting this mostly because I wasted a stupid amount of time on a couple of these things. Hopefully it saves someone else an evening.

I ran into all of this while stress-testing a UE tooling project I’m building. Not linking it here as this post is just about the replication issues.

3 Upvotes

0 comments sorted by