@nxg-org/mineflayer-physics-util 1.7.8 → 1.7.10

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.
@@ -112,7 +112,10 @@ export declare class BotcraftPhysics implements IPhysics {
112
112
  movePlayer(ctx: EPhysicsCtx, world: World): void;
113
113
  applyMovement(ctx: EPhysicsCtx, world: World): void;
114
114
  checkInsideBlocks(player: PlayerState, world: World): void;
115
- collideBoundingBox(world: World, bb: AABB, movement: Vec3): Vec3;
115
+ collideBoundingBox(world: World, bb: AABB, movement: Vec3, colliders?: AABB[]): Vec3;
116
+ private collideWithShapes;
117
+ shapeCollide(axis: number, bb: AABB, colliders: AABB[], movement: number): number;
118
+ private voxelShapeCollide;
116
119
  collideOneAxis(movedAABB: AABB, movement: Vec3, axis: number, colliders: AABB[]): void;
117
120
  applyInputs(inputStrength: number, player: PlayerState): void;
118
121
  isInClimbable(player: PlayerState, world: World): boolean;
@@ -212,12 +212,9 @@ class BotcraftPhysics {
212
212
  }
213
213
  }
214
214
  const playerFlag = ctx.entityType.type === "player";
215
- // if world is currently loaded at player position
216
- if (playerFlag) {
217
- // TODO: check if spectator mode
218
- }
219
215
  this.fluidPhysics(ctx, world, true);
220
216
  this.fluidPhysics(ctx, world, false);
217
+ // updateSwimming moved into AiStep.
221
218
  // separation into a new function
222
219
  // originally: https://github.com/adepierre/Botcraft/blob/6c572071b0237c27a85211a246ce10565ef4d80f/botcraft/src/Game/Physics/PhysicsManager.cpp#L325
