I have written distributed systems for a living, so when I sat down to build a tiny multiplayer prototype in Unreal I assumed the networking would be the easy part. Two players, a box you can pick up, a door that opens. How hard could replicated state be? The answer, delivered over a humbling evening, was: harder than I deserved to find it, because I had been thinking about state far too cheaply.
The thing that catches you in Unreal is authority. In my head, "the box moved" was one fact. In Unreal it is several facts that disagree until you make them agree. The server owns the truth. The client owns a hopeful prediction of the truth. When I picked the box up on the client, it moved immediately, because the client is optimistic, and then a few frames later the server's version arrived and snapped it somewhere else because the server had not agreed yet. The box teleported. My nice clean mental model had a visible seam in it.
The fix is conceptually obvious and emotionally annoying: do not let the client decide things it does not own. The pickup has to be a Server RPC, a request, not a command. The client asks. The server checks whether the box is already held, whether you are close enough, whether the box even still exists, and then it changes the authoritative state and replicates the result back. The variable carrying "who holds this box" needs to be a replicated property, and the moment it changes on a client you react to it in OnRep. I had been treating a request as if it were a decision, and the network was simply showing me, frame by frame, that it was not.
There was a second, smaller humiliation in the if (HasAuthority()) checks. I scattered them around defensively, then got confused about why some logic ran twice and some never ran at all. The listen server is the trap: it is both a server and a client at once, so code that "only runs on the server" also runs on the host player's machine, and code "only on clients" quietly excludes the host. Once I started actually drawing out who runs what (server, owning client, simulated proxy) the double-fires stopped, and so did the embarrassment of debugging a desync that was entirely my own confusion.
The thing I took away is not really about Unreal. It is that I had been carrying a comfortable lie from years of backend work: that I "understood" state. What I understood was state with a single owner and a database that arbitrated everything. The instant the truth lives on one machine and the experience lives on another, with latency in between, you are forced to be precise about a question I had been waving away for years. Who actually decides? In the prototype, the door now opens cleanly, the box stays put, and I have a great deal more respect for the people who ship this for sixty-four players instead of two. The prototype taught me humility the honest way, by being a small problem I was confidently wrong about.