package net.minecraft.server;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.koloboke.collect.set.hash.HashObjSets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
// CraftBukkit start
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.entity.HumanEntity;
import org.bukkit.potion.PotionEffect;
// CraftBukkit end
// Paper start
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionEffect;
import com.destroystokyo.paper.event.block.BeaconEffectEvent;
// Paper end
public class TileEntityBeacon extends TileEntityContainer implements ITickable, IWorldInventory {
public static final MobEffectList[][] a = new MobEffectList[][] { { MobEffects.FASTER_MOVEMENT, MobEffects.FASTER_DIG}, { MobEffects.RESISTANCE, MobEffects.JUMP}, { MobEffects.INCREASE_DAMAGE}, { MobEffects.REGENERATION}};
private static final Set<MobEffectList> f = HashObjSets.newMutableSet();
private final List<TileEntityBeacon.BeaconColorTracker> g = Lists.newArrayList();
private boolean j;
public int levels = -1;
@Nullable
public MobEffectList primaryEffect;
@Nullable
public MobEffectList secondaryEffect;
private ItemStack inventorySlot;
private String o;
// CraftBukkit start - add fields and methods
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
@Override
public List<ItemStack> getContents() {
return Arrays.asList(this.inventorySlot);
}
@Override
public void onOpen(CraftHumanEntity who) {
transaction.add(who);
}
@Override
public void onClose(CraftHumanEntity who) {
transaction.remove(who);
}
@Override
public List<HumanEntity> getViewers() {
return transaction;
}
@Override
public void setMaxStackSize(int size) {
maxStack = size;
}
public PotionEffect getPrimaryEffect() {
return (this.primaryEffect != null) ? CraftPotionUtil.toBukkit(new MobEffect(this.primaryEffect, getLevel(), getAmplification(), true, true)) : null;
}
public PotionEffect getSecondaryEffect() {
return (hasSecondaryEffect()) ? CraftPotionUtil.toBukkit(new MobEffect(this.secondaryEffect, getLevel(), getAmplification(), true, true)) : null;
}
// CraftBukkit end
public TileEntityBeacon() {
this.inventorySlot = ItemStack.a;
}
@Override
public void F_() {
if (this.world.getTime() % 80L == 0L) {
this.n();
}
}
public void n() {
if (this.world != null) {
this.F();
this.E();
}
}
// CraftBukkit start - split into components
private byte getAmplification() {
{
byte b0 = 0;
if (this.levels >= 4 && this.primaryEffect == this.secondaryEffect) {
b0 = 1;
}
return b0;
}
}
private int getLevel() {
{
int i = (9 + this.levels * 2) * 20;
return i;
}
}
public List getHumansInRange() {
{
double d0 = this.levels * 10 + 10;
int j = this.position.getX();
int k = this.position.getY();
int l = this.position.getZ();
AxisAlignedBB axisalignedbb = (new AxisAlignedBB(j, k, l, j + 1, k + 1, l + 1)).g(d0).b(0.0D, this.world.getHeight(), 0.0D);
List list = this.world.a(EntityHuman.class, axisalignedbb);
return list;
}
}
private void applyEffect(List list, MobEffectList effects, int i, int b0) {
// Paper - BeaconEffectEvent
applyEffect(list, effects, i, b0, true);
}
private void applyEffect(List list, MobEffectList effects, int i, int b0, boolean isPrimary) {
// Paper - BeaconEffectEvent
{
Iterator iterator = list.iterator();
EntityHuman entityhuman;
// Paper start - BeaconEffectEvent
org.bukkit.block.Block block = world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ());
PotionEffect effect = CraftPotionUtil.toBukkit(new MobEffect(effects, i, b0, true, true));
// Paper end
while (iterator.hasNext()) {
entityhuman = (EntityHuman) iterator.next();
// Paper start - BeaconEffectEvent
BeaconEffectEvent event = new BeaconEffectEvent(block, effect, (Player) entityhuman.getBukkitEntity(), isPrimary);
if (CraftEventFactory.callEvent(event).isCancelled()) continue;
PotionEffect eventEffect = event.getEffect();
entityhuman.getBukkitEntity().addPotionEffect(eventEffect, true);
// Paper end
}
}
}
private boolean hasSecondaryEffect() {
{
if (this.levels >= 4 && this.primaryEffect != this.secondaryEffect && this.secondaryEffect != null) {
return true;
}
return false;
}
}
private void E() {
if (this.j && this.levels > 0 && !this.world.isClientSide && this.primaryEffect != null) {
byte b0 = getAmplification();
int i = getLevel();
List list = getHumansInRange();
applyEffect(list, this.primaryEffect, i, b0, true); // Paper - BeaconEffectEvent
if (hasSecondaryEffect()) {
applyEffect(list, this.secondaryEffect, i, 0, false); // Paper - BeaconEffectEvent
}
}
}
// CraftBukkit end
private void F() {
int i = this.levels;
int j = this.position.getX();
int k = this.position.getY();
int l = this.position.getZ();
this.levels = 0;
this.g.clear();
this.j = true;
TileEntityBeacon.BeaconColorTracker tileentitybeacon_beaconcolortracker = new TileEntityBeacon.BeaconColorTracker(EntitySheep.a(EnumColor.WHITE));
this.g.add(tileentitybeacon_beaconcolortracker);
boolean flag = true;
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
int i1;
for (i1 = k + 1; i1 < 256; ++i1) {
IBlockData iblockdata = this.world.getType(blockposition_mutableblockposition.c(j, i1, l));
float[] afloat;
if (iblockdata.getBlock() == Blocks.STAINED_GLASS) {
afloat = EntitySheep.a(iblockdata.get(BlockStainedGlass.COLOR));
} else {
if (iblockdata.getBlock() != Blocks.STAINED_GLASS_PANE) {
if (iblockdata.c() >= 15 && iblockdata.getBlock() != Blocks.BEDROCK) {
this.j = false;
this.g.clear();
break;
}
tileentitybeacon_beaconcolortracker.a();
continue;
}
afloat = EntitySheep.a(iblockdata.get(BlockStainedGlassPane.COLOR));
}
if (!flag) {
afloat = new float[] { (tileentitybeacon_beaconcolortracker.b()[0] + afloat[0]) / 2.0F, (tileentitybeacon_beaconcolortracker.b()[1] + afloat[1]) / 2.0F, (tileentitybeacon_beaconcolortracker.b()[2] + afloat[2]) / 2.0F};
}
if (Arrays.equals(afloat, tileentitybeacon_beaconcolortracker.b())) {
tileentitybeacon_beaconcolortracker.a();
} else {
tileentitybeacon_beaconcolortracker = new TileEntityBeacon.BeaconColorTracker(afloat);
this.g.add(tileentitybeacon_beaconcolortracker);
}
flag = false;
}
if (this.j) {
for (i1 = 1; i1 <= 4; this.levels = i1++) {
int j1 = k - i1;
if (j1 < 0) {
break;
}
boolean flag1 = true;
for (int k1 = j - i1; k1 <= j + i1 && flag1; ++k1) {
for (int l1 = l - i1; l1 <= l + i1; ++l1) {
Block block = this.world.getType(new BlockPosition(k1, j1, l1)).getBlock();
if (block != Blocks.EMERALD_BLOCK && block != Blocks.GOLD_BLOCK && block != Blocks.DIAMOND_BLOCK && block != Blocks.IRON_BLOCK) {
flag1 = false;
break;
}
}
}
if (!flag1) {
break;
}
}
if (this.levels == 0) {
this.j = false;
}
}
if (!this.world.isClientSide && this.levels == 4 && i < this.levels) {
Iterator iterator = this.world.a(EntityHuman.class, (new AxisAlignedBB(j, k, l, j, k - 4, l)).grow(10.0D, 5.0D, 10.0D)).iterator();
while (iterator.hasNext()) {
EntityHuman entityhuman = (EntityHuman) iterator.next();
entityhuman.b(AchievementList.K);
}
}
}
@Override
@Nullable
public PacketPlayOutTileEntityData getUpdatePacket() {
return new PacketPlayOutTileEntityData(this.position, 3, this.d());
}
@Override
public NBTTagCompound d() {
return this.save(new NBTTagCompound());
}
@Nullable
private static MobEffectList f(int i) {
MobEffectList mobeffectlist = MobEffectList.fromId(i);
return TileEntityBeacon.f.contains(mobeffectlist) ? mobeffectlist : null;
}
@Override
public void a(NBTTagCompound nbttagcompound) {
super.a(nbttagcompound);
this.primaryEffect = f(nbttagcompound.getInt("Primary"));
this.secondaryEffect = f(nbttagcompound.getInt("Secondary"));
this.levels = nbttagcompound.getInt("Levels");
}
@Override
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
super.save(nbttagcompound);
nbttagcompound.setInt("Primary", MobEffectList.getId(this.primaryEffect));
nbttagcompound.setInt("Secondary", MobEffectList.getId(this.secondaryEffect));
nbttagcompound.setInt("Levels", this.levels);
return nbttagcompound;
}
@Override
public int getSize() {
return 1;
}
@Override
public boolean w_() {
return this.inventorySlot.isEmpty();
}
@Override
public ItemStack getItem(int i) {
return i == 0 ? this.inventorySlot : ItemStack.a;
}
@Override
public ItemStack splitStack(int i, int j) {
if (i == 0 && !this.inventorySlot.isEmpty()) {
if (j >= this.inventorySlot.getCount()) {
ItemStack itemstack = this.inventorySlot;
this.inventorySlot = ItemStack.a;
return itemstack;
} else {
return this.inventorySlot.cloneAndSubtract(j);
}
} else {
return ItemStack.a;
}
}
@Override
public ItemStack splitWithoutUpdate(int i) {
if (i == 0) {
ItemStack itemstack = this.inventorySlot;
this.inventorySlot = ItemStack.a;
return itemstack;
} else {
return ItemStack.a;
}
}
@Override
public void setItem(int i, ItemStack itemstack) {
if (i == 0) {
this.inventorySlot = itemstack;
}
}
@Override
public String getName() {
return this.hasCustomName() ? this.o : "container.beacon";
}
@Override
public boolean hasCustomName() {
return this.o != null && !this.o.isEmpty();
}
public void a(String s) {
this.o = s;
}
@Override
public int getMaxStackSize() {
return 1;
}
@Override
public boolean a(EntityHuman entityhuman) {
return this.world.getTileEntity(this.position) != this ? false : entityhuman.d(this.position.getX() + 0.5D, this.position.getY() + 0.5D, this.position.getZ() + 0.5D) <= 64.0D;
}
@Override
public void startOpen(EntityHuman entityhuman) {}
@Override
public void closeContainer(EntityHuman entityhuman) {}
@Override
public boolean b(int i, ItemStack itemstack) {
return itemstack.getItem() == Items.EMERALD || itemstack.getItem() == Items.DIAMOND || itemstack.getItem() == Items.GOLD_INGOT || itemstack.getItem() == Items.IRON_INGOT;
}
@Override
public String getContainerName() {
return "minecraft:beacon";
}
@Override
public Container createContainer(PlayerInventory playerinventory, EntityHuman entityhuman) {
return new ContainerBeacon(playerinventory, this);
}
@Override
public int getProperty(int i) {
switch (i) {
case 0:
return this.levels;
case 1:
return MobEffectList.getId(this.primaryEffect);
case 2:
return MobEffectList.getId(this.secondaryEffect);
default:
return 0;
}
}
@Override
public void setProperty(int i, int j) {
switch (i) {
case 0:
this.levels = j;
break;
case 1:
this.primaryEffect = f(j);
break;
case 2:
this.secondaryEffect = f(j);
}
}
@Override
public int h() {
return 3;
}
@Override
public void clear() {
this.inventorySlot = ItemStack.a;
}
@Override
public boolean c(int i, int j) {
if (i == 1) {
this.n();
return true;
} else {
return super.c(i, j);
}
}
@Override
public int[] getSlotsForFace(EnumDirection enumdirection) {
return new int[0];
}
@Override
public boolean canPlaceItemThroughFace(int i, ItemStack itemstack, EnumDirection enumdirection) {
return false;
}
@Override
public boolean canTakeItemThroughFace(int i, ItemStack itemstack, EnumDirection enumdirection) {
return false;
}
static {
MobEffectList[][] amobeffectlist = TileEntityBeacon.a;
int i = amobeffectlist.length;
for (int j = 0; j < i; ++j) {
MobEffectList[] amobeffectlist1 = amobeffectlist[j];
Collections.addAll(TileEntityBeacon.f, amobeffectlist1);
}
}
public static class BeaconColorTracker {
private final float[] a;
private int b;
public BeaconColorTracker(float[] afloat) {
this.a = afloat;
this.b = 1;
}
protected void a() {
++this.b;
}
public float[] b() {
return this.a;
}
}
}