chore: initial commit

This commit is contained in:
2026-10-22 17:07:08 +08:00
commit 0acef64f48
200 changed files with 35546 additions and 0 deletions
@@ -0,0 +1,24 @@
import type {Bot} from '@wp2508/mineflayer';
import type {BaseFunction, FunctionArgument} from '../../../types/bot/function/function.ts';
export class init implements BaseFunction<number[]> {
readonly name = 'change_main_hand_slot';
readonly i18n = {
lang: 'zh-CN', name: '切换主手槽位', description: '切换主手选中的快捷栏槽位,编号为 0 到 8',
};
readonly args: FunctionArgument[] = [{
name: 'slot', type: 'number',
i18n: {lang: 'zh-CN', name: '快捷栏槽位', description: '0 到 8 的整数,分别对应快捷栏第 1 到第 9 格'},
}];
async run(bot: Bot, args: number[]): Promise<boolean> {
if (!Array.isArray(args) || args.length !== 1 || !Number.isSafeInteger(args[0])
|| args[0] < 0 || args[0] > 8) return false;
try {
bot.setQuickBarSlot(args[0]);
return bot.quickBarSlot === args[0];
} catch {
return false;
}
}
}
@@ -0,0 +1,22 @@
import type {Bot} from '@wp2508/mineflayer';
import type {BaseFunction, FunctionArgument} from '../../../types/bot/function/function.ts';
export class init implements BaseFunction<[]> {
readonly name = 'close_current_window';
readonly i18n = {
lang: 'zh-CN', name: '关闭当前窗口', description: '关闭当前打开的容器窗口;没有打开窗口时直接成功',
};
readonly args: FunctionArgument[] = [];
async run(bot: Bot, args: []): Promise<boolean> {
if (!Array.isArray(args) || args.length !== 0) return false;
const window = bot.currentWindow;
if (!window) return true;
try {
await bot.closeWindow(window);
return bot.currentWindow == null;
} catch {
return false;
}
}
}
+12
View File
@@ -0,0 +1,12 @@
import {base_define} from "../../../types/bot/plugins/plugin.ts";
export const define: base_define = {
path: "inventory",
i18n: [
{
lang: "zh-CN",
name: "容器操作",
description: "Bot 容器操作, 提供容器相关功能"
}
]
}
+25
View File
@@ -0,0 +1,25 @@
import type {Bot} from '@wp2508/mineflayer';
import type {BaseFunction, FunctionArgument} from '../../../types/bot/function/function.ts';
export class init implements BaseFunction<number[]> {
readonly name = 'left_click_slot';
readonly i18n = {
lang: 'zh-CN', name: '左键点击槽位', description: '在当前窗口左键点击一个物品槽位,使用原生拾取、放置或合并行为',
};
readonly args: FunctionArgument[] = [{
name: 'slot', type: 'number',
i18n: {lang: 'zh-CN', name: '物品槽位', description: '当前窗口中的槽位编号'},
}];
async run(bot: Bot, args: number[]): Promise<boolean> {
const window = bot.currentWindow ?? bot.inventory;
if (!window || !Array.isArray(args) || args.length !== 1 || !Number.isSafeInteger(args[0])
|| args[0] < 0 || args[0] >= window.slots.length) return false;
try {
await bot.clickWindow(args[0], 0, 0);
return (bot.currentWindow ?? bot.inventory) === window;
} catch {
return false;
}
}
}
@@ -0,0 +1,25 @@
import type {Bot} from '@wp2508/mineflayer';
import type {BaseFunction, FunctionArgument} from '../../../types/bot/function/function.ts';
export class init implements BaseFunction<number[]> {
readonly name = 'right_click_slot';
readonly i18n = {
lang: 'zh-CN', name: '右键点击槽位', description: '在当前窗口右键点击一个物品槽位,使用原生半组拾取或单个放置行为',
};
readonly args: FunctionArgument[] = [{
name: 'slot', type: 'number',
i18n: {lang: 'zh-CN', name: '物品槽位', description: '当前窗口中的槽位编号'},
}];
async run(bot: Bot, args: number[]): Promise<boolean> {
const window = bot.currentWindow ?? bot.inventory;
if (!window || !Array.isArray(args) || args.length !== 1 || !Number.isSafeInteger(args[0])
|| args[0] < 0 || args[0] >= window.slots.length) return false;
try {
await bot.clickWindow(args[0], 1, 0);
return (bot.currentWindow ?? bot.inventory) === window;
} catch {
return false;
}
}
}
@@ -0,0 +1,45 @@
import type {Bot} from '@wp2508/mineflayer';
import type {BaseFunction, FunctionArgument} from '../../../types/bot/function/function.ts';
import {Mutex} from 'async-mutex';
import {cancellation_generation} from '../cancellation.ts';
const locks = new WeakMap<Bot, Mutex>();
export class init implements BaseFunction<number[]> {
readonly name = 'slot_switch_slot';
readonly i18n = {
lang: 'zh-CN', name: '物品交换', description: '依次左键点击源槽位、目标槽位,并将鼠标剩余物品放回源槽位;同类物品按原生规则合并',
};
readonly args: FunctionArgument[] = [
{name: 'slot', type: 'number', i18n: {lang: 'zh-CN', name: '物品槽位', description: '第一个槽位编号'}},
{name: 'new_slot', type: 'number', i18n: {lang: 'zh-CN', name: '目标槽位', description: '第二个槽位编号'}},
];
async run(bot: Bot, args: number[]): Promise<boolean> {
if (!Array.isArray(args) || args.length !== 2 || !args.every(Number.isSafeInteger)) return false;
const window = bot.currentWindow ?? bot.inventory;
if (!window) return false;
const generation = cancellation_generation(bot);
const active = () => cancellation_generation(bot) === generation;
let lock = locks.get(bot);
if (!lock) locks.set(bot, lock = new Mutex());
return lock.runExclusive(async () => {
const [slot, new_slot] = args;
if (!active() || (bot.currentWindow ?? bot.inventory) !== window || window.selectedItem
|| slot === new_slot || args.some(value => value < 0 || value >= window.slots.length)) return false;
try {
await bot.clickWindow(slot, 0, 0);
if (!active() || (bot.currentWindow ?? bot.inventory) !== window) return false;
await bot.clickWindow(new_slot, 0, 0);
if (!active() || (bot.currentWindow ?? bot.inventory) !== window) return false;
// An empty cursor means a final click would pick the source item up again.
if (window.selectedItem) {
await bot.clickWindow(slot, 0, 0);
}
return active() && (bot.currentWindow ?? bot.inventory) === window && !window.selectedItem;
} catch {
return false;
}
});
}
}
+65
View File
@@ -0,0 +1,65 @@
import type {Bot} from "@wp2508/mineflayer";
import type {BaseFunction, FunctionArgument} from "../../../types/bot/function/function.ts";
import {Mutex} from "async-mutex";
import {cancellation_generation} from '../cancellation.ts';
const locks = new WeakMap<Bot, Mutex>();
export class init implements BaseFunction<number[]> {
public name = "slot_to_slot";
public i18n = {
lang: "zh-CN",
name: "物品移动",
description: "将物品从一个槽位移动到另一个槽位, 目标槽位必须为空"
}
public args: FunctionArgument[] = [
{
name: "slot",
type: "number",
i18n: {
lang: "zh-CN",
name: "物品槽位",
description: "物品槽位"
}
},
{
name: "new_slot",
type: "number",
i18n: {
lang: "zh-CN",
name: "新物品槽位",
description: "新物品槽位"
}
}
]
async run(bot: Bot, args: number[]): Promise<boolean> {
if (!Array.isArray(args) || args.length !== 2 || !args.every(Number.isSafeInteger)) {
return false;
}
const [slot, new_slot] = args;
const window = bot.currentWindow ?? bot.inventory;
if (!window) return false;
const generation = cancellation_generation(bot);
const active = () => cancellation_generation(bot) === generation;
let lock = locks.get(bot);
if (!lock) locks.set(bot, lock = new Mutex());
return lock.runExclusive(async () => {
if (!active() || (bot.currentWindow ?? bot.inventory) !== window) return false;
if ([slot, new_slot].some(value => value < 0 || value >= window.slots.length)) {
return false;
}
if (slot === new_slot || !window.slots[slot] || window.slots[new_slot] || window.selectedItem) return false;
try {
await bot.clickWindow(slot, 0, 0);
// Never apply the destination click to a replacement window.
if (!active() || (bot.currentWindow ?? bot.inventory) !== window || window.slots[new_slot]) return false;
await bot.clickWindow(new_slot, 0, 0);
return active();
} catch {
return false;
}
});
}
}