Skip to content

Archived on 2026-10-24. This is a historical implementation note, not current setup instructions or an active task list. Original claims, code examples, file paths, and completion statements have not all been revalidated. Use the current documentation and issue register for maintenance decisions.

SaveDataDebugger - Comprehensive Save Data Debugging System

Overview

The SaveDataDebugger is a utility class designed to help diagnose issues with player data creation, loading, and migration in the save system. It provides detailed validation and logging for PlayerData objects at every stage of the save data pipeline.

Purpose

  • Identify where PlayerData dictionaries become null
  • Validate JSON serialization/deserialization
  • Check encryption/decryption integrity
  • Diagnose legacy save migration issues
  • Track data flow through the save system

Features

1. PlayerData Validation

Method: DebugPlayerData(PlayerData playerData, SaveDataType dataType, string context)

Validates all aspects of a PlayerData object: - Checks if PlayerData is null - Validates basic fields (version, soulPoint, chaosFragment) - Validates all 6 dictionaries: - unlockedChar - unlockedAchievement - unlockedSpecialUpgrade - shopUpgrade - unlockedStage - totalDataCounter - Checks boolean flags (legacyMigrated, isFirstLaunch) - Reports null dictionaries with clear error messages - Shows sample entries from each dictionary

2. JSON Serialization Testing

Method: DebugJsonSerialization(PlayerData playerData)

Tests Unity's JsonUtility serialization/deserialization: - Serializes PlayerData to JSON - Checks JSON length - Deserializes back to PlayerData - Critical Check: Verifies if dictionaries survive the round-trip - Reports if dictionaries become null (common Unity JsonUtility issue)

3. Encryption/Decryption Testing

Method: DebugEncryption(string data)

Validates encryption/decryption pipeline: - Encrypts test data - Decrypts back - Compares original vs decrypted - Reports any mismatches

4. Legacy Data Validation

Method: DebugLegacyData(List<PlayerData> legacyData)

Validates legacy save files before migration: - Checks if legacy data list is null - Counts legacy saves - Validates each legacy PlayerData - Reports null legacy saves - Shows achievement data from each legacy save

5. Merged Data Validation

Method: DebugMergedData(PlayerData merged, List<PlayerData> sources)

Validates data after merging: - Shows number of sources - Reports final currency values - Validates merged achievement dictionary - Reports if merged data is null

6. Full Diagnostic

Method: RunFullDiagnostic(PlayerData playerData, SaveDataType dataType, string context)

Runs comprehensive diagnostic including: - Complete PlayerData validation - JSON serialization test - Formatted output with clear headers

7. File Operations

Method: DebugFileOperations(string filePath, string operation)

Logs file operation details: - Operation type (load, save, etc.) - File path - File existence check

Integration Points

The debugger is integrated into SaveManager at these key points:

1. CreateNewPlayerData()

SaveDataDebugger.RunFullDiagnostic(Player, SaveDataDebugger.SaveDataType.NewSave, "CreateNewPlayerData");
Validates: New player data created for first-time players

2. LoadNewEncryptedSave()

SaveDataDebugger.DebugFileOperations(PLAYER_FILE, "LoadNewEncryptedSave");
Player = JsonUtility.FromJson<PlayerData>(json);
SaveDataDebugger.RunFullDiagnostic(Player, SaveDataDebugger.SaveDataType.LoadedSave, "LoadNewEncryptedSave");
Validates: Data loaded from existing save file

3. MigrateLegacySaveAsync()

SaveDataDebugger.DebugLegacyData(legacyData);  // Before merge
Player = MergeLegacyPlayers(legacyData);
SaveDataDebugger.DebugMergedData(Player, legacyData);  // After merge
SaveDataDebugger.RunFullDiagnostic(Player, SaveDataDebugger.SaveDataType.MigratedSave, "MigrateLegacySaveAsync");
Validates: Legacy save data before and after migration

Expected Output

Successful Data Creation

╔════════════════════════════════════════════════════════════╗
║         SAVEDATA DEBUGGER - FULL DIAGNOSTIC               ║
╚════════════════════════════════════════════════════════════╝
========================================
[SaveDataDebugger] Validating PlayerData (NewSave) - CreateNewPlayerData
========================================
[SaveDataDebugger] ✓ PlayerData object exists
[SaveDataDebugger] Version: 1.0.0
[SaveDataDebugger] SoulPoint: 0
[SaveDataDebugger] ChaosFragment: 0
[SaveDataDebugger] ✓ unlockedChar - Count: 10
[SaveDataDebugger] ✓ unlockedAchievement - Count: 0
[SaveDataDebugger] ✓ unlockedSpecialUpgrade - Count: 5
[SaveDataDebugger] ✓ shopUpgrade - Count: 8
[SaveDataDebugger] ✓ unlockedStage - Count: 20
[SaveDataDebugger] ✓ totalDataCounter - Count: 0
[SaveDataDebugger] ✓ All dictionaries are initialized
========================================
[SaveDataDebugger] Testing JSON serialization...
[SaveDataDebugger] ✓ JSON serialization successful
[SaveDataDebugger]   JSON length: 1234 characters
[SaveDataDebugger] ✓ JSON deserialization successful
[SaveDataDebugger] ✗ unlockedAchievement became NULL after deserialization!
[SaveDataDebugger]   This indicates Unity's JsonUtility cannot serialize Dictionaries properly!
╔════════════════════════════════════════════════════════════╗
║         DIAGNOSTIC COMPLETE                                  ║
╚════════════════════════════════════════════════════════════╝

