package makeo.gadomancy.common.blocks.tiles; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import makeo.gadomancy.common.entities.EntityPermNoClipItem; import makeo.gadomancy.common.aura.AuraEffectHandler; import makeo.gadomancy.common.utils.NBTHelper; import net.minecraft.block.Block; import net.minecraft.command.IEntitySelector; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MathHelper; import net.minecraftforge.common.util.ForgeDirection; import thaumcraft.api.ThaumcraftApiHelper; import thaumcraft.api.aspects.Aspect; import thaumcraft.api.aspects.AspectList; import thaumcraft.api.aspects.IAspectContainer; import thaumcraft.api.aspects.IEssentiaTransport; import thaumcraft.client.fx.ParticleEngine; import thaumcraft.client.fx.particles.FXEssentiaTrail; import thaumcraft.common.entities.EntityPermanentItem; import thaumcraft.common.entities.EntitySpecialItem; import thaumcraft.common.items.ItemCrystalEssence; import java.util.ArrayList; import java.util.List; /** * This class is part of the Gadomancy Mod * Gadomancy is Open Source and distributed under the * GNU LESSER GENERAL PUBLIC LICENSE * for more read the LICENSE file * <p/> * Created by HellFirePvP @ 11.11.2015 14:30 */ public class TileAuraPylon extends SynchronizedTileEntity implements IAspectContainer, IEssentiaTransport, EntityPermNoClipItem.IItemMasterTile { private ItemStack crystalEssentiaStack = null; private boolean isPartOfMultiblock = false; private int timeSinceLastItemInfo = 0; private int ticksExisted = 0; private Aspect holdingAspect; private int amount = 0; private int maxAmount = 5; private boolean isMasterTile; private boolean isInputTile; //Individual. @Override public void updateEntity() { ticksExisted++; timeSinceLastItemInfo++; if (!worldObj.isRemote) { if ((ticksExisted & 3) == 0) { if (checkComponents()) return; } if (isInputTile()) { handleIO(); } if (isMasterTile()) { TileAuraPylon io = getInputTile(); if(io != null && io.amount > 0) { if ((ticksExisted & 31) == 0) { drainEssentia(io); } doAuraEffects(holdingAspect); } if(holdingAspect != null && timeSinceLastItemInfo > 8) { informItemRemoval(); } } } else { if(isInputTile() && holdingAspect != null) { doEssentiaTrail(); } } if (isMasterTile()) { if (crystalEssentiaStack == null) { tryVortexPossibleItems(); } } } @Override public boolean canStillHoldItem() { return isMasterTile(); } @Override public void informMaster() { this.timeSinceLastItemInfo = 0; } private void doAuraEffects(Aspect aspect) { if(aspect == null) return; if(!isMasterTile()) return; if(worldObj.isRemote) return; AuraEffectHandler.distributeEffects(aspect, worldObj, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, ticksExisted); } private void drainEssentia(TileAuraPylon io) { if(!isMasterTile()) return; io.amount--; worldObj.markBlockForUpdate(io.xCoord, io.yCoord, io.zCoord); io.markDirty(); } //Client-Side input tile only! @SideOnly(Side.CLIENT) private void doEssentiaTrail() { if((ticksExisted & 1) == 0) return; TileAuraPylon tile = getMasterTile(); if(tile == null) return; TileAuraPylon inputTile = getInputTile(); if(inputTile == null) return; Aspect a = inputTile.getAspectType(); if(a == null) return; if(inputTile.amount <= 0) return; int count = 5; FXEssentiaTrail essentiaTrail = new FXEssentiaTrail(tile.getWorldObj(), inputTile.xCoord + 0.5, inputTile.yCoord + 0.2, inputTile.zCoord + 0.5, tile.xCoord + 0.5, tile.yCoord + 1.7, tile.zCoord + 0.5, count, a.getColor(), 1); essentiaTrail.noClip = true; essentiaTrail.motionY = (0.1F + MathHelper.sin(count / 3.0F) * 0.01F); essentiaTrail.motionX = (MathHelper.sin(count / 10.0F) * 0.001F + worldObj.rand.nextGaussian() * 0.002000000094994903D); essentiaTrail.motionZ = (MathHelper.sin(count / 10.0F) * 0.001F + worldObj.rand.nextGaussian() * 0.002000000094994903D); ParticleEngine.instance.addEffect(tile.getWorldObj(), essentiaTrail); } //Special to masterTile only! private void distributeAspectInformation() { if(!isMasterTile()) return; int count = 1; TileEntity iter = worldObj.getTileEntity(xCoord, yCoord - count, zCoord); while(iter != null && iter instanceof TileAuraPylon) { ((TileAuraPylon) iter).holdingAspect = holdingAspect; worldObj.markBlockForUpdate(xCoord, yCoord - count, zCoord); iter.markDirty(); count++; iter = worldObj.getTileEntity(xCoord, yCoord - count, zCoord); } } //Special to masterTile only! private void tryVortexPossibleItems() { TileAuraPylon io = getInputTile(); if (io == null) return; int masterY = yCoord + 1; float dst = ((float) (masterY - io.yCoord)) / 2F; float yC = masterY - dst; List entityItems = worldObj.selectEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getBoundingBox(xCoord - 0.5, yC - 0.5, zCoord - 0.5, xCoord + 0.5, yC + 0.5, zCoord + 0.5).expand(8, 8, 8), new IEntitySelector() { @Override public boolean isEntityApplicable(Entity e) { return !(e instanceof EntityPermanentItem) && !(e instanceof EntitySpecialItem) && e instanceof EntityItem && ((EntityItem) e).getEntityItem() != null && ((EntityItem) e).getEntityItem().getItem() instanceof ItemCrystalEssence && ((ItemCrystalEssence) ((EntityItem) e).getEntityItem().getItem()).getAspects(((EntityItem) e).getEntityItem()) != null; } }); Entity dummy = new EntityItem(worldObj); dummy.posX = xCoord + 0.5; dummy.posY = yC + 0.5; dummy.posZ = zCoord + 0.5; //MC code. EntityItem entity = null; double d0 = Double.MAX_VALUE; for (Object entityItem : entityItems) { EntityItem entityIt = (EntityItem) entityItem; if (entityIt != dummy) { double d1 = dummy.getDistanceSqToEntity(entityIt); if (d1 <= d0) { entity = entityIt; d0 = d1; } } } if(entity == null) return; if(dummy.getDistanceToEntity(entity) < 1 && !worldObj.isRemote) { ItemStack inter = entity.getEntityItem(); inter.stackSize--; this.crystalEssentiaStack = inter.copy(); this.crystalEssentiaStack.stackSize = 1; EntityPermNoClipItem item = new EntityPermNoClipItem(entity.worldObj, xCoord + 0.5F, yC + 0.3F, zCoord + 0.5F, crystalEssentiaStack, xCoord, yCoord, zCoord); entity.worldObj.spawnEntityInWorld(item); item.motionX = 0; item.motionY = 0; item.motionZ = 0; item.hoverStart = entity.hoverStart; item.age = entity.age; item.noClip = true; timeSinceLastItemInfo = 0; holdingAspect = ((ItemCrystalEssence) crystalEssentiaStack.getItem()).getAspects(crystalEssentiaStack).getAspects()[0]; distributeAspectInformation(); if(inter.stackSize <= 0) entity.setDead(); entity.noClip = false; item.delayBeforeCanPickup = 60; worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); markDirty(); } else { entity.noClip = true; applyMovementVectors(entity); } } //Special to masterTile only! private void applyMovementVectors(EntityItem entity) { double var3 = (this.xCoord + 0.5D - entity.posX) / 15.0D; double var5 = (this.yCoord + 0.5D - entity.posY) / 15.0D; double var7 = (this.zCoord + 0.5D - entity.posZ) / 15.0D; double var9 = Math.sqrt(var3 * var3 + var5 * var5 + var7 * var7); double var11 = 1.0D - var9; if (var11 > 0.0D) { var11 *= var11; entity.motionX += var3 / var9 * var11 * 0.15D; entity.motionY += var5 / var9 * var11 * 0.25D; entity.motionZ += var7 / var9 * var11 * 0.15D; } } //Special to inputTile only! private void handleIO() { if ((!worldObj.isRemote) && ((ticksExisted & 15) == 0) && (getEssentiaAmount() < getMaxAmount())) { TileEntity te = ThaumcraftApiHelper.getConnectableTile(this.worldObj, this.xCoord, this.yCoord, this.zCoord, ForgeDirection.DOWN); if (te != null) { IEssentiaTransport ic = (IEssentiaTransport) te; if (!ic.canOutputTo(ForgeDirection.UP)) { return; } if ((holdingAspect != null) && (ic.getSuctionAmount(ForgeDirection.UP) < getSuctionAmount(ForgeDirection.DOWN))) { addToContainer(holdingAspect, ic.takeEssentia(holdingAspect, 1, ForgeDirection.UP)); } } } } @Override public void informItemRemoval() { if(!isMasterTile()) return; this.crystalEssentiaStack = null; this.holdingAspect = null; worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); markDirty(); distributeAspectInformation(); TileAuraPylon io = getInputTile(); if(io == null) return; io.amount = 0; worldObj.markBlockForUpdate(io.xCoord, io.yCoord, io.zCoord); io.markDirty(); } //We don't want the item to change at any given point... @Override public EntityPermNoClipItem.ItemChangeTask getAndRemoveScheduledChangeTask() { return null; } @Override public void broadcastItemStack(ItemStack itemStack) { this.crystalEssentiaStack = itemStack; } //Individual. //Returns true, if state has changed, false if still complete state. private boolean checkComponents() { TileAuraPylon te = getMasterTile(); if (te == null) { breakTile(); return true; } te = getInputTile(); if (te == null) { breakTile(); return true; } if(!hasTopTile()) { breakTile(); return true; } return false; } private boolean hasTopTile() { TileAuraPylon master = getMasterTile(); if(master == null) return false; TileEntity te = worldObj.getTileEntity(master.xCoord, master.yCoord + 1, master.zCoord); return !(te == null || !(te instanceof TileAuraPylonTop)); } //Individual. private void breakTile() { if(!isPartOfMultiblock || worldObj.isRemote) return; int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord); Block pylon = worldObj.getBlock(xCoord, yCoord, zCoord); if(pylon != null) { ArrayList<ItemStack> stacks = pylon.getDrops(worldObj, xCoord, yCoord, zCoord, meta, 0); for(ItemStack i : stacks) { EntityItem item = new EntityItem(worldObj, xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, i); //ItemUtils.applyRandomDropOffset(item, worldObj.rand); worldObj.spawnEntityInWorld(item); } } worldObj.removeTileEntity(xCoord, yCoord, zCoord); worldObj.setBlockToAir(xCoord, yCoord, zCoord); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } //Individual public boolean isPartOfMultiblock() { return isPartOfMultiblock; } //Individual. public void setPartOfMultiblock(boolean isPartOfMultiblock) { this.isPartOfMultiblock = isPartOfMultiblock; } //Individual. @Override public boolean canUpdate() { return true; } //Individual. public void setTileInformation(boolean isMaster, boolean isInput) { this.isMasterTile = isMaster; this.isInputTile = isInput; } //Individual. public boolean isInputTile() { return isInputTile; } //Individual. public TileAuraPylon getInputTile() { if (isInputTile()) return this; if(worldObj == null) return null; TileEntity superTile = worldObj.getTileEntity(xCoord, yCoord - 1, zCoord); if (superTile == null || !(superTile instanceof TileAuraPylon)) return null; return ((TileAuraPylon) superTile).getInputTile(); } //Individual. public boolean isMasterTile() { return isMasterTile; } //Individual. public TileAuraPylon getMasterTile() { if (isMasterTile()) return this; if(worldObj == null) return null; TileEntity superTile = worldObj.getTileEntity(xCoord, yCoord + 1, zCoord); if (superTile == null || !(superTile instanceof TileAuraPylon)) return null; return ((TileAuraPylon) superTile).getMasterTile(); } //Dynamic. public int getEssentiaAmount() { TileAuraPylon io = getInputTile(); if (io == null) return 0; return io.amount; } //Dynamic. public Aspect getAspectType() { TileAuraPylon io = getInputTile(); if (io == null) return null; return io.holdingAspect; } //Dynamic. public int getMaxAmount() { TileAuraPylon io = getInputTile(); if (io == null) return 0; int max = io.maxAmount; int counter = 1; TileEntity superTile = worldObj.getTileEntity(xCoord, yCoord + counter, zCoord); while (superTile != null && superTile instanceof TileAuraPylon) { max += ((TileAuraPylon) superTile).maxAmount; counter++; superTile = worldObj.getTileEntity(xCoord, yCoord + counter, zCoord); } return max; } @Override public void readCustomNBT(NBTTagCompound compound) { this.isInputTile = compound.getBoolean("input"); this.isMasterTile = compound.getBoolean("master"); String tag = compound.getString("aspect"); if (tag != null && !tag.equals("")) { this.holdingAspect = Aspect.getAspect(tag); } else { this.holdingAspect = null; } this.amount = compound.getInteger("amount"); this.maxAmount = compound.getInteger("maxAmount"); this.isPartOfMultiblock = compound.getBoolean("partOfMultiblock"); this.crystalEssentiaStack = NBTHelper.getStack(compound, "crystalStack"); } @Override public void writeCustomNBT(NBTTagCompound compound) { compound.setBoolean("input", isInputTile); compound.setBoolean("master", isMasterTile); if (holdingAspect != null) { compound.setString("aspect", holdingAspect.getTag()); } compound.setInteger("amount", amount); compound.setInteger("maxAmount", maxAmount); compound.setBoolean("partOfMultiblock", isPartOfMultiblock); if(crystalEssentiaStack != null) NBTHelper.setStack(compound, "crystalStack", crystalEssentiaStack); } /////////////////////////////////////////////////////////////////////////////////////////////// // IAspectContainer /////////////////////////////////////////////////////////////////////////////////////////////// //Dynamic. @Override public AspectList getAspects() { TileAuraPylon io = getInputTile(); AspectList al = new AspectList(); if (io != null && io.holdingAspect != null && io.amount > 0) { al.add(io.holdingAspect, io.amount); } return al; } //NO-OP @Override public void setAspects(AspectList aspectList) { } //Individual. @Override public boolean doesContainerAccept(Aspect aspect) { return isInputTile() && holdingAspect != null && holdingAspect.equals(aspect); } //Individual. @Override public int addToContainer(Aspect aspect, int amount) { if (amount == 0) { return amount; } if (!isInputTile()) return 0; if (aspect == null) return 0; if (holdingAspect != null && this.amount < getMaxAmount() && aspect == holdingAspect) { int added = Math.min(amount, getMaxAmount() - this.amount); this.amount += added; amount -= added; this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); markDirty(); } return amount; } //Individual. @Override public boolean takeFromContainer(Aspect aspect, int i) { if (!isInputTile()) return false; if (aspect == null || holdingAspect == null) return false; if (this.amount >= i && holdingAspect.equals(aspect)) { this.amount -= i; if (this.amount <= 0) { this.holdingAspect = null; this.amount = 0; } this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); markDirty(); return true; } return false; } //Individual. //You may only extract 1 at a time. @Override public boolean takeFromContainer(AspectList aspectList) { return false; } //Individual. @Override public boolean doesContainerContainAmount(Aspect aspect, int i) { return isInputTile() && holdingAspect != null && this.amount >= i && aspect == holdingAspect; } //Individual. @Override public boolean doesContainerContain(AspectList list) { if (!isInputTile()) return false; if (holdingAspect == null) return false; for (Aspect a : list.getAspects()) if ((this.amount > 0) && (a == holdingAspect)) return true; return false; } //Individual. @Override public int containerContains(Aspect aspect) { return 0; } /////////////////////////////////////////////////////////////////////////////////////////////// // IEssentiaTransport /////////////////////////////////////////////////////////////////////////////////////////////// //Individual. @Override public boolean isConnectable(ForgeDirection face) { return isInputTile() && face == ForgeDirection.DOWN; } //Individual. @Override public boolean canInputFrom(ForgeDirection face) { return isInputTile() && face == ForgeDirection.DOWN; } //Individual. @Override public boolean canOutputTo(ForgeDirection face) { return false; } //NO-OP @Override public void setSuction(Aspect aspect, int i) { } //Individual. @Override public Aspect getSuctionType(ForgeDirection forgeDirection) { return isInputTile() ? holdingAspect : null; } @Override public int getSuctionAmount(ForgeDirection forgeDirection) { if (!isInputTile()) return 0; if (holdingAspect == null) return 0; return getMinimumSuction(); } @Override public int takeEssentia(Aspect aspect, int amt, ForgeDirection direction) { return 0; } @Override public int addEssentia(Aspect aspect, int amt, ForgeDirection direction) { if (!isInputTile()) return 0; return canInputFrom(direction) ? amount - addToContainer(aspect, amount) : 0; } //Individual. @Override public Aspect getEssentiaType(ForgeDirection forgeDirection) { return isInputTile() ? holdingAspect : null; } //Individual. @Override public int getEssentiaAmount(ForgeDirection forgeDirection) { return isInputTile() ? amount : 0; } @Override public int getMinimumSuction() { return 64; } //Individual. @Override public boolean renderExtendedTube() { return false; } public boolean isLowestTile() { if(worldObj == null) return false; TileEntity te = worldObj.getTileEntity(xCoord, yCoord - 1, zCoord); return te == null || !(te instanceof TileAuraPylon); } }