mirror of
https://github.com/GTNewHorizons/TinkersConstruct.git
synced 2026-10-25 20:32:32 +00:00
369 lines
14 KiB
Java
369 lines
14 KiB
Java
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;
|
|
import net.minecraft.world.World;
|
|
import net.minecraftforge.common.util.ForgeDirection;
|
|
|
|
import mantle.blocks.abstracts.InventoryLogic;
|
|
import tconstruct.tools.inventory.CraftingStationContainer;
|
|
import tconstruct.util.config.PHConstruct;
|
|
|
|
public class CraftingStationLogic extends InventoryLogic implements ISidedInventory {
|
|
|
|
private static final String SIDE_INVENTORY_PREFERENCES_TAG = "SideInventoryPreferences";
|
|
private static final int CRAFTING_GRID_FIRST_SLOT = 1;
|
|
private static final int CRAFTING_GRID_SIZE = 9;
|
|
private static final int VALID_SIDE_INVENTORY_PREFERENCES = (1 << CRAFTING_GRID_SIZE) - 1;
|
|
|
|
public ForgeDirection chestDirection = ForgeDirection.UNKNOWN;
|
|
public int chestSize;
|
|
public WeakReference<IInventory> chest;
|
|
public WeakReference<IInventory> doubleChest;
|
|
public WeakReference<IInventory> patternChest;
|
|
public WeakReference<IInventory> furnace;
|
|
public boolean tinkerTable;
|
|
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")
|
|
private WeakReference[] inventories = new WeakReference[4];
|
|
|
|
public CraftingStationLogic() {
|
|
super(10); // 9 for crafting, 1 for output
|
|
}
|
|
|
|
@Override
|
|
public boolean canDropInventorySlot(int slot) {
|
|
return slot != 0;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack decrStackSize(int slot, int quantity) {
|
|
if (slot == 0) {
|
|
for (int i = 1; i < getSizeInventory(); i++) decrStackSize(i, 1);
|
|
}
|
|
ItemStack removed = super.decrStackSize(slot, quantity);
|
|
clearSideInventoryPreferenceIfEmpty(slot);
|
|
return removed;
|
|
}
|
|
|
|
@Override
|
|
public void setInventorySlotContents(int slot, ItemStack itemstack) {
|
|
super.setInventorySlotContents(slot, itemstack);
|
|
clearSideInventoryPreferenceIfEmpty(slot);
|
|
}
|
|
|
|
public boolean prefersSideInventory(int slot) {
|
|
int preference = getSideInventoryPreference(slot);
|
|
return preference != 0 && (sideInventoryPreferences & preference) != 0;
|
|
}
|
|
|
|
public void setSideInventoryPreference(int slot, boolean prefersSideInventory) {
|
|
int preference = getSideInventoryPreference(slot);
|
|
if (preference == 0) return;
|
|
|
|
int updatedPreferences = prefersSideInventory ? sideInventoryPreferences | preference
|
|
: sideInventoryPreferences & ~preference;
|
|
setSideInventoryPreferences(updatedPreferences);
|
|
}
|
|
|
|
public int getSideInventoryPreferences() {
|
|
return sideInventoryPreferences;
|
|
}
|
|
|
|
public void setSideInventoryPreferences(int preferences) {
|
|
preferences &= VALID_SIDE_INVENTORY_PREFERENCES;
|
|
if (sideInventoryPreferences != preferences) {
|
|
sideInventoryPreferences = preferences;
|
|
markDirty();
|
|
}
|
|
}
|
|
|
|
private void clearSideInventoryPreferenceIfEmpty(int slot) {
|
|
if (slot < CRAFTING_GRID_FIRST_SLOT || slot >= CRAFTING_GRID_FIRST_SLOT + CRAFTING_GRID_SIZE) return;
|
|
|
|
ItemStack stack = getStackInSlot(slot);
|
|
if (stack == null || stack.stackSize <= 0) {
|
|
setSideInventoryPreference(slot, false);
|
|
}
|
|
}
|
|
|
|
private static int getSideInventoryPreference(int slot) {
|
|
int gridSlot = slot - CRAFTING_GRID_FIRST_SLOT;
|
|
return gridSlot >= 0 && gridSlot < CRAFTING_GRID_SIZE ? 1 << gridSlot : 0;
|
|
}
|
|
|
|
@Override
|
|
public void readFromNBT(NBTTagCompound tags) {
|
|
super.readFromNBT(tags);
|
|
sideInventoryPreferences = tags.getInteger(SIDE_INVENTORY_PREFERENCES_TAG) & VALID_SIDE_INVENTORY_PREFERENCES;
|
|
}
|
|
|
|
@Override
|
|
public void writeToNBT(NBTTagCompound tags) {
|
|
super.writeToNBT(tags);
|
|
tags.setInteger(SIDE_INVENTORY_PREFERENCES_TAG, sideInventoryPreferences);
|
|
}
|
|
|
|
@Override
|
|
public boolean isUseableByPlayer(EntityPlayer player) {
|
|
return isUseableByPlayer(player, this.getInventories()) && super.isUseableByPlayer(player);
|
|
}
|
|
|
|
@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;
|
|
chestDirection = ForgeDirection.UNKNOWN;
|
|
doubleChest = null;
|
|
patternChest = null;
|
|
furnace = null;
|
|
tinkerTable = false;
|
|
|
|
for (final ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
|
|
final int xPos = x + dir.offsetX, yPos = y + dir.offsetY, zPos = z + dir.offsetZ;
|
|
final TileEntity tile = world.getTileEntity(xPos, yPos, zPos);
|
|
if (!(tile instanceof IInventory inv) || (tile instanceof CraftingStationLogic)
|
|
|| isBlacklisted(tile.getClass()))
|
|
continue;
|
|
|
|
if (patternChest == null && tile instanceof PatternChestLogic) {
|
|
patternChest = new WeakReference<>(inv);
|
|
continue;
|
|
} else if (furnace == null && (tile instanceof TileEntityFurnace || tile instanceof FurnaceLogic)) {
|
|
furnace = new WeakReference<>(inv);
|
|
continue;
|
|
} else if (!tinkerTable && tile instanceof ToolStationLogic) {
|
|
tinkerTable = true;
|
|
continue;
|
|
}
|
|
|
|
if (tile instanceof ISidedInventory sidedIvn
|
|
&& sidedIvn.getAccessibleSlotsFromSide(dir.getOpposite().ordinal()).length == 0)
|
|
continue;
|
|
|
|
if (chest == null && inv.isUseableByPlayer(inventoryplayer.player)) {
|
|
chest = new WeakReference<>(inv);
|
|
chestDirection = dir;
|
|
|
|
if (tile instanceof TileEntityChest tileChest) {
|
|
if (tileChest.adjacentChestZPos != null) {
|
|
doubleChest = new WeakReference<>(tileChest.adjacentChestZPos);
|
|
doubleFirst = false;
|
|
} else if (tileChest.adjacentChestZNeg != null) {
|
|
doubleChest = new WeakReference<>(tileChest.adjacentChestZNeg);
|
|
doubleFirst = true;
|
|
} else if (tileChest.adjacentChestXPos != null) {
|
|
doubleChest = new WeakReference<>(tileChest.adjacentChestXPos);
|
|
doubleFirst = false;
|
|
} else if (tileChest.adjacentChestXNeg != null) {
|
|
doubleChest = new WeakReference<>(tileChest.adjacentChestXNeg);
|
|
doubleFirst = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
public boolean isDoubleChest() {
|
|
return this.doubleChest != null;
|
|
}
|
|
|
|
public IInventory getFirstInventory() {
|
|
if (doubleFirst && doubleChest != null) {
|
|
return doubleChest.get();
|
|
} else {
|
|
return chest != null ? chest.get() : null;
|
|
}
|
|
}
|
|
|
|
public IInventory getSecondInventory() {
|
|
if (!isDoubleChest()) return null;
|
|
|
|
if (doubleFirst) {
|
|
return chest.get();
|
|
} else {
|
|
return doubleChest == null ? null : doubleChest.get();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected String getDefaultName() {
|
|
return "crafters.CraftingStation";
|
|
}
|
|
|
|
@Override
|
|
public boolean hasCustomInventoryName() {
|
|
return true;
|
|
}
|
|
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
public static boolean isUseableByPlayer(EntityPlayer player, WeakReference[] inventories) {
|
|
for (WeakReference<IInventory> ref : inventories) {
|
|
if (ref != null) {
|
|
IInventory inv = ref.get();
|
|
if (inv != null && !inv.isUseableByPlayer(player)) return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@SuppressWarnings("rawtypes")
|
|
public WeakReference[] getInventories() {
|
|
return this.inventories;
|
|
}
|
|
|
|
@Override
|
|
public int[] getAccessibleSlotsFromSide(int var1) {
|
|
return NO_SLOTS;
|
|
}
|
|
|
|
@Override
|
|
public boolean canInsertItem(int i, ItemStack itemstack, int j) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean canExtractItem(int i, ItemStack itemstack, int j) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public String getInventoryName() {
|
|
return getDefaultName();
|
|
}
|
|
|
|
@Override
|
|
public void openInventory() {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public void closeInventory() {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public boolean canUpdate() {
|
|
return false;
|
|
}
|
|
}
|