mirror of
https://github.com/barkeser2002/CatServer.git
synced 2026-09-25 06:40:05 +03:00
738 lines
32 KiB
Diff
738 lines
32 KiB
Diff
--- ../src-base/minecraft/net/minecraft/world/chunk/Chunk.java
|
|
+++ ../src-work/minecraft/net/minecraft/world/chunk/Chunk.java
|
|
@@ -8,20 +8,27 @@
|
|
import java.util.Map;
|
|
import java.util.Random;
|
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
+import java.util.stream.Collectors;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.block.Block;
|
|
-import net.minecraft.block.ITileEntityProvider;
|
|
+import net.minecraft.block.BlockSand;
|
|
import net.minecraft.block.material.Material;
|
|
import net.minecraft.block.state.IBlockState;
|
|
import net.minecraft.crash.CrashReport;
|
|
import net.minecraft.crash.CrashReportCategory;
|
|
import net.minecraft.crash.ICrashReportDetail;
|
|
import net.minecraft.entity.Entity;
|
|
+import net.minecraft.entity.EntityLiving;
|
|
+import net.minecraft.entity.EnumCreatureType;
|
|
+import net.minecraft.entity.item.EntityItem;
|
|
+import net.minecraft.entity.player.EntityPlayerMP;
|
|
import net.minecraft.init.Biomes;
|
|
import net.minecraft.init.Blocks;
|
|
+import net.minecraft.inventory.IInventory;
|
|
import net.minecraft.network.PacketBuffer;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
import net.minecraft.util.ClassInheritanceMultiMap;
|
|
+import net.minecraft.util.EntitySelectors;
|
|
import net.minecraft.util.EnumFacing;
|
|
import net.minecraft.util.ReportedException;
|
|
import net.minecraft.util.math.AxisAlignedBB;
|
|
@@ -41,7 +48,9 @@
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
-public class Chunk
|
|
+import org.bukkit.Server;
|
|
+
|
|
+public class Chunk implements net.minecraftforge.common.capabilities.ICapabilityProvider
|
|
{
|
|
private static final Logger LOGGER = LogManager.getLogger();
|
|
public static final ExtendedBlockStorage NULL_BLOCK_STORAGE = null;
|
|
@@ -50,13 +59,13 @@
|
|
private final int[] precipitationHeightMap;
|
|
private final boolean[] updateSkylightColumns;
|
|
private boolean loaded;
|
|
- private final World world;
|
|
- private final int[] heightMap;
|
|
+ public final World world; // CatServer - private -> public
|
|
+ public final int[] heightMap; // CatServer - private -> public
|
|
public final int x;
|
|
public final int z;
|
|
private boolean isGapLightingUpdated;
|
|
- private final Map<BlockPos, TileEntity> tileEntities;
|
|
- private final ClassInheritanceMultiMap<Entity>[] entityLists;
|
|
+ public final Map<BlockPos, TileEntity> tileEntities; // CatServer - private -> public
|
|
+ public final ClassInheritanceMultiMap<Entity>[] entityLists; // CatServer - WARN: Spigot use List, some plugin need patch
|
|
private boolean isTerrainPopulated;
|
|
private boolean isLightPopulated;
|
|
private boolean ticked;
|
|
@@ -68,7 +77,95 @@
|
|
private int queuedLightChecks;
|
|
private final ConcurrentLinkedQueue<BlockPos> tileEntityPosQueue;
|
|
public boolean unloadQueued;
|
|
+ public gnu.trove.map.hash.TObjectIntHashMap<Class> entityCount = new gnu.trove.map.hash.TObjectIntHashMap<Class>(); // Spigot
|
|
|
|
+ // Paper start
|
|
+ // Track the number of minecarts and items
|
|
+ // Keep this synced with entitySlices.add() and entitySlices.remove()
|
|
+ private final int[] itemCounts = new int[16];
|
|
+ private final int[] inventoryEntityCounts = new int[16];
|
|
+ // Paper end
|
|
+
|
|
+ // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking
|
|
+ private int neighbors = 0x1 << 12;
|
|
+ public long chunkKey;
|
|
+
|
|
+ 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
|
|
+
|
|
+ private boolean loadingTileentity = false; // CatServer - prevent modification of tileentity list when chunk loading
|
|
+
|
|
+ // CatServer start
|
|
+ private void handleSpigotEntityAdd(Entity entityIn) {
|
|
+ // Spigot start - increment creature type count
|
|
+ // Keep this synced up with World.a(Class)
|
|
+ if (entityIn instanceof EntityLiving) {
|
|
+ EntityLiving entityinsentient = (EntityLiving) entityIn;
|
|
+ if (entityinsentient.canDespawn() && entityinsentient.isNoDespawnRequired()) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ for ( EnumCreatureType creatureType : EnumCreatureType.values() )
|
|
+ {
|
|
+ if ( creatureType.getCreatureClass().isAssignableFrom( entityIn.getClass() ) )
|
|
+ {
|
|
+ this.entityCount.adjustOrPutValue( creatureType.getCreatureClass(), 1, 1 );
|
|
+ }
|
|
+ }
|
|
+ // Spigot end
|
|
+ }
|
|
+
|
|
+ private void handleSpigotEntityRemove(Entity entityIn) {
|
|
+ // Spigot start - decrement creature type count
|
|
+ // Keep this synced up with World.a(Class)
|
|
+ if (entityIn instanceof EntityLiving) {
|
|
+ EntityLiving entityinsentient = (EntityLiving) entityIn;
|
|
+ if (entityinsentient.canDespawn() && entityinsentient.isNoDespawnRequired()) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ for ( EnumCreatureType creatureType : EnumCreatureType.values() )
|
|
+ {
|
|
+ if ( creatureType.getCreatureClass().isAssignableFrom( entityIn.getClass() ) )
|
|
+ {
|
|
+ this.entityCount.adjustValue( creatureType.getCreatureClass(), -1 );
|
|
+ }
|
|
+ }
|
|
+ // Spigot end
|
|
+ }
|
|
+
|
|
+ private void handleSpigotOnLoaded() {
|
|
+ this.entityCount.clear();
|
|
+ for (ClassInheritanceMultiMap<Entity> entityList : entityLists) {
|
|
+ for (Entity entity : entityList) {
|
|
+ handleSpigotEntityAdd(entity);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // CatServer end
|
|
+
|
|
public Chunk(World worldIn, int x, int z)
|
|
{
|
|
this.storageArrays = new ExtendedBlockStorage[16];
|
|
@@ -91,8 +188,14 @@
|
|
|
|
Arrays.fill(this.precipitationHeightMap, -999);
|
|
Arrays.fill(this.blockBiomeArray, (byte) - 1);
|
|
+ capabilities = net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(this);
|
|
+ this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
|
|
+ this.chunkKey = ChunkPos.asLong(this.x, this.z);
|
|
}
|
|
|
|
+ public org.bukkit.Chunk bukkitChunk;
|
|
+ public boolean mustSave;
|
|
+
|
|
public Chunk(World worldIn, ChunkPrimer primer, int x, int z)
|
|
{
|
|
this(worldIn, x, z);
|
|
@@ -179,7 +282,7 @@
|
|
{
|
|
IBlockState iblockstate = this.getBlockState(j, l - 1, k);
|
|
|
|
- if (iblockstate.getLightOpacity() != 0)
|
|
+ if (this.getBlockLightOpacity(j, l - 1, k) != 0)
|
|
{
|
|
this.heightMap[k << 4 | j] = l;
|
|
|
|
@@ -452,12 +555,13 @@
|
|
|
|
public int getBlockLightOpacity(BlockPos pos)
|
|
{
|
|
- return this.getBlockState(pos).getLightOpacity();
|
|
+ return this.getBlockState(pos).getLightOpacity(this.world, pos);
|
|
}
|
|
|
|
private int getBlockLightOpacity(int x, int y, int z)
|
|
{
|
|
- return this.getBlockState(x, y, z).getLightOpacity();
|
|
+ IBlockState state = this.getBlockState(x, y, z); //Forge: Can sometimes be called before we are added to the global world list. So use the less accurate one during that. It'll be recalculated later
|
|
+ return !loaded ? state.getLightOpacity() : state.getLightOpacity(world, new BlockPos(this.x << 4 | x & 15, y, this.z << 4 | z & 15));
|
|
}
|
|
|
|
public IBlockState getBlockState(BlockPos pos)
|
|
@@ -539,6 +643,7 @@
|
|
{
|
|
Block block = state.getBlock();
|
|
Block block1 = iblockstate.getBlock();
|
|
+ int k1 = iblockstate.getLightOpacity(this.world, pos); // Relocate old light value lookup here, so that it is called before TE is removed.
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[j >> 4];
|
|
boolean flag = false;
|
|
|
|
@@ -556,14 +661,19 @@
|
|
|
|
extendedblockstorage.set(i, j & 15, k, state);
|
|
|
|
- if (block1 != block)
|
|
+ //if (block1 != block)
|
|
{
|
|
if (!this.world.isRemote)
|
|
{
|
|
+ if (block1 != block) //Only fire block breaks when the block changes.
|
|
block1.breakBlock(this.world, pos, iblockstate);
|
|
+ TileEntity te = this.getTileEntity(pos, EnumCreateEntityType.CHECK);
|
|
+ if (te != null && te.shouldRefresh(this.world, pos, iblockstate, state)) this.world.removeTileEntity(pos);
|
|
}
|
|
- else if (block1 instanceof ITileEntityProvider)
|
|
+ else if (block1.hasTileEntity(iblockstate))
|
|
{
|
|
+ TileEntity te = this.getTileEntity(pos, EnumCreateEntityType.CHECK);
|
|
+ if (te != null && te.shouldRefresh(this.world, pos, iblockstate, state))
|
|
this.world.removeTileEntity(pos);
|
|
}
|
|
}
|
|
@@ -580,8 +690,7 @@
|
|
}
|
|
else
|
|
{
|
|
- int j1 = state.getLightOpacity();
|
|
- int k1 = iblockstate.getLightOpacity();
|
|
+ int j1 = state.getLightOpacity(this.world, pos);
|
|
|
|
if (j1 > 0)
|
|
{
|
|
@@ -601,28 +710,20 @@
|
|
}
|
|
}
|
|
|
|
- if (block1 instanceof ITileEntityProvider)
|
|
+ // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
|
|
+ // If capturing blocks, only run block physics for TE's. Non-TE's are handled in ForgeHooks.onPlaceItemIntoWorld
|
|
+ if (!this.world.isRemote && block1 != block && (!this.world.captureBlockSnapshots || block.hasTileEntity(state)))
|
|
{
|
|
- TileEntity tileentity = this.getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK);
|
|
-
|
|
- if (tileentity != null)
|
|
- {
|
|
- tileentity.updateContainingBlockInfo();
|
|
- }
|
|
- }
|
|
-
|
|
- if (!this.world.isRemote && block1 != block)
|
|
- {
|
|
block.onBlockAdded(this.world, pos, state);
|
|
}
|
|
|
|
- if (block instanceof ITileEntityProvider)
|
|
+ if (block.hasTileEntity(state))
|
|
{
|
|
- TileEntity tileentity1 = this.getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK);
|
|
+ TileEntity tileentity1 = this.getTileEntity(pos, EnumCreateEntityType.CHECK);
|
|
|
|
if (tileentity1 == null)
|
|
{
|
|
- tileentity1 = ((ITileEntityProvider)block).createNewTileEntity(this.world, block.getMetaFromState(state));
|
|
+ tileentity1 = block.createTileEntity(this.world, state);
|
|
this.world.setTileEntity(pos, tileentity1);
|
|
}
|
|
|
|
@@ -738,11 +839,22 @@
|
|
k = this.entityLists.length - 1;
|
|
}
|
|
|
|
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityEvent.EnteringChunk(entityIn, this.x, this.z, entityIn.chunkCoordX, entityIn.chunkCoordZ));
|
|
entityIn.addedToChunk = true;
|
|
entityIn.chunkCoordX = this.x;
|
|
entityIn.chunkCoordY = k;
|
|
entityIn.chunkCoordZ = this.z;
|
|
this.entityLists[k].add(entityIn);
|
|
+ this.markDirty(); // Forge - ensure chunks are marked to save after an entity add
|
|
+ // Paper start
|
|
+ if (entityIn instanceof EntityItem) {
|
|
+ itemCounts[k]++;
|
|
+ } else if (entityIn instanceof IInventory) {
|
|
+ inventoryEntityCounts[k]++;
|
|
+ }
|
|
+ // Paper end
|
|
+ if (loaded) handleSpigotEntityAdd(entityIn); // CatServer
|
|
+
|
|
}
|
|
|
|
public void removeEntity(Entity entityIn)
|
|
@@ -763,6 +875,15 @@
|
|
}
|
|
|
|
this.entityLists[index].remove(entityIn);
|
|
+ this.markDirty(); // Forge - ensure chunks are marked to save after entity removals
|
|
+ // Paper start
|
|
+ if (entityIn instanceof EntityItem) {
|
|
+ itemCounts[index]--;
|
|
+ } else if (entityIn instanceof IInventory) {
|
|
+ inventoryEntityCounts[index]--;
|
|
+ }
|
|
+ // Paper end
|
|
+ if (loaded) handleSpigotEntityRemove(entityIn); // CatServer
|
|
}
|
|
|
|
public boolean canSeeSky(BlockPos pos)
|
|
@@ -778,31 +899,35 @@
|
|
{
|
|
IBlockState iblockstate = this.getBlockState(pos);
|
|
Block block = iblockstate.getBlock();
|
|
- return !block.hasTileEntity() ? null : ((ITileEntityProvider)block).createNewTileEntity(this.world, iblockstate.getBlock().getMetaFromState(iblockstate));
|
|
+ return !block.hasTileEntity(iblockstate) ? null : block.createTileEntity(this.world, iblockstate);
|
|
}
|
|
|
|
@Nullable
|
|
- public TileEntity getTileEntity(BlockPos pos, Chunk.EnumCreateEntityType p_177424_2_)
|
|
+ public TileEntity getTileEntity(BlockPos pos, EnumCreateEntityType p_177424_2_)
|
|
{
|
|
- TileEntity tileentity = this.tileEntities.get(pos);
|
|
+ TileEntity tileentity = null;
|
|
+ if (tileentity == null) {
|
|
+ tileentity = this.tileEntities.get(pos);
|
|
+ }
|
|
|
|
+ if (tileentity != null && tileentity.isInvalid())
|
|
+ {
|
|
+ tileEntities.remove(pos);
|
|
+ tileentity = null;
|
|
+ }
|
|
+
|
|
if (tileentity == null)
|
|
{
|
|
- if (p_177424_2_ == Chunk.EnumCreateEntityType.IMMEDIATE)
|
|
+ if (p_177424_2_ == EnumCreateEntityType.IMMEDIATE && !this.loadingTileentity) // CatServer
|
|
{
|
|
tileentity = this.createNewTileEntity(pos);
|
|
this.world.setTileEntity(pos, tileentity);
|
|
}
|
|
- else if (p_177424_2_ == Chunk.EnumCreateEntityType.QUEUED)
|
|
+ else if (p_177424_2_ == EnumCreateEntityType.QUEUED)
|
|
{
|
|
- this.tileEntityPosQueue.add(pos);
|
|
+ this.tileEntityPosQueue.add(pos.toImmutable());
|
|
}
|
|
}
|
|
- else if (tileentity.isInvalid())
|
|
- {
|
|
- this.tileEntities.remove(pos);
|
|
- return null;
|
|
- }
|
|
|
|
return tileentity;
|
|
}
|
|
@@ -819,10 +944,12 @@
|
|
|
|
public void addTileEntity(BlockPos pos, TileEntity tileEntityIn)
|
|
{
|
|
+ if (loadingTileentity) throw new IllegalStateException("Try to add tileentity when chunk loading"); // CatServer
|
|
+ if (tileEntityIn.getWorld() != this.world) //Forge don't call unless it's changed, could screw up bad mods.
|
|
tileEntityIn.setWorld(this.world);
|
|
tileEntityIn.setPos(pos);
|
|
|
|
- if (this.getBlockState(pos).getBlock() instanceof ITileEntityProvider)
|
|
+ if (this.getBlockState(pos).getBlock().hasTileEntity(this.getBlockState(pos)))
|
|
{
|
|
if (this.tileEntities.containsKey(pos))
|
|
{
|
|
@@ -836,6 +963,7 @@
|
|
|
|
public void removeTileEntity(BlockPos pos)
|
|
{
|
|
+ if (loadingTileentity) throw new IllegalStateException("Try to remove tileentity when chunk loading"); // CatServer
|
|
if (this.loaded)
|
|
{
|
|
TileEntity tileentity = this.tileEntities.remove(pos);
|
|
@@ -850,16 +978,21 @@
|
|
public void onLoad()
|
|
{
|
|
this.loaded = true;
|
|
+ handleSpigotOnLoaded(); // CatServer
|
|
+ loadingTileentity = true; // CatServer
|
|
this.world.addTileEntities(this.tileEntities.values());
|
|
+ loadingTileentity = false; // CatServer
|
|
|
|
for (ClassInheritanceMultiMap<Entity> classinheritancemultimap : this.entityLists)
|
|
{
|
|
- this.world.loadEntities(classinheritancemultimap);
|
|
+ this.world.loadEntities(com.google.common.collect.ImmutableList.copyOf(classinheritancemultimap));
|
|
}
|
|
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkEvent.Load(this));
|
|
}
|
|
|
|
public void onUnload()
|
|
{
|
|
+ Arrays.stream(entityLists).forEach(multimap -> com.google.common.collect.Lists.newArrayList(multimap.getByClass(net.minecraft.entity.player.EntityPlayer.class)).forEach(player -> world.updateEntityWithOptionalForce(player, false))); // FORGE - Fix for MC-92916
|
|
this.loaded = false;
|
|
|
|
for (TileEntity tileentity : this.tileEntities.values())
|
|
@@ -869,8 +1002,16 @@
|
|
|
|
for (ClassInheritanceMultiMap<Entity> classinheritancemultimap : this.entityLists)
|
|
{
|
|
- this.world.unloadEntities(classinheritancemultimap);
|
|
+ // 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)
|
|
+ this.world.unloadEntities(
|
|
+ classinheritancemultimap
|
|
+ .stream()
|
|
+ .filter(entity -> !(entity instanceof EntityPlayerMP))
|
|
+ .collect(Collectors.toCollection(() -> new ClassInheritanceMultiMap<>(Entity.class)))
|
|
+ );
|
|
}
|
|
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkEvent.Unload(this));
|
|
}
|
|
|
|
public void markDirty()
|
|
@@ -880,8 +1021,8 @@
|
|
|
|
public void getEntitiesWithinAABBForEntity(@Nullable Entity entityIn, AxisAlignedBB aabb, List<Entity> listToFill, Predicate <? super Entity > filter)
|
|
{
|
|
- int i = MathHelper.floor((aabb.minY - 2.0D) / 16.0D);
|
|
- int j = MathHelper.floor((aabb.maxY + 2.0D) / 16.0D);
|
|
+ int i = MathHelper.floor((aabb.minY - World.MAX_ENTITY_RADIUS) / 16.0D);
|
|
+ int j = MathHelper.floor((aabb.maxY + World.MAX_ENTITY_RADIUS) / 16.0D);
|
|
i = MathHelper.clamp(i, 0, this.entityLists.length - 1);
|
|
j = MathHelper.clamp(j, 0, this.entityLists.length - 1);
|
|
|
|
@@ -889,6 +1030,15 @@
|
|
{
|
|
if (!this.entityLists[k].isEmpty())
|
|
{
|
|
+ // Paper start - Don't search for inventories if we have none, and that is all we want
|
|
+ /*
|
|
+ * We check if they want inventories by seeing if it is the static `IEntitySelector.c`
|
|
+ *
|
|
+ * Make sure the inventory selector stays in sync.
|
|
+ * It should be the one that checks `var1 instanceof IInventory && var1.isAlive()`
|
|
+ */
|
|
+ if (filter == EntitySelectors.HAS_INVENTORY && inventoryEntityCounts[k] <= 0) continue;
|
|
+ // Paper end
|
|
for (Entity entity : this.entityLists[k])
|
|
{
|
|
if (entity.getEntityBoundingBox().intersects(aabb) && entity != entityIn)
|
|
@@ -918,13 +1068,24 @@
|
|
|
|
public <T extends Entity> void getEntitiesOfTypeWithinAABB(Class <? extends T > entityClass, AxisAlignedBB aabb, List<T> listToFill, Predicate <? super T > filter)
|
|
{
|
|
- int i = MathHelper.floor((aabb.minY - 2.0D) / 16.0D);
|
|
- int j = MathHelper.floor((aabb.maxY + 2.0D) / 16.0D);
|
|
+ int i = MathHelper.floor((aabb.minY - World.MAX_ENTITY_RADIUS) / 16.0D);
|
|
+ int j = MathHelper.floor((aabb.maxY + World.MAX_ENTITY_RADIUS) / 16.0D);
|
|
i = MathHelper.clamp(i, 0, this.entityLists.length - 1);
|
|
j = MathHelper.clamp(j, 0, this.entityLists.length - 1);
|
|
|
|
+ // Paper start
|
|
+ int[] counts;
|
|
+ if (EntityItem.class.isAssignableFrom(entityClass)) {
|
|
+ counts = itemCounts;
|
|
+ } else if (IInventory.class.isAssignableFrom(entityClass)) {
|
|
+ counts = inventoryEntityCounts;
|
|
+ } else {
|
|
+ counts = null;
|
|
+ }
|
|
+ // Paper end
|
|
for (int k = i; k <= j; ++k)
|
|
{
|
|
+ if (counts != null && counts[k] <= 0) continue; // Paper - Don't check a chunk if it doesn't have the type we are looking for
|
|
for (T t : this.entityLists[k].getByClass(entityClass))
|
|
{
|
|
if (t.getEntityBoundingBox().intersects(aabb) && (filter == null || filter.apply(t)))
|
|
@@ -995,8 +1156,70 @@
|
|
}
|
|
}
|
|
|
|
+ public void populateCB(IChunkProvider chunkProvider, IChunkGenerator chunkGenrator, boolean newChunk)
|
|
+ {
|
|
+ world.timings.syncChunkLoadPostTimer.startTiming(); // Spigot
|
|
+ Server server = world.getServer();
|
|
+ if (server != null) {
|
|
+ /*
|
|
+ * If it's a new world, the first few chunks are generated inside
|
|
+ * the World constructor. We can't reliably alter that, so we have
|
|
+ * no way of creating a CraftWorld/CraftServer at that point.
|
|
+ */
|
|
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, newChunk));
|
|
+ }
|
|
+
|
|
+ // Update neighbor counts
|
|
+ for (int x = -2; x < 3; x++) {
|
|
+ for (int z = -2; z < 3; z++) {
|
|
+ if (x == 0 && z == 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ Chunk neighbor = getWorld().getChunkIfLoaded(this.x + x, this.z + z);
|
|
+ if (neighbor != null) {
|
|
+ neighbor.setNeighborLoaded(-x, -z);
|
|
+ setNeighborLoaded(x, z);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ Chunk chunk = chunkProvider.getLoadedChunk(this.x, this.z - 1);
|
|
+ Chunk chunk1 = chunkProvider.getLoadedChunk(this.x + 1, this.z);
|
|
+ Chunk chunk2 = chunkProvider.getLoadedChunk(this.x, this.z + 1);
|
|
+ Chunk chunk3 = chunkProvider.getLoadedChunk(this.x - 1, this.z);
|
|
+
|
|
+ if (chunk1 != null && chunk2 != null && chunkProvider.getLoadedChunk(this.x + 1, this.z + 1) != null)
|
|
+ {
|
|
+ this.populate(chunkGenrator);
|
|
+ }
|
|
+
|
|
+ if (chunk3 != null && chunk2 != null && chunkProvider.getLoadedChunk(this.x - 1, this.z + 1) != null)
|
|
+ {
|
|
+ chunk3.populate(chunkGenrator);
|
|
+ }
|
|
+
|
|
+ if (chunk != null && chunk1 != null && chunkProvider.getLoadedChunk(this.x + 1, this.z - 1) != null)
|
|
+ {
|
|
+ chunk.populate(chunkGenrator);
|
|
+ }
|
|
+
|
|
+ if (chunk != null && chunk3 != null)
|
|
+ {
|
|
+ Chunk chunk4 = chunkProvider.getLoadedChunk(this.x - 1, this.z - 1);
|
|
+
|
|
+ if (chunk4 != null)
|
|
+ {
|
|
+ chunk4.populate(chunkGenrator);
|
|
+ }
|
|
+ }
|
|
+ world.timings.syncChunkLoadPostTimer.stopTiming(); // Spigot
|
|
+ }
|
|
+
|
|
protected void populate(IChunkGenerator generator)
|
|
{
|
|
+ if (populating != null && net.minecraftforge.common.ForgeModContainer.logCascadingWorldGeneration) logCascadingWorldGeneration();
|
|
+ ChunkPos prev = populating;
|
|
+ populating = this.getPos();
|
|
if (this.isTerrainPopulated())
|
|
{
|
|
if (generator.generateStructures(this, this.x, this.z))
|
|
@@ -1008,8 +1231,32 @@
|
|
{
|
|
this.checkLight();
|
|
generator.populate(this.x, this.z);
|
|
+ BlockSand.fallInstantly = true;
|
|
+ Random random = new Random();
|
|
+ random.setSeed(world.getSeed());
|
|
+ long xRand = random.nextLong() / 2L * 2L + 1L;
|
|
+ long zRand = random.nextLong() / 2L * 2L + 1L;
|
|
+ random.setSeed((long) this.x * xRand + (long) this.z * zRand ^ world.getSeed());
|
|
+
|
|
+ org.bukkit.World world = this.world.getWorld();
|
|
+ if (world != null) {
|
|
+ this.world.populating = true;
|
|
+ try {
|
|
+ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
|
|
+ populator.populate(world, random, bukkitChunk);
|
|
+ }
|
|
+ } finally {
|
|
+ this.world.populating = false;
|
|
+ }
|
|
+ }
|
|
+ BlockSand.fallInstantly = false;
|
|
+ this.world.getServer().getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk));
|
|
+ if (world != null && !catserver.server.CatServer.getConfig().disableForgeGenerateWorlds.contains(world.getName())) {
|
|
+ net.minecraftforge.fml.common.registry.GameRegistry.generateWorld(this.x, this.z, this.world, generator, this.world.getChunkProvider());
|
|
+ }
|
|
this.markDirty();
|
|
}
|
|
+ populating = prev;
|
|
}
|
|
|
|
public BlockPos getPrecipitationHeight(BlockPos pos)
|
|
@@ -1064,7 +1311,7 @@
|
|
{
|
|
BlockPos blockpos = this.tileEntityPosQueue.poll();
|
|
|
|
- if (this.getTileEntity(blockpos, Chunk.EnumCreateEntityType.CHECK) == null && this.getBlockState(blockpos).getBlock().hasTileEntity())
|
|
+ if (this.getTileEntity(blockpos, EnumCreateEntityType.CHECK) == null && this.getBlockState(blockpos).getBlock().hasTileEntity(this.getBlockState(blockpos)))
|
|
{
|
|
TileEntity tileentity = this.createNewTileEntity(blockpos);
|
|
this.world.setTileEntity(blockpos, tileentity);
|
|
@@ -1075,7 +1322,7 @@
|
|
|
|
public boolean isPopulated()
|
|
{
|
|
- return this.ticked && this.isTerrainPopulated && this.isLightPopulated;
|
|
+ return this.ticked && this.isTerrainPopulated; // CatServer - remove light populated check
|
|
}
|
|
|
|
public boolean wasTicked()
|
|
@@ -1128,6 +1375,13 @@
|
|
@SideOnly(Side.CLIENT)
|
|
public void read(PacketBuffer buf, int availableSections, boolean groundUpContinuous)
|
|
{
|
|
+ for(TileEntity tileEntity : tileEntities.values())
|
|
+ {
|
|
+ tileEntity.updateContainingBlockInfo();
|
|
+ tileEntity.getBlockMetadata();
|
|
+ tileEntity.getBlockType();
|
|
+ }
|
|
+
|
|
boolean flag = this.world.provider.hasSkyLight();
|
|
|
|
for (int i = 0; i < this.storageArrays.length; ++i)
|
|
@@ -1176,10 +1430,16 @@
|
|
this.isTerrainPopulated = true;
|
|
this.generateHeightMap();
|
|
|
|
+ List<TileEntity> invalidList = new java.util.ArrayList<TileEntity>();
|
|
+
|
|
for (TileEntity tileentity : this.tileEntities.values())
|
|
{
|
|
+ if (tileentity.shouldRefresh(this.world, tileentity.getPos(), tileentity.getBlockType().getStateFromMeta(tileentity.getBlockMetadata()), getBlockState(tileentity.getPos())))
|
|
+ invalidList.add(tileentity);
|
|
tileentity.updateContainingBlockInfo();
|
|
}
|
|
+
|
|
+ for (TileEntity te : invalidList) te.invalidate();
|
|
}
|
|
|
|
public Biome getBiome(BlockPos pos, BiomeProvider provider)
|
|
@@ -1190,7 +1450,13 @@
|
|
|
|
if (k == 255)
|
|
{
|
|
- Biome biome = provider.getBiome(pos, Biomes.PLAINS);
|
|
+ // Forge: checking for client ensures that biomes are only generated on integrated server
|
|
+ // in singleplayer. Generating biomes on the client may corrupt the biome ID arrays on
|
|
+ // the server while they are being generated because IntCache can't be thread safe,
|
|
+ // so client and server may end up filling the same array.
|
|
+ // This is not necessary in 1.13 and newer versions.
|
|
+ Biome biome = world.isRemote ? Biomes.PLAINS : provider.getBiome(pos, Biomes.PLAINS);
|
|
+
|
|
k = Biome.getIdForBiome(biome);
|
|
this.blockBiomeArray[j << 4 | i] = (byte)(k & 255);
|
|
}
|
|
@@ -1244,13 +1510,13 @@
|
|
BlockPos blockpos1 = blockpos.add(k, (j << 4) + i1, l);
|
|
boolean flag = i1 == 0 || i1 == 15 || k == 0 || k == 15 || l == 0 || l == 15;
|
|
|
|
- if (this.storageArrays[j] == NULL_BLOCK_STORAGE && flag || this.storageArrays[j] != NULL_BLOCK_STORAGE && this.storageArrays[j].get(k, i1, l).getMaterial() == Material.AIR)
|
|
+ if (this.storageArrays[j] == NULL_BLOCK_STORAGE && flag || this.storageArrays[j] != NULL_BLOCK_STORAGE && this.storageArrays[j].get(k, i1, l).getBlock().isAir(this.storageArrays[j].get(k, i1, l), this.world, blockpos1))
|
|
{
|
|
for (EnumFacing enumfacing : EnumFacing.values())
|
|
{
|
|
BlockPos blockpos2 = blockpos1.offset(enumfacing);
|
|
|
|
- if (this.world.getBlockState(blockpos2).getLightValue() > 0)
|
|
+ if (this.world.getBlockState(blockpos2).getLightValue(this.world, blockpos2) > 0)
|
|
{
|
|
this.world.checkLight(blockpos2);
|
|
}
|
|
@@ -1381,7 +1647,7 @@
|
|
{
|
|
blockpos$mutableblockpos.setPos(blockpos$mutableblockpos.getX(), l, blockpos$mutableblockpos.getZ());
|
|
|
|
- if (this.getBlockState(blockpos$mutableblockpos).getLightValue() > 0)
|
|
+ if (this.getBlockState(blockpos$mutableblockpos).getLightValue(this.world, blockpos$mutableblockpos) > 0)
|
|
{
|
|
this.world.checkLight(blockpos$mutableblockpos);
|
|
}
|
|
@@ -1420,6 +1686,7 @@
|
|
else
|
|
{
|
|
System.arraycopy(newHeightMap, 0, this.heightMap, 0, this.heightMap.length);
|
|
+ this.heightMapMinimum = com.google.common.primitives.Ints.min(this.heightMap); // Forge: fix MC-117412
|
|
}
|
|
}
|
|
|
|
@@ -1489,4 +1756,61 @@
|
|
QUEUED,
|
|
CHECK;
|
|
}
|
|
+
|
|
+ /* ======================================== FORGE START =====================================*/
|
|
+ /**
|
|
+ * Removes the tile entity at the specified position, only if it's
|
|
+ * marked as invalid.
|
|
+ */
|
|
+ public void removeInvalidTileEntity(BlockPos pos)
|
|
+ {
|
|
+ if (loaded)
|
|
+ {
|
|
+ TileEntity entity = (TileEntity)tileEntities.get(pos);
|
|
+ if (entity != null && entity.isInvalid())
|
|
+ {
|
|
+ tileEntities.remove(pos);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static ChunkPos populating = null; // keep track of cascading chunk generation during chunk population
|
|
+
|
|
+ private void logCascadingWorldGeneration()
|
|
+ {
|
|
+ net.minecraftforge.fml.common.ModContainer activeModContainer = net.minecraftforge.fml.common.Loader.instance().activeModContainer();
|
|
+ String format = "{} loaded a new chunk {} in dimension {} ({}) while populating chunk {}, causing cascading worldgen lag.";
|
|
+
|
|
+ if (activeModContainer == null) { // vanilla minecraft has problems too (MC-114332), log it at a quieter level.
|
|
+ net.minecraftforge.fml.common.FMLLog.log.debug(format, "Minecraft", this.getPos(), this.world.provider.getDimension(), this.world.provider.getDimensionType().getName(), populating);
|
|
+ net.minecraftforge.fml.common.FMLLog.log.debug("Consider setting 'fixVanillaCascading' to 'true' in the Forge config to fix many cases where this occurs in the base game.");
|
|
+ } else {
|
|
+ net.minecraftforge.fml.common.FMLLog.log.warn(format, activeModContainer.getName(), this.getPos(), this.world.provider.getDimension(), this.world.provider.getDimensionType().getName(), populating);
|
|
+ net.minecraftforge.fml.common.FMLLog.log.warn("Please report this to the mod's issue tracker. This log can be disabled in the Forge config.");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private final net.minecraftforge.common.capabilities.CapabilityDispatcher capabilities;
|
|
+ @Nullable
|
|
+ public net.minecraftforge.common.capabilities.CapabilityDispatcher getCapabilities()
|
|
+ {
|
|
+ return 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);
|
|
+ }
|
|
+
|
|
+ // CatServer start
|
|
+ public List<Entity>[] getEntityLists_UnsafeList() {
|
|
+ return catserver.server.utils.UnsafeListEntityImpl.getUnsafeListEntityImpl(entityLists);
|
|
+ }
|
|
+ // CatServer end
|
|
}
|