add path blocked detection
This commit is contained in:
parent
0f2837029e
commit
01132299b5
@ -43,7 +43,7 @@ export class Account {
|
|||||||
password: this.password,
|
password: this.password,
|
||||||
})).data;
|
})).data;
|
||||||
|
|
||||||
return new SessionCache(auth_info.accessToken, auth_info.clientToken
|
return new YggdrasilSession(auth_info.accessToken, auth_info.clientToken
|
||||||
, auth_info.selectedProfile, auth_info.availableProfiles);
|
, auth_info.selectedProfile, auth_info.availableProfiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ export class Credentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async authProfile(profile) {
|
async authProfile(profile) {
|
||||||
let sc = await SessionCache.load(profile);
|
let sc = await YggdrasilSession.load(profile);
|
||||||
if (sc != null && !(await sc.validate(this.endpoint))) { sc = null; }
|
if (sc != null && !(await sc.validate(this.endpoint))) { sc = null; }
|
||||||
|
|
||||||
if (sc == null) {
|
if (sc == null) {
|
||||||
@ -92,7 +92,7 @@ export class Credentials {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export class SessionCache {
|
export class YggdrasilSession {
|
||||||
constructor(accessToken, clientToken, selectedProfile, availableProfiles) {
|
constructor(accessToken, clientToken, selectedProfile, availableProfiles) {
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
this.clientToken = clientToken;
|
this.clientToken = clientToken;
|
||||||
@ -120,7 +120,7 @@ export class SessionCache {
|
|||||||
static async load(profile) {
|
static async load(profile) {
|
||||||
let cache_data = await readJsonFile(`.cache/${profile}.json`);
|
let cache_data = await readJsonFile(`.cache/${profile}.json`);
|
||||||
if (cache_data == null) { return null; }
|
if (cache_data == null) { return null; }
|
||||||
return new SessionCache(cache_data.accessToken, cache_data.clientToken, cache_data.selectedProfile);
|
return new YggdrasilSession(cache_data.accessToken, cache_data.clientToken, cache_data.selectedProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
async validate(endpoint) {
|
async validate(endpoint) {
|
||||||
@ -181,3 +181,25 @@ export class SessionCache {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class OfflineSession {
|
||||||
|
constructor(username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
name() { return this.username; }
|
||||||
|
session() { return null; }
|
||||||
|
async store() {}
|
||||||
|
static async load(profile) { return new OfflineSession(profile); }
|
||||||
|
async validate() { return true; }
|
||||||
|
async selectProfile(profile) { this.username = profile; }
|
||||||
|
|
||||||
|
mineflayer() {
|
||||||
|
if (this.username == null) { throw new ProfileNotSelectedError(); }
|
||||||
|
|
||||||
|
return {
|
||||||
|
username: this.name(),
|
||||||
|
auth: 'offline',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
55
index.mjs
55
index.mjs
@ -3,7 +3,7 @@ import mineflayer from 'mineflayer';
|
|||||||
import yargs from 'yargs';
|
import yargs from 'yargs';
|
||||||
import { parseLogin, waitEvent } from 'compass-utils';
|
import { parseLogin, waitEvent } from 'compass-utils';
|
||||||
import repl from 'node:repl';
|
import repl from 'node:repl';
|
||||||
import vm from 'node:vm';
|
import debug from 'debug';
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const args = yargs((await import('yargs/helpers')).hideBin(process.argv))
|
const args = yargs((await import('yargs/helpers')).hideBin(process.argv))
|
||||||
@ -22,37 +22,62 @@ async function main() {
|
|||||||
description: 'Credentials\' library file.',
|
description: 'Credentials\' library file.',
|
||||||
type: "string",
|
type: "string",
|
||||||
default: "credentials.json",
|
default: "credentials.json",
|
||||||
|
}).option('offline', {
|
||||||
|
description: 'Login without credentials.',
|
||||||
|
type: 'boolean',
|
||||||
}).usage('Uasge: profile@host:port').help().alias('help', 'h').argv;
|
}).usage('Uasge: profile@host:port').help().alias('help', 'h').argv;
|
||||||
|
|
||||||
let login_info = args._[0];
|
let login_info = args._[0];
|
||||||
if (login_info == null) { return; }
|
if (login_info == null) { return; }
|
||||||
const [name, host, port] = parseLogin(login_info);
|
const [name, host, port] = parseLogin(login_info);
|
||||||
const credential_info = await authlib.Credentials.fromFile(args.credentialsLib);
|
|
||||||
if (credential_info == null) {
|
let session, endpoint = null;
|
||||||
throw new Error(`Cannot load credential ${args.credentialsLib}`);
|
if (args.offline) {
|
||||||
|
session = new authlib.OfflineSession(name);
|
||||||
|
} else {
|
||||||
|
const credential_info = await authlib.Credentials.fromFile(args.credentialsLib);
|
||||||
|
if (credential_info == null) {
|
||||||
|
throw new Error(`Cannot load credential ${args.credentialsLib}`);
|
||||||
|
}
|
||||||
|
session = await credential_info.authProfile(name);
|
||||||
|
endpoint = credential_info.endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = await credential_info.authProfile(name);
|
|
||||||
const bot = mineflayer.createBot({
|
const bot = mineflayer.createBot({
|
||||||
host, port, version: args.protocal,
|
host, port, version: args.protocal,
|
||||||
...session.mineflayer(credential_info.endpoint)
|
...session.mineflayer(endpoint)
|
||||||
});
|
});
|
||||||
bot.on('error', console.error);
|
bot.on('error', console.error);
|
||||||
bot.on('kicked', console.log);
|
bot.on('kicked', console.log);
|
||||||
|
bot.on('end', () => {
|
||||||
|
console.log('Disconnected. Exiting...');
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
await waitEvent(bot, 'inject_allowed');
|
await waitEvent(bot, 'inject_allowed');
|
||||||
bot.loadPlugin((await import('mineflayer-event-promise')).default);
|
bot.loadPlugin((await import('mineflayer-event-promise')).default);
|
||||||
bot.loadPlugin((await import('mineflayer-control')).default);
|
bot.loadPlugin((await import('mineflayer-control')).default);
|
||||||
await bot.waitEvent('spawn');
|
await bot.waitEvent('spawn');
|
||||||
|
|
||||||
let context = vm.createContext();
|
async function loadReplContextModules(context) {
|
||||||
context.bot = bot;
|
context.lib = {
|
||||||
context.Vec3 = (await import('vec3')).Vec3;
|
utils: await import('compass-utils'),
|
||||||
context.mineflayer = mineflayer;
|
control: await import('mineflayer-control'),
|
||||||
context.owner = () => {
|
};
|
||||||
if (!args.owner) { return null; }
|
context.bot = bot;
|
||||||
return bot.players[args.owner];
|
context.Vec3 = (await import('vec3')).Vec3;
|
||||||
};
|
context.mineflayer = mineflayer;
|
||||||
|
context.owner = () => {
|
||||||
|
if (!args.owner) { return null; }
|
||||||
|
return bot.players[args.owner];
|
||||||
|
};
|
||||||
|
|
||||||
|
context.sc = {};
|
||||||
|
context.sc.pos = () => bot.entity.position;
|
||||||
|
context.sc.debug_enable = (module) => debug.enable(module);
|
||||||
|
context.sc.debug_disable = (module) => debug.disable(module);
|
||||||
|
}
|
||||||
|
|
||||||
if (!args.noRepl) {
|
if (!args.noRepl) {
|
||||||
let r = repl.start({
|
let r = repl.start({
|
||||||
prompt: 'local > ',
|
prompt: 'local > ',
|
||||||
@ -62,7 +87,7 @@ async function main() {
|
|||||||
terminal: true,
|
terminal: true,
|
||||||
ignoreUndefined: true,
|
ignoreUndefined: true,
|
||||||
});
|
});
|
||||||
r.context = context;
|
loadReplContextModules(r.context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
import { Task } from 'compass-utils';
|
import { Queue, Task } from 'compass-utils';
|
||||||
import { Vec3 } from 'vec3';
|
import { Vec3 } from 'vec3';
|
||||||
const logger = debug('mineflayer-control');
|
const logger = debug('mineflayer-control');
|
||||||
|
|
||||||
@ -79,6 +79,10 @@ export class MoveInterferedError extends Error {
|
|||||||
constructor() { super('Move task has been interfered by an external force.'); }
|
constructor() { super('Move task has been interfered by an external force.'); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class MovePathBlockedError extends Error {
|
||||||
|
constructor() { super('Move path is possiblely blocked.'); }
|
||||||
|
};
|
||||||
|
|
||||||
async function moveAxisTask(bot, task, axis_raw, target_raw, level) {
|
async function moveAxisTask(bot, task, axis_raw, target_raw, level) {
|
||||||
const axis = AXIS[axis_raw];
|
const axis = AXIS[axis_raw];
|
||||||
const stable_axis = "xz"[axis % 2];
|
const stable_axis = "xz"[axis % 2];
|
||||||
@ -98,7 +102,8 @@ async function moveAxisTask(bot, task, axis_raw, target_raw, level) {
|
|||||||
logger(`moveAxisTask() distance: ${remaining_dis}.`);
|
logger(`moveAxisTask() distance: ${remaining_dis}.`);
|
||||||
logger(`moveAxisTask() stable_axis: ${stable_axis}.`);
|
logger(`moveAxisTask() stable_axis: ${stable_axis}.`);
|
||||||
logger(`moveAxisTask() Condition: ${delta[stable_axis]} ${delta.y}.`);
|
logger(`moveAxisTask() Condition: ${delta[stable_axis]} ${delta.y}.`);
|
||||||
if (Math.abs(delta.y) > Number.EPSILON || Math.abs(delta[stable_axis]) > Number.EPSILON) {
|
if (Math.abs(delta.y) > 0.5 + Number.EPSILON
|
||||||
|
|| Math.abs(delta[stable_axis]) > Number.EPSILON) {
|
||||||
throw new Error('Invalid Argument: target');
|
throw new Error('Invalid Argument: target');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +125,9 @@ async function moveAxisTask(bot, task, axis_raw, target_raw, level) {
|
|||||||
controls.apply(bot);
|
controls.apply(bot);
|
||||||
logger('moveAxisTask() started.');
|
logger('moveAxisTask() started.');
|
||||||
|
|
||||||
let time_used = 0;
|
let time_used = 0, pos_queue = new Queue();
|
||||||
|
const TRACK_TICKS = 5;
|
||||||
|
pos_queue.push(pos.clone());
|
||||||
do {
|
do {
|
||||||
await bot.waitForTicks(1);
|
await bot.waitForTicks(1);
|
||||||
task._interuptableHere();
|
task._interuptableHere();
|
||||||
@ -134,13 +141,33 @@ async function moveAxisTask(bot, task, axis_raw, target_raw, level) {
|
|||||||
logger(`moveAxisTask() pos.${stable_axis}: ${pos[stable_axis]}.`);
|
logger(`moveAxisTask() pos.${stable_axis}: ${pos[stable_axis]}.`);
|
||||||
throw new MoveInterferedError();
|
throw new MoveInterferedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Math.abs(pos.y - target.y) > 0.5 + Number.EPSILON) {
|
||||||
|
logger('moveAxisTask() y changed to much.');
|
||||||
|
logger(`moveAxisTask() target.y=${target.y} vs. pos.y=${pos.y}`);
|
||||||
|
throw new MoveInterferedError();
|
||||||
|
}
|
||||||
|
|
||||||
pos[stable_axis] = stable_axis_value;
|
pos[stable_axis] = stable_axis_value;
|
||||||
|
pos_queue.push(pos.clone());
|
||||||
|
if (pos_queue.size() > TRACK_TICKS) { pos_queue.popFront(); }
|
||||||
|
|
||||||
|
if (pos_queue.size() == 5) {
|
||||||
|
let pos5t = pos_queue.front();
|
||||||
|
if (pos.distanceSquared(pos5t) < Number.EPSILON) {
|
||||||
|
logger('moveAxisTask() position changed too little.');
|
||||||
|
logger(`moveAxisTask() position 5 ticks ago: ${pos5t}.`);
|
||||||
|
logger(`moveAxisTask() position now: ${pos}.`);
|
||||||
|
throw new MovePathBlockedError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delta.update(target.minus(pos));
|
delta.update(target.minus(pos));
|
||||||
remaining_dis = delta.dot(AXIS_UNIT[axis]);
|
remaining_dis = delta.dot(AXIS_UNIT[axis]);
|
||||||
if (Math.abs(remaining_dis) <= 0.5) {
|
if (Math.abs(remaining_dis) <= 0.5) {
|
||||||
logger('moveAxisTask() very close to target now.');
|
logger('moveAxisTask() very close to target now.');
|
||||||
pos.update(target);
|
pos.x = target.x;
|
||||||
|
pos.z = target.z;
|
||||||
bot.entity.velocity.x = 0;
|
bot.entity.velocity.x = 0;
|
||||||
bot.entity.velocity.z = 0;
|
bot.entity.velocity.z = 0;
|
||||||
break;
|
break;
|
||||||
@ -162,12 +189,14 @@ export default function inject(bot) {
|
|||||||
|
|
||||||
bot.control.moveAxis = (axis, target, level = MOVE_LEVEL.SPRINT) => {
|
bot.control.moveAxis = (axis, target, level = MOVE_LEVEL.SPRINT) => {
|
||||||
let task = new Task();
|
let task = new Task();
|
||||||
queueMicrotask(() => {
|
queueMicrotask(async () => {
|
||||||
task._start();
|
try {
|
||||||
moveAxisTask(bot, task, axis, target, level).catch(err => {
|
task._start();
|
||||||
|
await moveAxisTask(bot, task, axis, target, level);
|
||||||
|
} catch(err) {
|
||||||
bot.clearControlStates();
|
bot.clearControlStates();
|
||||||
task._fail(err);
|
task._fail(err);
|
||||||
});
|
};
|
||||||
});
|
});
|
||||||
return task;
|
return task;
|
||||||
};
|
};
|
||||||
|
@ -2,12 +2,15 @@ export class TaskInteruptedError extends Error {
|
|||||||
constructor() { super('Task has been interupted.'); }
|
constructor() { super('Task has been interupted.'); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let task_id = 0;
|
||||||
|
|
||||||
export class Task {
|
export class Task {
|
||||||
#promise;
|
#promise;
|
||||||
#resolve;
|
#resolve;
|
||||||
#reject;
|
#reject;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.id = ++task_id;
|
||||||
this.status = Task.STATUS.pending;
|
this.status = Task.STATUS.pending;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
this.result = null;
|
this.result = null;
|
||||||
@ -80,11 +83,16 @@ export class Task {
|
|||||||
|
|
||||||
valueOf() {
|
valueOf() {
|
||||||
return {
|
return {
|
||||||
|
id: this.id,
|
||||||
status: Task.STATUS_NAME[this.status],
|
status: Task.STATUS_NAME[this.status],
|
||||||
result: this.result,
|
result: this.result,
|
||||||
error: this.error,
|
error: this.error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return `[Task ${this.id}: ${Task.STATUS_NAME[this.status]}]`;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Task.STATUS_NAME = {
|
Task.STATUS_NAME = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user