/* * This file ("TileEntityBase.java") is part of the Actually Additions mod for Minecraft. * It is created and owned by Ellpeck and distributed * under the Actually Additions License to be found at * http://ellpeck.de/actaddlicense * View the source code at https://github.com/Ellpeck/ActuallyAdditions * * © 2015-2017 Ellpeck */ package de.ellpeck.actuallyadditions.mod.tile; import de.ellpeck.actuallyadditions.mod.ActuallyAdditions; import de.ellpeck.actuallyadditions.mod.config.values.ConfigIntValues; import de.ellpeck.actuallyadditions.mod.network.PacketHandler; import de.ellpeck.actuallyadditions.mod.network.PacketServerToClient; import de.ellpeck.actuallyadditions.mod.util.WorldUtil; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.energy.IEnergyStorage; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; public abstract class TileEntityBase extends TileEntity implements ITickable{ public final String name; public boolean isRedstonePowered; public boolean isPulseMode; public boolean stopFromDropping; protected int ticksElapsed; protected TileEntity[] tilesAround = new TileEntity[6]; protected boolean hasSavedDataOnChangeOrWorldStart; public TileEntityBase(String name){ this.name = name; } public static void init(){ ActuallyAdditions.LOGGER.info("Registering TileEntities..."); register(TileEntityCompost.class); register(TileEntityFeeder.class); register(TileEntityGiantChest.class); register(TileEntityGiantChestMedium.class); register(TileEntityGiantChestLarge.class); register(TileEntityGrinder.class); register(TileEntityFurnaceDouble.class); register(TileEntityInputter.class); register(TileEntityFishingNet.class); register(TileEntityFurnaceSolar.class); register(TileEntityHeatCollector.class); register(TileEntityItemRepairer.class); register(TileEntityBreaker.class); register(TileEntityDropper.class); register(TileEntityInputterAdvanced.class); register(TileEntityPlacer.class); register(TileEntityGrinderDouble.class); register(TileEntityCanolaPress.class); register(TileEntityFermentingBarrel.class); register(TileEntityOilGenerator.class); register(TileEntityCoalGenerator.class); register(TileEntityPhantomItemface.class); register(TileEntityPhantomLiquiface.class); register(TileEntityPhantomEnergyface.class); register(TileEntityPlayerInterface.class); register(TileEntityPhantomPlacer.class); register(TileEntityPhantomBreaker.class); register(TileEntityFluidCollector.class); register(TileEntityFluidPlacer.class); register(TileEntityLavaFactoryController.class); register(TileEntityCoffeeMachine.class); register(TileEntityPhantomBooster.class); register(TileEntityEnergizer.class); register(TileEntityEnervator.class); register(TileEntityXPSolidifier.class); register(TileEntitySmileyCloud.class); register(TileEntityLeafGenerator.class); register(TileEntityDirectionalBreaker.class); register(TileEntityRangedCollector.class); register(TileEntityAtomicReconstructor.class); register(TileEntityMiner.class); register(TileEntityFireworkBox.class); register(TileEntityPhantomRedstoneface.class); register(TileEntityLaserRelayItem.class); register(TileEntityLaserRelayEnergy.class); register(TileEntityLaserRelayEnergyAdvanced.class); register(TileEntityLaserRelayEnergyExtreme.class); register(TileEntityLaserRelayItemWhitelist.class); register(TileEntityItemViewer.class); register(TileEntityDisplayStand.class); register(TileEntityShockSuppressor.class); register(TileEntityEmpowerer.class); register(TileEntityLaserRelayFluids.class); register(TileEntityBioReactor.class); register(TileEntityFarmer.class); register(TileEntityItemViewerHopping.class); register(TileEntityBatteryBox.class); } private static void register(Class tileClass){ try{ //This is hacky and dirty but it works so whatever String name = ActuallyAdditions.MODID+":"+tileClass.newInstance().name; GameRegistry.registerTileEntity(tileClass, name); } catch(Exception e){ ActuallyAdditions.LOGGER.fatal("Registering a TileEntity failed!", e); } } @Override public final NBTTagCompound writeToNBT(NBTTagCompound compound){ this.writeSyncableNBT(compound, NBTType.SAVE_TILE); return compound; } @Override public final void readFromNBT(NBTTagCompound compound){ this.readSyncableNBT(compound, NBTType.SAVE_TILE); } @Override public final SPacketUpdateTileEntity getUpdatePacket(){ NBTTagCompound compound = new NBTTagCompound(); this.writeSyncableNBT(compound, NBTType.SYNC); return new SPacketUpdateTileEntity(this.pos, -1, compound); } @Override public final void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt){ this.readSyncableNBT(pkt.getNbtCompound(), NBTType.SYNC); } @Override public final NBTTagCompound getUpdateTag(){ NBTTagCompound compound = new NBTTagCompound(); this.writeSyncableNBT(compound, NBTType.SYNC); return compound; } @Override public final void handleUpdateTag(NBTTagCompound compound){ this.readSyncableNBT(compound, NBTType.SYNC); } public final void sendUpdate(){ if(this.world != null && !this.world.isRemote){ NBTTagCompound compound = new NBTTagCompound(); this.writeSyncableNBT(compound, NBTType.SYNC); NBTTagCompound data = new NBTTagCompound(); data.setTag("Data", compound); data.setInteger("X", this.pos.getX()); data.setInteger("Y", this.pos.getY()); data.setInteger("Z", this.pos.getZ()); PacketHandler.theNetwork.sendToAllAround(new PacketServerToClient(data, PacketHandler.TILE_ENTITY_HANDLER), new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ(), 64)); } } public void writeSyncableNBT(NBTTagCompound compound, NBTType type){ if(type != NBTType.SAVE_BLOCK) super.writeToNBT(compound); if(type == NBTType.SAVE_TILE){ compound.setBoolean("Redstone", this.isRedstonePowered); compound.setInteger("TicksElapsed", this.ticksElapsed); compound.setBoolean("StopDrop", this.stopFromDropping); } else if(type == NBTType.SYNC && stopFromDropping) compound.setBoolean("StopDrop", this.stopFromDropping); if(this.isRedstoneToggle() && (type != NBTType.SAVE_BLOCK || this.isPulseMode)){ compound.setBoolean("IsPulseMode", this.isPulseMode); } } public void readSyncableNBT(NBTTagCompound compound, NBTType type){ if(type != NBTType.SAVE_BLOCK) super.readFromNBT(compound); if(type == NBTType.SAVE_TILE){ this.isRedstonePowered = compound.getBoolean("Redstone"); this.ticksElapsed = compound.getInteger("TicksElapsed"); this.stopFromDropping = compound.getBoolean("StopDrop"); } else if(type == NBTType.SYNC) this.stopFromDropping = compound.getBoolean("StopDrop"); if(this.isRedstoneToggle()){ this.isPulseMode = compound.getBoolean("IsPulseMode"); } } @Override public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState){ return !oldState.getBlock().isAssociatedBlock(newState.getBlock()); } public String getNameForTranslation(){ return "container."+ActuallyAdditions.MODID+"."+this.name+".name"; } @Override public ITextComponent getDisplayName(){ return new TextComponentTranslation(this.getNameForTranslation()); } @Override public final void update(){ this.updateEntity(); } public int getComparatorStrength(){ return 0; } public void updateEntity(){ this.ticksElapsed++; if(!this.world.isRemote){ if(this instanceof ISharingEnergyProvider){ ISharingEnergyProvider provider = (ISharingEnergyProvider)this; if(provider.doesShareEnergy()){ int total = provider.getEnergyToSplitShare(); if(total > 0){ EnumFacing[] sides = provider.getEnergyShareSides(); int amount = total/sides.length; if(amount <= 0){ amount = total; } for(EnumFacing side : sides){ TileEntity tile = this.tilesAround[side.ordinal()]; if(tile != null && provider.canShareTo(tile)){ WorldUtil.doEnergyInteraction(this, tile, side, amount); } } } } } if(this instanceof ISharingFluidHandler){ ISharingFluidHandler handler = (ISharingFluidHandler)this; if(handler.doesShareFluid()){ int total = handler.getMaxFluidAmountToSplitShare(); if(total > 0){ EnumFacing[] sides = handler.getFluidShareSides(); int amount = total/sides.length; if(amount <= 0){ amount = total; } for(EnumFacing side : sides){ TileEntity tile = this.tilesAround[side.ordinal()]; if(tile != null){ WorldUtil.doFluidInteraction(this, tile, side, amount); } } } } } if(!this.hasSavedDataOnChangeOrWorldStart){ if(this.shouldSaveDataOnChangeOrWorldStart()){ this.saveDataOnChangeOrWorldStart(); } this.hasSavedDataOnChangeOrWorldStart = true; } } } public void saveDataOnChangeOrWorldStart(){ for(EnumFacing side : EnumFacing.values()){ BlockPos pos = this.pos.offset(side); if(this.world.isBlockLoaded(pos)){ this.tilesAround[side.ordinal()] = this.world.getTileEntity(pos); } } } public boolean shouldSaveDataOnChangeOrWorldStart(){ return this instanceof ISharingEnergyProvider || this instanceof ISharingFluidHandler; } public void setRedstonePowered(boolean powered){ this.isRedstonePowered = powered; this.markDirty(); } public boolean canPlayerUse(EntityPlayer player){ return player.getDistanceSq(this.getPos().getX()+0.5D, this.pos.getY()+0.5D, this.pos.getZ()+0.5D) <= 64 && !this.isInvalid() && this.world.getTileEntity(this.pos) == this; } protected boolean sendUpdateWithInterval(){ if(this.ticksElapsed%ConfigIntValues.TILE_ENTITY_UPDATE_INTERVAL.getValue() == 0){ this.sendUpdate(); return true; } else{ return false; } } @Override public boolean hasCapability(Capability capability, EnumFacing facing){ return this.getCapability(capability, facing) != null; } @SuppressWarnings("unchecked") @Override public T getCapability(Capability capability, EnumFacing facing){ if(capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY){ IItemHandler handler = this.getItemHandler(facing); if(handler != null){ return (T)handler; } } else if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY){ IFluidHandler tank = this.getFluidHandler(facing); if(tank != null){ return (T)tank; } } else if(capability == CapabilityEnergy.ENERGY){ IEnergyStorage storage = this.getEnergyStorage(facing); if(storage != null){ return (T)storage; } } return super.getCapability(capability, facing); } public IFluidHandler getFluidHandler(EnumFacing facing){ return null; } public IEnergyStorage getEnergyStorage(EnumFacing facing){ return null; } public IItemHandler getItemHandler(EnumFacing facing){ return null; } public boolean isRedstoneToggle(){ return false; } public void activateOnPulse(){ } public boolean respondsToPulses(){ return this.isRedstoneToggle() && this.isPulseMode; } public enum NBTType { /** * Use when normal writeToNBT/readToNBT is expected. */ SAVE_TILE, /** * Use when data needs to be sent to the client. */ SYNC, /** * Wat */ SAVE_BLOCK } }