JS:CD-Aware-AutoGather_修正&優化_1.7->1.7.5 (#1982)

* Update main.js

* JS:CD-Aware-AutoGather_修正&優化_1.7->1.7.5

1.CooldownData.txt修正
    修正
        白灵果: 每天0点
        夏槲果: 每天0点
    新增
        冷鮮肉: 12小时
2.取消任務不再記錄冷卻時間
    1.7.5前:取消任務也會記錄冷卻時間
    1.7.5后:中斷任務不會再觸發冷卻記錄。
3.切換隊伍後冷卻時間正常記錄
    1.7.5前:若第一隊缺少指定元素角色,切換到第二隊後執行任務不會記錄冷卻。
    1.7.5后:換隊後執行任務后,會正確記錄冷卻時間。
4.增加坐标撿測,判斷任務是否正常執行
    出現斷網情況時,記錄坐標位置失敗,不會再觸發冷卻記錄。
5.支援多帳號記錄冷卻時間
    可以手動輸入聯機帳號名稱,解決多人聯機採集時,無法記錄聯機帳號世界冷卻時間的問題。
    填空時會使用帳號右下角UID來記錄冷卻時間
    默认為默认账号
        適配之前沒有鈎選 我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)
This commit is contained in:
this-Fish
2025-09-24 20:24:18 +08:00
committed by GitHub
parent d0769e4654
commit f7198a0d0a
6 changed files with 175 additions and 47 deletions

View File

@@ -9,13 +9,9 @@
鳅鳅宝玉: 12小时
神秘的肉: 12小时
兽肉: 12小时
「冷鲜肉」: 12小时
蜥蜴尾巴: 12小时
鱼肉: 12小时
白灵果: 12小时
夏槲果: 12小时
沉玉仙茗: 24小时
白萝卜: 每天0点
薄荷: 每天0点
澄晶实: 每天0点
@@ -51,7 +47,9 @@
烛伞蘑菇: 每天0点
宿影花: 每天0点
寒涌石: 每天0点
白灵果: 每天0点
夏槲果: 每天0点
沉玉仙茗: 24小时
晶蝶: 每天4点
铁块: 每天0点
@@ -62,7 +60,6 @@
水晶块: 每3天0点
紫晶块: 每3天0点
虹滴晶: 每3天0点
奇异的「牙齿」: 46小时
冰雾花花朵: 46小时
冰雾花: 46小时

View File

@@ -32,7 +32,7 @@
| 设置首选队伍名称 | 执行采集任务前切换到指定的队伍,未设置则不切换。 |
| 设置备选队伍名称 | 首选队伍缺少对应的采集角色时使用。<br>两支队伍的名称不要存在包含关系,例如不能一支叫`特产`一支叫`特产备选` |
| 停止运行时间 | 超过此时间后停止后续的任务会等待正在运行的那条json路线结束。 |
| 我肝的账号不止一个 | 如果你有多个账号,可以选中此选项,选中后将分账号维护对应的材料刷新时间。 |
| 我肝的账号不止一个 | 如果你有多个账号,可在输入框内为每个游戏帐号填写一个唯一的字符串以使他们的刷新时间分开保存互不干扰。这个唯一的字符串并不必须是帐号的UID只要互不相同就可以了。 <br>如果填空会自动使用原神中右下角UID作为区分账号的唯一字符串 |
| 即使同一种材料有多个版本的路线,也全都执行采集 | 如果某种材料选中了多个版本的路线(常见于不同作者),默认只会执行第一个。勾选此选项后会每个版本都执行,可能造成部分点位重复(空跑)。 |
| `↓` 地方特产\稻妻\绯樱绣球 | 根据你订阅的路径追踪任务数量,这里将会显示相应个数的选择框。<br>勾选后将执行你选中的条目的采集任务。<br>Tip: `↓`符号是在提示你应该勾选文本下面的选择框 |

View File

