js:锄地一条龙1.15 (#1323)

This commit is contained in:
mno
2025-07-11 00:46:36 +08:00
committed by GitHub
parent e57f7771d9
commit bb40ec8f32
15 changed files with 90 additions and 15 deletions

View File

@@ -39,7 +39,7 @@
- - 选项 **强制刷新所有路线cd** 用于清除js记录的运行历史 - - 选项 **强制刷新所有路线cd** 用于清除js记录的运行历史
- **选择执行第几个路径组:** 本js会分组运行地图追踪分组方式详见后续选项需要分组运行时请确保精英目标数量小怪目标数量各个路径组的标签等信息【完全相同】复制配置组时未知原因无法正确复制配置请不要使用 - **选择执行第几个路径组:** 本js会分组运行地图追踪分组方式详见后续选项需要分组运行时请确保精英目标数量小怪目标数量各个路径组的标签等信息【完全相同】复制配置组时未知原因无法正确复制配置请不要使用
- **本路径组使用配队名称:** 填写该路径组使用的配队名称js会自动切换 - **本路径组使用配队名称:** 填写该路径组使用的配队名称js会自动切换
- **是否禁用js拾取:** 本js采用黑白名单结合的方式实现仅拾取部分物品默认只拾取狗粮和晶蝶如果你想要使用bgi默认的拾取以拾取绝大部分物品禁用 - **拾取模式** 本js采用黑白名单结合的方式实现仅拾取部分物品默认只拾取狗粮和晶蝶如果你想要使用bgi默认的拾取以拾取绝大部分物品选择bgi拾取如果不想拾取任何物品请选择不拾取任何物品
- **账户名称:** 本js支持多用户不同账户的记录分开存储当你需要使用多用户时请在这里填写不同的文本来区分不同账号的记录如果你只使用一个账号请不要修改该选项 - **账户名称:** 本js支持多用户不同账户的记录分开存储当你需要使用多用户时请在这里填写不同的文本来区分不同账号的记录如果你只使用一个账号请不要修改该选项
- **路径组x标签** 本js使用不同的标签来禁用或分组路线多个标签之间使用中文逗号分隔目前支持的标签如下 - **路径组x标签** 本js使用不同的标签来禁用或分组路线多个标签之间使用中文逗号分隔目前支持的标签如下
- - 水免:表明路线含有水元素伤害免疫的怪物,使用以水元素伤害为主的队伍处理该路线时可能较为麻烦 - - 水免:表明路线含有水元素伤害免疫的怪物,使用以水元素伤害为主的队伍处理该路线时可能较为麻烦
@@ -54,7 +54,8 @@
- **路线效率计算权重:** 影响js评估路线价值计算公式如下权重越大越看重总收益 - **路线效率计算权重:** 影响js评估路线价值计算公式如下权重越大越看重总收益
- $$ 怪均^k \times 秒均 $$ - $$ 怪均^k \times 秒均 $$
- **目标数量:** 选取路线目标达到的精英怪数量默认为400同理小怪数量默认为2000 - **目标数量:** 选取路线目标达到的精英怪数量默认为400同理小怪数量默认为2000
- **排除关键词:** 含有关键词的路线会被排除,例如填写纳塔来排除所有纳塔路线,填写暴徒来排除所有含有丘丘暴徒的路线,同样使用中文逗号分隔 - **优先关键词:**含有关键词的路线会被视为拥有最高效率例如填写600来让所有600怪物优先考虑填写骗骗花来优先考虑骗骗花
- **排除关键词:** 含有关键词的路线会被排除,例如填写纳塔来排除所有纳塔路线,同样使用中文逗号分隔
### 二、**锄地收益** ### 二、**锄地收益**
- 击杀精英怪和小怪通常会掉落对应的材料和一定量摩拉,同时为队伍中角色提供经验,精英怪还会概率掉落三四星的战狂、教官、流放者圣遗物 - 击杀精英怪和小怪通常会掉落对应的材料和一定量摩拉,同时为队伍中角色提供经验,精英怪还会概率掉落三四星的战狂、教官、流放者圣遗物
@@ -72,6 +73,10 @@
--- ---
### 更新日志 ### 更新日志
### 1.1.52025.07.10
1. 添加验证游戏卡住等情况下会终止js并不再将后续路线视为运行完成便于重跑
2. 添加优先关键词,便于优先考虑部分路线
3. 优化路线效率计算逻辑,现在计算路线效率时会考虑目标精英数量和小怪数量的比例
### 1.1.32025.07.09 ### 1.1.32025.07.09
1. 优化拾取逻辑 1. 优化拾取逻辑
2. 调整部分路线的数据 2. 调整部分路线的数据

View File

@@ -7,7 +7,7 @@ const pickupMode = settings.pickupMode || "js拾取默认只拾取狗粮和
//自定义配置处理 //自定义配置处理
const operationMode = settings.operationMode || "运行锄地路线"; const operationMode = settings.operationMode || "运行锄地路线";
let k = settings.efficiencyIndex || 0.5; let k = settings.efficiencyIndex || 0.5;
k = k / 1.25; k = k;
let targetEliteNum = (+settings.targetEliteNum || 400); let targetEliteNum = (+settings.targetEliteNum || 400);
targetEliteNum += 5;//预留漏怪 targetEliteNum += 5;//预留漏怪
let targetMonsterNum = (+settings.targetMonsterNum + 1 || 2000); let targetMonsterNum = (+settings.targetMonsterNum + 1 || 2000);
@@ -26,6 +26,7 @@ const pickupMode = settings.pickupMode || "js拾取默认只拾取狗粮和
// 将 group2Tags、group3Tags 和 group4Tags 的内容添加到 group1Tags 中,并去除重复项 // 将 group2Tags、group3Tags 和 group4Tags 的内容添加到 group1Tags 中,并去除重复项
group1Tags = [...new Set([...group1Tags, ...group2Tags, ...group3Tags, ...group4Tags])]; group1Tags = [...new Set([...group1Tags, ...group2Tags, ...group3Tags, ...group4Tags])];
const priorityTags = (settings.priorityTags || "").split("").map(tag => tag.trim()).filter(tag => tag.length > 0);
const excludeTags = (settings.excludeTags || "").split("").map(tag => tag.trim()).filter(tag => tag.length > 0); const excludeTags = (settings.excludeTags || "").split("").map(tag => tag.trim()).filter(tag => tag.length > 0);
const accountName = settings.accountName || "默认账户"; const accountName = settings.accountName || "默认账户";
// 拾取黑白名单处理 // 拾取黑白名单处理
@@ -57,8 +58,8 @@ const pickupMode = settings.pickupMode || "js拾取默认只拾取狗粮和
//加载路线cd信息 //加载路线cd信息
await initializeCdTime(pathings, accountName); await initializeCdTime(pathings, accountName);
//按照用户配置标记可用路线 //按照用户配置标记路线
await markPathings(pathings, group1Tags, group2Tags, group3Tags, group4Tags, excludeTags); await markPathings(pathings, group1Tags, group2Tags, group3Tags, group4Tags, priorityTags, excludeTags);
//找出最优组合 //找出最优组合
await findBestRouteGroups(pathings, k, targetEliteNum, targetMonsterNum); await findBestRouteGroups(pathings, k, targetEliteNum, targetMonsterNum);
@@ -184,7 +185,7 @@ async function processPathings() {
return pathings; // 返回处理后的 pathings 数组 return pathings; // 返回处理后的 pathings 数组
} }
async function markPathings(pathings, group1Tags, group2Tags, group3Tags, group4Tags, excludeTags) { async function markPathings(pathings, group1Tags, group2Tags, group3Tags, group4Tags, priorityTags, excludeTags) {
// 找出存在于 group1Tags 中且不在其他组标签中的标签 // 找出存在于 group1Tags 中且不在其他组标签中的标签
const uniqueTags = group1Tags.filter(tag => { const uniqueTags = group1Tags.filter(tag => {
return !group2Tags.includes(tag) && !group3Tags.includes(tag) && !group4Tags.includes(tag); return !group2Tags.includes(tag) && !group3Tags.includes(tag) && !group4Tags.includes(tag);
@@ -195,6 +196,9 @@ async function markPathings(pathings, group1Tags, group2Tags, group3Tags, group4
pathing.tags = pathing.tags || []; pathing.tags = pathing.tags || [];
pathing.monsterInfo = pathing.monsterInfo || {}; pathing.monsterInfo = pathing.monsterInfo || {};
// 初始化 pathing.prioritized 为 false
pathing.prioritized = false;
// 检查路径的 tags 是否包含 uniqueTags // 检查路径的 tags 是否包含 uniqueTags
const containsUniqueTag = uniqueTags.some(uniqueTag => pathing.tags.includes(uniqueTag)); const containsUniqueTag = uniqueTags.some(uniqueTag => pathing.tags.includes(uniqueTag));
@@ -211,10 +215,25 @@ async function markPathings(pathings, group1Tags, group2Tags, group3Tags, group4
return fullPathContainsExcludeTag || tagsContainExcludeTag || monsterInfoContainsExcludeTag; return fullPathContainsExcludeTag || tagsContainExcludeTag || monsterInfoContainsExcludeTag;
}); });
// 检查 fullPath、tags 或 monsterInfo 是否包含 priorityTags 中的任意一个子字符串
const containsPriorityTag = priorityTags.some(priorityTag => {
// 检查 fullPath 是否包含 priorityTag
const fullPathContainsPriorityTag = pathing.fullPath && pathing.fullPath.includes(priorityTag);
// 检查 tags 是否包含 priorityTag
const tagsContainPriorityTag = pathing.tags.some(tag => tag.includes(priorityTag));
// 检查 monsterInfo 的键是否包含 priorityTag
const monsterInfoContainsPriorityTag = Object.keys(pathing.monsterInfo).some(monsterName => monsterName.includes(priorityTag));
// 返回是否包含任意一个 priorityTag
return fullPathContainsPriorityTag || tagsContainPriorityTag || monsterInfoContainsPriorityTag;
});
// 如果包含 uniqueTags 或 excludeTags则标记为 false否则标记为 true // 如果包含 uniqueTags 或 excludeTags则标记为 false否则标记为 true
pathing.available = !(containsUniqueTag || containsExcludeTag); pathing.available = !(containsUniqueTag || containsExcludeTag);
});
// 如果包含 priorityTags则标记为 true
pathing.prioritized = containsPriorityTag;
});
} }
async function findBestRouteGroups(pathings, k, targetEliteNum, targetMonsterNum) { async function findBestRouteGroups(pathings, k, targetEliteNum, targetMonsterNum) {
@@ -228,6 +247,9 @@ async function findBestRouteGroups(pathings, k, targetEliteNum, targetMonsterNum
let totalGainCombined = 0; // 总收益 let totalGainCombined = 0; // 总收益
let totalTimeCombined = 0; // 总耗时 let totalTimeCombined = 0; // 总耗时
let maxE1 = 0;
let maxE2 = 0;
// 遍历 pathings计算并添加 G1、G2、E1 和 E2 属性 // 遍历 pathings计算并添加 G1、G2、E1 和 E2 属性
pathings.forEach(pathing => { pathings.forEach(pathing => {
pathing.selected = false; // 初始化 selected 属性为 false pathing.selected = false; // 初始化 selected 属性为 false
@@ -235,8 +257,24 @@ async function findBestRouteGroups(pathings, k, targetEliteNum, targetMonsterNum
pathing.G1 = G1; pathing.G1 = G1;
const G2 = pathing.mora_m; // 进入二组的收益 const G2 = pathing.mora_m; // 进入二组的收益
pathing.G2 = G2; pathing.G2 = G2;
pathing.E1 = pathing.e === 0 ? 0 : ((G1 - 0.5 * G2) / pathing.e) ** k * (G1 / pathing.t); // 进入一组的效率 pathing.E1 = pathing.e === 0 ? 0 : ((G1 - (targetEliteNum * G2) / (targetEliteNum + targetMonsterNum)) / pathing.e) ** k * (G1 / pathing.t); // 进入一组的效率
pathing.E2 = pathing.m === 0 ? 0 : (G2 / pathing.m) ** k * (G2 / pathing.t); // 进入二组的效率 pathing.E2 = pathing.m === 0 ? 0 : (G2 / pathing.m) ** k * (G2 / pathing.t); // 进入二组的效率
if (maxE1 < pathing.E1) {
maxE1 = pathing.E1;
}
if (maxE2 < pathing.E2) {
maxE2 = pathing.E2;
}
});
pathings.forEach(pathing => {
if (pathing.prioritized) {
pathing.E1 = maxE1 + 1;
pathing.E2 = maxE2 + 1;
}
}); });
// 封装第一轮选择逻辑 // 封装第一轮选择逻辑
@@ -671,6 +709,9 @@ async function copyPathingsByGroup(pathings) {
} }
async function processPathingsByGroup(pathings, targetTexts, blacklistKeywords, accountName) { async function processPathingsByGroup(pathings, targetTexts, blacklistKeywords, accountName) {
let lastX = 0;
let lastY = 0;
let runningFailCount = 0;
// 定义路径组名称到组号的映射 // 定义路径组名称到组号的映射
const groupMapping = { const groupMapping = {
"路径组一": 1, "路径组一": 1,
@@ -767,7 +808,27 @@ async function processPathingsByGroup(pathings, targetTexts, blacklistKeywords,
break; break;
} }
await fakeLog(`${pathing.fileName}`, false, false, 0); await fakeLog(`${pathing.fileName}`, false, false, 0);
// 计算下一个 UTC 时间的晚上 8 点
const miniMapPosition = await genshin.getPositionFromMap();
// 比较坐标
const diffX = Math.abs(lastX - miniMapPosition.X);
const diffY = Math.abs(lastY - miniMapPosition.Y);
lastX = miniMapPosition.X;
lastY = miniMapPosition.Y;
if ((diffX + diffY) < 5) {
runningFailCount++;
} else {
//log.info(`当前坐标(${miniMapPosition.X}${miniMapPosition.Y},距离上次距离${(diffX + diffY)}`)
runningFailCount = 0;
}
if (runningFailCount >= 2) {
log.error("连续三条路线终止时坐标不变,终止运行");
break;
}
// 计算下一个 UTC 时间的晚上 8 点(即北京时间凌晨四点)
const nextEightClock = new Date(now); const nextEightClock = new Date(now);
nextEightClock.setUTCHours(20, 0, 0, 0); // 设置为 UTC 时间的 20:00 nextEightClock.setUTCHours(20, 0, 0, 0); // 设置为 UTC 时间的 20:00
if (nextEightClock <= now) { if (nextEightClock <= now) {
@@ -833,8 +894,8 @@ async function updateCdTimeRecord(pathings, accountName) {
const cdTimeData = pathings.map(pathing => ({ const cdTimeData = pathings.map(pathing => ({
fileName: pathing.fileName, fileName: pathing.fileName,
//description: pathing.description, //description: pathing.description,
精英数量: pathing.e, //精英数量: pathing.e,
小怪数量: pathing.m, //小怪数量: pathing.m,
标签: pathing.tags, 标签: pathing.tags,
cdTime: pathing.cdTime cdTime: pathing.cdTime
})); }));

View File

@@ -1,7 +1,7 @@
{ {
"manifest_version": 1, "manifest_version": 1,
"name": "锄地一条龙", "name": "锄地一条龙",
"version": "1.1.4", "version": "1.1.5",
"description": "一站式解决自动化锄地支持只拾取狗粮请阅读README.md后使用", "description": "一站式解决自动化锄地支持只拾取狗粮请阅读README.md后使用",
"authors": [ "authors": [
{ {

View File

@@ -7,7 +7,9 @@
"description": " 路线信息该路线预计用时85.01秒包含以下怪物1只冰深渊法师、3只冰萤。", "description": " 路线信息该路线预计用时85.01秒包含以下怪物1只冰深渊法师、3只冰萤。",
"map_name": "Teyvat", "map_name": "Teyvat",
"bgi_version": "0.45.0", "bgi_version": "0.45.0",
"tags": [], "tags": [
"高危"
],
"last_modified_time": 1751638015174, "last_modified_time": 1751638015174,
"authors": [ "authors": [
{ {

View File

@@ -7,7 +7,9 @@
"description": " 路线信息该路线预计用时57.21秒包含以下怪物3只冰萤。", "description": " 路线信息该路线预计用时57.21秒包含以下怪物3只冰萤。",
"map_name": "Teyvat", "map_name": "Teyvat",
"bgi_version": "0.45.0", "bgi_version": "0.45.0",
"tags": [], "tags": [
"高危"
],
"last_modified_time": 1751639100937, "last_modified_time": 1751639100937,
"authors": [ "authors": [
{ {

View File

@@ -88,9 +88,14 @@
"label": "目标小怪数量", "label": "目标小怪数量",
"default": "2000" "default": "2000"
}, },
{
"name": "priorityTags",
"type": "input-text",
"label": "优先关键词,含关键词的路线会被视为最高效率\n不同关键词使用【中文逗号】分隔\n例如填骗骗花可以优先选择含有骗骗花的路线\n建议使用怪物图鉴中的名字"
},
{ {
"name": "excludeTags", "name": "excludeTags",
"type": "input-text", "type": "input-text",
"label": "排除关键词,含关键词的路线会被完全排除\n不同关键词使用【中文逗号】分隔\n例如填丘丘暴徒可以排除所有含有丘丘暴徒的路线" "label": "排除关键词,含关键词的路线会被完全排除\n不同关键词使用【中文逗号】分隔\n例如填火斧丘丘暴徒,可以排除所有含有火斧丘丘暴徒的路线\n建议使用怪物图鉴中的名字"
} }
] ]