Technical Specs
SafeSave is built as a native C++ module (FModuleInterface) that strictly adheres to the Unreal Engine Source Control Abstraction Layer (ISourceControlProvider). It does not rely on external Python scripts, hacked binaries, or screen scraping.
This section outlines the performance characteristics and execution logic for Systems Engineers and Technical Leads.
1. Performance & Tick Policy
SafeSave does not use the standard Tick() for its logic loop. To minimize main-thread overhead, the widget utilizes Slate’s Active Timer system.
Logic Loop: RegisterActiveTimer with a 1.0s (1Hz) interval.
Cost: < 0.05ms per interval on standard hardware.
Idle Behavior: If the Editor is not in focus or slate is sleeping, SafeSave suspends polling automatically.
2. The "Deep Scan" Memory Iterator
Unlike Content Browser filters which scan the Asset Registry (Disk), SafeSave scans Memory to determine the "Dirty" state. This ensures we detect changes to maps and assets the moment they are modified in RAM, even before a file exists on disk.
Mechanism: TObjectIterator<UPackage>
Filtering Strategy: The scan aggressively culls iteration to prevent scope creep.
Ignores: /Engine/, /Script/, /Memory/ namespaces.
Ignores: PKG_CompiledIn (Code modules) and GetTransientPackage().
Ignores: World Partition HLODs and WP Editor Cells (_InstanceOf_ regex match).
Target: Only strictly User Content (/Game/, /Plugins/) loaded in the Active World or Content Browser is evaluated.
3. Source Control Agnosticism (API Layer)
SafeSave is not a Git Client; it is an ISourceControlModule Wrapper. It binds to the abstract interface ISourceControlProvider defined in SourceControl module.
EStateCacheUsage::Use: For 99% of frames, we read from the Provider's local cache (Zero latency).
EStateCacheUsage::ForceUpdate: We force a synchronous update only on user interaction (Click) or periodically (every 3-5s) to validate IsCurrent() status against the remote server.
4. Threading Model
SafeSave respects the Unreal Engine main thread requirements while offloading network operations.
UI Paint: Runs on Main Thread (Slate).
Memory Scan: Runs on Main Thread (Required for UObject safety).
Network Operations: All calls to CheckForUpdates (git fetch, p4 sync -n) are dispatched using EConcurrency::Asynchronous.
This prevents the Editor from "hitching" or freezing while the plugin waits for a slow Git server to respond.
5. Conflict Resolution Pipeline (The Red Light)
When the "Safe Update" protocol is triggered, SafeSave orchestrates a multi-step dependency chain via FEditorFileUtils:
Flush: FEditorFileUtils::SaveDirtyPackages() is called with bPromptToSave=false (Implicit Save).
Sync: FSync operation is dispatched via the Provider.
Merge: Unreal Engine's native conflict logic (FAssetMergeUtility) detects the binary mismatch between the Local Head and Remote Head.
UI: The Engine spawns the standard Visual Merge Tool, allowing the user to diff properties.
SafeSave does not implement a custom merging algorithm. It relies entirely on the Engine's deterministic merge behavior to ensure data integrity.
6. Module Injection
The UI is injected via UToolMenus into LevelEditor.LevelEditorToolBar.User.
Clean Unload: The module implements ShutdownModule to explicitly unregister the Slate Widget and unbind delegates.
No Garbage: Disabling the plugin completely removes it from the Slate hierarchy; no ghost widgets remain in memory.
Last updated
