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

Valhalla Rumble: one of the sample multiplayer games shipped with 0.7.0:

A video tutorial is now available:

[0.8.0] update, 2026-10-10 :fight_cloud: :technologist:

Legend: :video_game: demos · :bug: fix · :warning: act on this in your own project · :counterclockwise_arrows_button: behaviour change · :white_check_mark: covered by tests · :test_tube: soak harness · :memo: docs · :sparkles: new

Animation montages now roll back, an offline match can rewind, and components can own rollback
state.
A second sample game, Rewind Arena, shows all three in 3D, and shows two peers playing
over the UDP transport after finding each other through an OnlineSubsystem Null LAN session.
Supported engines are unchanged (5.5, 5.6, 5.7, 5.8; 5.8 primary) and so is the wire protocol
(v6): a 0.8.0 peer plays a 0.7.0 peer as long as both run the same game.

:sparkles: Added — runtime

  • :sparkles: URollbackAnimationComponent — montages as rollback state. Each character’s montage
    timeline (which montage, from which simulation frame, at which integer play rate, from which
    section and offset, blending from what) lives in AnimState, which the component contributes to
    the actor’s snapshot. A rollback, a rewind or a determinism audit restores the pose exactly —
    mid-swing, mid-blend — because the pose shown is evaluated from the state for the frame being
    presented (URollbackAnimInstance, Native drive mode), not advanced by an animation clock.

    • Simulation API, all taking the frame being simulated: PlayMontage / PlayMontageAsset,
      JumpToSection, StopMontage, DelayTimeline (hit-stop that also holds the windows and root
      motion), IsInNotifyWindow, WasNotifyFired, GetSectionAt, GetMontageFrame,
      GetRootMotionDelta (actor space; RootMotionAxes handles the UE mannequin’s −90° mesh).
    • MontageSync drive mode keeps your own Anim Blueprint: the component holds the montage paused
      and sets its position every frame.
    • Corrections you can see: AnimationCorrectionCount and OnAnimationCorrected(Frame, Before, After) report every rollback that changed what a character was playing.
    • PresentationFrameOverride scrubs the pose to any frame the timeline covers.

    :white_check_mark: RollbackCorePro.Animation.*.

  • :sparkles: URollbackMontageData, URollbackNotifyWindow, Bake Rollback Montage Data. Gameplay never
    asks the animation system anything. Each montage carries a baked per-frame table (animation
    metadata, so it cooks with the asset): length, sections and links, notify windows, blend times and
    cumulative root translation at the project’s fixed tick rate. Rollback Window notify states
    (URollbackNotifyWindow) let designers place hit / cancel / invulnerability windows on the
    animation. Bake from the Content Browser (right-click montages) or
    URollbackMontageBakeLibrary::BakeMontages; IsMontageBakeCurrent reports a stale bake. Montages
    without data are baked at first use, with a warning, when bAllowRuntimeBake is on.
    :white_check_mark: RollbackCoreProEditor.BakeLibrary.RejectsUnusableMontages, RollbackCorePro.Animation.BakedMontageLookups.

  • :sparkles: IRollbackStateContributor — state that lives on a component. A component that implements it
    names its own properties; the actor’s URollbackStateComponent saves, restores, checksums and diffs
    them after the actor’s own (ordered by component name, then property), names them
    Component.Property in desync reports, and calls OnRollbackStateRestored(Frame) after a load.
    New on the state component: GetTrackedPropertyNames() and RefreshTrackedProperties().
    :white_check_mark: RollbackCorePro.State.*Contributor*.

  • :sparkles: URollbackManager::RewindToFrame(Frame) — offline rewind without replay. Every entity is
    restored to the frame, which becomes the present; the next AdvanceFrame() continues on a new
    branch, and each entity’s history after the frame is discarded
    (IRollbackEntity::DiscardRollbackHistoryAfter, a new virtual with an empty default). Refused while
    a peer is connected, during a rollback, and for a frame without a complete snapshot. Plus
    CanRewindToFrame, GetOldestRewindFrame and RewindCount (rewinds are not rollbacks).
    :white_check_mark: RollbackCorePro.Rewind.*.

  • :sparkles: URollbackManager::OnRollbackBegin / OnRollbackEnd (native multicast, (RollbackFrame, CurrentFrame)): fired by every accepted rollback before state is restored and after the replay
    caught up, never by a rewind. Presentation that wants to know what a rollback changed records its
    view on Begin and compares on End — the animation component detects corrections this way.

