diff --git a/repo/js/CD-Aware-AutoGather/README.md b/repo/js/CD-Aware-AutoGather/README.md
index a5bf6dda..aeca2a6d 100644
--- a/repo/js/CD-Aware-AutoGather/README.md
+++ b/repo/js/CD-Aware-AutoGather/README.md
@@ -28,11 +28,11 @@
| 选项 | 说明 |
| ---- | ---- |
+| `地图追踪`中已订阅的任务目录的处理方式 | 有三种处理方式:
- `每次自动扫描,并采集扫描到的所有材料`
- `手动扫描,并采集扫描到的所有材料`
- `手动扫描,只采集已勾选的材料`
`自动扫描`会在每次执行采集前扫描当前已订阅的任务目录,`手动扫描`则是手动将运行模式切换到扫描模式执行脚本进行扫描。
`采集所有`会无视后面的每个材料⬇️是否选中,`采集已勾选`则是根据勾选的列表进行采集 |
| 设置首选队伍名称 | 执行采集任务前切换到指定的队伍,未设置则不切换。 |
| 设置备选队伍名称 | 首选队伍缺少对应的采集角色时使用。
两支队伍的名称不要存在包含关系,例如不能一支叫`特产`一支叫`特产备选` |
| 停止运行时间 | 超过此时间后,停止后续的任务(会等待正在运行的那条json路线结束)。 |
| 我肝的账号不止一个 | 如果你有多个账号,可以选中此选项,选中后将分账号维护对应的材料刷新时间。 |
-| `地图追踪`中已订阅的任务目录的处理方式 | 有三种处理方式:
- `每次自动扫描,并采集扫描到的所有材料`
- `手动扫描,并采集扫描到的所有材料`
- `手动扫描,只采集已勾选的材料`
`自动扫描`会在每次执行采集前扫描当前已订阅的任务目录,`手动扫描`则是手动将运行模式切换到扫描模式执行脚本进行扫描。
`采集所有`会无视后面的每个材料⬇️是否选中,`采集已勾选`则是根据勾选的列表进行采集 |
| 即使同一种材料有多个版本的路线,也全都执行采集 | 如果某种材料选中了多个版本的路线(常见于不同作者),默认只会执行第一个。勾选此选项后会每个版本都执行,可能造成部分点位重复(空跑)。 |
| `↓` 地方特产\稻妻\绯樱绣球 | 根据你订阅的路径追踪任务数量,这里将会显示相应个数的选择框。
勾选后将执行你选中的条目的采集任务。
Tip: `↓`符号是在提示你应该勾选文本下面的选择框 |
diff --git a/repo/js/CD-Aware-AutoGather/lib/lib.js b/repo/js/CD-Aware-AutoGather/lib/lib.js
index a1ccb9bc..97816f7a 100644
--- a/repo/js/CD-Aware-AutoGather/lib/lib.js
+++ b/repo/js/CD-Aware-AutoGather/lib/lib.js
@@ -7,17 +7,16 @@
let scriptContext = {
scriptStartTime: new Date(),
- version: "1.0"
+ version: "1.1",
};
/**
- * 将 Date 对象格式化为 ISO 8601 字符串,包含本地时区(如:2020-09-28T20:20:20.999+08:00)
+ * 将 Date 对象格式化为 ISO 8601 字符串,包含本地时区(如:2020-09-28T20:20:20+08:00)
* @param {Date} date - 要格式化的日期对象
* @returns {string} 格式化后的字符串
*/
function formatDateTime(date) {
const pad = (n) => n.toString().padStart(2, "0");
- const padMs = (n) => n.toString().padStart(3, "0");
const year = date.getFullYear();
const month = pad(date.getMonth() + 1);
@@ -25,7 +24,6 @@ function formatDateTime(date) {
const hour = pad(date.getHours());
const minute = pad(date.getMinutes());
const second = pad(date.getSeconds());
- const ms = padMs(date.getMilliseconds());
// 获取时区偏移(分钟),转换成±HH:MM
const offset = -date.getTimezoneOffset();
@@ -33,7 +31,7 @@ function formatDateTime(date) {
const offsetHour = pad(Math.floor(Math.abs(offset) / 60));
const offsetMin = pad(Math.abs(offset) % 60);
- return `${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}${sign}${offsetHour}:${offsetMin}`;
+ return `${year}-${month}-${day}T${hour}:${minute}:${second}${sign}${offsetHour}:${offsetMin}`;
}
/**
@@ -329,9 +327,10 @@ async function switchPartySafely(partyName) {
*
* @async
* @param {*} multiAccount 是否使用OCR区分多个账号(可以传入一个设置项)
+ * @param {boolean} mask 对UID进行掩码,只保留开头和结尾
* @returns {Promise} 当前账号的UID,如果不区分多账号或OCR失败则返回"默认账号"。
*/
-async function getGameAccount(multiAccount = false) {
+async function getGameAccount(multiAccount = false, mask = true) {
let account = "默认账号";
if (!multiAccount) {
return account;
@@ -352,6 +351,10 @@ async function getGameAccount(multiAccount = false) {
const match = text.match(/\d+/);
if (match) {
account = match[0];
+ if (mask) {
+ // 避免完整UID出现在log中造成意外暴露
+ account = account.replace(/\d*(\d{4})\d{4}/, (match, group1) => match.replace(group1, "xxxx"));
+ }
}
break;
}
@@ -397,7 +400,7 @@ function getScriptName() {
* @returns {string} - 文件名。
*/
function basename(filePath) {
- const lastSlashIndex = filePath.lastIndexOf('\\'); // 或者使用 '/'
+ const lastSlashIndex = filePath.lastIndexOf("\\"); // 或者使用 '/'
return filePath.substring(lastSlashIndex + 1);
}
@@ -504,8 +507,9 @@ function _fakeLogCore(name, isJs = true, dateIn = null) {
logTime = dateIn;
}
- // 时间部分从第11位开始,长度是12("20:20:20.999")
- const formattedTime = formatDateTime(logTime).slice(11, 23);
+ const ms = logTime.getMilliseconds().toString().padStart(3, "0");
+ // 时间部分从第11位开始,长度是12("20:20:20")
+ const formattedTime = formatDateTime(logTime).slice(11, 19) + "." + ms;
if (isStart) {
logMessage =
@@ -594,3 +598,24 @@ function logFakeScriptEnd({ scriptName = null, startTime = new Date() } = {}) {
}
return _fakeLogCore(scriptName, true, startTime);
}
+
+/**
+ * 等待传送结束
+ * @param {Int} timeout 单位为ms
+ * @note 参考了七圣召唤七日历练脚本
+ */
+async function waitTpFinish(timeout = 30000) {
+ const region = RecognitionObject.ocr(1690, 230, 75, 350); // 队伍名称区域
+ const startTime = Date.now();
+
+ await sleep(500); //点击传送后等待一段时间避免误判
+ while (Date.now() - startTime < timeout) {
+ let res = captureGameRegion().find(region);
+ if (!res.isEmpty()) {
+ await sleep(600); //传送结束后有僵直
+ return;
+ }
+ await sleep(100);
+ }
+ throw new Error("传送时间超时");
+}
diff --git a/repo/js/CD-Aware-AutoGather/main.js b/repo/js/CD-Aware-AutoGather/main.js
index 8d7422ed..c1442c74 100644
--- a/repo/js/CD-Aware-AutoGather/main.js
+++ b/repo/js/CD-Aware-AutoGather/main.js
@@ -167,9 +167,8 @@ async function runClearMode() {
const resetTimeStr = formatDateTime(getDefaultTime());
let account = await getGameAccount(settings.iHaveMultipleAccounts);
for (const pathTask of selectedMaterials) {
- const jsonFiles = filterFilesInTaskDir(pathTask.label);
const recordFile = getRecordFilePath(account, pathTask);
- const lines = jsonFiles.map((filePath) => {
+ const lines = pathTask.jsonFiles.map((filePath) => {
return `${basename(filePath)}\t${resetTimeStr}`;
});
const content = lines.join("\n");
@@ -280,7 +279,7 @@ async function runPathScriptFile(jsonPath) {
async function runPathTaskIfCooldownExpired(account, pathTask) {
const recordFile = getRecordFilePath(account, pathTask);
- const jsonFiles = filterFilesInTaskDir(pathTask.label);
+ const jsonFiles = pathTask.jsonFiles;
log.info("{0}共有{1}条路线", pathTask.label, jsonFiles.length);
@@ -397,7 +396,13 @@ function getSelectedMaterials() {
if (selectAllMaterials || settings[entry.name] === true) {
let index = entry.label.indexOf(" ");
entry.label = entry.label.slice(index + 1); // 去除⬇️指示
- selectedMaterials.push(entry);
+ const jsonFiles = filterFilesInTaskDir(entry.label);
+ if (jsonFiles.length > 0) {
+ entry.jsonFiles = jsonFiles;
+ selectedMaterials.push(entry);
+ } else {
+ log.debug("跳过空文件夹: {0}", entry.label);
+ }
}
}
}
diff --git a/repo/js/CD-Aware-AutoGather/manifest.json b/repo/js/CD-Aware-AutoGather/manifest.json
index 07f3f1e4..f3656624 100644
--- a/repo/js/CD-Aware-AutoGather/manifest.json
+++ b/repo/js/CD-Aware-AutoGather/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "带CD管理的自动采集",
- "version": "1.4",
+ "version": "1.5",
"bgi_version": "0.45.0",
"description": "自动同步你通过BetterGI订阅的地图追踪任务,执行采集任务,并管理材料刷新时间(支持多账号)。\n首次使用前请先简单阅读说明(可在`全自动`——`JS脚本`页面,点击本脚本名称查看)",
"authors": [
diff --git a/repo/js/CD-Aware-AutoGather/settings.json b/repo/js/CD-Aware-AutoGather/settings.json
index b5c40abc..bb8379c1 100644
--- a/repo/js/CD-Aware-AutoGather/settings.json
+++ b/repo/js/CD-Aware-AutoGather/settings.json
@@ -9,6 +9,16 @@
"清除运行记录(重置材料刷新时间)"
]
},
+ {
+ "name": "subscribeMode",
+ "type": "select",
+ "label": "'地图追踪'中已订阅的任务目录的处理方式:",
+ "options": [
+ "每次自动扫描,并采集扫描到的所有材料",
+ "手动扫描,并采集扫描到的所有材料",
+ "手动扫描,只采集已勾选的材料"
+ ]
+ },
{
"name": "partyName",
"type": "input-text",
@@ -29,16 +39,6 @@
"type": "checkbox",
"label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)"
},
- {
- "name": "subscribeMode",
- "type": "select",
- "label": "'地图追踪'中已订阅的任务目录的处理方式:",
- "options": [
- "每次自动扫描,并采集扫描到的所有材料",
- "手动扫描,并采集扫描到的所有材料",
- "手动扫描,只采集已勾选的材料"
- ]
- },
{
"name": "acceptMultiplePathOfSameMaterial",
"type": "checkbox",
diff --git a/repo/js/CD-Aware-AutoGather/settings.template.json b/repo/js/CD-Aware-AutoGather/settings.template.json
index bd94811a..6841d05b 100644
--- a/repo/js/CD-Aware-AutoGather/settings.template.json
+++ b/repo/js/CD-Aware-AutoGather/settings.template.json
@@ -9,6 +9,16 @@
"清除运行记录(重置材料刷新时间)"
]
},
+ {
+ "name": "subscribeMode",
+ "type": "select",
+ "label": "'地图追踪'中已订阅的任务目录的处理方式:",
+ "options": [
+ "每次自动扫描,并采集扫描到的所有材料",
+ "手动扫描,并采集扫描到的所有材料",
+ "手动扫描,只采集已勾选的材料"
+ ]
+ },
{
"name": "partyName",
"type": "input-text",
@@ -29,16 +39,6 @@
"type": "checkbox",
"label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)"
},
- {
- "name": "subscribeMode",
- "type": "select",
- "label": "'地图追踪'中已订阅的任务目录的处理方式:",
- "options": [
- "每次自动扫描,并采集扫描到的所有材料",
- "手动扫描,并采集扫描到的所有材料",
- "手动扫描,只采集已勾选的材料"
- ]
- },
{
"name": "acceptMultiplePathOfSameMaterial",
"type": "checkbox",
diff --git a/repo/js/GeniusInvokationTCGQuickProficiency/README.md b/repo/js/GeniusInvokationTCGQuickProficiency/README.md
index f2f3ed8a..eb62fc28 100644
--- a/repo/js/GeniusInvokationTCGQuickProficiency/README.md
+++ b/repo/js/GeniusInvokationTCGQuickProficiency/README.md
@@ -34,6 +34,8 @@
这种情况只能手动操作小号投降(见前面的[使用说明](#使用说明))。由于发起邀请的角色(大号)操作会更复杂,建议用脚本来发起邀请。
+ 或者你也可以在QQ群或者QQ频道找同样想刷熟练度的玩家,互相挂投降模式协助对方。[右击此链接——在新窗口中打开](https://bettergi.com/community.html)查看QQ群和QQ频道信息。
+
- **只有一台电脑,能不能运行一个原神,运行一个云原神?**
Better GI在检测到已经有运行中的实例时不会再启动第二份,但并不像原神那样针对同一台物理设备。我也尝试过通过创建多个Windows账号,以双开Better GI,但是后启动的截图器会报错,可能是无法同时运行多个截图器。