229 lines
9.1 KiB
C#
229 lines
9.1 KiB
C#
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);
|
||
}
|
||
}
|