mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-05-17 09:36:55 +08:00
feat: 补全莉奈娅挖矿工具链 (#3203)
* feat: 优化路径 * feat: 优化路径 * feat: 矿石数量检测 * feat: 临时注释背包检测 * fix: 修复问题 * feat: 优化路线 * feat: 优化路线
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# 莉奈娅挖矿一条龙
|
||||
|
||||
专用于运行莉奈娅自瞄挖矿的脚本,不分矿种,只挖稳定刷新的矿物。
|
||||
专用于运行莉奈娅自瞄挖矿的脚本,不分矿种,只挖稳定刷新的矿物。
|
||||
自带月卡监听,可跨4点执行,但月卡跳出时脚本仍在执行,可能会引起故障。
|
||||
本脚本不会提供过多设置项,仅保留必要设置,最大程度限制设置数量。
|
||||
|
||||
<h1 style="color: red">当前脚本仅为先行版,占位避免撞车,出现异常为正常现象</h1>
|
||||
|
||||
@@ -18,18 +20,17 @@
|
||||
|
||||
## 说明
|
||||
|
||||
说在最开始:莉奈娅挖矿需要识别元素视野下的黄色岩元素属性矿物,原神设置项开的过低会导致黄色变浅,识别率下降,在足够运行的情况下请不要为了节省微乎其微的耗能将设置调的过低
|
||||
|
||||
其它:
|
||||
- 队伍中必须包含**莉奈娅**,不建议在**挪德卡莱**地区携带**哥伦比娅**,部分矿点的犀牛会影响挖矿。
|
||||
- 请配置好自动战斗策略,建议关闭战斗后的自动拾取,战斗点位仅为必经之路或高收益处。
|
||||
- 若观察到部分点位射一箭无法满足挖掘全部,请反馈给我(如果漏的是铁矿不会考虑)
|
||||
- 若观察到部分点位射一箭无法满足挖掘全部,请反馈给我(如果漏的是铁矿不会考虑,被小动物挡住也大概率不会修改)
|
||||
- 有一部分铁矿点位位置较为刁钻,加之铁矿这种矿物本身较无用,将不会收录在本脚本的路线内,同理,其它个别位置刁钻的矿物点位也不会专程前往。
|
||||
- 可在设置中指定队伍名称。
|
||||
|
||||
## 未来计划
|
||||
## 未来
|
||||
|
||||
- 运行指定时长
|
||||
- 效率排序
|
||||
|
||||
> 注:未来的部分逻辑会在最大程度减少配置项的基础上开发,可能会参考[矿产资源批发](https://bgi.sh/?type=js&path=AbundantOre)。
|
||||
> 注:未来的部分逻辑会在**最大程度减少配置项**的基础上开发,可能会参考[矿产资源批发](https://bgi.sh/?type=js&path=AbundantOre)。
|
||||
> 考虑到运行时长,不会支持多账号
|
||||
|
||||
> 又注:当前脚本仅为先行版,作占位避免撞车,因此缺少大部分路线,且路线暂未深度优化。所有国家都补全时将变更为正式版。
|
||||
|
||||
BIN
repo/js/LinneaMining/assets/images/amethyst_lump.png
Normal file
BIN
repo/js/LinneaMining/assets/images/amethyst_lump.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
repo/js/LinneaMining/assets/images/condessence_crystal.png
Normal file
BIN
repo/js/LinneaMining/assets/images/condessence_crystal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
repo/js/LinneaMining/assets/images/crystal_chunk.png
Normal file
BIN
repo/js/LinneaMining/assets/images/crystal_chunk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
repo/js/LinneaMining/assets/images/iron_chunk.png
Normal file
BIN
repo/js/LinneaMining/assets/images/iron_chunk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
repo/js/LinneaMining/assets/images/rainbowdrop_crystal.png
Normal file
BIN
repo/js/LinneaMining/assets/images/rainbowdrop_crystal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
repo/js/LinneaMining/assets/images/white_iron_chunk.png
Normal file
BIN
repo/js/LinneaMining/assets/images/white_iron_chunk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -1,123 +1,175 @@
|
||||
import { checkVersion } from "./utils/version.js";
|
||||
import { checkAvatar } from "./utils/avatar.js";
|
||||
import { getRoutes, filterByTags, filterByRegion } from "./utils/routes.js";
|
||||
import { loadRefreshData, cleanupStaleRecords, recordRoute, filterRunnableRoutes, getRouteDuration, estimateRoutesDuration, formatDuration } from "./utils/refresh.js";
|
||||
import { checkVersion } from "./utils/version.js"
|
||||
import { checkAvatar } from "./utils/avatar.js"
|
||||
import {
|
||||
getRoutes,
|
||||
filterByTags,
|
||||
filterByRegion
|
||||
} from "./utils/routes.js"
|
||||
import {
|
||||
loadRefreshData,
|
||||
cleanupStaleRecords,
|
||||
recordRoute,
|
||||
filterRunnableRoutes,
|
||||
getRouteDuration,
|
||||
estimateRoutesDuration,
|
||||
formatDuration
|
||||
} from "./utils/refresh.js"
|
||||
import {
|
||||
parseRunTimeLimit,
|
||||
isTimeUp
|
||||
} from "./utils/timeControl.js"
|
||||
// import {
|
||||
// getInventory,
|
||||
// formatYieldDiff,
|
||||
// formatInventory
|
||||
// } from "./utils/inventory.js"
|
||||
import {startMonthCardWatcher} from "../../../packages/utils/tool"
|
||||
|
||||
// 切换队伍
|
||||
async function switchParty(partyName) {
|
||||
if (!partyName) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
partyName = partyName.trim()
|
||||
log.info("切换队伍: " + partyName)
|
||||
if (!await genshin.switchParty(partyName)) {
|
||||
log.info("切换失败,前往七天神像重试")
|
||||
await genshin.tpToStatueOfTheSeven()
|
||||
await genshin.switchParty(partyName)
|
||||
}
|
||||
} catch {
|
||||
log.error("队伍切换失败")
|
||||
await genshin.returnMainUi()
|
||||
}
|
||||
}
|
||||
|
||||
// 运行单条路线
|
||||
async function runRoute(routePath) {
|
||||
try {
|
||||
await pathingScript.runFile(routePath)
|
||||
return true
|
||||
} catch (err) {
|
||||
log.error(`路线运行失败 ${routePath}:`, err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
(async function () {
|
||||
// 开启月卡监听
|
||||
const watcher = startMonthCardWatcher()
|
||||
|
||||
const version = getVersion()
|
||||
const minVersion = '0.60.2-alpha.3'
|
||||
const minVersion = '0.60.2-alpha.5'
|
||||
|
||||
if (!checkVersion(version, minVersion)) {
|
||||
log.warn(`当前 BetterGI 版本(${version})低于最低要求(${minVersion}),内部算法缺少优化,出现异常为正常情况`)
|
||||
log.warn(`当前 BetterGI 版本(${version})低于最低要求(${minVersion}),出现异常为正常情况`)
|
||||
}
|
||||
|
||||
setGameMetrics(1920, 1080, 1);
|
||||
await genshin.returnMainUi();
|
||||
setGameMetrics(1920, 1080, 1)
|
||||
await genshin.returnMainUi()
|
||||
|
||||
const partyName = settings.partyName || "";
|
||||
const excludeOreTypes = Array.from(settings.excludeOreTypes || []);
|
||||
const excludeRegions = Array.from(settings.excludeRegions || []);
|
||||
const skipBattleRoutes = settings.skipBattleRoutes === true;
|
||||
const partyName = settings.partyName || ""
|
||||
const excludeOreTypes = Array.from(settings.excludeOreTypes || [])
|
||||
const excludeRegions = Array.from(settings.excludeRegions || [])
|
||||
const skipBattleRoutes = settings.skipBattleRoutes === true
|
||||
const targetRunningMinutes = settings.targetRunningMinutes || null
|
||||
|
||||
// 切换队伍
|
||||
async function switchParty(partyName) {
|
||||
if (!partyName) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
partyName = partyName.trim();
|
||||
log.info("切换队伍: " + partyName);
|
||||
if (!await genshin.switchParty(partyName)) {
|
||||
log.info("切换失败,前往七天神像重试");
|
||||
await genshin.tpToStatueOfTheSeven();
|
||||
await genshin.switchParty(partyName);
|
||||
}
|
||||
} catch {
|
||||
log.error("队伍切换失败");
|
||||
notification.error(`队伍切换失败`);
|
||||
await genshin.returnMainUi();
|
||||
}
|
||||
}
|
||||
|
||||
// 运行单条路线
|
||||
async function runRoute(routePath) {
|
||||
try {
|
||||
await pathingScript.runFile(routePath);
|
||||
} catch (err) {
|
||||
log.error(`路线运行失败 ${routePath}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// 主逻辑
|
||||
await switchParty(partyName);
|
||||
|
||||
if (!checkAvatar("莉奈娅")) {
|
||||
log.error("队伍角色检查失败 - 未找到莉奈娅,脚本终止");
|
||||
return;
|
||||
}
|
||||
|
||||
const allRoutes = getRoutes();
|
||||
const allRoutes = getRoutes()
|
||||
if (allRoutes.length === 0) {
|
||||
log.error("未找到任何路线文件!请确保paths目录下存在路线文件。");
|
||||
return;
|
||||
log.error("未找到任何路线文件!请确保paths目录下存在路线文件。")
|
||||
return
|
||||
}
|
||||
|
||||
let routes = allRoutes;
|
||||
let routes = allRoutes
|
||||
|
||||
routes = filterByRegion(routes, excludeRegions);
|
||||
routes = filterByRegion(routes, excludeRegions)
|
||||
if (excludeRegions.length > 0 && routes.length < allRoutes.length) {
|
||||
log.info(`地区筛选:排除 ${allRoutes.length - routes.length} 条路线`);
|
||||
log.info(`地区筛选:排除 ${allRoutes.length - routes.length} 条路线`)
|
||||
}
|
||||
|
||||
routes = filterByTags(routes, excludeOreTypes);
|
||||
routes = filterByTags(routes, excludeOreTypes)
|
||||
if (excludeOreTypes.length > 0 && routes.length < allRoutes.length) {
|
||||
log.info(`矿物筛选:排除 ${allRoutes.length - routes.length} 条路线`);
|
||||
log.info(`矿物筛选:排除 ${allRoutes.length - routes.length} 条路线`)
|
||||
}
|
||||
|
||||
if (skipBattleRoutes) {
|
||||
routes = filterByTags(routes, ["战斗"]);
|
||||
routes = filterByTags(routes, ["战斗"])
|
||||
if (routes.length < allRoutes.length) {
|
||||
log.info(`跳过战斗路线:排除 ${allRoutes.length - routes.length} 条路线`);
|
||||
log.info(`跳过战斗路线:排除 ${allRoutes.length - routes.length} 条路线`)
|
||||
}
|
||||
}
|
||||
|
||||
const refreshData = loadRefreshData();
|
||||
cleanupStaleRecords(refreshData, routes);
|
||||
const refreshData = loadRefreshData()
|
||||
cleanupStaleRecords(refreshData, routes)
|
||||
|
||||
const runnableRoutes = filterRunnableRoutes(routes, refreshData);
|
||||
const runnableRoutes = filterRunnableRoutes(routes, refreshData)
|
||||
if (runnableRoutes.length === 0) {
|
||||
log.info("所有路线均未刷新,无需运行");
|
||||
return;
|
||||
log.info("所有路线均未刷新,无需运行")
|
||||
return
|
||||
}
|
||||
|
||||
log.info(`将运行 ${runnableRoutes.length}/${allRoutes.length} 条路线`);
|
||||
await switchParty(partyName)
|
||||
|
||||
dispatcher.addTimer(new RealtimeTimer("AutoPick"));
|
||||
if (!checkAvatar("莉奈娅")) {
|
||||
log.error("队伍角色检查失败 - 未找到莉奈娅,脚本终止")
|
||||
return
|
||||
}
|
||||
|
||||
log.info(`将运行 ${runnableRoutes.length}/${allRoutes.length} 条路线`)
|
||||
|
||||
const runUntilTime = parseRunTimeLimit(targetRunningMinutes)
|
||||
if (runUntilTime) {
|
||||
const minutes = Math.round((runUntilTime - Date.now()) / 60 / 1000)
|
||||
log.info(`将在 ${minutes} 分钟后停止运行`)
|
||||
}
|
||||
|
||||
dispatcher.addTimer(new RealtimeTimer("AutoPick"))
|
||||
|
||||
// const originalInventory = await getInventory()
|
||||
// log.info("当前背包:" + formatInventory(originalInventory))
|
||||
|
||||
const scriptStartTime = Date.now()
|
||||
|
||||
for (let i = 0; i < runnableRoutes.length; i++) {
|
||||
const route = runnableRoutes[i];
|
||||
const fileName = route.split('\\').pop();
|
||||
if (isTimeUp(runUntilTime)) {
|
||||
log.info("已到达运行时长限制,停止运行")
|
||||
break
|
||||
}
|
||||
const route = runnableRoutes[i]
|
||||
const fileName = route.split('\\').pop()
|
||||
|
||||
const remaining = runnableRoutes.slice(i);
|
||||
const remainingEst = estimateRoutesDuration(remaining, refreshData);
|
||||
const thisRouteEst = getRouteDuration(route, refreshData);
|
||||
const remaining = runnableRoutes.slice(i)
|
||||
const remainingEst = estimateRoutesDuration(remaining, refreshData)
|
||||
const thisRouteEst = getRouteDuration(route, refreshData)
|
||||
|
||||
if (thisRouteEst !== null) {
|
||||
log.info(`路线 ${i + 1}/${runnableRoutes.length}: ${fileName}(预计 ${formatDuration(thisRouteEst)},剩余 ${formatDuration(remainingEst)})`);
|
||||
log.info(`路线 ${i + 1}/${runnableRoutes.length}: ${fileName}(预计需要时间: ${formatDuration(thisRouteEst)},剩余时间: ${formatDuration(remainingEst)})`)
|
||||
} else {
|
||||
log.info(`路线 ${i + 1}/${runnableRoutes.length}: ${fileName}(预计 ${formatDuration(remainingEst)})`);
|
||||
log.info(`路线 ${i + 1}/${runnableRoutes.length}: ${fileName}(预计剩余时间: ${formatDuration(remainingEst)})`)
|
||||
}
|
||||
|
||||
const startTime = Date.now();
|
||||
await runRoute(route);
|
||||
await sleep(10);
|
||||
const duration = (Date.now() - startTime) / 1000;
|
||||
recordRoute(route, refreshData, duration);
|
||||
const startTime = Date.now()
|
||||
await sleep(10)
|
||||
const res = await runRoute(route)
|
||||
if (res) {
|
||||
const duration = (Date.now() - startTime) / 1000
|
||||
recordRoute(route, refreshData, duration)
|
||||
}
|
||||
|
||||
if (i < runnableRoutes.length - 1) {
|
||||
await sleep(2000);
|
||||
// 最后一条路线,给一定时间缓冲
|
||||
if (i === runnableRoutes.length - 1) {
|
||||
await sleep(2000)
|
||||
}
|
||||
}
|
||||
|
||||
log.info("所有路线运行完成");
|
||||
})();
|
||||
log.info("所有路线运行完成")
|
||||
|
||||
// const latestInventory = await getInventory()
|
||||
// const runningMinutes = (Date.now() - scriptStartTime) / 1000 / 60
|
||||
// const summary = `运行${runningMinutes.toFixed(2)}分钟,${formatYieldDiff(latestInventory, originalInventory)}`
|
||||
// log.info("当前背包:" + formatInventory(latestInventory))
|
||||
// log.info(summary)
|
||||
|
||||
await watcher.cancel()
|
||||
})()
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778073758649,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A01-希汐岛左下-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778073869657,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A01-希汐岛左下-02",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074015548,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A01-希汐岛左下-03",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074022774,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A02-沐光之台",
|
||||
"tags": [
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"bgi_version": "0.60.1",
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074188795,
|
||||
"map_match_method": "",
|
||||
"last_modified_time": 1778390462884,
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A03-月矩力实验设计局左侧",
|
||||
"tags": [
|
||||
@@ -135,8 +135,8 @@
|
||||
"id": 13,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 10095.1797,
|
||||
"y": 3334.8125
|
||||
"x": 10099.8203,
|
||||
"y": 3334.2969
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074354807,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A04-月矩力实验设计局右侧",
|
||||
"tags": [
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"bgi_version": "0.60.1",
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074685948,
|
||||
"map_match_method": "",
|
||||
"last_modified_time": 1778390516494,
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A05-刻拉蒂之眼",
|
||||
"tags": [
|
||||
@@ -107,8 +107,8 @@
|
||||
"id": 10,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8657.875,
|
||||
"y": 2271.8516
|
||||
"x": 8658.7773,
|
||||
"y": 2271.6797
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
@@ -116,31 +116,13 @@
|
||||
"id": 11,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8657.9258,
|
||||
"y": 2266.1318
|
||||
},
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"id": 12,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 8664.4902,
|
||||
"y": 2264.5488
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 13,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8663.6855,
|
||||
"y": 2286.3545
|
||||
},
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"id": 14,
|
||||
"id": 12,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 8656.8262,
|
||||
@@ -149,7 +131,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 15,
|
||||
"id": 13,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8637.0225,
|
||||
@@ -158,7 +140,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 16,
|
||||
"id": 14,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8643.2637,
|
||||
@@ -167,7 +149,7 @@
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"id": 17,
|
||||
"id": 15,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 8652.0293,
|
||||
@@ -176,7 +158,7 @@
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"id": 18,
|
||||
"id": 16,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 8644.9844,
|
||||
@@ -185,7 +167,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 19,
|
||||
"id": 17,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8646.9629,
|
||||
@@ -194,7 +176,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 20,
|
||||
"id": 18,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8669.3848,
|
||||
@@ -203,7 +185,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 21,
|
||||
"id": 19,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8675.917,
|
||||
@@ -212,7 +194,7 @@
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"id": 22,
|
||||
"id": 20,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 8682.9688,
|
||||
@@ -221,7 +203,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 23,
|
||||
"id": 21,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8714.1064,
|
||||
@@ -230,7 +212,7 @@
|
||||
{
|
||||
"action": "mining",
|
||||
"action_params": "",
|
||||
"id": 24,
|
||||
"id": 22,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8715.5771,
|
||||
@@ -239,7 +221,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 25,
|
||||
"id": 23,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8728.0361,
|
||||
@@ -248,7 +230,7 @@
|
||||
{
|
||||
"action": "mining",
|
||||
"action_params": "",
|
||||
"id": 26,
|
||||
"id": 24,
|
||||
"move_mode": "walk",
|
||||
"type": "target",
|
||||
"x": 8726.9141,
|
||||
@@ -257,7 +239,7 @@
|
||||
{
|
||||
"action": "mining",
|
||||
"action_params": "",
|
||||
"id": 27,
|
||||
"id": 25,
|
||||
"move_mode": "walk",
|
||||
"type": "target",
|
||||
"x": 8731.1055,
|
||||
@@ -266,7 +248,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 28,
|
||||
"id": 26,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8733.9531,
|
||||
@@ -275,7 +257,7 @@
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"id": 29,
|
||||
"id": 27,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 8749.1123,
|
||||
@@ -284,7 +266,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 30,
|
||||
"id": 28,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8735.2188,
|
||||
@@ -293,7 +275,7 @@
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 31,
|
||||
"id": 29,
|
||||
"move_mode": "walk",
|
||||
"type": "path",
|
||||
"x": 8710.1875,
|
||||
@@ -302,7 +284,7 @@
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"id": 32,
|
||||
"id": 30,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 8708.666,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777628877185,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A06-蓝珀胡左上",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074768168,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A07-苔骨荒原-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074799690,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A07-苔骨荒原-02",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074828909,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A07-苔骨荒原-03",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074887381,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A08-星砂滩左侧-01",
|
||||
"tags": [
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"bgi_version": "0.60.1",
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777641918526,
|
||||
"map_match_method": "",
|
||||
"last_modified_time": 1778390547978,
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A08-星砂滩左侧-02",
|
||||
"tags": [
|
||||
@@ -58,7 +58,7 @@
|
||||
},
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "2,4",
|
||||
"action_params": "2,5",
|
||||
"id": 5,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778074909070,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A08-星砂滩左侧-03",
|
||||
"tags": [
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"bgi_version": "0.60.1",
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629033680,
|
||||
"map_match_method": "",
|
||||
"last_modified_time": 1778390565171,
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A09-那夏镇下方",
|
||||
"tags": [
|
||||
@@ -67,7 +67,7 @@
|
||||
},
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "2,3",
|
||||
"action_params": "2,4",
|
||||
"id": 6,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778075130600,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A10-那夏镇左侧",
|
||||
"tags": [
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"bgi_version": "0.60.1",
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778075142681,
|
||||
"map_match_method": "",
|
||||
"last_modified_time": 1778390589087,
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A11-叮铃哐啷蛋卷工坊",
|
||||
"tags": [
|
||||
@@ -76,7 +76,7 @@
|
||||
},
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"action_params": "2",
|
||||
"id": 7,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
@@ -103,7 +103,7 @@
|
||||
},
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "",
|
||||
"action_params": "2,3",
|
||||
"id": 10,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1778075169912,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A12-苔古荒原地下",
|
||||
"tags": [
|
||||
|
||||
234
repo/js/LinneaMining/paths/挪德卡莱/A16-星砂滩右侧.json
Normal file
234
repo/js/LinneaMining/paths/挪德卡莱/A16-星砂滩右侧.json
Normal file
@@ -0,0 +1,234 @@
|
||||
{
|
||||
"config": {
|
||||
"realtime_triggers": {
|
||||
"AutoPick": true
|
||||
}
|
||||
},
|
||||
"farming_info": {
|
||||
"allow_farming_count": false,
|
||||
"duration_seconds": 0,
|
||||
"elite_details": "",
|
||||
"elite_mob_count": 0,
|
||||
"normal_mob_count": 0,
|
||||
"primary_target": "",
|
||||
"total_mora": 0
|
||||
},
|
||||
"info": {
|
||||
"authors": [
|
||||
{
|
||||
"links": "https://github.com/zaodonganqi",
|
||||
"name": "躁动的氨气"
|
||||
}
|
||||
],
|
||||
"bgi_version": "0.60.2-alpha.4",
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"items": [],
|
||||
"last_modified_time": 1778390948061,
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "A16-星砂滩右侧",
|
||||
"order": 0,
|
||||
"tags": [
|
||||
"虹滴晶"
|
||||
],
|
||||
"type": "collect",
|
||||
"version": ""
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"action": "",
|
||||
"id": 1,
|
||||
"move_mode": "walk",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "teleport",
|
||||
"x": 9563.1123,
|
||||
"y": 2135.2529
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"id": 2,
|
||||
"move_mode": "walk",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "path",
|
||||
"x": 9536.6689,
|
||||
"y": 2131.8125
|
||||
},
|
||||
{
|
||||
"action": "stop_flying",
|
||||
"action_params": "",
|
||||
"id": 3,
|
||||
"move_mode": "fly",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "path",
|
||||
"x": 9521.4668,
|
||||
"y": 2130.478
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"id": 4,
|
||||
"move_mode": "dash",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "path",
|
||||
"x": 9427.0605,
|
||||
"y": 2134.2529
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"id": 5,
|
||||
"move_mode": "walk",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "path",
|
||||
"x": 9397.4619,
|
||||
"y": 2138.647
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"id": 6,
|
||||
"move_mode": "walk",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "path",
|
||||
"x": 9388.877,
|
||||
"y": 2140.0547
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"id": 7,
|
||||
"move_mode": "walk",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "path",
|
||||
"x": 9368.5508,
|
||||
"y": 2155.9229
|
||||
},
|
||||
{
|
||||
"action": "combat_script",
|
||||
"action_params": "wait(4)",
|
||||
"id": 8,
|
||||
"locked": false,
|
||||
"move_mode": "walk",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "path",
|
||||
"x": 9360.0947,
|
||||
"y": 2159.4561
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"id": 9,
|
||||
"move_mode": "walk",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "path",
|
||||
"x": 9360.0947,
|
||||
"y": 2159.4561
|
||||
},
|
||||
{
|
||||
"action": "linnea_mining",
|
||||
"action_params": "3,6",
|
||||
"id": 10,
|
||||
"move_mode": "walk",
|
||||
"point_ext_params": {
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"misidentification": {
|
||||
"arrival_time": 0,
|
||||
"handling_mode": "previousDetectedPoint",
|
||||
"type": [
|
||||
"unrecognized"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "orientation",
|
||||
"x": 9356.416,
|
||||
"y": 2156.167
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629515332,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B01-悠悠度假村-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629562187,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B01-悠悠度假村-02",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629583442,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B01-悠悠度假村-03",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629601206,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B01-悠悠度假村-04",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629625023,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B01-悠悠度假村-05",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629653673,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B01-悠悠度假村-06",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629664654,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B01-悠悠度假村-07",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629830922,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B02-安绕之野-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629847224,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B02-安绕之野-02",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629860170,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B02-安绕之野-03",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629927183,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B02-安绕之野-04",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629908885,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B02-安绕之野-05",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629963179,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B03-奥奇卡纳塔-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629979794,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B03-奥奇卡纳塔-02",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777629996165,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B03-奥奇卡纳塔-03",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630005091,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B03-奥奇卡纳塔-04",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630017342,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B03-奥奇卡纳塔-05",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630038028,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B04-花羽会上方-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630079731,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B04-花羽会上方-02",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630107242,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B04-花羽会上方-03",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630098385,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B04-花羽会上方-04",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630131255,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B05-花羽会下方-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630148532,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B05-花羽会下方-02",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630165708,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B06-烟谜主左上-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630181378,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B06-烟谜主左上-02",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630258862,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B07-烟谜主右下-01",
|
||||
"tags": [
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1777630246744,
|
||||
"map_match_method": "",
|
||||
"map_match_method": "TemplateMatch",
|
||||
"map_name": "Teyvat",
|
||||
"name": "B07-烟谜主右下-02",
|
||||
"tags": [
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
[
|
||||
{
|
||||
"name": "partyName",
|
||||
"type": "input-text",
|
||||
"default": "",
|
||||
"label": "队伍名称"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"name": "excludeRegions",
|
||||
"type": "multi-checkbox",
|
||||
@@ -23,7 +14,7 @@
|
||||
{
|
||||
"name": "excludeOreTypes",
|
||||
"type": "multi-checkbox",
|
||||
"label": "不挖以下矿物",
|
||||
"label": "\n不挖以下矿物",
|
||||
"options": [
|
||||
"虹滴晶",
|
||||
"白铁块",
|
||||
@@ -39,6 +30,24 @@
|
||||
"name": "skipBattleRoutes",
|
||||
"type": "checkbox",
|
||||
"default": false,
|
||||
"label": "跳过战斗点位"
|
||||
"label": "\n跳过战斗点位"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"name": "partyName",
|
||||
"type": "input-text",
|
||||
"default": "",
|
||||
"label": "\n队伍名称"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"name": "targetRunningMinutes",
|
||||
"type": "input-text",
|
||||
"default": "",
|
||||
"label": "\n目标运行时长(分钟)"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
此目录下的文件为工具脚本,与主脚本的运行无关,仅用于开发时批量处理路线信息。
|
||||
|
||||
所有命令均从项目根目录运行。
|
||||
|
||||
---
|
||||
|
||||
## split-routes.js
|
||||
将包含多个传送点(`teleport`)的路线拆分为独立子路线,方便打 tag 管理。
|
||||
|
||||
```bash
|
||||
node repo/js/LinneaMining/tools/split-routes.js
|
||||
node split-routes.js
|
||||
```
|
||||
|
||||
拆分后自动运行 `reindex-positions.js`。
|
||||
@@ -17,7 +15,7 @@ node repo/js/LinneaMining/tools/split-routes.js
|
||||
将拆分后的子路线(`名称-01.json`、`名称-02.json`...)重新合并为父路线,tags 自动合并去重。
|
||||
|
||||
```bash
|
||||
node repo/js/LinneaMining/tools/merge-routes.js
|
||||
node merge-routes.js
|
||||
```
|
||||
|
||||
合并后自动运行 `reindex-positions.js`。
|
||||
@@ -26,26 +24,26 @@ node repo/js/LinneaMining/tools/merge-routes.js
|
||||
将所有路线文件中 positions 的 `id` 按数组顺序重新赋值(1, 2, 3...),附带 BOM 清理。
|
||||
|
||||
```bash
|
||||
node repo/js/LinneaMining/tools/reindex-positions.js
|
||||
node reindex-positions.js
|
||||
```
|
||||
|
||||
## update-bgi-version.js
|
||||
批量更新路线文件中 `info.bgi_version`,补充缺失的 `info.version`,附带 BOM 清理。修改脚本中的 `newVersion` 常量后运行。
|
||||
|
||||
```bash
|
||||
node repo/js/LinneaMining/tools/update-bgi-version.js
|
||||
node update-bgi-version.js
|
||||
```
|
||||
|
||||
## rename-tag.js
|
||||
将路线文件中匹配指定 tag 替换为新 tag(精确匹配单个元素)。修改脚本中的 `oldTag` 和 `newTag` 后运行。
|
||||
|
||||
```bash
|
||||
node repo/js/LinneaMining/tools/rename-tag.js
|
||||
node rename-tag.js
|
||||
```
|
||||
|
||||
## cleanup-fields.js
|
||||
批量删除路线文件中的 `config` 和 `farming_info` 字段,附带 BOM 清理。
|
||||
|
||||
```bash
|
||||
node repo/js/LinneaMining/tools/cleanup-fields.js
|
||||
node cleanup-fields.js
|
||||
```
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
* @returns {boolean} 队伍中是否包含该角色
|
||||
*/
|
||||
function checkAvatar(targetName) {
|
||||
const avatars = getAvatars();
|
||||
if (!avatars || avatars.length < 1) return false;
|
||||
const avatars = getAvatars()
|
||||
if (!avatars || avatars.length < 1) return false
|
||||
for (let i = 0; i < avatars.length; i++) {
|
||||
if (avatars[i] === targetName) return true;
|
||||
if (avatars[i] === targetName) return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
export { checkAvatar };
|
||||
export { checkAvatar }
|
||||
|
||||
112
repo/js/LinneaMining/utils/inventory.js
Normal file
112
repo/js/LinneaMining/utils/inventory.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import {openBag} from "../../../../packages/utils/tool"
|
||||
import crystal_chunk from "../assets/images/crystal_chunk.png"
|
||||
import amethyst_lump from "../assets/images/amethyst_lump.png"
|
||||
import condessence_crystal from "../assets/images/condessence_crystal.png"
|
||||
import rainbowdrop_crystal from "../assets/images/rainbowdrop_crystal.png"
|
||||
import white_iron_chunk from "../assets/images/white_iron_chunk.png"
|
||||
import iron_chunk from "../assets/images/iron_chunk.png"
|
||||
|
||||
const ORES = [
|
||||
{ name: "水晶块", mat: crystal_chunk },
|
||||
{ name: "紫晶块", mat: amethyst_lump },
|
||||
{ name: "萃凝晶", mat: condessence_crystal },
|
||||
{ name: "虹滴晶", mat: rainbowdrop_crystal },
|
||||
{ name: "白铁块", mat: white_iron_chunk },
|
||||
{ name: "铁块", mat: iron_chunk },
|
||||
]
|
||||
|
||||
/**
|
||||
* 检测背包中各类矿石的数量
|
||||
* 流程: 打开背包 -> 切换素材页 -> 模板匹配矿石图标 -> OCR 读取数量
|
||||
*
|
||||
* @returns {Object} 各矿石数量,键为矿石中文名,无法识别的数量为 0
|
||||
*/
|
||||
async function getInventory() {
|
||||
await genshin.returnMainUi()
|
||||
await openBag()
|
||||
click(964, 53)
|
||||
await sleep(500)
|
||||
|
||||
const result = Object.fromEntries(ORES.map(o => [o.name, 0]))
|
||||
const gameRegion = captureGameRegion()
|
||||
|
||||
for (const ore of ORES) {
|
||||
const ro = RecognitionObject.TemplateMatch(ore.mat)
|
||||
ro.threshold = 0.8
|
||||
ro.UseMask = true
|
||||
const res = gameRegion.find(ro)
|
||||
|
||||
if (!res.isEmpty()) {
|
||||
log.debug(`Found ${ore.name} at (${res.x}, ${res.y})`)
|
||||
|
||||
const ocrRes = gameRegion.find(
|
||||
RecognitionObject.ocr(res.x, res.y + 120, 120, 40)
|
||||
)
|
||||
if (ocrRes) {
|
||||
if (!isNaN(count) && count >= 0) {
|
||||
result[ore.name] = count
|
||||
} else {
|
||||
log.warn(`OCR 识别矿石数量失败: ${ore.name}, 文本: ${ocrRes.text}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gameRegion.dispose()
|
||||
await genshin.returnMainUi()
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两次背包检测结果之间的矿石总增量
|
||||
*
|
||||
* @param {Object} current - 当前检测结果
|
||||
* @param {Object} previous - 之前检测结果
|
||||
* @returns {number} 总增量
|
||||
*/
|
||||
function calcYield(current, previous) {
|
||||
let total = 0
|
||||
for (const key of Object.keys(current)) {
|
||||
total += (current[key] || 0) - (previous[key] || 0)
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化矿石变化量为可读字符串
|
||||
* 仅输出有变化的矿石,无变化时返回 "无收获"
|
||||
*
|
||||
* @param {Object} current - 当前检测结果
|
||||
* @param {Object} previous - 之前检测结果
|
||||
* @returns {string} 例如 "水晶块+5,萃凝晶+3"
|
||||
*/
|
||||
function formatYieldDiff(current, previous) {
|
||||
const parts = []
|
||||
for (const ore of ORES) {
|
||||
const diff = (current[ore.name] || 0) - (previous[ore.name] || 0)
|
||||
if (diff !== 0) {
|
||||
parts.push(`${ore.name}${diff > 0 ? "+" : ""}${diff}`)
|
||||
}
|
||||
}
|
||||
return parts.length > 0 ? parts.join(",") : "无收获"
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化矿石数量为日志字符串
|
||||
*
|
||||
* @param {Object} inventory - 检测结果,键为矿石中文名
|
||||
* @returns {string} 例如 "水晶块10个,紫晶块5个"
|
||||
*/
|
||||
function formatInventory(inventory) {
|
||||
return ORES
|
||||
.filter(o => inventory[o.name] !== undefined)
|
||||
.map(o => `${o.name}${inventory[o.name]}个`)
|
||||
.join(",")
|
||||
}
|
||||
|
||||
export {
|
||||
getInventory,
|
||||
calcYield,
|
||||
formatYieldDiff,
|
||||
formatInventory
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
const REFRESH_DATA_PATH = "local/refresh_records.json";
|
||||
const FALLBACK_DURATION = 60;
|
||||
const REFRESH_DATA_PATH = "local/refresh_records.json"
|
||||
const FALLBACK_DURATION = 60
|
||||
|
||||
/**
|
||||
* 从本地文件加载刷新记录数据
|
||||
@@ -8,10 +8,10 @@ const FALLBACK_DURATION = 60;
|
||||
*/
|
||||
function loadRefreshData() {
|
||||
try {
|
||||
const raw = file.readTextSync(REFRESH_DATA_PATH);
|
||||
return JSON.parse(raw) || {};
|
||||
const raw = file.readTextSync(REFRESH_DATA_PATH)
|
||||
return JSON.parse(raw) || {}
|
||||
} catch {
|
||||
return {};
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ function loadRefreshData() {
|
||||
* @param {Object} data - 刷新记录对象
|
||||
*/
|
||||
function saveRefreshData(data) {
|
||||
file.writeTextSync(REFRESH_DATA_PATH, JSON.stringify(data, null, 2));
|
||||
file.writeTextSync(REFRESH_DATA_PATH, JSON.stringify(data, null, 2))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,20 +32,20 @@ function saveRefreshData(data) {
|
||||
* @returns {Object} 清理后的刷新记录对象
|
||||
*/
|
||||
function cleanupStaleRecords(data, routePaths) {
|
||||
const pathSet = new Set(routePaths);
|
||||
const keys = Object.keys(data);
|
||||
let removed = 0;
|
||||
const pathSet = new Set(routePaths)
|
||||
const keys = Object.keys(data)
|
||||
let removed = 0
|
||||
for (const key of keys) {
|
||||
if (!pathSet.has(key)) {
|
||||
delete data[key];
|
||||
removed++;
|
||||
delete data[key]
|
||||
removed++
|
||||
}
|
||||
}
|
||||
if (removed > 0) {
|
||||
log.info(`清理了 ${removed} 条过期路线记录`);
|
||||
saveRefreshData(data);
|
||||
log.info(`清理了 ${removed} 条过期路线记录`)
|
||||
saveRefreshData(data)
|
||||
}
|
||||
return data;
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,14 +57,14 @@ function cleanupStaleRecords(data, routePaths) {
|
||||
* @param {number} duration - 本次运行时长(秒),0 或负数时不记录时长
|
||||
*/
|
||||
function recordRoute(routePath, data, duration) {
|
||||
const existing = data[routePath];
|
||||
const existing = data[routePath]
|
||||
if (existing && typeof existing === 'object') {
|
||||
existing.t = Date.now();
|
||||
if (duration > 0) existing.d = Math.round(duration);
|
||||
existing.t = Date.now()
|
||||
if (duration > 0) existing.d = Math.round(duration)
|
||||
} else {
|
||||
data[routePath] = { t: Date.now(), d: duration > 0 ? Math.round(duration) : null };
|
||||
data[routePath] = { t: Date.now(), d: duration > 0 ? Math.round(duration) : null }
|
||||
}
|
||||
saveRefreshData(data);
|
||||
saveRefreshData(data)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,17 +77,17 @@ function recordRoute(routePath, data, duration) {
|
||||
* @returns {boolean} 矿石是否已刷新,记录不存在视为已刷新
|
||||
*/
|
||||
function isRouteReady(routePath, data, refreshDays = 3) {
|
||||
const record = data[routePath];
|
||||
const lastRun = record?.t || (typeof record === 'number' ? record : null);
|
||||
if (!lastRun) return true;
|
||||
const record = data[routePath]
|
||||
const lastRun = record?.t || (typeof record === 'number' ? record : null)
|
||||
if (!lastRun) return true
|
||||
|
||||
const t = lastRun / 1000;
|
||||
let t0 = Math.floor(t / 86400) * 86400 + 57600;
|
||||
const t = lastRun / 1000
|
||||
let t0 = Math.floor(t / 86400) * 86400 + 57600
|
||||
if (t0 > t) {
|
||||
t0 -= 86400;
|
||||
t0 -= 86400
|
||||
}
|
||||
const respawnTime = t0 + 86400 * refreshDays;
|
||||
return respawnTime < Date.now() / 1000;
|
||||
const respawnTime = t0 + 86400 * refreshDays
|
||||
return respawnTime < Date.now() / 1000
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,16 +99,16 @@ function isRouteReady(routePath, data, refreshDays = 3) {
|
||||
* @returns {string[]} 已刷新的路线文件路径数组
|
||||
*/
|
||||
function filterRunnableRoutes(routePaths, data, refreshDays = 3) {
|
||||
const runnable = [];
|
||||
const runnable = []
|
||||
for (const routePath of routePaths) {
|
||||
if (isRouteReady(routePath, data, refreshDays)) {
|
||||
runnable.push(routePath);
|
||||
runnable.push(routePath)
|
||||
} else {
|
||||
const fileName = routePath.split('\\').pop();
|
||||
log.info(`跳过未刷新路线: ${fileName}`);
|
||||
const fileName = routePath.split('\\').pop()
|
||||
log.info(`跳过未刷新路线: ${fileName}`)
|
||||
}
|
||||
}
|
||||
return runnable;
|
||||
return runnable
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,10 +119,10 @@ function filterRunnableRoutes(routePaths, data, refreshDays = 3) {
|
||||
* @returns {number|null} 历史运行时长(秒),无记录返回 null
|
||||
*/
|
||||
function getRouteDuration(routePath, data) {
|
||||
const record = data[routePath];
|
||||
if (!record) return null;
|
||||
if (typeof record === 'object' && record.d) return record.d;
|
||||
return null;
|
||||
const record = data[routePath]
|
||||
if (!record) return null
|
||||
if (typeof record === 'object' && record.d) return record.d
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,12 +134,12 @@ function getRouteDuration(routePath, data) {
|
||||
* @returns {number} 估算总时长(秒)
|
||||
*/
|
||||
function estimateRoutesDuration(routePaths, data) {
|
||||
let total = 0;
|
||||
let total = 0
|
||||
for (const routePath of routePaths) {
|
||||
const d = getRouteDuration(routePath, data);
|
||||
total += d !== null ? d : FALLBACK_DURATION;
|
||||
const d = getRouteDuration(routePath, data)
|
||||
total += d !== null ? d : FALLBACK_DURATION
|
||||
}
|
||||
return total;
|
||||
return total
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,14 +150,24 @@ function estimateRoutesDuration(routePaths, data) {
|
||||
* @returns {string} 格式化后的时长字符串
|
||||
*/
|
||||
function formatDuration(seconds) {
|
||||
seconds = Math.max(0, Math.round(seconds));
|
||||
const h = Math.floor(seconds / 3600);
|
||||
const m = Math.floor((seconds % 3600) / 60);
|
||||
const s = seconds % 60;
|
||||
const mm = String(m).padStart(2, '0');
|
||||
const ss = String(s).padStart(2, '0');
|
||||
if (h > 0) return `${h}小时${mm}分${ss}秒`;
|
||||
return `${mm}分${ss}秒`;
|
||||
seconds = Math.max(0, Math.round(seconds))
|
||||
const h = Math.floor(seconds / 3600)
|
||||
const m = Math.floor((seconds % 3600) / 60)
|
||||
const s = seconds % 60
|
||||
const mm = String(m).padStart(2, '0')
|
||||
const ss = String(s).padStart(2, '0')
|
||||
if (h > 0) return `${h}小时${mm}分${ss}秒`
|
||||
return `${mm}分${ss}秒`
|
||||
}
|
||||
|
||||
export { loadRefreshData, saveRefreshData, cleanupStaleRecords, recordRoute, isRouteReady, filterRunnableRoutes, getRouteDuration, estimateRoutesDuration, formatDuration };
|
||||
export {
|
||||
loadRefreshData,
|
||||
saveRefreshData,
|
||||
cleanupStaleRecords,
|
||||
recordRoute,
|
||||
isRouteReady,
|
||||
filterRunnableRoutes,
|
||||
getRouteDuration,
|
||||
estimateRoutesDuration,
|
||||
formatDuration
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
* @returns {string[]} 所有 JSON 文件的完整路径数组
|
||||
*/
|
||||
function readRouteFiles(folderPath) {
|
||||
const files = [];
|
||||
const entries = file.ReadPathSync(folderPath);
|
||||
const files = []
|
||||
const entries = file.ReadPathSync(folderPath)
|
||||
|
||||
for (const entry of entries) {
|
||||
if (file.IsFolder(entry)) {
|
||||
files.push(...readRouteFiles(entry));
|
||||
files.push(...readRouteFiles(entry))
|
||||
} else if (entry.endsWith(".json")) {
|
||||
files.push(entry);
|
||||
files.push(entry)
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
return files
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,10 +26,10 @@ function readRouteFiles(folderPath) {
|
||||
*/
|
||||
function getRoutes() {
|
||||
try {
|
||||
return readRouteFiles("paths");
|
||||
return readRouteFiles("paths")
|
||||
} catch (err) {
|
||||
log.error("获取路线文件时出错:", err);
|
||||
return [];
|
||||
log.error("获取路线文件时出错:", err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,19 +41,19 @@ function getRoutes() {
|
||||
* @returns {string[]} 过滤后的路线文件路径数组
|
||||
*/
|
||||
function filterByTags(routePaths, excludedTags) {
|
||||
if (!excludedTags || excludedTags.length === 0) return routePaths;
|
||||
if (!excludedTags || excludedTags.length === 0) return routePaths
|
||||
|
||||
return routePaths.filter(routePath => {
|
||||
try {
|
||||
const raw = file.readTextSync(routePath);
|
||||
const data = JSON.parse(raw);
|
||||
const tags = data.info?.tags;
|
||||
if (!tags || tags.length === 0) return true;
|
||||
return tags.some(tag => !excludedTags.includes(tag));
|
||||
const raw = file.readTextSync(routePath)
|
||||
const data = JSON.parse(raw)
|
||||
const tags = data.info?.tags
|
||||
if (!tags || tags.length === 0) return true
|
||||
return tags.some(tag => !excludedTags.includes(tag))
|
||||
} catch {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,14 +64,18 @@ function filterByTags(routePaths, excludedTags) {
|
||||
* @returns {string[]} 过滤后的路线文件路径数组
|
||||
*/
|
||||
function filterByRegion(routePaths, excludedRegions) {
|
||||
if (!excludedRegions || excludedRegions.length === 0) return routePaths;
|
||||
if (!excludedRegions || excludedRegions.length === 0) return routePaths
|
||||
|
||||
return routePaths.filter(routePath => {
|
||||
const parts = routePath.replace(/\\/g, '/').split('/');
|
||||
const regionIdx = parts.indexOf("paths") + 1;
|
||||
if (regionIdx >= parts.length) return true;
|
||||
return !excludedRegions.includes(parts[regionIdx]);
|
||||
});
|
||||
const parts = routePath.replace(/\\/g, '/').split('/')
|
||||
const regionIdx = parts.indexOf("paths") + 1
|
||||
if (regionIdx >= parts.length) return true
|
||||
return !excludedRegions.includes(parts[regionIdx])
|
||||
})
|
||||
}
|
||||
|
||||
export { getRoutes, filterByTags, filterByRegion };
|
||||
export {
|
||||
getRoutes,
|
||||
filterByTags,
|
||||
filterByRegion
|
||||
}
|
||||
|
||||
30
repo/js/LinneaMining/utils/timeControl.js
Normal file
30
repo/js/LinneaMining/utils/timeControl.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 根据目标运行分钟数计算截止时间戳
|
||||
*
|
||||
* @param {number|string|null} targetMinutes - 目标运行分钟数
|
||||
* @returns {number|null} 截止时间戳,未设置返回 null
|
||||
*/
|
||||
function parseRunTimeLimit(targetMinutes) {
|
||||
if (!targetMinutes) return null
|
||||
const minutes = Number(targetMinutes)
|
||||
if (isNaN(minutes) || minutes <= 0) {
|
||||
log.warn(`无效的运行时长设置: ${targetMinutes}`)
|
||||
return null
|
||||
}
|
||||
return Date.now() + minutes * 60 * 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已到达运行截止时间
|
||||
*
|
||||
* @param {number|null} runUntilTime - 截止时间戳
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isTimeUp(runUntilTime) {
|
||||
return runUntilTime !== null && Date.now() >= runUntilTime
|
||||
}
|
||||
|
||||
export {
|
||||
parseRunTimeLimit,
|
||||
isTimeUp
|
||||
}
|
||||
@@ -26,4 +26,4 @@ function checkVersion(version, minVersion) {
|
||||
return a >= b
|
||||
}
|
||||
|
||||
export { checkVersion };
|
||||
export { checkVersion }
|
||||
|
||||
Reference in New Issue
Block a user