Reliable vs Unreliable RPC Budget¶
Reliable is a delivery promise, not a free "make multiplayer work" button. Use it for rare messages that must arrive, not for Tick, held input, aim spam, or state that should have been replicated.
At a glance
Use this for: choosing Reliable, Unreliable, RepNotify, or local prediction for beginner network events - Main rule: reliable traffic is a budget - Best default: durable results as replicated state, low-frequency requests as reliable, frequent/cosmetic events as unreliable or local - Official docs: Remote Procedure Calls, Network Debugging, and Testing and Debugging Networked Games
The one-minute version¶
- RPCs are one-way network messages. They do not return a value across the network.
- Reliable means the networking layer keeps trying to deliver the RPC while the connection is alive.
- Reliable does not mean instant, validated, cheat-proof, ordered against all other gameplay systems, or safe to call every frame.
- Backed-up reliable traffic can delay later reliable messages on that channel.
- Unreliable means the message may be dropped. That is acceptable for disposable or frequently refreshed data.
- If the result must still be correct for late joiners or newly relevant clients, use replicated state or RepNotify instead of relying on a one-time RPC.
- A beginner project should treat reliable RPCs as a small budget for low-frequency requests and important notifications.
What Reliable buys¶
Reliable buys delivery attempt and ordering within the reliable stream for that actor/channel path. It is useful when losing the message would break the feature:
Client:
clicks Ready once
-> ServerSetReady(true) Reliable
Server:
validates lobby state
sets PlayerState.bReady = true
If the packet has to be resent, the player may see latency, but the request is important enough to keep.
Reliable does not buy:
- server trust;
- bandwidth;
- instant response;
- immunity from bad ownership;
- a return value;
- correct state for late joiners;
- permission to call from Tick.
The server still validates every client request.
What Unreliable is for¶
Unreliable is for messages where the next update or local fallback matters more than an old missed packet.
Good unreliable candidates:
- cosmetic impact pings where the next impact can replace the old one;
- repeated remote aim/look updates if you choose an RPC path;
- footstep, muzzle, trail, or camera-style cues that are not gameplay truth;
- short-lived animation or audio cues for currently relevant clients;
- debug-only network markers during development.
Unreliable is not "bad." It is honest. Some messages are disposable.
The decision table¶
| Event / data | Better first choice | Why |
|---|---|---|
| Press ready in lobby | Reliable Server RPC -> replicated PlayerState | Rare request; durable result. |
| Open shared door | Reliable Server RPC request -> RepNotify door state | Request matters; open state must persist. |
| Fire hitscan weapon | Reliable or rate-limited Server RPC request -> replicated ammo/hit result | Request matters, but do not spam without cooldown. |
| Hold automatic fire | Local input loop + rate-limited server fire requests/state | One reliable RPC per Tick will clog. |
| Aim direction every frame | Unreliable updates, compressed replicated state, or Character/weapon state | Old aim packets are usually stale. |
| Footstep sound | Local/AnimNotify presentation, maybe unreliable multicast | Missing one footstep is acceptable. |
| Health value | Replicated/RepNotify variable | Current value matters after packets/events are gone. |
| Explosion destroyed barrel | RepNotify destroyed state + optional multicast FX | The visual is transient; destroyed state is durable. |
| Private "purchase failed" message | Reliable or normal Client RPC if rare | Only owning client needs the result. |
When in doubt, ask:
If this exact message is lost, can the next state update repair it?
If a late client joins, does it need to know this happened?
How many times per second can this graph call the RPC?
Held input and Tick¶
The common beginner bug:
Input Fire Triggered or Tick:
ServerFire Reliable
If this runs every frame while the button is held, a short lag spike can build a reliable backlog. The player releases fire, but old reliable fire requests are still queued.
Better shapes:
Semi-auto:
one press -> ServerFire once
server enforces cooldown
Automatic:
local held-input state starts a fire timer
fire timer sends requests at weapon fire rate, not frame rate
server validates cooldown/ammo
Continuous aim:
send compressed aim at a fixed low rate
use unreliable or replicated state depending on design
Rate limits are not polish. They are part of the network contract.
Reliable is not validation¶
A reliable client request can still be false, stale, or malicious.
Client:
Reliable ServerTryPickup(PickupActor)
Server must still check:
actor exists
pickup is relevant/valid
player is close enough
line of sight or overlap is still valid
inventory has space
pickup not already consumed
Reliable only helps the request arrive. The server decides whether the request is accepted.
Ordering is narrower than beginners expect¶
Reliable RPCs preserve ordering on the relevant network path, but gameplay systems around them can still surprise you:
- a replicated variable update and an RPC may be observed in an order your Blueprint did not mentally model;
- different actors/components have different channels and timing;
- network emulation can expose assumptions that only worked under zero lag;
- a late client can receive current replicated state without ever receiving the earlier transient RPC.
If two values must be interpreted together, replicate one struct or state enum. If an RPC depends on a state value, include the minimum data the receiver needs or make the receiver read a durable replicated state after it arrives.
Fire, reload, and ammo examples¶
Good semi-auto request¶
Owning client:
Input Fire Started
-> local muzzle/camera prediction if desired
-> ServerFire(AimData) Reliable or rate-limited
Server:
validate weapon, cooldown, ammo, aim, team
decrement replicated ammo
apply hit or spawn projectile
set replicated fire sequence / impact state as needed
Clients:
update ammo/UI from RepNotify
play confirmed impact/firing presentation
Bad automatic fire¶
Tick:
if bHoldingFire:
ServerFire Reliable
This ties network traffic to frame rate. Under packet loss, old fire requests can pile up.
Better automatic fire¶
Client:
bHoldingFire local
fire timer ticks at weapon fire interval
local prediction plays cautiously
ServerFire request at fire interval
Server:
rejects if cooldown/ammo does not allow it
replicated ammo/current fire state is the truth
The weapon fire rate, not the monitor refresh rate, controls the request rate.
When it fails, and what failure looks like¶
| Symptom | Likely cause |
|---|---|
| Game feels worse after checking Reliable | Reliable messages are being spammed and backing up. |
| Remote client action still does nothing | The actor is unowned/non-replicated, so reliability never made the RPC eligible. |
| Late joiner misses an important result | You used a one-time RPC instead of replicated durable state. |
| Player fires after releasing input | Old reliable fire requests were queued during lag. |
| Health UI misses intermediate hits | Health should be state plus optional hit sequence/cue, not only transient RPCs. |
| Multicast did not reach a client | The actor was not relevant to that client when the multicast was sent. |
| Server accepts impossible action | Reliable request was delivered but not validated. |
| Network emulation breaks the feature | The graph assumed zero latency or no packet loss. |
Debug by printing RPC name, actor, net mode, authority, owning connection path, timestamp/sequence if you use one, and whether the server accepted or rejected the request. Then test with packet lag/loss after the basic no-emulation path works.
What Reliable does not do¶
- It does not fix missing ownership.
- It does not make a non-replicated actor carry RPCs.
- It does not make Multicast global.
- It does not validate client input.
- It does not make high-frequency traffic free.
- It does not preserve durable state for late joiners.
- It does not avoid the need for RepNotify/UI refresh.
- It does not guarantee a good user experience under latency.
Lookalikes - which one do I want?¶
| Tool | Use when | Not for |
|---|---|---|
| Reliable Server RPC | Low-frequency owning-client request must reach server. | Tick, held input spam, or unvalidated gameplay. |
| Unreliable RPC | Transient/frequent event can be dropped. | Durable game state. |
| Replicated variable | Clients need the current value. | One-time sound/particle pulse. |
| RepNotify | Clients need local presentation when state arrives. | Client-to-server requests. |
| Run on Owning Client RPC | Server sends private feedback to one owner. | Public score/objective truth. |
| Multicast RPC | Server sends a transient cue to relevant clients now. | Late-join-safe state. |
| Local prediction | Owning client needs immediate feel before server result. | Final authority. |
| Timer/rate limiter | Held input should produce fixed-rate requests. | Per-frame networking. |
The quick path is to mark every RPC Reliable. The concrete cost is hidden traffic debt: the game can feel less responsive exactly when the network gets worse. Spend Reliable on messages that deserve it.
Going deeper¶
- Blueprint Custom Events as RPCs - Blueprint RPC modes, ownership, and naming.
- Replication basics - why durable state should be replicated state.
- RepNotify variables and local presentation - current values and local presentation hooks.
- First weapon fire pattern and impact cleanup - fire requests, cooldown, ammo, and hit feedback.
- Actor relevancy, owner-only, and dormancy basics - why multicast reaches relevant clients, not all possible clients.
- Network Emulation for beginner replication checks - testing reliable/unreliable assumptions under lag and loss.
- Official docs: Remote Procedure Calls, Actor Owner and Owning Connection, Replicate Actor Properties, Network Debugging, and Testing and Debugging Networked Games.
- Engine source (requires engine access - we do not reproduce it here):
actor RPC dispatch starts around
AActor::CallRemoteFunctioninEngine/Source/Runtime/Engine/Private/Actor.cpp; component RPC dispatch starts aroundUActorComponent::CallRemoteFunctioninEngine/Source/Runtime/Engine/Private/Components/ActorComponent.cpp; network channel and bunch handling, including reliable/unreliable traffic details, lives in engine networking code such asEngine/Source/Runtime/Engine/Private/DataChannel.cppand net driver code underEngine/Source/Runtime/Engine/Private/NetDriver.cpp.