Package com.nitnelave.CreeperHeal.block

Source Code of com.nitnelave.CreeperHeal.block.CreeperExplosion

package com.nitnelave.CreeperHeal.block;

import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;

import com.nitnelave.CreeperHeal.config.CfgVal;
import com.nitnelave.CreeperHeal.config.CreeperConfig;
import com.nitnelave.CreeperHeal.config.WorldConfig;
import com.nitnelave.CreeperHeal.events.CHBlockHealEvent;
import com.nitnelave.CreeperHeal.events.CHBlockHealEvent.CHBlockHealReason;
import com.nitnelave.CreeperHeal.utils.ShortLocation;
import com.nitnelave.CreeperHeal.utils.Suffocating;

/**
* Represents an explosion, with the list of blocks destroyed, the time of the
* explosion, and the radius.
*
* @author nitnelave
*
*/
public class CreeperExplosion
{
    /**
     * The time after which the block replacements begin.
     */
    private final LinkedList<Replaceable> blockList;
    private Location loc;
    private int locWeight = 0;
    private double radius = 0;
    private final WorldConfig world;
    private final HashSet<ShortLocation> checked = new HashSet<ShortLocation>();
    private ReplacementTimer timer;

    /**
     * Constructor.
     *
     * @param loc
     *            The location of the explosion.
     */
    public CreeperExplosion(Location loc)
    {
        world = CreeperConfig.getWorld(loc.getWorld());
        timer = new ReplacementTimer(new Date(new Date().getTime() + 1000
                                              * CreeperConfig.getInt(CfgVal.WAIT_BEFORE_HEAL)), world.isRepairTimed());
        blockList = new LinkedList<Replaceable>();
        this.loc = loc;
    }

    /**
     * Add blocks to an explosion, and reset the timer to the time of the last
     * explosion.
     *
     * @param blocks
     *            The list of blocks to add.
     */
    public void addBlocks(List<Block> blocks, Location newLoc)
    {
        timer = new ReplacementTimer(new Date(new Date().getTime() + 1000
                                              * CreeperConfig.getInt(CfgVal.WAIT_BEFORE_HEAL)), world.isRepairTimed());
        loc = new Location(loc.getWorld(), (locWeight * loc.getX() + newLoc.getX())
                                           / (locWeight + 1), (locWeight * loc.getY() + newLoc.getY())
                                                              / (locWeight + 1), (locWeight
                                                                                  * loc.getZ() + newLoc.getZ())
                                                                                 / (locWeight + 1));
        locWeight++;
        checked.clear();
        recordBlocks(blocks);
        if (CreeperConfig.getBool(CfgVal.EXPLODE_OBSIDIAN))
            checkForObsidian();

        Collections.sort(blockList, new CreeperComparator(loc));
        radius = computeRadius();
    }

    /**
     * Get the time of the explosion.
     *
     * @return The time of the explosion.
     */
    public Date getTime()
    {
        return timer.getTime();
    }

    /*
     * Get the distance between the explosion's location and the furthest block.
     */
    private double computeRadius()
    {
        double r = 0;
        for (Replaceable b : blockList)
        {
            Location bl = b.getBlock().getLocation();
            r = Math.max(r, loc.distance(bl));
        }
        return r + 1;
    }

    /**
     * Get the location of the explosion.
     *
     * @return The location of the explosion.
     */
    public Location getLocation()
    {
        return loc;
    }

    /**
     * Get the radius of the explosion (i.e. the distance between the location
     * and the furthest block).
     *
     * @return The radius of the explosion.
     */
    public double getRadius()
    {
        return radius;
    }

    /*
     * Replace all the blocks in the list.
     */
    protected void replace_blocks(boolean shouldDrop, CHBlockHealReason reason)
    {
        Iterator<Replaceable> iter = blockList.iterator();
        while (iter.hasNext())
        {
            Replaceable block = iter.next();
            CHBlockHealEvent event = new CHBlockHealEvent(block, shouldDrop, reason);
            Bukkit.getPluginManager().callEvent(event);
            if (!event.isCancelled() && block.replace(event.shouldDrop()))
                iter.remove();
        }
        if (shouldDrop)
        {
            blockList.clear();

            if (CreeperConfig.getBool(CfgVal.TELEPORT_ON_SUFFOCATE))
                Suffocating.checkPlayerExplosion(loc, radius);
        }
    }

