9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-28 19:39:22 +00:00

Fix bot use actions (#606) (#605)

* Stupid me

* Fix bot use actions

* clean up

* Update leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerUseItemAutoAction.java

AND operator always has higher priority than OR operator, this is not "unclear"

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerUseItemAutoAction.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Reuse getEntityHitResult

* No bukkit, yes nms

* Better rayTrace for inside aabb collision

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Lumine1909
2025-07-23 02:59:31 -07:00
committed by GitHub
parent 2f8255bd9e
commit a416f476d3
7 changed files with 104 additions and 72 deletions

View File

@@ -28,10 +28,12 @@ import net.minecraft.world.InteractionResult;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameRules;
@@ -40,7 +42,10 @@ import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.portal.TeleportTransition;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
@@ -496,19 +501,31 @@ public class ServerBot extends ServerPlayer {
return this.getBukkitEntity().getLocation();
}
public Entity getTargetEntity(int maxDistance, Predicate<? super Entity> predicate) {
List<Entity> entities = this.level().getEntities((Entity) null, this.getBoundingBox(), (e -> e != this && (predicate == null || predicate.test(e))));
if (!entities.isEmpty()) {
return entities.getFirst();
} else {
EntityHitResult result = this.getBukkitEntity().rayTraceEntity(maxDistance, false);
if (result != null && (predicate == null || predicate.test(result.getEntity()))) {
return result.getEntity();
}
public EntityHitResult getEntityHitResult(int maxDistance, Predicate<? super Entity> predicate) {
EntityHitResult result = this.pick(this, maxDistance);
if (result != null && (predicate == null || predicate.test(result.getEntity()))) {
return result;
}
return null;
}
private EntityHitResult pick(Entity entity, double maxDistance) {
double d = maxDistance;
double d1 = Mth.square(maxDistance);
Vec3 vec3 = entity.getEyePosition(1.0f);
HitResult hitResult = entity.pick(maxDistance, 1.0f, false);
double d2 = hitResult.getLocation().distanceToSqr(vec3);
if (hitResult.getType() != HitResult.Type.MISS) {
d1 = d2;
d = Math.sqrt(d2);
}
Vec3 viewStart = entity.getViewVector(1.0f);
Vec3 viewEnd = vec3.add(viewStart.x * d, viewStart.y * d, viewStart.z * d);
AABB aABB = entity.getBoundingBox().expandTowards(viewStart.scale(d)).inflate(1.0, 1.0, 1.0);
return ProjectileUtil.getEntityHitResult(entity, vec3, viewEnd, aABB, EntitySelector.CAN_BE_PICKED, d1);
}
public void dropAll(boolean death) {
NonNullList<ItemStack> items = this.getInventory().getNonEquipmentItems();
for (int i = 0; i < items.size(); i++) {

View File

@@ -1,6 +1,6 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.EntityHitResult;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftAttackAction;
@@ -13,11 +13,11 @@ public class ServerAttackAction extends ServerTimerBotAction<ServerAttackAction>
@Override
public boolean doTick(@NotNull ServerBot bot) {
Entity entity = bot.getTargetEntity(3, target -> target.isAttackable() && !target.skipAttackInteraction(bot));
if (entity == null) {
EntityHitResult hitResult = bot.getEntityHitResult(3, target -> target.isAttackable() && !target.skipAttackInteraction(bot));
if (hitResult == null) {
return false;
} else {
bot.attack(entity);
bot.attack(hitResult.getEntity());
return true;
}
}

View File

@@ -1,9 +1,10 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
@@ -74,11 +75,12 @@ public class ServerUseItemAutoAction extends ServerTimerBotAction<ServerUseItemA
return false;
}
Entity entity = bot.getTargetEntity(3, null);
EntityHitResult entityHitResult = bot.getEntityHitResult(3, null);
BlockHitResult blockHitResult = (BlockHitResult) bot.getRayTrace(5, ClipContext.Fluid.NONE);
boolean mainSuccess, useTo = entity != null, useOn = !bot.level().getBlockState(blockHitResult.getBlockPos()).isAir();
boolean mainSuccess, useTo = entityHitResult != null, useOn = !bot.level().getBlockState(blockHitResult.getBlockPos()).isAir();
if (useTo) {
mainSuccess = ServerUseItemToAction.execute(bot, entity) || ServerUseItemAction.execute(bot);
InteractionResult result = ServerUseItemToAction.execute(bot, entityHitResult);
mainSuccess = result.consumesAction() || (result == InteractionResult.PASS && ServerUseItemAction.execute(bot));
} else if (useOn) {
mainSuccess = ServerUseItemOnAction.execute(bot, blockHitResult) || ServerUseItemAction.execute(bot);
} else {
@@ -88,7 +90,8 @@ public class ServerUseItemAutoAction extends ServerTimerBotAction<ServerUseItemA
return true;
}
if (useTo) {
return ServerUseItemToOffhandAction.execute(bot, entity) || ServerUseItemOffhandAction.execute(bot);
InteractionResult result = ServerUseItemToOffhandAction.execute(bot, entityHitResult);
return result.consumesAction() || (result == InteractionResult.PASS && ServerUseItemOffhandAction.execute(bot));
} else if (useOn) {
return ServerUseItemOnOffhandAction.execute(bot, blockHitResult) || ServerUseItemOffhandAction.execute(bot);
} else {

View File

@@ -5,7 +5,6 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.TrappedChestBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
@@ -101,23 +100,23 @@ public class ServerUseItemOnAction extends ServerTimerBotAction<ServerUseItemOnA
BlockState state = bot.level().getBlockState(blockHitResult.getBlockPos());
if (state.isAir()) {
return false;
} else {
bot.swing(InteractionHand.MAIN_HAND);
if (state.getBlock() == Blocks.TRAPPED_CHEST) {
BlockEntity entity = bot.level().getBlockEntity(blockHitResult.getBlockPos());
if (entity instanceof TrappedChestBlockEntity chestBlockEntity) {
chestBlockEntity.startOpen(bot);
Bukkit.getScheduler().runTaskLater(MinecraftInternalPlugin.INSTANCE, () -> chestBlockEntity.stopOpen(bot), 1);
return true;
} else {
return false;
}
} else {
bot.updateItemInHand(InteractionHand.MAIN_HAND);
return bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.MAIN_HAND), InteractionHand.MAIN_HAND, blockHitResult).consumesAction();
}
}
boolean success;
if (state.getBlock() == Blocks.TRAPPED_CHEST &&
bot.level().getBlockEntity(blockHitResult.getBlockPos()) instanceof TrappedChestBlockEntity chestBlockEntity
) {
chestBlockEntity.startOpen(bot);
Bukkit.getScheduler().runTaskLater(MinecraftInternalPlugin.INSTANCE, () -> chestBlockEntity.stopOpen(bot), 1);
success = true;
} else {
bot.updateItemInHand(InteractionHand.MAIN_HAND);
success = bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.MAIN_HAND), InteractionHand.MAIN_HAND, blockHitResult).consumesAction();
}
if (success) {
bot.swing(InteractionHand.MAIN_HAND);
}
return success;
}
@Override
@@ -130,4 +129,4 @@ public class ServerUseItemOnAction extends ServerTimerBotAction<ServerUseItemOnA
public Object asCraft() {
return new CraftUseItemOnAction(this);
}
}
}

