Files
aibis-dream/Assets/Scripts/Utility/PeipeiMemoryJumpTool.cs
T

256 lines
8.5 KiB
C#

#if UNITY_EDITOR || DEVELOPMENT_BUILD
using System.Collections;
using System.Collections.Generic;
using AibisDream.Framework;
using AibisDream.FixSystem;
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 StatusWidth = 360f;
private const float StatusHeight = 28f;
private const int DevCommandCount = 1;
private static readonly PunchTape[] TestPunchTapes =
{
new("EyeView", "\u5929\u7a7a", "liuying1-3"),
new("EyeView", "\u6d77\u62a5", "liuying1-1"),
new("EyeView", "\u690d\u7269", "liuying1-2")
};
private static PeipeiMemoryJumpTool instance;
private bool isJumping;
private bool menuOpen;
private string status = "";
private float statusVisibleUntil;
private GUIStyle buttonStyle;
private GUIStyle menuBoxStyle;
private GUIStyle statusStyle;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void Bootstrap()
{
if (instance != null)
return;
var existing = FindObjectOfType<PeipeiMemoryJumpTool>();
if (existing != null)
{
instance = existing;
DontDestroyOnLoad(existing.gameObject);
return;
}
var toolObject = new GameObject("[Dev] Peipei Memory Jump Tool");
DontDestroyOnLoad(toolObject);
instance = toolObject.AddComponent<PeipeiMemoryJumpTool>();
}
private void OnGUI()
{
EnsureStyles();
float buttonX = Screen.width - UiMargin - DevButtonWidth;
float buttonY = Screen.height - UiMargin - DevButtonHeight;
var devButtonRect = new Rect(buttonX, buttonY, DevButtonWidth, DevButtonHeight);
if (menuOpen)
DrawCommandMenu(devButtonRect);
string label = isJumping ? "Busy..." : "Dev";
if (GUI.Button(devButtonRect, label, buttonStyle))
menuOpen = !menuOpen;
if (!string.IsNullOrEmpty(status) && Time.unscaledTime < statusVisibleUntil)
{
float menuHeight = GetMenuHeight();
float statusY = menuOpen
? buttonY - menuHeight - StatusHeight - UiMargin
: buttonY - StatusHeight - 8f;
var statusRect = new Rect(
Screen.width - UiMargin - StatusWidth,
Mathf.Max(UiMargin, statusY),
StatusWidth,
StatusHeight);
GUI.Label(statusRect, status, statusStyle);
}
}
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);
GUI.Box(menuRect, GUIContent.none, menuBoxStyle);
var commandRect = new Rect(
menuRect.x + 6f,
menuRect.y + 6f,
menuRect.width - 12f,
CommandButtonHeight);
DrawCommandButton(commandRect, "Jump: Peipei Memory", !isJumping, () => StartCoroutine(JumpToMemory()));
}
private static float GetMenuHeight()
{
return DevCommandCount * CommandButtonHeight + 12f;
}
private void DrawCommandButton(Rect rect, string label, bool enabled, System.Action action)
{
GUI.enabled = enabled;
if (GUI.Button(rect, label, buttonStyle))
{
menuOpen = false;
action?.Invoke();
}
GUI.enabled = true;
}
private IEnumerator JumpToMemory()
{
if (isJumping)
yield break;
isJumping = true;
SetStatus("Preparing Peipei memory jump...");
BeginGameLoopForJump();
StopCurrentDialog();
if (!IsPeipeiFixSceneLoaded())
{
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;
yield break;
}
SeedTestPunchTapes();
SetStatus("Entering memory module...");
yield return FixSystemCenter.Instance.TransitionToImmediate(FixSceneMode.Memory);
PunchTapeManager.Instance.OpenFavoritesPanel();
SetStatus("Peipei memory module is ready.", 3f);
isJumping = false;
}
private static bool IsPeipeiFixSceneLoaded()
{
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
{
favorites = new List<PunchTape>(TestPunchTapes.Length)
};
foreach (var tape in TestPunchTapes)
snapshot.favorites.Add(new PunchTape(tape.Category, tape.ClueName, tape.MemoryIndex));
PunchTapeManager.Instance.ApplyPunchTapeSnapshot(snapshot);
}
private void SetStatus(string message, float visibleSeconds = 30f)
{
status = message;
statusVisibleUntil = Time.unscaledTime + visibleSeconds;
Debug.Log($"[PeipeiMemoryJumpTool] {message}");
}
private void EnsureStyles()
{
if (buttonStyle != null && statusStyle != null)
return;
buttonStyle = new GUIStyle(GUI.skin.button)
{
fontSize = 15,
alignment = TextAnchor.MiddleCenter
};
menuBoxStyle = new GUIStyle(GUI.skin.box)
{
padding = new RectOffset(6, 6, 6, 6)
};
statusStyle = new GUIStyle(GUI.skin.box)
{
fontSize = 13,
alignment = TextAnchor.MiddleLeft,
padding = new RectOffset(8, 8, 4, 4)
};
}
}
}
#endif