test(fix-system): 扩展佩佩开发档读档跳转菜单
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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<PeipeiMemoryJumpTool>();
|
||||
}
|
||||
@@ -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<MemoryProcess>() != null
|
||||
&& FixPanelSystem.GetRepairPanel<CablePanel>() != 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<PunchTape>(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
|
||||
|
||||
Reference in New Issue
Block a user