fix and configure crafting station shift-click behavior (#337)

This commit is contained in:
Pxx500 authored and GitHub committed 2026-09-24 15:01:08 -04:00
1 parent 8f6e2496f7
commit 2e02b96996
3 files changed
+149 -48

No files matched your search

@@ -11,7 +11,6 @@ import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
@@ -20,8 +19,14 @@ import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.world.World;
import tconstruct.items.tools.Arrow;
import tconstruct.items.tools.BowBase;
import tconstruct.library.crafting.ModifyBuilder;
import tconstruct.library.modifier.IModifyable;
import tconstruct.library.tools.HarvestTool;
import tconstruct.library.tools.Weapon;
import tconstruct.library.weaponry.AmmoItem;
import tconstruct.library.weaponry.ProjectileWeapon;
import tconstruct.tools.TinkerTools;
import tconstruct.tools.gui.ChestSlot;
import tconstruct.tools.logic.CraftingStationLogic;
@@ -45,6 +50,7 @@ public class CraftingStationContainer extends Container {
private final int posX;
private final int posY;
private final int posZ;
private final boolean shiftClickToGrid;
@SuppressWarnings("rawtypes")
private final WeakReference[] inventories;
@@ -77,6 +83,7 @@ public class CraftingStationContainer extends Container {
this.posY = y;
this.posZ = z;
this.logic = logic;
this.shiftClickToGrid = logic.shiftClickToGrid;
craftMatrix = new InventoryCraftingStation(this, 3, 3, logic);
craftResult = new InventoryCraftingStationResult(logic);
this.inventories = logic.getInventories();
@@ -130,33 +137,20 @@ public class CraftingStationContainer extends Container {
IInventory secondInv = logic.getSecondInventory();
final int accessSide = logic.chestDirection.getOpposite().ordinal();
final int[] accessibleSlots = inv instanceof ISidedInventory
? ((ISidedInventory) inv).getAccessibleSlotsFromSide(accessSide)
: null;
int index = 0, curIndex;
IInventory curInv;
final int invSize = inv.getSizeInventory() * (secondInv != null ? 2 : 1);
for (row = 0; row < logic.invRows; row++) {
for (col = 0; col < logic.invColumns; col++) {
if (index >= invSize) break;
// Adjust the inventory to account for double chests
curInv = secondInv != null && index >= 27 ? secondInv : inv;
// Adjust the index for the inventory
curIndex = secondInv != null && index >= 27 ? index - 27 : index;
if (accessibleSlots != null) {
if (curIndex >= accessibleSlots.length) {
break;
} else {
curIndex = accessibleSlots[curIndex];
}
}
this.addSlotToContainer(
new ChestSlot(curInv, curIndex, index, 8 + col * 18, 19 + row * 18, accessSide));
index++;
}
int[] firstSlots = logic.getFirstInventorySlots();
int[] secondSlots = logic.getSecondInventorySlots();
for (int index = 0; index < firstSlots.length + secondSlots.length; index++) {
boolean first = index < firstSlots.length;
IInventory curInv = first ? inv : secondInv;
int curIndex = first ? firstSlots[index] : secondSlots[index - firstSlots.length];
this.addSlotToContainer(
new ChestSlot(
curInv,
curIndex,
index,
8 + index % logic.invColumns * 18,
19 + index / logic.invColumns * 18,
accessSide));
}
}
@@ -211,9 +205,11 @@ public class CraftingStationContainer extends Container {
// Player inventory is always the fallback, so NEI can clear the grid.
nothingDone &= moveToPlayerInventory(itemstack);
} else if (index >= PLAYER_INVENTORY_FIRST_SLOT && index < PLAYER_INVENTORY_END_SLOT) {
nothingDone &= moveToCraftingGrid(itemstack);
// Move player stacks to the attached inventory.
nothingDone &= this.moveToChest(itemstack);
} else { // From the Attached Chests
nothingDone &= moveToCraftingGrid(itemstack);
// Move attached inventory stacks to the player inventory.
nothingDone &= moveToPlayerInventory(itemstack);
}
@@ -239,6 +235,8 @@ public class CraftingStationContainer extends Container {
@Override
public ItemStack slotClick(int slotId, int clickedButton, int mode, EntityPlayer player) {
if (slotId >= inventorySlots.size()) return null;
ItemStack carriedBefore = copyStack(player.inventory.getItemStack());
boolean carriedPreferenceBefore = carriedStackPrefersSideInventory;
ItemStack clickedBefore = getSlotStackCopy(slotId);
@@ -437,23 +435,17 @@ public class CraftingStationContainer extends Container {
}
protected boolean refillChest(ItemStack itemstack) {
if (itemstack == null || itemstack.stackSize <= 0 || logic.slotCount == 0) return false;
if (itemstack == null || itemstack.stackSize <= 0 || inventorySlots.size() == SIDE_INVENTORY_FIRST_SLOT)
return false;
return !this.mergeItemStackRefill(
itemstack,
SIDE_INVENTORY_FIRST_SLOT,
SIDE_INVENTORY_FIRST_SLOT + logic.slotCount,
false);
return !this.mergeItemStackRefill(itemstack, SIDE_INVENTORY_FIRST_SLOT, inventorySlots.size(), false);
}
protected boolean moveToChest(ItemStack itemstack) {
if (itemstack == null || itemstack.stackSize <= 0 || logic.slotCount == 0) return false;
if (itemstack == null || itemstack.stackSize <= 0 || inventorySlots.size() == SIDE_INVENTORY_FIRST_SLOT)
return false;
return !this.mergeItemStack(
itemstack,
SIDE_INVENTORY_FIRST_SLOT,
SIDE_INVENTORY_FIRST_SLOT + logic.slotCount,
false);
return !this.mergeItemStack(itemstack, SIDE_INVENTORY_FIRST_SLOT, inventorySlots.size(), false);
}
protected boolean moveToPlayerInventory(ItemStack itemstack) {
@@ -462,6 +454,26 @@ public class CraftingStationContainer extends Container {
return !this.mergeItemStack(itemstack, PLAYER_INVENTORY_FIRST_SLOT, PLAYER_INVENTORY_END_SLOT, false);
}
protected boolean moveToCraftingGrid(ItemStack itemstack) {
if (itemstack == null || itemstack.stackSize <= 0) return true;
// Prefer the center for Tinkers' tools to make applying modifiers more convenient.
Item item = itemstack.getItem();
if (item instanceof Arrow || item instanceof BowBase
|| item instanceof HarvestTool
|| item instanceof Weapon
|| item instanceof AmmoItem
|| item instanceof ProjectileWeapon) {
if (this.mergeItemStack(itemstack, 5, 6, false)) {
return false;
}
}
if (!shiftClickToGrid && inventorySlots.size() > SIDE_INVENTORY_FIRST_SLOT) return true;
return !this.mergeItemStack(itemstack, CRAFTING_GRID_FIRST_SLOT, CRAFTING_GRID_END_SLOT, true);
}
public boolean func_94530_a /* canMergeSlot */(ItemStack par1ItemStack, Slot par2Slot) {
return par2Slot.inventory != this.craftResult && super.func_94530_a(par1ItemStack, par2Slot);
}
@@ -701,7 +713,7 @@ public class CraftingStationContainer extends Container {
// Dump crafting grid to connected chests
public void dumpCraftingGrid() {
if (logic.slotCount == 0) return;
if (inventorySlots.size() == SIDE_INVENTORY_FIRST_SLOT) return;
beginBatchCraftingUpdate();
try {
@@ -709,7 +721,7 @@ public class CraftingStationContainer extends Container {
for (int i = 0; i < 9; i++) {
ItemStack stack = craftMatrix.getStackInSlot(i);
if (stack != null && stack.stackSize > 0) {
if (mergeItemStack(stack, 46, 46 + logic.slotCount, false)) {
if (mergeItemStack(stack, SIDE_INVENTORY_FIRST_SLOT, inventorySlots.size(), false)) {
craftMatrix.setInventorySlotContents(i, stack.stackSize > 0 ? stack : null);
}
}
@@ -1,14 +1,18 @@
package tconstruct.tools.logic;
import java.lang.ref.WeakReference;
import java.util.stream.IntStream;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.tileentity.TileEntityFurnace;
@@ -36,11 +40,16 @@ public class CraftingStationLogic extends InventoryLogic implements ISidedInvent
public boolean stencilTable;
public boolean doubleFirst;
/** Server-selected shift-click behavior, synchronized before opening the GUI. */
public boolean shiftClickToGrid;
public int invRows, invColumns, slotCount;
private static final int[] NO_SLOTS = new int[0];
private int sideInventoryPreferences;
private int[] firstInventorySlots = NO_SLOTS;
private int[] secondInventorySlots = NO_SLOTS;
/** Cached result of {@link #getInventories()}; rebuilt when the adjacent inventories are rescanned. */
@SuppressWarnings("rawtypes")
@@ -130,6 +139,9 @@ public class CraftingStationLogic extends InventoryLogic implements ISidedInvent
@Override
public Container getGuiContainer(InventoryPlayer inventoryplayer, World world, int x, int y, int z) {
if (world.isRemote) return new CraftingStationContainer(inventoryplayer, this, x, y, z);
shiftClickToGrid = PHConstruct.craftingStationShiftClickToGrid;
chest = null;
chestSize = 0;
slotCount = 0;
@@ -164,10 +176,6 @@ public class CraftingStationLogic extends InventoryLogic implements ISidedInvent
if (chest == null && inv.isUseableByPlayer(inventoryplayer.player)) {
chest = new WeakReference<>(inv);
chestDirection = dir;
invColumns = 6;
chestSize = tile instanceof ISidedInventory sidedIvn
? sidedIvn.getAccessibleSlotsFromSide(dir.getOpposite().ordinal()).length
: inv.getSizeInventory();
if (tile instanceof TileEntityChest tileChest) {
if (tileChest.adjacentChestZPos != null) {
@@ -184,16 +192,90 @@ public class CraftingStationLogic extends InventoryLogic implements ISidedInvent
doubleFirst = true;
}
}
slotCount = chestSize * (doubleChest != null ? 2 : 1);
invRows = (int) Math.ceil((double) slotCount / invColumns);
}
}
this.inventories = new WeakReference[] { this.chest, this.doubleChest, this.patternChest, this.furnace };
firstInventorySlots = getInventorySlots(getFirstInventory());
secondInventorySlots = getInventorySlots(getSecondInventory());
chestSize = doubleFirst ? secondInventorySlots.length : firstInventorySlots.length;
slotCount = firstInventorySlots.length + secondInventorySlots.length;
invRows = (slotCount + 5) / 6;
invColumns = 6;
if (inventoryplayer.player instanceof EntityPlayerMP player) {
NBTTagCompound data = new NBTTagCompound();
data.setBoolean("CraftingStationGui", true);
writeInventoryReference(data, "Chest", chest);
writeInventoryReference(data, "DoubleChest", doubleChest);
writeInventoryReference(data, "PatternChest", patternChest);
writeInventoryReference(data, "Furnace", furnace);
data.setInteger("ChestDirection", chestDirection.ordinal());
data.setBoolean("DoubleFirst", doubleFirst);
data.setBoolean("TinkerTable", tinkerTable);
data.setBoolean("ShiftClickToGrid", shiftClickToGrid);
data.setIntArray("FirstSlots", firstInventorySlots);
data.setIntArray("SecondSlots", secondInventorySlots);
player.playerNetServerHandler.sendPacket(new S35PacketUpdateTileEntity(x, y, z, 0, data));
}
return new CraftingStationContainer(inventoryplayer, this, x, y, z);
}
private int[] getInventorySlots(IInventory inventory) {
if (inventory == null) return NO_SLOTS;
if (inventory instanceof ISidedInventory sided) {
return sided.getAccessibleSlotsFromSide(chestDirection.getOpposite().ordinal()).clone();
}
return IntStream.range(0, inventory.getSizeInventory()).toArray();
}
public int[] getFirstInventorySlots() {
return firstInventorySlots;
}
public int[] getSecondInventorySlots() {
return secondInventorySlots;
}
private static void writeInventoryReference(NBTTagCompound data, String key, WeakReference<IInventory> ref) {
if (ref != null && ref.get() instanceof TileEntity tile) {
data.setIntArray(key, new int[] { tile.xCoord, tile.yCoord, tile.zCoord });
}
}
private WeakReference<IInventory> readInventoryReference(NBTTagCompound data, String key) {
int[] pos = data.getIntArray(key);
if (pos.length == 3 && worldObj.getTileEntity(pos[0], pos[1], pos[2]) instanceof IInventory adjacent) {
return new WeakReference<>(adjacent);
}
return null;
}
@Override
public void onDataPacket(NetworkManager manager, S35PacketUpdateTileEntity packet) {
NBTTagCompound data = packet.func_148857_g();
if (!data.getBoolean("CraftingStationGui")) {
super.onDataPacket(manager, packet);
return;
}
chest = readInventoryReference(data, "Chest");
doubleChest = readInventoryReference(data, "DoubleChest");
patternChest = readInventoryReference(data, "PatternChest");
furnace = readInventoryReference(data, "Furnace");
chestDirection = ForgeDirection.getOrientation(data.getInteger("ChestDirection"));
doubleFirst = data.getBoolean("DoubleFirst");
tinkerTable = data.getBoolean("TinkerTable");
shiftClickToGrid = data.getBoolean("ShiftClickToGrid");
firstInventorySlots = data.getIntArray("FirstSlots");
secondInventorySlots = data.getIntArray("SecondSlots");
chestSize = doubleFirst ? secondInventorySlots.length : firstInventorySlots.length;
slotCount = firstInventorySlots.length + secondInventorySlots.length;
invColumns = 6;
invRows = (slotCount + 5) / 6;
inventories = new WeakReference[] { chest, doubleChest, patternChest, furnace };
}
private boolean isBlacklisted(Class<? extends TileEntity> clazz) {
return PHConstruct.craftingStationBlacklist.contains(clazz.getName());
}
@@ -246,6 +246,12 @@ public class PHConstruct {
"9, 400, 2, 1200, 2, true", "17, 320, 1, 1000, 3, true", "DAMAGE, 0.3, true" },
" If an effect fails to apply, check the console for information \n FORMAT: \n potionID (Can also put \"DAMAGE\" to hurt the player instead, \n effectDuration (in ticks) (or DAMAGE effect strength) , \n initialAmplifier (Exclude if the first parameter is DAMAGE), \n maxDuration (this is the maximum duration the potions can stack in ticks (Exclude if the first parameter is DAMAGE)), \n maxAmplifier (the maximum allowed potionAmplifier with multiple effects uses (Exclude if the first parameter is DAMAGE)), \n stackExclusiveEffect (a true or false value which allows the effect to be only applied when the essence berries are eaten while shift is held (Only works if Allow stackwise consumption = true)")
.getStringList();
craftingStationShiftClickToGrid = config.get(
"general",
"craftingStationShiftClickToGrid",
false,
"Shift-click items from the player or attached inventory into the crafting station grid first. When false, move items between the player and attached inventory, or into the grid if no inventory is attached. Tinkers' tools always prefer the center slot")
.getBoolean(false);
disableAllRecipes = config.get(
"general",
"Disable All Recipes",
@@ -497,6 +503,7 @@ public class PHConstruct {
public static String[] disgustingXPBerryEffects;
public static boolean disableAllRecipes;
public static boolean craftingStationShiftClickToGrid;
public static double HarvestToolAOERelativeStrength;
// Mobs