397 lines
12 KiB
Java
397 lines
12 KiB
Java
/**
|
|
* 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.lib.utils;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import net.minecraft.block.Block;
|
|
import net.minecraft.block.BlockStaticLiquid;
|
|
import net.minecraft.entity.item.EntityItem;
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
import net.minecraft.init.Blocks;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.network.play.server.S27PacketExplosion;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
import net.minecraft.tileentity.TileEntityChest;
|
|
import net.minecraft.world.ChunkPosition;
|
|
import net.minecraft.world.Explosion;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.WorldServer;
|
|
import net.minecraft.world.chunk.Chunk;
|
|
|
|
import cpw.mods.fml.common.FMLCommonHandler;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.common.util.ForgeDirection;
|
|
import net.minecraftforge.event.ForgeEventFactory;
|
|
import net.minecraftforge.event.world.BlockEvent.BreakEvent;
|
|
import net.minecraftforge.fluids.Fluid;
|
|
import net.minecraftforge.fluids.FluidContainerRegistry;
|
|
import net.minecraftforge.fluids.FluidRegistry;
|
|
import net.minecraftforge.fluids.FluidStack;
|
|
import net.minecraftforge.fluids.IFluidBlock;
|
|
|
|
import buildcraft.BuildCraftCore;
|
|
import buildcraft.api.blueprints.BuilderAPI;
|
|
import buildcraft.core.proxy.CoreProxy;
|
|
|
|
public final class BlockUtils {
|
|
/**
|
|
* Deactivate constructor
|
|
*/
|
|
private BlockUtils() {
|
|
}
|
|
|
|
public static List<ItemStack> getItemStackFromBlock(WorldServer world, int i, int j, int k) {
|
|
Block block = world.getBlock(i, j, k);
|
|
|
|
if (block == null || block.isAir(world, i, j, k)) {
|
|
return null;
|
|
}
|
|
|
|
int meta = world.getBlockMetadata(i, j, k);
|
|
|
|
ArrayList<ItemStack> dropsList = block.getDrops(world, i, j, k, meta, 0);
|
|
float dropChance = ForgeEventFactory.fireBlockHarvesting(dropsList, world, block, i, j, k, meta, 0, 1.0F,
|
|
false, CoreProxy.proxy.getBuildCraftPlayer(world).get());
|
|
|
|
ArrayList<ItemStack> returnList = new ArrayList<ItemStack>();
|
|
for (ItemStack s : dropsList) {
|
|
if (world.rand.nextFloat() <= dropChance) {
|
|
returnList.add(s);
|
|
}
|
|
}
|
|
|
|
return returnList;
|
|
}
|
|
|
|
public static boolean breakBlock(WorldServer world, int x, int y, int z) {
|
|
return breakBlock(world, x, y, z, BuildCraftCore.itemLifespan * 20);
|
|
}
|
|
|
|
public static boolean breakBlock(WorldServer world, int x, int y, int z, int forcedLifespan) {
|
|
List<ItemStack> items = new ArrayList<ItemStack>();
|
|
|
|
if (breakBlock(world, x, y, z, items)) {
|
|
for (ItemStack item : items) {
|
|
dropItem(world, x, y, z, forcedLifespan, item);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static EntityPlayer getFakePlayerWithTool(WorldServer world, int x, int y, int z, ItemStack tool) {
|
|
EntityPlayer player = CoreProxy.proxy.getBuildCraftPlayer(world, x, y, z).get();
|
|
int i = 0;
|
|
|
|
while (player.getHeldItem() != tool && i < 9) {
|
|
if (i > 0) {
|
|
player.inventory.setInventorySlotContents(i - 1, null);
|
|
}
|
|
|
|
player.inventory.setInventorySlotContents(i, tool);
|
|
i++;
|
|
}
|
|
|
|
return player;
|
|
}
|
|
|
|
public static boolean harvestBlock(WorldServer world, int x, int y, int z, ItemStack tool) {
|
|
Block block = world.getBlock(x, y, z);
|
|
int meta = world.getBlockMetadata(x, y, z);
|
|
|
|
EntityPlayer player = getFakePlayerWithTool(world, x, y, z, tool);
|
|
|
|
BreakEvent breakEvent = new BreakEvent(x, y, z, world, world.getBlock(x, y, z), world.getBlockMetadata(x, y, z), player);
|
|
MinecraftForge.EVENT_BUS.post(breakEvent);
|
|
|
|
if (breakEvent.isCanceled()) {
|
|
return false;
|
|
}
|
|
|
|
if (!block.canHarvestBlock(player, meta)) {
|
|
return false;
|
|
}
|
|
|
|
if (tool != null && tool.getItem() != null && tool.getItem().onBlockStartBreak(tool, x, y, z, player)) {
|
|
return false;
|
|
}
|
|
|
|
block.onBlockHarvested(world, x, y, z, meta, player);
|
|
block.harvestBlock(world, player, x, y, z, meta);
|
|
world.setBlockToAir(x, y, z);
|
|
|
|
return true;
|
|
}
|
|
|
|
public static boolean breakBlock(WorldServer world, int x, int y, int z, List<ItemStack> drops) {
|
|
BreakEvent breakEvent = new BreakEvent(x, y, z, world, world.getBlock(x, y, z),
|
|
world.getBlockMetadata(x, y, z), CoreProxy.proxy.getBuildCraftPlayer(world).get());
|
|
MinecraftForge.EVENT_BUS.post(breakEvent);
|
|
|
|
if (breakEvent.isCanceled()) {
|
|
return false;
|
|
}
|
|
|
|
if (!world.isAirBlock(x, y, z) && !world.isRemote
|
|
&& world.getGameRules().getGameRuleBooleanValue("doTileDrops")) {
|
|
drops.addAll(getItemStackFromBlock(world, x, y, z));
|
|
}
|
|
world.setBlockToAir(x, y, z);
|
|
|
|
return true;
|
|
}
|
|
|
|
public static void dropItem(WorldServer world, int x, int y, int z, int forcedLifespan, ItemStack stack) {
|
|
float var = 0.7F;
|
|
double dx = world.rand.nextFloat() * var + (1.0F - var) * 0.5D;
|
|
double dy = world.rand.nextFloat() * var + (1.0F - var) * 0.5D;
|
|
double dz = world.rand.nextFloat() * var + (1.0F - var) * 0.5D;
|
|
EntityItem entityitem = new EntityItem(world, x + dx, y + dy, z + dz, stack);
|
|
|
|
entityitem.lifespan = forcedLifespan;
|
|
entityitem.delayBeforeCanPickup = 10;
|
|
|
|
world.spawnEntityInWorld(entityitem);
|
|
}
|
|
|
|
public static boolean canChangeBlock(World world, int x, int y, int z) {
|
|
return canChangeBlock(world.getBlock(x, y, z), world, x, y, z);
|
|
}
|
|
|
|
public static boolean canChangeBlock(Block block, World world, int x, int y, int z) {
|
|
if (block == null || block.isAir(world, x, y, z)) {
|
|
return true;
|
|
}
|
|
|
|
if (isUnbreakableBlock(world, x, y, z, block)) {
|
|
return false;
|
|
}
|
|
|
|
if (block == Blocks.lava || block == Blocks.flowing_lava) {
|
|
return false;
|
|
} else if (block instanceof IFluidBlock && ((IFluidBlock) block).getFluid() != null) {
|
|
Fluid f = ((IFluidBlock) block).getFluid();
|
|
if (f.getDensity(world, x, y, z) >= 3000) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static float getBlockHardnessMining(World world, int x, int y, int z, Block b, ItemStack tool) {
|
|
if (world instanceof WorldServer && !BuildCraftCore.miningAllowPlayerProtectedBlocks) {
|
|
float relativeHardness = b.getPlayerRelativeBlockHardness(getFakePlayerWithTool((WorldServer) world, x, y, z, tool), world, x, y, z);
|
|
|
|
if (relativeHardness <= 0.0F) { // Forge's getPlayerRelativeBlockHardness hook returns 0.0F if the hardness is < 0.0F.
|
|
return -1.0F;
|
|
}
|
|
}
|
|
|
|
return b.getBlockHardness(world, x, y, z);
|
|
}
|
|
|
|
public static boolean isUnbreakableBlock(World world, int x, int y, int z, Block b) {
|
|
if (b == null) {
|
|
return false;
|
|
}
|
|
|
|
return getBlockHardnessMining(world, x, y, z, b, null) < 0;
|
|
}
|
|
|
|
public static boolean isUnbreakableBlock(World world, int x, int y, int z) {
|
|
return isUnbreakableBlock(world, x, y, z, world.getBlock(x, y, z));
|
|
}
|
|
|
|
/**
|
|
* Returns true if a block cannot be harvested without a tool.
|
|
*/
|
|
public static boolean isToughBlock(World world, int x, int y, int z) {
|
|
return !world.getBlock(x, y, z).getMaterial().isToolNotRequired();
|
|
}
|
|
|
|
public static boolean isFullFluidBlock(World world, int x, int y, int z) {
|
|
return isFullFluidBlock(world.getBlock(x, y, z), world, x, y, z);
|
|
}
|
|
|
|
public static boolean isFullFluidBlock(Block block, World world, int x, int y, int z) {
|
|
if (block instanceof IFluidBlock) {
|
|
return ((IFluidBlock) block).getFilledPercentage(world, x, y, z) == 1.0f;
|
|
} else if (block instanceof BlockStaticLiquid) {
|
|
return world.getBlockMetadata(x, y, z) == 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static Fluid getFluid(Block block) {
|
|
if (block instanceof IFluidBlock) {
|
|
return ((IFluidBlock) block).getFluid();
|
|
} else {
|
|
return FluidRegistry.lookupFluidForBlock(block);
|
|
}
|
|
}
|
|
|
|
public static FluidStack drainBlock(World world, int x, int y, int z, boolean doDrain) {
|
|
return drainBlock(world.getBlock(x, y, z), world, x, y, z, doDrain);
|
|
}
|
|
|
|
public static FluidStack drainBlock(Block block, World world, int x, int y, int z, boolean doDrain) {
|
|
if (block instanceof IFluidBlock) {
|
|
IFluidBlock fluidBlock = (IFluidBlock) block;
|
|
if (!fluidBlock.canDrain(world, x, y, z)) {
|
|
return null;
|
|
}
|
|
return fluidBlock.drain(world, x, y, z, doDrain);
|
|
} else {
|
|
Fluid fluid = getFluid(block);
|
|
|
|
if (fluid != null && FluidRegistry.isFluidRegistered(fluid)) {
|
|
int meta = world.getBlockMetadata(x, y, z);
|
|
if (meta != 0) {
|
|
return null;
|
|
}
|
|
|
|
if (doDrain) {
|
|
world.setBlockToAir(x, y, z);
|
|
}
|
|
|
|
return new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create an explosion which only affects a single block.
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public static void explodeBlock(World world, int x, int y, int z) {
|
|
if (FMLCommonHandler.instance().getEffectiveSide().isClient()) {
|
|
return;
|
|
}
|
|
|
|
Explosion explosion = new Explosion(world, null, x + .5, y + .5, z + .5, 3f);
|
|
explosion.affectedBlockPositions.add(new ChunkPosition(x, y, z));
|
|
explosion.doExplosionB(true);
|
|
|
|
for (EntityPlayer player : (List<EntityPlayer>) world.playerEntities) {
|
|
if (!(player instanceof EntityPlayerMP)) {
|
|
continue;
|
|
}
|
|
|
|
if (player.getDistanceSq(x, y, z) < 4096) {
|
|
((EntityPlayerMP) player).playerNetServerHandler.sendPacket(new S27PacketExplosion(x + .5, y + .5, z + .5, 3f, explosion.affectedBlockPositions, null));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static int computeBlockBreakEnergy(World world, int x, int y, int z) {
|
|
return (int) Math.floor(BuilderAPI.BREAK_ENERGY * BuildCraftCore.miningMultiplier * ((world.getBlock(x, y, z).getBlockHardness(world, x, y, z) + 1) * 2));
|
|
}
|
|
|
|
/**
|
|
* The following functions let you avoid unnecessary chunk loads, which is nice.
|
|
*/
|
|
public static TileEntity getTileEntity(World world, int x, int y, int z) {
|
|
return getTileEntity(world, x, y, z, false);
|
|
}
|
|
|
|
public static TileEntity getTileEntity(World world, int x, int y, int z, boolean force) {
|
|
if (!force) {
|
|
if (y < 0 || y > 255) {
|
|
return null;
|
|
}
|
|
Chunk chunk = ThreadSafeUtils.getChunk(world, x >> 4, z >> 4);
|
|
return chunk != null ? chunk.getTileEntityUnsafe(x & 15, y, z & 15) : null;
|
|
} else {
|
|
return world.getTileEntity(x, y, z);
|
|
}
|
|
}
|
|
|
|
public static Block getBlock(World world, int x, int y, int z) {
|
|
return getBlock(world, x, y, z, false);
|
|
}
|
|
|
|
public static Block getBlock(World world, int x, int y, int z, boolean force) {
|
|
if (!force) {
|
|
if (y < 0 || y > 255) {
|
|
return Blocks.air;
|
|
}
|
|
Chunk chunk = ThreadSafeUtils.getChunk(world, x >> 4, z >> 4);
|
|
return chunk != null ? chunk.getBlock(x & 15, y, z & 15) : Blocks.air;
|
|
} else {
|
|
return world.getBlock(x, y, z);
|
|
}
|
|
}
|
|
|
|
public static int getBlockMetadata(World world, int x, int y, int z) {
|
|
return getBlockMetadata(world, x, y, z, false);
|
|
|
|
}
|
|
|
|
public static int getBlockMetadata(World world, int x, int y, int z, boolean force) {
|
|
if (!force) {
|
|
if (y < 0 || y > 255) {
|
|
return 0;
|
|
}
|
|
Chunk chunk = ThreadSafeUtils.getChunk(world, x >> 4, z >> 4);
|
|
return chunk != null ? chunk.getBlockMetadata(x & 15, y, z & 15) : 0;
|
|
} else {
|
|
return world.getBlockMetadata(x, y, z);
|
|
}
|
|
}
|
|
|
|
public static boolean useItemOnBlock(World world, EntityPlayer player, ItemStack stack, int x,
|
|
int y, int z, ForgeDirection direction) {
|
|
boolean done = stack.getItem().onItemUseFirst(stack, player, world, x, y, z,
|
|
direction.ordinal(), 0.5F, 0.5F, 0.5F);
|
|
|
|
if (!done) {
|
|
done = stack.getItem().onItemUse(stack, player, world, x, y, z, direction.ordinal(),
|
|
0.5F, 0.5F, 0.5F);
|
|
}
|
|
return done;
|
|
}
|
|
|
|
public static void onComparatorUpdate(World world, int x, int y, int z, Block block) {
|
|
world.func_147453_f(x, y, z, block);
|
|
}
|
|
|
|
public static TileEntityChest getOtherDoubleChest(TileEntity inv) {
|
|
if (inv instanceof TileEntityChest) {
|
|
TileEntityChest chest = (TileEntityChest) inv;
|
|
|
|
TileEntityChest adjacent = null;
|
|
|
|
if (chest.adjacentChestXNeg != null) {
|
|
adjacent = chest.adjacentChestXNeg;
|
|
}
|
|
|
|
if (chest.adjacentChestXPos != null) {
|
|
adjacent = chest.adjacentChestXPos;
|
|
}
|
|
|
|
if (chest.adjacentChestZNeg != null) {
|
|
adjacent = chest.adjacentChestZNeg;
|
|
}
|
|
|
|
if (chest.adjacentChestZPos != null) {
|
|
adjacent = chest.adjacentChestZPos;
|
|
}
|
|
|
|
return adjacent;
|
|
}
|
|
return null;
|
|
}
|
|
}
|