Scar Rewind System
Rewind time, per actor or across the whole world.
A Blueprint-first rewind system with zero dependencies and no C++. Rewind a single actor or every eligible actor in the level, leave a ghost trail behind, gate it with an energy system, lock axes for 2D games, and jump to named bookmarks instantly. Drop the component on an actor and recording starts the moment you press Play.
- Engine support
- Unreal Engine 5.2 to 5.7
- Version
- 3.0
- Backends
- Not applicable
What you get
- Per-actor rewind and global world rewind
- Ghost trail using any Blueprint Actor you create, with configurable linger
- Pickup-safe global rewind via tags and ownership detection
- Rewind energy system with cooldown and axis lock
- Custom variable tracking and named bookmarks
- Post process hook for chromatic aberration, vignette and desaturation
- Zero dependencies, crash-free, drop-in to any project
What was fixed in version 3.0
Version 2.0 compiled without errors but crashed Unreal Engine 5.2 at runtime. Eight root causes were identified and resolved. Every fix is documented below for full transparency.
| Fix | Cause and resolution |
|---|---|
| 1. Raw AActor* map key crashed at actor destruction | The global rewind cache used a raw pointer key. When any tracked Actor was destroyed mid-session the pointer became dangling, causing an access violation on the next map access. Fixed by switching to FObjectKey with a TWeakObjectPtr inside the record, which is GC-safe and never dangling. |
| 2. FWorldDelegates::OnWorldPreActorTick does not exist in UE 5.2 | That delegate was added in a later engine version, producing a link error at best. Fixed by inheriting the subsystem from FTickableGameObject and implementing Tick(float), which is stable across all UE 5.x versions. |
| 3. TActorIterator run during world transitions | The global recording timer fired on a fixed interval regardless of world state. If it fired during level streaming or teardown, iterating actors in a partially destroyed world crashed. Fixed by accumulating delta time in Tick and guarding with WorldType checks. |
| 4. NewObject without proper attachment | The post process component was created and registered but never attached to the owner scene hierarchy, so engine cleanup during PIE stop could not find a valid outer and assert-crashed. Fixed by creating it with the owner as outer, then attaching and registering in the correct order with a unique generated name. |
| 5. Ghost Trail spawned the AActor base class directly | The old ghost trail tried to spawn a bare AActor or AStaticMeshActor and configure it from C++, which was brittle and inflexible. Replaced entirely by a Blueprint class picker, so developers assign any Blueprint Actor as the ghost. Full creative control, zero engine-internal assumptions. |
| 6. Deinitialize() calling GetWorld() on a null world | During editor shutdown and level streaming, GetWorld() can return nullptr in Deinitialize(), and the old code accessed the timer manager through it. Fixed by removing all GetWorld() calls from Deinitialize(). Cleanup now only resets flags and empties arrays, which is safe without a valid world. |
| 7. GlobalActorCache iteration with invalidated keys | Related to fix 1. Raw pointer keys could become stale between recording ticks. The fix adds an explicit stale-entry purge pass using weak-pointer validity checks after each recording cycle. |
| 8. StopGlobalRewind called from inside the playback loop | When all actors reached the start of their buffers, StopGlobalRewind() was called from inside the loop iterating the cache, modifying the map while iterating it and corrupting the hash table. Fixed with a deferred pending-stop flag that Tick processes after the loop completes. |
Quick start: Blueprint setup
The Scar Rewind System is fully Blueprint-native. Every feature is accessible through Blueprint nodes. No C++ is required at any stage.
- 01Enable the plugin. Go to Edit > Plugins, search for Scar Rewind System, check Enabled, and click Restart Now. The plugin appears under the Gameplay category.
- 02Add the component to your actor. Open any Blueprint Actor, click Add Component in the Components panel, and search Scar Rewind Component. Recording begins automatically when you press Play, with no extra setup.
- 03Wire up input to start rewind. In the Event Graph, add your Input Action event, for example IA_Rewind. Drag the Scar Rewind Component reference in and connect the Started or Pressed exec pin to Start Rewind.
- 04Wire up input to stop rewind. From the same input event, connect the Completed or Released exec pin to Stop Rewind on the component. That is the complete minimal setup.
- 05Test in-editor. Press Play and enable Show Debug on the component to see a live status overlay above the Actor showing state, buffer fill and energy. Hold your rewind key to see the Actor travel back in time.
Enhanced Input is recommended but not required. The component works with any input method, including legacy Input Action, keyboard events, or custom input systems.
Creating your ghost Blueprint actor
The ghost trail spawns a Blueprint Actor you create and fully control. This gives you complete creative freedom: any mesh, material, particle effect or animation can serve as the ghost echo. The component handles spawn, position updates and destruction automatically.
- 01Create a new Blueprint Actor. In the Content Browser right-click, choose Blueprint Class, then Actor. Name it something like BP_RewindGhost.
- 02Add a Static Mesh Component and assign the same mesh your character or prop uses.
- 03Apply a translucent material. Create a Material with Blend Mode set to Translucent and Lighting Model set to Unlit, set Opacity to around 0.35, and apply it to the mesh. You can also add a Niagara component for a particle-based echo.
- 04Disable collision. Select the mesh component, and in Details > Collision set Collision Presets to NoCollision so the ghost does not block the player or other actors.
- 05Optional: add effects. Niagara components, Timeline animations, audio, material animations, or any Blueprint logic. The ghost Blueprint can do anything a normal Blueprint Actor can do.
- 06Assign it in the rewind component. Select the Actor with the Scar Rewind Component, and under Details > Scar Rewind System > Ghost Trail set Ghost Actor Class to BP_RewindGhost and enable Show Ghost Trail.
- 07Set the linger duration. Under the same Ghost Trail category, set Ghost Trail Linger Duration to how many seconds the ghost should stay visible after rewind ends. The default is 1.5 seconds, and 0 destroys it immediately.
The component automatically spawns one ghost instance when rewind starts, moves it to match the rewound position every frame, and starts the linger timer when rewind ends. You do not need any Begin Play or construction logic in the ghost Blueprint for the basic trail to work.
For a dissolve effect, add a Timeline in the ghost Blueprint that fades opacity from 0.5 to 0 over the same duration as your Ghost Trail Linger Duration. The ghost then fades out gracefully instead of disappearing abruptly.
Component properties reference
All properties are editable from the Details panel in the Blueprint editor. No code is required to configure any of these settings.
Core
| Property | Default | Description |
|---|---|---|
| Buffer Duration | 10 s | Seconds of history stored. Raise for longer rewinds, up to 60 seconds. |
| Recording Interval | 0.05 s | Snapshot frequency. 0.05 seconds equals 20 snapshots per second. |
| Rewind Speed | 1.5x | Playback speed multiplier. 1.0 equals real time, 2.0 equals twice as fast. |
| Location Threshold | 2 cm | Minimum movement before saving a snapshot. Skips idle frames. |
| Rotation Threshold | 0.5 deg | Minimum rotation before saving a snapshot. |
Energy system
| Property | Default | Description |
|---|---|---|
| Use Rewind Energy | Off | Enable built-in stamina. Rewind stops automatically at zero energy. |
| Max Rewind Energy | 100 | Maximum size of the energy pool. |
| Energy Drain Rate | 20 / s | Energy consumed per second while rewinding. |
| Energy Recharge Rate | 10 / s | Energy restored per second when idle. |
| Min Energy To Start Rewind | 10 | Minimum energy required to begin a new rewind. |
Cooldown
| Property | Default | Description |
|---|---|---|
| Rewind Cooldown | 0 s | Seconds before another rewind can start after one ends. 0 means no cooldown. |
Axis lock
| Property | Default | Description |
|---|---|---|
| Lock Location X | Off | Prevent rewinding the X world-space position. |
| Lock Location Y | Off | Prevent rewinding the Y world-space position. Use this for 2D sidescrollers. |
| Lock Location Z | Off | Prevent rewinding height. Useful for top-down games. |
| Lock Rotation | Off | Prevent rewinding rotation. Position still rewinds normally. |
Ghost trail
| Property | Default | Description |
|---|---|---|
| Show Ghost Trail | Off | Spawn the ghost Blueprint Actor during rewind playback. |
| Ghost Actor Class | None | The Blueprint Actor class to spawn as the ghost. Create your own translucent Blueprint and assign it here. |
| Ghost Trail Linger Duration | 1.5 s | How long the ghost stays visible after rewind ends. 0 destroys it immediately. Positive values keep the ghost alive so players can see where they came from. |
Post process
| Property | Default | Description |
|---|---|---|
| Use Post Process Effect | Off | Automatically activate a post process effect during rewind. |
| Post Process Chromatic Aberration | 2.0 | RGB fringe strength. Gives a time-glitch look. 0 means none. |
| Post Process Vignette | 0.6 | Screen-edge darkening during rewind. 0 means none. |
| Post Process Desaturation | 0.8 | Colour drain amount. 1.0 equals full grayscale. |
Priority and debug
| Property | Default | Description |
|---|---|---|
| Rewind Priority | 5 | 1 to 10. Higher priority means a larger buffer allocation in the global memory budget. |
| Show Debug | Off | Draws live state text above the Actor. Compiled out automatically in Shipping builds. |
| Show Debug Path | Off | Draws the recorded movement path as coloured dots. Also compiled out in Shipping. |
Blueprint node reference
Every function listed here is available as a Blueprint node. Drag the Scar Rewind Component reference into the Event Graph and pull off a wire to search for any of these nodes.
Core nodes
| Node | Description |
|---|---|
| Start Rewind | Begin rewinding. Blocked automatically if the buffer is empty, rewind is already active, cooldown is running, or energy is too low. |
| Stop Rewind | Stop rewinding. The Actor stays at the rewound position and recording resumes automatically. |
| Clear Buffer | Erase all history. You cannot rewind past this call. All bookmarks are also cleared. |
| Set Recording Enabled (bool) | Pause or resume snapshot recording without affecting active playback. |
Bookmark nodes
Bookmarks save a named moment in history. Restore Bookmark is an instant teleport: it does not play through the intervening history, it jumps directly to that moment.
| Node | Description |
|---|---|
| Save Bookmark (Name) | Save a named moment at the current buffer head. Up to 16 per component. Re-saving the same name updates it. |
| Restore Bookmark (Name) -> bool | Instantly move the Actor to the saved position and restore tracked variables. Returns false if the name was not found. |
| Delete Bookmark (Name) | Remove a single bookmark by name. |
| Clear All Bookmarks | Remove all bookmarks. Does not clear the snapshot buffer. |
Call Save Bookmark when the player enters a safe zone. On death, call Restore Bookmark to teleport back instantly with no animation required.
Energy nodes
| Node | Description |
|---|---|
| Get Current Energy -> float | Raw energy value from 0 to Max Rewind Energy. |
| Get Energy Ratio -> float | Energy as a 0 to 1 fraction. Wire directly into a Progress Bar Percent binding. |
| Set Energy (float) | Force-set the energy value. Clamped to 0 through Max Rewind Energy. Fires On Energy Changed. |
Drag the On Energy Changed event onto the graph and wire it into a Progress Bar Set Percent node. This updates your energy UI automatically without polling every tick.
State query nodes
| Node | Description |
|---|---|
| Is Rewinding -> bool | True while rewind playback is active. |
| Is Recording -> bool | True while new snapshots are being saved. |
| Is On Cooldown -> bool | True while the cooldown timer is running. |
| Get Rewind State -> Enum | Returns Idle, Recording, Rewinding or Paused. |
| Get Buffer Size -> int | Number of snapshots currently in the buffer. |
| Get Buffer Capacity -> int | Maximum snapshot capacity of the buffer. |
| Get Buffer Fill Ratio -> float | Buffer fill as 0 to 1. Use for a rewind-meter progress bar. |
| Get Recorded Duration -> float | Approximate seconds of history currently stored. |
| Get Cooldown Remaining -> float | Seconds until cooldown expires. Returns 0 when ready. |
| Get Last Snapshot Custom Floats -> float[] | An array of the most recently recorded custom float values. Index matches registration order. |
Events and delegates
All events are BlueprintAssignable. In the Blueprint editor, select the Scar Rewind Component in the Components panel, then look in the Details panel under Events and click the green plus button next to any event to add it directly to the graph.
| Event | Fires when |
|---|---|
| On Rewind State Changed (bIsRewinding) | Rewind starts (true) or stops (false). Use this to play sounds, trigger VFX, update UI or lock player movement. This is the primary event for reacting to rewind in Blueprint. |
| On Rewind Buffer Exhausted | The buffer is fully consumed and rewind auto-stops. Show a no-more-rewind notification here, or trigger a screen shake or sound. |
| On Energy Changed (CurrentEnergy) | Energy changes by more than 0.01. Bind a Progress Bar to this instead of polling Get Energy Ratio every tick. It fires during both drain and recharge. |
| On Bookmark Saved (BookmarkName) | Save Bookmark succeeds. Use this to show a checkpoint-saved notification or play a confirmation sound. |
| On Global Rewind State Changed (bIsActive) | Fires on the Scar Rewind Subsystem when global world rewind starts or stops. Use it to apply Set Global Time Dilation or play a world-wide rewind sound. |
To bind an event in Blueprint: select the component in the Components panel, open the Details panel, scroll to the Events section, and click the green plus button next to the event you want. Unreal creates the event node in the Event Graph automatically.
Global world rewind
Global World Rewind rewinds every eligible movable Actor in the level simultaneously with a single Blueprint node. Enemies, projectiles, props and vehicles are all rewound together. Actors with a Scar Rewind Component use their own per-actor buffer, and all other eligible movable Actors use the global snapshot cache built by the subsystem.
How to access the subsystem in Blueprint
Right-click in any Blueprint Event Graph and search for Get World Subsystem. In the Class dropdown select Scar Rewind Subsystem. Pull off the return value wire to access all global rewind nodes.
Store the subsystem reference in a local variable to avoid repeating the Get World Subsystem call across multiple nodes.
| Node | Description |
|---|---|
| Start Global Rewind (Duration) | Rewind every eligible movable Actor. Duration 0 uses the full buffer. Duration 3.0 rewinds exactly 3 seconds back. |
| Stop Global Rewind | Stop global rewind. All Actors resume from their rewound positions. |
| Is Global Rewinding -> bool | True while global rewind is active. |
Global rewind settings (on the subsystem)
| Property | Default | Description |
|---|---|---|
| Global Buffer Duration | 10 s | History kept for Actors without a Scar Rewind Component. |
| Global Record Interval | 0.05 s | Snapshot frequency for the global cache. |
| Global Rewind Speed | 1.5x | Playback speed for all Actors during global rewind. |
To exclude any specific Actor from global rewind, add the tag ScarIgnoreGlobal in its Details panel under Tags. Actors with Mobility set to Static are always excluded automatically because they cannot move.
In large scenes with many dynamic Actors, raise Global Record Interval to 0.1 to reduce CPU cost, and tag non-essential background props with ScarIgnoreGlobal.
Pickup exclusion from global rewind
Global rewind does not affect pickups. Rewinding the world while the player has already collected an item would cause confusing behaviour, for example a weapon disappearing from the player hand or a health pack reappearing and then vanishing again as the timeline moves. The system provides two automatic methods to keep pickups out of the global rewind.
Method 1: tag the pickup actor (recommended)
Add the tag ScarIsPickup to any Actor Tags array in the Details panel. The global rewind system skips this Actor entirely, whether or not it has been picked up. Use this for weapons, health packs, ammo, keys, collectibles, and any other item the player can interact with.
- 01Select the pickup Actor in the level, or open its Blueprint.
- 02In Details, scroll to Tags.
- 03Click the plus button and type: ScarIsPickup
- 04That is all. The Actor is now permanently excluded from global rewind.
Method 2: ownership detection (automatic)
When a player picks up an item, most inventory and equipment systems set the item Owner to the Pawn that collected it. The global rewind system detects this automatically: any Actor whose Owner is a Pawn subclass is skipped during global rewind. That means already-collected items are excluded without any extra tags or configuration.
If your pickup system does not set the item Owner, use Method 1, the ScarIsPickup tag, as the reliable fallback. Both methods can be used together on the same Actor.
Summary of all exclusion rules
| Condition | Result |
|---|---|
| Actor has Mobility = Static | Always excluded. Static Actors cannot move. |
| Actor has tag ScarIgnoreGlobal | Excluded. General-purpose opt-out for any Actor. |
| Actor has tag ScarIsPickup | Excluded. Designed specifically for collectible items. |
| Actor Owner is a Pawn subclass | Excluded. The item has been picked up by a player or AI. |
| Actor has a Scar Rewind Component | Excluded from the global cache. Uses its own per-actor buffer instead. |
| Actor is a pure logic Actor (AInfo subclass) | Excluded. These have no world presence to rewind. |
The ScarIsPickup tag excludes the Actor permanently, even before the player picks it up. If you want un-picked items to rewind with the world but picked items to stay in the player hands, rely on Method 2, ownership detection, only and do not add the tag.
Batch operations via subsystem
The Scar Rewind Subsystem lets you control every registered Scar Rewind Component in the level at once. All components register automatically at Begin Play, so you do not need to manage this manually. Access it via Get World Subsystem > Scar Rewind Subsystem.
| Node | Category | Description |
|---|---|---|
| Rewind All Actors | Batch | Call Start Rewind on every registered component. |
| Stop All Rewinds | Batch | Call Stop Rewind on every registered component. |
| Clear All Buffers | Batch | Call Clear Buffer on every registered component. |
| Get Registered Component Count -> int | Batch | How many Scar Rewind Components are currently active in the world. |
| Start Global Rewind (Duration) | Global | Rewind every eligible movable Actor. Duration 0 uses the full buffer. |
| Stop Global Rewind | Global | Stop global rewind. All Actors resume from their rewound positions. |
| Is Global Rewinding -> bool | Global | True while global rewind is active. |
Game design recipes
Ready-made configurations for common rewind gameplay patterns. All settings are applied in the Details panel of the Scar Rewind Component or via Blueprint nodes. No code is required.
Death rewind
The player dies. Call Start Global Rewind with Duration 3.0 to rewind 3 seconds. The ghost trail with a 2-second linger shows the player where they were, post process desaturation signals the timeline reversal, and the energy system prevents abuse.
Use Rewind Energy .............. On
Show Ghost Trail ............... On (assign your ghost Blueprint)
Ghost Trail Linger Duration .... 2.0
Use Post Process Effect ........ On, Desaturation 0.8
// From your death event:
Start Global Rewind (3.0)Puzzle environment reset
// Add Scar Rewind Component to every puzzle Actor
On mistake: Rewind All Actors // subsystem
On success: Clear All Buffers // prevents rewinding past the clean stateBullet time sequence
Post Process Chromatic Aberration ... 3.0
Post Process Desaturation ........... 1.0
Set Global Time Dilation (0.2)
Start Global Rewind (2.0) // replays the last 2 seconds in slow motionCheckpoint restore
// At each safe zone trigger:
Save Bookmark ("Checkpoint")
// From your death or respawn event:
Restore Bookmark ("Checkpoint") // instant, no intervening historyResource-limited rewind
A stamina-gated rewind. The player gets 4 seconds per use, takes 20 seconds to fully recharge, and must wait 2 seconds between uses.
Use Rewind Energy ....... On
Max Rewind Energy ....... 100
Energy Drain Rate ....... 25
Energy Recharge Rate .... 5
Rewind Cooldown ......... 2.0
// Bind On Energy Changed -> Progress Bar Set Percent2D platformer side-scroller lock
Lock Location Y ... On // locks the depth axis
Lock Rotation ..... On // keeps the sprite facing correctlyCollectible-safe world rewind
// Add tag ScarIsPickup to every collectible Actor
Start Global Rewind
// Picked-up items (Owner is Pawn) and tagged items are excluded automaticallyPerformance notes
The Scar Rewind System is built with performance as a first priority. Here is what you get out of the box and what to watch for in large scenes.
| Behaviour | What it means |
|---|---|
| Tick disabled when idle | The component enables Tick only during active rewind, energy management or debug display. A stationary Actor with the component attached and no active features has zero per-frame cost. |
| Timer-based recording | Recording uses a looping timer, not a per-frame Tick. Snapshots are taken at your configured Recording Interval regardless of frame rate, and frames between intervals cost nothing. |
| Zero runtime allocations | The circular buffer is pre-allocated once in Begin Play. Pushing a snapshot overwrites existing memory in place, so there is no garbage collection pressure during play. |
| Movement threshold skips idle actors | Actors that have not moved or rotated beyond the threshold values do not write a snapshot on that cycle, so stationary Actors consume no buffer space. |
| FTickableGameObject subsystem | The subsystem uses FTickableGameObject rather than component Tick, avoiding ActorComponent tick prerequisites and running more predictably across versions. |
| Ghost linger timer is zero-cost when idle | A single timer handle, active only for the duration after rewind ends. If Ghost Trail Linger Duration is 0, no timer is created at all. |
| Global rewind at scale | The global recording iterator runs at Global Record Interval, not every frame. In scenes with 200 or more dynamic Actors, raise the interval to 0.1 and tag non-essential props with ScarIgnoreGlobal. Actors tagged ScarIsPickup are skipped entirely and add no recording overhead. |
File reference
All plugin source files are in your project Plugins/ScarRewindSystem/ folder. You do not need to edit any of these files to use the plugin. This reference is for developers who want to extend the system.
| File | Purpose |
|---|---|
| ScarRewindSystem.uplugin | Plugin descriptor, version info and Fab marketplace metadata. |
| ScarRewindSystem.Build.cs | Module build rules. Includes PhysicsCore and RenderCore. |
| ScarRewindSystemModule.h / .cpp | Module startup and shutdown. |
| ScarRewindSnapshot.h | FScarRewindSnapshot struct. Edit SCAR_MAX_CUSTOM_VARS here. |
| ScarCircularBuffer.h | TScarCircularBuffer template. Allocation-free ring buffer. |
| ScarRewindTypes.h | All shared delegates, the EScarRewindState enum, and FScarRewindBookmark. |
| ScarRewindComponent.h / .cpp | Main component. Per-actor rewind, ghost trail with linger timer, energy, bookmarks, axis lock and post process. |
| ScarRewindSubsystem.h / .cpp | World Subsystem. Batch operations, global world rewind, pickup exclusion and FTickableGameObject ticking. |
Stuck on something?
We answer every serious message ourselves. Discord is the fastest way to get an answer from the person who built the plugin.