introduce 26.1.2 changes
Fakeplayer Action Gui - Stage 1 (#161) Still needs some tweaks to fit Leaves' changes * pre add gui (not implemented) * fallback one change in Actions * pre for new structure of gui register * Enhance GUI node structure with item support and command handling * feat: update GUI node handling in bot actions * feat: enhance command building logic in GUI nodes * fix a bug * feat: implement GUI navigation and command execution in BotAction GUI * feat: refactor GuiNode and related classes to use Item instead of ItemStack * feat: update command building logic to include additional action parameters * feat: simplify command syntax in BotAction GUI and update inventory view handling * feat: add ActionType enum and implement action confirmation in BotAction GUI * feat: enhance ActionType handling and selection in BotAction GUI * feat: integrate GUI data handling in bot actions and enhance navigation * fix up * because of tmp move to new org, rebrand * Implement pagination for bot action GUI and enhance action stop functionality * ci updates * replace boarder item * fix https://github.com/LophineCraft/Lophine/pull/161#issuecomment-5012127501 issues - 1 * fix https://github.com/LophineCraft/Lophine/pull/161#issuecomment-5012127501 issues - 2 * fix index * replace some items * feat: use the same item shown for stop & start action * remove 2 todos, we wouldn't provide them * refactor: simplify rendering methods in BotActionGuiContainer * feat: add empty action placeholder and simplify item rendering * fix: remove extra suggestions * fix: update GUI icons for jump, move, and swap actions * fix: update comment in open action gui * set release mode to true --------- Co-authored-by: xiaoxijun <A3167717663@hotmail.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
package org.leavesmc.leaves.event.bot;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.leavesmc.leaves.entity.bot.Bot;
|
||||||
|
|
||||||
|
public class BotActionGuiOpenEvent extends BotEvent implements Cancellable {
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private final Player player;
|
||||||
|
private boolean cancel = false;
|
||||||
|
|
||||||
|
public BotActionGuiOpenEvent(@NotNull Bot who, @Nullable Player player) {
|
||||||
|
super(who);
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancel) {
|
||||||
|
this.cancel = cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Player getOpenPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,759 @@
|
|||||||
|
package fun.bm.lophine.bot;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.ActionType;
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiNode;
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.SimpleContainer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.item.component.CustomData;
|
||||||
|
import net.minecraft.world.item.component.ItemLore;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.leavesmc.leaves.bot.agent.actions.AbstractBotAction;
|
||||||
|
import org.leavesmc.leaves.entity.bot.CraftBot;
|
||||||
|
import org.leavesmc.leaves.entity.bot.action.BotAction;
|
||||||
|
import org.leavesmc.leaves.entity.bot.actions.CraftBotAction;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class BotActionGuiContainer extends SimpleContainer {
|
||||||
|
private static final Map<String, GuiRootNode> GUI_ROOT_NODE_MAP = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
private static final int CONTAINER_SIZE = 54;
|
||||||
|
|
||||||
|
private static final int[] BORDER_SLOTS = {
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||||
|
9, 17,
|
||||||
|
18, 26,
|
||||||
|
27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||||
|
36, 37, 38, 39, 40, 41, 42, 43, 44,
|
||||||
|
45, 46, 47, 48, 49, 50, 51, 52, 53
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int[] CONTENT_SLOTS = {
|
||||||
|
10, 11, 12, 13, 14, 15, 16,
|
||||||
|
19, 20, 21, 22, 23, 24, 25
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int BACK_BUTTON_SLOT = 38;
|
||||||
|
private static final int COMMAND_BUILDER_SLOT = 40;
|
||||||
|
private static final int HOME_BUTTON_SLOT = 42;
|
||||||
|
private static final int PREV_PAGE_SLOT = 39;
|
||||||
|
private static final int NEXT_PAGE_SLOT = 41;
|
||||||
|
|
||||||
|
private static final ItemStack boarder = new ItemStack(Items.STAINED_GLASS_PANE.white());
|
||||||
|
private static final ItemStack emptyActionPlaceholder = createEmptyActionPlaceholder();
|
||||||
|
|
||||||
|
private final CraftBot bot;
|
||||||
|
private final CraftPlayer player;
|
||||||
|
private final Deque<GuiNode> navigationStack = new ArrayDeque<>();
|
||||||
|
private final Deque<Boolean> fromRootLevelStack = new ArrayDeque<>(); // Track if we came from root level
|
||||||
|
private GuiNode currentNode = null;
|
||||||
|
|
||||||
|
// New state for action type selection flow
|
||||||
|
private ActionType selectedActionType = null;
|
||||||
|
private boolean isSelectingActionType = false;
|
||||||
|
|
||||||
|
// Pagination state
|
||||||
|
private int currentPage = 0;
|
||||||
|
|
||||||
|
public static void registerGuiRootNode(GuiRootNode guiRootNode) {
|
||||||
|
if (!GUI_ROOT_NODE_MAP.containsKey(guiRootNode.getName())) {
|
||||||
|
GUI_ROOT_NODE_MAP.put(guiRootNode.getName(), guiRootNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unregisterGuiRootNode(String name) {
|
||||||
|
GUI_ROOT_NODE_MAP.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GuiRootNode getGuiRootNode(String name) {
|
||||||
|
return GUI_ROOT_NODE_MAP.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, GuiRootNode> getGuiRootNodes() {
|
||||||
|
return new LinkedHashMap<>(GUI_ROOT_NODE_MAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BotActionGuiContainer(@NotNull CraftBot bot, CraftPlayer player) {
|
||||||
|
super(CONTAINER_SIZE, player);
|
||||||
|
this.bot = bot;
|
||||||
|
this.player = player;
|
||||||
|
this.showActionTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCommandBuilderSlot(int id) {
|
||||||
|
return id == COMMAND_BUILDER_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillBorder() {
|
||||||
|
for (int slot : BORDER_SLOTS) {
|
||||||
|
this.setItem(slot, boarder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showActionTypes() {
|
||||||
|
this.clearContent();
|
||||||
|
this.fillBorder();
|
||||||
|
this.currentNode = null;
|
||||||
|
this.navigationStack.clear();
|
||||||
|
this.fromRootLevelStack.clear();
|
||||||
|
this.selectedActionType = null;
|
||||||
|
this.isSelectingActionType = true;
|
||||||
|
this.currentPage = 0;
|
||||||
|
|
||||||
|
this.renderActionTypes();
|
||||||
|
this.addNavigationButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showRootNodes() {
|
||||||
|
this.clearContent();
|
||||||
|
this.fillBorder();
|
||||||
|
this.currentNode = null;
|
||||||
|
this.navigationStack.clear();
|
||||||
|
this.fromRootLevelStack.clear();
|
||||||
|
this.isSelectingActionType = false;
|
||||||
|
this.currentPage = 0;
|
||||||
|
|
||||||
|
List<GuiRootNode> allNodes = new ArrayList<>(GUI_ROOT_NODE_MAP.values());
|
||||||
|
if (allNodes.isEmpty()) {
|
||||||
|
// No root nodes, go back to action type selection
|
||||||
|
this.showActionTypes();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderRootNodes();
|
||||||
|
this.addNavigationButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void navigateToChild(GuiNode node) {
|
||||||
|
if (node == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're at root level (currentNode is null but not selecting action type),
|
||||||
|
// we need to track that we came from root nodes level
|
||||||
|
if (this.currentNode != null) {
|
||||||
|
this.navigationStack.push(this.currentNode);
|
||||||
|
this.fromRootLevelStack.push(false);
|
||||||
|
} else if (!this.isSelectingActionType && this.selectedActionType != null) {
|
||||||
|
// We're at root nodes level, mark that we should return to root nodes
|
||||||
|
this.fromRootLevelStack.push(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentNode = node;
|
||||||
|
this.currentPage = 0;
|
||||||
|
this.refreshContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean navigateBack() {
|
||||||
|
// If we're at root node level (no navigation stack), go back to action type selection
|
||||||
|
if (this.navigationStack.isEmpty() && this.fromRootLevelStack.isEmpty()) {
|
||||||
|
// If we have a selected action type, we're at the root nodes level
|
||||||
|
if (!this.isSelectingActionType && this.selectedActionType != null) {
|
||||||
|
this.showActionTypes();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Already at action type selection
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we should return to root nodes level
|
||||||
|
boolean fromRootLevel = !this.fromRootLevelStack.isEmpty() && this.fromRootLevelStack.pop();
|
||||||
|
|
||||||
|
if (fromRootLevel) {
|
||||||
|
// Return to root nodes level
|
||||||
|
this.currentNode = null;
|
||||||
|
this.showRootNodes();
|
||||||
|
} else if (!this.navigationStack.isEmpty()) {
|
||||||
|
// Pop from navigation stack and refresh
|
||||||
|
this.currentNode = this.navigationStack.pop();
|
||||||
|
this.refreshContainer();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void navigateHome() {
|
||||||
|
this.showActionTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshContainer() {
|
||||||
|
this.clearContent();
|
||||||
|
this.fillBorder();
|
||||||
|
|
||||||
|
Set<GuiNode> children = this.getChildrenOfCurrentNode();
|
||||||
|
if (children == null || children.isEmpty()) {
|
||||||
|
// Empty page: auto-navigate back
|
||||||
|
this.navigateBack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderCurrentNodeChildren();
|
||||||
|
this.addNavigationButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Set<GuiNode> getChildrenOfCurrentNode() {
|
||||||
|
if (this.currentNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (this.currentNode instanceof GuiRootNode rootNode) {
|
||||||
|
return rootNode.getChildren();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderActionTypes() {
|
||||||
|
List<ActionType> allTypes = List.of(ActionType.values());
|
||||||
|
this.renderPagedItems(allTypes, (actionType, slot) -> {
|
||||||
|
ItemStack item = actionType.toConfirmNode(null).getItemStack();
|
||||||
|
if (item != null && !item.isEmpty()) {
|
||||||
|
this.setItem(slot, item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderRootNodes() {
|
||||||
|
List<GuiRootNode> allNodes = new ArrayList<>(GUI_ROOT_NODE_MAP.values());
|
||||||
|
this.renderPagedItems(allNodes, (node, slot) -> {
|
||||||
|
ItemStack item = createNodeItemWithRunHint(node);
|
||||||
|
if (item != null && !item.isEmpty()) {
|
||||||
|
this.setItem(slot, item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderCurrentNodeChildren() {
|
||||||
|
Set<GuiNode> children = this.getChildrenOfCurrentNode();
|
||||||
|
if (children != null && !children.isEmpty()) {
|
||||||
|
List<GuiNode> childList = new ArrayList<>(children);
|
||||||
|
this.renderPagedItems(childList, (node, slot) -> {
|
||||||
|
ItemStack item = createNodeItemWithRunHint(node);
|
||||||
|
if (item != null && !item.isEmpty()) {
|
||||||
|
this.setItem(slot, item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderBotActions() {
|
||||||
|
int actionSize = this.bot.getActionSize();
|
||||||
|
if (actionSize > 0) {
|
||||||
|
List<Integer> actionIndices = new ArrayList<>();
|
||||||
|
for (int i = 0; i < actionSize; i++) {
|
||||||
|
actionIndices.add(i);
|
||||||
|
}
|
||||||
|
this.renderPagedItems(actionIndices, (index, slot) -> {
|
||||||
|
BotAction<?> action = this.bot.getAction(index);
|
||||||
|
ItemStack item = createActionItem(action, index);
|
||||||
|
if (!item.isEmpty()) {
|
||||||
|
this.setItem(slot, item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Show empty placeholder when no actions are active
|
||||||
|
this.setItem(CONTENT_SLOTS[0], emptyActionPlaceholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ItemStack createEmptyActionPlaceholder() {
|
||||||
|
ItemStack item = new ItemStack(Items.STRUCTURE_VOID);
|
||||||
|
item.set(DataComponents.CUSTOM_NAME, Component.literal("§cNo active actions"));
|
||||||
|
item.set(DataComponents.LORE, new ItemLore(List.of(
|
||||||
|
Component.literal("§cThis bot has no running actions"),
|
||||||
|
Component.literal("§cUse START to add new actions")
|
||||||
|
)));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public GuiNode getGuiNodeAtSlot(int slot) {
|
||||||
|
if (slot == BACK_BUTTON_SLOT && this.canNavigateBack()) {
|
||||||
|
return null; // back button is handled separately
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if slot is a border slot
|
||||||
|
for (int borderSlot : BORDER_SLOTS) {
|
||||||
|
if (borderSlot == slot) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<GuiNode> nodes = this.getCurrentDisplayNodes();
|
||||||
|
if (nodes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the content index for this slot
|
||||||
|
int contentIndex = -1;
|
||||||
|
for (int i = 0; i < CONTENT_SLOTS.length; i++) {
|
||||||
|
if (CONTENT_SLOTS[i] == slot) {
|
||||||
|
contentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentIndex == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply pagination offset
|
||||||
|
int actualIndex = this.currentPage * CONTENT_SLOTS.length + contentIndex;
|
||||||
|
int index = 0;
|
||||||
|
for (GuiNode node : nodes) {
|
||||||
|
if (index == actualIndex) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBackButtonSlot(int slot) {
|
||||||
|
return slot == BACK_BUTTON_SLOT && this.canNavigateBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHomeButtonSlot(int slot) {
|
||||||
|
return slot == HOME_BUTTON_SLOT && this.canNavigateHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ItemStack createBackButtonItem() {
|
||||||
|
ItemStack item = new ItemStack(Items.WOOL.red());
|
||||||
|
item.set(DataComponents.CUSTOM_NAME, Component.literal("§cBack"));
|
||||||
|
item.set(DataComponents.LORE, new ItemLore(List.of(Component.literal("Return to previous page"))));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ItemStack createHomeButtonItem() {
|
||||||
|
ItemStack item = new ItemStack(Items.BED.red());
|
||||||
|
item.set(DataComponents.CUSTOM_NAME, Component.literal("§aHome"));
|
||||||
|
item.set(DataComponents.LORE, new ItemLore(List.of(Component.literal("Return to main menu"))));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack createNodeItemWithRunHint(GuiNode node) {
|
||||||
|
ItemStack itemStack = node.getItemStack();
|
||||||
|
|
||||||
|
// Check if this is a last-level node (no children)
|
||||||
|
boolean isLastLevel;
|
||||||
|
if (node instanceof GuiRootNode rootNode) {
|
||||||
|
isLastLevel = rootNode.getChildren().isEmpty();
|
||||||
|
} else {
|
||||||
|
// Non-RootNode is always considered last level
|
||||||
|
isLastLevel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's the last level and we have an action type selected, add run hint
|
||||||
|
if (isLastLevel && this.selectedActionType != null && !this.isSelectingActionType) {
|
||||||
|
// Get existing lore or create new one
|
||||||
|
ItemLore existingLore = itemStack.get(DataComponents.LORE);
|
||||||
|
List<Component> loreLines = new ArrayList<>();
|
||||||
|
|
||||||
|
if (existingLore != null) {
|
||||||
|
loreLines.addAll(existingLore.lines());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add golden run hint
|
||||||
|
loreLines.add(Component.literal("§6Click to execute"));
|
||||||
|
|
||||||
|
itemStack.set(DataComponents.LORE, new ItemLore(loreLines));
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render items with pagination support.
|
||||||
|
*
|
||||||
|
* @param items the full list of items
|
||||||
|
* @param renderer callback to render each item at a specific slot
|
||||||
|
*/
|
||||||
|
private <T> void renderPagedItems(List<T> items, PagedItemRenderer<T> renderer) {
|
||||||
|
int pageSize = CONTENT_SLOTS.length;
|
||||||
|
int totalPages = Math.max(1, (items.size() + pageSize - 1) / pageSize);
|
||||||
|
|
||||||
|
// Clamp current page
|
||||||
|
if (this.currentPage >= totalPages) {
|
||||||
|
this.currentPage = totalPages - 1;
|
||||||
|
}
|
||||||
|
if (this.currentPage < 0) {
|
||||||
|
this.currentPage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int start = this.currentPage * pageSize;
|
||||||
|
int end = Math.min(start + pageSize, items.size());
|
||||||
|
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
int slotIndex = i - start;
|
||||||
|
renderer.render(items.get(i), CONTENT_SLOTS[slotIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface PagedItemRenderer<T> {
|
||||||
|
void render(T item, int slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add navigation buttons including pagination controls.
|
||||||
|
*/
|
||||||
|
private void addNavigationButtons() {
|
||||||
|
if (this.canNavigateBack()) {
|
||||||
|
this.setItem(BACK_BUTTON_SLOT, createBackButtonItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setItem(COMMAND_BUILDER_SLOT, createCommandBuilderItem());
|
||||||
|
|
||||||
|
if (this.canNavigateHome()) {
|
||||||
|
this.setItem(HOME_BUTTON_SLOT, createHomeButtonItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pagination buttons
|
||||||
|
if (this.hasPrevPage()) {
|
||||||
|
this.setItem(PREV_PAGE_SLOT, createPrevPageItem());
|
||||||
|
}
|
||||||
|
if (this.hasNextPage()) {
|
||||||
|
this.setItem(NEXT_PAGE_SLOT, createNextPageItem());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasPrevPage() {
|
||||||
|
return this.currentPage > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasNextPage() {
|
||||||
|
int totalItems = this.getCurrentTotalItemCount();
|
||||||
|
int totalPages = Math.max(1, (totalItems + CONTENT_SLOTS.length - 1) / CONTENT_SLOTS.length);
|
||||||
|
return this.currentPage < totalPages - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCurrentTotalItemCount() {
|
||||||
|
if (this.isSelectingActionType) {
|
||||||
|
return ActionType.values().length;
|
||||||
|
}
|
||||||
|
if (this.selectedActionType == ActionType.ACTION_STOP) {
|
||||||
|
return this.bot.getActionSize();
|
||||||
|
}
|
||||||
|
if (this.currentNode == null) {
|
||||||
|
return GUI_ROOT_NODE_MAP.size();
|
||||||
|
}
|
||||||
|
Set<GuiNode> children = this.getChildrenOfCurrentNode();
|
||||||
|
return children != null ? children.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prevPage() {
|
||||||
|
if (this.hasPrevPage()) {
|
||||||
|
this.currentPage--;
|
||||||
|
this.redisplayCurrentViewWithoutReset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nextPage() {
|
||||||
|
if (this.hasNextPage()) {
|
||||||
|
this.currentPage++;
|
||||||
|
this.redisplayCurrentViewWithoutReset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrevPageSlot(int slot) {
|
||||||
|
return slot == PREV_PAGE_SLOT && this.hasPrevPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNextPageSlot(int slot) {
|
||||||
|
return slot == NEXT_PAGE_SLOT && this.hasNextPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-render the current view without resetting pagination state.
|
||||||
|
* Used for page navigation to preserve currentPage value.
|
||||||
|
*/
|
||||||
|
private void redisplayCurrentViewWithoutReset() {
|
||||||
|
this.clearContent();
|
||||||
|
this.fillBorder();
|
||||||
|
|
||||||
|
if (this.isSelectingActionType) {
|
||||||
|
this.renderActionTypes();
|
||||||
|
} else if (this.selectedActionType == ActionType.ACTION_STOP) {
|
||||||
|
this.renderBotActions();
|
||||||
|
} else if (this.currentNode != null) {
|
||||||
|
this.renderCurrentNodeChildren();
|
||||||
|
} else {
|
||||||
|
this.renderRootNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addNavigationButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ItemStack createPrevPageItem() {
|
||||||
|
ItemStack item = new ItemStack(Items.ARROW);
|
||||||
|
item.set(DataComponents.CUSTOM_NAME, Component.literal("§ePrevious Page"));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ItemStack createNextPageItem() {
|
||||||
|
ItemStack item = new ItemStack(Items.ARROW);
|
||||||
|
item.set(DataComponents.CUSTOM_NAME, Component.literal("§eNext Page"));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack createCommandBuilderItem() {
|
||||||
|
ItemStack item = new ItemStack(Items.BOOK);
|
||||||
|
|
||||||
|
// Build the complete command preview
|
||||||
|
String commandPreview = buildCommandPreview();
|
||||||
|
|
||||||
|
// Check if current node is runnable (confirmable)
|
||||||
|
boolean canRun = this.currentNode != null && this.currentNode.isConfirmable();
|
||||||
|
|
||||||
|
List<Component> loreLines = new ArrayList<>();
|
||||||
|
loreLines.add(Component.literal("§eCommand:"));
|
||||||
|
loreLines.add(Component.literal("§f" + commandPreview));
|
||||||
|
|
||||||
|
// Add run hint if the node is confirmable
|
||||||
|
if (canRun) {
|
||||||
|
loreLines.add(Component.literal("§6Click to execute"));
|
||||||
|
}
|
||||||
|
|
||||||
|
item.set(DataComponents.CUSTOM_NAME, Component.literal("§6Command Builder"));
|
||||||
|
item.set(DataComponents.LORE, new ItemLore(loreLines));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildCommandPreview() {
|
||||||
|
if (this.selectedActionType == null) {
|
||||||
|
return "Select an action type first";
|
||||||
|
}
|
||||||
|
|
||||||
|
// For STOP action type, show different preview
|
||||||
|
if (this.selectedActionType == ActionType.ACTION_STOP) {
|
||||||
|
int actionSize = this.bot.getActionSize();
|
||||||
|
if (actionSize == 0) {
|
||||||
|
return "No actions to stop";
|
||||||
|
}
|
||||||
|
return "Click an action to stop it (" + actionSize + " active)";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String actionPrefix = this.selectedActionType.getCommandActionPrefix();
|
||||||
|
String actionSuffix = this.selectedActionType.getCommandActionSuffix();
|
||||||
|
if (!actionSuffix.isEmpty()) {
|
||||||
|
actionSuffix = actionSuffix + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
String extra = actionPrefix + " " + this.bot.getName() + " " + actionSuffix;
|
||||||
|
|
||||||
|
// If we have a current node and it's a GuiRootNode, build the command
|
||||||
|
if (this.currentNode instanceof GuiRootNode rootNode) {
|
||||||
|
String command = rootNode.buildCommand(extra);
|
||||||
|
|
||||||
|
// Apply parameter limit based on ActionType
|
||||||
|
if (this.selectedActionType.getMaxAllowedParameters() == 0) {
|
||||||
|
command = actionPrefix + " " + this.bot.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return command;
|
||||||
|
} else if (!this.isSelectingActionType) {
|
||||||
|
// At root nodes level or selecting action type
|
||||||
|
return extra.trim() + " <command>";
|
||||||
|
} else {
|
||||||
|
return "Select a command node";
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "Error building command";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Set<GuiNode> getCurrentDisplayNodes() {
|
||||||
|
// If selecting action type, return null (handled separately)
|
||||||
|
if (this.isSelectingActionType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (this.currentNode == null) {
|
||||||
|
return new LinkedHashSet<>(GUI_ROOT_NODE_MAP.values());
|
||||||
|
}
|
||||||
|
return this.getChildrenOfCurrentNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when user selects an ActionType (START/STOP)
|
||||||
|
*/
|
||||||
|
public void selectActionType(ActionType actionType) {
|
||||||
|
this.selectedActionType = actionType;
|
||||||
|
this.isSelectingActionType = false;
|
||||||
|
|
||||||
|
// If STOP action type is selected, show current bot actions instead of root nodes
|
||||||
|
if (actionType == ActionType.ACTION_STOP) {
|
||||||
|
this.showCurrentBotActions();
|
||||||
|
} else {
|
||||||
|
this.showRootNodes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the current bot's scheduled actions for stopping
|
||||||
|
*/
|
||||||
|
public void showCurrentBotActions() {
|
||||||
|
this.clearContent();
|
||||||
|
this.fillBorder();
|
||||||
|
this.currentNode = null;
|
||||||
|
this.navigationStack.clear();
|
||||||
|
this.fromRootLevelStack.clear();
|
||||||
|
this.isSelectingActionType = false;
|
||||||
|
this.currentPage = 0;
|
||||||
|
|
||||||
|
this.renderBotActions();
|
||||||
|
this.addNavigationButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an ItemStack representing a bot action for display in the GUI
|
||||||
|
*/
|
||||||
|
private ItemStack createActionItem(BotAction<?> action, int index) {
|
||||||
|
// Use the same item model as registered in GuiRootNode (start action display)
|
||||||
|
AbstractBotAction<?> handle = ((CraftBotAction<?, ?>) action).getHandle();
|
||||||
|
GuiRootNode guiData = handle.getGuiData();
|
||||||
|
ItemStack item = guiData != null ? guiData.getItemStack() : new ItemStack(Items.PAPER);
|
||||||
|
String actionName = action.getName();
|
||||||
|
String actionHash = action.getUUID().toString();
|
||||||
|
|
||||||
|
item.set(DataComponents.CUSTOM_NAME, Component.literal("§c" + actionName));
|
||||||
|
|
||||||
|
// Store action hash in CUSTOM_DATA for later retrieval
|
||||||
|
CompoundTag customTag = new CompoundTag();
|
||||||
|
customTag.putString("action_hash", actionHash);
|
||||||
|
item.set(DataComponents.CUSTOM_DATA, CustomData.of(customTag));
|
||||||
|
|
||||||
|
List<Component> loreLines = new ArrayList<>();
|
||||||
|
CompoundTag nbt = new CompoundTag();
|
||||||
|
((CraftBotAction<?, ?>) action).getHandle().save(nbt);
|
||||||
|
nbt.forEach((key, tag) -> loreLines.add(Component.literal("§7" + key + ": §f" + tag)));
|
||||||
|
loreLines.add(Component.literal("§7Index: §f" + index));
|
||||||
|
loreLines.add(Component.literal("§7Hash: §f" + actionHash.substring(0, 8)));
|
||||||
|
loreLines.add(Component.literal("§6Click to stop this action"));
|
||||||
|
|
||||||
|
item.set(DataComponents.LORE, new ItemLore(loreLines));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the action hash (UUID string) at a specific slot (for STOP action type)
|
||||||
|
* Returns null if not found or not in STOP mode
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getActionHashAtSlot(int slot) {
|
||||||
|
if (this.selectedActionType != ActionType.ACTION_STOP) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the action hash directly from the ItemStack's CUSTOM_DATA
|
||||||
|
ItemStack item = this.getItem(slot);
|
||||||
|
if (item.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomData customData = item.get(DataComponents.CUSTOM_DATA);
|
||||||
|
if (customData == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundTag tag = customData.copyTag();
|
||||||
|
if (tag.contains("action_hash")) {
|
||||||
|
return tag.getString("action_hash").get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ActionType at a specific slot, accounting for pagination offset.
|
||||||
|
* Returns null if the slot is not a valid content slot or the index is out of bounds.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ActionType getActionTypeAtSlot(int slot) {
|
||||||
|
if (!this.isSelectingActionType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int contentIndex = -1;
|
||||||
|
for (int i = 0; i < CONTENT_SLOTS.length; i++) {
|
||||||
|
if (CONTENT_SLOTS[i] == slot) {
|
||||||
|
contentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (contentIndex == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionType[] actionTypes = ActionType.values();
|
||||||
|
int actualIndex = this.currentPage * CONTENT_SLOTS.length + contentIndex;
|
||||||
|
if (actualIndex >= 0 && actualIndex < actionTypes.length) {
|
||||||
|
return actionTypes[actualIndex];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently selected ActionType
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ActionType getSelectedActionType() {
|
||||||
|
return this.selectedActionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we're in action type selection mode
|
||||||
|
*/
|
||||||
|
public boolean isSelectingActionType() {
|
||||||
|
return this.isSelectingActionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canNavigateBack() {
|
||||||
|
return !this.navigationStack.isEmpty() || (!this.isSelectingActionType && this.selectedActionType != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canNavigateHome() {
|
||||||
|
return !this.isSelectingActionType && (this.currentNode != null || this.selectedActionType != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the command builder can be executed.
|
||||||
|
* Returns true if there is a current node and it is confirmable.
|
||||||
|
*/
|
||||||
|
public boolean canExecuteCommandBuilder() {
|
||||||
|
return this.currentNode != null && this.currentNode.isConfirmable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public GuiNode getCurrentNode() {
|
||||||
|
return this.currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current parameter count (number of selected command nodes).
|
||||||
|
* This equals the navigation stack size plus 1 if currentNode is not null.
|
||||||
|
*/
|
||||||
|
public int getCurrentParameterCount() {
|
||||||
|
return this.navigationStack.size() + (this.currentNode != null ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CraftBot getBot() {
|
||||||
|
return this.bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CraftPlayer getPlayer() {
|
||||||
|
return this.player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stillValid(@NotNull Player player) {
|
||||||
|
return this.player.getHandle() == player && this.bot.isValid();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
package fun.bm.lophine.bot;
|
||||||
|
|
||||||
|
import com.mojang.logging.LogUtils;
|
||||||
|
import fun.bm.lophine.bot.action.gui.ActionType;
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiNode;
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
|
||||||
|
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.inventory.ContainerInput;
|
||||||
|
import net.minecraft.world.inventory.MenuType;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftInventory;
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.leavesmc.leaves.entity.bot.CraftBot;
|
||||||
|
|
||||||
|
import java.rmi.UnexpectedException;
|
||||||
|
|
||||||
|
public class BotActionGuiMenu extends AbstractContainerMenu {
|
||||||
|
private final BotActionGuiContainer container;
|
||||||
|
private final CraftBot bot;
|
||||||
|
private final CraftPlayer player;
|
||||||
|
private CraftInventoryView view = null;
|
||||||
|
|
||||||
|
public BotActionGuiMenu(int containerId, Inventory inventory, BotActionGuiContainer container) {
|
||||||
|
super(MenuType.GENERIC_9x6, containerId);
|
||||||
|
this.container = container;
|
||||||
|
this.bot = container.getBot();
|
||||||
|
this.player = container.getPlayer();
|
||||||
|
|
||||||
|
for (int row = 0; row < 6; row++) {
|
||||||
|
for (int col = 0; col < 9; col++) {
|
||||||
|
this.addSlot(new Slot(container, col + row * 9, 8 + col * 18, 18 + row * 18) {
|
||||||
|
@Override
|
||||||
|
public boolean mayPickup(Player player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mayPlace(ItemStack stack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int row = 0; row < 3; row++) {
|
||||||
|
for (int col = 0; col < 9; col++) {
|
||||||
|
this.addSlot(new Slot(inventory, col + row * 9 + 9, 8 + col * 18, 140 + row * 18));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int col = 0; col < 9; col++) {
|
||||||
|
this.addSlot(new Slot(inventory, col, 8 + col * 18, 198));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public org.bukkit.inventory.InventoryView getBukkitView() {
|
||||||
|
if (this.view == null) {
|
||||||
|
CraftInventory inventory = new CraftInventory(this.container);
|
||||||
|
this.view = new CraftInventoryView(
|
||||||
|
this.player,
|
||||||
|
inventory,
|
||||||
|
this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stillValid(@NotNull Player player) {
|
||||||
|
return this.container.stillValid(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clicked(int slotIndex, int buttonNum, ContainerInput containerInput, Player player) {
|
||||||
|
if (slotIndex >= 0 && slotIndex < 54) {
|
||||||
|
if (this.container.isBackButtonSlot(slotIndex)) {
|
||||||
|
this.container.navigateBack();
|
||||||
|
this.refreshSlots();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.container.isHomeButtonSlot(slotIndex)) {
|
||||||
|
this.container.navigateHome();
|
||||||
|
this.refreshSlots();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pagination buttons
|
||||||
|
if (this.container.isPrevPageSlot(slotIndex)) {
|
||||||
|
this.container.prevPage();
|
||||||
|
this.refreshSlots();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.container.isNextPageSlot(slotIndex)) {
|
||||||
|
this.container.nextPage();
|
||||||
|
this.refreshSlots();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle command builder click
|
||||||
|
if (this.container.isCommandBuilderSlot(slotIndex) && this.container.canExecuteCommandBuilder()) {
|
||||||
|
this.executeCommandBuilder(player);
|
||||||
|
this.refreshSlots();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle ActionType selection (with pagination offset)
|
||||||
|
if (this.container.isSelectingActionType()) {
|
||||||
|
ActionType clickedType = this.container.getActionTypeAtSlot(slotIndex);
|
||||||
|
if (clickedType != null) {
|
||||||
|
this.container.selectActionType(clickedType);
|
||||||
|
this.refreshSlots();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle action stop click (when STOP action type is selected)
|
||||||
|
if (this.container.getSelectedActionType() == ActionType.ACTION_STOP) {
|
||||||
|
String actionHash = this.container.getActionHashAtSlot(slotIndex);
|
||||||
|
if (actionHash != null) {
|
||||||
|
this.stopActionByHash(actionHash, player);
|
||||||
|
this.refreshSlots();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiNode node = this.container.getGuiNodeAtSlot(slotIndex);
|
||||||
|
if (node != null) {
|
||||||
|
this.handleNodeClick(node, player);
|
||||||
|
this.refreshSlots();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.clicked(slotIndex, buttonNum, containerInput, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNodeClick(GuiNode node, Player player) {
|
||||||
|
if (node instanceof GuiRootNode rootNode) {
|
||||||
|
// Get the selected action type
|
||||||
|
ActionType actionType = this.container.getSelectedActionType();
|
||||||
|
if (actionType == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxAllowedParameters = actionType.getMaxAllowedParameters();
|
||||||
|
|
||||||
|
// If the node has children, check parameter limit before navigating
|
||||||
|
if (!rootNode.getChildren().isEmpty()) {
|
||||||
|
// Calculate current parameter count (navigation stack size + 1 for current node if exists)
|
||||||
|
int currentParamCount = this.container.getCurrentParameterCount();
|
||||||
|
|
||||||
|
// If adding this node would exceed the limit, execute command instead of navigating
|
||||||
|
if (currentParamCount + 1 > maxAllowedParameters) {
|
||||||
|
this.executeCommand(rootNode, actionType, player);
|
||||||
|
// Close GUI after START action execution
|
||||||
|
if (actionType == ActionType.ACTION_START && player instanceof ServerPlayer serverPlayer) {
|
||||||
|
serverPlayer.closeContainer();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.container.navigateToChild(rootNode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Execute command with t`he selected action type
|
||||||
|
this.executeCommand(rootNode, actionType, player);
|
||||||
|
// Close GUI after START action execution
|
||||||
|
if (actionType == ActionType.ACTION_START && player instanceof ServerPlayer serverPlayer) {
|
||||||
|
serverPlayer.closeContainer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeCommand(GuiRootNode node, ActionType actionType, Player player) {
|
||||||
|
try {
|
||||||
|
String actionPrefix = actionType.getCommandActionPrefix();
|
||||||
|
String actionSuffix = actionType.getCommandActionSuffix();
|
||||||
|
if (!actionSuffix.isEmpty()) {
|
||||||
|
actionSuffix = actionSuffix + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
String extra = actionPrefix + " " + bot.getName() + " " + actionSuffix;
|
||||||
|
String command = node.buildCommand(extra);
|
||||||
|
|
||||||
|
// Apply parameter limit based on ActionType
|
||||||
|
if (actionType.getMaxAllowedParameters() == 0) {
|
||||||
|
// For actions like STOP that don't allow parameters, trim to just "action botName"
|
||||||
|
command = actionPrefix + " " + bot.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player instanceof ServerPlayer serverPlayer) {
|
||||||
|
MinecraftServer.getServer().getCommands().performPrefixedCommand(
|
||||||
|
serverPlayer.createCommandSourceStack(),
|
||||||
|
command
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.getLogger().warn("Error executing command: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the command from the command builder (book item).
|
||||||
|
* Uses the current node and selected action type.
|
||||||
|
*/
|
||||||
|
private void executeCommandBuilder(Player player) {
|
||||||
|
GuiNode currentNode = this.container.getCurrentNode();
|
||||||
|
ActionType actionType = this.container.getSelectedActionType();
|
||||||
|
|
||||||
|
if (currentNode instanceof GuiRootNode rootNode && actionType != null) {
|
||||||
|
this.executeCommand(rootNode, actionType, player);
|
||||||
|
// Close GUI after START action execution
|
||||||
|
if (actionType != ActionType.ACTION_STOP && player instanceof ServerPlayer serverPlayer) {
|
||||||
|
serverPlayer.closeContainer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop a bot action by its hash (UUID string)
|
||||||
|
*/
|
||||||
|
private void stopActionByHash(String actionHash, Player player) {
|
||||||
|
try {
|
||||||
|
if (player instanceof ServerPlayer serverPlayer) {
|
||||||
|
String command = getStopActionCommand(actionHash);
|
||||||
|
MinecraftServer.getServer().getCommands().performPrefixedCommand(
|
||||||
|
serverPlayer.createCommandSourceStack(),
|
||||||
|
command
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.getLogger().warn("Error stopping action with hash {}: ", actionHash, e);
|
||||||
|
}
|
||||||
|
// Always refresh to show updated action list after stop attempt
|
||||||
|
this.container.showCurrentBotActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStopActionCommand(String actionHash) throws UnexpectedException {
|
||||||
|
boolean botCommand = FakeplayerConfig.enable;
|
||||||
|
boolean playerCommand = FakePlayerCompatConfig.commandPlayer;
|
||||||
|
String command;
|
||||||
|
if (botCommand) {
|
||||||
|
command = "bot ";
|
||||||
|
} else if (playerCommand) {
|
||||||
|
command = "player ";
|
||||||
|
} else {
|
||||||
|
throw new UnexpectedException("Unable to build String from commandNode.");
|
||||||
|
}
|
||||||
|
command = command + "action " + this.bot.getName() + " stop " + actionHash;
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshSlots() {
|
||||||
|
for (int i = 0; i < 54; i++) {
|
||||||
|
Slot slot = this.slots.get(i);
|
||||||
|
ItemStack item = this.container.getItem(i);
|
||||||
|
slot.set(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack quickMoveStack(Player player, int index) {
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BotActionGuiContainer getContainer() {
|
||||||
|
return this.container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package fun.bm.lophine.bot.action.gui;
|
||||||
|
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.item.component.ItemLore;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public enum ActionType {
|
||||||
|
ACTION_START("Start", "Start a action", Items.DYE.lime(), "action", "start"),
|
||||||
|
ACTION_STOP("Stop", "Stop a action or see this bot scheduled tasks", Items.DYE.red(), "action", "stop", 0);
|
||||||
|
|
||||||
|
private final String displayName;
|
||||||
|
private final String description;
|
||||||
|
private final Item item;
|
||||||
|
private final String commandActionPrefix;
|
||||||
|
private final String commandActionSuffix;
|
||||||
|
private final int maxAllowedParameters;
|
||||||
|
|
||||||
|
ActionType(String displayName, String description, Item item, String commandActionPrefix) {
|
||||||
|
this(displayName, description, item, commandActionPrefix, "", Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionType(String displayName, String description, Item item, String commandActionPrefix, String commandActionSuffix) {
|
||||||
|
this(displayName, description, item, commandActionPrefix, commandActionSuffix, Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionType(String displayName, String description, Item item, String commandActionPrefix, String commandActionSuffix, int maxAllowedParameters) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.description = description;
|
||||||
|
this.item = item;
|
||||||
|
this.commandActionPrefix = commandActionPrefix;
|
||||||
|
this.commandActionSuffix = commandActionSuffix;
|
||||||
|
this.maxAllowedParameters = maxAllowedParameters;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return this.displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item getItem() {
|
||||||
|
return this.item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommandActionPrefix() {
|
||||||
|
return this.commandActionPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommandActionSuffix() {
|
||||||
|
return commandActionSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiNode toConfirmNode(GuiRootNode targetNode) {
|
||||||
|
return new ActionConfirmNode(this.displayName, this.description, this.item, targetNode, this.commandActionPrefix, this.maxAllowedParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxAllowedParameters() {
|
||||||
|
return maxAllowedParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special node used in the action type confirmation UI.
|
||||||
|
* It holds a reference to the target GuiRootNode and the selected action string.
|
||||||
|
*/
|
||||||
|
public static class ActionConfirmNode extends GuiNode {
|
||||||
|
private final GuiRootNode targetNode;
|
||||||
|
private final String action;
|
||||||
|
private final int maxAllowedParameters;
|
||||||
|
|
||||||
|
public ActionConfirmNode(String name, String description, Item item, GuiRootNode targetNode, String action, int maxAllowedParameters) {
|
||||||
|
super(name, description, item);
|
||||||
|
this.targetNode = targetNode;
|
||||||
|
this.action = action;
|
||||||
|
this.maxAllowedParameters = maxAllowedParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiRootNode getTargetNode() {
|
||||||
|
return this.targetNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAction() {
|
||||||
|
return this.action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxAllowedParameters() {
|
||||||
|
return this.maxAllowedParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack getItemStack() {
|
||||||
|
ItemStack itemStack = super.getItemStack();
|
||||||
|
|
||||||
|
// Add parameter limit info to lore
|
||||||
|
List<Component> loreLines = new ArrayList<>();
|
||||||
|
if (this.description != null && !this.description.isEmpty()) {
|
||||||
|
loreLines.add(Component.literal(this.description));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loreLines.isEmpty()) {
|
||||||
|
itemStack.set(DataComponents.LORE, new ItemLore(loreLines));
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package fun.bm.lophine.bot.action.gui;
|
||||||
|
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.item.component.ItemLore;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GuiNode {
|
||||||
|
protected final String name;
|
||||||
|
protected final String description;
|
||||||
|
protected final Item item;
|
||||||
|
protected final boolean confirmable;
|
||||||
|
|
||||||
|
private static final Item defaultItem = Items.PAPER;
|
||||||
|
|
||||||
|
public GuiNode(String name, String description, Item item, boolean confirmable) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
this.item = item;
|
||||||
|
this.confirmable = confirmable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiNode(String name, String description, Item item) {
|
||||||
|
this(name, description, item, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConfirmable() {
|
||||||
|
return this.confirmable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack getItemStack() {
|
||||||
|
ItemStack itemStack = new ItemStack(this.item == null ? defaultItem : this.item).copy();
|
||||||
|
itemStack.set(DataComponents.CUSTOM_NAME, Component.literal(this.name));
|
||||||
|
if (this.description != null && !this.description.isEmpty()) {
|
||||||
|
ItemLore lore = new ItemLore(List.of(Component.literal(this.description)));
|
||||||
|
itemStack.set(DataComponents.LORE, lore);
|
||||||
|
}
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package fun.bm.lophine.bot.action.gui;
|
||||||
|
|
||||||
|
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
|
||||||
|
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
|
||||||
|
import java.rmi.UnexpectedException;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class GuiRootNode extends GuiNode {
|
||||||
|
protected final Set<GuiNode> children;
|
||||||
|
protected final String commandNode;
|
||||||
|
|
||||||
|
public GuiRootNode(String name, String description, Item item, String commandNode) {
|
||||||
|
this(name, description, item, commandNode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiRootNode(String name, String description, Item item, String commandNode, boolean confirmable) {
|
||||||
|
this(name, description, item, new LinkedHashSet<>(), commandNode, confirmable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiRootNode(String name, String description, Item item, Set<GuiNode> children, String commandNode) {
|
||||||
|
this(name, description, item, children, commandNode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiRootNode(String name, String description, Item item, Set<GuiNode> children, String commandNode, boolean confirmable) {
|
||||||
|
super(name, description, item, confirmable);
|
||||||
|
this.children = children;
|
||||||
|
this.commandNode = commandNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void child(GuiNode... node) {
|
||||||
|
this.children.addAll(List.of(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public final void child(Supplier<? extends GuiNode>... node) {
|
||||||
|
this.children.addAll(Stream.of(node).map(Supplier::get).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<GuiNode> getChildren() {
|
||||||
|
return this.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<GuiNode> getAllFurthestChildren() {
|
||||||
|
if (this.children.isEmpty()) {
|
||||||
|
Set<GuiNode> result = new LinkedHashSet<>();
|
||||||
|
result.add(this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<GuiNode> furthestChildren = new LinkedHashSet<>();
|
||||||
|
for (GuiNode child : this.children) {
|
||||||
|
furthestChildren.addAll(((GuiRootNode) child).getAllFurthestChildren());
|
||||||
|
}
|
||||||
|
return furthestChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommandNode() {
|
||||||
|
return this.commandNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String buildCommand(String extra) throws UnexpectedException {
|
||||||
|
boolean botCommand = FakeplayerConfig.enable;
|
||||||
|
boolean playerCommand = FakePlayerCompatConfig.commandPlayer;
|
||||||
|
if (botCommand) {
|
||||||
|
return "bot " + extra + this.getCommandNode();
|
||||||
|
}
|
||||||
|
if (playerCommand) {
|
||||||
|
return "player " + extra + this.getCommandNode();
|
||||||
|
}
|
||||||
|
throw new UnexpectedException("Unable to build String from commandNode.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package fun.bm.lophine.bot.action.gui;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
|
||||||
|
import java.rmi.UnexpectedException;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class GuiSubNode extends GuiRootNode {
|
||||||
|
protected final GuiNode parent;
|
||||||
|
|
||||||
|
public GuiSubNode(String name, String description, Item item, GuiNode parent, Set<GuiNode> children, String commandNode) {
|
||||||
|
this(name, description, item, parent, children, commandNode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiSubNode(String name, String description, Item item, GuiNode parent, Set<GuiNode> children, String commandNode, boolean confirmable) {
|
||||||
|
super(name, description, item, children, commandNode, confirmable);
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiSubNode(String name, String description, Item item, GuiNode parent, String commandNode) {
|
||||||
|
this(name, description, item, parent, commandNode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiSubNode(String name, String description, Item item, GuiNode parent, String commandNode, boolean confirmable) {
|
||||||
|
this(name, description, item, parent, new LinkedHashSet<>(), commandNode, confirmable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuiNode getParent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String buildCommand(String extra) throws UnexpectedException {
|
||||||
|
return ((GuiRootNode) parent).buildCommand(extra) + " " + getCommandNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -40,6 +40,11 @@ public class FakeplayerConfig implements IConfigModule {
|
|||||||
Regeneration amount for fakeplayers""")
|
Regeneration amount for fakeplayers""")
|
||||||
public static double regenAmount = 0.0;
|
public static double regenAmount = 0.0;
|
||||||
|
|
||||||
|
@ConfigInfo(name = "open-action-gui", comments = """
|
||||||
|
Allow opening fakeplayer action gui,
|
||||||
|
need sneak to open if you enabled inventory open gui""")
|
||||||
|
public static boolean canOpenActionGui = false;
|
||||||
|
|
||||||
@ConfigInfo(name = "use-action", comments = """
|
@ConfigInfo(name = "use-action", comments = """
|
||||||
Allow fakeplayers to use actions""")
|
Allow fakeplayers to use actions""")
|
||||||
public static boolean canUseAction = true;
|
public static boolean canUseAction = true;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ package org.leavesmc.leaves.bot;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import fun.bm.lophine.LophineLogger;
|
import fun.bm.lophine.LophineLogger;
|
||||||
|
import fun.bm.lophine.bot.BotActionGuiContainer;
|
||||||
|
import fun.bm.lophine.bot.BotActionGuiMenu;
|
||||||
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
|
import fun.bm.lophine.carpet.config.modules.FakePlayerCompatConfig;
|
||||||
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
|
import fun.bm.lophine.config.modules.function.FakeplayerConfig;
|
||||||
import io.papermc.paper.adventure.PaperAdventure;
|
import io.papermc.paper.adventure.PaperAdventure;
|
||||||
@@ -357,15 +359,28 @@ public class ServerBot extends ServerPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand, @NotNull net.minecraft.world.phys.Vec3 location) { // Leaves - Paper 26.1: Entity#interact now takes Vec3
|
public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand, @NotNull net.minecraft.world.phys.Vec3 location) {
|
||||||
if (FakePlayerCompatConfig.openFakePlayerInventory) {
|
|
||||||
if (player instanceof ServerPlayer player1 && player.getMainHandItem().isEmpty()) {
|
if (player instanceof ServerPlayer player1 && player.getMainHandItem().isEmpty()) {
|
||||||
|
boolean isSneaking = player.isShiftKeyDown();
|
||||||
|
boolean enabled1Only = FakePlayerCompatConfig.openFakePlayerInventory ^ FakeplayerConfig.canOpenActionGui;
|
||||||
|
boolean openInventory = enabled1Only ? FakePlayerCompatConfig.openFakePlayerInventory : FakePlayerCompatConfig.openFakePlayerInventory && !isSneaking;
|
||||||
|
boolean openActionGui = enabled1Only ? FakeplayerConfig.canOpenActionGui : FakeplayerConfig.canOpenActionGui && isSneaking;
|
||||||
|
|
||||||
|
if (openInventory) {
|
||||||
BotInventoryOpenEvent event = new BotInventoryOpenEvent(this.getBukkitEntity(), player1.getBukkitEntity());
|
BotInventoryOpenEvent event = new BotInventoryOpenEvent(this.getBukkitEntity(), player1.getBukkitEntity());
|
||||||
getServer().server.getPluginManager().callEvent(event);
|
getServer().server.getPluginManager().callEvent(event);
|
||||||
if (!event.isCancelled()) {
|
if (!event.isCancelled()) {
|
||||||
player.openMenu(new SimpleMenuProvider((i, inventory, p) -> ChestMenu.sixRows(i, inventory, this.container), this.getDisplayName()));
|
player.openMenu(new SimpleMenuProvider((i, inventory, p) -> ChestMenu.sixRows(i, inventory, this.container), this.getDisplayName()));
|
||||||
return InteractionResult.SUCCESS;
|
return InteractionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
} else if (openActionGui) {
|
||||||
|
BotActionGuiOpenEvent event = new BotActionGuiOpenEvent(this.getBukkitEntity(), player1.getBukkitEntity());
|
||||||
|
getServer().server.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
BotActionGuiContainer container = new BotActionGuiContainer(this.getBukkitEntity(), player1.getBukkitEntity());
|
||||||
|
player.openMenu(new SimpleMenuProvider((i, inventory, p) -> new BotActionGuiMenu(i, inventory, container), this.getDisplayName()));
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.interact(player, hand, location);
|
return super.interact(player, hand, location);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent;
|
package org.leavesmc.leaves.bot.agent;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.BotActionGuiContainer;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -59,6 +60,9 @@ public class Actions {
|
|||||||
if (!actionsByName.containsKey(action.getName())) {
|
if (!actionsByName.containsKey(action.getName())) {
|
||||||
actionsByName.put(action.getName(), action);
|
actionsByName.put(action.getName(), action);
|
||||||
actionsByClass.put(type, action);
|
actionsByClass.put(type, action);
|
||||||
|
if (action.getGuiData() != null) {
|
||||||
|
BotActionGuiContainer.registerGuiRootNode(action.getGuiData());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -70,6 +74,8 @@ public class Actions {
|
|||||||
|
|
||||||
public static boolean unregister(@NotNull String name) {
|
public static boolean unregister(@NotNull String name) {
|
||||||
AbstractBotAction<?> action = actionsByName.remove(name);
|
AbstractBotAction<?> action = actionsByName.remove(name);
|
||||||
|
BotActionGuiContainer.unregisterGuiRootNode(name);
|
||||||
|
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
actionsByClass.remove(action.getClass());
|
actionsByClass.remove(action.getClass());
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+8
@@ -20,10 +20,12 @@ package org.leavesmc.leaves.bot.agent.actions;
|
|||||||
import com.mojang.brigadier.arguments.ArgumentType;
|
import com.mojang.brigadier.arguments.ArgumentType;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import fun.bm.lophine.LophineLogger;
|
import fun.bm.lophine.LophineLogger;
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
import net.minecraft.core.UUIDUtil;
|
import net.minecraft.core.UUIDUtil;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
import org.leavesmc.leaves.bot.agent.ExtraData;
|
import org.leavesmc.leaves.bot.agent.ExtraData;
|
||||||
import org.leavesmc.leaves.command.CommandContext;
|
import org.leavesmc.leaves.command.CommandContext;
|
||||||
@@ -57,6 +59,8 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
|
|||||||
private Consumer<E> onSuccess;
|
private Consumer<E> onSuccess;
|
||||||
private Consumer<E> onStop;
|
private Consumer<E> onStop;
|
||||||
|
|
||||||
|
protected GuiRootNode guiData;
|
||||||
|
|
||||||
public AbstractBotAction(String name, Supplier<E> creator) {
|
public AbstractBotAction(String name, Supplier<E> creator) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.uuid = UUID.randomUUID();
|
this.uuid = UUID.randomUUID();
|
||||||
@@ -261,4 +265,8 @@ public abstract class AbstractBotAction<E extends AbstractBotAction<E>> {
|
|||||||
public void setOnStop(Consumer<E> onStop) {
|
public void setOnStop(Consumer<E> onStop) {
|
||||||
this.onStop = onStop;
|
this.onStop = onStop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable GuiRootNode getGuiData() {
|
||||||
|
return this.guiData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-3
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiSubNode;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.agent.ExtraData;
|
import org.leavesmc.leaves.bot.agent.ExtraData;
|
||||||
@@ -29,13 +31,37 @@ import static org.leavesmc.leaves.command.ArgumentNode.ArgumentSuggestions.strin
|
|||||||
|
|
||||||
public abstract class AbstractTimerBotAction<E extends AbstractTimerBotAction<E>> extends AbstractBotAction<E> {
|
public abstract class AbstractTimerBotAction<E extends AbstractTimerBotAction<E>> extends AbstractBotAction<E> {
|
||||||
|
|
||||||
public AbstractTimerBotAction(String name, Supplier<E> creator) {
|
public AbstractTimerBotAction(String name, Supplier<E> creator, GuiRootNode guiData) {
|
||||||
super(name, creator);
|
super(name, creator);
|
||||||
this.addArgument("delay", integer(0)).suggests(strings("0", "5", "10", "20")).setOptional(true);
|
String[] delaySuggestions = {"0", "5", "10", "20"};
|
||||||
this.addArgument("interval", integer(0)).suggests(strings("20", "0", "5", "10")).setOptional(true);
|
String[] intervalSuggestions = {"20", "0", "5", "10"};
|
||||||
|
this.addArgument("delay", integer(0)).suggests(strings(delaySuggestions)).setOptional(true);
|
||||||
|
this.addArgument("interval", integer(0)).suggests(strings(intervalSuggestions)).setOptional(true);
|
||||||
this.addArgument("do_number", integer(-1))
|
this.addArgument("do_number", integer(-1))
|
||||||
.suggests(((context, builder) -> builder.suggest("-1", Component.literal("do infinite times"))))
|
.suggests(((context, builder) -> builder.suggest("-1", Component.literal("do infinite times"))))
|
||||||
.setOptional(true);
|
.setOptional(true);
|
||||||
|
|
||||||
|
if (guiData == null) return;
|
||||||
|
|
||||||
|
this.guiData = guiData;
|
||||||
|
GuiSubNode[] node1 = new GuiSubNode[delaySuggestions.length];
|
||||||
|
for (int i = 0; i < delaySuggestions.length; i++) {
|
||||||
|
node1[i] = new GuiSubNode(delaySuggestions[i], "Delay for a few ticks", null, guiData, delaySuggestions[i]);
|
||||||
|
guiData.child(node1[i]);
|
||||||
|
}
|
||||||
|
GuiSubNode[] node2 = new GuiSubNode[delaySuggestions.length * intervalSuggestions.length];
|
||||||
|
for (int i = 0; i < delaySuggestions.length; i++) {
|
||||||
|
for (int j = 0; j < intervalSuggestions.length; j++) {
|
||||||
|
int id = i * intervalSuggestions.length + j;
|
||||||
|
node2[id] = new GuiSubNode(intervalSuggestions[j], "Interval for a few ticks", null, node1[i], intervalSuggestions[j]);
|
||||||
|
node1[i].child(node2[id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (GuiSubNode node : node2) {
|
||||||
|
GuiSubNode subNode = new GuiSubNode("-1", "Number of times to do", null, node, "-1");
|
||||||
|
node.child(subNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+16
-2
@@ -17,6 +17,9 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiNode;
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiSubNode;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
@@ -35,8 +38,8 @@ public abstract class AbstractUseBotAction<T extends AbstractUseBotAction<T>> ex
|
|||||||
private int alreadyUsedTick = 0;
|
private int alreadyUsedTick = 0;
|
||||||
private int useItemRemainingTicks = 0;
|
private int useItemRemainingTicks = 0;
|
||||||
|
|
||||||
public AbstractUseBotAction(String name, Supplier<T> supplier) {
|
public AbstractUseBotAction(String name, Supplier<T> supplier, GuiRootNode guiData) {
|
||||||
super(name, supplier);
|
super(name, supplier, guiData);
|
||||||
this.addArgument("use_timeout", integer(-1))
|
this.addArgument("use_timeout", integer(-1))
|
||||||
.suggests((context, builder) -> {
|
.suggests((context, builder) -> {
|
||||||
builder.suggest("-1", Component.literal("no use timeout"));
|
builder.suggest("-1", Component.literal("no use timeout"));
|
||||||
@@ -44,6 +47,17 @@ public abstract class AbstractUseBotAction<T extends AbstractUseBotAction<T>> ex
|
|||||||
builder.suggest("10", Component.literal("minimum trident shoot time"));
|
builder.suggest("10", Component.literal("minimum trident shoot time"));
|
||||||
})
|
})
|
||||||
.setOptional(true);
|
.setOptional(true);
|
||||||
|
|
||||||
|
if (guiData == null) return;
|
||||||
|
|
||||||
|
for (GuiNode node : guiData.getAllFurthestChildren()) {
|
||||||
|
GuiSubNode node0 = (GuiSubNode) node;
|
||||||
|
node0.child(
|
||||||
|
new GuiSubNode("-1", "no use timeout", null, node0, "-1"),
|
||||||
|
new GuiSubNode("3", "minimum bow shoot time", null, node0, "3"),
|
||||||
|
new GuiSubNode("10", "minimum trident shoot time", null, node0, "10")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
-1
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.phys.EntityHitResult;
|
import net.minecraft.world.phys.EntityHitResult;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
@@ -25,7 +27,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftAttackAction;
|
|||||||
public class ServerAttackAction extends AbstractTimerBotAction<ServerAttackAction> {
|
public class ServerAttackAction extends AbstractTimerBotAction<ServerAttackAction> {
|
||||||
|
|
||||||
public ServerAttackAction() {
|
public ServerAttackAction() {
|
||||||
super("attack", ServerAttackAction::new);
|
GuiRootNode guiData = new GuiRootNode("Attack", "Attack an entity", Items.DIAMOND_SWORD, "attack");
|
||||||
|
super("attack", ServerAttackAction::new, guiData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
-1
@@ -17,10 +17,12 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.entity.EquipmentSlot;
|
import net.minecraft.world.entity.EquipmentSlot;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@@ -33,7 +35,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftBreakBlockAction;
|
|||||||
public class ServerBreakBlockAction extends AbstractTimerBotAction<ServerBreakBlockAction> {
|
public class ServerBreakBlockAction extends AbstractTimerBotAction<ServerBreakBlockAction> {
|
||||||
|
|
||||||
public ServerBreakBlockAction() {
|
public ServerBreakBlockAction() {
|
||||||
super("break", ServerBreakBlockAction::new);
|
GuiRootNode guiRootNode = new GuiRootNode("Break", "Break a block", Items.DIAMOND_PICKAXE, "break");
|
||||||
|
super("break", ServerBreakBlockAction::new, guiRootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ItemStack lastItem = null;
|
private ItemStack lastItem = null;
|
||||||
|
|||||||
+4
-1
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
import org.leavesmc.leaves.entity.bot.actions.CraftDropAction;
|
import org.leavesmc.leaves.entity.bot.actions.CraftDropAction;
|
||||||
@@ -24,7 +26,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftDropAction;
|
|||||||
public class ServerDropAction extends AbstractTimerBotAction<ServerDropAction> {
|
public class ServerDropAction extends AbstractTimerBotAction<ServerDropAction> {
|
||||||
|
|
||||||
public ServerDropAction() {
|
public ServerDropAction() {
|
||||||
super("drop", ServerDropAction::new);
|
GuiRootNode guiRootNode = new GuiRootNode("Drop", "Drop all items", Items.BARRIER, "drop");
|
||||||
|
super("drop", ServerDropAction::new, guiRootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
-1
@@ -17,11 +17,13 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.entity.projectile.FishingHook;
|
import net.minecraft.world.entity.projectile.FishingHook;
|
||||||
import net.minecraft.world.item.FishingRodItem;
|
import net.minecraft.world.item.FishingRodItem;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
import org.leavesmc.leaves.entity.bot.actions.CraftFishAction;
|
import org.leavesmc.leaves.entity.bot.actions.CraftFishAction;
|
||||||
@@ -29,7 +31,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftFishAction;
|
|||||||
public class ServerFishAction extends AbstractTimerBotAction<ServerFishAction> {
|
public class ServerFishAction extends AbstractTimerBotAction<ServerFishAction> {
|
||||||
|
|
||||||
public ServerFishAction() {
|
public ServerFishAction() {
|
||||||
super("fish", ServerFishAction::new);
|
GuiRootNode guiRootNode = new GuiRootNode("Fish", "Fish", Items.FISHING_ROD, "fish");
|
||||||
|
super("fish", ServerFishAction::new, guiRootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int CATCH_ENTITY_DELAY = 20;
|
private static final int CATCH_ENTITY_DELAY = 20;
|
||||||
|
|||||||
+4
-1
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
import org.leavesmc.leaves.entity.bot.actions.CraftJumpAction;
|
import org.leavesmc.leaves.entity.bot.actions.CraftJumpAction;
|
||||||
@@ -24,7 +26,8 @@ import org.leavesmc.leaves.entity.bot.actions.CraftJumpAction;
|
|||||||
public class ServerJumpAction extends AbstractTimerBotAction<ServerJumpAction> {
|
public class ServerJumpAction extends AbstractTimerBotAction<ServerJumpAction> {
|
||||||
|
|
||||||
public ServerJumpAction() {
|
public ServerJumpAction() {
|
||||||
super("jump", ServerJumpAction::new);
|
GuiRootNode guiRootNode = new GuiRootNode("Jump", "Jump", Items.ELYTRA, "jump");
|
||||||
|
super("jump", ServerJumpAction::new, guiRootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.entity.CraftVehicle;
|
import org.bukkit.craftbukkit.entity.CraftVehicle;
|
||||||
import org.bukkit.entity.Vehicle;
|
import org.bukkit.entity.Vehicle;
|
||||||
@@ -31,6 +33,8 @@ public class ServerMountAction extends AbstractBotAction<ServerMountAction> {
|
|||||||
|
|
||||||
public ServerMountAction() {
|
public ServerMountAction() {
|
||||||
super("mount", ServerMountAction::new);
|
super("mount", ServerMountAction::new);
|
||||||
|
|
||||||
|
this.guiData = new GuiRootNode("Mount", "Mount", Items.SADDLE, "mount");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+7
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
import org.leavesmc.leaves.bot.agent.ExtraData;
|
import org.leavesmc.leaves.bot.agent.ExtraData;
|
||||||
@@ -32,6 +34,11 @@ public class ServerMoveAction extends AbstractStateBotAction<ServerMoveAction> {
|
|||||||
public ServerMoveAction() {
|
public ServerMoveAction() {
|
||||||
super("move", ServerMoveAction::new);
|
super("move", ServerMoveAction::new);
|
||||||
this.addArgument("direction", EnumArgumentType.fromEnum(MoveDirection.class));
|
this.addArgument("direction", EnumArgumentType.fromEnum(MoveDirection.class));
|
||||||
|
|
||||||
|
this.guiData = new GuiRootNode("Move", "Move", null, "move", false);
|
||||||
|
for (MoveDirection direction : MoveDirection.values()) {
|
||||||
|
this.guiData.child(new GuiRootNode(direction.name, direction.name, Items.LEATHER_BOOTS, "move " + direction.name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+3
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
import org.leavesmc.leaves.entity.bot.actions.CraftSneakAction;
|
import org.leavesmc.leaves.entity.bot.actions.CraftSneakAction;
|
||||||
@@ -26,6 +27,8 @@ public class ServerSneakAction extends AbstractStateBotAction<ServerSneakAction>
|
|||||||
|
|
||||||
public ServerSneakAction() {
|
public ServerSneakAction() {
|
||||||
super("sneak", ServerSneakAction::new);
|
super("sneak", ServerSneakAction::new);
|
||||||
|
|
||||||
|
this.guiData = new GuiRootNode("Sneak", "Sneak", null, "sneak");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
@@ -17,8 +17,10 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
import org.leavesmc.leaves.entity.bot.actions.CraftSwapAction;
|
import org.leavesmc.leaves.entity.bot.actions.CraftSwapAction;
|
||||||
@@ -27,6 +29,8 @@ public class ServerSwapAction extends AbstractBotAction<ServerSwapAction> {
|
|||||||
|
|
||||||
public ServerSwapAction() {
|
public ServerSwapAction() {
|
||||||
super("swap", ServerSwapAction::new);
|
super("swap", ServerSwapAction::new);
|
||||||
|
|
||||||
|
this.guiData = new GuiRootNode("Swap", "Swap", Items.SHIELD, "swap");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.leavesmc.leaves.bot.ServerBot;
|
import org.leavesmc.leaves.bot.ServerBot;
|
||||||
@@ -26,6 +28,8 @@ public class ServerSwimAction extends AbstractStateBotAction<ServerSwimAction> {
|
|||||||
|
|
||||||
public ServerSwimAction() {
|
public ServerSwimAction() {
|
||||||
super("swim", ServerSwimAction::new);
|
super("swim", ServerSwimAction::new);
|
||||||
|
|
||||||
|
this.guiData = new GuiRootNode("Swim", "Swim", Items.WATER_BUCKET, "swim");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ import org.leavesmc.leaves.entity.bot.actions.CraftUseItemAction;
|
|||||||
public class ServerUseItemAction extends AbstractUseBotAction<ServerUseItemAction> {
|
public class ServerUseItemAction extends AbstractUseBotAction<ServerUseItemAction> {
|
||||||
|
|
||||||
public ServerUseItemAction() {
|
public ServerUseItemAction() {
|
||||||
super("use", ServerUseItemAction::new);
|
super("use", ServerUseItemAction::new, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
-1
@@ -17,10 +17,12 @@
|
|||||||
|
|
||||||
package org.leavesmc.leaves.bot.agent.actions;
|
package org.leavesmc.leaves.bot.agent.actions;
|
||||||
|
|
||||||
|
import fun.bm.lophine.bot.action.gui.GuiRootNode;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.EntityHitResult;
|
import net.minecraft.world.phys.EntityHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
@@ -37,7 +39,8 @@ import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemToAction.useIte
|
|||||||
public class ServerUseItemAutoAction extends AbstractUseBotAction<ServerUseItemAutoAction> {
|
public class ServerUseItemAutoAction extends AbstractUseBotAction<ServerUseItemAutoAction> {
|
||||||
|
|
||||||
public ServerUseItemAutoAction() {
|
public ServerUseItemAutoAction() {
|
||||||
super("use_auto", ServerUseItemAutoAction::new);
|
GuiRootNode guiRootNode = new GuiRootNode("Use", "Use Item", Items.BOW, "use_auto");
|
||||||
|
super("use_auto", ServerUseItemAutoAction::new, guiRootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemAction.useItem;
|
|||||||
public class ServerUseItemOffhandAction extends AbstractUseBotAction<ServerUseItemOffhandAction> {
|
public class ServerUseItemOffhandAction extends AbstractUseBotAction<ServerUseItemOffhandAction> {
|
||||||
|
|
||||||
public ServerUseItemOffhandAction() {
|
public ServerUseItemOffhandAction() {
|
||||||
super("use_offhand", ServerUseItemOffhandAction::new);
|
super("use_offhand", ServerUseItemOffhandAction::new, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ import org.leavesmc.leaves.entity.bot.actions.CraftUseItemOnAction;
|
|||||||
public class ServerUseItemOnAction extends AbstractUseBotAction<ServerUseItemOnAction> {
|
public class ServerUseItemOnAction extends AbstractUseBotAction<ServerUseItemOnAction> {
|
||||||
|
|
||||||
public ServerUseItemOnAction() {
|
public ServerUseItemOnAction() {
|
||||||
super("use_on", ServerUseItemOnAction::new);
|
super("use_on", ServerUseItemOnAction::new, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemOnAction.useIte
|
|||||||
public class ServerUseItemOnOffhandAction extends AbstractUseBotAction<ServerUseItemOnOffhandAction> {
|
public class ServerUseItemOnOffhandAction extends AbstractUseBotAction<ServerUseItemOnOffhandAction> {
|
||||||
|
|
||||||
public ServerUseItemOnOffhandAction() {
|
public ServerUseItemOnOffhandAction() {
|
||||||
super("use_on_offhand", ServerUseItemOnOffhandAction::new);
|
super("use_on_offhand", ServerUseItemOnOffhandAction::new, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@ import org.leavesmc.leaves.entity.bot.actions.CraftUseItemToAction;
|
|||||||
public class ServerUseItemToAction extends AbstractUseBotAction<ServerUseItemToAction> {
|
public class ServerUseItemToAction extends AbstractUseBotAction<ServerUseItemToAction> {
|
||||||
|
|
||||||
public ServerUseItemToAction() {
|
public ServerUseItemToAction() {
|
||||||
super("use_to", ServerUseItemToAction::new);
|
super("use_to", ServerUseItemToAction::new, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ import static org.leavesmc.leaves.bot.agent.actions.ServerUseItemToAction.useIte
|
|||||||
public class ServerUseItemToOffhandAction extends AbstractUseBotAction<ServerUseItemToOffhandAction> {
|
public class ServerUseItemToOffhandAction extends AbstractUseBotAction<ServerUseItemToOffhandAction> {
|
||||||
|
|
||||||
public ServerUseItemToOffhandAction() {
|
public ServerUseItemToOffhandAction() {
|
||||||
super("use_to_offhand", ServerUseItemToOffhandAction::new);
|
super("use_to_offhand", ServerUseItemToOffhandAction::new, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+43
@@ -18,6 +18,7 @@
|
|||||||
package org.leavesmc.leaves.command.bot.subcommands.action;
|
package org.leavesmc.leaves.command.bot.subcommands.action;
|
||||||
|
|
||||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||||
@@ -49,6 +50,7 @@ public class StopCommand extends LiteralNode {
|
|||||||
public StopCommand() {
|
public StopCommand() {
|
||||||
super("stop");
|
super("stop");
|
||||||
children(StopIndexArgument::new);
|
children(StopIndexArgument::new);
|
||||||
|
children(StopHashArgument::new);
|
||||||
children(StopAll::new);
|
children(StopAll::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +107,47 @@ public class StopCommand extends LiteralNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class StopHashArgument extends ArgumentNode<String> {
|
||||||
|
|
||||||
|
private StopHashArgument() {
|
||||||
|
super("hash", StringArgumentType.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean execute(CommandContext context) throws CommandSyntaxException {
|
||||||
|
ServerBot bot = ActionCommand.BotArgument.getBot(context);
|
||||||
|
CommandSender sender = context.getSender();
|
||||||
|
|
||||||
|
String hash = context.getArgument(StopHashArgument.class);
|
||||||
|
|
||||||
|
AbstractBotAction<?> action = null;
|
||||||
|
for (AbstractBotAction<?> action1 : bot.getBotActions()) {
|
||||||
|
if (action1.getUUID().toString().equals(hash)) {
|
||||||
|
action = action1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (action == null) throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create();
|
||||||
|
BotActionStopEvent event = new BotActionStopEvent(
|
||||||
|
bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender
|
||||||
|
);
|
||||||
|
event.callEvent();
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
action.stop(bot, BotActionStopEvent.Reason.COMMAND);
|
||||||
|
bot.getBotActions().remove(action);
|
||||||
|
sender.sendMessage(join(spaces(),
|
||||||
|
text("Already stopped", GRAY),
|
||||||
|
asAdventure(bot.getDisplayName()).append(text("'s", GRAY)),
|
||||||
|
text("action", GRAY),
|
||||||
|
text(action.getName(), AQUA).hoverEvent(showText(text(action.getActionDataString())))
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(text("Action stop cancelled by a plugin", RED));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class StopAll extends LiteralNode {
|
private static class StopAll extends LiteralNode {
|
||||||
|
|
||||||
private StopAll() {
|
private StopAll() {
|
||||||
|
|||||||
Reference in New Issue
Block a user