From c10cf1ea19b7c930435363aa12e9ae194b7a6dee Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:24:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A7=E5=AD=98=E6=A1=A3=E7=9A=84=E5=81=87?= =?UTF-8?q?=E5=8D=A1=E8=A1=A5=E4=B8=8A=E9=A3=8E=E6=89=87=E6=95=B0=E3=80=81?= =?UTF-8?q?=E4=BE=9B=E7=94=B5=E5=8F=A3=E7=A0=B4=E7=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- src/Decentralized.Domain/CardLook.cs | 13 +++++++++++++ src/Decentralized/Items.cs | 6 +++++- tests/Decentralized.Domain.Tests/Program.cs | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/Decentralized.Domain/CardLook.cs b/src/Decentralized.Domain/CardLook.cs index 8600de7..9b0dfc8 100644 --- a/src/Decentralized.Domain/CardLook.cs +++ b/src/Decentralized.Domain/CardLook.cs @@ -63,6 +63,19 @@ namespace Decentralized.Domain /// 六位数字,存在物品标签上:风扇、金手指、挡板、丝印、封条、序列号。 public string Encode() => $"{Fan}{Fingers}{Bracket}{Print}{Sticker}{Serial}{CountBad}{PinBad}"; + /// + /// 旧版存档的外观只有 5 或 6 位(没有风扇数、供电口两位):旧规则里假卡的风扇数和供电口只要档次不同就一定对不上。 + /// 这里按旧规则补上,旧存档里的假卡仍然露出同样的破绽。新格式(8 位)不动。 + /// + public static CardLook Legacy(string encoded, CardLook look, string label, string chip) + { + if (encoded == null || encoded.Length >= 8 || string.IsNullOrEmpty(chip) || chip == label) return look; + var l = Hardware.Specs[label]; var c = Hardware.Specs[chip]; + look.CountBad = Hardware.FanCount[l.Tier] != Hardware.FanCount[c.Tier] ? 1 : 0; + look.PinBad = Hardware.PinClass[l.Tier] != Hardware.PinClass[c.Tier] ? 1 : 0; + return look; + } + public static CardLook Decode(string s) { if (s == null || s.Length < 5 || s.Length > 8) return default; diff --git a/src/Decentralized/Items.cs b/src/Decentralized/Items.cs index 4507783..6536e7e 100644 --- a/src/Decentralized/Items.cs +++ b/src/Decentralized/Items.cs @@ -355,7 +355,11 @@ namespace Decentralized if (item.IsTag(FakeTag)) u.FakeOf = item.GetTagReadonly(FakeTag).GetString(); u.Refurbished = item.IsTag(RefurbTag); u.Dead = item.IsTag(DeadTag); - if (item.IsTag(LookTag)) u.Look = CardLook.Decode(item.GetTagReadonly(LookTag).GetString()); + if (item.IsTag(LookTag)) + { + var enc = item.GetTagReadonly(LookTag).GetString(); + u.Look = CardLook.Legacy(enc, CardLook.Decode(enc), u.Model, u.FakeOf); // 旧存档的假卡补上风扇数、供电口破绽 + } // 外观种子:没有记录的卡(正规渠道的新卡)用物品编号当种子,之后同样随损耗变旧 u.Look.Seed = item.IsTag(SeedTag) ? (uint)item.GetTagReadonly(SeedTag).GetInt() : (uint)(item.uniqueId * 2654435761u) | 1u; return u; diff --git a/tests/Decentralized.Domain.Tests/Program.cs b/tests/Decentralized.Domain.Tests/Program.cs index f7beb71..011e929 100644 --- a/tests/Decentralized.Domain.Tests/Program.cs +++ b/tests/Decentralized.Domain.Tests/Program.cs @@ -468,6 +468,24 @@ internal static class Program Check(new[] { CardLabels.RowCount, CardLabels.RowPin, CardLabels.RowPrint, CardLabels.RowSerial }.All(r => gs.Get(r) == gt.Get(r)), "真卡四项依据全部符合"); }); + Test("旧存档兼容:6 位旧外观的假卡补上风扇数、供电口破绽,真卡和新格式不动", () => + { + var old = CardLook.Decode("000000"); + var fake = CardLook.Legacy("000000", old, "RTX90", "RTX60"); + var u = new Unit { Model = "RTX90", FakeOf = "RTX60", Health = 80, Look = fake }; + Check(fake.CountBad == 1 && fake.PinBad == 1 && u.ObservedCount == 1 && u.ObservedPin == 0, "旧版的低档冒充高档:风扇数和供电口都对不上"); + var claim = new Claim { Model = "RTX90" }; + Check(claim.Get(CardLabels.RowCount) != Claim.Truth(u).Get(CardLabels.RowCount) && claim.Get(CardLabels.RowPin) != Claim.Truth(u).Get(CardLabels.RowPin), "说成标称型号时两项依据都与实物不符"); + var sameCount = CardLook.Legacy("000000", old, "RTX80", "RTX60"); + Check(sameCount.CountBad == 1 && sameCount.PinBad == 1, "RTX 80 冒充:风扇数 3 对 1、供电口 8 针对 6 针都不同"); + var same = CardLook.Legacy("000000", old, "RTX80", "RX800"); + Check(same.CountBad == 0 && same.PinBad == 0, "档次相同(风扇数、供电口一样)的假卡补不出破绽,也不会误加"); + Check(CardLook.Legacy("000000", old, "RTX90", null).CountBad == 0, "真卡不动"); + var newer = new CardLook { CountBad = 0, PinBad = 1, Print = 2 }; + Check(CardLook.Legacy(newer.Encode(), CardLook.Decode(newer.Encode()), "RTX90", "RTX60").CountBad == 0, "新格式(8 位)不再补"); + Check(CardLook.Decode(newer.Encode()).PinBad == 1 && CardLook.Decode("012012").Fan == 0 && CardLook.Decode("01201").Sticker == 1 && CardLook.Decode("01201").Serial == 0, "新旧格式都能读"); + }); + Test("外观随损耗重算:越旧外观越差;种子固定;算力受风扇与金手指影响", () => { var rng = new Rng(5);