9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-19 14:59:32 +00:00

Bot Improvements (#661)

* refactor: redesign bot use action

* fix: fix happy ghost and horse control

* fix: fix bot control boat

* fix: fix bot control vehicle

* fix: fix bot boat falling

* fix: fix comment and inline some vars

* fix: fix format and migrate use action nbt data
This commit is contained in:
MC_XiaoHei
2025-08-08 19:45:23 +08:00
committed by GitHub
parent e05f3f7c6a
commit 0c8662816d
14 changed files with 423 additions and 639 deletions

View File

@@ -356,6 +356,52 @@ index 61530843a32632f54f3d4ad913e649ee2dca3f38..d5051d8a2b0af5d8b63a0d10987c0a7e
final boolean xZero = movement.x == 0.0;
final boolean yZero = movement.y == 0.0;
final boolean zZero = movement.z == 0.0;
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 0c52e315557e1dae6a852694786e72241fff1e29..fbee8c381bc5ed04f5fb0fbd7b67704b9a159b47 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3117,7 +3117,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
private void travelRidden(Player player, Vec3 travelVector) {
Vec3 riddenInput = this.getRiddenInput(player, travelVector);
this.tickRidden(player, riddenInput);
- if (this.canSimulateMovement()) {
+ if (this.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - Fakeplayer
this.setSpeed(this.getRiddenSpeed(player));
this.travel(riddenInput);
} else {
@@ -3955,7 +3955,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
// Paper start - lag compensate eating
// we add 1 to the expected time to avoid lag compensating when we should not
final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L));
- if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide && !usingItem.useOnRelease()) {
+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !(this instanceof org.leavesmc.leaves.bot.ServerBot) && !this.level().isClientSide && !usingItem.useOnRelease()) { // Leaves - Fakeplayer skip this check
this.useItemRemaining = 0;
// Paper end - lag compensate eating
this.completeUsingItem();
@@ -4132,6 +4132,23 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
this.stopUsingItem();
}
+ // Leaves start - Fakeplayer
+ public boolean releaseUsingItemWithResult() {
+ ItemStack itemInHand = this.getItemInHand(this.getUsedItemHand());
+ boolean result = false;
+ if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInHand, this.useItem)) {
+ this.useItem = itemInHand;
+ result = this.useItem.releaseUsingWithResult(this.level(), this, this.getUseItemRemainingTicks());
+ if (this.useItem.useOnRelease()) {
+ this.updatingUsingItem();
+ }
+ }
+
+ this.stopUsingItem();
+ return result;
+ }
+ // Leaves end - Fakeplayer
+
public void stopUsingItem() {
if (!this.level().isClientSide) {
boolean isUsingItem = this.isUsingItem();
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 8f4c45fbea2d7c1317aff36031bb834b07b23a82..8ec6f52f58bcc985fdc758a692798a35d6c86378 100644
--- a/net/minecraft/world/entity/player/Player.java
@@ -413,6 +459,36 @@ index 5f3abbe943be394e9cb987945a238208940b5015..8c139d572bd3c44b8e2b6205e28ab09f
public int timeUntilLured;
public int timeUntilHooked;
public float fishAngle;
diff --git a/net/minecraft/world/entity/vehicle/AbstractBoat.java b/net/minecraft/world/entity/vehicle/AbstractBoat.java
index df360ff06d10fc7f996055dce5148825539e9261..b67ae301db4ed3c45a08941f036dc48078a9f12a 100644
--- a/net/minecraft/world/entity/vehicle/AbstractBoat.java
+++ b/net/minecraft/world/entity/vehicle/AbstractBoat.java
@@ -271,6 +271,11 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
}
this.move(MoverType.SELF, this.getDeltaMovement());
+ } else if (this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves start - Fakeplayer
+ this.floatBoat();
+ this.controlBoat();
+ this.move(MoverType.SELF, this.getDeltaMovement());
+ // Leaves end - Fakeplayer
} else {
this.setDeltaMovement(Vec3.ZERO);
}
@@ -381,6 +386,13 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
}
}
+ // Leaves start - Fakeplayer
+ @Override
+ public boolean canSimulateMovement() {
+ return super.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot;
+ }
+ // Leaves end - Fakeplayer
+
@Nullable
protected SoundEvent getPaddleSound() {
return switch (this.getStatus()) {
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
index 06846950348954328c07f64cd9b3359e79a1a468..e1783ad0adbb791b2ff7441243c9f0aeaf37c7f6 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -448,6 +524,40 @@ index 06846950348954328c07f64cd9b3359e79a1a468..e1783ad0adbb791b2ff7441243c9f0ae
private boolean tryItemClickBehaviourOverride(Player player, ClickAction action, Slot slot, ItemStack clickedItem, ItemStack carriedItem) {
FeatureFlagSet featureFlagSet = player.level().enabledFeatures();
return carriedItem.isItemEnabled(featureFlagSet) && carriedItem.overrideStackedOnOther(slot, action, player)
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index da16f4831c875e07c25d7ed041bed493db614658..462e2e4173ea07811022838e4fb592ab5f65e653 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -442,7 +442,7 @@ public final class ItemStack implements DataComponentHolder {
placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(serverLevel, player, hand, blocks.getFirst(), clickedPos);
}
- if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild()) && (!(player instanceof org.leavesmc.leaves.bot.ServerBot))) { // Leaves - Fakeplayer skip this check
interactionResult = InteractionResult.FAIL; // cancel placement
// PAIL: Remove this when MC-99075 fixed
player.containerMenu.forceHeldSlot(hand);
@@ -938,6 +938,20 @@ public final class ItemStack implements DataComponentHolder {
}
}
+ // Leaves start - Fakeplayer
+ public boolean releaseUsingWithResult(Level level, LivingEntity livingEntity, int timeLeft) {
+ ItemStack itemStack = this.copy();
+ if (this.getItem().releaseUsing(this, level, livingEntity, timeLeft)) {
+ ItemStack itemStack1 = this.applyAfterUseComponentSideEffects(livingEntity, itemStack);
+ if (itemStack1 != this) {
+ livingEntity.setItemInHand(livingEntity.getUsedItemHand(), itemStack1);
+ }
+ return true;
+ }
+ return false;
+ }
+ // Leaves end - Fakeplayer
+
public boolean useOnRelease() {
return this.getItem().useOnRelease(this);
}
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index f1ce4cff1c03a0037ade2c8ef989cf327c973a7e..0976aef81b950a062152094501372d00c20bb2b7 100644
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java

View File

@@ -312,7 +312,7 @@ index c1ca84cf0dbb4fd091cfab517721c87e0f9074a0..5f70277c3548a9cd423585d374978422
ItemStack item = container.getItem(i);
if (!item.isEmpty()) {
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index fdc92174fcb4f56fb4ff056f04c9b2429061d887..2fe3d7dedcd1151462161ebb0cf844204354a409 100644
index 1186cad641786aff2ea6f664724a53511aa1440e..4fc9d39382ed2f7c4423585473ee7b72039092cd 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -93,8 +93,12 @@ import net.minecraft.world.level.block.state.pattern.BlockInWorld;
@@ -329,7 +329,7 @@ index fdc92174fcb4f56fb4ff056f04c9b2429061d887..2fe3d7dedcd1151462161ebb0cf84420
private static final List<Component> OP_NBT_WARNING = List.of(
Component.translatable("item.op_warning.line1").withStyle(ChatFormatting.RED, ChatFormatting.BOLD),
Component.translatable("item.op_warning.line2").withStyle(ChatFormatting.RED),
@@ -958,6 +962,7 @@ public final class ItemStack implements DataComponentHolder {
@@ -972,6 +976,7 @@ public final class ItemStack implements DataComponentHolder {
@Nullable
public <T> T set(DataComponentType<T> component, @Nullable T value) {
@@ -337,7 +337,7 @@ index fdc92174fcb4f56fb4ff056f04c9b2429061d887..2fe3d7dedcd1151462161ebb0cf84420
return this.components.set(component, value);
}
@@ -1302,6 +1307,23 @@ public final class ItemStack implements DataComponentHolder {
@@ -1316,6 +1321,23 @@ public final class ItemStack implements DataComponentHolder {
}
public void setCount(int count) {
@@ -361,7 +361,7 @@ index fdc92174fcb4f56fb4ff056f04c9b2429061d887..2fe3d7dedcd1151462161ebb0cf84420
this.count = count;
}
@@ -1357,4 +1379,90 @@ public final class ItemStack implements DataComponentHolder {
@@ -1371,4 +1393,90 @@ public final class ItemStack implements DataComponentHolder {
public boolean canDestroyBlock(BlockState state, Level level, BlockPos pos, Player player) {
return this.getItem().canDestroyBlock(this, state, level, pos, player);
}

View File

@@ -32,8 +32,10 @@ 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.Input;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.entity.vehicle.AbstractBoat;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameRules;
@@ -83,6 +85,7 @@ public class ServerBot extends ServerPlayer {
public boolean resume = false;
public BotCreateState createState;
public UUID createPlayer;
public boolean handsBusy = false;
private final int tracingRange;
private final BotStatsCounter stats;
@@ -152,6 +155,19 @@ public class ServerBot extends ServerPlayer {
if (this.getConfigValue(Configs.TICK_TYPE) == TickType.ENTITY_LIST) {
this.doTick();
}
Input input = this.getLastClientInput();
this.setLastClientInput(
new Input(
this.zza > 0,
this.zza < 0,
this.xxa > 0,
this.xxa < 0,
input.jump(),
input.shift(),
input.sprint()
)
);
}
@Override
@@ -229,6 +245,23 @@ public class ServerBot extends ServerPlayer {
return true;
}
@Override
public void removeVehicle() {
super.removeVehicle();
this.handsBusy = false;
}
@Override
public void rideTick() {
super.rideTick();
this.handsBusy = false;
if (this.getControlledVehicle() instanceof AbstractBoat abstractBoat) {
Input input = this.getLastClientInput();
abstractBoat.setInput(input.left(), input.right(), input.forward(), input.backward());
this.handsBusy = this.handsBusy | (input.left() || input.right() || input.forward() || input.backward());
}
}
@Override
public @Nullable ServerBot teleport(@NotNull TeleportTransition teleportTransition) {
if (this.isSleeping() || this.isRemoved()) {

View File

@@ -76,13 +76,13 @@ public abstract class ServerBotAction<E extends ServerBotAction<E>> {
event.callEvent();
if (event.getResult() == BotActionExecuteEvent.Result.SOFT_CANCEL) {
this.tickToNext = this.getDoIntervalTick() - 1;
this.tickToNext = this.getDoIntervalTick();
return;
} else if (event.getResult() == BotActionExecuteEvent.Result.HARD_CANCEL) {
if (this.numberRemaining > 0) {
this.numberRemaining--;
}
this.tickToNext = this.getDoIntervalTick() - 1;
this.tickToNext = this.getDoIntervalTick();
return;
}
@@ -90,7 +90,7 @@ public abstract class ServerBotAction<E extends ServerBotAction<E>> {
if (this.numberRemaining > 0) {
this.numberRemaining--;
}
this.tickToNext = this.getDoIntervalTick() - 1;
this.tickToNext = this.getDoIntervalTick();
if (this.onSuccess != null) {
this.onSuccess.accept((E) this);
}
@@ -178,7 +178,7 @@ public abstract class ServerBotAction<E extends ServerBotAction<E>> {
}
public void setDoIntervalTick(int initialTickInterval) {
this.initialTickInterval = Math.max(1, initialTickInterval);
this.initialTickInterval = Math.max(0, initialTickInterval);
}
public int getDoIntervalTick() {

View File

@@ -22,7 +22,7 @@ public class ServerFishAction extends ServerTimerBotAction<ServerFishAction> {
@Override
public void setDoIntervalTick(int initialTickInterval) {
super.setDoIntervalTick(1);
super.setDoIntervalTick(0);
this.initialFishInterval = initialTickInterval;
}

View File

@@ -2,6 +2,7 @@ package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.world.entity.Entity;
import org.bukkit.Location;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.entity.CraftVehicle;
import org.bukkit.entity.Vehicle;
import org.jetbrains.annotations.NotNull;
@@ -24,13 +25,13 @@ public class ServerMountAction extends ServerBotAction<ServerMountAction> {
List<Vehicle> vehicles = center.getNearbyEntitiesByType(
Vehicle.class,
3,
vehicle -> manhattanDistance(bot, ((CraftVehicle) vehicle).getHandle()) <= 2
vehicle -> manhattanDistance(bot, ((CraftEntity) vehicle).getHandle()) <= 2
).stream().sorted(Comparator.comparingDouble(
(vehicle) -> center.distanceSquared(vehicle.getLocation())
)).toList();
for (Vehicle vehicle : vehicles) {
if (bot.startRiding(((CraftVehicle) vehicle).getHandle(), false)) {
if (bot.startRiding(((CraftEntity) vehicle).getHandle(), false)) {
return true;
}
}

View File

@@ -0,0 +1,127 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import java.util.List;
import java.util.function.Supplier;
public abstract class ServerUseBotAction<T extends ServerUseBotAction<T>> extends ServerTimerBotAction<T> {
private int useTick = -1;
private int alreadyUsedTick = 0;
private int useItemRemainingTicks = 0;
public ServerUseBotAction(String name, Supplier<T> supplier) {
super(name, CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), supplier);
this.setSuggestion(3, Pair.of(List.of("-1"), "[UseTick]"));
}
@Override
public void loadCommand(ServerPlayer player, @NotNull CommandArgumentResult result) {
super.loadCommand(player, result);
this.useTick = result.readInt(-1);
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
if (shouldStartUseItem()) {
boolean isSuccess = interact(bot);
syncUseItemRemainingTicks(bot);
if (alreadyUseOver()) {
resetAlreadyUsedTick();
return isSuccess;
}
} else {
syncUseItemRemainingTicks(bot);
}
if (alreadyUseOver()) {
resetAlreadyUsedTick();
bot.completeUsingItem();
return true;
} else {
increaseAlreadyUsedTick();
if (isUseTickLimitExceeded()) {
resetAlreadyUsedTick();
shouldStartUseItemNextTick();
return bot.releaseUsingItemWithResult();
}
return false;
}
}
protected abstract boolean interact(ServerBot bot);
public static boolean shouldSwing(InteractionResult result) {
return result instanceof InteractionResult.Success success && success.swingSource() != InteractionResult.SwingSource.NONE;
}
private boolean shouldStartUseItem() {
return useItemRemainingTicks == 0;
}
private boolean alreadyUseOver() {
return useItemRemainingTicks == 0;
}
private boolean isUseTickLimitExceeded() {
int useTickLimit = useTick == -1 ? Integer.MAX_VALUE : useTick;
return alreadyUsedTick > useTickLimit;
}
private void shouldStartUseItemNextTick() {
this.useItemRemainingTicks = 0;
}
private void resetAlreadyUsedTick() {
this.alreadyUsedTick = 0;
}
private void syncUseItemRemainingTicks(@NotNull ServerBot bot) {
this.useItemRemainingTicks = bot.getUseItemRemainingTicks();
}
private void increaseAlreadyUsedTick() {
this.alreadyUsedTick++;
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putInt("useTick", this.useTick);
nbt.putInt("alreadyUsedTick", this.alreadyUsedTick);
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
super.load(nbt);
this.useTick = nbt.getInt("useTick").orElseThrow();
this.alreadyUsedTick = nbt.getInt("alreadyUsedTick").orElseGet(
() -> this.useTick - nbt.getInt("tickToRelease").orElseThrow()
);
}
public int getUseTick() {
return useTick;
}
public void setUseTick(int useTick) {
this.useTick = useTick;
}
@Override
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
super.stop(bot, reason);
bot.releaseUsingItem();
}
}

View File

@@ -1,106 +1,28 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import org.apache.commons.lang3.tuple.Pair;
import net.minecraft.world.InteractionResult;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import org.leavesmc.leaves.entity.bot.actions.CraftUseItemAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import java.util.List;
public class ServerUseItemAction extends ServerTimerBotAction<ServerUseItemAction> {
private int useTick = -1;
private int tickToRelease = -1;
public class ServerUseItemAction extends ServerUseBotAction<ServerUseItemAction> {
public ServerUseItemAction() {
super("use", CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), ServerUseItemAction::new);
this.setSuggestion(3, Pair.of(List.of("-1"), "[UseTick]"));
super("use", ServerUseItemAction::new);
}
@Override
public void init() {
super.init();
syncTickToRelease();
protected boolean interact(@NotNull ServerBot bot) {
return useItem(bot, InteractionHand.MAIN_HAND).consumesAction();
}
@Override
public void loadCommand(ServerPlayer player, @NotNull CommandArgumentResult result) {
super.loadCommand(player, result);
this.useTick = result.readInt(-1);
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
boolean result = execute(bot);
if (useTick >= 0) {
return false;
} else {
return result;
}
} else {
syncTickToRelease();
bot.releaseUsingItem();
return true;
public static @NotNull InteractionResult useItem(@NotNull ServerBot bot, InteractionHand hand) {
InteractionResult result = bot.gameMode.useItem(bot, bot.level(), bot.getItemInHand(hand), hand);
if (shouldSwing(result)) {
bot.swing(hand);
}
}
private void syncTickToRelease() {
if (this.useTick >= 0) {
this.tickToRelease = this.useTick;
} else {
this.tickToRelease = Integer.MAX_VALUE;
}
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putInt("useTick", this.useTick);
nbt.putInt("tickToRelease", this.tickToRelease);
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
super.load(nbt);
this.useTick = nbt.getInt("useTick").orElseThrow();
this.tickToRelease = nbt.getInt("tickToRelease").orElseThrow();
}
public int getUseTick() {
return useTick;
}
public void setUseTick(int useTick) {
this.useTick = useTick;
}
public static boolean execute(@NotNull ServerBot bot) {
if (bot.isUsingItem()) {
return false;
}
boolean flag = bot.gameMode.useItem(bot, bot.level(), bot.getItemInHand(InteractionHand.MAIN_HAND), InteractionHand.MAIN_HAND).consumesAction();
if (flag) {
bot.swing(InteractionHand.MAIN_HAND);
bot.updateItemInHand(InteractionHand.MAIN_HAND);
}
return flag;
}
@Override
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
super.stop(bot, reason);
bot.completeUsingItem();
return result;
}
@Override

View File

@@ -1,110 +1,86 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import org.apache.commons.lang3.tuple.Pair;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import org.leavesmc.leaves.entity.bot.actions.CraftUseItemAutoAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import java.util.List;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemAction.useItem;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemOnAction.getBlockHitResult;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemOnAction.useItemOn;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemToAction.getEntityHitResult;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemToAction.useItemTo;
public class ServerUseItemAutoAction extends ServerTimerBotAction<ServerUseItemAutoAction> {
private int useTick = -1;
private int tickToRelease = -1;
public class ServerUseItemAutoAction extends ServerUseBotAction<ServerUseItemAutoAction> {
public ServerUseItemAutoAction() {
super("use_auto", CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), ServerUseItemAutoAction::new);
this.setSuggestion(3, Pair.of(List.of("-1"), "[UseTick]"));
super("use_auto", ServerUseItemAutoAction::new);
}
@Override
public void init() {
super.init();
syncTickToRelease();
}
@Override
public void loadCommand(ServerPlayer player, @NotNull CommandArgumentResult result) {
super.loadCommand(player, result);
this.useTick = result.readInt(-1);
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
boolean result = execute(bot);
if (useTick >= 0) {
protected boolean interact(ServerBot bot) {
HitResult hitResult = getHitResult(bot);
for (InteractionHand hand : InteractionHand.values()) {
ItemStack itemStack = bot.getItemInHand(hand);
if (!itemStack.isItemEnabled(bot.level().enabledFeatures())) {
return false;
} else {
return result;
}
if (hitResult != null) {
switch (hitResult.getType()) {
case ENTITY -> {
EntityHitResult entityHitResult = (EntityHitResult) hitResult;
InteractionResult entityResult = useItemTo(bot, entityHitResult, hand);
if (entityResult instanceof InteractionResult.Success) {
return true;
} else if (entityResult instanceof InteractionResult.Pass && entityHitResult.getEntity() instanceof ArmorStand) {
return false;
}
}
case BLOCK -> {
InteractionResult blockResult = useItemOn(bot, (BlockHitResult) hitResult, hand);
if (blockResult instanceof InteractionResult.Success) {
return true;
} else if (blockResult instanceof InteractionResult.Fail) {
return false;
}
}
}
}
if (!itemStack.isEmpty() && useItem(bot, hand) instanceof InteractionResult.Success) {
return true;
}
}
return false;
}
private static @Nullable HitResult getHitResult(@NotNull ServerBot bot) {
Vec3 eyePos = bot.getEyePosition();
EntityHitResult entityHitResult = getEntityHitResult(bot);
double entityDistance = entityHitResult != null ? entityHitResult.getLocation().distanceToSqr(eyePos) : Double.MAX_VALUE;
BlockHitResult blockHitResult = getBlockHitResult(bot);
double blockDistance = blockHitResult != null ? blockHitResult.getLocation().distanceToSqr(eyePos) : Double.MAX_VALUE;
if (entityDistance == Double.MAX_VALUE && blockDistance == Double.MAX_VALUE) {
return null;
} else if (entityDistance < blockDistance) {
return entityHitResult;
} else {
syncTickToRelease();
bot.releaseUsingItem();
return true;
return blockHitResult;
}
}
private void syncTickToRelease() {
if (this.useTick >= 0) {
this.tickToRelease = this.useTick;
} else {
this.tickToRelease = Integer.MAX_VALUE;
}
}
public int getUseTick() {
return useTick;
}
public void setUseTick(int useTick) {
this.useTick = useTick;
}
public boolean execute(@NotNull ServerBot bot) {
if (bot.isUsingItem()) {
return false;
}
EntityHitResult entityHitResult = bot.getEntityHitResult(3, null);
BlockHitResult blockHitResult = (BlockHitResult) bot.getRayTrace(5, ClipContext.Fluid.NONE);
boolean mainSuccess, useTo = entityHitResult != null, useOn = !bot.level().getBlockState(blockHitResult.getBlockPos()).isAir();
if (useTo) {
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 {
mainSuccess = ServerUseItemAction.execute(bot);
}
if (mainSuccess) {
return true;
}
if (useTo) {
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 {
return ServerUseItemOffhandAction.execute(bot);
}
}
@Override
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
super.stop(bot, reason);
bot.completeUsingItem();
}
@Override
public Object asCraft() {
return new CraftUseItemAutoAction(this);

View File

@@ -1,106 +1,21 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import org.leavesmc.leaves.entity.bot.actions.CraftUseItemOffhandAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import java.util.List;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemAction.useItem;
public class ServerUseItemOffhandAction extends ServerTimerBotAction<ServerUseItemOffhandAction> {
private int useTick = -1;
private int tickToRelease = -1;
public class ServerUseItemOffhandAction extends ServerUseBotAction<ServerUseItemOffhandAction> {
public ServerUseItemOffhandAction() {
super("use_offhand", CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), ServerUseItemOffhandAction::new);
this.setSuggestion(3, Pair.of(List.of("-1"), "[UseTick]"));
super("use_offhand", ServerUseItemOffhandAction::new);
}
@Override
public void init() {
super.init();
syncTickToRelease();
}
@Override
public void loadCommand(ServerPlayer player, @NotNull CommandArgumentResult result) {
super.loadCommand(player, result);
this.useTick = result.readInt(-1);
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
boolean result = execute(bot);
if (useTick >= 0) {
return false;
} else {
return result;
}
} else {
syncTickToRelease();
bot.releaseUsingItem();
return true;
}
}
private void syncTickToRelease() {
if (this.useTick >= 0) {
this.tickToRelease = this.useTick;
} else {
this.tickToRelease = Integer.MAX_VALUE;
}
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putInt("useTick", this.useTick);
nbt.putInt("tickToRelease", this.tickToRelease);
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
super.load(nbt);
this.useTick = nbt.getInt("useTick").orElseThrow();
this.tickToRelease = nbt.getInt("tickToRelease").orElseThrow();
}
public int getUseTick() {
return useTick;
}
public void setUseTick(int useTick) {
this.useTick = useTick;
}
public static boolean execute(@NotNull ServerBot bot) {
if (bot.isUsingItem()) {
return false;
}
boolean flag = bot.gameMode.useItem(bot, bot.level(), bot.getItemInHand(InteractionHand.OFF_HAND), InteractionHand.OFF_HAND).consumesAction();
if (flag) {
bot.swing(InteractionHand.OFF_HAND);
bot.updateItemInHand(InteractionHand.OFF_HAND);
}
return flag;
}
@Override
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
super.stop(bot, reason);
bot.completeUsingItem();
protected boolean interact(@NotNull ServerBot bot) {
return useItem(bot, InteractionHand.OFF_HAND).consumesAction();
}
@Override

View File

@@ -1,132 +1,57 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.TrappedChestBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import org.leavesmc.leaves.entity.bot.actions.CraftUseItemOnAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import java.util.List;
public class ServerUseItemOnAction extends ServerTimerBotAction<ServerUseItemOnAction> {
private int useTick = -1;
private int tickToRelease = -1;
public class ServerUseItemOnAction extends ServerUseBotAction<ServerUseItemOnAction> {
public ServerUseItemOnAction() {
super("use_on", CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), ServerUseItemOnAction::new);
this.setSuggestion(3, Pair.of(List.of("-1"), "[UseTick]"));
super("use_on", ServerUseItemOnAction::new);
}
@Override
public void init() {
super.init();
syncTickToRelease();
protected boolean interact(@NotNull ServerBot bot) {
BlockHitResult hitResult = getBlockHitResult(bot);
return useItemOn(bot, hitResult, InteractionHand.MAIN_HAND).consumesAction();
}
@Override
public void loadCommand(ServerPlayer player, @NotNull CommandArgumentResult result) {
super.loadCommand(player, result);
this.useTick = result.readInt(-1);
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
HitResult hitResult = bot.getRayTrace(5, ClipContext.Fluid.NONE);
boolean result = execute(bot, hitResult);
if (useTick >= 0) {
return false;
} else {
return result;
}
public static @Nullable BlockHitResult getBlockHitResult(@NotNull ServerBot bot) {
HitResult result = bot.getRayTrace((int) bot.blockInteractionRange(), ClipContext.Fluid.NONE);
if (result instanceof BlockHitResult blockHitResult) {
return blockHitResult;
} else {
syncTickToRelease();
bot.releaseUsingItem();
return true;
return null;
}
}
private void syncTickToRelease() {
if (this.useTick >= 0) {
this.tickToRelease = this.useTick;
} else {
this.tickToRelease = Integer.MAX_VALUE;
}
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putInt("useTick", this.useTick);
nbt.putInt("tickToRelease", this.tickToRelease);
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
super.load(nbt);
this.useTick = nbt.getInt("useTick").orElseThrow();
this.tickToRelease = nbt.getInt("tickToRelease").orElseThrow();
}
public int getUseTick() {
return useTick;
}
public void setUseTick(int useTick) {
this.useTick = useTick;
}
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;
public static InteractionResult useItemOn(ServerBot bot, BlockHitResult hitResult, InteractionHand hand) {
if (hitResult == null) {
return InteractionResult.FAIL;
}
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();
BlockPos blockPos = hitResult.getBlockPos();
if (!bot.level().getWorldBorder().isWithinBounds(blockPos)) {
return InteractionResult.FAIL;
}
if (success) {
bot.swing(InteractionHand.MAIN_HAND);
}
return success;
}
@Override
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
super.stop(bot, reason);
bot.completeUsingItem();
InteractionResult interactionResult = bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(hand), hand, hitResult);
if (shouldSwing(interactionResult)) {
bot.swing(hand);
}
return interactionResult;
}
@Override
public Object asCraft() {
return new CraftUseItemOnAction(this);
}
}
}

View File

@@ -1,128 +1,24 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.nbt.CompoundTag;
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.TrappedChestBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import org.leavesmc.leaves.entity.bot.actions.CraftUseItemOnOffhandAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import java.util.List;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemOnAction.getBlockHitResult;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemOnAction.useItemOn;
public class ServerUseItemOnOffhandAction extends ServerTimerBotAction<ServerUseItemOnOffhandAction> {
private int useTick = -1;
private int tickToRelease = -1;
public class ServerUseItemOnOffhandAction extends ServerUseBotAction<ServerUseItemOnOffhandAction> {
public ServerUseItemOnOffhandAction() {
super("use_on_offhand", CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), ServerUseItemOnOffhandAction::new);
this.setSuggestion(3, Pair.of(List.of("-1"), "[UseTick]"));
super("use_on_offhand", ServerUseItemOnOffhandAction::new);
}
@Override
public void init() {
super.init();
syncTickToRelease();
}
@Override
public void loadCommand(ServerPlayer player, @NotNull CommandArgumentResult result) {
super.loadCommand(player, result);
this.useTick = result.readInt(-1);
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
HitResult hitResult = bot.getRayTrace(5, ClipContext.Fluid.NONE);
boolean result = execute(bot, hitResult);
if (useTick >= 0) {
return false;
} else {
return result;
}
} else {
syncTickToRelease();
bot.releaseUsingItem();
return true;
}
}
private void syncTickToRelease() {
if (this.useTick >= 0) {
this.tickToRelease = this.useTick;
} else {
this.tickToRelease = Integer.MAX_VALUE;
}
}
@Override
@NotNull
public CompoundTag save(@NotNull CompoundTag nbt) {
super.save(nbt);
nbt.putInt("useTick", this.useTick);
nbt.putInt("tickToRelease", this.tickToRelease);
return nbt;
}
@Override
public void load(@NotNull CompoundTag nbt) {
super.load(nbt);
this.useTick = nbt.getInt("useTick").orElseThrow();
this.tickToRelease = nbt.getInt("tickToRelease").orElseThrow();
}
public int getUseTick() {
return useTick;
}
public void setUseTick(int useTick) {
this.useTick = useTick;
}
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;
}
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
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
super.stop(bot, reason);
bot.completeUsingItem();
protected boolean interact(@NotNull ServerBot bot) {
BlockHitResult hitResult = getBlockHitResult(bot);
return useItemOn(bot, hitResult, InteractionHand.OFF_HAND).consumesAction();
}
@Override

View File

@@ -1,98 +1,51 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.EntityHitResult;
import org.apache.commons.lang3.tuple.Pair;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import org.leavesmc.leaves.entity.bot.actions.CraftUseItemToAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import java.util.List;
public class ServerUseItemToAction extends ServerTimerBotAction<ServerUseItemToAction> {
private int useTick = -1;
private int tickToRelease = -1;
public class ServerUseItemToAction extends ServerUseBotAction<ServerUseItemToAction> {
public ServerUseItemToAction() {
super("use_to", CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), ServerUseItemToAction::new);
this.setSuggestion(3, Pair.of(List.of("-1"), "[UseTick]"));
super("use_to", ServerUseItemToAction::new);
}
@Override
public void init() {
super.init();
syncTickToRelease();
protected boolean interact(@NotNull ServerBot bot) {
EntityHitResult hitResult = getEntityHitResult(bot);
return useItemTo(bot, hitResult, InteractionHand.MAIN_HAND).consumesAction();
}
@Override
public void loadCommand(ServerPlayer player, @NotNull CommandArgumentResult result) {
super.loadCommand(player, result);
this.useTick = result.readInt(-1);
public static EntityHitResult getEntityHitResult(@NotNull ServerBot bot) {
return bot.getEntityHitResult((int) bot.entityInteractionRange(), null);
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
EntityHitResult hitResult = bot.getEntityHitResult(3, null);
boolean result = execute(bot, hitResult).consumesAction();
if (useTick >= 0) {
return false;
} else {
return result;
}
} else {
syncTickToRelease();
bot.releaseUsingItem();
return true;
}
}
private void syncTickToRelease() {
if (this.useTick >= 0) {
this.tickToRelease = this.useTick;
} else {
this.tickToRelease = Integer.MAX_VALUE;
}
}
public int getUseTick() {
return useTick;
}
public void setUseTick(int useTick) {
this.useTick = useTick;
}
public static InteractionResult execute(ServerBot bot, EntityHitResult hitResult) {
public static InteractionResult useItemTo(ServerBot bot, EntityHitResult hitResult, InteractionHand hand) {
if (hitResult == null) {
return InteractionResult.FAIL;
}
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);
Entity entity = hitResult.getEntity();
if (!bot.level().getWorldBorder().isWithinBounds(entity.blockPosition())) {
return InteractionResult.FAIL;
}
if (result.consumesAction()) {
bot.swing(InteractionHand.MAIN_HAND);
bot.updateItemInHand(InteractionHand.MAIN_HAND);
}
return result;
}
@Override
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
super.stop(bot, reason);
bot.completeUsingItem();
Vec3 vec3 = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ());
InteractionResult interactionResult = entity.interactAt(bot, vec3, hand);
if (!interactionResult.consumesAction()) {
interactionResult = bot.interactOn(hitResult.getEntity(), hand);
}
if (shouldSwing(interactionResult)) {
bot.swing(hand);
}
return interactionResult;
}
@Override

View File

@@ -1,98 +1,24 @@
package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
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;
import org.leavesmc.leaves.command.CommandArgument;
import org.leavesmc.leaves.command.CommandArgumentResult;
import org.leavesmc.leaves.command.CommandArgumentType;
import org.leavesmc.leaves.entity.bot.actions.CraftUseItemToOffhandAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import java.util.List;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemToAction.getEntityHitResult;
import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemToAction.useItemTo;
public class ServerUseItemToOffhandAction extends ServerTimerBotAction<ServerUseItemToOffhandAction> {
private int useTick = -1;
private int tickToRelease = -1;
public class ServerUseItemToOffhandAction extends ServerUseBotAction<ServerUseItemToOffhandAction> {
public ServerUseItemToOffhandAction() {
super("use_to_offhand", CommandArgument.of(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER, CommandArgumentType.INTEGER), ServerUseItemToOffhandAction::new);
this.setSuggestion(3, Pair.of(List.of("-1"), "[UseTick]"));
super("use_to_offhand", ServerUseItemToOffhandAction::new);
}
@Override
public void init() {
super.init();
syncTickToRelease();
}
@Override
public void loadCommand(ServerPlayer player, @NotNull CommandArgumentResult result) {
super.loadCommand(player, result);
this.useTick = result.readInt(-1);
}
@Override
public boolean doTick(@NotNull ServerBot bot) {
tickToRelease--;
if (tickToRelease >= 0) {
EntityHitResult hitResult = bot.getEntityHitResult(3, null);
boolean result = execute(bot, hitResult).consumesAction();
if (useTick >= 0) {
return false;
} else {
return result;
}
} else {
syncTickToRelease();
bot.releaseUsingItem();
return true;
}
}
private void syncTickToRelease() {
if (this.useTick >= 0) {
this.tickToRelease = this.useTick;
} else {
this.tickToRelease = Integer.MAX_VALUE;
}
}
public int getUseTick() {
return useTick;
}
public void setUseTick(int useTick) {
this.useTick = useTick;
}
public static InteractionResult execute(ServerBot bot, EntityHitResult hitResult) {
if (hitResult == null) {
return InteractionResult.FAIL;
}
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 result;
}
@Override
public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) {
super.stop(bot, reason);
bot.completeUsingItem();
protected boolean interact(@NotNull ServerBot bot) {
EntityHitResult hitResult = getEntityHitResult(bot);
return useItemTo(bot, hitResult, InteractionHand.OFF_HAND).consumesAction();
}
@Override