I spent a year building a multiplayer shooter template, and the hardest part was letting players build the map

I have been working on a third person shooter framework for UE5 for about a year. It started as a netcode exercise and turned into something I did not plan: a map editor that runs inside the game, where a map you build is sent to your friend over the network when they join.

This is a write-up of how the two halves fit together, and the parts that were harder than I expected. It is a commercial template - the link is at the bottom - but the interesting content here is the problems, not the sales pitch.

The shooter half

The combat is C++, server-authoritative, with the client predicting what it can.

Server-Side Rewind. The server keeps a short history of every character’s hitboxes. When a shot arrives it rewinds those boxes to the moment the client actually fired, traces against that older state, and puts everything back. Hitscan, projectiles and shotgun pellets all go through it, with headshot detection.

The part I did not anticipate: rewind becomes unfair past a certain ping. It does not delete the latency, it just decides the target absorbs it instead of the shooter. At 400 ms you are killing people who already reached cover on their own screen. So there is a ceiling - above a threshold rewind turns off, the shot falls back to plain server-authoritative detection, and a warning icon tells the player why the feel changed.

Weapons. Pistol, SMG, assault rifle, shotgun, sniper, grenade launcher, rocket launcher. Hitscan with surface-based impact FX, projectiles with their own flight and radial damage, shell-by-shell shotgun reloads, graduated scope zoom, predicted reloads and ammo.

Locomotion is Blueprint, built on Motion Matching - real starts, stops, pivots and turn-in-place, replicated for simulated proxies so other players animate without a per-tick network cost.

Match flow. Warmup, Match, Cooldown, team deathmatch and free-for-all, team spawns, scoring, leaderboard, winner announcement and restart.

The Creative Mode half

A map editor inside the game. No Unreal Editor, no cooking, no asset work - your players can use it.

You fly, you point, you click. A categorised palette of pieces, real move and rotate gizmos with grid and angle snapping, multi-select, 128-step undo where one action is one step whether it moved one piece or ten. Weapon, ammo and buff spawners you place yourself. Player starts for neutral or per team, so the same map works for both modes.

The sky is part of the map, not a backdrop. Five weather presets with blending, a day/night cycle you can set by hand or let run. Rain leaves splash ripples. Snow accumulates on every surface, changes the footstep sound, and keeps the prints players leave in it. Weather stops at a roof instead of falling through it - that one is a GPU depth-buffer collision module plus a shelter probe that moves the spawn band.

The part that was actually hard

Getting a player-built map onto the other machines.

The map only exists as data at runtime. There is no cooked level to travel to, so the usual answer - ServerTravel to a map name - has nothing to point at.

Replicating the geometry does not work either. A map of any real size blows straight past the replicated array size ceiling, and even if it fit you would be sending the same meshes everyone already has on disk.

What worked was not replicating the map at all. Each piece is stored as an id plus a transform. The host hands that list over on join, and every client rebuilds the level locally out of its own cooked assets. Nothing large crosses the wire and both machines end up with identical geometry.

Two things I would warn anyone about. Pieces have to become static once the match starts - leaving them movable looks fine in a single-player test and falls apart the moment two clients disagree about physics. And save files must store ids, never asset paths: the moment a path is baked into a save, moving an asset breaks every map anyone ever built.

What I would do differently

I hardcoded asset paths in C++ early on. A ConstructorHelpers FObjectFinder with a literal /Game/ path is invisible to the editor’s reference fixer, so when I reorganised content the game broke silently at runtime, and the editor’s own move tool reported success while doing nothing - because the loaded module was holding those assets. Everything that can be is exposed in Project Settings now, and the data assets are registered with the Asset Manager by class rather than by folder, so nothing depends on where a file sits.

Happy to answer anything about the netcode or the builder. The rewind ceiling in particular is a design decision more than a technical one, and I am curious what thresholds other people landed on.

Ultimate TPS on Fab: Ultimate Third Person Shooter — Multiplayer + Creative Mode + Lag Compensation | Fab