== AT ==
public net.minecraft.server.level.ServerChunkCache mainThread
public net.minecraft.server.level.ServerLevel chunkSource
public org.bukkit.craftbukkit.inventory.CraftItemStack handle
public net.minecraft.server.level.ChunkMap getVisibleChunkIfPresent(J)Lnet/minecraft/server/level/ChunkHolder;
public net.minecraft.server.level.ServerChunkCache mainThreadProcessor
public net.minecraft.server.level.ServerChunkCache$MainThreadExecutor
public net.minecraft.world.level.chunk.LevelChunkSection states
This commit is contained in:
Aikar
2016-03-28 20:55:47 -04:00
parent a82a09d198
commit b01c811c2f
81 changed files with 6261 additions and 473 deletions

View File

@@ -1,6 +1,14 @@
--- a/net/minecraft/world/level/BlockGetter.java
+++ b/net/minecraft/world/level/BlockGetter.java
@@ -31,7 +31,7 @@
@@ -12,6 +12,7 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
+import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
@@ -31,10 +32,19 @@
default <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos pos, BlockEntityType<T> type) {
BlockEntity tileentity = this.getBlockEntity(pos);
@@ -9,7 +17,19 @@
}
BlockState getBlockState(BlockPos pos);
@@ -59,8 +59,8 @@
+ // Paper start - if loaded util
+ @Nullable BlockState getBlockStateIfLoaded(BlockPos blockposition);
+
+ default @Nullable Block getBlockIfLoaded(BlockPos blockposition) {
+ BlockState type = this.getBlockStateIfLoaded(blockposition);
+ return type == null ? null : type.getBlock();
+ }
+ @Nullable FluidState getFluidIfLoaded(BlockPos blockposition);
+ // Paper end
FluidState getFluidState(BlockPos pos);
@@ -59,8 +69,8 @@
});
}
@@ -20,7 +40,7 @@
BlockState iblockdata = this.getBlockState(blockposition);
FluidState fluid = this.getFluidState(blockposition);
Vec3 vec3d = raytrace1.getFrom();
@@ -73,6 +73,12 @@
@@ -73,6 +83,12 @@
double d1 = movingobjectpositionblock1 == null ? Double.MAX_VALUE : raytrace1.getFrom().distanceToSqr(movingobjectpositionblock1.getLocation());
return d0 <= d1 ? movingobjectpositionblock : movingobjectpositionblock1;
@@ -33,7 +53,7 @@
}, (raytrace1) -> {
Vec3 vec3d = raytrace1.getFrom().subtract(raytrace1.getTo());
@@ -145,7 +151,7 @@
@@ -145,7 +161,7 @@
double d13 = d10 * (i1 > 0 ? 1.0D - Mth.frac(d4) : Mth.frac(d4));
double d14 = d11 * (j1 > 0 ? 1.0D - Mth.frac(d5) : Mth.frac(d5));

View File

@@ -0,0 +1,39 @@
--- a/net/minecraft/world/level/ChunkPos.java
+++ b/net/minecraft/world/level/ChunkPos.java
@@ -46,6 +46,7 @@
public static final int REGION_MAX_INDEX = 31;
public final int x;
public final int z;
+ public final long longKey; // Paper
private static final int HASH_A = 1664525;
private static final int HASH_C = 1013904223;
private static final int HASH_Z_XOR = -559038737;
@@ -53,16 +54,19 @@
public ChunkPos(int x, int z) {
this.x = x;
this.z = z;
+ this.longKey = asLong(this.x, this.z); // Paper
}
public ChunkPos(BlockPos pos) {
this.x = SectionPos.blockToSectionCoord(pos.getX());
this.z = SectionPos.blockToSectionCoord(pos.getZ());
+ this.longKey = asLong(this.x, this.z); // Paper
}
public ChunkPos(long pos) {
this.x = (int)pos;
this.z = (int)(pos >> 32);
+ this.longKey = asLong(this.x, this.z); // Paper
}
public static ChunkPos minFromRegion(int x, int z) {
@@ -74,7 +78,7 @@
}
public long toLong() {
- return asLong(this.x, this.z);
+ return longKey; // Paper
}
public static long asLong(int chunkX, int chunkZ) {

View File

@@ -0,0 +1,22 @@
--- a/net/minecraft/world/level/EmptyBlockGetter.java
+++ b/net/minecraft/world/level/EmptyBlockGetter.java
@@ -17,7 +17,19 @@
return null;
}
+ // Paper start - If loaded util
@Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ return Fluids.EMPTY.defaultFluidState();
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ return Blocks.AIR.defaultBlockState();
+ }
+ // Paper end
+
+ @Override
public BlockState getBlockState(BlockPos pos) {
return Blocks.AIR.defaultBlockState();
}

