@miner-org/mineflayer-physics-reworked 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +28 -0
- package/index.js +501 -0
- package/package.json +18 -0
- package/src/aabb.js +107 -0
- package/src/attribute.js +46 -0
- package/src/engine.js +1352 -0
- package/src/features.json +55 -0
- package/src/util.js +7 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PhysicsEngine } from "./src/engine";
|
|
2
|
+
|
|
3
|
+
interface ControlState {
|
|
4
|
+
forward: boolean;
|
|
5
|
+
back: boolean;
|
|
6
|
+
left: boolean;
|
|
7
|
+
right: boolean;
|
|
8
|
+
jump: boolean;
|
|
9
|
+
sneak: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare module "@miner-org/mineflayer-physics-reworked" {
|
|
13
|
+
export function inject(bot: Bot): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare module "mineflayer" {
|
|
17
|
+
interface Bot {
|
|
18
|
+
ashPhysics: PhysicsEngine;
|
|
19
|
+
ashPhysicsEnabled: boolean;
|
|
20
|
+
ashControlState: ControlState;
|
|
21
|
+
ashGetControlState(): ControlState;
|
|
22
|
+
ashClearControlStates(): void;
|
|
23
|
+
ashSetControlState(
|
|
24
|
+
control: "forward" | "back" | "left" | "right" | "jump" | "sneak",
|
|
25
|
+
value: boolean,
|
|
26
|
+
): void;
|
|
27
|
+
}
|
|
28
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
const { Vec3 } = require("vec3");
|
|
2
|
+
const assert = require("assert");
|
|
3
|
+
const math = require("mineflayer/lib/math");
|
|
4
|
+
const conv = require("mineflayer/lib/conversions");
|
|
5
|
+
const { performance } = require("perf_hooks");
|
|
6
|
+
const { createDoneTask, createTask } = require("mineflayer/lib/promise_utils");
|
|
7
|
+
|
|
8
|
+
const { PhysicsEngine, PlayerState } = require("./src/engine.js");
|
|
9
|
+
|
|
10
|
+
module.exports = inject;
|
|
11
|
+
|
|
12
|
+
const PI = Math.PI;
|
|
13
|
+
const PI_2 = Math.PI * 2;
|
|
14
|
+
const PHYSICS_INTERVAL_MS = 50;
|
|
15
|
+
const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000; // 0.05
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {import('mineflayer').Bot} bot
|
|
19
|
+
*/
|
|
20
|
+
function inject(bot) {
|
|
21
|
+
// Disable mineflayer's built-in physics
|
|
22
|
+
bot.physicsEnabled = false;
|
|
23
|
+
bot._client.on("position", () => {
|
|
24
|
+
bot.physicsEnabled = false;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const world = {
|
|
28
|
+
getBlock: (pos) => bot.blockAt(pos, false),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const physics = new PhysicsEngine(bot.registry, world);
|
|
32
|
+
|
|
33
|
+
const positionUpdateSentEveryTick = bot.supportFeature(
|
|
34
|
+
"positionUpdateSentEveryTick",
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Jump state
|
|
38
|
+
bot.jumpQueued = false;
|
|
39
|
+
bot.jumpTicks = 0;
|
|
40
|
+
|
|
41
|
+
// Control state
|
|
42
|
+
const controlState = {
|
|
43
|
+
forward: false,
|
|
44
|
+
back: false,
|
|
45
|
+
left: false,
|
|
46
|
+
right: false,
|
|
47
|
+
jump: false,
|
|
48
|
+
sprint: false,
|
|
49
|
+
sneak: false,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Look state
|
|
53
|
+
let lastSentYaw = null;
|
|
54
|
+
let lastSentPitch = null;
|
|
55
|
+
|
|
56
|
+
// Physics timing
|
|
57
|
+
let doPhysicsTimer = null;
|
|
58
|
+
|
|
59
|
+
// Physics enabled flags
|
|
60
|
+
let shouldUsePhysics = false;
|
|
61
|
+
bot.ashPhysicsEnabled = true;
|
|
62
|
+
let deadTicks = 21;
|
|
63
|
+
|
|
64
|
+
// Last sent packet data
|
|
65
|
+
const lastSent = {
|
|
66
|
+
x: 0,
|
|
67
|
+
y: 0,
|
|
68
|
+
z: 0,
|
|
69
|
+
yaw: 0,
|
|
70
|
+
pitch: 0,
|
|
71
|
+
onGround: false,
|
|
72
|
+
time: 0,
|
|
73
|
+
flags: { onGround: false, hasHorizontalCollision: false },
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
function doPhysics() {
|
|
77
|
+
const now = performance.now();
|
|
78
|
+
tickPhysics(now);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function tickPhysics(now) {
|
|
82
|
+
// Skip if chunk is unloaded
|
|
83
|
+
if (bot.blockAt(bot.entity.position) == null) return;
|
|
84
|
+
|
|
85
|
+
if (bot.ashPhysicsEnabled && shouldUsePhysics) {
|
|
86
|
+
const state = new PlayerState(bot, controlState);
|
|
87
|
+
|
|
88
|
+
physics.simulatePlayer(state);
|
|
89
|
+
state.apply(bot);
|
|
90
|
+
|
|
91
|
+
bot.emit("physicsTick");
|
|
92
|
+
bot.emit("physicTick"); // Deprecated
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (shouldUsePhysics) {
|
|
96
|
+
updatePosition(now);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Update position and send packets to server
|
|
102
|
+
*/
|
|
103
|
+
function updatePosition(now) {
|
|
104
|
+
if (isEntityRemoved()) return;
|
|
105
|
+
|
|
106
|
+
const dYaw = deltaYaw(bot.entity.yaw, lastSentYaw);
|
|
107
|
+
const dPitch = bot.entity.pitch - (lastSentPitch || 0);
|
|
108
|
+
|
|
109
|
+
const maxDeltaYaw = PHYSICS_TIMESTEP * physics.constants.yawSpeed;
|
|
110
|
+
const maxDeltaPitch = PHYSICS_TIMESTEP * physics.constants.pitchSpeed;
|
|
111
|
+
lastSentYaw += math.clamp(-maxDeltaYaw, dYaw, maxDeltaYaw);
|
|
112
|
+
lastSentPitch += math.clamp(-maxDeltaPitch, dPitch, maxDeltaPitch);
|
|
113
|
+
|
|
114
|
+
const yaw = Math.fround(conv.toNotchianYaw(lastSentYaw));
|
|
115
|
+
const pitch = Math.fround(conv.toNotchianPitch(lastSentPitch));
|
|
116
|
+
const position = bot.entity.position;
|
|
117
|
+
const onGround = bot.entity.onGround;
|
|
118
|
+
|
|
119
|
+
const positionUpdated =
|
|
120
|
+
lastSent.x !== position.x ||
|
|
121
|
+
lastSent.y !== position.y ||
|
|
122
|
+
lastSent.z !== position.z ||
|
|
123
|
+
Math.round((now - lastSent.time) / PHYSICS_INTERVAL_MS) *
|
|
124
|
+
PHYSICS_INTERVAL_MS >=
|
|
125
|
+
1000;
|
|
126
|
+
|
|
127
|
+
const lookUpdated = lastSent.yaw !== yaw || lastSent.pitch !== pitch;
|
|
128
|
+
|
|
129
|
+
if (positionUpdated && lookUpdated) {
|
|
130
|
+
sendPacketPositionAndLook(position, yaw, pitch, onGround);
|
|
131
|
+
lastSent.time = now;
|
|
132
|
+
} else if (positionUpdated) {
|
|
133
|
+
sendPacketPosition(position, onGround);
|
|
134
|
+
lastSent.time = now;
|
|
135
|
+
} else if (lookUpdated) {
|
|
136
|
+
sendPacketLook(yaw, pitch, onGround);
|
|
137
|
+
} else if (positionUpdateSentEveryTick || onGround !== lastSent.onGround) {
|
|
138
|
+
bot._client.write("flying", {
|
|
139
|
+
onGround: bot.entity.onGround,
|
|
140
|
+
flags: {
|
|
141
|
+
onGround: bot.entity.onGround,
|
|
142
|
+
hasHorizontalCollision: undefined,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
lastSent.onGround = bot.entity.onGround;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function sendPacketPosition(position, onGround) {
|
|
151
|
+
const oldPos = new Vec3(lastSent.x, lastSent.y, lastSent.z);
|
|
152
|
+
lastSent.x = position.x;
|
|
153
|
+
lastSent.y = position.y;
|
|
154
|
+
lastSent.z = position.z;
|
|
155
|
+
lastSent.onGround = onGround;
|
|
156
|
+
lastSent.flags = { onGround, hasHorizontalCollision: undefined };
|
|
157
|
+
bot._client.write("position", lastSent);
|
|
158
|
+
bot.emit("move", oldPos);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function sendPacketLook(yaw, pitch, onGround) {
|
|
162
|
+
const oldPos = new Vec3(lastSent.x, lastSent.y, lastSent.z);
|
|
163
|
+
lastSent.yaw = yaw;
|
|
164
|
+
lastSent.pitch = pitch;
|
|
165
|
+
lastSent.onGround = onGround;
|
|
166
|
+
lastSent.flags = { onGround, hasHorizontalCollision: undefined };
|
|
167
|
+
bot._client.write("look", lastSent);
|
|
168
|
+
bot.emit("move", oldPos);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function sendPacketPositionAndLook(position, yaw, pitch, onGround) {
|
|
172
|
+
const oldPos = new Vec3(lastSent.x, lastSent.y, lastSent.z);
|
|
173
|
+
lastSent.x = position.x;
|
|
174
|
+
lastSent.y = position.y;
|
|
175
|
+
lastSent.z = position.z;
|
|
176
|
+
lastSent.yaw = yaw;
|
|
177
|
+
lastSent.pitch = pitch;
|
|
178
|
+
lastSent.onGround = onGround;
|
|
179
|
+
lastSent.flags = { onGround, hasHorizontalCollision: undefined };
|
|
180
|
+
bot._client.write("position_look", lastSent);
|
|
181
|
+
bot.emit("move", oldPos);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function deltaYaw(yaw1, yaw2) {
|
|
185
|
+
let dYaw = (yaw1 - yaw2) % PI_2;
|
|
186
|
+
if (dYaw < -PI) dYaw += PI_2;
|
|
187
|
+
else if (dYaw > PI) dYaw -= PI_2;
|
|
188
|
+
return dYaw;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function isEntityRemoved() {
|
|
192
|
+
if (bot.isAlive === true) deadTicks = 0;
|
|
193
|
+
if (bot.isAlive === false && deadTicks <= 20) deadTicks++;
|
|
194
|
+
if (deadTicks >= 20) return true;
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function getEffectLevel(mcData, effectName, effects) {
|
|
199
|
+
const effectDescriptor = mcData.effectsByName[effectName];
|
|
200
|
+
if (!effectDescriptor) return 0;
|
|
201
|
+
const effectInfo = effects[effectDescriptor.id];
|
|
202
|
+
if (!effectInfo) return 0;
|
|
203
|
+
return effectInfo.amplifier + 1;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function cleanup() {
|
|
207
|
+
clearInterval(doPhysicsTimer);
|
|
208
|
+
doPhysicsTimer = null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Expose physics engine to bot
|
|
212
|
+
bot.ashPhysics = physics;
|
|
213
|
+
|
|
214
|
+
bot.ashSetControlState = (control, state) => {
|
|
215
|
+
assert.ok(control in controlState, `invalid control: ${control}`);
|
|
216
|
+
assert.ok(typeof state === "boolean", `invalid state: ${state}`);
|
|
217
|
+
if (controlState[control] === state) return;
|
|
218
|
+
|
|
219
|
+
controlState[control] = state;
|
|
220
|
+
|
|
221
|
+
if (control === "jump" && state) {
|
|
222
|
+
bot.jumpQueued = true;
|
|
223
|
+
} else if (control === "sprint") {
|
|
224
|
+
bot._client.write("entity_action", {
|
|
225
|
+
entityId: bot.entity.id,
|
|
226
|
+
actionId: state ? 3 : 4,
|
|
227
|
+
jumpBoost: 0,
|
|
228
|
+
});
|
|
229
|
+
} else if (control === "sneak") {
|
|
230
|
+
bot._client.write("entity_action", {
|
|
231
|
+
entityId: bot.entity.id,
|
|
232
|
+
actionId: state ? 0 : 1,
|
|
233
|
+
jumpBoost: 0,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
bot.ashGetControlState = (control) => {
|
|
239
|
+
assert.ok(control in controlState, `invalid control: ${control}`);
|
|
240
|
+
return controlState[control];
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
bot.ashClearControlStates = () => {
|
|
244
|
+
for (const control in controlState) {
|
|
245
|
+
bot.ashSetControlState(control, false);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
bot.ashControlState = {};
|
|
250
|
+
for (const control of Object.keys(controlState)) {
|
|
251
|
+
Object.defineProperty(bot.ashControlState, control, {
|
|
252
|
+
get() {
|
|
253
|
+
return controlState[control];
|
|
254
|
+
},
|
|
255
|
+
set(state) {
|
|
256
|
+
bot.ashSetControlState(control, state);
|
|
257
|
+
return state;
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let lookingTask = createDoneTask();
|
|
263
|
+
|
|
264
|
+
bot.on("move", () => {
|
|
265
|
+
if (
|
|
266
|
+
!lookingTask.done &&
|
|
267
|
+
Math.abs(deltaYaw(bot.entity.yaw, lastSentYaw)) < 0.001
|
|
268
|
+
) {
|
|
269
|
+
lookingTask.finish();
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
bot.look = async (yaw, pitch, force) => {
|
|
274
|
+
if (!lookingTask.done) {
|
|
275
|
+
lookingTask.finish();
|
|
276
|
+
}
|
|
277
|
+
lookingTask = createTask();
|
|
278
|
+
|
|
279
|
+
const sensitivity = conv.fromNotchianPitch(0.15);
|
|
280
|
+
const yawChange =
|
|
281
|
+
Math.round((yaw - bot.entity.yaw) / sensitivity) * sensitivity;
|
|
282
|
+
const pitchChange =
|
|
283
|
+
Math.round((pitch - bot.entity.pitch) / sensitivity) * sensitivity;
|
|
284
|
+
|
|
285
|
+
if (yawChange === 0 && pitchChange === 0) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
bot.entity.yaw += yawChange;
|
|
290
|
+
bot.entity.pitch += pitchChange;
|
|
291
|
+
|
|
292
|
+
if (force) {
|
|
293
|
+
lastSentYaw = yaw;
|
|
294
|
+
lastSentPitch = pitch;
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
await lookingTask.promise;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
bot.lookAt = async (point, force) => {
|
|
302
|
+
const delta = point.minus(
|
|
303
|
+
bot.entity.position.offset(0, bot.entity.eyeHeight, 0),
|
|
304
|
+
);
|
|
305
|
+
const yaw = Math.atan2(-delta.x, -delta.z);
|
|
306
|
+
const groundDistance = Math.sqrt(delta.x * delta.x + delta.z * delta.z);
|
|
307
|
+
const pitch = Math.atan2(delta.y, groundDistance);
|
|
308
|
+
await bot.look(yaw, pitch, force);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
bot.elytraFly = async () => {
|
|
312
|
+
if (bot.entity.elytraFlying) {
|
|
313
|
+
throw new Error("Already elytra flying");
|
|
314
|
+
} else if (bot.entity.onGround) {
|
|
315
|
+
throw new Error("Unable to fly from ground");
|
|
316
|
+
} else if (bot.entity.isInWater) {
|
|
317
|
+
throw new Error("Unable to elytra fly while in water");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const mcData = require("minecraft-data")(bot.version);
|
|
321
|
+
if (getEffectLevel(mcData, "Levitation", bot.entity.effects) > 0) {
|
|
322
|
+
throw new Error("Unable to elytra fly with levitation effect");
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const torsoSlot = bot.getEquipmentDestSlot("torso");
|
|
326
|
+
const item = bot.inventory.slots[torsoSlot];
|
|
327
|
+
if (item == null || item.name !== "elytra") {
|
|
328
|
+
throw new Error("Elytra must be equipped to start flying");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
bot._client.write("entity_action", {
|
|
332
|
+
entityId: bot.entity.id,
|
|
333
|
+
actionId: 8,
|
|
334
|
+
jumpBoost: 0,
|
|
335
|
+
});
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
bot.waitForTicks = async function (ticks) {
|
|
339
|
+
if (ticks <= 0) return;
|
|
340
|
+
|
|
341
|
+
await new Promise((resolve) => {
|
|
342
|
+
const tickListener = () => {
|
|
343
|
+
ticks--;
|
|
344
|
+
if (ticks === 0) {
|
|
345
|
+
bot.removeListener("physicsTick", tickListener);
|
|
346
|
+
resolve();
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
bot.on("physicsTick", tickListener);
|
|
350
|
+
});
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// Deprecated event warning
|
|
354
|
+
bot.on("newListener", (name) => {
|
|
355
|
+
if (name === "physicTick") {
|
|
356
|
+
console.warn(
|
|
357
|
+
"Mineflayer: You are using a deprecated event (physicTick)! Use physicsTick instead.",
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// Track crawling/pose state from server-confirmed entity metadata
|
|
363
|
+
bot._client.on("entity_metadata", (packet) => {
|
|
364
|
+
if (!bot.entity || packet.entityId !== bot.entity.id) return;
|
|
365
|
+
|
|
366
|
+
const entity = bot.entity;
|
|
367
|
+
|
|
368
|
+
if (bot.supportFeature("mcDataHasEntityMetadata")) {
|
|
369
|
+
const metadataKeys =
|
|
370
|
+
bot.registry.entitiesByName[entity.name]?.metadataKeys;
|
|
371
|
+
if (!metadataKeys) return;
|
|
372
|
+
|
|
373
|
+
const metas = Object.fromEntries(
|
|
374
|
+
packet.metadata.map((e) => [metadataKeys[e.key], e.value]),
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
if (metas.pose != null) {
|
|
378
|
+
entity._pose = metas.pose;
|
|
379
|
+
entity.isElytra = metas.pose === 1;
|
|
380
|
+
entity.isSwimmingPose = metas.pose === 3;
|
|
381
|
+
// Crawling is swimming pose but not in water
|
|
382
|
+
entity.isCrawling = metas.pose === 3 && !entity.isInWater;
|
|
383
|
+
|
|
384
|
+
bot.emit("botPoseUpdate", {
|
|
385
|
+
pose: metas.pose,
|
|
386
|
+
crawling: entity.isCrawling,
|
|
387
|
+
swimming: entity.isSwimmingPose && entity.isInWater,
|
|
388
|
+
elytra: entity.isElytra,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// Entity velocity — handles being pushed by players, mobs, minecarts, etc.
|
|
395
|
+
//this shit does not work for mineflayer bots :(
|
|
396
|
+
bot._client.on("entity_velocity", (packet) => {
|
|
397
|
+
if (packet.entityId !== bot.entity.id) return;
|
|
398
|
+
if (!bot.ashPhysicsEnabled) return;
|
|
399
|
+
|
|
400
|
+
bot.entity.velocity.x += packet.velocityX / 8000;
|
|
401
|
+
bot.entity.velocity.y += packet.velocityY / 8000;
|
|
402
|
+
bot.entity.velocity.z += packet.velocityZ / 8000;
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Explosion knockbakc
|
|
406
|
+
bot._client.on("explosion", (explosion) => {
|
|
407
|
+
if (bot.ashPhysicsEnabled && bot.game.gameMode !== "creative") {
|
|
408
|
+
if (explosion.playerKnockback) {
|
|
409
|
+
// 1.21.3+
|
|
410
|
+
bot.entity.velocity.add(
|
|
411
|
+
explosion.playerMotionX,
|
|
412
|
+
explosion.playerMotionY,
|
|
413
|
+
explosion.playerMotionZ,
|
|
414
|
+
);
|
|
415
|
+
} else if ("playerMotionX" in explosion) {
|
|
416
|
+
// older versions
|
|
417
|
+
bot.entity.velocity.x += explosion.playerMotionX;
|
|
418
|
+
bot.entity.velocity.y += explosion.playerMotionY;
|
|
419
|
+
bot.entity.velocity.z += explosion.playerMotionZ;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Handle player rotation packet (1.21.3+)
|
|
425
|
+
bot._client.on("player_rotation", (packet) => {
|
|
426
|
+
bot.entity.yaw = conv.fromNotchianYaw(packet.yaw);
|
|
427
|
+
bot.entity.pitch = conv.fromNotchianPitch(packet.pitch);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// Handle position updates from server
|
|
431
|
+
bot._client.on("position", (packet) => {
|
|
432
|
+
bot.entity.height = 1.8;
|
|
433
|
+
|
|
434
|
+
const vel = bot.entity.velocity;
|
|
435
|
+
const pos = bot.entity.position;
|
|
436
|
+
let newYaw, newPitch;
|
|
437
|
+
|
|
438
|
+
if (bot.registry.version[">="]("1.21.3")) {
|
|
439
|
+
const flags = packet.flags;
|
|
440
|
+
vel.set(flags.x ? vel.x : 0, flags.y ? vel.y : 0, flags.z ? vel.z : 0);
|
|
441
|
+
pos.set(
|
|
442
|
+
flags.x ? pos.x + packet.x : packet.x,
|
|
443
|
+
flags.y ? pos.y + packet.y : packet.y,
|
|
444
|
+
flags.z ? pos.z + packet.z : packet.z,
|
|
445
|
+
);
|
|
446
|
+
newYaw =
|
|
447
|
+
(flags.yaw ? conv.toNotchianYaw(bot.entity.yaw) : 0) + packet.yaw;
|
|
448
|
+
newPitch =
|
|
449
|
+
(flags.pitch ? conv.toNotchianPitch(bot.entity.pitch) : 0) +
|
|
450
|
+
packet.pitch;
|
|
451
|
+
} else {
|
|
452
|
+
vel.set(
|
|
453
|
+
packet.flags & 1 ? vel.x : 0,
|
|
454
|
+
packet.flags & 2 ? vel.y : 0,
|
|
455
|
+
packet.flags & 4 ? vel.z : 0,
|
|
456
|
+
);
|
|
457
|
+
pos.set(
|
|
458
|
+
packet.flags & 1 ? pos.x + packet.x : packet.x,
|
|
459
|
+
packet.flags & 2 ? pos.y + packet.y : packet.y,
|
|
460
|
+
packet.flags & 4 ? pos.z + packet.z : packet.z,
|
|
461
|
+
);
|
|
462
|
+
newYaw =
|
|
463
|
+
(packet.flags & 8 ? conv.toNotchianYaw(bot.entity.yaw) : 0) +
|
|
464
|
+
packet.yaw;
|
|
465
|
+
newPitch =
|
|
466
|
+
(packet.flags & 16 ? conv.toNotchianPitch(bot.entity.pitch) : 0) +
|
|
467
|
+
packet.pitch;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
bot.entity.yaw = conv.fromNotchianYaw(newYaw);
|
|
471
|
+
bot.entity.pitch = conv.fromNotchianPitch(newPitch);
|
|
472
|
+
bot.entity.onGround = false;
|
|
473
|
+
|
|
474
|
+
sendPacketPositionAndLook(pos, newYaw, newPitch, bot.entity.onGround);
|
|
475
|
+
|
|
476
|
+
shouldUsePhysics = true;
|
|
477
|
+
bot.jumpTicks = 0;
|
|
478
|
+
lastSentYaw = bot.entity.yaw;
|
|
479
|
+
lastSentPitch = bot.entity.pitch;
|
|
480
|
+
|
|
481
|
+
bot.emit("forcedMove");
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
bot.on("mount", () => {
|
|
485
|
+
shouldUsePhysics = false;
|
|
486
|
+
});
|
|
487
|
+
bot.on("respawn", () => {
|
|
488
|
+
shouldUsePhysics = false;
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
bot.on("login", () => {
|
|
492
|
+
shouldUsePhysics = false;
|
|
493
|
+
lastSentYaw = bot.entity.yaw;
|
|
494
|
+
lastSentPitch = bot.entity.pitch;
|
|
495
|
+
if (doPhysicsTimer === null) {
|
|
496
|
+
doPhysicsTimer = setInterval(doPhysics, PHYSICS_INTERVAL_MS);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
bot.on("end", cleanup);
|
|
501
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miner-org/mineflayer-physics-reworked",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"npm-publish-patch": "npm version patch && npm publish --access public && git push origin main --tags",
|
|
6
|
+
"npm-publish-minor": "npm version minor && npm publish --access public && git push origin main --tags",
|
|
7
|
+
"npm-publish-major": "npm version major && npm publish --access public && git push origin main --tags"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"mineflayer-physics"
|
|
11
|
+
],
|
|
12
|
+
"author": "Ash",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"description": "Mineflayer physics but with extra stuff like crawling support and scaffolding support",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"mineflayer": "^4.25.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/aabb.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
class AABB {
|
|
2
|
+
constructor (x0, y0, z0, x1, y1, z1) {
|
|
3
|
+
this.minX = x0
|
|
4
|
+
this.minY = y0
|
|
5
|
+
this.minZ = z0
|
|
6
|
+
this.maxX = x1
|
|
7
|
+
this.maxY = y1
|
|
8
|
+
this.maxZ = z1
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
clone () {
|
|
12
|
+
return new AABB(this.minX, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
floor () {
|
|
16
|
+
this.minX = Math.floor(this.minX)
|
|
17
|
+
this.minY = Math.floor(this.minY)
|
|
18
|
+
this.minZ = Math.floor(this.minZ)
|
|
19
|
+
this.maxX = Math.floor(this.maxX)
|
|
20
|
+
this.maxY = Math.floor(this.maxY)
|
|
21
|
+
this.maxZ = Math.floor(this.maxZ)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
extend (dx, dy, dz) {
|
|
25
|
+
if (dx < 0) this.minX += dx
|
|
26
|
+
else this.maxX += dx
|
|
27
|
+
|
|
28
|
+
if (dy < 0) this.minY += dy
|
|
29
|
+
else this.maxY += dy
|
|
30
|
+
|
|
31
|
+
if (dz < 0) this.minZ += dz
|
|
32
|
+
else this.maxZ += dz
|
|
33
|
+
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
contract (x, y, z) {
|
|
38
|
+
this.minX += x
|
|
39
|
+
this.minY += y
|
|
40
|
+
this.minZ += z
|
|
41
|
+
this.maxX -= x
|
|
42
|
+
this.maxY -= y
|
|
43
|
+
this.maxZ -= z
|
|
44
|
+
return this
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
expand (x, y, z) {
|
|
48
|
+
this.minX -= x
|
|
49
|
+
this.minY -= y
|
|
50
|
+
this.minZ -= z
|
|
51
|
+
this.maxX += x
|
|
52
|
+
this.maxY += y
|
|
53
|
+
this.maxZ += z
|
|
54
|
+
return this
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
offset (x, y, z) {
|
|
58
|
+
this.minX += x
|
|
59
|
+
this.minY += y
|
|
60
|
+
this.minZ += z
|
|
61
|
+
this.maxX += x
|
|
62
|
+
this.maxY += y
|
|
63
|
+
this.maxZ += z
|
|
64
|
+
return this
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
computeOffsetX (other, offsetX) {
|
|
68
|
+
if (other.maxY > this.minY && other.minY < this.maxY && other.maxZ > this.minZ && other.minZ < this.maxZ) {
|
|
69
|
+
if (offsetX > 0.0 && other.maxX <= this.minX) {
|
|
70
|
+
offsetX = Math.min(this.minX - other.maxX, offsetX)
|
|
71
|
+
} else if (offsetX < 0.0 && other.minX >= this.maxX) {
|
|
72
|
+
offsetX = Math.max(this.maxX - other.minX, offsetX)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return offsetX
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
computeOffsetY (other, offsetY) {
|
|
79
|
+
if (other.maxX > this.minX && other.minX < this.maxX && other.maxZ > this.minZ && other.minZ < this.maxZ) {
|
|
80
|
+
if (offsetY > 0.0 && other.maxY <= this.minY) {
|
|
81
|
+
offsetY = Math.min(this.minY - other.maxY, offsetY)
|
|
82
|
+
} else if (offsetY < 0.0 && other.minY >= this.maxY) {
|
|
83
|
+
offsetY = Math.max(this.maxY - other.minY, offsetY)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return offsetY
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
computeOffsetZ (other, offsetZ) {
|
|
90
|
+
if (other.maxX > this.minX && other.minX < this.maxX && other.maxY > this.minY && other.minY < this.maxY) {
|
|
91
|
+
if (offsetZ > 0.0 && other.maxZ <= this.minZ) {
|
|
92
|
+
offsetZ = Math.min(this.minZ - other.maxZ, offsetZ)
|
|
93
|
+
} else if (offsetZ < 0.0 && other.minZ >= this.maxZ) {
|
|
94
|
+
offsetZ = Math.max(this.maxZ - other.minZ, offsetZ)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return offsetZ
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
intersects (other) {
|
|
101
|
+
return this.minX < other.maxX && this.maxX > other.minX &&
|
|
102
|
+
this.minY < other.maxY && this.maxY > other.minY &&
|
|
103
|
+
this.minZ < other.maxZ && this.maxZ > other.minZ
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = AABB
|
package/src/attribute.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
exports.getAttributeValue = function (prop) {
|
|
2
|
+
let x = prop.value;
|
|
3
|
+
for (const mod of prop.modifiers) {
|
|
4
|
+
if (mod.operation !== 0) continue;
|
|
5
|
+
x += mod.amount;
|
|
6
|
+
}
|
|
7
|
+
let y = x;
|
|
8
|
+
for (const mod of prop.modifiers) {
|
|
9
|
+
if (mod.operation !== 1) continue;
|
|
10
|
+
y += x * mod.amount;
|
|
11
|
+
}
|
|
12
|
+
for (const mod of prop.modifiers) {
|
|
13
|
+
if (mod.operation !== 2) continue;
|
|
14
|
+
y += y * mod.amount;
|
|
15
|
+
}
|
|
16
|
+
return y;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
exports.createAttributeValue = function (base) {
|
|
20
|
+
const attributes = {
|
|
21
|
+
value: base,
|
|
22
|
+
modifiers: [],
|
|
23
|
+
};
|
|
24
|
+
return attributes;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
exports.addAttributeModifier = function (attributes, modifier) {
|
|
28
|
+
const end = attributes.modifiers.length;
|
|
29
|
+
// add modifer at the end
|
|
30
|
+
attributes.modifiers[end] = modifier;
|
|
31
|
+
return attributes;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
exports.checkAttributeModifier = function (attributes, uuid) {
|
|
35
|
+
for (const modifier of attributes.modifiers) {
|
|
36
|
+
if (modifier.uuid === uuid) return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
exports.deleteAttributeModifier = function (attributes, uuid) {
|
|
42
|
+
attributes.modifiers = attributes.modifiers.filter(
|
|
43
|
+
(modifier) => modifier.uuid !== uuid,
|
|
44
|
+
);
|
|
45
|
+
return attributes;
|
|
46
|
+
};
|