package com.hbm.tileentity; import java.util.HashSet; import java.util.Set; import com.hbm.blocks.BlockDummyable; import com.hbm.blocks.generic.BlockDoorGeneric; import com.hbm.lib.Library; import com.hbm.main.MainRegistry; import com.hbm.render.anim.HbmAnimations.Animation; import com.hbm.sound.AudioWrapper; import com.hbm.tileentity.machine.TileEntityLockableBase; import com.hbm.util.fauxpointtwelve.BlockPos; import com.hbm.util.fauxpointtwelve.Rotation; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import net.minecraftforge.common.util.ForgeDirection; public class TileEntityDoorGeneric extends TileEntityLockableBase { public static final byte STATE_CLOSED = 0; public static final byte STATE_OPEN = 1; public static final byte STATE_CLOSING = 2; public static final byte STATE_OPENING = 3; //0: closed, 1: open, 2: closing, 3: opening public byte state = STATE_CLOSED; protected DoorDecl doorType; public int openTicks = 0; public long animStartTime = 0; public int redstonePower; public boolean shouldUseBB = false; private byte skinIndex = 0; public Set activatedBlocks = new HashSet<>(4); private AudioWrapper audio; private AudioWrapper audio2; public Animation currentAnimation; @Override public void updateEntity() { if(state == STATE_OPENING) { openTicks++; if(openTicks >= getDoorType().timeToOpen()) openTicks = getDoorType().timeToOpen(); } else if(state == STATE_CLOSING) { openTicks--; if(openTicks <= 0) openTicks = 0; } if(!worldObj.isRemote) { BlockPos pos = new BlockPos(this); int[][] ranges = getDoorType().getDoorOpenRanges(); ForgeDirection dir = ForgeDirection.getOrientation(getBlockMetadata() - BlockDummyable.offset); if(state == STATE_OPENING) { for(int i = 0; i < ranges.length; i++) { int[] range = ranges[i]; BlockPos startPos = new BlockPos(range[0], range[1], range[2]); float time = getDoorType().getDoorRangeOpenTime(openTicks, i); for(int j = 0; j < Math.abs(range[3]); j++) { if((float)j / (Math.abs(range[3] - 1)) > time) break; for(int k = 0; k < range[4]; k++) { BlockPos add = new BlockPos(0, 0, 0); switch(range[5]) { case 0: add = new BlockPos(0, k, (int)Math.signum(range[3]) * j); break; case 1: add = new BlockPos(k, (int)Math.signum(range[3]) * j, 0); break; case 2: add = new BlockPos((int)Math.signum(range[3]) * j, k, 0); break; } Rotation r = Rotation.getBlockRotation(dir); if(dir == Library.POS_X || dir == Library.NEG_X) r = r.add(Rotation.CLOCKWISE_180); BlockPos finalPos = startPos.add(add).rotate(r).add(pos); if(finalPos.equals(pos)) { this.shouldUseBB = false; } else { ((BlockDummyable)getBlockType()).makeExtra(worldObj, finalPos.getX(), finalPos.getY(), finalPos.getZ()); } } } } } else if(state == STATE_CLOSING) { for(int i = 0; i < ranges.length; i++) { int[] range = ranges[i]; BlockPos startPos = new BlockPos(range[0], range[1], range[2]); float time = getDoorType().getDoorRangeOpenTime(openTicks, i); for(int j = Math.abs(range[3])-1; j >= 0; j--) { if((float)j / (Math.abs(range[3] - 1)) < time) break; for(int k = 0; k < range[4]; k++) { BlockPos add = new BlockPos(0, 0, 0); switch(range[5]) { case 0: add = new BlockPos(0, k, (int)Math.signum(range[3]) * j); break; case 1: add = new BlockPos(k, (int)Math.signum(range[3]) * j, 0); break; case 2: add = new BlockPos((int)Math.signum(range[3]) * j, k, 0); break; } Rotation r = Rotation.getBlockRotation(dir); if(dir == Library.POS_X || dir == Library.NEG_X) r = r.add(Rotation.CLOCKWISE_180); BlockPos finalPos = startPos.add(add).rotate(r).add(pos); if(finalPos.equals(pos)) { this.shouldUseBB = false; } else { ((BlockDummyable)getBlockType()).removeExtra(worldObj, finalPos.getX(), finalPos.getY(), finalPos.getZ()); } } } } } if(state == STATE_OPENING && openTicks == getDoorType().timeToOpen()) { state = STATE_OPEN; } if(state == STATE_CLOSING && openTicks == 0) { state = STATE_CLOSED; } this.networkPackNT(100); if(redstonePower == -1 && state == STATE_OPEN) { tryToggle(-1); } else if(redstonePower > 0 && state == STATE_CLOSED) { tryToggle(-1); } if(redstonePower == -1) { redstonePower = 0; } } } @Override public void serialize(ByteBuf buf) { buf.writeByte(state); buf.writeByte(skinIndex); buf.writeBoolean(shouldUseBB); } @Override public void deserialize(ByteBuf buf) { handleNewState(buf.readByte()); skinIndex = buf.readByte(); shouldUseBB = buf.readBoolean(); } @Override public void onChunkUnload() { if(audio != null) { audio.stopSound(); audio = null; } if(audio2 != null) { audio2.stopSound(); audio2 = null; } } public DoorDecl getDoorType() { if(this.doorType == null && this.getBlockType() instanceof BlockDoorGeneric) this.doorType = ((BlockDoorGeneric)this.getBlockType()).type; return this.doorType; } public boolean tryToggle(EntityPlayer player) { if(this.isLocked() && player == null) return false; if(state == STATE_CLOSED && redstonePower > 0) { //Redstone "power locks" doors, just like minecraft iron doors return false; } if(this.state == STATE_CLOSED) { if(!worldObj.isRemote && canAccess(player)) this.state = STATE_OPENING; return true; } else if(this.state == STATE_OPEN) { if(!worldObj.isRemote && canAccess(player)) this.state = STATE_CLOSING; return true; } return false; } public boolean tryToggle(int passcode) { if(this.isLocked() && passcode != this.lock) return false; if(this.state == STATE_CLOSED) { if(!worldObj.isRemote) this.state = STATE_OPENING; return true; } else if(this.state == STATE_OPEN) { if(!worldObj.isRemote) this.state = STATE_CLOSING; return true; } return false; } @SideOnly(Side.CLIENT) public void handleNewState(byte state) { if(this.state != state) { DoorDecl doorType = getDoorType(); if(this.state == STATE_CLOSED && state == STATE_OPENING) { // Door transitioning to open if(audio != null) { audio.stopSound(); audio.setKeepAlive(0); } if(doorType.getOpenSoundLoop() != null) { audio = MainRegistry.proxy.getLoopedSound(doorType.getOpenSoundLoop(), xCoord, yCoord, zCoord, doorType.getSoundVolume(), 10F, 1F); audio.startSound(); } if(doorType.getOpenSoundStart() != null) { worldObj.playSound(xCoord, yCoord, zCoord, doorType.getOpenSoundStart(), doorType.getSoundVolume(), 1F, false); } if(doorType.getSoundLoop2() != null) { if(audio2 != null) audio2.stopSound(); audio2 = MainRegistry.proxy.getLoopedSound(doorType.getSoundLoop2(), xCoord, yCoord, zCoord, doorType.getSoundVolume(), 10F, 1F); audio2.startSound(); } } if(this.state == STATE_OPEN && state == STATE_CLOSING) { // Door transitioning to closed if(audio != null) { audio.stopSound(); } if(doorType.getCloseSoundLoop() != null) { audio = MainRegistry.proxy.getLoopedSound(doorType.getCloseSoundLoop(), xCoord, yCoord, zCoord, doorType.getSoundVolume(), 10F, 1F); audio.startSound(); } if(doorType.getCloseSoundStart() != null) { worldObj.playSound(xCoord, yCoord, zCoord, doorType.getCloseSoundStart(), doorType.getSoundVolume(), 1F, false); } if(doorType.getSoundLoop2() != null) { if(audio2 != null) audio2.stopSound(); audio2 = MainRegistry.proxy.getLoopedSound(doorType.getSoundLoop2(), xCoord, yCoord, zCoord, doorType.getSoundVolume(), 10F, 1F); audio2.startSound(); } } if(state == STATE_OPEN || state == STATE_CLOSED) { // Door finished any transition if(audio != null) { audio.stopSound(); audio = null; } if(audio2 != null) { audio2.stopSound(); audio2 = null; } } if(this.state == STATE_OPENING && state == STATE_OPEN) { // Door finished transitioning to open if(doorType.getOpenSoundEnd() != null) { worldObj.playSound(xCoord, yCoord, zCoord, doorType.getOpenSoundEnd(), doorType.getSoundVolume(), 1F, false); } } if(this.state == STATE_CLOSING && state == STATE_CLOSED) { // Door finished transitioning to closed if(doorType.getCloseSoundEnd() != null) { worldObj.playSound(xCoord, yCoord, zCoord, doorType.getCloseSoundEnd(), doorType.getSoundVolume(), 1F, false); } } this.state = state; if(state == STATE_OPENING || state == STATE_CLOSING) { animStartTime = System.currentTimeMillis(); currentAnimation = this.doorType.getSEDNAAnim(state, this.skinIndex); } } } public int getSkinIndex() { return skinIndex; } public boolean cycleSkinIndex() { if(!getDoorType().hasSkins()) return false; this.skinIndex++; this.skinIndex %= getDoorType().getSkinCount(); this.markDirty(); return true; } /**Useful for logic block interactions, as a way to close/open doors**/ public void open(){ if(state == STATE_CLOSED) state = STATE_OPENING; } public void close() { if(state == STATE_OPEN) state = STATE_CLOSING; } @Override public AxisAlignedBB getRenderBoundingBox() { return INFINITE_EXTENT_AABB; } @Override public double getMaxRenderDistanceSquared() { return 65536D; } @Override public void readFromNBT(NBTTagCompound tag) { this.state = tag.getByte("state"); this.openTicks = tag.getInteger("openTicks"); this.animStartTime = tag.getInteger("animStartTime"); this.redstonePower = tag.getInteger("redstoned"); this.shouldUseBB = tag.getBoolean("shouldUseBB"); this.skinIndex = tag.getByte("skin"); NBTTagCompound activatedBlocks = tag.getCompoundTag("activatedBlocks"); this.activatedBlocks.clear(); for(int i = 0; i < activatedBlocks.func_150296_c().size() / 3; i++) { this.activatedBlocks.add(new BlockPos(activatedBlocks.getInteger("x" + i), activatedBlocks.getInteger("y" + i), activatedBlocks.getInteger("z" + i))); } super.readFromNBT(tag); } @Override public void writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); tag.setByte("state", state); tag.setInteger("openTicks", openTicks); tag.setLong("animStartTime", animStartTime); tag.setInteger("redstoned", redstonePower); tag.setBoolean("shouldUseBB", shouldUseBB); if(getDoorType().hasSkins()) tag.setByte("skin", skinIndex); NBTTagCompound activatedBlocks = new NBTTagCompound(); int i = 0; for(BlockPos p : this.activatedBlocks) { activatedBlocks.setInteger("x" + i, p.getX()); activatedBlocks.setInteger("y" + i, p.getY()); activatedBlocks.setInteger("z" + i, p.getZ()); i++; } tag.setTag("activatedBlocks", activatedBlocks); } @Override public void validate() { super.validate(); } @Override public void invalidate() { super.invalidate(); if(audio != null) { audio.stopSound(); audio = null; } if(audio2 != null) { audio2.stopSound(); audio2 = null; } } public void updateRedstonePower(int x, int y, int z) { //Drillgon200: Best I could come up with without having to use dummy tile entities BlockPos pos = new BlockPos(x, y, z); boolean powered = worldObj.isBlockIndirectlyGettingPowered(x, y, z); boolean contained = activatedBlocks.contains(pos); if(!contained && powered) { activatedBlocks.add(pos); if(redstonePower == -1) { redstonePower = 0; } redstonePower++; } else if(contained && !powered) { activatedBlocks.remove(pos); redstonePower--; if(redstonePower == 0) { redstonePower = -1; } } } }