:bug: Fixed

  • :bug: :warning: Struct members without SaveGame were silently not rolled back. Snapshots serialize with
    the SaveGame flag, and the engine then skips any member of a tracked struct that is not
    UPROPERTY(SaveGame) — on save and on restore, so no checksum ever disagreed. The state component
    now logs a warning naming each such member when it builds its schema. Natively serialized structs
    (FVector, FQuat, …) are written whole and are unaffected. If the warning names one of your
    members, mark it SaveGame (or confirm it is meant to stay out).
    :white_check_mark:
    RollbackCorePro.State.StructMembersWithoutSaveGameAreReported.

  • :bug: An empty UDP datagram stopped the transport reading for the rest of that pump. PumpSocket
    treated a zero-length datagram like “nothing to read” and stopped, so every packet queued behind
    it waited for the next pump — and the empty datagram itself was never counted. It is now counted,
    rejected and skipped. Found by the new malformed-packet test; RecvFrom returns false for “no
    data” on both the BSD and EOS socket subsystems, so a successful zero-byte read is always a real
    empty packet. :white_check_mark: RollbackCorePro.Network.MalformedPacketsAreRejected — 53 hostile datagrams
    (empty, truncated, oversized and negative counts, NaN axes, negative frames, unknown types and
    flags, zero nonce, foreign magic, seeded random bytes): every one rejected exactly once in a single
    pump, no peer created, no input buffered, and a real peer still connects afterwards.

:video_game: Added — Rewind Arena, a 3D sample game

  • :video_game: Rewind Arena (RollbackArenaGame, a non-Shipping DeveloperTool module; content in
    /RollbackCorePro/ArenaGame). Open Map_RewindArena and press Play, or run Rollback.PlayArena.
    Two UE5 mannequins, Ember and Frost, fight on a rune-lit platform at sunset, animated only by
    montages that roll back.

    • Modes: Versus CPU (three difficulties), Local Versus, Training with hold-to-rewind (R /
      left trigger runs fighters, montages and clock backwards; let go to play on), Netplay Lab,
      Online, Showcase, Options, About.
    • Fighting from the montage: a Jab → Cross → Hook chain that may continue only inside its
      RB_Cancel windows, a Roundhouse, a meter-powered Rush carried by baked root motion, block with
      chip, sidesteps invulnerable inside RB_Invuln, knockdowns, hit-stop via DelayTimeline. Every
      hit window is a notify state on the animation.
    • Rollback Lens: a ghost of every mispredicted pose, drawn from the correction’s Before
      timeline, and a panel with rollbacks, resimulation depth, montage corrections, ghosts drawn,
      replayed effects skipped, mispredicted inputs or desyncs, and the link.
    • Online, two peers: Host LAN Match advertises a Null OSS session through the plugin’s
      HostRollbackSession node; Find LAN Matches lists sessions (FindRollbackSessions); joining
      one (JoinRollbackSession) handshakes the UDP transport and both machines start the fight — host
      seat 0, joiner seat 1. Direct IP is the fallback. Match rules are rollback state, ticked after
      both fighters, so trades and rounds replay together; rematch needs both players. If the rival
      disconnects, the match stops cleanly and says so instead of stalling.
    • Presentation reads the simulation and never writes it: an orbit / fight camera, impact
      sparks and rings deduplicated by FRollbackCosmeticEventFilter, a rewind grade, a glyph halo
      above the arena that spins backwards while rewinding, flickering braziers, CC0 audio reused from
      Valhalla Rumble. HUD and menus are UMG widgets painted in NativePaint, so Movie Render Queue
      records them.
    • Content (~47 MB): the UE5 mannequins from Unreal Engine’s templates (Epic Games), 19 original
      animations and 17 baked montages authored in Blender by script, an original procedural arena, all
      authored in UE 5.5 (Tools/ArenaArt/Author-ArenaAssets.ps1) so it loads on every supported
      engine.

    :white_check_mark: 20 tests under RollbackArenaGame.*: Combat, Assets, Animation, Fighter,
    Rewind, Online, Flow, Presentation.

  • :video_game: Demo/Run-ArenaP2PDemo.ps1 — host and joiner side by side on one machine (-Auto: the AI
    plays both seats; -Packaged: a packaged build).

  • :test_tube: Tools/Verify-ArenaOnline.ps1 — the same two processes headless, CI-safe: fails unless the
    joiner finds the session through Null, both peers start and keep simulating, neither reports a
    desync and at least one rolled back. First run on UE 5.8: 4,560 frames per peer, 2,223 rollbacks,
    483 montage corrections, 0 desyncs.

  • :sparkles: Console commands Rollback.PlayArena, ArenaVsAI, ArenaLocal2P, ArenaTraining, ArenaLab,
    ArenaShowcase ([ember|frost] [auto]), ArenaRewind, ArenaNetHost, ArenaNetJoin,
    ArenaDirectHost, ArenaDirectJoin, ArenaMenu.

