1414import net .minecraft .network .protocol .game .ClientboundPlayerPositionPacket ;
1515import net .minecraft .network .protocol .game .ServerboundMovePlayerPacket ;
1616import net .minecraft .network .protocol .game .ServerboundMovePlayerPacket .StatusOnly ;
17+ import net .minecraft .world .entity .PositionMoveRotation ;
1718import net .minecraft .world .entity .ai .attributes .Attributes ;
1819import net .minecraft .world .InteractionHand ;
1920import net .minecraft .world .item .Items ;
@@ -125,18 +126,6 @@ public final class NoFallHack extends Hack implements UpdateListener,
125126 private final SliderSetting mlgMinFallDistance = new SliderSetting (
126127 "MLG MinFallDistance" , 5 , 2 , 50 , 0.5 , ValueDisplay .DECIMAL );
127128
128- private final CheckboxSetting mlgPickupWater =
129- new CheckboxSetting ("MLG PickUpWater" ,
130- "Attempts to pick up placed water after landing." , true );
131-
132- private final SliderSetting mlgPickupSpanMin =
133- new SliderSetting ("MLG PickupSpanMin" , 200 , 0 , 10000 , 10 ,
134- ValueDisplay .INTEGER .withSuffix (" ms" ));
135-
136- private final SliderSetting mlgPickupSpanMax =
137- new SliderSetting ("MLG PickupSpanMax" , 1000 , 0 , 10000 , 10 ,
138- ValueDisplay .INTEGER .withSuffix (" ms" ));
139-
140129 private final SliderSetting vulcanTpVoidLevel = new SliderSetting (
141130 "VulcanTP VoidLevel" , 0 , -256 , 0 , 1 , ValueDisplay .INTEGER );
142131
@@ -174,15 +163,19 @@ public final class NoFallHack extends Hack implements UpdateListener,
174163 "HypixelPacket OverVoid" , "Bypass over void." , false );
175164
176165 private long lastSetbackMs ;
177- private boolean grimPending ;
166+ private boolean grimSnapped ;
167+ private int grimSnapTicks ;
168+ private double grimSnapY = Double .NaN ;
169+ private double grimSnapX = Double .NaN ;
170+ private double grimSnapZ = Double .NaN ;
171+ private boolean grimAfterTeleport ;
178172 private boolean spoofLandingFlag ;
179173 private boolean packetJumpFalling ;
180174 private boolean hypixelDoJump ;
181175 private boolean blocksMcShouldClip ;
182176 private boolean blinkFall ;
183177 private boolean blinkWaitUntilGround = true ;
184178 private boolean blinkFlushing ;
185- private int mlgPickupCooldown ;
186179 private int rettungsCooldown ;
187180 private int spartanCooldown ;
188181
@@ -222,10 +215,6 @@ public NoFallHack()
222215 addSetting (packetJumpResetFallDistance );
223216
224217 addSetting (mlgMinFallDistance );
225- addSetting (mlgPickupWater );
226- addSetting (mlgPickupSpanMin );
227- addSetting (mlgPickupSpanMax );
228-
229218 addSetting (vulcanTpVoidLevel );
230219 addSetting (forceJumpBlockDistance );
231220 addSetting (forceJumpFallDistance );
@@ -278,15 +267,19 @@ protected void onDisable()
278267 EVENTS .remove (PacketInputListener .class , this );
279268 EVENTS .remove (PreMotionListener .class , this );
280269 EVENTS .remove (PacketOutputListener .class , this );
281- grimPending = false ;
270+ grimSnapped = false ;
271+ grimSnapTicks = 0 ;
272+ grimSnapY = Double .NaN ;
273+ grimSnapX = Double .NaN ;
274+ grimSnapZ = Double .NaN ;
275+ grimAfterTeleport = false ;
282276 spoofLandingFlag = false ;
283277 packetJumpFalling = false ;
284278 hypixelDoJump = false ;
285279 blocksMcShouldClip = false ;
286280 blinkFall = false ;
287281 blinkWaitUntilGround = true ;
288282 blinkFlushing = false ;
289- mlgPickupCooldown = 0 ;
290283 rettungsCooldown = 0 ;
291284 spartanCooldown = 0 ;
292285 blinkQueue .clear ();
@@ -302,12 +295,42 @@ public void onUpdate()
302295 if (shouldPause (player ))
303296 return ;
304297
298+ if (mode .getSelected () == Mode .GRIM_2371 && player .onGround ())
299+ {
300+ grimSnapped = false ;
301+ grimSnapTicks = 0 ;
302+ grimSnapY = Double .NaN ;
303+ grimSnapX = Double .NaN ;
304+ grimSnapZ = Double .NaN ;
305+ grimAfterTeleport = false ;
306+ }
307+
308+ if (mode .getSelected () == Mode .GRIM_2371 && grimSnapped
309+ && grimSnapTicks <= 0 && !player .onGround ()
310+ && player .fallDistance > 3.0F )
311+ {
312+ grimSnapped = false ;
313+ }
314+
315+ if (mode .getSelected () == Mode .GRIM_2371 && grimAfterTeleport
316+ && player .fallDistance >= 2.5F && player .getDeltaMovement ().y < 0 )
317+ {
318+ if (tryGrimSnap (player ))
319+ grimAfterTeleport = false ;
320+ }
321+
305322 switch (mode .getSelected ())
306323 {
307324 case GRIM_2371 ->
308325 {
309- if (player .fallDistance >= 2.5F && !player .onGround ())
310- grimPending = true ;
326+ if (player .fallDistance >= 2.5F && !player .onGround ()
327+ && player .getDeltaMovement ().y < 0 )
328+ {
329+ if (grimSnapped )
330+ break ;
331+ if (!tryGrimSnap (player ))
332+ break ;
333+ }
311334 }
312335
313336 case PACKET ->
@@ -367,19 +390,6 @@ public void onPreMotion()
367390 {
368391 if (mode .getSelected () != Mode .GRIM_2371 )
369392 return ;
370-
371- LocalPlayer player = MC .player ;
372- if (player == null )
373- return ;
374-
375- if (grimPending && player .onGround ())
376- {
377- player .connection
378- .send (new StatusOnly (true , player .horizontalCollision ));
379- player .fallDistance = 0 ;
380- player .jumpFromGround ();
381- grimPending = false ;
382- }
383393 }
384394
385395 @ Override
@@ -394,6 +404,8 @@ public void onSentPacket(PacketOutputEvent event)
394404
395405 switch (mode .getSelected ())
396406 {
407+ case GRIM_2371 -> handleGrimPacket (event , packet , player );
408+
397409 case SPOOF_GROUND -> handleSpoofGround (event , packet , player );
398410
399411 case SPOOF_LANDING -> handleSpoofLanding (event , packet , player );
@@ -454,6 +466,25 @@ public void onReceivedPacket(PacketInputEvent event)
454466 }
455467 }
456468
469+ if (mode .getSelected () == Mode .GRIM_2371
470+ && event .getPacket () instanceof ClientboundPlayerPositionPacket pos )
471+ {
472+ LocalPlayer player = MC .player ;
473+ if (player != null )
474+ {
475+ PositionMoveRotation abs = PositionMoveRotation
476+ .calculateAbsolute (PositionMoveRotation .of (player ),
477+ pos .change (), pos .relatives ());
478+ Vec3 target = abs .position ();
479+ Double groundY = findGroundYWithin (player , target .x , target .y ,
480+ target .z , 64.0 );
481+ if (groundY != null && target .y - groundY > 2.5 )
482+ tryGrimSnapAt (player , target .x , target .z , groundY );
483+ }
484+
485+ grimAfterTeleport = true ;
486+ }
487+
457488 if (mode .getSelected () == Mode .CANCEL
458489 && event .getPacket () instanceof ClientboundPlayerPositionPacket )
459490 {
@@ -661,9 +692,6 @@ private void handleBlocksMc(PacketOutputEvent event,
661692
662693 private void handleMlg (LocalPlayer player )
663694 {
664- if (mlgPickupCooldown > 0 )
665- mlgPickupCooldown --;
666-
667695 if (player .fallDistance <= mlgMinFallDistance .getValueF ())
668696 return ;
669697
@@ -674,11 +702,79 @@ private void handleMlg(LocalPlayer player)
674702 if (!tryMlgPlace (player , slot ))
675703 return ;
676704
677- if (!mlgPickupWater .isChecked ())
705+ }
706+
707+ private void handleGrimPacket (PacketOutputEvent event ,
708+ ServerboundMovePlayerPacket packet , LocalPlayer player )
709+ {
710+ if (player .fallDistance < 2.5F )
678711 return ;
679712
680- int maxMs = mlgPickupSpanMax .getValueI ();
681- mlgPickupCooldown = Math .max (1 , maxMs / 50 );
713+ if (player .getDeltaMovement ().y >= 0 )
714+ return ;
715+
716+ if (grimSnapTicks > 0 && !Double .isNaN (grimSnapY ))
717+ {
718+ double x = Double .isNaN (grimSnapX ) ? player .getX () : grimSnapX ;
719+ double z = Double .isNaN (grimSnapZ ) ? player .getZ () : grimSnapZ ;
720+ ServerboundMovePlayerPacket modified =
721+ PacketUtils .modifyPosition (packet , x , grimSnapY , z );
722+ modified = PacketUtils .modifyOnGround (modified , true );
723+ event .setPacket (modified );
724+ player .setPos (x , grimSnapY , z );
725+ player .setDeltaMovement (player .getDeltaMovement ().x , 0 ,
726+ player .getDeltaMovement ().z );
727+ player .fallDistance = 0 ;
728+ grimSnapTicks --;
729+ return ;
730+ }
731+
732+ Double groundY = findGroundYWithin (player , 64.0 );
733+ if (groundY == null )
734+ return ;
735+
736+ double x = packet .getX (player .getX ());
737+ double z = packet .getZ (player .getZ ());
738+ ServerboundMovePlayerPacket modified =
739+ PacketUtils .modifyPosition (packet , x , groundY , z );
740+ modified = PacketUtils .modifyOnGround (modified , true );
741+ event .setPacket (modified );
742+ player .setPos (x , groundY , z );
743+ player .setDeltaMovement (player .getDeltaMovement ().x , 0 ,
744+ player .getDeltaMovement ().z );
745+ grimSnapX = x ;
746+ grimSnapZ = z ;
747+ }
748+
749+ private boolean tryGrimSnap (LocalPlayer player )
750+ {
751+ Double groundY = findGroundYWithin (player , 64.0 );
752+ if (groundY == null )
753+ return false ;
754+
755+ return tryGrimSnapAt (player , player .getX (), player .getZ (), groundY );
756+ }
757+
758+ private boolean tryGrimSnapAt (LocalPlayer player , double x , double z ,
759+ double groundY )
760+ {
761+ ServerboundMovePlayerPacket packet =
762+ MovePacketType .POSITION_AND_ON_GROUND .generatePacket ();
763+ packet = PacketUtils .modifyPosition (packet , x , groundY , z );
764+ packet = PacketUtils .modifyOnGround (packet , true );
765+ player .connection .send (packet );
766+ player .connection
767+ .send (new StatusOnly (true , player .horizontalCollision ));
768+ player .setPos (x , groundY , z );
769+ player .setDeltaMovement (player .getDeltaMovement ().x , 0 ,
770+ player .getDeltaMovement ().z );
771+ player .fallDistance = 0 ;
772+ grimSnapped = true ;
773+ grimSnapTicks = 10 ;
774+ grimSnapY = groundY ;
775+ grimSnapX = x ;
776+ grimSnapZ = z ;
777+ return true ;
682778 }
683779
684780 private void handleRettungsplatform (LocalPlayer player )
@@ -876,6 +972,37 @@ private boolean collidesBottomVertical(LocalPlayer player)
876972 return MC .level .getBlockCollisions (player , box ).iterator ().hasNext ();
877973 }
878974
975+ private Double findGroundYWithin (LocalPlayer player , double x , double y ,
976+ double z , double maxDrop )
977+ {
978+ AABB box = player .getBoundingBox ().move (x - player .getX (),
979+ y - player .getY (), z - player .getZ ());
980+ return findGroundYWithin (box , maxDrop );
981+ }
982+
983+ private Double findGroundYWithin (LocalPlayer player , double maxDrop )
984+ {
985+ return findGroundYWithin (player .getBoundingBox (), maxDrop );
986+ }
987+
988+ private Double findGroundYWithin (AABB box , double maxDrop )
989+ {
990+ double epsilon = 0.03 ;
991+ AABB search = new AABB (box .minX , box .minY - maxDrop , box .minZ , box .maxX ,
992+ box .minY + 0.001 , box .maxZ ).inflate (epsilon , 0 , epsilon );
993+
994+ double [] best = new double []{Double .NEGATIVE_INFINITY };
995+ BlockUtils .getBlockCollisions (search ).forEach (aabb -> {
996+ if (aabb .maxY <= box .minY + 0.001 && box .minY - aabb .maxY <= maxDrop )
997+ best [0 ] = Math .max (best [0 ], aabb .maxY );
998+ });
999+
1000+ if (best [0 ] == Double .NEGATIVE_INFINITY )
1001+ return null ;
1002+
1003+ return best [0 ] + 0.001 ;
1004+ }
1005+
8791006 private boolean isVoidBelow (LocalPlayer player , int depth )
8801007 {
8811008 return doesNotCollideBelow (player ,
0 commit comments