From 0241a651680fc4c0e65692e3a4e4320b7ee35c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BA=81=E5=8A=A8=E7=9A=84=E6=B0=A8=E6=B0=94?= <131591012+zaodonganqi@users.noreply.github.com> Date: Mon, 24 Nov 2025 13:36:10 +0800 Subject: [PATCH] =?UTF-8?q?Revert=20"feat:=20vMiliastraExperienceAutomatio?= =?UTF-8?q?n=E5=9F=BA=E7=A1=80=E4=B8=8A=E4=BF=AE=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=87=AA=E5=B7=B1=E6=94=B6=E8=97=8F=E7=9A=84?= =?UTF-8?q?=E5=8D=83=E6=98=9F=E5=85=B3=E5=8D=A1=20(#2392)"=20(#2394)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 65d9652284b16156cdde56e73a4672aecff17a7e. --- .../README.md | 31 - .../assets/Enter.png | Bin 1692 -> 0 bytes .../assets/Enter2.png | Bin 1171 -> 0 bytes .../assets/Exit.png | Bin 2863 -> 0 bytes .../main.js | 530 ------------------ .../manifest.json | 26 - .../settings.json | 38 -- .../store/data.json | 7 - 8 files changed, 632 deletions(-) delete mode 100644 repo/js/MiliastraExperienceAutomationByCollect/README.md delete mode 100644 repo/js/MiliastraExperienceAutomationByCollect/assets/Enter.png delete mode 100644 repo/js/MiliastraExperienceAutomationByCollect/assets/Enter2.png delete mode 100644 repo/js/MiliastraExperienceAutomationByCollect/assets/Exit.png delete mode 100644 repo/js/MiliastraExperienceAutomationByCollect/main.js delete mode 100644 repo/js/MiliastraExperienceAutomationByCollect/manifest.json delete mode 100644 repo/js/MiliastraExperienceAutomationByCollect/settings.json delete mode 100644 repo/js/MiliastraExperienceAutomationByCollect/store/data.json diff --git a/repo/js/MiliastraExperienceAutomationByCollect/README.md b/repo/js/MiliastraExperienceAutomationByCollect/README.md deleted file mode 100644 index 0cde8e820..000000000 --- a/repo/js/MiliastraExperienceAutomationByCollect/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# MiliastraExperienceAutomationByCollect - -千星奇域每周刷取经验值,可以使用已经收藏的运行,这样下架的也能用,代码修改使用Gemini3 pro preview - -### 🌟 功能介绍 - -- 自动重复通关指定奇域关卡,高效刷取经验值。 -- 自动追踪每周经验获取进度,达到上限后再次执行将自动跳过,避免重复刷取。 -- 执行完毕后自动返回提瓦特大陆,不干扰其他自动化流程。 - -### 📖 使用方法 - -- 将本脚本添加至您的配置组中。 -- 右键点击脚本自定义配置项(当同时配置了多个关卡id时,假设设置了20次循环,会以20次A,然后20次B这样的形式依次循环)。 -- 点击运行按钮。 - -### 🛠️ 脚本配置 - -| 配置项 | 描述 | 默认值 | -| -------------- | ------------------------- |------------| -| goToTeyvat | 完成后返回提瓦特大陆 | true | -| room | 奇域关卡关键词或关卡 GUID(支持多个id,用中文或英文逗号隔开) | 7070702264 | -| force | 忽略本周经验值已达上限 | false | -| thisAttempts | 指定通关次数 | 0 | -| expWeeklyLimit | 每周可获取的经验值上限 | 4000 | -| expPerAttempt | 每次通关获取的经验值数量 | 20 | - -### ❗ 注意事项 - -- 请确保游戏窗口分辨率比例为 `16:9`,否则可能影响脚本正常运行。 -- 建议提前设置好快捷键,便于在需要时快速暂停或终止脚本。 diff --git a/repo/js/MiliastraExperienceAutomationByCollect/assets/Enter.png b/repo/js/MiliastraExperienceAutomationByCollect/assets/Enter.png deleted file mode 100644 index e53a33bf2b7bc0107f1bf3e36739bd397adbdc7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1692 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 diff --git a/repo/js/MiliastraExperienceAutomationByCollect/assets/Exit.png b/repo/js/MiliastraExperienceAutomationByCollect/assets/Exit.png deleted file mode 100644 index af8da74512575947d13297eecd677de5cbd40424..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2863 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 N002ovPDHLkV1g { - const { maxAttempts = defaultMaxAttempts, retryInterval = defaultRetryInterval } = options || {}; - for (let i = 0; i < maxAttempts; i++) { - if (i === 0 && condition()) - return true; - await retryAction?.(); - await sleep(retryInterval); - if (condition()) - return true; - } - return false; -}; -const waitForRegionAppear = async (regionProvider, retryAction, options) => { - return waitForAction(() => { - const region = regionProvider(); - return region != null && region.isExist(); - }, retryAction, options); -}; -const waitForRegionDisappear = async (regionProvider, retryAction, options) => { - return waitForAction(() => { - const region = regionProvider(); - return !region || !region.isExist(); - }, retryAction, options); -}; - -// node_modules/.pnpm/@bettergi+utils@0.1.1/node_modules/@bettergi/utils/dist/asserts.js -const assertRegionAppearing = async (regionProvider, message, retryAction, options) => { - const isAppeared = await waitForRegionAppear(regionProvider, retryAction, options); - if (!isAppeared) { - throw new Error(message); - } -}; -const assertRegionDisappearing = async (regionProvider, message, retryAction, options) => { - const isDisappeared = await waitForRegionDisappear(regionProvider, retryAction, options); - if (!isDisappeared) { - throw new Error(message); - } -}; - -// node_modules/.pnpm/@bettergi+utils@0.1.1/node_modules/@bettergi/utils/dist/ocr.js -const findFirst = (ir, ro, predicate) => { - const candidates = ir.findMulti(ro); - for (let i = 0; i < candidates.count; i++) { - if (predicate(candidates[i])) - return candidates[i]; - } - return void 0; -}; -const findImageWithinBounds = (path, x, y, w, h) => { - try { - const ir = captureGameRegion(); - const ro = RecognitionObject.templateMatch(file.readImageMatSync(path), x, y, w, h); - const result = findFirst(ir, ro, (region) => region.isExist()); - ir.dispose(); - return result; - } catch (err) { - err?.message && log.warn(`${err.message}`); - } -}; -const findText = (text, options) => { - const { ignoreCase = true, contains = false } = options || {}; - const searchText = ignoreCase ? text.toLowerCase() : text; - const ir = captureGameRegion(); - const ro = RecognitionObject.ocrThis; - const result = findFirst(ir, ro, (region) => { - const itemText = ignoreCase ? region.text.toLowerCase() : region.text; - const isMatch = contains ? itemText.includes(searchText) : itemText === searchText; - return isMatch && region.isExist(); - }); - ir.dispose(); - return result; -}; -const findTextWithinBounds = (text, x, y, w, h, options) => { - const { ignoreCase = true, contains = false } = options || {}; - const searchText = ignoreCase ? text.toLowerCase() : text; - const ir = captureGameRegion(); - const ro = RecognitionObject.ocr(x, y, w, h); - const result = findFirst(ir, ro, (region) => { - const itemText = ignoreCase ? region.text.toLowerCase() : region.text; - const isMatch = contains ? itemText.includes(searchText) : itemText === searchText; - return isMatch && region.isExist(); - }); - ir.dispose(); - return result; -}; - -// node_modules/.pnpm/@bettergi+utils@0.1.1/node_modules/@bettergi/utils/dist/store.js -const useStore = (name) => { - const filePath = `store/${name}.json`; - const obj = (() => { - try { - const text = file.readTextSync(filePath); - return JSON.parse(text); - } catch { - return {}; - } - })(); - const createProxy = (target, parentPath = []) => { - if (typeof target !== "object" || target === null) { - return target; - } - return new Proxy(target, { - get: (target2, key) => { - const value = Reflect.get(target2, key); - return typeof value === "object" && value !== null ? createProxy(value, [...parentPath, key]) : value; - }, - set: (target2, key, value) => { - const success = Reflect.set(target2, key, value); - if (success) { - Promise.resolve().then(() => { - file.writeTextSync(filePath, JSON.stringify(obj, null, 2)); - }); - } - return success; - }, - deleteProperty: (target2, key) => { - const success = Reflect.deleteProperty(target2, key); - if (success) { - Promise.resolve().then(() => { - file.writeTextSync(filePath, JSON.stringify(obj, null, 2)); - }); - } - return success; - } - }); - }; - return createProxy(obj); -}; - -// src/misc.ts -const findHeaderTitle = (title, contains) => findTextWithinBounds(title, 0, 0, 300, 95, { contains }); -const findBottomTitle = (title, contains) => findTextWithinBounds(title, 0, 600, 300, 400, { contains }); -const findBottomButton = (text, contains) => findTextWithinBounds(text, 960, 980, 960, 100, { contains }); -const getNextMonday4AM = () => { - const now = /* @__PURE__ */ new Date(); - const result = new Date(now); - result.setHours(4, 0, 0, 0); - const currentDay = now.getDay(); - let daysUntilMonday; - if (currentDay === 1 && now.getHours() < 4) { - daysUntilMonday = 0; - } else { - daysUntilMonday = 8 - currentDay; - } - result.setDate(now.getDate() + daysUntilMonday); - return result; -}; - -// src/lobby.ts -const findMessageEnter = () => findImageWithinBounds("assets/Enter.png", 0, 1020, 960, 60); -const findMessageEnter2 = () => findImageWithinBounds("assets/Enter2.png", 0, 1020, 960, 60); -const findExitButton = () => findImageWithinBounds("assets/Exit.png", 960, 0, 960, 540); -const findGotTeyvatButton = () => findTextWithinBounds("返回", 1500, 0, 300, 95, { contains: true }); -const findClickAnywhere = () => findTextWithinBounds("空白处", 610, 950, 700, 60, { contains: true }); -const isInLobby = () => findMessageEnter() !== void 0 || findMessageEnter2() !== void 0; -const goToLobby = async () => { - const ok = await waitForAction( - isInLobby, - () => { - findBottomButton("大厅", true)?.click(); - }, - { maxAttempts: 60 } - ); - if (!ok) throw new Error("返回大厅超时"); -}; -const goBackToTeyvat = async () => { - log.info("打开当前大厅..."); - await assertRegionAppearing( - () => findHeaderTitle("大厅", true), - "打开当前大厅超时", - () => { - keyPress("F2"); - }, - { maxAttempts: 10 } - ); - await assertRegionAppearing( - findMessageEnter, - "返回提瓦特大陆超时", - () => { - log.info("返回提瓦特大陆..."); - findGotTeyvatButton()?.click(); - findText("确认")?.click(); - }, - { maxAttempts: 120 } - ); -}; - -// src/room.ts -const createRoom = async (room) => { - log.info("打开人气奇域界面..."); - await assertRegionAppearing( - () => findHeaderTitle("人气", true), - "打开人气奇域界面超时", - () => { - keyPress("F6"); - } - ); - - log.info("打开收藏奇域界面..."); - await assertRegionAppearing( - () => findBottomTitle("收藏", true), - "打开收藏奇域界面超时", - () => { - findTextWithinBounds("收藏", 0, 500, 920, 580, { - contains: true - })?.click(); - } - ); - - log.info("搜索奇域关卡: {room}", room); - // 搜索栏范围:0-1920, 0-75 - const searchX = 0, searchY = 0, searchW = 1920, searchH = 75; - - // 1. 如果有残留文本,先清除 - const clearBtn = findTextWithinBounds("清除", searchX, searchY, searchW, searchH, { contains: true }); - if (clearBtn) { - log.info("清除旧搜索内容..."); - clearBtn.click(); - await sleep(500); - } - - // 2. 查找并点击搜索占位符 - const findSearchPlaceholder = () => findTextWithinBounds("搜索", searchX, searchY, searchW, searchH, { contains: true }); - await assertRegionAppearing( - findSearchPlaceholder, - "未找到搜索框", - undefined, - { maxAttempts: 10 } - ); - - const ph = findSearchPlaceholder(); - if (ph) { - ph.click(); - await sleep(500); - inputText(room); // 输入ID - await sleep(1000); - - // 3. 点击真正的搜索按钮 - const searchBtn = findTextWithinBounds("搜索", searchX, searchY, searchW, searchH, { contains: true }); - if (searchBtn) { - log.info("点击搜索按钮..."); - searchBtn.click(); - } - } - - // 4. 等待结果并点击固定坐标 (x:350, y:800) - log.info("等待搜索结果并选择..."); - await sleep(1500); - click(350, 800); - await sleep(1000); - - // 5. 循环检测进入逻辑 - // 大厅区域:1460-1600, 870-910 - const findEntryLobbyBtn = () => findTextWithinBounds("大厅", 1460, 870, 140, 40, { contains: true }); - // 开始区域:1470-1600, 870-905 - const findStartBtn = () => findTextWithinBounds("开始", 1470, 870, 130, 35, { contains: true }); - - log.info("准备进入房间..."); - - let loopCount = 0; - const maxLoops = 20; - - // 手动循环,确保点击“开始”后立即跳出 - while (loopCount < maxLoops) { - // 优先:如果看到“开始”,点击并直接退出函数 - const start = findStartBtn(); - if (start) { - log.info("发现'开始'按钮,点击并准备开始游戏..."); - start.click(); - await sleep(1000); // 确保点击生效 - return; // 【关键修改】直接结束 createRoom,不再重试 - } - - // 其次:如果看到“大厅”,点击进入 - const lobby = findEntryLobbyBtn(); - if (lobby) { - log.info("发现'大厅'入口,点击..."); - lobby.click(); - await sleep(1500); // 等待界面切换到出现“开始” - continue; // 继续下一次循环,去检测“开始” - } - - // 最后:如果什么都没看到,可能是卡片没点中,重试点击卡片 - log.info("未发现入口按钮,重试点击关卡卡片..."); - click(350, 800); - - await sleep(1500); // 等待卡片点击后的反应 - loopCount++; - } - - throw new Error("进入房间超时"); -}; - -const enterRoom = async (room) => { - const inLobby = isInLobby(); - if (inLobby) { - const enterButton = findTextWithinBounds("房间", 1580, 110, 320, 390, { - contains: true - }); - if (enterButton) { - log.info("当前已存在房间,进入房间...", room); - await assertRegionAppearing( - () => findHeaderTitle("房间", true), - "进入房间超时", - () => { - keyPress("P"); - } - ); - return; - } - } - log.info("当前不在房间内,创建房间...", room); - await createRoom(room); -}; - -const startGame = async () => { - let outputCount = 0; - - // 修改判定结束的条件 - // 区域 x 1660-1800 y 1000-1038 - // 宽 = 1800-1660 = 140, 高 = 1038-1000 = 38 - const findEndGameLobbyBtn = () => findTextWithinBounds("大厅", 1660, 1000, 140, 38, { contains: true }); - - log.info("进入游戏等待循环,等待关卡结束..."); - - await assertRegionAppearing( - findEndGameLobbyBtn, - "等待游戏结束超时", - async () => { - // 在等待结束的过程中,持续尝试点击“开始游戏”和“准备” - // 只有在没检测到结束的大厅按钮时,才尝试点击开始/准备,防止误触 - if (!findEndGameLobbyBtn()) { - findBottomButton("开始游戏")?.click(); - findBottomButton("准备", true)?.click(); - - const prepare = () => findText("加入准备", { contains: true }); - if (prepare()) { - log.info("加入准备区..."); - await assertRegionDisappearing(prepare, "等待加入准备区提示消失超时"); - click(770, 275); - } else { - // 出现升级提醒时,点击空白处继续 - findClickAnywhere()?.click(); - if (outputCount % 10 === 0) { - log.info("正在进行游戏,等待结束标志(x1660 y1000)..."); - } - outputCount++; - } - } - }, - { maxAttempts: 200, retryInterval: 2000 } // 增加等待时间 - ); - - log.info("检测到'大厅'按钮,本局游戏结束,返回大厅..."); - // 此时已经在大厅了,点击这个按钮返回大厅 - const btn = findEndGameLobbyBtn(); - if (btn) { - btn.click(); - await sleep(2000); // 等待返回动作完成 - } - - await goToLobby(); -}; - -// main.ts -(async function () { - setGameMetrics(1920, 1080, 1.5); - await genshin.returnMainUi(); - - // 检查当前是否在房间内,如果是则先退回到大厅 - const inLobby = isInLobby(); - if (!inLobby) { - log.info("检测到当前不在大厅,正在返回大厅..."); - try { - await goToLobby(); - } catch (e) { - log.warn("返回大厅失败,继续执行: " + (e.message || e)); - } - } - - const goToTeyvat = settings.goToTeyvat ?? true; - // 从房间号池中随机取一个 - let roomStr = settings.room; - // 支持中英文逗号分割多个房间号 - const rooms = roomStr.split(/[,,]/).map(r => r.trim()).filter(r => r); - const force = settings.force ?? false; - const thisAttempts = Math.max(0, Number(settings.thisAttempts || "0")); - const expWeeklyLimit = Math.max(1, Number(settings.expWeeklyLimit || "4000")); - const expPerAttempt = Math.max(1, Number(settings.expPerAttempt || "20")); - const store = useStore("data"); - store.weekly = store.weekly || { expGained: 0, attempts: 0 }; - store.nextWeek = store.nextWeek || getNextMonday4AM().getTime(); - if (Date.now() >= store.nextWeek) { - log.info("新的一周,重置本周经验值数据"); - store.weekly = { expGained: 0, attempts: 0 }; - store.nextWeek = getNextMonday4AM().getTime(); - } - - // 如果只有一个房间号,检查经验上限 - if (rooms.length === 1) { - if (store.weekly.expGained >= expWeeklyLimit) { - if (force) { - log.warn("本周获取经验值已达上限,强制执行"); - } else { - log.warn("本周获取经验值已达上限,跳过执行"); - return; - } - } - } else { - log.info("检测到多个房间号,将忽略经验上限直接执行"); - } - - // 如果指定了通关次数,不显示经验相关日志 - const isSpecifiedAttempts = thisAttempts > 0; - - try { - // 对每个房间号循环执行 - for (let roomIndex = 0; roomIndex < rooms.length; roomIndex++) { - const room = rooms[roomIndex]; - log.info("开始处理房间 " + room + " (" + (roomIndex + 1) + "/" + rooms.length + ")"); - - const expRemain = expWeeklyLimit - store.weekly.expGained; - let attempts = Math.ceil( - (expRemain > 0 ? expRemain : expWeeklyLimit) / expPerAttempt - ); - if (thisAttempts > 0) attempts = thisAttempts; - - // 对该房间执行指定次数 - for (let i = 0; i < attempts; i++) { - // 多房间模式时忽略经验上限检查 - if (rooms.length === 1 && !isSpecifiedAttempts) { - // 单房间模式且未指定次数:检查是否达到经验上限(仅第一次跳过,其他由内部判断) - if (i === 0 && store.weekly.expGained >= expWeeklyLimit && !force) { - log.warn("本周获取经验值已达上限,跳过该房间"); - break; - } - } - - // 首次执行时,先退出房间 - if (i === 0) { - const inLobby = isInLobby(); - if (inLobby) { - const enterButton = findTextWithinBounds("房间", 1580, 110, 320, 390, { - contains: true - }); - if (enterButton) { - log.info("首次执行,先退出已有房间..."); - await sleep(2000); - // 进入房间 - keyPress("P"); - await sleep(3000); - // 等待房间界面出现 - await assertRegionAppearing( - () => findHeaderTitle("房间", true), - "等待进入房间超时" - ); - // 点击退出按钮 - const exitBtn = findExitButton(); - if (exitBtn) { - log.info("找到退出按钮,点击退出..."); - exitBtn.click(); - await sleep(2000); - // 等待弹窗出现并点击"确认" - const confirmBtn = findText("确认"); - if (confirmBtn && confirmBtn.isExist && confirmBtn.isExist()) { - confirmBtn.click(); - await sleep(1000); - } else if (confirmBtn) { - confirmBtn.click(); - await sleep(1000); - } - } else { - log.warn("未找到退出按钮"); - } - // 确认已返回大厅 - const backToLobby = await waitForAction( - isInLobby, - null, - { maxAttempts: 30, retryInterval: 500 } - ); - if (backToLobby) { - log.info("已成功退出已有房间"); - } else { - log.warn("退出房间超时,但继续执行"); - } - } - } - } - - if (isSpecifiedAttempts) { - log.info( - "房间 {room}: [{c}/{t}] 开始第 {num} 次奇域挑战...", - room, - i + 1, - attempts, - i + 1 - ); - } else { - log.info( - "房间 {room}: [{c}/{t}] 开始本周第 {num} 次奇域挑战...", - room, - i + 1, - attempts, - store.weekly.attempts + 1 - ); - } - - await enterRoom(room); - await startGame(); - store.weekly.attempts += 1; - store.weekly.expGained += expPerAttempt; - - // 单房间模式且未指定次数时检查经验上限 - if (rooms.length === 1 && !isSpecifiedAttempts && store.weekly.expGained >= expWeeklyLimit && !force) { - log.warn("本周获取经验值已达上限,停止执行"); - break; - } - } - } - } catch (e) { - log.error("脚本执行出错: " + (e.message || e)); - await genshin.returnMainUi(); - } - if (goToTeyvat) { - await goBackToTeyvat(); - } -})(); \ No newline at end of file diff --git a/repo/js/MiliastraExperienceAutomationByCollect/manifest.json b/repo/js/MiliastraExperienceAutomationByCollect/manifest.json deleted file mode 100644 index 7e1e1e1e9..000000000 --- a/repo/js/MiliastraExperienceAutomationByCollect/manifest.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "manifest_version": 1, - "name": "千星奇域通过收藏每周刷取经验值", - "version": "0.9", - "bgi_version": "0.52.0", - "description": "千星奇域通过收藏每周刷取经验值,基于MiliastraExperienceAutomation修改", - "authors": [ - { - "name": "breadgrocery", - "link": "https://github.com/breadgrocery" - }, - { - "name": "躁动的氨气", - "link": "https://github.com/zaodonganqi" - }, - { - "name": "luguoyixiazi", - "link": "https://github.com/luguoyixiazi" - } - ], - "main": "main.js", - "settings_ui": "settings.json", - "saved_files": [ - "store/*.json" - ] -} diff --git a/repo/js/MiliastraExperienceAutomationByCollect/settings.json b/repo/js/MiliastraExperienceAutomationByCollect/settings.json deleted file mode 100644 index 1a23223fc..000000000 --- a/repo/js/MiliastraExperienceAutomationByCollect/settings.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "type": "checkbox", - "name": "goToTeyvat", - "label": "完成后返回提瓦特大陆", - "default": true - }, - { - "type": "input-text", - "name": "room", - "label": "奇域关卡关键词或关卡GUID\n(支持多个id,用中文或英文逗号隔开)", - "default": "7070702264" - }, - { - "type": "checkbox", - "name": "force", - "label": "忽略本周经验值已达上限", - "default": false - }, - { - "type": "input-text", - "name": "thisAttempts", - "label": "指定通关次数", - "default": "0" - }, - { - "type": "input-text", - "name": "expWeeklyLimit", - "label": "每周可获取的经验值上限", - "default": "4000" - }, - { - "type": "input-text", - "name": "expPerAttempt", - "label": "每次通关获取的经验值数量", - "default": "20" - } -] diff --git a/repo/js/MiliastraExperienceAutomationByCollect/store/data.json b/repo/js/MiliastraExperienceAutomationByCollect/store/data.json deleted file mode 100644 index 198512ac5..000000000 --- a/repo/js/MiliastraExperienceAutomationByCollect/store/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "weekly": { - "expGained": 80, - "attempts": 4 - }, - "nextWeek": 1763928000000 -} \ No newline at end of file