diff --git a/repo/js/CD-Aware-AutoGather/CooldownData.txt b/repo/js/CD-Aware-AutoGather/CooldownData.txt
index 70a8d867b..d55957b5e 100644
--- a/repo/js/CD-Aware-AutoGather/CooldownData.txt
+++ b/repo/js/CD-Aware-AutoGather/CooldownData.txt
@@ -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小时
diff --git a/repo/js/CD-Aware-AutoGather/README.md b/repo/js/CD-Aware-AutoGather/README.md
index aeca2a6d8..7dba9c38f 100644
--- a/repo/js/CD-Aware-AutoGather/README.md
+++ b/repo/js/CD-Aware-AutoGather/README.md
@@ -32,7 +32,7 @@
| 设置首选队伍名称 | 执行采集任务前切换到指定的队伍,未设置则不切换。 |
| 设置备选队伍名称 | 首选队伍缺少对应的采集角色时使用。
两支队伍的名称不要存在包含关系,例如不能一支叫`特产`一支叫`特产备选` |
| 停止运行时间 | 超过此时间后,停止后续的任务(会等待正在运行的那条json路线结束)。 |
-| 我肝的账号不止一个 | 如果你有多个账号,可以选中此选项,选中后将分账号维护对应的材料刷新时间。 |
+| 我肝的账号不止一个 | 如果你有多个账号,可在输入框内为每个游戏帐号填写一个唯一的字符串以使他们的刷新时间分开保存,互不干扰。这个唯一的字符串并不必须是帐号的UID,只要互不相同就可以了。
如果填空,会自动使用原神中右下角UID作为区分账号的唯一字符串 |
| 即使同一种材料有多个版本的路线,也全都执行采集 | 如果某种材料选中了多个版本的路线(常见于不同作者),默认只会执行第一个。勾选此选项后会每个版本都执行,可能造成部分点位重复(空跑)。 |
| `↓` 地方特产\稻妻\绯樱绣球 | 根据你订阅的路径追踪任务数量,这里将会显示相应个数的选择框。
勾选后将执行你选中的条目的采集任务。
Tip: `↓`符号是在提示你应该勾选文本下面的选择框 |
diff --git a/repo/js/CD-Aware-AutoGather/main.js b/repo/js/CD-Aware-AutoGather/main.js
index 3d5f75a8d..8053caa80 100644
--- a/repo/js/CD-Aware-AutoGather/main.js
+++ b/repo/js/CD-Aware-AutoGather/main.js
@@ -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);
}
diff --git a/repo/js/CD-Aware-AutoGather/manifest.json b/repo/js/CD-Aware-AutoGather/manifest.json
index 83b65e549..2b68fb53c 100644
--- a/repo/js/CD-Aware-AutoGather/manifest.json
+++ b/repo/js/CD-Aware-AutoGather/manifest.json
@@ -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"
}
\ No newline at end of file
diff --git a/repo/js/CD-Aware-AutoGather/settings.json b/repo/js/CD-Aware-AutoGather/settings.json
index bb8379c1b..e6f27169c 100644
--- a/repo/js/CD-Aware-AutoGather/settings.json
+++ b/repo/js/CD-Aware-AutoGather/settings.json
@@ -36,8 +36,9 @@
},
{
"name": "iHaveMultipleAccounts",
- "type": "checkbox",
- "label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)"
+ "type": "input-text",
+ "label": "我肝的账号不止一个\n根据唯一ID区分账号维护对应的材料刷新时间\n填空将使用右下角帐号UID区分账号维护对应的材料刷新时间",
+ "default": "默认账号"
},
{
"name": "acceptMultiplePathOfSameMaterial",
diff --git a/repo/js/CD-Aware-AutoGather/settings.template.json b/repo/js/CD-Aware-AutoGather/settings.template.json
index 6841d05b3..6316beb99 100644
--- a/repo/js/CD-Aware-AutoGather/settings.template.json
+++ b/repo/js/CD-Aware-AutoGather/settings.template.json
@@ -36,8 +36,9 @@
},
{
"name": "iHaveMultipleAccounts",
- "type": "checkbox",
- "label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)"
+ "type": "input-text",
+ "label": "我肝的账号不止一个\n根据唯一ID区分账号维护对应的材料刷新时间\n填空将使用右下角帐号UID区分账号维护对应的材料刷新时间",
+ "default": "默认账号"
},
{
"name": "acceptMultiplePathOfSameMaterial",