@@ -9,6 +9,16 @@ let currentParty = null;
let runMode = settings.runMode;
let subscribeMode = settings.subscribeMode;
// 用用戶自定義的唯一ID來區分不同帳號
async function get_profile_name() {
if (!settings.iHaveMultipleAccounts || settings.iHaveMultipleAccounts.trim() === "") {
// 使用OCR讀取UID作為目錄名
const uid = await getGameAccount(true, true);
return String(uid);
}
return settings.iHaveMultipleAccounts.toString().trim();
}
class ReachStopTime extends Error {
constructor(message) {
super(message);
@@ -135,7 +145,7 @@ async function runGatherMode() {
log.info(` - {0} (${info.coolType}刷新)`, item.label || item.name);
}
let account = await getGameAccount(settings.iHaveMultipleAccounts);
let account = await get_profile_name();
log.info("为{0}采集材料并管理CD", account);
await switchPartySafely(settings.partyName);
@@ -166,7 +176,7 @@ async function runClearMode() {
log.error("未选择任何材料,请在脚本配置中勾选所需项目");
}
const resetTimeStr = formatDateTime(getDefaultTime());
let account = await getGameAccount(settings.iHaveMultipleAccounts);
let account = await get_profile_name();
for (const pathTask of selectedMaterials) {
const recordFile = getRecordFilePath(account, pathTask);
const lines = pathTask.jsonFiles.map((filePath) => {
@@ -303,6 +313,33 @@ async function runPathTaskIfCooldownExpired(account, pathTask) {
log.debug(`记录文件{0}不存在或格式错误`, recordFile);
}
// 坐标检查函数
async function checkPositionChange(mapName, startX, startY) {
try {
await genshin.returnMainUi();
const endPos = await genshin.getPositionFromMap(mapName);
const endX = endPos.x;
const endY = endPos.y;
const diffX = Math.abs(endX - startX);
const diffY = Math.abs(endY - startY);
const totalDiff = diffX + diffY;
return {
success: true,
totalDiff: totalDiff,
shouldUpdate: totalDiff >= 5
};
} catch (error) {
log.error(`获取结束坐标失败: ${error.message}`);
return {
success: false,
totalDiff: 0,
shouldUpdate: false
};
}
}
// 3. 检查哪些 json 文件已过刷新时间
for (let i = 0; i < jsonFiles.length; i++) {
const jsonPath = jsonFiles[i];
@@ -320,35 +357,123 @@ async function runPathTaskIfCooldownExpired(account, pathTask) {
log.info(`${progress}{0}: 开始执行`, pathName);
let pathStartTime = new Date();
// 声明变量用于坐标检查
let startX, startY, mapName, gotStartPos = false;
// 获取地图名称和起始坐标
try {
await genshin.returnMainUi();
const jsonContent = file.readTextSync(jsonPath);
const jsonData = JSON.parse(jsonContent);
mapName = jsonData.info?.map_name || "Teyvat";
const startPos = await genshin.getPositionFromMap(mapName);
startX = startPos.x;
startY = startPos.y;
gotStartPos = true;
} catch (error) {
log.error(`获取起始坐标失败: ${error.message}`);
}
// 延迟抛出`UserCancelled`,以便正确更新运行记录
const cancel = await runPathScriptFile(jsonPath);
let diffTime = new Date() - pathStartTime;
// 如果用户取消,抛出异常
if (cancel) {
log.info(`${progress}{0}: 用户取消任務,不更新记录`, pathName);
throw new UserCancelled(cancel);
}
// 如果运行时间太短,尝试切换队伍
if (diffTime < 1000) {
// "队伍中没有对应元素角色"的错误不会抛出为异常,只能通过路径文件迅速结束来推测
if (settings.partyName && settings.partyName2nd) {
let newParty = (currentParty === settings.partyName) ? settings.partyName2nd : settings.partyName;
log.info("当前队伍{0}缺少该路线所需角色,尝试切换到{1}", currentParty, newParty);
await switchPartySafely(newParty);
await runPathScriptFile(jsonPath);
}
} else if (diffTime > 5000) {
recordMap[fileName] = calculateNextRunTime(new Date(), jsonPath);
const lines = [];
for (const [p, t] of Object.entries(recordMap)) {
lines.push(`${p}\t${formatDateTime(t)}`);
}
const content = lines.join("\n");
file.writeTextSync(recordFile, content);
log.info(`${progress}{0}: 已完成,下次刷新: ${formatDateTimeShort(recordMap[fileName])}`, pathName);
} else {
log.info(`${progress}{0}: 执行时间过短,不更新记录`, pathName);
}
logFakePathEnd(fileName, pathStart);
if (cancel) {
throw new UserCancelled(cancel);
log.info("当前队伍{0}缺少该路线所需角色,尝试切换到{1}", currentParty, newParty);
await switchPartySafely(newParty);
// 切换队伍后重新获取起始坐标
let secondStartX, secondStartY, secondGotStartPos = false;
try {
await genshin.returnMainUi();
const secondStartPos = await genshin.getPositionFromMap(mapName);
secondStartX = secondStartPos.x;
secondStartY = secondStartPos.y;
secondGotStartPos = true;
} catch (error) {
log.error(`第二次获取起始坐标失败: ${error.message}`);
}
// 记录第二次执行的开始时间
let secondPathStartTime = new Date();
const secondCancel = await runPathScriptFile(jsonPath);
let secondDiffTime = new Date() - secondPathStartTime;
if (secondCancel) {
log.info(`${progress}{0}: 用户取消任務,不更新记录`, pathName);
throw new UserCancelled(secondCancel);
}
// 检查坐标变化
let positionCheckResult = { success: false, shouldUpdate: false };
if (secondGotStartPos) {
positionCheckResult = await checkPositionChange(mapName, secondStartX, secondStartY);
}
// 根据运行时间和坐标变化决定是否更新记录
if (secondDiffTime < 1000) {
log.info(`${progress}{0}: 切换队伍后仍无法完成,不更新记录`, pathName);
} else if (secondDiffTime >= 5000 && positionCheckResult.success && positionCheckResult.shouldUpdate) {
// 二次执行成功&坐标变化足够 才更新记录
recordMap[fileName] = calculateNextRunTime(new Date(), jsonPath);
const lines = [];
for (const [p, t] of Object.entries(recordMap)) {
lines.push(`${p}\t${formatDateTime(t)}`);
}
const content = lines.join("\n");
file.writeTextSync(recordFile, content);
log.info(`${progress}{0}: 已完成,下次刷新: ${formatDateTimeShort(recordMap[fileName])}`, pathName);
} else if (!positionCheckResult.success) {
log.info(`${progress}{0}: 坐标获取失败,不更新记录`, pathName);
} else if (!positionCheckResult.shouldUpdate) {
log.info(`${progress}{0}: 切换队伍后出发点与终点过于接近,不记录运行数据`, pathName);
} else {
log.info(`${progress}{0}: 执行时间过短,不更新记录`, pathName);
}
} else {
log.info(`${progress}{0}: 执行时间过短,且无第二队伍,不更新记录`, pathName);
}
} else {
// 检查坐标变化
let positionCheckResult = { success: false, shouldUpdate: false };
if (gotStartPos) {
positionCheckResult = await checkPositionChange(mapName, startX, startY);
}
// 根据运行时间和坐标变化决定是否更新记录
if (diffTime >= 5000 && positionCheckResult.success && positionCheckResult.shouldUpdate) {
recordMap[fileName] = calculateNextRunTime(new Date(), jsonPath);
const lines = [];
for (const [p, t] of Object.entries(recordMap)) {
lines.push(`${p}\t${formatDateTime(t)}`);
}
const content = lines.join("\n");
file.writeTextSync(recordFile, content);
log.info(`${progress}{0}: 已完成,下次刷新: ${formatDateTimeShort(recordMap[fileName])}`, pathName);
} else if (!positionCheckResult.success) {
log.info(`${progress}{0}: 坐标获取失败,不更新记录`, pathName);
} else if (!positionCheckResult.shouldUpdate) {
log.info(`${progress}{0}: 出发点与终点过于接近,不记录运行数据`, pathName);
} else {
log.info(`${progress}{0}: 执行时间过短,不更新记录`, pathName);
}
}
logFakePathEnd(fileName, pathStart);
} else {
log.info(`${progress}{0}: 已跳过 (${formatDateTimeShort(recordMap[fileName])}刷新)`, pathName);
}

View File

@@ -1,15 +1,19 @@
{
"manifest_version": 1,
"name": "带CD管理的自动采",
"version": "1.7",
"bgi_version": "0.45.0",
"description": "自动同步你通过BetterGI订阅的地图追踪任务执行采集任务并管理材料刷新时间支持多账号。\n首次使用前请先简单阅读说明可在`全自动`——`JS脚本`页面,点击本脚本名称查看)",
"authors": [
{
"name": "Ayaka-Main",
"links": "https://github.com/Patrick-Ze"
}
],
"settings_ui": "settings.json",
"main": "main.js"
{
"manifest_version": 1,
"name": "带CD管理的自动采",
"version": "1.7.5",
"bgi_version": "0.45.0",
"description": "自动同步你通过BetterGI订阅的地图追踪任务执行采集任务并管理材料刷新时间支持多账号。\n首次使用前请先简单阅读说明可在`全自动`——`JS脚本`页面,点击本脚本名称查看)",
"authors": [
{
"name": "Ayaka-Main",
"links": "https://github.com/Patrick-Ze"
},
{
"name": "蜜柑魚",
"links": "https://github.com/this-Fish"
}
],
"settings_ui": "settings.json",
"main": "main.js"
}

View File

@@ -36,8 +36,9 @@
},
{
"name": "iHaveMultipleAccounts",
"type": "checkbox",
"label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间"
"type": "input-text",
"label": "我肝的账号不止一个\n根据唯一ID区分账号维护对应的材料刷新时间\n填空将使用右下角帐号UID区分账号维护对应的材料刷新时间",
"default": "默认账号"
},
{
"name": "acceptMultiplePathOfSameMaterial",

View File

@@ -36,8 +36,9 @@
},
{
"name": "iHaveMultipleAccounts",
"type": "checkbox",
"label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间"
"type": "input-text",
"label": "我肝的账号不止一个\n根据唯一ID区分账号维护对应的材料刷新时间\n填空将使用右下角帐号UID区分账号维护对应的材料刷新时间",
"default": "默认账号"
},
{
"name": "acceptMultiplePathOfSameMaterial",