View File

@@ -31,7 +31,7 @@
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.level.entity.LevelEntityGetter;
import net.minecraft.world.level.gameevent.GameEvent;
@@ -81,6 +85,25 @@
@@ -81,6 +85,26 @@
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Scoreboard;
@@ -48,6 +48,7 @@
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.SpigotTimings; // Spigot
+import org.bukkit.craftbukkit.block.CapturedBlockState;
+import org.bukkit.craftbukkit.block.CraftBlockState;
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
+import org.bukkit.craftbukkit.util.CraftSpawnCategory;
+import org.bukkit.entity.SpawnCategory;
@@ -57,7 +58,7 @@
public abstract class Level implements LevelAccessor, AutoCloseable {
public static final Codec<ResourceKey<Level>> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION);
@@ -121,23 +144,73 @@
@@ -121,23 +145,73 @@
private final DamageSources damageSources;
private long subTickCount;
@@ -140,7 +141,7 @@
}
};
} else {
@@ -145,11 +218,50 @@
@@ -145,11 +219,50 @@
}
this.thread = Thread.currentThread();
@@ -196,7 +197,77 @@
}
@Override
@@ -207,6 +319,18 @@
@@ -163,6 +276,13 @@
return null;
}
+ // Paper start
+ public net.minecraft.world.phys.BlockHitResult.Type clipDirect(Vec3 start, Vec3 end, net.minecraft.world.phys.shapes.CollisionContext context) {
+ // To be patched over
+ return this.clip(new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, context)).getType();
+ }
+ // Paper end
+
public boolean isInWorldBounds(BlockPos pos) {
return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos);
}
@@ -179,18 +299,52 @@
return y < -20000000 || y >= 20000000;
}
- public LevelChunk getChunkAt(BlockPos pos) {
+ public final LevelChunk getChunkAt(BlockPos pos) { // Paper - help inline
return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()));
}
@Override
- public LevelChunk getChunk(int chunkX, int chunkZ) {
- return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL);
+ public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline
+ return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump
}
+ // Paper start - if loaded
@Nullable
@Override
+ public final ChunkAccess getChunkIfLoadedImmediately(int x, int z) {
+ return ((ServerLevel)this).chunkSource.getChunkAtIfLoadedImmediately(x, z);
+ }
+
+ @Override
+ @Nullable
+ public final BlockState getBlockStateIfLoaded(BlockPos pos) {
+ // CraftBukkit start - tree generation
+ if (this.captureTreeGeneration) {
+ CraftBlockState previous = this.capturedBlockStates.get(pos);
+ if (previous != null) {
+ return previous.getHandle();
+ }
+ }
+ // CraftBukkit end
+ if (this.isOutsideBuildHeight(pos)) {
+ return Blocks.VOID_AIR.defaultBlockState();
+ } else {
+ ChunkAccess chunk = this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);
+
+ return chunk == null ? null : chunk.getBlockState(pos);
+ }
+ }
+
+ @Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ ChunkAccess chunk = this.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+
+ return chunk == null ? null : chunk.getFluidState(blockposition);
+ }
+
+ @Override
public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) {
+ // Paper end
ChunkAccess ichunkaccess = this.getChunkSource().getChunk(chunkX, chunkZ, leastStatus, create);
if (ichunkaccess == null && create) {
@@ -207,6 +361,18 @@
@Override
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
@@ -215,7 +286,7 @@
if (this.isOutsideBuildHeight(pos)) {
return false;
} else if (!this.isClientSide && this.isDebug()) {
@@ -214,45 +338,124 @@
@@ -214,44 +380,123 @@
} else {
LevelChunk chunk = this.getChunkAt(pos);
Block block = state.getBlock();
@@ -299,10 +370,10 @@
+ // CraftBukkit end
+
return true;
}
}
}
+ }
+ }
+ }
+
+ // CraftBukkit start - Split off from above in order to directly send client and physic updates
+ public void notifyAndUpdatePhysics(BlockPos blockposition, LevelChunk chunk, BlockState oldBlock, BlockState newBlock, BlockState actualBlock, int i, int j) {
+ BlockState iblockdata = newBlock;
@@ -322,7 +393,7 @@
+ if (!this.isClientSide && iblockdata.hasAnalogOutputSignal()) {
+ this.updateNeighbourForOutputSignal(blockposition, newBlock.getBlock());
+ }
+ }
}
+
+ if ((i & 16) == 0 && j > 0) {
+ int k = i & -34;
@@ -348,14 +419,13 @@
+ this.onBlockStateChange(blockposition, iblockdata1, iblockdata2);
+ }
+ // CraftBukkit end
+ }
+ }
}
}
+ // CraftBukkit end
+
public void onBlockStateChange(BlockPos pos, BlockState oldBlock, BlockState newBlock) {}
@Override
@@ -340,6 +543,14 @@
@@ -340,10 +585,18 @@
@Override
public BlockState getBlockState(BlockPos pos) {
@@ -370,7 +440,12 @@
if (this.isOutsideBuildHeight(pos)) {
return Blocks.VOID_AIR.defaultBlockState();
} else {
@@ -440,32 +651,48 @@
- LevelChunk chunk = this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()));
+ ChunkAccess chunk = this.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, true); // Paper - manually inline to reduce hops and avoid unnecessary null check to reduce total byte code size, this should never return null and if it does we will see it the next line but the real stack trace will matter in the chunk engine
return chunk.getBlockState(pos);
}
@@ -440,32 +693,48 @@
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("blockEntities");
@@ -423,7 +498,7 @@
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked");
@@ -510,13 +737,29 @@
@@ -510,13 +779,29 @@
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos) {
@@ -454,7 +529,7 @@
this.getChunkAt(blockposition).addAndRegisterBlockEntity(blockEntity);
}
}
@@ -643,7 +886,7 @@
@@ -643,7 +928,7 @@
for (int k = 0; k < j; ++k) {
EnderDragonPart entitycomplexpart = aentitycomplexpart[k];
@@ -463,7 +538,7 @@
if (t0 != null && predicate.test(t0)) {
result.add(t0);
@@ -912,7 +1155,7 @@
@@ -912,7 +1197,7 @@
public static enum ExplosionInteraction implements StringRepresentable {

View File

@@ -0,0 +1,12 @@
--- a/net/minecraft/world/level/LevelReader.java
+++ b/net/minecraft/world/level/LevelReader.java
@@ -26,6 +26,9 @@
@Nullable
ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create);
+ @Nullable ChunkAccess getChunkIfLoadedImmediately(int x, int z); // Paper - ifLoaded api (we need this since current impl blocks if the chunk is loading)
+ @Nullable default ChunkAccess getChunkIfLoadedImmediately(BlockPos pos) { return this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);}
+
@Deprecated
boolean hasChunk(int chunkX, int chunkZ);

View File

@@ -0,0 +1,51 @@
--- a/net/minecraft/world/level/PathNavigationRegion.java
+++ b/net/minecraft/world/level/PathNavigationRegion.java
@@ -8,6 +8,7 @@
import net.minecraft.core.Holder;
import net.minecraft.core.SectionPos;
import net.minecraft.core.registries.Registries;
+import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
@@ -66,7 +67,7 @@
private ChunkAccess getChunk(int chunkX, int chunkZ) {
int i = chunkX - this.centerX;
int j = chunkZ - this.centerZ;
- if (i >= 0 && i < this.chunks.length && j >= 0 && j < this.chunks[i].length) {
+ if (i >= 0 && i < this.chunks.length && j >= 0 && j < this.chunks[i].length) { // Paper - if this changes, update getChunkIfLoaded below
ChunkAccess chunkAccess = this.chunks[i][j];
return (ChunkAccess)(chunkAccess != null ? chunkAccess : new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), this.plains.get()));
} else {
@@ -74,7 +75,31 @@
}
}
+ // Paper start - if loaded util
+ private @Nullable ChunkAccess getChunkIfLoaded(int x, int z) {
+ // Based on getChunk(int, int)
+ int xx = x - this.centerX;
+ int zz = z - this.centerZ;
+
+ if (xx >= 0 && xx < this.chunks.length && zz >= 0 && zz < this.chunks[xx].length) {
+ return this.chunks[xx][zz];
+ }
+ return null;
+ }
@Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ ChunkAccess chunk = getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ return chunk == null ? null : chunk.getFluidState(blockposition);
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ ChunkAccess chunk = getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ return chunk == null ? null : chunk.getBlockState(blockposition);
+ }
+ // Paper end
+
+ @Override
public WorldBorder getWorldBorder() {
return this.level.getWorldBorder();
}

