package com.rwtema.funkylocomotion.blocks; import com.rwtema.funkylocomotion.EntityMovingEventHandler; import com.rwtema.funkylocomotion.Proxy; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; 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.AxisAlignedBB; import net.minecraft.util.math.Vec3d; import net.minecraftforge.fml.relauncher.Side; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public abstract class TileMovingBase extends TileEntity implements ITickable { private static final AxisAlignedBB[] blank = new AxisAlignedBB[0]; public final Side side; public AxisAlignedBB[] collisions = blank; public boolean isAir = true; public int time = 0; public int maxTime = 0; public NBTTagCompound block; public NBTTagCompound desc; public int dir = -1; public int lightLevel = 0; public int lightOpacity = 255; public int scheduledTickTime = -1; public int scheduledTickPriority; public TileMovingBase(Side side) { this.side = side; } public static boolean _Immovable() { return true; } private static NBTTagCompound NBTAxis(AxisAlignedBB bb) { NBTTagCompound tag = new NBTTagCompound(); tag.setFloat("a", (float) bb.minX); tag.setFloat("b", (float) bb.minY); tag.setFloat("c", (float) bb.minZ); tag.setFloat("d", (float) bb.maxX); tag.setFloat("e", (float) bb.maxY); tag.setFloat("f", (float) bb.maxZ); return tag; } private static AxisAlignedBB AxisNBT(NBTTagCompound tag) { return new AxisAlignedBB( tag.getFloat("a"), tag.getFloat("b"), tag.getFloat("c"), tag.getFloat("d"), tag.getFloat("e"), tag.getFloat("f") ); } protected static AxisAlignedBB[] AxisTags(NBTTagList tagList) { final int n = tagList.tagCount(); AxisAlignedBB[] bbs = new AxisAlignedBB[n]; for (int i = 0; i < n; i++) bbs[i] = AxisNBT(tagList.getCompoundTagAt(i)); return bbs; } protected static NBTTagList TagsAxis(AxisAlignedBB[] bbs) { NBTTagList tagList = new NBTTagList(); for (AxisAlignedBB bb : bbs) tagList.appendTag(NBTAxis(bb)); return tagList; } @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); block = tag.getCompoundTag("BlockTag"); desc = tag.getCompoundTag("DescTag"); time = tag.getInteger("Time"); maxTime = tag.getInteger("MaxTime"); dir = tag.getByte("Dir"); isAir = block.hasNoTags(); if (tag.hasKey("Collisions", 10)) collisions = AxisTags(tag.getTagList("Collisions", 10)); lightLevel = tag.getByte("Light"); lightOpacity = tag.getShort("Opacity"); if (tag.hasKey("TimeTime", 3)) { scheduledTickTime = tag.getInteger("TickTime"); scheduledTickPriority = tag.getInteger("TickPriority"); } } @Override @Nonnull public NBTTagCompound writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); if (block != null) tag.setTag("BlockTag", block); if (desc != null) tag.setTag("DescTag", desc); tag.setInteger("Time", time); tag.setInteger("MaxTime", maxTime); tag.setByte("Dir", (byte) dir); if (collisions.length > 0) tag.setTag("Collisions", TagsAxis(collisions)); if (lightLevel != 0) tag.setByte("Light", (byte) lightLevel); if (lightOpacity != 0) tag.setShort("Opacity", (short) lightOpacity); if (scheduledTickTime != -1) { tag.setInteger("TickTime", scheduledTickTime); tag.setInteger("TickPriority", scheduledTickPriority); } return tag; } @Nullable public EnumFacing getDir() { if (dir < 0 || dir >= 6) return null; return EnumFacing.values()[this.dir]; } public Vec3d getMovVec() { double d = 1.0 / maxTime; if (dir < 0 || dir >= 6) return Vec3d.ZERO; EnumFacing dir = EnumFacing.values()[this.dir]; return new Vec3d(dir.getFrontOffsetX() * d, dir.getFrontOffsetY() * d, dir.getFrontOffsetZ() * d); } @Override public void update() { if (maxTime == 0) return; if (getWorld().isRemote) { time = time + 1 - 1; } Vec3d mov = getMovVec(); Set<Entity> entityList = new HashSet<>(); time++; for (AxisAlignedBB bb : getTransformedColisions()) { List<Entity> entities = getWorld().getEntitiesWithinAABB(Entity.class, bb.expand(0, 0.1, 0)); for (Entity entity : entities) { entityList.add(entity); } } for (Entity a : entityList) { if (!a.isDead) { Map<Entity, Vec3d> map = EntityMovingEventHandler.getMovementMap(side); if (!map.containsKey(a)) { for (AxisAlignedBB bb : getTransformedColisions()) { AxisAlignedBB boundingBox = a.getEntityBoundingBox(); if (boundingBox.intersectsWith(bb)) { if (boundingBox.minY > bb.maxY - 0.2) { a.setEntityBoundingBox(boundingBox.offset(0, bb.maxY - boundingBox.minY, 0)); } } else if (dir == 0 && a.motionY <= 0 && boundingBox.intersectsWith(bb.offset(0, 0.2, 0))) { a.setEntityBoundingBox(boundingBox.offset(0, bb.maxY - boundingBox.minY, 0)); } } EntityMovingEventHandler.moveEntity(a, mov.xCoord, mov.yCoord, mov.zCoord); map.put(a, null); } } } } public AxisAlignedBB getCombinedCollisions(boolean renderOffset, boolean shrink) { if (isAir) return Block.NULL_AABB; AxisAlignedBB bb = null; for (AxisAlignedBB collision : collisions) { if (bb == null) { bb = collision; } else bb = bb.union(collision); } EnumFacing dir = this.getDir(); if (dir != null) { TileEntity other = getWorld().getTileEntity(pos.offset(dir)); if (other instanceof TileMovingBase) { AxisAlignedBB[] bbs1 = ((TileMovingBase) other).collisions; for (AxisAlignedBB bb1 : bbs1) { if (bb == null) bb = bb1.offset(dir.getFrontOffsetX(), dir.getFrontOffsetY(), dir.getFrontOffsetZ()); else bb = bb.union(bb1.offset(dir.getFrontOffsetX(), dir.getFrontOffsetY(), dir.getFrontOffsetZ())); } } } if (bb == null) return null; double h = offset(renderOffset); if (dir != null) { bb = bb.offset(h * dir.getFrontOffsetX(), h * dir.getFrontOffsetY(), h * dir.getFrontOffsetZ()); } else if (shrink) { double mult = this.dir == 6 ? h + 1 : -h; bb = new AxisAlignedBB( 0.5 + mult * (bb.minX - 0.5), 0.5 + mult * (bb.minY - 0.5), 0.5 + mult * (bb.minZ - 0.5), 0.5 + mult * (bb.maxX - 0.5), 0.5 + mult * (bb.maxY - 0.5), 0.5 + mult * (bb.maxZ - 0.5)); } return bb; } public AxisAlignedBB[] getTransformedColisions() { double h = offset(false); EnumFacing dir = getDir(); if (dir != null && h != 0) { AxisAlignedBB[] tbbs = new AxisAlignedBB[collisions.length]; for (int i = 0; i < collisions.length; i++) { tbbs[i] = collisions[i].offset(h * dir.getFrontOffsetX(), h * dir.getFrontOffsetY(), h * dir.getFrontOffsetZ()).offset(pos); } return tbbs; } else { return collisions; } } public float progress() { return time >= maxTime ? 1 : (time + Proxy.renderTimeOffset) / (maxTime); } public double offset(boolean t) { if (time >= maxTime) return 0; float f = t ? Proxy.renderTimeOffset : 0; return (time + f) / (maxTime) - 1; } @Nullable @Override public SPacketUpdateTileEntity getUpdatePacket() { return new SPacketUpdateTileEntity(this.pos, 0, this.getUpdateTag()); } @Override public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { handleUpdateTag(pkt.getNbtCompound()); } }