Outcome
Twenty-plus abilities shipped fully replicated with zero ability-state desyncs reported through QA or Early Access launch, on a codebase that contained no Gameplay Ability System ten weeks earlier.
Client name, project title and identifying detail are withheld under mutual NDA. Figures are as reported at handoff. Everything documented below is technique, which is the part that transfers.
Where It Broke
The project was an action RPG in production with a three-person team and a hard Early Access date ten weeks out. Combat had been built the way most small teams build it first: abilities as methods on character classes, cooldowns as float timers on the character, damage applied by direct function call at the moment a trace reported a hit.
That design is not wrong in single player. It is coherent, it is readable, and it shipped a playable vertical slice. It broke on contact with a second connected client, and it broke in the way that is hardest to debug late — not with a crash, but with two machines quietly disagreeing about game state.
Ten-week fixed runway to Early Access. Existing UE5 project, listen-server topology, cooperative play up to four. Client and project details withheld under mutual NDA — the technique is the citable asset here, not the client.
The reported symptom sounded cosmetic: abilities sometimes double-fire, health looks different on the host. The underlying cause was that the authority model had never been written down, so every ability had quietly invented its own.
Why Class-Based Combat Fails Across the Wire
Three failures compound, and they are the same three every time this pattern reaches multiplayer.
Authority is implicit, so it is inconsistent
When an ability is a method, whoever calls the method decides it happened. Some abilities were invoked from input on the owning client, some from an animation notify that fired on every machine, some from server-side AI. Nothing enforced a single answer to who decides that an ability started. Each ability had an authority model; no two matched.
State lives in unreplicated floats
Cooldowns, resource costs and status effects were plain UPROPERTY floats on the character, mutated locally. A client could believe a cooldown had elapsed while the server disagreed. The client fired, the server rejected silently, and the player experienced a dropped input with no feedback explaining it.
There is no rollback path
Hand-rolled input handling either responds immediately and is wrong when the server disagrees, or waits for the round trip and feels sluggish. Without a prediction framework there is no third option, because there is no record of what was predicted and therefore nothing to undo.
You cannot bolt replication onto a combat system that has no concept of authority. You have to decide who owns each piece of state, and that decision is the architecture.
The Migration
GAS was chosen over a bespoke framework for one reason that outweighed the feature list: it already contains a prediction and rollback model that Epic maintains, and a three-person team does not have ten weeks to write and debug their own.
The migration ran in a deliberate order, and the order is the transferable part. Each stage left the game playable.
- Tag taxonomy first. Before a single ability moved, the Gameplay Tag hierarchy was defined — states, cooldowns, immunities, damage types, ability sources. Tags are the vocabulary every later decision is expressed in, and retrofitting them costs far more than designing them.
- Attribute sets second. Health, stamina, resources and resistances moved off the character onto attribute sets with proper
PreAttributeChangeclamping andPostGameplayEffectExecutehandling for death. - ASC placement third. Player Ability System Components live on the Player State, not the Pawn, so ability and attribute state survives respawn. AI components live on the Pawn, which is the correct trade for actors whose lifetime is the match.
- Abilities fourth, in dependency order. The simplest instant-cost ability first, to prove the pipeline end to end; then channelled abilities, then abilities with projectiles, then the ones with target-actor selection.
- Cues last. All visual and audio feedback routed through Gameplay Cues, so presentation is a consequence of replicated state rather than a parallel system that can disagree with it.
Doing cues last is a discipline, not a preference. As long as VFX are triggered by the same code path that applies damage, a desync in one is invisible until it surfaces in the other.
Replication & Prediction
The replication mode decision was made once, explicitly, and documented — because it is the decision teams most often make by default and regret at scale.
| Mode | What it replicates | Used for |
|---|---|---|
| Full | Gameplay Effects to every client | Nothing here — reserved for single-player and offline |
| Mixed | GEs to the owning client only; tags and cues to all | All player characters |
| Minimal | Tags and cues only, no GEs | All AI characters |
Mixed for players and Minimal for AI is the standard split for a cooperative shooter or action RPG, and the reason is bandwidth arithmetic rather than taste. A remote client does not need the full Gameplay Effect object describing why an AI is slowed. It needs to know the AI is slowed, which is a replicated tag and a cue, and that costs a fraction of the bytes.
Client prediction was enabled only where a wrong prediction is cheap to correct. Movement-affecting and cosmetic ability starts predict; anything that grants an item, spends a rare resource or applies a death blow waits for server confirmation. The rule the team kept after handoff: predict what the player feels, confirm what the player keeps.
Predicting a spend against a shared resource is the classic mistake. Two abilities predicted against the same pool both look affordable on the client and only one is on the server. The rollback is correct and the player still experiences it as the game lying to them. Confirm, do not predict, anything contested.
Verification & Handoff
Correctness on a networked system is not established by playing it. The verification pass was explicit:
- A dedicated test map with every ability bound to a key, run in a four-client Play-In-Editor configuration with simulated latency and packet loss applied through
Net PktLagandNet PktLoss. - Server-side attribute logging compared against each client’s view after every ability activation, so a divergence is caught as a number rather than noticed as a feeling.
- A written architecture document covering the tag taxonomy, the replication mode decision and its reasoning, the predict-versus-confirm rule, and the procedure for adding a new ability without reading the C++.
The document is the deliverable that matters most on a three-person team. A system nobody but the contractor can extend is a liability handed over at the end of an engagement, not an asset.
What Transfers
Independent of this project:
- Design the tag taxonomy before the first ability. It is the cheapest decision to make early and the most expensive to change late.
- Put the player ASC on the Player State. Respawn will otherwise erase state you assumed was persistent.
- Choose the replication mode deliberately and write down why. Mixed for players, Minimal for AI is right far more often than Full.
- Predict what the player feels, confirm what the player keeps.
- Route all presentation through Gameplay Cues, and add them last, so visual and authoritative state cannot drift independently.