View File

@@ -5,7 +5,6 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.TrappedChestBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
@@ -94,30 +93,30 @@ public class ServerUseItemOnOffhandAction extends ServerTimerBotAction<ServerUse
this.useTick = useTick;
}
public static boolean execute(ServerBot bot, HitResult result) {
public static boolean execute(@NotNull ServerBot bot, HitResult result) {
if (!(result instanceof BlockHitResult blockHitResult)) {
return false;
}
BlockState state = bot.level().getBlockState(blockHitResult.getBlockPos());
if (state.isAir()) {
return false;
} else {
bot.swing(InteractionHand.OFF_HAND);
if (state.getBlock() == Blocks.TRAPPED_CHEST) {
BlockEntity entity = bot.level().getBlockEntity(blockHitResult.getBlockPos());
if (entity instanceof TrappedChestBlockEntity chestBlockEntity) {
chestBlockEntity.startOpen(bot);
Bukkit.getScheduler().runTaskLater(MinecraftInternalPlugin.INSTANCE, () -> chestBlockEntity.stopOpen(bot), 1);
return true;
} else {
return false;
}
} else {
bot.updateItemInHand(InteractionHand.OFF_HAND);
return bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.OFF_HAND), InteractionHand.OFF_HAND, blockHitResult).consumesAction();
}
}
boolean success;
if (state.getBlock() == Blocks.TRAPPED_CHEST &&
bot.level().getBlockEntity(blockHitResult.getBlockPos()) instanceof TrappedChestBlockEntity chestBlockEntity
) {
chestBlockEntity.startOpen(bot);
Bukkit.getScheduler().runTaskLater(MinecraftInternalPlugin.INSTANCE, () -> chestBlockEntity.stopOpen(bot), 1);
success = true;
} else {
bot.updateItemInHand(InteractionHand.OFF_HAND);
success = bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.OFF_HAND), InteractionHand.OFF_HAND, blockHitResult).consumesAction();
}
if (success) {
bot.swing(InteractionHand.OFF_HAND);
}
return success;
}
@Override

