package mekanism.common.tile; import io.netty.buffer.ByteBuf; import java.util.ArrayList; import java.util.EnumSet; import mekanism.api.Coord4D; import mekanism.api.EnumColor; import mekanism.api.IConfigCardAccess.ISpecialConfigData; import mekanism.api.MekanismConfig.client; import mekanism.api.Range4D; import mekanism.api.util.CapabilityUtils; import mekanism.common.HashList; import mekanism.common.Mekanism; import mekanism.common.MekanismSounds; import mekanism.common.base.IActiveState; import mekanism.common.base.ILogisticalTransporter; import mekanism.common.base.IRedstoneControl; import mekanism.common.base.ISustainedData; import mekanism.common.block.states.BlockStateMachine; import mekanism.common.capabilities.Capabilities; import mekanism.common.content.transporter.Finder.FirstFinder; import mekanism.common.content.transporter.InvStack; import mekanism.common.content.transporter.StackSearcher; import mekanism.common.content.transporter.TItemStackFilter; import mekanism.common.content.transporter.TransporterFilter; import mekanism.common.content.transporter.TransporterManager; import mekanism.common.network.PacketTileEntity.TileEntityMessage; import mekanism.common.security.ISecurityTile; import mekanism.common.tile.component.TileComponentSecurity; import mekanism.common.util.InventoryUtils; import mekanism.common.util.ItemDataUtils; import mekanism.common.util.MekanismUtils; import mekanism.common.util.TransporterUtils; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.SoundCategory; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.fml.common.FMLCommonHandler; public class TileEntityLogisticalSorter extends TileEntityElectricBlock implements IRedstoneControl, IActiveState, ISpecialConfigData, ISustainedData, ISecurityTile { public HashList<TransporterFilter> filters = new HashList<TransporterFilter>(); public RedstoneControl controlType = RedstoneControl.DISABLED; public EnumColor color; public boolean autoEject; public boolean roundRobin; public int rrIndex = 0; public final int MAX_DELAY = 10; public int delayTicks; public boolean isActive; public boolean clientActive; public final double ENERGY_PER_ITEM = 5; public TileComponentSecurity securityComponent = new TileComponentSecurity(this); public TileEntityLogisticalSorter() { super("LogisticalSorter", BlockStateMachine.MachineType.LOGISTICAL_SORTER.baseEnergy); inventory = new ItemStack[1]; doAutoSync = false; } @Override public void onUpdate() { super.onUpdate(); if(!worldObj.isRemote) { delayTicks = Math.max(0, delayTicks-1); if(delayTicks == 6) { setActive(false); } if(MekanismUtils.canFunction(this) && delayTicks == 0) { TileEntity back = Coord4D.get(this).offset(facing.getOpposite()).getTileEntity(worldObj); TileEntity front = Coord4D.get(this).offset(facing).getTileEntity(worldObj); if(back instanceof IInventory && (front != null && CapabilityUtils.hasCapability(front, Capabilities.LOGISTICAL_TRANSPORTER_CAPABILITY, facing.getOpposite()) || front instanceof IInventory)) { IInventory inventory = InventoryUtils.checkChestInv((IInventory)back); boolean sentItems = false; int min = 0; outer: for(TransporterFilter filter : filters) { inner: for(StackSearcher search = new StackSearcher(inventory, facing.getOpposite()); search.i >= 0;) { InvStack invStack = filter.getStackFromInventory(search); if(invStack == null || invStack.getStack() == null) { break inner; } if(filter.canFilter(invStack.getStack())) { if(filter instanceof TItemStackFilter) { TItemStackFilter itemFilter = (TItemStackFilter)filter; if(itemFilter.sizeMode) { min = itemFilter.min; } } ItemStack used = emitItemToTransporter(front, invStack, filter.color, min); if(used != null) { invStack.use(used.stackSize); inventory.markDirty(); setActive(true); sentItems = true; break outer; } } } } if(!sentItems && autoEject) { InvStack invStack = InventoryUtils.takeTopStack(inventory, facing.getOpposite(), new FirstFinder()); if(invStack != null && invStack.getStack() != null) { ItemStack used = emitItemToTransporter(front, invStack, color, 0); if(used != null) { invStack.use(used.stackSize); inventory.markDirty(); setActive(true); } } } delayTicks = 10; } } if(playersUsing.size() > 0) { for(EntityPlayer player : playersUsing) { Mekanism.packetHandler.sendTo(new TileEntityMessage(Coord4D.get(this), getGenericPacket(new ArrayList())), (EntityPlayerMP)player); } } } } /* * Returns used */ public ItemStack emitItemToTransporter(TileEntity front, InvStack inInventory, EnumColor filterColor, int min) { ItemStack used = null; if(CapabilityUtils.hasCapability(front, Capabilities.LOGISTICAL_TRANSPORTER_CAPABILITY, facing.getOpposite())) { ILogisticalTransporter transporter = CapabilityUtils.getCapability(front, Capabilities.LOGISTICAL_TRANSPORTER_CAPABILITY, facing.getOpposite()); if(!roundRobin) { ItemStack rejects = TransporterUtils.insert(this, transporter, inInventory.getStack(), filterColor, true, min); if(TransporterManager.didEmit(inInventory.getStack(), rejects)) { used = TransporterManager.getToUse(inInventory.getStack(), rejects); } } else { ItemStack rejects = TransporterUtils.insertRR(this, transporter, inInventory.getStack(), filterColor, true, min); if(TransporterManager.didEmit(inInventory.getStack(), rejects)) { used = TransporterManager.getToUse(inInventory.getStack(), rejects); } } } else if(front instanceof IInventory) { ItemStack rejects = InventoryUtils.putStackInInventory((IInventory)front, inInventory.getStack(), facing, false); if(TransporterManager.didEmit(inInventory.getStack(), rejects)) { used = TransporterManager.getToUse(inInventory.getStack(), rejects); } } return used; } @Override public NBTTagCompound writeToNBT(NBTTagCompound nbtTags) { super.writeToNBT(nbtTags); nbtTags.setInteger("controlType", controlType.ordinal()); if(color != null) { nbtTags.setInteger("color", TransporterUtils.colors.indexOf(color)); } nbtTags.setBoolean("autoEject", autoEject); nbtTags.setBoolean("roundRobin", roundRobin); nbtTags.setInteger("rrIndex", rrIndex); NBTTagList filterTags = new NBTTagList(); for(TransporterFilter filter : filters) { NBTTagCompound tagCompound = new NBTTagCompound(); filter.write(tagCompound); filterTags.appendTag(tagCompound); } if(filterTags.tagCount() != 0) { nbtTags.setTag("filters", filterTags); } return nbtTags; } @Override public void readFromNBT(NBTTagCompound nbtTags) { super.readFromNBT(nbtTags); controlType = RedstoneControl.values()[nbtTags.getInteger("controlType")]; if(nbtTags.hasKey("color")) { color = TransporterUtils.colors.get(nbtTags.getInteger("color")); } autoEject = nbtTags.getBoolean("autoEject"); roundRobin = nbtTags.getBoolean("roundRobin"); rrIndex = nbtTags.getInteger("rrIndex"); if(nbtTags.hasKey("filters")) { NBTTagList tagList = nbtTags.getTagList("filters", NBT.TAG_COMPOUND); for(int i = 0; i < tagList.tagCount(); i++) { filters.add(TransporterFilter.readFromNBT(tagList.getCompoundTagAt(i))); } } } @Override public void handlePacketData(ByteBuf dataStream) { if(FMLCommonHandler.instance().getEffectiveSide().isServer()) { int type = dataStream.readInt(); if(type == 0) { int clickType = dataStream.readInt(); if(clickType == 0) { color = TransporterUtils.increment(color); } else if(clickType == 1) { color = TransporterUtils.decrement(color); } else if(clickType == 2) { color = null; } } else if(type == 1) { autoEject = !autoEject; } else if(type == 2) { roundRobin = !roundRobin; rrIndex = 0; } else if(type == 3) { // Move filter up int filterIndex = dataStream.readInt(); filters.swap( filterIndex, filterIndex - 1 ); for(EntityPlayer player : playersUsing) openInventory(player); } else if(type == 4) { // Move filter down int filterIndex = dataStream.readInt(); filters.swap( filterIndex, filterIndex + 1 ); for(EntityPlayer player : playersUsing) openInventory(player); } return; } super.handlePacketData(dataStream); if(FMLCommonHandler.instance().getEffectiveSide().isClient()) { int type = dataStream.readInt(); if(type == 0) { clientActive = dataStream.readBoolean(); controlType = RedstoneControl.values()[dataStream.readInt()]; int c = dataStream.readInt(); if(c != -1) { color = TransporterUtils.colors.get(c); } else { color = null; } autoEject = dataStream.readBoolean(); roundRobin = dataStream.readBoolean(); filters.clear(); int amount = dataStream.readInt(); for(int i = 0; i < amount; i++) { filters.add(TransporterFilter.readFromPacket(dataStream)); } } else if(type == 1) { clientActive = dataStream.readBoolean(); controlType = RedstoneControl.values()[dataStream.readInt()]; int c = dataStream.readInt(); if(c != -1) { color = TransporterUtils.colors.get(c); } else { color = null; } autoEject = dataStream.readBoolean(); roundRobin = dataStream.readBoolean(); } else if(type == 2) { filters.clear(); int amount = dataStream.readInt(); for(int i = 0; i < amount; i++) { filters.add(TransporterFilter.readFromPacket(dataStream)); } } } } @Override public ArrayList<Object> getNetworkedData(ArrayList<Object> data) { super.getNetworkedData(data); data.add(0); data.add(isActive); data.add(controlType.ordinal()); if(color != null) { data.add(TransporterUtils.colors.indexOf(color)); } else { data.add(-1); } data.add(autoEject); data.add(roundRobin); data.add(filters.size()); for(TransporterFilter filter : filters) { filter.write(data); } return data; } public ArrayList getGenericPacket(ArrayList<Object> data) { super.getNetworkedData(data); data.add(1); data.add(isActive); data.add(controlType.ordinal()); if(color != null) { data.add(TransporterUtils.colors.indexOf(color)); } else { data.add(-1); } data.add(autoEject); data.add(roundRobin); return data; } public ArrayList getFilterPacket(ArrayList<Object> data) { super.getNetworkedData(data); data.add(2); data.add(filters.size()); for(TransporterFilter filter : filters) { filter.write(data); } return data; } public boolean canSendHome(ItemStack stack) { TileEntity back = Coord4D.get(this).offset(facing.getOpposite()).getTileEntity(worldObj); if(back instanceof IInventory) { return InventoryUtils.canInsert(back, null, stack, facing.getOpposite(), true); } return false; } public boolean hasInventory() { return Coord4D.get(this).offset(facing.getOpposite()).getTileEntity(worldObj) instanceof IInventory; } public ItemStack sendHome(ItemStack stack) { TileEntity back = Coord4D.get(this).offset(facing.getOpposite()).getTileEntity(worldObj); if(back instanceof IInventory) { return InventoryUtils.putStackInInventory((IInventory)back, stack, facing.getOpposite(), true); } return stack; } @Override public boolean canExtractItem(int slotID, ItemStack itemstack, EnumFacing side) { return false; } @Override public boolean isItemValidForSlot(int slotID, ItemStack itemstack) { return false; } @Override public int getInventoryStackLimit() { return 1; } @Override public int[] getSlotsForFace(EnumFacing side) { if(side == facing || side == facing.getOpposite()) { return new int[] {0}; } return InventoryUtils.EMPTY; } @Override public void openInventory(EntityPlayer player) { if(!worldObj.isRemote) { Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getFilterPacket(new ArrayList<Object>())), new Range4D(Coord4D.get(this))); } } @Override public RedstoneControl getControlType() { return controlType; } @Override public void setControlType(RedstoneControl type) { controlType = type; } @Override public boolean canPulse() { return true; } @Override public void setActive(boolean active) { isActive = active; if(clientActive != active) { Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList<Object>())), new Range4D(Coord4D.get(this))); if(active && client.enableMachineSounds) { worldObj.playSound(null, getPos().getX(), getPos().getY(), getPos().getZ(), MekanismSounds.CLICK, SoundCategory.BLOCKS, 0.3F, 1); } clientActive = active; } } @Override public boolean getActive() { return isActive; } @Override public boolean renderUpdate() { return true; } @Override public boolean lightUpdate() { return false; } @Override public EnumSet<EnumFacing> getConsumingSides() { return EnumSet.noneOf(EnumFacing.class); } @Override public boolean canSetFacing(int facing) { return true; } @Override public TileComponentSecurity getSecurity() { return securityComponent; } @Override public NBTTagCompound getConfigurationData(NBTTagCompound nbtTags) { if(color != null) { nbtTags.setInteger("color", TransporterUtils.colors.indexOf(color)); } nbtTags.setBoolean("autoEject", autoEject); nbtTags.setBoolean("roundRobin", roundRobin); nbtTags.setInteger("rrIndex", rrIndex); NBTTagList filterTags = new NBTTagList(); for(TransporterFilter filter : filters) { NBTTagCompound tagCompound = new NBTTagCompound(); filter.write(tagCompound); filterTags.appendTag(tagCompound); } if(filterTags.tagCount() != 0) { nbtTags.setTag("filters", filterTags); } return nbtTags; } @Override public void setConfigurationData(NBTTagCompound nbtTags) { if(nbtTags.hasKey("color")) { color = TransporterUtils.colors.get(nbtTags.getInteger("color")); } autoEject = nbtTags.getBoolean("autoEject"); roundRobin = nbtTags.getBoolean("roundRobin"); rrIndex = nbtTags.getInteger("rrIndex"); if(nbtTags.hasKey("filters")) { NBTTagList tagList = nbtTags.getTagList("filters", NBT.TAG_COMPOUND); for(int i = 0; i < tagList.tagCount(); i++) { filters.add(TransporterFilter.readFromNBT(tagList.getCompoundTagAt(i))); } } } @Override public String getDataType() { return getBlockType().getUnlocalizedName() + "." + fullName + ".name"; } @Override public void writeSustainedData(ItemStack itemStack) { ItemDataUtils.setBoolean(itemStack, "hasSorterConfig", true); if(color != null) { ItemDataUtils.setInt(itemStack, "color", TransporterUtils.colors.indexOf(color)); } ItemDataUtils.setBoolean(itemStack, "autoEject", autoEject); ItemDataUtils.setBoolean(itemStack, "roundRobin", roundRobin); NBTTagList filterTags = new NBTTagList(); for(TransporterFilter filter : filters) { NBTTagCompound tagCompound = new NBTTagCompound(); filter.write(tagCompound); filterTags.appendTag(tagCompound); } if(filterTags.tagCount() != 0) { ItemDataUtils.setList(itemStack, "filters", filterTags); } } @Override public void readSustainedData(ItemStack itemStack) { if(ItemDataUtils.hasData(itemStack, "hasSorterConfig")) { if(ItemDataUtils.hasData(itemStack, "color")) { color = TransporterUtils.colors.get(ItemDataUtils.getInt(itemStack, "color")); } autoEject = ItemDataUtils.getBoolean(itemStack, "autoEject"); roundRobin = ItemDataUtils.getBoolean(itemStack, "roundRobin"); if(ItemDataUtils.hasData(itemStack, "filters")) { NBTTagList tagList = ItemDataUtils.getList(itemStack, "filters"); for(int i = 0; i < tagList.tagCount(); i++) { filters.add(TransporterFilter.readFromNBT(tagList.getCompoundTagAt(i))); } } } } @Override public boolean hasCapability(Capability<?> capability, EnumFacing side) { return capability == Capabilities.CONFIG_CARD_CAPABILITY || capability == Capabilities.SPECIAL_CONFIG_DATA_CAPABILITY || super.hasCapability(capability, side); } @Override public <T> T getCapability(Capability<T> capability, EnumFacing side) { if(capability == Capabilities.CONFIG_CARD_CAPABILITY || capability == Capabilities.SPECIAL_CONFIG_DATA_CAPABILITY) { return (T)this; } return super.getCapability(capability, side); } }