What conditions other than packet loss cause unreliable RPCs to fail?

I have a function call that is marked to execute on the server only. It appears to not be called at all 95% of the time. What’s even more strange: when I’m testing with four clients, it appears to mostly affect players 3 and 4, not 1 and 2. Every other aspect of the game is replicating fine. To rule out packet loss, I also have tried locally with network emulation / packet loss turned off. I still have the same issue.

Marking reliable seems to “fix” the problem, but realistically, it seems like even unreliable function calls shouldn’t be this unreliable.

I’m on 4.25.1, if that helps. I don’t know if this is the right forum for this. This new forum UI is incomprehensible to me.

Reliable RPCs are not throttled by net limitations and always pushed thru. Judging from the symptoms it seems like you are sending way too much data per frame and hitting the 10kbps limits set by default. A couple of changes in ini’s can help to relax on these limitations, but it’s likely a better approach to rethink what the code does and avoid calling the RPC too frequently. One call per frame should work with a small amount of data, that’s exactly what Character Movement does when sending the ServerMove() for example.

Thanks, that makes sense. I agree it seems abnormal for just a small test game to be hitting those limits. Is there a way to debug what all is filling the pipe and causing things to be dropped?

Edit: (This particular RPC isn’t being called that frequently, for what it’s worth. I assume it’s just being pushed out because of other things).

I’ve tried fiddling with a few settings, setting them to values much higher than I think I need:




But nothing short of marking the RPC as Reliable seems to make it go through.

I turned on network stats and noticed when I have 3-4 players, my “saturated connection” stat will start going up when I move around, but it seems to be uncorrelated with the RPC failing to go through (e.g. it’s not as though the RPC goes through when saturated connections is 0 and fails when it’s at 4).

I’ve done a lot more testing. I have a lead, but it hasn’t given me any good answers.

I’ve noticed that if I call this RPC from my projectile’s graph, it mostly fails. If I call the RPC when pressing a key, that works fine. I thought this may have to do with the projectile’s priority, but upping it didn’t help. I tried a few things to force the call to “go through” the player (calling a function on the player that calls the RPC; calling an event dispatcher on the player instead), but none of that worked.

I’m at a loss. This is truly baffling to me. My hail mary next attempt will be to upgrade unreal to 4.26. If that doesn’t work, I guess I’ll just make the RPC reliable. I really don’t want to have to do that for everything though.

For an unrealiable RPC to arrive, the object must be already replicated to the client (!) and within the replication range. Perhaps you’re just calling it too early?

In this case, I’m calling the RPC when the projectile overlaps with the player, so in theory, it couldn’t be any closer. That being said, the actual RPC is stored on the Player object, not even on the projectile. So basically, the flow is this:

# Works ~5% of the time
Projectile Overlaps with Player -> Projectile calls Player.DoDamage (a server replicated RPC)
# Works 100% of the time
Press a debugging key -> Call Player.DoDamage

And to be clear, the DoDamage RPC is defined on the Player that is doing the damage (i.e. it has a “target” player for the damage to be applied to as one of the arguments). So the Player initiating the RPC should be the owning client.

As far as I can tell, upgrading to 4.26.3 seems to have fixed it. Wish I had tried that 10 hours ago.

debug the overlap with print string. If the print fails you need to look at collision. Turning on CCD etc. Yet I have projectiles with velocities around 900m/s that register fine without CCD.

The overlap wasn’t the problem. I confirmed the node directly before the RPC call was running fine (which is triggered on overlap). All other local actions that were set to run on overlap were running too.