From 0816a07924fbaf4b18b1da6f44b402d244acbe30 Mon Sep 17 00:00:00 2001 From: noramibu <50046813+noramibu@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:34:37 +0300 Subject: [PATCH 1/2] spear features for attribute swapping --- .../systems/modules/combat/AttributeSwap.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AttributeSwap.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AttributeSwap.java index ebef608eb0..98fee1579a 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AttributeSwap.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AttributeSwap.java @@ -29,12 +29,15 @@ import net.minecraft.registry.tag.EntityTypeTags; import net.minecraft.registry.tag.ItemTags; import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; public class AttributeSwap extends Module { private final SettingGroup sgGeneral = settings.getDefaultGroup(); private final SettingGroup sgSwappingOptions = settings.createGroup("Swapping Options"); private final SettingGroup sgSwordEnchants = settings.createGroup("Sword Enchants"); private final SettingGroup sgMaceEnchants = settings.createGroup("Mace Enchants"); + private final SettingGroup sgSpearEnchants = settings.createGroup("Spear Enchants"); private final SettingGroup sgOtherEnchants = settings.createGroup("Other Enchants"); private final SettingGroup sgWeapon = settings.createGroup("Weapon Options"); @@ -120,6 +123,14 @@ public class AttributeSwap extends Module { .build() ); + private final Setting spearSwapping = sgSwappingOptions.add(new BoolSetting.Builder() + .name("spear-swapping") + .description("Enables smart swapping for spear enchantments.") + .defaultValue(true) + .visible(() -> mode.get() == Mode.Smart) + .build() + ); + private final Setting enchantFireAspect = sgSwordEnchants.add(new BoolSetting.Builder() .name("fire-aspect") .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 { .build() ); + private final Setting enchantLunge = sgSpearEnchants.add(new BoolSetting.Builder() + .name("lunge") + .description("Swaps to a spear with Lunge for traveling.") + .defaultValue(true) + .visible(() -> mode.get() == Mode.Smart && spearSwapping.get()) + .build() + ); + + private final Setting spearHitbox = sgSpearEnchants.add(new BoolSetting.Builder() + .name("hitbox") + .description("Swaps to a spear for extended reach when target is far.") + .defaultValue(true) + .visible(() -> mode.get() == Mode.Smart && spearSwapping.get()) + .build() + ); + + private final Setting excludeLungeFromHitbox = sgSpearEnchants.add(new BoolSetting.Builder() + .name("exclude-lunge-from-hitbox") + .description("Don't use lunge-enchanted spears for hitbox extension.") + .defaultValue(true) + .visible(() -> mode.get() == Mode.Smart && spearSwapping.get() && spearHitbox.get()) + .build() + ); + private final Setting onlyOnWeapon = sgWeapon.add(new BoolSetting.Builder() .name("only-on-weapon") .description("Only swaps when holding a selected weapon in hand.") @@ -286,6 +321,29 @@ public void onDeactivate() { @EventHandler private void onAttack(DoAttackEvent event) { + if (mode.get() == Mode.Smart && spearSwapping.get()) { + + if (spearHitbox.get()) { + Entity target = getTargetEntity(7); + if (target != null) { + if (mc.player.distanceTo(target) <= 3.5) return; + int spearSlot = getSmartSpearSlot(false); + if (spearSlot != -1) { + doSwap(spearSlot); + return; + } + } + } + // lunge spear for travelling (or when enemy isn't in spear range) + if (enchantLunge.get()) { + int lungeSlot = getSmartSpearSlot(true); + if (lungeSlot != -1) { + doSwap(lungeSlot); + return; + } + } + } + if (!canSwapByWeapon() || mode.get() == Mode.Smart || !swapOnMiss.get()) return; if (mc.crosshairTarget.getType() == HitResult.Type.BLOCK) return; @@ -382,6 +440,47 @@ private int getSmartSlot(Entity target) { return bestSlot; } + private int getSmartSpearSlot(boolean requireLunge) { + for (int i = 0; i < 9; i++) { + if (i == mc.player.getInventory().getSelectedSlot()) continue; + ItemStack stack = mc.player.getInventory().getStack(i); + if (!stack.isIn(ItemTags.SPEARS)) continue; + + boolean hasLunge = Utils.getEnchantmentLevel(stack, Enchantments.LUNGE) > 0; + if (requireLunge && !hasLunge) continue; + if (!requireLunge && excludeLungeFromHitbox.get() && hasLunge) continue; + + return i; + } + return -1; + } + + private Entity getTargetEntity(double maxDistance) { + Vec3d start = mc.player.getCameraPosVec(1.0f); + Vec3d look = mc.player.getRotationVec(1.0f); + Vec3d end = start.add(look.multiply(maxDistance)); + + Box box = mc.player.getBoundingBox().stretch(look.multiply(maxDistance)).expand(1.0); + + Entity target = null; + double closestDistance = maxDistance * maxDistance; + + for (Entity entity : mc.world.getOtherEntities(mc.player, box, e -> !e.isSpectator() && e.canHit())) { + // expanding entity's hitbox by 0.15 to simulate spear's actual hitbox margin + Box expandedBox = entity.getBoundingBox().expand(0.150); + + if (expandedBox.raycast(start, end).isPresent()) { + double distSq = start.squaredDistanceTo(entity.getX(), entity.getY(), entity.getZ()); + if (distSq < closestDistance) { + closestDistance = distSq; + target = entity; + } + } + } + + return target; + } + 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) { double score = 0; From 51c5294ef7963dab312b9bffeb8c82d5b2b65261 Mon Sep 17 00:00:00 2001 From: Wide_Cat Date: Sat, 24 Jan 2026 19:34:17 +0000 Subject: [PATCH 2/2] refactors --- .../systems/modules/combat/AttributeSwap.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AttributeSwap.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AttributeSwap.java index 98fee1579a..2091f1b973 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AttributeSwap.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AttributeSwap.java @@ -115,17 +115,17 @@ public class AttributeSwap extends Module { .build() ); - private final Setting otherSwapping = sgSwappingOptions.add(new BoolSetting.Builder() - .name("other-swapping") - .description("Enables smart swapping for other enchantments like Impaling.") + private final Setting spearSwapping = sgSwappingOptions.add(new BoolSetting.Builder() + .name("spear-swapping") + .description("Enables smart swapping for spear enchantments.") .defaultValue(true) .visible(() -> mode.get() == Mode.Smart) .build() ); - private final Setting spearSwapping = sgSwappingOptions.add(new BoolSetting.Builder() - .name("spear-swapping") - .description("Enables smart swapping for spear enchantments.") + private final Setting otherSwapping = sgSwappingOptions.add(new BoolSetting.Builder() + .name("other-swapping") + .description("Enables smart swapping for other enchantments like Impaling.") .defaultValue(true) .visible(() -> mode.get() == Mode.Smart) .build() @@ -321,12 +321,13 @@ public void onDeactivate() { @EventHandler private void onAttack(DoAttackEvent event) { - if (mode.get() == Mode.Smart && spearSwapping.get()) { + if (mc.crosshairTarget.getType() == HitResult.Type.BLOCK || !canSwapByWeapon()) return; + if (mode.get() == Mode.Smart && spearSwapping.get()) { if (spearHitbox.get()) { - Entity target = getTargetEntity(7); + Entity target = getTargetEntity(); if (target != null) { - if (mc.player.distanceTo(target) <= 3.5) return; + if (mc.player.distanceTo(target) <= mc.player.getEntityInteractionRange() + 0.5) return; int spearSlot = getSmartSpearSlot(false); if (spearSlot != -1) { doSwap(spearSlot); @@ -334,6 +335,7 @@ private void onAttack(DoAttackEvent event) { } } } + // lunge spear for travelling (or when enemy isn't in spear range) if (enchantLunge.get()) { int lungeSlot = getSmartSpearSlot(true); @@ -344,9 +346,7 @@ private void onAttack(DoAttackEvent event) { } } - if (!canSwapByWeapon() || mode.get() == Mode.Smart || !swapOnMiss.get()) return; - if (mc.crosshairTarget.getType() == HitResult.Type.BLOCK) return; - + if (mode.get() == Mode.Smart || !swapOnMiss.get()) return; doSwap(targetSlot.get() - 1); } @@ -452,10 +452,12 @@ private int getSmartSpearSlot(boolean requireLunge) { return i; } + return -1; } - private Entity getTargetEntity(double maxDistance) { + private Entity getTargetEntity() { + double maxDistance = 7; Vec3d start = mc.player.getCameraPosVec(1.0f); Vec3d look = mc.player.getRotationVec(1.0f); Vec3d end = start.add(look.multiply(maxDistance));