@@ -343,6 +343,64 @@ function Physics (mcData, world) {
343
343
}
344
344
}
345
345
346
+ function getLookingVector ( entity ) {
347
+ // given a yaw pitch, we need the looking vector
348
+
349
+ // yaw is right handed rotation about y (up) starting from -z (north)
350
+ // pitch is -90 looking down, 90 looking up, 0 looking at horizon
351
+ // lets get its coordinate system.
352
+ // let x' = -z (north)
353
+ // let y' = -x (west)
354
+ // let z' = y (up)
355
+
356
+ // the non normalized looking vector in x', y', z' space is
357
+ // x' is cos(yaw)
358
+ // y' is sin(yaw)
359
+ // z' is tan(pitch)
360
+
361
+ // substituting back in x, y, z, we get the looking vector in the normal x, y, z space
362
+ // -z = cos(yaw) => z = -cos(yaw)
363
+ // -x = sin(yaw) => x = -sin(yaw)
364
+ // y = tan(pitch)
365
+
366
+ // normalizing the vectors, we divide each by |sqrt(x*x + y*y + z*z)|
367
+ // x*x + z*z = sin^2 + cos^2 = 1
368
+ // so |sqrt(xx+yy+zz)| = |sqrt(1+tan^2(pitch))|
369
+ // = |sqrt(1+sin^2(pitch)/cos^2(pitch))|
370
+ // = |sqrt((cos^2+sin^2)/cos^2(pitch))|
371
+ // = |sqrt(1/cos^2(pitch))|
372
+ // = |+/- 1/cos(pitch)|
373
+ // = 1/cos(pitch) since pitch in [-90, 90]
374
+
375
+ // the looking vector is therefore
376
+ // x = -sin(yaw) * cos(pitch)
377
+ // y = tan(pitch) * cos(pitch) = sin(pitch)
378
+ // z = -cos(yaw) * cos(pitch)
379
+
380
+ const yaw = entity . yaw
381
+ const pitch = entity . pitch
382
+ const sinYaw = Math . sin ( yaw )
383
+ const cosYaw = Math . cos ( yaw )
384
+ const sinPitch = Math . sin ( pitch )
385
+ const cosPitch = Math . cos ( pitch )
386
+ const lookX = - sinYaw * cosPitch
387
+ const lookY = sinPitch
388
+ const lookZ = - cosYaw * cosPitch
389
+ const lookDir = new Vec3 ( lookX , lookY , lookZ )
390
+ return {
391
+ yaw,
392
+ pitch,
393
+ sinYaw,
394
+ cosYaw,
395
+ sinPitch,
396
+ cosPitch,
397
+ lookX,
398
+ lookY,
399
+ lookZ,
400
+ lookDir
401
+ }
402
+ }
403
+
346
404
function applyHeading ( entity , strafe , forward , multiplier ) {
347
405
let speed = Math . sqrt ( strafe * strafe + forward * forward )
348
406
if ( speed < 0.01 ) return new Vec3 ( 0 , 0 , 0 )
@@ -377,7 +435,76 @@ function Physics (mcData, world) {
377
435
378
436
const gravityMultiplier = ( vel . y <= 0 && entity . slowFalling > 0 ) ? physics . slowFalling : 1
379
437
380
- if ( ! entity . isInWater && ! entity . isInLava ) {
438
+ if ( entity . isInWater || entity . isInLava ) {
439
+ // Water / Lava movement
440
+ const lastY = pos . y
441
+ let acceleration = physics . liquidAcceleration
442
+ const inertia = entity . isInWater ? physics . waterInertia : physics . lavaInertia
443
+ let horizontalInertia = inertia
444
+
445
+ if ( entity . isInWater ) {
446
+ let strider = Math . min ( entity . depthStrider , 3 )
447
+ if ( ! entity . onGround ) {
448
+ strider *= 0.5
449
+ }
450
+ if ( strider > 0 ) {
451
+ horizontalInertia += ( 0.546 - horizontalInertia ) * strider / 3
452
+ acceleration += ( 0.7 - acceleration ) * strider / 3
453
+ }
454
+
455
+ if ( entity . dolphinsGrace > 0 ) horizontalInertia = 0.96
456
+ }
457
+
458
+ applyHeading ( entity , strafe , forward , acceleration )
459
+ moveEntity ( entity , world , vel . x , vel . y , vel . z )
460
+ vel . y *= inertia
461
+ vel . y -= ( entity . isInWater ? physics . waterGravity : physics . lavaGravity ) * gravityMultiplier
462
+ vel . x *= horizontalInertia
463
+ vel . z *= horizontalInertia
464
+
465
+ if ( entity . isCollidedHorizontally && doesNotCollide ( world , pos . offset ( vel . x , vel . y + 0.6 - pos . y + lastY , vel . z ) ) ) {
466
+ vel . y = physics . outOfLiquidImpulse // jump out of liquid
467
+ }
468
+ } else if ( entity . elytraFlying ) {
469
+ const {
470
+ pitch,
471
+ sinPitch,
472
+ cosPitch,
473
+ lookDir
474
+ } = getLookingVector ( entity )
475
+ const horizontalSpeed = Math . sqrt ( vel . x * vel . x + vel . z * vel . z )
476
+ const cosPitchSquared = cosPitch * cosPitch
477
+ vel . y += physics . gravity * gravityMultiplier * ( - 1.0 + cosPitchSquared * 0.75 )
478
+ // cosPitch is in [0, 1], so cosPitch > 0.0 is just to protect against
479
+ // divide by zero errors
480
+ if ( vel . y < 0.0 && cosPitch > 0.0 ) {
481
+ const movingDownSpeedModifier = vel . y * ( - 0.1 ) * cosPitchSquared
482
+ vel . x += lookDir . x * movingDownSpeedModifier / cosPitch
483
+ vel . y += movingDownSpeedModifier
484
+ vel . z += lookDir . z * movingDownSpeedModifier / cosPitch
485
+ }
486
+
487
+ if ( pitch < 0.0 && cosPitch > 0.0 ) {
488
+ const lookDownSpeedModifier = horizontalSpeed * ( - sinPitch ) * 0.04
489
+ vel . x += - lookDir . x * lookDownSpeedModifier / cosPitch
490
+ vel . y += lookDownSpeedModifier * 3.2
491
+ vel . z += - lookDir . z * lookDownSpeedModifier / cosPitch
492
+ }
493
+
494
+ if ( cosPitch > 0.0 ) {
495
+ vel . x += ( lookDir . x / cosPitch * horizontalSpeed - vel . x ) * 0.1
496
+ vel . z += ( lookDir . z / cosPitch * horizontalSpeed - vel . z ) * 0.1
497
+ }
498
+
499
+ vel . x *= 0.99
500
+ vel . y *= 0.98
501
+ vel . z *= 0.99
502
+ moveEntity ( entity , world , vel . x , vel . y , vel . z )
503
+
504
+ if ( entity . onGround ) {
505
+ entity . elytraFlying = false
506
+ }
507
+ } else {
381
508
// Normal movement
382
509
let acceleration = 0.0
383
510
let inertia = 0.0
@@ -442,36 +569,6 @@ function Physics (mcData, world) {
442
569
vel . y *= physics . airdrag
443
570
vel . x *= inertia
444
571
vel . z *= inertia
445
- } else {
446
- // Water / Lava movement
447
- const lastY = pos . y
448
- let acceleration = physics . liquidAcceleration
449
- const inertia = entity . isInWater ? physics . waterInertia : physics . lavaInertia
450
- let horizontalInertia = inertia
451
-
452
- if ( entity . isInWater ) {
453
- let strider = Math . min ( entity . depthStrider , 3 )
454
- if ( ! entity . onGround ) {
455
- strider *= 0.5
456
- }
457
- if ( strider > 0 ) {
458
- horizontalInertia += ( 0.546 - horizontalInertia ) * strider / 3
459
- acceleration += ( 0.7 - acceleration ) * strider / 3
460
- }
461
-
462
- if ( entity . dolphinsGrace > 0 ) horizontalInertia = 0.96
463
- }
464
-
465
- applyHeading ( entity , strafe , forward , acceleration )
466
- moveEntity ( entity , world , vel . x , vel . y , vel . z )
467
- vel . y *= inertia
468
- vel . y -= ( entity . isInWater ? physics . waterGravity : physics . lavaGravity ) * gravityMultiplier
469
- vel . x *= horizontalInertia
470
- vel . z *= horizontalInertia
471
-
472
- if ( entity . isCollidedHorizontally && doesNotCollide ( world , pos . offset ( vel . x , vel . y + 0.6 - pos . y + lastY , vel . z ) ) ) {
473
- vel . y = physics . outOfLiquidImpulse // jump out of liquid
474
- }
475
572
}
476
573
}
477
574
@@ -617,6 +714,20 @@ function Physics (mcData, world) {
617
714
forward *= physics . sneakSpeed
618
715
}
619
716
717
+ entity . elytraFlying = entity . elytraFlying && entity . elytraEquipped && ! entity . onGround && ! entity . levitation
718
+
719
+ if ( entity . fireworkRocketDuration > 0 ) {
720
+ if ( ! entity . elytraFlying ) {
721
+ entity . fireworkRocketDuration = 0
722
+ } else {
723
+ const { lookDir } = getLookingVector ( entity )
724
+ vel . x += lookDir . x * 0.1 + ( lookDir . x * 1.5 - vel . x ) * 0.5
725
+ vel . y += lookDir . y * 0.1 + ( lookDir . y * 1.5 - vel . y ) * 0.5
726
+ vel . z += lookDir . z * 0.1 + ( lookDir . z * 1.5 - vel . z ) * 0.5
727
+ -- entity . fireworkRocketDuration
728
+ }
729
+ }
730
+
620
731
moveEntityWithHeading ( entity , world , strafe , forward )
621
732
622
733
return entity
@@ -669,8 +780,10 @@ class PlayerState {
669
780
this . isInWeb = bot . entity . isInWeb
670
781
this . isCollidedHorizontally = bot . entity . isCollidedHorizontally
671
782
this . isCollidedVertically = bot . entity . isCollidedVertically
783
+ this . elytraFlying = bot . entity . elytraFlying
672
784
this . jumpTicks = bot . jumpTicks
673
785
this . jumpQueued = bot . jumpQueued
786
+ this . fireworkRocketDuration = bot . fireworkRocketDuration
674
787
675
788
// Input only (not modified)
676
789
this . attributes = bot . entity . attributes
@@ -698,6 +811,10 @@ class PlayerState {
698
811
} else {
699
812
this . depthStrider = 0
700
813
}
814
+
815
+ // extra elytra requirements
816
+ const item = bot . inventory . slots [ 6 ]
817
+ this . elytraEquipped = item != null && item . name === 'elytra'
701
818
}
702
819
703
820
apply ( bot ) {
@@ -709,8 +826,10 @@ class PlayerState {
709
826
bot . entity . isInWeb = this . isInWeb
710
827
bot . entity . isCollidedHorizontally = this . isCollidedHorizontally
711
828
bot . entity . isCollidedVertically = this . isCollidedVertically
829
+ bot . entity . elytraFlying = this . elytraFlying
712
830
bot . jumpTicks = this . jumpTicks
713
831
bot . jumpQueued = this . jumpQueued
832
+ bot . fireworkRocketDuration = this . fireworkRocketDuration
714
833
}
715
834
}
716
835
0 commit comments