1111import meteordevelopment .meteorclient .settings .*;
1212import meteordevelopment .meteorclient .systems .modules .Categories ;
1313import meteordevelopment .meteorclient .systems .modules .Module ;
14+ import meteordevelopment .meteorclient .systems .modules .Modules ;
1415import meteordevelopment .meteorclient .utils .Utils ;
1516import meteordevelopment .meteorclient .utils .player .InvUtils ;
1617import meteordevelopment .orbit .EventHandler ;
2829import net .minecraft .world .item .TridentItem ;
2930import net .minecraft .world .item .enchantment .Enchantments ;
3031import net .minecraft .world .phys .AABB ;
32+ import net .minecraft .world .phys .EntityHitResult ;
3133import net .minecraft .world .phys .HitResult ;
3234import net .minecraft .world .phys .Vec3 ;
3335
@@ -297,6 +299,14 @@ public class AttributeSwap extends Module {
297299 .build ()
298300 );
299301
302+ private final Setting <Boolean > spear = sgWeapon .add (new BoolSetting .Builder ()
303+ .name ("spear" )
304+ .description ("Works while holding a spear." )
305+ .defaultValue (true )
306+ .visible (onlyOnWeapon ::get )
307+ .build ()
308+ );
309+
300310 private final Setting <Boolean > trident = sgWeapon .add (new BoolSetting .Builder ()
301311 .name ("trident" )
302312 .description ("Works while holding a trident." )
@@ -320,18 +330,27 @@ public void onDeactivate() {
320330
321331 @ EventHandler
322332 private void onAttack (DoAttackEvent event ) {
323- if (mc .hitResult .getType () == HitResult .Type .BLOCK || !canSwapByWeapon ()) return ;
333+ if (mc .hitResult == null || mc .hitResult .getType () == HitResult .Type .BLOCK || !canSwapByWeapon ()) return ;
334+
335+ if (mc .hitResult instanceof EntityHitResult entityHitResult ) {
336+ if (mode .get () == Mode .Simple ) {
337+ if (!swapOnMiss .get ()) {
338+ performSwap (entityHitResult .getEntity ());
339+ return ;
340+ }
341+ } else if (isWithinMeleeRange (entityHitResult )) {
342+ performSwap (entityHitResult .getEntity ());
343+ return ;
344+ }
345+ }
324346
325347 if (mode .get () == Mode .Smart && spearSwapping .get ()) {
326348 if (spearHitbox .get ()) {
327- Entity target = getTargetEntity ();
349+ Entity target = mc . hitResult instanceof EntityHitResult entityHitResult ? entityHitResult . getEntity () : getTargetEntity ();
328350 if (target != null ) {
329- if (mc .player .distanceTo (target ) <= mc .player .entityInteractionRange () + 0.5 ) return ;
330351 int spearSlot = getSmartSpearSlot (false );
331- if (spearSlot != -1 ) {
332- doSwap (spearSlot );
333- return ;
334- }
352+ if (spearSlot != -1 ) doSwap (spearSlot );
353+ return ;
335354 }
336355 }
337356
@@ -394,6 +413,7 @@ private boolean canSwapByWeapon() {
394413 (shovel .get () && item .is (ItemTags .SHOVELS )) ||
395414 (hoe .get () && item .is (ItemTags .HOES )) ||
396415 (mace .get () && item .getItem () instanceof MaceItem ) ||
416+ (spear .get () && item .is (ItemTags .SPEARS )) ||
397417 (trident .get () && item .getItem () instanceof TridentItem )
398418 );
399419 }
@@ -407,7 +427,7 @@ private int getSmartSlot(Entity target) {
407427 if (axeSlot != -1 ) return axeSlot ;
408428 }
409429
410- boolean isFalling = mc .player .fallDistance > 1.5 ;
430+ boolean isFalling = mc .player .fallDistance > 1.5 && ! mc . player . isFallFlying () ;
411431 boolean durability = smartDurability .get ();
412432
413433 boolean isLiving = target instanceof LivingEntity ;
@@ -439,22 +459,35 @@ private int getSmartSlot(Entity target) {
439459 return bestSlot ;
440460 }
441461
442- private int getSmartSpearSlot (boolean requireLunge ) {
443- for (int i = 0 ; i < 9 ; i ++) {
444- if (i == mc .player .getInventory ().getSelectedSlot ()) continue ;
445- ItemStack stack = mc .player .getInventory ().getItem (i );
446- if (!stack .is (ItemTags .SPEARS )) continue ;
462+ private boolean isWithinMeleeRange (EntityHitResult hitResult ) {
463+ double range = mc .player .entityInteractionRange ();
464+ return hitResult .getLocation ().distanceToSqr (mc .player .getEyePosition (1.0f )) <= range * range ;
465+ }
447466
448- boolean hasLunge = Utils .getEnchantmentLevel (stack , Enchantments .LUNGE ) > 0 ;
449- if (requireLunge && !hasLunge ) continue ;
450- if (!requireLunge && excludeLungeFromHitbox .get () && hasLunge ) continue ;
467+ private int getSmartSpearSlot (boolean requireLunge ) {
468+ int selectedSlot = mc .player .getInventory ().getSelectedSlot ();
469+ if (isValidSpear (mc .player .getInventory ().getItem (selectedSlot ), requireLunge )) {
470+ return selectedSlot ;
471+ }
451472
452- return i ;
473+ for (int i = 0 ; i < 9 ; i ++) {
474+ if (i == selectedSlot ) continue ;
475+ if (isValidSpear (mc .player .getInventory ().getItem (i ), requireLunge )) {
476+ return i ;
477+ }
453478 }
454479
455480 return -1 ;
456481 }
457482
483+ private boolean isValidSpear (ItemStack stack , boolean requireLunge ) {
484+ if (!stack .is (ItemTags .SPEARS )) return false ;
485+
486+ boolean hasLunge = Utils .getEnchantmentLevel (stack , Enchantments .LUNGE ) > 0 ;
487+ if (requireLunge && !hasLunge ) return false ;
488+ return requireLunge || !excludeLungeFromHitbox .get () || !hasLunge ;
489+ }
490+
458491 private Entity getTargetEntity () {
459492 double maxDistance = 7 ;
460493 Vec3 start = mc .player .getEyePosition (1.0f );
@@ -465,10 +498,12 @@ private Entity getTargetEntity() {
465498
466499 Entity target = null ;
467500 double closestDistance = maxDistance * maxDistance ;
501+ Hitboxes hitboxes = Modules .get () != null ? Modules .get ().get (Hitboxes .class ) : null ;
468502
469503 for (Entity entity : mc .level .getEntities (mc .player , box , e -> !e .isSpectator () && e .isPickable ())) {
470504 // expanding entity's hitbox by 0.15 to simulate spear's actual hitbox margin
471- AABB expandedBox = entity .getBoundingBox ().inflate (0.150 );
505+ double extraMargin = hitboxes != null ? hitboxes .getEntityValue (entity ) : 0 ;
506+ AABB expandedBox = entity .getBoundingBox ().inflate (0.150 + extraMargin );
472507
473508 if (expandedBox .clip (start , end ).isPresent ()) {
474509 double distSq = start .distanceToSqr (entity .getX (), entity .getY (), entity .getZ ());
0 commit comments