base mod created
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.BlockFlower;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public enum BannerPattern
|
||||
{
|
||||
BASE("base", "b"),
|
||||
SQUARE_BOTTOM_LEFT("square_bottom_left", "bl", " ", " ", "# "),
|
||||
SQUARE_BOTTOM_RIGHT("square_bottom_right", "br", " ", " ", " #"),
|
||||
SQUARE_TOP_LEFT("square_top_left", "tl", "# ", " ", " "),
|
||||
SQUARE_TOP_RIGHT("square_top_right", "tr", " #", " ", " "),
|
||||
STRIPE_BOTTOM("stripe_bottom", "bs", " ", " ", "###"),
|
||||
STRIPE_TOP("stripe_top", "ts", "###", " ", " "),
|
||||
STRIPE_LEFT("stripe_left", "ls", "# ", "# ", "# "),
|
||||
STRIPE_RIGHT("stripe_right", "rs", " #", " #", " #"),
|
||||
STRIPE_CENTER("stripe_center", "cs", " # ", " # ", " # "),
|
||||
STRIPE_MIDDLE("stripe_middle", "ms", " ", "###", " "),
|
||||
STRIPE_DOWNRIGHT("stripe_downright", "drs", "# ", " # ", " #"),
|
||||
STRIPE_DOWNLEFT("stripe_downleft", "dls", " #", " # ", "# "),
|
||||
STRIPE_SMALL("small_stripes", "ss", "# #", "# #", " "),
|
||||
CROSS("cross", "cr", "# #", " # ", "# #"),
|
||||
STRAIGHT_CROSS("straight_cross", "sc", " # ", "###", " # "),
|
||||
TRIANGLE_BOTTOM("triangle_bottom", "bt", " ", " # ", "# #"),
|
||||
TRIANGLE_TOP("triangle_top", "tt", "# #", " # ", " "),
|
||||
TRIANGLES_BOTTOM("triangles_bottom", "bts", " ", "# #", " # "),
|
||||
TRIANGLES_TOP("triangles_top", "tts", " # ", "# #", " "),
|
||||
DIAGONAL_LEFT("diagonal_left", "ld", "## ", "# ", " "),
|
||||
DIAGONAL_RIGHT("diagonal_up_right", "rd", " ", " #", " ##"),
|
||||
DIAGONAL_LEFT_MIRROR("diagonal_up_left", "lud", " ", "# ", "## "),
|
||||
DIAGONAL_RIGHT_MIRROR("diagonal_right", "rud", " ##", " #", " "),
|
||||
CIRCLE_MIDDLE("circle", "mc", " ", " # ", " "),
|
||||
RHOMBUS_MIDDLE("rhombus", "mr", " # ", "# #", " # "),
|
||||
HALF_VERTICAL("half_vertical", "vh", "## ", "## ", "## "),
|
||||
HALF_HORIZONTAL("half_horizontal", "hh", "###", "###", " "),
|
||||
HALF_VERTICAL_MIRROR("half_vertical_right", "vhr", " ##", " ##", " ##"),
|
||||
HALF_HORIZONTAL_MIRROR("half_horizontal_bottom", "hhb", " ", "###", "###"),
|
||||
BORDER("border", "bo", "###", "# #", "###"),
|
||||
CURLY_BORDER("curly_border", "cbo", new ItemStack(Blocks.VINE)),
|
||||
CREEPER("creeper", "cre", new ItemStack(Items.SKULL, 1, 4)),
|
||||
GRADIENT("gradient", "gra", "# #", " # ", " # "),
|
||||
GRADIENT_UP("gradient_up", "gru", " # ", " # ", "# #"),
|
||||
BRICKS("bricks", "bri", new ItemStack(Blocks.BRICK_BLOCK)),
|
||||
SKULL("skull", "sku", new ItemStack(Items.SKULL, 1, 1)),
|
||||
FLOWER("flower", "flo", new ItemStack(Blocks.RED_FLOWER, 1, BlockFlower.EnumFlowerType.OXEYE_DAISY.getMeta())),
|
||||
MOJANG("mojang", "moj", new ItemStack(Items.GOLDEN_APPLE, 1, 1));
|
||||
|
||||
private final String fileName;
|
||||
private final String hashname;
|
||||
private final String[] patterns;
|
||||
private ItemStack patternItem;
|
||||
|
||||
private BannerPattern(String p_i47245_3_, String p_i47245_4_)
|
||||
{
|
||||
this.patterns = new String[3];
|
||||
this.patternItem = ItemStack.EMPTY;
|
||||
this.fileName = p_i47245_3_;
|
||||
this.hashname = p_i47245_4_;
|
||||
}
|
||||
|
||||
private BannerPattern(String p_i47246_3_, String p_i47246_4_, ItemStack p_i47246_5_)
|
||||
{
|
||||
this(p_i47246_3_, p_i47246_4_);
|
||||
this.patternItem = p_i47246_5_;
|
||||
}
|
||||
|
||||
private BannerPattern(String p_i47247_3_, String p_i47247_4_, String p_i47247_5_, String p_i47247_6_, String p_i47247_7_)
|
||||
{
|
||||
this(p_i47247_3_, p_i47247_4_);
|
||||
this.patterns[0] = p_i47247_5_;
|
||||
this.patterns[1] = p_i47247_6_;
|
||||
this.patterns[2] = p_i47247_7_;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public String getFileName()
|
||||
{
|
||||
return this.fileName;
|
||||
}
|
||||
|
||||
public String getHashname()
|
||||
{
|
||||
return this.hashname;
|
||||
}
|
||||
|
||||
public String[] getPatterns()
|
||||
{
|
||||
return this.patterns;
|
||||
}
|
||||
|
||||
public boolean hasPattern()
|
||||
{
|
||||
return !this.patternItem.isEmpty() || this.patterns[0] != null;
|
||||
}
|
||||
|
||||
public boolean hasPatternItem()
|
||||
{
|
||||
return !this.patternItem.isEmpty();
|
||||
}
|
||||
|
||||
public ItemStack getPatternItem()
|
||||
{
|
||||
return this.patternItem;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static BannerPattern byHash(String hash)
|
||||
{
|
||||
for (BannerPattern bannerpattern : values())
|
||||
{
|
||||
if (bannerpattern.hashname.equals(hash))
|
||||
{
|
||||
return bannerpattern;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.command.CommandResultStats;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
import net.minecraft.crash.ICrashReportDetail;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.ReportedException;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public abstract class CommandBlockBaseLogic implements ICommandSender
|
||||
{
|
||||
/** The formatting for the timestamp on commands run. */
|
||||
private static final SimpleDateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("HH:mm:ss");
|
||||
private long lastExecution = -1L;
|
||||
private boolean updateLastExecution = true;
|
||||
/** The number of successful commands run. (used for redstone output) */
|
||||
private int successCount;
|
||||
private boolean trackOutput = true;
|
||||
/** The previously run command. */
|
||||
private ITextComponent lastOutput;
|
||||
/** The command stored in the command block. */
|
||||
private String commandStored = "";
|
||||
/** The custom name of the command block. (defaults to "@") */
|
||||
private String customName = "@";
|
||||
private final CommandResultStats resultStats = new CommandResultStats();
|
||||
|
||||
/**
|
||||
* returns the successCount int.
|
||||
*/
|
||||
public int getSuccessCount()
|
||||
{
|
||||
return this.successCount;
|
||||
}
|
||||
|
||||
public void setSuccessCount(int successCountIn)
|
||||
{
|
||||
this.successCount = successCountIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lastOutput.
|
||||
*/
|
||||
public ITextComponent getLastOutput()
|
||||
{
|
||||
return (ITextComponent)(this.lastOutput == null ? new TextComponentString("") : this.lastOutput);
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound p_189510_1_)
|
||||
{
|
||||
p_189510_1_.setString("Command", this.commandStored);
|
||||
p_189510_1_.setInteger("SuccessCount", this.successCount);
|
||||
p_189510_1_.setString("CustomName", this.customName);
|
||||
p_189510_1_.setBoolean("TrackOutput", this.trackOutput);
|
||||
|
||||
if (this.lastOutput != null && this.trackOutput)
|
||||
{
|
||||
p_189510_1_.setString("LastOutput", ITextComponent.Serializer.componentToJson(this.lastOutput));
|
||||
}
|
||||
|
||||
p_189510_1_.setBoolean("UpdateLastExecution", this.updateLastExecution);
|
||||
|
||||
if (this.updateLastExecution && this.lastExecution > 0L)
|
||||
{
|
||||
p_189510_1_.setLong("LastExecution", this.lastExecution);
|
||||
}
|
||||
|
||||
this.resultStats.writeStatsToNBT(p_189510_1_);
|
||||
return p_189510_1_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads NBT formatting and stored data into variables.
|
||||
*/
|
||||
public void readDataFromNBT(NBTTagCompound nbt)
|
||||
{
|
||||
this.commandStored = nbt.getString("Command");
|
||||
this.successCount = nbt.getInteger("SuccessCount");
|
||||
|
||||
if (nbt.hasKey("CustomName", 8))
|
||||
{
|
||||
this.customName = nbt.getString("CustomName");
|
||||
}
|
||||
|
||||
if (nbt.hasKey("TrackOutput", 1))
|
||||
{
|
||||
this.trackOutput = nbt.getBoolean("TrackOutput");
|
||||
}
|
||||
|
||||
if (nbt.hasKey("LastOutput", 8) && this.trackOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lastOutput = ITextComponent.Serializer.jsonToComponent(nbt.getString("LastOutput"));
|
||||
}
|
||||
catch (Throwable throwable)
|
||||
{
|
||||
this.lastOutput = new TextComponentString(throwable.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.lastOutput = null;
|
||||
}
|
||||
|
||||
if (nbt.hasKey("UpdateLastExecution"))
|
||||
{
|
||||
this.updateLastExecution = nbt.getBoolean("UpdateLastExecution");
|
||||
}
|
||||
|
||||
if (this.updateLastExecution && nbt.hasKey("LastExecution"))
|
||||
{
|
||||
this.lastExecution = nbt.getLong("LastExecution");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.lastExecution = -1L;
|
||||
}
|
||||
|
||||
this.resultStats.readStatsFromNBT(nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the CommandSender is allowed to execute the command, {@code false} if not
|
||||
*/
|
||||
public boolean canUseCommand(int permLevel, String commandName)
|
||||
{
|
||||
return permLevel <= 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command.
|
||||
*/
|
||||
public void setCommand(String command)
|
||||
{
|
||||
this.commandStored = command;
|
||||
this.successCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command of the command block.
|
||||
*/
|
||||
public String getCommand()
|
||||
{
|
||||
return this.commandStored;
|
||||
}
|
||||
|
||||
public boolean trigger(World worldIn)
|
||||
{
|
||||
if (!worldIn.isRemote && worldIn.getTotalWorldTime() != this.lastExecution)
|
||||
{
|
||||
if ("Searge".equalsIgnoreCase(this.commandStored))
|
||||
{
|
||||
this.lastOutput = new TextComponentString("#itzlipofutzli");
|
||||
this.successCount = 1;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MinecraftServer minecraftserver = this.getServer();
|
||||
|
||||
if (minecraftserver != null && minecraftserver.isAnvilFileSet() && minecraftserver.isCommandBlockEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
this.lastOutput = null;
|
||||
this.successCount = minecraftserver.getCommandManager().executeCommand(this, this.commandStored);
|
||||
}
|
||||
catch (Throwable throwable)
|
||||
{
|
||||
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Executing command block");
|
||||
CrashReportCategory crashreportcategory = crashreport.makeCategory("Command to be executed");
|
||||
crashreportcategory.addDetail("Command", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
return CommandBlockBaseLogic.this.getCommand();
|
||||
}
|
||||
});
|
||||
crashreportcategory.addDetail("Name", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
return CommandBlockBaseLogic.this.getName();
|
||||
}
|
||||
});
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.successCount = 0;
|
||||
}
|
||||
|
||||
if (this.updateLastExecution)
|
||||
{
|
||||
this.lastExecution = worldIn.getTotalWorldTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.lastExecution = -1L;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.customName;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.customName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a chat message to the CommandSender
|
||||
*/
|
||||
public void sendMessage(ITextComponent component)
|
||||
{
|
||||
if (this.trackOutput && this.getEntityWorld() != null && !this.getEntityWorld().isRemote)
|
||||
{
|
||||
this.lastOutput = (new TextComponentString("[" + TIMESTAMP_FORMAT.format(new Date()) + "] ")).appendSibling(component);
|
||||
this.updateCommand();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the command sender should be sent feedback about executed commands
|
||||
*/
|
||||
public boolean sendCommandFeedback()
|
||||
{
|
||||
MinecraftServer minecraftserver = this.getServer();
|
||||
return minecraftserver == null || !minecraftserver.isAnvilFileSet() || minecraftserver.worlds[0].getGameRules().getBoolean("commandBlockOutput");
|
||||
}
|
||||
|
||||
public void setCommandStat(CommandResultStats.Type type, int amount)
|
||||
{
|
||||
this.resultStats.setCommandStatForSender(this.getServer(), this, type, amount);
|
||||
}
|
||||
|
||||
public abstract void updateCommand();
|
||||
|
||||
/**
|
||||
* Currently this returns 0 for the traditional command block, and 1 for the minecart command block
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract int getCommandBlockType();
|
||||
|
||||
/**
|
||||
* Fills in information about the command block for the packet. entityId for the minecart version, and X/Y/Z for the
|
||||
* traditional version
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract void fillInInfo(ByteBuf buf);
|
||||
|
||||
public void setLastOutput(@Nullable ITextComponent lastOutputMessage)
|
||||
{
|
||||
this.lastOutput = lastOutputMessage;
|
||||
}
|
||||
|
||||
public void setTrackOutput(boolean shouldTrackOutput)
|
||||
{
|
||||
this.trackOutput = shouldTrackOutput;
|
||||
}
|
||||
|
||||
public boolean shouldTrackOutput()
|
||||
{
|
||||
return this.trackOutput;
|
||||
}
|
||||
|
||||
public boolean tryOpenEditCommandBlock(EntityPlayer playerIn)
|
||||
{
|
||||
if (!playerIn.canUseCommandBlock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (playerIn.getEntityWorld().isRemote)
|
||||
{
|
||||
playerIn.displayGuiEditCommandCart(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public CommandResultStats getCommandResultStats()
|
||||
{
|
||||
return this.resultStats;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IHopper extends IInventory
|
||||
{
|
||||
/**
|
||||
* Returns the worldObj for this tileEntity.
|
||||
*/
|
||||
World getWorld();
|
||||
|
||||
/**
|
||||
* Gets the world X position for this hopper entity.
|
||||
*/
|
||||
double getXPos();
|
||||
|
||||
/**
|
||||
* Gets the world Y position for this hopper entity.
|
||||
*/
|
||||
double getYPos();
|
||||
|
||||
/**
|
||||
* Gets the world Z position for this hopper entity.
|
||||
*/
|
||||
double getZPos();
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.IEntityLivingData;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.StringUtils;
|
||||
import net.minecraft.util.WeightedRandom;
|
||||
import net.minecraft.util.WeightedSpawnerEntity;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public abstract class MobSpawnerBaseLogic
|
||||
{
|
||||
/** The delay to spawn. */
|
||||
private int spawnDelay = 20;
|
||||
/** List of potential entities to spawn */
|
||||
private final List<WeightedSpawnerEntity> potentialSpawns = Lists.<WeightedSpawnerEntity>newArrayList();
|
||||
private WeightedSpawnerEntity spawnData = new WeightedSpawnerEntity();
|
||||
/** The rotation of the mob inside the mob spawner */
|
||||
private double mobRotation;
|
||||
/** the previous rotation of the mob inside the mob spawner */
|
||||
private double prevMobRotation;
|
||||
private int minSpawnDelay = 200;
|
||||
private int maxSpawnDelay = 800;
|
||||
private int spawnCount = 4;
|
||||
/** Cached instance of the entity to render inside the spawner. */
|
||||
private Entity cachedEntity;
|
||||
private int maxNearbyEntities = 6;
|
||||
/** The distance from which a player activates the spawner. */
|
||||
private int activatingRangeFromPlayer = 16;
|
||||
/** The range coefficient for spawning entities around. */
|
||||
private int spawnRange = 4;
|
||||
|
||||
@Nullable
|
||||
private ResourceLocation getEntityId()
|
||||
{
|
||||
String s = this.spawnData.getNbt().getString("id");
|
||||
return StringUtils.isNullOrEmpty(s) ? null : new ResourceLocation(s);
|
||||
}
|
||||
|
||||
public void setEntityId(@Nullable ResourceLocation id)
|
||||
{
|
||||
if (id != null)
|
||||
{
|
||||
this.spawnData.getNbt().setString("id", id.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there's a player close enough to this mob spawner to activate it.
|
||||
*/
|
||||
private boolean isActivated()
|
||||
{
|
||||
BlockPos blockpos = this.getSpawnerPosition();
|
||||
return this.getSpawnerWorld().isAnyPlayerWithinRangeAt((double)blockpos.getX() + 0.5D, (double)blockpos.getY() + 0.5D, (double)blockpos.getZ() + 0.5D, (double)this.activatingRangeFromPlayer);
|
||||
}
|
||||
|
||||
public void updateSpawner()
|
||||
{
|
||||
if (!this.isActivated())
|
||||
{
|
||||
this.prevMobRotation = this.mobRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos blockpos = this.getSpawnerPosition();
|
||||
|
||||
if (this.getSpawnerWorld().isRemote)
|
||||
{
|
||||
double d3 = (double)((float)blockpos.getX() + this.getSpawnerWorld().rand.nextFloat());
|
||||
double d4 = (double)((float)blockpos.getY() + this.getSpawnerWorld().rand.nextFloat());
|
||||
double d5 = (double)((float)blockpos.getZ() + this.getSpawnerWorld().rand.nextFloat());
|
||||
this.getSpawnerWorld().spawnParticle(EnumParticleTypes.SMOKE_NORMAL, d3, d4, d5, 0.0D, 0.0D, 0.0D);
|
||||
this.getSpawnerWorld().spawnParticle(EnumParticleTypes.FLAME, d3, d4, d5, 0.0D, 0.0D, 0.0D);
|
||||
|
||||
if (this.spawnDelay > 0)
|
||||
{
|
||||
--this.spawnDelay;
|
||||
}
|
||||
|
||||
this.prevMobRotation = this.mobRotation;
|
||||
this.mobRotation = (this.mobRotation + (double)(1000.0F / ((float)this.spawnDelay + 200.0F))) % 360.0D;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.spawnDelay == -1)
|
||||
{
|
||||
this.resetTimer();
|
||||
}
|
||||
|
||||
if (this.spawnDelay > 0)
|
||||
{
|
||||
--this.spawnDelay;
|
||||
return;
|
||||
}
|
||||
|
||||
boolean flag = false;
|
||||
|
||||
for (int i = 0; i < this.spawnCount; ++i)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = this.spawnData.getNbt();
|
||||
NBTTagList nbttaglist = nbttagcompound.getTagList("Pos", 6);
|
||||
World world = this.getSpawnerWorld();
|
||||
int j = nbttaglist.tagCount();
|
||||
double d0 = j >= 1 ? nbttaglist.getDoubleAt(0) : (double)blockpos.getX() + (world.rand.nextDouble() - world.rand.nextDouble()) * (double)this.spawnRange + 0.5D;
|
||||
double d1 = j >= 2 ? nbttaglist.getDoubleAt(1) : (double)(blockpos.getY() + world.rand.nextInt(3) - 1);
|
||||
double d2 = j >= 3 ? nbttaglist.getDoubleAt(2) : (double)blockpos.getZ() + (world.rand.nextDouble() - world.rand.nextDouble()) * (double)this.spawnRange + 0.5D;
|
||||
Entity entity = AnvilChunkLoader.readWorldEntityPos(nbttagcompound, world, d0, d1, d2, false);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int k = world.getEntitiesWithinAABB(entity.getClass(), (new AxisAlignedBB((double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ(), (double)(blockpos.getX() + 1), (double)(blockpos.getY() + 1), (double)(blockpos.getZ() + 1))).grow((double)this.spawnRange)).size();
|
||||
|
||||
if (k >= this.maxNearbyEntities)
|
||||
{
|
||||
this.resetTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
EntityLiving entityliving = entity instanceof EntityLiving ? (EntityLiving)entity : null;
|
||||
entity.setLocationAndAngles(entity.posX, entity.posY, entity.posZ, world.rand.nextFloat() * 360.0F, 0.0F);
|
||||
|
||||
if (entityliving == null || net.minecraftforge.event.ForgeEventFactory.canEntitySpawnSpawner(entityliving, getSpawnerWorld(), (float)entity.posX, (float)entity.posY, (float)entity.posZ, this))
|
||||
{
|
||||
if (this.spawnData.getNbt().getSize() == 1 && this.spawnData.getNbt().hasKey("id", 8) && entity instanceof EntityLiving)
|
||||
{
|
||||
if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(entityliving, this.getSpawnerWorld(), (float)entity.posX, (float)entity.posY, (float)entity.posZ, this))
|
||||
((EntityLiving)entity).onInitialSpawn(world.getDifficultyForLocation(new BlockPos(entity)), (IEntityLivingData)null);
|
||||
}
|
||||
|
||||
AnvilChunkLoader.spawnEntity(entity, world);
|
||||
world.playEvent(2004, blockpos, 0);
|
||||
|
||||
if (entityliving != null)
|
||||
{
|
||||
entityliving.spawnExplosionParticle();
|
||||
}
|
||||
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
this.resetTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetTimer()
|
||||
{
|
||||
if (this.maxSpawnDelay <= this.minSpawnDelay)
|
||||
{
|
||||
this.spawnDelay = this.minSpawnDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = this.maxSpawnDelay - this.minSpawnDelay;
|
||||
this.spawnDelay = this.minSpawnDelay + this.getSpawnerWorld().rand.nextInt(i);
|
||||
}
|
||||
|
||||
if (!this.potentialSpawns.isEmpty())
|
||||
{
|
||||
this.setNextSpawnData((WeightedSpawnerEntity)WeightedRandom.getRandomItem(this.getSpawnerWorld().rand, this.potentialSpawns));
|
||||
}
|
||||
|
||||
this.broadcastEvent(1);
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound nbt)
|
||||
{
|
||||
this.spawnDelay = nbt.getShort("Delay");
|
||||
this.potentialSpawns.clear();
|
||||
|
||||
if (nbt.hasKey("SpawnPotentials", 9))
|
||||
{
|
||||
NBTTagList nbttaglist = nbt.getTagList("SpawnPotentials", 10);
|
||||
|
||||
for (int i = 0; i < nbttaglist.tagCount(); ++i)
|
||||
{
|
||||
this.potentialSpawns.add(new WeightedSpawnerEntity(nbttaglist.getCompoundTagAt(i)));
|
||||
}
|
||||
}
|
||||
|
||||
if (nbt.hasKey("SpawnData", 10))
|
||||
{
|
||||
this.setNextSpawnData(new WeightedSpawnerEntity(1, nbt.getCompoundTag("SpawnData")));
|
||||
}
|
||||
else if (!this.potentialSpawns.isEmpty())
|
||||
{
|
||||
this.setNextSpawnData((WeightedSpawnerEntity)WeightedRandom.getRandomItem(this.getSpawnerWorld().rand, this.potentialSpawns));
|
||||
}
|
||||
|
||||
if (nbt.hasKey("MinSpawnDelay", 99))
|
||||
{
|
||||
this.minSpawnDelay = nbt.getShort("MinSpawnDelay");
|
||||
this.maxSpawnDelay = nbt.getShort("MaxSpawnDelay");
|
||||
this.spawnCount = nbt.getShort("SpawnCount");
|
||||
}
|
||||
|
||||
if (nbt.hasKey("MaxNearbyEntities", 99))
|
||||
{
|
||||
this.maxNearbyEntities = nbt.getShort("MaxNearbyEntities");
|
||||
this.activatingRangeFromPlayer = nbt.getShort("RequiredPlayerRange");
|
||||
}
|
||||
|
||||
if (nbt.hasKey("SpawnRange", 99))
|
||||
{
|
||||
this.spawnRange = nbt.getShort("SpawnRange");
|
||||
}
|
||||
|
||||
if (this.getSpawnerWorld() != null)
|
||||
{
|
||||
this.cachedEntity = null;
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound p_189530_1_)
|
||||
{
|
||||
ResourceLocation resourcelocation = this.getEntityId();
|
||||
|
||||
if (resourcelocation == null)
|
||||
{
|
||||
return p_189530_1_;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_189530_1_.setShort("Delay", (short)this.spawnDelay);
|
||||
p_189530_1_.setShort("MinSpawnDelay", (short)this.minSpawnDelay);
|
||||
p_189530_1_.setShort("MaxSpawnDelay", (short)this.maxSpawnDelay);
|
||||
p_189530_1_.setShort("SpawnCount", (short)this.spawnCount);
|
||||
p_189530_1_.setShort("MaxNearbyEntities", (short)this.maxNearbyEntities);
|
||||
p_189530_1_.setShort("RequiredPlayerRange", (short)this.activatingRangeFromPlayer);
|
||||
p_189530_1_.setShort("SpawnRange", (short)this.spawnRange);
|
||||
p_189530_1_.setTag("SpawnData", this.spawnData.getNbt().copy());
|
||||
NBTTagList nbttaglist = new NBTTagList();
|
||||
|
||||
if (this.potentialSpawns.isEmpty())
|
||||
{
|
||||
nbttaglist.appendTag(this.spawnData.toCompoundTag());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (WeightedSpawnerEntity weightedspawnerentity : this.potentialSpawns)
|
||||
{
|
||||
nbttaglist.appendTag(weightedspawnerentity.toCompoundTag());
|
||||
}
|
||||
}
|
||||
|
||||
p_189530_1_.setTag("SpawnPotentials", nbttaglist);
|
||||
return p_189530_1_;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delay to minDelay if parameter given is 1, else return false.
|
||||
*/
|
||||
public boolean setDelayToMin(int delay)
|
||||
{
|
||||
if (delay == 1 && this.getSpawnerWorld().isRemote)
|
||||
{
|
||||
this.spawnDelay = this.minSpawnDelay;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public Entity getCachedEntity()
|
||||
{
|
||||
if (this.cachedEntity == null)
|
||||
{
|
||||
this.cachedEntity = AnvilChunkLoader.readWorldEntity(this.spawnData.getNbt(), this.getSpawnerWorld(), false);
|
||||
|
||||
if (this.spawnData.getNbt().getSize() == 1 && this.spawnData.getNbt().hasKey("id", 8) && this.cachedEntity instanceof EntityLiving)
|
||||
{
|
||||
((EntityLiving)this.cachedEntity).onInitialSpawn(this.getSpawnerWorld().getDifficultyForLocation(new BlockPos(this.cachedEntity)), (IEntityLivingData)null);
|
||||
}
|
||||
}
|
||||
|
||||
return this.cachedEntity;
|
||||
}
|
||||
|
||||
public void setNextSpawnData(WeightedSpawnerEntity p_184993_1_)
|
||||
{
|
||||
this.spawnData = p_184993_1_;
|
||||
}
|
||||
|
||||
public abstract void broadcastEvent(int id);
|
||||
|
||||
public abstract World getSpawnerWorld();
|
||||
|
||||
public abstract BlockPos getSpawnerPosition();
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public double getMobRotation()
|
||||
{
|
||||
return this.mobRotation;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public double getPrevMobRotation()
|
||||
{
|
||||
return this.prevMobRotation;
|
||||
}
|
||||
|
||||
/* ======================================== FORGE START =====================================*/
|
||||
@Nullable public Entity getSpawnerEntity() { return null; }
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockJukebox;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
import net.minecraft.crash.ICrashReportDetail;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.util.Mirror;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.Rotation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.RegistryNamespaced;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public abstract class TileEntity implements net.minecraftforge.common.capabilities.ICapabilitySerializable<NBTTagCompound>
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final RegistryNamespaced < ResourceLocation, Class <? extends TileEntity >> REGISTRY = new RegistryNamespaced < ResourceLocation, Class <? extends TileEntity >> ();
|
||||
/** the instance of the world the tile entity is in. */
|
||||
protected World world;
|
||||
protected BlockPos pos = BlockPos.ORIGIN;
|
||||
protected boolean tileEntityInvalid;
|
||||
private int blockMetadata = -1;
|
||||
/** the Block type that this TileEntity is contained within */
|
||||
protected Block blockType;
|
||||
|
||||
public static void register(String id, Class <? extends TileEntity > clazz)
|
||||
{
|
||||
REGISTRY.putObject(new ResourceLocation(id), clazz);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ResourceLocation getKey(Class <? extends TileEntity > clazz)
|
||||
{
|
||||
return REGISTRY.getNameForObject(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the worldObj for this tileEntity.
|
||||
*/
|
||||
public World getWorld()
|
||||
{
|
||||
return this.world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the worldObj for this tileEntity.
|
||||
*/
|
||||
public void setWorld(World worldIn)
|
||||
{
|
||||
this.world = worldIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the worldObj isn't null.
|
||||
*/
|
||||
public boolean hasWorld()
|
||||
{
|
||||
return this.world != null;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
this.pos = new BlockPos(compound.getInteger("x"), compound.getInteger("y"), compound.getInteger("z"));
|
||||
if (compound.hasKey("ForgeData")) this.customTileData = compound.getCompoundTag("ForgeData");
|
||||
if (this.capabilities != null && compound.hasKey("ForgeCaps")) this.capabilities.deserializeNBT(compound.getCompoundTag("ForgeCaps"));
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
return this.writeInternal(compound);
|
||||
}
|
||||
|
||||
private NBTTagCompound writeInternal(NBTTagCompound compound)
|
||||
{
|
||||
ResourceLocation resourcelocation = REGISTRY.getNameForObject(this.getClass());
|
||||
|
||||
if (resourcelocation == null)
|
||||
{
|
||||
throw new RuntimeException(this.getClass() + " is missing a mapping! This is a bug!");
|
||||
}
|
||||
else
|
||||
{
|
||||
compound.setString("id", resourcelocation.toString());
|
||||
compound.setInteger("x", this.pos.getX());
|
||||
compound.setInteger("y", this.pos.getY());
|
||||
compound.setInteger("z", this.pos.getZ());
|
||||
if (this.customTileData != null) compound.setTag("ForgeData", this.customTileData);
|
||||
if (this.capabilities != null) compound.setTag("ForgeCaps", this.capabilities.serializeNBT());
|
||||
return compound;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TileEntity create(World worldIn, NBTTagCompound compound)
|
||||
{
|
||||
TileEntity tileentity = null;
|
||||
String s = compound.getString("id");
|
||||
Class <? extends TileEntity > oclass = null;
|
||||
|
||||
try
|
||||
{
|
||||
oclass = (Class)REGISTRY.getObject(new ResourceLocation(s));
|
||||
|
||||
if (oclass != null)
|
||||
{
|
||||
tileentity = oclass.newInstance();
|
||||
}
|
||||
}
|
||||
catch (Throwable throwable1)
|
||||
{
|
||||
LOGGER.error("Failed to create block entity {}", s, throwable1);
|
||||
net.minecraftforge.fml.common.FMLLog.log.error("A TileEntity {}({}) has thrown an exception during loading, its state cannot be restored. Report this to the mod author",
|
||||
s, oclass == null ? null : oclass.getName(), throwable1);
|
||||
}
|
||||
|
||||
if (tileentity != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
tileentity.setWorldCreate(worldIn);
|
||||
tileentity.readFromNBT(compound);
|
||||
}
|
||||
catch (Throwable throwable)
|
||||
{
|
||||
LOGGER.error("Failed to load data for block entity {}", s, throwable);
|
||||
net.minecraftforge.fml.common.FMLLog.log.error("A TileEntity {}({}) has thrown an exception during loading, its state cannot be restored. Report this to the mod author",
|
||||
s, oclass.getName(), throwable);
|
||||
tileentity = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Skipping BlockEntity with id {}", (Object)s);
|
||||
}
|
||||
|
||||
return tileentity;
|
||||
}
|
||||
|
||||
protected void setWorldCreate(World worldIn)
|
||||
{
|
||||
}
|
||||
|
||||
public int getBlockMetadata()
|
||||
{
|
||||
if (this.blockMetadata == -1)
|
||||
{
|
||||
IBlockState iblockstate = this.world.getBlockState(this.pos);
|
||||
this.blockMetadata = iblockstate.getBlock().getMetaFromState(iblockstate);
|
||||
}
|
||||
|
||||
return this.blockMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* For tile entities, ensures the chunk containing the tile entity is saved to disk later - the game won't think it
|
||||
* hasn't changed and skip it.
|
||||
*/
|
||||
public void markDirty()
|
||||
{
|
||||
if (this.world != null)
|
||||
{
|
||||
IBlockState iblockstate = this.world.getBlockState(this.pos);
|
||||
this.blockMetadata = iblockstate.getBlock().getMetaFromState(iblockstate);
|
||||
this.world.markChunkDirty(this.pos, this);
|
||||
|
||||
if (this.getBlockType() != Blocks.AIR)
|
||||
{
|
||||
this.world.updateComparatorOutputLevel(this.pos, this.getBlockType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the square of the distance between this entity and the passed in coordinates.
|
||||
*/
|
||||
public double getDistanceSq(double x, double y, double z)
|
||||
{
|
||||
double d0 = (double)this.pos.getX() + 0.5D - x;
|
||||
double d1 = (double)this.pos.getY() + 0.5D - y;
|
||||
double d2 = (double)this.pos.getZ() + 0.5D - z;
|
||||
return d0 * d0 + d1 * d1 + d2 * d2;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public double getMaxRenderDistanceSquared()
|
||||
{
|
||||
return 4096.0D;
|
||||
}
|
||||
|
||||
public BlockPos getPos()
|
||||
{
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block type at the location of this entity (client-only).
|
||||
*/
|
||||
public Block getBlockType()
|
||||
{
|
||||
if (this.blockType == null && this.world != null)
|
||||
{
|
||||
this.blockType = this.world.getBlockState(this.pos).getBlock();
|
||||
}
|
||||
|
||||
return this.blockType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeInternal(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public boolean isInvalid()
|
||||
{
|
||||
return this.tileEntityInvalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* invalidates a tile entity
|
||||
*/
|
||||
public void invalidate()
|
||||
{
|
||||
this.tileEntityInvalid = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* validates a tile entity
|
||||
*/
|
||||
public void validate()
|
||||
{
|
||||
this.tileEntityInvalid = false;
|
||||
}
|
||||
|
||||
public boolean receiveClientEvent(int id, int type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateContainingBlockInfo()
|
||||
{
|
||||
this.blockType = null;
|
||||
this.blockMetadata = -1;
|
||||
}
|
||||
|
||||
public void addInfoToCrashReport(CrashReportCategory reportCategory)
|
||||
{
|
||||
reportCategory.addDetail("Name", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
return TileEntity.REGISTRY.getNameForObject(TileEntity.this.getClass()) + " // " + TileEntity.this.getClass().getCanonicalName();
|
||||
}
|
||||
});
|
||||
|
||||
if (this.world != null)
|
||||
{
|
||||
CrashReportCategory.addBlockInfo(reportCategory, this.pos, this.getBlockType(), this.getBlockMetadata());
|
||||
reportCategory.addDetail("Actual block type", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
int i = Block.getIdFromBlock(TileEntity.this.world.getBlockState(TileEntity.this.pos).getBlock());
|
||||
|
||||
try
|
||||
{
|
||||
return String.format("ID #%d (%s // %s // %s)", i, Block.getBlockById(i).getUnlocalizedName(), Block.getBlockById(i).getClass().getName(), Block.getBlockById(i).getRegistryName());
|
||||
}
|
||||
catch (Throwable var3)
|
||||
{
|
||||
return "ID #" + i;
|
||||
}
|
||||
}
|
||||
});
|
||||
reportCategory.addDetail("Actual block data value", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
IBlockState iblockstate = TileEntity.this.world.getBlockState(TileEntity.this.pos);
|
||||
int i = iblockstate.getBlock().getMetaFromState(iblockstate);
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
return "Unknown? (Got " + i + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
String s = String.format("%4s", Integer.toBinaryString(i)).replace(" ", "0");
|
||||
return String.format("%1$d / 0x%1$X / 0b%2$s", i, s);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void setPos(BlockPos posIn)
|
||||
{
|
||||
this.pos = posIn.toImmutable();
|
||||
}
|
||||
|
||||
public boolean onlyOpsCanSetNbt()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted ChatComponent that will be used for the sender's username in chat
|
||||
*/
|
||||
@Nullable
|
||||
public ITextComponent getDisplayName()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void rotate(Rotation rotationIn)
|
||||
{
|
||||
}
|
||||
|
||||
public void mirror(Mirror mirrorIn)
|
||||
{
|
||||
}
|
||||
|
||||
// -- BEGIN FORGE PATCHES --
|
||||
/**
|
||||
* Called when you receive a TileEntityData packet for the location this
|
||||
* TileEntity is currently in. On the client, the NetworkManager will always
|
||||
* be the remote server. On the server, it will be whomever is responsible for
|
||||
* sending the packet.
|
||||
*
|
||||
* @param net The NetworkManager the packet originated from
|
||||
* @param pkt The data packet
|
||||
*/
|
||||
public void onDataPacket(net.minecraft.network.NetworkManager net, net.minecraft.network.play.server.SPacketUpdateTileEntity pkt)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the chunk's TE update tag, gotten from {@link #getUpdateTag()}, is received on the client.
|
||||
* <p>
|
||||
* Used to handle this tag in a special way. By default this simply calls {@link #readFromNBT(NBTTagCompound)}.
|
||||
*
|
||||
* @param tag The {@link NBTTagCompound} sent from {@link #getUpdateTag()}
|
||||
*/
|
||||
public void handleUpdateTag(NBTTagCompound tag)
|
||||
{
|
||||
this.readFromNBT(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the chunk this TileEntity is on is Unloaded.
|
||||
*/
|
||||
public void onChunkUnload()
|
||||
{
|
||||
}
|
||||
|
||||
private boolean isVanilla = getClass().getName().startsWith("net.minecraft.");
|
||||
/**
|
||||
* Called from Chunk.setBlockIDWithMetadata and Chunk.fillChunk, determines if this tile entity should be re-created when the ID, or Metadata changes.
|
||||
* Use with caution as this will leave straggler TileEntities, or create conflicts with other TileEntities if not used properly.
|
||||
*
|
||||
* @param world Current world
|
||||
* @param pos Tile's world position
|
||||
* @param oldState The old ID of the block
|
||||
* @param newState The new ID of the block (May be the same)
|
||||
* @return true forcing the invalidation of the existing TE, false not to invalidate the existing TE
|
||||
*/
|
||||
public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate)
|
||||
{
|
||||
return isVanilla ? (oldState.getBlock() != newSate.getBlock()) : oldState != newSate;
|
||||
}
|
||||
|
||||
public boolean shouldRenderInPass(int pass)
|
||||
{
|
||||
return pass == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes default render bounding box: infinite in scope. Used to control rendering on {@link TileEntitySpecialRenderer}.
|
||||
*/
|
||||
public static final net.minecraft.util.math.AxisAlignedBB INFINITE_EXTENT_AABB = new net.minecraft.util.math.AxisAlignedBB(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
|
||||
/**
|
||||
* Return an {@link AxisAlignedBB} that controls the visible scope of a {@link TileEntitySpecialRenderer} associated with this {@link TileEntity}
|
||||
* Defaults to the collision bounding box {@link Block#getCollisionBoundingBoxFromPool(World, int, int, int)} associated with the block
|
||||
* at this location.
|
||||
*
|
||||
* @return an appropriately size {@link AxisAlignedBB} for the {@link TileEntity}
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public net.minecraft.util.math.AxisAlignedBB getRenderBoundingBox()
|
||||
{
|
||||
net.minecraft.util.math.AxisAlignedBB bb = INFINITE_EXTENT_AABB;
|
||||
Block type = getBlockType();
|
||||
BlockPos pos = getPos();
|
||||
if (type == Blocks.ENCHANTING_TABLE)
|
||||
{
|
||||
bb = new net.minecraft.util.math.AxisAlignedBB(pos, pos.add(1, 1, 1));
|
||||
}
|
||||
else if (type == Blocks.CHEST || type == Blocks.TRAPPED_CHEST)
|
||||
{
|
||||
bb = new net.minecraft.util.math.AxisAlignedBB(pos.add(-1, 0, -1), pos.add(2, 2, 2));
|
||||
}
|
||||
else if (type == Blocks.STRUCTURE_BLOCK)
|
||||
{
|
||||
bb = INFINITE_EXTENT_AABB;
|
||||
}
|
||||
else if (type != null && type != Blocks.BEACON)
|
||||
{
|
||||
net.minecraft.util.math.AxisAlignedBB cbb = null;
|
||||
try
|
||||
{
|
||||
cbb = world.getBlockState(getPos()).getCollisionBoundingBox(world, pos).offset(pos);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// We have to capture any exceptions that may occur here because BUKKIT servers like to send
|
||||
// the tile entity data BEFORE the chunk data, you know, the OPPOSITE of what vanilla does!
|
||||
// So we can not GARENTEE that the world state is the real state for the block...
|
||||
// So, once again in the long line of US having to accommodate BUKKIT breaking things,
|
||||
// here it is, assume that the TE is only 1 cubic block. Problem with this is that it may
|
||||
// cause the TileEntity renderer to error further down the line! But alas, nothing we can do.
|
||||
cbb = new net.minecraft.util.math.AxisAlignedBB(getPos().add(-1, 0, -1), getPos().add(1, 1, 1));
|
||||
}
|
||||
if (cbb != null) bb = cbb;
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this tile entity knows how to render its 'breaking' overlay effect.
|
||||
* If this returns true, The TileEntitySpecialRenderer will be called again with break progress set.
|
||||
* @return True to re-render tile with breaking effect.
|
||||
*/
|
||||
public boolean canRenderBreaking()
|
||||
{
|
||||
Block block = this.getBlockType();
|
||||
return (block instanceof net.minecraft.block.BlockChest ||
|
||||
block instanceof net.minecraft.block.BlockEnderChest ||
|
||||
block instanceof net.minecraft.block.BlockSign ||
|
||||
block instanceof net.minecraft.block.BlockSkull);
|
||||
}
|
||||
|
||||
private NBTTagCompound customTileData;
|
||||
|
||||
/**
|
||||
* Gets a {@link NBTTagCompound} that can be used to store custom data for this tile entity.
|
||||
* It will be written, and read from disc, so it persists over world saves.
|
||||
*
|
||||
* @return A compound tag for custom data
|
||||
*/
|
||||
public NBTTagCompound getTileData()
|
||||
{
|
||||
if (this.customTileData == null)
|
||||
{
|
||||
this.customTileData = new NBTTagCompound();
|
||||
}
|
||||
return this.customTileData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the player can overwrite the NBT data of this tile entity while they place it using a ItemStack.
|
||||
* Added as a fix for MC-75630 - Exploit with signs and command blocks
|
||||
* @return True to prevent NBT copy, false to allow.
|
||||
*/
|
||||
public boolean restrictNBTCopy()
|
||||
{
|
||||
return this instanceof TileEntityCommandBlock ||
|
||||
this instanceof TileEntityMobSpawner ||
|
||||
this instanceof TileEntitySign;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when this is first added to the world (by {@link World#addTileEntity(TileEntity)}).
|
||||
* Override instead of adding {@code if (firstTick)} stuff in update.
|
||||
*/
|
||||
public void onLoad()
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* If the TileEntitySpecialRenderer associated with this TileEntity can be batched in with another renderers, and won't access the GL state.
|
||||
* If TileEntity returns true, then TESR should have the same functionality as (and probably extend) the FastTESR class.
|
||||
*/
|
||||
public boolean hasFastRenderer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private net.minecraftforge.common.capabilities.CapabilityDispatcher capabilities;
|
||||
public TileEntity()
|
||||
{
|
||||
capabilities = net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, @Nullable net.minecraft.util.EnumFacing facing)
|
||||
{
|
||||
return capabilities == null ? false : capabilities.hasCapability(capability, facing);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable net.minecraft.util.EnumFacing facing)
|
||||
{
|
||||
return capabilities == null ? null : capabilities.getCapability(capability, facing);
|
||||
}
|
||||
|
||||
public void deserializeNBT(NBTTagCompound nbt)
|
||||
{
|
||||
this.readFromNBT(nbt);
|
||||
}
|
||||
|
||||
public NBTTagCompound serializeNBT()
|
||||
{
|
||||
NBTTagCompound ret = new NBTTagCompound();
|
||||
this.writeToNBT(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
register("furnace", TileEntityFurnace.class);
|
||||
register("chest", TileEntityChest.class);
|
||||
register("ender_chest", TileEntityEnderChest.class);
|
||||
register("jukebox", BlockJukebox.TileEntityJukebox.class);
|
||||
register("dispenser", TileEntityDispenser.class);
|
||||
register("dropper", TileEntityDropper.class);
|
||||
register("sign", TileEntitySign.class);
|
||||
register("mob_spawner", TileEntityMobSpawner.class);
|
||||
register("noteblock", TileEntityNote.class);
|
||||
register("piston", TileEntityPiston.class);
|
||||
register("brewing_stand", TileEntityBrewingStand.class);
|
||||
register("enchanting_table", TileEntityEnchantmentTable.class);
|
||||
register("end_portal", TileEntityEndPortal.class);
|
||||
register("beacon", TileEntityBeacon.class);
|
||||
register("skull", TileEntitySkull.class);
|
||||
register("daylight_detector", TileEntityDaylightDetector.class);
|
||||
register("hopper", TileEntityHopper.class);
|
||||
register("comparator", TileEntityComparator.class);
|
||||
register("flower_pot", TileEntityFlowerPot.class);
|
||||
register("banner", TileEntityBanner.class);
|
||||
register("structure_block", TileEntityStructure.class);
|
||||
register("end_gateway", TileEntityEndGateway.class);
|
||||
register("command_block", TileEntityCommandBlock.class);
|
||||
register("shulker_box", TileEntityShulkerBox.class);
|
||||
register("bed", TileEntityBed.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.item.EnumDyeColor;
|
||||
import net.minecraft.item.ItemBanner;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.IWorldNameable;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntityBanner extends TileEntity implements IWorldNameable
|
||||
{
|
||||
private String name;
|
||||
private EnumDyeColor baseColor = EnumDyeColor.BLACK;
|
||||
/** A list of all the banner patterns. */
|
||||
private NBTTagList patterns;
|
||||
private boolean patternDataSet;
|
||||
/** A list of all patterns stored on this banner. */
|
||||
private List<BannerPattern> patternList;
|
||||
/** A list of all the color values stored on this banner. */
|
||||
private List<EnumDyeColor> colorList;
|
||||
/** This is a String representation of this banners pattern and color lists, used for texture caching. */
|
||||
private String patternResourceLocation;
|
||||
|
||||
public void setItemValues(ItemStack stack, boolean p_175112_2_)
|
||||
{
|
||||
this.patterns = null;
|
||||
NBTTagCompound nbttagcompound = stack.getSubCompound("BlockEntityTag");
|
||||
|
||||
if (nbttagcompound != null && nbttagcompound.hasKey("Patterns", 9))
|
||||
{
|
||||
this.patterns = nbttagcompound.getTagList("Patterns", 10).copy();
|
||||
}
|
||||
|
||||
this.baseColor = p_175112_2_ ? getColor(stack) : ItemBanner.getBaseColor(stack);
|
||||
this.patternList = null;
|
||||
this.colorList = null;
|
||||
this.patternResourceLocation = "";
|
||||
this.patternDataSet = true;
|
||||
this.name = stack.hasDisplayName() ? stack.getDisplayName() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.name : "banner";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this thing is named
|
||||
*/
|
||||
public boolean hasCustomName()
|
||||
{
|
||||
return this.name != null && !this.name.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted ChatComponent that will be used for the sender's username in chat
|
||||
*/
|
||||
public ITextComponent getDisplayName()
|
||||
{
|
||||
return (ITextComponent)(this.hasCustomName() ? new TextComponentString(this.getName()) : new TextComponentTranslation(this.getName(), new Object[0]));
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setInteger("Base", this.baseColor.getDyeDamage());
|
||||
|
||||
if (this.patterns != null)
|
||||
{
|
||||
compound.setTag("Patterns", this.patterns);
|
||||
}
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
compound.setString("CustomName", this.name);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
|
||||
if (compound.hasKey("CustomName", 8))
|
||||
{
|
||||
this.name = compound.getString("CustomName");
|
||||
}
|
||||
|
||||
this.baseColor = EnumDyeColor.byDyeDamage(compound.getInteger("Base"));
|
||||
this.patterns = compound.getTagList("Patterns", 10);
|
||||
this.patternList = null;
|
||||
this.colorList = null;
|
||||
this.patternResourceLocation = null;
|
||||
this.patternDataSet = true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 6, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the amount of patterns stored on an ItemStack. If the tag does not exist this value will be 0.
|
||||
*/
|
||||
public static int getPatterns(ItemStack stack)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = stack.getSubCompound("BlockEntityTag");
|
||||
return nbttagcompound != null && nbttagcompound.hasKey("Patterns") ? nbttagcompound.getTagList("Patterns", 10).tagCount() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of patterns for this tile entity. The banner data will be initialized/refreshed before this
|
||||
* happens.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public List<BannerPattern> getPatternList()
|
||||
{
|
||||
this.initializeBannerData();
|
||||
return this.patternList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of colors for this tile entity. The banner data will be initialized/refreshed before this
|
||||
* happens.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public List<EnumDyeColor> getColorList()
|
||||
{
|
||||
this.initializeBannerData();
|
||||
return this.colorList;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public String getPatternResourceLocation()
|
||||
{
|
||||
this.initializeBannerData();
|
||||
return this.patternResourceLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes all of the basic properties for the banner. This will also apply the data from the tile entities nbt
|
||||
* tag compounds.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
private void initializeBannerData()
|
||||
{
|
||||
if (this.patternList == null || this.colorList == null || this.patternResourceLocation == null)
|
||||
{
|
||||
if (!this.patternDataSet)
|
||||
{
|
||||
this.patternResourceLocation = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.patternList = Lists.<BannerPattern>newArrayList();
|
||||
this.colorList = Lists.<EnumDyeColor>newArrayList();
|
||||
this.patternList.add(BannerPattern.BASE);
|
||||
this.colorList.add(this.baseColor);
|
||||
this.patternResourceLocation = "b" + this.baseColor.getDyeDamage();
|
||||
|
||||
if (this.patterns != null)
|
||||
{
|
||||
for (int i = 0; i < this.patterns.tagCount(); ++i)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = this.patterns.getCompoundTagAt(i);
|
||||
BannerPattern bannerpattern = BannerPattern.byHash(nbttagcompound.getString("Pattern"));
|
||||
|
||||
if (bannerpattern != null)
|
||||
{
|
||||
this.patternList.add(bannerpattern);
|
||||
int j = nbttagcompound.getInteger("Color");
|
||||
this.colorList.add(EnumDyeColor.byDyeDamage(j));
|
||||
this.patternResourceLocation = this.patternResourceLocation + bannerpattern.getHashname() + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the banner related data from a provided instance of ItemStack.
|
||||
*/
|
||||
public static void removeBannerData(ItemStack stack)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = stack.getSubCompound("BlockEntityTag");
|
||||
|
||||
if (nbttagcompound != null && nbttagcompound.hasKey("Patterns", 9))
|
||||
{
|
||||
NBTTagList nbttaglist = nbttagcompound.getTagList("Patterns", 10);
|
||||
|
||||
if (!nbttaglist.hasNoTags())
|
||||
{
|
||||
nbttaglist.removeTag(nbttaglist.tagCount() - 1);
|
||||
|
||||
if (nbttaglist.hasNoTags())
|
||||
{
|
||||
stack.getTagCompound().removeTag("BlockEntityTag");
|
||||
|
||||
if (stack.getTagCompound().hasNoTags())
|
||||
{
|
||||
stack.setTagCompound((NBTTagCompound)null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ItemStack getItem()
|
||||
{
|
||||
ItemStack itemstack = ItemBanner.makeBanner(this.baseColor, this.patterns);
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
itemstack.setStackDisplayName(this.getName());
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
public static EnumDyeColor getColor(ItemStack p_190616_0_)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = p_190616_0_.getSubCompound("BlockEntityTag");
|
||||
return nbttagcompound != null && nbttagcompound.hasKey("Base") ? EnumDyeColor.byDyeDamage(nbttagcompound.getInteger("Base")) : EnumDyeColor.BLACK;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,568 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.block.BlockBed;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.EnumDyeColor;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntityBed extends TileEntity
|
||||
{
|
||||
private EnumDyeColor color = EnumDyeColor.RED;
|
||||
|
||||
public void setItemValues(ItemStack p_193051_1_)
|
||||
{
|
||||
this.setColor(EnumDyeColor.byMetadata(p_193051_1_.getMetadata()));
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
|
||||
if (compound.hasKey("color"))
|
||||
{
|
||||
this.color = EnumDyeColor.byMetadata(compound.getInteger("color"));
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setInteger("color", this.color.getMetadata());
|
||||
return compound;
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 11, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public EnumDyeColor getColor()
|
||||
{
|
||||
return this.color;
|
||||
}
|
||||
|
||||
public void setColor(EnumDyeColor color)
|
||||
{
|
||||
this.color = color;
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean isHeadPiece()
|
||||
{
|
||||
return BlockBed.isHeadPiece(this.getBlockMetadata());
|
||||
}
|
||||
|
||||
public ItemStack getItemStack()
|
||||
{
|
||||
return new ItemStack(Items.BED, 1, this.color.getMetadata());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import java.util.Arrays;
|
||||
import net.minecraft.block.BlockBrewingStand;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ContainerBrewingStand;
|
||||
import net.minecraft.inventory.ISidedInventory;
|
||||
import net.minecraft.inventory.InventoryHelper;
|
||||
import net.minecraft.inventory.ItemStackHelper;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.potion.PotionHelper;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class TileEntityBrewingStand extends TileEntityLockable implements ITickable, ISidedInventory
|
||||
{
|
||||
/** an array of the input slot indices */
|
||||
private static final int[] SLOTS_FOR_UP = new int[] {3};
|
||||
private static final int[] SLOTS_FOR_DOWN = new int[] {0, 1, 2, 3};
|
||||
/** an array of the output slot indices */
|
||||
private static final int[] OUTPUT_SLOTS = new int[] {0, 1, 2, 4};
|
||||
/** The ItemStacks currently placed in the slots of the brewing stand */
|
||||
private NonNullList<ItemStack> brewingItemStacks = NonNullList.<ItemStack>withSize(5, ItemStack.EMPTY);
|
||||
private int brewTime;
|
||||
/** an integer with each bit specifying whether that slot of the stand contains a potion */
|
||||
private boolean[] filledSlots;
|
||||
/** used to check if the current ingredient has been removed from the brewing stand during brewing */
|
||||
private Item ingredientID;
|
||||
private String customName;
|
||||
private int fuel;
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.customName : "container.brewing";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 number of slots in the inventory.
|
||||
*/
|
||||
public int getSizeInventory()
|
||||
{
|
||||
return this.brewingItemStacks.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (ItemStack itemstack : this.brewingItemStacks)
|
||||
{
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
ItemStack itemstack = this.brewingItemStacks.get(4);
|
||||
|
||||
if (this.fuel <= 0 && itemstack.getItem() == Items.BLAZE_POWDER)
|
||||
{
|
||||
this.fuel = 20;
|
||||
itemstack.shrink(1);
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
boolean flag = this.canBrew();
|
||||
boolean flag1 = this.brewTime > 0;
|
||||
ItemStack itemstack1 = this.brewingItemStacks.get(3);
|
||||
|
||||
if (flag1)
|
||||
{
|
||||
--this.brewTime;
|
||||
boolean flag2 = this.brewTime == 0;
|
||||
|
||||
if (flag2 && flag)
|
||||
{
|
||||
this.brewPotions();
|
||||
this.markDirty();
|
||||
}
|
||||
else if (!flag)
|
||||
{
|
||||
this.brewTime = 0;
|
||||
this.markDirty();
|
||||
}
|
||||
else if (this.ingredientID != itemstack1.getItem())
|
||||
{
|
||||
this.brewTime = 0;
|
||||
this.markDirty();
|
||||
}
|
||||
}
|
||||
else if (flag && this.fuel > 0)
|
||||
{
|
||||
--this.fuel;
|
||||
this.brewTime = 400;
|
||||
this.ingredientID = itemstack1.getItem();
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
boolean[] aboolean = this.createFilledSlotsArray();
|
||||
|
||||
if (!Arrays.equals(aboolean, this.filledSlots))
|
||||
{
|
||||
this.filledSlots = aboolean;
|
||||
IBlockState iblockstate = this.world.getBlockState(this.getPos());
|
||||
|
||||
if (!(iblockstate.getBlock() instanceof BlockBrewingStand))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < BlockBrewingStand.HAS_BOTTLE.length; ++i)
|
||||
{
|
||||
iblockstate = iblockstate.withProperty(BlockBrewingStand.HAS_BOTTLE[i], Boolean.valueOf(aboolean[i]));
|
||||
}
|
||||
|
||||
this.world.setBlockState(this.pos, iblockstate, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of boolean values, each value represents a potion input slot, value is true if the slot is not
|
||||
* null.
|
||||
*/
|
||||
public boolean[] createFilledSlotsArray()
|
||||
{
|
||||
boolean[] aboolean = new boolean[3];
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (!((ItemStack)this.brewingItemStacks.get(i)).isEmpty())
|
||||
{
|
||||
aboolean[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return aboolean;
|
||||
}
|
||||
|
||||
private boolean canBrew()
|
||||
{
|
||||
if (1 == 1) return net.minecraftforge.common.brewing.BrewingRecipeRegistry.canBrew(brewingItemStacks, brewingItemStacks.get(3), OUTPUT_SLOTS); // divert to VanillaBrewingRegistry
|
||||
ItemStack itemstack = this.brewingItemStacks.get(3);
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!PotionHelper.isReagent(itemstack))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
ItemStack itemstack1 = this.brewingItemStacks.get(i);
|
||||
|
||||
if (!itemstack1.isEmpty() && PotionHelper.hasConversions(itemstack1, itemstack))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void brewPotions()
|
||||
{
|
||||
if (net.minecraftforge.event.ForgeEventFactory.onPotionAttemptBrew(brewingItemStacks)) return;
|
||||
ItemStack itemstack = this.brewingItemStacks.get(3);
|
||||
|
||||
net.minecraftforge.common.brewing.BrewingRecipeRegistry.brewPotions(brewingItemStacks, brewingItemStacks.get(3), OUTPUT_SLOTS);
|
||||
|
||||
itemstack.shrink(1);
|
||||
BlockPos blockpos = this.getPos();
|
||||
|
||||
if (itemstack.getItem().hasContainerItem(itemstack))
|
||||
{
|
||||
ItemStack itemstack1 = itemstack.getItem().getContainerItem(itemstack);
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
itemstack = itemstack1;
|
||||
}
|
||||
else
|
||||
{
|
||||
InventoryHelper.spawnItemStack(this.world, (double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ(), itemstack1);
|
||||
}
|
||||
}
|
||||
|
||||
this.brewingItemStacks.set(3, itemstack);
|
||||
this.world.playEvent(1035, blockpos, 0);
|
||||
net.minecraftforge.event.ForgeEventFactory.onPotionBrewed(brewingItemStacks);
|
||||
}
|
||||
|
||||
public static void registerFixesBrewingStand(DataFixer fixer)
|
||||
{
|
||||
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityBrewingStand.class, new String[] {"Items"}));
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.brewingItemStacks = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
|
||||
ItemStackHelper.loadAllItems(compound, this.brewingItemStacks);
|
||||
this.brewTime = compound.getShort("BrewTime");
|
||||
|
||||
if (compound.hasKey("CustomName", 8))
|
||||
{
|
||||
this.customName = compound.getString("CustomName");
|
||||
}
|
||||
|
||||
this.fuel = compound.getByte("Fuel");
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setShort("BrewTime", (short)this.brewTime);
|
||||
ItemStackHelper.saveAllItems(compound, this.brewingItemStacks);
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
compound.setString("CustomName", this.customName);
|
||||
}
|
||||
|
||||
compound.setByte("Fuel", (byte)this.fuel);
|
||||
return compound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stack in the given slot.
|
||||
*/
|
||||
public ItemStack getStackInSlot(int index)
|
||||
{
|
||||
return index >= 0 && index < this.brewingItemStacks.size() ? (ItemStack)this.brewingItemStacks.get(index) : 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)
|
||||
{
|
||||
return ItemStackHelper.getAndSplit(this.brewingItemStacks, index, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a stack from the given slot and returns it.
|
||||
*/
|
||||
public ItemStack removeStackFromSlot(int index)
|
||||
{
|
||||
return ItemStackHelper.getAndRemove(this.brewingItemStacks, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 && index < this.brewingItemStacks.size())
|
||||
{
|
||||
this.brewingItemStacks.set(index, stack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
|
||||
*/
|
||||
public int getInventoryStackLimit()
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (index == 3)
|
||||
{
|
||||
return net.minecraftforge.common.brewing.BrewingRecipeRegistry.isValidIngredient(stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
Item item = stack.getItem();
|
||||
|
||||
if (index == 4)
|
||||
{
|
||||
return item == Items.BLAZE_POWDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
return net.minecraftforge.common.brewing.BrewingRecipeRegistry.isValidInput(stack) && this.getStackInSlot(index).isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getSlotsForFace(EnumFacing side)
|
||||
{
|
||||
if (side == EnumFacing.UP)
|
||||
{
|
||||
return SLOTS_FOR_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
return side == EnumFacing.DOWN ? SLOTS_FOR_DOWN : OUTPUT_SLOTS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 this.isItemValidForSlot(index, itemStackIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (index == 3)
|
||||
{
|
||||
return stack.getItem() == Items.GLASS_BOTTLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public String getGuiID()
|
||||
{
|
||||
return "minecraft:brewing_stand";
|
||||
}
|
||||
|
||||
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
||||
{
|
||||
return new ContainerBrewingStand(playerInventory, this);
|
||||
}
|
||||
|
||||
public int getField(int id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0:
|
||||
return this.brewTime;
|
||||
case 1:
|
||||
return this.fuel;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void setField(int id, int value)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0:
|
||||
this.brewTime = value;
|
||||
break;
|
||||
case 1:
|
||||
this.fuel = value;
|
||||
}
|
||||
}
|
||||
|
||||
net.minecraftforge.items.IItemHandler handlerInput = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.UP);
|
||||
net.minecraftforge.items.IItemHandler handlerOutput = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.DOWN);
|
||||
net.minecraftforge.items.IItemHandler handlerSides = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.NORTH);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@javax.annotation.Nullable
|
||||
public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @javax.annotation.Nullable net.minecraft.util.EnumFacing facing)
|
||||
{
|
||||
if (facing != null && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
{
|
||||
if (facing == EnumFacing.UP)
|
||||
return (T) handlerInput;
|
||||
else if (facing == EnumFacing.DOWN)
|
||||
return (T) handlerOutput;
|
||||
else
|
||||
return (T) handlerSides;
|
||||
}
|
||||
return super.getCapability(capability, facing);
|
||||
}
|
||||
|
||||
public int getFieldCount()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
this.brewingItemStacks.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockChest;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ContainerChest;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.InventoryLargeChest;
|
||||
import net.minecraft.inventory.ItemStackHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class TileEntityChest extends TileEntityLockableLoot implements ITickable
|
||||
{
|
||||
private NonNullList<ItemStack> chestContents = NonNullList.<ItemStack>withSize(27, ItemStack.EMPTY);
|
||||
/** Determines if the check for adjacent chests has taken place. */
|
||||
public boolean adjacentChestChecked;
|
||||
/** Contains the chest tile located adjacent to this one (if any) */
|
||||
public TileEntityChest adjacentChestZNeg;
|
||||
/** Contains the chest tile located adjacent to this one (if any) */
|
||||
public TileEntityChest adjacentChestXPos;
|
||||
/** Contains the chest tile located adjacent to this one (if any) */
|
||||
public TileEntityChest adjacentChestXNeg;
|
||||
/** Contains the chest tile located adjacent to this one (if any) */
|
||||
public TileEntityChest adjacentChestZPos;
|
||||
/** The current angle of the lid (between 0 and 1) */
|
||||
public float lidAngle;
|
||||
/** The angle of the lid last tick */
|
||||
public float prevLidAngle;
|
||||
/** The number of players currently using this chest */
|
||||
public int numPlayersUsing;
|
||||
/** Server sync counter (once per 20 ticks) */
|
||||
private int ticksSinceSync;
|
||||
private BlockChest.Type cachedChestType;
|
||||
|
||||
public TileEntityChest()
|
||||
{
|
||||
}
|
||||
|
||||
public TileEntityChest(BlockChest.Type typeIn)
|
||||
{
|
||||
this.cachedChestType = typeIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of slots in the inventory.
|
||||
*/
|
||||
public int getSizeInventory()
|
||||
{
|
||||
return 27;
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (ItemStack itemstack : this.chestContents)
|
||||
{
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.customName : "container.chest";
|
||||
}
|
||||
|
||||
public static void registerFixesChest(DataFixer fixer)
|
||||
{
|
||||
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityChest.class, new String[] {"Items"}));
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.chestContents = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
|
||||
|
||||
if (!this.checkLootAndRead(compound))
|
||||
{
|
||||
ItemStackHelper.loadAllItems(compound, this.chestContents);
|
||||
}
|
||||
|
||||
if (compound.hasKey("CustomName", 8))
|
||||
{
|
||||
this.customName = compound.getString("CustomName");
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
|
||||
if (!this.checkLootAndWrite(compound))
|
||||
{
|
||||
ItemStackHelper.saveAllItems(compound, this.chestContents);
|
||||
}
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
compound.setString("CustomName", this.customName);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
|
||||
*/
|
||||
public int getInventoryStackLimit()
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
public void updateContainingBlockInfo()
|
||||
{
|
||||
super.updateContainingBlockInfo();
|
||||
this.adjacentChestChecked = false;
|
||||
doubleChestHandler = null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
private void setNeighbor(TileEntityChest chestTe, EnumFacing side)
|
||||
{
|
||||
if (chestTe.isInvalid())
|
||||
{
|
||||
this.adjacentChestChecked = false;
|
||||
}
|
||||
else if (this.adjacentChestChecked)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case NORTH:
|
||||
|
||||
if (this.adjacentChestZNeg != chestTe)
|
||||
{
|
||||
this.adjacentChestChecked = false;
|
||||
}
|
||||
|
||||
break;
|
||||
case SOUTH:
|
||||
|
||||
if (this.adjacentChestZPos != chestTe)
|
||||
{
|
||||
this.adjacentChestChecked = false;
|
||||
}
|
||||
|
||||
break;
|
||||
case EAST:
|
||||
|
||||
if (this.adjacentChestXPos != chestTe)
|
||||
{
|
||||
this.adjacentChestChecked = false;
|
||||
}
|
||||
|
||||
break;
|
||||
case WEST:
|
||||
|
||||
if (this.adjacentChestXNeg != chestTe)
|
||||
{
|
||||
this.adjacentChestChecked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the check for adjacent chests to determine if this chest is double or not.
|
||||
*/
|
||||
public void checkForAdjacentChests()
|
||||
{
|
||||
if (!this.adjacentChestChecked)
|
||||
{
|
||||
if (this.world == null || !this.world.isAreaLoaded(this.pos, 1)) return; // Forge: prevent loading unloaded chunks when checking neighbors
|
||||
this.adjacentChestChecked = true;
|
||||
this.adjacentChestXNeg = this.getAdjacentChest(EnumFacing.WEST);
|
||||
this.adjacentChestXPos = this.getAdjacentChest(EnumFacing.EAST);
|
||||
this.adjacentChestZNeg = this.getAdjacentChest(EnumFacing.NORTH);
|
||||
this.adjacentChestZPos = this.getAdjacentChest(EnumFacing.SOUTH);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected TileEntityChest getAdjacentChest(EnumFacing side)
|
||||
{
|
||||
BlockPos blockpos = this.pos.offset(side);
|
||||
|
||||
if (this.isChestAt(blockpos))
|
||||
{
|
||||
TileEntity tileentity = this.world.getTileEntity(blockpos);
|
||||
|
||||
if (tileentity instanceof TileEntityChest)
|
||||
{
|
||||
TileEntityChest tileentitychest = (TileEntityChest)tileentity;
|
||||
tileentitychest.setNeighbor(this, side.getOpposite());
|
||||
return tileentitychest;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isChestAt(BlockPos posIn)
|
||||
{
|
||||
if (this.world == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Block block = this.world.getBlockState(posIn).getBlock();
|
||||
return block instanceof BlockChest && ((BlockChest)block).chestType == this.getChestType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
this.checkForAdjacentChests();
|
||||
int i = this.pos.getX();
|
||||
int j = this.pos.getY();
|
||||
int k = this.pos.getZ();
|
||||
++this.ticksSinceSync;
|
||||
|
||||
if (!this.world.isRemote && this.numPlayersUsing != 0 && (this.ticksSinceSync + i + j + k) % 200 == 0)
|
||||
{
|
||||
this.numPlayersUsing = 0;
|
||||
float f = 5.0F;
|
||||
|
||||
for (EntityPlayer entityplayer : this.world.getEntitiesWithinAABB(EntityPlayer.class, new AxisAlignedBB((double)((float)i - 5.0F), (double)((float)j - 5.0F), (double)((float)k - 5.0F), (double)((float)(i + 1) + 5.0F), (double)((float)(j + 1) + 5.0F), (double)((float)(k + 1) + 5.0F))))
|
||||
{
|
||||
if (entityplayer.openContainer instanceof ContainerChest)
|
||||
{
|
||||
IInventory iinventory = ((ContainerChest)entityplayer.openContainer).getLowerChestInventory();
|
||||
|
||||
if (iinventory == this || iinventory instanceof InventoryLargeChest && ((InventoryLargeChest)iinventory).isPartOfLargeChest(this))
|
||||
{
|
||||
++this.numPlayersUsing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.prevLidAngle = this.lidAngle;
|
||||
float f1 = 0.1F;
|
||||
|
||||
if (this.numPlayersUsing > 0 && this.lidAngle == 0.0F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
|
||||
{
|
||||
double d1 = (double)i + 0.5D;
|
||||
double d2 = (double)k + 0.5D;
|
||||
|
||||
if (this.adjacentChestZPos != null)
|
||||
{
|
||||
d2 += 0.5D;
|
||||
}
|
||||
|
||||
if (this.adjacentChestXPos != null)
|
||||
{
|
||||
d1 += 0.5D;
|
||||
}
|
||||
|
||||
this.world.playSound((EntityPlayer)null, d1, (double)j + 0.5D, d2, SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
|
||||
}
|
||||
|
||||
if (this.numPlayersUsing == 0 && this.lidAngle > 0.0F || this.numPlayersUsing > 0 && this.lidAngle < 1.0F)
|
||||
{
|
||||
float f2 = this.lidAngle;
|
||||
|
||||
if (this.numPlayersUsing > 0)
|
||||
{
|
||||
this.lidAngle += 0.1F;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.lidAngle -= 0.1F;
|
||||
}
|
||||
|
||||
if (this.lidAngle > 1.0F)
|
||||
{
|
||||
this.lidAngle = 1.0F;
|
||||
}
|
||||
|
||||
float f3 = 0.5F;
|
||||
|
||||
if (this.lidAngle < 0.5F && f2 >= 0.5F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
|
||||
{
|
||||
double d3 = (double)i + 0.5D;
|
||||
double d0 = (double)k + 0.5D;
|
||||
|
||||
if (this.adjacentChestZPos != null)
|
||||
{
|
||||
d0 += 0.5D;
|
||||
}
|
||||
|
||||
if (this.adjacentChestXPos != null)
|
||||
{
|
||||
d3 += 0.5D;
|
||||
}
|
||||
|
||||
this.world.playSound((EntityPlayer)null, d3, (double)j + 0.5D, d0, SoundEvents.BLOCK_CHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
|
||||
}
|
||||
|
||||
if (this.lidAngle < 0.0F)
|
||||
{
|
||||
this.lidAngle = 0.0F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean receiveClientEvent(int id, int type)
|
||||
{
|
||||
if (id == 1)
|
||||
{
|
||||
this.numPlayersUsing = type;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.receiveClientEvent(id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public void openInventory(EntityPlayer player)
|
||||
{
|
||||
if (!player.isSpectator())
|
||||
{
|
||||
if (this.numPlayersUsing < 0)
|
||||
{
|
||||
this.numPlayersUsing = 0;
|
||||
}
|
||||
|
||||
++this.numPlayersUsing;
|
||||
this.world.addBlockEvent(this.pos, this.getBlockType(), 1, this.numPlayersUsing);
|
||||
this.world.notifyNeighborsOfStateChange(this.pos, this.getBlockType(), false);
|
||||
|
||||
if (this.getChestType() == BlockChest.Type.TRAP)
|
||||
{
|
||||
this.world.notifyNeighborsOfStateChange(this.pos.down(), this.getBlockType(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void closeInventory(EntityPlayer player)
|
||||
{
|
||||
if (!player.isSpectator() && this.getBlockType() instanceof BlockChest)
|
||||
{
|
||||
--this.numPlayersUsing;
|
||||
this.world.addBlockEvent(this.pos, this.getBlockType(), 1, this.numPlayersUsing);
|
||||
this.world.notifyNeighborsOfStateChange(this.pos, this.getBlockType(), false);
|
||||
|
||||
if (this.getChestType() == BlockChest.Type.TRAP)
|
||||
{
|
||||
this.world.notifyNeighborsOfStateChange(this.pos.down(), this.getBlockType(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public net.minecraftforge.items.VanillaDoubleChestItemHandler doubleChestHandler;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable net.minecraft.util.EnumFacing facing)
|
||||
{
|
||||
if (capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
{
|
||||
if(doubleChestHandler == null || doubleChestHandler.needsRefresh())
|
||||
doubleChestHandler = net.minecraftforge.items.VanillaDoubleChestItemHandler.get(this);
|
||||
if (doubleChestHandler != null && doubleChestHandler != net.minecraftforge.items.VanillaDoubleChestItemHandler.NO_ADJACENT_CHESTS_INSTANCE)
|
||||
return (T) doubleChestHandler;
|
||||
}
|
||||
return super.getCapability(capability, facing);
|
||||
}
|
||||
|
||||
public net.minecraftforge.items.IItemHandler getSingleChestHandler()
|
||||
{
|
||||
return super.getCapability(net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* invalidates a tile entity
|
||||
*/
|
||||
public void invalidate()
|
||||
{
|
||||
super.invalidate();
|
||||
this.updateContainingBlockInfo();
|
||||
this.checkForAdjacentChests();
|
||||
}
|
||||
|
||||
public BlockChest.Type getChestType()
|
||||
{
|
||||
if (this.cachedChestType == null)
|
||||
{
|
||||
if (this.world == null || !(this.getBlockType() instanceof BlockChest))
|
||||
{
|
||||
return BlockChest.Type.BASIC;
|
||||
}
|
||||
|
||||
this.cachedChestType = ((BlockChest)this.getBlockType()).chestType;
|
||||
}
|
||||
|
||||
return this.cachedChestType;
|
||||
}
|
||||
|
||||
public String getGuiID()
|
||||
{
|
||||
return "minecraft:chest";
|
||||
}
|
||||
|
||||
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
||||
{
|
||||
this.fillWithLoot(playerIn);
|
||||
return new ContainerChest(playerInventory, this, playerIn);
|
||||
}
|
||||
|
||||
protected NonNullList<ItemStack> getItems()
|
||||
{
|
||||
return this.chestContents;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockCommandBlock;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.command.CommandResultStats;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntityCommandBlock extends TileEntity
|
||||
{
|
||||
private boolean powered;
|
||||
private boolean auto;
|
||||
private boolean conditionMet;
|
||||
private boolean sendToClient;
|
||||
private final CommandBlockBaseLogic commandBlockLogic = new CommandBlockBaseLogic()
|
||||
{
|
||||
/**
|
||||
* Get the position in the world. <b>{@code null} is not allowed!</b> If you are not an entity in the world,
|
||||
* return the coordinates 0, 0, 0
|
||||
*/
|
||||
public BlockPos getPosition()
|
||||
{
|
||||
return TileEntityCommandBlock.this.pos;
|
||||
}
|
||||
/**
|
||||
* Get the position vector. <b>{@code null} is not allowed!</b> If you are not an entity in the world, return
|
||||
* 0.0D, 0.0D, 0.0D
|
||||
*/
|
||||
public Vec3d getPositionVector()
|
||||
{
|
||||
return new Vec3d((double)TileEntityCommandBlock.this.pos.getX() + 0.5D, (double)TileEntityCommandBlock.this.pos.getY() + 0.5D, (double)TileEntityCommandBlock.this.pos.getZ() + 0.5D);
|
||||
}
|
||||
/**
|
||||
* Get the world, if available. <b>{@code null} is not allowed!</b> If you are not an entity in the world,
|
||||
* return the overworld
|
||||
*/
|
||||
public World getEntityWorld()
|
||||
{
|
||||
return TileEntityCommandBlock.this.getWorld();
|
||||
}
|
||||
/**
|
||||
* Sets the command.
|
||||
*/
|
||||
public void setCommand(String command)
|
||||
{
|
||||
super.setCommand(command);
|
||||
TileEntityCommandBlock.this.markDirty();
|
||||
}
|
||||
public void updateCommand()
|
||||
{
|
||||
IBlockState iblockstate = TileEntityCommandBlock.this.world.getBlockState(TileEntityCommandBlock.this.pos);
|
||||
TileEntityCommandBlock.this.getWorld().notifyBlockUpdate(TileEntityCommandBlock.this.pos, iblockstate, iblockstate, 3);
|
||||
}
|
||||
/**
|
||||
* Currently this returns 0 for the traditional command block, and 1 for the minecart command block
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public int getCommandBlockType()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Fills in information about the command block for the packet. entityId for the minecart version, and X/Y/Z for
|
||||
* the traditional version
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void fillInInfo(ByteBuf buf)
|
||||
{
|
||||
buf.writeInt(TileEntityCommandBlock.this.pos.getX());
|
||||
buf.writeInt(TileEntityCommandBlock.this.pos.getY());
|
||||
buf.writeInt(TileEntityCommandBlock.this.pos.getZ());
|
||||
}
|
||||
/**
|
||||
* Get the Minecraft server instance
|
||||
*/
|
||||
public MinecraftServer getServer()
|
||||
{
|
||||
return TileEntityCommandBlock.this.world.getMinecraftServer();
|
||||
}
|
||||
};
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
this.commandBlockLogic.writeToNBT(compound);
|
||||
compound.setBoolean("powered", this.isPowered());
|
||||
compound.setBoolean("conditionMet", this.isConditionMet());
|
||||
compound.setBoolean("auto", this.isAuto());
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.commandBlockLogic.readDataFromNBT(compound);
|
||||
this.powered = compound.getBoolean("powered");
|
||||
this.conditionMet = compound.getBoolean("conditionMet");
|
||||
this.setAuto(compound.getBoolean("auto"));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
if (this.isSendToClient())
|
||||
{
|
||||
this.setSendToClient(false);
|
||||
NBTTagCompound nbttagcompound = this.writeToNBT(new NBTTagCompound());
|
||||
return new SPacketUpdateTileEntity(this.pos, 2, nbttagcompound);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onlyOpsCanSetNbt()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public CommandBlockBaseLogic getCommandBlockLogic()
|
||||
{
|
||||
return this.commandBlockLogic;
|
||||
}
|
||||
|
||||
public CommandResultStats getCommandResultStats()
|
||||
{
|
||||
return this.commandBlockLogic.getCommandResultStats();
|
||||
}
|
||||
|
||||
public void setPowered(boolean poweredIn)
|
||||
{
|
||||
this.powered = poweredIn;
|
||||
}
|
||||
|
||||
public boolean isPowered()
|
||||
{
|
||||
return this.powered;
|
||||
}
|
||||
|
||||
public boolean isAuto()
|
||||
{
|
||||
return this.auto;
|
||||
}
|
||||
|
||||
public void setAuto(boolean autoIn)
|
||||
{
|
||||
boolean flag = this.auto;
|
||||
this.auto = autoIn;
|
||||
|
||||
if (!flag && autoIn && !this.powered && this.world != null && this.getMode() != TileEntityCommandBlock.Mode.SEQUENCE)
|
||||
{
|
||||
Block block = this.getBlockType();
|
||||
|
||||
if (block instanceof BlockCommandBlock)
|
||||
{
|
||||
this.setConditionMet();
|
||||
this.world.scheduleUpdate(this.pos, block, block.tickRate(this.world));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConditionMet()
|
||||
{
|
||||
return this.conditionMet;
|
||||
}
|
||||
|
||||
public boolean setConditionMet()
|
||||
{
|
||||
this.conditionMet = true;
|
||||
|
||||
if (this.isConditional())
|
||||
{
|
||||
BlockPos blockpos = this.pos.offset(((EnumFacing)this.world.getBlockState(this.pos).getValue(BlockCommandBlock.FACING)).getOpposite());
|
||||
|
||||
if (this.world.getBlockState(blockpos).getBlock() instanceof BlockCommandBlock)
|
||||
{
|
||||
TileEntity tileentity = this.world.getTileEntity(blockpos);
|
||||
this.conditionMet = tileentity instanceof TileEntityCommandBlock && ((TileEntityCommandBlock)tileentity).getCommandBlockLogic().getSuccessCount() > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.conditionMet = false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.conditionMet;
|
||||
}
|
||||
|
||||
public boolean isSendToClient()
|
||||
{
|
||||
return this.sendToClient;
|
||||
}
|
||||
|
||||
public void setSendToClient(boolean p_184252_1_)
|
||||
{
|
||||
this.sendToClient = p_184252_1_;
|
||||
}
|
||||
|
||||
public TileEntityCommandBlock.Mode getMode()
|
||||
{
|
||||
Block block = this.getBlockType();
|
||||
|
||||
if (block == Blocks.COMMAND_BLOCK)
|
||||
{
|
||||
return TileEntityCommandBlock.Mode.REDSTONE;
|
||||
}
|
||||
else if (block == Blocks.REPEATING_COMMAND_BLOCK)
|
||||
{
|
||||
return TileEntityCommandBlock.Mode.AUTO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return block == Blocks.CHAIN_COMMAND_BLOCK ? TileEntityCommandBlock.Mode.SEQUENCE : TileEntityCommandBlock.Mode.REDSTONE;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConditional()
|
||||
{
|
||||
IBlockState iblockstate = this.world.getBlockState(this.getPos());
|
||||
return iblockstate.getBlock() instanceof BlockCommandBlock ? ((Boolean)iblockstate.getValue(BlockCommandBlock.CONDITIONAL)).booleanValue() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* validates a tile entity
|
||||
*/
|
||||
public void validate()
|
||||
{
|
||||
this.blockType = null;
|
||||
super.validate();
|
||||
}
|
||||
|
||||
public static enum Mode
|
||||
{
|
||||
SEQUENCE,
|
||||
AUTO,
|
||||
REDSTONE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public class TileEntityComparator extends TileEntity
|
||||
{
|
||||
private int outputSignal;
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setInteger("OutputSignal", this.outputSignal);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.outputSignal = compound.getInteger("OutputSignal");
|
||||
}
|
||||
|
||||
public int getOutputSignal()
|
||||
{
|
||||
return this.outputSignal;
|
||||
}
|
||||
|
||||
public void setOutputSignal(int outputSignalIn)
|
||||
{
|
||||
this.outputSignal = outputSignalIn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.block.BlockDaylightDetector;
|
||||
import net.minecraft.util.ITickable;
|
||||
|
||||
public class TileEntityDaylightDetector extends TileEntity implements ITickable
|
||||
{
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
if (this.world != null && !this.world.isRemote && this.world.getTotalWorldTime() % 20L == 0L)
|
||||
{
|
||||
this.blockType = this.getBlockType();
|
||||
|
||||
if (this.blockType instanceof BlockDaylightDetector)
|
||||
{
|
||||
((BlockDaylightDetector)this.blockType).updatePower(this.world, this.pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import java.util.Random;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ContainerDispenser;
|
||||
import net.minecraft.inventory.ItemStackHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
||||
|
||||
public class TileEntityDispenser extends TileEntityLockableLoot
|
||||
{
|
||||
private static final Random RNG = new Random();
|
||||
private NonNullList<ItemStack> stacks = NonNullList.<ItemStack>withSize(9, ItemStack.EMPTY);
|
||||
|
||||
/**
|
||||
* Returns the number of slots in the inventory.
|
||||
*/
|
||||
public int getSizeInventory()
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (ItemStack itemstack : this.stacks)
|
||||
{
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getDispenseSlot()
|
||||
{
|
||||
this.fillWithLoot((EntityPlayer)null);
|
||||
int i = -1;
|
||||
int j = 1;
|
||||
|
||||
for (int k = 0; k < this.stacks.size(); ++k)
|
||||
{
|
||||
if (!((ItemStack)this.stacks.get(k)).isEmpty() && RNG.nextInt(j++) == 0)
|
||||
{
|
||||
i = k;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given ItemStack to this Dispenser. Return the Slot the Item was placed in or -1 if no free slot is
|
||||
* available.
|
||||
*/
|
||||
public int addItemStack(ItemStack stack)
|
||||
{
|
||||
for (int i = 0; i < this.stacks.size(); ++i)
|
||||
{
|
||||
if (((ItemStack)this.stacks.get(i)).isEmpty())
|
||||
{
|
||||
this.setInventorySlotContents(i, stack);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.customName : "container.dispenser";
|
||||
}
|
||||
|
||||
public static void registerFixes(DataFixer fixer)
|
||||
{
|
||||
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityDispenser.class, new String[] {"Items"}));
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.stacks = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
|
||||
|
||||
if (!this.checkLootAndRead(compound))
|
||||
{
|
||||
ItemStackHelper.loadAllItems(compound, this.stacks);
|
||||
}
|
||||
|
||||
if (compound.hasKey("CustomName", 8))
|
||||
{
|
||||
this.customName = compound.getString("CustomName");
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
|
||||
if (!this.checkLootAndWrite(compound))
|
||||
{
|
||||
ItemStackHelper.saveAllItems(compound, this.stacks);
|
||||
}
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
compound.setString("CustomName", this.customName);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
|
||||
*/
|
||||
public int getInventoryStackLimit()
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
public String getGuiID()
|
||||
{
|
||||
return "minecraft:dispenser";
|
||||
}
|
||||
|
||||
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
||||
{
|
||||
this.fillWithLoot(playerIn);
|
||||
return new ContainerDispenser(playerInventory, this);
|
||||
}
|
||||
|
||||
protected NonNullList<ItemStack> getItems()
|
||||
{
|
||||
return this.stacks;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
||||
|
||||
public class TileEntityDropper extends TileEntityDispenser
|
||||
{
|
||||
public static void registerFixesDropper(DataFixer fixer)
|
||||
{
|
||||
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityDropper.class, new String[] {"Items"}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.customName : "container.dropper";
|
||||
}
|
||||
|
||||
public String getGuiID()
|
||||
{
|
||||
return "minecraft:dropper";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import java.util.Random;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ContainerEnchantment;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.IInteractionObject;
|
||||
|
||||
public class TileEntityEnchantmentTable extends TileEntity implements ITickable, IInteractionObject
|
||||
{
|
||||
public int tickCount;
|
||||
public float pageFlip;
|
||||
public float pageFlipPrev;
|
||||
public float flipT;
|
||||
public float flipA;
|
||||
public float bookSpread;
|
||||
public float bookSpreadPrev;
|
||||
public float bookRotation;
|
||||
public float bookRotationPrev;
|
||||
public float tRot;
|
||||
private static final Random rand = new Random();
|
||||
private String customName;
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
compound.setString("CustomName", this.customName);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
|
||||
if (compound.hasKey("CustomName", 8))
|
||||
{
|
||||
this.customName = compound.getString("CustomName");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
this.bookSpreadPrev = this.bookSpread;
|
||||
this.bookRotationPrev = this.bookRotation;
|
||||
EntityPlayer entityplayer = this.world.getClosestPlayer((double)((float)this.pos.getX() + 0.5F), (double)((float)this.pos.getY() + 0.5F), (double)((float)this.pos.getZ() + 0.5F), 3.0D, false);
|
||||
|
||||
if (entityplayer != null)
|
||||
{
|
||||
double d0 = entityplayer.posX - (double)((float)this.pos.getX() + 0.5F);
|
||||
double d1 = entityplayer.posZ - (double)((float)this.pos.getZ() + 0.5F);
|
||||
this.tRot = (float)MathHelper.atan2(d1, d0);
|
||||
this.bookSpread += 0.1F;
|
||||
|
||||
if (this.bookSpread < 0.5F || rand.nextInt(40) == 0)
|
||||
{
|
||||
float f1 = this.flipT;
|
||||
|
||||
while (true)
|
||||
{
|
||||
this.flipT += (float)(rand.nextInt(4) - rand.nextInt(4));
|
||||
|
||||
if (f1 != this.flipT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.tRot += 0.02F;
|
||||
this.bookSpread -= 0.1F;
|
||||
}
|
||||
|
||||
while (this.bookRotation >= (float)Math.PI)
|
||||
{
|
||||
this.bookRotation -= ((float)Math.PI * 2F);
|
||||
}
|
||||
|
||||
while (this.bookRotation < -(float)Math.PI)
|
||||
{
|
||||
this.bookRotation += ((float)Math.PI * 2F);
|
||||
}
|
||||
|
||||
while (this.tRot >= (float)Math.PI)
|
||||
{
|
||||
this.tRot -= ((float)Math.PI * 2F);
|
||||
}
|
||||
|
||||
while (this.tRot < -(float)Math.PI)
|
||||
{
|
||||
this.tRot += ((float)Math.PI * 2F);
|
||||
}
|
||||
|
||||
float f2;
|
||||
|
||||
for (f2 = this.tRot - this.bookRotation; f2 >= (float)Math.PI; f2 -= ((float)Math.PI * 2F))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
while (f2 < -(float)Math.PI)
|
||||
{
|
||||
f2 += ((float)Math.PI * 2F);
|
||||
}
|
||||
|
||||
this.bookRotation += f2 * 0.4F;
|
||||
this.bookSpread = MathHelper.clamp(this.bookSpread, 0.0F, 1.0F);
|
||||
++this.tickCount;
|
||||
this.pageFlipPrev = this.pageFlip;
|
||||
float f = (this.flipT - this.pageFlip) * 0.4F;
|
||||
float f3 = 0.2F;
|
||||
f = MathHelper.clamp(f, -0.2F, 0.2F);
|
||||
this.flipA += (f - this.flipA) * 0.9F;
|
||||
this.pageFlip += this.flipA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.customName : "container.enchant";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this thing is named
|
||||
*/
|
||||
public boolean hasCustomName()
|
||||
{
|
||||
return this.customName != null && !this.customName.isEmpty();
|
||||
}
|
||||
|
||||
public void setCustomName(String customNameIn)
|
||||
{
|
||||
this.customName = customNameIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted ChatComponent that will be used for the sender's username in chat
|
||||
*/
|
||||
public ITextComponent getDisplayName()
|
||||
{
|
||||
return (ITextComponent)(this.hasCustomName() ? new TextComponentString(this.getName()) : new TextComponentTranslation(this.getName(), new Object[0]));
|
||||
}
|
||||
|
||||
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
||||
{
|
||||
return new ContainerEnchantment(playerInventory, this.world, this.pos);
|
||||
}
|
||||
|
||||
public String getGuiID()
|
||||
{
|
||||
return "minecraft:enchanting_table";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldProviderEnd;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.gen.feature.WorldGenEndGateway;
|
||||
import net.minecraft.world.gen.feature.WorldGenEndIsland;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class TileEntityEndGateway extends TileEntityEndPortal implements ITickable
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private long age;
|
||||
private int teleportCooldown;
|
||||
private BlockPos exitPortal;
|
||||
private boolean exactTeleport;
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setLong("Age", this.age);
|
||||
|
||||
if (this.exitPortal != null)
|
||||
{
|
||||
compound.setTag("ExitPortal", NBTUtil.createPosTag(this.exitPortal));
|
||||
}
|
||||
|
||||
if (this.exactTeleport)
|
||||
{
|
||||
compound.setBoolean("ExactTeleport", this.exactTeleport);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.age = compound.getLong("Age");
|
||||
|
||||
if (compound.hasKey("ExitPortal", 10))
|
||||
{
|
||||
this.exitPortal = NBTUtil.getPosFromTag(compound.getCompoundTag("ExitPortal"));
|
||||
}
|
||||
|
||||
this.exactTeleport = compound.getBoolean("ExactTeleport");
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public double getMaxRenderDistanceSquared()
|
||||
{
|
||||
return 65536.0D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
boolean flag = this.isSpawning();
|
||||
boolean flag1 = this.isCoolingDown();
|
||||
++this.age;
|
||||
|
||||
if (flag1)
|
||||
{
|
||||
--this.teleportCooldown;
|
||||
}
|
||||
else if (!this.world.isRemote)
|
||||
{
|
||||
List<Entity> list = this.world.<Entity>getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(this.getPos()));
|
||||
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
this.teleportEntity(list.get(0));
|
||||
}
|
||||
|
||||
if (this.age % 2400L == 0L)
|
||||
{
|
||||
this.triggerCooldown();
|
||||
}
|
||||
}
|
||||
|
||||
if (flag != this.isSpawning() || flag1 != this.isCoolingDown())
|
||||
{
|
||||
this.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSpawning()
|
||||
{
|
||||
return this.age < 200L;
|
||||
}
|
||||
|
||||
public boolean isCoolingDown()
|
||||
{
|
||||
return this.teleportCooldown > 0;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getSpawnPercent(float p_184302_1_)
|
||||
{
|
||||
return MathHelper.clamp(((float)this.age + p_184302_1_) / 200.0F, 0.0F, 1.0F);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getCooldownPercent(float p_184305_1_)
|
||||
{
|
||||
return 1.0F - MathHelper.clamp(((float)this.teleportCooldown - p_184305_1_) / 40.0F, 0.0F, 1.0F);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 8, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public void triggerCooldown()
|
||||
{
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.teleportCooldown = 40;
|
||||
this.world.addBlockEvent(this.getPos(), this.getBlockType(), 1, 0);
|
||||
this.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean receiveClientEvent(int id, int type)
|
||||
{
|
||||
if (id == 1)
|
||||
{
|
||||
this.teleportCooldown = 40;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.receiveClientEvent(id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public void teleportEntity(Entity entityIn)
|
||||
{
|
||||
if (!this.world.isRemote && !this.isCoolingDown())
|
||||
{
|
||||
this.teleportCooldown = 100;
|
||||
|
||||
if (this.exitPortal == null && this.world.provider instanceof WorldProviderEnd)
|
||||
{
|
||||
this.findExitPortal();
|
||||
}
|
||||
|
||||
if (this.exitPortal != null)
|
||||
{
|
||||
BlockPos blockpos = this.exactTeleport ? this.exitPortal : this.findExitPosition();
|
||||
entityIn.setPositionAndUpdate((double)blockpos.getX() + 0.5D, (double)blockpos.getY() + 0.5D, (double)blockpos.getZ() + 0.5D);
|
||||
}
|
||||
|
||||
this.triggerCooldown();
|
||||
}
|
||||
}
|
||||
|
||||
private BlockPos findExitPosition()
|
||||
{
|
||||
BlockPos blockpos = findHighestBlock(this.world, this.exitPortal, 5, false);
|
||||
LOGGER.debug("Best exit position for portal at {} is {}", this.exitPortal, blockpos);
|
||||
return blockpos.up();
|
||||
}
|
||||
|
||||
private void findExitPortal()
|
||||
{
|
||||
Vec3d vec3d = (new Vec3d((double)this.getPos().getX(), 0.0D, (double)this.getPos().getZ())).normalize();
|
||||
Vec3d vec3d1 = vec3d.scale(1024.0D);
|
||||
|
||||
for (int i = 16; getChunk(this.world, vec3d1).getTopFilledSegment() > 0 && i-- > 0; vec3d1 = vec3d1.add(vec3d.scale(-16.0D)))
|
||||
{
|
||||
LOGGER.debug("Skipping backwards past nonempty chunk at {}", (Object)vec3d1);
|
||||
}
|
||||
|
||||
for (int j = 16; getChunk(this.world, vec3d1).getTopFilledSegment() == 0 && j-- > 0; vec3d1 = vec3d1.add(vec3d.scale(16.0D)))
|
||||
{
|
||||
LOGGER.debug("Skipping forward past empty chunk at {}", (Object)vec3d1);
|
||||
}
|
||||
|
||||
LOGGER.debug("Found chunk at {}", (Object)vec3d1);
|
||||
Chunk chunk = getChunk(this.world, vec3d1);
|
||||
this.exitPortal = findSpawnpointInChunk(chunk);
|
||||
|
||||
if (this.exitPortal == null)
|
||||
{
|
||||
this.exitPortal = new BlockPos(vec3d1.x + 0.5D, 75.0D, vec3d1.z + 0.5D);
|
||||
LOGGER.debug("Failed to find suitable block, settling on {}", (Object)this.exitPortal);
|
||||
(new WorldGenEndIsland()).generate(this.world, new Random(this.exitPortal.toLong()), this.exitPortal);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.debug("Found block at {}", (Object)this.exitPortal);
|
||||
}
|
||||
|
||||
this.exitPortal = findHighestBlock(this.world, this.exitPortal, 16, true);
|
||||
LOGGER.debug("Creating portal at {}", (Object)this.exitPortal);
|
||||
this.exitPortal = this.exitPortal.up(10);
|
||||
this.createExitPortal(this.exitPortal);
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
private static BlockPos findHighestBlock(World p_184308_0_, BlockPos p_184308_1_, int p_184308_2_, boolean p_184308_3_)
|
||||
{
|
||||
BlockPos blockpos = null;
|
||||
|
||||
for (int i = -p_184308_2_; i <= p_184308_2_; ++i)
|
||||
{
|
||||
for (int j = -p_184308_2_; j <= p_184308_2_; ++j)
|
||||
{
|
||||
if (i != 0 || j != 0 || p_184308_3_)
|
||||
{
|
||||
for (int k = 255; k > (blockpos == null ? 0 : blockpos.getY()); --k)
|
||||
{
|
||||
BlockPos blockpos1 = new BlockPos(p_184308_1_.getX() + i, k, p_184308_1_.getZ() + j);
|
||||
IBlockState iblockstate = p_184308_0_.getBlockState(blockpos1);
|
||||
|
||||
if (iblockstate.isBlockNormalCube() && (p_184308_3_ || iblockstate.getBlock() != Blocks.BEDROCK))
|
||||
{
|
||||
blockpos = blockpos1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blockpos == null ? p_184308_1_ : blockpos;
|
||||
}
|
||||
|
||||
private static Chunk getChunk(World worldIn, Vec3d vec3)
|
||||
{
|
||||
return worldIn.getChunkFromChunkCoords(MathHelper.floor(vec3.x / 16.0D), MathHelper.floor(vec3.z / 16.0D));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static BlockPos findSpawnpointInChunk(Chunk chunkIn)
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(chunkIn.x * 16, 30, chunkIn.z * 16);
|
||||
int i = chunkIn.getTopFilledSegment() + 16 - 1;
|
||||
BlockPos blockpos1 = new BlockPos(chunkIn.x * 16 + 16 - 1, i, chunkIn.z * 16 + 16 - 1);
|
||||
BlockPos blockpos2 = null;
|
||||
double d0 = 0.0D;
|
||||
|
||||
for (BlockPos blockpos3 : BlockPos.getAllInBox(blockpos, blockpos1))
|
||||
{
|
||||
IBlockState iblockstate = chunkIn.getBlockState(blockpos3);
|
||||
|
||||
if (iblockstate.getBlock() == Blocks.END_STONE && !chunkIn.getBlockState(blockpos3.up(1)).isBlockNormalCube() && !chunkIn.getBlockState(blockpos3.up(2)).isBlockNormalCube())
|
||||
{
|
||||
double d1 = blockpos3.distanceSqToCenter(0.0D, 0.0D, 0.0D);
|
||||
|
||||
if (blockpos2 == null || d1 < d0)
|
||||
{
|
||||
blockpos2 = blockpos3;
|
||||
d0 = d1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blockpos2;
|
||||
}
|
||||
|
||||
private void createExitPortal(BlockPos posIn)
|
||||
{
|
||||
(new WorldGenEndGateway()).generate(this.world, new Random(), posIn);
|
||||
TileEntity tileentity = this.world.getTileEntity(posIn);
|
||||
|
||||
if (tileentity instanceof TileEntityEndGateway)
|
||||
{
|
||||
TileEntityEndGateway tileentityendgateway = (TileEntityEndGateway)tileentity;
|
||||
tileentityendgateway.exitPortal = new BlockPos(this.getPos());
|
||||
tileentityendgateway.markDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Couldn't save exit portal at {}", (Object)posIn);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean shouldRenderFace(EnumFacing p_184313_1_)
|
||||
{
|
||||
return this.getBlockType().getDefaultState().shouldSideBeRendered(this.world, this.getPos(), p_184313_1_);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public int getParticleAmount()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (EnumFacing enumfacing : EnumFacing.values())
|
||||
{
|
||||
i += this.shouldRenderFace(enumfacing) ? 1 : 0;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public void setExactPosition(BlockPos p_190603_1_)
|
||||
{
|
||||
this.exactTeleport = true;
|
||||
this.exitPortal = p_190603_1_;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntityEndPortal extends TileEntity
|
||||
{
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean shouldRenderFace(EnumFacing p_184313_1_)
|
||||
{
|
||||
return p_184313_1_ == EnumFacing.UP;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
|
||||
public class TileEntityEnderChest extends TileEntity implements ITickable
|
||||
{
|
||||
public float lidAngle;
|
||||
/** The angle of the ender chest lid last tick */
|
||||
public float prevLidAngle;
|
||||
public int numPlayersUsing;
|
||||
private int ticksSinceSync;
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
if (++this.ticksSinceSync % 20 * 4 == 0)
|
||||
{
|
||||
this.world.addBlockEvent(this.pos, Blocks.ENDER_CHEST, 1, this.numPlayersUsing);
|
||||
}
|
||||
|
||||
this.prevLidAngle = this.lidAngle;
|
||||
int i = this.pos.getX();
|
||||
int j = this.pos.getY();
|
||||
int k = this.pos.getZ();
|
||||
float f = 0.1F;
|
||||
|
||||
if (this.numPlayersUsing > 0 && this.lidAngle == 0.0F)
|
||||
{
|
||||
double d0 = (double)i + 0.5D;
|
||||
double d1 = (double)k + 0.5D;
|
||||
this.world.playSound((EntityPlayer)null, d0, (double)j + 0.5D, d1, SoundEvents.BLOCK_ENDERCHEST_OPEN, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
|
||||
}
|
||||
|
||||
if (this.numPlayersUsing == 0 && this.lidAngle > 0.0F || this.numPlayersUsing > 0 && this.lidAngle < 1.0F)
|
||||
{
|
||||
float f2 = this.lidAngle;
|
||||
|
||||
if (this.numPlayersUsing > 0)
|
||||
{
|
||||
this.lidAngle += 0.1F;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.lidAngle -= 0.1F;
|
||||
}
|
||||
|
||||
if (this.lidAngle > 1.0F)
|
||||
{
|
||||
this.lidAngle = 1.0F;
|
||||
}
|
||||
|
||||
float f1 = 0.5F;
|
||||
|
||||
if (this.lidAngle < 0.5F && f2 >= 0.5F)
|
||||
{
|
||||
double d3 = (double)i + 0.5D;
|
||||
double d2 = (double)k + 0.5D;
|
||||
this.world.playSound((EntityPlayer)null, d3, (double)j + 0.5D, d2, SoundEvents.BLOCK_ENDERCHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
|
||||
}
|
||||
|
||||
if (this.lidAngle < 0.0F)
|
||||
{
|
||||
this.lidAngle = 0.0F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean receiveClientEvent(int id, int type)
|
||||
{
|
||||
if (id == 1)
|
||||
{
|
||||
this.numPlayersUsing = type;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.receiveClientEvent(id, type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* invalidates a tile entity
|
||||
*/
|
||||
public void invalidate()
|
||||
{
|
||||
this.updateContainingBlockInfo();
|
||||
super.invalidate();
|
||||
}
|
||||
|
||||
public void openChest()
|
||||
{
|
||||
++this.numPlayersUsing;
|
||||
this.world.addBlockEvent(this.pos, Blocks.ENDER_CHEST, 1, this.numPlayersUsing);
|
||||
}
|
||||
|
||||
public void closeChest()
|
||||
{
|
||||
--this.numPlayersUsing;
|
||||
this.world.addBlockEvent(this.pos, Blocks.ENDER_CHEST, 1, this.numPlayersUsing);
|
||||
}
|
||||
|
||||
public boolean canBeUsed(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
|
||||
public class TileEntityFlowerPot extends TileEntity
|
||||
{
|
||||
private Item flowerPotItem;
|
||||
private int flowerPotData;
|
||||
|
||||
public TileEntityFlowerPot()
|
||||
{
|
||||
}
|
||||
|
||||
public TileEntityFlowerPot(Item potItem, int potData)
|
||||
{
|
||||
this.flowerPotItem = potItem;
|
||||
this.flowerPotData = potData;
|
||||
}
|
||||
|
||||
public static void registerFixesFlowerPot(DataFixer fixer)
|
||||
{
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
ResourceLocation resourcelocation = Item.REGISTRY.getNameForObject(this.flowerPotItem);
|
||||
compound.setString("Item", resourcelocation == null ? "" : resourcelocation.toString());
|
||||
compound.setInteger("Data", this.flowerPotData);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
|
||||
if (compound.hasKey("Item", 8))
|
||||
{
|
||||
this.flowerPotItem = Item.getByNameOrId(compound.getString("Item"));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.flowerPotItem = Item.getItemById(compound.getInteger("Item"));
|
||||
}
|
||||
|
||||
this.flowerPotData = compound.getInteger("Data");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 5, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public void setItemStack(ItemStack stack)
|
||||
{
|
||||
this.flowerPotItem = stack.getItem();
|
||||
this.flowerPotData = stack.getMetadata();
|
||||
}
|
||||
|
||||
public ItemStack getFlowerItemStack()
|
||||
{
|
||||
return this.flowerPotItem == null ? ItemStack.EMPTY : new ItemStack(this.flowerPotItem, 1, this.flowerPotData);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Item getFlowerPotItem()
|
||||
{
|
||||
return this.flowerPotItem;
|
||||
}
|
||||
|
||||
public int getFlowerPotData()
|
||||
{
|
||||
return this.flowerPotData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,610 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockFurnace;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ContainerFurnace;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.ISidedInventory;
|
||||
import net.minecraft.inventory.ItemStackHelper;
|
||||
import net.minecraft.inventory.SlotFurnaceFuel;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBoat;
|
||||
import net.minecraft.item.ItemDoor;
|
||||
import net.minecraft.item.ItemHoe;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemSword;
|
||||
import net.minecraft.item.ItemTool;
|
||||
import net.minecraft.item.crafting.FurnaceRecipes;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntityFurnace extends TileEntityLockable implements ITickable, ISidedInventory
|
||||
{
|
||||
private static final int[] SLOTS_TOP = new int[] {0};
|
||||
private static final int[] SLOTS_BOTTOM = new int[] {2, 1};
|
||||
private static final int[] SLOTS_SIDES = new int[] {1};
|
||||
/** The ItemStacks that hold the items currently being used in the furnace */
|
||||
private NonNullList<ItemStack> furnaceItemStacks = NonNullList.<ItemStack>withSize(3, ItemStack.EMPTY);
|
||||
/** The number of ticks that the furnace will keep burning */
|
||||
private int furnaceBurnTime;
|
||||
/** The number of ticks that a fresh copy of the currently-burning item would keep the furnace burning for */
|
||||
private int currentItemBurnTime;
|
||||
private int cookTime;
|
||||
private int totalCookTime;
|
||||
private String furnaceCustomName;
|
||||
|
||||
/**
|
||||
* Returns the number of slots in the inventory.
|
||||
*/
|
||||
public int getSizeInventory()
|
||||
{
|
||||
return this.furnaceItemStacks.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (ItemStack itemstack : this.furnaceItemStacks)
|
||||
{
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stack in the given slot.
|
||||
*/
|
||||
public ItemStack getStackInSlot(int index)
|
||||
{
|
||||
return this.furnaceItemStacks.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return ItemStackHelper.getAndSplit(this.furnaceItemStacks, index, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a stack from the given slot and returns it.
|
||||
*/
|
||||
public ItemStack removeStackFromSlot(int index)
|
||||
{
|
||||
return ItemStackHelper.getAndRemove(this.furnaceItemStacks, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
ItemStack itemstack = this.furnaceItemStacks.get(index);
|
||||
boolean flag = !stack.isEmpty() && stack.isItemEqual(itemstack) && ItemStack.areItemStackTagsEqual(stack, itemstack);
|
||||
this.furnaceItemStacks.set(index, stack);
|
||||
|
||||
if (stack.getCount() > this.getInventoryStackLimit())
|
||||
{
|
||||
stack.setCount(this.getInventoryStackLimit());
|
||||
}
|
||||
|
||||
if (index == 0 && !flag)
|
||||
{
|
||||
this.totalCookTime = this.getCookTime(stack);
|
||||
this.cookTime = 0;
|
||||
this.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.furnaceCustomName : "container.furnace";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this thing is named
|
||||
*/
|
||||
public boolean hasCustomName()
|
||||
{
|
||||
return this.furnaceCustomName != null && !this.furnaceCustomName.isEmpty();
|
||||
}
|
||||
|
||||
public void setCustomInventoryName(String p_145951_1_)
|
||||
{
|
||||
this.furnaceCustomName = p_145951_1_;
|
||||
}
|
||||
|
||||
public static void registerFixesFurnace(DataFixer fixer)
|
||||
{
|
||||
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityFurnace.class, new String[] {"Items"}));
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.furnaceItemStacks = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
|
||||
ItemStackHelper.loadAllItems(compound, this.furnaceItemStacks);
|
||||
this.furnaceBurnTime = compound.getInteger("BurnTime");
|
||||
this.cookTime = compound.getInteger("CookTime");
|
||||
this.totalCookTime = compound.getInteger("CookTimeTotal");
|
||||
this.currentItemBurnTime = getItemBurnTime(this.furnaceItemStacks.get(1));
|
||||
|
||||
if (compound.hasKey("CustomName", 8))
|
||||
{
|
||||
this.furnaceCustomName = compound.getString("CustomName");
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setInteger("BurnTime", (short)this.furnaceBurnTime);
|
||||
compound.setInteger("CookTime", (short)this.cookTime);
|
||||
compound.setInteger("CookTimeTotal", (short)this.totalCookTime);
|
||||
ItemStackHelper.saveAllItems(compound, this.furnaceItemStacks);
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
compound.setString("CustomName", this.furnaceCustomName);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
|
||||
*/
|
||||
public int getInventoryStackLimit()
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Furnace isBurning
|
||||
*/
|
||||
public boolean isBurning()
|
||||
{
|
||||
return this.furnaceBurnTime > 0;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static boolean isBurning(IInventory inventory)
|
||||
{
|
||||
return inventory.getField(0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
boolean flag = this.isBurning();
|
||||
boolean flag1 = false;
|
||||
|
||||
if (this.isBurning())
|
||||
{
|
||||
--this.furnaceBurnTime;
|
||||
}
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
ItemStack itemstack = this.furnaceItemStacks.get(1);
|
||||
|
||||
if (this.isBurning() || !itemstack.isEmpty() && !((ItemStack)this.furnaceItemStacks.get(0)).isEmpty())
|
||||
{
|
||||
if (!this.isBurning() && this.canSmelt())
|
||||
{
|
||||
this.furnaceBurnTime = getItemBurnTime(itemstack);
|
||||
this.currentItemBurnTime = this.furnaceBurnTime;
|
||||
|
||||
if (this.isBurning())
|
||||
{
|
||||
flag1 = true;
|
||||
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
Item item = itemstack.getItem();
|
||||
itemstack.shrink(1);
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
ItemStack item1 = item.getContainerItem(itemstack);
|
||||
this.furnaceItemStacks.set(1, item1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isBurning() && this.canSmelt())
|
||||
{
|
||||
++this.cookTime;
|
||||
|
||||
if (this.cookTime == this.totalCookTime)
|
||||
{
|
||||
this.cookTime = 0;
|
||||
this.totalCookTime = this.getCookTime(this.furnaceItemStacks.get(0));
|
||||
this.smeltItem();
|
||||
flag1 = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.cookTime = 0;
|
||||
}
|
||||
}
|
||||
else if (!this.isBurning() && this.cookTime > 0)
|
||||
{
|
||||
this.cookTime = MathHelper.clamp(this.cookTime - 2, 0, this.totalCookTime);
|
||||
}
|
||||
|
||||
if (flag != this.isBurning())
|
||||
{
|
||||
flag1 = true;
|
||||
BlockFurnace.setState(this.isBurning(), this.world, this.pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (flag1)
|
||||
{
|
||||
this.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public int getCookTime(ItemStack stack)
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the furnace can smelt an item, i.e. has a source item, destination stack isn't full, etc.
|
||||
*/
|
||||
private boolean canSmelt()
|
||||
{
|
||||
if (((ItemStack)this.furnaceItemStacks.get(0)).isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemStack itemstack = FurnaceRecipes.instance().getSmeltingResult(this.furnaceItemStacks.get(0));
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemStack itemstack1 = this.furnaceItemStacks.get(2);
|
||||
|
||||
if (itemstack1.isEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (!itemstack1.isItemEqual(itemstack))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (itemstack1.getCount() + itemstack.getCount() <= this.getInventoryStackLimit() && itemstack1.getCount() + itemstack.getCount() <= itemstack1.getMaxStackSize()) // Forge fix: make furnace respect stack sizes in furnace recipes
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return itemstack1.getCount() + itemstack.getCount() <= itemstack.getMaxStackSize(); // Forge fix: make furnace respect stack sizes in furnace recipes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn one item from the furnace source stack into the appropriate smelted item in the furnace result stack
|
||||
*/
|
||||
public void smeltItem()
|
||||
{
|
||||
if (this.canSmelt())
|
||||
{
|
||||
ItemStack itemstack = this.furnaceItemStacks.get(0);
|
||||
ItemStack itemstack1 = FurnaceRecipes.instance().getSmeltingResult(itemstack);
|
||||
ItemStack itemstack2 = this.furnaceItemStacks.get(2);
|
||||
|
||||
if (itemstack2.isEmpty())
|
||||
{
|
||||
this.furnaceItemStacks.set(2, itemstack1.copy());
|
||||
}
|
||||
else if (itemstack2.getItem() == itemstack1.getItem())
|
||||
{
|
||||
itemstack2.grow(itemstack1.getCount());
|
||||
}
|
||||
|
||||
if (itemstack.getItem() == Item.getItemFromBlock(Blocks.SPONGE) && itemstack.getMetadata() == 1 && !((ItemStack)this.furnaceItemStacks.get(1)).isEmpty() && ((ItemStack)this.furnaceItemStacks.get(1)).getItem() == Items.BUCKET)
|
||||
{
|
||||
this.furnaceItemStacks.set(1, new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks that the supplied fuel item will keep the furnace burning, or 0 if the item isn't
|
||||
* fuel
|
||||
*/
|
||||
public static int getItemBurnTime(ItemStack stack)
|
||||
{
|
||||
if (stack.isEmpty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int burnTime = net.minecraftforge.event.ForgeEventFactory.getItemBurnTime(stack);
|
||||
if (burnTime >= 0) return burnTime;
|
||||
Item item = stack.getItem();
|
||||
|
||||
if (item == Item.getItemFromBlock(Blocks.WOODEN_SLAB))
|
||||
{
|
||||
return 150;
|
||||
}
|
||||
else if (item == Item.getItemFromBlock(Blocks.WOOL))
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
else if (item == Item.getItemFromBlock(Blocks.CARPET))
|
||||
{
|
||||
return 67;
|
||||
}
|
||||
else if (item == Item.getItemFromBlock(Blocks.LADDER))
|
||||
{
|
||||
return 300;
|
||||
}
|
||||
else if (item == Item.getItemFromBlock(Blocks.WOODEN_BUTTON))
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
else if (Block.getBlockFromItem(item).getDefaultState().getMaterial() == Material.WOOD)
|
||||
{
|
||||
return 300;
|
||||
}
|
||||
else if (item == Item.getItemFromBlock(Blocks.COAL_BLOCK))
|
||||
{
|
||||
return 16000;
|
||||
}
|
||||
else if (item instanceof ItemTool && "WOOD".equals(((ItemTool)item).getToolMaterialName()))
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
else if (item instanceof ItemSword && "WOOD".equals(((ItemSword)item).getToolMaterialName()))
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
else if (item instanceof ItemHoe && "WOOD".equals(((ItemHoe)item).getMaterialName()))
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
else if (item == Items.STICK)
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
else if (item != Items.BOW && item != Items.FISHING_ROD)
|
||||
{
|
||||
if (item == Items.SIGN)
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
else if (item == Items.COAL)
|
||||
{
|
||||
return 1600;
|
||||
}
|
||||
else if (item == Items.LAVA_BUCKET)
|
||||
{
|
||||
return 20000;
|
||||
}
|
||||
else if (item != Item.getItemFromBlock(Blocks.SAPLING) && item != Items.BOWL)
|
||||
{
|
||||
if (item == Items.BLAZE_ROD)
|
||||
{
|
||||
return 2400;
|
||||
}
|
||||
else if (item instanceof ItemDoor && item != Items.IRON_DOOR)
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
else
|
||||
{
|
||||
return item instanceof ItemBoat ? 400 : 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isItemFuel(ItemStack stack)
|
||||
{
|
||||
return getItemBurnTime(stack) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (index == 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (index != 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemStack itemstack = this.furnaceItemStacks.get(1);
|
||||
return isItemFuel(stack) || SlotFurnaceFuel.isBucket(stack) && itemstack.getItem() != Items.BUCKET;
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getSlotsForFace(EnumFacing side)
|
||||
{
|
||||
if (side == EnumFacing.DOWN)
|
||||
{
|
||||
return SLOTS_BOTTOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
return side == EnumFacing.UP ? SLOTS_TOP : SLOTS_SIDES;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 this.isItemValidForSlot(index, itemStackIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (direction == EnumFacing.DOWN && index == 1)
|
||||
{
|
||||
Item item = stack.getItem();
|
||||
|
||||
if (item != Items.WATER_BUCKET && item != Items.BUCKET)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getGuiID()
|
||||
{
|
||||
return "minecraft:furnace";
|
||||
}
|
||||
|
||||
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
||||
{
|
||||
return new ContainerFurnace(playerInventory, this);
|
||||
}
|
||||
|
||||
public int getField(int id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0:
|
||||
return this.furnaceBurnTime;
|
||||
case 1:
|
||||
return this.currentItemBurnTime;
|
||||
case 2:
|
||||
return this.cookTime;
|
||||
case 3:
|
||||
return this.totalCookTime;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void setField(int id, int value)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0:
|
||||
this.furnaceBurnTime = value;
|
||||
break;
|
||||
case 1:
|
||||
this.currentItemBurnTime = value;
|
||||
break;
|
||||
case 2:
|
||||
this.cookTime = value;
|
||||
break;
|
||||
case 3:
|
||||
this.totalCookTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int getFieldCount()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
this.furnaceItemStacks.clear();
|
||||
}
|
||||
|
||||
net.minecraftforge.items.IItemHandler handlerTop = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.UP);
|
||||
net.minecraftforge.items.IItemHandler handlerBottom = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.DOWN);
|
||||
net.minecraftforge.items.IItemHandler handlerSide = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.WEST);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@javax.annotation.Nullable
|
||||
public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @javax.annotation.Nullable net.minecraft.util.EnumFacing facing)
|
||||
{
|
||||
if (facing != null && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
if (facing == EnumFacing.DOWN)
|
||||
return (T) handlerBottom;
|
||||
else if (facing == EnumFacing.UP)
|
||||
return (T) handlerTop;
|
||||
else
|
||||
return (T) handlerSide;
|
||||
return super.getCapability(capability, facing);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,695 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockChest;
|
||||
import net.minecraft.block.BlockHopper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ContainerHopper;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.ISidedInventory;
|
||||
import net.minecraft.inventory.ItemStackHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EntitySelectors;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class TileEntityHopper extends TileEntityLockableLoot implements IHopper, ITickable
|
||||
{
|
||||
private NonNullList<ItemStack> inventory = NonNullList.<ItemStack>withSize(5, ItemStack.EMPTY);
|
||||
private int transferCooldown = -1;
|
||||
private long tickedGameTime;
|
||||
|
||||
public static void registerFixesHopper(DataFixer fixer)
|
||||
{
|
||||
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityHopper.class, new String[] {"Items"}));
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.inventory = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
|
||||
|
||||
if (!this.checkLootAndRead(compound))
|
||||
{
|
||||
ItemStackHelper.loadAllItems(compound, this.inventory);
|
||||
}
|
||||
|
||||
if (compound.hasKey("CustomName", 8))
|
||||
{
|
||||
this.customName = compound.getString("CustomName");
|
||||
}
|
||||
|
||||
this.transferCooldown = compound.getInteger("TransferCooldown");
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
|
||||
if (!this.checkLootAndWrite(compound))
|
||||
{
|
||||
ItemStackHelper.saveAllItems(compound, this.inventory);
|
||||
}
|
||||
|
||||
compound.setInteger("TransferCooldown", this.transferCooldown);
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
compound.setString("CustomName", this.customName);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of slots in the inventory.
|
||||
*/
|
||||
public int getSizeInventory()
|
||||
{
|
||||
return this.inventory.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
this.fillWithLoot((EntityPlayer)null);
|
||||
ItemStack itemstack = ItemStackHelper.getAndSplit(this.getItems(), index, count);
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
this.fillWithLoot((EntityPlayer)null);
|
||||
this.getItems().set(index, stack);
|
||||
|
||||
if (stack.getCount() > this.getInventoryStackLimit())
|
||||
{
|
||||
stack.setCount(this.getInventoryStackLimit());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.customName : "container.hopper";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
|
||||
*/
|
||||
public int getInventoryStackLimit()
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
if (this.world != null && !this.world.isRemote)
|
||||
{
|
||||
--this.transferCooldown;
|
||||
this.tickedGameTime = this.world.getTotalWorldTime();
|
||||
|
||||
if (!this.isOnTransferCooldown())
|
||||
{
|
||||
this.setTransferCooldown(0);
|
||||
this.updateHopper();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean updateHopper()
|
||||
{
|
||||
if (this.world != null && !this.world.isRemote)
|
||||
{
|
||||
if (!this.isOnTransferCooldown() && BlockHopper.isEnabled(this.getBlockMetadata()))
|
||||
{
|
||||
boolean flag = false;
|
||||
|
||||
if (!this.isInventoryEmpty())
|
||||
{
|
||||
flag = this.transferItemsOut();
|
||||
}
|
||||
|
||||
if (!this.isFull())
|
||||
{
|
||||
flag = pullItems(this) || flag;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
this.setTransferCooldown(8);
|
||||
this.markDirty();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInventoryEmpty()
|
||||
{
|
||||
for (ItemStack itemstack : this.inventory)
|
||||
{
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return this.isInventoryEmpty();
|
||||
}
|
||||
|
||||
private boolean isFull()
|
||||
{
|
||||
for (ItemStack itemstack : this.inventory)
|
||||
{
|
||||
if (itemstack.isEmpty() || itemstack.getCount() != itemstack.getMaxStackSize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean transferItemsOut()
|
||||
{
|
||||
if (net.minecraftforge.items.VanillaInventoryCodeHooks.insertHook(this)) { return true; }
|
||||
IInventory iinventory = this.getInventoryForHopperTransfer();
|
||||
|
||||
if (iinventory == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EnumFacing enumfacing = BlockHopper.getFacing(this.getBlockMetadata()).getOpposite();
|
||||
|
||||
if (this.isInventoryFull(iinventory, enumfacing))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < this.getSizeInventory(); ++i)
|
||||
{
|
||||
if (!this.getStackInSlot(i).isEmpty())
|
||||
{
|
||||
ItemStack itemstack = this.getStackInSlot(i).copy();
|
||||
ItemStack itemstack1 = putStackInInventoryAllSlots(this, iinventory, this.decrStackSize(i, 1), enumfacing);
|
||||
|
||||
if (itemstack1.isEmpty())
|
||||
{
|
||||
iinventory.markDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
this.setInventorySlotContents(i, itemstack);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if the inventory has any room to place items in
|
||||
*/
|
||||
private boolean isInventoryFull(IInventory inventoryIn, EnumFacing side)
|
||||
{
|
||||
if (inventoryIn instanceof ISidedInventory)
|
||||
{
|
||||
ISidedInventory isidedinventory = (ISidedInventory)inventoryIn;
|
||||
int[] aint = isidedinventory.getSlotsForFace(side);
|
||||
|
||||
for (int k : aint)
|
||||
{
|
||||
ItemStack itemstack1 = isidedinventory.getStackInSlot(k);
|
||||
|
||||
if (itemstack1.isEmpty() || itemstack1.getCount() != itemstack1.getMaxStackSize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = inventoryIn.getSizeInventory();
|
||||
|
||||
for (int j = 0; j < i; ++j)
|
||||
{
|
||||
ItemStack itemstack = inventoryIn.getStackInSlot(j);
|
||||
|
||||
if (itemstack.isEmpty() || itemstack.getCount() != itemstack.getMaxStackSize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if the specified IInventory contains any items
|
||||
*/
|
||||
private static boolean isInventoryEmpty(IInventory inventoryIn, EnumFacing side)
|
||||
{
|
||||
if (inventoryIn instanceof ISidedInventory)
|
||||
{
|
||||
ISidedInventory isidedinventory = (ISidedInventory)inventoryIn;
|
||||
int[] aint = isidedinventory.getSlotsForFace(side);
|
||||
|
||||
for (int i : aint)
|
||||
{
|
||||
if (!isidedinventory.getStackInSlot(i).isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int j = inventoryIn.getSizeInventory();
|
||||
|
||||
for (int k = 0; k < j; ++k)
|
||||
{
|
||||
if (!inventoryIn.getStackInSlot(k).isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull dropped {@link net.minecraft.entity.item.EntityItem EntityItem}s from the world above the hopper and items
|
||||
* from any inventory attached to this hopper into the hopper's inventory.
|
||||
*
|
||||
* @param hopper the hopper in question
|
||||
* @return whether any items were successfully added to the hopper
|
||||
*/
|
||||
public static boolean pullItems(IHopper hopper)
|
||||
{
|
||||
Boolean ret = net.minecraftforge.items.VanillaInventoryCodeHooks.extractHook(hopper);
|
||||
if (ret != null) return ret;
|
||||
IInventory iinventory = getSourceInventory(hopper);
|
||||
|
||||
if (iinventory != null)
|
||||
{
|
||||
EnumFacing enumfacing = EnumFacing.DOWN;
|
||||
|
||||
if (isInventoryEmpty(iinventory, enumfacing))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iinventory instanceof ISidedInventory)
|
||||
{
|
||||
ISidedInventory isidedinventory = (ISidedInventory)iinventory;
|
||||
int[] aint = isidedinventory.getSlotsForFace(enumfacing);
|
||||
|
||||
for (int i : aint)
|
||||
{
|
||||
if (pullItemFromSlot(hopper, iinventory, i, enumfacing))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int j = iinventory.getSizeInventory();
|
||||
|
||||
for (int k = 0; k < j; ++k)
|
||||
{
|
||||
if (pullItemFromSlot(hopper, iinventory, k, enumfacing))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (EntityItem entityitem : getCaptureItems(hopper.getWorld(), hopper.getXPos(), hopper.getYPos(), hopper.getZPos()))
|
||||
{
|
||||
if (putDropInInventoryAllSlots((IInventory)null, hopper, entityitem))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls from the specified slot in the inventory and places in any available slot in the hopper. Returns true if
|
||||
* the entire stack was moved
|
||||
*/
|
||||
private static boolean pullItemFromSlot(IHopper hopper, IInventory inventoryIn, int index, EnumFacing direction)
|
||||
{
|
||||
ItemStack itemstack = inventoryIn.getStackInSlot(index);
|
||||
|
||||
if (!itemstack.isEmpty() && canExtractItemFromSlot(inventoryIn, itemstack, index, direction))
|
||||
{
|
||||
ItemStack itemstack1 = itemstack.copy();
|
||||
ItemStack itemstack2 = putStackInInventoryAllSlots(inventoryIn, hopper, inventoryIn.decrStackSize(index, 1), (EnumFacing)null);
|
||||
|
||||
if (itemstack2.isEmpty())
|
||||
{
|
||||
inventoryIn.markDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
inventoryIn.setInventorySlotContents(index, itemstack1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to place the passed EntityItem's stack into the inventory using as many slots as possible. Returns false
|
||||
* if the stackSize of the drop was not depleted.
|
||||
*/
|
||||
public static boolean putDropInInventoryAllSlots(IInventory source, IInventory destination, EntityItem entity)
|
||||
{
|
||||
boolean flag = false;
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemStack itemstack = entity.getItem().copy();
|
||||
ItemStack itemstack1 = putStackInInventoryAllSlots(source, destination, itemstack, (EnumFacing)null);
|
||||
|
||||
if (itemstack1.isEmpty())
|
||||
{
|
||||
flag = true;
|
||||
entity.setDead();
|
||||
}
|
||||
else
|
||||
{
|
||||
entity.setItem(itemstack1);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected net.minecraftforge.items.IItemHandler createUnSidedHandler()
|
||||
{
|
||||
return new net.minecraftforge.items.VanillaHopperItemHandler(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to place the passed stack in the inventory, using as many slots as required. Returns leftover items
|
||||
*/
|
||||
public static ItemStack putStackInInventoryAllSlots(IInventory source, IInventory destination, ItemStack stack, @Nullable EnumFacing direction)
|
||||
{
|
||||
if (destination instanceof ISidedInventory && direction != null)
|
||||
{
|
||||
ISidedInventory isidedinventory = (ISidedInventory)destination;
|
||||
int[] aint = isidedinventory.getSlotsForFace(direction);
|
||||
|
||||
for (int k = 0; k < aint.length && !stack.isEmpty(); ++k)
|
||||
{
|
||||
stack = insertStack(source, destination, stack, aint[k], direction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = destination.getSizeInventory();
|
||||
|
||||
for (int j = 0; j < i && !stack.isEmpty(); ++j)
|
||||
{
|
||||
stack = insertStack(source, destination, stack, j, direction);
|
||||
}
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can this hopper insert the specified item from the specified slot on the specified side?
|
||||
*/
|
||||
private static boolean canInsertItemInSlot(IInventory inventoryIn, ItemStack stack, int index, EnumFacing side)
|
||||
{
|
||||
if (!inventoryIn.isItemValidForSlot(index, stack))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return !(inventoryIn instanceof ISidedInventory) || ((ISidedInventory)inventoryIn).canInsertItem(index, stack, side);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can this hopper extract the specified item from the specified slot on the specified side?
|
||||
*/
|
||||
private static boolean canExtractItemFromSlot(IInventory inventoryIn, ItemStack stack, int index, EnumFacing side)
|
||||
{
|
||||
return !(inventoryIn instanceof ISidedInventory) || ((ISidedInventory)inventoryIn).canExtractItem(index, stack, side);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the specified stack to the specified inventory and return any leftover items
|
||||
*/
|
||||
private static ItemStack insertStack(IInventory source, IInventory destination, ItemStack stack, int index, EnumFacing direction)
|
||||
{
|
||||
ItemStack itemstack = destination.getStackInSlot(index);
|
||||
|
||||
if (canInsertItemInSlot(destination, stack, index, direction))
|
||||
{
|
||||
boolean flag = false;
|
||||
boolean flag1 = destination.isEmpty();
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
destination.setInventorySlotContents(index, stack);
|
||||
stack = ItemStack.EMPTY;
|
||||
flag = true;
|
||||
}
|
||||
else if (canCombine(itemstack, stack))
|
||||
{
|
||||
int i = stack.getMaxStackSize() - itemstack.getCount();
|
||||
int j = Math.min(stack.getCount(), i);
|
||||
stack.shrink(j);
|
||||
itemstack.grow(j);
|
||||
flag = j > 0;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
if (flag1 && destination instanceof TileEntityHopper)
|
||||
{
|
||||
TileEntityHopper tileentityhopper1 = (TileEntityHopper)destination;
|
||||
|
||||
if (!tileentityhopper1.mayTransfer())
|
||||
{
|
||||
int k = 0;
|
||||
|
||||
if (source != null && source instanceof TileEntityHopper)
|
||||
{
|
||||
TileEntityHopper tileentityhopper = (TileEntityHopper)source;
|
||||
|
||||
if (tileentityhopper1.tickedGameTime >= tileentityhopper.tickedGameTime)
|
||||
{
|
||||
k = 1;
|
||||
}
|
||||
}
|
||||
|
||||
tileentityhopper1.setTransferCooldown(8 - k);
|
||||
}
|
||||
}
|
||||
|
||||
destination.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IInventory that this hopper is pointing into
|
||||
*/
|
||||
private IInventory getInventoryForHopperTransfer()
|
||||
{
|
||||
EnumFacing enumfacing = BlockHopper.getFacing(this.getBlockMetadata());
|
||||
return getInventoryAtPosition(this.getWorld(), this.getXPos() + (double)enumfacing.getFrontOffsetX(), this.getYPos() + (double)enumfacing.getFrontOffsetY(), this.getZPos() + (double)enumfacing.getFrontOffsetZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the inventory that the provided hopper will transfer items from.
|
||||
*/
|
||||
public static IInventory getSourceInventory(IHopper hopper)
|
||||
{
|
||||
return getInventoryAtPosition(hopper.getWorld(), hopper.getXPos(), hopper.getYPos() + 1.0D, hopper.getZPos());
|
||||
}
|
||||
|
||||
public static List<EntityItem> getCaptureItems(World worldIn, double p_184292_1_, double p_184292_3_, double p_184292_5_)
|
||||
{
|
||||
return worldIn.<EntityItem>getEntitiesWithinAABB(EntityItem.class, new AxisAlignedBB(p_184292_1_ - 0.5D, p_184292_3_, p_184292_5_ - 0.5D, p_184292_1_ + 0.5D, p_184292_3_ + 1.5D, p_184292_5_ + 0.5D), EntitySelectors.IS_ALIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IInventory (if applicable) of the TileEntity at the specified position
|
||||
*/
|
||||
public static IInventory getInventoryAtPosition(World worldIn, double x, double y, double z)
|
||||
{
|
||||
IInventory iinventory = null;
|
||||
int i = MathHelper.floor(x);
|
||||
int j = MathHelper.floor(y);
|
||||
int k = MathHelper.floor(z);
|
||||
BlockPos blockpos = new BlockPos(i, j, k);
|
||||
net.minecraft.block.state.IBlockState state = worldIn.getBlockState(blockpos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (block.hasTileEntity(state))
|
||||
{
|
||||
TileEntity tileentity = worldIn.getTileEntity(blockpos);
|
||||
|
||||
if (tileentity instanceof IInventory)
|
||||
{
|
||||
iinventory = (IInventory)tileentity;
|
||||
|
||||
if (iinventory instanceof TileEntityChest && block instanceof BlockChest)
|
||||
{
|
||||
iinventory = ((BlockChest)block).getContainer(worldIn, blockpos, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iinventory == null)
|
||||
{
|
||||
List<Entity> list = worldIn.getEntitiesInAABBexcluding((Entity)null, new AxisAlignedBB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelectors.HAS_INVENTORY);
|
||||
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
iinventory = (IInventory)list.get(worldIn.rand.nextInt(list.size()));
|
||||
}
|
||||
}
|
||||
|
||||
return iinventory;
|
||||
}
|
||||
|
||||
private static boolean canCombine(ItemStack stack1, ItemStack stack2)
|
||||
{
|
||||
if (stack1.getItem() != stack2.getItem())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (stack1.getMetadata() != stack2.getMetadata())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (stack1.getCount() > stack1.getMaxStackSize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ItemStack.areItemStackTagsEqual(stack1, stack2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world X position for this hopper entity.
|
||||
*/
|
||||
public double getXPos()
|
||||
{
|
||||
return (double)this.pos.getX() + 0.5D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world Y position for this hopper entity.
|
||||
*/
|
||||
public double getYPos()
|
||||
{
|
||||
return (double)this.pos.getY() + 0.5D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world Z position for this hopper entity.
|
||||
*/
|
||||
public double getZPos()
|
||||
{
|
||||
return (double)this.pos.getZ() + 0.5D;
|
||||
}
|
||||
|
||||
public void setTransferCooldown(int ticks)
|
||||
{
|
||||
this.transferCooldown = ticks;
|
||||
}
|
||||
|
||||
private boolean isOnTransferCooldown()
|
||||
{
|
||||
return this.transferCooldown > 0;
|
||||
}
|
||||
|
||||
public boolean mayTransfer()
|
||||
{
|
||||
return this.transferCooldown > 8;
|
||||
}
|
||||
|
||||
public String getGuiID()
|
||||
{
|
||||
return "minecraft:hopper";
|
||||
}
|
||||
|
||||
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
||||
{
|
||||
this.fillWithLoot(playerIn);
|
||||
return new ContainerHopper(playerInventory, this, playerIn);
|
||||
}
|
||||
|
||||
protected NonNullList<ItemStack> getItems()
|
||||
{
|
||||
return this.inventory;
|
||||
}
|
||||
|
||||
public long getLastUpdateTime() { return tickedGameTime; } // Forge
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.ILockableContainer;
|
||||
import net.minecraft.world.LockCode;
|
||||
|
||||
public abstract class TileEntityLockable extends TileEntity implements ILockableContainer
|
||||
{
|
||||
private LockCode code = LockCode.EMPTY_CODE;
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.code = LockCode.fromNBT(compound);
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
|
||||
if (this.code != null)
|
||||
{
|
||||
this.code.toNBT(compound);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public boolean isLocked()
|
||||
{
|
||||
return this.code != null && !this.code.isEmpty();
|
||||
}
|
||||
|
||||
public LockCode getLockCode()
|
||||
{
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public void setLockCode(LockCode code)
|
||||
{
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted ChatComponent that will be used for the sender's username in chat
|
||||
*/
|
||||
public ITextComponent getDisplayName()
|
||||
{
|
||||
return (ITextComponent)(this.hasCustomName() ? new TextComponentString(this.getName()) : new TextComponentTranslation(this.getName(), new Object[0]));
|
||||
}
|
||||
|
||||
private net.minecraftforge.items.IItemHandler itemHandler;
|
||||
|
||||
protected net.minecraftforge.items.IItemHandler createUnSidedHandler()
|
||||
{
|
||||
return new net.minecraftforge.items.wrapper.InvWrapper(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
@javax.annotation.Nullable
|
||||
public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @javax.annotation.Nullable net.minecraft.util.EnumFacing facing)
|
||||
{
|
||||
if (capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
return (T) (itemHandler == null ? (itemHandler = createUnSidedHandler()) : itemHandler);
|
||||
return super.getCapability(capability, facing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, @javax.annotation.Nullable net.minecraft.util.EnumFacing facing)
|
||||
{
|
||||
return capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || super.hasCapability(capability, facing);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import java.util.Random;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.ItemStackHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.storage.loot.ILootContainer;
|
||||
import net.minecraft.world.storage.loot.LootContext;
|
||||
import net.minecraft.world.storage.loot.LootTable;
|
||||
|
||||
public abstract class TileEntityLockableLoot extends TileEntityLockable implements ILootContainer
|
||||
{
|
||||
protected ResourceLocation lootTable;
|
||||
protected long lootTableSeed;
|
||||
protected String customName;
|
||||
|
||||
protected boolean checkLootAndRead(NBTTagCompound compound)
|
||||
{
|
||||
if (compound.hasKey("LootTable", 8))
|
||||
{
|
||||
this.lootTable = new ResourceLocation(compound.getString("LootTable"));
|
||||
this.lootTableSeed = compound.getLong("LootTableSeed");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean checkLootAndWrite(NBTTagCompound compound)
|
||||
{
|
||||
if (this.lootTable != null)
|
||||
{
|
||||
compound.setString("LootTable", this.lootTable.toString());
|
||||
|
||||
if (this.lootTableSeed != 0L)
|
||||
{
|
||||
compound.setLong("LootTableSeed", this.lootTableSeed);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void fillWithLoot(@Nullable EntityPlayer player)
|
||||
{
|
||||
if (this.lootTable != null)
|
||||
{
|
||||
LootTable loottable = this.world.getLootTableManager().getLootTableFromLocation(this.lootTable);
|
||||
this.lootTable = null;
|
||||
Random random;
|
||||
|
||||
if (this.lootTableSeed == 0L)
|
||||
{
|
||||
random = new Random();
|
||||
}
|
||||
else
|
||||
{
|
||||
random = new Random(this.lootTableSeed);
|
||||
}
|
||||
|
||||
LootContext.Builder lootcontext$builder = new LootContext.Builder((WorldServer)this.world);
|
||||
|
||||
if (player != null)
|
||||
{
|
||||
lootcontext$builder.withLuck(player.getLuck()).withPlayer(player); // Forge: add player to LootContext
|
||||
}
|
||||
|
||||
loottable.fillInventory(this, random, lootcontext$builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceLocation getLootTable()
|
||||
{
|
||||
return this.lootTable;
|
||||
}
|
||||
|
||||
public void setLootTable(ResourceLocation p_189404_1_, long p_189404_2_)
|
||||
{
|
||||
this.lootTable = p_189404_1_;
|
||||
this.lootTableSeed = p_189404_2_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this thing is named
|
||||
*/
|
||||
public boolean hasCustomName()
|
||||
{
|
||||
return this.customName != null && !this.customName.isEmpty();
|
||||
}
|
||||
|
||||
public void setCustomName(String p_190575_1_)
|
||||
{
|
||||
this.customName = p_190575_1_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stack in the given slot.
|
||||
*/
|
||||
public ItemStack getStackInSlot(int index)
|
||||
{
|
||||
this.fillWithLoot((EntityPlayer)null);
|
||||
return (ItemStack)this.getItems().get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
this.fillWithLoot((EntityPlayer)null);
|
||||
ItemStack itemstack = ItemStackHelper.getAndSplit(this.getItems(), index, count);
|
||||
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a stack from the given slot and returns it.
|
||||
*/
|
||||
public ItemStack removeStackFromSlot(int index)
|
||||
{
|
||||
this.fillWithLoot((EntityPlayer)null);
|
||||
return ItemStackHelper.getAndRemove(this.getItems(), index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
|
||||
*/
|
||||
public void setInventorySlotContents(int index, @Nullable ItemStack stack)
|
||||
{
|
||||
this.fillWithLoot((EntityPlayer)null);
|
||||
this.getItems().set(index, stack);
|
||||
|
||||
if (stack.getCount() > this.getInventoryStackLimit())
|
||||
{
|
||||
stack.setCount(this.getInventoryStackLimit());
|
||||
}
|
||||
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 true;
|
||||
}
|
||||
|
||||
public int getField(int id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setField(int id, int value)
|
||||
{
|
||||
}
|
||||
|
||||
public int getFieldCount()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
this.fillWithLoot((EntityPlayer)null);
|
||||
this.getItems().clear();
|
||||
}
|
||||
|
||||
protected abstract NonNullList<ItemStack> getItems();
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.WeightedSpawnerEntity;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.IDataFixer;
|
||||
import net.minecraft.util.datafix.IDataWalker;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class TileEntityMobSpawner extends TileEntity implements ITickable
|
||||
{
|
||||
private final MobSpawnerBaseLogic spawnerLogic = new MobSpawnerBaseLogic()
|
||||
{
|
||||
public void broadcastEvent(int id)
|
||||
{
|
||||
TileEntityMobSpawner.this.world.addBlockEvent(TileEntityMobSpawner.this.pos, Blocks.MOB_SPAWNER, id, 0);
|
||||
}
|
||||
public World getSpawnerWorld()
|
||||
{
|
||||
return TileEntityMobSpawner.this.world;
|
||||
}
|
||||
public BlockPos getSpawnerPosition()
|
||||
{
|
||||
return TileEntityMobSpawner.this.pos;
|
||||
}
|
||||
public void setNextSpawnData(WeightedSpawnerEntity p_184993_1_)
|
||||
{
|
||||
super.setNextSpawnData(p_184993_1_);
|
||||
|
||||
if (this.getSpawnerWorld() != null)
|
||||
{
|
||||
IBlockState iblockstate = this.getSpawnerWorld().getBlockState(this.getSpawnerPosition());
|
||||
this.getSpawnerWorld().notifyBlockUpdate(TileEntityMobSpawner.this.pos, iblockstate, iblockstate, 4);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static void registerFixesMobSpawner(DataFixer fixer)
|
||||
{
|
||||
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new IDataWalker()
|
||||
{
|
||||
public NBTTagCompound process(IDataFixer fixer, NBTTagCompound compound, int versionIn)
|
||||
{
|
||||
if (TileEntity.getKey(TileEntityMobSpawner.class).equals(new ResourceLocation(compound.getString("id"))))
|
||||
{
|
||||
if (compound.hasKey("SpawnPotentials", 9))
|
||||
{
|
||||
NBTTagList nbttaglist = compound.getTagList("SpawnPotentials", 10);
|
||||
|
||||
for (int i = 0; i < nbttaglist.tagCount(); ++i)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i);
|
||||
nbttagcompound.setTag("Entity", fixer.process(FixTypes.ENTITY, nbttagcompound.getCompoundTag("Entity"), versionIn));
|
||||
}
|
||||
}
|
||||
|
||||
compound.setTag("SpawnData", fixer.process(FixTypes.ENTITY, compound.getCompoundTag("SpawnData"), versionIn));
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.spawnerLogic.readFromNBT(compound);
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
this.spawnerLogic.writeToNBT(compound);
|
||||
return compound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
this.spawnerLogic.updateSpawner();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 1, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
NBTTagCompound nbttagcompound = this.writeToNBT(new NBTTagCompound());
|
||||
nbttagcompound.removeTag("SpawnPotentials");
|
||||
return nbttagcompound;
|
||||
}
|
||||
|
||||
public boolean receiveClientEvent(int id, int type)
|
||||
{
|
||||
return this.spawnerLogic.setDelayToMin(id) ? true : super.receiveClientEvent(id, type);
|
||||
}
|
||||
|
||||
public boolean onlyOpsCanSetNbt()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public MobSpawnerBaseLogic getSpawnerBaseLogic()
|
||||
{
|
||||
return this.spawnerLogic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class TileEntityNote extends TileEntity
|
||||
{
|
||||
/** Note to play */
|
||||
public byte note;
|
||||
/** stores the latest redstone state */
|
||||
public boolean previousRedstoneState;
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setByte("note", this.note);
|
||||
compound.setBoolean("powered", this.previousRedstoneState);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.note = compound.getByte("note");
|
||||
this.note = (byte)MathHelper.clamp(this.note, 0, 24);
|
||||
this.previousRedstoneState = compound.getBoolean("powered");
|
||||
}
|
||||
|
||||
/**
|
||||
* change pitch by -> (currentPitch + 1) % 25
|
||||
*/
|
||||
public void changePitch()
|
||||
{
|
||||
byte old = note;
|
||||
this.note = (byte)((this.note + 1) % 25);
|
||||
if (!net.minecraftforge.common.ForgeHooks.onNoteChange(this, old)) return;
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
public void triggerNote(World worldIn, BlockPos posIn)
|
||||
{
|
||||
if (worldIn.getBlockState(posIn.up()).getMaterial() == Material.AIR)
|
||||
{
|
||||
IBlockState iblockstate = worldIn.getBlockState(posIn.down());
|
||||
Material material = iblockstate.getMaterial();
|
||||
int i = 0;
|
||||
|
||||
if (material == Material.ROCK)
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
|
||||
if (material == Material.SAND)
|
||||
{
|
||||
i = 2;
|
||||
}
|
||||
|
||||
if (material == Material.GLASS)
|
||||
{
|
||||
i = 3;
|
||||
}
|
||||
|
||||
if (material == Material.WOOD)
|
||||
{
|
||||
i = 4;
|
||||
}
|
||||
|
||||
Block block = iblockstate.getBlock();
|
||||
|
||||
if (block == Blocks.CLAY)
|
||||
{
|
||||
i = 5;
|
||||
}
|
||||
|
||||
if (block == Blocks.GOLD_BLOCK)
|
||||
{
|
||||
i = 6;
|
||||
}
|
||||
|
||||
if (block == Blocks.WOOL)
|
||||
{
|
||||
i = 7;
|
||||
}
|
||||
|
||||
if (block == Blocks.PACKED_ICE)
|
||||
{
|
||||
i = 8;
|
||||
}
|
||||
|
||||
if (block == Blocks.BONE_BLOCK)
|
||||
{
|
||||
i = 9;
|
||||
}
|
||||
|
||||
worldIn.addBlockEvent(posIn, Blocks.NOTEBLOCK, i, this.note);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockPistonBase;
|
||||
import net.minecraft.block.BlockPistonExtension;
|
||||
import net.minecraft.block.material.EnumPushReaction;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.MoverType;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntityPiston extends TileEntity implements ITickable
|
||||
{
|
||||
private IBlockState pistonState;
|
||||
private EnumFacing pistonFacing;
|
||||
/** if this piston is extending or not */
|
||||
private boolean extending;
|
||||
private boolean shouldHeadBeRendered;
|
||||
private static final ThreadLocal<EnumFacing> MOVING_ENTITY = new ThreadLocal<EnumFacing>()
|
||||
{
|
||||
protected EnumFacing initialValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
private float progress;
|
||||
/** the progress in (de)extending */
|
||||
private float lastProgress;
|
||||
|
||||
public TileEntityPiston()
|
||||
{
|
||||
}
|
||||
|
||||
public TileEntityPiston(IBlockState pistonStateIn, EnumFacing pistonFacingIn, boolean extendingIn, boolean shouldHeadBeRenderedIn)
|
||||
{
|
||||
this.pistonState = pistonStateIn;
|
||||
this.pistonFacing = pistonFacingIn;
|
||||
this.extending = extendingIn;
|
||||
this.shouldHeadBeRendered = shouldHeadBeRenderedIn;
|
||||
}
|
||||
|
||||
public IBlockState getPistonState()
|
||||
{
|
||||
return this.pistonState;
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public int getBlockMetadata()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a piston is extending
|
||||
*/
|
||||
public boolean isExtending()
|
||||
{
|
||||
return this.extending;
|
||||
}
|
||||
|
||||
public EnumFacing getFacing()
|
||||
{
|
||||
return this.pistonFacing;
|
||||
}
|
||||
|
||||
public boolean shouldPistonHeadBeRendered()
|
||||
{
|
||||
return this.shouldHeadBeRendered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interpolated progress value (between lastProgress and progress) given the fractional time between ticks as an
|
||||
* argument
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getProgress(float ticks)
|
||||
{
|
||||
if (ticks > 1.0F)
|
||||
{
|
||||
ticks = 1.0F;
|
||||
}
|
||||
|
||||
return this.lastProgress + (this.progress - this.lastProgress) * ticks;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getOffsetX(float ticks)
|
||||
{
|
||||
return (float)this.pistonFacing.getFrontOffsetX() * this.getExtendedProgress(this.getProgress(ticks));
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getOffsetY(float ticks)
|
||||
{
|
||||
return (float)this.pistonFacing.getFrontOffsetY() * this.getExtendedProgress(this.getProgress(ticks));
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getOffsetZ(float ticks)
|
||||
{
|
||||
return (float)this.pistonFacing.getFrontOffsetZ() * this.getExtendedProgress(this.getProgress(ticks));
|
||||
}
|
||||
|
||||
private float getExtendedProgress(float p_184320_1_)
|
||||
{
|
||||
return this.extending ? p_184320_1_ - 1.0F : 1.0F - p_184320_1_;
|
||||
}
|
||||
|
||||
public AxisAlignedBB getAABB(IBlockAccess p_184321_1_, BlockPos p_184321_2_)
|
||||
{
|
||||
return this.getAABB(p_184321_1_, p_184321_2_, this.progress).union(this.getAABB(p_184321_1_, p_184321_2_, this.lastProgress));
|
||||
}
|
||||
|
||||
public AxisAlignedBB getAABB(IBlockAccess p_184319_1_, BlockPos p_184319_2_, float p_184319_3_)
|
||||
{
|
||||
p_184319_3_ = this.getExtendedProgress(p_184319_3_);
|
||||
IBlockState iblockstate = this.getCollisionRelatedBlockState();
|
||||
return iblockstate.getBoundingBox(p_184319_1_, p_184319_2_).offset((double)(p_184319_3_ * (float)this.pistonFacing.getFrontOffsetX()), (double)(p_184319_3_ * (float)this.pistonFacing.getFrontOffsetY()), (double)(p_184319_3_ * (float)this.pistonFacing.getFrontOffsetZ()));
|
||||
}
|
||||
|
||||
private IBlockState getCollisionRelatedBlockState()
|
||||
{
|
||||
return !this.isExtending() && this.shouldPistonHeadBeRendered() ? Blocks.PISTON_HEAD.getDefaultState().withProperty(BlockPistonExtension.TYPE, this.pistonState.getBlock() == Blocks.STICKY_PISTON ? BlockPistonExtension.EnumPistonType.STICKY : BlockPistonExtension.EnumPistonType.DEFAULT).withProperty(BlockPistonExtension.FACING, this.pistonState.getValue(BlockPistonBase.FACING)) : this.pistonState;
|
||||
}
|
||||
|
||||
private void moveCollidedEntities(float p_184322_1_)
|
||||
{
|
||||
EnumFacing enumfacing = this.extending ? this.pistonFacing : this.pistonFacing.getOpposite();
|
||||
double d0 = (double)(p_184322_1_ - this.progress);
|
||||
List<AxisAlignedBB> list = Lists.<AxisAlignedBB>newArrayList();
|
||||
this.getCollisionRelatedBlockState().addCollisionBoxToList(this.world, BlockPos.ORIGIN, new AxisAlignedBB(BlockPos.ORIGIN), list, (Entity)null, true);
|
||||
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
AxisAlignedBB axisalignedbb = this.moveByPositionAndProgress(this.getMinMaxPiecesAABB(list));
|
||||
List<Entity> list1 = this.world.getEntitiesWithinAABBExcludingEntity((Entity)null, this.getMovementArea(axisalignedbb, enumfacing, d0).union(axisalignedbb));
|
||||
|
||||
if (!list1.isEmpty())
|
||||
{
|
||||
boolean flag = this.pistonState.getBlock().isStickyBlock(this.pistonState);
|
||||
|
||||
for (int i = 0; i < list1.size(); ++i)
|
||||
{
|
||||
Entity entity = list1.get(i);
|
||||
|
||||
if (entity.getPushReaction() != EnumPushReaction.IGNORE)
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
switch (enumfacing.getAxis())
|
||||
{
|
||||
case X:
|
||||
entity.motionX = (double)enumfacing.getFrontOffsetX();
|
||||
break;
|
||||
case Y:
|
||||
entity.motionY = (double)enumfacing.getFrontOffsetY();
|
||||
break;
|
||||
case Z:
|
||||
entity.motionZ = (double)enumfacing.getFrontOffsetZ();
|
||||
}
|
||||
}
|
||||
|
||||
double d1 = 0.0D;
|
||||
|
||||
for (int j = 0; j < list.size(); ++j)
|
||||
{
|
||||
AxisAlignedBB axisalignedbb1 = this.getMovementArea(this.moveByPositionAndProgress(list.get(j)), enumfacing, d0);
|
||||
AxisAlignedBB axisalignedbb2 = entity.getEntityBoundingBox();
|
||||
|
||||
if (axisalignedbb1.intersects(axisalignedbb2))
|
||||
{
|
||||
d1 = Math.max(d1, this.getMovement(axisalignedbb1, enumfacing, axisalignedbb2));
|
||||
|
||||
if (d1 >= d0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (d1 > 0.0D)
|
||||
{
|
||||
d1 = Math.min(d1, d0) + 0.01D;
|
||||
MOVING_ENTITY.set(enumfacing);
|
||||
entity.move(MoverType.PISTON, d1 * (double)enumfacing.getFrontOffsetX(), d1 * (double)enumfacing.getFrontOffsetY(), d1 * (double)enumfacing.getFrontOffsetZ());
|
||||
MOVING_ENTITY.set(null);
|
||||
|
||||
if (!this.extending && this.shouldHeadBeRendered)
|
||||
{
|
||||
this.fixEntityWithinPistonBase(entity, enumfacing, d0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AxisAlignedBB getMinMaxPiecesAABB(List<AxisAlignedBB> p_191515_1_)
|
||||
{
|
||||
double d0 = 0.0D;
|
||||
double d1 = 0.0D;
|
||||
double d2 = 0.0D;
|
||||
double d3 = 1.0D;
|
||||
double d4 = 1.0D;
|
||||
double d5 = 1.0D;
|
||||
|
||||
for (AxisAlignedBB axisalignedbb : p_191515_1_)
|
||||
{
|
||||
d0 = Math.min(axisalignedbb.minX, d0);
|
||||
d1 = Math.min(axisalignedbb.minY, d1);
|
||||
d2 = Math.min(axisalignedbb.minZ, d2);
|
||||
d3 = Math.max(axisalignedbb.maxX, d3);
|
||||
d4 = Math.max(axisalignedbb.maxY, d4);
|
||||
d5 = Math.max(axisalignedbb.maxZ, d5);
|
||||
}
|
||||
|
||||
return new AxisAlignedBB(d0, d1, d2, d3, d4, d5);
|
||||
}
|
||||
|
||||
private double getMovement(AxisAlignedBB p_190612_1_, EnumFacing facing, AxisAlignedBB p_190612_3_)
|
||||
{
|
||||
switch (facing.getAxis())
|
||||
{
|
||||
case X:
|
||||
return getDeltaX(p_190612_1_, facing, p_190612_3_);
|
||||
case Y:
|
||||
default:
|
||||
return getDeltaY(p_190612_1_, facing, p_190612_3_);
|
||||
case Z:
|
||||
return getDeltaZ(p_190612_1_, facing, p_190612_3_);
|
||||
}
|
||||
}
|
||||
|
||||
private AxisAlignedBB moveByPositionAndProgress(AxisAlignedBB p_190607_1_)
|
||||
{
|
||||
double d0 = (double)this.getExtendedProgress(this.progress);
|
||||
return p_190607_1_.offset((double)this.pos.getX() + d0 * (double)this.pistonFacing.getFrontOffsetX(), (double)this.pos.getY() + d0 * (double)this.pistonFacing.getFrontOffsetY(), (double)this.pos.getZ() + d0 * (double)this.pistonFacing.getFrontOffsetZ());
|
||||
}
|
||||
|
||||
private AxisAlignedBB getMovementArea(AxisAlignedBB p_190610_1_, EnumFacing p_190610_2_, double p_190610_3_)
|
||||
{
|
||||
double d0 = p_190610_3_ * (double)p_190610_2_.getAxisDirection().getOffset();
|
||||
double d1 = Math.min(d0, 0.0D);
|
||||
double d2 = Math.max(d0, 0.0D);
|
||||
|
||||
switch (p_190610_2_)
|
||||
{
|
||||
case WEST:
|
||||
return new AxisAlignedBB(p_190610_1_.minX + d1, p_190610_1_.minY, p_190610_1_.minZ, p_190610_1_.minX + d2, p_190610_1_.maxY, p_190610_1_.maxZ);
|
||||
case EAST:
|
||||
return new AxisAlignedBB(p_190610_1_.maxX + d1, p_190610_1_.minY, p_190610_1_.minZ, p_190610_1_.maxX + d2, p_190610_1_.maxY, p_190610_1_.maxZ);
|
||||
case DOWN:
|
||||
return new AxisAlignedBB(p_190610_1_.minX, p_190610_1_.minY + d1, p_190610_1_.minZ, p_190610_1_.maxX, p_190610_1_.minY + d2, p_190610_1_.maxZ);
|
||||
case UP:
|
||||
default:
|
||||
return new AxisAlignedBB(p_190610_1_.minX, p_190610_1_.maxY + d1, p_190610_1_.minZ, p_190610_1_.maxX, p_190610_1_.maxY + d2, p_190610_1_.maxZ);
|
||||
case NORTH:
|
||||
return new AxisAlignedBB(p_190610_1_.minX, p_190610_1_.minY, p_190610_1_.minZ + d1, p_190610_1_.maxX, p_190610_1_.maxY, p_190610_1_.minZ + d2);
|
||||
case SOUTH:
|
||||
return new AxisAlignedBB(p_190610_1_.minX, p_190610_1_.minY, p_190610_1_.maxZ + d1, p_190610_1_.maxX, p_190610_1_.maxY, p_190610_1_.maxZ + d2);
|
||||
}
|
||||
}
|
||||
|
||||
private void fixEntityWithinPistonBase(Entity p_190605_1_, EnumFacing p_190605_2_, double p_190605_3_)
|
||||
{
|
||||
AxisAlignedBB axisalignedbb = p_190605_1_.getEntityBoundingBox();
|
||||
AxisAlignedBB axisalignedbb1 = Block.FULL_BLOCK_AABB.offset(this.pos);
|
||||
|
||||
if (axisalignedbb.intersects(axisalignedbb1))
|
||||
{
|
||||
EnumFacing enumfacing = p_190605_2_.getOpposite();
|
||||
double d0 = this.getMovement(axisalignedbb1, enumfacing, axisalignedbb) + 0.01D;
|
||||
double d1 = this.getMovement(axisalignedbb1, enumfacing, axisalignedbb.intersect(axisalignedbb1)) + 0.01D;
|
||||
|
||||
if (Math.abs(d0 - d1) < 0.01D)
|
||||
{
|
||||
d0 = Math.min(d0, p_190605_3_) + 0.01D;
|
||||
MOVING_ENTITY.set(p_190605_2_);
|
||||
p_190605_1_.move(MoverType.PISTON, d0 * (double)enumfacing.getFrontOffsetX(), d0 * (double)enumfacing.getFrontOffsetY(), d0 * (double)enumfacing.getFrontOffsetZ());
|
||||
MOVING_ENTITY.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double getDeltaX(AxisAlignedBB p_190611_0_, EnumFacing facing, AxisAlignedBB p_190611_2_)
|
||||
{
|
||||
return facing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE ? p_190611_0_.maxX - p_190611_2_.minX : p_190611_2_.maxX - p_190611_0_.minX;
|
||||
}
|
||||
|
||||
private static double getDeltaY(AxisAlignedBB p_190608_0_, EnumFacing facing, AxisAlignedBB p_190608_2_)
|
||||
{
|
||||
return facing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE ? p_190608_0_.maxY - p_190608_2_.minY : p_190608_2_.maxY - p_190608_0_.minY;
|
||||
}
|
||||
|
||||
private static double getDeltaZ(AxisAlignedBB p_190604_0_, EnumFacing facing, AxisAlignedBB p_190604_2_)
|
||||
{
|
||||
return facing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE ? p_190604_0_.maxZ - p_190604_2_.minZ : p_190604_2_.maxZ - p_190604_0_.minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes a piston's tile entity (and if the piston is moving, stops it)
|
||||
*/
|
||||
public void clearPistonTileEntity()
|
||||
{
|
||||
if (this.lastProgress < 1.0F && this.world != null)
|
||||
{
|
||||
this.progress = 1.0F;
|
||||
this.lastProgress = this.progress;
|
||||
this.world.removeTileEntity(this.pos);
|
||||
this.invalidate();
|
||||
|
||||
if (this.world.getBlockState(this.pos).getBlock() == Blocks.PISTON_EXTENSION)
|
||||
{
|
||||
this.world.setBlockState(this.pos, this.pistonState, 3);
|
||||
this.world.neighborChanged(this.pos, this.pistonState.getBlock(), this.pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
this.lastProgress = this.progress;
|
||||
|
||||
if (this.lastProgress >= 1.0F)
|
||||
{
|
||||
this.world.removeTileEntity(this.pos);
|
||||
this.invalidate();
|
||||
|
||||
if (this.world.getBlockState(this.pos).getBlock() == Blocks.PISTON_EXTENSION)
|
||||
{
|
||||
this.world.setBlockState(this.pos, this.pistonState, 3);
|
||||
this.world.neighborChanged(this.pos, this.pistonState.getBlock(), this.pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = this.progress + 0.5F;
|
||||
this.moveCollidedEntities(f);
|
||||
this.progress = f;
|
||||
|
||||
if (this.progress >= 1.0F)
|
||||
{
|
||||
this.progress = 1.0F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerFixesPiston(DataFixer fixer)
|
||||
{
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.pistonState = Block.getBlockById(compound.getInteger("blockId")).getStateFromMeta(compound.getInteger("blockData"));
|
||||
this.pistonFacing = EnumFacing.getFront(compound.getInteger("facing"));
|
||||
this.progress = compound.getFloat("progress");
|
||||
this.lastProgress = this.progress;
|
||||
this.extending = compound.getBoolean("extending");
|
||||
this.shouldHeadBeRendered = compound.getBoolean("source");
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setInteger("blockId", Block.getIdFromBlock(this.pistonState.getBlock()));
|
||||
compound.setInteger("blockData", this.pistonState.getBlock().getMetaFromState(this.pistonState));
|
||||
compound.setInteger("facing", this.pistonFacing.getIndex());
|
||||
compound.setFloat("progress", this.lastProgress);
|
||||
compound.setBoolean("extending", this.extending);
|
||||
compound.setBoolean("source", this.shouldHeadBeRendered);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void addCollissionAABBs(World p_190609_1_, BlockPos p_190609_2_, AxisAlignedBB p_190609_3_, List<AxisAlignedBB> p_190609_4_, @Nullable Entity p_190609_5_)
|
||||
{
|
||||
if (!this.extending && this.shouldHeadBeRendered)
|
||||
{
|
||||
this.pistonState.withProperty(BlockPistonBase.EXTENDED, Boolean.valueOf(true)).addCollisionBoxToList(p_190609_1_, p_190609_2_, p_190609_3_, p_190609_4_, p_190609_5_, false);
|
||||
}
|
||||
|
||||
EnumFacing enumfacing = MOVING_ENTITY.get();
|
||||
|
||||
if ((double)this.progress >= 1.0D || enumfacing != (this.extending ? this.pistonFacing : this.pistonFacing.getOpposite()))
|
||||
{
|
||||
int i = p_190609_4_.size();
|
||||
IBlockState iblockstate;
|
||||
|
||||
if (this.shouldPistonHeadBeRendered())
|
||||
{
|
||||
iblockstate = Blocks.PISTON_HEAD.getDefaultState().withProperty(BlockPistonExtension.FACING, this.pistonFacing).withProperty(BlockPistonExtension.SHORT, Boolean.valueOf(this.extending != 1.0F - this.progress < 0.25F));
|
||||
}
|
||||
else
|
||||
{
|
||||
iblockstate = this.pistonState;
|
||||
}
|
||||
|
||||
float f = this.getExtendedProgress(this.progress);
|
||||
double d0 = (double)((float)this.pistonFacing.getFrontOffsetX() * f);
|
||||
double d1 = (double)((float)this.pistonFacing.getFrontOffsetY() * f);
|
||||
double d2 = (double)((float)this.pistonFacing.getFrontOffsetZ() * f);
|
||||
iblockstate.addCollisionBoxToList(p_190609_1_, p_190609_2_, p_190609_3_.offset(-d0, -d1, -d2), p_190609_4_, p_190609_5_, true);
|
||||
|
||||
for (int j = i; j < p_190609_4_.size(); ++j)
|
||||
{
|
||||
p_190609_4_.set(j, ((AxisAlignedBB)p_190609_4_.get(j)).offset(d0, d1, d2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,448 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockShulkerBox;
|
||||
import net.minecraft.block.material.EnumPushReaction;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.MoverType;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.ContainerShulkerBox;
|
||||
import net.minecraft.inventory.ISidedInventory;
|
||||
import net.minecraft.inventory.ItemStackHelper;
|
||||
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.util.EnumFacing;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntityShulkerBox extends TileEntityLockableLoot implements ITickable, ISidedInventory
|
||||
{
|
||||
private static final int[] SLOTS = new int[27];
|
||||
private NonNullList<ItemStack> items;
|
||||
private boolean hasBeenCleared;
|
||||
private int openCount;
|
||||
private TileEntityShulkerBox.AnimationStatus animationStatus;
|
||||
private float progress;
|
||||
private float progressOld;
|
||||
private EnumDyeColor color;
|
||||
private boolean destroyedByCreativePlayer;
|
||||
|
||||
public TileEntityShulkerBox()
|
||||
{
|
||||
this((EnumDyeColor)null);
|
||||
}
|
||||
|
||||
public TileEntityShulkerBox(@Nullable EnumDyeColor colorIn)
|
||||
{
|
||||
this.items = NonNullList.<ItemStack>withSize(27, ItemStack.EMPTY);
|
||||
this.animationStatus = TileEntityShulkerBox.AnimationStatus.CLOSED;
|
||||
this.color = colorIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
this.updateAnimation();
|
||||
|
||||
if (this.animationStatus == TileEntityShulkerBox.AnimationStatus.OPENING || this.animationStatus == TileEntityShulkerBox.AnimationStatus.CLOSING)
|
||||
{
|
||||
this.moveCollidedEntities();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateAnimation()
|
||||
{
|
||||
this.progressOld = this.progress;
|
||||
|
||||
switch (this.animationStatus)
|
||||
{
|
||||
case CLOSED:
|
||||
this.progress = 0.0F;
|
||||
break;
|
||||
case OPENING:
|
||||
this.progress += 0.1F;
|
||||
|
||||
if (this.progress >= 1.0F)
|
||||
{
|
||||
this.moveCollidedEntities();
|
||||
this.animationStatus = TileEntityShulkerBox.AnimationStatus.OPENED;
|
||||
this.progress = 1.0F;
|
||||
}
|
||||
|
||||
break;
|
||||
case CLOSING:
|
||||
this.progress -= 0.1F;
|
||||
|
||||
if (this.progress <= 0.0F)
|
||||
{
|
||||
this.animationStatus = TileEntityShulkerBox.AnimationStatus.CLOSED;
|
||||
this.progress = 0.0F;
|
||||
}
|
||||
|
||||
break;
|
||||
case OPENED:
|
||||
this.progress = 1.0F;
|
||||
}
|
||||
}
|
||||
|
||||
public TileEntityShulkerBox.AnimationStatus getAnimationStatus()
|
||||
{
|
||||
return this.animationStatus;
|
||||
}
|
||||
|
||||
public AxisAlignedBB getBoundingBox(IBlockState p_190584_1_)
|
||||
{
|
||||
return this.getBoundingBox((EnumFacing)p_190584_1_.getValue(BlockShulkerBox.FACING));
|
||||
}
|
||||
|
||||
public AxisAlignedBB getBoundingBox(EnumFacing p_190587_1_)
|
||||
{
|
||||
return Block.FULL_BLOCK_AABB.expand((double)(0.5F * this.getProgress(1.0F) * (float)p_190587_1_.getFrontOffsetX()), (double)(0.5F * this.getProgress(1.0F) * (float)p_190587_1_.getFrontOffsetY()), (double)(0.5F * this.getProgress(1.0F) * (float)p_190587_1_.getFrontOffsetZ()));
|
||||
}
|
||||
|
||||
private AxisAlignedBB getTopBoundingBox(EnumFacing p_190588_1_)
|
||||
{
|
||||
EnumFacing enumfacing = p_190588_1_.getOpposite();
|
||||
return this.getBoundingBox(p_190588_1_).contract((double)enumfacing.getFrontOffsetX(), (double)enumfacing.getFrontOffsetY(), (double)enumfacing.getFrontOffsetZ());
|
||||
}
|
||||
|
||||
private void moveCollidedEntities()
|
||||
{
|
||||
IBlockState iblockstate = this.world.getBlockState(this.getPos());
|
||||
|
||||
if (iblockstate.getBlock() instanceof BlockShulkerBox)
|
||||
{
|
||||
EnumFacing enumfacing = (EnumFacing)iblockstate.getValue(BlockShulkerBox.FACING);
|
||||
AxisAlignedBB axisalignedbb = this.getTopBoundingBox(enumfacing).offset(this.pos);
|
||||
List<Entity> list = this.world.getEntitiesWithinAABBExcludingEntity((Entity)null, axisalignedbb);
|
||||
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
for (int i = 0; i < list.size(); ++i)
|
||||
{
|
||||
Entity entity = list.get(i);
|
||||
|
||||
if (entity.getPushReaction() != EnumPushReaction.IGNORE)
|
||||
{
|
||||
double d0 = 0.0D;
|
||||
double d1 = 0.0D;
|
||||
double d2 = 0.0D;
|
||||
AxisAlignedBB axisalignedbb1 = entity.getEntityBoundingBox();
|
||||
|
||||
switch (enumfacing.getAxis())
|
||||
{
|
||||
case X:
|
||||
|
||||
if (enumfacing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE)
|
||||
{
|
||||
d0 = axisalignedbb.maxX - axisalignedbb1.minX;
|
||||
}
|
||||
else
|
||||
{
|
||||
d0 = axisalignedbb1.maxX - axisalignedbb.minX;
|
||||
}
|
||||
|
||||
d0 = d0 + 0.01D;
|
||||
break;
|
||||
case Y:
|
||||
|
||||
if (enumfacing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE)
|
||||
{
|
||||
d1 = axisalignedbb.maxY - axisalignedbb1.minY;
|
||||
}
|
||||
else
|
||||
{
|
||||
d1 = axisalignedbb1.maxY - axisalignedbb.minY;
|
||||
}
|
||||
|
||||
d1 = d1 + 0.01D;
|
||||
break;
|
||||
case Z:
|
||||
|
||||
if (enumfacing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE)
|
||||
{
|
||||
d2 = axisalignedbb.maxZ - axisalignedbb1.minZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
d2 = axisalignedbb1.maxZ - axisalignedbb.minZ;
|
||||
}
|
||||
|
||||
d2 = d2 + 0.01D;
|
||||
}
|
||||
|
||||
entity.move(MoverType.SHULKER_BOX, d0 * (double)enumfacing.getFrontOffsetX(), d1 * (double)enumfacing.getFrontOffsetY(), d2 * (double)enumfacing.getFrontOffsetZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of slots in the inventory.
|
||||
*/
|
||||
public int getSizeInventory()
|
||||
{
|
||||
return this.items.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended.
|
||||
*/
|
||||
public int getInventoryStackLimit()
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
public boolean receiveClientEvent(int id, int type)
|
||||
{
|
||||
if (id == 1)
|
||||
{
|
||||
this.openCount = type;
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
this.animationStatus = TileEntityShulkerBox.AnimationStatus.CLOSING;
|
||||
}
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
this.animationStatus = TileEntityShulkerBox.AnimationStatus.OPENING;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.receiveClientEvent(id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public void openInventory(EntityPlayer player)
|
||||
{
|
||||
if (!player.isSpectator())
|
||||
{
|
||||
if (this.openCount < 0)
|
||||
{
|
||||
this.openCount = 0;
|
||||
}
|
||||
|
||||
++this.openCount;
|
||||
this.world.addBlockEvent(this.pos, this.getBlockType(), 1, this.openCount);
|
||||
|
||||
if (this.openCount == 1)
|
||||
{
|
||||
this.world.playSound((EntityPlayer)null, this.pos, SoundEvents.BLOCK_SHULKER_BOX_OPEN, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void closeInventory(EntityPlayer player)
|
||||
{
|
||||
if (!player.isSpectator())
|
||||
{
|
||||
--this.openCount;
|
||||
this.world.addBlockEvent(this.pos, this.getBlockType(), 1, this.openCount);
|
||||
|
||||
if (this.openCount <= 0)
|
||||
{
|
||||
this.world.playSound((EntityPlayer)null, this.pos, SoundEvents.BLOCK_SHULKER_BOX_CLOSE, SoundCategory.BLOCKS, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn)
|
||||
{
|
||||
return new ContainerShulkerBox(playerInventory, this, playerIn);
|
||||
}
|
||||
|
||||
public String getGuiID()
|
||||
{
|
||||
return "minecraft:shulker_box";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.hasCustomName() ? this.customName : "container.shulkerBox";
|
||||
}
|
||||
|
||||
public static void registerFixesShulkerBox(DataFixer fixer)
|
||||
{
|
||||
fixer.registerWalker(FixTypes.BLOCK_ENTITY, new ItemStackDataLists(TileEntityShulkerBox.class, new String[] {"Items"}));
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.loadFromNbt(compound);
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
return this.saveToNbt(compound);
|
||||
}
|
||||
|
||||
public void loadFromNbt(NBTTagCompound compound)
|
||||
{
|
||||
this.items = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
|
||||
|
||||
if (!this.checkLootAndRead(compound) && compound.hasKey("Items", 9))
|
||||
{
|
||||
ItemStackHelper.loadAllItems(compound, this.items);
|
||||
}
|
||||
|
||||
if (compound.hasKey("CustomName", 8))
|
||||
{
|
||||
this.customName = compound.getString("CustomName");
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound saveToNbt(NBTTagCompound compound)
|
||||
{
|
||||
if (!this.checkLootAndWrite(compound))
|
||||
{
|
||||
ItemStackHelper.saveAllItems(compound, this.items, false);
|
||||
}
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
compound.setString("CustomName", this.customName);
|
||||
}
|
||||
|
||||
if (!compound.hasKey("Lock") && this.isLocked())
|
||||
{
|
||||
this.getLockCode().toNBT(compound);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
protected NonNullList<ItemStack> getItems()
|
||||
{
|
||||
return this.items;
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (ItemStack itemstack : this.items)
|
||||
{
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int[] getSlotsForFace(EnumFacing side)
|
||||
{
|
||||
return SLOTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 !(Block.getBlockFromItem(itemStackIn.getItem()) instanceof BlockShulkerBox);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 true;
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
this.hasBeenCleared = true;
|
||||
super.clear();
|
||||
}
|
||||
|
||||
public boolean isCleared()
|
||||
{
|
||||
return this.hasBeenCleared;
|
||||
}
|
||||
|
||||
public float getProgress(float p_190585_1_)
|
||||
{
|
||||
return this.progressOld + (this.progress - this.progressOld) * p_190585_1_;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public EnumDyeColor getColor()
|
||||
{
|
||||
if (this.color == null)
|
||||
{
|
||||
this.color = BlockShulkerBox.getColorFromBlock(this.getBlockType());
|
||||
}
|
||||
|
||||
return this.color;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 10, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public boolean isDestroyedByCreativePlayer()
|
||||
{
|
||||
return this.destroyedByCreativePlayer;
|
||||
}
|
||||
|
||||
public void setDestroyedByCreativePlayer(boolean p_190579_1_)
|
||||
{
|
||||
this.destroyedByCreativePlayer = p_190579_1_;
|
||||
}
|
||||
|
||||
public boolean shouldDrop()
|
||||
{
|
||||
return !this.isDestroyedByCreativePlayer() || !this.isEmpty() || this.hasCustomName() || this.lootTable != null;
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < SLOTS.length; SLOTS[i] = i++)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum AnimationStatus
|
||||
{
|
||||
CLOSED,
|
||||
OPENING,
|
||||
OPENED,
|
||||
CLOSING;
|
||||
}
|
||||
|
||||
protected net.minecraftforge.items.IItemHandler createUnSidedHandler()
|
||||
{
|
||||
return new net.minecraftforge.items.wrapper.SidedInvWrapper(this, EnumFacing.UP);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.command.CommandException;
|
||||
import net.minecraft.command.CommandResultStats;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.Style;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextComponentUtils;
|
||||
import net.minecraft.util.text.event.ClickEvent;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntitySign extends TileEntity
|
||||
{
|
||||
public final ITextComponent[] signText = new ITextComponent[] {new TextComponentString(""), new TextComponentString(""), new TextComponentString(""), new TextComponentString("")};
|
||||
/**
|
||||
* The index of the line currently being edited. Only used on client side, but defined on both. Note this is only
|
||||
* really used when the > < are going to be visible.
|
||||
*/
|
||||
public int lineBeingEdited = -1;
|
||||
private boolean isEditable = true;
|
||||
private EntityPlayer player;
|
||||
private final CommandResultStats stats = new CommandResultStats();
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
String s = ITextComponent.Serializer.componentToJson(this.signText[i]);
|
||||
compound.setString("Text" + (i + 1), s);
|
||||
}
|
||||
|
||||
this.stats.writeStatsToNBT(compound);
|
||||
return compound;
|
||||
}
|
||||
|
||||
protected void setWorldCreate(World worldIn)
|
||||
{
|
||||
this.setWorld(worldIn);
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
this.isEditable = false;
|
||||
super.readFromNBT(compound);
|
||||
ICommandSender icommandsender = new ICommandSender()
|
||||
{
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return "Sign";
|
||||
}
|
||||
/**
|
||||
* Returns {@code true} if the CommandSender is allowed to execute the command, {@code false} if not
|
||||
*/
|
||||
public boolean canUseCommand(int permLevel, String commandName)
|
||||
{
|
||||
return permLevel <= 2; //Forge: Fixes MC-75630 - Exploit with signs and command blocks
|
||||
}
|
||||
/**
|
||||
* Get the position in the world. <b>{@code null} is not allowed!</b> If you are not an entity in the world,
|
||||
* return the coordinates 0, 0, 0
|
||||
*/
|
||||
public BlockPos getPosition()
|
||||
{
|
||||
return TileEntitySign.this.pos;
|
||||
}
|
||||
/**
|
||||
* Get the position vector. <b>{@code null} is not allowed!</b> If you are not an entity in the world,
|
||||
* return 0.0D, 0.0D, 0.0D
|
||||
*/
|
||||
public Vec3d getPositionVector()
|
||||
{
|
||||
return new Vec3d((double)TileEntitySign.this.pos.getX() + 0.5D, (double)TileEntitySign.this.pos.getY() + 0.5D, (double)TileEntitySign.this.pos.getZ() + 0.5D);
|
||||
}
|
||||
/**
|
||||
* Get the world, if available. <b>{@code null} is not allowed!</b> If you are not an entity in the world,
|
||||
* return the overworld
|
||||
*/
|
||||
public World getEntityWorld()
|
||||
{
|
||||
return TileEntitySign.this.world;
|
||||
}
|
||||
/**
|
||||
* Get the Minecraft server instance
|
||||
*/
|
||||
public MinecraftServer getServer()
|
||||
{
|
||||
return TileEntitySign.this.world.getMinecraftServer();
|
||||
}
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
String s = compound.getString("Text" + (i + 1));
|
||||
ITextComponent itextcomponent = ITextComponent.Serializer.jsonToComponent(s);
|
||||
|
||||
try
|
||||
{
|
||||
this.signText[i] = TextComponentUtils.processComponent(icommandsender, itextcomponent, (Entity)null);
|
||||
}
|
||||
catch (CommandException var7)
|
||||
{
|
||||
this.signText[i] = itextcomponent;
|
||||
}
|
||||
}
|
||||
|
||||
this.stats.readStatsFromNBT(compound);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 9, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public boolean onlyOpsCanSetNbt()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean getIsEditable()
|
||||
{
|
||||
return this.isEditable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sign's isEditable flag to the specified parameter.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void setEditable(boolean isEditableIn)
|
||||
{
|
||||
this.isEditable = isEditableIn;
|
||||
|
||||
if (!isEditableIn)
|
||||
{
|
||||
this.player = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setPlayer(EntityPlayer playerIn)
|
||||
{
|
||||
this.player = playerIn;
|
||||
}
|
||||
|
||||
public EntityPlayer getPlayer()
|
||||
{
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public boolean executeCommand(final EntityPlayer playerIn)
|
||||
{
|
||||
ICommandSender icommandsender = new ICommandSender()
|
||||
{
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return playerIn.getName();
|
||||
}
|
||||
/**
|
||||
* Get the formatted ChatComponent that will be used for the sender's username in chat
|
||||
*/
|
||||
public ITextComponent getDisplayName()
|
||||
{
|
||||
return playerIn.getDisplayName();
|
||||
}
|
||||
/**
|
||||
* Send a chat message to the CommandSender
|
||||
*/
|
||||
public void sendMessage(ITextComponent component)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Returns {@code true} if the CommandSender is allowed to execute the command, {@code false} if not
|
||||
*/
|
||||
public boolean canUseCommand(int permLevel, String commandName)
|
||||
{
|
||||
return permLevel <= 2;
|
||||
}
|
||||
/**
|
||||
* Get the position in the world. <b>{@code null} is not allowed!</b> If you are not an entity in the world,
|
||||
* return the coordinates 0, 0, 0
|
||||
*/
|
||||
public BlockPos getPosition()
|
||||
{
|
||||
return TileEntitySign.this.pos;
|
||||
}
|
||||
/**
|
||||
* Get the position vector. <b>{@code null} is not allowed!</b> If you are not an entity in the world,
|
||||
* return 0.0D, 0.0D, 0.0D
|
||||
*/
|
||||
public Vec3d getPositionVector()
|
||||
{
|
||||
return new Vec3d((double)TileEntitySign.this.pos.getX() + 0.5D, (double)TileEntitySign.this.pos.getY() + 0.5D, (double)TileEntitySign.this.pos.getZ() + 0.5D);
|
||||
}
|
||||
/**
|
||||
* Get the world, if available. <b>{@code null} is not allowed!</b> If you are not an entity in the world,
|
||||
* return the overworld
|
||||
*/
|
||||
public World getEntityWorld()
|
||||
{
|
||||
return playerIn.getEntityWorld();
|
||||
}
|
||||
/**
|
||||
* Returns the entity associated with the command sender. MAY BE NULL!
|
||||
*/
|
||||
public Entity getCommandSenderEntity()
|
||||
{
|
||||
return playerIn;
|
||||
}
|
||||
/**
|
||||
* Returns true if the command sender should be sent feedback about executed commands
|
||||
*/
|
||||
public boolean sendCommandFeedback()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public void setCommandStat(CommandResultStats.Type type, int amount)
|
||||
{
|
||||
if (TileEntitySign.this.world != null && !TileEntitySign.this.world.isRemote)
|
||||
{
|
||||
TileEntitySign.this.stats.setCommandStatForSender(TileEntitySign.this.world.getMinecraftServer(), this, type, amount);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the Minecraft server instance
|
||||
*/
|
||||
public MinecraftServer getServer()
|
||||
{
|
||||
return playerIn.getServer();
|
||||
}
|
||||
};
|
||||
|
||||
for (ITextComponent itextcomponent : this.signText)
|
||||
{
|
||||
Style style = itextcomponent == null ? null : itextcomponent.getStyle();
|
||||
|
||||
if (style != null && style.getClickEvent() != null)
|
||||
{
|
||||
ClickEvent clickevent = style.getClickEvent();
|
||||
|
||||
if (clickevent.getAction() == ClickEvent.Action.RUN_COMMAND)
|
||||
{
|
||||
playerIn.getServer().getCommandManager().executeCommand(icommandsender, clickevent.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public CommandResultStats getStats()
|
||||
{
|
||||
return this.stats;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.BlockSkull;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.server.management.PlayerProfileCache;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.Mirror;
|
||||
import net.minecraft.util.Rotation;
|
||||
import net.minecraft.util.StringUtils;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntitySkull extends TileEntity implements ITickable
|
||||
{
|
||||
private int skullType;
|
||||
private int skullRotation;
|
||||
private GameProfile playerProfile;
|
||||
private int dragonAnimatedTicks;
|
||||
private boolean dragonAnimated;
|
||||
private static PlayerProfileCache profileCache;
|
||||
private static MinecraftSessionService sessionService;
|
||||
|
||||
public static void setProfileCache(PlayerProfileCache profileCacheIn)
|
||||
{
|
||||
profileCache = profileCacheIn;
|
||||
}
|
||||
|
||||
public static void setSessionService(MinecraftSessionService sessionServiceIn)
|
||||
{
|
||||
sessionService = sessionServiceIn;
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setByte("SkullType", (byte)(this.skullType & 255));
|
||||
compound.setByte("Rot", (byte)(this.skullRotation & 255));
|
||||
|
||||
if (this.playerProfile != null)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = new NBTTagCompound();
|
||||
NBTUtil.writeGameProfile(nbttagcompound, this.playerProfile);
|
||||
compound.setTag("Owner", nbttagcompound);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.skullType = compound.getByte("SkullType");
|
||||
this.skullRotation = compound.getByte("Rot");
|
||||
|
||||
if (this.skullType == 3)
|
||||
{
|
||||
if (compound.hasKey("Owner", 10))
|
||||
{
|
||||
this.playerProfile = NBTUtil.readGameProfileFromNBT(compound.getCompoundTag("Owner"));
|
||||
}
|
||||
else if (compound.hasKey("ExtraType", 8))
|
||||
{
|
||||
String s = compound.getString("ExtraType");
|
||||
|
||||
if (!StringUtils.isNullOrEmpty(s))
|
||||
{
|
||||
this.playerProfile = new GameProfile((UUID)null, s);
|
||||
this.updatePlayerProfile();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
if (this.skullType == 5)
|
||||
{
|
||||
if (this.world.isBlockPowered(this.pos))
|
||||
{
|
||||
this.dragonAnimated = true;
|
||||
++this.dragonAnimatedTicks;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dragonAnimated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getAnimationProgress(float p_184295_1_)
|
||||
{
|
||||
return this.dragonAnimated ? (float)this.dragonAnimatedTicks + p_184295_1_ : (float)this.dragonAnimatedTicks;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GameProfile getPlayerProfile()
|
||||
{
|
||||
return this.playerProfile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 4, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public void setType(int type)
|
||||
{
|
||||
this.skullType = type;
|
||||
this.playerProfile = null;
|
||||
}
|
||||
|
||||
public void setPlayerProfile(@Nullable GameProfile playerProfile)
|
||||
{
|
||||
this.skullType = 3;
|
||||
this.playerProfile = playerProfile;
|
||||
this.updatePlayerProfile();
|
||||
}
|
||||
|
||||
private void updatePlayerProfile()
|
||||
{
|
||||
this.playerProfile = updateGameprofile(this.playerProfile);
|
||||
this.markDirty();
|
||||
}
|
||||
|
||||
public static GameProfile updateGameprofile(GameProfile input)
|
||||
{
|
||||
if (input != null && !StringUtils.isNullOrEmpty(input.getName()))
|
||||
{
|
||||
if (input.isComplete() && input.getProperties().containsKey("textures"))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
else if (profileCache != null && sessionService != null)
|
||||
{
|
||||
GameProfile gameprofile = profileCache.getGameProfileForUsername(input.getName());
|
||||
|
||||
if (gameprofile == null)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
Property property = (Property)Iterables.getFirst(gameprofile.getProperties().get("textures"), (Object)null);
|
||||
|
||||
if (property == null)
|
||||
{
|
||||
gameprofile = sessionService.fillProfileProperties(gameprofile, true);
|
||||
}
|
||||
|
||||
return gameprofile;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return input;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSkullType()
|
||||
{
|
||||
return this.skullType;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public int getSkullRotation()
|
||||
{
|
||||
return this.skullRotation;
|
||||
}
|
||||
|
||||
public void setSkullRotation(int rotation)
|
||||
{
|
||||
this.skullRotation = rotation;
|
||||
}
|
||||
|
||||
public void mirror(Mirror mirrorIn)
|
||||
{
|
||||
if (this.world != null && this.world.getBlockState(this.getPos()).getValue(BlockSkull.FACING) == EnumFacing.UP)
|
||||
{
|
||||
this.skullRotation = mirrorIn.mirrorRotation(this.skullRotation, 16);
|
||||
}
|
||||
}
|
||||
|
||||
public void rotate(Rotation rotationIn)
|
||||
{
|
||||
if (this.world != null && this.world.getBlockState(this.getPos()).getValue(BlockSkull.FACING) == EnumFacing.UP)
|
||||
{
|
||||
this.skullRotation = rotationIn.rotate(this.skullRotation, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,677 @@
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockStructure;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.ChatAllowedCharacters;
|
||||
import net.minecraft.util.IStringSerializable;
|
||||
import net.minecraft.util.Mirror;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.Rotation;
|
||||
import net.minecraft.util.StringUtils;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.gen.structure.StructureBoundingBox;
|
||||
import net.minecraft.world.gen.structure.template.PlacementSettings;
|
||||
import net.minecraft.world.gen.structure.template.Template;
|
||||
import net.minecraft.world.gen.structure.template.TemplateManager;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class TileEntityStructure extends TileEntity
|
||||
{
|
||||
private String name = "";
|
||||
private String author = "";
|
||||
private String metadata = "";
|
||||
private BlockPos position = new BlockPos(0, 1, 0);
|
||||
private BlockPos size = BlockPos.ORIGIN;
|
||||
private Mirror mirror = Mirror.NONE;
|
||||
private Rotation rotation = Rotation.NONE;
|
||||
private TileEntityStructure.Mode mode = TileEntityStructure.Mode.DATA;
|
||||
private boolean ignoreEntities = true;
|
||||
private boolean powered;
|
||||
private boolean showAir;
|
||||
private boolean showBoundingBox = true;
|
||||
private float integrity = 1.0F;
|
||||
private long seed;
|
||||
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeToNBT(compound);
|
||||
compound.setString("name", this.name);
|
||||
compound.setString("author", this.author);
|
||||
compound.setString("metadata", this.metadata);
|
||||
compound.setInteger("posX", this.position.getX());
|
||||
compound.setInteger("posY", this.position.getY());
|
||||
compound.setInteger("posZ", this.position.getZ());
|
||||
compound.setInteger("sizeX", this.size.getX());
|
||||
compound.setInteger("sizeY", this.size.getY());
|
||||
compound.setInteger("sizeZ", this.size.getZ());
|
||||
compound.setString("rotation", this.rotation.toString());
|
||||
compound.setString("mirror", this.mirror.toString());
|
||||
compound.setString("mode", this.mode.toString());
|
||||
compound.setBoolean("ignoreEntities", this.ignoreEntities);
|
||||
compound.setBoolean("powered", this.powered);
|
||||
compound.setBoolean("showair", this.showAir);
|
||||
compound.setBoolean("showboundingbox", this.showBoundingBox);
|
||||
compound.setFloat("integrity", this.integrity);
|
||||
compound.setLong("seed", this.seed);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readFromNBT(compound);
|
||||
this.setName(compound.getString("name"));
|
||||
this.author = compound.getString("author");
|
||||
this.metadata = compound.getString("metadata");
|
||||
int i = MathHelper.clamp(compound.getInteger("posX"), -32, 32);
|
||||
int j = MathHelper.clamp(compound.getInteger("posY"), -32, 32);
|
||||
int k = MathHelper.clamp(compound.getInteger("posZ"), -32, 32);
|
||||
this.position = new BlockPos(i, j, k);
|
||||
int l = MathHelper.clamp(compound.getInteger("sizeX"), 0, 32);
|
||||
int i1 = MathHelper.clamp(compound.getInteger("sizeY"), 0, 32);
|
||||
int j1 = MathHelper.clamp(compound.getInteger("sizeZ"), 0, 32);
|
||||
this.size = new BlockPos(l, i1, j1);
|
||||
|
||||
try
|
||||
{
|
||||
this.rotation = Rotation.valueOf(compound.getString("rotation"));
|
||||
}
|
||||
catch (IllegalArgumentException var11)
|
||||
{
|
||||
this.rotation = Rotation.NONE;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.mirror = Mirror.valueOf(compound.getString("mirror"));
|
||||
}
|
||||
catch (IllegalArgumentException var10)
|
||||
{
|
||||
this.mirror = Mirror.NONE;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.mode = TileEntityStructure.Mode.valueOf(compound.getString("mode"));
|
||||
}
|
||||
catch (IllegalArgumentException var9)
|
||||
{
|
||||
this.mode = TileEntityStructure.Mode.DATA;
|
||||
}
|
||||
|
||||
this.ignoreEntities = compound.getBoolean("ignoreEntities");
|
||||
this.powered = compound.getBoolean("powered");
|
||||
this.showAir = compound.getBoolean("showair");
|
||||
this.showBoundingBox = compound.getBoolean("showboundingbox");
|
||||
|
||||
if (compound.hasKey("integrity"))
|
||||
{
|
||||
this.integrity = compound.getFloat("integrity");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.integrity = 1.0F;
|
||||
}
|
||||
|
||||
this.seed = compound.getLong("seed");
|
||||
this.updateBlockState();
|
||||
}
|
||||
|
||||
private void updateBlockState()
|
||||
{
|
||||
if (this.world != null)
|
||||
{
|
||||
BlockPos blockpos = this.getPos();
|
||||
IBlockState iblockstate = this.world.getBlockState(blockpos);
|
||||
|
||||
if (iblockstate.getBlock() == Blocks.STRUCTURE_BLOCK)
|
||||
{
|
||||
this.world.setBlockState(blockpos, iblockstate.withProperty(BlockStructure.MODE, this.mode), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SPacketUpdateTileEntity getUpdatePacket()
|
||||
{
|
||||
return new SPacketUpdateTileEntity(this.pos, 7, this.getUpdateTag());
|
||||
}
|
||||
|
||||
public NBTTagCompound getUpdateTag()
|
||||
{
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
public boolean usedBy(EntityPlayer player)
|
||||
{
|
||||
if (!player.canUseCommandBlock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player.getEntityWorld().isRemote)
|
||||
{
|
||||
player.openEditStructure(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String nameIn)
|
||||
{
|
||||
String s = nameIn;
|
||||
|
||||
for (char c0 : ChatAllowedCharacters.ILLEGAL_STRUCTURE_CHARACTERS)
|
||||
{
|
||||
s = s.replace(c0, '_');
|
||||
}
|
||||
|
||||
this.name = s;
|
||||
}
|
||||
|
||||
public void createdBy(EntityLivingBase p_189720_1_)
|
||||
{
|
||||
if (!StringUtils.isNullOrEmpty(p_189720_1_.getName()))
|
||||
{
|
||||
this.author = p_189720_1_.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public BlockPos getPosition()
|
||||
{
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public void setPosition(BlockPos posIn)
|
||||
{
|
||||
this.position = posIn;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public BlockPos getStructureSize()
|
||||
{
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public void setSize(BlockPos sizeIn)
|
||||
{
|
||||
this.size = sizeIn;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public Mirror getMirror()
|
||||
{
|
||||
return this.mirror;
|
||||
}
|
||||
|
||||
public void setMirror(Mirror mirrorIn)
|
||||
{
|
||||
this.mirror = mirrorIn;
|
||||
}
|
||||
|
||||
public void setRotation(Rotation rotationIn)
|
||||
{
|
||||
this.rotation = rotationIn;
|
||||
}
|
||||
|
||||
public void setMetadata(String metadataIn)
|
||||
{
|
||||
this.metadata = metadataIn;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public Rotation getRotation()
|
||||
{
|
||||
return this.rotation;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public String getMetadata()
|
||||
{
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
public TileEntityStructure.Mode getMode()
|
||||
{
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
public void setMode(TileEntityStructure.Mode modeIn)
|
||||
{
|
||||
this.mode = modeIn;
|
||||
IBlockState iblockstate = this.world.getBlockState(this.getPos());
|
||||
|
||||
if (iblockstate.getBlock() == Blocks.STRUCTURE_BLOCK)
|
||||
{
|
||||
this.world.setBlockState(this.getPos(), iblockstate.withProperty(BlockStructure.MODE, modeIn), 2);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIgnoresEntities(boolean ignoreEntitiesIn)
|
||||
{
|
||||
this.ignoreEntities = ignoreEntitiesIn;
|
||||
}
|
||||
|
||||
public void setIntegrity(float integrityIn)
|
||||
{
|
||||
this.integrity = integrityIn;
|
||||
}
|
||||
|
||||
public void setSeed(long seedIn)
|
||||
{
|
||||
this.seed = seedIn;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void nextMode()
|
||||
{
|
||||
switch (this.getMode())
|
||||
{
|
||||
case SAVE:
|
||||
this.setMode(TileEntityStructure.Mode.LOAD);
|
||||
break;
|
||||
case LOAD:
|
||||
this.setMode(TileEntityStructure.Mode.CORNER);
|
||||
break;
|
||||
case CORNER:
|
||||
this.setMode(TileEntityStructure.Mode.DATA);
|
||||
break;
|
||||
case DATA:
|
||||
this.setMode(TileEntityStructure.Mode.SAVE);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean ignoresEntities()
|
||||
{
|
||||
return this.ignoreEntities;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getIntegrity()
|
||||
{
|
||||
return this.integrity;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public long getSeed()
|
||||
{
|
||||
return this.seed;
|
||||
}
|
||||
|
||||
public boolean detectSize()
|
||||
{
|
||||
if (this.mode != TileEntityStructure.Mode.SAVE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos blockpos = this.getPos();
|
||||
int i = 80;
|
||||
BlockPos blockpos1 = new BlockPos(blockpos.getX() - 80, 0, blockpos.getZ() - 80);
|
||||
BlockPos blockpos2 = new BlockPos(blockpos.getX() + 80, 255, blockpos.getZ() + 80);
|
||||
List<TileEntityStructure> list = this.getNearbyCornerBlocks(blockpos1, blockpos2);
|
||||
List<TileEntityStructure> list1 = this.filterRelatedCornerBlocks(list);
|
||||
|
||||
if (list1.size() < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
StructureBoundingBox structureboundingbox = this.calculateEnclosingBoundingBox(blockpos, list1);
|
||||
|
||||
if (structureboundingbox.maxX - structureboundingbox.minX > 1 && structureboundingbox.maxY - structureboundingbox.minY > 1 && structureboundingbox.maxZ - structureboundingbox.minZ > 1)
|
||||
{
|
||||
this.position = new BlockPos(structureboundingbox.minX - blockpos.getX() + 1, structureboundingbox.minY - blockpos.getY() + 1, structureboundingbox.minZ - blockpos.getZ() + 1);
|
||||
this.size = new BlockPos(structureboundingbox.maxX - structureboundingbox.minX - 1, structureboundingbox.maxY - structureboundingbox.minY - 1, structureboundingbox.maxZ - structureboundingbox.minZ - 1);
|
||||
this.markDirty();
|
||||
IBlockState iblockstate = this.world.getBlockState(blockpos);
|
||||
this.world.notifyBlockUpdate(blockpos, iblockstate, iblockstate, 3);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<TileEntityStructure> filterRelatedCornerBlocks(List<TileEntityStructure> p_184415_1_)
|
||||
{
|
||||
Iterable<TileEntityStructure> iterable = Iterables.filter(p_184415_1_, new Predicate<TileEntityStructure>()
|
||||
{
|
||||
public boolean apply(@Nullable TileEntityStructure p_apply_1_)
|
||||
{
|
||||
return p_apply_1_.mode == TileEntityStructure.Mode.CORNER && TileEntityStructure.this.name.equals(p_apply_1_.name);
|
||||
}
|
||||
});
|
||||
return Lists.newArrayList(iterable);
|
||||
}
|
||||
|
||||
private List<TileEntityStructure> getNearbyCornerBlocks(BlockPos p_184418_1_, BlockPos p_184418_2_)
|
||||
{
|
||||
List<TileEntityStructure> list = Lists.<TileEntityStructure>newArrayList();
|
||||
|
||||
for (BlockPos.MutableBlockPos blockpos$mutableblockpos : BlockPos.getAllInBoxMutable(p_184418_1_, p_184418_2_))
|
||||
{
|
||||
IBlockState iblockstate = this.world.getBlockState(blockpos$mutableblockpos);
|
||||
|
||||
if (iblockstate.getBlock() == Blocks.STRUCTURE_BLOCK)
|
||||
{
|
||||
TileEntity tileentity = this.world.getTileEntity(blockpos$mutableblockpos);
|
||||
|
||||
if (tileentity != null && tileentity instanceof TileEntityStructure)
|
||||
{
|
||||
list.add((TileEntityStructure)tileentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private StructureBoundingBox calculateEnclosingBoundingBox(BlockPos p_184416_1_, List<TileEntityStructure> p_184416_2_)
|
||||
{
|
||||
StructureBoundingBox structureboundingbox;
|
||||
|
||||
if (p_184416_2_.size() > 1)
|
||||
{
|
||||
BlockPos blockpos = ((TileEntityStructure)p_184416_2_.get(0)).getPos();
|
||||
structureboundingbox = new StructureBoundingBox(blockpos, blockpos);
|
||||
}
|
||||
else
|
||||
{
|
||||
structureboundingbox = new StructureBoundingBox(p_184416_1_, p_184416_1_);
|
||||
}
|
||||
|
||||
for (TileEntityStructure tileentitystructure : p_184416_2_)
|
||||
{
|
||||
BlockPos blockpos1 = tileentitystructure.getPos();
|
||||
|
||||
if (blockpos1.getX() < structureboundingbox.minX)
|
||||
{
|
||||
structureboundingbox.minX = blockpos1.getX();
|
||||
}
|
||||
else if (blockpos1.getX() > structureboundingbox.maxX)
|
||||
{
|
||||
structureboundingbox.maxX = blockpos1.getX();
|
||||
}
|
||||
|
||||
if (blockpos1.getY() < structureboundingbox.minY)
|
||||
{
|
||||
structureboundingbox.minY = blockpos1.getY();
|
||||
}
|
||||
else if (blockpos1.getY() > structureboundingbox.maxY)
|
||||
{
|
||||
structureboundingbox.maxY = blockpos1.getY();
|
||||
}
|
||||
|
||||
if (blockpos1.getZ() < structureboundingbox.minZ)
|
||||
{
|
||||
structureboundingbox.minZ = blockpos1.getZ();
|
||||
}
|
||||
else if (blockpos1.getZ() > structureboundingbox.maxZ)
|
||||
{
|
||||
structureboundingbox.maxZ = blockpos1.getZ();
|
||||
}
|
||||
}
|
||||
|
||||
return structureboundingbox;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void writeCoordinates(ByteBuf buf)
|
||||
{
|
||||
buf.writeInt(this.pos.getX());
|
||||
buf.writeInt(this.pos.getY());
|
||||
buf.writeInt(this.pos.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the template, writing it to disk.
|
||||
*
|
||||
* @return true if the template was successfully saved.
|
||||
*/
|
||||
public boolean save()
|
||||
{
|
||||
return this.save(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the template, either updating the local version or writing it to disk.
|
||||
*
|
||||
* @return true if the template was successfully saved.
|
||||
*
|
||||
* @param writeToDisk If true, {@link TemplateManager#writeTemplate} will be called with the template, and its
|
||||
* return value will dictate the return value of this method. If false, the template will be updated but not written
|
||||
* to disk.
|
||||
*/
|
||||
public boolean save(boolean writeToDisk)
|
||||
{
|
||||
if (this.mode == TileEntityStructure.Mode.SAVE && !this.world.isRemote && !StringUtils.isNullOrEmpty(this.name))
|
||||
{
|
||||
BlockPos blockpos = this.getPos().add(this.position);
|
||||
WorldServer worldserver = (WorldServer)this.world;
|
||||
MinecraftServer minecraftserver = this.world.getMinecraftServer();
|
||||
TemplateManager templatemanager = worldserver.getStructureTemplateManager();
|
||||
Template template = templatemanager.getTemplate(minecraftserver, new ResourceLocation(this.name));
|
||||
template.takeBlocksFromWorld(this.world, blockpos, this.size, !this.ignoreEntities, Blocks.STRUCTURE_VOID);
|
||||
template.setAuthor(this.author);
|
||||
return !writeToDisk || templatemanager.writeTemplate(minecraftserver, new ResourceLocation(this.name));
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given template, both into this structure block and into the world, aborting if the size of the template
|
||||
* does not match the size in this structure block.
|
||||
*
|
||||
* @return true if the template was successfully added to the world.
|
||||
*/
|
||||
public boolean load()
|
||||
{
|
||||
return this.load(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given template, both into this structure block and into the world.
|
||||
*
|
||||
* @return true if the template was successfully added to the world.
|
||||
*
|
||||
* @param requireMatchingSize If true, and the size of the loaded template does not match the size in this structure
|
||||
* block, the structure will not be loaded into the world and false will be returned. Regardless of the value of
|
||||
* this parameter, the size in the structure block will be updated after calling this method.
|
||||
*/
|
||||
public boolean load(boolean requireMatchingSize)
|
||||
{
|
||||
if (this.mode == TileEntityStructure.Mode.LOAD && !this.world.isRemote && !StringUtils.isNullOrEmpty(this.name))
|
||||
{
|
||||
BlockPos blockpos = this.getPos();
|
||||
BlockPos blockpos1 = blockpos.add(this.position);
|
||||
WorldServer worldserver = (WorldServer)this.world;
|
||||
MinecraftServer minecraftserver = this.world.getMinecraftServer();
|
||||
TemplateManager templatemanager = worldserver.getStructureTemplateManager();
|
||||
Template template = templatemanager.get(minecraftserver, new ResourceLocation(this.name));
|
||||
|
||||
if (template == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!StringUtils.isNullOrEmpty(template.getAuthor()))
|
||||
{
|
||||
this.author = template.getAuthor();
|
||||
}
|
||||
|
||||
BlockPos blockpos2 = template.getSize();
|
||||
boolean flag = this.size.equals(blockpos2);
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
this.size = blockpos2;
|
||||
this.markDirty();
|
||||
IBlockState iblockstate = this.world.getBlockState(blockpos);
|
||||
this.world.notifyBlockUpdate(blockpos, iblockstate, iblockstate, 3);
|
||||
}
|
||||
|
||||
if (requireMatchingSize && !flag)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlacementSettings placementsettings = (new PlacementSettings()).setMirror(this.mirror).setRotation(this.rotation).setIgnoreEntities(this.ignoreEntities).setChunk((ChunkPos)null).setReplacedBlock((Block)null).setIgnoreStructureBlock(false);
|
||||
|
||||
if (this.integrity < 1.0F)
|
||||
{
|
||||
placementsettings.setIntegrity(MathHelper.clamp(this.integrity, 0.0F, 1.0F)).setSeed(Long.valueOf(this.seed));
|
||||
}
|
||||
|
||||
template.addBlocksToWorldChunk(this.world, blockpos1, placementsettings);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadStructure()
|
||||
{
|
||||
WorldServer worldserver = (WorldServer)this.world;
|
||||
TemplateManager templatemanager = worldserver.getStructureTemplateManager();
|
||||
templatemanager.remove(new ResourceLocation(this.name));
|
||||
}
|
||||
|
||||
public boolean isStructureLoadable()
|
||||
{
|
||||
if (this.mode == TileEntityStructure.Mode.LOAD && !this.world.isRemote)
|
||||
{
|
||||
WorldServer worldserver = (WorldServer)this.world;
|
||||
MinecraftServer minecraftserver = this.world.getMinecraftServer();
|
||||
TemplateManager templatemanager = worldserver.getStructureTemplateManager();
|
||||
return templatemanager.get(minecraftserver, new ResourceLocation(this.name)) != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPowered()
|
||||
{
|
||||
return this.powered;
|
||||
}
|
||||
|
||||
public void setPowered(boolean poweredIn)
|
||||
{
|
||||
this.powered = poweredIn;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean showsAir()
|
||||
{
|
||||
return this.showAir;
|
||||
}
|
||||
|
||||
public void setShowAir(boolean showAirIn)
|
||||
{
|
||||
this.showAir = showAirIn;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean showsBoundingBox()
|
||||
{
|
||||
return this.showBoundingBox;
|
||||
}
|
||||
|
||||
public void setShowBoundingBox(boolean showBoundingBoxIn)
|
||||
{
|
||||
this.showBoundingBox = showBoundingBoxIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted ChatComponent that will be used for the sender's username in chat
|
||||
*/
|
||||
@Nullable
|
||||
public ITextComponent getDisplayName()
|
||||
{
|
||||
return new TextComponentTranslation("structure_block.hover." + this.mode.modeName, new Object[] {this.mode == TileEntityStructure.Mode.DATA ? this.metadata : this.name});
|
||||
}
|
||||
|
||||
public static enum Mode implements IStringSerializable
|
||||
{
|
||||
SAVE("save", 0),
|
||||
LOAD("load", 1),
|
||||
CORNER("corner", 2),
|
||||
DATA("data", 3);
|
||||
|
||||
private static final TileEntityStructure.Mode[] MODES = new TileEntityStructure.Mode[values().length];
|
||||
private final String modeName;
|
||||
private final int modeId;
|
||||
|
||||
private Mode(String modeNameIn, int modeIdIn)
|
||||
{
|
||||
this.modeName = modeNameIn;
|
||||
this.modeId = modeIdIn;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return this.modeName;
|
||||
}
|
||||
|
||||
public int getModeId()
|
||||
{
|
||||
return this.modeId;
|
||||
}
|
||||
|
||||
public static TileEntityStructure.Mode getById(int id)
|
||||
{
|
||||
return id >= 0 && id < MODES.length ? MODES[id] : MODES[0];
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
for (TileEntityStructure.Mode tileentitystructure$mode : values())
|
||||
{
|
||||
MODES[tileentitystructure$mode.getModeId()] = tileentitystructure$mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Auto generated package-info by MCP
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraft.tileentity;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
Reference in New Issue
Block a user