View File

@@ -50,7 +50,33 @@
}
state.spawnAfterBreak(world, pos, ItemStack.EMPTY, flag);
@@ -1125,9 +1139,15 @@
@@ -873,12 +887,14 @@
}
}
+ protected boolean shapeExceedsCube = true; // Paper - moved from actual method to here
public void initCache() {
this.fluidState = ((Block) this.owner).getFluidState(this.asState());
this.isRandomlyTicking = ((Block) this.owner).isRandomlyTicking(this.asState());
if (!this.getBlock().hasDynamicShape()) {
this.cache = new BlockBehaviour.BlockStateBase.Cache(this.asState());
}
+ this.shapeExceedsCube = this.cache == null || this.cache.largeCollisionShape; // Paper - moved from actual method to here
this.legacySolid = this.calculateSolid();
this.occlusionShape = this.canOcclude ? ((Block) this.owner).getOcclusionShape(this.asState()) : Shapes.empty();
@@ -945,8 +961,8 @@
return this.occlusionShape;
}
- public boolean hasLargeCollisionShape() {
- return this.cache == null || this.cache.largeCollisionShape;
+ public final boolean hasLargeCollisionShape() { // Paper
+ return this.shapeExceedsCube; // Paper - moved into shape cache init
}
public boolean useShapeForLightOcclusion() {
@@ -1125,9 +1141,15 @@
}
public void onPlace(Level world, BlockPos pos, BlockState state, boolean notify) {

View File

@@ -1,6 +1,15 @@
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -85,6 +85,11 @@
@@ -65,7 +65,7 @@
protected final ShortList[] postProcessing;
private volatile boolean unsaved;
private volatile boolean isLightCorrect;
- protected final ChunkPos chunkPos;
+ protected final ChunkPos chunkPos; public final long coordinateKey; public final int locX; public final int locZ; // Paper - cache coordinate key
private long inhabitedTime;
/** @deprecated */
@Nullable
@@ -85,8 +85,14 @@
protected final LevelHeightAccessor levelHeightAccessor;
protected final LevelChunkSection[] sections;
@@ -10,9 +19,13 @@
+ // CraftBukkit end
+
public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry<Biome> biomeRegistry, long inhabitedTime, @Nullable LevelChunkSection[] sectionArray, @Nullable BlendingData blendingData) {
this.chunkPos = pos;
- this.chunkPos = pos;
+ this.locX = pos.x; this.locZ = pos.z; // Paper - reduce need for field lookups
+ this.chunkPos = pos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key
this.upgradeData = upgradeData;
@@ -103,7 +108,11 @@
this.levelHeightAccessor = heightLimitView;
this.sections = new LevelChunkSection[heightLimitView.getSectionsCount()];
@@ -103,7 +109,11 @@
}
ChunkAccess.replaceMissingSections(biomeRegistry, this.sections);
@@ -24,7 +37,7 @@
private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sectionArray) {
for (int i = 0; i < sectionArray.length; ++i) {
@@ -275,6 +284,7 @@
@@ -275,6 +285,7 @@
public boolean tryMarkSaved() {
if (this.unsaved) {
this.unsaved = false;
@@ -32,7 +45,7 @@
return true;
} else {
return false;
@@ -282,7 +292,7 @@
@@ -282,7 +293,7 @@
}
public boolean isUnsaved() {
@@ -41,10 +54,15 @@
}
public abstract ChunkStatus getPersistedStatus();
@@ -463,6 +473,27 @@
}
}
@@ -458,10 +469,31 @@
crashreportsystemdetails.setDetail("Location", () -> {
return CrashReportCategory.formatLocation(this, biomeX, biomeY, biomeZ);
+ });
+ throw new ReportedException(crashreport);
+ }
+ }
+
+ // CraftBukkit start
+ public void setBiome(int i, int j, int k, Holder<Biome> biome) {
+ try {
@@ -60,12 +78,11 @@
+
+ crashreportsystemdetails.setDetail("Location", () -> {
+ return CrashReportCategory.formatLocation(this, i, j, k);
+ });
+ throw new ReportedException(crashreport);
+ }
+ }
});
throw new ReportedException(crashreport);
}
}
+ // CraftBukkit end
+
public void fillBiomesFromNoise(BiomeResolver biomeSupplier, Climate.Sampler sampler) {
ChunkPos chunkcoordintpair = this.getPos();
int i = QuartPos.fromBlock(chunkcoordintpair.getMinBlockX());

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/level/chunk/EmptyLevelChunk.java
+++ b/net/minecraft/world/level/chunk/EmptyLevelChunk.java
@@ -25,6 +25,12 @@
public BlockState getBlockState(BlockPos pos) {
return Blocks.VOID_AIR.defaultBlockState();
}
+ // Paper start
+ @Override
+ public BlockState getBlockState(final int x, final int y, final int z) {
+ return Blocks.VOID_AIR.defaultBlockState();
+ }
+ // Paper end
@Nullable
@Override

View File

@@ -18,7 +18,7 @@
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap();
Heightmap.Types[] aheightmap_type = Heightmap.Types.values();
int j = aheightmap_type.length;
@@ -116,6 +116,11 @@
@@ -116,6 +116,15 @@
this.fluidTicks = fluidTickScheduler;
}
@@ -26,11 +26,15 @@
+ public boolean mustNotSave;
+ public boolean needsDecoration;
+ // CraftBukkit end
+
+ // Paper start
+ boolean loadedTicketLevel;
+ // Paper end
+
public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) {
this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), entityLoader, protoChunk.getBlendingData());
if (!Collections.disjoint(protoChunk.pendingBlockEntities.keySet(), protoChunk.blockEntities.keySet())) {
@@ -151,6 +156,10 @@
@@ -151,6 +160,10 @@
this.skyLightSources = protoChunk.skyLightSources;
this.setLightCorrect(protoChunk.isLightCorrect());
this.markUnsaved();
@@ -41,7 +45,53 @@
}
public void setUnsavedListener(LevelChunk.UnsavedListener unsavedListener) {
@@ -272,78 +281,86 @@
@@ -200,8 +213,25 @@
}
}
+ // Paper start - Perf: Reduce instructions and provide final method
+ public BlockState getBlockState(final int x, final int y, final int z) {
+ return this.getBlockStateFinal(x, y, z);
+ }
+ public BlockState getBlockStateFinal(final int x, final int y, final int z) {
+ // Copied and modified from below
+ final int sectionIndex = this.getSectionIndex(y);
+ if (sectionIndex < 0 || sectionIndex >= this.sections.length
+ || this.sections[sectionIndex].nonEmptyBlockCount == 0) {
+ return Blocks.AIR.defaultBlockState();
+ }
+ return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
+ }
@Override
public BlockState getBlockState(BlockPos pos) {
+ if (true) {
+ return this.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
+ }
+ // Paper end - Perf: Reduce instructions and provide final method
int i = pos.getX();
int j = pos.getY();
int k = pos.getZ();
@@ -243,7 +273,19 @@
}
}
+ // Paper start - If loaded util
@Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ return this.getFluidState(blockposition);
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ return this.getBlockState(blockposition);
+ }
+ // Paper end
+
+ @Override
public FluidState getFluidState(BlockPos pos) {
return this.getFluidState(pos.getX(), pos.getY(), pos.getZ());
}
@@ -272,78 +314,86 @@
}
}
@@ -153,7 +203,7 @@
this.updateBlockEntityTicker(tileentity);
}
}
@@ -375,7 +392,12 @@
@@ -375,7 +425,12 @@
@Nullable
public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) {
@@ -167,7 +217,7 @@
if (tileentity == null) {
CompoundTag nbttagcompound = (CompoundTag) this.pendingBlockEntities.remove(pos);
@@ -447,6 +469,7 @@
@@ -447,6 +502,7 @@
if (!iblockdata.hasBlockEntity()) {
LevelChunk.LOGGER.warn("Trying to set block entity {} at position {}, but state {} does not allow it", new Object[]{blockEntity, blockposition, iblockdata});
@@ -175,7 +225,7 @@
} else {
BlockState iblockdata1 = blockEntity.getBlockState();
@@ -500,6 +523,12 @@
@@ -500,6 +556,12 @@
if (this.isInLevel()) {
BlockEntity tileentity = (BlockEntity) this.blockEntities.remove(pos);
@@ -188,7 +238,7 @@
if (tileentity != null) {
Level world = this.level;
@@ -549,10 +578,61 @@
@@ -549,9 +611,68 @@
if (this.postLoad != null) {
this.postLoad.run(this);
this.postLoad = null;
@@ -198,7 +248,11 @@
+
+ // CraftBukkit start
+ public void loadCallback() {
+ // Paper start
+ this.loadedTicketLevel = true;
+ // Paper end
+ org.bukkit.Server server = this.level.getCraftServer();
+ this.level.getChunkSource().addLoadedChunk(this); // Paper
+ if (server != null) {
+ /*
+ * If it's a new world, the first few chunks are generated inside
@@ -239,18 +293,21 @@
+ server.getPluginManager().callEvent(unloadEvent);
+ // note: saving can be prevented, but not forced if no saving is actually required
+ this.mustNotSave = !unloadEvent.isSaveChunk();
}
+ this.level.getChunkSource().removeLoadedChunk(this); // Paper
+ // Paper start
+ this.loadedTicketLevel = false;
+ // Paper end
+ }
+
+ @Override
+ public boolean isUnsaved() {
+ return super.isUnsaved() && !this.mustNotSave;
+ }
}
+ // CraftBukkit end
+
public boolean isEmpty() {
return false;
}
@@ -750,7 +830,7 @@
@@ -750,7 +871,7 @@
private <T extends BlockEntity> void updateBlockEntityTicker(T blockEntity) {
BlockState iblockdata = blockEntity.getBlockState();
@@ -259,7 +316,7 @@
if (blockentityticker == null) {
this.removeBlockEntityTicker(blockEntity.getBlockPos());
@@ -841,7 +921,7 @@
@@ -841,7 +962,7 @@
private boolean loggedInvalidBlockState;
BoundTickingBlockEntity(final BlockEntity tileentity, final BlockEntityTicker blockentityticker) {
@@ -268,7 +325,7 @@
this.ticker = blockentityticker;
}
@@ -855,6 +935,7 @@
@@ -855,6 +976,7 @@
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push(this::getType);
@@ -276,7 +333,7 @@
BlockState iblockdata = LevelChunk.this.getBlockState(blockposition);
if (this.blockEntity.getType().isValid(iblockdata)) {
@@ -872,6 +953,10 @@
@@ -872,6 +994,10 @@
this.blockEntity.fillCrashReportCategory(crashreportsystemdetails);
throw new ReportedException(crashreport);

View File

@@ -1,6 +1,11 @@
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -23,7 +23,7 @@
@@ -19,11 +19,11 @@
public static final int SECTION_HEIGHT = 16;
public static final int SECTION_SIZE = 4096;
public static final int BIOME_CONTAINER_BITS = 2;
- private short nonEmptyBlockCount;
+ short nonEmptyBlockCount; // Paper - package private
private short tickingBlockCount;
private short tickingFluidCount;
public final PalettedContainer<BlockState> states;

View File

@@ -0,0 +1,22 @@
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
@@ -81,7 +81,19 @@
@Override
public ChunkAccess.PackedTicks getTicksForSerialization(long time) {
return new ChunkAccess.PackedTicks(this.blockTicks.pack(time), this.fluidTicks.pack(time));
+ }
+
+ // Paper start - If loaded util
+ @Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ return this.getFluidState(blockposition);
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ return this.getBlockState(blockposition);
}
+ // Paper end
@Override
public BlockState getBlockState(BlockPos pos) {

View File

@@ -18,9 +18,12 @@
ChunkStatusTasks.postLoadProtoChunk(worldserver, protochunk.getEntities());
});
generationchunkholder.replaceProtoChunk(new ImposterProtoChunk(chunk1, false));
@@ -170,7 +170,17 @@
@@ -168,9 +168,19 @@
}, context.mainThreadExecutor());
}
private static void postLoadProtoChunk(ServerLevel world, List<CompoundTag> entities) {
- private static void postLoadProtoChunk(ServerLevel world, List<CompoundTag> entities) {
+ public static void postLoadProtoChunk(ServerLevel world, List<CompoundTag> entities) { // Paper - public
if (!entities.isEmpty()) {
- world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entities, world, EntitySpawnReason.LOAD));
+ // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities

View File

@@ -32,7 +32,24 @@
void removeSectionIfEmpty(long sectionPos, EntitySection<T> section) {
if (section.isEmpty()) {
this.sectionStorage.remove(sectionPos);
@@ -196,27 +211,35 @@
@@ -76,6 +91,16 @@
}
private boolean addEntity(T entity, boolean existing) {
+ // Paper start - chunk system hooks
+ // I don't want to know why this is a generic type.
+ Entity entityCasted = (Entity)entity;
+ boolean wasRemoved = entityCasted.isRemoved();
+ boolean screened = ca.spottedleaf.moonrise.common.util.ChunkSystem.screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, existing, true);
+ if ((!wasRemoved && entityCasted.isRemoved()) || !screened) {
+ // removed by callback
+ return false;
+ }
+ // Paper end - chunk system hooks
if (!this.addEntityUuid(entity)) {
return false;
} else {
@@ -196,27 +221,35 @@
}
private boolean storeChunkSections(long chunkPos, Consumer<T> action) {
@@ -74,7 +91,7 @@
return true;
}
}
@@ -238,7 +261,7 @@
@@ -238,7 +271,7 @@
private boolean processChunkUnload(long chunkPos) {
boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> {
entityaccess.getPassengersAndSelf().forEach(this::unloadEntity);
@@ -83,7 +100,7 @@
if (!flag) {
return false;
@@ -249,24 +272,28 @@
@@ -249,24 +282,28 @@
}
private void unloadEntity(EntityAccess entity) {
@@ -115,7 +132,7 @@
}
}
@@ -292,7 +319,7 @@
@@ -292,7 +329,7 @@
}
public void autoSave() {
@@ -124,7 +141,7 @@
boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN;
if (flag) {
@@ -311,7 +338,7 @@
@@ -311,7 +348,7 @@
while (!longset.isEmpty()) {
this.permanentStorage.flush(false);
this.processPendingLoads();
@@ -133,7 +150,7 @@
boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN;
return flag ? this.processChunkUnload(i) : this.storeChunkSections(i, (entityaccess) -> {
@@ -323,7 +350,15 @@
@@ -323,7 +360,15 @@
}
public void close() throws IOException {
@@ -150,7 +167,7 @@
this.permanentStorage.close();
}
@@ -350,7 +385,7 @@
@@ -350,7 +395,7 @@
public void dumpSections(Writer writer) throws IOException {
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("visibility").addColumn("load_status").addColumn("entity_count").build(writer);
@@ -159,7 +176,7 @@
PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(i);
this.sectionStorage.getExistingSectionPositionsInChunk(i).forEach((j) -> {
@@ -394,7 +429,7 @@
@@ -394,7 +439,7 @@
private EntitySection<T> currentSection;
Callback(final EntityAccess entityaccess, final long i, final EntitySection entitysection) {