From c7aa1eada63170a2fb6945af26398702849030f5 Mon Sep 17 00:00:00 2001 From: Lance5057 Date: Wed, 20 Apr 2016 05:15:15 -0500 Subject: Wrench changes, start of unified armor renderer API's in flux, please fix. --- src/api/java/cofh/api/block/IDismantleable.java | 27 + src/api/java/cofh/api/energy/EnergyStorage.java | 158 ++++++ .../java/cofh/api/energy/IEnergyConnection.java | 21 + .../java/cofh/api/energy/IEnergyContainerItem.java | 10 +- src/api/java/cofh/api/energy/IEnergyHandler.java | 57 +++ src/api/java/cofh/api/energy/IEnergyProvider.java | 38 ++ src/api/java/cofh/api/energy/IEnergyReceiver.java | 38 ++ src/api/java/cofh/api/energy/IEnergyStorage.java | 46 ++ .../java/cofh/api/energy/ItemEnergyContainer.java | 110 ++++ .../java/cofh/api/energy/TileEnergyHandler.java | 65 +++ src/api/java/cofh/api/item/IToolHammer.java | 44 ++ .../java/cofh/lib/util/helpers/BlockHelper.java | 567 +++++++++++++++++++++ 12 files changed, 1176 insertions(+), 5 deletions(-) create mode 100644 src/api/java/cofh/api/block/IDismantleable.java create mode 100644 src/api/java/cofh/api/energy/EnergyStorage.java create mode 100644 src/api/java/cofh/api/energy/IEnergyConnection.java create mode 100644 src/api/java/cofh/api/energy/IEnergyHandler.java create mode 100644 src/api/java/cofh/api/energy/IEnergyProvider.java create mode 100644 src/api/java/cofh/api/energy/IEnergyReceiver.java create mode 100644 src/api/java/cofh/api/energy/IEnergyStorage.java create mode 100644 src/api/java/cofh/api/energy/ItemEnergyContainer.java create mode 100644 src/api/java/cofh/api/energy/TileEnergyHandler.java create mode 100644 src/api/java/cofh/api/item/IToolHammer.java create mode 100644 src/api/java/cofh/lib/util/helpers/BlockHelper.java (limited to 'src/api/java/cofh') diff --git a/src/api/java/cofh/api/block/IDismantleable.java b/src/api/java/cofh/api/block/IDismantleable.java new file mode 100644 index 0000000..12c09e3 --- /dev/null +++ b/src/api/java/cofh/api/block/IDismantleable.java @@ -0,0 +1,27 @@ +package cofh.api.block; + +import java.util.ArrayList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * Implemented on Blocks which have some method of being instantly dismantled. + * + * @author King Lemming + * + */ +public interface IDismantleable { + + /** + * Dismantles the block. If returnDrops is true, the drop(s) should be placed into the player's inventory. + */ + ArrayList dismantleBlock(EntityPlayer player, World world, int x, int y, int z, boolean returnDrops); + + /** + * Return true if the block can be dismantled. The criteria for this is entirely up to the block. + */ + boolean canDismantle(EntityPlayer player, World world, int x, int y, int z); + +} diff --git a/src/api/java/cofh/api/energy/EnergyStorage.java b/src/api/java/cofh/api/energy/EnergyStorage.java new file mode 100644 index 0000000..25e0126 --- /dev/null +++ b/src/api/java/cofh/api/energy/EnergyStorage.java @@ -0,0 +1,158 @@ +package cofh.api.energy; + +import net.minecraft.nbt.NBTTagCompound; + +/** + * Reference implementation of {@link IEnergyStorage}. Use/extend this or implement your own. + * + * @author King Lemming + * + */ +public class EnergyStorage implements IEnergyStorage { + + protected int energy; + protected int capacity; + protected int maxReceive; + protected int maxExtract; + + public EnergyStorage(int capacity) { + + this(capacity, capacity, capacity); + } + + public EnergyStorage(int capacity, int maxTransfer) { + + this(capacity, maxTransfer, maxTransfer); + } + + public EnergyStorage(int capacity, int maxReceive, int maxExtract) { + + this.capacity = capacity; + this.maxReceive = maxReceive; + this.maxExtract = maxExtract; + } + + public EnergyStorage readFromNBT(NBTTagCompound nbt) { + + this.energy = nbt.getInteger("Energy"); + + if (energy > capacity) { + energy = capacity; + } + return this; + } + + public NBTTagCompound writeToNBT(NBTTagCompound nbt) { + + if (energy < 0) { + energy = 0; + } + nbt.setInteger("Energy", energy); + return nbt; + } + + public void setCapacity(int capacity) { + + this.capacity = capacity; + + if (energy > capacity) { + energy = capacity; + } + } + + public void setMaxTransfer(int maxTransfer) { + + setMaxReceive(maxTransfer); + setMaxExtract(maxTransfer); + } + + public void setMaxReceive(int maxReceive) { + + this.maxReceive = maxReceive; + } + + public void setMaxExtract(int maxExtract) { + + this.maxExtract = maxExtract; + } + + public int getMaxReceive() { + + return maxReceive; + } + + public int getMaxExtract() { + + return maxExtract; + } + + /** + * This function is included to allow for server -> client sync. Do not call this externally to the containing Tile Entity, as not all IEnergyHandlers + * are guaranteed to have it. + * + * @param energy + */ + public void setEnergyStored(int energy) { + + this.energy = energy; + + if (this.energy > capacity) { + this.energy = capacity; + } else if (this.energy < 0) { + this.energy = 0; + } + } + + /** + * This function is included to allow the containing tile to directly and efficiently modify the energy contained in the EnergyStorage. Do not rely on this + * externally, as not all IEnergyHandlers are guaranteed to have it. + * + * @param energy + */ + public void modifyEnergyStored(int energy) { + + this.energy += energy; + + if (this.energy > capacity) { + this.energy = capacity; + } else if (this.energy < 0) { + this.energy = 0; + } + } + + /* IEnergyStorage */ + @Override + public int receiveEnergy(int maxReceive, boolean simulate) { + + int energyReceived = Math.min(capacity - energy, Math.min(this.maxReceive, maxReceive)); + + if (!simulate) { + energy += energyReceived; + } + return energyReceived; + } + + @Override + public int extractEnergy(int maxExtract, boolean simulate) { + + int energyExtracted = Math.min(energy, Math.min(this.maxExtract, maxExtract)); + + if (!simulate) { + energy -= energyExtracted; + } + return energyExtracted; + } + + @Override + public int getEnergyStored() { + + return energy; + } + + @Override + public int getMaxEnergyStored() { + + return capacity; + } + +} diff --git a/src/api/java/cofh/api/energy/IEnergyConnection.java b/src/api/java/cofh/api/energy/IEnergyConnection.java new file mode 100644 index 0000000..301271e --- /dev/null +++ b/src/api/java/cofh/api/energy/IEnergyConnection.java @@ -0,0 +1,21 @@ +package cofh.api.energy; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Implement this interface on TileEntities which should connect to energy transportation blocks. This is intended for blocks which generate energy but do not + * accept it; otherwise just use IEnergyHandler. + *