View File

@@ -2,7 +2,9 @@ package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.phys.EntityHitResult;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
@@ -39,8 +41,8 @@ public class ServerUseItemToAction extends ServerTimerBotAction<ServerUseItemToA
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
Entity entity = bot.getTargetEntity(3, null);
boolean result = execute(bot, entity);
EntityHitResult hitResult = bot.getEntityHitResult(3, null);
boolean result = execute(bot, hitResult).consumesAction();
if (useTick >= 0) {
return false;
} else {
@@ -69,17 +71,22 @@ public class ServerUseItemToAction extends ServerTimerBotAction<ServerUseItemToA
this.useTick = useTick;
}
public static boolean execute(ServerBot bot, Entity entity) {
if (entity == null) {
return false;
public static InteractionResult execute(ServerBot bot, EntityHitResult hitResult) {
if (hitResult == null) {
return InteractionResult.FAIL;
}
boolean flag = bot.interactOn(entity, InteractionHand.MAIN_HAND).consumesAction();
if (flag) {
InteractionResult result;
if (hitResult.getEntity() instanceof ArmorStand armorStand) {
result = armorStand.interactAt(bot, hitResult.getLocation().subtract(armorStand.position()), InteractionHand.MAIN_HAND);
} else {
result = bot.interactOn(hitResult.getEntity(), InteractionHand.MAIN_HAND);
}
if (result.consumesAction()) {
bot.swing(InteractionHand.MAIN_HAND);
bot.updateItemInHand(InteractionHand.MAIN_HAND);
}
return flag;
return result;
}
@Override

View File

@@ -2,7 +2,9 @@ package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.phys.EntityHitResult;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
@@ -39,8 +41,8 @@ public class ServerUseItemToOffhandAction extends ServerTimerBotAction<ServerUse
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
Entity entity = bot.getTargetEntity(3, null);
boolean result = execute(bot, entity);
EntityHitResult hitResult = bot.getEntityHitResult(3, null);
boolean result = execute(bot, hitResult).consumesAction();
if (useTick >= 0) {
return false;
} else {
@@ -69,17 +71,22 @@ public class ServerUseItemToOffhandAction extends ServerTimerBotAction<ServerUse
this.useTick = useTick;
}
public static boolean execute(ServerBot bot, Entity entity) {
if (entity == null) {
return false;
public static InteractionResult execute(ServerBot bot, EntityHitResult hitResult) {
if (hitResult == null) {
return InteractionResult.FAIL;
}
boolean flag = bot.interactOn(entity, InteractionHand.OFF_HAND).consumesAction();
if (flag) {
InteractionResult result;
if (hitResult.getEntity() instanceof ArmorStand armorStand) {
result = armorStand.interactAt(bot, hitResult.getLocation().subtract(armorStand.position()), InteractionHand.OFF_HAND);
} else {
result = bot.interactOn(hitResult.getEntity(), InteractionHand.OFF_HAND);
}
if (result.consumesAction()) {
bot.swing(InteractionHand.OFF_HAND);
bot.updateItemInHand(InteractionHand.OFF_HAND);
}
return flag;
return result;
}
@Override