Null Dictionary Error

========================================
[SaveDataDebugger] Validating PlayerData (LoadedSave) - LoadNewEncryptedSave
========================================
[SaveDataDebugger] ✓ PlayerData object exists
[SaveDataDebugger] Version: 1.0.0
[SaveDataDebugger] SoulPoint: 100
[SaveDataDebugger] ChaosFragment: 50
[SaveDataDebugger] ✓ unlockedChar - Count: 10
[SaveDataDebugger] ✗ unlockedAchievement is NULL!
[SaveDataDebugger] ✓ unlockedSpecialUpgrade - Count: 5
[SaveDataDebugger] ✓ shopUpgrade - Count: 8
[SaveDataDebugger] ✓ unlockedStage - Count: 20
[SaveDataDebugger] ✓ totalDataCounter - Count: 15
[SaveDataDebugger] ✗ FOUND 1 NULL DICTIONARIES - This will cause issues!
========================================

Common Issues & Solutions

Issue 1: Dictionaries become null after JSON deserialization

Symptom: unlockedAchievement became NULL after deserialization!

Cause: Unity's JsonUtility cannot serialize Dictionary<TKey, TValue> types.

Solution: Use a custom JSON serializer (Newtonsoft.Json) or create wrapper classes for dictionaries.

Issue 2: Dictionaries are null in loaded save

Symptom: ✗ unlockedAchievement is NULL!

Cause: Save file was created before dictionary initialization was properly implemented.

Solution: Add migration code to handle null dictionaries by initializing them:

if (playerData.unlockedAchievement == null)
    playerData.unlockedAchievement = new Dictionary<string, bool>();

Issue 3: Legacy save has null achievement data

Symptom: ⚠ unlockedAchievement is NULL in legacy save

Cause: Legacy save file doesn't contain achievement data or it was never initialized.

Solution: Ensure merge code handles null dictionaries gracefully:

if (legacy.unlockedAchievement != null)
{
    MergeBoolDict(merged.unlockedAchievement, legacy.unlockedAchievement);
}

Usage Example

Adding Debugger to New Code

public void YourSaveMethod()
{
    PlayerData data = CreateOrLoadData();

    // Validate the data
    SaveDataDebugger.RunFullDiagnostic(data, SaveDataDebugger.SaveDataType.LoadedSave, "YourMethod");

    // Use the data
    ProcessData(data);
}

Specific Validation

if (data != null)
{
    // Check only achievement dictionary
    if (data.unlockedAchievement == null)
    {
        Debug.LogError("Achievement dictionary is null!");
        SaveDataDebugger.DebugPlayerData(data, SaveDataDebugger.SaveDataType.LoadedSave, "BeforeFix");

        // Fix it
        data.unlockedAchievement = new Dictionary<string, bool>();
    }
}

Troubleshooting Guide

  1. Game crashes on startup
  2. Look for PlayerData is NULL in logs
  3. Check if PlayerData is being created before use
  4. Verify SaveManager.Instance.Player is not null

  5. Achievements not loading

  6. Look for unlockedAchievement is NULL after loading
  7. Check if JSON serialization is losing dictionary data
  8. Verify save file contains achievement data

  9. Save file corrupted

  10. Check encryption/decryption logs for mismatches
  11. Verify JSON length is reasonable
  12. Check for null PlayerData after deserialization

  13. Legacy migration fails

  14. Review DebugLegacyData output
  15. Check if legacy saves are null
  16. Verify merge logic handles null dictionaries

Performance Considerations

The debugger adds logging overhead: - Use only during development/debugging - Remove or disable in production builds - Consider adding a compile-time flag to disable:

#if UNITY_EDITOR || DEVELOPMENT_BUILD
    SaveDataDebugger.RunFullDiagnostic(playerData, SaveDataType.SaveDataType.NewSave, "context");
#endif

Future Enhancements

  • Add validation for data ranges (e.g., negative soulPoint)
  • Add checksum verification for save files
  • Add timeline tracking of data changes
  • Add export of diagnostic data to file
  • Add automated fix suggestions for common issues