223
220
  if (playerFlag) {
@@ -697,12 +694,14 @@ class BotcraftPhysics {
697
694
  blockJumpFactor = 0.4;
698
695
  }
699
696
  if (this.verLessThan("1.20.5")) {
700
- player.vel.y = 0.42 * blockJumpFactor + jumpBoost;
697
+ player.vel.y = Math.fround(0.42) * blockJumpFactor + jumpBoost;
701
698
  if (player.sprinting) {
702
- const yawRad = player.yaw; // should already be in yaw.
699
+ const yawRad = Math.PI - player.yaw; // should already be in yaw. MINEFLAYER SPECIFC CHANGE, MATH.PI -
703
700
  // potential inconsistency here. This may not be accurate.
704
- player.vel.x -= Math.fround(Math.sin(yawRad)) * 0.2;
705
- player.vel.z += Math.fround(Math.cos(yawRad)) * 0.2;
701
+ const offsetX = Math.fround(Math.sin(yawRad)) * 0.2;
702
+ const offsetZ = Math.fround(Math.cos(yawRad)) * 0.2;
703
+ player.vel.x -= offsetX;
704
+ player.vel.z += offsetZ;
706
705
  }
707
706
  }
708
707
  else {
@@ -711,7 +710,7 @@ class BotcraftPhysics {
711
710
  if (jumpPower > 1e-5) {
712
711
  player.vel.y = jumpPower;
713
712
  if (player.sprinting) {
714
- const yawRad = player.yaw; // should already be in yaw.
713
+ const yawRad = Math.PI - player.yaw; // should already be in yaw. MINEFLAYER SPECIFC CHANGE, MATH.PI -
715
714
  player.vel.x -= Math.sin(yawRad) * 0.2;
716
715
  player.vel.z += Math.cos(yawRad) * 0.2;
717
716
  }
@@ -893,7 +892,18 @@ class BotcraftPhysics {
893
892
  const inertia = player.onGround ? friction * ctx.airborneInertia : ctx.airborneInertia;
894
893
  // deviation, adding additional logic for changing attribute values.
895
894
  const movementSpeedAttr = this.getMovementSpeedAttribute(ctx);
896
- const inputStrength = player.onGround ? movementSpeedAttr * (0.21600002 / (friction * friction * friction)) : 0.02;
895
+ let inputStrength;
896
+ if (player.onGround) {
897
+ inputStrength = movementSpeedAttr * (0.21600002 / (friction * friction * friction));
898
+ }
899
+ else {
900
+ inputStrength = 0.02;
901
+ // DEVIATION: taken from p-physics, fixes motion!
902
+ if (player.control.sprint) {
903
+ const airSprintFactor = ctx.airborneAccel * 0.3;
904
+ inputStrength += airSprintFactor;
905
+ }
906
+ }
897
907
  this.applyInputs(inputStrength, player);
898
908
  if (player.onClimbable) {
899
909
  // LivingEntity::handleOnClimbable
@@ -941,9 +951,9 @@ class BotcraftPhysics {
941
951
  player.stuckSpeedMultiplier.set(0, 0, 0);
942
952
  player.vel.set(0, 0, 0);
943
953
  }
944
- let maxStepUp = ctx.stepHeight;
954
+ let maxUpStep = ctx.stepHeight;
945
955
  if (!this.verLessThan("1.20.5")) {
946
- maxStepUp = player.attributes[this.stepHeightAttribute].value;
956
+ maxUpStep = player.attributes[this.stepHeightAttribute].value;
947
957
  }
948
958
  // const playerAABB = player.getBB();
949
959
  if (!player.flying && movement.y <= 0.0 && player.control.sneak && player.onGround) {
@@ -955,58 +965,48 @@ class BotcraftPhysics {
955
965
  bb.expand(-1e-7, -1e-7, -1e-7);
956
966
  return bb;
957
967
  };
958
- while (movement.x != 0.0 && this.worldIsFree(world, prepare(movement.x, -maxStepUp, 0), false)) {
968
+ while (movement.x != 0.0 && this.worldIsFree(world, prepare(movement.x, -maxUpStep, 0), false)) {
959
969
  movement.x = movement.x < step && movement.x >= -step ? 0.0 : movement.x > 0.0 ? movement.x - step : movement.x + step;
960
970
  }
961
- while (movement.z != 0.0 && this.worldIsFree(world, prepare(0, -maxStepUp, movement.z), false)) {
971
+ while (movement.z != 0.0 && this.worldIsFree(world, prepare(0, -maxUpStep, movement.z), false)) {
962
972
  movement.z = movement.z < step && movement.z >= -step ? 0.0 : movement.z > 0.0 ? movement.z - step : movement.z + step;
963
973
  }
964
- while ((movement.x != 0.0 && movement.z != 0.0 && prepare(movement.x, -maxStepUp, movement.z), false)) {
974
+ while ((movement.x != 0.0 && movement.z != 0.0 && prepare(movement.x, -maxUpStep, movement.z), false)) {
965
975
  movement.x = movement.x < step && movement.x >= -step ? 0.0 : movement.x > 0.0 ? movement.x - step : movement.x + step;
966
976
  movement.z = movement.z < step && movement.z >= -step ? 0.0 : movement.z > 0.0 ? movement.z - step : movement.z + step;
967
977
  }
968
978
  }
969
979
  const movementBeforeCollisions = movement.clone();
970
- {
971
- // Entity::collide
972
- if (Math.pow(movement.norm(), 2) != 0.0) {
973
- const playerAABB = player.getBB();
974
- movement = this.collideBoundingBox(world, playerAABB, movement);
975
- }
976
- // Step up if block height delta is < max_up_step
977
- // If already on ground (or collided with the ground while moving down) and horizontal collision
978
- // TODO: changed in 1.21, check if this is still accurate
979
- if ((player.onGround || (movement.y != movementBeforeCollisions.y && movementBeforeCollisions.y < 0.0)) &&
980
- (movement.x != movementBeforeCollisions.x || movement.z != movementBeforeCollisions.z)) {
981
- let movementWithStepUp = this.collideBoundingBox(world, player.getBB(), new vec3_1.Vec3(movementBeforeCollisions.x, maxStepUp, movementBeforeCollisions.z));
982
- const horizontalMovement = new vec3_1.Vec3(movementBeforeCollisions.x, 0, movementBeforeCollisions.z);
983
- // TODO: this code might straight up be wrong. It looks wrong. But the way they wrote it is so awkward.
984
- // update: is he trying to offset a change with these 0.5s?
985
- // const stepUpBB = player.getBB();
986
- // stepUpBB.translate(horizontalMovement.x * 0.5, 0, horizontalMovement.z * 0.5);
987
- // stepUpBB.expand(horizontalMovement.x, 0, horizontalMovement.z);
988
- // stepUpBB.translate(0, maxStepUp, 0);
989
- // const movementStepUpOnly = this.collideBoundingBox(world, stepUpBB, horizontalMovement);
990
- const movementStepUpOnly = this.collideBoundingBox(world, player.getBB(), new vec3_1.Vec3(0, maxStepUp, 0));
991
- if (movementStepUpOnly.y < maxStepUp) {
992
- const check = this.collideBoundingBox(world, player.getBB().translateVec(movementStepUpOnly), horizontalMovement).plus(movementStepUpOnly);
993
- if (check.x * check.x + check.z * check.z >
994
- movementWithStepUp.x * movementWithStepUp.x + movementWithStepUp.z * movementWithStepUp.z) {
995
- movementWithStepUp = check;
980
+ { // Entity::collide
981
+ const playerAABB = player.getBB();
982
+ const hDist = (vec) => Math.sqrt(vec.x * vec.x + vec.z * vec.z);
983
+ // const entityCollisions = world.getEntityCollisions(player, playerAABB.expand(movement));
984
+ let newMovement = Math.pow(movement.norm(), 2) === 0 ? movement : this.collideBoundingBox(world, playerAABB, movement);
985
+ const collisionX = Math.abs(movement.x - newMovement.x) > 1e-7;
986
+ const collisionY = Math.abs(movement.y - newMovement.y) > 1e-7;
987
+ const collisionZ = Math.abs(movement.z - newMovement.z) > 1e-7;
988
+ const onGround = player.onGround || (collisionY && movement.y < 0);
989
+ if (maxUpStep > 0 && onGround && (collisionX || collisionZ)) {
990
+ let stepUpMovement = this.collideBoundingBox(world, playerAABB, new vec3_1.Vec3(movement.x, maxUpStep, movement.z));
991
+ const stepOnlyMovement = this.collideBoundingBox(world, playerAABB.expandTowardsCoords(movement.x, 0, movement.z), new vec3_1.Vec3(0, maxUpStep, 0));
992
+ if (stepOnlyMovement.y < maxUpStep) {
993
+ const adjustedStepUp = this.collideBoundingBox(world, playerAABB.translateVec(stepOnlyMovement), new vec3_1.Vec3(movement.x, 0, movement.z)).add(stepOnlyMovement);
994
+ if (hDist(adjustedStepUp) > hDist(stepUpMovement)) {
995
+ stepUpMovement = adjustedStepUp;
996
996
  }
997
997
  }
998
- if (movementWithStepUp.x * movementWithStepUp.x + movementWithStepUp.z * movementWithStepUp.z >
999
- movement.x * movement.x + movement.z * movement.z) {
1000
- movement = movementWithStepUp.plus(this.collideBoundingBox(world, player.getBB().translateVec(movementWithStepUp), new vec3_1.Vec3(0.0, -movementWithStepUp.y + movementBeforeCollisions.y, 0.0)));
998
+ if (hDist(stepUpMovement) > hDist(newMovement)) {
999
+ newMovement = stepUpMovement.add(this.collideBoundingBox(world, playerAABB.translateVec(stepUpMovement), new vec3_1.Vec3(0, -stepUpMovement.y + movement.y, 0)));
1001
1000
  }
1002
1001
  }
1002
+ movement = newMovement;
1003
1003
  }
1004
1004
  if (Math.pow(movement.norm(), 2) > 1e-7) {
1005
1005
  player.pos.add(movement);
1006
1006
  }
1007
- const collisionX = movement.x != movementBeforeCollisions.x;
1008
- const collisionY = movement.y != movementBeforeCollisions.y;
1009
- const collisionZ = movement.z != movementBeforeCollisions.z;
1007
+ const collisionX = Math.abs(movement.x - movementBeforeCollisions.x) > 1e-7;
1008
+ const collisionY = Math.abs(movement.y - movementBeforeCollisions.y) > 1e-7;
1009
+ const collisionZ = Math.abs(movement.z - movementBeforeCollisions.z) > 1e-7;
1010
1010
  player.isCollidedHorizontally = collisionX || collisionZ;
1011
1011
  player.isCollidedVertically = collisionY;
1012
1012
  // TODO: add minor horizontal collision check
@@ -1135,27 +1135,99 @@ class BotcraftPhysics {
1135
1135
  }
1136
1136
  }
1137
1137
  }
1138
- collideBoundingBox(world, bb, movement) {
1139
- // BIG DEVIATION.
1140
- const newBB = bb.clone();
1141
- // newBB.translateVec(movement);
1142
- const colliders = this.getSurroundingBBs(newBB, world);
1138
+ collideBoundingBox(world, bb, movement, colliders = []) {
1139
+ const queryBB = bb.clone().expandTowards(movement);
1140
+ const combinedColliders = [...colliders];
1141
+ const blockCollisions = this.getSurroundingBBs(queryBB, world);
1142
+ for (const block of blockCollisions) {
1143
+ combinedColliders.push(block);
1144
+ }
1145
+ return this.collideWithShapes(movement, bb, combinedColliders);
1146
+ }
1147
+ collideWithShapes(movement, bb, colliders = []) {
1143
1148
  if (colliders.length === 0) {
1144
1149
  return movement;
1145
1150
  }
1146
- let collidedMovement = movement;
1147
- let movedAABB = newBB.clone();
1148
- this.collideOneAxis(movedAABB, collidedMovement, 1, colliders);
1149
- // collision on X before Z
1150
- if (Math.abs(collidedMovement.x) > Math.abs(collidedMovement.z)) {
1151
- this.collideOneAxis(movedAABB, collidedMovement, 0, colliders);
1152
- this.collideOneAxis(movedAABB, collidedMovement, 2, colliders);
1151
+ let dx = movement.x;
1152
+ let dy = movement.y;
1153
+ let dz = movement.z;
1154
+ if (dy !== 0.0) {
1155
+ dy = this.shapeCollide(1, bb, colliders, dy);
1156
+ if (dy !== 0.0) {
1157
+ bb = bb.translate(0, dy, 0);
1158
+ }
1153
1159
  }
1154
- else {
1155
- this.collideOneAxis(movedAABB, collidedMovement, 2, colliders);
1156
- this.collideOneAxis(movedAABB, collidedMovement, 0, colliders);
1160
+ const prioritizeZ = Math.abs(dx) < Math.abs(dz);
1161
+ if (prioritizeZ && dz !== 0.0) {
1162
+ dz = this.shapeCollide(2, bb, colliders, dz);
1163
+ if (dz !== 0.0) {
1164
+ bb = bb.translate(0, 0, dz);
1165
+ }
1166
+ }
1167
+ if (dx !== 0.0) {
1168
+ dx = this.shapeCollide(0, bb, colliders, dx);
1169
+ if (!prioritizeZ && dx !== 0.0) {
1170
+ bb = bb.translate(dx, 0, 0);
1171
+ }
1172
+ }
1173
+ if (!prioritizeZ && dz !== 0.0) {
1174
+ dz = this.shapeCollide(2, bb, colliders, dz);
1175
+ }
1176
+ return new vec3_1.Vec3(dx, dy, dz);
1177
+ }
1178
+ shapeCollide(axis, bb, colliders, movement) {
1179
+ if (Math.abs(movement) < 1e-7) {
1180
+ return 0.0;
1181
+ }
1182
+ movement = this.voxelShapeCollide(axis, bb, movement, colliders);
1183
+ return movement;
1184
+ }
1185
+ voxelShapeCollide(axis, bb, movement, colliders) {
1186
+ if (Math.abs(movement) < 1e-7) {
1187
+ return 0.0;
1188
+ }
1189
+ const [minBB, maxBB] = bb.minAndMaxArrays();
1190
+ const maxAxis = axis === 0 ? bb.maxX : axis === 1 ? bb.maxY : bb.maxZ;
1191
+ const minAxis = axis === 0 ? bb.minX : axis === 1 ? bb.minY : bb.minZ;
1192
+ const offAxis1 = (axis + 1) % 3;
1193
+ const offAxis2 = (axis + 2) % 3;
1194
+ if (movement > 0.0) {
1195
+ for (const collider of colliders) {
1196
+ const colliderMin = axis === 0 ? collider.minX : axis === 1 ? collider.minY : collider.minZ;
1197
+ // verify that the other axis are colliding.
1198
+ const [minPt, maxPt] = collider.minAndMaxArrays();
1199
+ if (maxBB[offAxis1] - 1e-7 <= minPt[offAxis1] || minBB[offAxis1] + 1e-7 >= maxPt[offAxis1] ||
1200
+ maxBB[offAxis2] - 1e-7 <= minPt[offAxis2] || minBB[offAxis2] + 1e-7 >= maxPt[offAxis2]) {
1201
+ continue;
1202
+ }
1203
+ if (colliderMin >= maxAxis) {
1204
+ const distance = colliderMin - maxAxis;
1205
+ if (distance >= -1e-7) {
1206
+ movement = Math.min(movement, distance);
1207
+ }
1208
+ // return movement;
1209
+ }
1210
+ }
1211
+ }
1212
+ else if (movement < 0.0) {
1213
+ for (const collider of colliders) {
1214
+ // verify that the other axis are colliding.
1215
+ const [minPt, maxPt] = collider.minAndMaxArrays();
1216
+ if (maxBB[offAxis1] - 1e-7 <= minPt[offAxis1] || minBB[offAxis1] + 1e-7 >= maxPt[offAxis1] ||
1217
+ maxBB[offAxis2] - 1e-7 <= minPt[offAxis2] || minBB[offAxis2] + 1e-7 >= maxPt[offAxis2]) {
1218
+ continue;
1219
+ }
1220
+ const colliderMax = axis === 0 ? collider.maxX : axis === 1 ? collider.maxY : collider.maxZ;
1221
+ if (colliderMax <= minAxis) {
1222
+ const distance = colliderMax - minAxis;
1223
+ if (distance <= 1e-7) {
1224
+ movement = Math.max(movement, distance);
1225
+ }
1226
+ // return movement;
1227
+ }
1228
+ }
1157
1229
  }
1158
- return collidedMovement;
1230
+ return movement;
1159
1231
  }
1160
1232
  collideOneAxis(movedAABB, movement, axis, colliders) {
1161
1233
  const minAABB = movedAABB.minPoint().toArray();
@@ -1172,17 +1244,6 @@ class BotcraftPhysics {
1172
1244
  const maxCollider = collider.maxPoint().toArray();
1173
1245
  const cond1 = movementLst[thisAxis] > 0.0 && maxAABB[thisAxis] - 1e-7 <= minCollider[thisAxis];
1174
1246
  const cond2 = movementLst[thisAxis] < 0.0 && minAABB[thisAxis] + 1e-7 >= maxCollider[thisAxis];
1175
- // if (collider.minY === 5 && thisAxis === 2) {
1176
- // console.log("collider", collider);
1177
- // console.log("movement", movement);
1178
- // console.log("movedAABB", movedAABB);
1179
- // console.log("movementLst", movementLst);
1180
- // console.log(minCollider, maxCollider);
1181
- // console.log(minAABB, maxAABB);
1182
- // console.log("axis", thisAxis);
1183
- // console.log(movementLst[thisAxis], maxAABB[thisAxis] - 1e-7, minCollider[thisAxis], cond1);
1184
- // console.log(movementLst[thisAxis], minAABB[thisAxis] + 1e-7, maxCollider[thisAxis], cond2);
1185
- // }
1186
1247
  if (maxAABB[axis1] - 1e-7 > minCollider[axis1] &&
1187
1248
  minAABB[axis1] + 1e-7 < maxCollider[axis1] &&
1188
1249
  maxAABB[axis2] - 1e-7 > minCollider[axis2] &&
@@ -1211,7 +1272,7 @@ class BotcraftPhysics {
1211
1272
  if (sqrNorm > 1) {
1212
1273
  inputVector.normalize();
1213
1274
  }
1214
- inputVector.scale(inputStrength / Math.max(1, sqrNorm));
1275
+ inputVector.scale(inputStrength);
1215
1276
  const yaw = Math.PI - player.yaw;
1216
1277
  const sinYaw = Math.sin(yaw);
1217
1278
  const cosYaw = Math.cos(yaw);
@@ -620,6 +620,7 @@ class EntityPhysics {
620
620
  else
621
621
  vel.y -= entity.gravity * gravityMultiplier;
622
622
  }
623
+ console.log(dragOrFriction);
623
624
  vel.x *= dragOrFriction;
624
625
  vel.z *= dragOrFriction;
625
626
  }
@@ -432,6 +432,7 @@ class PlayerState {
432
432
  const dz = vec3.z - this.pos.z;
433
433
  this.yaw = Math.atan2(dz, dx) * 180 / Math.PI - 90;
434
434
  this.pitch = -Math.atan2(dy, Math.sqrt(dx * dx + dz * dz)) * 180 / Math.PI;
435
+ console.log(this.yaw, this.pitch);
435
436
  }
436
437
  look(yaw, pitch) {
437
438
  this.yaw = yaw;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxg-org/mineflayer-physics-util",
3
- "version": "1.7.8",
3
+ "version": "1.7.10",
4
4
  "description": "Provides functionality for more accurate entity and projectile tracking.",
5
5
  "keywords": [
6
6
  "mineflayer",
@@ -1,141 +1,183 @@
1
1
  import { pathfinder, goals } from "mineflayer-pathfinder";
2
2
  import { Bot, createBot } from "mineflayer";
3
- const physicsInject = require("mineflayer/lib/plugins/physics")
3
+ const physicsInject = require("mineflayer/lib/plugins/physics");
4
4
  import loader, { BotcraftPhysics, EntityPhysics, EntityState, EPhysicsCtx } from "../src/index";
5
5
  import { PlayerState } from "../src/physics/states";
6
6
 
7
7
  const { Physics } = require("prismarine-physics");
8
8
 
9
- const bot: Bot = createBot({
10
- host: process.argv[2],
11
- port: Number(process.argv[3]),
12
- username: "testingbot",
13
- version: process.argv[4],
14
- });
15
-
16
- bot.once("spawn", async () => {
17
- bot.loadPlugin(loader);
18
- bot.loadPlugin(pathfinder);
19
- await bot.waitForTicks(20);
20
- (bot as any).physics.yawSpeed = 50;
21
- (bot as any).physics.pitchSpeed = 50;
22
- // setupNewPhysics(bot);
23
- });
24
-
25
9
  const rl = require("readline").createInterface({
26
10
  input: process.stdin,
27
11
  output: process.stdout,
28
12
  });
29
13
 
30
- rl.on("line", (line: any) => bot.chat(line));
31
14
 
32
- // print whenever bot hits the ground
33
-
34
- let wasOnGround = false;
35
- let printNextPos = false;
36
- bot.on("move", (pos) => {
37
- if (bot.entity.onGround && !wasOnGround) {
38
- bot.chat("Hit the ground! " + bot.entity.position.toString());
15
+ let bot1: Bot;
16
+ function buildBot() {
17
+ console.log('hey!')
18
+
19
+ const bot = createBot({
20
+ host: process.argv[2],
21
+ port: Number(process.argv[3]),
22
+ username: "testingbot",
23
+ version: process.argv[4],
24
+ });
25
+
26
+ bot.once("spawn", async () => {
27
+ bot.loadPlugin(loader);
28
+ bot.loadPlugin(pathfinder);
29
+ await bot.waitForTicks(20);
30
+ (bot as any).physics.yawSpeed = 50;
31
+ (bot as any).physics.pitchSpeed = 50;
32
+ // setupNewPhysics(bot);
33
+ });
34
+
35
+ let wasOnGround = false;
36
+ let printNextPos = false;
37
+
38
+ bot.on("move", (pos) => {
39
+ // console.log(pos);
40
+ if (bot.entity.onGround && !wasOnGround) {
41
+ // bot.chat("Hit the ground! " + bot.entity.position.toString());
42
+ }
43
+ wasOnGround = bot.entity.onGround;
44
+ });
45
+
46
+ // print whenever another player hits the ground
47
+ let lastPositions: Record<string, boolean> = {};
48
+ bot.on("entityMoved", (entity) => {
49
+ if (entity.username && entity.username !== bot.username) {
50
+ // check by seeing is y value is an integer
51
+ if (Math.floor(entity.position.y) === entity.position.y && !lastPositions[entity.username]) {
52
+ // check if in liquid
53
+ const block = bot.blockAt(entity.position);
54
+ if (block && (block.type === bot.registry.blocksByName.water.id || block.type === bot.registry.blocksByName.lava.id)) return;
55
+
56
+ bot.chat(`${entity.username} hit the ground! ${entity.position.toString()}`);
57
+ lastPositions[entity.username] = true;
58
+ } else if (Math.floor(entity.position.y) !== entity.position.y) {
59
+ lastPositions[entity.username] = false;
60
+ }
61
+ }
62
+ });
63
+
64
+ let usingNew = false;
65
+ let oldSimulate: any = null;
66
+
67
+ function setupNewPhysics(bot: Bot) {
68
+ if (usingNew) return;
69
+ usingNew = true;
70
+ oldSimulate = (bot.physics as any).simulatePlayer;
71
+
72
+ const val = new BotcraftPhysics(bot.registry);
73
+
74
+ (EntityState.prototype as any).apply = function (this: EntityState, bot: Bot) {
75
+ // console.log(this.control, this.isUsingItem);
76
+ this.applyToBot(bot);
77
+ };
78
+
79
+ const ctx = EPhysicsCtx.FROM_BOT(val, bot);
80
+ const state = ctx.state as PlayerState;
81
+
82
+ // EntityPhysics.prototype.simulate = function (ctx, world) {
83
+ // bot.physics.simulatePlayer(ctx.state, world);
84
+ // }
85
+
86
+ (bot.physics as any).autojumpCooldown = 0;
87
+ // (bot.physics).jumpTicks = 0;
88
+
89
+ (bot.physics as any).simulatePlayer = (...args: any[]) => {
90
+ state.update(bot);
91
+ ctx.state.jumpTicks = 0; // allow immediate jumping
92
+ return val.simulate(ctx, bot.world);
93
+ };
39
94
  }
40
- wasOnGround = bot.entity.onGround;
41
- });
42
-
43
- // print whenever another player hits the ground
44
- let lastPositions: Record<string, boolean> = {};
45
- bot.on("entityMoved", (entity) => {
46
- if (entity.username && entity.username !== bot.username) {
47
- // check by seeing is y value is an integer
48
- if (Math.floor(entity.position.y) === entity.position.y && !lastPositions[entity.username]) {
49
-
50
- // check if in liquid
51
- const block = bot.blockAt(entity.position);
52
- if (block && (block.type === bot.registry.blocksByName.water.id || block.type === bot.registry.blocksByName.lava.id)) return;
53
-
54
- bot.chat(`${entity.username} hit the ground! ${entity.position.toString()}`);
55
- lastPositions[entity.username] = true;
56
- } else if (Math.floor(entity.position.y) !== entity.position.y) {
57
- lastPositions[entity.username] = false;
58
- }}
59
- });
60
95
 
61
- function setupNewPhysics(bot: Bot) {
62
- const val = new BotcraftPhysics(bot.registry);
63
-
64
- (EntityState.prototype as any).apply = function (this: EntityState, bot: Bot) {
65
- // console.log(this.control, this.isUsingItem);
66
- this.applyToBot(bot);
67
- };
68
-
69
- const ctx = EPhysicsCtx.FROM_BOT(val, bot);
70
- const state = ctx.state as PlayerState
96
+ bot.on("chat", async (user, message) => {
97
+ const [cmd, ...args] = message.split(" ");
98
+ const author = bot.nearestEntity((e) => e.username === user);
99
+
100
+ switch (cmd) {
101
+ case "using":
102
+ bot.chat(`Using new physics: ${usingNew}`);
103
+ break;
104
+ case "lookatme":
105
+ if (!author) return bot.chat("I can't see you!");
106
+ bot.lookAt(author.position.offset(0, author.height, 0));
107
+ break;
108
+ case "status":
109
+ const str = `onGround: ${bot.entity.onGround}, hCol:${(bot.entity as any).isCollidedHorizontally}, vCol:${
110
+ (bot.entity as any).isCollidedVertically
111
+ }, inWater:${(bot.entity as any).isInWater}, inLava:${(bot.entity as any).isInLava}`;
112
+ bot.chat(str);
113
+ break;
114
+ case "use":
115
+ if (bot.usingHeldItem) bot.deactivateItem();
116
+ else bot.activateItem();
117
+ break;
118
+ case "useoff":
119
+ bot.deactivateItem();
120
+ bot.activateItem(true);
121
+ break;
122
+ case "control":
123
+ if (args[0] === "clear") return bot.clearControlStates();
124
+ if (args.length === 1) return bot.setControlState(args[0] as any, !bot.getControlState(args[0] as any));
125
+ bot.setControlState(args[0] as any, args[1] === "true");
126
+ break;
127
+ case "sim":
128
+ // turn all but the mentioned ones off
129
+ const [time, ...controls] = args;
130
+ bot.clearControlStates();
131
+ for (const control of controls) {
132
+ bot.setControlState(control as any, true);
133
+ }
134
+
135
+ for (let i = 0; i <= Number(time); i++) {
136
+ console.log(bot.entity.position, bot.entity.velocity, i);
137
+ await bot.waitForTicks(1);
138
+ }
139
+ bot.clearControlStates();
140
+
141
+ break;
142
+ case "reset":
143
+ usingNew = false;
144
+ bot.quit();
145
+ await new Promise((res) => setTimeout(res, 3000));
146
+ bot1 = buildBot();
147
+
148
+ break;
149
+ case "new":
150
+ setupNewPhysics(bot);
151
+ bot.chat("Switched to new physics!");
152
+ break;
153
+ case "jump":
154
+ bot.setControlState("jump", true);
155
+ break;
156
+ case "come":
157
+ if (!author) return bot.chat(`Cannot see ${user}!`);
158
+ const goal0 = new goals.GoalNear(author.position.x, author.position.y, author.position.z, 3);
159
+ bot.pathfinder.setGoal(goal0);
160
+ break;
161
+ case "goto":
162
+ if (!author) return bot.chat(`Cannot see ${user}!`);
163
+ const goal1 = new goals.GoalNear(Number(args[0]), Number(args[1]), Number(args[2]), 3);
164
+ bot.pathfinder.setGoal(goal1);
165
+ break;
166
+ case "stop":
167
+ bot.deactivateItem();
168
+ bot.pathfinder.stop();
169
+ bot.clearControlStates();
170
+ bot.chat("Stopped!");
171
+ break;
172
+ }
173
+ });
174
+
175
+
176
+ rl.on("line", (line: any) => bot.chat(line));
177
+
178
+ return bot;
179
+ }
71
180
 
72
- // EntityPhysics.prototype.simulate = function (ctx, world) {
73
- // bot.physics.simulatePlayer(ctx.state, world);
74
- // }
75
181
 
76
- (bot.physics as any).autojumpCooldown = 0;
77
- // (bot.physics).jumpTicks = 0;
78
182
 
79
- (bot.physics as any).simulatePlayer = (...args: any[]) => {
80
- state.update(bot);
81
- ctx.state.jumpTicks = 0; // allow immediate jumping
82
- return val.simulate(ctx, bot.world);
83
- };
84
- }
85
-
86
- bot.on("chat", (user, message) => {
87
- const [cmd, ...args] = message.split(" ");
88
- const author = bot.nearestEntity((e) => e.username === user);
89
-
90
- switch (cmd) {
91
- case "lookatme":
92
- if (!author) return bot.chat("I can't see you!");
93
- bot.lookAt(author.position.offset(0, author.height, 0));
94
- break;
95
- case "status":
96
- const str = `onGround: ${bot.entity.onGround}, hCol:${(bot.entity as any).isCollidedHorizontally}, vCol:${(bot.entity as any).isCollidedVertically}, inWater:${(bot.entity as any).isInWater}, inLava:${(bot.entity as any).isInLava}`;
97
- bot.chat(str);
98
- break
99
- case "use":
100
- if (bot.usingHeldItem) bot.deactivateItem();
101
- else bot.activateItem();
102
- break;
103
- case "useoff":
104
- bot.deactivateItem()
105
- bot.activateItem(true)
106
- break
107
- case "control":
108
-
109
- if (args[0] === "clear") return bot.clearControlStates();
110
- if (args.length !== 2) return bot.chat("Invalid control command!");
111
- bot.setControlState(args[0] as any, args[1] === "true");
112
- break;
113
- case "original":
114
- bot.loadPlugin(physicsInject);
115
- bot.chat("Switched to original physics!");
116
- break;
117
- case "new":
118
- setupNewPhysics(bot);
119
- bot.chat("Switched to new physics!");
120
- break;
121
- case "jump":
122
- bot.setControlState("jump", true);
123
- break;
124
- case "come":
125
- if (!author) return bot.chat(`Cannot see ${user}!`);
126
- const goal0 = new goals.GoalNear(author.position.x, author.position.y, author.position.z, 3);
127
- bot.pathfinder.setGoal(goal0);
128
- break;
129
- case "goto":
130
- if (!author) return bot.chat(`Cannot see ${user}!`);
131
- const goal1 = new goals.GoalNear(Number(args[0]), Number(args[1]), Number(args[2]), 3);
132
- bot.pathfinder.setGoal(goal1);
133
- break;
134
- case "stop":
135
- bot.deactivateItem();
136
- bot.pathfinder.stop();
137
- bot.clearControlStates();
138
- bot.chat("Stopped!");
139
- break;
140
- }
141
- });
183
+ bot1 = buildBot();
@@ -13,10 +13,11 @@ import { Bot, ControlState } from "mineflayer";
13
13
 
14
14
  const version = "1.12.2";
15
15
  const mcData = md(version);
16
+ const Engine = BotcraftPhysics;
16
17
  const Block = block(version) as typeof PBlock;
17
18
 
18
- const groundLevel = 4;
19
- const floatingOffset = 20;
19
+ const groundLevel = 67;
20
+ const floatingOffset = 100 - groundLevel;
20
21
  const control: { [key: string]: boolean } = {};
21
22
 
22
23
  class FakeWorld {
@@ -47,12 +48,13 @@ class FakeWorld {
47
48
  }
48
49
  }
49
50
 
50
- function createFakePlayer(pos: Vec3, groundLevel: number) {
51
+ function createFakePlayer(pos: Vec3, tmpGroundLevel: number = groundLevel) {
52
+ const onGround = pos.y === tmpGroundLevel
51
53
  return {
52
54
  entity: {
53
55
  position: pos,
54
- velocity: new Vec3(0, -0.08, 0),
55
- onGround: pos.y === groundLevel,
56
+ velocity: new Vec3(0, onGround ? -0.08 : 0, 0),
57
+ onGround: onGround,
56
58
  isInWater: false,
57
59
  isInLava: false,
58
60
  isInWeb: false,
@@ -94,7 +96,7 @@ describe("Physics Simulation Tests", () => {
94
96
  const setupEntity = (yOffset: number) => {
95
97
  fakePlayer = createFakePlayer(new Vec3(0, groundLevel + yOffset, 0), groundLevel);
96
98
  fakePlayer.entity = applyMdToNewEntity(EPhysicsCtx, playerType, fakePlayer.entity);
97
- physics = new BotcraftPhysics(mcData);
99
+ physics = new Engine(mcData);
98
100
  playerCtx = EPhysicsCtx.FROM_BOT(physics, fakePlayer);
99
101
  playerState = playerCtx.state as PlayerState;
100
102
  playerState.control = ControlStateHandler.DEFAULT();
@@ -110,7 +112,7 @@ describe("Physics Simulation Tests", () => {
110
112
  playerState.vel.y = 0;
111
113
  playerCtx.gravity = 0;
112
114
 
113
- for (let i = 0; i < 10; i++) {
115
+ for (let i = 0; i < 2; i++) {
114
116
  // playerState.update(fakePlayer);
115
117
  physics.simulate(playerCtx, fakeWorld);
116
118
  playerState.apply(fakePlayer);
@@ -127,6 +129,7 @@ describe("Physics Simulation Tests", () => {
127
129
  for (let i = 0; i < 10; i++) {
128
130
  physics.simulate(playerCtx, fakeWorld);
129
131
  playerState.apply(fakePlayer);
132
+ // console.log(fakePlayer.entity.position, playerState.pos, playerState.vel, playerState.age)
130
133
  }
131
134
 
132
135
  if (playerState.control.forward) {
@@ -136,10 +139,10 @@ describe("Physics Simulation Tests", () => {
136
139
  }
137
140
  });
138
141
 
139
- it("test sprint-jumping", () => {
142
+ it("sprint-jumping", () => {
140
143
  setupEntity(0);
141
144
  playerState.control.forward = true;
142
- // playerState.control.sprint = true;
145
+ playerState.control.sprint = true;
143
146
 
144
147
  for (let i = 0; i < 4; i++) {
145
148
  physics.simulate(playerCtx, fakeWorld);
@@ -156,37 +159,39 @@ describe("Physics Simulation Tests", () => {
156
159
  }
157
160
 
158
161
  expect(fakePlayer.entity.position.y).toEqual(groundLevel);
159
- expect(fakePlayer.entity.position.z).toEqual(-2.610639097306083);
162
+ expect(fakePlayer.entity.position.z).toEqual(-4.085029471928113);
160
163
  });
161
164
 
162
- it("falling movement speed", () => {
165
+ it("walk_fallspeed", () => {
163
166
  setupEntity(floatingOffset);
164
167
  playerState.control.forward = true;
165
168
 
166
169
  while (!fakePlayer.entity.onGround && playerState.age < 100) {
167
170
  physics.simulate(playerCtx, fakeWorld);
171
+ // console.log(fakePlayer.entity.position, playerState.pos, playerState.vel, playerState.age)
168
172
  playerState.apply(fakePlayer);
169
173
  }
170
174
 
175
+ expect(fakePlayer.entity.position.z).toEqual(-5.082680598494437);
171
176
  expect(fakePlayer.entity.position.y).toEqual(groundLevel);
172
- expect(fakePlayer.entity.position.z).toEqual(-3.253675739201285);
173
-
174
- const landingPos = playerState.pos.clone();
177
+ });
175
178
 
179
+ it ("sprint_fallspeed", () => {
176
180
  setupEntity(floatingOffset);
177
181
  playerState.control.forward = true;
178
182
  playerState.control.sprint = true;
179
183
 
184
+ // console.log(playerState.vel)
180
185
  while (!fakePlayer.entity.onGround && playerState.age < 100) {
181
186
  physics.simulate(playerCtx, fakeWorld);
182
187
  playerState.apply(fakePlayer);
183
188
  }
184
189
 
185
- console.log(fakePlayer.entity.position, landingPos, playerState.pos)
190
+ // console.log(fakePlayer.entity.position, landingPos, playerState.pos, playerState.control)
186
191
 
192
+ expect(fakePlayer.entity.position.z).toEqual(-7.624010798740387);
187
193
  expect(fakePlayer.entity.position.y).toEqual(groundLevel);
188
- expect(fakePlayer.entity.position).toEqual(landingPos);
189
- });
194
+ })
190
195
 
191
196
  it("should restore position after gravity toggle", () => {
192
197
  setupEntity(floatingOffset);
@@ -219,7 +224,7 @@ describe("Physics Simulation Tests", () => {
219
224
  playerState.apply(fakePlayer);
220
225
  }
221
226
 
222
- expect(fakePlayer.entity.position.y).toEqual(5.001335979112147);
227
+ expect(fakePlayer.entity.position.y).toEqual(groundLevel + 1.001335979112147);
223
228
 
224
229
  for (let i = 0; i < 9; i++) {
225
230
  physics.simulate(playerCtx, fakeWorld);
@@ -229,18 +234,71 @@ describe("Physics Simulation Tests", () => {
229
234
  expect(fakePlayer.entity.position.y).toEqual(groundLevel);
230
235
  });
231
236
 
232
- it("horizonal collision detection", () => {
237
+ it("hCol-z", () => {
233
238
  setupEntity(0);
234
- fakeWorld.setOverrideBlock(new Vec3(0, groundLevel + 1, -2), mcData.blocksByName.stone.id);
239
+ const blockPos = new Vec3(0, groundLevel + 1, -2);
240
+ fakeWorld.setOverrideBlock(blockPos, mcData.blocksByName.dirt.id);
241
+ playerState.look(0, 0);
235
242
  playerState.control.forward = true;
236
243
 
237
244
  for (let i = 0; i < 10; i++) {
238
245
  physics.simulate(playerCtx, fakeWorld);
239
246
  playerState.apply(fakePlayer);
240
- // console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
247
+ console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
241
248
  }
242
249
 
243
250
  expect(playerState.pos.z).toEqual(-0.7);
244
251
  expect(playerState.isCollidedHorizontally).toEqual(true);
245
252
  });
253
+
254
+ it("hCol--z", () => {
255
+ setupEntity(0);
256
+ const blockPos = new Vec3(0, groundLevel + 1, 1);
257
+ fakeWorld.setOverrideBlock(blockPos, mcData.blocksByName.dirt.id);
258
+ playerState.look(-359.9999 * (Math.PI / 360), 0);
259
+ playerState.control.forward = true;
260
+
261
+ for (let i = 0; i < 10; i++) {
262
+ physics.simulate(playerCtx, fakeWorld);
263
+ playerState.apply(fakePlayer);
264
+ console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
265
+ }
266
+
267
+ expect(playerState.pos.z).toEqual(0.7);
268
+ expect(playerState.isCollidedHorizontally).toEqual(true);
269
+ });
270
+
271
+ it("hCol--x", () => {
272
+ setupEntity(0);
273
+ const blockPos = new Vec3(-2, groundLevel + 1, 0);
274
+ fakeWorld.setOverrideBlock(blockPos, mcData.blocksByName.dirt.id);
275
+ playerState.look(180 * (Math.PI / 360), 0)
276
+ playerState.control.forward = true;
277
+
278
+ for (let i = 0; i < 10; i++) {
279
+ physics.simulate(playerCtx, fakeWorld);
280
+ playerState.apply(fakePlayer);
281
+ console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
282
+ }
283
+
284
+ expect(playerState.pos.x).toEqual(-0.7);
285
+ expect(playerState.isCollidedHorizontally).toEqual(true);
286
+ });
287
+
288
+ it("hCol-x", () => {
289
+ setupEntity(0);
290
+ const blockPos = new Vec3(1, groundLevel + 1, 0);
291
+ fakeWorld.setOverrideBlock(blockPos, mcData.blocksByName.dirt.id);
292
+ playerState.look(-180 * (Math.PI / 360), 0);
293
+ playerState.control.forward = true;
294
+
295
+ for (let i = 0; i < 10; i++) {
296
+ physics.simulate(playerCtx, fakeWorld);
297
+ playerState.apply(fakePlayer);
298
+ console.log(fakePlayer.entity.position, playerState.isCollidedHorizontally);
299
+ }
300
+
301
+ expect(playerState.pos.x).toEqual(0.7);
302
+ expect(playerState.isCollidedHorizontally).toEqual(true);
303
+ });
246
304
  });