/** * Copyright (c) 2011-2015, SpaceToad and the BuildCraft Team * http://www.mod-buildcraft.com * <p/> * BuildCraft is distributed under the terms of the Minecraft Mod Public * License 1.0, or MMPL. Please check the contents of the license located in * http://www.mod-buildcraft.com/MMPL-1.0.txt */ package buildcraft.core.builders; import java.util.Date; import java.util.LinkedList; import java.util.List; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.MathHelper; import net.minecraftforge.common.util.Constants; import buildcraft.BuildCraftCore; import buildcraft.api.blueprints.IBuilderContext; import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.MappingRegistry; import buildcraft.api.core.ISerializable; import buildcraft.api.core.Position; import buildcraft.core.BlockBuildTool; import buildcraft.core.StackAtPosition; import buildcraft.core.lib.inventory.InvUtils; public class BuildingItem implements IBuildingItem, ISerializable { public static int ITEMS_SPACE = 2; public Position origin, destination; public LinkedList<StackAtPosition> stacksToDisplay = new LinkedList<StackAtPosition>(); public boolean isDone = false; public BuildingSlot slotToBuild; public IBuilderContext context; private long previousUpdate; private float lifetimeDisplay = 0; private float maxLifetime = 0; private boolean initialized = false; private double vx, vy, vz; private double maxHeight; private float lifetime = 0; public void initialize() { if (!initialized) { double dx = destination.x - origin.x; double dy = destination.y - origin.y; double dz = destination.z - origin.z; double size = Math.sqrt(dx * dx + dy * dy + dz * dz); maxLifetime = (float) size * 4; // maxHeight = 5.0 + (destination.y - origin.y) / 2.0; maxHeight = size / 2; // the below computation is an approximation of the distance to // travel for the object. It really follows a sinus, but we compute // the size of a triangle for simplification. Position middle = new Position(); middle.x = (destination.x + origin.x) / 2; middle.y = (destination.y + origin.y) / 2; middle.z = (destination.z + origin.z) / 2; Position top = new Position(); top.x = middle.x; top.y = middle.y + maxHeight; top.z = middle.z; Position originToTop = new Position(); originToTop.x = top.x - origin.x; originToTop.y = top.y - origin.y; originToTop.z = top.z - origin.z; Position destinationToTop = new Position(); destinationToTop.x = destination.x - origin.x; destinationToTop.y = destination.y - origin.y; destinationToTop.z = destination.z - origin.z; double d1 = Math.sqrt(originToTop.x * originToTop.x + originToTop.y * originToTop.y + originToTop.z * originToTop.z); double d2 = Math.sqrt(destinationToTop.x * destinationToTop.x + destinationToTop.y * destinationToTop.y + destinationToTop.z * destinationToTop.z); d1 = d1 / size * maxLifetime; d2 = d2 / size * maxLifetime; maxLifetime = (float) d1 + (float) d2; vx = dx / maxLifetime; vy = dy / maxLifetime; vz = dz / maxLifetime; if (stacksToDisplay.size() == 0) { StackAtPosition sPos = new StackAtPosition(); sPos.stack = new ItemStack(BuildCraftCore.buildToolBlock); stacksToDisplay.add(sPos); } initialized = true; } } public Position getDisplayPosition(float time) { Position result = new Position(); result.x = origin.x + vx * time; result.y = origin.y + vy * time + MathHelper.sin(time / maxLifetime * (float) Math.PI) * maxHeight; result.z = origin.z + vz * time; return result; } public void update() { if (isDone) { return; } initialize(); lifetime++; if (lifetime > maxLifetime + stacksToDisplay.size() * ITEMS_SPACE - 1) { isDone = true; build(); } lifetimeDisplay = lifetime; previousUpdate = new Date().getTime(); if (slotToBuild != null && lifetime > maxLifetime) { slotToBuild.writeCompleted(context, (lifetime - maxLifetime) / (stacksToDisplay.size() * ITEMS_SPACE)); } } public void displayUpdate() { initialize(); float tickDuration = 50.0F; // miliseconds long currentUpdate = new Date().getTime(); float timeSpan = currentUpdate - previousUpdate; previousUpdate = currentUpdate; float displayPortion = timeSpan / tickDuration; if (lifetimeDisplay - lifetime <= 1.0) { lifetimeDisplay += 1.0 * displayPortion; } } private void build() { if (slotToBuild != null) { /*if (BlockUtil.isToughBlock(context.world(), destX, destY, destZ)) { BlockUtil.breakBlock(context.world(), destX, destY, destZ, BuildCraftBuilders.fillerLifespanTough); } else { BlockUtil.breakBlock(context.world(), destX, destY, destZ, BuildCraftBuilders.fillerLifespanNormal); }*/ int destX = (int) Math.floor(destination.x); int destY = (int) Math.floor(destination.y); int destZ = (int) Math.floor(destination.z); Block oldBlock = context.world().getBlock(destX, destY, destZ); int oldMeta = context.world().getBlockMetadata(destX, destY, destZ); if (slotToBuild.writeToWorld(context)) { context.world().playAuxSFXAtEntity(null, 2001, destX, destY, destZ, Block.getIdFromBlock(oldBlock) + (oldMeta << 12)); } else if (slotToBuild.stackConsumed != null) { for (ItemStack s : slotToBuild.stackConsumed) { if (s != null && !(s.getItem() instanceof ItemBlock && Block.getBlockFromItem(s.getItem()) instanceof BlockBuildTool)) { InvUtils.dropItems(context.world(), s, destX, destY, destZ); } } } } } public LinkedList<StackAtPosition> getStacks() { int d = 0; for (StackAtPosition s : stacksToDisplay) { float stackLife = lifetimeDisplay - d; if (stackLife <= maxLifetime && stackLife > 0) { s.pos = getDisplayPosition(stackLife); s.display = true; } else { s.display = false; } d += ITEMS_SPACE; } return stacksToDisplay; } @Override public boolean isDone() { return isDone; } public void writeToNBT(NBTTagCompound nbt) { NBTTagCompound originNBT = new NBTTagCompound(); origin.writeToNBT(originNBT); nbt.setTag("origin", originNBT); NBTTagCompound destinationNBT = new NBTTagCompound(); destination.writeToNBT(destinationNBT); nbt.setTag("destination", destinationNBT); nbt.setFloat("lifetime", lifetime); NBTTagList items = new NBTTagList(); for (StackAtPosition s : stacksToDisplay) { NBTTagCompound cpt = new NBTTagCompound(); s.stack.writeToNBT(cpt); items.appendTag(cpt); } nbt.setTag("items", items); MappingRegistry registry = new MappingRegistry(); NBTTagCompound slotNBT = new NBTTagCompound(); NBTTagCompound registryNBT = new NBTTagCompound(); slotToBuild.writeToNBT(slotNBT, registry); registry.write(registryNBT); nbt.setTag("registry", registryNBT); if (slotToBuild instanceof BuildingSlotBlock) { nbt.setByte("slotKind", (byte) 0); } else { nbt.setByte("slotKind", (byte) 1); } nbt.setTag("slotToBuild", slotNBT); } public void readFromNBT(NBTTagCompound nbt) throws MappingNotFoundException { origin = new Position(nbt.getCompoundTag("origin")); destination = new Position(nbt.getCompoundTag("destination")); lifetime = nbt.getFloat("lifetime"); NBTTagList items = nbt.getTagList("items", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < items.tagCount(); ++i) { StackAtPosition sPos = new StackAtPosition(); sPos.stack = ItemStack.loadItemStackFromNBT(items .getCompoundTagAt(i)); stacksToDisplay.add(sPos); } MappingRegistry registry = new MappingRegistry(); registry.read(nbt.getCompoundTag("registry")); if (nbt.getByte("slotKind") == 0) { slotToBuild = new BuildingSlotBlock(); } else { slotToBuild = new BuildingSlotEntity(); } slotToBuild.readFromNBT(nbt.getCompoundTag("slotToBuild"), registry); } public void setStacksToDisplay(List<ItemStack> stacks) { if (stacks != null) { for (ItemStack s : stacks) { for (int i = 0; i < s.stackSize; ++i) { StackAtPosition sPos = new StackAtPosition(); sPos.stack = s.copy(); sPos.stack.stackSize = 1; stacksToDisplay.add(sPos); } } } } @Override public void readData(ByteBuf stream) { origin = new Position(); destination = new Position(); origin.readData(stream); destination.readData(stream); lifetime = stream.readFloat(); stacksToDisplay.clear(); int size = stream.readUnsignedShort(); for (int i = 0; i < size; i++) { StackAtPosition e = new StackAtPosition(); e.readData(stream); stacksToDisplay.add(e); } } @Override public void writeData(ByteBuf stream) { origin.writeData(stream); destination.writeData(stream); stream.writeFloat(lifetime); stream.writeShort(stacksToDisplay.size()); for (StackAtPosition s : stacksToDisplay) { s.writeData(stream); } } @Override public int hashCode() { return (131 * origin.hashCode()) + destination.hashCode(); } }