568 lines
16 KiB
Java
568 lines
16 KiB
Java
package net.minecraft.tileentity;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Sets;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.advancements.CriteriaTriggers;
|
|
import net.minecraft.block.Block;
|
|
import net.minecraft.block.BlockStainedGlass;
|
|
import net.minecraft.block.BlockStainedGlassPane;
|
|
import net.minecraft.block.state.IBlockState;
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
import net.minecraft.entity.player.InventoryPlayer;
|
|
import net.minecraft.init.Blocks;
|
|
import net.minecraft.init.Items;
|
|
import net.minecraft.init.MobEffects;
|
|
import net.minecraft.inventory.Container;
|
|
import net.minecraft.inventory.ContainerBeacon;
|
|
import net.minecraft.inventory.ISidedInventory;
|
|
import net.minecraft.item.EnumDyeColor;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
|
import net.minecraft.potion.Potion;
|
|
import net.minecraft.potion.PotionEffect;
|
|
import net.minecraft.util.EnumFacing;
|
|
import net.minecraft.util.ITickable;
|
|
import net.minecraft.util.math.AxisAlignedBB;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraftforge.fml.relauncher.Side;
|
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
|
|
|
public class TileEntityBeacon extends TileEntityLockable implements ITickable, ISidedInventory
|
|
{
|
|
/** List of effects that Beacon can apply */
|
|
public static final Potion[][] EFFECTS_LIST = new Potion[][] {{MobEffects.SPEED, MobEffects.HASTE}, {MobEffects.RESISTANCE, MobEffects.JUMP_BOOST}, {MobEffects.STRENGTH}, {MobEffects.REGENERATION}};
|
|
private static final Set<Potion> VALID_EFFECTS = Sets.<Potion>newHashSet();
|
|
/** A list of beam segments for this beacon */
|
|
private final List<TileEntityBeacon.BeamSegment> beamSegments = Lists.<TileEntityBeacon.BeamSegment>newArrayList();
|
|
@SideOnly(Side.CLIENT)
|
|
private long beamRenderCounter;
|
|
@SideOnly(Side.CLIENT)
|
|
private float beamRenderScale;
|
|
private boolean isComplete;
|
|
/** Level of this beacon's pyramid. */
|
|
private int levels = -1;
|
|
/** Primary potion effect given by this beacon. */
|
|
@Nullable
|
|
private Potion primaryEffect;
|
|
/** Secondary potion effect given by this beacon. */
|
|
@Nullable
|
|
private Potion secondaryEffect;
|
|
/** Item given to this beacon as payment. */
|
|
private ItemStack payment = ItemStack.EMPTY;
|
|
private String customName;
|
|
|
|
/**
|
|
* Like the old updateEntity(), except more generic.
|
|
*/
|
|
public void update()
|
|
{
|
|
if (this.world.getTotalWorldTime() % 80L == 0L)
|
|
{
|
|
this.updateBeacon();
|
|
}
|
|
}
|
|
|
|
public void updateBeacon()
|
|
{
|
|
if (this.world != null)
|
|
{
|
|
this.updateSegmentColors();
|
|
this.addEffectsToPlayers();
|
|
}
|
|
}
|
|
|
|
private void addEffectsToPlayers()
|
|
{
|
|
if (this.isComplete && this.levels > 0 && !this.world.isRemote && this.primaryEffect != null)
|
|
{
|
|
double d0 = (double)(this.levels * 10 + 10);
|
|
int i = 0;
|
|
|
|
if (this.levels >= 4 && this.primaryEffect == this.secondaryEffect)
|
|
{
|
|
i = 1;
|
|
}
|
|
|
|
int j = (9 + this.levels * 2) * 20;
|
|
int k = this.pos.getX();
|
|
int l = this.pos.getY();
|
|
int i1 = this.pos.getZ();
|
|
AxisAlignedBB axisalignedbb = (new AxisAlignedBB((double)k, (double)l, (double)i1, (double)(k + 1), (double)(l + 1), (double)(i1 + 1))).grow(d0).expand(0.0D, (double)this.world.getHeight(), 0.0D);
|
|
List<EntityPlayer> list = this.world.<EntityPlayer>getEntitiesWithinAABB(EntityPlayer.class, axisalignedbb);
|
|
|
|
for (EntityPlayer entityplayer : list)
|
|
{
|
|
entityplayer.addPotionEffect(new PotionEffect(this.primaryEffect, j, i, true, true));
|
|
}
|
|
|
|
if (this.levels >= 4 && this.primaryEffect != this.secondaryEffect && this.secondaryEffect != null)
|
|
{
|
|
for (EntityPlayer entityplayer1 : list)
|
|
{
|
|
entityplayer1.addPotionEffect(new PotionEffect(this.secondaryEffect, j, 0, true, true));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void updateSegmentColors()
|
|
{
|
|
int i = this.pos.getX();
|
|
int j = this.pos.getY();
|
|
int k = this.pos.getZ();
|
|
int l = this.levels;
|
|
this.levels = 0;
|
|
this.beamSegments.clear();
|
|
this.isComplete = true;
|
|
TileEntityBeacon.BeamSegment tileentitybeacon$beamsegment = new TileEntityBeacon.BeamSegment(EnumDyeColor.WHITE.getColorComponentValues());
|
|
this.beamSegments.add(tileentitybeacon$beamsegment);
|
|
boolean flag = true;
|
|
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
|
|
|
|
for (int i1 = j + 1; i1 < 256; ++i1)
|
|
{
|
|
IBlockState iblockstate = this.world.getBlockState(blockpos$mutableblockpos.setPos(i, i1, k));
|
|
float[] afloat;
|
|
|
|
if (iblockstate.getBlock() == Blocks.STAINED_GLASS)
|
|
{
|
|
afloat = ((EnumDyeColor)iblockstate.getValue(BlockStainedGlass.COLOR)).getColorComponentValues();
|
|
}
|
|
else
|
|
{
|
|
if (iblockstate.getBlock() != Blocks.STAINED_GLASS_PANE)
|
|
{
|
|
if (iblockstate.getLightOpacity(world, blockpos$mutableblockpos) >= 15 && iblockstate.getBlock() != Blocks.BEDROCK)
|
|
{
|
|
this.isComplete = false;
|
|
this.beamSegments.clear();
|
|
break;
|
|
}
|
|
float[] customColor = iblockstate.getBlock().getBeaconColorMultiplier(iblockstate, this.world, blockpos$mutableblockpos, getPos());
|
|
if (customColor != null)
|
|
afloat = customColor;
|
|
else {
|
|
tileentitybeacon$beamsegment.incrementHeight();
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
afloat = ((EnumDyeColor)iblockstate.getValue(BlockStainedGlassPane.COLOR)).getColorComponentValues();
|
|
}
|
|
|
|
if (!flag)
|
|
{
|
|
afloat = new float[] {(tileentitybeacon$beamsegment.getColors()[0] + afloat[0]) / 2.0F, (tileentitybeacon$beamsegment.getColors()[1] + afloat[1]) / 2.0F, (tileentitybeacon$beamsegment.getColors()[2] + afloat[2]) / 2.0F};
|
|
}
|
|
|
|
if (Arrays.equals(afloat, tileentitybeacon$beamsegment.getColors()))
|
|
{
|
|
tileentitybeacon$beamsegment.incrementHeight();
|
|
}
|
|
else
|
|
{
|
|
tileentitybeacon$beamsegment = new TileEntityBeacon.BeamSegment(afloat);
|
|
this.beamSegments.add(tileentitybeacon$beamsegment);
|
|
}
|
|
|
|
flag = false;
|
|
}
|
|
|
|
if (this.isComplete)
|
|
{
|
|
for (int l1 = 1; l1 <= 4; this.levels = l1++)
|
|
{
|
|
int i2 = j - l1;
|
|
|
|
if (i2 < 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
boolean flag1 = true;
|
|
|
|
for (int j1 = i - l1; j1 <= i + l1 && flag1; ++j1)
|
|
{
|
|
for (int k1 = k - l1; k1 <= k + l1; ++k1)
|
|
{
|
|
Block block = this.world.getBlockState(new BlockPos(j1, i2, k1)).getBlock();
|
|
|
|
if (!block.isBeaconBase(this.world, new BlockPos(j1, i2, k1), getPos()))
|
|
{
|
|
flag1 = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!flag1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (this.levels == 0)
|
|
{
|
|
this.isComplete = false;
|
|
}
|
|
}
|
|
|
|
if (!this.world.isRemote && l < this.levels)
|
|
{
|
|
for (EntityPlayerMP entityplayermp : this.world.getEntitiesWithinAABB(EntityPlayerMP.class, (new AxisAlignedBB((double)i, (double)j, (double)k, (double)i, (double)(j - 4), (double)k)).grow(10.0D, 5.0D, 10.0D)))
|
|
{
|
|
CriteriaTriggers.CONSTRUCT_BEACON.trigger(entityplayermp, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
public List<TileEntityBeacon.BeamSegment> getBeamSegments()
|
|
{
|
|
return this.beamSegments;
|
|
}
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
public float shouldBeamRender()
|
|
{
|
|
if (!this.isComplete)
|
|
{
|
|
return 0.0F;
|
|
}
|
|
else
|
|
{
|
|
int i = (int)(this.world.getTotalWorldTime() - this.beamRenderCounter);
|
|
this.beamRenderCounter = this.world.getTotalWorldTime();
|
|
|
|
if (i > 1)
|
|
{
|
|
this.beamRenderScale -= (float)i / 40.0F;
|
|
|
|
if (this.beamRenderScale < 0.0F)
|
|
{
|
|
this.beamRenderScale = 0.0F;
|
|
}
|
|
}
|
|
|
|
this.beamRenderScale += 0.025F;
|
|
|
|
if (this.beamRenderScale > 1.0F)
|
|
{
|
|
this.beamRenderScale = 1.0F;
|
|
}
|
|
|
|
return this.beamRenderScale;
|
|
}
|
|
}
|
|
|
|
public int getLevels()
|
|
{
|
|
return this.levels;
|
|
}
|
|
|
|
@Nullable
|
|
public SPacketUpdateTileEntity getUpdatePacket()
|
|
{
|
|
return new SPacketUpdateTileEntity(this.pos, 3, this.getUpdateTag());
|
|
}
|
|
|
|
public NBTTagCompound getUpdateTag()
|
|
{
|
|
return this.writeToNBT(new NBTTagCompound());
|
|
}
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
public double getMaxRenderDistanceSquared()
|
|
{
|
|
return 65536.0D;
|
|
}
|
|
|
|
@Nullable
|
|
private static Potion isBeaconEffect(int p_184279_0_)
|
|
{
|
|
Potion potion = Potion.getPotionById(p_184279_0_);
|
|
return VALID_EFFECTS.contains(potion) ? potion : null;
|
|
}
|
|
|
|
public void readFromNBT(NBTTagCompound compound)
|
|
{
|
|
super.readFromNBT(compound);
|
|
this.primaryEffect = isBeaconEffect(compound.getInteger("Primary"));
|
|
this.secondaryEffect = isBeaconEffect(compound.getInteger("Secondary"));
|
|
this.levels = compound.getInteger("Levels");
|
|
}
|
|
|
|
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
|
{
|
|
super.writeToNBT(compound);
|
|
compound.setInteger("Primary", Potion.getIdFromPotion(this.primaryEffect));
|
|
compound.setInteger("Secondary", Potion.getIdFromPotion(this.secondaryEffect));
|
|
compound.setInteger("Levels", this.levels);
|
|
return compound;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of slots in the inventory.
|
|
*/
|
|
public int getSizeInventory()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
public boolean isEmpty()
|
|
{
|
|
return this.payment.isEmpty();
|
|
}
|
|
|
|
/**
|
|
* Returns the stack in the given slot.
|
|
*/
|
|
public ItemStack getStackInSlot(int index)
|
|
{
|
|
return index == 0 ? this.payment : ItemStack.EMPTY;
|
|
}
|
|
|
|
/**
|
|
* Removes up to a specified number of items from an inventory slot and returns them in a new stack.
|
|
*/
|
|
public ItemStack decrStackSize(int index, int count)
|
|
{
|
|
if (index == 0 && !this.payment.isEmpty())
|
|
{
|
|
if (count >= this.payment.getCount())
|
|
{
|
|
ItemStack itemstack = this.payment;
|
|
this.payment = ItemStack.EMPTY;
|
|
return itemstack;
|
|
}
|
|
else
|
|
{
|
|
return this.payment.splitStack(count);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return ItemStack.EMPTY;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes a stack from the given slot and returns it.
|
|
*/
|
|
public ItemStack removeStackFromSlot(int index)
|
|
{
|
|
if (index == 0)
|
|
{
|
|
ItemStack itemstack = this.payment;
|
|
this.payment = ItemStack.EMPTY;
|
|
return itemstack;
|
|
}
|
|
else
|
|
{
|
|
return ItemStack.EMPTY;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
|
|
*/
|
|
public void setInventorySlotContents(int index, ItemStack stack)
|
|
{
|
|
if (index == 0)
|
|
{
|
|
this.payment = stack;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the name of this object. For players this returns their username
|
|
*/
|
|
public String getName()
|
|
{
|
|
return this.hasCustomName() ? this.customName : "container.beacon";
|
|
}
|
|
|
|
/**
|
|
* Returns true if this thing is named
|
|
*/
|
|
public boolean hasCustomName()
|
|
{
|
|
return this.customName != null && !this.customName.isEmpty();
|
|
}
|
|
|
|
public void setName(String name)
|
|
{
|
|
this.customName = name;
|
|
}
|
|
|
|
/**
|
|
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
|
|
*/
|
|
public int getInventoryStackLimit()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Don't rename this method to canInteractWith due to conflicts with Container
|
|
*/
|
|
public boolean isUsableByPlayer(EntityPlayer player)
|
|
{
|
|
if (this.world.getTileEntity(this.pos) != this)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
|
|
}
|
|
}
|
|
|
|
public void openInventory(EntityPlayer player)
|
|
{
|
|
}
|
|
|
|
public void closeInventory(EntityPlayer player)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot. For
|
|
* guis use Slot.isItemValid
|
|
*/
|
|
public boolean isItemValidForSlot(int index, ItemStack stack)
|
|
{
|
|
return stack.getItem() != null && stack.getItem().isBeaconPayment(stack);
|
|
}
|
|
|
|
public String getGuiID()
|
|
{
|
|
return "minecraft:beacon";
|
|
}
|
|
|
|
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
|
{
|
|
return new ContainerBeacon(playerInventory, this);
|
|
}
|
|
|
|
public int getField(int id)
|
|
{
|
|
switch (id)
|
|
{
|
|
case 0:
|
|
return this.levels;
|
|
case 1:
|
|
return Potion.getIdFromPotion(this.primaryEffect);
|
|
case 2:
|
|
return Potion.getIdFromPotion(this.secondaryEffect);
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public void setField(int id, int value)
|
|
{
|
|
switch (id)
|
|
{
|
|
case 0:
|
|
this.levels = value;
|
|
break;
|
|
case 1:
|
|
this.primaryEffect = isBeaconEffect(value);
|
|
break;
|
|
case 2:
|
|
this.secondaryEffect = isBeaconEffect(value);
|
|
}
|
|
}
|
|
|
|
public int getFieldCount()
|
|
{
|
|
return 3;
|
|
}
|
|
|
|
public void clear()
|
|
{
|
|
this.payment = ItemStack.EMPTY;
|
|
}
|
|
|
|
public boolean receiveClientEvent(int id, int type)
|
|
{
|
|
if (id == 1)
|
|
{
|
|
this.updateBeacon();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return super.receiveClientEvent(id, type);
|
|
}
|
|
}
|
|
|
|
public int[] getSlotsForFace(EnumFacing side)
|
|
{
|
|
return new int[0];
|
|
}
|
|
|
|
/**
|
|
* Returns true if automation can insert the given item in the given slot from the given side.
|
|
*/
|
|
public boolean canInsertItem(int index, ItemStack itemStackIn, EnumFacing direction)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns true if automation can extract the given item in the given slot from the given side.
|
|
*/
|
|
public boolean canExtractItem(int index, ItemStack stack, EnumFacing direction)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static
|
|
{
|
|
for (Potion[] apotion : EFFECTS_LIST)
|
|
{
|
|
Collections.addAll(VALID_EFFECTS, apotion);
|
|
}
|
|
}
|
|
|
|
public static class BeamSegment
|
|
{
|
|
/** RGB (0 to 1.0) colors of this beam segment */
|
|
private final float[] colors;
|
|
private int height;
|
|
|
|
public BeamSegment(float[] colorsIn)
|
|
{
|
|
this.colors = colorsIn;
|
|
this.height = 1;
|
|
}
|
|
|
|
protected void incrementHeight()
|
|
{
|
|
++this.height;
|
|
}
|
|
|
|
/**
|
|
* Returns RGB (0 to 1.0) colors of this beam segment
|
|
*/
|
|
public float[] getColors()
|
|
{
|
|
return this.colors;
|
|
}
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
public int getHeight()
|
|
{
|
|
return this.height;
|
|
}
|
|
}
|
|
} |