package net.minecraft.server;
import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import co.aikar.timings.MinecraftTimings; // Paper
import co.aikar.timings.Timing; // Paper
import org.bukkit.inventory.InventoryHolder; // CraftBukkit
public abstract class TileEntity {
public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper
boolean isLoadingStructure = false; // Paper
private static final Logger a = LogManager.getLogger();
private static final RegistryMaterials<MinecraftKey, Class<? extends TileEntity>> f = new RegistryMaterials();
protected World world;
protected BlockPosition position;
protected boolean d;
private int g;
protected Block e;
public TileEntity() {
this.position = BlockPosition.ZERO;
this.g = -1;
}
private static void a(String s, Class<? extends TileEntity> oclass) {
TileEntity.f.a(new MinecraftKey(s), oclass);
}
@Nullable
public static MinecraftKey a(Class<? extends TileEntity> oclass) {
return TileEntity.f.b(oclass);
}
static boolean IGNORE_TILE_UPDATES = false; // Paper
public World getWorld() {
return this.world;
}
public void a(World world) {
this.world = world;
}
public boolean u() {
return this.world != null;
}
public void a(NBTTagCompound nbttagcompound) {
this.position = new BlockPosition(nbttagcompound.getInt("x"), nbttagcompound.getInt("y"), nbttagcompound.getInt("z"));
}
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
return this.c(nbttagcompound);
}
private NBTTagCompound c(NBTTagCompound nbttagcompound) {
MinecraftKey minecraftkey = TileEntity.f.b(this.getClass());
if (minecraftkey == null) {
throw new RuntimeException(this.getClass() + " is missing a mapping! This is a bug!");
} else {
nbttagcompound.setString("id", minecraftkey.toString());
nbttagcompound.setInt("x", this.position.getX());
nbttagcompound.setInt("y", this.position.getY());
nbttagcompound.setInt("z", this.position.getZ());
return nbttagcompound;
}
}
@Nullable
public static TileEntity a(World world, NBTTagCompound nbttagcompound) {
TileEntity tileentity = null;
String s = nbttagcompound.getString("id");
try {
Class oclass = TileEntity.f.get(new MinecraftKey(s));
if (oclass != null) {
tileentity = (TileEntity) oclass.newInstance();
}
} catch (Throwable throwable) {
TileEntity.a.error("Failed to create block entity {}", new Object[] { s, throwable});
}
if (tileentity != null) {
try {
tileentity.b(world);
tileentity.a(nbttagcompound);
} catch (Throwable throwable1) {
TileEntity.a.error("Failed to load data for block entity {}", new Object[] { s, throwable1});
tileentity = null;
}
} else {
TileEntity.a.warn("Skipping BlockEntity with id {}", new Object[] { s});
}
return tileentity;
}
protected void b(World world) {}
public int v() {
if (this.g == -1) {
IBlockData iblockdata = this.world.getType(this.position);
this.g = iblockdata.getBlock().toLegacyData(iblockdata);
}
return this.g;
}
public void update() {
if (this.world != null) {
if (IGNORE_TILE_UPDATES) return; // Paper
IBlockData iblockdata = this.world.getType(this.position);
this.g = iblockdata.getBlock().toLegacyData(iblockdata);
this.world.b(this.position, this);
if (this.getBlock() != Blocks.AIR) {
this.world.updateAdjacentComparators(this.position, this.getBlock());
}
}
}
public BlockPosition getPosition() {
return this.position;
}
public Block getBlock() {
if (this.e == null && this.world != null) {
this.e = this.world.getType(this.position).getBlock();
}
return this.e;
}
@Nullable
public PacketPlayOutTileEntityData getUpdatePacket() {
return null;
}
public NBTTagCompound d() {
return this.c(new NBTTagCompound());
}
public boolean y() {
return this.d;
}
public void z() {
this.d = true;
}
public void A() {
this.d = false;
}
public boolean c(int i, int j) {
return false;
}
public void invalidateBlockCache() {
this.e = null;
this.g = -1;
}
public void a(CrashReportSystemDetails crashreportsystemdetails) {
crashreportsystemdetails.a("Name", new CrashReportCallable() {
public String a() throws Exception {
return TileEntity.f.b(TileEntity.this.getClass()) + " // " + TileEntity.this.getClass().getCanonicalName();
}
@Override
public Object call() throws Exception {
return this.a();
}
});
if (this.world != null) {
// Paper start - Prevent TileEntity and Entity crashes
Block block = this.getBlock();
if (block != null) {
CrashReportSystemDetails.a(crashreportsystemdetails, this.position, this.getBlock(), this.v());
}
// Paper end
crashreportsystemdetails.a("Actual block type", new CrashReportCallable() {
public String a() throws Exception {
int i = Block.getId(TileEntity.this.world.getType(TileEntity.this.position).getBlock());
try {
return String.format("ID #%d (%s // %s)", new Object[] { Integer.valueOf(i), Block.getById(i).a(), Block.getById(i).getClass().getCanonicalName()});
} catch (Throwable throwable) {
return "ID #" + i;
}
}
@Override
public Object call() throws Exception {
return this.a();
}
});
crashreportsystemdetails.a("Actual block data value", new CrashReportCallable() {
public String a() throws Exception {
IBlockData iblockdata = TileEntity.this.world.getType(TileEntity.this.position);
int i = iblockdata.getBlock().toLegacyData(iblockdata);
if (i < 0) {
return "Unknown? (Got " + i + ")";
} else {
String s = String.format("%4s", new Object[] { Integer.toBinaryString(i)}).replace(" ", "0");
return String.format("%1$d / 0x%1$X / 0b%2$s", new Object[] { Integer.valueOf(i), s});
}
}
@Override
public Object call() throws Exception {
return this.a();
}
});
}
}
public void setPosition(BlockPosition blockposition) {
this.position = blockposition.h();
}
public boolean isFilteredNBT() {
return false;
}
@Nullable
public IChatBaseComponent i_() {
return null;
}
public void a(EnumBlockRotation enumblockrotation) {}
public void a(EnumBlockMirror enumblockmirror) {}
static {
a("furnace", TileEntityFurnace.class);
a("chest", TileEntityChest.class);
a("ender_chest", TileEntityEnderChest.class);
a("jukebox", BlockJukeBox.TileEntityRecordPlayer.class);
a("dispenser", TileEntityDispenser.class);
a("dropper", TileEntityDropper.class);
a("sign", TileEntitySign.class);
a("mob_spawner", TileEntityMobSpawner.class);
a("noteblock", TileEntityNote.class);
a("piston", TileEntityPiston.class);
a("brewing_stand", TileEntityBrewingStand.class);
a("enchanting_table", TileEntityEnchantTable.class);
a("end_portal", TileEntityEnderPortal.class);
a("beacon", TileEntityBeacon.class);
a("skull", TileEntitySkull.class);
a("daylight_detector", TileEntityLightDetector.class);
a("hopper", TileEntityHopper.class);
a("comparator", TileEntityComparator.class);
a("flower_pot", TileEntityFlowerPot.class);
a("banner", TileEntityBanner.class);
a("structure_block", TileEntityStructure.class);
a("end_gateway", TileEntityEndGateway.class);
a("command_block", TileEntityCommand.class);
a("shulker_box", TileEntityShulkerBox.class);
}
// CraftBukkit start - add method
public InventoryHolder getOwner() {
if (world == null) return null;
// Spigot start
org.bukkit.block.Block block = world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ());
if (block == null) {
org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "No block for owner at %s %d %d %d", new Object[]{world.getWorld(), position.getX(), position.getY(), position.getZ()});
return null;
}
// Spigot end
org.bukkit.block.BlockState state = block.getState();
if (state instanceof InventoryHolder) return (InventoryHolder) state;
return null;
}
// CraftBukkit end
}