Data Persistence System¶
A robust, configurable data persistence solution for Unity applications built with the LoL Engine framework.
Quick Start¶
IMPORTANT: Config Assets Must Be In Resources Folder
- Create LoLEngineConfig (Right-click → Create → LoLEngine → Config → LoLEngineConfig):
- Save at:
Assets/[YourProject]/Resources/Configs/DefaultLoLEngineConfig.asset -
Configure: obfuscation (enabled by default), encryption (off by default), compression, save paths
-
Create SaveConfig (Right-click → Create → LoLEngine → Data Persistence → Save Configuration):
- Save at:
Assets/[YourProject]/Resources/Configs/DefaultSaveConfig.asset -
Configure: save slots, auto-save interval, quick-save settings
-
Enable Services in your
ServiceConfiguration.asset: Enable Data Persistence Service(core save system)Enable Serialization Service(required for JSON)Enable Compression Service(if using compression)Enable Encryption Service(if using encryption)Enable Auto Save Service(optional, for auto-saving)-
Enable Quick Save Service(optional, for F5/F9 quick save) -
Add ImprovedGameInitializer to your first scene and assign your
ServiceConfiguration
Basic usage:
using LoLEngine.Core.DataPersistence.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
var saveSystem = ServiceLocator.Instance.Get<ISaveSystem>();
// Access or create data
var player = saveSystem.GetData<PlayerData>();
player.PlayerName = "Hero";
player.Health = 100;
// Save/Load
saveSystem.SaveGame("save1");
bool ok = saveSystem.LoadGame("save1");
Note: This file reflects recent improvements to the Save System. It aligns with the current LoLEngine implementation: engine-wide compression/obfuscation/encryption live in LoLEngineConfig, AutoSave uses SaveConfig if present, saves use atomic writes, and the save management API is available.
Overview¶
The LoL Engine Data Persistence system provides a service-based approach to saving and loading game data. Built on the Service Locator pattern, it offers JSON serialization with optional compression and protection (obfuscation or encryption), plus an organized structure for managing persistent game data.
Features¶
- Type-safe data persistence through
PersistableDatainheritance - Multiple formats: JSON, JSON with obfuscation, or JSON with encryption
- Obfuscation for fast save protection (enabled by default)
- Optional compression to reduce save file sizes
- Optional encryption for sensitive game data (configured in
LoLEngineConfig) - Save slots for multiple save files
- Asynchronous operations for performance
- Events for save begin/complete (via
GameEvent) - Auto-save functionality
- Checksum stored with save container (validation available to call)
- Configuration via
LoLEngineConfig(engine-wide compression/obfuscation/encryption, paths, extensions) andSaveConfig(game behavior for autosave/quicksave slots/intervals). - Atomic save operations (writing to temporary files first) for enhanced data integrity.
- Data versioning support within save files.
- Checksum validation for save file integrity.
- Asynchronous operations by default for non-blocking save/loads.
Overhaul Summary and How To Use It¶
The Save System received a major update. This section explains what changed and how to adopt it.
What Changed¶
- SECURITY: Removed committed encryption keys from the repository. Use environment variables or build-time injection for production keys.
- ARCHITECTURE: Consolidated configuration. Protection/compression now live in
LoLEngineConfig(single source of truth).SaveConfigfocuses on gameplay behavior (slots/intervals/toggles for auto/quick save). - PRODUCTION PATHS: Saves now use
Application.persistentDataPathfor builds. Editor paths remain predictable for debugging. - FLEXIBILITY: File extensions are resolved dynamically via
SaveSettings.GetFileExtension(); do not hardcode extensions. - SCENE-AWARE AUTOSAVE: AutoSave service can exclude common non-gameplay scenes using a built-in list (e.g., MainMenu/Boot/Loading). Toggle with
RestrictAutoSaveToGameplay. - API ENHANCEMENT: Added
ListSavesAsync,DeleteAsync,GetLatestAsync,HasAnySavesAsyncfor richer file management. - VERSION SUPPORT: Added on-load version validation and a foundation for save migrations.
- INTERFACE CONSISTENCY: Clarified
ISaveSystemvsIAutoSaveServiceresponsibilities.
Setup Steps (New)¶
1. LoLEngineConfig (engine-wide)
- Create/locate Resources/Configs/DefaultLoLEngineConfig.asset (created via menu: LoLEngine/Config/LoLEngineConfig).
- Set compression/obfuscation/encryption here. Do NOT place production keys in the repo; inject via environment variables/CI and write into LoLEngineConfig at build/startup.
2. SaveConfig (game behavior)
- Create via: Create → LoLEngine → Data Persistence → Save Configuration.
- Configure: default/quick/auto save slots, quick-save limits, auto-save interval, and whether to restrict auto-save to gameplay scenes.
- Placement: put the asset at Resources/Configs/DefaultSaveConfig.asset to be auto-discovered by AutoSave.
3. ServiceConfiguration - Enable: Serialization, (optional) Compression, (optional) Encryption services. - Enable: Data Persistence (Save System), Auto Save Service (if needed), Quick Save Service (optional).
4. Game Initializer
- Use ImprovedGameInitializer and assign your ServiceConfiguration.
- The initializer registers SaveSystem and (optionally) AutoSaveService. AutoSave picks up settings from DefaultSaveConfig if present; SaveSystem reads engine-level settings from LoLEngineConfig.
Where to Put Obfuscation/Encryption Configuration¶
- Put obfuscation and encryption configuration in
LoLEngineConfigONLY. - Obfuscation (default): Set
obfuscateSaveFiles = truefor fast protection. - Encryption: Set
encryptSaveFiles = trueonly for sensitive data. This takes precedence over obfuscation at runtime. - In production, inject encryption keys via environment variables or CI/build scripts. Do not commit production keys.
Save Paths and Extensions¶
- Use
SaveSettings.GetSaveFilePath(slot)to get the full path underApplication.persistentDataPath. - Use
SaveSettings.GetFileExtension()to get the correct extension for current settings (do not hardcode.sav/.osav/encrypted ext).
AutoSave Scene Filtering¶
- Configure an excluded-scenes list (e.g.,
Boot,MainMenu,Loading) inSaveConfig. - The AutoSave service subscribes to scene changes and pauses/resumes accordingly.
New Save Management API¶
// List existing save files (with file system metadata)
IReadOnlyList<SaveFileInfo> files = await _saveSystem.ListSavesAsync();
// Delete a save
await _saveSystem.DeleteAsync("save1");
// Get the most recent save
var latest = await _saveSystem.GetLatestAsync();
// Do we have any saves at all?
bool any = await _saveSystem.HasAnySavesAsync();
SaveFileInfo provides file-level metadata (name, timestamp, size) and is separate from your game's SaveMetadata.
Atomic Writes and Integrity¶
- Saves write to a temporary file and then perform an atomic move to prevent partial/corrupted files.
- Checksums validate integrity during load.
Versioning and Migration¶
- Override
SchemaVersionon eachPersistableDatasubclass whose serialized fields change, then register a per-domain migration with_saveSystem.RegisterDomainMigration(...)(a bundle-levelISaveMigrationviaRegisterMigration(...)is also available). - The system validates each domain's stored version at load and routes incompatible versions to your registered migration steps.
Security Checklist¶
- Never commit production keys.
- Use environment variables or CI secrets to inject keys.
- Keep Encryption/Compression config in
LoLEngineConfigonly (do not duplicate inSaveConfig).
Architecture¶
The Data Persistence system is organized as follows:
DataPersistence/
├── Data/ # Core data structures
│ ├── GameSaveData.cs # Container for all game data
│ └── PersistableData.cs # Base class for all save data
├── Events/ # Save-related events
│ └── SaveEvents.cs # Event definitions
├── Interfaces/ # Service interfaces
│ ├── IAutoSaveService.cs # Auto-save functionality
│ ├── IQuickSaveService.cs # Quick save functionality
│ └── ISaveSystem.cs # Main persistence interface
├── Service/ # Service implementations
│ ├── AutoSaveService.cs # Auto-save implementation
│ ├── QuickSaveService.cs # Quick save implementation
│ └── SaveSystem.cs # Main persistence implementation
└── Settings/ # Configuration
├── SaveConfig.cs # ScriptableObject for editor-time configuration
└── SaveSettings.cs # Runtime persistence setting (derived from SaveConfig)
Getting Started¶
1. Configure and Initialize the Save System¶
The Data Persistence system is initialized as part of the LoL Engine's startup sequence when using the ImprovedGameInitializer. Configuration is primarily handled through ScriptableObject assets:
-
Enable Data Persistence Services:
- In your
ServiceConfigurationasset (assigned toImprovedGameInitializer), ensure the relevant data persistence services are enabled:EnableDataPersistenceService(for the coreISaveSystem)EnableAutoSaveService(if you need auto-save functionality)EnableQuickSaveService(if you need quick save/load)- Ensure
EnableSerializationService,EnableCompressionService, andEnableEncryptionServiceare enabled if you intend to use their respective features with saving.
- In your
-
Create a
SaveConfigAsset:- Create a
SaveConfigasset in your project (Right-click in Project window →Create→LoLEngine→Data Persistence→Save Configuration). - Customize settings within this
SaveConfigasset: default/quick/auto save slots, max quick saves, auto-save interval, and restrict-to-gameplay toggle. - Place the asset at
Resources/Configs/DefaultSaveConfig.assetso AutoSave can auto-discover it.
- Create a
-
Ensure
ImprovedGameInitializeris Set Up:- Have an
ImprovedGameInitializercomponent in your first scene with yourServiceConfigurationassigned to it.
- Have an
The engine will then use these configurations to initialize the SaveSystem and related services.
2. Define Data Classes¶
Create data classes by inheriting from PersistableData:
using System;
using LoLEngine.Core.DataPersistence.Data;
using UnityEngine;
namespace YourGame.Data
{
[Serializable]
public class PlayerData : PersistableData
{
// Unique identifier for this data class
public override string DataId => "player";
// Serialized fields
[SerializeField] private string playerName;
[SerializeField] private int health;
[SerializeField] private Vector3 position;
// Properties with getters/setters
public string PlayerName
{
get => playerName;
set => playerName = value;
}
public int Health
{
get => health;
set => health = value;
}
public Vector3 Position
{
get => position;
set => position = value;
}
// Optional lifecycle hooks
public override void OnBeforeSave()
{
// Prepare data before saving (e.g., update timestamps)
}
public override void OnAfterLoad()
{
// Process data after loading (e.g., validate values)
}
}
}
3. Register and Use Data¶
Access the save system and register your data objects:
using LoLEngine.Core.DataPersistence.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
using UnityEngine;
using YourGame.Data;
public class GameManager : MonoBehaviour
{
private ISaveSystem _saveSystem;
private void Awake()
{
// Get save system through service locator
_saveSystem = ServiceLocator.Instance.Get<ISaveSystem>();
// Initialize game data
InitializeGameData();
}
private void InitializeGameData()
{
// Create or get player data
var playerData = _saveSystem.GetData<PlayerData>();
// Initialize with default values if needed
playerData.PlayerName = "Hero";
playerData.Health = 100;
playerData.Position = Vector3.zero;
// Register other game data types
// Note: GetData automatically registers a new instance if not found
var inventoryData = _saveSystem.GetData<InventoryData>();
var questData = _saveSystem.GetData<QuestData>();
}
// Call this to manually save the game
public void SaveGame()
{
// Update values before saving
var playerData = _saveSystem.GetData<PlayerData>();
playerData.Position = transform.position;
try
{
// Save to "save1" slot
_saveSystem.SaveGame("save1");
Debug.Log("Game saved successfully");
}
catch (System.Exception e)
{
Debug.LogError($"Save failed: {e.Message}");
}
}
// Call this to load a saved game
public void LoadGame()
{
// Check if save exists before loading
if (_saveSystem.HasSaveFile("save1"))
{
if (_saveSystem.LoadGame("save1"))
{
// Access loaded data
var playerData = _saveSystem.GetData<PlayerData>();
// Apply loaded values to game state
transform.position = playerData.Position;
Debug.Log($"Loaded player: {playerData.PlayerName}, Health: {playerData.Health}");
}
else
{
Debug.LogError("Failed to load save file");
}
}
else
{
Debug.Log("No save file found");
}
}
// For large save files, use async methods
public async void SaveGameAsync()
{
try
{
await _saveSystem.SaveGameAsync("save1");
Debug.Log("Game saved asynchronously");
}
catch (System.Exception e)
{
Debug.LogError($"Async save failed: {e.Message}");
}
}
}
Configuration Options¶
Configuration is split between LoLEngineConfig (engine-wide) and SaveConfig (game behavior):
LoLEngineConfig(Resources/Configs/DefaultLoLEngineConfig):saveDirectory,saveFileExtension,obfuscatedSaveFileExtension,encryptedSaveFileExtensioncompressSaveFiles,compressionLevelForSaveFiles-
obfuscateSaveFiles(default),encryptSaveFiles,defaultEncryptionKey,encryptionKeySeed -
SaveConfig(Resources/Configs/DefaultSaveConfig): DefaultSaveSlot,QuickSaveSlot,AutoSaveSlotMaxSaveSlots,EnableQuickSave,EnableAutoSaveAutoSaveInterval,RestrictAutoSaveToGameplay
Tip: You generally do not need to construct SaveSettings yourself. SaveSystem reads engine-wide options from LoLEngineConfig; AutoSaveService reads game behavior from DefaultSaveConfig if present.
Save File Types¶
The system supports three formats with automatic detection (names configurable in LoLEngineConfig):
- Obfuscated JSON (default, fast) — default extension .osav
- Encrypted JSON (for sensitive data) — default extension .esave
- Plain JSON — default extension .sav (not recommended)
Priority when loading: obfuscated > encrypted > plain. Always use SaveSettings.GetFileExtension() rather than hardcoding extensions.
Priority when loading: obfuscated > encrypted > plain. Always use SaveSettings.GetFileExtension() rather than hardcoding extensions.
See Save protection below for obfuscation vs encryption guidance.
Advanced Features¶
Save Slots¶
The system supports multiple save files:
// Save to different slots
_saveSystem.SaveGame("quicksave");
_saveSystem.SaveGame("slot1");
_saveSystem.SaveGame("autosave");
// Load from specific slot
_saveSystem.LoadGame("slot1");
// Check if a save exists
if (_saveSystem.HasSaveFile("quicksave"))
{
// Save exists
}
Auto-Save (IAutoSaveService)¶
Enable in ServiceConfiguration: Enable Auto Save Service (requires Data Persistence + Serialization).
Configure behavior in SaveConfig:
Auto Save Settings:
├─ Auto Save Enabled: true
├─ Auto Save Interval: 300 (seconds)
├─ Auto Save Slot: "autosave"
└─ Restrict Auto Save To Gameplay: true
Auto-save starts automatically when the service initializes (if enabled in config). Use DefaultSaveConfig at Resources/Configs/DefaultSaveConfig.asset so AutoSave can auto-discover settings.
using LoLEngine.Core.DataPersistence.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
var autoSave = ServiceLocator.Instance.Get<IAutoSaveService>();
autoSave.StartAutoSave(); // resume periodic saves
autoSave.StopAutoSave(); // pause (e.g. main menu)
autoSave.SaveNow(); // force immediate save (scene transitions, quit)
Scene filtering: When RestrictAutoSaveToGameplay is true, AutoSave pauses in scenes whose names match the six built-in exclusions (MainMenu, Boot, Loading, Splash, Settings, Credits). Add your own (e.g. CharacterSelect, Lobby, Tutorial) via SaveConfig.excludedSceneNames.
Recommended intervals: 60–120s (action/permadeath), 300–600s (RPG/strategy), 900–1800s (casual games with manual saves).
Quick Save (IQuickSaveService)¶
Enable in ServiceConfiguration: Enable Quick Save Service (requires Data Persistence + Serialization).
Configure in SaveConfig:
Quick Save Settings:
├─ Quick Save Enabled: true
└─ Max Quick Saves: 5
using LoLEngine.Core.DataPersistence.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
using UnityEngine;
public class QuickSaveHandler : MonoBehaviour
{
private IQuickSaveService _quickSave;
void Start() => _quickSave = ServiceLocator.Instance.Get<IQuickSaveService>();
void Update()
{
if (Input.GetKeyDown(KeyCode.F5)) _quickSave.QuickSave();
if (Input.GetKeyDown(KeyCode.F9)) _quickSave.QuickLoad();
}
}
API highlights:
| Method / property | Purpose |
|---|---|
QuickSave() |
Create a timestamped quick save |
QuickLoad(index = 0) |
Load most recent (0) or older slot (1, 2, …) |
HasQuickSave() |
Whether any quick save exists |
GetLatestQuickSaveSlot() |
Most recent slot name |
QuickSaveSlots |
All current quick save slot names |
MaxQuickSaves |
Rotation limit (oldest removed when exceeded) |
Quick saves use timestamped names: quicksave_yyyyMMdd_HHmmss (e.g. quicksave_20250108_143025).
QuickSaveService exposes BeforeQuickSave / AfterQuickSave events (on the concrete class) for UI feedback — pause, show indicators, notifications.
Save Protection (Obfuscation and Encryption)¶
Configure in LoLEngineConfig only (not SaveConfig). Enable Serialization Service; obfuscation/encryption run through the serializer pipeline automatically when saving.
Priority at runtime: obfuscation → encryption → plain JSON.
| Mode | Extension (default) | When to use |
|---|---|---|
| Obfuscation (default) | .osav |
Game progress, settings — fast, stops casual editing |
| Encryption | .esav |
Payment data, PII, compliance requirements |
| Plain | .sav |
Debugging only — not recommended for shipping |
Performance comparison:
| Obfuscation (XOR) | Encryption (AES-256) | |
|---|---|---|
| Speed | ~10× faster | Slower (PBKDF2 key derivation) |
| Security | Casual protection | Strong |
| Best for | Frequent saves, mobile | Sensitive data, rare saves |
Recommended defaults (most games):
// LoLEngineConfig
obfuscateSaveFiles = true; // on by default
encryptSaveFiles = false; // only for sensitive data
Obfuscation — automatic when enabled; no extra code at save sites:
await _saveSystem.SaveGameAsync("save1"); // writes save1.osav
await _saveSystem.LoadGameAsync("save1"); // auto-detects .osav / .esav / .sav
Direct service access (advanced):
var obfuscation = ServiceLocator.Instance.Get<IObfuscationService>();
string obfuscated = obfuscation.Obfuscate(plainText, key: "");
string restored = obfuscation.Deobfuscate(obfuscated, key: "");
Encryption — enable encryptSaveFiles in LoLEngineConfig. Keys come from SecureKeyProvider + optional encryptionKeySeed. Never commit production keys — inject via CI/environment at build time.
// Keys are wired by ConfigurableServiceInitializer from LoLEngineConfig
var encryption = ServiceLocator.Instance.Get<IEncryptionService>();
string encrypted = encryption.EncryptString(sensitiveData, password);
string decrypted = encryption.DecryptString(encrypted, password);
Security tips:
- Obfuscation does not stop determined reverse engineering — validate loaded data (sanity checks, checksums).
- For multiplayer, validate critical values server-side.
- Migrating encryption → obfuscation: new saves use
.osav; old.esav/.savfiles still load.
Compression (ICompressionService)¶
Enable in ServiceConfiguration: Enable Compression Service. Toggle save compression in LoLEngineConfig (compressSaveFiles, compressionLevelForSaveFiles).
When enabled, the save/serializer pipeline compresses JSON before obfuscation/encryption. Useful for large save files; skip for tiny saves if CPU matters more than disk.
Direct service access (non-save use cases):
using LoLEngine.Core.Compression.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
using System.IO.Compression;
var compression = ServiceLocator.Instance.Get<ICompressionService>();
string compressed = compression.CompressString(largeJson, CompressionLevel.Optimal);
string restored = compression.DecompressString(compressed);
compression.CompressFile(sourcePath, outputZipPath, CompressionLevel.Fastest);
compression.DecompressFile(inputZipPath, outputDirectory);
Services register automatically via ImprovedGameInitializer — do not manually register unless writing custom bootstrap code.
Event System Integration¶
The system publishes events for save begin/complete via GameEvent. Subscribe with GameEvent.Subscribe and implement IEventListener<T>:
using LoLEngine.Core.DataPersistence.Events;
using LoLEngine.Core.Events.GameEvents;
using LoLEngine.Core.Events.Interfaces;
using UnityEngine;
public class SaveEventsListener : MonoBehaviour,
IEventListener<SaveBeginEvent>,
IEventListener<SaveCompleteEvent>
{
private void OnEnable()
{
GameEvent.Subscribe(this as IEventListener<SaveBeginEvent>);
GameEvent.Subscribe(this as IEventListener<SaveCompleteEvent>);
}
private void OnDisable()
{
GameEvent.Unsubscribe(this as IEventListener<SaveBeginEvent>);
GameEvent.Unsubscribe(this as IEventListener<SaveCompleteEvent>);
}
public void OnGameEvent(SaveBeginEvent e)
{
Debug.Log($"Save starting for slot: {e.SaveSlot}");
}
public void OnGameEvent(SaveCompleteEvent e)
{
Debug.Log($"Save completed for slot: {e.SaveSlot}, Success: {e.Success}");
}
}
Note: Quick/Auto save/load event types exist but are not emitted by all services yet; rely on the save begin/complete events for now.
Best Practices¶
-
DataId Uniqueness: Ensure each
PersistableDataclass has a uniqueDataId -
Data Registration: Use
GetData<T>()which auto-registers new data instances if needed -
Data Updates: Update your data objects before calling
SaveGame() -
Error Handling: Always handle exceptions from save operations
-
Save File Management:
- Use meaningful slot names
- Implement a save management UI
-
Clean up old saves to prevent storage bloat
-
Performance:
- Use asynchronous methods for large saves
- Configure compression level based on your needs
- Use obfuscation for normal game saves (10x faster than encryption)
-
Only encrypt truly sensitive data (payment info, personal details)
-
Testing:
- Test with various save sizes
- Verify data integrity between saves
-
Test on target platforms (mobile devices may have different storage behavior)
-
Use
SaveConfigfor autosave/quicksave behavior andLoLEngineConfigfor engine-wide protection/compression settings.
Integration with Other Systems¶
-
UI Integration: Create a save/load UI that displays save slots and timestamps
-
Scene Management: Save current scene information to restore game state properly
-
Player Settings: Save user preferences such as graphics quality, sound volume, etc.
Example: Complete Save System Implementation¶
using LoLEngine.Core.DataPersistence.Interfaces;
using LoLEngine.Core.ServiceManagement.Service;
using LoLEngine.Core.Events.GameEvents;
using LoLEngine.Core.DataPersistence.Events;
using UnityEngine;
using System;
using YourGame.Data;
public class SaveManager : MonoBehaviour,
LoLEngine.Core.Events.Interfaces.IEventListener<SaveBeginEvent>,
LoLEngine.Core.Events.Interfaces.IEventListener<SaveCompleteEvent>
{
private ISaveSystem _saveSystem;
private IQuickSaveService _quickSaveService;
[SerializeField] private string defaultSlot = "save1";
public event Action<string> OnSaveCompleted;
public event Action<string> OnLoadCompleted;
private void Awake()
{
_saveSystem = ServiceLocator.Instance.Get<ISaveSystem>();
_quickSaveService = ServiceLocator.Instance.Get<IQuickSaveService>();
// Subscribe to events (save begin/complete)
GameEvent.Subscribe(this as IEventListener<SaveBeginEvent>);
GameEvent.Subscribe(this as IEventListener<SaveCompleteEvent>);
}
private void OnDestroy()
{
// Unsubscribe from events
GameEvent.Unsubscribe(this as IEventListener<SaveBeginEvent>);
GameEvent.Unsubscribe(this as IEventListener<SaveCompleteEvent>);
}
public void QuickSave()
{
_quickSaveService.QuickSave();
}
public void QuickLoad()
{
_quickSaveService.QuickLoad();
}
public void SaveToSlot(string slotName)
{
try
{
UpdateAllData();
_saveSystem.SaveGame(slotName);
}
catch (Exception e)
{
Debug.LogError($"Error saving to slot {slotName}: {e.Message}");
}
}
public bool LoadFromSlot(string slotName)
{
if (!_saveSystem.HasSaveFile(slotName))
{
Debug.LogWarning($"No save file found in slot: {slotName}");
return false;
}
bool success = _saveSystem.LoadGame(slotName);
if (success)
{
ApplyLoadedData();
}
else
{
Debug.LogError($"Failed to load from slot: {slotName}");
}
return success;
}
public string[] GetAllSaveSlots()
{
// Implementation would depend on additional methods in SaveSystem
// This is just a conceptual example
return new string[] { "save1", "save2", "quicksave", "autosave" };
}
private void UpdateAllData()
{
// Update player data before saving
var playerData = _saveSystem.GetData<PlayerData>();
playerData.Position = FindFirstObjectByType<PlayerController>().transform.position;
playerData.Health = FindFirstObjectByType<PlayerHealth>().CurrentHealth;
// Update other game data...
}
private void ApplyLoadedData()
{
// Get loaded data
var playerData = _saveSystem.GetData<PlayerData>();
// Apply to game objects
var player = FindFirstObjectByType<PlayerController>();
if (player != null)
{
player.transform.position = playerData.Position;
}
var healthComp = FindFirstObjectByType<PlayerHealth>();
if (healthComp != null)
{
healthComp.SetHealth(playerData.Health);
}
// Apply other game data...
}
public void OnGameEvent(SaveBeginEvent e)
{
Debug.Log($"Starting save to slot: {e.SaveSlot}");
}
public void OnGameEvent(SaveCompleteEvent e)
{
Debug.Log($"Save {(e.Success ? "succeeded" : "failed")} for slot: {e.SaveSlot}");
if (e.Success) OnSaveCompleted?.Invoke(e.SaveSlot);
}
}