Skip to content
This repository was archived by the owner on Sep 20, 2026. It is now read-only.

fix(event-preview): resolve dynamic reward totals - #195

Merged
cauyxy merged 1 commit into
masterfrom
codex/event-preview-live-totals
Aug 2, 2026
Merged

cauyxy merged 1 commit into
masterfrom
codex/event-preview-live-totals

Conversation

@pengx17

@pengx17 pengx17 commented Aug 2, 2026

Copy link
Copy Markdown
Member

Context

事件和升级奖励的预览文案会在静态缓存阶段替换 {ability.*} / {aura.*}。固定值可以直接读取,但依赖当前 run 的表达式无法在缓存构建时求值,因此会留下空占位,例如:

  • Heroic Encounters (Dabora):每输掉一场玩家战斗恢复 2 Prestige;若本局已输 3 场,应显示合计 [6]
  • Prosperous Estates / Side Hustle:按当前手牌与仓库中的指定物品数量计算金币总额。
  • Rest / Regenerative Tincture:按玩家当前等级计算奖励总量。
  • Old Memories:按当前物品标签数量计算总量。
  • [Shrouded Figure] Sacrifice Ancient Locket:组合“当前最大生命 × Ancient Locket 累计次数 × 百分比”的嵌套表达式。

对当前 GameData 的盘点发现 29 个静态阶段无法解析的占位符,其中 28 个是有效的动态值:18 个玩家属性引用,10 个卡牌计数引用;另 1 个 {aura.3} 没有对应 aura,属于游戏数据中的无效引用,且不经过当前预览链路。

改动重点

  • 数值读取:为 ability / aura 增加基于游戏原生 ITValue.GetValue(ValueContext) 的实时求值。
  • 事件预览:把实时求值器贯穿事件本体、选项、随机池和结果说明。
  • 升级预览:升级奖励候选项使用同一实时求值链,覆盖物品计数和等级相关文案。
  • 容错:静态缓存值仍优先;实时上下文不足时只放弃单个占位符,不影响整段预览。
  • 测试:覆盖 PvP 败场、手牌/仓库计数、嵌套卡牌属性聚合及升级奖励文案。

协作过程

sequenceDiagram
    participant U as 用户
    participant C as 实现
    participant G as GameData
    participant D as 反编译游戏代码
    participant T as 测试

    U->>C: PvP 败场恢复声望未显示合计
    U->>C: 查找并覆盖同类文案
    C->>G: 盘点未解析占位符
    G-->>C: 18 个玩家属性 + 10 个卡牌计数
    C->>D: 验证游戏原生求值路径
    D-->>C: ITValue + ValueContext(run)
    C->>T: 验证原生表达式及两条预览链
    T-->>C: 事件、升级与架构测试通过
Loading

方案讨论

ADR-001:动态总量的求值位置

Context

静态预览缓存没有当前 run、玩家属性、手牌或仓库状态,因此不能得出动态合计。

Considered Options

  1. 为玩家属性、卡牌计数和聚合表达式分别实现插件侧计算。
  2. 把表达式描述序列化进缓存,再由插件解释执行。
  3. 展示时使用当前 run 构造游戏原生 ValueContext,直接执行模板中的 ITValue 表达式图。

Decision

采用方案 3。静态值继续从缓存读取;只有静态阶段缺失的基础 ability / aura 值才进入实时求值。

Consequences

  • 新增的同类表达式通常无需插件继续硬编码。
  • 嵌套 modifier、玩家属性和卡牌聚合沿用游戏规则。
  • 依赖目标卡牌等额外上下文的表达式可能无法求值;异常会被隔离到单个占位符。

最终方案

flowchart LR
    A["事件 / 升级奖励文案"] --> B{"静态缓存有值?"}
    B -->|是| C["使用缓存值"]
    B -->|否| D["当前 Run 的 ValueContext"]
    D --> E["游戏原生 ITValue 表达式"]
    E --> F["格式化实时合计"]
    C --> G["渲染预览"]
    F --> G
    E -->|上下文不足| H["仅跳过该占位符"]
Loading

验证情况

  • dotnet csharpier check .
  • git diff --check
  • CollectionEncounterTooltip.Tests:168 passed
  • Architecture.Tests:129 passed
  • Debug 构建随测试成功完成,并复制插件 DLL 到本地 BepInEx 插件目录

已知局限 / 后续工作

  • GameData 中无对应效果的 {aura.3} 不会被猜测或伪造。
  • 需要 targeting card 等额外上下文的表达式仍保持安全降级;本次已盘点的 28 个有效动态占位符均属于当前 run 可求值范围。

@pengx17
pengx17 marked this pull request as ready for review August 2, 2026 17:55
Copilot AI review requested due to automatic review settings August 2, 2026 17:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves event and level-up reward preview text by resolving previously-unfilled dynamic {ability.*} / {aura.*} placeholders at presentation time using the game’s native ITValue.GetValue(ValueContext) evaluation, rather than relying solely on static-cache substitution.

Changes:

  • Add a live placeholder-resolution path (LiveAbilityValueResolver) and thread it through event preview, choice pools, and level-up reward candidate formatting.
  • Implement live ability/aura evaluation in the runtime via ValueContext(run) + CardAbilityValueReader.TryEvaluate*.
  • Add/extend tests covering missing static totals (PvP loss aggregation, hand+stash counts, nested aggregates) and level-up tooltip rendering.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/CollectionEncounterTooltip.Tests/EventPreviewLocalizationTests.cs Adds a focused test proving live fallback fills a missing {ability.0} total.
tests/CollectionEncounterTooltip.Tests/EncounterPreviewModuleTests.cs Extends module-level snapshot test coverage to include live-resolved totals in compiled preview output.
tests/CollectionEncounterTooltip.Tests/CollectionLevelUpTooltipTextTests.cs Adds a level-up tooltip test ensuring dynamic totals are resolved via the live resolver.
tests/CollectionEncounterTooltip.Tests/CollectionEncounterTooltip.Tests.csproj Adds BazaarGameClient reference required for new runtime model-based tests.
tests/CollectionEncounterTooltip.Tests/CardAbilityValueReaderTests.cs Introduces unit tests validating native live evaluation for player attrs, card counts, and nested aggregates.
src/BazaarPlusPlus/GameInterop/Cards/CardAbilityValueReader.cs Adds TryEvaluate* that evaluates ITValue against a ValueContext for dynamic totals.
src/BazaarPlusPlus/Game/EventPreview/LevelUpPreviewTextFormatter.cs Threads live resolver through reward selection and description formatting.
src/BazaarPlusPlus/Game/EventPreview/EventPreviewLocalization.cs Adds LiveAbilityValueResolver plumbing to resolve missing cached ability/aura placeholders.
src/BazaarPlusPlus/Game/EventPreview/EncounterPreviewModule.cs Wires live evaluation into both event and level-up preview request paths.
src/BazaarPlusPlus/Game/EventPreview/EncounterPreviewGameRuntime.cs Implements live evaluation against the current Run using ValueContext.
src/BazaarPlusPlus/Game/EventPreview/EncounterEventDetailResolver.cs Ensures live resolution is used across event description, choices, and pool summaries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +89 to +91
valueText = value.ValueText;
unit = value.Unit;
return true;
@cauyxy
cauyxy merged commit ceeb278 into master Aug 2, 2026
1 check passed
@cauyxy
cauyxy deleted the codex/event-preview-live-totals branch August 6, 2026 11:16
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants