@nxg-org/mineflayer-physics-util 1.8.18 → 1.9.0

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.
@@ -1,354 +0,0 @@
1
- import { describe, it, beforeEach } from "mocha";
2
- import expect from "expect";
3
- import { Vec3 } from "vec3";
4
- import md from "minecraft-data";
5
- import block, { Block as PBlock } from "prismarine-block";
6
- import { applyMdToNewEntity } from "../src/util/physicsUtils";
7
- import { EPhysicsCtx, PhysicsWorldSettings } from "../src/physics/settings";
8
- import { ControlStateHandler } from "../src/physics/player";
9
- import { BotcraftPhysics, EntityPhysics, IPhysics } from "../src/physics/engines";
10
- import { initSetup } from "../src/index";
11
- import { PlayerState } from "../src/physics/states";
12
- import { Bot, ControlState } from "mineflayer";
13
- import { AABB } from "@nxg-org/mineflayer-util-plugin";
14
-
15
- const version = "1.12.2";
16
- const mcData = md(version);
17
- const Engine = BotcraftPhysics;
18
- const Block = block(version) as typeof PBlock;
19
-
20
- const groundLevel = 67;
21
- const floatingOffset = 100 - groundLevel;
22
- const control: { [key: string]: boolean } = {};
23
-
24
- class FakeWorld {
25
- overrideBlocks: { [key: string]: PBlock } = {};
26
-
27
- setOverrideBlock(pos: Vec3, type: number) {
28
- pos = pos.floored();
29
- const block = new Block(type, 0, 0);
30
- block.position = pos;
31
- this.overrideBlocks[`${pos.x},${pos.y},${pos.z}`] = block;
32
- }
33
-
34
- clearOverrides() {
35
- this.overrideBlocks = {};
36
- }
37
-
38
- getBlock(pos: Vec3) {
39
- pos = pos.floored();
40
- const key = `${pos.x},${pos.y},${pos.z}`;
41
- if (this.overrideBlocks[key]) {
42
- return this.overrideBlocks[key];
43
- }
44
-
45
- const type = pos.y < groundLevel ? mcData.blocksByName.stone.id : mcData.blocksByName.air.id;
46
- const b = new Block(type, 0, 0);
47
- b.position = pos;
48
- return b;
49
- }
50
- }
51
-
52
- function createFakePlayer(pos: Vec3, tmpGroundLevel: number = groundLevel) {
53
- const onGround = pos.y === tmpGroundLevel
54
- return {
55
- entity: {
56
- position: pos,
57
- velocity: new Vec3(0, onGround ? -0.08 : 0, 0),
58
- onGround: onGround,
59
- isInWater: false,
60
- isInLava: false,
61
- isInWeb: false,
62
- isCollidedHorizontally: false,
63
- isCollidedVertically: false,
64
- yaw: 0,
65
- effects: [],
66
- attributes: {}
67
- },
68
- jumpTicks: 0,
69
- jumpQueued: false,
70
- version: version,
71
- inventory: { slots: [] },
72
- equipment: [],
73
- food: 20,
74
- game: { gameMode: "survival" },
75
- registry: mcData,
76
- setControlState: (name: ControlState, value: boolean) => {
77
- control[name] = value;
78
- },
79
- getControlState: (name: ControlState) => {
80
- return control?.[name] ?? false;
81
- },
82
- getEquipmentDestSlot: () => {},
83
- };
84
- }
85
-
86
- initSetup(mcData);
87
-
88
- const playerType = mcData.entitiesByName["player"];
89
-
90
- describe("Physics Simulation Tests", () => {
91
- let fakePlayer: ReturnType<typeof createFakePlayer> | any;
92
- let physics: IPhysics;
93
- let playerCtx: EPhysicsCtx;
94
- let playerState: PlayerState;
95
- const fakeWorld = new FakeWorld();
96
-
97
- const setupEntity = (yOffset: number) => {
98
- fakePlayer = createFakePlayer(new Vec3(0, groundLevel + yOffset, 0), groundLevel);
99
- fakePlayer.entity = applyMdToNewEntity(EPhysicsCtx, playerType, fakePlayer.entity);
100
- physics = new Engine(mcData);
101
- playerCtx = EPhysicsCtx.FROM_BOT(physics, fakePlayer);
102
- playerState = playerCtx.state as PlayerState;
103
- playerState.control = ControlStateHandler.DEFAULT();
104
- };
105
-
106
- afterEach(() => {
107
- fakeWorld.clearOverrides();
108
- });
109
-
110
- it("should maintain position when gravity is zero", () => {
111
- setupEntity(floatingOffset);
112
- fakePlayer.entity.velocity = new Vec3(0, 0, 0);
113
- playerState.vel.y = 0;
114
- playerCtx.gravity = 0;
115
-
116
- for (let i = 0; i < 2; i++) {
117
- // playerState.update(fakePlayer);
118
- physics.simulate(playerCtx, fakeWorld);
119
- playerState.apply(fakePlayer);
120
- }
121
-
122
- expect(fakePlayer.entity.position).toEqual(new Vec3(0, groundLevel + floatingOffset, 0));
123
- });
124
-
125
- it("should move forward correctly given proper gravity", () => {
126
- setupEntity(0);
127
- playerState.control.forward = true;
128
- playerState.control.sprint = true;
129
-
130
- for (let i = 0; i < 10; i++) {
131
- physics.simulate(playerCtx, fakeWorld);
132
- playerState.apply(fakePlayer);
133
- // console.log(fakePlayer.entity.position, playerState.pos, playerState.vel, playerState.age)
134
- }
135
-
136
- if (playerState.control.forward) {
137
- expect(fakePlayer.entity.position).toEqual(new Vec3(0, groundLevel, -2.4694812397932626));
138
- } else {
139
- expect(fakePlayer.entity.position).toEqual(new Vec3(0, groundLevel, 0));
140
- }
141
- });
142
-
143
- it("sprint-jumping", () => {
144
- setupEntity(0);
145
- playerState.control.forward = true;
146
- playerState.control.sprint = true;
147
-
148
- for (let i = 0; i < 4; i++) {
149
- physics.simulate(playerCtx, fakeWorld);
150
- playerState.apply(fakePlayer);
151
- // console.log(playerState.sprinting, playerState.onGround, playerState.pos)
152
- }
153
-
154
- playerState.control.jump = true;
155
-
156
- for (let i = 0; i < 12; i++) {
157
- physics.simulate(playerCtx, fakeWorld);
158
- playerState.apply(fakePlayer);
159
- // console.log(playerState.sprinting, playerState.onGround, playerState.pos)
160
- }
161
-
162
- expect(fakePlayer.entity.position.y).toEqual(groundLevel);
163
- expect(fakePlayer.entity.position.z).toEqual(-4.085029471928113);
164
- });
165
-
166
- it("walk_fallspeed", () => {
167
- setupEntity(floatingOffset);
168
- playerState.control.forward = true;
169
-
170
- while (!fakePlayer.entity.onGround && playerState.age < 100) {
171
- physics.simulate(playerCtx, fakeWorld);
172
- // console.log(fakePlayer.entity.position, playerState.pos, playerState.vel, playerState.age)
173
- playerState.apply(fakePlayer);
174
- }
175
-
176
- expect(fakePlayer.entity.position.z).toEqual(-5.082680598494437);
177
- expect(fakePlayer.entity.position.y).toEqual(groundLevel);
178
- });
179
-
180
- it ("sprint_fallspeed", () => {
181
- setupEntity(floatingOffset);
182
- playerState.control.forward = true;
183
- playerState.control.sprint = true;
184
-
185
- // console.log(playerState.vel)
186
- while (!fakePlayer.entity.onGround && playerState.age < 100) {
187
- physics.simulate(playerCtx, fakeWorld);
188
- playerState.apply(fakePlayer);
189
- }
190
-
191
- // console.log(fakePlayer.entity.position, landingPos, playerState.pos, playerState.control)
192
-
193
- expect(fakePlayer.entity.position.z).toEqual(-6.607484778042766);
194
- expect(fakePlayer.entity.position.y).toEqual(groundLevel);
195
- })
196
-
197
- it("should restore position after gravity toggle", () => {
198
- setupEntity(floatingOffset);
199
- const orgGravity = playerCtx.gravity;
200
- fakePlayer.entity.velocity = new Vec3(0, 0, 0);
201
- playerState.vel.y = 0;
202
- playerCtx.gravity = 0;
203
-
204
- for (let i = 0; i < 5; i++) {
205
- physics.simulate(playerCtx, fakeWorld);
206
- playerState.apply(fakePlayer);
207
- }
208
- expect(fakePlayer.entity.position).toEqual(new Vec3(0, groundLevel + floatingOffset, 0));
209
- playerCtx.gravity = orgGravity;
210
-
211
- while (!fakePlayer.entity.onGround && playerState.age < 100) {
212
- physics.simulate(playerCtx, fakeWorld);
213
- playerState.apply(fakePlayer);
214
- }
215
-
216
- expect(fakePlayer.entity.position.y).toEqual(groundLevel); // Verify movement in Z direction
217
- });
218
-
219
- it("should jump and fall correctly", () => {
220
- setupEntity(0);
221
- playerState.control.jump = true;
222
-
223
- for (let i = 0; i < 3; i++) {
224
- physics.simulate(playerCtx, fakeWorld);
225
- playerState.apply(fakePlayer);
226
- }
227
-
228
- expect(fakePlayer.entity.position.y).toEqual(groundLevel + 1.001335979112147);
229
-
230
- for (let i = 0; i < 9; i++) {
231
- physics.simulate(playerCtx, fakeWorld);
232
- playerState.apply(fakePlayer);
233
- }
234
-
235
- expect(fakePlayer.entity.position.y).toEqual(groundLevel);
236
- });
237
-
238
- it("hCol--z", () => {
239
- setupEntity(0);
240
- const blockPos = new Vec3(0, groundLevel + 1, -2);
241
- fakeWorld.setOverrideBlock(blockPos, mcData.blocksByName.dirt.id);
242
- playerState.look(0, 0);
243
- playerState.control.forward = true;
244
-
245
- for (let i = 0; i < 10; i++) {
246
- physics.simulate(playerCtx, fakeWorld);
247
- playerState.apply(fakePlayer);
248
- console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
249
- }
250
-
251
- expect(playerState.pos.z).toEqual(-0.7);
252
- expect(playerState.isCollidedHorizontally).toEqual(true);
253
- });
254
-
255
- it("hCol-z", () => {
256
- setupEntity(0);
257
- const blockPos = new Vec3(0, groundLevel + 1, 1);
258
- fakeWorld.setOverrideBlock(blockPos, mcData.blocksByName.dirt.id);
259
- playerState.look(-359.9999 * (Math.PI / 360), 0);
260
- playerState.control.forward = true;
261
-
262
- for (let i = 0; i < 10; i++) {
263
- physics.simulate(playerCtx, fakeWorld);
264
- playerState.apply(fakePlayer);
265
- console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
266
- }
267
-
268
- expect(playerState.pos.z).toEqual(0.7);
269
- expect(playerState.isCollidedHorizontally).toEqual(true);
270
- });
271
-
272
- it("hCol--x", () => {
273
- setupEntity(0);
274
- const blockPos = new Vec3(-2, groundLevel + 1, 0);
275
- fakeWorld.setOverrideBlock(blockPos, mcData.blocksByName.dirt.id);
276
- playerState.look(180 * (Math.PI / 360), 0)
277
- playerState.control.forward = true;
278
-
279
- for (let i = 0; i < 10; i++) {
280
- physics.simulate(playerCtx, fakeWorld);
281
- playerState.apply(fakePlayer);
282
- console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
283
- }
284
-
285
- expect(playerState.pos.x).toEqual(-0.7);
286
- expect(playerState.isCollidedHorizontally).toEqual(true);
287
- });
288
-
289
- it("hCol-x", () => {
290
- setupEntity(0);
291
- const blockPos = new Vec3(1, groundLevel + 1, 0);
292
- fakeWorld.setOverrideBlock(blockPos, mcData.blocksByName.dirt.id);
293
- playerState.look(-180 * (Math.PI / 360), 0);
294
- playerState.control.forward = true;
295
-
296
- for (let i = 0; i < 10; i++) {
297
- physics.simulate(playerCtx, fakeWorld);
298
- playerState.apply(fakePlayer);
299
- console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
300
- }
301
-
302
- expect(playerState.pos.x).toEqual(0.7);
303
- expect(playerState.isCollidedHorizontally).toEqual(true);
304
- });
305
-
306
- it("jumpIntoBlock", () => {
307
- setupEntity(0);
308
-
309
- const bl1 = new Vec3(0, groundLevel + 1, 1);
310
- fakeWorld.setOverrideBlock(bl1, mcData.blocksByName.dirt.id);
311
-
312
- fakePlayer.entity.position = new Vec3(0.5, groundLevel, 0.7); // right up against a block
313
- playerState.pos = fakePlayer.entity.position.clone();
314
- playerState.look(-359.9999 * (Math.PI / 360), 0);
315
-
316
- playerState.control.jump = true;
317
- playerState.control.forward = true;
318
- playerState.control.sprint = true;
319
-
320
- for (let i = 0; i < 12; i++) {
321
- physics.simulate(playerCtx, fakeWorld);
322
- playerState.apply(fakePlayer);
323
- // console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
324
- }
325
-
326
- expect(playerState.pos.z).toEqual(0.7);
327
- expect(playerState.isCollidedHorizontally).toEqual(true);
328
- });
329
-
330
- it("walkUpStairs", () => {
331
- setupEntity(0);
332
-
333
- const bl1 = new Vec3(0, groundLevel, -1);
334
- fakeWorld.setOverrideBlock(bl1, mcData.blocksByName.stone_stairs.id);
335
-
336
- const shapes = fakeWorld.getBlock(bl1).shapes;
337
- const bbs = shapes.map((shape) => AABB.fromShape(shape, bl1));
338
-
339
- fakePlayer.entity.position = new Vec3(-0.3, groundLevel, -0.5); // right up against a block
340
- playerState.pos = fakePlayer.entity.position.clone();
341
- playerState.look(-180 * (Math.PI / 360), 0);
342
-
343
- playerState.control.forward = true;
344
- playerState.control.sprint = true;
345
-
346
- for (let i = 0; i < 4; i++) {
347
- // console.log(fakePlayer.entity.position, playerState.pos, playerState.isCollidedHorizontally);
348
- physics.simulate(playerCtx, fakeWorld);
349
- playerState.apply(fakePlayer);
350
- }
351
-
352
- expect(playerState.pos.y).toEqual(groundLevel + 1);
353
- });
354
- });
@@ -1,73 +0,0 @@
1
- import { createBot } from "mineflayer";
2
- import { Vec3 } from "vec3";
3
- import loader, { EntityPhysics, EPhysicsCtx } from "../src/index";
4
- import { SimulationTypes } from "../src/wrapper";
5
- import { Entity } from "prismarine-entity";
6
-
7
- const bot = createBot({
8
- username: "shot-testing",
9
- host: process.argv[2] ?? "localhost",
10
- port: Number(process.argv[3]) ?? 25565,
11
- version: process.argv[4],
12
- });
13
-
14
- bot.loadPlugin(loader);
15
-
16
- const checkedEntities: Record<number, Vec3[]> = {};
17
- const emptyVec = new Vec3(0, 0, 0);
18
-
19
- // this code shows the trajectory of a projectile and whether it may hit people.
20
-
21
- const lastPrintedEntities: Record<number, number> = {};
22
- async function showSim(entity: Entity) {
23
- if (lastPrintedEntities[entity.id] - performance.now() < 3000) return;
24
- lastPrintedEntities[entity.id] = performance.now();
25
- checkedEntities[entity.id] = [];
26
-
27
- const physics = new EntityPhysics(bot.registry);
28
- const ectx = EPhysicsCtx.FROM_ENTITY(physics, entity);
29
-
30
- for (let i = 0; i < 300; i++) {
31
- let state = ectx.state;
32
- state = physics.simulate(ectx, bot.world);
33
-
34
- if (state.onGround) {
35
- console.log("Hit ground at", state.pos);
36
- checkedEntities[entity.id].push(state.pos.clone());
37
- break;
38
- }
39
-
40
- // bot.chat(`/particle flame ${x} ${y} ${z} 0 0 0 0 1 force`);
41
- checkedEntities[entity.id].push(state.pos.clone());
42
- }
43
-
44
- for (let i = 0; i < 5; i++) {
45
- let j = 0;
46
- for (const pos of checkedEntities[entity.id]) {
47
- j++;
48
- if (j === checkedEntities[entity.id].length) bot.chat(`/particle heart ${pos.x} ${pos.y} ${pos.z} 0 0 0 0 1 force`);
49
- bot.chat(`/particle flame ${pos.x} ${pos.y} ${pos.z} 0 0 0 0 1 force`);
50
- }
51
-
52
- await bot.waitForTicks(20);
53
- }
54
-
55
- delete checkedEntities[entity.id];
56
- delete lastPrintedEntities[entity.id];
57
- }
58
-
59
- bot.on("entityMoved", async (ent) => {
60
- const physics = new EntityPhysics(bot.registry);
61
-
62
- if (ent.velocity.equals(emptyVec)) return;
63
-
64
-
65
-
66
- if (ent.type === "projectile") {
67
- console.log(ent.velocity, ent.name);
68
- showSim(ent as Entity);
69
- }
70
-
71
-
72
- // console.log(ent)
73
- });
@@ -1,68 +0,0 @@
1
- import { Effect } from "mineflayer";
2
- import { Entity } from "prismarine-entity";
3
- import { Vec3 } from "vec3";
4
- import md from "minecraft-data";
5
- import block from "prismarine-block";
6
- import entity from "prismarine-entity"
7
-
8
- export default function load(version: string) {
9
-
10
- const mcData = md(version);
11
- const Block = (block as any)(version);
12
- const Entity = (entity as any)(version)
13
-
14
-
15
- const fakeWorld = {
16
- getBlock: (pos: { x: number; y: number; z: number }) => {
17
- const type = pos.y < 60 ? mcData.blocksByName.stone.id : mcData.blocksByName.air.id;
18
- const b = new Block(type, 0, 0);
19
- b.position = pos;
20
- return b;
21
- },
22
- };
23
-
24
- const createFakeEntity = (name: string, pos: Vec3) => {
25
- if (!mcData.entitiesByName[name!]) throw "invalid name"
26
- const tmp = mcData.entitiesByName[name!]
27
- return {
28
- name: name,
29
- type: tmp.type,
30
- height: tmp.height,
31
- width: tmp.width,
32
- position: pos,
33
- velocity: new Vec3(0, 0, 0),
34
- onGround: false,
35
- isInWater: false,
36
- isInLava: false,
37
- isInWeb: false,
38
- isCollidedHorizontally: false,
39
- isCollidedVertically: false,
40
- yaw: 0,
41
- effects: {} as Effect[],
42
- metadata: [],
43
- equipment: new Array(6)
44
- } as unknown as Entity
45
- }
46
-
47
- const modifyEntity = (name: string, entity: Entity) => {
48
- if (!mcData.entitiesByName[name!]) throw "invalid name"
49
- const tmp = mcData.entitiesByName[name!]
50
- entity.height = tmp.height ?? 0
51
- entity.width = tmp.width ?? 0
52
- }
53
-
54
- const createFakePlayer = (pos: Vec3) => {
55
- return {
56
- entity: createFakeEntity("player", pos),
57
- jumpTicks: 0,
58
- jumpQueued: false,
59
- version: "1.17.1",
60
- inventory: {
61
- slots: [],
62
- },
63
- world: fakeWorld
64
- };
65
- }
66
-
67
- return { mcData, Block, Entity, fakeWorld, createFakePlayer, createFakeEntity, modifyEntity };
68
- }