You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
16 KiB
378 lines
16 KiB
--- ../src-base/minecraft/net/minecraft/world/chunk/Chunk.java |
|
+++ ../src-work/minecraft/net/minecraft/world/chunk/Chunk.java |
|
@@ -36,6 +36,17 @@ |
|
import org.apache.logging.log4j.LogManager; |
|
import org.apache.logging.log4j.Logger; |
|
|
|
+// CraftBukkit start |
|
+import net.minecraft.block.BlockContainer; |
|
+import org.bukkit.Bukkit; |
|
+// CraftBukkit end |
|
+// Spigot start |
|
+import net.minecraft.entity.EntityLiving; |
|
+import net.minecraft.entity.EnumCreatureType; |
|
+import net.minecraft.entity.player.EntityPlayerMP; |
|
+import net.minecraft.inventory.IInventory; |
|
+// Spigot end |
|
+ |
|
public class Chunk |
|
{ |
|
private static final Logger logger = LogManager.getLogger(); |
|
@@ -62,8 +73,42 @@ |
|
public int heightMapMinimum; |
|
public long inhabitedTime; |
|
private int queuedLightChecks; |
|
+ public gnu.trove.map.hash.TObjectIntHashMap<Class> entityCount = new gnu.trove.map.hash.TObjectIntHashMap<Class>(); // Spigot (Cauldron protected -> public) |
|
+ // PaperSpigot start - Asynchronous light updates |
|
+ public java.util.concurrent.atomic.AtomicInteger pendingLightUpdates = new java.util.concurrent.atomic.AtomicInteger(); |
|
+ public long lightUpdateTime; |
|
+ // PaperSpigot end |
|
+ public int lastAccessedTick; // Cauldron track last time the chunk was accessed |
|
private static final String __OBFID = "CL_00000373"; |
|
|
|
+ // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking |
|
+ private int neighbors = 0x1 << 12; |
|
+ |
|
+ public boolean areNeighborsLoaded(final int radius) { |
|
+ switch(radius) { |
|
+ case 2: |
|
+ return this.neighbors == Integer.MAX_VALUE >> 6; |
|
+ case 1: |
|
+ final int mask = |
|
+ // x z offset x z offset x z offset |
|
+ ( 0x1 << (1 * 5 + 1 + 12) ) | ( 0x1 << (0 * 5 + 1 + 12) ) | ( 0x1 << (-1 * 5 + 1 + 12) ) | |
|
+ ( 0x1 << (1 * 5 + 0 + 12) ) | ( 0x1 << (0 * 5 + 0 + 12) ) | ( 0x1 << (-1 * 5 + 0 + 12) ) | |
|
+ ( 0x1 << (1 * 5 + -1 + 12) ) | ( 0x1 << (0 * 5 + -1 + 12) ) | ( 0x1 << (-1 * 5 + -1 + 12) ); |
|
+ return (this.neighbors & mask) == mask; |
|
+ default: |
|
+ throw new UnsupportedOperationException(String.valueOf(radius)); |
|
+ } |
|
+ } |
|
+ |
|
+ public void setNeighborLoaded(final int x, final int z) { |
|
+ this.neighbors |= 0x1 << (x * 5 + 12 + z); |
|
+ } |
|
+ |
|
+ public void setNeighborUnloaded(final int x, final int z) { |
|
+ this.neighbors &= ~(0x1 << (x * 5 + 12 + z)); |
|
+ } |
|
+ // CraftBukkit end |
|
+ |
|
public Chunk(World p_i1995_1_, int p_i1995_2_, int p_i1995_3_) |
|
{ |
|
this.storageArrays = new ExtendedBlockStorage[16]; |
|
@@ -80,13 +125,22 @@ |
|
|
|
for (int k = 0; k < this.entityLists.length; ++k) |
|
{ |
|
- this.entityLists[k] = new ArrayList(); |
|
+ this.entityLists[k] = new org.bukkit.craftbukkit.util.UnsafeList(); // CraftBukkit - ArrayList -> UnsafeList |
|
} |
|
|
|
Arrays.fill(this.precipitationHeightMap, -999); |
|
Arrays.fill(this.blockBiomeArray, (byte) - 1); |
|
+ // CraftBukkit start |
|
+ if (!(this instanceof EmptyChunk)) |
|
+ { |
|
+ this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); |
|
+ } |
|
} |
|
|
|
+ public org.bukkit.Chunk bukkitChunk; |
|
+ public boolean mustSave; |
|
+ // CraftBukkit end |
|
+ |
|
public Chunk(World p_i45446_1_, Block[] p_i45446_2_, int p_i45446_3_, int p_i45446_4_) |
|
{ |
|
this(p_i45446_1_, p_i45446_3_, p_i45446_4_); |
|
@@ -512,10 +566,10 @@ |
|
|
|
if (extendedblockstorage != null) |
|
{ |
|
- try |
|
- { |
|
+ /*try |
|
+ {*/ // Exception handled by high-level class with safier deletion |
|
block = extendedblockstorage.getBlockByExtId(p_150810_1_, p_150810_2_ & 15, p_150810_3_); |
|
- } |
|
+ /*} |
|
catch (Throwable throwable) |
|
{ |
|
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block"); |
|
@@ -529,7 +583,7 @@ |
|
} |
|
}); |
|
throw new ReportedException(crashreport); |
|
- } |
|
+ }*/ |
|
} |
|
} |
|
|
|
@@ -589,9 +643,10 @@ |
|
|
|
if (!this.worldObj.isRemote) |
|
{ |
|
+ if (block1 == null) return false; // Cauldron |
|
block1.onBlockPreDestroy(this.worldObj, l1, p_150807_2_, i2, k1); |
|
} |
|
- |
|
+ // Cauldron - Removed CB patch that fixes BUKKIT-5238 to prevent stackoverflows. See issue #1165 and #1169 |
|
extendedblockstorage.func_150818_a(p_150807_1_, p_150807_2_ & 15, p_150807_3_, p_150807_4_); |
|
extendedblockstorage.setExtBlockMetadata(p_150807_1_, p_150807_2_ & 15, p_150807_3_, p_150807_5_); // This line duplicates the one below, so breakBlock fires with valid worldstate |
|
|
|
@@ -777,8 +832,20 @@ |
|
|
|
if (i != this.xPosition || j != this.zPosition) |
|
{ |
|
- logger.warn("Wrong location! " + p_76612_1_ + " (at " + i + ", " + j + " instead of " + this.xPosition + ", " + this.zPosition + ")"); |
|
- Thread.dumpStack(); |
|
+ // CraftBukkit start |
|
+ Bukkit.getLogger().warning("Wrong location for " + p_76612_1_ + " in world '" + worldObj.getWorld().getName() + "'!"); |
|
+ //logger.warn("Wrong location! " + p_76612_1_ + " (at " + i + ", " + j + " instead of " + this.xPosition + ", " + this.zPosition + ")"); |
|
+ //Thread.dumpStack(); |
|
+ Bukkit.getLogger().warning( |
|
+ "Entity is at " + p_76612_1_.posX + "," + p_76612_1_.posZ + " (chunk " + i + "," + j + ") but was stored in chunk " + this.xPosition + "," |
|
+ + this.zPosition); |
|
+ if (!(p_76612_1_ instanceof EntityPlayerMP)) |
|
+ { |
|
+ Bukkit.getLogger().warning("Cauldron has removed " + p_76612_1_ + " to prevent a server crash."); |
|
+ p_76612_1_.setDead(); |
|
+ return; |
|
+ } |
|
+ // CraftBukkit end |
|
} |
|
|
|
int k = MathHelper.floor_double(p_76612_1_.posY / 16.0D); |
|
@@ -799,6 +866,26 @@ |
|
p_76612_1_.chunkCoordY = k; |
|
p_76612_1_.chunkCoordZ = this.zPosition; |
|
this.entityLists[k].add(p_76612_1_); |
|
+ // Spigot start - increment creature type count |
|
+ // Keep this synced up with World.a(Class) |
|
+ if (p_76612_1_ instanceof EntityLiving) |
|
+ { |
|
+ EntityLiving entityliving = (EntityLiving) p_76612_1_; |
|
+ |
|
+ if (entityliving.canDespawn_CB() && entityliving.isNoDespawnRequired()) |
|
+ { |
|
+ return; |
|
+ } |
|
+ } |
|
+ |
|
+ for (EnumCreatureType creatureType : EnumCreatureType.values()) |
|
+ { |
|
+ if (creatureType.getCreatureClass().isAssignableFrom(p_76612_1_.getClass())) |
|
+ { |
|
+ this.entityCount.adjustOrPutValue(creatureType.getCreatureClass(), 1, 1); |
|
+ } |
|
+ } |
|
+ // Spigot end |
|
} |
|
|
|
public void removeEntity(Entity p_76622_1_) |
|
@@ -819,6 +906,26 @@ |
|
} |
|
|
|
this.entityLists[p_76608_2_].remove(p_76608_1_); |
|
+ // Spigot start - decrement creature type count |
|
+ // Keep this synced up with World.a(Class) |
|
+ if (p_76608_1_ instanceof EntityLiving) |
|
+ { |
|
+ EntityLiving entityliving = (EntityLiving) p_76608_1_; |
|
+ |
|
+ if (entityliving.canDespawn_CB() && entityliving.isNoDespawnRequired()) |
|
+ { |
|
+ return; |
|
+ } |
|
+ } |
|
+ |
|
+ for (EnumCreatureType creatureType : EnumCreatureType.values()) |
|
+ { |
|
+ if (creatureType.getCreatureClass().isAssignableFrom(p_76608_1_.getClass())) |
|
+ { |
|
+ this.entityCount.adjustValue(creatureType.getCreatureClass(), -1); |
|
+ } |
|
+ } |
|
+ // Spigot end |
|
} |
|
|
|
public boolean canBlockSeeTheSky(int p_76619_1_, int p_76619_2_, int p_76619_3_) |
|
@@ -874,9 +981,23 @@ |
|
p_150812_4_.xCoord = this.xPosition * 16 + p_150812_1_; |
|
p_150812_4_.yCoord = p_150812_2_; |
|
p_150812_4_.zCoord = this.zPosition * 16 + p_150812_3_; |
|
+ // Cauldron start - validate TE for corrupted data |
|
+ Block block = null; |
|
+ try |
|
+ { |
|
+ block = this.getBlock(p_150812_1_, p_150812_2_, p_150812_3_); |
|
+ } |
|
+ catch (ArrayIndexOutOfBoundsException e) |
|
+ { |
|
+ System.out.println("ERROR: Detected corrupted TileEntity " + p_150812_4_ + " with bad extended block ID of " |
|
+ + ((p_150812_2_ & 15) << 8 | p_150812_3_ << 4 | p_150812_1_) + " @ " + p_150812_4_.xCoord + ", " + p_150812_4_.yCoord + ", " |
|
+ + p_150812_4_.zCoord + ". Removing TE to avoid crash..."); |
|
+ p_150812_4_.invalidate(); |
|
+ return; |
|
+ } |
|
|
|
int metadata = getBlockMetadata(p_150812_1_, p_150812_2_, p_150812_3_); |
|
- if (this.getBlock(p_150812_1_, p_150812_2_, p_150812_3_).hasTileEntity(metadata)) |
|
+ if (block != null && block.hasTileEntity(metadata)) // Cauldron end |
|
{ |
|
if (this.chunkTileEntityMap.containsKey(chunkposition)) |
|
{ |
|
@@ -886,6 +1007,16 @@ |
|
p_150812_4_.validate(); |
|
this.chunkTileEntityMap.put(chunkposition, p_150812_4_); |
|
} |
|
+ // CraftBukkit start |
|
+ else if (net.minecraft.server.MinecraftServer.getServer().tileEntityConfig.enableTEPlaceWarning.getValue()) // Cauldron |
|
+ { |
|
+ System.out.println("Attempted to place a tile entity (" + p_150812_4_ + ") at " + p_150812_4_.xCoord + "," + p_150812_4_.yCoord + "," |
|
+ + p_150812_4_.zCoord + " (" + org.bukkit.Material.getMaterial(Block.getIdFromBlock(getBlock(p_150812_1_, p_150812_2_, p_150812_3_))) |
|
+ + ") where there was no entity tile!"); |
|
+ System.out.println("Chunk coordinates: " + (this.xPosition * 16) + "," + (this.zPosition * 16)); |
|
+ new Exception().printStackTrace(); |
|
+ } |
|
+ // CraftBukkit end |
|
} |
|
|
|
public void removeTileEntity(int p_150805_1_, int p_150805_2_, int p_150805_3_) |
|
@@ -936,6 +1067,21 @@ |
|
|
|
for (int i = 0; i < this.entityLists.length; ++i) |
|
{ |
|
+ // CraftBukkit start |
|
+ java.util.Iterator iter = this.entityLists[i].iterator(); |
|
+ |
|
+ while (iter.hasNext()) |
|
+ { |
|
+ Entity entity = (Entity) iter.next(); |
|
+ |
|
+ // Do not pass along players, as doing so can get them stuck outside of time. |
|
+ // (which for example disables inventory icon updates and prevents block breaking) |
|
+ if (entity instanceof EntityPlayerMP) |
|
+ { |
|
+ iter.remove(); |
|
+ } |
|
+ } |
|
+ // CraftBukkit end |
|
this.worldObj.unloadEntities(this.entityLists[i]); |
|
} |
|
MinecraftForge.EVENT_BUS.post(new ChunkEvent.Unload(this)); |
|
@@ -1015,7 +1161,7 @@ |
|
return true; |
|
} |
|
} |
|
- else if (this.hasEntities && this.worldObj.getTotalWorldTime() >= this.lastSaveTime + 600L) |
|
+ else if (this.hasEntities && this.worldObj.getTotalWorldTime() >= this.lastSaveTime + net.minecraft.server.MinecraftServer.getServer().autosavePeriod * 4) // PaperSpigot - Only save if we've passed 4 auto save intervals without modification |
|
{ |
|
return true; |
|
} |
|
@@ -1025,7 +1171,7 @@ |
|
|
|
public Random getRandomWithSeed(long p_76617_1_) |
|
{ |
|
- return new Random(this.worldObj.getSeed() + (long)(this.xPosition * this.xPosition * 4987142) + (long)(this.xPosition * 5947611) + (long)(this.zPosition * this.zPosition) * 4392871L + (long)(this.zPosition * 389711) ^ p_76617_1_); |
|
+ return new Random(this.worldObj.getSeed() + (4987142L * this.xPosition * this.xPosition) + (5947611L * this.xPosition) + (4392871L * this.zPosition * this.zPosition) + (389711L * this.zPosition) ^ p_76617_1_); |
|
} |
|
|
|
public boolean isEmpty() |
|
@@ -1035,6 +1181,7 @@ |
|
|
|
public void populateChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int p_76624_3_, int p_76624_4_) |
|
{ |
|
+ worldObj.timings.syncChunkLoadPostTimer.startTiming(); // Spigot |
|
if (!this.isTerrainPopulated && p_76624_1_.chunkExists(p_76624_3_ + 1, p_76624_4_ + 1) && p_76624_1_.chunkExists(p_76624_3_, p_76624_4_ + 1) && p_76624_1_.chunkExists(p_76624_3_ + 1, p_76624_4_)) |
|
{ |
|
p_76624_1_.populate(p_76624_2_, p_76624_3_, p_76624_4_); |
|
@@ -1054,6 +1201,7 @@ |
|
{ |
|
p_76624_1_.populate(p_76624_2_, p_76624_3_ - 1, p_76624_4_ - 1); |
|
} |
|
+ worldObj.timings.syncChunkLoadPostTimer.stopTiming(); // Spigot |
|
} |
|
|
|
public int getPrecipitationHeight(int p_76626_1_, int p_76626_2_) |
|
@@ -1091,7 +1239,7 @@ |
|
{ |
|
if (this.isGapLightingUpdated && !this.worldObj.provider.hasNoSky && !p_150804_1_) |
|
{ |
|
- this.recheckGaps(this.worldObj.isRemote); |
|
+ this.recheckGapsAsync(this.worldObj.isRemote); |
|
} |
|
|
|
this.field_150815_m = true; |
|
@@ -1184,8 +1332,10 @@ |
|
if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null) |
|
{ |
|
nibblearray = this.storageArrays[l].getMetadataArray(); |
|
- System.arraycopy(p_76607_1_, k, nibblearray.data, 0, nibblearray.data.length); |
|
- k += nibblearray.data.length; |
|
+ // Spigot start |
|
+ System.arraycopy(p_76607_1_, k, nibblearray.getValueArray(), 0, nibblearray.getValueArray().length); |
|
+ k += nibblearray.getValueArray().length; |
|
+ // Spigot end |
|
} |
|
} |
|
|
|
@@ -1194,8 +1344,10 @@ |
|
if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null) |
|
{ |
|
nibblearray = this.storageArrays[l].getBlocklightArray(); |
|
- System.arraycopy(p_76607_1_, k, nibblearray.data, 0, nibblearray.data.length); |
|
- k += nibblearray.data.length; |
|
+ // Spigot start |
|
+ System.arraycopy(p_76607_1_, k, nibblearray.getValueArray(), 0, nibblearray.getValueArray().length); |
|
+ k += nibblearray.getValueArray().length; |
|
+ // Spigot end |
|
} |
|
} |
|
|
|
@@ -1206,8 +1358,10 @@ |
|
if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null) |
|
{ |
|
nibblearray = this.storageArrays[l].getSkylightArray(); |
|
- System.arraycopy(p_76607_1_, k, nibblearray.data, 0, nibblearray.data.length); |
|
- k += nibblearray.data.length; |
|
+ // Spigot start |
|
+ System.arraycopy(p_76607_1_, k, nibblearray.getValueArray(), 0, nibblearray.getValueArray().length); |
|
+ k += nibblearray.getValueArray().length; |
|
+ // Spigot end |
|
} |
|
} |
|
} |
|
@@ -1229,8 +1383,8 @@ |
|
nibblearray = this.storageArrays[l].createBlockMSBArray(); |
|
} |
|
|
|
- System.arraycopy(p_76607_1_, k, nibblearray.data, 0, nibblearray.data.length); |
|
- k += nibblearray.data.length; |
|
+ System.arraycopy(p_76607_1_, k, nibblearray.getValueArray(), 0, nibblearray.getValueArray().length); |
|
+ k += nibblearray.getValueArray().length; |
|
} |
|
} |
|
else if (p_76607_4_ && this.storageArrays[l] != null && this.storageArrays[l].getBlockMSBArray() != null) |
|
@@ -1523,4 +1677,21 @@ |
|
} |
|
} |
|
} |
|
+ |
|
+ /** |
|
+ * PaperSpigot - Recheck gaps asynchronously. |
|
+ */ |
|
+ public void recheckGapsAsync(final boolean isStatic) { |
|
+ if (!worldObj.spigotConfig.useAsyncLighting) { |
|
+ this.recheckGaps(isStatic); |
|
+ return; |
|
+ } |
|
+ |
|
+ worldObj.lightingExecutor.submit(new Runnable() { |
|
+ @Override |
|
+ public void run() { |
|
+ Chunk.this.recheckGaps(isStatic); |
|
+ } |
|
+ }); |
|
+ } |
|
}
|
|
|