资讯动态

Path of Building 修改符计算引擎拆解:Mod 模型、ModDB 求值与缓存如何协作

发布时间:2026/10/15 20:20:57 来源:尧图企业网站定制
Path of Building 修改符计算引擎拆解Mod 模型、ModDB 求值与缓存如何协作【免费下载链接】PathOfBuildingOffline build planner for Path of Exile.项目地址: https://gitcode.com/GitHub_Trending/pa/PathOfBuildingPath of Building 是《流放之路》的离线构建规划器它的核心不是一张树图而是一台计算引擎被动树节点、装备词条、技能宝石、光环与诅咒全部被归一成同一种 Mod 结构由 ModDB 按类型求值最终产出 DPS 与防御面板。生成文件 src/Data/ModCache.lua 有 23215 行正是这台引擎把解析从运行时热路径上挪走的证据。本文带你沿一条词条走完从游戏文本到面板数字的链路并逐组件拆解 src/Modules/ModParser.lua、src/Classes/ModDB.lua、src/Modules/CalcPerform.lua 各自的红线与协作方式。为什么不能为每条词条写一个 if朴素做法有三条都走不通。第一条给每个技能写 if/else 伤害分支——但 PoE 每赛季都引入新机制3.29 Allflame 一个赛季就带来了 Pacts、Vestigial、Intangibility 解析、Abyss 永恒宝石等一整批新词条分支写法每赛季重写一遍。第二条每条新词条写一个解析函数——同一措辞会出现在装备、宝石、天赋三处三份实现必然漂移。第三条每次启动都重新解析全库——PoB 每次打开都要算满屏技能逐条跑正则会成为冷启动瓶颈。PoB 的答案是把问题拆成三段统一数据模型——无论词条来自哪里都归一成mod(ModName, ModType, Value, source, modFlags, keywordFlags, extraTags)这一个结构ModType 只有 BASE / INC / MORE / OVERRIDE / FLAG外加 MAX / MIN几种求值逻辑只认类型不认来源。解析与求值分离——文本→Mod 的解析是纯函数产物可以缓存求值只消费 Mod永远不回头看文本。解析产物持久化——解析结果被预生成进 src/Data/ModCache.lua运行时优先查表正则解析只作未命中的兜底。组件位置文件/模块一句话职责红线职责绝不做的事ModParsersrc/Modules/ModParser.lua把词条文本扫成 Mod 结构绝不参与运行时求值绝不决定数值ModCachesrc/Data/ModCache.lua存放文本→Mod的预解析结果绝不允许手写只能由 ModParser 生成ModDBsrc/Classes/ModDB.lua按名分桶、按 ModType 聚合求值绝不做文本解析绝不算总 DPSCalcPerform / CalcOffencesrc/Modules/CalcPerform.lua驱动 hit speed / damage / ailments 各 pass绝不解析词条绝不在 pass 内偷改全局输出一条词条如何变成 DPS 面板上的数字拿 Solidity 天赋的 Attack skills deal 20% increased damage while holding a Shield 走一遍共七步加载构建查 ModCache词条文本命中缓存表未命中才落到 ModParser 的五级扫描产出mod(Damage,INC,20,…)带上 ModFlag 与{ typeCondition, varUsingShield }标签挂进该构建的 ModDB按名字入mods[Damage]桶CalcPerform 先mergeKeystones、初始化 minion 的 modDB、对三套 DB 做applyEnemyModifiersCalcOffence 在 damage pass 里以1 Sum(INC)/100 × More(...)聚合求值条件为真才计入输出写入outputFullDPS 再按技能逐个重算、汇总各源 DPS。容易忽略的两个协调细节ModCache 不是手写的而是开发模式下CtrlF5时由 ModParser 全量重跑生成的产物提交前必须确认它已同步同一套 ModDB 类同时实例化给 player、minion、enemy 三方但桶与桶之间绝不串用——诅咒打在敌人身上用的是 enemyDB 的求值结果。ModParser扫描、标记、分桶——但绝不算数职责红线绝不参与运行时求值它的唯一产出是 Mod 结构绝不在每次启动时对全库重新解析热路径永远先查缓存绝不手写 ModCache 里的任何一行那是生成文件。关键流程preFlagList先扫attack skills deal存下KeywordFlag.Attack。先摘标志而不是最后补因为标志决定后续所有匹配的 ModFlag 语境。preSkillNameList看行首是否为技能名主要用于武器附魔不是就原样继续。formList命中^(%d)%% increasedModType 定成 INC、数值 20 先存进modValue。先定形式再谈内容形式错了后面全是错的。modTagList走两遍摘出while holding a shield转成 Condition 标签。走两遍是为了让一条词条最多挂两个限制条件。剩下的damage由modNameList映射为 Mod 名 Damage全行消费完毕。设计细节文档原话是——Since mods in most builds contain just the raw mod text, and are not tied to the underlying mod from GGGs data, we need to keep old mod wordings intact so those keep working on older builds. 白话说构建文件里存的是词条原文而不是数据 ID老措辞一旦删掉老构建就废了所以解析必须向后兼容而不是跟着游戏文案清理旧词条。兜底的specialModList只留给既不标准又不够多的少数词条文档明确要求加新词条先想 flag 和 tag再考虑进 specialModList。ModDB分桶、聚合、覆盖——但绝不碰文本职责红线绝不做词条文本解析进来就只能是 Mod 结构绝不算总 DPS它是 actor 级账本汇总是 CalcOffence 的事绝不让子库的桶泄漏到父库parent 只用于向上查不到时继续找。关键流程AddMod把 Mod 塞进self.mods[name]列表。按名分桶后求值只扫一个桶而不是全表。EvalMod/Sum(INC)/More按 ModType 聚合BASE 直接求和INC 求和后 100 变倍率MORE 连乘——这正是 PoE 游戏内加法堆、乘法乘的语义。ReplaceModInternal与ConvertModInternal在同桶找不到匹配项时沿 parent 链上溯。宝石的替换某节点词条把 Str 转成 All这类语义本质就是跨桶的移动向上找让子 DB 能改写父 DB 里的条目。player、minion、enemy 各持一套实例minion 初始化时直接按怪物常数表填基础属性例如基础暴伤倍率来自base_critical_strike_multiplier。设计细节minion 的 modDB 不是复制玩家的再打补丁而是独立建库、按怪物等级查monsterConstants填底。这是刻意的——仆从的生命成长曲线、抗性、暴伤与玩家完全是两套数据共享一个库会让玩家的 Onslaught 是否传给骷髅这类条件判定全部失真。CalcPerform合并、初始化、跑 pass——但绝不在 pass 里偷改全局输出职责红线绝不做任何文本解析它拿到的全部是 ModDB 与技能数据绝不在 pass 循环内隐式修改全局output双手的值必须显式合并绝不跨技能复用未标记的缓存。关键流程mergeKeystones合并基石词条并复制出每个主动技能的skillModList。基石会改写其他节点的词条必须在任何求值前落库。为主技能若有 minion初始化minion.modDB并createMinionSkills。对 player / minion / enemy 三套 DB 依次applyEnemyModifiers。进入 src/Modules/CalcOffence.lua 的三组 passhit speed 与命中、damage、ailments 与 debuff攻击技能对主手、副手各跑一遍非攻击只跑一遍。每轮 pass 结束后用combineStat把MainHand/OffHand的结果合回全局outputFullDPS 再按技能 UUID 取缓存或重算。设计细节docs/calcOffence.md 原句是——any value added to output inside of a damage pass may not be added onto the main or global output白话说pass 内你写的output.X实际落在actor.output.MainHand.X或OffHand.X不显式合并就会静默丢失。这个坑被写成文档而不是留在代码注释里因为它的症状是数值对不上但没有任何报错只有文档能拦住下一个踩坑的人。值得借鉴的细节先定数据模型再加解析器所有来源归一成同一种 mod 结构后求值只认 ModType 不认来源新词条进来几乎不动计算核心。⚡把最贵的一步从热路径搬走23215 行的 ModCache 是预解析产物运行时只剩查表未命中才跑正则冷启动与重算都受益。缓存键必须包含全部影响因子calcFullDPS按技能 UUID 取缓存并用limitedSkills防无限递归注释里写明了原因——缓存键漏掉一个因子比较结果就是A 和 A 比差异全为零。快速上手git clone -b dev https://gitcode.com/GitHub_Trending/pa/PathOfBuilding.git # 取开发分支 cd PathOfBuilding ./runtime/Path{space}of{space}Building.exe # 从仓库运行即自动进入 Dev Mode # 修改 ModParser 后按 Ctrl F5 重新生成 ModCache用 Ctrl 打开控制台核对改了 src/Modules/ModParser.lua 之后必须重新生成 src/Data/ModCache.lua 并随 PR 一起提交——运行时靠它做缓存命中漏交意味着你的修复在真实环境里根本不会生效。同理src/Data下所有带 This file is automatically generated, do not edit! 头部的文件都不许手改要动就去改 src/Export 里的导出脚本再重跑。延伸阅读Mod 语法总表见 docs/modSyntax.md解析管线与兼容性注意事项见 docs/addingMods.md伤害 pass 的 output 陷阱见 docs/calcOffence.md开发环境搭建见 CONTRIBUTING.md——四份文档读完这台计算引擎的每一条红线你都能自己指出来。【免费下载链接】PathOfBuildingOffline build planner for Path of Exile.项目地址: https://gitcode.com/GitHub_Trending/pa/PathOfBuilding创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