Buff重构方案(草案) #152
Steinwaysj
started this conversation in
Ideas
Replies: 1 comment
-
|
建议通过代码示例,将各模块间流转的数据的数据结构、类的属性和方法、方法的参数和返回值等都列出来,更具体地展现运行流程,后续拆分任务时也更方便 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
注意
本方案仅为草案,若对具体实现细节有疑问,请在评论区指出。该草案讨论事件截止到下周一(2025.10.13),届时重构方案将会定型,本discussion关闭,在Github Wiki上传新的确定版的重构方案文档。
现状和背景
ZSim开发进程推进至今,
Buff模块已经成为了最大的瓶颈,也是目前开源社区参与开发的最大障碍。所以,我们决定对Buff模块进行重构,本次重构规模极大,涉及到的功能较多,所有和Buff有关的业务逻辑都被彻底推翻重来。
触发判断.csv、激活判断.csv、buff_effect.csv,触发判断.csv记录了Buff的各种属性和参数,是需要保留的表,激活判断.csv则存放了简单触发条件,在未来,这部分内容会被全新的出发判定逻辑所取代,所以这张表格的内容完全不需要;buff_effect.csv中记录了Buff的效果;start、end、refresh等状态管理方法buff.ft.index)作为索引值,而引入buff.id: int。event_router担任逻辑中枢的新业务逻辑event_listener,将所有监听器探针交给event_router,修改对应角色的监听器业务逻辑。新系统的思考和架构
GlobalBuffController_buff_box——内部的Buff仓库,存储本次模拟中构造的所有Buff对象。buff_initiate_factory——原buff_0_manager,负责Buff初始化BuffManager——虽然Buff自身可以完成最基础的start、end等操作,但是角色对象持有的有效Buff的CRUD还是需要通过BuffManager进行的。BuffOperator——对角色的active_buff_list进行操作,新增、去除Buff。event_router——解析复杂对象,触发事件。__init__——包含一个HandlerMap、一个Buff事件树,以及一个激活事件列表。ZSimEvent和EventProfile——模拟器事件和事件画像。这是ZSim的两个重要概念,是新架构得以成立的基石。ZSimEvent——ZSim中的事件,这里只展示基类。EventProfile——事件画像类,对ZSim事件的封装。并且提供对外接口,以获取内部所封装的复杂对象的参数。Buff——原buff_class,定义了Buff类buff_feature——原buff_feature或buff.ft,记录了Buff的静态信息(最大持续时间、层数、更新规则)buff_dynamic——原buff_dynamic或buff.dy,记录了Buff的动态信息(更新时间、动态层数等)bonus_class——记录Buff效果的基类effect: effect_base_class——effect_base_class类:Buff效果对象Character和Calculator中进行的对应适配改动:dynamic_attribute——重构动态属性类attribute_calculator——负责动态属性的计算(需要调用buff_manager.bonus_applier)Load阶段的关于技能事件相关的功能整合进event_router中。关于EventRouter和新触发器系统的运作方式
“事件”与“计划事件”的区别
事件触发器树
event_trigger_tree的构造事件画像
EventProfile和event_trigger_tree的交互关于Buff系统新架构的一些重要信息
Buff系统重构的基本原则:
1. Buff是角色的一个属性,角色/Enemy对象只持有激活的Buff/Debuff
2. 仅在初始化阶段对Buff进行统一构造,模拟过程中只进行Buff信息的更新,而不重复构造。
3. Buff负责自身状态管理:保留
buff.start、buff.end、buff.refresh等核心状态管理方法,移除buff.judge、buff.update、buff.exit_judge等外部判定逻辑4.
event_router将通过监听器组以及逻辑树来承担触发Buff的全部业务5.Buff的CRUD操作由
BuffManager统一管理Buff的分类
注意,在理念上,这些Buff需要被进行分类,但是在实现过程中,Buff是不分类的。这里的分类讨论只是为了明确Buff的业务逻辑框架。根据Buff的功能性,我们可以将Buff分成2类
不光是ZSim,可以说所有游戏中的Buff都可以被概括为这两个类别。
这一Buff分类准则作为ZSimBuff系统的底层设计,在本次重构中并未改变。只是,新系统重,不同类型的Buff需要构建不同给的Handler来处理它们的业务逻辑
Buff的生命周期管理(CRUD):
Buff的创建
logic_id中记录的子条件组合,调用event_router的注册器,将自己注册到对应的逻辑树节点上。Buff的新增/刷新:
event_router提供的事件画像触发了逻辑树上的对应节点,节点激活时,会调用publish方法,调用buff_event_handler来调用buff的start和end方法,同时发布一个buff更新事件.buff.start()或者buff.end()方法调用时,会更新自身的信息,BuffManager收到buff更新事件时,会执行对应角色的Buff增删操作。Buff的查找:
buff_manager的对应接口来实现Buff的查找Buff的消退:
event_router或是GlobalBuffController抛出事件、调用对应的Handler执行。注意,部分Buff的消退不依赖于自然时间的流逝,而是具有特殊的判定行为,这部分业务交由event_router的逻辑树管理,Buff自身不负责判定何时消退。关于Buff效果系统的重构
老框架
buff_effect.csv获取Buff对应的效果dict[str, int | float],然后借助data_analyzer.py等模块,最终在构造乘区类MultiplierData时,转译成各属性、乘区加成data_analyzer.py的业务逻辑基本就是字符串解释器,扩展性较差,而且维护、拓展非常烧脑,并且运行需要传入Generator来构造list[Buff],耦合程度太高,难以测试。MultiplierData框架设计于立项初期,未考虑拓展和解耦,导致处理任何计算事件时都需要把全部属性、乘区都构造一遍,且生命周期极短,用完就扔,性能浪费严重,MultiplierData没有设计供外部调用的接口,导致外部模块(例如Buff.logic或是Character)需要知道角色的动态属性时,就不得不调用大量参数就地构建一个新的MultiplierData新框架
Buff,Character,Calculator等多个模块)进行了重构,彻底实现“Buff生效”功能的解耦。Character对象,一同归入Character的还有计算属性和乘区的一些方法Character内部构造专门的容器用来存放效果对象,容器私有,外部只能访问Character提供的接口来获取所关心属性的实时加成buff_effect池和active_buff_list池之间,构建自动化的同步流程,保证Buff新增时,加成池同步更新(但是需要考虑类似于席德强袭Buff这种“存在但不生效”的情况)buff_effect自己不知道是否应该加入效果池,所以,在active_buff_list更新时,buff_effect池子默认保持更新,而独立存在一个“去除Buff效果”或者是“使Buff存在但效果静默”的事件来执行这件事情——这属于一个Buff的额外效果,需要注册到事件树中。Calculator中,对新架构进行适配(工作量略大)相关重构细节如下(仅限于
buff_effect以及角色属性、乘区相关)effect_base_class相关(新增)effect_base_class就是本轮重构中,为“Buff效果”设计的类,专门服务于更改属性、乘区的Buff效果而创建,至于Buff触发器,将直接通过事件树进行注册,而不走effect_base_class路径,也不会进入Character的加成池。[ { "target_attribute": "固定攻击力", "value": 100, "element_type": [1,2,3], "skill_tag": ["1301_SNA_1", "1301_SNA_2"] }, { "target_attribute": "增伤", "value": 0.3 }, ]json数据,由Buff对象来负责构建Buff.effect对象。该对象会在Buff激活时,直接加入BuffManager.buff_effect_pool中,注意,一个Buff对应的effect的json字段可能有多个,此时我们需要构造多个effect对象,做到一个effect对象仅管理一种效果。考虑到Buff的效果被分为“属性值增减益”和“事件触发器两类”,所以,设计两个继承自effect_base_class的类,分别处理两种不同的业务。bonus_effect_class(effect_base_class)对象,具有属性和方法:value:每一层Buff增幅的数值target_attribute:增幅的项目apply_condition_list: list:能够使Buff生效的额外条件,除target_attribute和value字段以外的其他字段,都会被视作生效条件约束,它们都会被编入apply_judger.apply_condition_list中trigger_class(effect_base_class)对象,具有属性和方法:json字段中含有trigger参数,且对应值为True时,其他参数除event_id以外,全部失效(当然,最好要通过pydantic进行检测,这样可以尽早暴露JSON文件填写的问题)Character相关Character下,构建一个新的dynamic_attribute(暂时名)类,与原有的Statement并列MultiplierData管理的动态属性和乘区占位符合并、转移到dynamic_attribute下attribute_calculator对象,迁移位于Calculator.py中的大量计算属性、乘区的方法,业务逻辑上:通过调用Character原有的Statement方法获取静态面板,然后调用buff_manager.bonus_applier方法获取当前的动态加成,最后计算出实时属性。Character相关的新组件buff_effect_selector方法,接收核心参数environment_profile(事件画像),该参数由外部结构event_router抛出,根据该对象中记录的事件标签组合,从当前激活的Buff中筛选出适配的效果bonus_applier方法,该方法仅接受核心参数:target_attribute和applied_buff_effect_list,通过遍历applied_buff_effect_list,计算target_attribute的加成,返回给Character.dynamic_attribute.attribute_calculatoractive_buff_list:Character级别的动态Buff列表,通过订阅Buff状态变更事件自动维护bonus_pool:Character级别的增益池对象,封装了效果池,以及效果池所需的CRUD方法。buff_effect_data:这是整个bonus_pool对象的核心,是一个手动搭建的二维数据结构,但不能data_frameadd_buff_effect:向buff_effect_data中新增Buff效果的方法cancel_buff_effect:向buff_effect_data中删除Buff效果的方法buff_effect_data数据结构示意图
以下是复合字典结构在ZSim中的应用示例:
多字典索引结构
对应的字典结构
Beta Was this translation helpful? Give feedback.
All reactions