fix(Economics): Core 修正 NPC 伤害结算漏算扣血 + NPC 配置语义修复#1142
fix(Economics): Core 修正 NPC 伤害结算漏算扣血 + NPC 配置语义修复#1142Controllerdestiny merged 8 commits intoUnrealMultiple:masterfrom
Conversation
There was a problem hiding this comment.
Hey - 我发现了 1 个问题
给 AI Agents 的提示
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/Economics.Deal/Command.cs" line_range="99-100" />
<code_context>
+ {
+ MaxLinesPerPage = Config.Instance.PageMax,
+ NothingToDisplayString = GetString($"没有找到包含\"{keyword}\"的交易物品"),
+ HeaderFormat = GetString($"搜索\"{keyword}\"的结果 ({{0}}/{{1}}):"),
+ FooterFormat = GetString($"输入 {Commands.Specifier}deal search {keyword} {{0}} 查看更多")
+ });
+ }
</code_context>
<issue_to_address>
**issue (bug_risk):** 为了本地化和格式化的正确性,Header/FooterFormat 也应当在调用 GetString 之前避免使用字符串插值。
在 `GetString` 调用中插入 `keyword`/`Commands.Specifier` 会使查找键变成动态的,从而破坏本地化;同时还会把运行时的值和 `PaginationTools` 应该使用的 `{0}`/`{1}` 占位符混在一起。
相反,应当保持资源键是静态的,并将 `HeaderFormat`/`FooterFormat` 视为格式字符串。比如:
```csharp
HeaderFormat = string.Format(
GetString("搜索\"{0}\"的结果 ({1}/{2}):"),
keyword,
"{0}",
"{1}"),
FooterFormat = string.Format(
GetString("输入 {0}deal search {1} {2} 查看更多"),
Commands.Specifier,
keyword,
"{0}");
```
或者,让 `GetString` 返回的字符串中已经包含供 `PaginationTools` 使用的字面量 `{0}`/`{1}` 占位符,然后在本地化之后再替换 `keyword`/`specifier`。
</issue_to_address>帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/Economics.Deal/Command.cs" line_range="99-100" />
<code_context>
+ {
+ MaxLinesPerPage = Config.Instance.PageMax,
+ NothingToDisplayString = GetString($"没有找到包含\"{keyword}\"的交易物品"),
+ HeaderFormat = GetString($"搜索\"{keyword}\"的结果 ({{0}}/{{1}}):"),
+ FooterFormat = GetString($"输入 {Commands.Specifier}deal search {keyword} {{0}} 查看更多")
+ });
+ }
</code_context>
<issue_to_address>
**issue (bug_risk):** Header/FooterFormat should also avoid string interpolation before GetString for localization and formatting correctness.
Interpolating `keyword`/`Commands.Specifier` inside the `GetString` call makes the lookup key dynamic, which will break localization, and also mixes runtime values with `{0}`/`{1}` placeholders that `PaginationTools` is supposed to use.
Instead, keep the resource key static and treat `HeaderFormat`/`FooterFormat` as format strings. For example:
```csharp
HeaderFormat = string.Format(
GetString("搜索\"{0}\"的结果 ({1}/{2}):"),
keyword,
"{0}",
"{1}"),
FooterFormat = string.Format(
GetString("输入 {0}deal search {1} {2} 查看更多"),
Commands.Specifier,
keyword,
"{0}");
```
Alternatively, have `GetString` return a string that already contains the literal `{0}`/`{1}` placeholders for `PaginationTools`, and only substitute `keyword`/`specifier` after localization.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| HeaderFormat = GetString($"搜索\"{keyword}\"的结果 ({{0}}/{{1}}):"), | ||
| FooterFormat = GetString($"输入 {Commands.Specifier}deal search {keyword} {{0}} 查看更多") |
There was a problem hiding this comment.
issue (bug_risk): 为了本地化和格式化的正确性,Header/FooterFormat 也应当在调用 GetString 之前避免使用字符串插值。
在 GetString 调用中插入 keyword/Commands.Specifier 会使查找键变成动态的,从而破坏本地化;同时还会把运行时的值和 PaginationTools 应该使用的 {0}/{1} 占位符混在一起。
相反,应当保持资源键是静态的,并将 HeaderFormat/FooterFormat 视为格式字符串。比如:
HeaderFormat = string.Format(
GetString("搜索\"{0}\"的结果 ({1}/{2}):"),
keyword,
"{0}",
"{1}"),
FooterFormat = string.Format(
GetString("输入 {0}deal search {1} {2} 查看更多"),
Commands.Specifier,
keyword,
"{0}");或者,让 GetString 返回的字符串中已经包含供 PaginationTools 使用的字面量 {0}/{1} 占位符,然后在本地化之后再替换 keyword/specifier。
Original comment in English
issue (bug_risk): Header/FooterFormat should also avoid string interpolation before GetString for localization and formatting correctness.
Interpolating keyword/Commands.Specifier inside the GetString call makes the lookup key dynamic, which will break localization, and also mixes runtime values with {0}/{1} placeholders that PaginationTools is supposed to use.
Instead, keep the resource key static and treat HeaderFormat/FooterFormat as format strings. For example:
HeaderFormat = string.Format(
GetString("搜索\"{0}\"的结果 ({1}/{2}):"),
keyword,
"{0}",
"{1}"),
FooterFormat = string.Format(
GetString("输入 {0}deal search {1} {2} 查看更多"),
Commands.Specifier,
keyword,
"{0}");Alternatively, have GetString return a string that already contains the literal {0}/{1} placeholders for PaginationTools, and only substitute keyword/specifier after localization.
在 OnStrike 里将本次计入的伤害裁剪到 NPC 当前剩余血量,防止一击秒杀兔子等低血怪时,玩家按武器原始伤害(而非实际造成伤害)获得货币。
记录 OnStrike 溢出伤害裁剪修复对应的版本更新与 changelog。
NpcStrike hook 触发时 args.Npc.life 已是扣血后的值,致命一击时为 0 或负数, 直接用作上界会导致最后一击的有效伤害被整个丢弃,solo 击杀无法累计到满血, rw = damage / lifeMax 恒小于 1,下游按输出瓜分的奖励永远拿不到满额。改为 以 "lifeMax - 已累计伤害" 作为上界,同时保留对原始伤害溢出剩余血量的裁剪。
将伤害追踪从 ServerApi.Hooks.NpcStrike 迁移到 TShock 的 GetDataHandlers.NPCStrike: 前者在 StrikeNPC 之后触发,args.Npc.life 已被扣到 ≤0,最后一击容易丢失;后者在 客户端 NpcStrike 包处理阶段触发,npc.life 仍是攻前剩余血量,可直接用作裁剪上界。 新实现走 Main.CalculateDamageNPCsTake + Ichor + 暴击的公式(参考 SEconomy 的 WorldEconomy.AddNPCDamage),把 raw 武器伤害换算成实际掉血。 针对 debuff DoT 和环境伤害直接修改 npc.life、不经过 NpcStrike 路径导致 Strike 累加器总和小于 lifeMax 的场景,OnKillNpc 在触发玩家奖励事件前按 lifeMax 对每个 玩家的累计伤害做比例校正,确保 solo 击杀能拿到 rw=1 对应的满额奖励,多人瓜分也 按各自贡献的相对占比分配。
"转换率更改" 原实现把 AllocationRatio 当成奖励池总量用(rw × AllocationRatio), 与字段命名严重脱节,导致配置 "转换率": 1.5 的 Boss 玩家只能拿到 1-5 块钱。改为 作为 Core 默认 KillNpc 奖励的加成系数(damage × ConversionRate × AllocationRatio), 且对每种 KillNpc 型货币分别结算,行为与 Core 默认路径一致,包括 ContainsID 过滤 和 CombatMsgOption.Enable 检查。 同时修复转换率分支末尾 return 吞掉后续"额外奖励列表"分支的问题,两段配置现在可以 共存同一只 NPC。转换率分支在玩家进度不达标时也改为 fallback 到 Core 默认结算,而 不是吞掉全部奖励。 版本号从 2.0.0.4 跃迁到 2.1.0.0,体现"转换率更改"字段的语义变更是 breaking change, 按旧语义填写的 AllocationRatio 值升级后行为会有明显差异。
Summary
Economics.Core v2.1.0.0
ServerApi.Hooks.NpcStrike.args.Damage)作为结算依据,忽略了防御、Ichor、暴击以及最后一击触发时args.Npc.life已被扣到 0/负数等多个环节,导致累计伤害与 NPC 实际扣血不一致。现在改走GetDataHandlers.NPCStrike(攻前时机),用Main.CalculateDamageNPCsTake+ 防御 + Ichor + 暴击换算出真实掉血量,并以攻前npc.life作为每次攻击的裁剪上界NpcStrike包含进累计伤害,导致按输出瓜分的奖励池玩家拿不到满额的问题。OnKillNpc现在会把累计伤害按lifeMax做比例校正,solo 击杀能稳定拿到完整奖励,多人击杀按各自对 Boss 的实际伤害占比瓜分Economics.NPC v2.1.0.0
转换率更改的转换率字段语义修正为"默认击杀奖励的加成系数",例如填 `1.5` 表示拿到默认奖励的 150%。此前实现错误地把它当作奖励池总量使用,导致设置 `1.5` 的 Boss 玩家实际只能拿到 1-5 块钱。升级后请根据新语义重新评估配置值Test plan
Economics.Core
Economics.NPC
Summary by Sourcery
更新 Economics.Core、Economics.NPC 和 Economics.Deal,以提升基于 NPC 伤害的奖励精确度,优化 NPC 货币转换语义,并为交易系统新增物品搜索功能。
New Features:
/deal search指令,用于按名称搜索已挂单的交易物品。Bug Fixes:
Enhancements:
Documentation:
Original summary in English
Summary by Sourcery
Update Economics.Core, Economics.NPC, and Economics.Deal to improve NPC damage-based rewards accuracy, refine NPC currency conversion semantics, and add item search to the trading system.
New Features:
Bug Fixes:
Enhancements:
Documentation: