mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-03-15 03:23:22 +08:00
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.1 KiB |
76
repo/js/采集cd管理/assets/学习螃蟹技能2.json
Normal file
76
repo/js/采集cd管理/assets/学习螃蟹技能2.json
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"info": {
|
||||
"authors": [
|
||||
{
|
||||
"name": "芝士贝果",
|
||||
"links": "https://github.com/cheese-bagel"
|
||||
}
|
||||
],
|
||||
"bgi_version": "0.54.1-alpha.3",
|
||||
"description": "",
|
||||
"enable_monster_loot_split": false,
|
||||
"last_modified_time": 1765869417061,
|
||||
"map_match_method": "",
|
||||
"map_name": "SeaOfBygoneEras",
|
||||
"name": "E00-卡皮托利姆旧宫(学习螃蟹技能)",
|
||||
"tags": [],
|
||||
"type": "collect",
|
||||
"version": "1.0"
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 1,
|
||||
"move_mode": "walk",
|
||||
"type": "teleport",
|
||||
"x": 3543.8477,
|
||||
"y": 1380.2609
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 2,
|
||||
"move_mode": "run",
|
||||
"type": "path",
|
||||
"x": 3556.3594,
|
||||
"y": 1374.9818
|
||||
},
|
||||
{
|
||||
"action": "combat_script",
|
||||
"action_params": "keydown(VK_LCONTROL);wait(3);keyup(VK_LCONTROL);click(middle);wait(0.5);moveby(0,700)",
|
||||
"id": 3,
|
||||
"move_mode": "run",
|
||||
"type": "path",
|
||||
"x": 3569.1558,
|
||||
"y": 1379.5138
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 4,
|
||||
"move_mode": "dash",
|
||||
"type": "path",
|
||||
"x": 3600.522,
|
||||
"y": 1386.7323
|
||||
},
|
||||
{
|
||||
"action": "combat_script",
|
||||
"action_params": "attack",
|
||||
"id": 5,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 3613.7422,
|
||||
"y": 1393.2585
|
||||
},
|
||||
{
|
||||
"action": "combat_script",
|
||||
"action_params": "attack",
|
||||
"id": 6,
|
||||
"move_mode": "walk",
|
||||
"type": "orientation",
|
||||
"x": 3614.2134,
|
||||
"y": 1384.8744
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
repo/js/采集cd管理/assets/螃蟹技能图标.png
Normal file
BIN
repo/js/采集cd管理/assets/螃蟹技能图标.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
@@ -35,13 +35,13 @@ const userSettings = {
|
||||
disableJsons: settings.disableJsons || ""
|
||||
};
|
||||
|
||||
let ingredientProcessingFood = settings.ingredientProcessingFood;
|
||||
let foodCounts = settings.foodCount;
|
||||
let processingIngredient = settings.processingIngredient;
|
||||
|
||||
let firstCook = true;
|
||||
let firstsettime = true;
|
||||
let lastCookTime = new Date();
|
||||
let lastsettimeTime = new Date();
|
||||
let lastMapName = "";
|
||||
|
||||
// 解析禁用名单
|
||||
let disableArray = [];
|
||||
@@ -89,7 +89,6 @@ let lastRoll = new Date();
|
||||
let checkDelay = Math.round(findFInterval / 2);
|
||||
|
||||
let Foods = [];
|
||||
let foodCount = [];
|
||||
|
||||
const FiconRo = RecognitionObject.TemplateMatch(fIcontemplate, 1102, 335, 34, 400);
|
||||
FiconRo.Threshold = 0.95;
|
||||
@@ -97,8 +96,6 @@ FiconRo.InitTemplate();
|
||||
|
||||
const mainUiRo = RecognitionObject.TemplateMatch(mainUITemplate, 0, 0, 150, 150);
|
||||
|
||||
let underWater = false;
|
||||
|
||||
let checkInterval = +settings.checkInterval || 50;
|
||||
|
||||
(async function () {
|
||||
@@ -203,14 +200,29 @@ let checkInterval = +settings.checkInterval || 50;
|
||||
"default": "100"
|
||||
},
|
||||
{
|
||||
"name": "ingredientProcessingFood",
|
||||
"type": "input-text",
|
||||
"label": "食材名称\n用中文逗号,分隔"
|
||||
},
|
||||
{
|
||||
"name": "foodCount",
|
||||
"type": "input-text",
|
||||
"label": "食材数量\n数量对应上方的食材\n用中文逗号,分隔"
|
||||
"name": "processingIngredient",
|
||||
"type": "multi-checkbox",
|
||||
"label": "要加工的食材种类",
|
||||
"default": [],
|
||||
"options": [
|
||||
"面粉",
|
||||
"兽肉",
|
||||
"鱼肉",
|
||||
"神秘的肉",
|
||||
"黑麦粉",
|
||||
"奶油",
|
||||
"熏禽肉",
|
||||
"黄油",
|
||||
"火腿",
|
||||
"糖",
|
||||
"香辛料",
|
||||
"酸奶油",
|
||||
"蟹黄",
|
||||
"果酱",
|
||||
"奶酪",
|
||||
"培根",
|
||||
"香肠"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "checkInterval",
|
||||
@@ -438,12 +450,9 @@ let checkInterval = +settings.checkInterval || 50;
|
||||
log.error(`写入文件失败: ${recordFilePath}`);
|
||||
}
|
||||
|
||||
if (typeof ingredientProcessingFood === 'string' && ingredientProcessingFood.trim()) {
|
||||
Foods = ingredientProcessingFood
|
||||
.split(/[,,;;\s]+/) // 支持中英文逗号、分号、空格
|
||||
.map(word => word.trim())
|
||||
.filter(word => word.length > 0);
|
||||
}
|
||||
try {
|
||||
Foods = Array.from(processingIngredient);
|
||||
} catch (e) { Foods = []; }
|
||||
|
||||
if (typeof foodCounts === 'string' && foodCounts.trim()) {
|
||||
foodCount = foodCounts
|
||||
@@ -667,8 +676,8 @@ let checkInterval = +settings.checkInterval || 50;
|
||||
|
||||
const pickedCounter = {};
|
||||
priorityItemSet.forEach(n => pickedCounter[n] = 0);
|
||||
/* ===== 每轮开始输出剩余物品 ===== */
|
||||
log.info(`剩余目标材料 ${priorityList.map(t => `${t.itemName}*${t.count}`).join(', ')} `);
|
||||
/* ===== 剩余物品 ===== */
|
||||
let remaining = priorityList.map(t => `${t.itemName}*${t.count}`).join(', ');
|
||||
/* 4-1 扫描 + 读 record + 前置过滤(禁用/时间/材料相关)+ 计算效率 + CD后置排除 */
|
||||
const allFiles = await readFolder('pathing', true);
|
||||
const rawRecord = await file.readText(`${recordFolder}/${subFolderName}/record.json`);
|
||||
@@ -783,12 +792,14 @@ let checkInterval = +settings.checkInterval || 50;
|
||||
}
|
||||
}
|
||||
|
||||
log.info(`当前进度:执行路线 ${fileName},剩余优先材料:${remaining}`);
|
||||
|
||||
let timeNow = new Date();
|
||||
if (Foods.length != 0 && (((timeNow - lastCookTime) > cookInterval) || firstCook)) {
|
||||
firstCook = false;
|
||||
await ingredientProcessing();
|
||||
lastCookTime = new Date();
|
||||
underWater = false;
|
||||
lastMapName = "Teyvat";
|
||||
}
|
||||
|
||||
if (settings.setTimeMode && settings.setTimeMode != "不调节时间" && (((timeNow - lastsettimeTime) > settimeInterval) || firstsettime)) {
|
||||
@@ -804,16 +815,28 @@ let checkInterval = +settings.checkInterval || 50;
|
||||
runOnce.push(fileName);
|
||||
|
||||
/* ================================= */
|
||||
log.info(`当前进度:执行路线 ${fileName}`);
|
||||
state.running = true;
|
||||
|
||||
const raw = file.readTextSync(filePath);
|
||||
const json = JSON.parse(raw);
|
||||
const mapName = (json.info?.map_name && json.info.map_name.trim()) ? json.info.map_name : 'Teyvat';
|
||||
if (filePath.includes('枫丹水下')) {
|
||||
log.info("当前路线为水下路线,检查螃蟹技能");
|
||||
let skillRes = await findAndClick("assets/螃蟹技能图标.png", false, 1000);
|
||||
if (!skillRes || lastMapName != mapName) {
|
||||
log.info("识别到没有螃蟹技能或上一条路线处于其他地图,前往获取螃蟹技能");
|
||||
|
||||
if (mapName === "SeaOfBygoneEras") {
|
||||
await pathingScript.runFile("assets/学习螃蟹技能2.json");
|
||||
}
|
||||
else {
|
||||
"assets/学习螃蟹技能1.json";
|
||||
}
|
||||
}
|
||||
}
|
||||
lastMapName = mapName;
|
||||
const pickupTask = recognizeAndInteract();
|
||||
if (!underWater && filePath.includes('枫丹水下')) {
|
||||
await pathingScript.runFile("assets/A00-塞洛海原(学习螃蟹技能).json");
|
||||
underWater = true;
|
||||
}
|
||||
if (underWater && !filePath.includes('枫丹水下')) {
|
||||
underWater = false;
|
||||
}
|
||||
|
||||
try {
|
||||
await pathingScript.runFile(filePath);
|
||||
} catch (e) {
|
||||
@@ -1116,7 +1139,7 @@ let checkInterval = +settings.checkInterval || 50;
|
||||
firstCook = false;
|
||||
await ingredientProcessing();
|
||||
lastCookTime = new Date();
|
||||
underWater = false;
|
||||
lastMapName = "Teyvat";
|
||||
}
|
||||
|
||||
if (settings.setTimeMode && settings.setTimeMode != "不调节时间" && (((timeNow - lastsettimeTime) > settimeInterval) || firstsettime)) {
|
||||
@@ -1155,17 +1178,29 @@ let checkInterval = +settings.checkInterval || 50;
|
||||
/* ======================================= */
|
||||
|
||||
state.running = true;
|
||||
const raw = file.readTextSync(filePath.fullPath);
|
||||
const json = JSON.parse(raw);
|
||||
const mapName = (json.info?.map_name && json.info.map_name.trim()) ? json.info.map_name : 'Teyvat';
|
||||
if (filePath.fullPath.includes('枫丹水下')) {
|
||||
log.info("当前路线为水下路线,检查螃蟹技能");
|
||||
let skillRes = await findAndClick("assets/螃蟹技能图标.png", false);
|
||||
if (!skillRes || lastMapName != mapName) {
|
||||
log.info("识别到没有螃蟹技能或上一条路线处于其他地图,前往获取螃蟹技能");
|
||||
|
||||
if (mapName === "SeaOfBygoneEras") {
|
||||
await pathingScript.runFile("assets/学习螃蟹技能2.json");
|
||||
}
|
||||
else {
|
||||
"assets/学习螃蟹技能1.json";
|
||||
}
|
||||
}
|
||||
}
|
||||
lastMapName = mapName;
|
||||
const pickupTask = recognizeAndInteract();
|
||||
|
||||
log.info(`当前进度:路径组${i} ${folder} ${fileName} 为第 ${groupFiles.indexOf(filePath) + 1}/${groupFiles.length} 个`);
|
||||
log.info(`当前进度:执行路线 ${fileName},路径组${i} ${folder} 第 ${groupFiles.indexOf(filePath) + 1}/${groupFiles.length} 个`);
|
||||
log.info(`当前路线分均效率为 ${(filePath._efficiency ?? 0).toFixed(2)}`);
|
||||
if (!underWater && filePath.fullPath.includes('枫丹水下')) {
|
||||
await pathingScript.runFile("assets/A00-塞洛海原(学习螃蟹技能).json");
|
||||
underWater = true;
|
||||
}
|
||||
if (underWater && !filePath.fullPath.includes('枫丹水下')) {
|
||||
underWater = false;
|
||||
}
|
||||
|
||||
try {
|
||||
state.runPickupLog = []; // 新路线开始前清空
|
||||
await pathingScript.runFile(filePath.fullPath);
|
||||
@@ -1797,7 +1832,7 @@ async function isTimeRestricted(timeRule, threshold = 5) {
|
||||
/**
|
||||
* 食材加工主函数,用于自动前往指定地点进行食材的加工
|
||||
*
|
||||
* 该函数会根据 Foods 和 foodCount 数组中的食材名称和数量,依次查找并制作对应的料食材
|
||||
* 该函数会根据 Foods 数组中的食材名称,依次查找并制作对应的料食材
|
||||
* 支持调味品类食材(直接在“食材加工”界面查找)
|
||||
*
|
||||
* @returns {Promise<void>} 无返回值,执行完所有加工流程后退出
|
||||
@@ -1809,11 +1844,9 @@ async function ingredientProcessing() {
|
||||
"奶酪", "培根", "香肠"
|
||||
];
|
||||
if (Foods.length == 0) { log.error("未选择要加工的食材"); return; }
|
||||
if (Foods.length != foodCount.length) { log.error("请检查食材与对应的数量是否一致!"); return; }
|
||||
const taskList = Foods.map((name, i) => `${name}*${foodCount[i]}`).join(",");
|
||||
const tasks = Foods.map((name, idx) => ({
|
||||
const taskList = Foods.map((name) => `${name}`).join(",");
|
||||
const tasks = Foods.map((name) => ({
|
||||
name,
|
||||
count: Number(foodCount[idx]) || 0,
|
||||
done: false
|
||||
}));
|
||||
log.info(`本次加工食材:${taskList}`);
|
||||
@@ -1889,7 +1922,6 @@ async function ingredientProcessing() {
|
||||
await sleep(100);
|
||||
}
|
||||
Foods.splice(i, 1);
|
||||
foodCount.splice(i, 1);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1898,9 +1930,9 @@ async function ingredientProcessing() {
|
||||
await findPNG("选择加工数量");
|
||||
click(960, 460);
|
||||
await sleep(800);
|
||||
inputText(String(tasks[i].count));
|
||||
inputText(String(99));
|
||||
|
||||
log.info(`尝试制作${tasks[i].name} ${tasks[i].count}个`);
|
||||
log.info(`尝试制作${tasks[i].name} 99个`);
|
||||
await clickPNG("确认加工");
|
||||
await sleep(500);
|
||||
|
||||
@@ -1917,7 +1949,6 @@ async function ingredientProcessing() {
|
||||
await sleep(100);
|
||||
}
|
||||
Foods.splice(i, 1);
|
||||
foodCount.splice(i, 1);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1954,7 +1985,7 @@ async function ingredientProcessing() {
|
||||
}
|
||||
}
|
||||
|
||||
const remain1 = tasks.filter(t => !t.done).map(t => `${t.name}*${t.count}`).join(",") || "无";
|
||||
const remain1 = tasks.filter(t => !t.done).map(t => `${t.name}`).join(",") || "无";
|
||||
log.info(`剩余待加工食材:${remain1}`);
|
||||
|
||||
if (remain1 === "无") {
|
||||
@@ -1980,7 +2011,7 @@ async function ingredientProcessing() {
|
||||
|
||||
for (const item of foodItems) {
|
||||
click(item.x, item.y); await sleep(1 * checkInterval);
|
||||
click(item.x, item.y); await sleep(6 * checkInterval);
|
||||
click(item.x, item.y); await sleep(3 * checkInterval);
|
||||
|
||||
for (let round = 0; round < 5; round++) {
|
||||
const rg = captureGameRegion();
|
||||
@@ -2022,7 +2053,7 @@ async function ingredientProcessing() {
|
||||
}
|
||||
}
|
||||
|
||||
const remain = tasks.filter(t => !t.done).map(t => `${t.name}*${t.count}`).join(",") || "无";
|
||||
const remain = tasks.filter(t => !t.done).map(t => `${t.name}`).join(",") || "无";
|
||||
log.info(`剩余待加工食材:${remain}`);
|
||||
|
||||
|
||||
@@ -2075,7 +2106,7 @@ async function clickPNG(png, maxAttempts = 20) {
|
||||
const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/RecognitionObject/${png}.png`));
|
||||
pngRo.Threshold = 0.95;
|
||||
pngRo.InitTemplate();
|
||||
return await findAndClick(pngRo, true, maxAttempts);
|
||||
return await findAndClick(pngRo, true, maxAttempts * checkInterval, checkInterval);
|
||||
}
|
||||
|
||||
async function findPNG(png, maxAttempts = 20) {
|
||||
@@ -2083,19 +2114,75 @@ async function findPNG(png, maxAttempts = 20) {
|
||||
const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/RecognitionObject/${png}.png`));
|
||||
pngRo.Threshold = 0.95;
|
||||
pngRo.InitTemplate();
|
||||
return await findAndClick(pngRo, false, maxAttempts);
|
||||
return await findAndClick(pngRo, false, maxAttempts * checkInterval, checkInterval);
|
||||
}
|
||||
|
||||
async function findAndClick(target, doClick = true, maxAttempts = 60) {
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
const rg = captureGameRegion();
|
||||
try {
|
||||
const res = rg.find(target);
|
||||
if (res.isExist()) { await sleep(checkInterval * 2 + 50); if (doClick) { res.click(); } await sleep(50); return true; }
|
||||
} finally { rg.dispose(); }
|
||||
if (i < maxAttempts - 1) await sleep(checkInterval);
|
||||
/**
|
||||
* 通用找图/找RO并可选点击(支持单图片文件路径、单RO、图片文件路径数组、RO数组)
|
||||
* @param {string|string[]|RecognitionObject|RecognitionObject[]} target
|
||||
* @param {boolean} [doClick=true] 是否点击
|
||||
* @param {number} [timeout=3000] 识别时间上限(ms)
|
||||
* @param {number} [interval=50] 识别间隔(ms)
|
||||
* @param {number} [retType=0] 0-返回布尔;1-返回 Region 结果
|
||||
* @param {number} [preClickDelay=50] 点击前等待
|
||||
* @param {number} [postClickDelay=50] 点击后等待
|
||||
* @returns {boolean|Region} 根据 retType 返回是否成功或最终 Region
|
||||
*/
|
||||
async function findAndClick(target,
|
||||
doClick = true,
|
||||
timeout = 3000,
|
||||
interval = 50,
|
||||
retType = 0,
|
||||
preClickDelay = 50,
|
||||
postClickDelay = 50) {
|
||||
try {
|
||||
// 1. 统一转成 RecognitionObject 数组
|
||||
let ros = [];
|
||||
if (Array.isArray(target)) {
|
||||
ros = target.map(t =>
|
||||
(typeof t === 'string')
|
||||
? RecognitionObject.TemplateMatch(file.ReadImageMatSync(t))
|
||||
: t
|
||||
);
|
||||
} else {
|
||||
ros = [(typeof target === 'string')
|
||||
? RecognitionObject.TemplateMatch(file.ReadImageMatSync(target))
|
||||
: target];
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
let found = null;
|
||||
|
||||
while (Date.now() - start <= timeout) {
|
||||
const gameRegion = captureGameRegion();
|
||||
try {
|
||||
// 依次尝试每一个 ro
|
||||
for (const ro of ros) {
|
||||
const res = gameRegion.find(ro);
|
||||
if (!res.isEmpty()) { // 找到
|
||||
found = res;
|
||||
if (doClick) {
|
||||
await sleep(preClickDelay);
|
||||
res.click();
|
||||
await sleep(postClickDelay);
|
||||
}
|
||||
break; // 成功即跳出 for
|
||||
}
|
||||
}
|
||||
if (found) break; // 成功即跳出 while
|
||||
} finally {
|
||||
gameRegion.dispose();
|
||||
}
|
||||
await sleep(interval); // 没找到时等待
|
||||
}
|
||||
|
||||
// 3. 按需返回
|
||||
return retType === 0 ? !!found : (found || null);
|
||||
|
||||
} catch (error) {
|
||||
log.error(`执行通用识图时出现错误:${error.message}`);
|
||||
return retType === 0 ? false : null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2128,6 +2215,7 @@ function isArrivedAtEndPoint(fullPath) {
|
||||
if (endX === 0 && endY === 0) return false; // 没找到有效点
|
||||
|
||||
/* 2. 取当前人物坐标 */
|
||||
|
||||
const mapName = (json.info?.map_name && json.info.map_name.trim()) ? json.info.map_name : 'Teyvat';
|
||||
const pos = genshin.getPositionFromMap(mapName, 3000);
|
||||
const curX = pos.X;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "采集cd管理",
|
||||
"version": "2.9.5",
|
||||
"version": "2.10.1",
|
||||
"bgi_version": "0.44.8",
|
||||
"description": "仅面对会操作文件和读readme的用户,基于文件夹操作自动管理采集路线的cd,会按照路径组的顺序依次运行,直到指定的时间,并会按照给定的cd类型,自动跳过未刷新的路线",
|
||||
"saved_files": [
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user