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 <noreply@anthropic.com>
This commit is contained in:
1 parent
e643332a41
commit
c05fe41ca9
6 files changed
+169
-17
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
using Decentralized.Domain;
|
using Decentralized.Domain;
|
||||||
|
|
||||||
namespace Decentralized
|
namespace Decentralized
|
||||||
@@ -23,6 +24,20 @@ namespace Decentralized
|
|||||||
Items.Give(Items.NewCard("RZ6800", 30, "RZ580", rng));
|
Items.Give(Items.NewCard("RZ6800", 30, "RZ580", rng));
|
||||||
Items.Give(Items.NewCard("RZ7900", 90, "RZ470", 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<UnityEngine.UI.Image>();
|
||||||
|
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)", () =>
|
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Dr. Jackson stock (test)", () =>
|
||||||
{
|
{
|
||||||
EmporiumEntry.Instance.ClearFrontInv();
|
EmporiumEntry.Instance.ClearFrontInv();
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Decentralized
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 放大镜检视显卡时的大图:和香烟一样把物品放大摆在检视台上,正反面各一张,看外观自己判断真假。
|
||||||
|
/// 游戏没有给 mod 开放检视界面,这里不打补丁,只在检视台(InspectionUIManager.panel)下面挂一个自己的界面,
|
||||||
|
/// 用一个常驻的 MonoBehaviour 每帧看一眼是否正在检视显卡。
|
||||||
|
/// </summary>
|
||||||
|
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<GpuInspectView>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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>();
|
||||||
|
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<RectTransform>();
|
||||||
|
root.SetParent(m.panel.transform, false);
|
||||||
|
root.sizeDelta = new Vector2(1920, 1080);
|
||||||
|
root.localPosition = Vector3.zero;
|
||||||
|
cardRoot = new GameObject("Card", typeof(RectTransform)).GetComponent<RectTransform>();
|
||||||
|
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<Button>();
|
||||||
|
flip.onClick = new Button.ButtonClickedEvent();
|
||||||
|
flip.onClick.AddListener(() => { if (shown != null) Items.Flip(shown); });
|
||||||
|
flipText = go.GetComponentInChildren<TextMeshProUGUI>();
|
||||||
|
// 去掉复制来的按钮上驱动文字的组件(本地化 / 提交逻辑),文字由这里设置
|
||||||
|
foreach (var mb in go.GetComponentsInChildren<MonoBehaviour>(true))
|
||||||
|
{
|
||||||
|
string n = mb.GetType().Name;
|
||||||
|
if (mb is Button || mb is Image || mb is TextMeshProUGUI || mb is CanvasRenderer) continue;
|
||||||
|
if (n.Contains("Local") || n.Contains("Appraisal") || n.Contains("Send")) Destroy(mb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Redraw(GameItem item)
|
||||||
|
{
|
||||||
|
foreach (Transform c in cardRoot) Destroy(c.gameObject);
|
||||||
|
var keys = new List<string>();
|
||||||
|
string baseKey = Items.LookKeys(item, keys);
|
||||||
|
keys.Insert(0, baseKey);
|
||||||
|
foreach (var k in keys)
|
||||||
|
{
|
||||||
|
var sprite = Items.ModSprite(k);
|
||||||
|
if (sprite == null) continue;
|
||||||
|
var go = new GameObject(k, typeof(RectTransform), typeof(Image));
|
||||||
|
var rt = go.GetComponent<RectTransform>();
|
||||||
|
rt.SetParent(cardRoot, false);
|
||||||
|
rt.sizeDelta = new Vector2(sprite.rect.width, sprite.rect.height);
|
||||||
|
rt.localScale = Vector3.one * 14f;
|
||||||
|
var img = go.GetComponent<Image>();
|
||||||
|
img.sprite = sprite;
|
||||||
|
img.raycastTarget = false;
|
||||||
|
}
|
||||||
|
if (flipText != null) flipText.text = L.T(Items.IsBack(item) ? "inspect.flip.front" : "inspect.flip.back");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
-17
@@ -70,6 +70,7 @@ namespace Decentralized
|
|||||||
{
|
{
|
||||||
var item = ItemDirectory.CreateEmptyItem(GpuId(spec.Model));
|
var item = ItemDirectory.CreateEmptyItem(GpuId(spec.Model));
|
||||||
item.SetGameItemType("MATERIAL");
|
item.SetGameItemType("MATERIAL");
|
||||||
|
InspectableHelper.InitInspectableItem(item);
|
||||||
item.onLoaded = Refresh;
|
item.onLoaded = Refresh;
|
||||||
// 右键"切换"翻面;外观差异用叠加图画在同一张底图上
|
// 右键"切换"翻面;外观差异用叠加图画在同一张底图上
|
||||||
item.EnableTag(ToggleAppearanceHelper.TOGGLE_APPEARANCE_TAG);
|
item.EnableTag(ToggleAppearanceHelper.TOGGLE_APPEARANCE_TAG);
|
||||||
@@ -77,8 +78,7 @@ namespace Decentralized
|
|||||||
item.canToggleSlotItemFunc = (_, _, _) => true;
|
item.canToggleSlotItemFunc = (_, _, _) => true;
|
||||||
item.onToggleSlotItemFunc = (toggled, _, _) => Log.Guard("显卡翻面", () =>
|
item.onToggleSlotItemFunc = (toggled, _, _) => Log.Guard("显卡翻面", () =>
|
||||||
{
|
{
|
||||||
if (toggled.IsTag(BackTag)) toggled.ModifyTag(BackTag, t => t.Disable()); else toggled.EnableTag(BackTag);
|
Flip(toggled);
|
||||||
Refresh(toggled);
|
|
||||||
});
|
});
|
||||||
item.getItemSpriteModifierForItemFunc = Overlays;
|
item.getItemSpriteModifierForItemFunc = Overlays;
|
||||||
ModHelper.SetSource(item, ModInfo.Id, ModInfo.Name);
|
ModHelper.SetSource(item, ModInfo.Id, ModInfo.Name);
|
||||||
@@ -152,33 +152,51 @@ namespace Decentralized
|
|||||||
SyncValue(item);
|
SyncValue(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Sprite ModSprite(string key)
|
public static bool IsBack(GameItem item) => item.IsTag(BackTag);
|
||||||
|
|
||||||
|
public static void Flip(GameItem item)
|
||||||
{
|
{
|
||||||
var mod = ModLoader.Mods.Find(m => m.Manifest.ID.Equals(ModInfo.Id));
|
if (IsBack(item)) item.ModifyTag(BackTag, t => t.Disable()); else item.EnableTag(BackTag);
|
||||||
return mod != null && mod.Sprites.TryGetValue(key, out var sprite) ? sprite : null;
|
Refresh(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>外观叠加图:正面三个维度,背面丝印与贴纸;烧毁的卡不叠。</summary>
|
/// <summary>当前面的底图名与叠加图名:正面三个维度,背面丝印与贴纸;烧毁的卡不叠。</summary>
|
||||||
private static List<ItemSpriteModifier> Overlays(GameItem item)
|
public static string LookKeys(GameItem item, List<string> overlays)
|
||||||
{
|
{
|
||||||
var list = new List<ItemSpriteModifier>();
|
|
||||||
SyncValue(item); // 归属变化(买下)后价格随之变回真实价值
|
|
||||||
if (item.IsTag(DeadTag)) return list;
|
|
||||||
var u = ToUnit(item);
|
var u = ToUnit(item);
|
||||||
var keys = new List<string>();
|
bool back = IsBack(item);
|
||||||
if (!item.IsTag(BackTag))
|
string brand = u.Label.Brand == Hardware.Probidia ? "gpu_probidia" : "gpu_pmd";
|
||||||
|
if (u.Dead) return back ? "gpu_burnt_b" : "gpu_burnt_f";
|
||||||
|
if (!back)
|
||||||
{
|
{
|
||||||
if (u.Look.Fan > 0) keys.Add("gpu_ov_fan" + u.Look.Fan);
|
if (u.Look.Fan > 0) overlays.Add("gpu_ov_fan" + u.Look.Fan);
|
||||||
if (u.Look.Fingers > 0) keys.Add("gpu_ov_fin" + u.Look.Fingers);
|
if (u.Look.Fingers > 0) overlays.Add("gpu_ov_fin" + u.Look.Fingers);
|
||||||
if (u.Look.Bracket > 0) keys.Add("gpu_ov_brk" + u.Look.Bracket);
|
if (u.Look.Bracket > 0) overlays.Add("gpu_ov_brk" + u.Look.Bracket);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 丝印:0 标称型号;1 印的是真实芯片型号;2 标称型号但字歪(重印过)
|
// 丝印:0 标称型号;1 印的是真实芯片型号;2 标称型号但字歪(重印过)
|
||||||
string model = u.Look.Print == 1 && u.FakeOf != null ? u.FakeOf : u.Model;
|
string model = u.Look.Print == 1 && u.FakeOf != null ? u.FakeOf : u.Model;
|
||||||
keys.Add((u.Look.Print == 2 ? "gpu_ov_txs_" : "gpu_ov_txt_") + model.ToLowerInvariant());
|
overlays.Add((u.Look.Print == 2 ? "gpu_ov_txs_" : "gpu_ov_txt_") + model.ToLowerInvariant());
|
||||||
if (u.Look.Sticker > 0) keys.Add("gpu_ov_stk" + u.Look.Sticker);
|
if (u.Look.Sticker > 0) overlays.Add("gpu_ov_stk" + u.Look.Sticker);
|
||||||
}
|
}
|
||||||
|
return brand + (back ? "_b" : "_f");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Sprite ModSprite(string key)
|
||||||
|
{
|
||||||
|
var mod = ModLoader.Mods.Find(m => m.Manifest.ID.Equals(ModInfo.Id));
|
||||||
|
return mod != null && mod.Sprites.TryGetValue(key, out var sprite) ? sprite : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>物品栏里的外观叠加图。</summary>
|
||||||
|
private static List<ItemSpriteModifier> Overlays(GameItem item)
|
||||||
|
{
|
||||||
|
var list = new List<ItemSpriteModifier>();
|
||||||
|
SyncValue(item); // 归属变化(买下)后价格随之变回真实价值
|
||||||
|
if (item.IsTag(DeadTag)) return list;
|
||||||
|
var keys = new List<string>();
|
||||||
|
LookKeys(item, keys);
|
||||||
int priority = 0;
|
int priority = 0;
|
||||||
foreach (var k in keys)
|
foreach (var k in keys)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace Decentralized
|
|||||||
Night.Subscribe();
|
Night.Subscribe();
|
||||||
DealerStock.Subscribe();
|
DealerStock.Subscribe();
|
||||||
UsedDealerClient.Subscribe();
|
UsedDealerClient.Subscribe();
|
||||||
|
GpuInspectView.Ensure();
|
||||||
ModHook.OnGameLoadedLate += Session.Load;
|
ModHook.OnGameLoadedLate += Session.Load;
|
||||||
ModHook.OnNewGameStarted += OnNewGame;
|
ModHook.OnNewGameStarted += OnNewGame;
|
||||||
Log.Info($"{ModInfo.Name} {ModInfo.Version} 已启用");
|
Log.Info($"{ModInfo.Name} {ModInfo.Version} 已启用");
|
||||||
@@ -27,6 +28,7 @@ namespace Decentralized
|
|||||||
Night.Unsubscribe();
|
Night.Unsubscribe();
|
||||||
DealerStock.Unsubscribe();
|
DealerStock.Unsubscribe();
|
||||||
UsedDealerClient.Unsubscribe();
|
UsedDealerClient.Unsubscribe();
|
||||||
|
GpuInspectView.Remove();
|
||||||
ModHook.OnGameLoadedLate -= Session.Load;
|
ModHook.OnGameLoadedLate -= Session.Load;
|
||||||
ModHook.OnNewGameStarted -= OnNewGame;
|
ModHook.OnNewGameStarted -= OnNewGame;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,3 +66,5 @@ dealer.line1.3,"Picked these up on the road. First-hand price."
|
|||||||
dealer.line2.1,"See for yourself, turn them over and check the back."
|
dealer.line2.1,"See for yourself, turn them over and check the back."
|
||||||
dealer.line2.2,"No warranty. Look before you take."
|
dealer.line2.2,"No warranty. Look before you take."
|
||||||
dealer.line2.3,"Price is negotiable if you want them."
|
dealer.line2.3,"Price is negotiable if you want them."
|
||||||
|
inspect.flip.back,"Turn over"
|
||||||
|
inspect.flip.front,"Front side"
|
||||||
|
@@ -65,3 +65,5 @@ dealer.line1.3,"路上收来的货,一手价。"
|
|||||||
dealer.line2.1,"自己看,背面也翻过来看。"
|
dealer.line2.1,"自己看,背面也翻过来看。"
|
||||||
dealer.line2.2,"不保修,看好了再拿。"
|
dealer.line2.2,"不保修,看好了再拿。"
|
||||||
dealer.line2.3,"要的话价钱好商量。"
|
dealer.line2.3,"要的话价钱好商量。"
|
||||||
|
inspect.flip.back,"翻到背面"
|
||||||
|
inspect.flip.front,"翻到正面"
|
||||||
|
Reference in new issue
Block a user