AutoDomainCustomizable支援原粹樹脂刷取數量 (#2940)

* 自定義參數的自動秘境腳本

可自訂義樹脂數量、刷取輪次、隊伍等參數的自動秘境腳本

* 支持週期性素材

支持天賦書、武器升級素材

* 支持週期性素材刷取

支持武器素材、天賦書刷取,顯示從秘境名稱改為以掉落物為主

* 适配月之四版本,重构以便后续维护

1.适配月之四版本:新增圣遗物秘境
2.重构以便后续维护:将秘境信息与main.js拆分

* Add files via upload
This commit is contained in:
FFA
2026-02-28 10:05:12 +08:00
committed by GitHub
parent 6a4bccbf6b
commit e71fd942e6
4 changed files with 159 additions and 115 deletions

View File

@@ -5,14 +5,14 @@
---
如果你看到以下错误信息:
> 错误: 未找到对应的秘境 的传送点
代表BetterGI本体尚未支援新秘境请等待Bettergi本体更新支援新秘境。
⚠️有任何问题 **务必** 先阅读错误讯息,依照错误讯息指示修改设定,并确保你已 **完整阅读** 本说明。⚠️
---
遇到无法排除的问题,请将日志去除敏感资讯(如帐户名称)后至github提issue上传。
本JS脚本修改者没有QQ帐号。
本脚本采用AI进行生成修改修改者没有任何编程能力
故在此授权任何人可以在不标注、不知会修改者(RJFAC)的情况下对脚本内容维护、修改、重写、分享、上传、覆盖此脚本的部分或全部内容。
没有附上日志纪录的问题将被 **无视**
日志预设位置在 BetterGI\\log\\
---
@@ -28,72 +28,80 @@
## 🚀 使用方法
> ⚠️ **重要**:本脚本的参数需要在**调度器**中配置!
⚠️ **重要** :本脚本的参数需要在 **调度器** 中配置!
1. 在调度器中添加脚本。
2. **右键点击**脚本并选择 **“修改JS脚本自定义配置”**。
1. 在调度器中添加脚本。
2. **右键点击**脚本并选择 **“修改JS脚本自定义配置”**。
### 📌 必填项
* **指定要前往的秘境**
* 请在下拉菜单中选择目标副本。
* **注意**:【角色天赋】、【武器升级】、【圣遗物】三类选项**互斥** (只能选其中一个),若同时选择多项,脚本将报错停止
* 请在下拉菜单中选择目标副本
* **注意**:【角色天赋】、【武器升级】、【圣遗物】三类选项**互斥** (只能选其中一个),若同时选择多项,脚本将报错停止。
* **树脂策略配置**
* **刷取至树脂耗尽 (最高优先级)**
* 若启用此选项,脚本将**忽略**下方所有具体次数的设定。
* 消耗逻辑:优先使用**浓缩树脂**,耗尽后使用**原粹树脂**。
* **指定每种树脂刷取次数**
* 仅在“刷取至树脂耗尽”**关闭**时生效
* 脚本将按照设定的次数进行刷取(若四项均为 0 则不执行战斗)。
* 支持的树脂类型:
* **浓缩树脂**
* **原粹树脂** (注意:单次消耗 20 或 40 取决于秘境内上次的记忆设定)
* **须臾树脂**
* **脆弱树脂**
* **刷取至树脂耗尽 (最高优先级)**
* 若启用此选项,脚本将**忽略**下方所有具体次数的设定。
* 依照配置中 **树脂刷取顺序** 栏位中的树脂种类依序刷取至耗尽,未填写在顺序栏位中的树脂 **不会** 进行刷取
* **指定每种树脂刷取数量**
* 仅在“刷取至树脂耗尽”**关闭** 时生效。
* 脚本将按照设定的次数进行刷取(若四项均为 0 则不执行战斗)。
* 支持的树脂类型:
* **浓缩树脂**
* **原粹树脂(依照数量计算最少刷取次数)**
* **须臾树脂**
* **脆弱树脂**
### ⚙️ 可选项
* **【风险】强制运行**
* **功能**:勾选后将**忽略日期与星期几的检查**,直接进入副本。
* **适用场景**:仅在确认游戏内有“限时全开”或“精通移涌”活动时使用
* **警告**:若当日未开放该素材且无活动,勾选此项将会导致刷错素材
* **功能**:勾选后将**忽略日期与星期几的检查**,直接进入副本
* **适用场景**:仅在确认游戏内有“限时全开”或“精通移涌”活动时使用
* **警告**:若当日未开放该素材且无活动,勾选此项将会导致刷错素材。
* **自动切换到指定队伍**
* 输入预设队伍名称(需与游戏内完全一致,支持正则表达式),留空则不切换。
* 输入预设队伍名称(需与游戏内完全一致,支持正则表达式),留空则不切换。
* **秘境刷取轮数**
* `0`:刷到体力耗尽或达到指定树脂次数(默认)。
* `数字`:刷满该场数后强制停止(无论是否还有体力)。
* `0`:刷到体力耗尽或达到指定树脂次数(默认)。
* `数字`:刷满该场数后强制停止(无论是否还有体力)。
* **战斗完成后等待时间**
* 设置战斗结算后的缓冲秒数(默认 5 秒),防止因电脑读取卡顿导致过早退出或识别失败。
* 设置战斗结算后的缓冲秒数(默认 5 秒),防止因电脑读取卡顿导致过早退出或识别失败。
* **结束后自动分解圣遗物**
* **功能**:开启后,任务结束前会自动执行圣遗物分解逻辑。
* **分解星级**:可指定分解 **1~4 星** 的圣遗物(需配合下拉菜单设置)
* **功能**:开启后,任务结束前会自动执行圣遗物分解逻辑
* **分解星级**:可指定分解 **1~4 星** 的圣遗物(需配合下拉菜单设置)。
* **启用调试模式**
* 开启后会输出更多详细日志信息,用于脚本出错时排查问题。
* 开启后会输出更多详细日志信息,用于脚本出错时排查问题。
---
## ⏰ 时区设置
脚本会自动读取 BetterGI 的全局设置来判定今日素材。
请务必前往 **BetterGI设置 > 其他设置 > 服务器时区设置** 进行正确配置(如服设为 UTC+08:00
请务必前往 **BetterGI设置 > 其他设置 > 服务器时区设置** 进行正确配置(如官服/亚服/B服设为 UTC+08:00
---
## ⚠️ 已知问题
### 1. 原粹树脂消耗量 (20 vs 40)
BetterGI 传送并自动秘境任务不支持JS脚本选择 20 或 40 树脂。
若未手动切换,游戏会**沿用上一次**刷取时的设定。
* **操作建议**:若您打算使用原粹树脂,请在运行脚本前**手动进入一次秘境**,调整好 20 或 40 的选项。
### 为什么不能自动识别 "限时全开" 活动?
### 2. 为什么不能自动识别 "限时全开" 活动?
受限于 BetterGI 的底层架构设计,**JS 脚本无法获取游戏内的画面资讯**
* **执行时序矛盾**JS 脚本必须在任务开始 **前** 决定策略(刷什么副本),而 "限时全开" 的 OCR 识别是在任务开始 **后**C# 底层进入秘境介面时)才执行 。
* **数据无法回传**BetterGI 的 API 设计为「射后不理」(Fire-and-Wait),底层的 OCR 识别结果(如是否有限时字样)并不会回传给 JS 层 。
@@ -101,8 +109,13 @@ BetterGI 传送并自动秘境任务不支持JS脚本选择 20 或 40 树脂。
---
本脚本采用AI进行生成修改修改者 **没有任何编程能力**
故在此授权任何人可以在不标注、不知会修改者(RJFAC)的情况下对脚本内容维护、修改、重写、分享、上传、覆盖此脚本的部分或全部内容。
---
## 👨‍💻 关于作者
* **原作者**: [huiyadanli](https://github.com/huiyadanli), iris, 霁
* **修改者**: [RJFAC](https://github.com/RJFAC)
* **辅助生成**: AI
* **辅助生成**: AI

View File

@@ -1,3 +1,4 @@
// Version: 1.1
(async function () {
// =========================================================================
// 0. 动态加载数据 (基于 Genshin_Domains_SC_Live_Source.json)
@@ -6,10 +7,8 @@
const DB_FILENAME = "Genshin_Domains_SC_Live_Source.json";
try {
// [修正] 使用正确的方法名 ReadTextSync 读取文件
let rawContent = file.ReadTextSync(DB_FILENAME);
// 检查读取结果是否为空
if (!rawContent) {
throw new Error("读取文件返回空内容");
}
@@ -25,7 +24,6 @@
sourceData.domains.talent_books.forEach(item => {
let domain = item.domain_name_sc;
let schedule = item.schedule;
// 映射规则: Mon_Thu -> 1, Tue_Fri -> 2, Wed_Sat -> 3
if (schedule.Mon_Thu) MATERIAL_DB[schedule.Mon_Thu] = { domain: domain, idx: 1 };
if (schedule.Tue_Fri) MATERIAL_DB[schedule.Tue_Fri] = { domain: domain, idx: 2 };
if (schedule.Wed_Sat) MATERIAL_DB[schedule.Wed_Sat] = { domain: domain, idx: 3 };
@@ -47,7 +45,6 @@
if (sourceData.domains.artifacts) {
sourceData.domains.artifacts.forEach(item => {
let domain = item.domain_name_sc;
// 将 drops 数组组合成 key格式为 "Drop1 / Drop2"
let key = item.drops.join(" / ");
MATERIAL_DB[key] = { domain: domain, type: "artifact" };
});
@@ -58,23 +55,20 @@
} catch (e) {
log.error(`【致命错误】无法读取或解析 ${DB_FILENAME}`);
log.error(`错误详情: ${e.message}`);
log.error("请确保 JSON 文件存在于脚本目录中且格式正确。脚本已停止。");
return;
}
// =========================================================================
// 1. 读取用户设置
// 1. 读取并验证用户设置 (防呆机制)
// =========================================================================
let userConfig = settings;
let enableDebug = userConfig.EnableDebug;
// --- 读取三个独立栏位 ---
let pTalent = userConfig.TargetTalentMaterialName;
let pWeapon = userConfig.TargetWeaponMaterialName;
let pArtifact = userConfig.TargetArtifactName;
let pForceRunMode = userConfig.ForceRunMode;
// --- 互斥检查与目标确定 ---
let selectedCount = (pTalent ? 1 : 0) + (pWeapon ? 1 : 0) + (pArtifact ? 1 : 0);
if (selectedCount === 0) {
@@ -88,104 +82,111 @@
}
let pTargetMaterial = pTalent || pWeapon || pArtifact;
// --- 通用参数 ---
let pPartyName = userConfig.PartyName || "";
let pRunUntilDepleted = userConfig.RunUntilResinDepleted;
let pAutoArtifactSalvage = userConfig.AutoArtifactSalvage;
let pMaxArtifactStar = userConfig.MaxArtifactStar || "4";
// 初始化目标参数
let pDomainName = "";
let pSundaySelectedValue = "";
// 数值参数
let pOriginal = parseInt(userConfig.OriginalResinUseCount) || 0;
// --- 数值读取与防呆验证 ---
let pOriginalAmount = parseInt(userConfig.OriginalResinAmount) || 0;
let pOriginal40 = Math.floor(pOriginalAmount / 40);
let pOriginal20 = Math.floor((pOriginalAmount % 40) / 20);
let pCondensed = parseInt(userConfig.CondensedResinUseCount) || 0;
let pTransient = parseInt(userConfig.TransientResinUseCount) || 0;
let pFragile = parseInt(userConfig.FragileResinUseCount) || 0;
let pDomainRoundNum = parseInt(userConfig.DomainRoundNum) || 0;
let pFightEndDelay = parseInt(userConfig.FightEndDelay) || 5;
// 脆弱树脂 (手动输入框防呆)
let pFragileRaw = parseInt(userConfig.FragileResinUseCount);
let pFragile = (isNaN(pFragileRaw) || pFragileRaw < 0) ? 0 : pFragileRaw;
if (userConfig.FragileResinUseCount && (isNaN(pFragileRaw) || pFragileRaw < 0)) {
log.warn("【配置警告】脆弱树脂刷取数量输入无效或为负数,已自动重置为 0。");
}
// [新增] 树脂机制警告
if (!pRunUntilDepleted && pOriginal > 0) {
log.warn("【树脂警告】您设置了使用原粹树脂。由于 BetterGI 本体任务目前不支持选择 20/40 树脂:");
log.warn(" -> 请务必在运行脚本前,手动进入一次秘境,确认并调整好游戏内的树脂消耗选项,否则可能导致消耗不符合预期。");
// 秘境轮数 (手动输入框防呆)
let pDomainRoundNumRaw = parseInt(userConfig.DomainRoundNum);
let pDomainRoundNum = (isNaN(pDomainRoundNumRaw) || pDomainRoundNumRaw < 0) ? 0 : pDomainRoundNumRaw;
if (userConfig.DomainRoundNum && (isNaN(pDomainRoundNumRaw) || pDomainRoundNumRaw < 0)) {
log.warn("【配置警告】秘境刷取轮数输入无效,已自动重置为 0 (无限轮直至树脂耗尽)。");
}
// 战斗后等待时间 (手动输入框防呆)
let pFightEndDelayRaw = parseInt(userConfig.FightEndDelay);
let pFightEndDelay = (isNaN(pFightEndDelayRaw) || pFightEndDelayRaw < 0) ? 5 : pFightEndDelayRaw;
if (userConfig.FightEndDelay && (isNaN(pFightEndDelayRaw) || pFightEndDelayRaw < 0)) {
log.warn("【配置警告】战斗完成后等待时间输入无效,已恢复默认值 5 秒。");
}
// 树脂刷取顺序防呆 (正则过滤与去重)
let rawOrderStr = (userConfig.ResinUsageOrder || "").toString().trim();
if (/[^12345]/.test(rawOrderStr) && !pRunUntilDepleted) {
log.warn(`【配置警告】树脂刷取顺序包含无效字符,非 1~5 的内容已被自动过滤。`);
}
// 仅保留1~5并去除重复数字
let pOrderStr = [...new Set(rawOrderStr.replace(/[^12345]/g, '').split(''))].join('');
if (rawOrderStr.replace(/[^12345]/g, '').length !== pOrderStr.length && !pRunUntilDepleted) {
log.warn(`【配置警告】树脂刷取顺序中存在重复设定的数字,已自动去重处理为: ${pOrderStr}`);
}
let priorityList = [];
for (let char of pOrderStr) {
if (char === '1') priorityList.push("浓缩树脂");
else if (char === '2') priorityList.push("原粹树脂40");
else if (char === '3') priorityList.push("原粹树脂20");
else if (char === '4') priorityList.push("须臾树脂");
else if (char === '5') priorityList.push("脆弱树脂");
}
// 零动作警告
if (!pRunUntilDepleted && pOriginalAmount === 0 && pCondensed === 0 && pTransient === 0 && pFragile === 0 && pDomainRoundNum === 0) {
log.warn("【配置警告】您未设置任何树脂消耗数量,也未限制秘境轮数!脚本可能进本后无事可做。");
}
// =========================================================================
// 2. 智能逻辑处理
// 2. 智能逻辑处理 (日期检查)
// =========================================================================
// 中文星期对照表 (0-6)
const WEEK_MAP = ["日", "一", "二", "三", "四", "五", "六"];
let materialInfo = MATERIAL_DB[pTargetMaterial];
if (!materialInfo) {
log.error(`【数据错误】无法在数据库中找到项目:${pTargetMaterial}`);
log.error("请检查 JSON 数据文件是否包含此素材,或 settings.json 中的名称是否一致。");
return;
}
if (materialInfo.type === 'artifact') {
// [圣遗物] 每日开放,直接放行
pDomainName = materialInfo.domain;
pSundaySelectedValue = "";
log.info(`【圣遗物模式】目标:${pTargetMaterial}`);
log.info(`【自动定位】秘境:${pDomainName} (每日开放)`);
} else {
// [天赋/武器素材] 需要日期检查
let requiredIdx = materialInfo.idx;
pDomainName = materialInfo.domain;
pSundaySelectedValue = requiredIdx.toString();
// --- 全球通用时间逻辑 (跨时区修正版) ---
// 1. 获取 BGI 配置的服务器偏移量 (例如亚服为 +8小时单位毫秒)
let serverOffsetMs = ServerTime.GetServerTimeZoneOffset();
// 2. 获取当前的 UTC 时间戳 (全球统一,不受电脑时区影响)
let utcNow = Date.now();
// 3. 计算"游戏服务器的逻辑时间戳"
// 算法: UTC时间 + 服务器偏移量 - 4小时(换日)
// 这样算出来的时间,如果视作 UTC 时间,其"星期几"就是游戏内的"星期几"
let logicTimeMs = utcNow + serverOffsetMs - (4 * 60 * 60 * 1000);
let logicDate = new Date(logicTimeMs);
// 4. 获取 UTC 星期 (关键: 必须用 getUTCDay忽略本地时区)
let dayOfWeek = logicDate.getUTCDay();
let dayStr = WEEK_MAP[dayOfWeek];
if (enableDebug) {
// 调试信息:计算当前的服务器名义时间
let serverTimeDate = new Date(utcNow + serverOffsetMs);
log.info(`[DEBUG] 游戏服务器时间(UTC视角): ${serverTimeDate.toUTCString()}`);
log.info(`[DEBUG] 逻辑判定后星期: ${dayStr}`);
log.info(`[DEBUG] 游戏服务器时间: ${serverTimeDate.toUTCString()}`);
}
// 判断今日是否开放
let isDateOpen = false;
if (dayOfWeek === 0) isDateOpen = true; // 周日
else if (requiredIdx === 1 && (dayOfWeek === 1 || dayOfWeek === 4)) isDateOpen = true;
else if (requiredIdx === 2 && (dayOfWeek === 2 || dayOfWeek === 5)) isDateOpen = true;
else if (requiredIdx === 3 && (dayOfWeek === 3 || dayOfWeek === 6)) isDateOpen = true;
let isDateOpen = (dayOfWeek === 0) ||
(requiredIdx === 1 && (dayOfWeek === 1 || dayOfWeek === 4)) ||
(requiredIdx === 2 && (dayOfWeek === 2 || dayOfWeek === 5)) ||
(requiredIdx === 3 && (dayOfWeek === 3 || dayOfWeek === 6));
log.info(`【智能匹配】目标: ${pTargetMaterial} (游戏内星期${dayStr})`);
if (isDateOpen) {
log.info(`日期检查】通过,今日为常规开放日`);
} else {
log.warn(`【日期检查】警告:今日 (游戏内星期${dayStr}) 非该素材常规开放日!`);
if (pForceRunMode) {
log.warn(`【强制运行】检测到"强制运行"已勾选。脚本将继续执行。`);
log.warn(`【风险提示】若游戏内并无"限时全开"活动,底层的 OCR 将无法识别活动BetterGI 将会直接进入今日预设副本,导致刷错素材!`);
} else {
log.error(`【停止运行】为防止刷错素材,脚本已停止。`);
log.error(` -> 若您确认当前游戏有"限时全开/精通移涌"活动,请在设置中勾选"强制运行"以忽略此警告。`);
return; // 安全退出
}
if (!isDateOpen && !pForceRunMode) {
log.error(`停止运行】今日非该素材开放日。若需强制运行,请在设置中勾选`);
return;
}
}
@@ -202,12 +203,34 @@
taskParam.SundaySelectedValue = pSundaySelectedValue;
taskParam.SpecifyResinUse = !pRunUntilDepleted;
if (!pRunUntilDepleted) {
taskParam.OriginalResinUseCount = pOriginal;
// 赋值各类型树脂次数
taskParam.OriginalResin20UseCount = pOriginal20;
taskParam.OriginalResin40UseCount = pOriginal40;
taskParam.OriginalResinUseCount = 0; // 核心逻辑已改用 20/40 独立计算此项设为0
taskParam.CondensedResinUseCount = pCondensed;
taskParam.TransientResinUseCount = pTransient;
taskParam.FragileResinUseCount = pFragile;
taskParam.SetResinPriorityList("浓缩树脂", "原粹树脂", "须臾树脂", "脆弱树脂");
// 逻辑冲突警告检查
if (pOrderStr === "") {
log.warn("【配置警告】树脂刷取顺序完全留空!在指定次数模式下,脚本将不会消耗任何树脂。");
} else {
if (pCondensed > 0 && !pOrderStr.includes('1')) log.warn("【配置警告】浓缩树脂数量大于0但未配置在刷取顺序(1)中,将被底层忽略!");
if (pOriginal40 > 0 && !pOrderStr.includes('2')) log.warn("【配置警告】原粹树脂需要消耗40体力但未配置在刷取顺序(2)中,将被底层忽略!");
if (pOriginal20 > 0 && !pOrderStr.includes('3')) log.warn("【配置警告】原粹树脂需要消耗20体力但未配置在刷取顺序(3)中,将被底层忽略!");
if (pTransient > 0 && !pOrderStr.includes('4')) log.warn("【配置警告】须臾树脂数量大于0但未配置在刷取顺序(4)中,将被底层忽略!");
if (pFragile > 0 && !pOrderStr.includes('5')) log.warn("【配置警告】脆弱树脂数量大于0但未配置在刷取顺序(5)中,将被底层忽略!");
}
// 传入自定义优先级
if (priorityList.length > 0) {
taskParam.SetResinPriorityList(...priorityList);
} else {
// 若留空,传递空字串防止报错
taskParam.SetResinPriorityList("");
}
} else {
taskParam.SetResinPriorityList("浓缩树脂", "原粹树脂");
}
@@ -231,12 +254,11 @@
} else if (msg.includes("TaskCanceledException")) {
log.info("[脚本] 任务已取消。");
break;
} else if (msg.includes("未找到对应的秘境")) {
log.error("请等待BetterGI本体更新支援新秘境");
throw ex;
} else {
log.error(`[脚本] 错误: ${msg}`);
// [修改] 新增针对未找到传送点的错误提示
if (msg.includes("未找到对应的秘境")) {
log.error("请等待BetterGI本体更新支援新秘境");
}
throw ex;
}
}

View File

@@ -1,8 +1,8 @@
{
"manifest_version": 1,
"name": "传送并自动秘境(增强版)",
"version": "0.6",
"bgi_version": "0.55.0",
"version": "0.7",
"bgi_version": "0.57.0",
"description": "BetterGI自带脚本的增强版用于传送后并执行自动秘境。秘境中角色死亡复活后继续回去战斗。支持自定义各项参数如树脂设置、自动废弃圣遗物、轮数设置等与周期性素材刷取。(本脚本由AI辅助生成)",
"authors": [
{

View File

@@ -99,27 +99,36 @@
"default": false
},
{
"name": "OriginalResinUseCount",
"name": "ResinUsageOrder",
"type": "input-text",
"label": "原粹树脂刷取次数 (请先在游戏内手动调整 20/40 选项)",
"label": "树脂刷取顺序(1浓缩 2原40 3原20 4须臾 5脆弱)",
"default": "123"
},
{
"name": "OriginalResinAmount",
"type": "select",
"label": "原粹树脂刷取数量",
"options": ["0", "20", "40", "60", "80", "100", "120", "140", "160", "180", "200"],
"default": "0"
},
{
"name": "CondensedResinUseCount",
"type": "input-text",
"label": "浓缩树脂刷取数",
"type": "select",
"label": "浓缩树脂刷取数",
"options": ["0", "1", "2", "3", "4", "5"],
"default": "0"
},
{
"name": "TransientResinUseCount",
"type": "input-text",
"label": "须臾树脂刷取数",
"type": "select",
"label": "须臾树脂刷取数",
"options": ["0", "1", "2", "3"],
"default": "0"
},
{
"name": "FragileResinUseCount",
"type": "input-text",
"label": "脆弱树脂刷取数",
"label": "脆弱树脂刷取数",
"default": "0"
},
{