+ * Note that {@link IEnergyHandler} is an extension of this. + * + * @author King Lemming + * + */ +public interface IEnergyConnection { + + /** + * Returns TRUE if the TileEntity can connect on a given side. + */ + boolean canConnectEnergy(ForgeDirection from); + +} diff --git a/src/api/java/cofh/api/energy/IEnergyContainerItem.java b/src/api/java/cofh/api/energy/IEnergyContainerItem.java index 0bcfda6..3ef7257 100644 --- a/src/api/java/cofh/api/energy/IEnergyContainerItem.java +++ b/src/api/java/cofh/api/energy/IEnergyContainerItem.java @@ -4,17 +4,17 @@ import net.minecraft.item.ItemStack; /** * Implement this interface on Item classes that support external manipulation of their internal energy storages. - * + *

* A reference implementation is provided {@link ItemEnergyContainer}. - * + * * @author King Lemming - * + * */ public interface IEnergyContainerItem { /** * Adds energy to a container item. Returns the quantity of energy that was accepted. This should always return 0 if the item cannot be externally charged. - * + * * @param container * ItemStack to be charged. * @param maxReceive @@ -28,7 +28,7 @@ public interface IEnergyContainerItem { /** * Removes energy from a container item. Returns the quantity of energy that was removed. This should always return 0 if the item cannot be externally * discharged. - * + * * @param container * ItemStack to be discharged. * @param maxExtract diff --git a/src/api/java/cofh/api/energy/IEnergyHandler.java b/src/api/java/cofh/api/energy/IEnergyHandler.java new file mode 100644 index 0000000..6a4600a --- /dev/null +++ b/src/api/java/cofh/api/energy/IEnergyHandler.java @@ -0,0 +1,57 @@ +package cofh.api.energy; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Implement this interface on Tile Entities which should handle energy, generally storing it in one or more internal {@link IEnergyStorage} objects. + *

+ * A reference implementation is provided {@link TileEnergyHandler}. + * + * @author King Lemming + * + */ +public interface IEnergyHandler extends IEnergyProvider, IEnergyReceiver { + + // merely a convenience interface (remove these methods in 1.8; provided here for back-compat via compiler doing things) + + /** + * Add energy to an IEnergyReceiver, internal distribution is left entirely to the IEnergyReceiver. + * + * @param from + * Orientation the energy is received from. + * @param maxReceive + * Maximum amount of energy to receive. + * @param simulate + * If TRUE, the charge will only be simulated. + * @return Amount of energy that was (or would have been, if simulated) received. + */ + @Override + int receiveEnergy(ForgeDirection from, int maxReceive, boolean simulate); + + /** + * Remove energy from an IEnergyProvider, internal distribution is left entirely to the IEnergyProvider. + * + * @param from + * Orientation the energy is extracted from. + * @param maxExtract + * Maximum amount of energy to extract. + * @param simulate + * If TRUE, the extraction will only be simulated. + * @return Amount of energy that was (or would have been, if simulated) extracted. + */ + @Override + int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate); + + /** + * Returns the amount of energy currently stored. + */ + @Override + int getEnergyStored(ForgeDirection from); + + /** + * Returns the maximum amount of energy that can be stored. + */ + @Override + int getMaxEnergyStored(ForgeDirection from); + +} diff --git a/src/api/java/cofh/api/energy/IEnergyProvider.java b/src/api/java/cofh/api/energy/IEnergyProvider.java new file mode 100644 index 0000000..05287b3 --- /dev/null +++ b/src/api/java/cofh/api/energy/IEnergyProvider.java @@ -0,0 +1,38 @@ +package cofh.api.energy; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Implement this interface on Tile Entities which should provide energy, generally storing it in one or more internal {@link IEnergyStorage} objects. + *

+ * A reference implementation is provided {@link TileEnergyHandler}. + * + * @author King Lemming + * + */ +public interface IEnergyProvider extends IEnergyConnection { + + /** + * Remove energy from an IEnergyProvider, internal distribution is left entirely to the IEnergyProvider. + * + * @param from + * Orientation the energy is extracted from. + * @param maxExtract + * Maximum amount of energy to extract. + * @param simulate + * If TRUE, the extraction will only be simulated. + * @return Amount of energy that was (or would have been, if simulated) extracted. + */ + int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate); + + /** + * Returns the amount of energy currently stored. + */ + int getEnergyStored(ForgeDirection from); + + /** + * Returns the maximum amount of energy that can be stored. + */ + int getMaxEnergyStored(ForgeDirection from); + +} diff --git a/src/api/java/cofh/api/energy/IEnergyReceiver.java b/src/api/java/cofh/api/energy/IEnergyReceiver.java new file mode 100644 index 0000000..c726e09 --- /dev/null +++ b/src/api/java/cofh/api/energy/IEnergyReceiver.java @@ -0,0 +1,38 @@ +package cofh.api.energy; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Implement this interface on Tile Entities which should receive energy, generally storing it in one or more internal {@link IEnergyStorage} objects. + *

+ * A reference implementation is provided {@link TileEnergyHandler}. + * + * @author King Lemming + * + */ +public interface IEnergyReceiver extends IEnergyConnection { + + /** + * Add energy to an IEnergyReceiver, internal distribution is left entirely to the IEnergyReceiver. + * + * @param from + * Orientation the energy is received from. + * @param maxReceive + * Maximum amount of energy to receive. + * @param simulate + * If TRUE, the charge will only be simulated. + * @return Amount of energy that was (or would have been, if simulated) received. + */ + int receiveEnergy(ForgeDirection from, int maxReceive, boolean simulate); + + /** + * Returns the amount of energy currently stored. + */ + int getEnergyStored(ForgeDirection from); + + /** + * Returns the maximum amount of energy that can be stored. + */ + int getMaxEnergyStored(ForgeDirection from); + +} diff --git a/src/api/java/cofh/api/energy/IEnergyStorage.java b/src/api/java/cofh/api/energy/IEnergyStorage.java new file mode 100644 index 0000000..414b265 --- /dev/null +++ b/src/api/java/cofh/api/energy/IEnergyStorage.java @@ -0,0 +1,46 @@ +package cofh.api.energy; + +/** + * An energy storage is the unit of interaction with Energy inventories.
+ * This is not to be implemented on TileEntities. This is for internal use only. + *

+ * A reference implementation can be found at {@link EnergyStorage}. + * + * @author King Lemming + * + */ +public interface IEnergyStorage { + + /** + * Adds energy to the storage. Returns quantity of energy that was accepted. + * + * @param maxReceive + * Maximum amount of energy to be inserted. + * @param simulate + * If TRUE, the insertion will only be simulated. + * @return Amount of energy that was (or would have been, if simulated) accepted by the storage. + */ + int receiveEnergy(int maxReceive, boolean simulate); + + /** + * Removes energy from the storage. Returns quantity of energy that was removed. + * + * @param maxExtract + * Maximum amount of energy to be extracted. + * @param simulate + * If TRUE, the extraction will only be simulated. + * @return Amount of energy that was (or would have been, if simulated) extracted from the storage. + */ + int extractEnergy(int maxExtract, boolean simulate); + + /** + * Returns the amount of energy currently stored. + */ + int getEnergyStored(); + + /** + * Returns the maximum amount of energy that can be stored. + */ + int getMaxEnergyStored(); + +} diff --git a/src/api/java/cofh/api/energy/ItemEnergyContainer.java b/src/api/java/cofh/api/energy/ItemEnergyContainer.java new file mode 100644 index 0000000..2d3659c --- /dev/null +++ b/src/api/java/cofh/api/energy/ItemEnergyContainer.java @@ -0,0 +1,110 @@ +package cofh.api.energy; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +/** + * Reference implementation of {@link IEnergyContainerItem}. Use/extend this or implement your own. + * + * @author King Lemming + * + */ +public class ItemEnergyContainer extends Item implements IEnergyContainerItem { + + protected int capacity; + protected int maxReceive; + protected int maxExtract; + + public ItemEnergyContainer() { + + } + + public ItemEnergyContainer(int capacity) { + + this(capacity, capacity, capacity); + } + + public ItemEnergyContainer(int capacity, int maxTransfer) { + + this(capacity, maxTransfer, maxTransfer); + } + + public ItemEnergyContainer(int capacity, int maxReceive, int maxExtract) { + + this.capacity = capacity; + this.maxReceive = maxReceive; + this.maxExtract = maxExtract; + } + + public ItemEnergyContainer setCapacity(int capacity) { + + this.capacity = capacity; + return this; + } + + public void setMaxTransfer(int maxTransfer) { + + setMaxReceive(maxTransfer); + setMaxExtract(maxTransfer); + } + + public void setMaxReceive(int maxReceive) { + + this.maxReceive = maxReceive; + } + + public void setMaxExtract(int maxExtract) { + + this.maxExtract = maxExtract; + } + + /* IEnergyContainerItem */ + @Override + public int receiveEnergy(ItemStack container, int maxReceive, boolean simulate) { + + if (container.stackTagCompound == null) { + container.stackTagCompound = new NBTTagCompound(); + } + int energy = container.stackTagCompound.getInteger("Energy"); + int energyReceived = Math.min(capacity - energy, Math.min(this.maxReceive, maxReceive)); + + if (!simulate) { + energy += energyReceived; + container.stackTagCompound.setInteger("Energy", energy); + } + return energyReceived; + } + + @Override + public int extractEnergy(ItemStack container, int maxExtract, boolean simulate) { + + if (container.stackTagCompound == null || !container.stackTagCompound.hasKey("Energy")) { + return 0; + } + int energy = container.stackTagCompound.getInteger("Energy"); + int energyExtracted = Math.min(energy, Math.min(this.maxExtract, maxExtract)); + + if (!simulate) { + energy -= energyExtracted; + container.stackTagCompound.setInteger("Energy", energy); + } + return energyExtracted; + } + + @Override + public int getEnergyStored(ItemStack container) { + + if (container.stackTagCompound == null || !container.stackTagCompound.hasKey("Energy")) { + return 0; + } + return container.stackTagCompound.getInteger("Energy"); + } + + @Override + public int getMaxEnergyStored(ItemStack container) { + + return capacity; + } + +} diff --git a/src/api/java/cofh/api/energy/TileEnergyHandler.java b/src/api/java/cofh/api/energy/TileEnergyHandler.java new file mode 100644 index 0000000..7cc655e --- /dev/null +++ b/src/api/java/cofh/api/energy/TileEnergyHandler.java @@ -0,0 +1,65 @@ +package cofh.api.energy; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Reference implementation of {@link IEnergyHandler}. Use/extend this or implement your own. + * + * @author King Lemming + * + */ +public class TileEnergyHandler extends TileEntity implements IEnergyHandler { + + protected EnergyStorage storage = new EnergyStorage(32000); + + @Override + public void readFromNBT(NBTTagCompound nbt) { + + super.readFromNBT(nbt); + storage.readFromNBT(nbt); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + + super.writeToNBT(nbt); + storage.writeToNBT(nbt); + } + + /* IEnergyConnection */ + @Override + public boolean canConnectEnergy(ForgeDirection from) { + + return true; + } + + /* IEnergyReceiver */ + @Override + public int receiveEnergy(ForgeDirection from, int maxReceive, boolean simulate) { + + return storage.receiveEnergy(maxReceive, simulate); + } + + /* IEnergyProvider */ + @Override + public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { + + return storage.extractEnergy(maxExtract, simulate); + } + + /* IEnergyReceiver and IEnergyProvider */ + @Override + public int getEnergyStored(ForgeDirection from) { + + return storage.getEnergyStored(); + } + + @Override + public int getMaxEnergyStored(ForgeDirection from) { + + return storage.getMaxEnergyStored(); + } + +} diff --git a/src/api/java/cofh/api/item/IToolHammer.java b/src/api/java/cofh/api/item/IToolHammer.java new file mode 100644 index 0000000..f1b4bb9 --- /dev/null +++ b/src/api/java/cofh/api/item/IToolHammer.java @@ -0,0 +1,44 @@ +package cofh.api.item; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; + +/** + * Implement this interface on subclasses of Item to have that item work as a tool for CoFH mods. + */ +public interface IToolHammer { + + /** + * Called to ensure that the tool can be used. + * + * @param item + * The itemstack for the tool. Not required to match equipped item (e.g., multi-tools that contain other tools) + * @param user + * The entity using the tool + * @param x + * X location of the block/tile + * @param y + * Y location of the block/tile + * @param z + * Z location of the block/tile + * @return True if this tool can be used + */ + boolean isUsable(ItemStack item, EntityLivingBase user, int x, int y, int z); + + /** + * Callback for when the tool has been used reactively. + * + * @param item + * The ItemStack for the tool. Not required to match equipped item (e.g., multi-tools that contain other tools) + * @param user + * The entity using the tool + * @param x + * X location of the block/tile + * @param y + * Y location of the block/tile + * @param z + * Z location of the block/tile + */ + void toolUsed(ItemStack item, EntityLivingBase user, int x, int y, int z); + +} diff --git a/src/api/java/cofh/lib/util/helpers/BlockHelper.java b/src/api/java/cofh/lib/util/helpers/BlockHelper.java new file mode 100644 index 0000000..5342727 --- /dev/null +++ b/src/api/java/cofh/lib/util/helpers/BlockHelper.java @@ -0,0 +1,567 @@ +package cofh.lib.util.helpers; + +import java.util.LinkedList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MathHelper; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Contains various helper functions to assist with {@link Block} and Block-related manipulation and interaction. + * + * @author King Lemming + * + */ +public final class BlockHelper { + + private BlockHelper() { + + } + + public static int MAX_ID = 1024; + public static byte[] rotateType = new byte[MAX_ID]; + public static final int[][] SIDE_COORD_MOD = { { 0, -1, 0 }, { 0, 1, 0 }, { 0, 0, -1 }, { 0, 0, 1 }, { -1, 0, 0 }, { 1, 0, 0 } }; + public static float[][] SIDE_COORD_AABB = { { 1, -2, 1 }, { 1, 2, 1 }, { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 1 }, { 2, 1, 1 } }; + public static final byte[] SIDE_LEFT = { 4, 5, 5, 4, 2, 3 }; + public static final byte[] SIDE_RIGHT = { 5, 4, 4, 5, 3, 2 }; + public static final byte[] SIDE_OPPOSITE = { 1, 0, 3, 2, 5, 4 }; + public static final byte[] SIDE_ABOVE = { 3, 2, 1, 1, 1, 1 }; + public static final byte[] SIDE_BELOW = { 2, 3, 0, 0, 0, 0 }; + + // These assume facing is towards negative - looking AT side 1, 3, or 5. + public static final byte[] ROTATE_CLOCK_Y = { 0, 1, 4, 5, 3, 2 }; + public static final byte[] ROTATE_CLOCK_Z = { 5, 4, 2, 3, 0, 1 }; + public static final byte[] ROTATE_CLOCK_X = { 2, 3, 1, 0, 4, 5 }; + + public static final byte[] ROTATE_COUNTER_Y = { 0, 1, 5, 4, 2, 3 }; + public static final byte[] ROTATE_COUNTER_Z = { 4, 5, 2, 3, 1, 0 }; + public static final byte[] ROTATE_COUNTER_X = { 3, 2, 0, 1, 4, 5 }; + + public static final byte[] INVERT_AROUND_Y = { 0, 1, 3, 2, 5, 4 }; + public static final byte[] INVERT_AROUND_Z = { 1, 0, 2, 3, 5, 4 }; + public static final byte[] INVERT_AROUND_X = { 1, 0, 3, 2, 4, 5 }; + + // Map which gives relative Icon to use on a block which can be placed on any side. + public static final byte[][] ICON_ROTATION_MAP = new byte[6][]; + + static { + ICON_ROTATION_MAP[0] = new byte[] { 0, 1, 2, 3, 4, 5 }; + ICON_ROTATION_MAP[1] = new byte[] { 1, 0, 2, 3, 4, 5 }; + ICON_ROTATION_MAP[2] = new byte[] { 3, 2, 0, 1, 4, 5 }; + ICON_ROTATION_MAP[3] = new byte[] { 3, 2, 1, 0, 5, 4 }; + ICON_ROTATION_MAP[4] = new byte[] { 3, 2, 5, 4, 0, 1 }; + ICON_ROTATION_MAP[5] = new byte[] { 3, 2, 4, 5, 1, 0 }; + } + + public static final class RotationType { + + public static final int PREVENT = -1; + public static final int FOUR_WAY = 1; + public static final int SIX_WAY = 2; + public static final int RAIL = 3; + public static final int PUMPKIN = 4; + public static final int STAIRS = 5; + public static final int REDSTONE = 6; + public static final int LOG = 7; + public static final int SLAB = 8; + public static final int CHEST = 9; + public static final int LEVER = 10; + public static final int SIGN = 11; + } + + static { // TODO: review which of these can be removed in favor of the vanilla handler + rotateType[Block.getIdFromBlock(Blocks.bed)] = RotationType.PREVENT; + + rotateType[Block.getIdFromBlock(Blocks.stone_slab)] = RotationType.SLAB; + rotateType[Block.getIdFromBlock(Blocks.wooden_slab)] = RotationType.SLAB; + + rotateType[Block.getIdFromBlock(Blocks.rail)] = RotationType.RAIL; + rotateType[Block.getIdFromBlock(Blocks.golden_rail)] = RotationType.RAIL; + rotateType[Block.getIdFromBlock(Blocks.detector_rail)] = RotationType.RAIL; + rotateType[Block.getIdFromBlock(Blocks.activator_rail)] = RotationType.RAIL; + + rotateType[Block.getIdFromBlock(Blocks.pumpkin)] = RotationType.PUMPKIN; + rotateType[Block.getIdFromBlock(Blocks.lit_pumpkin)] = RotationType.PUMPKIN; + + rotateType[Block.getIdFromBlock(Blocks.furnace)] = RotationType.FOUR_WAY; + rotateType[Block.getIdFromBlock(Blocks.lit_furnace)] = RotationType.FOUR_WAY; + rotateType[Block.getIdFromBlock(Blocks.ender_chest)] = RotationType.FOUR_WAY; + + rotateType[Block.getIdFromBlock(Blocks.trapped_chest)] = RotationType.CHEST; + rotateType[Block.getIdFromBlock(Blocks.chest)] = RotationType.CHEST; + + rotateType[Block.getIdFromBlock(Blocks.dispenser)] = RotationType.SIX_WAY; + rotateType[Block.getIdFromBlock(Blocks.sticky_piston)] = RotationType.SIX_WAY; + rotateType[Block.getIdFromBlock(Blocks.piston)] = RotationType.SIX_WAY; + rotateType[Block.getIdFromBlock(Blocks.hopper)] = RotationType.SIX_WAY; + rotateType[Block.getIdFromBlock(Blocks.dropper)] = RotationType.SIX_WAY; + + rotateType[Block.getIdFromBlock(Blocks.unpowered_repeater)] = RotationType.REDSTONE; + rotateType[Block.getIdFromBlock(Blocks.unpowered_comparator)] = RotationType.REDSTONE; + rotateType[Block.getIdFromBlock(Blocks.powered_repeater)] = RotationType.REDSTONE; + rotateType[Block.getIdFromBlock(Blocks.powered_comparator)] = RotationType.REDSTONE; + + rotateType[Block.getIdFromBlock(Blocks.lever)] = RotationType.LEVER; + + rotateType[Block.getIdFromBlock(Blocks.standing_sign)] = RotationType.SIGN; + + rotateType[Block.getIdFromBlock(Blocks.oak_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.stone_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.brick_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.stone_brick_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.nether_brick_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.sandstone_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.spruce_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.birch_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.jungle_stairs)] = RotationType.STAIRS; + rotateType[Block.getIdFromBlock(Blocks.quartz_stairs)] = RotationType.STAIRS; + } + + public static int getMicroBlockAngle(int side, float hitX, float hitY, float hitZ) { + + int direction = side ^ 1; + float degreeCenter = 0.32f / 2; + + float x = 0, y = 0; + switch (side >> 1) { + case 0: + x = hitX; + y = hitZ; + break; + case 1: + x = hitX; + y = hitY; + break; + case 2: + x = hitY; + y = hitZ; + break; + } + x -= .5f; + y -= .5f; + + if (x * x + y * y > degreeCenter * degreeCenter) { + + int a = (int) ((Math.atan2(x, y) + Math.PI) * 4 / Math.PI); + a = ++a & 7; + switch (a >> 1) { + case 0: + case 4: + direction = 2; + break; + case 1: + direction = 4; + break; + case 2: + direction = 3; + break; + case 3: + direction = 5; + break; + } + } + return direction; + } + + public static ForgeDirection getMicroBlockAngle(ForgeDirection side, float hitX, float hitY, float hitZ) { + + return ForgeDirection.VALID_DIRECTIONS[getMicroBlockAngle(side.ordinal(), hitX, hitY, hitZ)]; + } + + public static int getHighestY(World world, int x, int z) { + + return world.getChunkFromBlockCoords(x, z).getTopFilledSegment() + 16; + } + + public static int getSurfaceBlockY(World world, int x, int z) { + + int y = world.getChunkFromBlockCoords(x, z).getTopFilledSegment() + 16; + + Block block; + do { + if (--y < 0) { + break; + } + block = world.getBlock(x, y, z); + } while (block.isAir(world, x, y, z) || block.isReplaceable(world, x, y, z) || block.isLeaves(world, x, y, z) || block.isFoliage(world, x, y, z) + || block.canBeReplacedByLeaves(world, x, y, z)); + return y; + } + + public static int getTopBlockY(World world, int x, int z) { + + int y = world.getChunkFromBlockCoords(x, z).getTopFilledSegment() + 16; + + Block block; + do { + if (--y < 0) { + break; + } + block = world.getBlock(x, y, z); + } while (block.isAir(world, x, y, z)); + return y; + } + + public static MovingObjectPosition getCurrentMovingObjectPosition(EntityPlayer player, double distance, boolean fluid) { + + Vec3 posVec = Vec3.createVectorHelper(player.posX, player.posY, player.posZ); + Vec3 lookVec = player.getLook(1); + posVec.yCoord += player.getEyeHeight(); + lookVec = posVec.addVector(lookVec.xCoord * distance, lookVec.yCoord * distance, lookVec.zCoord * distance); + return player.worldObj.rayTraceBlocks(posVec, lookVec, fluid); + } + + public static MovingObjectPosition getCurrentMovingObjectPosition(EntityPlayer player, double distance) { + + return getCurrentMovingObjectPosition(player, distance, false); + } + + public static MovingObjectPosition getCurrentMovingObjectPosition(EntityPlayer player, boolean fluid) { + + return getCurrentMovingObjectPosition(player, player.capabilities.isCreativeMode ? 5.0F : 4.5F, fluid); + } + + public static MovingObjectPosition getCurrentMovingObjectPosition(EntityPlayer player) { + + return getCurrentMovingObjectPosition(player, player.capabilities.isCreativeMode ? 5.0F : 4.5F, false); + } + + public static int getCurrentMousedOverSide(EntityPlayer player) { + + MovingObjectPosition mouseOver = getCurrentMovingObjectPosition(player); + return mouseOver == null ? 0 : mouseOver.sideHit; + } + + public static int determineXZPlaceFacing(EntityLivingBase living) { + + int quadrant = MathHelper.floor_double(living.rotationYaw * 4.0F / 360.0F + 0.5D) & 3; + + switch (quadrant) { + case 0: + return 2; + case 1: + return 5; + case 2: + return 3; + case 3: + return 4; + } + return 3; + } + + public static boolean isEqual(Block blockA, Block blockB) { + + if (blockA == blockB) { + return true; + } + if (blockA == null | blockB == null) { + return false; + } + return blockA.equals(blockB) || blockA.isAssociatedBlock(blockB); + } + + /* UNSAFE Tile Entity Retrieval */ + // public static TileEntity getAdjacentTileEntityUnsafe(World world, int x, int y, int z, ForgeDirection dir) { + // + // if (world == null) { + // return null; + // } + // Chunk chunk = world.getChunkFromBlockCoords(x + dir.offsetX, z + dir.offsetZ); + // return chunk == null ? null : chunk.getChunkBlockTileEntityUnsafe((x + dir.offsetX) & 0xF, y + dir.offsetY, (z + dir.offsetZ) & 0xF); + // } + // + // public static TileEntity getAdjacentTileEntityUnsafe(World world, int x, int y, int z, int side) { + // + // return world == null ? null : getAdjacentTileEntityUnsafe(world, x, y, z, ForgeDirection.values()[side]); + // } + // + // public static TileEntity getAdjacentTileEntityUnsafe(TileEntity refTile, ForgeDirection dir) { + // + // return refTile == null ? null : getAdjacentTileEntityUnsafe(refTile.worldObj, refTile.xCoord, refTile.yCoord, refTile.zCoord, dir); + // } + // + // public static TileEntity getAdjacentTileEntityUnsafe(TileEntity refTile, int side) { + // + // return refTile == null ? null : getAdjacentTileEntityUnsafe(refTile.worldObj, refTile.xCoord, refTile.yCoord, refTile.zCoord, + // ForgeDirection.values()[side]); + // } + + public static Block getAdjacentBlock(World world, int x, int y, int z, ForgeDirection dir) { + + x += dir.offsetX; + y += dir.offsetY; + z += dir.offsetZ; + return world == null || !world.blockExists(x, y, z) ? Blocks.air : world.getBlock(x, y, z); + } + + public static Block getAdjacentBlock(World world, int x, int y, int z, int side) { + + return world == null ? Blocks.air : getAdjacentBlock(world, x, y, z, ForgeDirection.getOrientation(side)); + } + + /* Safe Tile Entity Retrieval */ + public static TileEntity getAdjacentTileEntity(World world, int x, int y, int z, ForgeDirection dir) { + + x += dir.offsetX; + y += dir.offsetY; + z += dir.offsetZ; + return world == null || !world.blockExists(x, y, z) ? null : world.getTileEntity(x, y, z); + } + + public static TileEntity getAdjacentTileEntity(World world, int x, int y, int z, int side) { + + return world == null ? null : getAdjacentTileEntity(world, x, y, z, ForgeDirection.getOrientation(side)); + } + + public static TileEntity getAdjacentTileEntity(TileEntity refTile, ForgeDirection dir) { + + return refTile == null ? null : getAdjacentTileEntity(refTile.getWorldObj(), refTile.xCoord, refTile.yCoord, refTile.zCoord, dir); + } + + public static TileEntity getAdjacentTileEntity(TileEntity refTile, int side) { + + return refTile == null ? null : getAdjacentTileEntity(refTile.getWorldObj(), refTile.xCoord, refTile.yCoord, refTile.zCoord, + ForgeDirection.values()[side]); + } + + public static int determineAdjacentSide(TileEntity refTile, int x, int y, int z) { + + return y > refTile.yCoord ? 1 : y < refTile.yCoord ? 0 : z > refTile.zCoord ? 3 : z < refTile.zCoord ? 2 : x > refTile.xCoord ? 5 : 4; + } + + /* COORDINATE TRANSFORM */ + public static int[] getAdjacentCoordinatesForSide(MovingObjectPosition pos) { + + return getAdjacentCoordinatesForSide(pos.blockX, pos.blockY, pos.blockZ, pos.sideHit); + } + + public static int[] getAdjacentCoordinatesForSide(int x, int y, int z, int side) { + + return new int[] { x + SIDE_COORD_MOD[side][0], y + SIDE_COORD_MOD[side][1], z + SIDE_COORD_MOD[side][2] }; + } + + public static AxisAlignedBB getAdjacentAABBForSide(MovingObjectPosition pos) { + + return getAdjacentAABBForSide(pos.blockX, pos.blockY, pos.blockZ, pos.sideHit); + } + + public static AxisAlignedBB getAdjacentAABBForSide(int x, int y, int z, int side) { + + return AxisAlignedBB.getBoundingBox(x + SIDE_COORD_MOD[side][0], y + SIDE_COORD_MOD[side][1], z + SIDE_COORD_MOD[side][2], + x + SIDE_COORD_AABB[side][0], y + SIDE_COORD_AABB[side][1], z + SIDE_COORD_AABB[side][2]); + } + + public static int getLeftSide(int side) { + + return SIDE_LEFT[side]; + } + + public static int getRightSide(int side) { + + return SIDE_RIGHT[side]; + } + + public static int getOppositeSide(int side) { + + return SIDE_OPPOSITE[side]; + } + + public static int getAboveSide(int side) { + + return SIDE_ABOVE[side]; + } + + public static int getBelowSide(int side) { + + return SIDE_BELOW[side]; + } + + /* BLOCK ROTATION */ + public static boolean canRotate(Block block) { + + int bId = Block.getIdFromBlock(block); + return bId < MAX_ID ? rotateType[Block.getIdFromBlock(block)] != 0 : false; + } + + public static int rotateVanillaBlock(World world, Block block, int x, int y, int z) { + + int bId = Block.getIdFromBlock(block), bMeta = world.getBlockMetadata(x, y, z); + switch (rotateType[bId]) { + case RotationType.FOUR_WAY: + return SIDE_LEFT[bMeta]; + case RotationType.SIX_WAY: + if (bMeta < 6) { + return ++bMeta % 6; + } + return bMeta; + case RotationType.RAIL: + if (bMeta < 2) { + return ++bMeta % 2; + } + return bMeta; + case RotationType.PUMPKIN: + return ++bMeta % 4; + case RotationType.STAIRS: + return ++bMeta % 8; + case RotationType.REDSTONE: + int upper = bMeta & 0xC; + int lower = bMeta & 0x3; + return upper + ++lower % 4; + case RotationType.LOG: + return (bMeta + 4) % 12; + case RotationType.SLAB: + return (bMeta + 8) % 16; + case RotationType.CHEST: + int coords[] = new int[3]; + for (int i = 2; i < 6; i++) { + coords = getAdjacentCoordinatesForSide(x, y, z, i); + if (isEqual(world.getBlock(coords[0], coords[1], coords[2]), block)) { + world.setBlockMetadataWithNotify(coords[0], coords[1], coords[2], SIDE_OPPOSITE[bMeta], 1); + return SIDE_OPPOSITE[bMeta]; + } + } + return SIDE_LEFT[bMeta]; + case RotationType.LEVER: + int shift = 0; + if (bMeta > 7) { + bMeta -= 8; + shift = 8; + } + if (bMeta == 5) { + return 6 + shift; + } else if (bMeta == 6) { + return 5 + shift; + } else if (bMeta == 7) { + return 0 + shift; + } else if (bMeta == 0) { + return 7 + shift; + } + return bMeta + shift; + case RotationType.SIGN: + return ++bMeta % 16; + case RotationType.PREVENT: + default: + return bMeta; + } + } + + public static int rotateVanillaBlockAlt(World world, Block block, int x, int y, int z) { + + int bId = Block.getIdFromBlock(block), bMeta = world.getBlockMetadata(x, y, z); + switch (rotateType[bId]) { + case RotationType.FOUR_WAY: + return SIDE_RIGHT[bMeta]; + case RotationType.SIX_WAY: + if (bMeta < 6) { + return (bMeta + 5) % 6; + } + return bMeta; + case RotationType.RAIL: + if (bMeta < 2) { + return ++bMeta % 2; + } + return bMeta; + case RotationType.PUMPKIN: + return (bMeta + 3) % 4; + case RotationType.STAIRS: + return (bMeta + 7) % 8; + case RotationType.REDSTONE: + int upper = bMeta & 0xC; + int lower = bMeta & 0x3; + return upper + (lower + 3) % 4; + case RotationType.LOG: + return (bMeta + 8) % 12; + case RotationType.SLAB: + return (bMeta + 8) % 16; + case RotationType.CHEST: + int coords[] = new int[3]; + for (int i = 2; i < 6; i++) { + coords = getAdjacentCoordinatesForSide(x, y, z, i); + if (isEqual(world.getBlock(coords[0], coords[1], coords[2]), block)) { + world.setBlockMetadataWithNotify(coords[0], coords[1], coords[2], SIDE_OPPOSITE[bMeta], 1); + return SIDE_OPPOSITE[bMeta]; + } + } + return SIDE_RIGHT[bMeta]; + case RotationType.LEVER: + int shift = 0; + if (bMeta > 7) { + bMeta -= 8; + shift = 8; + } + if (bMeta == 5) { + return 6 + shift; + } else if (bMeta == 6) { + return 5 + shift; + } else if (bMeta == 7) { + return 0 + shift; + } else if (bMeta == 0) { + return 7 + shift; + } + case RotationType.SIGN: + return ++bMeta % 16; + case RotationType.PREVENT: + default: + return bMeta; + } + } + + public static List breakBlock(World worldObj, int x, int y, int z, Block block, int fortune, boolean doBreak, boolean silkTouch) { + + return breakBlock(worldObj, null, x, y, z, block, fortune, doBreak, silkTouch); + } + + public static List breakBlock(World worldObj, EntityPlayer player, int x, int y, int z, Block block, int fortune, boolean doBreak, + boolean silkTouch) { + + if (block.getBlockHardness(worldObj, x, y, z) == -1) { + return new LinkedList(); + } + int meta = worldObj.getBlockMetadata(x, y, z); + List stacks = null; + if (silkTouch && block.canSilkHarvest(worldObj, player, x, y, z, meta)) { + stacks = new LinkedList(); + stacks.add(createStackedBlock(block, meta)); + } else { + stacks = block.getDrops(worldObj, x, y, z, meta, fortune); + } + if (!doBreak) { + return stacks; + } + worldObj.playAuxSFXAtEntity(player, 2001, x, y, z, Block.getIdFromBlock(block) + (meta << 12)); + worldObj.setBlockToAir(x, y, z); + + List result = worldObj.getEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getBoundingBox(x - 2, y - 2, z - 2, x + 3, y + 3, z + 3)); + for (int i = 0; i < result.size(); i++) { + EntityItem entity = result.get(i); + if (entity.isDead || entity.getEntityItem().stackSize <= 0) { + continue; + } + stacks.add(entity.getEntityItem()); + entity.worldObj.removeEntity(entity); + } + return stacks; + } + + public static ItemStack createStackedBlock(Block block, int bMeta) { + + Item item = Item.getItemFromBlock(block); + if (item.getHasSubtypes()) { + return new ItemStack(item, 1, bMeta); + } + return new ItemStack(item, 1, 0); + } + +} -- cgit v1.2.3