:counterclockwise_arrows_button: Changed

  • :counterclockwise_arrows_button: The Setup Wizard’s Package The Sample packages both samples: it adds
    /RollbackCorePro/VikingGame and /RollbackCorePro/ArenaGame to Directories To Always Cook and
    both maps to Maps To Cook. A project that packaged only the Viking sample with 0.7 is offered the
    button again. :white_check_mark: RollbackCoreProEditor.Wizard.PackageTheSampleCooksContentAndMap.
  • :counterclockwise_arrows_button: RollbackCorePro.uplugin lists the RollbackArenaGame module (DeveloperTool, Win64 / Linux /
    Android).

:test_tube: Soak harness: §12.13 and §12.14 closed

  • :test_tube: §12.14, the soak’s intermittent permanent divergence, was the harness. It set the local
    pawn’s input once per loop iteration, so when one Tick() caught up several frames the same input
    was scheduled for all of them while the send loop put the correct per-frame inputs on the wire. This
    machine never produced a multi-frame Tick on its own (0 in 8 full soak runs, with and without the
    harness’s repair), so the soak now forces them: RCPSoak.Hitch.CatchUpAdvancesStayInSync
    stalls peer A’s process for 3 frames every 90 and requires zero divergence across 13 catch-up
    advances; RCPSoak.Hitch.ControlWithoutRepairDiverges runs the same hitches with the repair off and
    requires the worlds to diverge (first desync 13 frames after the first catch-up; 61 and 73
    steady-state desyncs). An integration that sends what its state component scheduled
    (GetInputForFrame(Frame), as both samples do) cannot diverge this way.
  • :test_tube: §12.13, BurstLoss’s window: bursts are now scheduled (the link goes dark both ways for 13
    frames at 6 s and 13 s) instead of Poisson-distributed, and the window of 32 carries its
    derivation (13 + 2 round trips + input delay = 25, + jitter margin). Six standalone runs: peak
    confirmation lag 20–22 every time (the random model ranged 26–46), deepest rollback 30.
  • :test_tube: Tools/Soak-Pacing.ps1 expects 9 tests.

:test_tube: Verification

  • :white_check_mark: 207 automation tests pass on each of UE 5.5.4, 5.6.1, 5.7.4 and 5.8.3 (clean build per engine,
    counted from the engine’s JSON report): 106 RollbackCorePro.* (30 new), 4 RollbackCoreProEditor.*,
    77 RollbackVikingGame.*, 20 RollbackArenaGame.*. Tools/Run-AutomationTests.ps1 now includes
    RollbackArenaGame by default and fails below 200 tests.
  • :white_check_mark: RunUAT BuildPlugin -StrictIncludes (no PCH, no unity): UE 5.8 and 5.7 for Win64 and Android
    (NDK Clang, arm64 + x64), 5.6 for Win64 and Android, 5.5 for Win64 (no Android support installed
    for 5.5). The strict build found one include a unity build had hidden, in a test file; fixed.
  • :white_check_mark: Linux game target on UE 5.8 with Clang 20.1.8: every module, 0 warnings.
  • :white_check_mark: Pacing soak 9/9 on UE 5.8; BurstLoss 6/6 more on its own.
  • :white_check_mark: Tools/Verify-Matchmaking.ps1 and Tools/Verify-ArenaOnline.ps1 (two processes each) pass.
  • :white_check_mark: Every shipped asset loads on UE 5.5 (Check-AssetEngineCompat.ps1: 276 assets ≤ package version
    1013).
  • :white_check_mark: Looked at, not just logged: Rewind Arena’s title, menus, online page, Versus / Showcase fights,
    the Netplay Lab with ghosts, Training’s rewind on UE 5.8; the Showcase and Netplay Lab on UE 5.5; and
    the two-window online demo with both windows on the same frame and 0 desyncs. Looking found three
    things no test had: impact rings three times too large, fighters lit by their own rim term at
    dusk exposure, and HUD / ghost colours that followed the seat instead of the fighter (now pinned by
    RollbackArenaGame.Flow.MenuStartsTheChosenModeAndFighter).

:memo: Docs

  • :memo: New Docs/arena-demo.md. Manual: new sections Animation Rollback and Rewind (later sections
    renumbered), component state and the SaveGame-member rule under State Capture, API and console
    tables. QuickStart: State that lives on a component, Montages that roll back, Rewind
    (offline)
    . FAQ: montages, component state, rewind. credits.md covers Rewind Arena.

A tutorial is now available for the 0.8.0 update specifically: