add path blocked detection
This commit is contained in:
parent
0f2837029e
commit
01132299b5
@ -43,7 +43,7 @@ export class Account {
|
||||
password: this.password,
|
||||
})).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);
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ export class Credentials {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -92,7 +92,7 @@ export class Credentials {
|
||||
}
|
||||
};
|
||||
|
||||
export class SessionCache {
|
||||
export class YggdrasilSession {
|
||||
constructor(accessToken, clientToken, selectedProfile, availableProfiles) {
|
||||
this.accessToken = accessToken;
|
||||
this.clientToken = clientToken;
|
||||
@ -120,7 +120,7 @@ export class SessionCache {
|
||||
static async load(profile) {
|
||||
let cache_data = await readJsonFile(`.cache/${profile}.json`);
|
||||
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) {
|
||||
@ -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 { parseLogin, waitEvent } from 'compass-utils';
|
||||
import repl from 'node:repl';
|
||||
import vm from 'node:vm';
|
||||
import debug from 'debug';
|
||||
|
||||
async function main() {
|
||||
const args = yargs((await import('yargs/helpers')).hideBin(process.argv))
|
||||
@ -22,37 +22,62 @@ async function main() {
|
||||
description: 'Credentials\' library file.',
|
||||
type: "string",
|
||||
default: "credentials.json",
|
||||
}).option('offline', {
|
||||
description: 'Login without credentials.',
|
||||
type: 'boolean',
|
||||
}).usage('Uasge: profile@host:port').help().alias('help', 'h').argv;
|
||||
|
||||
let login_info = args._[0];
|
||||
if (login_info == null) { return; }
|
||||
const [name, host, port] = parseLogin(login_info);
|
||||
const credential_info = await authlib.Credentials.fromFile(args.credentialsLib);
|
||||
if (credential_info == null) {
|
||||
throw new Error(`Cannot load credential ${args.credentialsLib}`);
|
||||
|
||||
let session, endpoint = null;
|
||||
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({
|
||||
host, port, version: args.protocal,
|
||||
...session.mineflayer(credential_info.endpoint)
|
||||
...session.mineflayer(endpoint)
|
||||
});
|
||||
bot.on('error', console.error);
|
||||
bot.on('kicked', console.log);
|
||||
bot.on('end', () => {
|
||||
console.log('Disconnected. Exiting...');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
await waitEvent(bot, 'inject_allowed');
|
||||
bot.loadPlugin((await import('mineflayer-event-promise')).default);
|
||||
bot.loadPlugin((await import('mineflayer-control')).default);
|
||||
await bot.waitEvent('spawn');
|
||||
|
||||
let context = vm.createContext();
|
||||
context.bot = bot;
|
||||
context.Vec3 = (await import('vec3')).Vec3;
|
||||
context.mineflayer = mineflayer;
|
||||
context.owner = () => {
|
||||
if (!args.owner) { return null; }
|
||||
return bot.players[args.owner];
|
||||
};
|
||||
async function loadReplContextModules(context) {
|
||||
context.lib = {
|
||||
utils: await import('compass-utils'),
|
||||
control: await import('mineflayer-control'),
|
||||
};
|
||||
context.bot = bot;
|
||||
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) {
|
||||
let r = repl.start({
|
||||
prompt: 'local > ',
|
||||
@ -62,7 +87,7 @@ async function main() {
|
||||
terminal: true,
|
||||
ignoreUndefined: true,
|
||||
});
|
||||
r.context = context;
|
||||
loadReplContextModules(r.context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import debug from 'debug';
|
||||
import { Task } from 'compass-utils';
|
||||
import { Queue, Task } from 'compass-utils';
|
||||
import { Vec3 } from 'vec3';
|
||||
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.'); }
|
||||
};
|
||||
|
||||
export class MovePathBlockedError extends Error {
|
||||
constructor() { super('Move path is possiblely blocked.'); }
|
||||
};
|
||||
|
||||
async function moveAxisTask(bot, task, axis_raw, target_raw, level) {
|
||||
const axis = AXIS[axis_raw];
|
||||
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() stable_axis: ${stable_axis}.`);
|
||||
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');
|
||||
}
|
||||
|
||||
@ -120,7 +125,9 @@ async function moveAxisTask(bot, task, axis_raw, target_raw, level) {
|
||||
controls.apply(bot);
|
||||
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 {
|
||||
await bot.waitForTicks(1);
|
||||
task._interuptableHere();
|
||||
@ -134,13 +141,33 @@ async function moveAxisTask(bot, task, axis_raw, target_raw, level) {
|
||||
logger(`moveAxisTask() pos.${stable_axis}: ${pos[stable_axis]}.`);
|
||||
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_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));
|
||||
remaining_dis = delta.dot(AXIS_UNIT[axis]);
|
||||
if (Math.abs(remaining_dis) <= 0.5) {
|
||||
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.z = 0;
|
||||
break;
|
||||
@ -162,12 +189,14 @@ export default function inject(bot) {
|
||||
|
||||
bot.control.moveAxis = (axis, target, level = MOVE_LEVEL.SPRINT) => {
|
||||
let task = new Task();
|
||||
queueMicrotask(() => {
|
||||
task._start();
|
||||
moveAxisTask(bot, task, axis, target, level).catch(err => {
|
||||
queueMicrotask(async () => {
|
||||
try {
|
||||
task._start();
|
||||
await moveAxisTask(bot, task, axis, target, level);
|
||||
} catch(err) {
|
||||
bot.clearControlStates();
|
||||
task._fail(err);
|
||||
});
|
||||
};
|
||||
});
|
||||
return task;
|
||||
};
|
||||
|
@ -2,12 +2,15 @@ export class TaskInteruptedError extends Error {
|
||||
constructor() { super('Task has been interupted.'); }
|
||||
};
|
||||
|
||||
let task_id = 0;
|
||||
|
||||
export class Task {
|
||||
#promise;
|
||||
#resolve;
|
||||
#reject;
|
||||
|
||||
constructor() {
|
||||
this.id = ++task_id;
|
||||
this.status = Task.STATUS.pending;
|
||||
this.error = null;
|
||||
this.result = null;
|
||||
@ -80,11 +83,16 @@ export class Task {
|
||||
|
||||
valueOf() {
|
||||
return {
|
||||
id: this.id,
|
||||
status: Task.STATUS_NAME[this.status],
|
||||
result: this.result,
|
||||
error: this.error,
|
||||
};
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `[Task ${this.id}: ${Task.STATUS_NAME[this.status]}]`;
|
||||
}
|
||||
};
|
||||
|
||||
Task.STATUS_NAME = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user