using System; using System.IO; using UnityEngine; using UnityEngine.SceneManagement; public partial class PlayerPoseController { // --- Persistence: the selected pose index --- // // Saved on quit / play-stop and restored on the next start, so the player keeps the pose they // had selected. Mirrors the project's other X.Persistence.cs partials (small JSON state under // the shared MeshPaint folder). [Header("Persistence")] [Tooltip("Save the selected pose index on quit / play-stop and restore it on the next start. " + "Off = the selection starts at the default pose.")] public bool persistPose = true; [Tooltip("Save file identifier. Empty = derived from the active scene + object name. Set " + "explicitly to keep a save stable across object renames.")] public string poseSaveId = ""; private const int PoseFileVersion = 1; private bool _poseSavedOnTeardown; // guards a double save across OnApplicationQuit + OnDestroy private static string PoseSaveDir => Path.Combine(Application.persistentDataPath, "MeshPaint"); private string PoseSavePath() { string key = string.IsNullOrEmpty(poseSaveId) ? SanitizePoseKey(SceneManager.GetActiveScene().name + "_" + gameObject.name) : SanitizePoseKey(poseSaveId); return Path.Combine(PoseSaveDir, key + ".pose"); } private static string SanitizePoseKey(string s) { foreach (char c in Path.GetInvalidFileNameChars()) s = s.Replace(c, '_'); return s.Replace(' ', '_'); } [Serializable] private class PoseState { public int version = PoseFileVersion; public int index; } void Start() => RestorePoseState(); private void OnApplicationQuit() => SavePoseOnTeardown(); private void OnDestroy() => SavePoseOnTeardown(); /// Saves once during teardown (OnApplicationQuit and OnDestroy both call this; only the first writes). private void SavePoseOnTeardown() { if (_poseSavedOnTeardown) return; _poseSavedOnTeardown = true; SavePoseState(); } /// Writes the current pose index to disk. public void SavePoseState() { if (!persistPose) return; try { var state = new PoseState { index = _currentIndex }; Directory.CreateDirectory(PoseSaveDir); File.WriteAllText(PoseSavePath(), JsonUtility.ToJson(state, true)); } catch (Exception e) { Debug.LogWarning($"[PlayerPoseController] Saving pose state failed: {e.Message}", this); } } /// Restores the saved pose index, or does nothing if there is no save. private void RestorePoseState() { if (!persistPose) return; var state = LoadPoseState(); if (state == null) return; SetPoseIndex(state.index); } private PoseState LoadPoseState() { string path = PoseSavePath(); if (!File.Exists(path)) return null; try { var state = JsonUtility.FromJson(File.ReadAllText(path)); if (state == null || state.version != PoseFileVersion) return null; return state; } catch (Exception e) { Debug.LogWarning($"[PlayerPoseController] Loading pose state failed: {e.Message}", this); return null; } } /// Deletes the saved pose state (next start uses the default pose). Editor convenience. [ContextMenu("Clear Saved Pose State")] public void ClearSavedPoseState() { try { string path = PoseSavePath(); if (File.Exists(path)) File.Delete(path); Debug.Log($"[PlayerPoseController] Cleared saved pose state: {path}", this); } catch (Exception e) { Debug.LogWarning($"[PlayerPoseController] Clearing saved pose state failed: {e.Message}", this); } } }