Files
bettergi-scripts-list/repo/js/AutoDomainCustomizable/main.js
FFA d86b52079c 自动秘境脚本适配月之四版本,重构以便后续维护 (#2758)
* 自定義參數的自動秘境腳本

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

* 支持週期性素材

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

* 支持週期性素材刷取

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

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

1.适配月之四版本:新增圣遗物秘境
2.重构以便后续维护:将秘境信息与main.js拆分
2026-01-22 14:00:24 +08:00

244 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(async function () {
// =========================================================================
// 0. 动态加载数据 (基于 Genshin_Domains_SC_Live_Source.json)
// =========================================================================
let MATERIAL_DB = {};
const DB_FILENAME = "Genshin_Domains_SC_Live_Source.json";
try {
// [修正] 使用正确的方法名 ReadTextSync 读取文件
let rawContent = file.ReadTextSync(DB_FILENAME);
// 检查读取结果是否为空
if (!rawContent) {
throw new Error("读取文件返回空内容");
}
let sourceData = JSON.parse(rawContent);
if (!sourceData || !sourceData.domains) {
throw new Error("JSON文件格式不正确缺少 domains 字段");
}
// --- 1. 转换角色天赋素材 ---
if (sourceData.domains.talent_books) {
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 };
});
}
// --- 2. 转换武器升级素材 ---
if (sourceData.domains.weapon_materials) {
sourceData.domains.weapon_materials.forEach(item => {
let domain = item.domain_name_sc;
let schedule = item.schedule;
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 };
});
}
// --- 3. 转换圣遗物 (type: 'artifact') ---
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" };
});
}
log.info(`【系统】成功加载外部数据文件: ${DB_FILENAME},包含 ${Object.keys(MATERIAL_DB).length} 条记录`);
} catch (e) {
log.error(`【致命错误】无法读取或解析 ${DB_FILENAME}`);
log.error(`错误详情: ${e.message}`);
log.error("请确保 JSON 文件存在于脚本目录中且格式正确。脚本已停止。");
return;
}
// =========================================================================
// 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) {
log.error("【配置错误】您未选择任何素材!请在天赋、武器或圣遗物中选择一项。");
return;
}
if (selectedCount > 1) {
log.error("【配置冲突】您同时选择了多种类型的素材!请只保留一项,将其余两项设为空。");
return;
}
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 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;
// [新增] 树脂机制警告
if (!pRunUntilDepleted && pOriginal > 0) {
log.warn("【树脂警告】您设置了使用原粹树脂。由于 BetterGI 本体任务目前不支持选择 20/40 树脂:");
log.warn(" -> 请务必在运行脚本前,手动进入一次秘境,确认并调整好游戏内的树脂消耗选项,否则可能导致消耗不符合预期。");
}
// =========================================================================
// 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}`);
}
// 判断今日是否开放
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;
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; // 安全退出
}
}
}
// =========================================================================
// 3. 执行主流程
// =========================================================================
while (true) {
try {
let taskParam = new AutoDomainParam(pDomainRoundNum);
taskParam.DomainName = pDomainName;
taskParam.PartyName = pPartyName;
taskParam.AutoArtifactSalvage = pAutoArtifactSalvage;
taskParam.MaxArtifactStar = pMaxArtifactStar;
taskParam.SundaySelectedValue = pSundaySelectedValue;
taskParam.SpecifyResinUse = !pRunUntilDepleted;
if (!pRunUntilDepleted) {
taskParam.OriginalResinUseCount = pOriginal;
taskParam.CondensedResinUseCount = pCondensed;
taskParam.TransientResinUseCount = pTransient;
taskParam.FragileResinUseCount = pFragile;
taskParam.SetResinPriorityList("浓缩树脂", "原粹树脂", "须臾树脂", "脆弱树脂");
} else {
taskParam.SetResinPriorityList("浓缩树脂", "原粹树脂");
}
await dispatcher.RunAutoDomainTask(taskParam);
if (pFightEndDelay > 0) {
log.info(`[脚本] 任务结束,等待 ${pFightEndDelay} 秒...`);
await sleep(pFightEndDelay * 1000);
}
break;
} catch (ex) {
let msg = ex.message || "";
if (msg.includes("背包物品已满") || msg.includes("未检测到秘境结束")) {
log.warn(`[脚本] 任务可能已完成,但检测到: ${msg}`);
break;
} else if (msg.includes("复苏")) {
log.warn(`[脚本] 角色死亡5秒后重试...`);
await sleep(5000);
continue;
} else if (msg.includes("TaskCanceledException")) {
log.info("[脚本] 任务已取消。");
break;
} else {
log.error(`[脚本] 错误: ${msg}`);
// [修改] 新增针对未找到传送点的错误提示
if (msg.includes("未找到对应的秘境")) {
log.error("请等待BetterGI本体更新支援新秘境");
}
throw ex;
}
}
}
})();