package net.minecraft.server;
import com.koloboke.collect.map.hash.HashObjIntMaps;
import com.koloboke.collect.Equivalence;
import java.util.Map;
import java.util.Random;
import javax.annotation.Nullable;
// CraftBukkit start
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockSpreadEvent;
// CraftBukkit end
public class BlockFire extends Block {
public static final BlockStateInteger AGE = BlockStateInteger.of("age", 0, 15);
public static final BlockStateBoolean NORTH = BlockStateBoolean.of("north");
public static final BlockStateBoolean EAST = BlockStateBoolean.of("east");
public static final BlockStateBoolean SOUTH = BlockStateBoolean.of("south");
public static final BlockStateBoolean WEST = BlockStateBoolean.of("west");
public static final BlockStateBoolean UPPER = BlockStateBoolean.of("up");
private final Map<Block, Integer> flameChances = HashObjIntMaps.getDefaultFactory().withKeyEquivalence(Equivalence.identity()).newMutableMap();
private final Map<Block, Integer> B = HashObjIntMaps.getDefaultFactory().withKeyEquivalence(Equivalence.identity()).newMutableMap();
@Override
public IBlockData updateState(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition) {
return !iblockaccess.getType(blockposition.down()).r() && !Blocks.FIRE.c(iblockaccess, blockposition.down()) ? iblockdata.set(BlockFire.NORTH, Boolean.valueOf(this.c(iblockaccess, blockposition.north()))).set(BlockFire.EAST, Boolean.valueOf(this.c(iblockaccess, blockposition.east()))).set(BlockFire.SOUTH, Boolean.valueOf(this.c(iblockaccess, blockposition.south()))).set(BlockFire.WEST, Boolean.valueOf(this.c(iblockaccess, blockposition.west()))).set(BlockFire.UPPER, Boolean.valueOf(this.c(iblockaccess, blockposition.up()))) : this.getBlockData();
}
protected BlockFire() {
super(Material.FIRE);
this.y(this.blockStateList.getBlockData().set(BlockFire.AGE, Integer.valueOf(0)).set(BlockFire.NORTH, Boolean.valueOf(false)).set(BlockFire.EAST, Boolean.valueOf(false)).set(BlockFire.SOUTH, Boolean.valueOf(false)).set(BlockFire.WEST, Boolean.valueOf(false)).set(BlockFire.UPPER, Boolean.valueOf(false)));
this.a(true);
}
public static void e() {
Blocks.FIRE.a(Blocks.PLANKS, 5, 20);
Blocks.FIRE.a(Blocks.DOUBLE_WOODEN_SLAB, 5, 20);
Blocks.FIRE.a(Blocks.WOODEN_SLAB, 5, 20);
Blocks.FIRE.a(Blocks.FENCE_GATE, 5, 20);
Blocks.FIRE.a(Blocks.SPRUCE_FENCE_GATE, 5, 20);
Blocks.FIRE.a(Blocks.BIRCH_FENCE_GATE, 5, 20);
Blocks.FIRE.a(Blocks.JUNGLE_FENCE_GATE, 5, 20);
Blocks.FIRE.a(Blocks.DARK_OAK_FENCE_GATE, 5, 20);
Blocks.FIRE.a(Blocks.ACACIA_FENCE_GATE, 5, 20);
Blocks.FIRE.a(Blocks.FENCE, 5, 20);
Blocks.FIRE.a(Blocks.SPRUCE_FENCE, 5, 20);
Blocks.FIRE.a(Blocks.BIRCH_FENCE, 5, 20);
Blocks.FIRE.a(Blocks.JUNGLE_FENCE, 5, 20);
Blocks.FIRE.a(Blocks.DARK_OAK_FENCE, 5, 20);
Blocks.FIRE.a(Blocks.ACACIA_FENCE, 5, 20);
Blocks.FIRE.a(Blocks.OAK_STAIRS, 5, 20);
Blocks.FIRE.a(Blocks.BIRCH_STAIRS, 5, 20);
Blocks.FIRE.a(Blocks.SPRUCE_STAIRS, 5, 20);
Blocks.FIRE.a(Blocks.JUNGLE_STAIRS, 5, 20);
Blocks.FIRE.a(Blocks.ACACIA_STAIRS, 5, 20);
Blocks.FIRE.a(Blocks.DARK_OAK_STAIRS, 5, 20);
Blocks.FIRE.a(Blocks.LOG, 5, 5);
Blocks.FIRE.a(Blocks.LOG2, 5, 5);
Blocks.FIRE.a(Blocks.LEAVES, 30, 60);
Blocks.FIRE.a(Blocks.LEAVES2, 30, 60);
Blocks.FIRE.a(Blocks.BOOKSHELF, 30, 20);
Blocks.FIRE.a(Blocks.TNT, 15, 100);
Blocks.FIRE.a(Blocks.TALLGRASS, 60, 100);
Blocks.FIRE.a(Blocks.DOUBLE_PLANT, 60, 100);
Blocks.FIRE.a(Blocks.YELLOW_FLOWER, 60, 100);
Blocks.FIRE.a(Blocks.RED_FLOWER, 60, 100);
Blocks.FIRE.a(Blocks.DEADBUSH, 60, 100);
Blocks.FIRE.a(Blocks.WOOL, 30, 60);
Blocks.FIRE.a(Blocks.VINE, 15, 100);
Blocks.FIRE.a(Blocks.COAL_BLOCK, 5, 5);
Blocks.FIRE.a(Blocks.HAY_BLOCK, 60, 20);
Blocks.FIRE.a(Blocks.CARPET, 60, 20);
}
public void a(Block block, int i, int j) {
this.flameChances.put(block, Integer.valueOf(i));
this.B.put(block, Integer.valueOf(j));
}
@Override
@Nullable
public AxisAlignedBB a(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition) {
return BlockFire.k;
}
@Override
public boolean b(IBlockData iblockdata) {
return false;
}
@Override
public boolean c(IBlockData iblockdata) {
return false;
}
@Override
public int a(Random random) {
return 0;
}
@Override
public int a(World world) {
return 30;
}
@Override
public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) {
if (world.getGameRules().getBoolean("doFireTick")) {
if (!this.canPlace(world, blockposition)) {
fireExtinguished(world, blockposition); // CraftBukkit - invalid place location
}
Block block = world.getType(blockposition.down()).getBlock();
boolean flag = block == Blocks.NETHERRACK;
if (world.worldProvider instanceof WorldProviderTheEnd && block == Blocks.BEDROCK) {
flag = true;
}
int i = iblockdata.get(BlockFire.AGE).intValue();
if (!flag && world.W() && this.b(world, blockposition) && random.nextFloat() < 0.2F + i * 0.03F) {
fireExtinguished(world, blockposition); // CraftBukkit - extinguished by rain
} else {
if (i < 15) {
iblockdata = iblockdata.set(BlockFire.AGE, Integer.valueOf(i + random.nextInt(3) / 2));
world.setTypeAndData(blockposition, iblockdata, 4);
}
world.a(blockposition, this, this.a(world) + random.nextInt(10));
if (!flag) {
if (!this.c(world, blockposition)) {
if (!world.getType(blockposition.down()).r() || i > 3) {
fireExtinguished(world, blockposition); // CraftBukkit
}
return;
}
if (!this.c((IBlockAccess) world, blockposition.down()) && i == 15 && random.nextInt(4) == 0) {
fireExtinguished(world, blockposition); // CraftBukkit
return;
}
}
boolean flag1 = world.C(blockposition);
byte b0 = 0;
if (flag1) {
b0 = -50;
}
// CraftBukkit start - add source blockposition to burn calls
this.a(world, blockposition.east(), 300 + b0, random, i, blockposition);
this.a(world, blockposition.west(), 300 + b0, random, i, blockposition);
this.a(world, blockposition.down(), 250 + b0, random, i, blockposition);
this.a(world, blockposition.up(), 250 + b0, random, i, blockposition);
this.a(world, blockposition.north(), 300 + b0, random, i, blockposition);
this.a(world, blockposition.south(), 300 + b0, random, i, blockposition);
// CraftBukkit end
for (int j = -1; j <= 1; ++j) {
for (int k = -1; k <= 1; ++k) {
for (int l = -1; l <= 4; ++l) {
if (j != 0 || l != 0 || k != 0) {
int i1 = 100;
if (l > 1) {
i1 += (l - 1) * 100;
}
BlockPosition blockposition1 = blockposition.a(j, l, k);
if (!world.isLoaded(blockposition1)) continue; // Paper
int j1 = this.d(world, blockposition1);
if (j1 > 0) {
int k1 = (j1 + 40 + world.getDifficulty().a() * 7) / (i + 30);
if (flag1) {
k1 /= 2;
}
if (k1 > 0 && random.nextInt(i1) <= k1 && (!world.W() || !this.b(world, blockposition1))) {
int l1 = i + random.nextInt(5) / 4;
if (l1 > 15) {
l1 = 15;
}
// CraftBukkit start - Call to stop spread of fire
if (world.getType(blockposition1) != Blocks.FIRE) {
if (CraftEventFactory.callBlockIgniteEvent(world, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ(), blockposition.getX(), blockposition.getY(), blockposition.getZ()).isCancelled()) {
continue;
}
org.bukkit.Server server = world.getServer();
org.bukkit.World bworld = world.getWorld();
org.bukkit.block.BlockState blockState = bworld.getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()).getState();
blockState.setTypeId(Block.getId(this));
blockState.setData(new org.bukkit.material.MaterialData(Block.getId(this), (byte) l1));
BlockSpreadEvent spreadEvent = new BlockSpreadEvent(blockState.getBlock(), bworld.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), blockState);
server.getPluginManager().callEvent(spreadEvent);
if (!spreadEvent.isCancelled()) {
blockState.update(true);
}
}
// CraftBukkit end
}
}
}
}
}
}
}
}
}
protected boolean b(World world, BlockPosition blockposition) {
return world.isRainingAt(blockposition) || world.isRainingAt(blockposition.west()) || world.isRainingAt(blockposition.east()) || world.isRainingAt(blockposition.north()) || world.isRainingAt(blockposition.south());
}
@Override
public boolean r() {
return false;
}
private int c(Block block) {
Integer integer = this.B.get(block);
return integer == null ? 0 : integer.intValue();
}
private int d(Block block) {
Integer integer = this.flameChances.get(block);
return integer == null ? 0 : integer.intValue();
}
private void a(World world, BlockPosition blockposition, int i, Random random, int j, BlockPosition sourceposition) { // CraftBukkit add sourceposition
// Paper start
final IBlockData iblockdata = world.getTypeIfLoaded(blockposition);
if (iblockdata == null) return;
int k = this.c(iblockdata.getBlock());
// Paper end
if (random.nextInt(i) < k) {
//IBlockData iblockdata = world.getType(blockposition); // Paper
// CraftBukkit start
org.bukkit.block.Block theBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
org.bukkit.block.Block sourceBlock = world.getWorld().getBlockAt(sourceposition.getX(), sourceposition.getY(), sourceposition.getZ());
BlockBurnEvent event = new BlockBurnEvent(theBlock, sourceBlock);
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
// CraftBukkit end
if (random.nextInt(j + 10) < 5 && !world.isRainingAt(blockposition)) {
int l = j + random.nextInt(5) / 4;
if (l > 15) {
l = 15;
}
world.setTypeAndData(blockposition, this.getBlockData().set(BlockFire.AGE, Integer.valueOf(l)), 3);
} else {
world.setAir(blockposition);
}
if (iblockdata.getBlock() == Blocks.TNT) {
Blocks.TNT.postBreak(world, blockposition, iblockdata.set(BlockTNT.EXPLODE, Boolean.valueOf(true)));
}
}
}
private boolean c(World world, BlockPosition blockposition) {
EnumDirection[] aenumdirection = EnumDirection.values();
int i = aenumdirection.length;
for (int j = 0; j < i; ++j) {
EnumDirection enumdirection = aenumdirection[j];
if (this.c((IBlockAccess) world, blockposition.shift(enumdirection))) {
return true;
}
}
return false;
}
private int d(World world, BlockPosition blockposition) {
if (!world.isEmpty(blockposition)) {
return 0;
} else {
int i = 0;
EnumDirection[] aenumdirection = EnumDirection.values();
int j = aenumdirection.length;
for (int k = 0; k < j; ++k) {
EnumDirection enumdirection = aenumdirection[k];
final IBlockData type = world.getTypeIfLoaded(blockposition.shift(enumdirection)); // Paper
if (type == null) continue; // Paper
i = Math.max(this.d(type.getBlock()), i); // Paper
}
return i;
}
}
@Override
public boolean m() {
return false;
}
public boolean c(IBlockAccess iblockaccess, BlockPosition blockposition) {
return this.d(iblockaccess.getType(blockposition).getBlock()) > 0;
}
@Override
public boolean canPlace(World world, BlockPosition blockposition) {
return world.getType(blockposition.down()).r() || this.c(world, blockposition);
}
@Override
public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) {
if (!world.getType(blockposition.down()).r() && !this.c(world, blockposition)) {
fireExtinguished(world, blockposition); // CraftBukkit - fuel block gone
}
}
@Override
public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
if (world.worldProvider.getDimensionManager().getDimensionID() > 0 || !Blocks.PORTAL.b(world, blockposition)) {
if (!world.getType(blockposition.down()).r() && !this.c(world, blockposition)) {
fireExtinguished(world, blockposition); // CraftBukkit - fuel block broke
} else {
world.a(blockposition, this, this.a(world) + world.random.nextInt(10));
}
}
}
@Override
public MaterialMapColor r(IBlockData iblockdata) {
return MaterialMapColor.f;
}
@Override
public IBlockData fromLegacyData(int i) {
return this.getBlockData().set(BlockFire.AGE, Integer.valueOf(i));
}
@Override
public int toLegacyData(IBlockData iblockdata) {
return iblockdata.get(BlockFire.AGE).intValue();
}
@Override
protected BlockStateList getStateList() {
return new BlockStateList(this, new IBlockState[] { BlockFire.AGE, BlockFire.NORTH, BlockFire.EAST, BlockFire.SOUTH, BlockFire.WEST, BlockFire.UPPER});
}
// CraftBukkit start
private void fireExtinguished(World world, BlockPosition position) {
if (!CraftEventFactory.callBlockFadeEvent(world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), Blocks.AIR).isCancelled()) {
world.setAir(position);
}
}
// CraftBukkit end
}