    /**
     * Replace the first block of the list.
     *
     * @return False if the list is now empty.
     */
    private void replace_one_block()
    {
        Replaceable block;
        if (blockList.isEmpty())
            return;
        block = blockList.remove();
        CHBlockHealEvent event = new CHBlockHealEvent(block, false, CHBlockHealReason.BLOCK_BY_BLOCK);
        Bukkit.getPluginManager().callEvent(event);
        if (!event.isCancelled() && !block.replace(event.shouldDrop()))
            block.delayReplacement(CHBlockHealReason.BLOCK_BY_BLOCK);
        if (CreeperConfig.getBool(CfgVal.TELEPORT_ON_SUFFOCATE))
            Suffocating.checkPlayerOneBlock(block.getBlock().getLocation());
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object o)
    {
        if (this == o)
            return true;
        if (o instanceof CreeperExplosion)
        {
            CreeperExplosion e = (CreeperExplosion) o;
            return e.timer == timer && e.loc == loc && e.radius == radius;
        }
        return false;
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode()
    {
        return (int) (timer.hashCode() + radius + loc.hashCode());
    }

    /*
     * Check for dependent blocks and record them first.
     */
    private void recordBlocks(List<Block> blocks)
    {
        if (!blocks.isEmpty())
        {
            Iterator<Block> iter = blocks.iterator();
            while (iter.hasNext())
            {
                Block b = iter.next();
                if (CreeperBlock.isDependent(b.getTypeId()))
                {
                    record(b);
                    iter.remove();
                }
            }
            for (Block b : blocks)
                record(b);
        }
    }

    /*
     * In case of possible obsidian destruction, check for obsidian around, and
     * give them a chance to be destroyed.
     */
    private void checkForObsidian()
    {
        int radius = CreeperConfig.getInt(CfgVal.OBSIDIAN_RADIUS);
        double chance = ((float) CreeperConfig.getInt(CfgVal.OBSIDIAN_CHANCE)) / 100;
        World w = loc.getWorld();

        Random r = new Random(System.currentTimeMillis());
        boolean table = CreeperConfig.getBool(CfgVal.OBSIDIAN_TABLE);

        for (int i = loc.getBlockX() - radius; i < loc.getBlockX() + radius; i++)
            for (int j = Math.max(0, loc.getBlockY() - radius); j < Math.min(w.getMaxHeight(), loc.getBlockY()
                                                                                               + radius); j++)
                for (int k = loc.getBlockZ() - radius; k < loc.getBlockZ() + radius; k++)
                {
                    Location l = new Location(w, i, j, k);
                    if (l.distance(loc) > radius)
                        continue;
                    Block b = l.getBlock();
                    if (isObsidianLike(b.getType(), table) && r.nextDouble() < chance)
                        record(b);
                }
    }

    private boolean isObsidianLike(Material m, boolean table)
    {
        return m == Material.OBSIDIAN
               || (table && (m == Material.ENCHANTMENT_TABLE || m == Material.ENDER_CHEST));
    }

    /**
     * Record one block and remove it. If it is protected, add to the
     * replace-immediately list. Check for dependent blocks around.
     *
     * @param block
     *            The block to record.
     */
    public void record(Block block)
    {
      if (block.getType() == Material.PORTAL)
        return;
     
        CreeperBlock cBlock = CreeperBlock.newBlock(block.getState());

        if (cBlock == null || checked.contains(new ShortLocation(block)))
            return;

        checked.add(new ShortLocation(block));

        if ((CreeperConfig.getBool(CfgVal.PREVENT_CHAIN_REACTION) && block.getType().equals(Material.TNT))
            || world.isProtected(block))
        {
            CreeperBlock b = CreeperBlock.newBlock(block.getState());
            if (b != null)
            {
                ToReplaceList.addToReplace(b);
                b.remove();
            }
            return;
        }

        BlockId id = new BlockId(block);
        if (!world.isBlackListed(id))
        {
            // The block should be replaced.

            for (NeighborBlock b : cBlock.getDependentNeighbors())
                if (b.isNeighbor())
                    record(b.getBlock());

            CreeperBlock b = CreeperBlock.newBlock(block.getState());
            if (b != null)
            {
                blockList.add(b);
                b.remove();
            }
        }
        else if (CreeperConfig.getBool(CfgVal.DROP_DESTROYED_BLOCKS))
        {
            cBlock.drop(false);
            cBlock.remove();

        }

    }

    /**
     * Add a Replaceable to the list, and remove it from the world.
     *
     * @param block
     *            The Replaceable to add.
     */
    public void record(Replaceable block)
    {
        if (block != null)
        {
            blockList.add(block);
            block.remove();
        }
    }

    /**
     * Check if the explosion has blocks to repair, and repair them (or one of
     * them in case of block per block).
     *
     * @return False if the explosion has not started its replacements yet
     *         because it is not time.
     */
    public boolean checkReplace()
    {
        if (timer.isTimed())
            return true;
        if (timer.checkReplace())
        {
            if (CreeperConfig.getBool(CfgVal.BLOCK_PER_BLOCK))
                replace_one_block();
            else
                replace_blocks(true, CHBlockHealReason.EXPLOSION);
            return true;

        }
        return false;
    }

    /**
     * Get whether the explosion has started replacing (only in block per block
     * mode).
     *
     * @return True if the explosion has started replacing blocks
     */
    public boolean hasStartedReplacing()
    {
        if (timer.isTimed())
            return false;
        return timer.checkReplace();
    }

    /**
     * Get whether the list of blocks to be replaced is empty.
     *
     * @return Whether the list is empty.
     */
    public boolean isEmpty()
    {
        return blockList.isEmpty();
    }

}
TOP

Related Classes of com.nitnelave.CreeperHeal.block.CreeperExplosion

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.