diff --git a/Assets/Scripts/Utility/PeipeiMemoryJumpTool.cs b/Assets/Scripts/Utility/PeipeiMemoryJumpTool.cs index f372e277a..4006c9357 100644 --- a/Assets/Scripts/Utility/PeipeiMemoryJumpTool.cs +++ b/Assets/Scripts/Utility/PeipeiMemoryJumpTool.cs @@ -1,33 +1,65 @@ #if UNITY_EDITOR || DEVELOPMENT_BUILD using System.Collections; -using System.Collections.Generic; -using AibisDream.Framework; -using AibisDream.FixSystem; +using System.IO; using AibisDream.SaveSystem; using UnityEngine; -using UnityEngine.SceneManagement; namespace AibisDream { public class PeipeiMemoryJumpTool : MonoBehaviour { - private const string TargetSceneKey = "Scene/PeipeiFixScene"; - private const string TargetSceneName = "PeipeiFixScene"; - private const float WaitTimeout = 15f; private const float UiMargin = 16f; private const float DevButtonWidth = 96f; private const float DevButtonHeight = 34f; - private const float CommandButtonWidth = 220f; - private const float CommandButtonHeight = 34f; + private const float MenuWidth = 300f; + private const float MaxMenuHeight = 560f; + private const float RowHeight = 30f; + private const float HeaderHeight = 24f; private const float StatusWidth = 360f; private const float StatusHeight = 28f; - private const int DevCommandCount = 1; + private const string SaveRootFolder = "AllOurBrokenParts"; + private const string TestSaveFolder = "testsavs"; + private const string SnapshotFileName = "snapshot"; - private static readonly PunchTape[] TestPunchTapes = + private static readonly DevSaveEntry[] Peipei1Saves = { - new("EyeView", "\u5929\u7a7a", "liuying1-3"), - new("EyeView", "\u6d77\u62a5", "liuying1-1"), - new("EyeView", "\u690d\u7269", "liuying1-2") + new("PP1 01 Intro", "20260629_191732_683_"), + new("PP1 02 Enter Room", "20260629_191737_198_"), + new("PP1 03 Body UF", "20260629_191745_604_"), + new("PP1 04 UF Deep", "20260629_191747_751_"), + new("PP1 05 Body Vision", "20260629_191751_564_"), + new("PP1 06 Memory Start", "20260629_191806_710_"), + new("PP1 07 Memory Check", "20260629_191807_884_"), + new("PP1 08 Analysis", "20260629_191947_383_"), + new("PP1 09 Pre Talk", "20260629_191953_429_"), + new("PP1 10 Surgery", "20260629_191957_937_"), + new("PP1 11 CutLine", "20260629_192000_426_"), + new("PP1 12 Recheck", "20260629_192000_744_"), + new("PP1 13 Recheck Vision", "20260629_192002_368_"), + new("PP1 14 Ending Talk", "20260629_192010_965_") + }; + + private static readonly DevSaveEntry[] Peipei2Saves = + { + new("PP2 01 Start", "20260630_142906_700_"), + new("PP2 02 Intro", "20260630_142906_849_"), + new("PP2 03 First Heat", "20260630_142915_334_"), + new("PP2 04 Heat System", "20260630_142918_072_"), + new("PP2 05 Body Check", "20260630_142921_707_"), + new("PP2 06 UF Locked", "20260630_142923_878_"), + new("PP2 07 UF Shell", "20260630_142928_045_"), + new("PP2 08 UF Check", "20260630_142931_587_"), + new("PP2 09 Eye View", "20260630_142938_533_"), + new("PP2 10 Analysis", "20260630_142956_453_"), + new("PP2 11 Pre Talk", "20260630_143007_149_"), + new("PP2 12 Stop Image", "20260630_143014_716_"), + new("PP2 13 Stop Check", "20260630_143020_779_"), + new("PP2 14 Cool Fail Talk", "20260630_143042_615_"), + new("PP2 15 Remove UF", "20260630_143043_024_"), + new("PP2 16 Pre Talk 2", "20260630_143044_410_"), + new("PP2 17 Surgery", "20260630_143058_329_"), + new("PP2 18 Memory Plugin", "20260630_143100_380_"), + new("PP2 19 Ending Talk", "20260630_143118_278_") }; private static PeipeiMemoryJumpTool instance; @@ -36,7 +68,9 @@ namespace AibisDream private bool menuOpen; private string status = ""; private float statusVisibleUntil; + private Vector2 menuScroll; private GUIStyle buttonStyle; + private GUIStyle headerStyle; private GUIStyle menuBoxStyle; private GUIStyle statusStyle; @@ -54,7 +88,7 @@ namespace AibisDream return; } - var toolObject = new GameObject("[Dev] Peipei Memory Jump Tool"); + var toolObject = new GameObject("[Dev] Peipei Jump Tool"); DontDestroyOnLoad(toolObject); instance = toolObject.AddComponent(); } @@ -92,23 +126,57 @@ namespace AibisDream private void DrawCommandMenu(Rect devButtonRect) { float menuHeight = GetMenuHeight(); - float menuX = Screen.width - UiMargin - CommandButtonWidth; - float menuY = devButtonRect.y - menuHeight - 8f; - var menuRect = new Rect(menuX, menuY, CommandButtonWidth, menuHeight); + float menuX = Screen.width - UiMargin - MenuWidth; + float menuY = Mathf.Max(UiMargin, devButtonRect.y - menuHeight - 8f); + var menuRect = new Rect(menuX, menuY, MenuWidth, menuHeight); GUI.Box(menuRect, GUIContent.none, menuBoxStyle); - var commandRect = new Rect( + var viewRect = new Rect(0f, 0f, MenuWidth - 28f, GetContentHeight()); + var scrollRect = new Rect( menuRect.x + 6f, menuRect.y + 6f, menuRect.width - 12f, - CommandButtonHeight); - DrawCommandButton(commandRect, "Jump: Peipei Memory", !isJumping, () => StartCoroutine(JumpToMemory())); + menuRect.height - 12f); + + menuScroll = GUI.BeginScrollView(scrollRect, menuScroll, viewRect); + + float y = 0f; + DrawHeader(ref y, "Peipei 1"); + DrawSaveEntries(ref y, Peipei1Saves); + y += 6f; + DrawHeader(ref y, "Peipei 2"); + DrawSaveEntries(ref y, Peipei2Saves); + + GUI.EndScrollView(); + } + + private void DrawHeader(ref float y, string label) + { + GUI.Label(new Rect(0f, y, MenuWidth - 32f, HeaderHeight), label, headerStyle); + y += HeaderHeight; + } + + private void DrawSaveEntries(ref float y, DevSaveEntry[] entries) + { + foreach (var entry in entries) + { + var rect = new Rect(0f, y, MenuWidth - 32f, RowHeight); + DrawCommandButton(rect, entry.Label, !isJumping, () => StartCoroutine(LoadDevSave(entry))); + y += RowHeight; + } } private static float GetMenuHeight() { - return DevCommandCount * CommandButtonHeight + 12f; + return Mathf.Min(MaxMenuHeight, GetContentHeight() + 12f); + } + + private static float GetContentHeight() + { + return HeaderHeight * 2f + + RowHeight * (Peipei1Saves.Length + Peipei2Saves.Length) + + 6f; } private void DrawCommandButton(Rect rect, string label, bool enabled, System.Action action) @@ -119,105 +187,90 @@ namespace AibisDream menuOpen = false; action?.Invoke(); } + GUI.enabled = true; } - private IEnumerator JumpToMemory() + private IEnumerator LoadDevSave(DevSaveEntry entry) { if (isJumping) yield break; - isJumping = true; - SetStatus("Preparing Peipei memory jump..."); - - BeginGameLoopForJump(); - StopCurrentDialog(); - - if (!IsPeipeiFixSceneLoaded()) + string savePath = ResolveSnapshotPath(entry); + if (string.IsNullOrEmpty(savePath)) { - if (SceneLoader.Instance == null) - { - SetStatus("Jump failed: SceneLoader is not ready.", 5f); - isJumping = false; - yield break; - } - - SetStatus("Loading Peipei fix scene..."); - yield return SceneLoader.Instance.LoadSceneAsync(TargetSceneKey); - } - - yield return null; - SetStatus("Waiting for fix systems..."); - bool ready = false; - float deadline = Time.unscaledTime + WaitTimeout; - while (Time.unscaledTime < deadline) - { - if (FixSystemCenter.Instance != null - && FixSystemCenter.Instance.IsDirectorReady - && FixSystemCenter.SystemDic.Get() != null - && FixPanelSystem.GetRepairPanel() != null) - { - ready = true; - break; - } - - yield return null; - } - - if (!ready) - { - SetStatus("Jump failed: Peipei memory systems were not ready.", 5f); - isJumping = false; + SetStatus($"Save missing: {entry.Label}", 5f); yield break; } - SeedTestPunchTapes(); - SetStatus("Entering memory module..."); - yield return FixSystemCenter.Instance.TransitionToImmediate(FixSceneMode.Memory); + isJumping = true; - PunchTapeManager.Instance.OpenFavoritesPanel(); - SetStatus("Peipei memory module is ready.", 3f); + if (NeedsResetToMainMenu()) + { + SetStatus($"Resetting: {entry.Label}"); + GameManager.Instance.QuitGame(); + yield return WaitForMainMenuReady(); + } + + SetStatus($"Loading: {entry.Label}"); + yield return SaveRestoreOrchestrator.RestoreFromFile(savePath); + SetStatus($"Loaded: {entry.Label}", 3f); isJumping = false; } - private static bool IsPeipeiFixSceneLoaded() + private static bool NeedsResetToMainMenu() { - if (SceneLoader.Instance != null && SceneLoader.Instance.CurrentSceneName == TargetSceneKey) - return true; - - return SceneManager.GetSceneByName(TargetSceneName).isLoaded; - } - - private static void BeginGameLoopForJump() - { - if (GameManager.Instance != null && GameManager.Instance.state.isInGame) - return; - - EnumEventSystem.Global.Send(GameLoopEnum.GameStart); - } - - private static void StopCurrentDialog() - { - if (DialogController.Instance != null && DialogController.Instance.DialogueRunner != null) - DialogController.Instance.StopDialog(); - else if (DialogUIManager.Instance != null) - DialogUIManager.Instance.HideDialog(); - } - - private static void SeedTestPunchTapes() - { - if (PunchTapeManager.Instance == null) - return; - - var snapshot = new PunchTapeSnapshotDto + var gameManager = GameManager.Instance; + if (gameManager == null) { - favorites = new List(TestPunchTapes.Length) - }; + return false; + } - foreach (var tape in TestPunchTapes) - snapshot.favorites.Add(new PunchTape(tape.Category, tape.ClueName, tape.MemoryIndex)); + if (gameManager.state.isInGame) + { + return true; + } - PunchTapeManager.Instance.ApplyPunchTapeSnapshot(snapshot); + var sceneLoader = SceneLoader.Instance; + return sceneLoader != null && !string.IsNullOrEmpty(sceneLoader.CurrentSceneName); + } + + private static IEnumerator WaitForMainMenuReady() + { + const float timeoutSeconds = 15f; + float elapsed = 0f; + + while (elapsed < timeoutSeconds) + { + var gameManager = GameManager.Instance; + var sceneLoader = SceneLoader.Instance; + bool sceneCleared = sceneLoader == null || string.IsNullOrEmpty(sceneLoader.CurrentSceneName); + bool notInGame = gameManager == null || !gameManager.state.isInGame; + + if (sceneCleared && notInGame) + { + yield break; + } + + elapsed += Time.unscaledDeltaTime; + yield return null; + } + + Debug.LogWarning("[PeipeiMemoryJumpTool] 等待主界面超时,继续读档。"); + } + + private static string ResolveSnapshotPath(DevSaveEntry entry) + { + string archiveRoot = Path.Combine(Application.persistentDataPath, SaveRootFolder, TestSaveFolder); + if (!Directory.Exists(archiveRoot)) + return null; + + var matches = Directory.GetDirectories(archiveRoot, entry.DirectoryPrefix + "*"); + if (matches.Length == 0) + return null; + + string path = Path.Combine(matches[0], SnapshotFileName); + return File.Exists(path + ".json") ? path : null; } private void SetStatus(string message, float visibleSeconds = 30f) @@ -234,10 +287,18 @@ namespace AibisDream buttonStyle = new GUIStyle(GUI.skin.button) { - fontSize = 15, + fontSize = 14, alignment = TextAnchor.MiddleCenter }; + headerStyle = new GUIStyle(GUI.skin.label) + { + fontSize = 13, + fontStyle = FontStyle.Bold, + alignment = TextAnchor.MiddleLeft, + padding = new RectOffset(6, 0, 3, 0) + }; + menuBoxStyle = new GUIStyle(GUI.skin.box) { padding = new RectOffset(6, 6, 6, 6) @@ -250,6 +311,18 @@ namespace AibisDream padding = new RectOffset(8, 8, 4, 4) }; } + + private readonly struct DevSaveEntry + { + public readonly string Label; + public readonly string DirectoryPrefix; + + public DevSaveEntry(string label, string directoryPrefix) + { + Label = label; + DirectoryPrefix = directoryPrefix; + } + } } } #endif