Prototyping a 2-4 player co-op top-down action game and decided to commit to Godot 4's native MultiplayerAPI instead of pulling in a third-party solution. ENet peer setup is fine, RPCs behave the way the docs promise, and the MultiplayerSpawner + MultiplayerSynchronizer combo is clever on paper. I was feeling good about it for about two weeks.
Then I started pushing on it and the seams showed up. Authority assignment is workable but I keep writing the same guard clause in every function that touches game state:
func _on_hit_received(damage: int) -> void:
if not is_multiplayer_authority():
return
health -= damage
rpc("sync_health", health)
Fine, that's the model. I get it. The real friction is client-side prediction. MultiplayerSynchronizer is server-authoritative with no prediction layer built in, which is a fair design decision, but at 80ms latency character movement starts feeling noticeably laggy. I'm looking at two paths: build prediction from scratch on top of the synchronizer, or ditch the synchronizer entirely and manage delta state manually over RPCs. Neither feels clean.
The inspector-driven replication config also bites me whenever I refactor. Add a property to a synchronized node, forget to update the Synchronizer's property list in the inspector, and you're debugging why state doesn't replicate with zero error messages telling you why.
I've looked at alternatives. Nakama feels like serious backend infrastructure for what is genuinely a 4-player game. GodotSteam is appealing but I want to ship on itch.io as well. Fishnet exists if I wanted to jump to Unity, but I'm not there yet.
Has anyone actually shipped something, not just prototyped, using Godot 4's native multiplayer stack? Did you stick with MultiplayerSynchronizer or end up rolling state sync manually? And if you tackled client-side prediction, is there a pattern that didn't fall apart under pressure?