package net.minecraft.server;
import com.destroystokyo.paper.event.server.ServerExceptionEvent;
import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nullable;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.event.block.BlockCanBuildEvent;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.generator.ChunkGenerator;
// Paper start
import java.util.Set;
import com.koloboke.collect.map.hash.HashIntObjMap;
import com.koloboke.collect.map.hash.HashIntObjMaps;
// Paper end
import com.koloboke.collect.map.hash.HashObjFloatMaps;
import com.koloboke.collect.map.hash.HashObjObjMaps;
import com.koloboke.collect.set.hash.HashObjSets;
public abstract class World implements IBlockAccess {
private int a = 63;
protected boolean d;
// Spigot start - guard entity list from removals
public final List<Entity> entityList = new java.util.ArrayList<Entity>()
{
@Override
public Entity remove(int index)
{
guard();
return super.remove( index );
}
@Override
public boolean remove(Object o)
{
guard();
return super.remove( o );
}
private void guard()
{
if ( guardEntityList )
{
throw new java.util.ConcurrentModificationException();
}
}
};
// Spigot end
protected final Set<Entity> f = HashObjSets.newMutableSet(); // Paper
//public final List<TileEntity> tileEntityList = Lists.newArrayList(); // Paper - remove unused list
public final List<TileEntity> tileEntityListTick = Lists.newArrayList();
private final List<TileEntity> b = Lists.newArrayList();
private final Set<TileEntity> tileEntityListUnload = HashObjSets.newMutableSet(); // Paper
public final List<EntityHuman> players = Lists.newArrayList();
public final List<Entity> j = Lists.newArrayList();
protected final IntHashMap<Entity> entitiesById = new IntHashMap<Entity>();
private final long I = 16777215L;
private int J;
protected int l = ThreadLocalRandom.current().nextInt();
protected final int m = 1013904223;
protected float n;
public float o;
protected float p;
public float q;
private int K;
public final Random random = new Random();
public WorldProvider worldProvider;
protected NavigationListener t = new NavigationListener();
protected List<IWorldAccess> u;
protected IChunkProvider chunkProvider;
protected final IDataManager dataManager;
public WorldData worldData;
protected boolean isLoading;
public PersistentCollection worldMaps;
protected PersistentVillage villages;
protected LootTableRegistry B;
public final MethodProfiler methodProfiler;
private final Calendar L;
public Scoreboard scoreboard;
public final boolean isClientSide;
public boolean allowMonsters;
public boolean allowAnimals;
private boolean M;
private final WorldBorder N;
int[] H;
// CraftBukkit start Added the following
private final CraftWorld world;
public boolean pvpMode;
public boolean keepSpawnInMemory = true;
public ChunkGenerator generator;
public boolean captureBlockStates = false;
public boolean captureTreeGeneration = false;
public ArrayList<BlockState> capturedBlockStates= new ArrayList<BlockState>(){
@Override
public boolean add( BlockState blockState ) {
Iterator<BlockState> blockStateIterator = this.iterator();
while( blockStateIterator.hasNext() ) {
BlockState blockState1 = blockStateIterator.next();
if ( blockState1.getLocation().equals( blockState.getLocation() ) ) {
return false;
}
}
return super.add( blockState );
}
};
public long ticksPerAnimalSpawns;
public long ticksPerMonsterSpawns;
public boolean populating;
private int tickPosition;
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
private boolean guardEntityList; // Spigot
public static boolean haveWeSilencedAPhysicsCrash;
public static String blockLocation;
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
public final Map<Explosion.CacheKey, Float> explosionDensityCache = HashObjFloatMaps.newMutableMap(); // Paper - Optimize explosions
public CraftWorld getWorld() {
return this.world;
}
public CraftServer getServer() {
return (CraftServer) Bukkit.getServer();
}
// Paper start
public Chunk getChunkIfLoaded(BlockPosition blockposition) {
return this.chunkProvider.getLoadedChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4);
}
// Paper end
public Chunk getChunkIfLoaded(int x, int z) {
return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x, z);
}
protected World(IDataManager idatamanager, WorldData worlddata, WorldProvider worldprovider, MethodProfiler methodprofiler, boolean flag, ChunkGenerator gen, org.bukkit.World.Environment env) {
this.spigotConfig = new org.spigotmc.SpigotWorldConfig( worlddata.getName() ); // Spigot
this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(worlddata.getName(), this.spigotConfig); // Paper
this.generator = gen;
this.world = new CraftWorld((WorldServer) this, gen, env);
this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit
this.ticksPerMonsterSpawns = this.getServer().getTicksPerMonsterSpawns(); // CraftBukkit
// CraftBukkit end
this.u = Lists.newArrayList(new IWorldAccess[] { this.t});
this.L = Calendar.getInstance();
this.scoreboard = new Scoreboard();
this.allowMonsters = true;
this.allowAnimals = true;
this.H = new int['\u8000'];
this.dataManager = idatamanager;
this.methodProfiler = methodprofiler;
this.worldData = worlddata;
this.worldProvider = worldprovider;
this.isClientSide = flag;
this.N = worldprovider.getWorldBorder();
// CraftBukkit start
getWorldBorder().world = (WorldServer) this;
// From PlayerList.setPlayerFileData
getWorldBorder().a(new IWorldBorderListener() {
@Override
public void a(WorldBorder worldborder, double d0) {
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.SET_SIZE), worldborder.world);
}
@Override
public void a(WorldBorder worldborder, double d0, double d1, long i) {
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.LERP_SIZE), worldborder.world);
}
@Override
public void a(WorldBorder worldborder, double d0, double d1) {
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.SET_CENTER), worldborder.world);
}
@Override
public void a(WorldBorder worldborder, int i) {
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.SET_WARNING_TIME), worldborder.world);
}
@Override
public void b(WorldBorder worldborder, int i) {
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.SET_WARNING_BLOCKS), worldborder.world);
}
@Override
public void b(WorldBorder worldborder, double d0) {}
@Override
public void c(WorldBorder worldborder, double d0) {}
});
this.getServer().addWorld(this.world);
// CraftBukkit end
timings = new co.aikar.timings.WorldTimingsHandler(this); // Paper - code below can generate new world and access timings
this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper
this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
}
public World b() {
return this;
}
public BiomeBase getBiome(final BlockPosition blockposition) {
if (this.isLoaded(blockposition)) {
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
try {
return chunk.getBiome(blockposition, this.worldProvider.k());
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Getting biome");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Coordinates of biome request");
crashreportsystemdetails.a("Location", new CrashReportCallable() {
public String a() throws Exception {
return CrashReportSystemDetails.a(blockposition);
}
@Override
public Object call() throws Exception {
return this.a();
}
});
throw new ReportedException(crashreport);
}
} else {
return this.worldProvider.k().getBiome(blockposition, Biomes.c);
}
}
public WorldChunkManager getWorldChunkManager() {
return this.worldProvider.k();
}
protected abstract IChunkProvider n();
public void a(WorldSettings worldsettings) {
this.worldData.d(true);
}
@Nullable
public MinecraftServer getMinecraftServer() {
return null;
}
public IBlockData c(BlockPosition blockposition) {
BlockPosition blockposition1;
for (blockposition1 = new BlockPosition(blockposition.getX(), this.K(), blockposition.getZ()); !this.isEmpty(blockposition1.up()); blockposition1 = blockposition1.up()) {
;
}
return this.getType(blockposition1);
}
private static boolean isValidLocation(BlockPosition blockposition) { // Paper - unused but incase reflection / future uses
return blockposition.isValidLocation(); // Paper
}
private static boolean E(BlockPosition blockposition) { // Paper - unused but incase reflection / future uses
return blockposition.isInvalidYLocation(); // Paper
}
@Override
public boolean isEmpty(BlockPosition blockposition) {
return this.getType(blockposition).getMaterial() == Material.AIR;
}
public boolean isLoaded(BlockPosition blockposition) {
return getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null; // Paper
}
public boolean a(BlockPosition blockposition, boolean flag) {
return this.isChunkLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4, flag);
}
public boolean areChunksLoaded(BlockPosition blockposition, int i) {
return this.areChunksLoaded(blockposition, i, true);
}
public boolean areChunksLoaded(BlockPosition blockposition, int i, boolean flag) {
return this.isAreaLoaded(blockposition.getX() - i, blockposition.getY() - i, blockposition.getZ() - i, blockposition.getX() + i, blockposition.getY() + i, blockposition.getZ() + i, flag);
}
public boolean areChunksLoadedBetween(BlockPosition blockposition, BlockPosition blockposition1) {
return this.areChunksLoadedBetween(blockposition, blockposition1, true);
}
public boolean areChunksLoadedBetween(BlockPosition blockposition, BlockPosition blockposition1, boolean flag) {
return this.isAreaLoaded(blockposition.getX(), blockposition.getY(), blockposition.getZ(), blockposition1.getX(), blockposition1.getY(), blockposition1.getZ(), flag);
}
public boolean a(StructureBoundingBox structureboundingbox) {
return this.b(structureboundingbox, true);
}
public boolean b(StructureBoundingBox structureboundingbox, boolean flag) {
return this.isAreaLoaded(structureboundingbox.a, structureboundingbox.b, structureboundingbox.c, structureboundingbox.d, structureboundingbox.e, structureboundingbox.f, flag);
}
private boolean isAreaLoaded(int i, int j, int k, int l, int i1, int j1, boolean flag) {
if (i1 >= 0 && j < 256) {
i >>= 4;
k >>= 4;
l >>= 4;
j1 >>= 4;
for (int k1 = i; k1 <= l; ++k1) {
for (int l1 = k; l1 <= j1; ++l1) {
if (!this.isChunkLoaded(k1, l1, flag)) {
return false;
}
}
}
return true;
} else {
return false;
}
}
protected abstract boolean isChunkLoaded(int i, int j, boolean flag);
public Chunk getChunkAtWorldCoords(BlockPosition blockposition) {
return this.getChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4);
}
public Chunk getChunkAt(int i, int j) {
return this.chunkProvider.getChunkAt(i, j);
}
public boolean b(int i, int j) {
return this.isChunkLoaded(i, j, false) ? true : this.chunkProvider.e(i, j);
}
/**
* Sets the block state at a given location, flags can be added together.
* Flag 1 will cause a block update.
* Flag 2 will send the change to clients (you almost always want this).
* Flag 4 prevents the block from being re-rendered, if this is a client world.
*/
public boolean setTypeAndData(BlockPosition blockposition, IBlockData iblockdata, int flags) {
// CraftBukkit start - tree generation
if (this.captureTreeGeneration) {
BlockState blockstate = null;
Iterator<BlockState> it = capturedBlockStates.iterator();
while (it.hasNext()) {
BlockState previous = it.next();
if (previous.getX() == blockposition.getX() && previous.getY() == blockposition.getY() && previous.getZ() == blockposition.getZ()) {
blockstate = previous;
it.remove();
break;
}
}
if (blockstate == null) {
blockstate = org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(this, blockposition.getX(), blockposition.getY(), blockposition.getZ(), flags);
}
blockstate.setTypeId(CraftMagicNumbers.getId(iblockdata.getBlock()));
blockstate.setRawData((byte) iblockdata.getBlock().toLegacyData(iblockdata));
this.capturedBlockStates.add(blockstate);
return true;
}
// CraftBukkit end
if (blockposition.isInvalidYLocation()) { // Paper
return false;
} else if (!this.isClientSide && this.worldData.getType() == WorldType.DEBUG_ALL_BLOCK_STATES) {
return false;
} else {
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
Block block = iblockdata.getBlock();
// CraftBukkit start - capture blockstates
BlockState blockstate = null;
if (this.captureBlockStates) {
blockstate = org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(this, blockposition.getX(), blockposition.getY(), blockposition.getZ(), flags);
this.capturedBlockStates.add(blockstate);
}
// CraftBukkit end
IBlockData iblockdata1 = chunk.a(blockposition, iblockdata);
if (iblockdata1 == null) {
// CraftBukkit start - remove blockstate if failed
if (this.captureBlockStates) {
this.capturedBlockStates.remove(blockstate);
}
// CraftBukkit end
return false;
} else {
if (iblockdata.c() != iblockdata1.c() || iblockdata.d() != iblockdata1.d()) {
this.methodProfiler.a("checkLight");
chunk.lightingQueue.add(() -> this.w(blockposition)); // Paper - Queue light update
}
/*
if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && chunk.isReady()) {
this.notify(blockposition, iblockdata1, iblockdata, i);
}
if (!this.isClientSide && (i & 1) != 0) {
this.update(blockposition, iblockdata1.getBlock(), true);
if (iblockdata.o()) {
this.updateAdjacentComparators(blockposition, block);
}
} else if (!this.isClientSide && (i & 16) == 0) {
this.c(blockposition, block);
}
*/
// CraftBukkit start
if (!this.captureBlockStates) { // Don't notify clients or update physics while capturing blockstates
// Modularize client and physic updates
notifyAndUpdatePhysics(blockposition, chunk, iblockdata1, iblockdata, flags);
}
// CraftBukkit end
return true;
}
}
}
// CraftBukkit start - Split off from above in order to directly send client and physic updates
public void notifyAndUpdatePhysics(BlockPosition blockposition, Chunk chunk, IBlockData oldBlock, IBlockData newBlock, int i) {
if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (chunk == null || chunk.isReady())) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement
this.notify(blockposition, oldBlock, newBlock, i);
}
if (!this.isClientSide && (i & 1) != 0) {
this.update(blockposition, oldBlock.getBlock(), true);
if (newBlock.o()) {
this.updateAdjacentComparators(blockposition, newBlock.getBlock());
}
} else if (!this.isClientSide && (i & 16) == 0) {
this.c(blockposition, newBlock.getBlock());
}
}
// CraftBukkit end
public boolean setAir(BlockPosition blockposition) {
return this.setTypeAndData(blockposition, Blocks.AIR.getBlockData(), 3);
}
public boolean setAir(BlockPosition blockposition, boolean flag) {
IBlockData iblockdata = this.getType(blockposition);
Block block = iblockdata.getBlock();
if (iblockdata.getMaterial() == Material.AIR) {
return false;
} else {
this.triggerEffect(2001, blockposition, Block.getCombinedId(iblockdata));
if (flag) {
block.b(this, blockposition, iblockdata, 0);
}
return this.setTypeAndData(blockposition, Blocks.AIR.getBlockData(), 3);
}
}
public boolean setTypeUpdate(BlockPosition blockposition, IBlockData iblockdata) {
return this.setTypeAndData(blockposition, iblockdata, 3);
}
public void notify(BlockPosition blockposition, IBlockData iblockdata, IBlockData iblockdata1, int i) {
for (int j = 0; j < this.u.size(); ++j) {
this.u.get(j).a(this, blockposition, iblockdata, iblockdata1, i);
}
}
public void update(BlockPosition blockposition, Block block, boolean flag) {
if (this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES) {
// CraftBukkit start
if (populating) {
return;
}
// CraftBukkit end
this.applyPhysics(blockposition, block, flag);
}
}
public void a(int i, int j, int k, int l) {
int i1;
if (k > l) {
i1 = l;
l = k;
k = i1;
}
if (this.worldProvider.m()) {
for (i1 = k; i1 <= l; ++i1) {
this.c(EnumSkyBlock.SKY, new BlockPosition(i, i1, j));
}
}
this.b(i, k, j, i, l, j);
}
public void b(BlockPosition blockposition, BlockPosition blockposition1) {
this.b(blockposition.getX(), blockposition.getY(), blockposition.getZ(), blockposition1.getX(), blockposition1.getY(), blockposition1.getZ());
}
public void b(int i, int j, int k, int l, int i1, int j1) {
for (int k1 = 0; k1 < this.u.size(); ++k1) {
this.u.get(k1).a(i, j, k, l, i1, j1);
}
}
public void c(BlockPosition blockposition, Block block) {
this.b(blockposition.west(), block, blockposition);
this.b(blockposition.east(), block, blockposition);
this.b(blockposition.down(), block, blockposition);
this.b(blockposition.up(), block, blockposition);
this.b(blockposition.north(), block, blockposition);
this.b(blockposition.south(), block, blockposition);
}
public void applyPhysics(BlockPosition blockposition, Block block, boolean flag) {
if (captureBlockStates) { return; } // Paper - Cancel all physics during placement
this.a(blockposition.west(), block, blockposition);
this.a(blockposition.east(), block, blockposition);
this.a(blockposition.down(), block, blockposition);
this.a(blockposition.up(), block, blockposition);
this.a(blockposition.north(), block, blockposition);
this.a(blockposition.south(), block, blockposition);
if (flag) {
this.c(blockposition, block);
}
}
public void a(BlockPosition blockposition, Block block, EnumDirection enumdirection) {
if (enumdirection != EnumDirection.WEST) {
this.a(blockposition.west(), block, blockposition);
}
if (enumdirection != EnumDirection.EAST) {
this.a(blockposition.east(), block, blockposition);
}
if (enumdirection != EnumDirection.DOWN) {
this.a(blockposition.down(), block, blockposition);
}
if (enumdirection != EnumDirection.UP) {
this.a(blockposition.up(), block, blockposition);
}
if (enumdirection != EnumDirection.NORTH) {
this.a(blockposition.north(), block, blockposition);
}
if (enumdirection != EnumDirection.SOUTH) {
this.a(blockposition.south(), block, blockposition);
}
}
/** PAIL: neighborChanged */
public void a(BlockPosition blockposition, final Block block, BlockPosition blockposition1) {
if (!this.isClientSide) {
IBlockData iblockdata = this.getType(blockposition);
try {
// CraftBukkit start
CraftWorld world = ((WorldServer) this).getWorld();
if (world != null && !((WorldServer)this).stopPhysicsEvent) { // Paper
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftMagicNumbers.getId(block));
this.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
// CraftBukkit end
iblockdata.doPhysics(this, blockposition, block, blockposition1);
} catch (StackOverflowError stackoverflowerror) { // Spigot Start
haveWeSilencedAPhysicsCrash = true;
blockLocation = blockposition.getX() + ", " + blockposition.getY() + ", " + blockposition.getZ();
// Spigot End
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Exception while updating neighbours");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Block being updated");
crashreportsystemdetails.a("Source block type", new CrashReportCallable() {
public String a() throws Exception {
try {
return String.format("ID #%d (%s // %s)", new Object[] { Integer.valueOf(Block.getId(block)), block.a(), block.getClass().getCanonicalName()});
} catch (Throwable throwable) {
return "ID #" + Block.getId(block);
}
}
@Override
public Object call() throws Exception {
return this.a();
}
});
CrashReportSystemDetails.a(crashreportsystemdetails, blockposition, iblockdata);
throw new ReportedException(crashreport);
}
}
}
public void b(BlockPosition blockposition, final Block block, BlockPosition blockposition1) {
if (!this.isClientSide) {
IBlockData iblockdata = this.getType(blockposition);
if (iblockdata.getBlock() == Blocks.dk) {
try {
((BlockObserver) iblockdata.getBlock()).b(iblockdata, this, blockposition, block, blockposition1);
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Exception while updating neighbours");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Block being updated");
crashreportsystemdetails.a("Source block type", new CrashReportCallable() {
public String a() throws Exception {
try {
return String.format("ID #%d (%s // %s)", new Object[] { Integer.valueOf(Block.getId(block)), block.a(), block.getClass().getCanonicalName()});
} catch (Throwable throwable) {
return "ID #" + Block.getId(block);
}
}
@Override
public Object call() throws Exception {
return this.a();
}
});
CrashReportSystemDetails.a(crashreportsystemdetails, blockposition, iblockdata);
throw new ReportedException(crashreport);
}
}
}
}
public boolean a(BlockPosition blockposition, Block block) {
return false;
}
public boolean h(BlockPosition blockposition) {
return this.getChunkAtWorldCoords(blockposition).c(blockposition);
}
public boolean i(BlockPosition blockposition) {
if (blockposition.getY() >= this.K()) {
return this.h(blockposition);
} else {
BlockPosition blockposition1 = new BlockPosition(blockposition.getX(), this.K(), blockposition.getZ());
if (!this.h(blockposition1)) {
return false;
} else {
for (blockposition1 = blockposition1.down(); blockposition1.getY() > blockposition.getY(); blockposition1 = blockposition1.down()) {
IBlockData iblockdata = this.getType(blockposition1);
if (iblockdata.c() > 0 && !iblockdata.getMaterial().isLiquid()) {
return false;
}
}
return true;
}
}
}
public int j(BlockPosition blockposition) {
if (blockposition.getY() < 0) {
return 0;
} else {
if (blockposition.getY() >= 256) {
blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ());
}
return this.getChunkAtWorldCoords(blockposition).a(blockposition, 0);
}
}
// Paper start - test if meets light level, return faster
// logic copied from below
public boolean isLightLevel(BlockPosition blockposition, int level) {
if (blockposition.isValidLocation()) {
if (this.getType(blockposition).f()) {
if (this.c(blockposition.up(), false) >= level) {
return true;
}
if (this.c(blockposition.east(), false) >= level) {
return true;
}
if (this.c(blockposition.west(), false) >= level) {
return true;
}
if (this.c(blockposition.south(), false) >= level) {
return true;
}
if (this.c(blockposition.north(), false) >= level) {
return true;
}
return false;
} else {
if (blockposition.getY() >= 256) {
blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ());
}
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
return chunk.a(blockposition, this.J) >= level;
}
} else {
return true;
}
}
// Paper end
public int getLightLevel(BlockPosition blockposition) {
return this.c(blockposition, true);
}
public int c(BlockPosition blockposition, boolean flag) {
if (blockposition.getX() >= -30000000 && blockposition.getZ() >= -30000000 && blockposition.getX() < 30000000 && blockposition.getZ() < 30000000) {
if (flag && this.getType(blockposition).f()) {
int i = this.c(blockposition.up(), false);
int j = this.c(blockposition.east(), false);
int k = this.c(blockposition.west(), false);
int l = this.c(blockposition.south(), false);
int i1 = this.c(blockposition.north(), false);
if (j > i) {
i = j;
}
if (k > i) {
i = k;
}
if (l > i) {
i = l;
}
if (i1 > i) {
i = i1;
}
return i;
} else if (blockposition.getY() < 0) {
return 0;
} else {
if (blockposition.getY() >= 256) {
blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ());
}
if (!this.isLoaded(blockposition)) return 0; // Paper
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
return chunk.a(blockposition, this.J);
}
} else {
return 15;
}
}
public BlockPosition getHighestBlockYAt(BlockPosition blockposition) {
return new BlockPosition(blockposition.getX(), this.c(blockposition.getX(), blockposition.getZ()), blockposition.getZ());
}
public int c(int i, int j) {
int k;
if (i >= -30000000 && j >= -30000000 && i < 30000000 && j < 30000000) {
if (this.isChunkLoaded(i >> 4, j >> 4, true)) {
k = this.getChunkAt(i >> 4, j >> 4).b(i & 15, j & 15);
} else {
k = 0;
}
} else {
k = this.K() + 1;
}
return k;
}
@Deprecated
public int d(int i, int j) {
if (i >= -30000000 && j >= -30000000 && i < 30000000 && j < 30000000) {
if (!this.isChunkLoaded(i >> 4, j >> 4, true)) {
return 0;
} else {
Chunk chunk = this.getChunkAt(i >> 4, j >> 4);
return chunk.w();
}
} else {
return this.K() + 1;
}
}
public int getBrightness(EnumSkyBlock enumskyblock, BlockPosition blockposition) {
if (blockposition.getY() < 0) {
blockposition = new BlockPosition(blockposition.getX(), 0, blockposition.getZ());
}
if (!blockposition.isValidLocation()) { // Paper
return enumskyblock.c;
} else if (!this.isLoaded(blockposition)) {
return enumskyblock.c;
} else {
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
return chunk.getBrightness(enumskyblock, blockposition);
}
}
public void a(EnumSkyBlock enumskyblock, BlockPosition blockposition, int i) {
if (blockposition.isValidLocation()) { // Paper
if (this.isLoaded(blockposition)) {
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
chunk.a(enumskyblock, blockposition, i);
this.m(blockposition);
}
}
}
public void m(BlockPosition blockposition) {
for (int i = 0; i < this.u.size(); ++i) {
this.u.get(i).a(blockposition);
}
}
public float n(BlockPosition blockposition) {
return this.worldProvider.o()[this.getLightLevel(blockposition)];
}
// Paper start - reduces need to do isLoaded before getType
public IBlockData getTypeIfLoaded(BlockPosition blockposition) {
// CraftBukkit start - tree generation
final int x = blockposition.getX();
final int y = blockposition.getY();
final int z = blockposition.getZ();
if (captureTreeGeneration) {
final IBlockData previous = getCapturedBlockType(x, y, z);
if (previous != null) {
return previous;
}
}
// CraftBukkit end
Chunk chunk = ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x >> 4, z >> 4);
if (chunk != null) {
return chunk.getBlockData(x, y, z);
}
return null;
}
// Paper end
@Override
public IBlockData getType(BlockPosition blockposition) {
// CraftBukkit start - tree generation
// Paper start - optimize getType lookup to reduce instructions - getBlockData already enforces valid Y, move tree out
final int x = blockposition.getX();
final int y = blockposition.getY();
final int z = blockposition.getZ();
if (captureTreeGeneration) {
final IBlockData previous = getCapturedBlockType(x, y, z);
if (previous != null) {
return previous;
}
}
// CraftBukkit end
return this.chunkProvider.getChunkAt(x >> 4, z >> 4).getBlockData(x, y, z);
// Paper end
}
// Paper start
private IBlockData getCapturedBlockType(int x, int y, int z) {
Iterator<BlockState> it = capturedBlockStates.iterator();
while (it.hasNext()) {
BlockState previous = it.next();
if (previous.getX() == x && previous.getY() == y && previous.getZ() == z) {
return CraftMagicNumbers.getBlock(previous.getTypeId()).fromLegacyData(previous.getRawData());
}
}
return null;
}
// Paper end
public boolean B() {
return this.J < 4;
}
@Nullable
public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1) {
return this.rayTrace(vec3d, vec3d1, false, false, false);
}
@Nullable
public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1, boolean flag) {
return this.rayTrace(vec3d, vec3d1, flag, false, false);
}
@Nullable
public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1, boolean flag, boolean flag1, boolean flag2) {
if (!Double.isNaN(vec3d.x) && !Double.isNaN(vec3d.y) && !Double.isNaN(vec3d.z)) {
if (!Double.isNaN(vec3d1.x) && !Double.isNaN(vec3d1.y) && !Double.isNaN(vec3d1.z)) {
int i = MathHelper.floor(vec3d1.x);
int j = MathHelper.floor(vec3d1.y);
int k = MathHelper.floor(vec3d1.z);
int l = MathHelper.floor(vec3d.x);
int i1 = MathHelper.floor(vec3d.y);
int j1 = MathHelper.floor(vec3d.z);
BlockPosition blockposition = new BlockPosition(l, i1, j1);
IBlockData iblockdata = this.getType(blockposition);
Block block = iblockdata.getBlock();
if ((!flag1 || iblockdata.c(this, blockposition) != Block.k) && block.a(iblockdata, flag)) {
MovingObjectPosition movingobjectposition = iblockdata.a(this, blockposition, vec3d, vec3d1);
if (movingobjectposition != null) {
return movingobjectposition;
}
}
MovingObjectPosition movingobjectposition1 = null;
int k1 = 200;
while (k1-- >= 0) {
if (Double.isNaN(vec3d.x) || Double.isNaN(vec3d.y) || Double.isNaN(vec3d.z)) {
return null;
}
if (l == i && i1 == j && j1 == k) {
return flag2 ? movingobjectposition1 : null;
}
boolean flag3 = true;
boolean flag4 = true;
boolean flag5 = true;
double d0 = 999.0D;
double d1 = 999.0D;
double d2 = 999.0D;
if (i > l) {
d0 = l + 1.0D;
} else if (i < l) {
d0 = l + 0.0D;
} else {
flag3 = false;
}
if (j > i1) {
d1 = i1 + 1.0D;
} else if (j < i1) {
d1 = i1 + 0.0D;
} else {
flag4 = false;
}
if (k > j1) {
d2 = j1 + 1.0D;
} else if (k < j1) {
d2 = j1 + 0.0D;
} else {
flag5 = false;
}
double d3 = 999.0D;
double d4 = 999.0D;
double d5 = 999.0D;
double d6 = vec3d1.x - vec3d.x;
double d7 = vec3d1.y - vec3d.y;
double d8 = vec3d1.z - vec3d.z;
if (flag3) {
d3 = (d0 - vec3d.x) / d6;
}
if (flag4) {
d4 = (d1 - vec3d.y) / d7;
}
if (flag5) {
d5 = (d2 - vec3d.z) / d8;
}
if (d3 == -0.0D) {
d3 = -1.0E-4D;
}
if (d4 == -0.0D) {
d4 = -1.0E-4D;
}
if (d5 == -0.0D) {
d5 = -1.0E-4D;
}
EnumDirection enumdirection;
if (d3 < d4 && d3 < d5) {
enumdirection = i > l ? EnumDirection.WEST : EnumDirection.EAST;
vec3d = new Vec3D(d0, vec3d.y + d7 * d3, vec3d.z + d8 * d3);
} else if (d4 < d5) {
enumdirection = j > i1 ? EnumDirection.DOWN : EnumDirection.UP;
vec3d = new Vec3D(vec3d.x + d6 * d4, d1, vec3d.z + d8 * d4);
} else {
enumdirection = k > j1 ? EnumDirection.NORTH : EnumDirection.SOUTH;
vec3d = new Vec3D(vec3d.x + d6 * d5, vec3d.y + d7 * d5, d2);
}
l = MathHelper.floor(vec3d.x) - (enumdirection == EnumDirection.EAST ? 1 : 0);
i1 = MathHelper.floor(vec3d.y) - (enumdirection == EnumDirection.UP ? 1 : 0);
j1 = MathHelper.floor(vec3d.z) - (enumdirection == EnumDirection.SOUTH ? 1 : 0);
blockposition = new BlockPosition(l, i1, j1);
IBlockData iblockdata1 = this.getType(blockposition);
Block block1 = iblockdata1.getBlock();
if (!flag1 || iblockdata1.getMaterial() == Material.PORTAL || iblockdata1.c(this, blockposition) != Block.k) {
if (block1.a(iblockdata1, flag)) {
MovingObjectPosition movingobjectposition2 = iblockdata1.a(this, blockposition, vec3d, vec3d1);
if (movingobjectposition2 != null) {
return movingobjectposition2;
}
} else {
movingobjectposition1 = new MovingObjectPosition(MovingObjectPosition.EnumMovingObjectType.MISS, vec3d, enumdirection, blockposition);
}
}
}
return flag2 ? movingobjectposition1 : null;
} else {
return null;
}
} else {
return null;
}
}
public void a(@Nullable EntityHuman entityhuman, BlockPosition blockposition, SoundEffect soundeffect, SoundCategory soundcategory, float f, float f1) {
this.a(entityhuman, blockposition.getX() + 0.5D, blockposition.getY() + 0.5D, blockposition.getZ() + 0.5D, soundeffect, soundcategory, f, f1);
}
public void a(@Nullable EntityHuman entityhuman, double d0, double d1, double d2, SoundEffect soundeffect, SoundCategory soundcategory, float f, float f1) {
for (int i = 0; i < this.u.size(); ++i) {
this.u.get(i).a(entityhuman, soundeffect, soundcategory, d0, d1, d2, f, f1);
}
}
public void a(double d0, double d1, double d2, SoundEffect soundeffect, SoundCategory soundcategory, float f, float f1, boolean flag) {}
public void a(BlockPosition blockposition, @Nullable SoundEffect soundeffect) {
for (int i = 0; i < this.u.size(); ++i) {
this.u.get(i).a(soundeffect, blockposition);
}
}
public void addParticle(EnumParticle enumparticle, double d0, double d1, double d2, double d3, double d4, double d5, int... aint) {
this.a(enumparticle.c(), enumparticle.e(), d0, d1, d2, d3, d4, d5, aint);
}
public void a(int i, double d0, double d1, double d2, double d3, double d4, double d5, int... aint) {
for (int j = 0; j < this.u.size(); ++j) {
this.u.get(j).a(i, false, true, d0, d1, d2, d3, d4, d5, aint);
}
}
private void a(int i, boolean flag, double d0, double d1, double d2, double d3, double d4, double d5, int... aint) {
for (int j = 0; j < this.u.size(); ++j) {
this.u.get(j).a(i, flag, d0, d1, d2, d3, d4, d5, aint);
}
}
public boolean strikeLightning(Entity entity) {
this.j.add(entity);
return true;
}
public boolean addEntity(Entity entity) {
// CraftBukkit start - Used for entities other than creatures
return addEntity(entity, SpawnReason.DEFAULT);
}
public boolean addEntity(Entity entity, SpawnReason spawnReason) { // Changed signature, added SpawnReason
org.spigotmc.AsyncCatcher.catchOp( "entity add"); // Spigot
if (entity == null) return false;
if (entity.valid) { MinecraftServer.LOGGER.error("Attempted Double World add on " + entity, new Throwable()); return true; } // Paper
// CraftBukkit end
int i = MathHelper.floor(entity.locX / 16.0D);
int j = MathHelper.floor(entity.locZ / 16.0D);
boolean flag = entity.attachedToPlayer;
// Paper start - Set origin location when the entity is being added to the world
if (entity.origin == null) {
entity.origin = entity.getBukkitEntity().getLocation();
}
// Paper end
if (entity instanceof EntityHuman) {
flag = true;
}
// CraftBukkit start
org.bukkit.event.Cancellable event = null;
if (entity instanceof EntityLiving && !(entity instanceof EntityPlayer)) {
boolean isAnimal = entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal || entity instanceof EntityGolem;
boolean isMonster = entity instanceof EntityMonster || entity instanceof EntityGhast || entity instanceof EntitySlime;
boolean isNpc = entity instanceof NPC;
if (spawnReason != SpawnReason.CUSTOM) {
if (isAnimal && !allowAnimals || isMonster && !allowMonsters || isNpc && !getServer().getServer().getSpawnNPCs()) {
entity.dead = true;
return false;
}
}
event = CraftEventFactory.callCreatureSpawnEvent((EntityLiving) entity, spawnReason);
} else if (entity instanceof EntityItem) {
event = CraftEventFactory.callItemSpawnEvent((EntityItem) entity);
} else if (entity.getBukkitEntity() instanceof org.bukkit.entity.Projectile) {
// Not all projectiles extend EntityProjectile, so check for Bukkit interface instead
event = CraftEventFactory.callProjectileLaunchEvent(entity);
} else if (entity.getBukkitEntity() instanceof org.bukkit.entity.Vehicle){
event = CraftEventFactory.callVehicleCreateEvent(entity);
}
// Spigot start
else if (entity instanceof EntityExperienceOrb) {
EntityExperienceOrb xp = (EntityExperienceOrb) entity;
double radius = spigotConfig.expMerge;
if (radius > 0) {
List<Entity> entities = this.getEntities(entity, entity.getBoundingBox().grow(radius, radius, radius));
for (Entity e : entities) {
if (e instanceof EntityExperienceOrb) {
EntityExperienceOrb loopItem = (EntityExperienceOrb) e;
if (!loopItem.dead) {
xp.value += loopItem.value;
loopItem.die();
}
}
}
}
} // Spigot end
if (event != null && (event.isCancelled() || entity.dead)) {
entity.dead = true;
return false;
}
// CraftBukkit end
if (!flag && !this.isChunkLoaded(i, j, false)) {
return false;
} else {
if (entity instanceof EntityHuman) {
EntityHuman entityhuman = (EntityHuman) entity;
this.players.add(entityhuman);
this.everyoneSleeping();
}
this.getChunkAt(i, j).a(entity);
this.entityList.add(entity);
this.b(entity);
return true;
}
}
protected void b(Entity entity) {
for (int i = 0; i < this.u.size(); ++i) {
this.u.get(i).a(entity);
}
entity.valid = true; // CraftBukkit
new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
}
protected void c(Entity entity) {
for (int i = 0; i < this.u.size(); ++i) {
this.u.get(i).b(entity);
}
new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
entity.valid = false; // CraftBukkit
}
public void kill(Entity entity) {
if (entity.isVehicle()) {
entity.az();
}
if (entity.isPassenger()) {
entity.stopRiding();
}
entity.die();
if (entity instanceof EntityHuman) {
this.players.remove(entity);
// Spigot start
for ( Object o : worldMaps.c )
{
if ( o instanceof WorldMap )
{
WorldMap map = (WorldMap) o;
map.k.remove( entity );
for ( Iterator<WorldMap.WorldMapHumanTracker> iter = map.i.iterator(); iter.hasNext(); )
{
if ( iter.next().trackee == entity )
{
map.decorations.remove(entity.getUniqueID()); // Paper
iter.remove();
}
}
}
}
// Spigot end
this.everyoneSleeping();
this.c(entity);
}
}
public void removeEntity(Entity entity) {
org.spigotmc.AsyncCatcher.catchOp( "entity remove"); // Spigot
entity.b(false);
entity.die();
if (entity instanceof EntityHuman) {
this.players.remove(entity);
this.everyoneSleeping();
}
if (!guardEntityList) { // Spigot - It will get removed after the tick if we are ticking
int i = entity.ab;
int j = entity.ad;
if (entity.aa && this.isChunkLoaded(i, j, true)) {
this.getChunkAt(i, j).b(entity);
}
// CraftBukkit start - Decrement loop variable field if we've already ticked this entity
int index = this.entityList.indexOf(entity);
if (index != -1) {
if (index <= this.tickPosition) {
this.tickPosition--;
}
this.entityList.remove(index);
}
// CraftBukkit end
} // Spigot
this.c(entity);
}
public void addIWorldAccess(IWorldAccess iworldaccess) {
this.u.add(iworldaccess);
}
private boolean a(@Nullable Entity entity, AxisAlignedBB axisalignedbb, boolean flag, @Nullable List<AxisAlignedBB> list) {
int i = MathHelper.floor(axisalignedbb.a) - 1;
int j = MathHelper.f(axisalignedbb.d) + 1;
int k = MathHelper.floor(axisalignedbb.b) - 1;
int l = MathHelper.f(axisalignedbb.e) + 1;
int i1 = MathHelper.floor(axisalignedbb.c) - 1;
int j1 = MathHelper.f(axisalignedbb.f) + 1;
WorldBorder worldborder = this.getWorldBorder();
boolean flag1 = entity != null && entity.br();
boolean flag2 = entity != null && this.g(entity);
IBlockData iblockdata = Blocks.STONE.getBlockData();
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
try {
for (int k1 = i; k1 < j; ++k1) {
for (int l1 = i1; l1 < j1; ++l1) {
boolean flag3 = k1 == i || k1 == j - 1;
boolean flag4 = l1 == i1 || l1 == j1 - 1;
if ((!flag3 || !flag4) && this.isLoaded(blockposition_pooledblockposition.f(k1, 64, l1))) {
for (int i2 = k; i2 < l; ++i2) {
if (!flag3 && !flag4 || i2 != l - 1) {
if (flag) {
if (k1 < -30000000 || k1 >= 30000000 || l1 < -30000000 || l1 >= 30000000) {
boolean flag5 = true;
return flag5;
}
} else if (entity != null && flag1 == flag2) {
entity.k(!flag2);
}
blockposition_pooledblockposition.f(k1, i2, l1);
IBlockData iblockdata1;
if (!flag && !worldborder.a(blockposition_pooledblockposition) && flag2) {
iblockdata1 = iblockdata;
} else {
iblockdata1 = this.getType(blockposition_pooledblockposition);
}
iblockdata1.a(this, blockposition_pooledblockposition, axisalignedbb, list, entity, false);
if (flag && !list.isEmpty()) {
boolean flag6 = true;
return flag6;
}
}
}
}
}
}
return !list.isEmpty();
} finally {
blockposition_pooledblockposition.t();
}
}
public List<AxisAlignedBB> getCubes(@Nullable Entity entity, AxisAlignedBB axisalignedbb) {
ArrayList arraylist = Lists.newArrayList();
this.a(entity, axisalignedbb, false, arraylist);
if (entity != null) {
if (entity instanceof EntityArmorStand && !entity.world.paperConfig.armorStandEntityLookups) return arraylist; // Paper
List list = this.getEntities(entity, axisalignedbb.g(0.25D));
for (int i = 0; i < list.size(); ++i) {
Entity entity1 = (Entity) list.get(i);
if (!entity.x(entity1)) {
AxisAlignedBB axisalignedbb1 = entity1.ag();
if (axisalignedbb1 != null && axisalignedbb1.c(axisalignedbb)) {
arraylist.add(axisalignedbb1);
}
axisalignedbb1 = entity.j(entity1);
if (axisalignedbb1 != null && axisalignedbb1.c(axisalignedbb)) {
arraylist.add(axisalignedbb1);
}
}
}
}
return arraylist;
}
public boolean g(Entity entity) {
double d0 = this.N.b();
double d1 = this.N.c();
double d2 = this.N.d();
double d3 = this.N.e();
if (entity.br()) {
++d0;
++d1;
--d2;
--d3;
} else {
--d0;
--d1;
++d2;
++d3;
}
return entity.locX > d0 && entity.locX < d2 && entity.locZ > d1 && entity.locZ < d3;
}
public boolean a(AxisAlignedBB axisalignedbb) {
return this.a((Entity) null, axisalignedbb, true, Lists.<AxisAlignedBB>newArrayList()); // CraftBukkit - decompile error
}
public int a(float f) {
float f1 = this.c(f);
float f2 = 1.0F - (MathHelper.cos(f1 * 6.2831855F) * 2.0F + 0.5F);
f2 = MathHelper.a(f2, 0.0F, 1.0F);
f2 = 1.0F - f2;
f2 = (float) (f2 * (1.0D - this.j(f) * 5.0F / 16.0D));
f2 = (float) (f2 * (1.0D - this.h(f) * 5.0F / 16.0D));
f2 = 1.0F - f2;
return (int) (f2 * 11.0F);
}
public float c(float f) {
return this.worldProvider.a(this.worldData.getDayTime(), f);
}
public float E() {
return WorldProvider.a[this.worldProvider.a(this.worldData.getDayTime())];
}
public float d(float f) {
float f1 = this.c(f);
return f1 * 6.2831855F;
}
public BlockPosition p(BlockPosition blockposition) {
return this.getChunkAtWorldCoords(blockposition).f(blockposition);
}
public BlockPosition getTopSolidOrLiquidBlock(BlockPosition position) { return this.q(position); } // OBFHELPER
public BlockPosition q(BlockPosition blockposition) {
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
BlockPosition blockposition1;
BlockPosition blockposition2;
for (blockposition1 = new BlockPosition(blockposition.getX(), chunk.g() + 16, blockposition.getZ()); blockposition1.getY() >= 0; blockposition1 = blockposition2) {
blockposition2 = blockposition1.down();
Material material = chunk.getBlockData(blockposition2).getMaterial();
if (material.isSolid() && material != Material.LEAVES) {
break;
}
}
return blockposition1;
}
public boolean b(BlockPosition blockposition, Block block) {
return true;
}
public void a(BlockPosition blockposition, Block block, int i) {}
public void a(BlockPosition blockposition, Block block, int i, int j) {}
public void b(BlockPosition blockposition, Block block, int i, int j) {}
public void tickEntities() {
this.methodProfiler.a("entities");
this.methodProfiler.a("global");
int i;
Entity entity;
for (i = 0; i < this.j.size(); ++i) {
entity = this.j.get(i);
// CraftBukkit start - Fixed an NPE
if (entity == null) {
continue;
}
// CraftBukkit end
try {
++entity.ticksLived;
entity.A_();
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Ticking entity");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being ticked");
if (entity == null) {
crashreportsystemdetails.a("Entity", "~~NULL~~");
} else {
entity.appendEntityCrashDetails(crashreportsystemdetails);
}
throw new ReportedException(crashreport);
}
if (entity.dead) {
this.j.remove(i--);
}
}
this.methodProfiler.c("remove");
timings.entityRemoval.startTiming(); // Paper
this.entityList.removeAll(this.f);
int j;
// Paper start - Set based removal lists
for (Entity e : this.f) {
j = e.getChunkZ();
int k = e.getChunkX();
if (e.isAddedToChunk() && this.isChunkLoaded(k, j, true)) {
this.getChunkAt(k, j).b(e);
}
}
for (Entity e : this.f) {
this.c(e);
}
// Paper end
this.f.clear();
this.l();
timings.entityRemoval.stopTiming(); // Paper
this.methodProfiler.c("regular");
CrashReportSystemDetails crashreportsystemdetails1;
CrashReport crashreport1;
org.spigotmc.ActivationRange.activateEntities(this); // Spigot
timings.entityTick.startTiming(); // Spigot
guardEntityList = true; // Spigot
// CraftBukkit start - Use field for loop variable
co.aikar.timings.TimingHistory.entityTicks += this.entityList.size(); // Paper
int entitiesThisCycle = 0;
// Paper start - Disable tick limiters
//if (tickPosition < 0) tickPosition = 0;
for (tickPosition = 0; tickPosition < entityList.size(); tickPosition++) {
// Paper end
tickPosition = (tickPosition < entityList.size()) ? tickPosition : 0;
entity = this.entityList.get(this.tickPosition);
// CraftBukkit end
Entity entity1 = entity.bB();
if (entity1 != null) {
if (!entity1.dead && entity1.w(entity)) {
continue;
}
entity.stopRiding();
}
this.methodProfiler.a("tick");
if (!entity.dead && !(entity instanceof EntityPlayer)) {
try {
entity.tickTimer.startTiming(); // Paper
this.h(entity);
entity.tickTimer.stopTiming(); // Paper
} catch (Throwable throwable1) {
entity.tickTimer.stopTiming();
// Paper start - Prevent tile entity and entity crashes
String msg = "Entity threw exception at " + entity.world.getWorld().getName() + ":" + entity.locX + "," + entity.locY + "," + entity.locZ;
System.err.println(msg);
throwable1.printStackTrace();
getServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable1)));
entity.dead = true;
continue;
// Paper end
}
}
this.methodProfiler.a("remove");
if (entity.dead) {
j = entity.ab;
int l = entity.ad;
if (entity.aa && this.isChunkLoaded(j, l, true)) {
this.getChunkAt(j, l).b(entity);
}
guardEntityList = false; // Spigot
this.entityList.remove(this.tickPosition--); // CraftBukkit - Use field for loop variable
guardEntityList = true; // Spigot
this.c(entity);
}
}
guardEntityList = false; // Spigot
timings.entityTick.stopTiming(); // Spigot
this.methodProfiler.c("blockEntities");
this.M = true;
timings.tileEntityTick.startTiming(); // Spigot
// CraftBukkit start - From below, clean up tile entities before ticking them
if (!this.tileEntityListUnload.isEmpty()) {
this.tileEntityListTick.removeAll(this.tileEntityListUnload);
//this.tileEntityList.removeAll(this.tileEntityListUnload); // Paper - remove unused list
this.tileEntityListUnload.clear();
}
// CraftBukkit end
// Spigot start
// Iterator iterator = this.tileEntityListTick.iterator();
int tilesThisCycle = 0;
for (tileTickPosition = 0; tileTickPosition < tileEntityListTick.size(); tileTickPosition++) { // Paper - Disable tick limiters
tileTickPosition = (tileTickPosition < tileEntityListTick.size()) ? tileTickPosition : 0;
TileEntity tileentity = this.tileEntityListTick.get(tileTickPosition);
// Spigot start
if (tileentity == null) {
getServer().getLogger().severe("Spigot has detected a null entity and has removed it, preventing a crash");
tilesThisCycle--;
this.tileEntityListTick.remove(tileTickPosition--);
continue;
}
// Spigot end
if (!tileentity.y() && tileentity.u()) {
BlockPosition blockposition = tileentity.getPosition();
if (this.isLoaded(blockposition) && this.N.a(blockposition)) {
try {
this.methodProfiler.a("ticking"/*tileentity.getClass().getSimpleName()*/); // CraftBukkit: SPIGOT-1900
tileentity.tickTimer.startTiming(); // Spigot
((ITickable) tileentity).F_();
} catch (Throwable throwable2) {
// Paper start - Prevent tile entity and entity crashes
String msg = "TileEntity threw exception at " + tileentity.world.getWorld().getName() + ":" + tileentity.position.getX() + "," + tileentity.position.getY() + "," + tileentity.position.getZ();
System.err.println(msg);
throwable2.printStackTrace();
getServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable2)));
tilesThisCycle--;
this.tileEntityListTick.remove(tileTickPosition--);
continue;
// Paper end
}
// Spigot start
finally {
tileentity.tickTimer.stopTiming();
}
// Spigot end
}
}
if (tileentity.y()) {
tilesThisCycle--;
this.tileEntityListTick.remove(tileTickPosition--);
//this.tileEntityList.remove(tileentity); // Paper - remove unused list
if (this.isLoaded(tileentity.getPosition())) {
this.getChunkAtWorldCoords(tileentity.getPosition()).d(tileentity.getPosition());
}
}
}
timings.tileEntityTick.stopTiming(); // Spigot
timings.tileEntityPending.startTiming(); // Spigot
this.M = false;
/* CraftBukkit start - Moved up
if (!this.tileEntityListUnload.isEmpty()) {
this.tileEntityListTick.removeAll(this.tileEntityListUnload);
this.tileEntityList.removeAll(this.tileEntityListUnload);
this.tileEntityListUnload.clear();
}
// CraftBukkit end */
this.methodProfiler.c("pendingBlockEntities");
if (!this.b.isEmpty()) {
for (int i1 = 0; i1 < this.b.size(); ++i1) {
TileEntity tileentity1 = this.b.get(i1);
if (!tileentity1.y()) {
/* CraftBukkit start - Order matters, moved down
if (!this.tileEntityList.contains(tileentity1)) {
this.a(tileentity1);
}
// CraftBukkit end */
if (this.isLoaded(tileentity1.getPosition())) {
Chunk chunk = this.getChunkAtWorldCoords(tileentity1.getPosition());
IBlockData iblockdata = chunk.getBlockData(tileentity1.getPosition());
chunk.a(tileentity1.getPosition(), tileentity1);
this.notify(tileentity1.getPosition(), iblockdata, iblockdata, 3);
// CraftBukkit start
// From above, don't screw this up - SPIGOT-1746
if (true) { // Paper - remove unused list
this.a(tileentity1);
}
// CraftBukkit end
}
}
}
this.b.clear();
}
timings.tileEntityPending.stopTiming(); // Spigot
co.aikar.timings.TimingHistory.tileEntityTicks += this.tileEntityListTick.size(); // Paper
}
protected void l() {}
public boolean a(TileEntity tileentity) {
boolean flag = true; // Paper - remove unused list
if (flag && tileentity instanceof ITickable && !this.tileEntityListTick.contains(tileentity)) { // Paper
this.tileEntityListTick.add(tileentity);
}
if (this.isClientSide) {
BlockPosition blockposition = tileentity.getPosition();
IBlockData iblockdata = this.getType(blockposition);
this.notify(blockposition, iblockdata, iblockdata, 2);
}
return flag;
}
public void b(Collection<TileEntity> collection) {
if (this.M) {
this.b.addAll(collection);
} else {
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
TileEntity tileentity = (TileEntity) iterator.next();
this.a(tileentity);
}
}
}
public void h(Entity entity) {
this.entityJoinedWorld(entity, true);
}
public void entityJoinedWorld(Entity entity, boolean flag) {
//int i = MathHelper.floor(entity.locX);
//int j = MathHelper.floor(entity.locZ);
//boolean flag1 = true;
// Spigot start
if (flag && !org.spigotmc.ActivationRange.checkIfActive(entity)) {
entity.ticksLived++;
entity.inactiveTick();
} else {
// CraftBukkit end
entity.M = entity.locX;
entity.N = entity.locY;
entity.O = entity.locZ;
entity.lastYaw = entity.yaw;
entity.lastPitch = entity.pitch;
if (flag && entity.aa) {
++entity.ticksLived;
++co.aikar.timings.TimingHistory.activatedEntityTicks; // Paper
if (entity.isPassenger()) {
entity.aw();
} else {
entity.A_();
entity.postTick(); // CraftBukkit
}
}
this.methodProfiler.a("chunkCheck");
if (Double.isNaN(entity.locX) || Double.isInfinite(entity.locX)) {
entity.locX = entity.M;
}
if (Double.isNaN(entity.locY) || Double.isInfinite(entity.locY)) {
entity.locY = entity.N;
}
if (Double.isNaN(entity.locZ) || Double.isInfinite(entity.locZ)) {
entity.locZ = entity.O;
}
if (Double.isNaN(entity.pitch) || Double.isInfinite(entity.pitch)) {
entity.pitch = entity.lastPitch;
}
if (Double.isNaN(entity.yaw) || Double.isInfinite(entity.yaw)) {
entity.yaw = entity.lastYaw;
}
int k = MathHelper.floor(entity.locX / 16.0D);
int l = Math.min(15, Math.max(0, MathHelper.floor(entity.locY / 16.0D))); // Paper - stay consistent with chunk add/remove behavior
int i1 = MathHelper.floor(entity.locZ / 16.0D);
if (!entity.aa || entity.ab != k || entity.ac != l || entity.ad != i1) {
if (entity.aa && this.isChunkLoaded(entity.ab, entity.ad, true)) {
this.getChunkAt(entity.ab, entity.ad).a(entity, entity.ac);
}
if (!entity.bv() && !this.isChunkLoaded(k, i1, true)) {
entity.aa = false;
} else {
this.getChunkAt(k, i1).a(entity);
}
}
if (flag && entity.aa) {
Iterator iterator = entity.bx().iterator();
while (iterator.hasNext()) {
Entity entity1 = (Entity) iterator.next();
if (!entity1.dead && entity1.bB() == entity) {
this.h(entity1);
} else {
entity1.stopRiding();
}
}
}
}
}
public boolean b(AxisAlignedBB axisalignedbb) {
return this.a(axisalignedbb, (Entity) null);
}
// Paper start - Based on method below
/**
* @param axisalignedbb area to search within
* @param entity causing the action ex. block placer
* @return if there are no visible players colliding
*/
public boolean checkNoVisiblePlayerCollisions(AxisAlignedBB axisalignedbb, @Nullable Entity entity) {
List list = this.getEntities((Entity) null, axisalignedbb);
for (int i = 0; i < list.size(); ++i) {
Entity entity1 = (Entity) list.get(i);
if (entity instanceof EntityPlayer && entity1 instanceof EntityPlayer) {
if (!((EntityPlayer) entity).getBukkitEntity().canSee(((EntityPlayer) entity1).getBukkitEntity())) {
continue;
}
}
if (!entity1.dead && entity1.blocksEntitySpawning()) {
return false;
}
}
return true;
}
// Paper end
public boolean a(AxisAlignedBB axisalignedbb, @Nullable Entity entity) {
List list = this.getEntities((Entity) null, axisalignedbb);
for (int i = 0; i < list.size(); ++i) {
Entity entity1 = (Entity) list.get(i);
if (!entity1.dead && entity1.i && entity1 != entity && (entity == null || entity1.x(entity))) {
return false;
}
}
return true;
}
public boolean c(AxisAlignedBB axisalignedbb) {
int i = MathHelper.floor(axisalignedbb.a);
int j = MathHelper.f(axisalignedbb.d);
int k = MathHelper.floor(axisalignedbb.b);
int l = MathHelper.f(axisalignedbb.e);
int i1 = MathHelper.floor(axisalignedbb.c);
int j1 = MathHelper.f(axisalignedbb.f);
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
for (int k1 = i; k1 < j; ++k1) {
for (int l1 = k; l1 < l; ++l1) {
for (int i2 = i1; i2 < j1; ++i2) {
IBlockData iblockdata = this.getType(blockposition_pooledblockposition.f(k1, l1, i2));
if (iblockdata.getMaterial() != Material.AIR) {
blockposition_pooledblockposition.t();
return true;
}
}
}
}
blockposition_pooledblockposition.t();
return false;
}
public boolean containsLiquid(AxisAlignedBB axisalignedbb) {
int i = MathHelper.floor(axisalignedbb.a);
int j = MathHelper.f(axisalignedbb.d);
int k = MathHelper.floor(axisalignedbb.b);
int l = MathHelper.f(axisalignedbb.e);
int i1 = MathHelper.floor(axisalignedbb.c);
int j1 = MathHelper.f(axisalignedbb.f);
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
for (int k1 = i; k1 < j; ++k1) {
for (int l1 = k; l1 < l; ++l1) {
for (int i2 = i1; i2 < j1; ++i2) {
IBlockData iblockdata = this.getType(blockposition_pooledblockposition.f(k1, l1, i2));
if (iblockdata.getMaterial().isLiquid()) {
blockposition_pooledblockposition.t();
return true;
}
}
}
}
blockposition_pooledblockposition.t();
return false;
}
public boolean e(AxisAlignedBB axisalignedbb) {
int i = MathHelper.floor(axisalignedbb.a);
int j = MathHelper.f(axisalignedbb.d);
int k = MathHelper.floor(axisalignedbb.b);
int l = MathHelper.f(axisalignedbb.e);
int i1 = MathHelper.floor(axisalignedbb.c);
int j1 = MathHelper.f(axisalignedbb.f);
if (this.isAreaLoaded(i, k, i1, j, l, j1, true)) {
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
int k1 = i;
while (true) {
if (k1 >= j) {
blockposition_pooledblockposition.t();
break;
}
for (int l1 = k; l1 < l; ++l1) {
for (int i2 = i1; i2 < j1; ++i2) {
Block block = this.getType(blockposition_pooledblockposition.f(k1, l1, i2)).getBlock();
if (block == Blocks.FIRE || block == Blocks.FLOWING_LAVA || block == Blocks.LAVA) {
blockposition_pooledblockposition.t();
return true;
}
}
}
++k1;
}
}
return false;
}
public boolean a(AxisAlignedBB axisalignedbb, Material material, Entity entity) {
int i = MathHelper.floor(axisalignedbb.a);
int j = MathHelper.f(axisalignedbb.d);
int k = MathHelper.floor(axisalignedbb.b);
int l = MathHelper.f(axisalignedbb.e);
int i1 = MathHelper.floor(axisalignedbb.c);
int j1 = MathHelper.f(axisalignedbb.f);
if (!this.isAreaLoaded(i, k, i1, j, l, j1, true)) {
return false;
} else {
boolean flag = false;
Vec3D vec3d = Vec3D.a;
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
for (int k1 = i; k1 < j; ++k1) {
for (int l1 = k; l1 < l; ++l1) {
for (int i2 = i1; i2 < j1; ++i2) {
blockposition_pooledblockposition.f(k1, l1, i2);
IBlockData iblockdata = this.getType(blockposition_pooledblockposition);
Block block = iblockdata.getBlock();
if (iblockdata.getMaterial() == material) {
double d0 = l1 + 1 - BlockFluids.e(iblockdata.get(BlockFluids.LEVEL).intValue());
if (l >= d0) {
flag = true;
vec3d = block.a(this, blockposition_pooledblockposition, entity, vec3d);
}
}
}
}
}
blockposition_pooledblockposition.t();
if (vec3d.b() > 0.0D && entity.bg()) {
vec3d = vec3d.a();
double d1 = 0.014D;
entity.motX += vec3d.x * 0.014D;
entity.motY += vec3d.y * 0.014D;
entity.motZ += vec3d.z * 0.014D;
}
return flag;
}
}
public boolean a(AxisAlignedBB axisalignedbb, Material material) {
int i = MathHelper.floor(axisalignedbb.a);
int j = MathHelper.f(axisalignedbb.d);
int k = MathHelper.floor(axisalignedbb.b);
int l = MathHelper.f(axisalignedbb.e);
int i1 = MathHelper.floor(axisalignedbb.c);
int j1 = MathHelper.f(axisalignedbb.f);
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
for (int k1 = i; k1 < j; ++k1) {
for (int l1 = k; l1 < l; ++l1) {
for (int i2 = i1; i2 < j1; ++i2) {
if (this.getType(blockposition_pooledblockposition.f(k1, l1, i2)).getMaterial() == material) {
blockposition_pooledblockposition.t();
return true;
}
}
}
}
blockposition_pooledblockposition.t();
return false;
}
public Explosion explode(@Nullable Entity entity, double d0, double d1, double d2, float f, boolean flag) {
return this.createExplosion(entity, d0, d1, d2, f, false, flag);
}
public Explosion createExplosion(@Nullable Entity entity, double d0, double d1, double d2, float f, boolean flag, boolean flag1) {
Explosion explosion = new Explosion(this, entity, d0, d1, d2, f, flag, flag1);
explosion.a();
explosion.a(true);
return explosion;
}
public float a(Vec3D vec3d, AxisAlignedBB axisalignedbb) {
double d0 = 1.0D / ((axisalignedbb.d - axisalignedbb.a) * 2.0D + 1.0D);
double d1 = 1.0D / ((axisalignedbb.e - axisalignedbb.b) * 2.0D + 1.0D);
double d2 = 1.0D / ((axisalignedbb.f - axisalignedbb.c) * 2.0D + 1.0D);
double d3 = (1.0D - Math.floor(1.0D / d0) * d0) / 2.0D;
double d4 = (1.0D - Math.floor(1.0D / d2) * d2) / 2.0D;
if (d0 >= 0.0D && d1 >= 0.0D && d2 >= 0.0D) {
int i = 0;
int j = 0;
for (float f = 0.0F; f <= 1.0F; f = (float) (f + d0)) {
for (float f1 = 0.0F; f1 <= 1.0F; f1 = (float) (f1 + d1)) {
for (float f2 = 0.0F; f2 <= 1.0F; f2 = (float) (f2 + d2)) {
double d5 = axisalignedbb.a + (axisalignedbb.d - axisalignedbb.a) * f;
double d6 = axisalignedbb.b + (axisalignedbb.e - axisalignedbb.b) * f1;
double d7 = axisalignedbb.c + (axisalignedbb.f - axisalignedbb.c) * f2;
if (this.rayTrace(new Vec3D(d5 + d3, d6, d7 + d4), vec3d) == null) {
++i;
}
++j;
}
}
}
return (float) i / (float) j;
} else {
return 0.0F;
}
}
public boolean douseFire(@Nullable EntityHuman entityhuman, BlockPosition blockposition, EnumDirection enumdirection) {
blockposition = blockposition.shift(enumdirection);
if (this.getType(blockposition).getBlock() == Blocks.FIRE) {
this.a(entityhuman, 1009, blockposition, 0);
this.setAir(blockposition);
return true;
} else {
return false;
}
}
public Map<BlockPosition, TileEntity> capturedTileEntities = HashObjObjMaps.newMutableMap();
@Override
@Nullable
public TileEntity getTileEntity(BlockPosition blockposition) {
if (blockposition.isInvalidYLocation()) { // Paper
return null;
} else {
// CraftBukkit start
if (capturedTileEntities.containsKey(blockposition)) {
return capturedTileEntities.get(blockposition);
}
// CraftBukkit end
TileEntity tileentity = null;
if (this.M) {
tileentity = this.F(blockposition);
}
if (tileentity == null) {
tileentity = this.getChunkAtWorldCoords(blockposition).a(blockposition, Chunk.EnumTileEntityState.IMMEDIATE);
}
if (tileentity == null) {
tileentity = this.F(blockposition);
}
return tileentity;
}
}
@Nullable
private TileEntity F(BlockPosition blockposition) {
for (int i = 0; i < this.b.size(); ++i) {
TileEntity tileentity = this.b.get(i);
if (!tileentity.y() && tileentity.getPosition().equals(blockposition)) {
return tileentity;
}
}
return null;
}
public void setTileEntity(BlockPosition blockposition, @Nullable TileEntity tileentity) {
if (!blockposition.isInvalidYLocation()) {
if (tileentity != null && !tileentity.y()) {
// CraftBukkit start
if (captureBlockStates) {
tileentity.a(this);
tileentity.setPosition(blockposition);
capturedTileEntities.put(blockposition, tileentity);
return;
}
// CraftBukkit end
if (this.M) {
tileentity.setPosition(blockposition);
Iterator iterator = this.b.iterator();
while (iterator.hasNext()) {
TileEntity tileentity1 = (TileEntity) iterator.next();
if (tileentity1.getPosition().equals(blockposition)) {
tileentity1.z();
iterator.remove();
}
}
tileentity.a(this); // Spigot - No null worlds
this.b.add(tileentity);
} else {
this.getChunkAtWorldCoords(blockposition).a(blockposition, tileentity);
this.a(tileentity);
}
}
}
}
public void s(BlockPosition blockposition) {
TileEntity tileentity = this.getTileEntity(blockposition);
if (tileentity != null && this.M) {
tileentity.z();
this.b.remove(tileentity);
} else {
if (tileentity != null) {
this.b.remove(tileentity);
//this.tileEntityList.remove(tileentity); // Paper - remove unused list
this.tileEntityListTick.remove(tileentity);
}
this.getChunkAtWorldCoords(blockposition).d(blockposition);
}
}
public void b(TileEntity tileentity) {
this.tileEntityListUnload.add(tileentity);
}
public boolean t(BlockPosition blockposition) {
AxisAlignedBB axisalignedbb = this.getType(blockposition).c(this, blockposition);
return axisalignedbb != Block.k && axisalignedbb.a() >= 1.0D;
}
public boolean d(BlockPosition blockposition, boolean flag) {
if (blockposition.isInvalidYLocation()) { // Paper
return false;
} else {
Chunk chunk = this.chunkProvider.getLoadedChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4);
if (chunk != null && !chunk.isEmpty()) {
IBlockData iblockdata = this.getType(blockposition);
return iblockdata.getMaterial().k() && iblockdata.h();
} else {
return flag;
}
}
}
public void H() {
int i = this.a(1.0F);
if (i != this.J) {
this.J = i;
}
}
public void setSpawnFlags(boolean flag, boolean flag1) {
this.allowMonsters = flag;
this.allowAnimals = flag1;
}
public void doTick() {
this.t();
}
protected void I() {
if (this.worldData.hasStorm()) {
this.o = 1.0F;
if (this.worldData.isThundering()) {
this.q = 1.0F;
}
}
}
protected void t() {
if (this.worldProvider.m()) {
if (!this.isClientSide) {
boolean flag = this.getGameRules().getBoolean("doWeatherCycle");
if (flag) {
int i = this.worldData.z();
if (i > 0) {
--i;
this.worldData.i(i);
this.worldData.setThunderDuration(this.worldData.isThundering() ? 1 : 2);
this.worldData.setWeatherDuration(this.worldData.hasStorm() ? 1 : 2);
}
int j = this.worldData.getThunderDuration();
if (j <= 0) {
if (this.worldData.isThundering()) {
this.worldData.setThunderDuration(this.random.nextInt(12000) + 3600);
} else {
this.worldData.setThunderDuration(this.random.nextInt(168000) + 12000);
}
} else {
--j;
this.worldData.setThunderDuration(j);
if (j <= 0) {
this.worldData.setThundering(!this.worldData.isThundering());
}
}
int k = this.worldData.getWeatherDuration();
if (k <= 0) {
if (this.worldData.hasStorm()) {
this.worldData.setWeatherDuration(this.random.nextInt(12000) + 12000);
} else {
this.worldData.setWeatherDuration(this.random.nextInt(168000) + 12000);
}
} else {
--k;
this.worldData.setWeatherDuration(k);
if (k <= 0) {
this.worldData.setStorm(!this.worldData.hasStorm());
}
}
}
this.p = this.q;
if (this.worldData.isThundering()) {
this.q = (float) (this.q + 0.01D);
} else {
this.q = (float) (this.q - 0.01D);
}
this.q = MathHelper.a(this.q, 0.0F, 1.0F);
this.n = this.o;
if (this.worldData.hasStorm()) {
this.o = (float) (this.o + 0.01D);
} else {
this.o = (float) (this.o - 0.01D);
}
this.o = MathHelper.a(this.o, 0.0F, 1.0F);
// CraftBukkit start
for (int idx = 0; idx < this.players.size(); ++idx) {
if (((EntityPlayer) this.players.get(idx)).world == this) {
((EntityPlayer) this.players.get(idx)).tickWeather();
}
}
// CraftBukkit end
}
}
}
protected void j() {}
public void a(BlockPosition blockposition, IBlockData iblockdata, Random random) {
this.d = true;
iblockdata.getBlock().b(this, blockposition, iblockdata, random);
this.d = false;
}
public boolean u(BlockPosition blockposition) {
return this.e(blockposition, false);
}
public boolean v(BlockPosition blockposition) {
return this.e(blockposition, true);
}
public boolean e(BlockPosition blockposition, boolean flag) {
BiomeBase biomebase = this.getBiome(blockposition);
float f = biomebase.a(blockposition);
if (f >= 0.15F) {
return false;
} else {
if (blockposition.getY() >= 0 && blockposition.getY() < 256 && this.getBrightness(EnumSkyBlock.BLOCK, blockposition) < 10) {
IBlockData iblockdata = this.getType(blockposition);
Block block = iblockdata.getBlock();
if ((block == Blocks.WATER || block == Blocks.FLOWING_WATER) && iblockdata.get(BlockFluids.LEVEL).intValue() == 0) {
if (!flag) {
return true;
}
boolean flag1 = this.G(blockposition.west()) && this.G(blockposition.east()) && this.G(blockposition.north()) && this.G(blockposition.south());
if (!flag1) {
return true;
}
}
}
return false;
}
}
private boolean G(BlockPosition blockposition) {
return this.getType(blockposition).getMaterial() == Material.WATER;
}
public boolean f(BlockPosition blockposition, boolean flag) {
BiomeBase biomebase = this.getBiome(blockposition);
float f = biomebase.a(blockposition);
if (f >= 0.15F) {
return false;
} else if (!flag) {
return true;
} else {
if (blockposition.getY() >= 0 && blockposition.getY() < 256 && this.getBrightness(EnumSkyBlock.BLOCK, blockposition) < 10) {
IBlockData iblockdata = this.getType(blockposition);
if (iblockdata.getMaterial() == Material.AIR && Blocks.SNOW_LAYER.canPlace(this, blockposition)) {
return true;
}
}
return false;
}
}
public boolean w(BlockPosition blockposition) {
boolean flag = false;
if (this.worldProvider.m()) {
flag |= this.c(EnumSkyBlock.SKY, blockposition);
}
flag |= this.c(EnumSkyBlock.BLOCK, blockposition);
return flag;
}
private int a(BlockPosition blockposition, EnumSkyBlock enumskyblock) {
if (enumskyblock == EnumSkyBlock.SKY && this.h(blockposition)) {
return 15;
} else {
IBlockData iblockdata = this.getType(blockposition);
int i = enumskyblock == EnumSkyBlock.SKY ? 0 : iblockdata.d();
int j = iblockdata.c();
if (j >= 15 && iblockdata.d() > 0) {
j = 1;
}
if (j < 1) {
j = 1;
}
if (j >= 15) {
return 0;
} else if (i >= 14) {
return i;
} else {
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
EnumDirection[] aenumdirection = EnumDirection.values();
int k = aenumdirection.length;
for (int l = 0; l < k; ++l) {
EnumDirection enumdirection = aenumdirection[l];
blockposition_pooledblockposition.j(blockposition).d(enumdirection);
int i1 = this.getBrightness(enumskyblock, blockposition_pooledblockposition) - j;
if (i1 > i) {
i = i1;
}
if (i >= 14) {
return i;
}
}
blockposition_pooledblockposition.t();
return i;
}
}
}
public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition) {
// CraftBukkit start - Use neighbor cache instead of looking up
Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
if (chunk == null || !chunk.areNeighborsLoaded(1) /*!this.areChunksLoaded(blockposition, 17, false)*/) {
// CraftBukkit end
return false;
} else {
int i = 0;
int j = 0;
this.methodProfiler.a("getBrightness");
int k = this.getBrightness(enumskyblock, blockposition);
int l = this.a(blockposition, enumskyblock);
int i1 = blockposition.getX();
int j1 = blockposition.getY();
int k1 = blockposition.getZ();
int l1;
int i2;
int j2;
int k2;
int l2;
int i3;
int j3;
int k3;
if (l > k) {
this.H[j++] = 133152;
} else if (l < k) {
this.H[j++] = 133152 | k << 18;
while (i < j) {
l1 = this.H[i++];
i2 = (l1 & 63) - 32 + i1;
j2 = (l1 >> 6 & 63) - 32 + j1;
k2 = (l1 >> 12 & 63) - 32 + k1;
int l3 = l1 >> 18 & 15;
BlockPosition blockposition1 = new BlockPosition(i2, j2, k2);
l2 = this.getBrightness(enumskyblock, blockposition1);
if (l2 == l3) {
this.a(enumskyblock, blockposition1, 0);
if (l3 > 0) {
i3 = MathHelper.a(i2 - i1);
j3 = MathHelper.a(j2 - j1);
k3 = MathHelper.a(k2 - k1);
if (i3 + j3 + k3 < 17) {
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
EnumDirection[] aenumdirection = EnumDirection.values();
int i4 = aenumdirection.length;
for (int j4 = 0; j4 < i4; ++j4) {
EnumDirection enumdirection = aenumdirection[j4];
int k4 = i2 + enumdirection.getAdjacentX();
int l4 = j2 + enumdirection.getAdjacentY();
int i5 = k2 + enumdirection.getAdjacentZ();
blockposition_pooledblockposition.f(k4, l4, i5);
int j5 = Math.max(1, this.getType(blockposition_pooledblockposition).c());
l2 = this.getBrightness(enumskyblock, blockposition_pooledblockposition);
if (l2 == l3 - j5 && j < this.H.length) {
this.H[j++] = k4 - i1 + 32 | l4 - j1 + 32 << 6 | i5 - k1 + 32 << 12 | l3 - j5 << 18;
}
}
blockposition_pooledblockposition.t();
}
}
}
}
i = 0;
}
this.methodProfiler.a("checkedPosition < toCheckCount");
while (i < j) {
l1 = this.H[i++];
i2 = (l1 & 63) - 32 + i1;
j2 = (l1 >> 6 & 63) - 32 + j1;
k2 = (l1 >> 12 & 63) - 32 + k1;
BlockPosition blockposition2 = new BlockPosition(i2, j2, k2);
int k5 = this.getBrightness(enumskyblock, blockposition2);
l2 = this.a(blockposition2, enumskyblock);
if (l2 != k5) {
this.a(enumskyblock, blockposition2, l2);
if (l2 > k5) {
i3 = Math.abs(i2 - i1);
j3 = Math.abs(j2 - j1);
k3 = Math.abs(k2 - k1);
boolean flag = j < this.H.length - 6;
if (i3 + j3 + k3 < 17 && flag) {
if (this.getBrightness(enumskyblock, blockposition2.west()) < l2) {
this.H[j++] = i2 - 1 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
}
if (this.getBrightness(enumskyblock, blockposition2.east()) < l2) {
this.H[j++] = i2 + 1 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
}
if (this.getBrightness(enumskyblock, blockposition2.down()) < l2) {
this.H[j++] = i2 - i1 + 32 + (j2 - 1 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
}
if (this.getBrightness(enumskyblock, blockposition2.up()) < l2) {
this.H[j++] = i2 - i1 + 32 + (j2 + 1 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
}
if (this.getBrightness(enumskyblock, blockposition2.north()) < l2) {
this.H[j++] = i2 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - 1 - k1 + 32 << 12);
}
if (this.getBrightness(enumskyblock, blockposition2.south()) < l2) {
this.H[j++] = i2 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 + 1 - k1 + 32 << 12);
}
}
}
}
}
return true;
}
}
public boolean a(boolean flag) {
return false;
}
@Nullable
public List<NextTickListEntry> a(Chunk chunk, boolean flag) {
return null;
}
@Nullable
public List<NextTickListEntry> a(StructureBoundingBox structureboundingbox, boolean flag) {
return null;
}
public List<Entity> getEntities(@Nullable Entity entity, AxisAlignedBB axisalignedbb) {
return this.getEntities(entity, axisalignedbb, IEntitySelector.e);
}
public List<Entity> getEntities(@Nullable Entity entity, AxisAlignedBB axisalignedbb, @Nullable Predicate<? super Entity> predicate) {
ArrayList arraylist = Lists.newArrayList();
int i = MathHelper.floor((axisalignedbb.a - 2.0D) / 16.0D);
int j = MathHelper.floor((axisalignedbb.d + 2.0D) / 16.0D);
int k = MathHelper.floor((axisalignedbb.c - 2.0D) / 16.0D);
int l = MathHelper.floor((axisalignedbb.f + 2.0D) / 16.0D);
for (int i1 = i; i1 <= j; ++i1) {
for (int j1 = k; j1 <= l; ++j1) {
if (this.isChunkLoaded(i1, j1, true)) {
this.getChunkAt(i1, j1).a(entity, axisalignedbb, arraylist, predicate);
}
}
}
return arraylist;
}
public <T extends Entity> List<T> a(Class<? extends T> oclass, Predicate<? super T> predicate) {
ArrayList arraylist = Lists.newArrayList();
Iterator iterator = this.entityList.iterator();
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
if (oclass.isAssignableFrom(entity.getClass()) && predicate.apply((T) entity)) {
arraylist.add(entity);
}
}
return arraylist;
}
public <T extends Entity> List<T> b(Class<? extends T> oclass, Predicate<? super T> predicate) {
ArrayList arraylist = Lists.newArrayList();
Iterator iterator = this.players.iterator();
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
if (oclass.isAssignableFrom(entity.getClass()) && predicate.apply((T) entity)) { // CraftBukkit - fix decompile error
arraylist.add(entity);
}
}
return arraylist;
}
public <T extends Entity> List<T> a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb) {
return this.a(oclass, axisalignedbb, IEntitySelector.e);
}
public <T extends Entity> List<T> a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb, @Nullable Predicate<? super T> predicate) {
int i = MathHelper.floor((axisalignedbb.a - 2.0D) / 16.0D);
int j = MathHelper.f((axisalignedbb.d + 2.0D) / 16.0D);
int k = MathHelper.floor((axisalignedbb.c - 2.0D) / 16.0D);
int l = MathHelper.f((axisalignedbb.f + 2.0D) / 16.0D);
ArrayList arraylist = Lists.newArrayList();
for (int i1 = i; i1 < j; ++i1) {
for (int j1 = k; j1 < l; ++j1) {
if (this.isChunkLoaded(i1, j1, true)) {
this.getChunkAt(i1, j1).a(oclass, axisalignedbb, arraylist, predicate);
}
}
}
return arraylist;
}
@Nullable
public <T extends Entity> T a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb, T t0) {
List list = this.a(oclass, axisalignedbb);
Entity entity = null;
double d0 = Double.MAX_VALUE;
for (int i = 0; i < list.size(); ++i) {
Entity entity1 = (Entity) list.get(i);
if (entity1 != t0 && IEntitySelector.e.apply(entity1)) {
double d1 = t0.h(entity1);
if (d1 <= d0) {
entity = entity1;
d0 = d1;
}
}
}
return (T) entity; // CraftBukkit fix decompile error
}
@Nullable
public Entity getEntity(int i) {
return this.entitiesById.get(i);
}
public void b(BlockPosition blockposition, TileEntity tileentity) {
if (this.isLoaded(blockposition)) {
this.getChunkAtWorldCoords(blockposition).e();
}
}
public int a(Class<?> oclass) {
int i = 0;
Iterator iterator = this.entityList.iterator();
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
// CraftBukkit start - Split out persistent check, don't apply it to special persistent mobs
if (entity instanceof EntityInsentient) {
EntityInsentient entityinsentient = (EntityInsentient) entity;
if (entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) {
continue;
}
}
if (oclass.isAssignableFrom(entity.getClass())) {
// if ((!(entity instanceof EntityInsentient) || !((EntityInsentient) entity).isPersistent()) && oclass.isAssignableFrom(entity.getClass())) {
// CraftBukkit end
++i;
}
}
return i;
}
public void a(Collection<Entity> collection) {
org.spigotmc.AsyncCatcher.catchOp( "entity world add"); // Spigot
// CraftBukkit start
// this.entityList.addAll(collection);
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
if (entity == null) {
continue;
}
this.entityList.add(entity);
// CraftBukkit end
this.b(entity);
}
}
public void c(Collection<Entity> collection) {
this.f.addAll(collection);
}
public boolean a(Block block, BlockPosition blockposition, boolean flag, EnumDirection enumdirection, @Nullable Entity entity) {
IBlockData iblockdata = this.getType(blockposition);
AxisAlignedBB axisalignedbb = flag ? null : block.getBlockData().c(this, blockposition);
// CraftBukkit start - store default return
boolean defaultReturn = axisalignedbb != Block.k && !this.checkNoVisiblePlayerCollisions(axisalignedbb.a(blockposition), entity) ? false : (iblockdata.getMaterial() == Material.ORIENTABLE && block == Blocks.ANVIL ? true : iblockdata.getMaterial().isReplaceable() && block.canPlace(this, blockposition, enumdirection)); // Paper - Use our entity search
BlockCanBuildEvent event = new BlockCanBuildEvent(this.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftMagicNumbers.getId(block), defaultReturn);
this.getServer().getPluginManager().callEvent(event);
return event.isBuildable();
// CraftBukkit end
}
public int K() {
return this.a;
}
public void b(int i) {
this.a = i;
}
@Override
public int getBlockPower(BlockPosition blockposition, EnumDirection enumdirection) {
return this.getType(blockposition).b(this, blockposition, enumdirection);
}
public WorldType L() {
return this.worldData.getType();
}
public int getBlockPower(BlockPosition blockposition) {
byte b0 = 0;
int i = Math.max(b0, this.getBlockPower(blockposition.down(), EnumDirection.DOWN));
if (i >= 15) {
return i;
} else {
i = Math.max(i, this.getBlockPower(blockposition.up(), EnumDirection.UP));
if (i >= 15) {
return i;
} else {
i = Math.max(i, this.getBlockPower(blockposition.north(), EnumDirection.NORTH));
if (i >= 15) {
return i;
} else {
i = Math.max(i, this.getBlockPower(blockposition.south(), EnumDirection.SOUTH));
if (i >= 15) {
return i;
} else {
i = Math.max(i, this.getBlockPower(blockposition.west(), EnumDirection.WEST));
if (i >= 15) {
return i;
} else {
i = Math.max(i, this.getBlockPower(blockposition.east(), EnumDirection.EAST));
return i >= 15 ? i : i;
}
}
}
}
}
}
public boolean isBlockFacePowered(BlockPosition blockposition, EnumDirection enumdirection) {
return this.getBlockFacePower(blockposition, enumdirection) > 0;
}
public int getBlockFacePower(BlockPosition blockposition, EnumDirection enumdirection) {
IBlockData iblockdata = this.getType(blockposition);
return iblockdata.m() ? this.getBlockPower(blockposition) : iblockdata.a(this, blockposition, enumdirection);
}
public boolean isBlockIndirectlyPowered(BlockPosition blockposition) {
return this.getBlockFacePower(blockposition.down(), EnumDirection.DOWN) > 0 ? true : (this.getBlockFacePower(blockposition.up(), EnumDirection.UP) > 0 ? true : (this.getBlockFacePower(blockposition.north(), EnumDirection.NORTH) > 0 ? true : (this.getBlockFacePower(blockposition.south(), EnumDirection.SOUTH) > 0 ? true : (this.getBlockFacePower(blockposition.west(), EnumDirection.WEST) > 0 ? true : this.getBlockFacePower(blockposition.east(), EnumDirection.EAST) > 0))));
}
public int z(BlockPosition blockposition) {
int i = 0;
EnumDirection[] aenumdirection = EnumDirection.values();
int j = aenumdirection.length;
for (int k = 0; k < j; ++k) {
EnumDirection enumdirection = aenumdirection[k];
int l = this.getBlockFacePower(blockposition.shift(enumdirection), enumdirection);
if (l >= 15) {
return 15;
}
if (l > i) {
i = l;
}
}
return i;
}
@Nullable
public EntityHuman findNearbyPlayer(Entity entity, double d0) {
return this.a(entity.locX, entity.locY, entity.locZ, d0, false);
}
@Nullable
public EntityHuman b(Entity entity, double d0) {
return this.a(entity.locX, entity.locY, entity.locZ, d0, true);
}
@Nullable
public EntityHuman a(double d0, double d1, double d2, double d3, boolean flag) {
Predicate predicate = flag ? IEntitySelector.d : IEntitySelector.e;
return this.a(d0, d1, d2, d3, predicate);
}
@Nullable
public EntityHuman a(double d0, double d1, double d2, double d3, Predicate<Entity> predicate) {
double d4 = -1.0D;
EntityHuman entityhuman = null;
for (int i = 0; i < this.players.size(); ++i) {
EntityHuman entityhuman1 = this.players.get(i);
// CraftBukkit start - Fixed an NPE
if (entityhuman1 == null || entityhuman1.dead) {
continue;
}
// CraftBukkit end
if (predicate.apply(entityhuman1)) {
double d5 = entityhuman1.d(d0, d1, d2);
if ((d3 < 0.0D || d5 < d3 * d3) && (d4 == -1.0D || d5 < d4)) {
d4 = d5;
entityhuman = entityhuman1;
}
}
}
return entityhuman;
}
public boolean isPlayerNearby(double d0, double d1, double d2, double d3) {
for (int i = 0; i < this.players.size(); ++i) {
EntityHuman entityhuman = this.players.get(i);
if (IEntitySelector.e.apply(entityhuman) && entityhuman.affectsSpawning) { // Paper - Affects Spawning API
double d4 = entityhuman.d(d0, d1, d2);
if (d3 < 0.0D || d4 < d3 * d3) {
return true;
}
}
}
return false;
}
@Nullable
public EntityHuman a(Entity entity, double d0, double d1) {
return this.a(entity.locX, entity.locY, entity.locZ, d0, d1, (Function) null, (Predicate) null);
}
@Nullable
public EntityHuman a(BlockPosition blockposition, double d0, double d1) {
return this.a(blockposition.getX() + 0.5F, blockposition.getY() + 0.5F, blockposition.getZ() + 0.5F, d0, d1, (Function) null, (Predicate) null);
}
@Nullable
public EntityHuman a(double d0, double d1, double d2, double d3, double d4, @Nullable Function<EntityHuman, Double> function, @Nullable Predicate<EntityHuman> predicate) {
double d5 = -1.0D;
EntityHuman entityhuman = null;
for (int i = 0; i < this.players.size(); ++i) {
EntityHuman entityhuman1 = this.players.get(i);
if (!entityhuman1.abilities.isInvulnerable && entityhuman1.isAlive() && !entityhuman1.isSpectator() && (predicate == null || predicate.apply(entityhuman1))) {
double d6 = entityhuman1.d(d0, entityhuman1.locY, d2);
double d7 = d3;
if (entityhuman1.isSneaking()) {
d7 = d3 * 0.800000011920929D;
}
if (entityhuman1.isInvisible()) {
float f = entityhuman1.cO();
if (f < 0.1F) {
f = 0.1F;
}
d7 *= 0.7F * f;
}
if (function != null) {
d7 *= Objects.firstNonNull(function.apply(entityhuman1), Double.valueOf(1.0D)).doubleValue();
}
if ((d4 < 0.0D || Math.abs(entityhuman1.locY - d1) < d4 * d4) && (d3 < 0.0D || d6 < d7 * d7) && (d5 == -1.0D || d6 < d5)) {
d5 = d6;
entityhuman = entityhuman1;
}
}
}
return entityhuman;
}
@Nullable
public EntityHuman a(String s) {
for (int i = 0; i < this.players.size(); ++i) {
EntityHuman entityhuman = this.players.get(i);
if (s.equals(entityhuman.getName())) {
return entityhuman;
}
}
return null;
}
@Nullable
public EntityHuman b(UUID uuid) {
for (int i = 0; i < this.players.size(); ++i) {
EntityHuman entityhuman = this.players.get(i);
if (uuid.equals(entityhuman.getUniqueID())) {
return entityhuman;
}
}
return null;
}
public void checkSession() throws ExceptionWorldConflict {
this.dataManager.checkSession();
}
public long getSeed() {
return this.worldData.getSeed();
}
public long getTime() {
return this.worldData.getTime();
}
public long getDayTime() {
return this.worldData.getDayTime();
}
public void setDayTime(long i) {
this.worldData.setDayTime(i);
}
public BlockPosition getSpawn() {
BlockPosition blockposition = new BlockPosition(this.worldData.b(), this.worldData.c(), this.worldData.d());
if (!this.getWorldBorder().a(blockposition)) {
blockposition = this.getHighestBlockYAt(new BlockPosition(this.getWorldBorder().getCenterX(), 0.0D, this.getWorldBorder().getCenterZ()));
}
return blockposition;
}
public void A(BlockPosition blockposition) {
this.worldData.setSpawn(blockposition);
}
public boolean a(EntityHuman entityhuman, BlockPosition blockposition) {
return true;
}
public void broadcastEntityEffect(Entity entity, byte b0) {}
public IChunkProvider getChunkProvider() {
return this.chunkProvider;
}
public void playBlockAction(BlockPosition blockposition, Block block, int i, int j) {
this.getType(blockposition).a(this, blockposition, i, j);
}
public IDataManager getDataManager() {
return this.dataManager;
}
public WorldData getWorldData() {
return this.worldData;
}
public GameRules getGameRules() {
return this.worldData.w();
}
public void everyoneSleeping() {}
// CraftBukkit start
// Calls the method that checks to see if players are sleeping
// Called by CraftPlayer.setPermanentSleeping()
public void checkSleepStatus() {
if (!this.isClientSide) {
this.everyoneSleeping();
}
}
// CraftBukkit end
public float h(float f) {
return (this.p + (this.q - this.p) * f) * this.j(f);
}
public float j(float f) {
return this.n + (this.o - this.n) * f;
}
public boolean V() {
return this.h(1.0F) > 0.9D;
}
public boolean W() {
return this.j(1.0F) > 0.2D;
}
public boolean isRainingAt(BlockPosition blockposition) {
if (!this.W()) {
return false;
} else if (!this.h(blockposition)) {
return false;
} else if (this.p(blockposition).getY() > blockposition.getY()) {
return false;
} else {
BiomeBase biomebase = this.getBiome(blockposition);
return biomebase.c() ? false : (this.f(blockposition, false) ? false : biomebase.d());
}
}
public boolean C(BlockPosition blockposition) {
BiomeBase biomebase = this.getBiome(blockposition);
return biomebase.e();
}
@Nullable
public PersistentCollection X() {
return this.worldMaps;
}
public void a(String s, PersistentBase persistentbase) {
this.worldMaps.a(s, persistentbase);
}
@Nullable
public PersistentBase a(Class<? extends PersistentBase> oclass, String s) {
return this.worldMaps.get(oclass, s);
}
public int b(String s) {
return this.worldMaps.a(s);
}
public void a(int i, BlockPosition blockposition, int j) {
for (int k = 0; k < this.u.size(); ++k) {
this.u.get(k).a(i, blockposition, j);
}
}
public void triggerEffect(int i, BlockPosition blockposition, int j) {
this.a((EntityHuman) null, i, blockposition, j);
}
public void a(@Nullable EntityHuman entityhuman, int i, BlockPosition blockposition, int j) {
try {
for (int k = 0; k < this.u.size(); ++k) {
this.u.get(k).a(entityhuman, i, blockposition, j);
}
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Playing level event");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Level event being played");
crashreportsystemdetails.a("Block coordinates", CrashReportSystemDetails.a(blockposition));
crashreportsystemdetails.a("Event source", entityhuman);
crashreportsystemdetails.a("Event type", Integer.valueOf(i));
crashreportsystemdetails.a("Event data", Integer.valueOf(j));
throw new ReportedException(crashreport);
}
}
public int getHeight() {
return 256;
}
public int getActualWorldHeight() { return this.Z(); } // OBFHELPER
public int Z() {
return this.worldProvider.n() ? 128 : 256;
}
public Random a(int i, int j, int k) {
long l = i * 341873128712L + j * 132897987541L + this.getWorldData().getSeed() + k;
this.random.setSeed(l);
return this.random;
}
public CrashReportSystemDetails a(CrashReport crashreport) {
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Affected level", 1);
crashreportsystemdetails.a("Level name", this.worldData == null ? "????" : this.worldData.getName());
crashreportsystemdetails.a("All players", new CrashReportCallable() {
public String a() {
return World.this.players.size() + " total; " + World.this.players;
}
@Override
public Object call() throws Exception {
return this.a();
}
});
crashreportsystemdetails.a("Chunk stats", new CrashReportCallable() {
public String a() {
return World.this.chunkProvider.getName();
}
@Override
public Object call() throws Exception {
return this.a();
}
});
try {
this.worldData.a(crashreportsystemdetails);
} catch (Throwable throwable) {
crashreportsystemdetails.a("Level Data Unobtainable", throwable);
}
return crashreportsystemdetails;
}
public void c(int i, BlockPosition blockposition, int j) {
for (int k = 0; k < this.u.size(); ++k) {
IWorldAccess iworldaccess = this.u.get(k);
iworldaccess.b(i, blockposition, j);
}
}
public Calendar ac() {
if (this.getTime() % 600L == 0L) {
this.L.setTimeInMillis(MinecraftServer.aw());
}
return this.L;
}
public Scoreboard getScoreboard() {
return this.scoreboard;
}
public void updateAdjacentComparators(BlockPosition blockposition, Block block) {
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
while (iterator.hasNext()) {
EnumDirection enumdirection = (EnumDirection) iterator.next();
BlockPosition blockposition1 = blockposition.shift(enumdirection);
if (this.isLoaded(blockposition1)) {
IBlockData iblockdata = this.getType(blockposition1);
if (Blocks.UNPOWERED_COMPARATOR.E(iblockdata)) {
iblockdata.doPhysics(this, blockposition1, block, blockposition);
} else if (iblockdata.m()) {
blockposition1 = blockposition1.shift(enumdirection);
iblockdata = this.getType(blockposition1);
if (Blocks.UNPOWERED_COMPARATOR.E(iblockdata)) {
iblockdata.doPhysics(this, blockposition1, block, blockposition);
}
}
}
}
}
public DifficultyDamageScaler createDamageScaler(BlockPosition position) { return this.D(position); } // OBFHELPER
public DifficultyDamageScaler D(BlockPosition blockposition) {
long i = 0L;
float f = 0.0F;
if (this.isLoaded(blockposition)) {
f = this.E();
i = this.getChunkAtWorldCoords(blockposition).x();
}
return new DifficultyDamageScaler(this.getDifficulty(), this.getDayTime(), i, f);
}
public EnumDifficulty getDifficulty() {
return this.getWorldData().getDifficulty();
}
public int af() {
return this.J;
}
public void c(int i) {
this.J = i;
}
public void d(int i) {
this.K = i;
}
public PersistentVillage ai() {
return this.villages;
}
public WorldBorder getWorldBorder() {
return this.N;
}
public boolean shouldStayLoaded(int i, int j) { return e(i, j); } // Paper - OBFHELPER
public boolean e(int i, int j) {
BlockPosition blockposition = this.getSpawn();
int k = i * 16 + 8 - blockposition.getX();
int l = j * 16 + 8 - blockposition.getZ();
boolean flag = true;
short keepLoadedRange = paperConfig.keepLoadedRange; // Paper
return k >= -keepLoadedRange && k <= keepLoadedRange && l >= -keepLoadedRange && l <= keepLoadedRange && this.keepSpawnInMemory; // CraftBukkit - Added 'this.keepSpawnInMemory' // Paper - Re-add range var
}
public void a(Packet<?> packet) {
throw new UnsupportedOperationException("Can\'t send packets to server unless you\'re on the client.");
}
public LootTableRegistry ak() {
return this.B;
}
@Nullable
public BlockPosition a(String s, BlockPosition blockposition, boolean flag) {
return null;
}
}