From c05fe41ca9e0a3fb97d3d61a5826625423b7d8ef Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Tue, 3 Nov 2026 12:08:51 +0800 Subject: [PATCH] Magnifier inspection view for graphics cards Cards are inspectable. While the magnifier inspection tray shows a card, a mod-owned panel under the tray draws the card enlarged with its appearance overlays and a turn-over button. No Harmony patches: a resident component watches the inspection manager. Co-Authored-By: Claude Sonnet 5.5 --- src/Decentralized/DealerStock.cs | 15 +++ src/Decentralized/GpuInspectView.cs | 113 ++++++++++++++++++ src/Decentralized/Items.cs | 52 +++++--- src/Decentralized/ModEntry.cs | 2 + .../ModFiles/Localization/en.csv | 2 + .../ModFiles/Localization/zh.csv | 2 + 6 files changed, 169 insertions(+), 17 deletions(-) create mode 100644 src/Decentralized/GpuInspectView.cs diff --git a/src/Decentralized/DealerStock.cs b/src/Decentralized/DealerStock.cs index c2f687c..c850545 100644 --- a/src/Decentralized/DealerStock.cs +++ b/src/Decentralized/DealerStock.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using UnityEngine; using Decentralized.Domain; namespace Decentralized @@ -23,6 +24,20 @@ namespace Decentralized Items.Give(Items.NewCard("RZ6800", 30, "RZ580", rng)); Items.Give(Items.NewCard("RZ7900", 90, "RZ470", rng)); }); + ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Dump inspection UI (test)", () => Log.Guard("检视界面结构", () => + { + var sb = new System.Text.StringBuilder("\n"); + void Walk(Transform t, int depth) + { + var rt = t as RectTransform; + var img = t.GetComponent(); + sb.AppendLine($"{new string(' ', depth * 2)}{t.name} active={t.gameObject.activeSelf} pos={t.localPosition} size={(rt != null ? rt.sizeDelta.ToString() : "-")} scale={t.localScale}{(img != null ? " img=" + (img.sprite != null ? img.sprite.name : "null") : "")}"); + if (depth < 5) foreach (Transform c in t) Walk(c, depth + 1); + } + var m = InspectionUIManager.Instance; + Walk(m.panel.transform, 0); + Log.Info(sb.ToString()); + })); ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Dr. Jackson stock (test)", () => { EmporiumEntry.Instance.ClearFrontInv(); diff --git a/src/Decentralized/GpuInspectView.cs b/src/Decentralized/GpuInspectView.cs new file mode 100644 index 0000000..718be50 --- /dev/null +++ b/src/Decentralized/GpuInspectView.cs @@ -0,0 +1,113 @@ +using System.Collections.Generic; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace Decentralized +{ + /// + /// 放大镜检视显卡时的大图:和香烟一样把物品放大摆在检视台上,正反面各一张,看外观自己判断真假。 + /// 游戏没有给 mod 开放检视界面,这里不打补丁,只在检视台(InspectionUIManager.panel)下面挂一个自己的界面, + /// 用一个常驻的 MonoBehaviour 每帧看一眼是否正在检视显卡。 + /// + public sealed class GpuInspectView : MonoBehaviour + { + private static GpuInspectView instance; + private RectTransform root, cardRoot; + private Button flip; + private TextMeshProUGUI flipText; + private GameItem shown; + private string shownSig; + + public static void Ensure() + { + if (instance != null) return; + var go = new GameObject("pd_gpu_inspect_view"); + DontDestroyOnLoad(go); + instance = go.AddComponent(); + } + + public static void Remove() + { + if (instance != null) Destroy(instance.gameObject); + instance = null; + } + + private void Update() + { + var m = InspectionUIManager.Instance; + var item = m != null && m.panel != null && m.panel.activeSelf ? m.currentInspectingItem : null; + if (item == null || !Items.IsGpu(item)) + { + if (root != null && root.gameObject.activeSelf) root.gameObject.SetActive(false); + shown = null; + return; + } + Log.Guard("显卡检视大图", () => + { + if (root == null) Build(m); + if (!root.gameObject.activeSelf) root.gameObject.SetActive(true); + var keys = new List(); + string sig = Items.LookKeys(item, keys) + "|" + string.Join(",", keys); + if (item != shown || sig != shownSig) + { + shown = item; + shownSig = sig; + Redraw(item); + } + }); + } + + private void Build(InspectionUIManager m) + { + root = new GameObject("_PdGpuInspection", typeof(RectTransform)).GetComponent(); + root.SetParent(m.panel.transform, false); + root.sizeDelta = new Vector2(1920, 1080); + root.localPosition = Vector3.zero; + cardRoot = new GameObject("Card", typeof(RectTransform)).GetComponent(); + cardRoot.SetParent(root, false); + cardRoot.localPosition = new Vector3(0, 40, 0); + // 翻面按钮:复制鉴定面板里"发送"按钮的外观 + var template = m.appraisalPanel.transform.Find("buttonSend"); + if (template != null) + { + var go = Instantiate(template.gameObject, root, false); + go.name = "Flip"; + go.transform.localPosition = new Vector3(0, -300, 0); + flip = go.GetComponent