3177 lines
122 KiB
Java
3177 lines
122 KiB
Java
package net.minecraft.server;
|
|
|
|
import co.aikar.timings.Timings;
|
|
import io.akarin.server.core.AkarinWorldAccessor;
|
|
|
|
import com.destroystokyo.paper.antixray.ChunkPacketBlockController; // Paper - Anti-Xray
|
|
import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray; // Paper - Anti-Xray
|
|
import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
|
import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import com.google.common.base.MoreObjects;
|
|
import com.google.common.collect.Lists;
|
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
|
import it.unimi.dsi.fastutil.longs.LongSets;
|
|
import java.util.Collection;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Random;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
import java.util.function.BooleanSupplier;
|
|
import java.util.function.Function;
|
|
import java.util.function.Predicate;
|
|
import java.util.stream.Stream;
|
|
import javax.annotation.Nullable;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
// CraftBukkit start
|
|
import com.google.common.collect.Maps;
|
|
import com.koloboke.collect.map.hash.HashObjObjMaps;
|
|
import com.koloboke.collect.set.hash.HashObjSets;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap; // Paper
|
|
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.block.CraftBlockState;
|
|
import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
|
import org.bukkit.craftbukkit.event.CraftEventFactory;
|
|
import org.bukkit.craftbukkit.util.LongHashSet; // Paper
|
|
import org.bukkit.event.block.BlockPhysicsEvent;
|
|
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
|
import org.bukkit.generator.ChunkGenerator;
|
|
// CraftBukkit end
|
|
|
|
public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAccess, AutoCloseable, Cloneable { // Paper
|
|
|
|
protected static final Logger e = LogManager.getLogger();
|
|
private static final EnumDirection[] a = EnumDirection.values();
|
|
private int b = 63;
|
|
// Spigot start - guard entity list from removals
|
|
public final com.destroystokyo.paper.PaperWorldEntityList entityList = new com.destroystokyo.paper.PaperWorldEntityList(this);
|
|
/* // Paper start
|
|
{
|
|
@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();
|
|
}
|
|
}
|
|
};
|
|
*/ // Paper end
|
|
// Spigot end
|
|
protected final Set<Entity> g = HashObjSets.newMutableSet(); public Set<Entity> getEntityUnloadQueue() { return g; };// Paper - OBFHELPER // Akarin
|
|
//public final List<TileEntity> tileEntityList = Lists.newArrayList(); // Paper - remove unused list
|
|
public final List<TileEntity> tileEntityListTick = Lists.newArrayList();
|
|
private final List<TileEntity> c = Lists.newArrayList();
|
|
private final Set<TileEntity> tileEntityListUnload = HashObjSets.newMutableSet(); // Paper // Akarin
|
|
public final List<EntityHuman> players = Lists.newCopyOnWriteArrayList(); // Akarin - iterate safety
|
|
public final Map<String, EntityHuman> playersByName = HashObjObjMaps.newMutableMap(); // Paper - World EntityHuman Lookup Optimizations // Akarin
|
|
public final List<Entity> k = Lists.newArrayList();
|
|
protected final IntHashMap<Entity> entitiesById = new IntHashMap<>();
|
|
private final long F = 16777215L;
|
|
private int G; public int getSkylightSubtracted() { return this.G; } public void setSkylightSubtracted(int value) { this.G = value;} // Paper - OBFHELPER
|
|
protected int m = (new Random()).nextInt();
|
|
protected final int n = 1013904223;
|
|
protected float o;
|
|
protected float p;
|
|
protected float q;
|
|
protected float r;
|
|
private int H;
|
|
public final Random random = new Random();
|
|
public WorldProvider worldProvider;
|
|
protected NavigationListener u = new NavigationListener();
|
|
protected List<IWorldAccess> v;
|
|
private AkarinWorldAccessor worldAccessor; // Akarin
|
|
protected IChunkProvider chunkProvider;
|
|
protected final IDataManager dataManager;
|
|
public WorldData worldData;
|
|
@Nullable
|
|
public final PersistentCollection worldMaps;
|
|
protected PersistentVillage villages;
|
|
public final MethodProfiler methodProfiler;
|
|
public final boolean isClientSide;
|
|
// Paper start - yes this is hacky as shit
|
|
RegionLimitedWorldAccess regionLimited;
|
|
World originalWorld;
|
|
public World regionLimited(RegionLimitedWorldAccess limitedWorldAccess) {
|
|
try {
|
|
World clone = (World) super.clone();
|
|
clone.regionLimited = limitedWorldAccess;
|
|
clone.originalWorld = this;
|
|
return clone;
|
|
} catch (CloneNotSupportedException e1) {
|
|
}
|
|
return null;
|
|
}
|
|
ChunkCoordIntPair[] strongholdCoords;
|
|
final java.util.concurrent.atomic.AtomicBoolean
|
|
strongholdInit = new java.util.concurrent.atomic.AtomicBoolean
|
|
(false);
|
|
// Paper end
|
|
public boolean allowMonsters;
|
|
public boolean allowAnimals;
|
|
private boolean J;
|
|
private final WorldBorder K;
|
|
int[] E;
|
|
|
|
// CraftBukkit start Added the following
|
|
private final CraftWorld world;
|
|
public boolean pvpMode;
|
|
public boolean keepSpawnInMemory = true;
|
|
public ChunkGenerator generator;
|
|
public static final boolean DEBUG_ENTITIES = Boolean.getBoolean("debug.entities"); // Paper
|
|
|
|
public boolean captureBlockStates = false;
|
|
public boolean captureTreeGeneration = false;
|
|
public ArrayList<CraftBlockState> capturedBlockStates = new ArrayList<CraftBlockState>() {
|
|
@Override
|
|
public boolean add(CraftBlockState blockState) {
|
|
Iterator<CraftBlockState> blockStateIterator = this.iterator();
|
|
while (blockStateIterator.hasNext()) {
|
|
BlockState blockState1 = blockStateIterator.next();
|
|
if (blockState1.getLocation().equals(blockState.getLocation())) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return super.add(blockState);
|
|
}
|
|
};
|
|
public List<EntityItem> captureDrops;
|
|
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 ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
|
|
|
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
|
|
public boolean guardEntityList; // Spigot // Paper - public
|
|
public static BlockPosition lastPhysicsProblem; // 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 = new HashMap<>(); // Paper - Optimize explosions
|
|
|
|
public CraftWorld getWorld() {
|
|
return this.world;
|
|
}
|
|
|
|
public CraftServer getServer() {
|
|
return (CraftServer) Bukkit.getServer();
|
|
}
|
|
|
|
public Chunk getChunkIfLoaded(int x, int z) {
|
|
return ((ChunkProviderServer) this.chunkProvider).chunks.get(ChunkCoordIntPair.a(x, z)); // Paper - optimize getChunkIfLoaded
|
|
}
|
|
|
|
protected World(IDataManager idatamanager, @Nullable PersistentCollection persistentcollection, 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.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this.paperConfig) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
|
|
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.v = Lists.newArrayList(); // Akarin
|
|
this.allowMonsters = true;
|
|
this.allowAnimals = true;
|
|
this.E = new int['\u8000'];
|
|
this.dataManager = idatamanager;
|
|
this.worldMaps = persistentcollection;
|
|
this.methodProfiler = methodprofiler;
|
|
this.worldData = worlddata;
|
|
this.worldProvider = worldprovider;
|
|
this.isClientSide = flag;
|
|
this.K = worldprovider.getWorldBorder();
|
|
// CraftBukkit start
|
|
getWorldBorder().world = (WorldServer) this;
|
|
// From PlayerList.setPlayerFileData
|
|
getWorldBorder().a(new IWorldBorderListener() {
|
|
public void a(WorldBorder worldborder, double d0) {
|
|
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.SET_SIZE), worldborder.world);
|
|
}
|
|
|
|
public void a(WorldBorder worldborder, double d0, double d1, long i) {
|
|
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.LERP_SIZE), worldborder.world);
|
|
}
|
|
|
|
public void a(WorldBorder worldborder, double d0, double d1) {
|
|
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.SET_CENTER), worldborder.world);
|
|
}
|
|
|
|
public void a(WorldBorder worldborder, int i) {
|
|
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.SET_WARNING_TIME), worldborder.world);
|
|
}
|
|
|
|
public void b(WorldBorder worldborder, int i) {
|
|
getServer().getHandle().sendAll(new PacketPlayOutWorldBorder(worldborder, PacketPlayOutWorldBorder.EnumWorldBorderAction.SET_WARNING_BLOCKS), worldborder.world);
|
|
}
|
|
|
|
public void b(WorldBorder worldborder, double d0) {}
|
|
|
|
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 BiomeBase getBiome(BlockPosition blockposition) {
|
|
if (this.isLoaded(blockposition)) {
|
|
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
|
|
|
|
try {
|
|
return chunk.getBiome(blockposition);
|
|
} catch (Throwable throwable) {
|
|
CrashReport crashreport = CrashReport.a(throwable, "Getting biome");
|
|
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Coordinates of biome request");
|
|
|
|
crashreportsystemdetails.a("Location", () -> {
|
|
return CrashReportSystemDetails.a(blockposition);
|
|
});
|
|
throw new ReportedException(crashreport);
|
|
}
|
|
} else {
|
|
return this.chunkProvider.getChunkGenerator().getWorldChunkManager().getBiome(blockposition, Biomes.PLAINS);
|
|
}
|
|
}
|
|
|
|
protected abstract IChunkProvider r();
|
|
|
|
public void a(WorldSettings worldsettings) {
|
|
this.worldData.d(true);
|
|
}
|
|
|
|
public boolean e() {
|
|
return this.isClientSide;
|
|
}
|
|
|
|
@Nullable
|
|
public MinecraftServer getMinecraftServer() {
|
|
return null;
|
|
}
|
|
|
|
public IBlockData i(BlockPosition blockposition) {
|
|
BlockPosition blockposition1;
|
|
|
|
for (blockposition1 = new BlockPosition(blockposition.getX(), this.getSeaLevel(), blockposition.getZ()); !this.isEmpty(blockposition1.up()); blockposition1 = blockposition1.up()) {
|
|
;
|
|
}
|
|
|
|
return this.getType(blockposition1);
|
|
}
|
|
|
|
public static boolean isValidLocation(BlockPosition blockposition) {
|
|
return blockposition.isValidLocation(); // Paper
|
|
}
|
|
|
|
public static boolean k(BlockPosition blockposition) {
|
|
return blockposition.isInvalidYLocation(); // Paper
|
|
}
|
|
|
|
public boolean isEmpty(BlockPosition blockposition) {
|
|
return this.getType(blockposition).isAir();
|
|
}
|
|
|
|
public boolean isLoaded(BlockPosition blockposition) {
|
|
return getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null; // Paper
|
|
}
|
|
|
|
// Paper start
|
|
public boolean isLoadedAndInBounds(BlockPosition blockposition) {
|
|
return getWorldBorder().isInBounds(blockposition) && getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null;
|
|
}
|
|
public Chunk getChunkIfLoaded(BlockPosition blockposition) {
|
|
return getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
|
|
}
|
|
// 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).c(this, blockposition)) {
|
|
int sky = getSkylightSubtracted();
|
|
if (this.getLightLevel(blockposition.up(), sky) >= level) {
|
|
return true;
|
|
}
|
|
if (this.getLightLevel(blockposition.east(), sky) >= level) {
|
|
return true;
|
|
}
|
|
if (this.getLightLevel(blockposition.west(), sky) >= level) {
|
|
return true;
|
|
}
|
|
if (this.getLightLevel(blockposition.south(), sky) >= level) {
|
|
return true;
|
|
}
|
|
if (this.getLightLevel(blockposition.north(), sky) >= 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.getLightSubtracted(blockposition, this.getSkylightSubtracted()) >= level;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
// reduces need to do isLoaded before getType
|
|
public IBlockData getTypeIfLoadedAndInBounds(BlockPosition blockposition) {
|
|
return getWorldBorder().isInBounds(blockposition) ? getTypeIfLoaded(blockposition) : null;
|
|
}
|
|
public IBlockData getTypeIfLoaded(BlockPosition blockposition) {
|
|
// CraftBukkit start - tree generation
|
|
if (captureTreeGeneration) {
|
|
for (CraftBlockState previous : capturedBlockStates) {
|
|
if (previous.getX() == blockposition.getX() && previous.getY() == blockposition.getY() && previous.getZ() == blockposition.getZ()) {
|
|
return previous.getHandle();
|
|
}
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
Chunk chunk = this.getChunkIfLoaded(blockposition);
|
|
if (chunk != null) {
|
|
return blockposition.isValidLocation() ? chunk.getBlockData(blockposition) : Blocks.AIR.getBlockData(); // Paper
|
|
}
|
|
return null;
|
|
}
|
|
public Block getBlockIfLoaded(BlockPosition blockposition) {
|
|
IBlockData type = getTypeIfLoaded(blockposition);
|
|
if (type == null) {
|
|
return null;
|
|
}
|
|
return type.getBlock();
|
|
}
|
|
public Material getMaterialIfLoaded(BlockPosition blockposition) {
|
|
IBlockData type = getTypeIfLoaded(blockposition);
|
|
if (type == null) {
|
|
return null;
|
|
}
|
|
return type.getBlock().material;
|
|
}
|
|
// Paper end
|
|
|
|
public Chunk getChunkAtWorldCoords(BlockPosition blockposition) {
|
|
return this.getChunkAt(blockposition.getX() >> 4, blockposition.getZ() >> 4);
|
|
}
|
|
|
|
public Chunk getChunkAt(int i, int j) {
|
|
Chunk chunk = this.chunkProvider.getChunkAt(i, j, true, true);
|
|
|
|
if (chunk == null) {
|
|
throw new IllegalStateException("Should always be able to create a chunk!");
|
|
} else {
|
|
return chunk;
|
|
}
|
|
}
|
|
|
|
public boolean setTypeAndData(BlockPosition blockposition, IBlockData iblockdata, int i) {
|
|
// CraftBukkit start - tree generation
|
|
if (this.captureTreeGeneration) {
|
|
CraftBlockState blockstate = null;
|
|
Iterator<CraftBlockState> it = capturedBlockStates.iterator();
|
|
while (it.hasNext()) {
|
|
CraftBlockState previous = it.next();
|
|
if (previous.getPosition().equals(blockposition)) {
|
|
blockstate = previous;
|
|
it.remove();
|
|
break;
|
|
}
|
|
}
|
|
if (blockstate == null) {
|
|
blockstate = org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(this, blockposition, i);
|
|
}
|
|
blockstate.setData(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
|
|
CraftBlockState blockstate = null;
|
|
if (this.captureBlockStates) {
|
|
blockstate = (CraftBlockState) world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()).getState(); // Paper - use CB getState to get a suitable snapshot
|
|
this.capturedBlockStates.add(blockstate);
|
|
}
|
|
// CraftBukkit end
|
|
|
|
IBlockData iblockdata1 = chunk.setType(blockposition, iblockdata, (i & 64) != 0, (i & 1024) == 0); // CraftBukkit custom NO_PLACE flag
|
|
this.chunkPacketBlockController.onBlockChange(this, blockposition, iblockdata, iblockdata1, i); // Paper - Anti-Xray
|
|
|
|
if (iblockdata1 == null) {
|
|
// CraftBukkit start - remove blockstate if failed
|
|
if (this.captureBlockStates) {
|
|
this.capturedBlockStates.remove(blockstate);
|
|
}
|
|
// CraftBukkit end
|
|
return false;
|
|
} else {
|
|
IBlockData iblockdata2 = this.getType(blockposition);
|
|
|
|
if (iblockdata2.b(this, blockposition) != iblockdata1.b(this, blockposition) || iblockdata2.e() != iblockdata1.e()) {
|
|
//this.methodProfiler.enter(* // Akarin - remove caller
|
|
chunk.runOrQueueLightUpdate(() -> this.r(blockposition)); // Paper - Queue light update
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
}
|
|
|
|
/*
|
|
if (iblockdata2 == iblockdata) {
|
|
if (iblockdata1 != iblockdata2) {
|
|
this.a(blockposition, blockposition);
|
|
}
|
|
|
|
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());
|
|
if (iblockdata.isComplexRedstone()) {
|
|
this.updateAdjacentComparators(blockposition, block);
|
|
}
|
|
}
|
|
|
|
if ((i & 16) == 0) {
|
|
int j = i & -2;
|
|
|
|
iblockdata1.b(this, blockposition, j);
|
|
iblockdata.a((GeneratorAccess) this, blockposition, j);
|
|
iblockdata.b(this, blockposition, j);
|
|
}
|
|
}
|
|
*/
|
|
|
|
// CraftBukkit start
|
|
if (!this.captureBlockStates) { // Don't notify clients or update physics while capturing blockstates
|
|
// Modularize client and physic updates
|
|
// Spigot start
|
|
try {
|
|
notifyAndUpdatePhysics(blockposition, chunk, iblockdata1, iblockdata, iblockdata2, i);
|
|
} catch (StackOverflowError ex) {
|
|
lastPhysicsProblem = new BlockPosition(blockposition);
|
|
}
|
|
// Spigot end
|
|
}
|
|
// 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, IBlockData actualBlock, int i) {
|
|
IBlockData iblockdata = newBlock;
|
|
IBlockData iblockdata1 = oldBlock;
|
|
IBlockData iblockdata2 = actualBlock;
|
|
if (iblockdata2 == iblockdata) {
|
|
// Akarin start
|
|
/*
|
|
if (iblockdata1 != iblockdata2) {
|
|
this.a(blockposition, blockposition);
|
|
}
|
|
*/
|
|
// Akarin end
|
|
|
|
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, iblockdata1, iblockdata, i);
|
|
}
|
|
|
|
if (!this.isClientSide && (i & 1) != 0) {
|
|
this.update(blockposition, iblockdata1.getBlock());
|
|
if (iblockdata.isComplexRedstone()) {
|
|
this.updateAdjacentComparators(blockposition, newBlock.getBlock());
|
|
}
|
|
}
|
|
|
|
if ((i & 16) == 0) {
|
|
int j = i & -2;
|
|
|
|
// CraftBukkit start
|
|
iblockdata1.b(this, blockposition, j); // Don't call an event for the old block to limit event spam
|
|
CraftWorld world = ((WorldServer) this).getWorld();
|
|
if (world != null && ((WorldServer)this).hasPhysicsEvent && !io.akarin.server.core.AkarinGlobalConfig.fixPhysicsEventBehaviour) { // Paper // Akarin - fixes physics event
|
|
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata));
|
|
this.getServer().getPluginManager().callEvent(event);
|
|
|
|
if (event.isCancelled()) {
|
|
return;
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
iblockdata.a((GeneratorAccess) this, blockposition, j);
|
|
iblockdata.b(this, blockposition, j);
|
|
}
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
|
|
public boolean setAir(BlockPosition blockposition) {
|
|
Fluid fluid = this.getFluid(blockposition);
|
|
|
|
return this.setTypeAndData(blockposition, fluid.i(), 3);
|
|
}
|
|
|
|
public boolean setAir(BlockPosition blockposition, boolean flag) {
|
|
IBlockData iblockdata = this.getType(blockposition);
|
|
|
|
if (iblockdata.isAir()) {
|
|
return false;
|
|
} else {
|
|
Fluid fluid = this.getFluid(blockposition);
|
|
// Paper start - while the above setAir method is named same and looks very similar
|
|
// they are NOT used with same intent and the above should not fire this event. The above method is more of a BlockSetToAirEvent,
|
|
// it doesn't imply destruction of a block that plays a sound effect / drops an item.
|
|
boolean playEffect = true;
|
|
if (com.destroystokyo.paper.event.block.BlockDestroyEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
|
com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(MCUtil.toBukkitBlock(this, blockposition), fluid.i().createCraftBlockData(), flag);
|
|
if (!event.callEvent()) {
|
|
return false;
|
|
}
|
|
playEffect = event.playEffect();
|
|
}
|
|
// Paper end
|
|
|
|
if (playEffect) this.triggerEffect(2001, blockposition, Block.getCombinedId(iblockdata)); // Paper
|
|
if (flag) {
|
|
iblockdata.a(this, blockposition, 0);
|
|
}
|
|
|
|
return this.setTypeAndData(blockposition, fluid.i(), 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) {
|
|
// Akarin start
|
|
/*
|
|
for (int j = 0; j < this.v.size(); ++j) {
|
|
((IWorldAccess) this.v.get(j)).a(this, blockposition, iblockdata, iblockdata1, i);
|
|
}
|
|
*/
|
|
worldAccessor.a(this, blockposition, iblockdata, iblockdata1, i);
|
|
// Akarin end
|
|
|
|
}
|
|
|
|
public void update(BlockPosition blockposition, Block block) {
|
|
if (this.worldData.getType() != WorldType.DEBUG_ALL_BLOCK_STATES) {
|
|
// CraftBukkit start
|
|
if (populating) {
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
this.applyPhysics(blockposition, block);
|
|
}
|
|
|
|
}
|
|
|
|
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.g()) {
|
|
Chunk chunk = getChunkIfLoaded(i >> 4, j >> 4); // Paper
|
|
for (i1 = k; chunk != null && i1 <= l; ++i1) { // Paper
|
|
this.updateBrightness(EnumSkyBlock.SKY, new BlockPosition(i, i1, j), chunk); // Paper
|
|
}
|
|
}
|
|
|
|
//this.a(i, k, j, i, l, j); // Akarin
|
|
}
|
|
|
|
public void a(BlockPosition blockposition, BlockPosition blockposition1) {
|
|
this.a(blockposition.getX(), blockposition.getY(), blockposition.getZ(), blockposition1.getX(), blockposition1.getY(), blockposition1.getZ());
|
|
}
|
|
|
|
public void a(int i, int j, int k, int l, int i1, int j1) {
|
|
for (int k1 = 0; k1 < this.v.size(); ++k1) {
|
|
((IWorldAccess) this.v.get(k1)).a(i, j, k, l, i1, j1);
|
|
}
|
|
|
|
}
|
|
|
|
public void applyPhysics(BlockPosition blockposition, Block block) {
|
|
if (captureBlockStates) { return; } // Paper - Cancel all physics during placement
|
|
this.a(blockposition.shiftX(-1), block, blockposition); // Akarin - west
|
|
this.a(blockposition.shiftX(2), block, blockposition); // Akarin - east
|
|
this.a(blockposition.shiftX(-1).shiftY(-1), block, blockposition); // Akarin - down
|
|
this.a(blockposition.shiftY(2), block, blockposition); // Akarin - up
|
|
this.a(blockposition.shiftY(-1).shiftZ(-1), block, blockposition); // Akarin - north
|
|
this.a(blockposition.shiftZ(2), block, blockposition); // Akarin - south
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
}
|
|
|
|
public void neighborChanged(BlockPosition pos, Block blockIn, BlockPosition fromPos) { a(pos, blockIn, fromPos); } // Paper - OBFHELPER
|
|
public void a(BlockPosition blockposition, 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).hasPhysicsEvent) { // Paper
|
|
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata), world.getBlockAt(blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()));
|
|
this.getServer().getPluginManager().callEvent(event);
|
|
|
|
if (event.isCancelled()) {
|
|
return;
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
iblockdata.doPhysics(this, blockposition, block, blockposition1);
|
|
// Spigot Start
|
|
} catch (StackOverflowError ex) {
|
|
lastPhysicsProblem = new BlockPosition(blockposition);
|
|
// 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", () -> {
|
|
try {
|
|
return String.format("ID #%s (%s // %s)", IRegistry.BLOCK.getKey(block), block.m(), block.getClass().getCanonicalName());
|
|
} catch (Throwable throwable1) {
|
|
return "ID #" + IRegistry.BLOCK.getKey(block);
|
|
}
|
|
});
|
|
CrashReportSystemDetails.a(crashreportsystemdetails, blockposition, iblockdata);
|
|
throw new ReportedException(crashreport);
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean e(BlockPosition blockposition) {
|
|
return this.getChunkAtWorldCoords(blockposition).c(blockposition);
|
|
}
|
|
|
|
public int getLightLevel(BlockPosition blockposition, int i) {
|
|
if (blockposition.getX() >= -30000000 && blockposition.getZ() >= -30000000 && blockposition.getX() < 30000000 && blockposition.getZ() < 30000000) {
|
|
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
|
|
|
|
return this.getChunkAtWorldCoords(blockposition).a(blockposition, i);
|
|
}
|
|
} else {
|
|
return 15;
|
|
}
|
|
}
|
|
|
|
public int a(HeightMap.Type heightmap_type, 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).a(heightmap_type, i & 15, j & 15) + 1;
|
|
} else {
|
|
k = 0;
|
|
}
|
|
} else {
|
|
k = this.getSeaLevel() + 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.D();
|
|
}
|
|
} else {
|
|
return this.getSeaLevel() + 1;
|
|
}
|
|
}
|
|
|
|
public int getBrightness(EnumSkyBlock enumskyblock, BlockPosition blockposition) {
|
|
if (blockposition.getY() < 0) {
|
|
blockposition = new BlockPosition(blockposition.getX(), 0, blockposition.getZ());
|
|
}
|
|
|
|
Chunk chunk; // Paper
|
|
return !blockposition.isValidLocation() ? enumskyblock.c : ((chunk = this.getChunkIfLoaded(blockposition)) == null ? enumskyblock.c : chunk.getBrightness(enumskyblock, blockposition)); // Paper - optimize ifChunkLoaded
|
|
}
|
|
|
|
public void a(EnumSkyBlock enumskyblock, BlockPosition blockposition, int i) {
|
|
if (blockposition.isValidLocation()) { // Paper
|
|
if (this.isLoaded(blockposition)) {
|
|
this.getChunkAtWorldCoords(blockposition).a(enumskyblock, blockposition, i);
|
|
//this.m(blockposition); // Akarin
|
|
}
|
|
}
|
|
}
|
|
|
|
public void m(BlockPosition blockposition) {
|
|
for (int i = 0; i < this.v.size(); ++i) {
|
|
((IWorldAccess) this.v.get(i)).a(blockposition);
|
|
}
|
|
|
|
}
|
|
|
|
// Paper - async variant
|
|
public java.util.concurrent.CompletableFuture<IBlockData> getTypeAsync(BlockPosition blockposition) {
|
|
int x = blockposition.getX();
|
|
int z = blockposition.getZ();
|
|
if (captureTreeGeneration) {
|
|
Iterator<CraftBlockState> it = capturedBlockStates.iterator();
|
|
while (it.hasNext()) {
|
|
CraftBlockState previous = it.next();
|
|
if (previous.getX() == x && previous.getY() == blockposition.getY() && previous.getZ() == z) {
|
|
return java.util.concurrent.CompletableFuture.completedFuture(previous.getHandle());
|
|
}
|
|
}
|
|
}
|
|
if (blockposition.isInvalidYLocation()) {
|
|
return java.util.concurrent.CompletableFuture.completedFuture(Blocks.VOID_AIR.getBlockData());
|
|
} else {
|
|
java.util.concurrent.CompletableFuture<IBlockData> future = new java.util.concurrent.CompletableFuture<>();
|
|
((ChunkProviderServer) chunkProvider).getChunkAt(x << 4, z << 4, true, true, (chunk) -> {
|
|
future.complete(chunk.getType(blockposition));
|
|
});
|
|
return future;
|
|
}
|
|
}
|
|
// Paper end
|
|
|
|
public IBlockData getType(BlockPosition blockposition) {
|
|
// CraftBukkit start - tree generation
|
|
if (captureTreeGeneration) { // If any of this logic updates, update async variant above
|
|
Iterator<CraftBlockState> it = capturedBlockStates.iterator();
|
|
while (it.hasNext()) { // If any of this logic updates, update async variant above
|
|
CraftBlockState previous = it.next();
|
|
if (previous.getX() == blockposition.getX() && previous.getY() == blockposition.getY() && previous.getZ() == blockposition.getZ()) {
|
|
return previous.getHandle(); // If any of this logic updates, update async variant above
|
|
}
|
|
} // If any of this logic updates, update async variant above
|
|
}
|
|
// CraftBukkit end
|
|
if (blockposition.isInvalidYLocation()) { // Paper
|
|
return Blocks.VOID_AIR.getBlockData();
|
|
} else {
|
|
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
|
|
|
|
return chunk.getType(blockposition);
|
|
}
|
|
}
|
|
// Paper start
|
|
public Fluid getFluidIfLoaded(BlockPosition blockposition) {
|
|
if (blockposition.isInvalidYLocation()) { // Paper
|
|
return getFluid(blockposition);
|
|
} else {
|
|
Chunk chunk = this.getChunkIfLoaded(blockposition);
|
|
|
|
return chunk != null ? chunk.getFluid(blockposition) : null;
|
|
}
|
|
}
|
|
// Paper end
|
|
public Fluid getFluid(BlockPosition blockposition) {
|
|
if (blockposition.isInvalidYLocation()) { // Paper
|
|
return FluidTypes.EMPTY.i();
|
|
} else {
|
|
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
|
|
|
|
return chunk.getFluid(blockposition);
|
|
}
|
|
}
|
|
|
|
public boolean isDayTime() { return L(); } // Paper - OBFHELPER
|
|
public boolean L() {
|
|
return this.G < 4;
|
|
}
|
|
|
|
@Nullable
|
|
public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1) {
|
|
return this.rayTrace(vec3d, vec3d1, FluidCollisionOption.NEVER, false, false);
|
|
}
|
|
|
|
@Nullable
|
|
public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1, FluidCollisionOption fluidcollisionoption) {
|
|
return this.rayTrace(vec3d, vec3d1, fluidcollisionoption, false, false);
|
|
}
|
|
|
|
@Nullable
|
|
public MovingObjectPosition rayTrace(Vec3D vec3d, Vec3D vec3d1, FluidCollisionOption fluidcollisionoption, boolean flag, boolean flag1) {
|
|
double d0 = vec3d.x;
|
|
double d1 = vec3d.y;
|
|
double d2 = vec3d.z;
|
|
|
|
if (!Double.isNaN(d0) && !Double.isNaN(d1) && !Double.isNaN(d2)) {
|
|
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(d0);
|
|
int i1 = MathHelper.floor(d1);
|
|
int j1 = MathHelper.floor(d2);
|
|
BlockPosition blockposition = new BlockPosition(l, i1, j1);
|
|
IBlockData iblockdata = this.getTypeIfLoaded(blockposition); // Paper
|
|
if (iblockdata == null) return null; // Paper
|
|
Fluid fluid = this.getFluid(blockposition);
|
|
boolean flag2;
|
|
boolean flag3;
|
|
|
|
if (!flag || !iblockdata.getCollisionShape(this, blockposition).isEmpty()) {
|
|
flag2 = iblockdata.getBlock().isCollidable(iblockdata);
|
|
flag3 = fluidcollisionoption.predicate.test(fluid);
|
|
if (flag2 || flag3) {
|
|
MovingObjectPosition movingobjectposition = null;
|
|
|
|
if (flag2) {
|
|
movingobjectposition = Block.rayTrace(iblockdata, this, blockposition, vec3d, vec3d1);
|
|
}
|
|
|
|
if (movingobjectposition == null && flag3) {
|
|
movingobjectposition = VoxelShapes.create(0.0D, 0.0D, 0.0D, 1.0D, (double) fluid.getHeight(), 1.0D).rayTrace(vec3d, vec3d1, blockposition);
|
|
}
|
|
|
|
if (movingobjectposition != null) {
|
|
return movingobjectposition;
|
|
}
|
|
}
|
|
}
|
|
|
|
MovingObjectPosition movingobjectposition1 = null;
|
|
int k1 = 200;
|
|
|
|
while (k1-- >= 0) {
|
|
if (Double.isNaN(d0) || Double.isNaN(d1) || Double.isNaN(d2)) {
|
|
return null;
|
|
}
|
|
|
|
if (l == i && i1 == j && j1 == k) {
|
|
return flag1 ? movingobjectposition1 : null;
|
|
}
|
|
|
|
flag2 = true;
|
|
flag3 = true;
|
|
boolean flag4 = true;
|
|
double d3 = 999.0D;
|
|
double d4 = 999.0D;
|
|
double d5 = 999.0D;
|
|
|
|
if (i > l) {
|
|
d3 = (double) l + 1.0D;
|
|
} else if (i < l) {
|
|
d3 = (double) l + 0.0D;
|
|
} else {
|
|
flag2 = false;
|
|
}
|
|
|
|
if (j > i1) {
|
|
d4 = (double) i1 + 1.0D;
|
|
} else if (j < i1) {
|
|
d4 = (double) i1 + 0.0D;
|
|
} else {
|
|
flag3 = false;
|
|
}
|
|
|
|
if (k > j1) {
|
|
d5 = (double) j1 + 1.0D;
|
|
} else if (k < j1) {
|
|
d5 = (double) j1 + 0.0D;
|
|
} else {
|
|
flag4 = false;
|
|
}
|
|
|
|
double d6 = 999.0D;
|
|
double d7 = 999.0D;
|
|
double d8 = 999.0D;
|
|
double d9 = vec3d1.x - d0;
|
|
double d10 = vec3d1.y - d1;
|
|
double d11 = vec3d1.z - d2;
|
|
|
|
if (flag2) {
|
|
d6 = (d3 - d0) / d9;
|
|
}
|
|
|
|
if (flag3) {
|
|
d7 = (d4 - d1) / d10;
|
|
}
|
|
|
|
if (flag4) {
|
|
d8 = (d5 - d2) / d11;
|
|
}
|
|
|
|
if (d6 == -0.0D) {
|
|
d6 = -1.0E-4D;
|
|
}
|
|
|
|
if (d7 == -0.0D) {
|
|
d7 = -1.0E-4D;
|
|
}
|
|
|
|
if (d8 == -0.0D) {
|
|
d8 = -1.0E-4D;
|
|
}
|
|
|
|
EnumDirection enumdirection;
|
|
|
|
if (d6 < d7 && d6 < d8) {
|
|
enumdirection = i > l ? EnumDirection.WEST : EnumDirection.EAST;
|
|
d0 = d3;
|
|
d1 += d10 * d6;
|
|
d2 += d11 * d6;
|
|
} else if (d7 < d8) {
|
|
enumdirection = j > i1 ? EnumDirection.DOWN : EnumDirection.UP;
|
|
d0 += d9 * d7;
|
|
d1 = d4;
|
|
d2 += d11 * d7;
|
|
} else {
|
|
enumdirection = k > j1 ? EnumDirection.NORTH : EnumDirection.SOUTH;
|
|
d0 += d9 * d8;
|
|
d1 += d10 * d8;
|
|
d2 = d5;
|
|
}
|
|
|
|
l = MathHelper.floor(d0) - (enumdirection == EnumDirection.EAST ? 1 : 0);
|
|
i1 = MathHelper.floor(d1) - (enumdirection == EnumDirection.UP ? 1 : 0);
|
|
j1 = MathHelper.floor(d2) - (enumdirection == EnumDirection.SOUTH ? 1 : 0);
|
|
blockposition = new BlockPosition(l, i1, j1);
|
|
IBlockData iblockdata1 = this.getTypeIfLoaded(blockposition); // Paper
|
|
if (iblockdata1 == null) return null; // Paper
|
|
Fluid fluid1 = this.getFluid(blockposition);
|
|
|
|
if (!flag || iblockdata1.getMaterial() == Material.PORTAL || !iblockdata1.getCollisionShape(this, blockposition).isEmpty()) {
|
|
boolean flag5 = iblockdata1.getBlock().isCollidable(iblockdata1);
|
|
boolean flag6 = fluidcollisionoption.predicate.test(fluid1);
|
|
|
|
if (!flag5 && !flag6) {
|
|
movingobjectposition1 = new MovingObjectPosition(MovingObjectPosition.EnumMovingObjectType.MISS, new Vec3D(d0, d1, d2), enumdirection, blockposition);
|
|
} else {
|
|
MovingObjectPosition movingobjectposition2 = null;
|
|
|
|
if (flag5) {
|
|
movingobjectposition2 = Block.rayTrace(iblockdata1, this, blockposition, vec3d, vec3d1);
|
|
}
|
|
|
|
if (movingobjectposition2 == null && flag6) {
|
|
movingobjectposition2 = VoxelShapes.create(0.0D, 0.0D, 0.0D, 1.0D, (double) fluid1.getHeight(), 1.0D).rayTrace(vec3d, vec3d1, blockposition);
|
|
}
|
|
|
|
if (movingobjectposition2 != null) {
|
|
return movingobjectposition2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return flag1 ? 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, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, soundeffect, soundcategory, f, f1);
|
|
}
|
|
|
|
// Paper start - OBFHELPER
|
|
public final void sendSoundEffect(@Nullable EntityHuman fromEntity, double x, double y, double z, SoundEffect soundeffect, SoundCategory soundcategory, float volume, float pitch) {
|
|
this.a(fromEntity, x, y, z, soundeffect, soundcategory, volume, pitch);
|
|
}
|
|
// Paper end
|
|
|
|
public void a(@Nullable EntityHuman entityhuman, double d0, double d1, double d2, SoundEffect soundeffect, SoundCategory soundcategory, float f, float f1) {
|
|
// Akarin start
|
|
/*
|
|
for (int i = 0; i < this.v.size(); ++i) {
|
|
((IWorldAccess) this.v.get(i)).a(entityhuman, soundeffect, soundcategory, d0, d1, d2, f, f1);
|
|
}
|
|
*/
|
|
worldAccessor.a(entityhuman, soundeffect, soundcategory, d0, d1, d2, f, f1);
|
|
// Akarin end
|
|
|
|
}
|
|
|
|
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.v.size(); ++i) {
|
|
((IWorldAccess) this.v.get(i)).a(soundeffect, blockposition);
|
|
}
|
|
|
|
}
|
|
|
|
public void addParticle(ParticleParam particleparam, double d0, double d1, double d2, double d3, double d4, double d5) {
|
|
for (int i = 0; i < this.v.size(); ++i) {
|
|
((IWorldAccess) this.v.get(i)).a(particleparam, particleparam.b().e(), d0, d1, d2, d3, d4, d5);
|
|
}
|
|
|
|
}
|
|
|
|
public void b(ParticleParam particleparam, double d0, double d1, double d2, double d3, double d4, double d5) {
|
|
for (int i = 0; i < this.v.size(); ++i) {
|
|
((IWorldAccess) this.v.get(i)).a(particleparam, false, true, d0, d1, d2, d3, d4, d5);
|
|
}
|
|
|
|
}
|
|
|
|
public boolean strikeLightning(Entity entity) {
|
|
this.k.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
|
|
// Paper start
|
|
if (entity.spawnReason == null) entity.spawnReason = spawnReason;
|
|
if (regionLimited != null) {
|
|
return regionLimited.addEntity(entity, spawnReason);
|
|
}
|
|
// Paper end
|
|
//org.spigotmc.AsyncCatcher.catchOp( "entity add"); // Spigot // Akarin
|
|
if (entity.valid) { MinecraftServer.LOGGER.error("Attempted Double World add on " + entity, new Throwable()); return true; } // Paper
|
|
if (!CraftEventFactory.doEntityAddEventCalling(this, entity, spawnReason)) {
|
|
return false;
|
|
}
|
|
// CraftBukkit end
|
|
|
|
int i = MathHelper.floor(entity.locX / 16.0D);
|
|
int j = MathHelper.floor(entity.locZ / 16.0D);
|
|
boolean flag = true; // Paper - always load chunks for entity adds
|
|
|
|
// 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;
|
|
}
|
|
|
|
if (!flag && !this.isChunkLoaded(i, j, false)) {
|
|
return false;
|
|
} else {
|
|
if (entity instanceof EntityHuman) {
|
|
EntityHuman entityhuman = (EntityHuman) entity;
|
|
|
|
this.players.add(entityhuman);
|
|
this.playersByName.put(entityhuman.getName(), entityhuman);
|
|
// Paper end
|
|
this.everyoneSleeping();
|
|
}
|
|
|
|
this.getChunkAt(i, j).a(entity);
|
|
if (entity.dead) return false; // Paper - don't add dead entities, chunk registration may of killed it
|
|
this.entityList.add(entity);
|
|
this.b(entity);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected void b(Entity entity) {
|
|
// Akarin start
|
|
/*
|
|
for (int i = 0; i < this.v.size(); ++i) {
|
|
((IWorldAccess) this.v.get(i)).a(entity);
|
|
}
|
|
*/
|
|
worldAccessor.a(entity);
|
|
// Akarin end
|
|
|
|
entity.valid = true; // CraftBukkit
|
|
entity.shouldBeRemoved = false; // Paper - shouldn't be removed after being re-added
|
|
new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
|
|
}
|
|
|
|
protected void c(Entity entity) {
|
|
// Akarin start
|
|
/*
|
|
for (int i = 0; i < this.v.size(); ++i) {
|
|
((IWorldAccess) this.v.get(i)).b(entity);
|
|
}
|
|
*/
|
|
worldAccessor.b(entity);
|
|
// Akarin end
|
|
|
|
new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
|
|
entity.valid = false; // CraftBukkit
|
|
}
|
|
|
|
public void kill(Entity entity) {
|
|
//org.spigotmc.AsyncCatcher.catchOp( "entity kill"); // Spigot // Akarin
|
|
if (entity.isVehicle()) {
|
|
entity.ejectPassengers();
|
|
}
|
|
|
|
if (entity.isPassenger()) {
|
|
entity.stopRiding();
|
|
}
|
|
|
|
entity.die();
|
|
if (entity instanceof EntityHuman) {
|
|
this.players.remove(entity);
|
|
this.playersByName.remove(entity.getName()); // Paper - World EntityHuman Lookup Optimizations
|
|
// Spigot start
|
|
for ( WorldPersistentData worldData : worldMaps.worldMap.values() )
|
|
{
|
|
for (Object o : worldData.data.values() )
|
|
{
|
|
if ( o instanceof WorldMap )
|
|
{
|
|
WorldMap map = (WorldMap) o;
|
|
map.humans.remove( (EntityHuman) entity );
|
|
for ( Iterator<WorldMap.WorldMapHumanTracker> iter = (Iterator<WorldMap.WorldMapHumanTracker>) map.h.iterator(); iter.hasNext(); )
|
|
{
|
|
if ( iter.next().trackee == entity )
|
|
{
|
|
map.decorations.remove(entity.getDisplayName().getString()); // Paper
|
|
iter.remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Spigot end
|
|
this.everyoneSleeping();
|
|
this.c(entity);
|
|
}
|
|
|
|
}
|
|
|
|
public void removeEntity(Entity entity) {
|
|
//org.spigotmc.AsyncCatcher.catchOp( "entity remove"); // Spigot // Akarin
|
|
entity.b(false);
|
|
entity.die();
|
|
if (entity instanceof EntityHuman) {
|
|
this.players.remove(entity);
|
|
this.playersByName.remove(entity.getName()); // Paper - World EntityHuman Lookup Optimizations
|
|
this.everyoneSleeping();
|
|
}
|
|
|
|
// if (!guardEntityList) { // Spigot - It will get removed after the tick if we are ticking // Paper - move down
|
|
int i = entity.chunkX;
|
|
int j = entity.chunkZ;
|
|
|
|
if (entity.inChunk && this.isChunkLoaded(i, j, true)) {
|
|
this.getChunkAt(i, j).b(entity);
|
|
}
|
|
entity.shouldBeRemoved = true; // Paper
|
|
entityList.updateEntityCount(entity, -1); // Paper
|
|
|
|
if (!guardEntityList) { // Spigot - It will get removed after the tick if we are ticking // Paper - always remove from current chunk above
|
|
// 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) {
|
|
// Akarin start
|
|
if (worldAccessor != null)
|
|
worldAccessor.add(iworldaccess);
|
|
else if (iworldaccess instanceof WorldManager)
|
|
worldAccessor = new AkarinWorldAccessor((WorldManager) iworldaccess, this.u);
|
|
else
|
|
worldAccessor = new AkarinWorldAccessor(this.u);
|
|
//this.v.add(iworldaccess);
|
|
// Akarin end
|
|
}
|
|
|
|
public int a(float f) {
|
|
float f1 = this.k(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) ((double) f2 * (1.0D - (double) (this.i(f) * 5.0F) / 16.0D));
|
|
f2 = (float) ((double) f2 * (1.0D - (double) (this.g(f) * 5.0F) / 16.0D));
|
|
f2 = 1.0F - f2;
|
|
return (int) (f2 * 11.0F);
|
|
}
|
|
|
|
public float c(float f) {
|
|
float f1 = this.k(f);
|
|
|
|
return f1 * 6.2831855F;
|
|
}
|
|
|
|
public void tickEntities() {
|
|
//this.methodProfiler.enter(* // Akarin - remove caller
|
|
//this.methodProfiler.enter(* // Akarin - remove caller
|
|
|
|
Entity entity;
|
|
int i;
|
|
|
|
for (i = 0; i < this.k.size(); ++i) {
|
|
entity = (Entity) this.k.get(i);
|
|
// CraftBukkit start - Fixed an NPE
|
|
if (entity == null) {
|
|
continue;
|
|
}
|
|
// CraftBukkit end
|
|
|
|
try {
|
|
if (!entity.dead) { // Akarin start - do not tick dead entity
|
|
++entity.ticksLived;
|
|
entity.tick();
|
|
} // Akarin end
|
|
} catch (Throwable throwable) {
|
|
CrashReport crashreport = CrashReport.a(throwable, "Ticking entity");
|
|
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being ticked");
|
|
|
|
if (entity == null) {
|
|
crashreportsystemdetails.a("Entity", (Object) "~~NULL~~");
|
|
} else {
|
|
entity.appendEntityCrashDetails(crashreportsystemdetails);
|
|
}
|
|
|
|
throw new ReportedException(crashreport);
|
|
}
|
|
|
|
if (entity.dead) {
|
|
this.k.remove(i--);
|
|
}
|
|
}
|
|
|
|
//this.methodProfiler.exitEnter("remove"); // Akarin - remove caller
|
|
timings.entityRemoval.startTimingUnsafe(); // Paper // Akarin
|
|
this.entityList.removeAll(this.g);
|
|
|
|
int j;
|
|
// Paper start - Set based removal lists
|
|
for (Entity e : this.g) {
|
|
/*
|
|
j = e.getChunkZ();
|
|
int k = e.getChunkX();
|
|
|
|
if (e.inChunk && this.isChunkLoaded(k, j, true)) {
|
|
this.getChunkAt(k, j).b(e);
|
|
}*/
|
|
Chunk chunk = e.inChunk ? e.getCurrentChunk() : null;
|
|
if (chunk != null) chunk.removeEntity(e);
|
|
}
|
|
|
|
for (Entity e : this.g) {
|
|
this.c(e);
|
|
}
|
|
// Paper end
|
|
|
|
this.g.clear();
|
|
this.p_();
|
|
timings.entityRemoval.stopTimingUnsafe(); // Paper // Akarin
|
|
//this.methodProfiler.exitEnter("regular");// Akarin - remove caller
|
|
|
|
CrashReport crashreport1;
|
|
CrashReportSystemDetails crashreportsystemdetails1;
|
|
|
|
org.spigotmc.ActivationRange.activateEntities(this); // Spigot
|
|
timings.entityTick.startTimingUnsafe(); // Spigot // Akarin
|
|
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 = (Entity) this.entityList.get(this.tickPosition);
|
|
// CraftBukkit end
|
|
Entity entity1 = entity.getVehicle();
|
|
|
|
if (entity1 != null) {
|
|
if (!entity1.dead && entity1.w(entity)) {
|
|
continue;
|
|
}
|
|
|
|
entity.stopRiding();
|
|
}
|
|
|
|
//this.methodProfiler.enter(* // Akarin - remove caller
|
|
if (!entity.dead && !(entity instanceof EntityPlayer)) {
|
|
try {
|
|
entity.tickTimer.startTimingUnsafe(); // Paper
|
|
this.g(entity);
|
|
entity.tickTimer.stopTimingUnsafe(); // Paper
|
|
} catch (Throwable throwable1) {
|
|
entity.tickTimer.stopTimingUnsafe();
|
|
// 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.exit(); // Akarin - remove caller
|
|
//this.methodProfiler.enter(* // Akarin - remove caller
|
|
if (entity.dead) {
|
|
// Paper start
|
|
/*
|
|
j = entity.chunkX;
|
|
int l = entity.chunkZ;
|
|
|
|
if (entity.inChunk && this.isChunkLoaded(j, l, true)) {
|
|
this.getChunkAt(j, l).b(entity);
|
|
}*/
|
|
Chunk chunk = entity.inChunk ? entity.getCurrentChunk() : null;
|
|
if (chunk != null) chunk.removeEntity(entity);
|
|
// Paper end
|
|
|
|
guardEntityList = false; // Spigot
|
|
this.entityList.remove(this.tickPosition--); // CraftBukkit - Use field for loop variable
|
|
guardEntityList = true; // Spigot
|
|
this.c(entity);
|
|
}
|
|
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
}
|
|
guardEntityList = false; // Spigot
|
|
|
|
timings.entityTick.stopTimingUnsafe(); // Spigot // Akarin
|
|
//this.methodProfiler.exitEnter("blockEntities");// Akarin - remove caller
|
|
timings.tileEntityTick.startTimingUnsafe(); // Spigot // Akarin
|
|
if (!this.tileEntityListUnload.isEmpty()) {
|
|
// Paper start - Use alternate implementation with faster contains
|
|
java.util.Set<TileEntity> toRemove = com.koloboke.collect.set.hash.HashObjSets.getDefaultFactory().withNullKeyAllowed(true).withEquivalence(com.koloboke.collect.Equivalence.identity()).newImmutableSet(tileEntityListUnload); // Akarin - koloboke
|
|
//toRemove.addAll(tileEntityListUnload); // Akarin - koloboke
|
|
this.tileEntityListTick.removeAll(toRemove);
|
|
// Paper end
|
|
//this.tileEntityList.removeAll(this.tileEntityListUnload); // Paper - remove unused list
|
|
this.tileEntityListUnload.clear();
|
|
}
|
|
|
|
this.J = true;
|
|
// 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 = (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.x() && tileentity.hasWorld()) {
|
|
BlockPosition blockposition = tileentity.getPosition();
|
|
|
|
// Paper start - Skip ticking in chunks scheduled for unload
|
|
net.minecraft.server.Chunk chunk = tileentity.getCurrentChunk();
|
|
boolean shouldTick = chunk != null;
|
|
if(this.paperConfig.skipEntityTickingInChunksScheduledForUnload)
|
|
shouldTick = shouldTick && chunk.scheduledForUnload == null;
|
|
if (shouldTick && this.K.a(blockposition)) {
|
|
// Paper end
|
|
try {
|
|
// Akarin start
|
|
//this.methodProfiler.a(() -> {
|
|
// return String.valueOf(TileEntityTypes.a(tileentity.C()));
|
|
//});
|
|
// Akarin end
|
|
tileentity.tickTimer.startTimingUnsafe(); // Spigot
|
|
((ITickable) tileentity).tick();
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
} 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.stopTimingUnsafe();
|
|
}
|
|
// Spigot end
|
|
}
|
|
}
|
|
|
|
if (tileentity.x()) {
|
|
tilesThisCycle--;
|
|
this.tileEntityListTick.remove(tileTickPosition--);
|
|
//this.tileEntityList.remove(tileentity); // Paper - remove unused list
|
|
// Paper start
|
|
net.minecraft.server.Chunk chunk = tileentity.getCurrentChunk();
|
|
if (chunk != null) {
|
|
chunk.removeTileEntity(tileentity.getPosition());
|
|
// Paper end
|
|
}
|
|
}
|
|
}
|
|
|
|
timings.tileEntityTick.stopTimingUnsafe(); // Spigot // Akarin
|
|
timings.tileEntityPending.startTimingUnsafe(); // Spigot // Akarin
|
|
this.J = false;
|
|
this.methodProfiler.exitEnter("pendingBlockEntities");
|
|
if (!this.c.isEmpty()) {
|
|
for (int i1 = 0; i1 < this.c.size(); ++i1) {
|
|
TileEntity tileentity1 = (TileEntity) this.c.get(i1);
|
|
|
|
if (!tileentity1.x()) {
|
|
/* 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.getType(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.c.clear();
|
|
}
|
|
|
|
timings.tileEntityPending.stopTimingUnsafe(); // Spigot // Akarin
|
|
co.aikar.timings.TimingHistory.tileEntityTicks += this.tileEntityListTick.size(); // Paper
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
}
|
|
|
|
protected void p_() {}
|
|
|
|
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 a(Collection<TileEntity> collection) {
|
|
if (this.J) {
|
|
this.c.addAll(collection);
|
|
} else {
|
|
Iterator iterator = collection.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
TileEntity tileentity = (TileEntity) iterator.next();
|
|
|
|
this.a(tileentity);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public void g(Entity entity) {
|
|
this.entityJoinedWorld(entity, true);
|
|
}
|
|
|
|
public void entityJoinedWorld(Entity entity, boolean flag) {
|
|
int i;
|
|
int j;
|
|
|
|
// CraftBukkit start - check if chunks are loaded as done in previous versions
|
|
// TODO: Go back to Vanilla behaviour when comfortable
|
|
// Spigot start
|
|
// Chunk startingChunk = this.getChunkIfLoaded(MathHelper.floor(entity.locX) >> 4, MathHelper.floor(entity.locZ) >> 4);
|
|
if (flag && !org.spigotmc.ActivationRange.checkIfActive(entity)) {
|
|
entity.ticksLived++;
|
|
entity.inactiveTick();
|
|
// Spigot end
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
|
|
entity.N = entity.locX;
|
|
entity.O = entity.locY;
|
|
entity.P = entity.locZ;
|
|
entity.lastYaw = entity.yaw;
|
|
entity.lastPitch = entity.pitch;
|
|
if (flag && entity.inChunk) {
|
|
++entity.ticksLived;
|
|
++co.aikar.timings.TimingHistory.activatedEntityTicks; // Paper
|
|
if (entity.isPassenger()) {
|
|
entity.aH();
|
|
} else {
|
|
// Akarin start
|
|
//this.methodProfiler.a(() -> {
|
|
// return IRegistry.ENTITY_TYPE.getKey(entity.P()).toString();
|
|
//});
|
|
// Akarin end
|
|
entity.tick();
|
|
entity.postTick(); // CraftBukkit
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
}
|
|
}
|
|
|
|
//this.methodProfiler.enter(* // Akarin - remove caller
|
|
if (Double.isNaN(entity.locX) || Double.isInfinite(entity.locX)) {
|
|
entity.locX = entity.N;
|
|
}
|
|
|
|
if (Double.isNaN(entity.locY) || Double.isInfinite(entity.locY)) {
|
|
entity.locY = entity.O;
|
|
}
|
|
|
|
if (Double.isNaN(entity.locZ) || Double.isInfinite(entity.locZ)) {
|
|
entity.locZ = entity.P;
|
|
}
|
|
|
|
if (Double.isNaN((double) entity.pitch) || Double.isInfinite((double) entity.pitch)) {
|
|
entity.pitch = entity.lastPitch;
|
|
}
|
|
|
|
if (Double.isNaN((double) entity.yaw) || Double.isInfinite((double) entity.yaw)) {
|
|
entity.yaw = entity.lastYaw;
|
|
}
|
|
|
|
i = MathHelper.floor(entity.locX / 16.0D);
|
|
j = Math.min(15, Math.max(0, MathHelper.floor(entity.locY / 16.0D))); // Paper - stay consistent with chunk add/remove behavior
|
|
int k = MathHelper.floor(entity.locZ / 16.0D);
|
|
|
|
if (!entity.inChunk || entity.chunkX != i || entity.chunkY != j || entity.chunkZ != k) {
|
|
if (entity.inChunk && this.isChunkLoaded(entity.chunkX, entity.chunkZ, true)) {
|
|
this.getChunkAt(entity.chunkX, entity.chunkZ).a(entity, entity.chunkY);
|
|
}
|
|
|
|
if (!entity.valid && !entity.bN() && !this.isChunkLoaded(i, k, true)) { // Paper - always load chunks to register valid entities location
|
|
entity.inChunk = false;
|
|
} else {
|
|
this.getChunkAt(i, k).a(entity);
|
|
}
|
|
}
|
|
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
if (flag && entity.inChunk) {
|
|
Iterator iterator = entity.bP().iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
Entity entity1 = (Entity) iterator.next();
|
|
|
|
if (!entity1.dead && entity1.getVehicle() == entity) {
|
|
this.g(entity1);
|
|
} else {
|
|
entity1.stopRiding();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Paper start - Based on method below
|
|
/**
|
|
* @param entity causing the action ex. block placer
|
|
* @param voxelshape area to search within
|
|
* @return if there are no visible players colliding
|
|
*/
|
|
public boolean checkNoVisiblePlayerCollisions(@Nullable Entity entity, VoxelShape voxelshape) {
|
|
if (voxelshape.isEmpty()) {
|
|
return true;
|
|
} else {
|
|
List list = this.getEntities((Entity) null, voxelshape.getBoundingBox());
|
|
|
|
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(@Nullable Entity entity, VoxelShape voxelshape) {
|
|
if (voxelshape.isEmpty()) {
|
|
return true;
|
|
} else {
|
|
List<Entity> list = this.getEntities((Entity) null, voxelshape.getBoundingBox());
|
|
|
|
for (int i = 0; i < list.size(); ++i) {
|
|
Entity entity1 = (Entity) list.get(i);
|
|
|
|
if (!entity1.dead && entity1.j && entity1 != entity && (entity == null || !entity1.x(entity)) && VoxelShapes.c(voxelshape, VoxelShapes.a(entity1.getBoundingBox()), OperatorBoolean.AND)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Paper start - Prevent armor stands from doing entity lookups
|
|
@Override
|
|
public boolean getCubes(@Nullable Entity entity, AxisAlignedBB axisAlignedBB) {
|
|
if (entity instanceof EntityArmorStand && !entity.world.paperConfig.armorStandEntityLookups) return false;
|
|
return GeneratorAccess.super.getCubes(entity, axisAlignedBB);
|
|
}
|
|
// Paper end
|
|
|
|
public boolean a(AxisAlignedBB axisalignedbb) {
|
|
int i = MathHelper.floor(axisalignedbb.minX);
|
|
int j = MathHelper.f(axisalignedbb.maxX);
|
|
int k = MathHelper.floor(axisalignedbb.minY);
|
|
int l = MathHelper.f(axisalignedbb.maxY);
|
|
int i1 = MathHelper.floor(axisalignedbb.minZ);
|
|
int j1 = MathHelper.f(axisalignedbb.maxZ);
|
|
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.r();
|
|
Throwable throwable = null;
|
|
|
|
try {
|
|
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.c(k1, l1, i2));
|
|
|
|
if (!iblockdata.isAir()) {
|
|
boolean flag = true;
|
|
|
|
return flag;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} catch (Throwable throwable1) {
|
|
throwable = throwable1;
|
|
throw throwable1;
|
|
} finally {
|
|
if (blockposition_pooledblockposition != null) {
|
|
if (throwable != null) {
|
|
try {
|
|
blockposition_pooledblockposition.close();
|
|
} catch (Throwable throwable2) {
|
|
throwable.addSuppressed(throwable2);
|
|
}
|
|
} else {
|
|
blockposition_pooledblockposition.close();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
public boolean b(AxisAlignedBB axisalignedbb) {
|
|
int i = MathHelper.floor(axisalignedbb.minX);
|
|
int j = MathHelper.f(axisalignedbb.maxX);
|
|
int k = MathHelper.floor(axisalignedbb.minY);
|
|
int l = MathHelper.f(axisalignedbb.maxY);
|
|
int i1 = MathHelper.floor(axisalignedbb.minZ);
|
|
int j1 = MathHelper.f(axisalignedbb.maxZ);
|
|
|
|
if (this.isAreaLoaded(i, k, i1, j, l, j1, true)) {
|
|
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.r();
|
|
Throwable throwable = null;
|
|
|
|
try {
|
|
for (int k1 = i; k1 < j; ++k1) {
|
|
for (int l1 = k; l1 < l; ++l1) {
|
|
for (int i2 = i1; i2 < j1; ++i2) {
|
|
Block block = this.getType(blockposition_pooledblockposition.c(k1, l1, i2)).getBlock();
|
|
|
|
if (block == Blocks.FIRE || block == Blocks.LAVA) {
|
|
boolean flag = true;
|
|
|
|
return flag;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} catch (Throwable throwable1) {
|
|
throwable = throwable1;
|
|
throw throwable1;
|
|
} finally {
|
|
if (blockposition_pooledblockposition != null) {
|
|
if (throwable != null) {
|
|
try {
|
|
blockposition_pooledblockposition.close();
|
|
} catch (Throwable throwable2) {
|
|
throwable.addSuppressed(throwable2);
|
|
}
|
|
} else {
|
|
blockposition_pooledblockposition.close();
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
public IBlockData a(AxisAlignedBB axisalignedbb, Block block) {
|
|
int i = MathHelper.floor(axisalignedbb.minX);
|
|
int j = MathHelper.f(axisalignedbb.maxX);
|
|
int k = MathHelper.floor(axisalignedbb.minY);
|
|
int l = MathHelper.f(axisalignedbb.maxY);
|
|
int i1 = MathHelper.floor(axisalignedbb.minZ);
|
|
int j1 = MathHelper.f(axisalignedbb.maxZ);
|
|
|
|
if (this.isAreaLoaded(i, k, i1, j, l, j1, true)) {
|
|
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.r();
|
|
Throwable throwable = null;
|
|
|
|
try {
|
|
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.c(k1, l1, i2));
|
|
|
|
if (iblockdata.getBlock() == block) {
|
|
IBlockData iblockdata1 = iblockdata;
|
|
|
|
return iblockdata1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
} catch (Throwable throwable1) {
|
|
throwable = throwable1;
|
|
throw throwable1;
|
|
} finally {
|
|
if (blockposition_pooledblockposition != null) {
|
|
if (throwable != null) {
|
|
try {
|
|
blockposition_pooledblockposition.close();
|
|
} catch (Throwable throwable2) {
|
|
throwable.addSuppressed(throwable2);
|
|
}
|
|
} else {
|
|
blockposition_pooledblockposition.close();
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public boolean a(AxisAlignedBB axisalignedbb, Material material) {
|
|
int i = MathHelper.floor(axisalignedbb.minX);
|
|
int j = MathHelper.f(axisalignedbb.maxX);
|
|
int k = MathHelper.floor(axisalignedbb.minY);
|
|
int l = MathHelper.f(axisalignedbb.maxY);
|
|
int i1 = MathHelper.floor(axisalignedbb.minZ);
|
|
int j1 = MathHelper.f(axisalignedbb.maxZ);
|
|
MaterialPredicate materialpredicate = MaterialPredicate.a(material);
|
|
BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.r();
|
|
Throwable throwable = null;
|
|
|
|
try {
|
|
for (int k1 = i; k1 < j; ++k1) {
|
|
for (int l1 = k; l1 < l; ++l1) {
|
|
for (int i2 = i1; i2 < j1; ++i2) {
|
|
if (materialpredicate.test(this.getType(blockposition_pooledblockposition.c(k1, l1, i2)))) {
|
|
boolean flag = true;
|
|
|
|
return flag;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} catch (Throwable throwable1) {
|
|
throwable = throwable1;
|
|
throw throwable1;
|
|
} finally {
|
|
if (blockposition_pooledblockposition != null) {
|
|
if (throwable != null) {
|
|
try {
|
|
blockposition_pooledblockposition.close();
|
|
} catch (Throwable throwable2) {
|
|
throwable.addSuppressed(throwable2);
|
|
}
|
|
} else {
|
|
blockposition_pooledblockposition.close();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
public Explosion explode(@Nullable Entity entity, double d0, double d1, double d2, float f, boolean flag) {
|
|
return this.createExplosion(entity, (DamageSource) null, d0, d1, d2, f, false, flag);
|
|
}
|
|
|
|
public Explosion createExplosion(@Nullable Entity entity, double d0, double d1, double d2, float f, boolean flag, boolean flag1) {
|
|
return this.createExplosion(entity, (DamageSource) null, d0, d1, d2, f, flag, flag1);
|
|
}
|
|
|
|
public Explosion createExplosion(@Nullable Entity entity, @Nullable DamageSource damagesource, double d0, double d1, double d2, float f, boolean flag, boolean flag1) {
|
|
Explosion explosion = new Explosion(this, entity, d0, d1, d2, f, flag, flag1);
|
|
|
|
if (damagesource != null) {
|
|
explosion.a(damagesource);
|
|
}
|
|
|
|
explosion.a();
|
|
explosion.a(true);
|
|
return explosion;
|
|
}
|
|
|
|
public float a(Vec3D vec3d, AxisAlignedBB axisalignedbb) {
|
|
double d0 = 1.0D / ((axisalignedbb.maxX - axisalignedbb.minX) * 2.0D + 1.0D);
|
|
double d1 = 1.0D / ((axisalignedbb.maxY - axisalignedbb.minY) * 2.0D + 1.0D);
|
|
double d2 = 1.0D / ((axisalignedbb.maxZ - axisalignedbb.minZ) * 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) ((double) f + d0)) {
|
|
for (float f1 = 0.0F; f1 <= 1.0F; f1 = (float) ((double) f1 + d1)) {
|
|
for (float f2 = 0.0F; f2 <= 1.0F; f2 = (float) ((double) f2 + d2)) {
|
|
double d5 = axisalignedbb.minX + (axisalignedbb.maxX - axisalignedbb.minX) * (double) f;
|
|
double d6 = axisalignedbb.minY + (axisalignedbb.maxY - axisalignedbb.minY) * (double) f1;
|
|
double d7 = axisalignedbb.minZ + (axisalignedbb.maxZ - axisalignedbb.minZ) * (double) 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 = Maps.newHashMap();
|
|
@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.J) {
|
|
tileentity = this.E(blockposition);
|
|
}
|
|
|
|
if (tileentity == null) {
|
|
tileentity = this.getChunkAtWorldCoords(blockposition).a(blockposition, Chunk.EnumTileEntityState.IMMEDIATE);
|
|
}
|
|
|
|
if (tileentity == null) {
|
|
tileentity = this.E(blockposition);
|
|
}
|
|
|
|
return tileentity;
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
private TileEntity E(BlockPosition blockposition) {
|
|
for (int i = 0; i < this.c.size(); ++i) {
|
|
TileEntity tileentity = (TileEntity) this.c.get(i);
|
|
|
|
if (!tileentity.x() && tileentity.getPosition().equals(blockposition)) {
|
|
return tileentity;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void setTileEntity(BlockPosition blockposition, @Nullable TileEntity tileentity) {
|
|
if (!blockposition.isInvalidYLocation()) { // Paper
|
|
if (tileentity != null && !tileentity.x()) {
|
|
// CraftBukkit start
|
|
if (captureBlockStates) {
|
|
tileentity.setWorld(this);
|
|
tileentity.setPosition(blockposition);
|
|
capturedTileEntities.put(blockposition, tileentity);
|
|
return;
|
|
}
|
|
// CraftBukkit end
|
|
if (this.J) {
|
|
tileentity.setPosition(blockposition);
|
|
Iterator iterator = this.c.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
TileEntity tileentity1 = (TileEntity) iterator.next();
|
|
|
|
if (tileentity1.getPosition().equals(blockposition)) {
|
|
tileentity1.y();
|
|
iterator.remove();
|
|
}
|
|
}
|
|
|
|
tileentity.setWorld(this); // Spigot - No null worlds
|
|
this.c.add(tileentity);
|
|
} else {
|
|
this.getChunkAtWorldCoords(blockposition).a(blockposition, tileentity);
|
|
this.a(tileentity);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
public void n(BlockPosition blockposition) {
|
|
TileEntity tileentity = this.getTileEntity(blockposition);
|
|
|
|
if (tileentity != null && this.J) {
|
|
tileentity.y();
|
|
this.c.remove(tileentity);
|
|
} else {
|
|
if (tileentity != null) {
|
|
this.c.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 o(BlockPosition blockposition) {
|
|
return Block.a(this.getType(blockposition).getCollisionShape(this, blockposition));
|
|
}
|
|
|
|
public boolean p(BlockPosition blockposition) {
|
|
if (blockposition.isInvalidYLocation()) { // Paper
|
|
return false;
|
|
} else {
|
|
Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4); // Paper - optimize ifLoaded
|
|
|
|
return chunk != null && !chunk.isEmpty();
|
|
}
|
|
}
|
|
|
|
public boolean q(BlockPosition blockposition) {
|
|
return this.p(blockposition) && this.getType(blockposition).q();
|
|
}
|
|
|
|
public void P() {
|
|
int i = this.a(1.0F);
|
|
|
|
if (i != this.G) {
|
|
this.G = i;
|
|
}
|
|
|
|
}
|
|
|
|
public void setSpawnFlags(boolean flag, boolean flag1) {
|
|
this.allowMonsters = flag;
|
|
this.allowAnimals = flag1;
|
|
}
|
|
|
|
public void doTick(BooleanSupplier booleansupplier) {
|
|
this.K.r();
|
|
this.w();
|
|
}
|
|
|
|
protected void Q() {
|
|
if (this.worldData.hasStorm()) {
|
|
this.p = 1.0F;
|
|
if (this.worldData.isThundering()) {
|
|
this.r = 1.0F;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public void close() {
|
|
this.chunkProvider.close();
|
|
}
|
|
|
|
protected void w() {
|
|
if (this.worldProvider.g()) {
|
|
if (!this.isClientSide) {
|
|
boolean flag = this.getGameRules().getBoolean("doWeatherCycle");
|
|
|
|
if (flag) {
|
|
int i = this.worldData.z();
|
|
|
|
if (i > 0) {
|
|
--i;
|
|
this.worldData.g(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.q = this.r;
|
|
if (this.worldData.isThundering()) {
|
|
this.r = (float) ((double) this.r + 0.01D);
|
|
} else {
|
|
this.r = (float) ((double) this.r - 0.01D);
|
|
}
|
|
|
|
this.r = MathHelper.a(this.r, 0.0F, 1.0F);
|
|
this.o = this.p;
|
|
if (this.worldData.hasStorm()) {
|
|
this.p = (float) ((double) this.p + 0.01D);
|
|
} else {
|
|
this.p = (float) ((double) this.p - 0.01D);
|
|
}
|
|
|
|
this.p = MathHelper.a(this.p, 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 n_() {}
|
|
|
|
public boolean r(BlockPosition blockposition) {
|
|
boolean flag = false;
|
|
|
|
if (this.worldProvider.g()) {
|
|
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.e(blockposition)) {
|
|
return 15;
|
|
} else {
|
|
IBlockData iblockdata = this.getType(blockposition);
|
|
int i = enumskyblock == EnumSkyBlock.SKY ? 0 : iblockdata.e();
|
|
int j = iblockdata.b(this, blockposition);
|
|
|
|
if (j >= 15 && iblockdata.e() > 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.r();
|
|
Throwable throwable = null;
|
|
|
|
try {
|
|
EnumDirection[] aenumdirection = World.a;
|
|
int k = aenumdirection.length;
|
|
|
|
for (int l = 0; l < k; ++l) {
|
|
EnumDirection enumdirection = aenumdirection[l];
|
|
|
|
blockposition_pooledblockposition.g(blockposition).c(enumdirection);
|
|
int i1 = this.getBrightness(enumskyblock, blockposition_pooledblockposition) - j;
|
|
|
|
if (i1 > i) {
|
|
i = i1;
|
|
}
|
|
|
|
if (i >= 14) {
|
|
int j1 = i;
|
|
|
|
return j1;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
} catch (Throwable throwable1) {
|
|
throwable = throwable1;
|
|
throw throwable1;
|
|
} finally {
|
|
if (blockposition_pooledblockposition != null) {
|
|
if (throwable != null) {
|
|
try {
|
|
blockposition_pooledblockposition.close();
|
|
} catch (Throwable throwable2) {
|
|
throwable.addSuppressed(throwable2);
|
|
}
|
|
} else {
|
|
blockposition_pooledblockposition.close();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
// Paper start - optimize light updates where chunk is known
|
|
return updateBrightness(enumskyblock, blockposition, chunk);
|
|
}
|
|
public boolean updateBrightness(EnumSkyBlock enumskyblock, BlockPosition blockposition, Chunk chunk) {
|
|
// Paper end
|
|
if (chunk == null || !chunk.areNeighborsLoaded(1) /*!this.areChunksLoaded(blockposition, 17, false)*/) {
|
|
// CraftBukkit end
|
|
return false;
|
|
} else {
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
//this.methodProfiler.enter(* // Akarin - remove caller
|
|
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.E[j++] = 133152;
|
|
} else if (l < k) {
|
|
this.E[j++] = 133152 | k << 18;
|
|
|
|
while (i < j) {
|
|
l1 = this.E[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.r();
|
|
Throwable throwable = null;
|
|
|
|
try {
|
|
EnumDirection[] aenumdirection = World.a;
|
|
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.c(k4, l4, i5);
|
|
int j5 = Math.max(1, this.getType(blockposition_pooledblockposition).b(this, blockposition_pooledblockposition));
|
|
|
|
l2 = this.getBrightness(enumskyblock, blockposition_pooledblockposition);
|
|
if (l2 == l3 - j5 && j < this.E.length) {
|
|
this.E[j++] = k4 - i1 + 32 | l4 - j1 + 32 << 6 | i5 - k1 + 32 << 12 | l3 - j5 << 18;
|
|
}
|
|
}
|
|
} catch (Throwable throwable1) {
|
|
throwable = throwable1;
|
|
throw throwable1;
|
|
} finally {
|
|
if (blockposition_pooledblockposition != null) {
|
|
if (throwable != null) {
|
|
try {
|
|
blockposition_pooledblockposition.close();
|
|
} catch (Throwable throwable2) {
|
|
throwable.addSuppressed(throwable2);
|
|
}
|
|
} else {
|
|
blockposition_pooledblockposition.close();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
}
|
|
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
//this.methodProfiler.enter(* // Akarin - remove caller
|
|
|
|
while (i < j) {
|
|
l1 = this.E[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.E.length - 6;
|
|
|
|
if (i3 + j3 + k3 < 17 && flag) {
|
|
if (this.getBrightness(enumskyblock, blockposition2.west()) < l2) {
|
|
this.E[j++] = i2 - 1 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
|
|
}
|
|
|
|
if (this.getBrightness(enumskyblock, blockposition2.east()) < l2) {
|
|
this.E[j++] = i2 + 1 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
|
|
}
|
|
|
|
if (this.getBrightness(enumskyblock, blockposition2.down()) < l2) {
|
|
this.E[j++] = i2 - i1 + 32 + (j2 - 1 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
|
|
}
|
|
|
|
if (this.getBrightness(enumskyblock, blockposition2.up()) < l2) {
|
|
this.E[j++] = i2 - i1 + 32 + (j2 + 1 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
|
|
}
|
|
|
|
if (this.getBrightness(enumskyblock, blockposition2.north()) < l2) {
|
|
this.E[j++] = i2 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - 1 - k1 + 32 << 12);
|
|
}
|
|
|
|
if (this.getBrightness(enumskyblock, blockposition2.south()) < l2) {
|
|
this.E[j++] = i2 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 + 1 - k1 + 32 << 12);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//this.methodProfiler.exit(); // Akarin - remove caller
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public Stream<VoxelShape> a(@Nullable Entity entity, VoxelShape voxelshape, VoxelShape voxelshape1, Set<Entity> set) {
|
|
Stream<VoxelShape> stream = IIBlockAccess.super.a(entity, voxelshape, voxelshape1, set); // CraftBukkit - decompile error
|
|
|
|
return entity == null ? stream : Stream.concat(stream, this.a(entity, voxelshape, set));
|
|
}
|
|
|
|
public List<Entity> getEntities(@Nullable Entity entity, AxisAlignedBB axisalignedbb, @Nullable Predicate<? super Entity> predicate) {
|
|
List<Entity> list = Lists.newArrayList();
|
|
int i = MathHelper.floor((axisalignedbb.minX - 2.0D) / 16.0D);
|
|
int j = MathHelper.floor((axisalignedbb.maxX + 2.0D) / 16.0D);
|
|
int k = MathHelper.floor((axisalignedbb.minZ - 2.0D) / 16.0D);
|
|
int l = MathHelper.floor((axisalignedbb.maxZ + 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, list, predicate);
|
|
}
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
public <T extends Entity> List<T> a(Class<? extends T> oclass, Predicate<? super T> predicate) {
|
|
List<T> list = Lists.newArrayList();
|
|
Iterator iterator = this.entityList.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
Entity entity = (Entity) iterator.next();
|
|
if (entity.shouldBeRemoved) continue; // Paper
|
|
|
|
if (oclass.isAssignableFrom(entity.getClass()) && predicate.test((T) entity)) { // CraftBukkit - decompile error
|
|
list.add((T) entity); // CraftBukkit - decompile error
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
public <T extends Entity> List<T> b(Class<? extends T> oclass, Predicate<? super T> predicate) {
|
|
List<T> list = Lists.newArrayList();
|
|
Iterator iterator = this.players.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
Entity entity = (Entity) iterator.next();
|
|
|
|
if (oclass.isAssignableFrom(entity.getClass()) && predicate.test((T) entity)) { // CraftBukkit - decompile error
|
|
list.add((T) entity); // CraftBukkit - decompile error
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
public <T extends Entity> List<T> a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb) {
|
|
return this.a(oclass, axisalignedbb, IEntitySelector.f);
|
|
}
|
|
|
|
public <T extends Entity> List<T> a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb, @Nullable Predicate<? super T> predicate) {
|
|
int i = MathHelper.floor((axisalignedbb.minX - 2.0D) / 16.0D);
|
|
int j = MathHelper.f((axisalignedbb.maxX + 2.0D) / 16.0D);
|
|
int k = MathHelper.floor((axisalignedbb.minZ - 2.0D) / 16.0D);
|
|
int l = MathHelper.f((axisalignedbb.maxZ + 2.0D) / 16.0D);
|
|
List<T> list = 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, list, predicate);
|
|
}
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
@Nullable
|
|
public <T extends Entity> T a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb, T t0) {
|
|
List<T> list = this.a(oclass, axisalignedbb);
|
|
T t1 = null;
|
|
double d0 = Double.MAX_VALUE;
|
|
|
|
for (int i = 0; i < list.size(); ++i) {
|
|
T t2 = (T) list.get(i); // CraftBukkit - decompile error
|
|
|
|
if (t2 != t0 && IEntitySelector.f.test(t2)) {
|
|
double d1 = t0.h(t2);
|
|
|
|
if (d1 <= d0) {
|
|
t1 = t2;
|
|
d0 = d1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return t1;
|
|
}
|
|
|
|
@Nullable
|
|
public Entity getEntity(int i) {
|
|
return (Entity) this.entitiesById.get(i);
|
|
}
|
|
|
|
public void b(BlockPosition blockposition, TileEntity tileentity) {
|
|
if (this.isLoaded(blockposition)) {
|
|
this.getChunkAtWorldCoords(blockposition).markDirty();
|
|
}
|
|
|
|
}
|
|
|
|
public int a(Class<?> oclass, int i) {
|
|
int j = 0;
|
|
Iterator iterator = this.entityList.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
Entity entity = (Entity) iterator.next();
|
|
if (entity.shouldBeRemoved) continue; // Paper
|
|
// 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 (true || !(entity instanceof EntityInsentient) || !((EntityInsentient) entity).isPersistent()) {
|
|
// CraftBukkit end
|
|
if (oclass.isAssignableFrom(entity.getClass())) {
|
|
++j;
|
|
}
|
|
|
|
if (j > i) {
|
|
return j;
|
|
}
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
public void addChunkEntities(Stream<Entity> collection) { a(collection); } // Paper - OBFHELPER
|
|
public void a(Stream<Entity> stream) {
|
|
//org.spigotmc.AsyncCatcher.catchOp( "entity world add"); // Spigot // Akarin
|
|
stream.forEach((entity) -> {
|
|
if (entity == null || entity.dead || entity.valid) { // Paper - prevent adding already added or dead entities
|
|
return;
|
|
}
|
|
this.entityList.add(entity);
|
|
this.b(entity);
|
|
});
|
|
}
|
|
|
|
public void b(Collection<Entity> collection) {
|
|
this.g.addAll(collection);
|
|
}
|
|
|
|
public int getSeaLevel() {
|
|
return this.b;
|
|
}
|
|
|
|
public World getMinecraftWorld() {
|
|
return this;
|
|
}
|
|
|
|
public void b(int i) {
|
|
this.b = i;
|
|
}
|
|
|
|
public int a(BlockPosition blockposition, EnumDirection enumdirection) {
|
|
return this.getType(blockposition).b((IBlockAccess) this, blockposition, enumdirection);
|
|
}
|
|
|
|
public WorldType S() {
|
|
return this.worldData.getType();
|
|
}
|
|
|
|
public int getBlockPower(BlockPosition blockposition) {
|
|
byte b0 = 0;
|
|
int i = Math.max(b0, this.a(blockposition.down(), EnumDirection.DOWN));
|
|
|
|
if (i >= 15) {
|
|
return i;
|
|
} else {
|
|
i = Math.max(i, this.a(blockposition.up(), EnumDirection.UP));
|
|
if (i >= 15) {
|
|
return i;
|
|
} else {
|
|
i = Math.max(i, this.a(blockposition.north(), EnumDirection.NORTH));
|
|
if (i >= 15) {
|
|
return i;
|
|
} else {
|
|
i = Math.max(i, this.a(blockposition.south(), EnumDirection.SOUTH));
|
|
if (i >= 15) {
|
|
return i;
|
|
} else {
|
|
i = Math.max(i, this.a(blockposition.west(), EnumDirection.WEST));
|
|
if (i >= 15) {
|
|
return i;
|
|
} else {
|
|
i = Math.max(i, this.a(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.isOccluding() ? this.getBlockPower(blockposition) : iblockdata.a((IBlockAccess) 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 isBlockIndirectlyGettingPowered(BlockPosition pos) { return u(pos); } // Paper - OBFHELPER
|
|
public int u(BlockPosition blockposition) {
|
|
int i = 0;
|
|
EnumDirection[] aenumdirection = World.a;
|
|
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 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 = (EntityHuman) this.players.get(i);
|
|
// CraftBukkit start - Fixed an NPE
|
|
if (entityhuman1 == null || entityhuman1.dead) {
|
|
continue;
|
|
}
|
|
// CraftBukkit end
|
|
|
|
if (predicate.test(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 = (EntityHuman) this.players.get(i);
|
|
|
|
if (IEntitySelector.f.test(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;
|
|
}
|
|
|
|
public boolean b(double d0, double d1, double d2, double d3) {
|
|
Iterator iterator = this.players.iterator();
|
|
|
|
double d4;
|
|
|
|
do {
|
|
EntityHuman entityhuman;
|
|
|
|
do {
|
|
do {
|
|
if (!iterator.hasNext()) {
|
|
return false;
|
|
}
|
|
|
|
entityhuman = (EntityHuman) iterator.next();
|
|
} while (!IEntitySelector.f.test(entityhuman));
|
|
} while (!IEntitySelector.b.test(entityhuman));
|
|
|
|
d4 = entityhuman.d(d0, d1, d2);
|
|
} while (d3 >= 0.0D && d4 >= d3 * d3);
|
|
|
|
return true;
|
|
}
|
|
|
|
@Nullable
|
|
public EntityHuman a(double d0, double d1, double d2) {
|
|
double d3 = -1.0D;
|
|
EntityHuman entityhuman = null;
|
|
|
|
for (int i = 0; i < this.players.size(); ++i) {
|
|
EntityHuman entityhuman1 = (EntityHuman) this.players.get(i);
|
|
|
|
if (IEntitySelector.f.test(entityhuman1)) {
|
|
double d4 = entityhuman1.d(d0, entityhuman1.locY, d1);
|
|
|
|
if ((d2 < 0.0D || d4 < d2 * d2) && (d3 == -1.0D || d4 < d3)) {
|
|
d3 = d4;
|
|
entityhuman = entityhuman1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return entityhuman;
|
|
}
|
|
|
|
@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((double) ((float) blockposition.getX() + 0.5F), (double) ((float) blockposition.getY() + 0.5F), (double) ((float) 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 = (EntityHuman) this.players.get(i);
|
|
|
|
// Paper start
|
|
// move distance check up, if set, check distance^2 is less than XZlimit^2, continue
|
|
// 4th method param is XZlimit (at least at the time of commit)
|
|
double d6 = entityhuman1.d(d0, entityhuman1.locY, d2);
|
|
if (d3 < 0.0D || d6 < d3 * d3)
|
|
if (!entityhuman1.abilities.isInvulnerable && entityhuman1.isAlive() && !entityhuman1.isSpectator() && (predicate == null || predicate.test(entityhuman1))) {
|
|
// Paper end
|
|
double d7 = d3;
|
|
|
|
if (entityhuman1.isSneaking()) {
|
|
d7 = d3 * 0.800000011920929D;
|
|
}
|
|
|
|
if (entityhuman1.isInvisible()) {
|
|
float f = entityhuman1.dk();
|
|
|
|
if (f < 0.1F) {
|
|
f = 0.1F;
|
|
}
|
|
|
|
d7 *= (double) (0.7F * f);
|
|
}
|
|
|
|
if (function != null) {
|
|
d7 *= (Double) MoreObjects.firstNonNull(function.apply(entityhuman1), 1.0D);
|
|
}
|
|
|
|
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) {
|
|
// Paper start - World EntityHuman Lookup Optimizations
|
|
/*
|
|
for (int i = 0; i < this.players.size(); ++i) {
|
|
EntityHuman entityhuman = (EntityHuman) this.players.get(i);
|
|
|
|
if (s.equals(entityhuman.getDisplayName().getString())) {
|
|
return entityhuman;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
*/
|
|
return this.playersByName.get(s);
|
|
// Paper end
|
|
}
|
|
|
|
@Nullable
|
|
public EntityHuman b(UUID uuid) {
|
|
// Paper start - World EntityHuman Lookup Optimizations
|
|
/*
|
|
for (int i = 0; i < this.players.size(); ++i) {
|
|
EntityHuman entityhuman = (EntityHuman) this.players.get(i);
|
|
|
|
if (uuid.equals(entityhuman.getUniqueID())) {
|
|
return entityhuman;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
*/
|
|
Entity entity = ((WorldServer)this).entitiesByUUID.get(uuid);
|
|
return entity instanceof EntityHuman ? (EntityHuman) entity : null;
|
|
// Paper end
|
|
}
|
|
|
|
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(HeightMap.Type.MOTION_BLOCKING, new BlockPosition(this.getWorldBorder().getCenterX(), 0.0D, this.getWorldBorder().getCenterZ()));
|
|
}
|
|
|
|
return blockposition;
|
|
}
|
|
|
|
public void v(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 g(float f) {
|
|
return (this.q + (this.r - this.q) * f) * this.i(f);
|
|
}
|
|
|
|
public float i(float f) {
|
|
return this.o + (this.p - this.o) * f;
|
|
}
|
|
|
|
public boolean Y() {
|
|
return this.worldProvider.g() && !this.worldProvider.h() ? (double) this.g(1.0F) > 0.9D : false;
|
|
}
|
|
|
|
public boolean isRaining() {
|
|
return (double) this.i(1.0F) > 0.2D;
|
|
}
|
|
|
|
public boolean isRainingAt(BlockPosition blockposition) {
|
|
return !this.isRaining() ? false : (!this.e(blockposition) ? false : (this.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING, blockposition).getY() > blockposition.getY() ? false : this.getBiome(blockposition).c() == BiomeBase.Precipitation.RAIN));
|
|
}
|
|
|
|
public boolean x(BlockPosition blockposition) {
|
|
BiomeBase biomebase = this.getBiome(blockposition);
|
|
|
|
return biomebase.d();
|
|
}
|
|
|
|
@Nullable
|
|
public PersistentCollection h() {
|
|
return this.worldMaps;
|
|
}
|
|
|
|
public void a(int i, BlockPosition blockposition, int j) {
|
|
// Akarin start
|
|
/*
|
|
for (int k = 0; k < this.v.size(); ++k) {
|
|
((IWorldAccess) this.v.get(k)).a(i, blockposition, j);
|
|
}
|
|
*/
|
|
worldAccessor.a(i, blockposition, j);
|
|
// Akarin end
|
|
|
|
}
|
|
|
|
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 {
|
|
// Akarin start
|
|
/*
|
|
for (int k = 0; k < this.v.size(); ++k) {
|
|
((IWorldAccess) this.v.get(k)).a(entityhuman, i, blockposition, j);
|
|
}
|
|
*/
|
|
worldAccessor.a(entityhuman, i, blockposition, j);
|
|
// Akarin end
|
|
|
|
} catch (Throwable throwable) {
|
|
CrashReport crashreport = CrashReport.a(throwable, "Playing level event");
|
|
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Level event being played");
|
|
|
|
crashreportsystemdetails.a("Block coordinates", (Object) CrashReportSystemDetails.a(blockposition));
|
|
crashreportsystemdetails.a("Event source", (Object) entityhuman);
|
|
crashreportsystemdetails.a("Event type", (Object) i);
|
|
crashreportsystemdetails.a("Event data", (Object) j);
|
|
throw new ReportedException(crashreport);
|
|
}
|
|
}
|
|
|
|
public int getHeight() {
|
|
return 256;
|
|
}
|
|
|
|
public int ab() {
|
|
return this.worldProvider.h() ? 128 : 256;
|
|
}
|
|
|
|
public CrashReportSystemDetails a(CrashReport crashreport) {
|
|
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Affected level", 1);
|
|
|
|
crashreportsystemdetails.a("Level name", (Object) (this.worldData == null ? "????" : this.worldData.getName()));
|
|
crashreportsystemdetails.a("All players", () -> {
|
|
return this.players.size() + " total; " + this.players;
|
|
});
|
|
crashreportsystemdetails.a("Chunk stats", () -> {
|
|
return this.chunkProvider.getName();
|
|
});
|
|
|
|
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) {
|
|
// Akarin start
|
|
/*
|
|
for (int k = 0; k < this.v.size(); ++k) {
|
|
IWorldAccess iworldaccess = (IWorldAccess) this.v.get(k);
|
|
|
|
iworldaccess.b(i, blockposition, j);
|
|
}
|
|
*/
|
|
worldAccessor.b(i, blockposition, j);
|
|
// Akarin end
|
|
|
|
}
|
|
|
|
public abstract Scoreboard getScoreboard();
|
|
|
|
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 (iblockdata.getBlock() == Blocks.COMPARATOR) {
|
|
iblockdata.doPhysics(this, blockposition1, block, blockposition);
|
|
} else if (iblockdata.isOccluding()) {
|
|
blockposition1 = blockposition1.shift(enumdirection);
|
|
iblockdata = this.getType(blockposition1);
|
|
if (iblockdata.getBlock() == Blocks.COMPARATOR) {
|
|
iblockdata.doPhysics(this, blockposition1, block, blockposition);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public DifficultyDamageScaler getDamageScaler(BlockPosition blockposition) {
|
|
long i = 0L;
|
|
float f = 0.0F;
|
|
|
|
if (this.isLoaded(blockposition)) {
|
|
f = this.ah();
|
|
i = this.getChunkAtWorldCoords(blockposition).m();
|
|
}
|
|
|
|
return new DifficultyDamageScaler(this.getDifficulty(), this.getDayTime(), i, f);
|
|
}
|
|
|
|
public int c() {
|
|
return this.G;
|
|
}
|
|
|
|
public void c(int i) {
|
|
this.G = i;
|
|
}
|
|
|
|
public void d(int i) {
|
|
this.H = i;
|
|
}
|
|
|
|
public PersistentVillage af() {
|
|
return this.villages;
|
|
}
|
|
|
|
public WorldBorder getWorldBorder() {
|
|
return this.K;
|
|
}
|
|
|
|
public boolean isSpawnChunk(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 LongSet ag() {
|
|
ForcedChunk forcedchunk = (ForcedChunk) this.a(this.worldProvider.getDimensionManager(), ForcedChunk::new, "chunks");
|
|
|
|
return (LongSet) (forcedchunk != null ? LongSets.unmodifiable(forcedchunk.a()) : LongSets.EMPTY_SET);
|
|
}
|
|
|
|
public boolean isForceLoaded(int i, int j) {
|
|
ForcedChunk forcedchunk = (ForcedChunk) this.a(this.worldProvider.getDimensionManager(), ForcedChunk::new, "chunks");
|
|
|
|
return forcedchunk != null && forcedchunk.a().contains(ChunkCoordIntPair.a(i, j));
|
|
}
|
|
|
|
public boolean setForceLoaded(int i, int j, boolean flag) {
|
|
String s = "chunks";
|
|
ForcedChunk forcedchunk = (ForcedChunk) this.a(this.worldProvider.getDimensionManager(), ForcedChunk::new, "chunks");
|
|
|
|
if (forcedchunk == null) {
|
|
forcedchunk = new ForcedChunk("chunks");
|
|
this.a(this.worldProvider.getDimensionManager(), "chunks", (PersistentBase) forcedchunk);
|
|
}
|
|
|
|
long k = ChunkCoordIntPair.a(i, j);
|
|
boolean flag1;
|
|
|
|
if (flag) {
|
|
flag1 = forcedchunk.a().add(k);
|
|
if (flag1) {
|
|
this.getChunkAt(i, j);
|
|
}
|
|
} else {
|
|
flag1 = forcedchunk.a().remove(k);
|
|
}
|
|
|
|
forcedchunk.a(flag1);
|
|
return flag1;
|
|
}
|
|
|
|
public void a(Packet<?> packet) {
|
|
throw new UnsupportedOperationException("Can't send packets to server unless you're on the client.");
|
|
}
|
|
|
|
@Nullable
|
|
public BlockPosition a(String s, BlockPosition blockposition, int i, boolean flag) {
|
|
return null;
|
|
}
|
|
|
|
public WorldProvider o() {
|
|
return this.worldProvider;
|
|
}
|
|
|
|
public Random m() {
|
|
return this.random;
|
|
}
|
|
|
|
public abstract CraftingManager getCraftingManager();
|
|
|
|
public abstract TagRegistry F();
|
|
}
|