|
29 | 29 | import net.minecraft.registry.tag.EntityTypeTags; |
30 | 30 | import net.minecraft.registry.tag.ItemTags; |
31 | 31 | import net.minecraft.util.hit.HitResult; |
| 32 | +import net.minecraft.util.math.Box; |
| 33 | +import net.minecraft.util.math.Vec3d; |
32 | 34 |
|
33 | 35 | public class AttributeSwap extends Module { |
34 | 36 | private final SettingGroup sgGeneral = settings.getDefaultGroup(); |
35 | 37 | private final SettingGroup sgSwappingOptions = settings.createGroup("Swapping Options"); |
36 | 38 | private final SettingGroup sgSwordEnchants = settings.createGroup("Sword Enchants"); |
37 | 39 | private final SettingGroup sgMaceEnchants = settings.createGroup("Mace Enchants"); |
| 40 | + private final SettingGroup sgSpearEnchants = settings.createGroup("Spear Enchants"); |
38 | 41 | private final SettingGroup sgOtherEnchants = settings.createGroup("Other Enchants"); |
39 | 42 | private final SettingGroup sgWeapon = settings.createGroup("Weapon Options"); |
40 | 43 |
|
@@ -120,6 +123,14 @@ public class AttributeSwap extends Module { |
120 | 123 | .build() |
121 | 124 | ); |
122 | 125 |
|
| 126 | + private final Setting<Boolean> spearSwapping = sgSwappingOptions.add(new BoolSetting.Builder() |
| 127 | + .name("spear-swapping") |
| 128 | + .description("Enables smart swapping for spear enchantments.") |
| 129 | + .defaultValue(true) |
| 130 | + .visible(() -> mode.get() == Mode.Smart) |
| 131 | + .build() |
| 132 | + ); |
| 133 | + |
123 | 134 | private final Setting<Boolean> enchantFireAspect = sgSwordEnchants.add(new BoolSetting.Builder() |
124 | 135 | .name("fire-aspect") |
125 | 136 | .description("Swaps to an item with Fire Aspect to set the target on fire, if target isn't already on fire") |
@@ -208,6 +219,30 @@ public class AttributeSwap extends Module { |
208 | 219 | .build() |
209 | 220 | ); |
210 | 221 |
|
| 222 | + private final Setting<Boolean> enchantLunge = sgSpearEnchants.add(new BoolSetting.Builder() |
| 223 | + .name("lunge") |
| 224 | + .description("Swaps to a spear with Lunge for traveling.") |
| 225 | + .defaultValue(true) |
| 226 | + .visible(() -> mode.get() == Mode.Smart && spearSwapping.get()) |
| 227 | + .build() |
| 228 | + ); |
| 229 | + |
| 230 | + private final Setting<Boolean> spearHitbox = sgSpearEnchants.add(new BoolSetting.Builder() |
| 231 | + .name("hitbox") |
| 232 | + .description("Swaps to a spear for extended reach when target is far.") |
| 233 | + .defaultValue(true) |
| 234 | + .visible(() -> mode.get() == Mode.Smart && spearSwapping.get()) |
| 235 | + .build() |
| 236 | + ); |
| 237 | + |
| 238 | + private final Setting<Boolean> excludeLungeFromHitbox = sgSpearEnchants.add(new BoolSetting.Builder() |
| 239 | + .name("exclude-lunge-from-hitbox") |
| 240 | + .description("Don't use lunge-enchanted spears for hitbox extension.") |
| 241 | + .defaultValue(true) |
| 242 | + .visible(() -> mode.get() == Mode.Smart && spearSwapping.get() && spearHitbox.get()) |
| 243 | + .build() |
| 244 | + ); |
| 245 | + |
211 | 246 | private final Setting<Boolean> onlyOnWeapon = sgWeapon.add(new BoolSetting.Builder() |
212 | 247 | .name("only-on-weapon") |
213 | 248 | .description("Only swaps when holding a selected weapon in hand.") |
@@ -286,6 +321,29 @@ public void onDeactivate() { |
286 | 321 |
|
287 | 322 | @EventHandler |
288 | 323 | private void onAttack(DoAttackEvent event) { |
| 324 | + if (mode.get() == Mode.Smart && spearSwapping.get()) { |
| 325 | + |
| 326 | + if (spearHitbox.get()) { |
| 327 | + Entity target = getTargetEntity(7); |
| 328 | + if (target != null) { |
| 329 | + if (mc.player.distanceTo(target) <= 3.5) return; |
| 330 | + int spearSlot = getSmartSpearSlot(false); |
| 331 | + if (spearSlot != -1) { |
| 332 | + doSwap(spearSlot); |
| 333 | + return; |
| 334 | + } |
| 335 | + } |
| 336 | + } |
| 337 | + // lunge spear for travelling (or when enemy isn't in spear range) |
| 338 | + if (enchantLunge.get()) { |
| 339 | + int lungeSlot = getSmartSpearSlot(true); |
| 340 | + if (lungeSlot != -1) { |
| 341 | + doSwap(lungeSlot); |
| 342 | + return; |
| 343 | + } |
| 344 | + } |
| 345 | + } |
| 346 | + |
289 | 347 | if (!canSwapByWeapon() || mode.get() == Mode.Smart || !swapOnMiss.get()) return; |
290 | 348 | if (mc.crosshairTarget.getType() == HitResult.Type.BLOCK) return; |
291 | 349 |
|
@@ -382,6 +440,47 @@ private int getSmartSlot(Entity target) { |
382 | 440 | return bestSlot; |
383 | 441 | } |
384 | 442 |
|
| 443 | + private int getSmartSpearSlot(boolean requireLunge) { |
| 444 | + for (int i = 0; i < 9; i++) { |
| 445 | + if (i == mc.player.getInventory().getSelectedSlot()) continue; |
| 446 | + ItemStack stack = mc.player.getInventory().getStack(i); |
| 447 | + if (!stack.isIn(ItemTags.SPEARS)) continue; |
| 448 | + |
| 449 | + boolean hasLunge = Utils.getEnchantmentLevel(stack, Enchantments.LUNGE) > 0; |
| 450 | + if (requireLunge && !hasLunge) continue; |
| 451 | + if (!requireLunge && excludeLungeFromHitbox.get() && hasLunge) continue; |
| 452 | + |
| 453 | + return i; |
| 454 | + } |
| 455 | + return -1; |
| 456 | + } |
| 457 | + |
| 458 | + private Entity getTargetEntity(double maxDistance) { |
| 459 | + Vec3d start = mc.player.getCameraPosVec(1.0f); |
| 460 | + Vec3d look = mc.player.getRotationVec(1.0f); |
| 461 | + Vec3d end = start.add(look.multiply(maxDistance)); |
| 462 | + |
| 463 | + Box box = mc.player.getBoundingBox().stretch(look.multiply(maxDistance)).expand(1.0); |
| 464 | + |
| 465 | + Entity target = null; |
| 466 | + double closestDistance = maxDistance * maxDistance; |
| 467 | + |
| 468 | + for (Entity entity : mc.world.getOtherEntities(mc.player, box, e -> !e.isSpectator() && e.canHit())) { |
| 469 | + // expanding entity's hitbox by 0.15 to simulate spear's actual hitbox margin |
| 470 | + Box expandedBox = entity.getBoundingBox().expand(0.150); |
| 471 | + |
| 472 | + if (expandedBox.raycast(start, end).isPresent()) { |
| 473 | + double distSq = start.squaredDistanceTo(entity.getX(), entity.getY(), entity.getZ()); |
| 474 | + if (distSq < closestDistance) { |
| 475 | + closestDistance = distSq; |
| 476 | + target = entity; |
| 477 | + } |
| 478 | + } |
| 479 | + } |
| 480 | + |
| 481 | + return target; |
| 482 | + } |
| 483 | + |
385 | 484 | private double getItemScore(ItemStack stack, boolean isFalling, boolean durability, boolean isLiving, boolean isPlayer, boolean isOnFire, boolean hasFireResistance, boolean isUndead, boolean isArthropod, boolean isAquatic, double armor, float health) { |
386 | 485 | double score = 0; |
387 | 486 |
|
|
0 commit comments