MAA 基建换班三种模式的决策链路与自定义排班 JSON 字段行为
【免费下载链接】MaaAssistantArknights《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients.项目地址: https://gitcode.com/GitHub_Trending/ma/MaaAssistantArknights
MAA(《明日方舟》小助手)的基建换班模块负责把干员排进制造站、贸易站、控制中枢等设施,并完成心情恢复与产物切换。本文面向已跑通基础功能、想弄清换班如何决策与如何写自定义排班 JSON 的中高级用户:读完你可以按源码口径解释任意一次换班的执行顺序,并能独立编写、校验自己的排班作业。
从一次点击到换班完成:三种 mode 的执行路径
现象上你在任务设置里选择"常规模式""队列轮换"或"自定义基建配置",其余操作一致。差异全部集中在参数注入阶段:src/MaaCore/Task/Interface/InfrastTask.cpp 的set_params读取mode参数(枚举定义在 src/MaaCore/Task/Interface/InfrastTask.h:Default = 0、Custom = 10000、Rotation = 20000),再据此装配一条子任务链。
| mode 值 | 模式 | 参数依赖 |
|---|---|---|
| 0 | 常规(Default) | facility、threshold、drones、四个跨设施组合开关 |
| 10000 | 自定义(Custom) | facility、filename、plan_index |
| 20000 | 队列轮换(Rotation) | facility;drones不生效 |
换班设施列表为什么不是顺序
在常规模式下,facility参数(取值Dorm/Mfg/Trade/Power/Office/Control/Reception/Processing/Training/AssistantChange)在 AsstInfrastDef.h 的build_facility_plan中先被装入std::unordered_set去重,然后按固定顺序输出步骤:制造站巡检 → 宿舍前置轮 → 发电站 → 办公室 → 控制中枢 → 制造站 → 贸易站 → 会客室 → 宿舍重排轮 → 加工站 → 训练室 → 副手换人。也就是说你在 GUI 里调整"换班设施"的顺序不会产生任何效果,顺序由这套固定编码决定。
两个特殊分支:
- 只启用贸易站未启用制造站时,计划开头插入
MfgInspect:制造站以set_inspect_only(true)运行,只读取产物类型与赤金线数量供贸易站评分使用,不进入干员选择、不使用无人机(InfrastTask.cpp构造函数与build_facility_plan注释)。 - 宿舍前置轮
DormPrepare在常规模式下仅当fiammetta_recovery_enabled为 true 时才执行,否则整步跳过;宿舍重排轮DormRearrange不受影响,始终清空宿舍后按心情升序安置低心情干员。
触发条件 → 处理 → 结果的降级逻辑:facility中出现未知字符串,或某项不是字符串时,set_params会清空已装配的子任务、只保留进入基建入口任务,并返回 false,本次基建换班直接失败。
常规模式下的菲亚梅塔心情恢复走的是常驻m_dorm_task_ptr(prepare 相位):fiammetta_targets经infrast::normalize_fiammetta_targets规范化(最多 3 名),换班开始时挑当前心情最低的目标与菲亚梅塔同进宿舍互换,再把目标换出。这与自定义模式由 JSON 注入的临时宿舍任务(见后文)是两条独立实现。
验证方法:常规模式下只勾选贸易站与宿舍,观察EnterFacility回调序列,会依次出现 Mfg(巡检)→ Dorm → Trade → Dorm,与勾选顺序无关;把fiammetta_recovery_enabled关掉后,前置宿舍轮不再出现。
队列轮换与自定义模式的装配差异
队列轮换(mode=20000)走build_facility_plan的另一分支:步骤按facility的声明顺序输出(该分支保留数组顺序),但Dorm、Power、Office、Control四类设施被rotation_skips集合整体跳过;制造站、贸易站、会客室三个任务被set_skip_shift(true),只做轮换不执行换人,并在链首插入InfrastEnterRotation入口任务(set_ignore_error(true),进入失败不阻断后续)。
自定义模式(mode=10000)不读取 GUI 的drones、四个跨设施组合开关(相关代码位于mode != Mode::Custom与default_mode判断之后),全部行为由filename指向的作业文件决定。
决策流:每个设施入口处的筛选、枚举与复核
现象上,MAA 点进每个房间后"自动选了效率最高的干员"。这一句背后是 InfrastProductionTask.cpp 中shift_facility_list()的固定次序:产物识别 → 无人机(pre)→ skip 判定 → 换人(编组匹配 / 自定义选择 / 算法选择)→ 复核 → 确认 → 无人机(post)。
产物识别与无人机触发点
每个房间先按InfrastFlag*模板匹配当前产物,只有得分达到模板阈值才采信(set_product回调ProductOfFacility);识别不可靠时清空m_product,跳过所有依赖产物的分支。常规模式下制造站还会在此处按产物是否赤金更新TaskData::gold_station_num,供后续贸易站评分。无人机按m_custom_drones_config.order分两侧:Pre在换人之前、Post在换人之后触发,且index(已转为 0 基)必须等于当前房间下标才生效。
干员候选如何过滤
opers_detect()滑完整个干员列表,过滤规则是:mood_ratio低于m_mood_threshold(即 GUI 的"基建工作心情阈值",默认 0.3)的干员剔除;脸像哈希距离过近的视为同一干员去重。常规模式下,技能集合无法唯一确定身份时调用resolve_operator_identity做 OCR 确认,身份仍冲突的干员只计通用技能效果,不触发特殊加成与跨设施联动——这就是"识别不出名字的干员不会被误联动"的底层原因。
常规模式如何给组合打分
optimal_calc()在常规模式下构建ScoreContext(设施、产物、空位数、宿舍容量与等级和、赤金线数、发电站数、selected_operator_ids等),调用 InfrastScore.cpp 的select_best_opers做全组合枚举,用score_trade/score_mfg打分取最高分。打分基于 8 小时平均收益近似:不计算心情消耗与换班间隔,概率性效果忽略,部分技能值被手动微调以制造优先级。两个值得注意的规则:
- 容量防护:
max_storage + storage_sum < 20 || storage_sum < -15时组合直接禁选(score_mfg末尾)。 only_need机制:巫恋组、温蒂自动化类等特殊组合标记出唯一需要的干员,select_combinations会把其余被选中干员从结果中释放给后续房间使用。
跨设施加成的判定依据是context.selected_operator_ids,例如黑键在贸易站的"怅惘和声"只有在絮雨或迷迭香已被选入其他设施时补 0.44 效率。这份已选集合来自共享的TaskData,干员点进房间时仅stage_operator_selection暂存到 pending,点击确认按钮(click_confirm_button)才真正commit_pending进入全局集合——所以设施间"谁先上"直接受前面提到的固定换班顺序影响。
红松骑士团、感知信息、人间烟火、深海猎人四个参数(use_pinus_sylvestris/use_perception_information/use_worldly_plight/use_abyssal_hunter)只写入m_default_mode任务,自定义模式传了也会被忽略。
验证方法:查看日志中optimal_calc输出的infrastructure optimal score(设施名、分数、选中数);把"基建工作心情阈值"调到 1.0 会看到几乎所有干员被过滤、房间留空。
配置面:自定义排班 JSON 的解析、校验与字段行为
现象上你只改一个 JSON 文件,但它的解析发生在set_params阶段而非运行时:任何解析错误(文件不存在、JSON 非法、plan_index越界、未知product、未知房间键、无人机room取值错误)都会让set_params返回 false,整次基建换班无法启动。⚠️ 因此先验证 JSON 语法再运行,比事后看日志更快。
解析链与失败点
parse_and_set_custom_config的执行顺序(均在 InfrastTask.cpp):校验文件存在且为普通文件 → 打开 JSON → 按plan_index从plans数组取计划 → 录入groups编组 → 遍历rooms把每类设施注入对应任务 → 处理Fiammetta→ 处理drones。其中rooms的键必须命中control/manufacture/trading/power/meeting/hire/processing/dormitory之一,否则整体失败;注意这里的键名与facility参数的取值(Dorm、Mfg等)是两套词表。
换人后的复核(select_opers_review,InfrastAbstractTask.cpp):OCR 已选列表,逐一核销自定义名单,若选中了"工作中"的干员或自定义名单未选全则返回 false,调用方还原原始房间配置并重选。宿舍类房间(is_dorm_order)跳过复核,直接按心情排序进驻。
房间字段与执行时序
房间数组的下标必须与游戏内房间 tab 序号一致(current_room_config()用m_cur_facility_index取配置,越界时该房间起不再换班)。
| 字段 | 默认值 | 行为要点 |
|---|---|---|
skip | false | 只跳过换人;产物识别、无人机、线索交流等操作照常 |
autofill | false | 空名单 = 整房走原算法;非空 = 只按单干员效率补位,不算组合 |
sort | false | 仅当选中人数大于 1 时生效;稀音/帕拉斯等需要暖机顺序的干员必须置true |
product | 空 | 取值Battle Record/Pure Gold/Dualchip/Originium Shard/LMD/Orundum;未知值解析直接失败 |
candidates | 空 | 备选名单,有谁选谁直到选满;文档声明与autofill: true不兼容 |
use_operator_groups | false | 启用后operators里写的是编组名,按声明顺序取第一个全员可用的编组 |
groups(plan 级) | 空 | 编组定义,仅对 control / manufacture / trading 生效;只装载被引用的编组;匹配失败回调CustomInfrastRoomGroupsMatchFailed |
Fiammetta(plan 级) | 无 | target经 OCR 识别,为空则整段跳过;order取值pre/post,默认pre |
drones(plan 级) | 无 | room只接受trading/manufacture;index为 1 基(对应左侧 tab 序号,内部减 1);order默认pre;rule为保留字段,当前无任何代码读取 |
duration(plan 级) | — | 保留字段,当前版本不产生任何行为 |
period字段 core 同样不处理,按计划文档说明需接口集成方自行实现按时段选计划的逻辑。产物不一致时触发ProductIncorrect回调(界面红色提示),随后change_product每类产物最多重试 3 次;切换失败只记录警告,不阻断后续换人。
无人机与菲亚梅塔都是pre时,additional_advance_drones触发:在链首插入一个独立的纯无人机任务(目标房间用skip: true占位,只执行use_drone),注释说明"无人机和菲亚梅塔同时为 true 时,优先使用无人机"。菲亚梅塔pre的实现是插入两个临时InfrastDormTask:先把target单独挪出宿舍,再按target+菲亚梅塔的顺序进驻——源码注释解释了原因:若菲亚梅塔本来就在宿舍第二格,直接换不会触发技能,所以强制变位。
最小可用示例与字段速查
{ "title": "基础两班", "plans": [ { "name": "A 班", "drones": { "room": "trading", "index": 1, "order": "pre" }, "rooms": { "manufacture": [ { "operators": ["芬", "稀音", "克洛丝"], "sort": true, "product": "Battle Record" }, { "skip": true } ], "trading": [ { "operators": ["古米", "银灰"], "candidates": ["梅"], "autofill": true } ], "power": [ { "autofill": true } ] } }, { "name": "B 班", "Fiammetta": { "target": "可露希尔", "order": "pre" }, "rooms": { "manufacture": [ { "autofill": true }, { "autofill": true } ], "trading": [ { "autofill": true } ] } } ] }注释仅为示意,直接复制会报错。rooms里没写的设施(如control、dormitory)使用默认算法换班;想完全不处理某个设施,用房间级skip: true,或在任务设置里取消对应设施勾选。内置作业可参考 resource/custom_infrast/153_layout_3_times_a_day.json,注意其文件头声明干员配置要求极高。
延伸材料
- 协议文档:docs/zh-cn/protocol/base-scheduling-schema.md
- 官方手册:docs/zh-cn/manual/introduction/infrastructure.md
- 任务装配:src/MaaCore/Task/Interface/InfrastTask.cpp
- 换班计划与设施步骤枚举:src/MaaCore/Common/AsstInfrastDef.h
- 组合评分:src/MaaCore/Task/Infrast/InfrastScore.cpp
- 选人与复核:src/MaaCore/Task/Infrast/InfrastAbstractTask.cpp
【免费下载链接】MaaAssistantArknights《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients.项目地址: https://gitcode.com/GitHub_Trending/ma/MaaAssistantArknights
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考