FantasyAsset/Assets/Scripts/ES3SingleStore.cs

229 lines
9.1 KiB
C#
Raw Normal View History

2025-10-08 01:03:39 +05:00
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Reflection;
// Optional Dialogue System / Quest Machine snapshot:
// #define USE_PIXELCRUSHERS
#if USE_PIXELCRUSHERS
using PixelCrushers;
#endif
public static class ES3SingleStore
{
// One file for everything:
private const string FILE = "save.es3";
// Stable keys:
private const string K_Version = "v";
private const string K_SavedAt = "t";
private const string K_Obj = "obj"; // ObjectiveManager data
private const string K_LevelIdx = "lvl"; // currentLevelIndex
private const string K_IsRunning = "run"; // currentLevel != null
private const string K_DSJSON = "dsj"; // Dialogue System snapshot (optional)
private const string K_ActStep = "actStep"; // NEW
private static ES3Settings Settings => new ES3Settings
{
encryptionType = ES3.EncryptionType.AES,
encryptionPassword = "change-me-strong-pass", // must match!
prettyPrint = false
};
// ----- DTOs for ObjectiveManager -----
[Serializable] public class ObjectiveData { public string text; public bool completed; }
[Serializable]
public class ObjectiveManagerData
{
public List<ObjectiveData> list = new();
public int activeIndex = 0;
public List<string> queuedNextObjectives = null;
public int queuedNextStartIndex = 0;
}
public static void Save()
{
// header/meta
ES3.Save(K_Version, "1.0.0", FILE, Settings);
ES3.Save(K_SavedAt, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), FILE, Settings);
// ObjectiveManager
if (ObjectiveManager.Instance != null)
{
var om = ObjectiveManager.Instance;
var data = new ObjectiveManagerData
{
activeIndex = Mathf.Clamp(om.activeIndex, 0, Math.Max(0, om.objectives.Count - 1)),
queuedNextObjectives = om._queuedNextObjectives != null ? new List<string>(om._queuedNextObjectives) : null,
queuedNextStartIndex = GetPrivate<int>(om, "_queuedNextStartIndex")
};
foreach (var o in om.objectives)
data.list.Add(new ObjectiveData { text = o.text, completed = o.completed });
ES3.Save(K_Obj, data, FILE, Settings);
}
if (ActivatorManager.Instance != null)
{
PlayerPrefs.SetInt("StepIndex",ActivatorManager.Instance.stepIndex);
}
//if (ActivatorManager.Instance != null)
//{
// ES3.Save(K_ActStep, ActivatorManager.Instance.stepIndex, FILE, Settings);
//}
//Debug.Log("[Save] Wrote save.es3");
// GameplayManager
var gm = GameplayManager.Instance;
if (gm != null)
{
var currentLevelIndex = GetPrivate<int>(gm, "currentLevelIndex");
var isLevelRunning = GetPrivate<object>(gm, "currentLevel") != null;
ES3.Save(K_LevelIdx, currentLevelIndex, FILE, Settings);
ES3.Save(K_IsRunning, isLevelRunning, FILE, Settings);
}
#if USE_PIXELCRUSHERS
// Dialogue System/Quest Machine snapshot
string dsJson = null;
if (SaveSystem.instance != null)
{
var sg = SaveSystem.Serialize(); // SavedGameData
dsJson = sg != null ? JsonUtility.ToJson(sg) : null;
}
ES3.Save(K_DSJSON, dsJson, FILE, Settings);
#endif
}
public static bool LoadObjectives()
{
if (!ES3.FileExists(FILE)) return false;
try
{
// ObjectiveManager first (UI ready)
if (ObjectiveManager.Instance != null /* no KeyExists call here */)
{
// If the key doesn't exist, ES3 will throw; so catch and ignore.
if (ES3.KeyExists(K_Obj, new ES3Settings(FILE, Settings.encryptionType, Settings.encryptionPassword)))
{
var data = ES3.Load<ObjectiveManagerData>(K_Obj, FILE, Settings);
var om = ObjectiveManager.Instance;
om.objectives.Clear();
if (data.list != null)
foreach (var od in data.list)
om.objectives.Add(new ObjectiveManager.Objective { text = od.text, completed = od.completed });
om.activeIndex = Mathf.Clamp(data.activeIndex, 0, Math.Max(0, om.objectives.Count - 1));
om._queuedNextObjectives = data.queuedNextObjectives != null ? new List<string>(data.queuedNextObjectives) : null;
SetPrivate(om, "_queuedNextStartIndex", data.queuedNextStartIndex);
om.RefreshUI();
}
}
// GameplayManager
var gm = GameplayManager.Instance;
if (gm != null)
{
int idx = -1; bool run = false;
if (ES3.KeyExists(K_LevelIdx, new ES3Settings(FILE, Settings.encryptionType, Settings.encryptionPassword)))
idx = ES3.Load<int>(K_LevelIdx, FILE, Settings);
if (ES3.KeyExists(K_IsRunning, new ES3Settings(FILE, Settings.encryptionType, Settings.encryptionPassword)))
run = ES3.Load<bool>(K_IsRunning, FILE, Settings);
idx = Mathf.Clamp(idx, -1, gm.levels.Count - 1);
if (run && idx >= 0) gm.StartLevel(idx);
else
{
int next = idx < 0 ? 0 : Mathf.Min(idx + 1, gm.levels.Count - 1);
InvokePrivate(gm, "EnableOnlyTrigger", new object[] { next });
//if (gm.levels != null && gm.levels.Count > 0 && ObjectiveManager.Instance != null)
//{
// int upcoming = Mathf.Clamp(next, 0, gm.levels.Count - 1);
// var upcomingLevel = gm.levels[upcoming];
// if (upcomingLevel != null && upcomingLevel.config != null)
// ObjectiveManager.Instance.SetList(upcomingLevel.config.objectives, upcomingLevel.config.startObjectiveIndex);
//}
}
}
//if (ActivatorManager.Instance != null)
//{
// try
// {
// if (ES3.KeyExists(K_ActStep, new ES3Settings(FILE, Settings.encryptionType, Settings.encryptionPassword)))
// {
// var savedStep = ES3.Load<int>(K_ActStep, FILE, Settings);
// // Set the index:
// ActivatorManager.Instance.stepIndex = Mathf.Max(0, savedStep);
// // Optional: rebuild world state by replaying events 0..stepIndex
// // Comment out if you DON'T want to auto-replay.
// ActivatorManager.Instance.ReplayTo(ActivatorManager.Instance.stepIndex);
// }
// }
// catch { /* older saves may not have this key; ignore */ }
//}
#if USE_PIXELCRUSHERS
if (ES3.KeyExists(K_DSJSON, new ES3Settings(FILE, Settings.encryptionType, Settings.encryptionPassword)))
{
var dsJson = ES3.Load<string>(K_DSJSON, FILE, Settings);
if (!string.IsNullOrEmpty(dsJson) && SaveSystem.instance != null)
{
var sg = JsonUtility.FromJson<SavedGameData>(dsJson);
SaveSystem.ApplySavedGameData(sg);
}
}
#endif
Debug.Log("[Save] Loaded save.es3");
return true;
}
catch (System.Exception ex)
{
Debug.LogError($"[Save] Load failed: {ex.Message}\n" +
"If you changed encryption or reused an old non-ES3 file, delete save.es3 and save again.");
return false;
}
}
public static bool Load()
{
if (ActivatorManager.Instance != null)
{
ActivatorManager.Instance.stepIndex = PlayerPrefs.GetInt("StepIndex", 0);
Debug.Log("Step index: " + ActivatorManager.Instance.stepIndex);
ActivatorManager.Instance.ReplayTo(ActivatorManager.Instance.stepIndex);
return true;
}
return false;
}
public static void Delete()
{
if (ES3.FileExists(FILE)) ES3.DeleteFile(FILE);
}
// ---- reflection helpers (so you don<6F>t edit your classes) ----
private static T GetPrivate<T>(object obj, string field)
{
var f = obj.GetType().GetField(field, BindingFlags.Instance | BindingFlags.NonPublic);
return f != null ? (T)f.GetValue(obj) : default;
}
private static void SetPrivate(object obj, string field, object value)
{
var f = obj.GetType().GetField(field, BindingFlags.Instance | BindingFlags.NonPublic);
if (f != null) f.SetValue(obj, value);
}
private static void InvokePrivate(object obj, string method, object[] args)
{
var m = obj.GetType().GetMethod(method, BindingFlags.Instance | BindingFlags.NonPublic);
m?.Invoke(obj, args);
}
}