From 819854af30dbd5bc289cc4b8f7311eb99724df18 Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Thu, 6 Aug 2026 15:58:09 +0800 Subject: [PATCH] fix(combat-insights): restore replay hidden tags --- .../Data/CombatImpactEntitySnapshotReader.cs | 20 ++++++++++++++++++- .../Data/CombatImpactModels.cs | 19 ++++++++++++++++++ .../CombatImpactEntitySnapshotReaderTests.cs | 13 ++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/BazaarPlusPlus/Game/PostCombatImpact/Data/CombatImpactEntitySnapshotReader.cs b/src/BazaarPlusPlus/Game/PostCombatImpact/Data/CombatImpactEntitySnapshotReader.cs index 33e174fc0..309e0eaab 100644 --- a/src/BazaarPlusPlus/Game/PostCombatImpact/Data/CombatImpactEntitySnapshotReader.cs +++ b/src/BazaarPlusPlus/Game/PostCombatImpact/Data/CombatImpactEntitySnapshotReader.cs @@ -1,5 +1,6 @@ #nullable enable using BazaarGameClient.Domain.Models.Cards; +using BazaarGameShared.Domain.Cards.Item; using BazaarGameShared.Domain.Core.Types; using BazaarGameShared.Domain.Effect; using BazaarGameShared.Domain.Effect.Actions; @@ -70,7 +71,7 @@ internal static IReadOnlyDictionary Read() effectAttributes.Auras, effectAttributes.ReferenceValuedAuraEffectIds, card.LeftSocketId, - card.HiddenTags == null ? null : card.HiddenTags.ToArray() + ResolveHiddenTags(card) ); } @@ -84,6 +85,23 @@ internal static IReadOnlyDictionary Read() return entities; } + internal static IReadOnlyCollection? ResolveHiddenTags(Card card) + { + IReadOnlyCollection? enchantmentHiddenTags = null; + if ( + card is ItemCard { Enchantment: { } enchantment } + && card.Template is TCardItem { Enchantments: not null } itemTemplate + && itemTemplate.Enchantments.TryGetValue(enchantment, out var enchantmentTemplate) + ) + enchantmentHiddenTags = enchantmentTemplate?.HiddenTags; + + return CombatImpactHiddenTags.Merge( + card.HiddenTags, + card.Template?.HiddenTags, + enchantmentHiddenTags + ); + } + private static EffectAttributeTypes ReadEffectAttributeTypes(Card card, ItemCard? item) { try diff --git a/src/BazaarPlusPlus/Game/PostCombatImpact/Data/CombatImpactModels.cs b/src/BazaarPlusPlus/Game/PostCombatImpact/Data/CombatImpactModels.cs index 1a97601d2..5e7b95cbb 100644 --- a/src/BazaarPlusPlus/Game/PostCombatImpact/Data/CombatImpactModels.cs +++ b/src/BazaarPlusPlus/Game/PostCombatImpact/Data/CombatImpactModels.cs @@ -104,6 +104,25 @@ internal sealed record CombatImpactEntity( IReadOnlyCollection? HiddenTags = null ); +internal static class CombatImpactHiddenTags +{ + internal static IReadOnlyCollection? Merge( + IReadOnlyCollection? runtime, + IReadOnlyCollection? template, + IReadOnlyCollection? enchantment + ) + { + var hiddenTags = new HashSet(); + if (runtime != null) + hiddenTags.UnionWith(runtime); + if (template != null) + hiddenTags.UnionWith(template); + if (enchantment != null) + hiddenTags.UnionWith(enchantment); + return hiddenTags.Count == 0 ? null : hiddenTags.ToArray(); + } +} + internal sealed record CombatImpactEvent( CombatImpactKind Kind, string SourceId, diff --git a/tests/PostCombatImpact.Tests/CombatImpactEntitySnapshotReaderTests.cs b/tests/PostCombatImpact.Tests/CombatImpactEntitySnapshotReaderTests.cs index d6cc3027b..7a46590e3 100644 --- a/tests/PostCombatImpact.Tests/CombatImpactEntitySnapshotReaderTests.cs +++ b/tests/PostCombatImpact.Tests/CombatImpactEntitySnapshotReaderTests.cs @@ -1,3 +1,4 @@ +using BazaarGameShared.Domain.Core.Types; using BazaarPlusPlus.Game.PostCombatImpact.Data; using Xunit; @@ -5,6 +6,18 @@ namespace PostCombatImpact.Tests; public sealed class CombatImpactEntitySnapshotReaderTests { + [Fact] + public void Hidden_tags_fall_back_to_the_template_for_rehydrated_replay_cards() + { + var hiddenTags = CombatImpactHiddenTags.Merge( + runtime: [], + template: [EHiddenTag.Haste], + enchantment: null + ); + + Assert.Contains(EHiddenTag.Haste, hiddenTags!); + } + [Theory] [InlineData("Radiant\nHunter's Journal")] [InlineData("Hunter's Journal")]