# GregOrigin - Rollback Core Pro: Accessible Netcode Framework for Fighting & Platform Games

**URL:** <https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262>\
**Category:** Product Discussion\
**Tags:** fab\
**Created:** [June 12, 2026, 3:03pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262 "2026-06-12T15:03:21Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 12, 2026, 3:03pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/1 "2026-06-12T15:03:21Z")

</div>

##### **✨** [**Initial video (v0.2)**](https://www.youtube.com/watch?v=_uteUvbLIq4)[**|**](https://www.youtube.com/watch?v=YlBrR46wOUc) **✍🏼** [**Read the manual.**](https://gregorigin.com/Manuals/Rollback_Core/)[**|**](https://forums.unrealengine.com/t/gregorigin-pso-autopilot-shader-compilation-warm-up-system-to-prevent-lag-crashes/2704140) **💬** [](https://www.toptal.com/designers/htmlarrows/symbols/ballot-box-with-check/)[**Discord support. |**](https://discord.gg/nqYQ5mtmHb) **🎁** [**Get the Core version on GitHub:**](https://github.com/gregorik/Rollback-Core)[](https://github.com/gregorik/PSO-Autopilot)a functional open-source variety that I recommend you try before buying the **Pro** version. | 👨‍💼 [Contact for custom integration / implementation.](https://gregorigin.com/contact.html) 🔥Say goodbye to input lag and latency in Unreal Engine! Introducing **Rollback Core (Pro)**, the ultimate deterministic GGPO-style rollback netcode framework built specifically for UE5.

Whether you're building a fast-paced fighting game, a platform brawler, or a tight co-op experience, standard server-client networking just doesn't cut it. Rollback Core flips the script: simulate locally, predict remote inputs, and seamlessly re-simulate history when the truth arrives late. The result? Zero perceived input lag for your players. ⚡️🎮

##### ✨ Why Choose Rollback Core?

🔹 Auto State-Saving (No Code Required): Forget writing complex C++ serializers. Just check the standard SaveGame flag on any Blueprint variable, and we'll automatically handle snapshots, transforms, and velocities via reflection. 💾

📖 Custom UDP Transport: Highly-optimized netcode featuring per-frame input redundancy, reliable ACKs, and built-in latency/packet-loss simulation for effortless stress testing. 📡

💬 Deterministic Fixed-Step Logic: Decouple your visual framerate from your game logic! Runs a perfectly rigid, predictable simulation under the hood. ⏱️ 👀 Visual Frame Debugger: Spawn our intuitive debugger right into your world to scrub through frames, view prediction ghost trails, and analyze rollback markers in real-time. 👻

👇 Seamless Matchmaking: Full OnlineSubsystem support so your players can effortlessly advertise, query, and join sessions out-of-the-box. 🤝

👾 3 Playable Demos Included: Learn by doing! We've included a fully playable 2D Viking Duel (with hitboxes & blockstun), a Network Packet-loss stress test, and a Basic Prediction environment. ⚔️

🛡️ Guided Editor Wizard: Get set up in 5 minutes with the onboarding Wizard. It automatically fixes project settings and injects the necessary rollback components directly into your existing Pawn. 🪄

🚀 Ready to upgrade your netcode?

✦ **Disclaimer** : this plugin assumes a working knowledge of UE5 workflows, editor tooling, asset setup and so on. Custom integration, extension or modification may also require comfort reading and writing C++. If you are new to UE5 or plugin-based development, expect a learning curve. Before purchasing the Fab version, it is recommended that you explore the open-source [GitHub version](https://github.com/gregorik?tab=repositories) and the online manual first to understand the architecture, setup requirements, and integration style. This will help you determine whether the plugin fits your project and experience level.

> **[Rollback Core Pro: Accessible Netcode Framework for Fighting & Platform Games](https://www.fab.com/listings/03aa010f-2413-4a98-91b1-4fa67d0aedd4)**
>
> ✨Initial video (v0.2) | ✍🏼Read the manual. | 💬 Discord support. | 🎁 Get the Core version on GitHub: a functional open-source variety that I recommend you try before buying the Pro version. | 👨‍💼 Contact for custom integration /...

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 12, 2026, 5:28pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/2 "2026-06-12T17:28:09Z")

</div>

Launch video:

[![](https://d3kjluh73b9h9o.cloudfront.net/original/4X/b/d/3/bd3b331751dfbcd347190f81fdb8e5d1f7c66492.jpeg "No more input lag & latency in Unreal Engine: innovative rollback netcode framework (UE5, 2026)") ](https://www.youtube.com/watch?v=_uteUvbLIq4)

---

<div class="post-metadata">

**Author:** ![Marco\_RKL](https://d3kjluh73b9h9o.cloudfront.net/original/4X/2/8/5/28502927f1d97ba1051b3b47ccfe17233bf41ef0.png) [@Marco\_RKL](https://forums.unrealengine.com/u/Marco_RKL)\
**Post date:** [June 12, 2026, 8:45pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/3 "2026-06-12T20:45:05Z")

</div>

Can it be used for a 3D fighting game in the likes of Tekken?

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 13, 2026, 3:49am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/4 "2026-06-13T03:49:15Z")

</div>

Hi there. It can, in fact 2 of the basic demos that come with it are fully 3D. And I’ll make more demos in the future.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 15, 2026, 6:39am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/5 "2026-06-15T06:39:01Z")

</div>

# 0.2.0, 2026-06-16 🛜

Networking correctness pass for peer identity and disconnect handling,  
driven by reported issues with the `Rollback.Net*` console  
workflow. **Contains a UDP wire-protocol change** (packet  
version 1 → 2): all participants must run this build to interoperate.

### Changed

- 🛡 **Wire protocol v2.** Every UDP packet header now carries a  
`SenderPlayerId` field and `PacketVersion` is bumped 1 → 2. Mismatched  
versions are rejected (never misparsed), so v2 peers cannot talk to v1  
peers. Ship all participants on this version.
- **`Rollback.NetClient` argument semantics.** The 4th arg is  
now _this client’s own_ `PlayerId`, announced to the host, instead of  
the remote peer’s id. The host now identifies the client by it, so  
`Rollback.NetDisconnect <id>` / `Rollback.NetPeers` can reference it.  
`Rollback.NetConnect` still takes the _remote_ peer’s id. Help and  
usage text updated.
- Peers now learn each other’s `PlayerId` from the handshake header on  
any packet (including `Hello`), instead of only from received input  
frames. An id set explicitly via `ConnectToPeer` is never overridden.
- `Rollback.NetHost` now announces a host identity (`LocalPlayerId = 0`).
- `Rollback.NetClient` now opens a single connection. It previously both  
auto-connected (via `StartUdpPeer` with `RemoteHost` set) and called  
`ConnectToPeer`, creating two peer records for the same endpoint.
- `URollbackNetSubsystem::ConnectToPeer` is now idempotent per endpoint:  
reconnecting to an already-connected endpoint refreshes that peer (and  
promotes its id) instead of adding a duplicate record.
- `URollbackNetSubsystem::DisconnectPeer` now returns `bool` (was  
`void`): `true` when a matching peer was found and removed.
- `URollbackNetworkBlueprintLibrary::DisconnectRemotePeer` Blueprint node  
now returns `bool`. This adds an output pin; existing graphs that  
ignore it are unaffected.
- `Rollback.NetDisconnect` logging is now accurate: it reports remaining  
peers from `GetAllPeerInfo()` (consistent with `Rollback.NetPeers`) and  
prints “No connected peer with PlayerId=N” when nothing matched,  
instead of always claiming success.

### Added

- `FRollbackTransportConfig::LocalPlayerId` (default `-1`): this peer’s  
own id, announced in every packet header. `-1` preserves the previous  
behaviour of learning ids from input frames.
- `FRollbackTransportConfig::DisconnectCooldownSeconds` (default `3.0`):  
after an explicit `DisconnectPeer`, the endpoint cannot be  
auto-re-accepted for this window.
- Automation tests: `RollbackCorePro.Network.PeerDisconnectStaysGone`,  
`.PeerIdentityHandshake`, `.ConnectEndpointDedup`, `.DisconnectReturn`.

### Fixed

- **Disconnected peer immediately reappearing.** `DisconnectPeer` removed  
the peer, but the still-running remote’s next packet hit the  
auto-accept path and re-created it with reset counters. A per-endpoint  
cooldown now prevents resurrection.
- **`Rollback.NetDisconnect <id>` doing nothing yet reporting success**  
for console-connected peers. The host never learned the peer’s id (it  
stayed `-1`), so the id never matched. Header identity + accurate  
logging fix this.
- **Duplicate peer record on the connecting client.** Connecting with an  
explicit id produced two records for the host endpoint (one `-1`, one  
the id); the `-1` record received all traffic and showed real  
`RTT`/counters while the id record sat idle. Single-connect + endpoint  
dedup fix this.
- **`Rollback.NetDisconnect` “Remaining peers” disagreeing with  
 `Rollback.NetPeers`** for unassigned (`-1`) peers: the two commands  
counted different collections. Both now read `GetAllPeerInfo()`.
- Flaky `RollbackCorePro.Network.PeerDisconnect` automation test (it  
asserted connectivity before the receiving subsystem had pumped the  
handshake) made deterministic with a pump loop.

### Build / verification

- Compile-validated clean on UE 5.5, 5.6, and 5.7 via `rcp_assemble.ps1`; full suite green on 5.7 (15/15).
- Per-engine staging regenerated for 5.5 / 5.6 / 5.7. The Blueprint `DisconnectRemotePeer` return-`bool` change landed afterward and is source-only.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 15, 2026, 8:56pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/6 "2026-06-15T20:56:27Z")

</div>

# 0.2.0a update, 2026-06-16

### Added

- `URollbackNetSubsystem::OnPeerReconnected` (`BlueprintAssignable`): fired when a previously-known endpoint is auto-accepted again after a timeout, carrying the restored `PlayerId` and endpoint. Additive; lets UI distinguish a transient reconnect from a brand-new connection.
- `Rollback.NetJoinNull [Index=0] [LocalPlayerId=1] [LocalPort=0]` and `Rollback.NetSessions` console commands. These complete the console-driven Null-LAN matchmaking loop in a packaged build: a host advertises (`Rollback.NetHost`), a second instance discovers (`Rollback.NetFindNull`), lists results (`Rollback.NetSessions`), and joins (`Rollback.NetJoinNull`), which brings up the UDP transport (announcing its own id) and connects to the advertised host endpoint. Previously `JoinPlatformSessionByIndex` was only reachable from the editor Setup Wizard.

### Fixed

- **Timed-out peer reconnecting as a fresh `PlayerId=-1`.** When a peer  
went quiet long enough to time out (`CheckPeerTimeouts`) and then  
resumed sending, the auto-accept path re-created it as a brand-new  
`-1` record with reset counters, so `OnPeerDisconnected` (“Peer timed  
out”) was immediately followed by `Rollback.NetPeers` showing a  
connected `-1` peer with recent activity, which looked contradictory.  
A timeout (unlike an explicit kick) now records the endpoint’s  
`PlayerId`; the returning peer is re-accepted as the same peer with  
that id restored and fires `OnPeerReconnected` instead. The explicit  
`DisconnectPeer` cooldown path is unchanged (kicked peers stay gone).
- **Disconnected peer immediately reappearing.** `DisconnectPeer` removed  
the peer, but the still-running remote’s next packet hit the  
auto-accept path and re-created it with reset counters. A per-endpoint  
cooldown now prevents resurrection.
- **`Rollback.NetDisconnect <id>` doing nothing yet reporting success**  
for console-connected peers. The host never learned the peer’s id (it  
stayed `-1`), so the id never matched. Header identity + accurate  
logging fix this.
- **Duplicate peer record on the connecting client.** Connecting with an  
explicit id produced two records for the host endpoint (one `-1`, one  
the id); the `-1` record received all traffic and showed real  
`RTT`/counters while the id record sat idle. Single-connect + endpoint  
dedup fix this.
- **`Rollback.NetDisconnect` “Remaining peers” disagreeing with  
 `Rollback.NetPeers`** for unassigned (`-1`) peers — the two commands  
counted different collections. Both now read `GetAllPeerInfo()`.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 15, 2026, 9:07pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/7 "2026-06-15T21:07:48Z")

</div>

Optional map (Content/Maps/RollbackNetDemo) for the available 2-Peer UDP Demo:

[RollbackNetDemo.umap](https://forums.unrealengine.com/uploads/short-url/c0qNOH0mEZwyKEOcNDF47fpQuIW.umap) (20.8 KB)  
[DefaultEngine.ini](https://forums.unrealengine.com/uploads/short-url/wgCE7Bw2NniwEii9pK2HKbHT9ub.ini) (601 Bytes)

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 16, 2026, 5:44am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/8 "2026-06-16T05:44:28Z")

</div>

Please note that the plugin is still 0.2.0: not recommended for live production games yet. It’s robust, but still “early access” till indicated otherwise.  
As always, liberal experimentation with the [open source core](https://github.com/gregorik/Rollback-Core) is recommended at this point. 🔬

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 17, 2026, 6:34am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/9 "2026-06-17T06:34:23Z")

</div>

# 0.2.2 update, 2026-06-18 🏁

### 🎮 Matchmaking — async Blueprint nodes, configurable search timeout & examples

A Blueprint-first matchmaking pass: the previously hidden session-search timeout is now configurable and readable, and the Find / Host / Join flow is exposed as Advanced-Sessions-style latent nodes with example assets. Additive with no API breaks.

> Legend: ✨ new Blueprint node · ➕ new API · 🔄 changed · ✅ tests · 📝 docs · 🔧 tooling · 🐍 Python · 🧩 example asset

#### ⏱ Configurable session-search timeout

- 🔄 `URollbackNetSubsystem::FindPlatformSessions` no longer hard-codes a  
`10.0f` search timeout; it reads a configurable value, so callers can size  
their own “Searching…” watchdog/UI to the real search instead of guessing.
- ➕ `SessionSearchTimeoutSeconds` (`EditAnywhere`, default `10s`, `ClampMin 0.1`)  
plus `GetSessionSearchTimeoutSeconds()` (`BlueprintPure`) and  
`SetSessionSearchTimeoutSeconds()` (`BlueprintCallable`, clamps to `0.1`).

#### 📡 Results-carrying completion delegates

- ➕ `OnFindSessionsComplete(bool, TArray<FRollbackMatchmakingResult>, FString)`; hands back the whole session list in one shot when a search finishes.
- ➕ `OnCreateSessionComplete(bool, FName SessionName, FString)`.
- ➕ `OnJoinSessionComplete(bool, FString)`; fires after the UDP transport  
actually connects on a successful join (kept in lock-step with the generic  
`OnMatchmakingComplete` via an internal `BroadcastJoinComplete` helper).

#### ✨ Async / latent matchmaking nodes (the Find / Host / Join trio)

- ✨ **Find Rollback Sessions (Async)**; `URollbackFindSessionsAsync`: runs a  
search, waits for completion (bounded by the timeout), delivers the list on  
`On Found` / `On Failed`. Optional `Timeout Seconds` pin (`-1` = use configured).
- ✨ **Host Rollback Session (Async)**; `URollbackCreateSessionAsync`: brings up  
the UDP transport on `Host Port` if needed, advertises the session →  
`On Hosted (SessionName)` / `On Failed`.
- ✨ **Join Rollback Session (Async)**; `URollbackJoinSessionAsync`: joins a Find  
result and waits until the transport connects → `On Joined` / `On Failed`.
- ➕ Pure helpers `FindBestRollbackSession` (lowest ping with an open slot) and  
`FormatRollbackSession` (one-line summary) on `URollbackNetworkBlueprintLibrary`.

#### 🧩 Example actor & Blueprint generator

- 🧩 `ARollbackMatchmakingExampleActor` (`Blueprintable`) wires all three nodes  
into one actor with editable defaults (Match Id, LAN, port, timeout, auto-find)  
and `OnSessionsFound / OnHosted / OnJoined / OnError` events for UI.
- 🐍 `Content/Python/generate_matchmaking_examples.py`; run in-editor to create  
`/RollbackCorePro/Examples/BP_RollbackMatchmakingExample` (a ready-to-drop  
subclass of the example actor).

#### ✅ Tests

- ✅ New automation tests: `RollbackCorePro.Matchmaking.FindSessionsCompleteDelegate`,  
`.FindSessionsAsyncNode`, `.FindSessionsAsyncNodeFailure`,  
`.HostSessionAsyncNodeFailure`, `.JoinSessionAsyncNodeFailure`.
- ✅ Added `URollbackMatchmakingTestSink`, a reflected UObject that captures the  
dynamic-delegate / node-pin payloads tests assert on.
- 🔄 `RollbackCorePro.Network.NullMatchmakingConnect` now derives its poll window  
from `GetSessionSearchTimeoutSeconds()` instead of a magic `12.0` constant.

#### 📝 Docs

- 📝 HTML manual: new delegate rows, an async-node table (Find/Host/Join), the  
pure helpers, the example-asset + Python-generator instructions, and an updated  
client-flow snippet showing the obtainable timeout.

#### 🔧 Project / tooling

- 🔧 Enabled `PythonScriptPlugin` in `RollbackCorePro.uproject` (required to run  
the example generator).

#### 🛠 Build / verification

- 🛠 Clean on UE 5.5 - 5.7; `RollbackCorePro.Matchmaking` automation suite **6/6  
green**; the Python generator verified to produce the example Blueprint asset.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 17, 2026, 1:09pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/10 "2026-06-17T13:09:27Z")

</div>

A 2-peer demo in action, version 0.2.2+

[![](https://d3kjluh73b9h9o.cloudfront.net/original/4X/b/d/3/bd3b331751dfbcd347190f81fdb8e5d1f7c66492.jpeg "Rollback Core 2-Peer Demo (UDP P2P transport and Null OSS matchmaking, UE5 2026)") ](https://www.youtube.com/watch?v=fr8WJ6vyJOs)

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 19, 2026, 2:25pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/11 "2026-06-19T14:25:54Z")

</div>

# 0.2.2a update, 2026-06-20 ⬆

### 🎮 UMG matchmaking menu example

- 🧩 `URollbackMatchmakingMenuWidget` (with row widget `URollbackMatchmakingMenuRow`): a fully **native** UMG menu (no `.uasset` required): Host / Find buttons and a scrollable list of found sessions, each with a Join button. It builds its own tree in `RebuildWidget`, drives the Find / Host / Join async nodes (mirroring `ARollbackMatchmakingExampleActor`), and exposes config (Match Id, LAN, port, timeout, …) plus `OnHosted / OnJoined / OnSessionsFound / OnError` events. Subclass it as a Widget Blueprint to restyle: the behaviour stays in C++.
- ✨ `Rollback.ShowMatchmakingMenu`: creates the menu and adds it to the viewport (running game / PIE).
- 🧩 The example generator now also emits `/RollbackCorePro/Examples/WBP_RollbackMatchmakingMenu` (a Widget Blueprint subclass of the menu widget).

### 🖥️ Console-command parity for the async Host/Find/Join flow

- ✨ `Rollback.Host [MatchId] [Port=7777] [Slots=2] [LAN=1]`, `Rollback.Find [MatchId] [Max=20] [LAN=1] [Timeout=-1]`, and `Rollback.Join [Index=0]`: drive the **same** `URollbackCreateSessionAsync` / `URollbackFindSessionsAsync` / `URollbackJoinSessionAsync` nodes the Blueprint flow uses, for console/headless testing parity. `Rollback.Join` joins a result cached by a prior `Rollback.Find`. (Previously the async flow was Blueprint-only; the existing `Rollback.Net*` commands call the subsystem directly.)
- ➕ `URollbackNetConsoleSink`: a small UObject that binds the async nodes' dynamic result pins (which cannot bind lambdas), logs each outcome, and self-releases.

### 🔧 Editor: one-click example generation

- 🔧 **Generate Example Content** on the _Rollback_ toolbar combo (new _Examples_ section) and **Generate Example Blueprints** on the Setup Wizard's Integration page run the bundled generator via `IPythonScriptPlugin` (`FRollbackCoreProEditorModule::GenerateExampleContent()` → returns whether it ran), degrading gracefully with an on-screen note when the Python Editor Script Plugin is unavailable. The wizard reflects the real outcome in its toast and Finish-page summary.
- 🔧 `RollbackCoreProEditor` now privately depends on `PythonScriptPlugin`, and the plugin descriptor enables it.
- 🐍 `generatematchmakingexamples.py` extended to also author the WBP menu via `WidgetBlueprintFactory`.

### ✅ Tests & verification

- ✅ New automation tests: `RollbackCorePro.Matchmaking.ConsoleSinkHostFailure`, `.ConsoleCommandsRegistered`, `RollbackCorePro.UI.MatchmakingMenuRowJoin`, `.ShowMatchmakingMenuRegistered`.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 19, 2026, 8:04pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/12 "2026-06-19T20:04:07Z")

</div>

Rollback P2P demo. Edit the file to use your own paths. (Powershell scripts are not allowed in Fab builds.)

[README.md](https://forums.unrealengine.com/uploads/short-url/sBCgGPAS8CYUpjWyM4RjkHZr97M.md) (4.3 KB)  
[RunRollbackP2PDemo.ps1](https://forums.unrealengine.com/uploads/short-url/pZ7l1UzilSdvWIkQdV2yvrQ9O5M.ps1) (3.7 KB)

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 22, 2026, 6:29am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/13 "2026-06-22T06:29:48Z")

</div>

# 0.3.0 update, 2026-06-23 🛼

Rollback **correctness & netcode** pass: fixes the core replay off-by-one, completes  
state restore (velocity / angular velocity / CharacterMovement), and upgrades desync  
detection from a local replay check to genuine **cross-peer checksum exchange**  
(auto-wired). **Contains a breaking UDP wire-protocol change** (packet version 2 → 3):  
all peers must run this build to interoperate.

> Legend: 🎯 correctness · 🛡 hardening · 🌐 networking · 🧊 physics/CMC · ➕ new API · ✨ new component · 🔄 changed · ⚠ breaking · ✅ tests · 🛠 build/verify · 📝 docs

### 🎯 Rollback correctness

- 🎯 **Off-by-one double-application fixed.** `SimulateFrame` now snapshots the  
**start-of-frame** state _before_ ticking, so `RollbackToFrame(F)` restores  
`StateBuffer[F]` and replays from `F` applying the target frame’s input **exactly  
once**. Previously the snapshot was taken _after_ the tick, so every rollback  
re-applied the corrected frame twice and drifted by one frame of its motion. (The  
prior tests used all-neutral input, where the double-apply was invisible.)
- ✅ `RollbackCorePro.Rollback.NoOpReplayIsIdentity`: a no-op rollback (identical  
recorded inputs) must reproduce the exact pre-rollback state.

### 🌐 Cross-peer desync detection: was local-only

- ⚠ **BREAKING: wire protocol v3.** New `StateChecksum` packet type; `PacketVersion`  
bumped **2 → 3**. Mismatched versions are rejected (never misparsed), so v3 peers  
cannot talk to ≤ `0.2.2` (v2) peers. Ship all participants on this build.
- ➕ Genuine **cross-peer** detection: peers exchange per-frame state checksums and  
compare each against their own; a true mismatch calls `RecordDesync()` and broadcasts  
`OnDesyncDetected(Frame, peer, delta)`. Previously the “desync detector” only compared  
an entity’s _own_ pre/post-rollback checksums locally (a replay-determinism check) and  
could never observe two machines diverging.
- ➕ **Auto-wired:** `URollbackManager` records and (on an interval) sends the  
confirmed-frame checksum automatically while transport is connected — the demos  
inherit it for free. New API: `RecordLocalStateChecksum`, `SendStateChecksum`,  
`ComputeStateChecksum` (order-independent XOR aggregate), `GetConfirmedFrame` /  
`GetConfirmedFrameForPlayer`.
- 🔄 **Confirmed-frame policy:** only frames whose inputs are all in from every peer  
(highest contiguous received input) are checksummed, so the state is final and a  
mismatch is a real desync: no false positives from in-flight prediction.

### 🧊 State-complete physics / CharacterMovement rollback

- 🔧 **Velocity is now restored on rollback** (it was saved but never re-applied).  
Physics roots get `SetPhysicsLinearVelocity`; every entity also surfaces it via  
`LastRestoredVelocity` and the new `OnRollbackStateLoaded(Frame, Velocity)` event so  
custom/kinematic movement can re-apply it.
- 🧊 **Full rigid-body + CharacterMovement state captured/restored.** The snapshot gains  
angular velocity and CMC `MovementMode`/`CustomMovementMode`; save/load now restore  
linear + angular physics velocity and CMC velocity/movement mode. Surfaced via  
`LastRestoredAngularVelocity`.
- ✨ `URollbackCharacterMovementComponent`: a `UCharacterMovementComponent` subclass  
driven by the rollback loop (its own engine tick disabled); the state component calls  
its `RollbackStep(dt)` once per fixed frame for both live and replayed frames.
- ⚠ **Determinism boundary unchanged:** restore is now correct and complete, but  
cross-machine forward-sim determinism (collision / Chaos) is **not** guaranteed: use  
flat/kinematic movement or a deterministic mover where that matters.

### 🛡 Robustness

- 🛡 **Rollback to an evicted/missing frame now aborts cleanly** instead of replaying  
forward from the live state and corrupting the buffer. `RollbackToFrame` no-ops (no  
state change, no rollback counted) when no entity holds the target frame’s snapshot;  
usable rollback depth is bounded to `MaxBufferSize` snapshots per entity.

### ✅ Tests & verification

- ✅ **12 new automation tests** (`Rollback.NoOpReplayIsIdentity`,  
`Rollback.MissingFrameAborts`, `State.VelocityRestored`,  
`State.AngularVelocityRestored`, `State.CharacterMovementRestored`,  
`State.ChecksumDeterministic`, `State.ChecksumOrderIndependent`,  
`Network.CrossPeerChecksumDesync`, `Network.ConfirmedFrameTracking`,  
`Network.ManagerAutoChecksum`, `Movement.RollbackStepSafe`,  
`Movement.CMCDrivenByRollbackTick`). Full `RollbackCorePro` suite **40/41 green** (the  
two-process-only `Network.NullMatchmakingConnect` fails single-process by design).
- 🛠 **Two-process packaged P2P session verified:** Null OSS matchmaking + UDP  
transport + the new v3 `StateChecksum` traffic ran ~1440 frames with both peers  
connected, **no desync false positives** , and no transport/parse errors.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [June 22, 2026, 6:31am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/14 "2026-06-22T06:31:56Z")

</div>

Updating the manual to 0.3.0 (online & PDF) will take a few days, until then these features are undocumented. Thanks for your patience. 🙏

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [August 6, 2026, 11:51am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/15 "2026-08-06T11:51:45Z")

</div>

## [0.5.0 update] - 2026-08-07 🎢

### Breaking changes: all peers must upgrade together 🤲

- **The wire protocol moves from v5 to v6.** Every packet header now carries the sender’s own frame  
advantage, which is what lets pacing act on the difference between two peers instead of on the  
local confirmation age. **A 0.4.0 peer and a 0.5.0 peer cannot play together.** The failure is at  
connect time rather than a mid-match desync: through matchmaking the protocol string is a search  
filter, so a 0.4.0 peer never discovers a 0.5.0 session; connecting directly, version-mismatched  
packets are discarded on receipt — including the handshake — so it presents as a connection  
timeout with no explicit version error. Upgrade every participant, including packaged demos.
- **`Max Frame Advantage` changes meaning, and its default moves 8 → 4.** It used to bound how far  
the local clock ran ahead of its own newest confirmed frame; it now bounds the smoothed  
_difference_ between the two peers’ self-reported advantages. The difference counts each peer’s  
contribution once, so the new default of 4 tolerates 8 frames of real divergence. Projects that  
raised the old value should not carry that number across — start from the new default.

### Behaviour changes: read before upgrading 🪸

- **Input delay now defaults to 2 frames** (`Simulation | Latency → Input Delay`). Input polled  
while simulating frame _F_ now drives frame _F+2_. This is the right default for netplay and  
removes the large majority of rollbacks, but it does change gameplay timing. Offline-only  
projects that want zero added latency should set it to `0`. It must be identical on every peer.
- The rollback subsystems are **no longer created in editor worlds** (Game and PIE only). The  
Rollback Stats panel now reports “inactive” outside PIE instead of showing an editor-world  
frame counter.

### Fixed

- **Peers’ fixed-step clocks no longer free-run apart.** Nothing previously kept two peers in  
step: the faster machine pulled ahead until incoming corrections were older than the rollback  
window, at which point `RollbackToFrame` rejected them outright and the peers diverged for good.  
`URollbackManager` now paces the local clock against the peer, clamped to `Max Rollback Depth` so  
a correction is always still shallow enough to apply. Exposed via `GetFrameAdvantage()`,  
`GetFrameAdvantageDelta()`, `ShouldStallForFrameAdvantage()` and `StalledFrameCount`. Regression  
test: `RollbackCorePro.Production.FrameAdvantagePacing` (a peer previously reached a 58-frame  
advantage against a 12-frame window in 60 ticks).
- **A high-latency match no longer runs in permanent slow motion.** Pacing originally stalled on  
confirmation _age_: how old the newest confirmed frame was — which latency alone drives past the  
bound even when both clocks are perfectly in step, so every peer on a slow link stalled  
continuously. The pre-fix soak measured both peers pinned at the bound with 1183 stalls out of  
~1199 frames and an effective rate of **0.80 Hz**. Pacing now acts on the smoothed difference  
between the two peers’ self-reported advantages, so latency shared by both sides cancels to zero  
and only genuine divergence stalls anything. Regression test:  
`RollbackCorePro.Production.SymmetricLatencyDoesNotStall`.
- **Pacing no longer starves the peer it is pacing against.** Withholding a frame also withholds  
the input the other peer needs to advance its own confirmation, so a clock that stopped entirely  
drove its peer’s advantage up until it stalled too, and the pair oscillated — measured on the  
180 ms profile as the effective rate halving to 40.84 Hz with confirmation frozen for 15.58 s of  
a 20 s run. Corrections are now applied at a duty cycle, withholding at most one frame in four,  
so the clock yields ground at 75% rate while the input stream never stops. The clock still holds  
outright against a peer that has genuinely gone silent while already past the rollback window,  
since frames advanced there could never be reconciled. Regression tests:  
`RollbackCorePro.Production.PacingKeepsInputFlowing`,  
`RollbackCorePro.Production.StallHoldsInsideRollbackWindow`.
- **A two-second lag spike no longer latches a session into permanent divergence.**  
`Max Future Input Frames` (was 120) rejected any input frame more than that far ahead of the  
_receiver’s_ clock, and the rejection path discards the whole packet — including the redundant  
copies of in-window frames that exist to heal holes. So once a peer fell 2 s behind, every packet  
from the leader was discarded wholesale and its confirmation froze permanently. That freeze then  
fed pacing the wrong sign, because `GetFrameAdvantage()` is `CurrentFrame - ConfirmedFrame`: the  
peer that was _behind_ looked far ahead and got stalled, driving it further behind. Measured: 464  
packets rejected on one peer, confirmation stuck at frame 133 while the peer had produced 904.  
The window now defaults to 600, matching `Max Remote Input Frames Per Player`, which is what  
actually bounds the memory a peer can make you hold — so this costs no new exposure.
- **One dropped frame no longer freezes a peer’s confirmation for the rest of the session.**  
Confirmation advances only over a contiguous prefix, and redundancy cannot heal a frame that was  
never sent in the first place. Callers poll input once per engine tick while the fixed clock can  
step up to `Max Catch-Up Frames Per Tick` frames, so any engine frame slower than the fixed rate  
silently dropped a frame from the wire — permanently. The documented Blueprint path  
(`SendRollbackInputForCurrentFrame`) and both demo environments were all affected. New  
`SendInputFramesThrough()` sends every frame from a per-player watermark through the current one,  
repeating the polled input across the gap — which is exactly what the local simulation did with  
it. Regression tests: `RollbackCorePro.Network.InputStreamHasNoHoles`,  
`RollbackCorePro.Network.InputStreamPartialFillRetries`.
- **Analog input no longer desyncs peers.** `FRollbackInput::Axes` is a double-precision `FVector`  
but the wire carries three floats, so any stick value that is not exactly float-representable  
left the sender simulating a frame with `0.59999999999999998` while the receiver used  
`0.60000002384185791`. Axes are now normalised to wire precision at every entry point  
(`InjectInputForFrame`, `SendInputFrame`, `BufferRemoteInputForRollback`, local input capture)  
via `FRollbackInput::QuantizeAxes()`. Regression test:  
`RollbackCorePro.Network.AnalogInputSurvivesWire`.
- `URollbackManager` and `URollbackNetSubsystem` no longer instantiate in editor worlds, where  
they ticked a second fixed-step clock and pumped a transport for the editor’s whole lifetime and  
gave every PIE session a sibling manager on an unrelated `CurrentFrame`. Regression test:  
`RollbackCorePro.Production.NoEditorWorldSubsystems`.
- The Setup Wizard now persists settings with `TryUpdateDefaultConfigFile()` instead of  
`SaveConfig()`. `URollbackCoreProSettings` is a `DefaultConfig` class, so wizard changes were  
landing in the machine-local `Saved/Config` tree rather than the project’s `DefaultEngine.ini`  
that the Project Settings panel writes: the two paths could disagree and wizard choices were  
never source-controlled.
- The wizard’s FilterPlugin check tested for a path that the blanket `/Content/...` rule already  
matched, so it always reported the rule missing and its “fix” appended a redundant line. It now  
tests for the exclusion rule that actually decides whether the demo content ships, and the fix  
removes that rule.

### Known issues 🥲

- **The 180 ms / 3% loss soak profile still fails intermittently: roughly one run in four.** When  
it trips, one peer’s confirmation freezes for around 3 s and the effective rate drops to ~53 Hz.  
Correctness is not affected in any observed run: `DesyncCount` and `RejectedRollbackCount` stayed  
at zero throughout, so this degrades pacing, it does not diverge peers. It is also distinct from  
the packet-rejection latch fixed above — rejections are zero in the failing runs — and its cause  
is not yet identified. For reference, 180 ms one-way is 360 ms RTT, well past what rollback  
fighting games target, and that profile already needs `Max Rollback Depth` raised to 20. The four  
profiles at or below 120 ms one-way are clean across every run.

### Added

- `Simulation | Latency` project settings: **Input Delay (frames)** (default 2), **Enable  
Frame-Advantage Pacing**(default on),**Max Frame Advantage (frames)** (default 8).
- `URollbackStateComponent::SetInputDelayFrames()` / `GetInputDelayFrames()` for runtime control.
- `Rollback.NetAutoJoinNull [MatchId] [LocalPlayerId] [LocalPort]`: searches for a Null LAN  
session and joins the best result automatically. The search is async, so a single `-ExecCmds`  
could not previously sequence find and join; this makes the whole matchmaking path scriptable.
- `Tools/Run-AutomationTests.ps1` — headless suite runner that exits non-zero on failure and  
fails the build if suspiciously few tests ran (which is how a silently-skipped plugin load  
presents itself).
- `.github/workflows/ci.yml` — builds and runs the suite on UE 5.7, verifies two-process  
matchmaking, then compile-validates the plugin against 5.5, 5.6 and 5.7.
- `Tools/README.md` documenting the supported packaging pipeline.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [August 29, 2026, 9:18pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/16 "2026-08-29T21:18:53Z")

</div>

# [0.6.0] update, 2026-08-31 🪐

[This is a very technical & detailed changelog. All the info is not essential for plugin usage, but may be useful to some.]

**The wire protocol is unchanged at v6, but you (the user) still need to ship this to every peer at once.** The  
float-semantics fix below changes the compiled simulation, and determinism is a property of the  
binary rather than of the source. A 0.5.0 peer and a peer on this build therefore agree on the  
protocol, connect normally, and then diverge in the last bit; which surfaces as a desync partway  
into a match rather than as a clean refusal at the handshake. Treat this as a lockstep upgrade even  
though nothing in the packet format moved.

### Added 🧑‍🔧

- **Protocol mismatches are reported instead of looking like a timeout.** A datagram carrying our  
magic with a different version byte is a real peer on an incompatible build, and it was handled  
identically to line noise: `PacketsRejected++` and nothing else. It now logs a warning naming  
both versions, counts `FRollbackTransportStats::ProtocolMismatches`, records  
`GetLastProtocolMismatchVersion()`, and broadcasts `OnProtocolVersionMismatch` (throttled per  
endpoint). Bind it to tell the player to update. `GetWireProtocolVersion()` and the  
`RollbackWireProtocol` constants are now public so a title can display and compare it.
- **Desyncs name the field that diverged.** Previously a desync reported a frame, an entity, and  
the XOR of two checksums - which is not a lead. `URollbackManager::CompareRollbackStates` and  
`DescribeRollbackStateDifference` report per-field differences at full precision  
(`Velocity: (12, 0, 0) -> (12.5, 0, 0)`), and `GetLastDesyncDetail()` carries the newest one.
- **Desyncs inside the SaveGame payload can name the property.** `ActorData` is one opaque blob, so  
it could only ever be reported as a byte offset. `SetDetailedDesyncDiagnosticsEnabled(true)` adds  
a per-property checksum to each snapshot and attributes the divergence by name. Off by default -  
it costs an extra reflection walk per saved frame.
- **`ValidateDeterminism(FramesBack)` catches nondeterminism in one process.** Resimulates the  
window from its saved inputs and reports any field that comes out different. Most desyncs are not  
network faults but gameplay code that cannot reproduce its own result - unseeded randomness,  
`TMap`/`TSet` iteration order, uninitialised members - and those are enormously cheaper to find  
here than across two machines. Violations are counted separately from `DesyncCount` so an audit  
never perturbs the metrics it audits.
- **Socket subsystem selection is documented and diagnosable.**  
`FRollbackTransportConfig::SocketSubsystemName` (and a project-wide default in Project Settings)  
selects the `ISocketSubsystem` carrying the transport - the seam for routing over EOS P2P to get  
NAT traversal and relay fallback. An unavailable subsystem now fails with a message naming what  
was requested, listing what is registered, and explaining the usual cause, rather than  
`"...is not available."` It deliberately does not fall back to platform UDP: a silent fall back  
would ship a project that believes it has relay support and passes every LAN test.  
New guide: `Docs/nat-traversal-and-eos.md`.

### Changed 🔂

- **The pacing soak now exercises the rollback path.** It previously sent, flushed and ticked, and  
never called `ApplyBufferedInputsToState` or `RollbackToFrame` - so the `rollbacks=0` /  
`rejected=0` it reported were zero _by construction_, not by measurement. Each peer now applies  
the other’s real input and rolls back on disagreement (~1190 corrections per 20 s profile), and  
the suite asserts the path was genuinely driven so it cannot silently regress to the old  
behaviour.
- **The soak’s two peers no longer share a clock rate.** `FLatencyProfile::ClockDriftPpm` scales one  
peer’s delta, reproducing the drift between two machines’ crystals that pacing exists to absorb -  
the one property two in-process peers otherwise cannot have. Values are deliberately accelerated  
(real crystals differ by ~200 ppm, which is a quarter of a frame over 20 s and would exercise  
nothing). New `RCPSoak.Latency.ClockDrift` profile runs a 1% rate difference.
- **The soak audits resimulation determinism** at the end of each profile and fails on a violation.

### Fixed

- **`RollbackNetworkCommands.cpp` compiles standalone.** It opened `#if !UE_BUILD_SHIPPING` before  
including anything that defines it; under a unity build a neighbouring file had already pulled in  
`Misc/Build.h`, so it only broke when compiled on its own - a `C4668` under warnings-as-errors and  
a routine marketplace rejection. Surfaced by switching `Make-FabBuild.ps1` to  
`BuildPlugin -StrictIncludes`; `-Rocket` and `-installed` are not `BuildPlugin` parameters and had  
been silently ignored for two releases.

### Fixed (cross-build determinism)

- **The simulation was not bit-reproducible across build configurations.** Unreal compiles with  
fast-math by default, which permits the compiler to reassociate float expressions and to contract  
`a*b+c` into an FMA with a single rounding. Neither module set `FPSemantics`, so both inherited it.  
A **DebugGame** and a **Development** build of identical source, fed bit-identical input, diverged  
at frame 3 of a 240-frame trace with 57 of 240 frames differing. Two players on differently-built  
clients would desync with nothing wrong in the gameplay code — and since Win64, Mac, Linux,  
Android and iOS are all declared, cross-platform play means different compilers and architectures  
by definition.

### Added (differential build testing)

- **`Tools\Diff-BuildDeterminism.ps1`** runs the same simulation in two build configurations and  
compares per-frame state checksums. This is how the defect above was found, and it closes a gap  
that no amount of single-configuration testing could: environmental nondeterminism (optimisation  
level, reassociation, FMA contraction, a differing math library) is invisible to a suite that  
holds all of those constant.
- **`URollbackManager::RunDeterminismTrace`** is the engine behind it: a fixed, self-contained  
simulation with no wall clock, no network and no randomness beyond a seeded integer input  
pattern. Deliberately **not** gated behind `WITH_DEV_AUTOMATION_TESTS` or `!UE_BUILD_SHIPPING`,  
because a comparison that cannot include the configuration you ship cannot speak about it;  
`-RollbackDeterminismTrace=<file>` emits the stream from any build, Shipping included.

### Fixed (Linux build)

Cross-compiling for Linux with Clang 20 surfaced two defects immediately, both of which MSVC accepts silently:

- **A range-for over `FJsonObject::Values` bound a reference to a temporary.**  
`RollbackVikingFighter.cpp` declared the loop variable as  
`const TPair<FString, TSharedPtr<FJsonValue>>&`, but that map is not keyed by `FString` on  
every engine version — UE 5.8 keys it by `UE::TSharedString<char16_t>`. MSVC silently  
constructed a temporary per entry (a copy nobody asked for); Clang rejects it outright under  
`-Wrange-loop-construct`. Now `const auto&`, which is correct on every version.
- **`URollbackVikingGameSubsystem` outscoped its own dependency.** Its `Initialize` calls  
`InitializeDependency<URollbackNetSubsystem>()`, but it declared no `DoesSupportWorldType`  
while the net subsystem is Game/PIE only. In editor, inactive and preview worlds — all of  
which a cook creates — it was constructed without its dependency and UE ensured with “Failed  
a call to GetSubsystem from within Initialize of another subsystem”. A handled ensure fails a  
cook outright, which is how the first Linux cook died. It now declares the same world types.  
Regression test: `RollbackVikingGame.Subsystem.MatchesDependencyWorldTypes`.

With both fixed, Linux cooks and runs, and its determinism trace is **identical** to the  
Win64/MSVC trace of the same engine over 600 frames.

### Fixed (soak harness)

- **The latency soak was connecting with a quarter of the shipped input redundancy.**  
`ConnectLoopbackPeers` set `InputRedundancyFrames = 2` against a shipped default of 8. Input  
packets are unreliable and are never resent, so a frame’s only redundancy is the copies riding in  
the next N packets — 3 delivery chances instead of 9. At the `Transcontinental` profile’s ~5.9%  
end-to-end loss that is roughly 0.5 unrecoverable input holes per 20 s run, and it failed that  
profile on about 4 runs in 7. Now 8, after which 8 consecutive full-suite runs passed with max  
frame advantage 12–16 against a bound of 20 and no pacing stalls at all.

### Fixed (burst packet loss could hang a match permanently)

- **A burst of lost packets could freeze a session for good, and starve both players.** Input  
packets are unreliable and carry `InputRedundancyFrames` copies of recent history, so uniform  
loss is absorbed almost perfectly — but a burst wider than that window left a hole in the  
contiguous input stream that nothing could fill. `ConfirmedFrame` advances only over a contiguous  
prefix, so one missing frame pinned it permanently while later input piled up unused behind it.  
Pacing derives frame advantage from confirmation, so the pin did not stay local: advantage grew  
without bound, pacing concluded the peer had gone silent, and held the clock against a peer that  
was transmitting perfectly — which suppressed the local input stream and starved that peer in  
turn. Measured on a 24-packet burst profile: confirmation frozen for 17 s of a 20 s run, peak  
frame advantage 550 against a rollback window of 20, both peers stalled, the match running at  
half rate and never recovering. A burst of 9 packets at 60 Hz is 150 ms — ordinary mobile or  
congested-wifi jitter.

### Added (burst-loss diagnostics)

- **`SimulatedBurstLossLength`** on `FRollbackTransportConfig` — drops packets in consecutive runs  
rather than independently, so a test can reproduce how real links fail. 0 (the default) keeps the  
existing uniform model.
- **`GetTransportStats().UnrecoverableInputHoles`** — input frames written off as undeliverable.  
Non-zero means the link lost a burst wider than redundancy could repair; expect a checksum  
divergence for those frames.
- **`URollbackNetSubsystem::IsPeerSilent()`** (Blueprint-pure) — whether the transport has heard  
from the peer recently.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [August 30, 2026, 5:08am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/17 "2026-08-30T05:08:26Z")

</div>

Please note: plugin functionality on UE 5.8.2 is problematic and not yet available. It is currently shipped for 5.5, 5.6, 5.7.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [September 14, 2026, 10:05am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/18 "2026-09-14T10:05:49Z")

</div>

# 0.6.1 update, 2026-09-15

Rollback Core is still a work-in-progress solution. It is advanced, but I do not claim it is production-ready yet. Also check out its [open-source sibling](https://github.com/gregorik/Rollback-Core).

### 🐛 Fixed

- 🎮 **The two-peer P2P demo no longer starts its peers out of step.** `ARollbackP2PDemoEnvironment`  
spawned its rollback pawns in `BeginPlay`, so each peer’s frame clock ran from its own launch.  
`Demo/RunRollbackP2PDemo.ps1` starts the host 3 s early, so at connect the host was ~150 frames  
ahead, and pacing took ~15 s to pull it back. For that stretch:

- 🎮 **The demos no longer report every correction as a desync.** The two-peer, network and Viking  
demos rolled back with `RollbackToFrame(Frame)`. With the second argument left at its default of  
-1, the manager compares every replayed frame with its first, mispredicted result, so the frames a  
correction exists to change were reported as desyncs. Each one logged `Desync on resimulation`,  
fired `OnDesyncDetected`, and raised both `DesyncCount` and the `Desyncs` figure in  
`Rollback.Perf`, the figure the QuickStart tells you to keep at 0. One run of the packaged  
two-peer demo logged 80 of them on a match whose two screens agreed. The demos now pass the  
changed frame as both arguments, as the Viking online flow and `ApplyBufferedInputsAndRollback`  
already did. ✅ Covered by `RollbackCorePro.Demo.P2PAcceptedCorrectionIsNotADesync` and  
`RollbackCorePro.Demo.VikingDemoAcceptedCorrectionIsNotADesync`, which counted 5 and 165 false  
desyncs on the old code.

- 🔄 **A correction for the frame not yet simulated no longer counts as a rejected rollback.** Every  
shipped caller that scans through `CurrentFrame` — both networked demo environments, the  
`ApplyBufferedInputsAndRollback` Blueprint node, and the QuickStart/README snippets — routinely  
finds its correction at `CurrentFrame` itself. That input is injected in time and needs no  
rollback, but `RollbackToFrame` was called anyway, refused the depth-0 request, and incremented  
`RejectedRollbackCount`. ⚠ That is the counter the QuickStart troubleshooting list tells you to  
watch as a sign corrections arrive **too late** , so the healthiest case reported itself as the  
failure case — in the soak, up to 1190 spurious rejections in a 1190-frame run, now 0 on all  
seven profiles. **If you wrote your own call site, guard it with  
 `EarliestChangedFrame < CurrentFrame`**; the shipped snippets now show this.

- 🐛 ⚠ **`ApplyBufferedInputsAndRollback`’s `bOutRolledBack` now means what it says.** It was passed  
straight through to `ApplyBufferedInputsToState`, whose out parameter means “the input changed” —  
a different and much more frequent question — so the node reported a rollback on corrections that  
performed none. QuickStart already documented it as reporting “whether a rollback happened”; the  
code now matches the documentation. `OutRollbackFrame` is unchanged and still reports the earliest  
changed frame either way. ✅ Covered by  
`RollbackCorePro.Network.JustInTimeCorrectionIsNotARejectedRollback`.

### 🧪 Changed (soak harness)

- 🧪 **The soak asserts that the rollback path actually ran, not that corrections were applied.**  
`AssertHealthy` asserted `RemoteInputsApplied > 0` and described it as proving the rollback path,  
but that counts corrections applied — including the ones needing no rollback — so runs passed it  
with a single accepted rollback in 20 s. It now also asserts accepted rollbacks, on the five  
profiles whose minimum one-way latency exceeds one frame period and where late corrections are  
therefore guaranteed. Clean (0 ms) and LAN (5–15 ms, under a 16.67 ms frame) are reported instead:  
a link that delivers inside the frame is _supposed_ to need no rollback, and both are bimodal by  
harness phase — Clean was measured locking at exactly 1 in 5 of 8 runs, LAN as low as 8. On the  
five asserting profiles the measured minimum across 30 peer-samples is 105.

- 🧪 **The soak no longer asserts that pacing never overshoots its own trigger.** `AssertHealthy`  
bounded the smoothed frame-advantage delta at 4 on all seven profiles, and that 4 is  
`MaxFrameAdvantageFrames` — the value at which pacing _starts_ correcting. Asserting a reactive  
controller never passes its own setpoint is not satisfiable, and it made `RCPSoak.Latency.BurstLoss`  
fail about 1 run in 8 whenever pacing engaged at all. Every one of those failures was the  
controller working. The peak is now **reported** ; what is asserted instead is that the delta does  
not **dwell** at the setpoint, bounded by the same 5% budget the neighbouring stall-rate assertion  
uses — the two are the same quantity a factor of `StallDutyCycleFrames` apart, so they now agree  
rather than contradict each other. Measured worst case across the seven profiles is 1.9%; with  
frame-advantage pacing forced off, the new assertion fires at 42.6%. No plugin behaviour changed.

- 🧪 **The soak rolls back with the changed frame too** , so its `crossPeerDesyncs` figure no longer  
includes the false desyncs described above. On the Clean profile it reads 79 per peer with the fix  
and read 88 without it, in every run of each; the difference is exactly the 9 false desyncs each  
old run produced. The remaining 79 come from a known harness limitation (it does not model  
prediction faithfully), which is why the figure is still reported rather than asserted.

### 📝 Changed (documentation)

- 📝 **The integration docs now say when to start the clock.** QuickStart §5, the README networking  
snippet and the manual’s C++ usage call `ResetSimulationClock()` once the peer connects, and spawn  
rollback actors only after that. None of them mentioned it before, which is how the two-peer demo  
shipped the frame-skew defect above.
- 📝 **The README and manual networking snippets searched 15 frames back for late input.** That is  
wider than the default 12-frame rollback window, so a correction older than 12 frames was found  
and then rejected. They now search `GetMaxRollbackDepthFrames()` back, as the QuickStart already  
did.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [September 20, 2026, 4:47pm UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/20 "2026-09-20T16:47:24Z")

</div>

# 0.6.2 update, 2026-09-22

> Legend: 🐛 fix · ⚠ act on this in your own project · 🔄 behaviour change · ✅ covered by tests · 🧪 soak harness · 🔍 diagnostics · 🚧 known issue
> 
> **No plugin code changed in this entry.** Everything below is the soak harness and what it  
> measures. It is listed because it closes a 0.6.0 known issue and changes what a green soak means.

### 🧪 Fixed (soak harness)

- 🧪 🐛 **A multi-frame `Tick` gave two frames the same local input, and the two soak worlds then  
diverged permanently.** `Tick()` advances up to `MaxCatchUpFramesPerTick` frames in ONE call after  
a scheduling hitch, and `RollbackTick` runs once per frame advanced — each time reading the _same_  
`CurrentLocalInput`, which the harness set once per loop iteration. The send loop beside it emits  
the correct per-frame value for every frame. So the local world and the wire disagreed about the  
frames stepped over, and nothing ever corrected it:

### 🧪 Changed (soak harness)

- 🧪 🔄 **The cross-peer checksum comparison is now asserted, not just reported** — this closes the  
0.6.0 known issue. It took the fix above plus three harness corrections: corrections and rollback  
now run _before_ `Tick` (the checksum is computed inside `AdvanceFrame`, so applying them after it  
checksummed stale predicted state), remote pawns now predict by holding the last received input  
instead of neutral zeros, and the opening frames are pre-seeded. `Clean` went from **79  
cross-peer desyncs to 0**, with `remoteInputsApplied` at 1190 of 1199 frames, so it is not passing  
vacuously.

- 🧪 🔄 **The desync assertion no longer bounds the count by the input-hole count.** The first  
version asserted `crossPeerDesyncs <= UnrecoverableInputHoles`, which is wrong two independent  
ways: divergence is **persistent, not per-frame** (one written-off hole has no repair path, so  
every later comparison mismatches — dozens of reports from one event), and  
`UnrecoverableInputHoles` is **per-peer while divergence is symmetric** (a hole written off on one  
side diverges both worlds, and the other side’s own counter stays 0). Measured refutation:  
`BurstLoss` PeerB, **0 holes and 37 desyncs** , asserted at `== 0` by a branch it could never  
satisfy. What is asserted now is that divergence is _explained_ — with no hole on **either** peer,  
any disagreement fails; with one, the count is reported, because its magnitude is not a design  
constant.

- 🧪 🔄 **Agreement is asserted from a confirmation baseline, not from frame 0.**  
`UpdateInputConfirmation` takes its baseline from the first input packet to _arrive_ — deliberate,  
because a live session joins mid-stream — so under jitter a frame can count as confirmed before  
every earlier frame’s input has been applied. The product claims no agreement over that window, so  
neither does the soak: the assertion starts at the baseline plus one round trip and one checksum  
interval. ✅ Power checked — with the harness’s `RollbackToFrame` call removed, **all seven  
profiles fail **, `Clean` at 79 from frame 15 with** 0** excluded as startup; across every profile  
the exclusion swallowed only **0–1** desyncs per peer, so it is narrow rather than an amnesty.

### 🔍 Diagnostics

- 🔍 🧪 **The soak logs the per-`Tick` frame delta and the frames that disagreed.** `tickDelta(max=… multiAdvances=… firstMulti=… firstDesync=… verdict=…)` and `desyncFrames(first=… frames=[…])`.  
The frame list is what made the shape legible — evenly spaced entries 15 apart mean one divergence  
re-reported, not many independent ones — and the verdict field correlates the two directly.

### 🚧 Known issues

- 🚧 **The startup window before the confirmation baseline is excluded, not solved.** Whether  
`UpdateInputConfirmation` should instead take the lowest frame seen in a short opening window,  
rather than the first to arrive, is an open design question. It was measured at 0–1 desyncs per  
peer and affects only the first frames after connect.

---

<div class="post-metadata">

**Author:** ![andgregori](https://d1ap1mz92jnks1.cloudfront.net/user_avatar/forums.unrealengine.com/andgregori/32/1148407_2.png) [@andgregori](https://forums.unrealengine.com/u/andgregori)\
**Post date:** [September 25, 2026, 5:48am UTC](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262/21 "2026-09-25T05:48:52Z")

</div>

# [0.7.0] update, 2026-09-29 🤩 🫯

> Legend: 🎮 demos · 🐛 fix · ⚠ act on this in your own project · 🔄 behaviour change · ✅ covered by tests · 🧪 soak harness · 📝 docs · ✨ new

**Unreal Engine 5.8 is now declared and is the primary engine.** Supported: **5.5, 5.6, 5.7, 5.8**.  
Platforms are unchanged (Win64, Linux) and so is the wire protocol (v6). The Viking sample’s rules  
changed, though, so both peers of a Viking match must run 0.7.0. Android support needs further testing.  
Mac support needs extensive testing. iOS is permanently dropped.  
The [open-source branch](https://github.com/gregorik/Rollback-Core) remains functional for many use cases, but will not incorporate 0.7+ updates.

### ✨ Added — Valhalla Rumble

- 🎮 **The Viking sample is now a complete game: Valhalla Rumble.** Open  
`/RollbackCorePro/VikingGame/Map_VikingArena` and press Play, or run `Rollback.PlayValhalla`.

- 🎮 **Netplay Lab + Rollback Lens: rollback you can see.** You fight the AI through a simulated link  
whose latency and jitter you pick (and can change mid-fight with `[` / `]`, clamped to the rollback  
window). The Lens overlay shows:

- ✨ **`FRollbackCosmeticEventFilter`** (`RollbackCosmeticEventFilter.h`) and  
**`URollbackManager::IsReplayingRollback()`**. A rollback replays frames, so gameplay code that  
plays a sound or spawns an effect from inside the simulation plays it again on every replay. The  
filter lets each (frame, event) through exactly once, whether it first happens live or during a  
replay. You prune it with `PruneBefore` once frames fall out of the rollback window.  
✅ `RollbackCorePro.Cosmetic.*` (4 tests), `RollbackVikingGame.Presentation.ReplayDoesNotRefireEvents`.  
⚠ If your game triggers presentation from rollback ticks, route it through the filter  
(QuickStart § _Effects and sounds from the simulation_).

- ✨ **`URollbackManager::SetSimulationPaused(bool)` / `IsSimulationPaused()`** — holds the real-time  
fixed-step clock for a pause menu:

- ✨ **`LogRollbackCore`** (`RollbackCoreProLog.h`) — the runtime module logs to its own category now  
instead of `LogTemp`. ⚠ Update any log filter or `-LogCmds` that matched `LogTemp`.

- ✨ Console commands `Rollback.PlayValhalla`, `Rollback.PlayVikingNetplayLab`, and  
`Rollback.VikingShowcase` (a scripted tour of the game; the walkthrough video is rendered from it).

- ✨ Editor console commands `Rollback.OpenSetupWizard [page]`, `Rollback.OpenStatsPanel`,  
`Rollback.OpenProjectSettings`. Opening the wizard again now replaces the open one instead of  
stacking a second window. ✅ `RollbackCoreProEditor.Commands.Registered`.

### 🔄 Changed

- 🔄 **UE 5.8 is declared.** The descriptor pins 5.8, and 5.8 is the CI runtime engine. The compile  
matrix is 5.5, 5.6, 5.7, 5.8, and the scripts’ default engine is 5.8.

- 🔄 **`Rollback.SpawnVikingDemo` opens the Netplay Lab** when the sample module is loaded — the same  
demonstration, done properly. Without the module the legacy scene still spawns.

- 🔄 **Packaging the sample is a Setup Wizard opt-in: _Package The Sample_.** It adds  
`/RollbackCorePro/VikingGame` to _Directories To Always Cook_ and `Map_VikingArena` to _Maps To  
Cook_ (about 25 MB). The fighter JSON is staged by the sample module’s own `RuntimeDependencies`.  
Verified by packaging a Development build and playing it.  
⚠ If you had removed 0.6’s `FilterPlugin.ini` exclusion to package the demo, click the new button  
instead — see the next item.

- 🔄 **Fighter data moved** to `Content/VikingGame/Data/viking_fighters.json` (schema 2: per-frame  
asset paths, 448-pixel canvas, a `moves` block with frame data). The 0.6 path under  
`Content/Demo/Generated/` is still read as a fallback.

- 🔄 **`ARollbackVikingFighter` was extended** , not replaced:

- 🔄 The Viking match flow has a locked **round intro** and a **KO pause** before the round ends. Both  
enum values are appended, never reordered.

- 🔄 36 `UPROPERTY` raw object pointers are now `TObjectPtr`, and the demos call  
`SetShowMouseCursor()`.

### 🐛 Fixed

- 🎮 **Grey Beard’s sprite frames had issues since they shipped.** The 0.6 frames were cut with a  
global colour key, which erased every grey pixel: his beard, cape and tunic. He rendered as  
fragments, and several Red Beard frames were cropped from the wrong cells. All 76 frames are  
re-extracted from the source sheets, feet-aligned on one pivot.

- 🐛 **Four matchmaking tests could never pass on UE 5.5.** They passed an occurrence count of -1 to  
`AddExpectedMessagePlain`, which means “ignore” only from UE 5.6; 5.5 rejects it and fails the  
test. The suite had only ever been run on 5.7 and 5.8. It is now green on 5.5 as well.  
✅ The full 0.7.0 suite passes 149/149 on each of UE 5.5, 5.6, 5.7 and 5.8.

- 🐛 **0.6’s “Stage Demo Content” had persistent issues.** It removed a `FilterPlugin.ini` rule on  
the premise that `FilterPlugin.ini` stages loose files into packaged games. It does not; it only  
shapes the plugin’s own package. Packaging a game with the rule in place left a loose file under  
the plugin’s `Content/` unstaged (verified 2026-09-25 with the fighter JSON), so the same mechanism  
could not have delivered the viking frames either. The  
file’s comment, the wizard and the docs now say what it does.

- 🐛 **The Setup Wizard’s footer claimed “v1.1”.** It carried its own version literal; it now shows  
the descriptor’s `VersionName`. ✅ `RollbackCoreProEditor.Wizard.ShowsTheDescriptorVersion`.

### 📝 Docs

- 📝 `Docs/viking-demo.md` rewritten for Valhalla Rumble: modes, controls, frame data, the Lens,  
architecture, packaging and reskinning.
- 📝 New `Docs/credits.md` with every CC0 source.
- 📝 QuickStart: cosmetic events and pause.
- 📝 Support policy, README and manual declare UE 5.8.

[Next page](https://forums.unrealengine.com/t/gregorigin-rollback-core-pro-accessible-netcode-framework-for-fighting-platform-games/2728262.md?page=2)
