Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion common/src/main/java/com/pathmind/nodes/NodeCatalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,11 @@ public final class NodeCatalog {
NodeType.OPEN_INVENTORY,
NodeType.CLOSE_GUI);

// This flag is what makes a node draw its parameter strip, and the mode selector lives
// inside that strip (NodeRenderer.renderInlineParameterContent). A node with modes but
// without this tag has no way to reach them in the editor.
tag(NodeFlag.RENDER_INLINE_PARAMETERS,
NodeType.CLICK_SLOT,
NodeType.UI_UTILS,
NodeType.SENSOR_FABRIC_EVENT,
NodeType.SENSOR_ATTRIBUTE_DETECTION,
Expand Down Expand Up @@ -903,6 +907,12 @@ public final class NodeCatalog {
modeParameters(NodeMode.FARM_WAYPOINT,
of("Waypoint", ParameterType.STRING, "farm"),
of("Range", ParameterType.INTEGER, "10"));
// Click Slot's three modes take the same Slot number; they differ only in the click the
// node sends. Keeping the id and label identical to the old type parameter is what lets
// presets saved before the modes existed restore their slot unchanged.
modeParameters(NodeMode.CLICK_SLOT_LEFT, of("click_slot_index", "Slot", ParameterType.INTEGER, "0"));
modeParameters(NodeMode.CLICK_SLOT_SHIFT, of("click_slot_index", "Slot", ParameterType.INTEGER, "0"));
modeParameters(NodeMode.CLICK_SLOT_SWAP_OFFHAND, of("click_slot_index", "Slot", ParameterType.INTEGER, "0"));
modeParameters(NodeMode.WAIT_SECONDS, of("Duration", ParameterType.DOUBLE, ""));
modeParameters(NodeMode.WAIT_TICKS, of("Duration", ParameterType.DOUBLE, ""));
modeParameters(NodeMode.WAIT_MINUTES, of("Duration", ParameterType.DOUBLE, ""));
Expand Down Expand Up @@ -948,7 +958,6 @@ public final class NodeCatalog {
of("drop_slot_index", "Slot", ParameterType.INTEGER, "0"),
of("Count", ParameterType.INTEGER, "0"),
of("EntireStack", ParameterType.BOOLEAN, "true"));
typeParameters(NodeType.CLICK_SLOT, of("click_slot_index", "Slot", ParameterType.INTEGER, "0"));
typeParameters(NodeType.CLICK_SCREEN,
of("X", ParameterType.INTEGER, "0"),
of("Y", ParameterType.INTEGER, "0"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import net.minecraft.world.item.Items;

final class NodeInventoryCommandExecutor {
private static final int OFFHAND_SWAP_BUTTON = 40;

private final Node owner;
private final NodeType type;
private final NodeRuntimeState runtimeState;
Expand Down Expand Up @@ -197,11 +199,12 @@ void executeClickSlotCommand(CompletableFuture<Void> future) {
return;
}

NodeMode mode = owner.getMode();
interactionManager.handleInventoryMouseClick(
handler.containerId,
resolution.handlerSlotIndex,
0,
ClickType.PICKUP,
clickSlotButton(mode),
clickSlotClickType(mode),
client.player
);

Expand All @@ -210,6 +213,24 @@ void executeClickSlotCommand(CompletableFuture<Void> future) {
future.complete(null);
}

// The three Click Slot modes send exactly what the vanilla screen sends for the same input:
// a plain left click is PICKUP, shift-click is QUICK_MOVE, and F is SWAP on button 40, which
// is the offhand's button index in AbstractContainerScreen. A node saved before the modes
// existed loads with the default CLICK_SLOT_LEFT, and a null mode is the same plain click.
static ClickType clickSlotClickType(NodeMode mode) {
if (mode == NodeMode.CLICK_SLOT_SHIFT) {
return ClickType.QUICK_MOVE;
}
if (mode == NodeMode.CLICK_SLOT_SWAP_OFFHAND) {
return ClickType.SWAP;
}
return ClickType.PICKUP;
}

static int clickSlotButton(NodeMode mode) {
return mode == NodeMode.CLICK_SLOT_SWAP_OFFHAND ? OFFHAND_SWAP_BUTTON : 0;
}

void executeClickScreenCommand(CompletableFuture<Void> future) {
net.minecraft.client.Minecraft client = net.minecraft.client.Minecraft.getInstance();
if (client == null || client.getWindow() == null) {
Expand Down
9 changes: 9 additions & 0 deletions common/src/main/java/com/pathmind/nodes/NodeMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
* Each mode corresponds to a specific behavior within a generalized node type.
*/
public enum NodeMode {
// CLICK_SLOT modes
CLICK_SLOT_LEFT("Left Click", "Pick up or place the stack, as a plain left click does"),
CLICK_SLOT_SHIFT("Shift Click", "Move the stack to the other container, as shift-clicking does"),
CLICK_SLOT_SWAP_OFFHAND("F", "Swap the stack with the offhand, as pressing F does"),

// GOTO modes
GOTO_XYZ("Go to XYZ", "Go to specific X, Y, Z coordinates"),
GOTO_XZ("Go to XZ", "Go to X, Z coordinates (Y defaults to surface)"),
Expand Down Expand Up @@ -176,6 +181,9 @@ public static NodeMode[] getModesForNodeType(NodeType nodeType) {
case SENSOR_LOOK_DIRECTION -> new NodeMode[]{
SENSOR_LOOK_YAW, SENSOR_LOOK_PITCH, SENSOR_LOOK_ROTATION
};
case CLICK_SLOT -> new NodeMode[]{
CLICK_SLOT_LEFT, CLICK_SLOT_SHIFT, CLICK_SLOT_SWAP_OFFHAND
};
default -> new NodeMode[0];
};
}
Expand All @@ -200,6 +208,7 @@ public static NodeMode getDefaultModeForNodeType(NodeType nodeType) {
case WAIT, PARAM_DURATION -> WAIT_SECONDS;
case SENSOR_POSITION_OF -> SENSOR_POSITION_XYZ;
case SENSOR_LOOK_DIRECTION -> SENSOR_LOOK_ROTATION;
case CLICK_SLOT -> CLICK_SLOT_LEFT;
default -> null;
};
}
Expand Down
6 changes: 6 additions & 0 deletions common/src/main/resources/assets/pathmind/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,12 @@
"pathmind.node.mode.goal_xz.desc": "Set goal to X, Z coordinates (Y defaults to surface)",
"pathmind.node.mode.goal_y": "Set Goal Y",
"pathmind.node.mode.goal_y.desc": "Set goal to specific Y level",
"pathmind.node.mode.click_slot_left": "Left Click",
"pathmind.node.mode.click_slot_left.desc": "Pick up or place the stack, as a plain left click does",
"pathmind.node.mode.click_slot_shift": "Shift Click",
"pathmind.node.mode.click_slot_shift.desc": "Move the stack to the other container, as shift-clicking does",
"pathmind.node.mode.click_slot_swap_offhand": "F",
"pathmind.node.mode.click_slot_swap_offhand.desc": "Swap the stack with the offhand, as pressing F does",
"pathmind.node.mode.goto_block": "Go to Block",
"pathmind.node.mode.goto_block.desc": "Go to nearest block of specified type",
"pathmind.node.mode.goto_xyz": "Go to XYZ",
Expand Down
50 changes: 50 additions & 0 deletions common/src/test/java/com/pathmind/nodes/NodeClickSlotTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.pathmind.nodes;

import static org.junit.jupiter.api.Assertions.assertEquals;

import net.minecraft.world.inventory.ClickType;
import org.junit.jupiter.api.Test;

class NodeClickSlotTest {

@Test
void eachModeSendsTheClickVanillaSendsForTheSameInput() {
assertEquals(ClickType.PICKUP,
NodeInventoryCommandExecutor.clickSlotClickType(NodeMode.CLICK_SLOT_LEFT));
assertEquals(ClickType.QUICK_MOVE,
NodeInventoryCommandExecutor.clickSlotClickType(NodeMode.CLICK_SLOT_SHIFT));
assertEquals(ClickType.SWAP,
NodeInventoryCommandExecutor.clickSlotClickType(NodeMode.CLICK_SLOT_SWAP_OFFHAND));

// Only the offhand swap carries a button; SWAP with any other button hits a hotbar slot.
assertEquals(0, NodeInventoryCommandExecutor.clickSlotButton(NodeMode.CLICK_SLOT_LEFT));
assertEquals(0, NodeInventoryCommandExecutor.clickSlotButton(NodeMode.CLICK_SLOT_SHIFT));
assertEquals(40, NodeInventoryCommandExecutor.clickSlotButton(NodeMode.CLICK_SLOT_SWAP_OFFHAND));
}

@Test
void aNodeSavedBeforeTheModesExistedStillSendsAPlainLeftClick() {
assertEquals(ClickType.PICKUP, NodeInventoryCommandExecutor.clickSlotClickType(null));
assertEquals(0, NodeInventoryCommandExecutor.clickSlotButton(null));
}

@Test
void clickSlotOffersItsThreeModesWithLeftClickAsTheDefault() {
assertEquals(NodeMode.CLICK_SLOT_LEFT, NodeMode.getDefaultModeForNodeType(NodeType.CLICK_SLOT));
assertEquals(3, NodeMode.getModesForNodeType(NodeType.CLICK_SLOT).length);
}

@Test
void everyModeKeepsTheSlotParameterSoOldPresetsRestoreIt() {
// initializeParameters reads mode parameters instead of type parameters once a node has
// modes, so a mode missing the Slot definition would silently drop the saved value.
for (NodeMode mode : NodeMode.getModesForNodeType(NodeType.CLICK_SLOT)) {
java.util.List<NodeParameter> parameters = new java.util.ArrayList<>();
NodeCatalog.initializeParameters(parameters, NodeType.CLICK_SLOT, mode);
assertEquals(1, parameters.size(), mode.name());
assertEquals("Slot", parameters.get(0).getName(), mode.name());
assertEquals("click_slot_index", parameters.get(0).getId(), mode.name());
assertEquals("0", parameters.get(0).getStringValue(), mode.name());
}
}
}