Files
bansonic_beta_main/Assets/scripts/UI/UnimplementedFeaturePrompt.cs
T

486 lines
16 KiB
C#

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class UnimplementedFeaturePrompt : MonoBehaviour
{
public static bool RuntimeEnabled = false;
private static UnimplementedFeaturePrompt instance;
[Header("Flash")]
[SerializeField] private int flashCount = 2;
[SerializeField] private float flashOnTime = 0.04f;
[SerializeField] private float flashOffTime = 0.03f;
private GameObject root;
private GameObject pressText;
private GameObject noChoice;
private GameObject choiceLessThanFive;
private GameObject image3;
private Button continueButton;
private Button considerButton;
private Button doNotShowAgainButton;
private Button okayButton;
private Coroutine flashRoutine;
public static void ShowPrompt()
{
if (!RuntimeEnabled)
return;
EnsureInstance();
if (instance != null)
instance.ShowInternal();
}
private static void EnsureInstance()
{
if (instance != null)
return;
GameObject host = SceneObjectLookupCache.Find("__UnimplementedFeaturePromptHost");
if (host == null)
{
host = new GameObject("__UnimplementedFeaturePromptHost");
DontDestroyOnLoad(host);
}
instance = host.GetComponent<UnimplementedFeaturePrompt>();
if (instance == null)
instance = host.AddComponent<UnimplementedFeaturePrompt>();
}
private void OnEnable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// Re-resolve references every scene so we can reuse existing UI if present.
root = null;
pressText = null;
noChoice = null;
choiceLessThanFive = null;
image3 = null;
continueButton = null;
considerButton = null;
doNotShowAgainButton = null;
okayButton = null;
}
private void ShowInternal()
{
EnsurePromptRoot();
if (root == null)
{
Debug.LogWarning("[UnimplementedFeaturePrompt] Prompt root was not found and fallback creation failed.");
return;
}
EnsureMinimumPromptElements();
BringRootToFront();
BindOkayButton();
root.SetActive(true);
CanvasGroup rootGroup = root.GetComponent<CanvasGroup>();
if (rootGroup != null)
rootGroup.alpha = 1f;
SetActiveSafe(noChoice, false);
SetActiveSafe(choiceLessThanFive, false);
SetActiveSafe(image3, false);
SetButtonVisible(continueButton, false);
SetButtonVisible(considerButton, false);
SetButtonVisible(doNotShowAgainButton, false);
SetButtonVisible(okayButton, true);
SetActiveSafe(pressText, true);
if (flashRoutine != null)
StopCoroutine(flashRoutine);
flashRoutine = StartCoroutine(FlashMessage());
}
private IEnumerator FlashMessage()
{
GameObject target = pressText != null ? pressText : root;
if (target == null)
yield break;
CanvasGroup cg = target.GetComponent<CanvasGroup>();
if (cg == null)
cg = target.AddComponent<CanvasGroup>();
int count = Mathf.Max(1, flashCount);
float onTime = Mathf.Clamp(flashOnTime, 0.01f, 0.05f);
float offTime = Mathf.Clamp(flashOffTime, 0.01f, 0.05f);
cg.alpha = 0f;
for (int i = 0; i < count; i++)
{
cg.alpha = 1f;
yield return new WaitForSecondsRealtime(onTime);
if (i < count - 1)
{
cg.alpha = 0f;
yield return new WaitForSecondsRealtime(offTime);
}
}
cg.alpha = 1f;
flashRoutine = null;
}
private void OnOkayClicked()
{
if (flashRoutine != null)
{
StopCoroutine(flashRoutine);
flashRoutine = null;
}
if (root != null)
root.SetActive(false);
}
private void BindOkayButton()
{
if (okayButton == null)
return;
okayButton.onClick.RemoveListener(OnOkayClicked);
okayButton.onClick.AddListener(OnOkayClicked);
}
private void EnsurePromptRoot()
{
Scene activeScene = SceneManager.GetActiveScene();
if (root != null && root.scene.IsValid() && root.scene == activeScene)
return;
root = FindSceneObjectByExactName("\uFF01mustselectyouridol");
if (root == null)
root = FindSceneObjectByContainsName("mustselectyouridol");
if (root == null)
root = CreateFallbackPrompt();
if (root == null)
return;
pressText = FindChildByName(root.transform, "Press an unimplemented feature");
if (pressText == null)
pressText = FindChildByName(root.transform, "pressanunimplementedfeature");
noChoice = FindChildByName(root.transform, "No choice");
choiceLessThanFive = FindChildByName(root.transform, "choice < 5");
image3 = FindChildByName(root.transform, "Image (3)");
continueButton = FindButtonByName(root.transform, "Continue");
considerButton = FindButtonByName(root.transform, "Consider");
doNotShowAgainButton = FindButtonByName(root.transform, "Do not show again");
okayButton = FindButtonByName(root.transform, "okay");
if (okayButton == null)
okayButton = FindButtonByContainsName(root.transform, "ok");
}
private GameObject CreateFallbackPrompt()
{
Canvas canvas = FindTopCanvasInActiveScene();
if (canvas == null)
canvas = CreateFallbackCanvas();
if (canvas == null)
return null;
GameObject rootGo = new GameObject("\uFF01mustselectyouridol", typeof(RectTransform), typeof(CanvasGroup), typeof(Image));
rootGo.transform.SetParent(canvas.transform, false);
RectTransform rootRt = rootGo.GetComponent<RectTransform>();
rootRt.anchorMin = Vector2.zero;
rootRt.anchorMax = Vector2.one;
rootRt.offsetMin = Vector2.zero;
rootRt.offsetMax = Vector2.zero;
Image bg = rootGo.GetComponent<Image>();
bg.color = new Color(0f, 0f, 0f, 0.35f);
GameObject textGo = new GameObject("Press an unimplemented feature", typeof(RectTransform), typeof(Text));
textGo.transform.SetParent(rootGo.transform, false);
RectTransform textRt = textGo.GetComponent<RectTransform>();
textRt.anchorMin = new Vector2(0.5f, 0.5f);
textRt.anchorMax = new Vector2(0.5f, 0.5f);
textRt.sizeDelta = new Vector2(820f, 80f);
textRt.anchoredPosition = new Vector2(0f, 40f);
Text t = textGo.GetComponent<Text>();
t.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
t.fontSize = 40;
t.alignment = TextAnchor.MiddleCenter;
t.color = Color.white;
t.text = "Press an unimplemented feature";
GameObject okayGo = new GameObject("okay", typeof(RectTransform), typeof(Image), typeof(Button));
okayGo.transform.SetParent(rootGo.transform, false);
RectTransform okayRt = okayGo.GetComponent<RectTransform>();
okayRt.anchorMin = new Vector2(0.5f, 0.5f);
okayRt.anchorMax = new Vector2(0.5f, 0.5f);
okayRt.sizeDelta = new Vector2(200f, 60f);
okayRt.anchoredPosition = new Vector2(0f, -40f);
Image okBg = okayGo.GetComponent<Image>();
okBg.color = Color.white;
GameObject okayTextGo = new GameObject("Text (Legacy)", typeof(RectTransform), typeof(Text));
okayTextGo.transform.SetParent(okayGo.transform, false);
RectTransform okayTextRt = okayTextGo.GetComponent<RectTransform>();
okayTextRt.anchorMin = Vector2.zero;
okayTextRt.anchorMax = Vector2.one;
okayTextRt.offsetMin = Vector2.zero;
okayTextRt.offsetMax = Vector2.zero;
Text okText = okayTextGo.GetComponent<Text>();
okText.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
okText.fontSize = 30;
okText.alignment = TextAnchor.MiddleCenter;
okText.color = new Color(0.23f, 0.23f, 0.23f, 1f);
okText.text = "okay";
return rootGo;
}
private static void SetButtonVisible(Button button, bool visible)
{
if (button != null)
button.gameObject.SetActive(visible);
}
private static void SetActiveSafe(GameObject go, bool active)
{
if (go != null)
go.SetActive(active);
}
private static GameObject FindSceneObjectByExactName(string objectName)
{
if (string.IsNullOrEmpty(objectName))
return null;
Scene scene = SceneManager.GetActiveScene();
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
Transform t = all[i];
if (t == null || t.gameObject.scene != scene)
continue;
if (string.Equals(t.name, objectName, System.StringComparison.OrdinalIgnoreCase))
return t.gameObject;
}
return null;
}
private static GameObject FindSceneObjectByContainsName(string token)
{
if (string.IsNullOrEmpty(token))
return null;
Scene scene = SceneManager.GetActiveScene();
Transform[] all = UnityEngine.Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < all.Length; i++)
{
Transform t = all[i];
if (t == null || t.gameObject.scene != scene)
continue;
if (t.name.IndexOf(token, System.StringComparison.OrdinalIgnoreCase) >= 0)
return t.gameObject;
}
return null;
}
private static GameObject FindChildByName(Transform root, string childName)
{
if (root == null || string.IsNullOrEmpty(childName))
return null;
Transform[] children = root.GetComponentsInChildren<Transform>(true);
for (int i = 0; i < children.Length; i++)
{
Transform c = children[i];
if (c != null && string.Equals(c.name, childName, System.StringComparison.OrdinalIgnoreCase))
return c.gameObject;
}
return null;
}
private static Button FindButtonByName(Transform root, string buttonName)
{
if (root == null || string.IsNullOrEmpty(buttonName))
return null;
Button[] buttons = root.GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
Button b = buttons[i];
if (b != null && string.Equals(b.name, buttonName, System.StringComparison.OrdinalIgnoreCase))
return b;
}
return null;
}
private static Button FindButtonByContainsName(Transform root, string token)
{
if (root == null || string.IsNullOrEmpty(token))
return null;
string normalizedToken = token.Replace(" ", "").ToLowerInvariant();
Button[] buttons = root.GetComponentsInChildren<Button>(true);
for (int i = 0; i < buttons.Length; i++)
{
Button b = buttons[i];
if (b == null)
continue;
string current = b.name.Replace(" ", "").ToLowerInvariant();
if (current.Contains(normalizedToken))
return b;
}
return null;
}
private static Canvas FindTopCanvasInActiveScene()
{
Scene scene = SceneManager.GetActiveScene();
Canvas[] canvases = UnityEngine.Object.FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.None);
Canvas best = null;
int bestOrder = int.MinValue;
for (int i = 0; i < canvases.Length; i++)
{
Canvas c = canvases[i];
if (c == null || c.gameObject.scene != scene)
continue;
int order = c.sortingOrder;
if (c.renderMode == RenderMode.ScreenSpaceOverlay)
order += 10000;
if (best == null || order > bestOrder)
{
best = c;
bestOrder = order;
}
}
return best;
}
private static Canvas CreateFallbackCanvas()
{
Scene scene = SceneManager.GetActiveScene();
if (!scene.IsValid() || !scene.isLoaded)
return null;
GameObject go = new GameObject("__UnimplementedPromptCanvas",
typeof(RectTransform),
typeof(Canvas),
typeof(CanvasScaler),
typeof(GraphicRaycaster));
try
{
SceneManager.MoveGameObjectToScene(go, scene);
}
catch
{
// keep default scene placement if move fails
}
Canvas canvas = go.GetComponent<Canvas>();
if (canvas != null)
{
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = 32700;
}
CanvasScaler scaler = go.GetComponent<CanvasScaler>();
if (scaler != null)
{
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920f, 1080f);
scaler.matchWidthOrHeight = 0.5f;
}
return canvas;
}
private void EnsureMinimumPromptElements()
{
if (root == null)
return;
if (pressText == null)
{
GameObject textGo = new GameObject("Press an unimplemented feature", typeof(RectTransform), typeof(Text));
textGo.transform.SetParent(root.transform, false);
RectTransform textRt = textGo.GetComponent<RectTransform>();
textRt.anchorMin = new Vector2(0.5f, 0.5f);
textRt.anchorMax = new Vector2(0.5f, 0.5f);
textRt.sizeDelta = new Vector2(820f, 80f);
textRt.anchoredPosition = new Vector2(0f, 40f);
Text t = textGo.GetComponent<Text>();
t.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
t.fontSize = 40;
t.alignment = TextAnchor.MiddleCenter;
t.color = Color.white;
t.text = "Press an unimplemented feature";
pressText = textGo;
}
if (okayButton == null)
{
GameObject okayGo = new GameObject("okay", typeof(RectTransform), typeof(Image), typeof(Button));
okayGo.transform.SetParent(root.transform, false);
RectTransform okayRt = okayGo.GetComponent<RectTransform>();
okayRt.anchorMin = new Vector2(0.5f, 0.5f);
okayRt.anchorMax = new Vector2(0.5f, 0.5f);
okayRt.sizeDelta = new Vector2(200f, 60f);
okayRt.anchoredPosition = new Vector2(0f, -40f);
Image okBg = okayGo.GetComponent<Image>();
okBg.color = Color.white;
GameObject textGo = new GameObject("Text (Legacy)", typeof(RectTransform), typeof(Text));
textGo.transform.SetParent(okayGo.transform, false);
RectTransform textRt = textGo.GetComponent<RectTransform>();
textRt.anchorMin = Vector2.zero;
textRt.anchorMax = Vector2.one;
textRt.offsetMin = Vector2.zero;
textRt.offsetMax = Vector2.zero;
Text t = textGo.GetComponent<Text>();
t.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
t.fontSize = 30;
t.alignment = TextAnchor.MiddleCenter;
t.color = new Color(0.23f, 0.23f, 0.23f, 1f);
t.text = "okay";
okayButton = okayGo.GetComponent<Button>();
}
}
private void BringRootToFront()
{
if (root == null)
return;
Canvas canvas = root.GetComponent<Canvas>();
if (canvas == null)
canvas = root.AddComponent<Canvas>();
if (root.GetComponent<GraphicRaycaster>() == null)
root.AddComponent<GraphicRaycaster>();
canvas.overrideSorting = true;
canvas.sortingOrder = 32700;
if (root.transform.parent != null)
root.transform.SetAsLastSibling();
}
}