Files
2025-01-01 05:47:59 +08:00

1862 lines
78 KiB
Diff

--- ../src-base/minecraft/net/minecraft/world/World.java
+++ ../src-work/minecraft/net/minecraft/world/World.java
@@ -4,14 +4,12 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Random;
-import java.util.UUID;
+
+import java.util.*;
import java.util.function.Supplier;
import javax.annotation.Nullable;
+
+import com.google.common.collect.Maps;
import net.minecraft.advancements.AdvancementManager;
import net.minecraft.advancements.FunctionManager;
import net.minecraft.block.Block;
@@ -24,12 +22,22 @@
import net.minecraft.crash.ICrashReportDetail;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.item.EntityItem;
+import net.minecraft.entity.item.EntityXPOrb;
+import net.minecraft.entity.monster.EntityGhast;
+import net.minecraft.entity.monster.EntityGolem;
+import net.minecraft.entity.monster.EntityMob;
+import net.minecraft.entity.monster.EntitySlime;
+import net.minecraft.entity.passive.EntityAnimal;
+import net.minecraft.entity.passive.EntityWaterMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Biomes;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.Packet;
+import net.minecraft.network.play.server.SPacketWorldBorder;
import net.minecraft.pathfinding.PathWorldListener;
import net.minecraft.profiler.Profiler;
import net.minecraft.scoreboard.Scoreboard;
@@ -43,28 +51,46 @@
import net.minecraft.util.ReportedException;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
-import net.minecraft.util.math.AxisAlignedBB;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.util.math.MathHelper;
-import net.minecraft.util.math.RayTraceResult;
-import net.minecraft.util.math.Vec3d;
+import net.minecraft.util.math.*;
import net.minecraft.village.VillageCollection;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeProvider;
+import net.minecraft.world.border.IBorderListener;
import net.minecraft.world.border.WorldBorder;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
+import net.minecraft.world.gen.ChunkProviderServer;
import net.minecraft.world.gen.structure.StructureBoundingBox;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.MapStorage;
import net.minecraft.world.storage.WorldInfo;
import net.minecraft.world.storage.WorldSavedData;
import net.minecraft.world.storage.loot.LootTableManager;
+import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.SpigotTimings;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
+import org.bukkit.entity.NPC;
+import org.bukkit.event.block.BlockCanBuildEvent;
+import org.bukkit.event.block.BlockPhysicsEvent;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.generator.ChunkGenerator;
-public abstract class World implements IBlockAccess
+public abstract class World implements IBlockAccess, net.minecraftforge.common.capabilities.ICapabilityProvider
{
+ /**
+ * Used in the getEntitiesWithinAABB functions to expand the search area for entities.
+ * Modders should change this variable to a higher value if it is less then the radius
+ * of one of there entities.
+ */
+ public static double MAX_ENTITY_RADIUS = 2.0D;
+
+ private int tilesThisCycle = 0; // CatServer - Move up to keep LVT clean
private int seaLevel = 63;
protected boolean scheduledUpdatesAreImmediate;
public final List<Entity> loadedEntityList = Lists.<Entity>newArrayList();
@@ -86,30 +112,149 @@
public float thunderingStrength;
private int lastLightningBolt;
public final Random rand = new Random();
- public final WorldProvider provider;
+ public WorldProvider provider;
protected PathWorldListener pathListener = new PathWorldListener();
protected List<IWorldEventListener> eventListeners;
protected IChunkProvider chunkProvider;
protected final ISaveHandler saveHandler;
- protected WorldInfo worldInfo;
+ public WorldInfo worldInfo;
protected boolean findingSpawnPoint;
- protected MapStorage mapStorage;
+ public MapStorage mapStorage;
public VillageCollection villageCollection;
protected LootTableManager lootTable;
protected AdvancementManager advancementManager;
protected FunctionManager functionManager;
public final Profiler profiler;
private final Calendar calendar;
- protected Scoreboard worldScoreboard;
+ public Scoreboard worldScoreboard;
public final boolean isRemote;
- protected boolean spawnHostileMobs;
- protected boolean spawnPeacefulMobs;
+ public boolean spawnHostileMobs;
+ public boolean spawnPeacefulMobs;
private boolean processingLoadedTiles;
private final WorldBorder worldBorder;
int[] lightUpdateBlockList;
+ public boolean restoringBlockSnapshots = false;
+ public boolean captureBlockSnapshots = false;
+ public java.util.ArrayList<net.minecraftforge.common.util.BlockSnapshot> capturedBlockSnapshots = new java.util.ArrayList<net.minecraftforge.common.util.BlockSnapshot>();
+ private net.minecraftforge.common.capabilities.CapabilityDispatcher capabilities;
+ private net.minecraftforge.common.util.WorldCapabilityData capabilityData;
+
+ private final CraftWorld world;
+ public boolean pvpMode;
+ public boolean keepSpawnInMemory = true;
+ public ChunkGenerator generator;
+
+ public boolean captureTreeGeneration = false;
+
+ 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 SpigotTimings.WorldTimingsHandler timings; // 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) {
+ if (this.chunkProvider instanceof ChunkProviderServer) {
+ return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x, z);
+ } else {
+ return isChunkLoaded(x, z, true) ? this.chunkProvider.getLoadedChunk(x, z) : null;
+ }
+ }
+
+ protected World(ISaveHandler saveHandlerIn, WorldInfo info, WorldProvider providerIn, Profiler profilerIn, boolean client, ChunkGenerator gen, org.bukkit.World.Environment env) {
+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig( info.getWorldName() ); // Spigot
+ 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.eventListeners = Lists.newArrayList(this.pathListener);
+ this.calendar = Calendar.getInstance();
+ this.worldScoreboard = new Scoreboard();
+ this.spawnHostileMobs = true;
+ this.spawnPeacefulMobs = true;
+ this.lightUpdateBlockList = new int[32768];
+ this.saveHandler = saveHandlerIn;
+ this.profiler = profilerIn;
+ this.worldInfo = info;
+ this.provider = providerIn;
+ this.isRemote = client;
+ this.worldBorder = providerIn.createWorldBorder();
+ perWorldStorage = new MapStorage((ISaveHandler)null);
+ // CatServer start
+ if(this.worldInfo != null) // Use saved dimension from level.dat. Fixes issues with MultiVerse
+ {
+ if (this.worldInfo.getDimension() != 0)
+ this.provider.setDimension(this.worldInfo.getDimension());
+ else
+ {
+ this.worldInfo.setDimension(this.provider.getDimension());
+ }
+ }
+
+ if (this.worldInfo.getDimension() == 0) // Set generator for overworld
+ {
+ generator = this.getServer().getGenerator(this.worldInfo.getWorldName());
+ getWorld().generator = generator;
+ }
+ // CatServer end
+ // CraftBukkit start
+ getWorldBorder().world = (WorldServer) this;
+ // From PlayerList.setPlayerFileData
+ getWorldBorder().addListener(new IBorderListener() {
+ public void onSizeChanged(WorldBorder worldborder, double d0) {
+ getServer().getHandle().sendAll(new SPacketWorldBorder(worldborder, SPacketWorldBorder.Action.SET_SIZE), worldborder.world);
+ }
+
+ public void onTransitionStarted(WorldBorder worldborder, double d0, double d1, long i) {
+ getServer().getHandle().sendAll(new SPacketWorldBorder(worldborder, SPacketWorldBorder.Action.LERP_SIZE), worldborder.world);
+ }
+
+ public void onCenterChanged(WorldBorder worldborder, double d0, double d1) {
+ getServer().getHandle().sendAll(new SPacketWorldBorder(worldborder, SPacketWorldBorder.Action.SET_CENTER), worldborder.world);
+ }
+
+ public void onWarningTimeChanged(WorldBorder worldborder, int i) {
+ getServer().getHandle().sendAll(new SPacketWorldBorder(worldborder, SPacketWorldBorder.Action.SET_WARNING_TIME), worldborder.world);
+ }
+
+ public void onWarningDistanceChanged(WorldBorder worldborder, int i) {
+ getServer().getHandle().sendAll(new SPacketWorldBorder(worldborder, SPacketWorldBorder.Action.SET_WARNING_BLOCKS), worldborder.world);
+ }
+
+ public void onDamageAmountChanged(WorldBorder worldborder, double d0) {}
+
+ public void onDamageBufferChanged(WorldBorder worldborder, double d0) {}
+ });
+ this.getServer().addWorld(this.world);
+ // CraftBukkit end
+ timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings
+ this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
+ this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
+ }
+
protected World(ISaveHandler saveHandlerIn, WorldInfo info, WorldProvider providerIn, Profiler profilerIn, boolean client)
{
+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig( info.getWorldName() ); // Spigot
+ this.world = DimensionManager.getWorld(0) != null ? DimensionManager.getWorld(0).getWorld() : null;
this.eventListeners = Lists.newArrayList(this.pathListener);
this.calendar = Calendar.getInstance();
this.worldScoreboard = new Scoreboard();
@@ -122,6 +267,10 @@
this.provider = providerIn;
this.isRemote = client;
this.worldBorder = providerIn.createWorldBorder();
+ perWorldStorage = new MapStorage((ISaveHandler)null);
+ timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings
+ this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
+ this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
}
public World init()
@@ -131,6 +280,11 @@
public Biome getBiome(final BlockPos pos)
{
+ return this.provider.getBiomeForCoords(pos);
+ }
+
+ public Biome getBiomeForCoordsBody(final BlockPos pos)
+ {
if (this.isBlockLoaded(pos))
{
Chunk chunk = this.getChunkFromBlockCoords(pos);
@@ -207,7 +361,7 @@
public boolean isAirBlock(BlockPos pos)
{
- return this.getBlockState(pos).getMaterial() == Material.AIR;
+ return this.getBlockState(pos).getBlock().isAir(this.getBlockState(pos), this, pos);
}
public boolean isBlockLoaded(BlockPos pos)
@@ -278,7 +432,7 @@
}
}
- protected abstract boolean isChunkLoaded(int x, int z, boolean allowEmpty);
+ public abstract boolean isChunkLoaded(int x, int z, boolean allowEmpty);
public Chunk getChunkFromBlockCoords(BlockPos pos)
{
@@ -297,6 +451,26 @@
public boolean setBlockState(BlockPos pos, IBlockState newState, int flags)
{
+ // CatServer start - tree generation
+ if (this.captureTreeGeneration) {
+ net.minecraftforge.common.util.BlockSnapshot blocksnapshot = null;
+
+ for (net.minecraftforge.common.util.BlockSnapshot previous : this.capturedBlockSnapshots)
+ {
+ if (previous.getPos().equals(pos))
+ {
+ blocksnapshot = previous;
+ break;
+ }
+ }
+ if (blocksnapshot != null)
+ {
+ this.capturedBlockSnapshots.remove(blocksnapshot);
+ }
+ this.capturedBlockSnapshots.add(new net.minecraftforge.common.util.BlockSnapshot(this, pos, newState, flags));
+ return true;
+ }
+ // CatServer end
if (this.isOutsideBuildHeight(pos))
{
return false;
@@ -308,24 +482,53 @@
else
{
Chunk chunk = this.getChunkFromBlockCoords(pos);
- Block block = newState.getBlock();
+
+ pos = pos.toImmutable(); // Forge - prevent mutable BlockPos leaks
+ net.minecraftforge.common.util.BlockSnapshot blockSnapshot = null;
+ if (this.captureBlockSnapshots && !this.isRemote)
+ {
+ blockSnapshot = net.minecraftforge.common.util.BlockSnapshot.getBlockSnapshot(this, pos, flags);
+ this.capturedBlockSnapshots.add(blockSnapshot);
+ }
+
+ IBlockState oldState = getBlockState(pos);
+ int oldLight = oldState.getLightValue(this, pos);
+ int oldOpacity = oldState.getLightOpacity(this, pos);
+
IBlockState iblockstate = chunk.setBlockState(pos, newState);
if (iblockstate == null)
{
+ if (blockSnapshot != null) this.capturedBlockSnapshots.remove(blockSnapshot);
return false;
}
else
{
- if (newState.getLightOpacity() != iblockstate.getLightOpacity() || newState.getLightValue() != iblockstate.getLightValue())
+ if (newState.getLightOpacity(this, pos) != oldOpacity || newState.getLightValue(this, pos) != oldLight)
{
this.profiler.startSection("checkLight");
this.checkLight(pos);
this.profiler.endSection();
}
- if ((flags & 2) != 0 && (!this.isRemote || (flags & 4) == 0) && chunk.isPopulated())
+ if (blockSnapshot == null) // Don't notify clients or update physics while capturing blockstates
{
+ this.markAndNotifyBlock(pos, chunk, iblockstate, newState, flags);
+ }
+
+ return true;
+ }
+ }
+ }
+
+ // Split off from original setBlockState(BlockPos, IBlockState, int) method in order to directly send client and physic updates
+ public void markAndNotifyBlock(BlockPos pos, @Nullable Chunk chunk, IBlockState iblockstate, IBlockState newState, int flags)
+ {
+ Block block = newState.getBlock();
+ {
+ {
+ if ((flags & 2) != 0 && (!this.isRemote || (flags & 4) == 0) && (chunk == null || chunk.isPopulated()))
+ {
this.notifyBlockUpdate(pos, iblockstate, newState, flags);
}
@@ -342,8 +545,6 @@
{
this.updateObservingBlocksAt(pos, block);
}
-
- return true;
}
}
}
@@ -358,7 +559,7 @@
IBlockState iblockstate = this.getBlockState(pos);
Block block = iblockstate.getBlock();
- if (iblockstate.getMaterial() == Material.AIR)
+ if (block.isAir(iblockstate, this, pos))
{
return false;
}
@@ -392,6 +593,9 @@
{
if (this.worldInfo.getTerrainType() != WorldType.DEBUG_ALL_BLOCK_STATES)
{
+ if (populating) {
+ return;
+ }
this.notifyNeighborsOfStateChange(pos, blockType, p_175722_3_);
}
}
@@ -441,6 +645,9 @@
public void notifyNeighborsOfStateChange(BlockPos pos, Block blockType, boolean updateObservers)
{
+ if(net.minecraftforge.event.ForgeEventFactory.onNeighborNotify(this, pos, this.getBlockState(pos), java.util.EnumSet.allOf(EnumFacing.class), updateObservers).isCanceled())
+ return;
+
this.neighborChanged(pos.west(), blockType, pos);
this.neighborChanged(pos.east(), blockType, pos);
this.neighborChanged(pos.down(), blockType, pos);
@@ -456,6 +663,11 @@
public void notifyNeighborsOfStateExcept(BlockPos pos, Block blockType, EnumFacing skipSide)
{
+ java.util.EnumSet<EnumFacing> directions = java.util.EnumSet.allOf(EnumFacing.class);
+ directions.remove(skipSide);
+ if(net.minecraftforge.event.ForgeEventFactory.onNeighborNotify(this, pos, this.getBlockState(pos), directions, false).isCanceled())
+ return;
+
if (skipSide != EnumFacing.WEST)
{
this.neighborChanged(pos.west(), blockType, pos);
@@ -495,6 +707,15 @@
try
{
+ CraftWorld world = this.getWorld();
+ if (world != null) {
+ BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftMagicNumbers.getId(blockIn));
+ this.getServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ return;
+ }
+ }
iblockstate.neighborChanged(this, pos, blockIn, fromPos);
}
catch (Throwable throwable)
@@ -507,7 +728,7 @@
{
try
{
- return String.format("ID #%d (%s // %s)", Block.getIdFromBlock(blockIn), blockIn.getUnlocalizedName(), blockIn.getClass().getCanonicalName());
+ return String.format("ID #%d (%s // %s // %s)", Block.getIdFromBlock(blockIn), blockIn.getUnlocalizedName(), blockIn.getClass().getName(), blockIn.getRegistryName());
}
catch (Throwable var2)
{
@@ -527,12 +748,17 @@
{
IBlockState iblockstate = this.getBlockState(pos);
- if (iblockstate.getBlock() == Blocks.OBSERVER)
+ if (true)
{
try
{
- ((BlockObserver)iblockstate.getBlock()).observedNeighborChanged(iblockstate, this, pos, p_190529_2_, p_190529_3_);
+ iblockstate.getBlock().observedNeighborChange(iblockstate, this, pos, p_190529_2_, p_190529_3_);
}
+ catch (StackOverflowError stackoverflowerror) { // Spigot Start
+ haveWeSilencedAPhysicsCrash = true;
+ blockLocation = pos.getX() + ", " + pos.getY() + ", " + pos.getZ();
+ // Spigot End
+ }
catch (Throwable throwable)
{
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Exception while updating neighbours");
@@ -588,7 +814,7 @@
{
IBlockState iblockstate = this.getBlockState(blockpos1);
- if (iblockstate.getLightOpacity() > 0 && !iblockstate.getMaterial().isLiquid())
+ if (iblockstate.getBlock().getLightOpacity(iblockstate, this, blockpos) > 0 && !iblockstate.getMaterial().isLiquid())
{
return false;
}
@@ -849,12 +1075,24 @@
public IBlockState getBlockState(BlockPos pos)
{
+ // CatServer start - tree generation
+ if (captureTreeGeneration)
+ {
+ for (net.minecraftforge.common.util.BlockSnapshot blocksnapshot : this.capturedBlockSnapshots)
+ {
+ if (blocksnapshot.getPos().equals(pos)) {
+ return blocksnapshot.getReplacedBlock();
+ }
+ }
+ }
+ // CraftBukkit end
if (this.isOutsideBuildHeight(pos))
{
return Blocks.AIR.getDefaultState();
}
else
{
+ if (catserver.server.CatServer.getConfig().preventBlockLoadChunk && !isBlockLoaded(pos)) return Blocks.AIR.getDefaultState();
Chunk chunk = this.getChunkFromBlockCoords(pos);
return chunk.getBlockState(pos);
}
@@ -862,7 +1100,7 @@
public boolean isDaytime()
{
- return this.skylightSubtracted < 4;
+ return this.provider.isDaytime();
}
@Nullable
@@ -1065,6 +1303,13 @@
public void playSound(@Nullable EntityPlayer player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, float volume, float pitch)
{
+ net.minecraftforge.event.entity.PlaySoundAtEntityEvent event = net.minecraftforge.event.ForgeEventFactory.onPlaySoundAtEntity(player, soundIn, category, volume, pitch);
+ if (event.isCanceled() || event.getSound() == null) return;
+ soundIn = event.getSound();
+ category = event.getCategory();
+ volume = event.getVolume();
+ pitch = event.getPitch();
+
for (int i = 0; i < this.eventListeners.size(); ++i)
{
((IWorldEventListener)this.eventListeners.get(i)).playSoundToAllNearExcept(player, soundIn, category, x, y, z, volume, pitch);
@@ -1112,17 +1357,76 @@
public boolean addWeatherEffect(Entity entityIn)
{
+ if(net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityJoinWorldEvent(entityIn, this)))
+ return false;
+
this.weatherEffects.add(entityIn);
return true;
}
public boolean spawnEntity(Entity entityIn)
{
- int i = MathHelper.floor(entityIn.posX / 16.0D);
- int j = MathHelper.floor(entityIn.posZ / 16.0D);
- boolean flag = entityIn.forceSpawn;
+ // CraftBukkit start - Used for entities other than creatures
+ return addEntity(entityIn, CreatureSpawnEvent.SpawnReason.DEFAULT);
+ }
- if (entityIn instanceof EntityPlayer)
+ public boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {
+ if (catserver.server.AsyncCatcher.checkAsync("add entity")) return catserver.server.AsyncCatcher.ensureExecuteOnPrimaryThread(() -> addEntity(entity, spawnReason)); // CatServer
+ if (entity == null) return false;
+
+ org.bukkit.event.Cancellable event = null;
+ if (entity instanceof EntityLivingBase && !(entity instanceof EntityPlayerMP)) {
+ boolean isAnimal = entity instanceof EntityAnimal || entity instanceof EntityWaterMob || entity instanceof EntityGolem;
+ boolean isMonster = entity instanceof EntityMob || entity instanceof EntityGhast || entity instanceof EntitySlime;
+ boolean isNpc = entity instanceof NPC;
+
+ if (spawnReason != CreatureSpawnEvent.SpawnReason.CUSTOM) {
+ if (isAnimal && !spawnPeacefulMobs || isMonster && !spawnHostileMobs || isNpc && !getServer().getServer().getCanSpawnNPCs()) {
+ entity.isDead = true;
+ return false;
+ }
+ }
+
+ event = CraftEventFactory.callCreatureSpawnEvent((EntityLivingBase) entity, spawnReason);
+ } else if (entity instanceof EntityItem) {
+ event = CraftEventFactory.callItemSpawnEvent((EntityItem) entity);
+ } else if (entity.getBukkitEntity() instanceof org.bukkit.entity.Projectile) {
+ // Not all projectiles extend EntityProjectile, so check for Bukkit interface instead
+ event = CraftEventFactory.callProjectileLaunchEvent(entity);
+ } else if (entity.getBukkitEntity() instanceof org.bukkit.entity.Vehicle){
+ event = CraftEventFactory.callVehicleCreateEvent(entity);
+ }
+ // Spigot start
+ else if (entity instanceof EntityXPOrb) {
+ EntityXPOrb xp = (EntityXPOrb) entity;
+ double radius = spigotConfig.expMerge;
+ if (radius > 0) {
+ List<Entity> entities = this.getEntitiesWithinAABBExcludingEntity(entity, entity.getEntityBoundingBox().grow(radius, radius, radius));
+ for (Entity e : entities) {
+ if (e instanceof EntityXPOrb) {
+ EntityXPOrb loopItem = (EntityXPOrb) e;
+ if (!loopItem.isDead) {
+ xp.xpValue += loopItem.xpValue;
+ loopItem.setDead();
+ }
+ }
+ }
+ }
+ } // Spigot end
+
+ if (event != null && (event.isCancelled() || entity.isDead)) {
+ entity.isDead = true;
+ return false;
+ }
+ // CraftBukkit end
+ // do not drop any items while restoring blocksnapshots. Prevents dupes
+ if (!this.isRemote && (entity == null || (entity instanceof net.minecraft.entity.item.EntityItem && this.restoringBlockSnapshots))) return false;
+
+ int i = MathHelper.floor(entity.posX / 16.0D);
+ int j = MathHelper.floor(entity.posZ / 16.0D);
+ boolean flag = entity.forceSpawn;
+
+ if (entity instanceof EntityPlayer)
{
flag = true;
}
@@ -1133,16 +1437,18 @@
}
else
{
- if (entityIn instanceof EntityPlayer)
+ if (entity instanceof EntityPlayer)
{
- EntityPlayer entityplayer = (EntityPlayer)entityIn;
+ EntityPlayer entityplayer = (EntityPlayer)entity;
this.playerEntities.add(entityplayer);
this.updateAllPlayersSleepingFlag();
}
- this.getChunkFromChunkCoords(i, j).addEntity(entityIn);
- this.loadedEntityList.add(entityIn);
- this.onEntityAdded(entityIn);
+ if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityJoinWorldEvent(entity, this)) && !flag) return false;
+
+ this.getChunkFromChunkCoords(i, j).addEntity(entity);
+ this.loadedEntityList.add(entity);
+ this.onEntityAdded(entity);
return true;
}
}
@@ -1153,6 +1459,8 @@
{
((IWorldEventListener)this.eventListeners.get(i)).onEntityAdded(entityIn);
}
+ entityIn.onAddedToWorld();
+ entityIn.valid = true;
}
public void onEntityRemoved(Entity entityIn)
@@ -1161,10 +1469,13 @@
{
((IWorldEventListener)this.eventListeners.get(i)).onEntityRemoved(entityIn);
}
+ entityIn.onRemovedFromWorld();
+ entityIn.valid = false;
}
public void removeEntity(Entity entityIn)
{
+ if (catserver.server.AsyncCatcher.checkAsync("kill entity")) { catserver.server.AsyncCatcher.ensureExecuteOnPrimaryThread(() -> removeEntity(entityIn)); return; } // CatServer
if (entityIn.isBeingRidden())
{
entityIn.removePassengers();
@@ -1187,6 +1498,7 @@
public void removeEntityDangerously(Entity entityIn)
{
+ if (catserver.server.AsyncCatcher.checkAsync("remove entity")) { catserver.server.AsyncCatcher.ensureExecuteOnPrimaryThread(() -> removeEntityDangerously(entityIn)); return; } // CatServer
entityIn.setDropItemsWhenDead(false);
entityIn.setDead();
@@ -1204,7 +1516,16 @@
this.getChunkFromChunkCoords(i, j).removeEntity(entityIn);
}
- this.loadedEntityList.remove(entityIn);
+ // this.loadedEntityList.remove(entityIn);
+ // CraftBukkit start - Decrement loop variable field if we've already ticked this entity
+ int index = this.loadedEntityList.indexOf(entityIn);
+ if (index != -1) {
+ if (index <= this.tickPosition) {
+ this.tickPosition--;
+ }
+ this.loadedEntityList.remove(index);
+ }
+ // CraftBukkit end
this.onEntityRemoved(entityIn);
}
@@ -1227,6 +1548,7 @@
IBlockState iblockstate = Blocks.STONE.getDefaultState();
BlockPos.PooledMutableBlockPos blockpos$pooledmutableblockpos = BlockPos.PooledMutableBlockPos.retain();
+ if (p_191504_3_ && !net.minecraftforge.event.ForgeEventFactory.gatherCollisionBoxes(this, entityIn, aabb, outList)) return true;
try
{
for (int k1 = i; k1 < j; ++k1)
@@ -1269,7 +1591,7 @@
iblockstate1.addCollisionBoxToList(this, blockpos$pooledmutableblockpos, aabb, outList, entityIn, false);
- if (p_191504_3_ && !outList.isEmpty())
+ if (p_191504_3_ && !net.minecraftforge.event.ForgeEventFactory.gatherCollisionBoxes(this, entityIn, aabb, outList))
{
boolean flag5 = true;
return flag5;
@@ -1319,11 +1641,10 @@
}
}
}
-
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.GetCollisionBoxesEvent(this, entityIn, aabb, list));
return list;
}
- @SideOnly(Side.CLIENT)
public void removeEventListener(IWorldEventListener listener)
{
this.eventListeners.remove(listener);
@@ -1361,19 +1682,38 @@
public int calculateSkylightSubtracted(float partialTicks)
{
+ float f = provider.getSunBrightnessFactor(partialTicks);
+ f = 1 - f;
+ return (int)(f * 11);
+ }
+
+ /**
+ * The current sun brightness factor for this dimension.
+ * 0.0f means no light at all, and 1.0f means maximum sunlight.
+ * Highly recommended for sunlight detection like solar panel.
+ *
+ * @return The current brightness factor
+ * */
+ public float getSunBrightnessFactor(float partialTicks)
+ {
float f = this.getCelestialAngle(partialTicks);
float f1 = 1.0F - (MathHelper.cos(f * ((float)Math.PI * 2F)) * 2.0F + 0.5F);
f1 = MathHelper.clamp(f1, 0.0F, 1.0F);
f1 = 1.0F - f1;
f1 = (float)((double)f1 * (1.0D - (double)(this.getRainStrength(partialTicks) * 5.0F) / 16.0D));
f1 = (float)((double)f1 * (1.0D - (double)(this.getThunderStrength(partialTicks) * 5.0F) / 16.0D));
- f1 = 1.0F - f1;
- return (int)(f1 * 11.0F);
+ return f1;
}
@SideOnly(Side.CLIENT)
public float getSunBrightness(float partialTicks)
{
+ return this.provider.getSunBrightness(partialTicks);
+ }
+
+ @SideOnly(Side.CLIENT)
+ public float getSunBrightnessBody(float partialTicks)
+ {
float f = this.getCelestialAngle(partialTicks);
float f1 = 1.0F - (MathHelper.cos(f * ((float)Math.PI * 2F)) * 2.0F + 0.2F);
f1 = MathHelper.clamp(f1, 0.0F, 1.0F);
@@ -1386,6 +1726,12 @@
@SideOnly(Side.CLIENT)
public Vec3d getSkyColor(Entity entityIn, float partialTicks)
{
+ return this.provider.getSkyColor(entityIn, partialTicks);
+ }
+
+ @SideOnly(Side.CLIENT)
+ public Vec3d getSkyColorBody(Entity entityIn, float partialTicks)
+ {
float f = this.getCelestialAngle(partialTicks);
float f1 = MathHelper.cos(f * ((float)Math.PI * 2F)) * 2.0F + 0.5F;
f1 = MathHelper.clamp(f1, 0.0F, 1.0F);
@@ -1393,9 +1739,7 @@
int j = MathHelper.floor(entityIn.posY);
int k = MathHelper.floor(entityIn.posZ);
BlockPos blockpos = new BlockPos(i, j, k);
- Biome biome = this.getBiome(blockpos);
- float f2 = biome.getTemperature(blockpos);
- int l = biome.getSkyColorByTemp(f2);
+ int l = net.minecraftforge.client.ForgeHooksClient.getSkyBlendColour(this, blockpos);
float f3 = (float)(l >> 16 & 255) / 255.0F;
float f4 = (float)(l >> 8 & 255) / 255.0F;
float f5 = (float)(l & 255) / 255.0F;
@@ -1444,20 +1788,25 @@
public float getCelestialAngle(float partialTicks)
{
- return this.provider.calculateCelestialAngle(this.worldInfo.getWorldTime(), partialTicks);
+ return this.provider.calculateCelestialAngle(this.getWorldTime(), partialTicks);
}
@SideOnly(Side.CLIENT)
public int getMoonPhase()
{
- return this.provider.getMoonPhase(this.worldInfo.getWorldTime());
+ return this.provider.getMoonPhase(this.getWorldTime());
}
public float getCurrentMoonPhaseFactor()
{
- return WorldProvider.MOON_PHASE_FACTORS[this.provider.getMoonPhase(this.worldInfo.getWorldTime())];
+ return provider.getCurrentMoonPhaseFactor();
}
+ public float getCurrentMoonPhaseFactorBody()
+ {
+ return WorldProvider.MOON_PHASE_FACTORS[this.provider.getMoonPhase(this.getWorldTime())];
+ }
+
public float getCelestialAngleRadians(float partialTicks)
{
float f = this.getCelestialAngle(partialTicks);
@@ -1467,6 +1816,12 @@
@SideOnly(Side.CLIENT)
public Vec3d getCloudColour(float partialTicks)
{
+ return this.provider.getCloudColor(partialTicks);
+ }
+
+ @SideOnly(Side.CLIENT)
+ public Vec3d getCloudColorBody(float partialTicks)
+ {
float f = this.getCelestialAngle(partialTicks);
float f1 = MathHelper.cos(f * ((float)Math.PI * 2F)) * 2.0F + 0.5F;
f1 = MathHelper.clamp(f1, 0.0F, 1.0F);
@@ -1522,9 +1877,9 @@
for (blockpos = new BlockPos(pos.getX(), chunk.getTopFilledSegment() + 16, pos.getZ()); blockpos.getY() >= 0; blockpos = blockpos1)
{
blockpos1 = blockpos.down();
- Material material = chunk.getBlockState(blockpos1).getMaterial();
+ IBlockState state = chunk.getBlockState(blockpos1);
- if (material.blocksMovement() && material != Material.LEAVES)
+ if (state.getMaterial().blocksMovement() && !state.getBlock().isLeaves(state, this, blockpos1) && !state.getBlock().isFoliage(this, blockpos1))
{
break;
}
@@ -1536,6 +1891,12 @@
@SideOnly(Side.CLIENT)
public float getStarBrightness(float partialTicks)
{
+ return this.provider.getStarBrightness(partialTicks);
+ }
+
+ @SideOnly(Side.CLIENT)
+ public float getStarBrightnessBody(float partialTicks)
+ {
float f = this.getCelestialAngle(partialTicks);
float f1 = 1.0F - (MathHelper.cos(f * ((float)Math.PI * 2F)) * 2.0F + 0.25F);
f1 = MathHelper.clamp(f1, 0.0F, 1.0F);
@@ -1567,9 +1928,14 @@
for (int i = 0; i < this.weatherEffects.size(); ++i)
{
Entity entity = this.weatherEffects.get(i);
-
+ // CraftBukkit start - Fixed an NPE
+ if (entity == null) {
+ continue;
+ }
+ // CraftBukkit end
try
{
+ if(entity.updateBlocked) continue;
++entity.ticksExisted;
entity.onUpdate();
}
@@ -1587,6 +1953,12 @@
entity.addEntityCrashInfo(crashreportcategory);
}
+ if (net.minecraftforge.common.ForgeModContainer.removeErroringEntities)
+ {
+ net.minecraftforge.fml.common.FMLLog.log.fatal("{}", crashreport.getCompleteReport());
+ removeEntity(entity);
+ }
+ else
throw new ReportedException(crashreport);
}
@@ -1620,9 +1992,20 @@
this.tickPlayers();
this.profiler.endStartSection("regular");
- for (int i1 = 0; i1 < this.loadedEntityList.size(); ++i1)
- {
- Entity entity2 = this.loadedEntityList.get(i1);
+ org.spigotmc.ActivationRange.activateEntities(this); // Spigot
+ timings.entityTick.startTiming(); // Spigot
+ { // CatServer - Dont break asm
+ // CraftBukkit start - Use field for loop variable
+ int entitiesThisCycle = 0;
+ if (tickPosition < 0) tickPosition = 0;
+ for ( entityLimiter.initTick();
+ entitiesThisCycle < loadedEntityList.size() && (entitiesThisCycle % 10 != 0 || entityLimiter.shouldContinue());
+ tickPosition++, entitiesThisCycle++) {
+ if (catserver.server.WorldTickSkipManager.shouldSkipWorldEntityTick && playerEntities.size() == 0) continue; // CatServer - Don't update Entity for no player world
+ tickPosition = (tickPosition < loadedEntityList.size()) ? tickPosition : 0;
+ Entity entity2 = (Entity) this.loadedEntityList.get(this.tickPosition);
+ // CraftBukkit end
+ if (catserver.server.WorldTickSkipManager.shouldSkipEntity && entity2.skipTick) continue; // CatServer
Entity entity3 = entity2.getRidingEntity();
if (entity3 != null)
@@ -1641,13 +2024,25 @@
{
try
{
+ SpigotTimings.tickEntityTimer.startTiming(); // Spigot
+ net.minecraftforge.server.timings.TimeTracker.ENTITY_UPDATE.trackStart(entity2);
+ catserver.server.command.internal.CommandChunkStats.onTickStart();
this.updateEntity(entity2);
+ catserver.server.command.internal.CommandChunkStats.onTickEnd(this, entity2.getPosition());
+ net.minecraftforge.server.timings.TimeTracker.ENTITY_UPDATE.trackEnd(entity2);
+ SpigotTimings.tickEntityTimer.stopTiming(); // Spigot
}
catch (Throwable throwable1)
{
CrashReport crashreport1 = CrashReport.makeCrashReport(throwable1, "Ticking entity");
CrashReportCategory crashreportcategory1 = crashreport1.makeCategory("Entity being ticked");
entity2.addEntityCrashInfo(crashreportcategory1);
+ if (net.minecraftforge.common.ForgeModContainer.removeErroringEntities)
+ {
+ net.minecraftforge.fml.common.FMLLog.log.fatal("{}", crashreport1.getCompleteReport());
+ removeEntity(entity2);
+ }
+ else
throw new ReportedException(crashreport1);
}
}
@@ -1665,34 +2060,59 @@
this.getChunkFromChunkCoords(l1, i2).removeEntity(entity2);
}
- this.loadedEntityList.remove(i1--);
+ this.loadedEntityList.remove(this.tickPosition--); // CraftBukkit - Use field for loop variable
this.onEntityRemoved(entity2);
}
this.profiler.endSection();
}
+ } // CatServer - Dont break asm
+ timings.entityTick.stopTiming(); // Spigot
this.profiler.endStartSection("blockEntities");
+ timings.tileEntityTick.startTiming(); // Spigot
+ this.processingLoadedTiles = true; //FML Move above remove to prevent CMEs
+
if (!this.tileEntitiesToBeRemoved.isEmpty())
{
- this.tickableTileEntities.removeAll(this.tileEntitiesToBeRemoved);
- this.loadedTileEntityList.removeAll(this.tileEntitiesToBeRemoved);
+ for (Object tile : tileEntitiesToBeRemoved)
+ {
+ ((TileEntity)tile).onChunkUnload();
+ }
+
+ // forge: faster "contains" makes this removal much more efficient
+ java.util.Set<TileEntity> remove = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap<>());
+ remove.addAll(tileEntitiesToBeRemoved);
+ this.tickableTileEntities.removeAll(remove);
+ this.loadedTileEntityList.removeAll(remove);
this.tileEntitiesToBeRemoved.clear();
}
- this.processingLoadedTiles = true;
- Iterator<TileEntity> iterator = this.tickableTileEntities.iterator();
+ // Iterator<TileEntity> iterator = this.tickableTileEntities.iterator();
+ Iterator<TileEntity> iterator = this.tickableTileEntities.iterator(); // The code is no used, but do not remove, if remove will asm boom
- while (iterator.hasNext())
- {
- TileEntity tileentity = iterator.next();
-
+ { // CatServer - Dont break asm
+ tilesThisCycle = 0; // CatServer - reset value
+ for (tileLimiter.initTick();
+ tilesThisCycle < this.tickableTileEntities.size() && (tilesThisCycle % 10 != 0 || tileLimiter.shouldContinue());
+ tileTickPosition++, tilesThisCycle++) {
+ tileTickPosition = (tileTickPosition < tickableTileEntities.size()) ? tileTickPosition : 0;
+ TileEntity tileentity = (TileEntity) this.tickableTileEntities.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.tickableTileEntities.remove(tileTickPosition--);
+ continue;
+ }
+ // Spigot end
if (!tileentity.isInvalid() && tileentity.hasWorld())
{
+ if (catserver.server.WorldTickSkipManager.shouldSkipTileEntity && tileentity.skipTick) continue; // CatServer
BlockPos blockpos = tileentity.getPos();
- if (this.isBlockLoaded(blockpos) && this.worldBorder.contains(blockpos))
+ if (this.isBlockLoaded(blockpos, false) && this.worldBorder.contains(blockpos)) //Forge: Fix TE's getting an extra tick on the client side....
{
try
{
@@ -1700,7 +2120,12 @@
{
return String.valueOf((Object)TileEntity.getKey(tileentity.getClass()));
});
+ tileentity.tickTimer.startTiming(); // Spigot
+ net.minecraftforge.server.timings.TimeTracker.TILE_ENTITY_UPDATE.trackStart(tileentity);
+ catserver.server.command.internal.CommandChunkStats.onTickStart();
((ITickable)tileentity).update();
+ catserver.server.command.internal.CommandChunkStats.onTickEnd(this, tileentity.getPos());
+ net.minecraftforge.server.timings.TimeTracker.TILE_ENTITY_UPDATE.trackEnd(tileentity);
this.profiler.endSection();
}
catch (Throwable throwable)
@@ -1708,23 +2133,43 @@
CrashReport crashreport2 = CrashReport.makeCrashReport(throwable, "Ticking block entity");
CrashReportCategory crashreportcategory2 = crashreport2.makeCategory("Block entity being ticked");
tileentity.addInfoToCrashReport(crashreportcategory2);
+ if (net.minecraftforge.common.ForgeModContainer.removeErroringTileEntities)
+ {
+ net.minecraftforge.fml.common.FMLLog.log.fatal("{}", crashreport2.getCompleteReport());
+ tileentity.invalidate();
+ this.removeTileEntity(tileentity.getPos());
+ }
+ else
throw new ReportedException(crashreport2);
}
+ // Spigot start
+ finally {
+ tileentity.tickTimer.stopTiming();
+ }
+ // Spigot end
+
}
}
if (tileentity.isInvalid())
{
- iterator.remove();
+ tilesThisCycle--;
+ this.tickableTileEntities.remove(tileTickPosition--);
this.loadedTileEntityList.remove(tileentity);
if (this.isBlockLoaded(tileentity.getPos()))
{
- this.getChunkFromBlockCoords(tileentity.getPos()).removeTileEntity(tileentity.getPos());
+ //Forge: Bugfix: If we set the tile entity it immediately sets it in the chunk, so we could be desyned
+ Chunk chunk = this.getChunkFromBlockCoords(tileentity.getPos());
+ if (chunk.getTileEntity(tileentity.getPos(), Chunk.EnumCreateEntityType.CHECK) == tileentity)
+ chunk.removeTileEntity(tileentity.getPos());
}
}
}
+ } // CatServer - Dont break asm
+ timings.tileEntityTick.stopTiming(); // Spigot
+ timings.tileEntityPending.startTiming(); // Spigot
this.processingLoadedTiles = false;
this.profiler.endStartSection("pendingBlockEntities");
@@ -1736,10 +2181,12 @@
if (!tileentity1.isInvalid())
{
+ /* CraftBukkit start - Order matters, moved down
if (!this.loadedTileEntityList.contains(tileentity1))
{
this.addTileEntity(tileentity1);
}
+ // CraftBukkit end */
if (this.isBlockLoaded(tileentity1.getPos()))
{
@@ -1747,6 +2194,12 @@
IBlockState iblockstate = chunk.getBlockState(tileentity1.getPos());
chunk.addTileEntity(tileentity1.getPos(), tileentity1);
this.notifyBlockUpdate(tileentity1.getPos(), iblockstate, iblockstate, 3);
+ // CraftBukkit start
+ // From above, don't screw this up - SPIGOT-1746
+ if (!this.loadedTileEntityList.contains(tileentity1)) {
+ this.addTileEntity(tileentity1);
+ }
+ // CraftBukkit end
}
}
}
@@ -1754,6 +2207,7 @@
this.addedTileEntityList.clear();
}
+ timings.tileEntityPending.stopTiming(); // Spigot
this.profiler.endSection();
this.profiler.endSection();
}
@@ -1764,12 +2218,18 @@
public boolean addTileEntity(TileEntity tile)
{
+ // Forge - set the world early as vanilla doesn't set it until next tick
+ if (tile.getWorld() != this) tile.setWorld(this);
+ // Forge: wait to add new TE if we're currently processing existing ones
+ if (processingLoadedTiles) return addedTileEntityList.add(tile);
+
boolean flag = this.loadedTileEntityList.add(tile);
if (flag && tile instanceof ITickable)
{
this.tickableTileEntities.add(tile);
}
+ tile.onLoad();
if (this.isRemote)
{
@@ -1785,6 +2245,11 @@
{
if (this.processingLoadedTiles)
{
+ for (TileEntity te : tileEntityCollection)
+ {
+ if (te.getWorld() != this) // Forge - set the world early as vanilla doesn't set it until next tick
+ te.setWorld(this);
+ }
this.addedTileEntityList.addAll(tileEntityCollection);
}
else
@@ -1807,14 +2272,26 @@
{
int j2 = MathHelper.floor(entityIn.posX);
int k2 = MathHelper.floor(entityIn.posZ);
- int l2 = 32;
- if (forceUpdate && !this.isAreaLoaded(j2 - 32, 0, k2 - 32, j2 + 32, 0, k2 + 32, true))
+ boolean isForced = !this.isRemote && getPersistentChunks().containsKey(new net.minecraft.util.math.ChunkPos(j2 >> 4, k2 >> 4));
+ int range = isForced ? 0 : 32;
+ boolean canUpdate = !forceUpdate || this.isAreaLoaded(j2 - range, 0, k2 - range, j2 + range, 0, k2 + range, true);
+ if (!canUpdate) canUpdate = net.minecraftforge.event.ForgeEventFactory.canEntityUpdate(entityIn);
+
+ if (!canUpdate)
{
return;
}
}
+ // Spigot start
+ if (forceUpdate && !org.spigotmc.ActivationRange.checkIfActive(entityIn)) {
+ entityIn.ticksExisted++;
+ entityIn.inactiveTick();
+ return;
+ }
+ // Spigot end
+
entityIn.lastTickPosX = entityIn.posX;
entityIn.lastTickPosY = entityIn.posY;
entityIn.lastTickPosZ = entityIn.posZ;
@@ -1831,7 +2308,9 @@
}
else
{
+ if(!entityIn.updateBlocked)
entityIn.onUpdate();
+ entityIn.postTick();
}
}
@@ -1914,7 +2393,7 @@
{
Entity entity4 = list.get(j2);
- if (!entity4.isDead && entity4.preventEntitySpawning && entity4 != entityIn && (entityIn == null || entity4.isRidingSameEntity(entityIn)))
+ if (!entity4.isDead && entity4.preventEntitySpawning && entity4 != entityIn && (entityIn == null || !entity4.isRidingSameEntity(entityIn))) // Forge: fix MC-103516
{
return false;
}
@@ -1972,6 +2451,12 @@
{
IBlockState iblockstate1 = this.getBlockState(blockpos$pooledmutableblockpos.setPos(l3, i4, j4));
+ Boolean result = iblockstate1.getBlock().isAABBInsideLiquid(this, blockpos$pooledmutableblockpos, bb);
+ if (result != null) {
+ if (!result) continue;
+ blockpos$pooledmutableblockpos.release();
+ return true;
+ }
if (iblockstate1.getMaterial().isLiquid())
{
blockpos$pooledmutableblockpos.release();
@@ -2011,6 +2496,11 @@
blockpos$pooledmutableblockpos.release();
return true;
}
+ else if (block.isBurning(this, new BlockPos(l3, i4, j4)))
+ {
+ blockpos$pooledmutableblockpos.release();
+ return true;
+ }
}
}
}
@@ -2050,6 +2540,16 @@
IBlockState iblockstate1 = this.getBlockState(blockpos$pooledmutableblockpos);
Block block = iblockstate1.getBlock();
+ Boolean result = block.isEntityInsideMaterial(this, blockpos$pooledmutableblockpos, iblockstate1, entityIn, (double)i3, materialIn, false);
+ if (result != null && result == true)
+ {
+ // Forge: When requested call blocks modifyAcceleration method, and more importantly cause this method to return true, which results in an entity being "inWater"
+ flag = true;
+ vec3d = block.modifyAcceleration(this, blockpos$pooledmutableblockpos, entityIn, vec3d);
+ continue;
+ }
+ else if (result != null && result == false) continue;
+
if (iblockstate1.getMaterial() == materialIn)
{
double d0 = (double)((float)(i4 + 1) - BlockLiquid.getLiquidHeightPercent(((Integer)iblockstate1.getValue(BlockLiquid.LEVEL)).intValue()));
@@ -2095,7 +2595,14 @@
{
for (int j4 = j3; j4 < k3; ++j4)
{
- if (this.getBlockState(blockpos$pooledmutableblockpos.setPos(l3, i4, j4)).getMaterial() == materialIn)
+ IBlockState iblockstate1 = this.getBlockState(blockpos$pooledmutableblockpos.setPos(l3, i4, j4));
+ Boolean result = iblockstate1.getBlock().isAABBInsideMaterial(this, blockpos$pooledmutableblockpos, bb, materialIn);
+ if (result != null) {
+ if (!result) continue;
+ blockpos$pooledmutableblockpos.release();
+ return true;
+ }
+ if (iblockstate1.getMaterial() == materialIn)
{
blockpos$pooledmutableblockpos.release();
return true;
@@ -2116,6 +2623,7 @@
public Explosion newExplosion(@Nullable Entity entityIn, double x, double y, double z, float strength, boolean isFlaming, boolean isSmoking)
{
Explosion explosion = new Explosion(this, entityIn, x, y, z, strength, isFlaming, isSmoking);
+ if (net.minecraftforge.event.ForgeEventFactory.onExplosionStart(this, explosion)) return explosion;
explosion.doExplosionA();
explosion.doExplosionB(true);
return explosion;
@@ -2206,7 +2714,7 @@
tileentity2 = this.getPendingTileEntityAt(pos);
}
- if (tileentity2 == null)
+ if (tileentity2 == null && (!catserver.server.CatServer.getConfig().preventBlockLoadChunk || isBlockLoaded(pos)))
{
tileentity2 = this.getChunkFromBlockCoords(pos).getTileEntity(pos, Chunk.EnumCreateEntityType.IMMEDIATE);
}
@@ -2238,6 +2746,7 @@
public void setTileEntity(BlockPos pos, @Nullable TileEntity tileEntityIn)
{
+ pos = pos.toImmutable(); // Forge - prevent mutable BlockPos leaks
if (!this.isOutsideBuildHeight(pos))
{
if (tileEntityIn != null && !tileEntityIn.isInvalid())
@@ -2245,7 +2754,10 @@
if (this.processingLoadedTiles)
{
tileEntityIn.setPos(pos);
+ if (tileEntityIn.getWorld() != this)
+ tileEntityIn.setWorld(this); // Forge - set the world early as vanilla doesn't set it until next tick
Iterator<TileEntity> iterator1 = this.addedTileEntityList.iterator();
+ List<TileEntity> toInvalidate = Lists.newArrayList();
while (iterator1.hasNext())
{
@@ -2253,16 +2765,19 @@
if (tileentity2.getPos().equals(pos))
{
- tileentity2.invalidate();
+ toInvalidate.add(tileentity2); // Forge - don't call invalidate while iterating
iterator1.remove();
}
}
+ tileEntityIn.setWorld(this); // Spigot - No null worlds
+ toInvalidate.forEach(TileEntity::invalidate);
this.addedTileEntityList.add(tileEntityIn);
}
else
{
- this.getChunkFromBlockCoords(pos).addTileEntity(pos, tileEntityIn);
+ Chunk chunk = this.getChunkFromBlockCoords(pos);
+ if (chunk != null) chunk.addTileEntity(pos, tileEntityIn);
this.addTileEntity(tileEntityIn);
}
}
@@ -2277,6 +2792,8 @@
{
tileentity2.invalidate();
this.addedTileEntityList.remove(tileentity2);
+ if (!(tileentity2 instanceof ITickable)) //Forge: If they are not tickable they wont be removed in the update loop.
+ this.loadedTileEntityList.remove(tileentity2);
}
else
{
@@ -2289,6 +2806,7 @@
this.getChunkFromBlockCoords(pos).removeTileEntity(pos);
}
+ this.updateComparatorOutputLevel(pos, getBlockState(pos).getBlock()); //Notify neighbors of changes
}
public void markTileEntityForRemoval(TileEntity tileEntityIn)
@@ -2315,7 +2833,7 @@
if (chunk1 != null && !chunk1.isEmpty())
{
IBlockState iblockstate1 = this.getBlockState(pos);
- return iblockstate1.getMaterial().isOpaque() && iblockstate1.isFullCube();
+ return iblockstate1.getBlock().isNormalCube(iblockstate1, this, pos);
}
else
{
@@ -2338,6 +2856,7 @@
{
this.spawnHostileMobs = hostile;
this.spawnPeacefulMobs = peaceful;
+ this.provider.setAllowedSpawnTypes(hostile, peaceful);
}
public void tick()
@@ -2347,6 +2866,11 @@
protected void calculateInitialWeather()
{
+ this.provider.calculateInitialWeather();
+ }
+
+ public void calculateInitialWeatherBody()
+ {
if (this.worldInfo.isRaining())
{
this.rainingStrength = 1.0F;
@@ -2360,6 +2884,11 @@
protected void updateWeather()
{
+ this.provider.updateWeather();
+ }
+
+ public void updateWeatherBody()
+ {
if (this.provider.hasSkyLight())
{
if (!this.isRemote)
@@ -2451,6 +2980,11 @@
}
this.rainingStrength = MathHelper.clamp(this.rainingStrength, 0.0F, 1.0F);
+ for (int idx = 0; idx < this.playerEntities.size(); ++idx) {
+ if (((EntityPlayerMP) this.playerEntities.get(idx)).world == this) {
+ ((EntityPlayerMP) this.playerEntities.get(idx)).tickWeather();
+ }
+ }
}
}
}
@@ -2484,6 +3018,11 @@
public boolean canBlockFreeze(BlockPos pos, boolean noWaterAdj)
{
+ return this.provider.canBlockFreeze(pos, noWaterAdj);
+ }
+
+ public boolean canBlockFreezeBody(BlockPos pos, boolean noWaterAdj)
+ {
Biome biome = this.getBiome(pos);
float f = biome.getTemperature(pos);
@@ -2525,6 +3064,11 @@
public boolean canSnowAt(BlockPos pos, boolean checkLight)
{
+ return this.provider.canSnowAt(pos, checkLight);
+ }
+
+ public boolean canSnowAtBody(BlockPos pos, boolean checkLight)
+ {
Biome biome = this.getBiome(pos);
float f = biome.getTemperature(pos);
@@ -2542,7 +3086,7 @@
{
IBlockState iblockstate1 = this.getBlockState(pos);
- if (iblockstate1.getMaterial() == Material.AIR && Blocks.SNOW_LAYER.canPlaceBlockAt(this, pos))
+ if (iblockstate1.getBlock().isAir(iblockstate1, this, pos) && Blocks.SNOW_LAYER.canPlaceBlockAt(this, pos))
{
return true;
}
@@ -2574,10 +3118,10 @@
else
{
IBlockState iblockstate1 = this.getBlockState(pos);
- int j2 = lightType == EnumSkyBlock.SKY ? 0 : iblockstate1.getLightValue();
- int k2 = iblockstate1.getLightOpacity();
+ int j2 = lightType == EnumSkyBlock.SKY ? 0 : iblockstate1.getBlock().getLightValue(iblockstate1, this, pos);
+ int k2 = iblockstate1.getBlock().getLightOpacity(iblockstate1, this, pos);
- if (k2 >= 15 && iblockstate1.getLightValue() > 0)
+ if (false) // Forge: fix MC-119932
{
k2 = 1;
}
@@ -2589,7 +3133,7 @@
if (k2 >= 15)
{
- return 0;
+ return j2; // Forge: fix MC-119932
}
else if (j2 >= 14)
{
@@ -2630,12 +3174,16 @@
public boolean checkLightFor(EnumSkyBlock lightType, BlockPos pos)
{
- if (!this.isAreaLoaded(pos, 17, false))
+ // CraftBukkit start - Use neighbor cache instead of looking up
+ Chunk chunk = this.getChunkIfLoaded(pos.getX() >> 4, pos.getZ() >> 4);
+ if (chunk == null || !chunk.areNeighborsLoaded(1) /*!this.isAreaLoaded(pos, 16, false)*/)
{
+ // CraftBukkit end
return false;
}
else
{
+ int updateRange = this.isAreaLoaded(pos, 18, false) ? 17 : 15;
int j2 = 0;
int k2 = 0;
this.profiler.startSection("getBrightness");
@@ -2673,7 +3221,7 @@
int l5 = MathHelper.abs(k4 - k3);
int i6 = MathHelper.abs(l4 - l3);
- if (k5 + l5 + i6 < 17)
+ if (k5 + l5 + i6 < updateRange)
{
BlockPos.PooledMutableBlockPos blockpos$pooledmutableblockpos = BlockPos.PooledMutableBlockPos.retain();
@@ -2683,7 +3231,8 @@
int k6 = k4 + enumfacing.getFrontOffsetY();
int l6 = l4 + enumfacing.getFrontOffsetZ();
blockpos$pooledmutableblockpos.setPos(j6, k6, l6);
- int i7 = Math.max(1, this.getBlockState(blockpos$pooledmutableblockpos).getLightOpacity());
+ IBlockState bs = this.getBlockState(blockpos$pooledmutableblockpos);
+ int i7 = Math.max(1, bs.getBlock().getLightOpacity(bs, this, blockpos$pooledmutableblockpos));
j5 = this.getLightFor(lightType, blockpos$pooledmutableblockpos);
if (j5 == i5 - i7 && k2 < this.lightUpdateBlockList.length)
@@ -2725,7 +3274,7 @@
int j9 = Math.abs(i8 - l3);
boolean flag = k2 < this.lightUpdateBlockList.length - 6;
- if (l8 + i9 + j9 < 17 && flag)
+ if (l8 + i9 + j9 < updateRange && flag)
{
if (this.getLightFor(lightType, blockpos2.west()) < k8)
{
@@ -2791,10 +3340,10 @@
public List<Entity> getEntitiesInAABBexcluding(@Nullable Entity entityIn, AxisAlignedBB boundingBox, @Nullable Predicate <? super Entity > predicate)
{
List<Entity> list = Lists.<Entity>newArrayList();
- int j2 = MathHelper.floor((boundingBox.minX - 2.0D) / 16.0D);
- int k2 = MathHelper.floor((boundingBox.maxX + 2.0D) / 16.0D);
- int l2 = MathHelper.floor((boundingBox.minZ - 2.0D) / 16.0D);
- int i3 = MathHelper.floor((boundingBox.maxZ + 2.0D) / 16.0D);
+ int j2 = MathHelper.floor((boundingBox.minX - MAX_ENTITY_RADIUS) / 16.0D);
+ int k2 = MathHelper.floor((boundingBox.maxX + MAX_ENTITY_RADIUS) / 16.0D);
+ int l2 = MathHelper.floor((boundingBox.minZ - MAX_ENTITY_RADIUS) / 16.0D);
+ int i3 = MathHelper.floor((boundingBox.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
for (int j3 = j2; j3 <= k2; ++j3)
{
@@ -2847,10 +3396,10 @@
public <T extends Entity> List<T> getEntitiesWithinAABB(Class <? extends T > clazz, AxisAlignedBB aabb, @Nullable Predicate <? super T > filter)
{
- int j2 = MathHelper.floor((aabb.minX - 2.0D) / 16.0D);
- int k2 = MathHelper.ceil((aabb.maxX + 2.0D) / 16.0D);
- int l2 = MathHelper.floor((aabb.minZ - 2.0D) / 16.0D);
- int i3 = MathHelper.ceil((aabb.maxZ + 2.0D) / 16.0D);
+ int j2 = MathHelper.floor((aabb.minX - MAX_ENTITY_RADIUS) / 16.0D);
+ int k2 = MathHelper.ceil((aabb.maxX + MAX_ENTITY_RADIUS) / 16.0D);
+ int l2 = MathHelper.floor((aabb.minZ - MAX_ENTITY_RADIUS) / 16.0D);
+ int i3 = MathHelper.ceil((aabb.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
List<T> list = Lists.<T>newArrayList();
for (int j3 = j2; j3 < k2; ++j3)
@@ -2919,7 +3468,16 @@
for (Entity entity4 : this.loadedEntityList)
{
- if ((!(entity4 instanceof EntityLiving) || !((EntityLiving)entity4).isNoDespawnRequired()) && entityType.isAssignableFrom(entity4.getClass()))
+ // CraftBukkit start - Split out persistent check, don't apply it to special persistent mobs
+ if (entity4 instanceof EntityLiving) {
+ EntityLiving entityinsentient = (EntityLiving) entity4;
+ if (entityinsentient.canDespawn() && entityinsentient.isNoDespawnRequired()) {
+ continue;
+ }
+ }
+
+ // if ((!(entity4 instanceof EntityLiving) || !((EntityLiving)entity4).isNoDespawnRequired()) && entityType.isAssignableFrom(entity4.getClass()))
+ if (entityType.isAssignableFrom(entity4.getClass()))
{
++j2;
}
@@ -2930,11 +3488,17 @@
public void loadEntities(Collection<Entity> entityCollection)
{
- this.loadedEntityList.addAll(entityCollection);
-
+ if (catserver.server.AsyncCatcher.checkAsync("load entities")) { catserver.server.AsyncCatcher.ensureExecuteOnPrimaryThread(() -> loadEntities(entityCollection)); return; } // CatServer
for (Entity entity4 : entityCollection)
{
- this.onEntityAdded(entity4);
+ if (!net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityJoinWorldEvent(entity4, this)))
+ {
+ if (entity4 == null) {
+ continue;
+ }
+ loadedEntityList.add(entity4);
+ this.onEntityAdded(entity4);
+ }
}
}
@@ -2948,18 +3512,24 @@
IBlockState iblockstate1 = this.getBlockState(pos);
AxisAlignedBB axisalignedbb = skipCollisionCheck ? null : blockIn.getDefaultState().getCollisionBoundingBox(this, pos);
- if (axisalignedbb != Block.NULL_AABB && !this.checkNoEntityCollision(axisalignedbb.offset(pos), placer))
+ if (!((placer instanceof EntityPlayer) || !net.minecraftforge.event.ForgeEventFactory.onBlockPlace(placer, new net.minecraftforge.common.util.BlockSnapshot(this, pos, blockIn.getDefaultState()), sidePlacedOn).isCanceled())) return false;
+ boolean defaultReturn;
+ if (axisalignedbb != Block.NULL_AABB && !this.checkNoEntityCollision(axisalignedbb.offset(pos))) // Forge: Remove second parameter, we patch placer to be non-null, passing it here skips collision checks for the placer
{
- return false;
+ defaultReturn = false;
}
else if (iblockstate1.getMaterial() == Material.CIRCUITS && blockIn == Blocks.ANVIL)
{
- return true;
+ defaultReturn = true;
}
else
{
- return iblockstate1.getMaterial().isReplaceable() && blockIn.canPlaceBlockOnSide(this, pos, sidePlacedOn);
+ defaultReturn = iblockstate1.getBlock().isReplaceable(this, pos) && blockIn.canPlaceBlockOnSide(this, pos, sidePlacedOn);
}
+ BlockCanBuildEvent event = new BlockCanBuildEvent(this.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftMagicNumbers.getId(blockIn), defaultReturn);
+ this.getServer().getPluginManager().callEvent(event);
+
+ return event.isBuildable();
}
public int getSeaLevel()
@@ -3042,7 +3612,7 @@
public int getRedstonePower(BlockPos pos, EnumFacing facing)
{
IBlockState iblockstate1 = this.getBlockState(pos);
- return iblockstate1.isNormalCube() ? this.getStrongPower(pos) : iblockstate1.getWeakPower(this, pos, facing);
+ return iblockstate1.getBlock().shouldCheckWeakPower(iblockstate1, this, pos, facing) ? this.getStrongPower(pos) : iblockstate1.getWeakPower(this, pos, facing);
}
public boolean isBlockPowered(BlockPos pos)
@@ -3124,6 +3694,12 @@
{
EntityPlayer entityplayer1 = this.playerEntities.get(j2);
+ // CraftBukkit start - Fixed an NPE
+ if (entityplayer1 == null || entityplayer1.isDead) {
+ continue;
+ }
+ // CraftBukkit end
+
if (p_190525_9_.apply(entityplayer1))
{
double d1 = entityplayer1.getDistanceSq(x, y, z);
@@ -3208,6 +3784,8 @@
d2 *= ((Double)MoreObjects.firstNonNull(playerToDouble.apply(entityplayer1), Double.valueOf(1.0D))).doubleValue();
}
+ d2 = net.minecraftforge.common.ForgeHooks.getPlayerVisibilityDistance(entityplayer1, d2, maxYDistance);
+
if ((maxYDistance < 0.0D || Math.abs(entityplayer1.posY - posY) < maxYDistance * maxYDistance) && (maxXZDistance < 0.0D || d1 < d2 * d2) && (d0 == -1.0D || d1 < d0))
{
d0 = d1;
@@ -3269,7 +3847,7 @@
public long getSeed()
{
- return this.worldInfo.getSeed();
+ return this.provider.getSeed();
}
public long getTotalWorldTime()
@@ -3279,17 +3857,17 @@
public long getWorldTime()
{
- return this.worldInfo.getWorldTime();
+ return this.provider.getWorldTime();
}
public void setWorldTime(long time)
{
- this.worldInfo.setWorldTime(time);
+ this.provider.setWorldTime(time);
}
public BlockPos getSpawnPoint()
{
- BlockPos blockpos1 = new BlockPos(this.worldInfo.getSpawnX(), this.worldInfo.getSpawnY(), this.worldInfo.getSpawnZ());
+ BlockPos blockpos1 = this.provider.getSpawnPoint();
if (!this.getWorldBorder().contains(blockpos1))
{
@@ -3301,7 +3879,7 @@
public void setSpawnPoint(BlockPos pos)
{
- this.worldInfo.setSpawn(pos);
+ this.provider.setSpawnPoint(pos);
}
@SideOnly(Side.CLIENT)
@@ -3321,12 +3899,18 @@
if (!this.loadedEntityList.contains(entityIn))
{
+ if (!net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityJoinWorldEvent(entityIn, this)))
this.loadedEntityList.add(entityIn);
}
}
public boolean isBlockModifiable(EntityPlayer player, BlockPos pos)
{
+ return this.provider.canMineBlock(player, pos);
+ }
+
+ public boolean canMineBlockBody(EntityPlayer player, BlockPos pos)
+ {
return true;
}
@@ -3363,6 +3947,16 @@
{
}
+ // CraftBukkit start
+ // Calls the method that checks to see if players are sleeping
+ // Called by CraftPlayer.setPermanentSleeping()
+ public void checkSleepStatus() {
+ if (!this.isRemote) {
+ this.updateAllPlayersSleepingFlag();
+ }
+ }
+ // CraftBukkit end
+
public float getThunderStrength(float delta)
{
return (this.prevThunderingStrength + (this.thunderingStrength - this.prevThunderingStrength) * delta) * this.getRainStrength(delta);
@@ -3428,8 +4022,7 @@
public boolean isBlockinHighHumidity(BlockPos pos)
{
- Biome biome = this.getBiome(pos);
- return biome.isHighHumidity();
+ return this.provider.isBlockHighHumidity(pos);
}
@Nullable
@@ -3490,12 +4083,12 @@
public int getHeight()
{
- return 256;
+ return this.provider.getHeight();
}
public int getActualHeight()
{
- return this.provider.isNether() ? 128 : 256;
+ return this.provider.getActualHeight();
}
public Random setRandomSeed(int p_72843_1_, int p_72843_2_, int p_72843_3_)
@@ -3539,7 +4132,7 @@
@SideOnly(Side.CLIENT)
public double getHorizon()
{
- return this.worldInfo.getTerrainType() == WorldType.FLAT ? 0.0D : 63.0D;
+ return provider.getHorizon();
}
public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress)
@@ -3573,7 +4166,7 @@
public void updateComparatorOutputLevel(BlockPos pos, Block blockIn)
{
- for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL)
+ for (EnumFacing enumfacing : EnumFacing.VALUES)
{
BlockPos blockpos1 = pos.offset(enumfacing);
@@ -3581,18 +4174,15 @@
{
IBlockState iblockstate1 = this.getBlockState(blockpos1);
- if (Blocks.UNPOWERED_COMPARATOR.isSameDiode(iblockstate1))
+ iblockstate1.getBlock().onNeighborChange(this, blockpos1, pos);
+ if (iblockstate1.getBlock().isNormalCube(iblockstate1, this, blockpos1))
{
- iblockstate1.neighborChanged(this, blockpos1, blockIn, pos);
- }
- else if (iblockstate1.isNormalCube())
- {
blockpos1 = blockpos1.offset(enumfacing);
iblockstate1 = this.getBlockState(blockpos1);
- if (Blocks.UNPOWERED_COMPARATOR.isSameDiode(iblockstate1))
+ if (iblockstate1.getBlock().getWeakChanges(this, blockpos1))
{
- iblockstate1.neighborChanged(this, blockpos1, blockIn, pos);
+ iblockstate1.getBlock().onNeighborChange(this, blockpos1, pos);
}
}
}
@@ -3655,9 +4245,127 @@
int j2 = x * 16 + 8 - blockpos1.getX();
int k2 = z * 16 + 8 - blockpos1.getZ();
int l2 = 128;
- return j2 >= -128 && j2 <= 128 && k2 >= -128 && k2 <= 128;
+ return j2 >= -128 && j2 <= 128 && k2 >= -128 && k2 <= 128 && this.keepSpawnInMemory;
}
+ /* ======================================== FORGE START =====================================*/
+ /**
+ * Determine if the given block is considered solid on the
+ * specified side. Used by placement logic.
+ *
+ * @param pos Block Position
+ * @param side The Side in question
+ * @return True if the side is solid
+ */
+ public boolean isSideSolid(BlockPos pos, EnumFacing side)
+ {
+ return isSideSolid(pos, side, false);
+ }
+
+ /**
+ * Determine if the given block is considered solid on the
+ * specified side. Used by placement logic.
+ *
+ * @param pos Block Position
+ * @param side The Side in question
+ * @param _default The default to return if the block doesn't exist.
+ * @return True if the side is solid
+ */
+ @Override
+ public boolean isSideSolid(BlockPos pos, EnumFacing side, boolean _default)
+ {
+ if (!this.isValid(pos)) return _default;
+
+ Chunk chunk = getChunkFromBlockCoords(pos);
+ if (chunk == null || chunk.isEmpty()) return _default;
+ return getBlockState(pos).isSideSolid(this, pos, side);
+ }
+
+ /**
+ * Get the persistent chunks for this world
+ *
+ * @return
+ */
+ public com.google.common.collect.ImmutableSetMultimap<net.minecraft.util.math.ChunkPos, net.minecraftforge.common.ForgeChunkManager.Ticket> getPersistentChunks()
+ {
+ return net.minecraftforge.common.ForgeChunkManager.getPersistentChunksFor(this);
+ }
+
+ public Iterator<Chunk> getPersistentChunkIterable(Iterator<Chunk> chunkIterator)
+ {
+ return net.minecraftforge.common.ForgeChunkManager.getPersistentChunksIterableFor(this, chunkIterator);
+ }
+ /**
+ * Readded as it was removed, very useful helper function
+ *
+ * @param pos Block position
+ * @return The blocks light opacity
+ */
+ public int getBlockLightOpacity(BlockPos pos)
+ {
+ if (!this.isValid(pos)) return 0;
+ return getChunkFromBlockCoords(pos).getBlockLightOpacity(pos);
+ }
+
+ /**
+ * Returns a count of entities that classify themselves as the specified creature type.
+ */
+ public int countEntities(net.minecraft.entity.EnumCreatureType type, boolean forSpawnCount)
+ {
+ int count = 0;
+ for (int x = 0; x < loadedEntityList.size(); x++)
+ {
+ if (((Entity)loadedEntityList.get(x)).isCreatureType(type, forSpawnCount))
+ {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ @Deprecated // remove in 1.13
+ public void markTileEntitiesInChunkForRemoval(Chunk chunk)
+ {
+ for (TileEntity tileentity : chunk.getTileEntityMap().values())
+ {
+ markTileEntityForRemoval(tileentity);
+ }
+ }
+
+ protected void initCapabilities()
+ {
+ net.minecraftforge.common.capabilities.ICapabilityProvider parent = provider.initCapabilities();
+ capabilities = net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(this, parent);
+ net.minecraftforge.common.util.WorldCapabilityData data = (net.minecraftforge.common.util.WorldCapabilityData)perWorldStorage.getOrLoadData(net.minecraftforge.common.util.WorldCapabilityData.class, net.minecraftforge.common.util.WorldCapabilityData.ID);
+ if (data == null)
+ {
+ capabilityData = new net.minecraftforge.common.util.WorldCapabilityData(capabilities);
+ perWorldStorage.setData(capabilityData.mapName, capabilityData);
+ }
+ else
+ {
+ capabilityData = data;
+ capabilityData.setCapabilities(provider, capabilities);
+ }
+ }
+ @Override
+ public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, @Nullable EnumFacing facing)
+ {
+ return capabilities == null ? false : capabilities.hasCapability(capability, facing);
+ }
+ @Override
+ @Nullable
+ public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable EnumFacing facing)
+ {
+ return capabilities == null ? null : capabilities.getCapability(capability, facing);
+ }
+
+ protected MapStorage perWorldStorage; //Moved to a getter to simulate final without being final so we can load in subclasses.
+ public MapStorage getPerWorldStorage()
+ {
+ return perWorldStorage;
+ }
+
public void sendPacketToServer(Packet<?> packetIn)
{
throw new UnsupportedOperationException("Can't send packets to server unless you're on the client.");
@@ -3673,4 +4381,6 @@
{
return null;
}
+
+ public Map<BlockPos, TileEntity> capturedTileEntities = Maps.newHashMap(); // CatServer - Add spigot field, no used
}