1.21.5
Co-authored-by: Bjarne Koll <git@lynxplay.dev> Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com> Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Co-authored-by: MiniDigger | Martin <admin@minidigger.dev> Co-authored-by: Nassim Jahnke <nassim@njahnke.dev> Co-authored-by: Noah van der Aa <ndvdaa@gmail.com> Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Co-authored-by: Shane Freeder <theboyetronic@gmail.com> Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com> Co-authored-by: Tamion <70228790+notTamion@users.noreply.github.com> Co-authored-by: Warrior <50800980+Warriorrrr@users.noreply.github.com>
This commit is contained in:
@@ -39,15 +39,16 @@
|
||||
}
|
||||
|
||||
private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) {
|
||||
@@ -123,6 +_,7 @@
|
||||
@@ -123,6 +_,8 @@
|
||||
return GameEventListenerRegistry.NOOP;
|
||||
}
|
||||
|
||||
+ public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper
|
||||
+
|
||||
@Nullable
|
||||
public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving);
|
||||
|
||||
@@ -273,6 +_,7 @@
|
||||
public BlockState setBlockState(BlockPos pos, BlockState state) {
|
||||
return this.setBlockState(pos, state, 3);
|
||||
@@ -278,6 +_,7 @@
|
||||
public boolean tryMarkSaved() {
|
||||
if (this.unsaved) {
|
||||
this.unsaved = false;
|
||||
@@ -55,7 +56,7 @@
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -280,7 +_,7 @@
|
||||
@@ -285,7 +_,7 @@
|
||||
}
|
||||
|
||||
public boolean isUnsaved() {
|
||||
@@ -64,7 +65,7 @@
|
||||
}
|
||||
|
||||
public abstract ChunkStatus getPersistedStatus();
|
||||
@@ -446,6 +_,22 @@
|
||||
@@ -451,6 +_,22 @@
|
||||
throw new ReportedException(crashReport);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
) {
|
||||
+ // Paper start - StructuresLocateEvent
|
||||
+ final org.bukkit.World bukkitWorld = level.getWorld();
|
||||
+ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(level, pos);
|
||||
+ final org.bukkit.Location origin = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level);
|
||||
+ final List<org.bukkit.generator.structure.Structure> apiStructures = structure.stream().map(Holder::value).map(nms -> org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(nms)).toList();
|
||||
+ if (!apiStructures.isEmpty()) {
|
||||
+ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, searchRadius, skipKnownStructures);
|
||||
@@ -27,7 +27,7 @@
|
||||
+ if (event.getResult() != null) {
|
||||
+ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), level.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(event.getResult().structure())));
|
||||
+ }
|
||||
+ pos = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin());
|
||||
+ pos = org.bukkit.craftbukkit.util.CraftLocation.toBlockPosition(event.getOrigin());
|
||||
+ searchRadius = event.getRadius();
|
||||
+ skipKnownStructures = event.shouldFindUnexplored();
|
||||
+ structure = HolderSet.direct(api -> level.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(api)), event.getStructures());
|
||||
@@ -36,7 +36,7 @@
|
||||
ChunkGeneratorStructureState generatorState = level.getChunkSource().getGeneratorState();
|
||||
Map<StructurePlacement, Set<Holder<Structure>>> map = new Object2ObjectArrayMap<>();
|
||||
|
||||
@@ -222,6 +_,7 @@
|
||||
@@ -221,6 +_,7 @@
|
||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
|
||||
for (ChunkPos chunkPos : ringPositionsFor) {
|
||||
@@ -44,7 +44,7 @@
|
||||
mutableBlockPos.set(SectionPos.sectionToBlockCoord(chunkPos.x, 8), 32, SectionPos.sectionToBlockCoord(chunkPos.z, 8));
|
||||
double d1 = mutableBlockPos.distSqr(pos);
|
||||
boolean flag = pair == null || d1 < d;
|
||||
@@ -255,11 +_,15 @@
|
||||
@@ -254,11 +_,15 @@
|
||||
int spacing = spreadPlacement.spacing();
|
||||
|
||||
for (int i = -z; i <= z; i++) {
|
||||
@@ -64,7 +64,7 @@
|
||||
int i2 = x + spacing * i;
|
||||
int i3 = y + spacing * i1;
|
||||
ChunkPos potentialStructureChunk = spreadPlacement.getPotentialStructureChunk(seed, i2, i3);
|
||||
@@ -312,7 +_,7 @@
|
||||
@@ -311,7 +_,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
ChunkPos pos = chunk.getPos();
|
||||
if (!SharedConstants.debugVoidTerrain(pos)) {
|
||||
SectionPos sectionPos = SectionPos.of(pos, level.getMinSectionY());
|
||||
@@ -385,7 +_,14 @@
|
||||
@@ -382,7 +_,14 @@
|
||||
int i3 = ints[i2];
|
||||
PlacedFeature placedFeature = stepFeatureData1.features().get(i3);
|
||||
Supplier<String> supplier1 = () -> registry1.getResourceKey(placedFeature).map(Object::toString).orElseGet(placedFeature::toString);
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
try {
|
||||
level.setCurrentlyGenerating(supplier1);
|
||||
@@ -407,6 +_,32 @@
|
||||
@@ -404,6 +_,32 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
private static BoundingBox getWritableArea(ChunkAccess chunk) {
|
||||
ChunkPos pos = chunk.getPos();
|
||||
@@ -483,7 +_,7 @@
|
||||
@@ -478,7 +_,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
if (list.size() == 1) {
|
||||
this.tryGenerateStructure(
|
||||
list.get(0),
|
||||
@@ -577,6 +_,14 @@
|
||||
@@ -572,6 +_,14 @@
|
||||
predicate
|
||||
);
|
||||
if (structureStart.isValid()) {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
--- a/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||
@@ -25,6 +_,12 @@
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
@@ -26,6 +_,13 @@
|
||||
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
|
||||
public BlockState setBlockState(BlockPos pos, BlockState state, int flags) {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
--- a/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||
@@ -56,6 +_,12 @@
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
@@ -57,6 +_,13 @@
|
||||
return this.wrapped.getBlockState(pos);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public final BlockState getBlockState(final int x, final int y, final int z) {
|
||||
+ return this.wrapped.getBlockStateFinal(x, y, z);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
+
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
return this.wrapped.getFluidState(pos);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -76,7 +_,7 @@
|
||||
@@ -77,7 +_,7 @@
|
||||
};
|
||||
private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel = Maps.newHashMap();
|
||||
public boolean loaded;
|
||||
@@ -9,7 +9,7 @@
|
||||
@Nullable
|
||||
private Supplier<FullChunkStatus> fullStatus;
|
||||
@Nullable
|
||||
@@ -85,6 +_,14 @@
|
||||
@@ -86,6 +_,14 @@
|
||||
private final LevelChunkTicks<Block> blockTicks;
|
||||
private final LevelChunkTicks<Fluid> fluidTicks;
|
||||
private LevelChunk.UnsavedListener unsavedListener = chunkPos -> {};
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
public LevelChunk(Level level, ChunkPos pos) {
|
||||
this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null);
|
||||
@@ -102,7 +_,7 @@
|
||||
@@ -103,7 +_,7 @@
|
||||
@Nullable BlendingData blendingData
|
||||
) {
|
||||
super(pos, data, level, level.registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData);
|
||||
@@ -33,7 +33,7 @@
|
||||
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
for (Heightmap.Types types : Heightmap.Types.values()) {
|
||||
@@ -154,6 +_,10 @@
|
||||
@@ -155,6 +_,10 @@
|
||||
this.skyLightSources = chunk.skyLightSources;
|
||||
this.setLightCorrect(chunk.isLightCorrect());
|
||||
this.markUnsaved();
|
||||
@@ -44,7 +44,7 @@
|
||||
}
|
||||
|
||||
public void setUnsavedListener(LevelChunk.UnsavedListener unsavedListener) {
|
||||
@@ -162,6 +_,12 @@
|
||||
@@ -163,6 +_,12 @@
|
||||
unsavedListener.setUnsaved(this.chunkPos);
|
||||
}
|
||||
}
|
||||
@@ -57,14 +57,16 @@
|
||||
|
||||
@Override
|
||||
public void markUnsaved() {
|
||||
@@ -195,8 +_,25 @@
|
||||
@@ -196,8 +_,28 @@
|
||||
: super.getListenerRegistry(sectionY);
|
||||
}
|
||||
|
||||
+ // Paper start - Perf: Reduce instructions and provide final method
|
||||
+ @Override
|
||||
+ 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);
|
||||
@@ -74,6 +76,7 @@
|
||||
+ }
|
||||
+ return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
+ if (true) {
|
||||
@@ -83,19 +86,19 @@
|
||||
int x = pos.getX();
|
||||
int y = pos.getY();
|
||||
int z = pos.getZ();
|
||||
@@ -231,33 +_,54 @@
|
||||
@@ -232,28 +_,42 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - If loaded util
|
||||
+ @Override
|
||||
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
||||
+ return this.getFluidState(blockposition);
|
||||
+ public final FluidState getFluidIfLoaded(BlockPos pos) {
|
||||
+ return this.getFluidState(pos);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
|
||||
+ return this.getBlockState(blockposition);
|
||||
+ public final BlockState getBlockStateIfLoaded(BlockPos pos) {
|
||||
+ return this.getBlockState(pos);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@@ -128,37 +131,16 @@
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving) {
|
||||
+// CraftBukkit start
|
||||
+ return this.setBlockState(pos, state, isMoving, true);
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving, boolean doPlace) {
|
||||
+ // CraftBukkit end
|
||||
int y = pos.getY();
|
||||
LevelChunkSection section = this.getSection(this.getSectionIndex(y));
|
||||
boolean hasOnlyAir = section.hasOnlyAir();
|
||||
@@ -292,7 +_,7 @@
|
||||
}
|
||||
|
||||
boolean hasBlockEntity = blockState.hasBlockEntity();
|
||||
- if (!this.level.isClientSide) {
|
||||
+ if (!this.level.isClientSide && !this.level.isBlockPlaceCancelled) { // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
||||
blockState.onRemove(this.level, pos, state, isMoving);
|
||||
} else if (!blockState.is(block) && hasBlockEntity) {
|
||||
this.removeBlockEntity(pos);
|
||||
@@ -301,7 +_,7 @@
|
||||
@@ -313,7 +_,7 @@
|
||||
if (!section.getBlockState(i, i1, i2).is(block)) {
|
||||
return null;
|
||||
} else {
|
||||
- if (!this.level.isClientSide) {
|
||||
+ if (!this.level.isClientSide && doPlace && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
|
||||
state.onPlace(this.level, pos, blockState, isMoving);
|
||||
- if (!this.level.isClientSide && (flags & 512) == 0) {
|
||||
+ if (!this.level.isClientSide && (flags & 512) == 0 && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
|
||||
state.onPlace(this.level, pos, blockState, flag1);
|
||||
}
|
||||
|
||||
@@ -355,7 +_,12 @@
|
||||
@@ -367,7 +_,12 @@
|
||||
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) {
|
||||
@@ -172,7 +154,7 @@
|
||||
if (blockEntity == null) {
|
||||
CompoundTag compoundTag = this.pendingBlockEntities.remove(pos);
|
||||
if (compoundTag != null) {
|
||||
@@ -409,7 +_,13 @@
|
||||
@@ -421,7 +_,13 @@
|
||||
BlockPos blockPos = blockEntity.getBlockPos();
|
||||
BlockState blockState = this.getBlockState(blockPos);
|
||||
if (!blockState.hasBlockEntity()) {
|
||||
@@ -187,7 +169,7 @@
|
||||
} else {
|
||||
BlockState blockState1 = blockEntity.getBlockState();
|
||||
if (blockState != blockState1) {
|
||||
@@ -457,6 +_,11 @@
|
||||
@@ -469,6 +_,11 @@
|
||||
public void removeBlockEntity(BlockPos pos) {
|
||||
if (this.isInLevel()) {
|
||||
BlockEntity blockEntity = this.blockEntities.remove(pos);
|
||||
@@ -199,7 +181,7 @@
|
||||
if (blockEntity != null) {
|
||||
if (this.level instanceof ServerLevel serverLevel) {
|
||||
this.removeGameEventListener(blockEntity, serverLevel);
|
||||
@@ -499,6 +_,65 @@
|
||||
@@ -511,6 +_,65 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +247,7 @@
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
@@ -711,23 +_,24 @@
|
||||
@@ -719,23 +_,24 @@
|
||||
if (this.blockEntity.getType().isValid(blockState)) {
|
||||
this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity);
|
||||
this.loggedInvalidBlockState = false;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
public FluidState getFluidState(int x, int y, int z) {
|
||||
- return this.states.get(x, y, z).getFluidState();
|
||||
+ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid; diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid.
|
||||
+ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise LevelChunk#getFluidState; diff on change - we expect this to be effectively just get(x, y, z).getFluidState(). If this changes we need to check other patches that use BlockBehaviour#getFluidState.
|
||||
}
|
||||
|
||||
public void acquire() {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
@@ -85,14 +_,32 @@
|
||||
@@ -85,14 +_,33 @@
|
||||
return new ChunkAccess.PackedTicks(this.blockTicks.pack(gametime), this.fluidTicks.pack(gametime));
|
||||
}
|
||||
|
||||
+ // Paper start - If loaded util
|
||||
+ @Override
|
||||
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
||||
+ return this.getFluidState(blockposition);
|
||||
+ public final FluidState getFluidIfLoaded(BlockPos pos) {
|
||||
+ return this.getFluidState(pos);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
|
||||
+ return this.getBlockState(blockposition);
|
||||
+ public final BlockState getBlockStateIfLoaded(BlockPos pos) {
|
||||
+ return this.getBlockState(pos);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@@ -20,8 +20,9 @@
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
- int y = pos.getY();
|
||||
+ // Paper start
|
||||
+ return getBlockState(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ return this.getBlockState(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ }
|
||||
+
|
||||
+ public BlockState getBlockState(final int x, final int y, final int z) {
|
||||
+ // Paper end
|
||||
if (this.isOutsideBuildHeight(y)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/chunk/UpgradeData.java
|
||||
+++ b/net/minecraft/world/level/chunk/UpgradeData.java
|
||||
@@ -113,6 +_,24 @@
|
||||
@@ -87,6 +_,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - filter out relocated neighbour ticks
|
||||
+
|
||||
public void upgrade(LevelChunk chunk) {
|
||||
this.upgradeInside(chunk);
|
||||
|
||||
@@ -120,6 +_,10 @@
|
||||
@@ -94,6 +_,10 @@
|
||||
upgradeSides(chunk, direction8);
|
||||
}
|
||||
|
||||
@@ -34,13 +35,13 @@
|
||||
+ filterTickList(chunk.locX, chunk.locZ, this.neighborFluidTicks);
|
||||
+ // Paper end - filter out relocated neighbour ticks
|
||||
Level level = chunk.getLevel();
|
||||
this.neighborBlockTicks.forEach(blockTicker -> {
|
||||
Block block = blockTicker.type() == Blocks.AIR ? level.getBlockState(blockTicker.pos()).getBlock() : blockTicker.type();
|
||||
@@ -129,6 +_,7 @@
|
||||
Fluid fluid = fluidTicker.type() == Fluids.EMPTY ? level.getFluidState(fluidTicker.pos()).getType() : fluidTicker.type();
|
||||
level.scheduleTick(fluidTicker.pos(), fluid, fluidTicker.delay(), fluidTicker.priority());
|
||||
this.neighborBlockTicks.forEach(savedTick -> {
|
||||
Block block = savedTick.type() == Blocks.AIR ? level.getBlockState(savedTick.pos()).getBlock() : savedTick.type();
|
||||
@@ -103,6 +_,7 @@
|
||||
Fluid fluid = savedTick.type() == Fluids.EMPTY ? level.getFluidState(savedTick.pos()).getType() : savedTick.type();
|
||||
level.scheduleTick(savedTick.pos(), fluid, savedTick.delay(), savedTick.priority());
|
||||
});
|
||||
+ UpgradeData.BlockFixers.values(); // Paper - force the class init so that we don't access CHUNKY_FIXERS before all BlockFixers are initialised
|
||||
CHUNKY_FIXERS.forEach(fixers -> fixers.processChunk(level));
|
||||
CHUNKY_FIXERS.forEach(blockFixer -> blockFixer.processChunk(level));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,9 @@
|
||||
worldGenContext.generator()
|
||||
.createStructures(
|
||||
serverLevel.registryAccess(),
|
||||
@@ -196,9 +_,60 @@
|
||||
}, worldGenContext.mainThreadExecutor());
|
||||
}
|
||||
@@ -198,7 +_,58 @@
|
||||
|
||||
- private static void postLoadProtoChunk(ServerLevel level, List<CompoundTag> entityTags) {
|
||||
+ public static void postLoadProtoChunk(ServerLevel level, List<CompoundTag> entityTags) { // Paper - public
|
||||
public static void postLoadProtoChunk(ServerLevel level, List<CompoundTag> entityTags) {
|
||||
if (!entityTags.isEmpty()) {
|
||||
- level.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entityTags, level, EntitySpawnReason.LOAD));
|
||||
- }
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
try {
|
||||
+ // CraftBukkit start
|
||||
+ if (version < 1466) {
|
||||
+ CompoundTag level = chunkData.getCompound("Level");
|
||||
+ if (level.getBoolean("TerrainPopulated") && !level.getBoolean("LightPopulated")) {
|
||||
+ CompoundTag level = chunkData.getCompoundOrEmpty("Level");
|
||||
+ if (level.getBooleanOr("TerrainPopulated", false) && !level.getBooleanOr("LightPopulated", false)) {
|
||||
+ // Light is purged updating to 1.14+. We need to set light populated to true so the converter recognizes the chunk as being "full"
|
||||
+ level.putBoolean("LightPopulated", true);
|
||||
+ }
|
||||
@@ -32,7 +32,7 @@
|
||||
+ // CraftBukkit end
|
||||
if (version < 1493) {
|
||||
chunkData = DataFixTypes.CHUNK.update(this.fixerUpper, chunkData, version, 1493);
|
||||
if (chunkData.getCompound("Level").getBoolean("hasLegacyStructureData")) {
|
||||
if (chunkData.getCompound("Level").flatMap(compoundTag -> compoundTag.getBoolean("hasLegacyStructureData")).orElse(false)) {
|
||||
@@ -57,8 +_,22 @@
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@
|
||||
+ boolean belowZeroGenerationInExistingChunks = (levelAccessor != null) ? ((net.minecraft.server.level.ServerLevel) levelAccessor).spigotConfig.belowZeroGenerationInExistingChunks : org.spigotmc.SpigotConfig.belowZeroGenerationInExistingChunks;
|
||||
+
|
||||
+ if (version <= 2730 && !belowZeroGenerationInExistingChunks) {
|
||||
+ stopBelowZero = "full".equals(chunkData.getCompound("Level").getString("Status"));
|
||||
+ stopBelowZero = "full".equals(chunkData.getCompound("Level").flatMap(l -> l.getString("Status")).orElse(null));
|
||||
+ }
|
||||
+ // Spigot end
|
||||
+
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
) {
|
||||
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(
|
||||
Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()
|
||||
@@ -107,12 +_,39 @@
|
||||
@@ -109,12 +_,38 @@
|
||||
public static final String BLOCK_LIGHT_TAG = "BlockLight";
|
||||
public static final String SKY_LIGHT_TAG = "SkyLight";
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
+ public static ChunkPos getChunkCoordinate(final CompoundTag chunkData) {
|
||||
+ final int dataVersion = ChunkStorage.getVersion(chunkData);
|
||||
+ if (dataVersion < 2842) { // Level tag is removed after this version
|
||||
+ final CompoundTag levelData = chunkData.getCompound("Level");
|
||||
+ return new ChunkPos(levelData.getInt("xPos"), levelData.getInt("zPos"));
|
||||
+ final CompoundTag levelData = chunkData.getCompoundOrEmpty("Level");
|
||||
+ return new ChunkPos(levelData.getIntOr("xPos", 0), levelData.getIntOr("zPos", 0));
|
||||
+ } else {
|
||||
+ return new ChunkPos(chunkData.getInt("xPos"), chunkData.getInt("zPos"));
|
||||
+ return new ChunkPos(chunkData.getIntOr("xPos", 0), chunkData.getIntOr("zPos", 0));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - guard against serializing mismatching coordinates
|
||||
@@ -32,50 +32,49 @@
|
||||
+
|
||||
@Nullable
|
||||
public static SerializableChunkData parse(LevelHeightAccessor levelHeightAccessor, RegistryAccess registries, CompoundTag tag) {
|
||||
if (!tag.contains("Status", 8)) {
|
||||
if (tag.getString("Status").isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
- ChunkPos chunkPos = new ChunkPos(tag.getInt("xPos"), tag.getInt("zPos"));
|
||||
- ChunkPos chunkPos = new ChunkPos(tag.getIntOr("xPos", 0), tag.getIntOr("zPos", 0));
|
||||
+ // Paper start - Do not let the server load chunks from newer versions
|
||||
+ if (tag.contains("DataVersion", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) {
|
||||
+ final int dataVersion = tag.getInt("DataVersion");
|
||||
+ tag.getInt("DataVersion").ifPresent(dataVersion -> {
|
||||
+ if (!JUST_CORRUPT_IT && dataVersion > CURRENT_DATA_VERSION) {
|
||||
+ new RuntimeException("Server attempted to load chunk saved with newer version of minecraft! " + dataVersion + " > " + CURRENT_DATA_VERSION).printStackTrace();
|
||||
+ System.exit(1);
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end - Do not let the server load chunks from newer versions
|
||||
+ ChunkPos chunkPos = new ChunkPos(tag.getInt("xPos"), tag.getInt("zPos")); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate
|
||||
long _long = tag.getLong("LastUpdate");
|
||||
long _long1 = tag.getLong("InhabitedTime");
|
||||
ChunkStatus chunkStatus = ChunkStatus.byName(tag.getString("Status"));
|
||||
@@ -181,7 +_,7 @@
|
||||
ListTag list7 = tag.getList("sections", 10);
|
||||
List<SerializableChunkData.SectionData> list8 = new ArrayList<>(list7.size());
|
||||
+ ChunkPos chunkPos = new ChunkPos(tag.getIntOr("xPos", 0), tag.getIntOr("zPos", 0)); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate
|
||||
long longOr = tag.getLongOr("LastUpdate", 0L);
|
||||
long longOr1 = tag.getLongOr("InhabitedTime", 0L);
|
||||
ChunkStatus chunkStatus = tag.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY);
|
||||
@@ -154,7 +_,7 @@
|
||||
ListTag listOrEmpty2 = tag.getListOrEmpty("sections");
|
||||
List<SerializableChunkData.SectionData> list5 = new ArrayList<>(listOrEmpty2.size());
|
||||
Registry<Biome> registry = registries.lookupOrThrow(Registries.BIOME);
|
||||
- Codec<PalettedContainerRO<Holder<Biome>>> codec = makeBiomeCodec(registry);
|
||||
+ Codec<PalettedContainer<Holder<Biome>>> codec = makeBiomeCodecRW(registry); // CraftBukkit - read/write
|
||||
|
||||
for (int i2 = 0; i2 < list7.size(); i2++) {
|
||||
CompoundTag compound2 = list7.getCompound(i2);
|
||||
@@ -199,7 +_,7 @@
|
||||
);
|
||||
}
|
||||
|
||||
- PalettedContainerRO<Holder<Biome>> palettedContainerRo;
|
||||
+ PalettedContainer<Holder<Biome>> palettedContainerRo; // CraftBukkit - read/write
|
||||
if (compound2.contains("biomes", 10)) {
|
||||
palettedContainerRo = codec.parse(NbtOps.INSTANCE, compound2.getCompound("biomes"))
|
||||
.promotePartial(string -> logErrors(chunkPos, _byte, string))
|
||||
@@ -239,6 +_,7 @@
|
||||
list5,
|
||||
list6,
|
||||
compound1
|
||||
for (int i2 = 0; i2 < listOrEmpty2.size(); i2++) {
|
||||
Optional<CompoundTag> compound = listOrEmpty2.getCompound(i2);
|
||||
@@ -174,7 +_,7 @@
|
||||
Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES
|
||||
)
|
||||
);
|
||||
- PalettedContainerRO<Holder<Biome>> palettedContainerRo = compoundTag.getCompound("biomes")
|
||||
+ PalettedContainer<Holder<Biome>> palettedContainerRo = compoundTag.getCompound("biomes") // CraftBukkit - read/write
|
||||
.map(
|
||||
compoundTag1 -> codec.parse(NbtOps.INSTANCE, compoundTag1)
|
||||
.promotePartial(string -> logErrors(chunkPos, byteOr, string))
|
||||
@@ -215,6 +_,7 @@
|
||||
list3,
|
||||
list4,
|
||||
compoundOrEmpty
|
||||
+ , tag.get("ChunkBukkitValues") // CraftBukkit - ChunkBukkitValues
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -316,6 +_,12 @@
|
||||
@@ -292,6 +_,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,21 +87,7 @@
|
||||
chunkAccess.setLightCorrect(this.lightCorrect);
|
||||
EnumSet<Heightmap.Types> set = EnumSet.noneOf(Heightmap.Types.class);
|
||||
|
||||
@@ -346,6 +_,13 @@
|
||||
}
|
||||
|
||||
for (CompoundTag compoundTag : this.blockEntities) {
|
||||
+ // Paper start - do not read tile entities positioned outside the chunk
|
||||
+ final BlockPos blockposition = BlockEntity.getPosFromTag(compoundTag);
|
||||
+ if ((blockposition.getX() >> 4) != this.chunkPos.x || (blockposition.getZ() >> 4) != this.chunkPos.z) {
|
||||
+ LOGGER.warn("Tile entity serialized in chunk {} in world '{}' positioned at {} is located outside of the chunk", this.chunkPos, level.getWorld().getName(), blockposition);
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - do not read tile entities positioned outside the chunk
|
||||
protoChunk1.setBlockEntityNbt(compoundTag);
|
||||
}
|
||||
|
||||
@@ -370,6 +_,12 @@
|
||||
@@ -346,6 +_,12 @@
|
||||
);
|
||||
}
|
||||
|
||||
@@ -115,7 +100,7 @@
|
||||
public static SerializableChunkData copyOf(ServerLevel level, ChunkAccess chunk) {
|
||||
if (!chunk.canBeSerialized()) {
|
||||
throw new IllegalArgumentException("Chunk can't be serialized: " + chunk);
|
||||
@@ -428,6 +_,12 @@
|
||||
@@ -404,6 +_,12 @@
|
||||
CompoundTag compoundTag = packStructureData(
|
||||
StructurePieceSerializationContext.fromLevel(level), pos, chunk.getAllStarts(), chunk.getAllReferences()
|
||||
);
|
||||
@@ -128,7 +113,7 @@
|
||||
return new SerializableChunkData(
|
||||
level.registryAccess().lookupOrThrow(Registries.BIOME),
|
||||
pos,
|
||||
@@ -447,6 +_,7 @@
|
||||
@@ -423,6 +_,7 @@
|
||||
list2,
|
||||
list1,
|
||||
compoundTag
|
||||
@@ -136,7 +121,7 @@
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -525,6 +_,11 @@
|
||||
@@ -489,6 +_,11 @@
|
||||
this.heightmaps.forEach((types, longs) -> compoundTag2.put(types.getSerializationKey(), new LongArrayTag(longs)));
|
||||
compoundTag.put("Heightmaps", compoundTag2);
|
||||
compoundTag.put("structures", this.structureData);
|
||||
@@ -148,26 +133,12 @@
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
@@ -562,6 +_,13 @@
|
||||
chunk.setBlockEntityNbt(compoundTag);
|
||||
} else {
|
||||
BlockPos posFromTag = BlockEntity.getPosFromTag(compoundTag);
|
||||
+ // Paper start - do not read tile entities positioned outside the chunk
|
||||
+ ChunkPos chunkPos = chunk.getPos();
|
||||
+ if ((posFromTag.getX() >> 4) != chunkPos.x || (posFromTag.getZ() >> 4) != chunkPos.z) {
|
||||
+ LOGGER.warn("Tile entity serialized in chunk " + chunkPos + " in world '" + level.getWorld().getName() + "' positioned at " + posFromTag + " is located outside of the chunk");
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - do not read tile entities positioned outside the chunk
|
||||
BlockEntity blockEntity = BlockEntity.loadStatic(posFromTag, chunk.getBlockState(posFromTag), compoundTag, level.registryAccess());
|
||||
if (blockEntity != null) {
|
||||
chunk.setBlockEntity(blockEntity);
|
||||
@@ -610,6 +_,12 @@
|
||||
@@ -562,6 +_,12 @@
|
||||
} else {
|
||||
StructureStart structureStart = StructureStart.loadStaticStart(context, compound.getCompound(string), seed);
|
||||
StructureStart structureStart = StructureStart.loadStaticStart(context, compoundOrEmpty.getCompoundOrEmpty(string), seed);
|
||||
if (structureStart != null) {
|
||||
+ // CraftBukkit start - load persistent data for structure start
|
||||
+ net.minecraft.nbt.Tag persistentBase = compound.getCompound(string).get("StructureBukkitValues");
|
||||
+ net.minecraft.nbt.Tag persistentBase = compoundOrEmpty.getCompoundOrEmpty(string).get("StructureBukkitValues");
|
||||
+ if (persistentBase instanceof CompoundTag compoundTag) {
|
||||
+ structureStart.persistentDataContainer.putAll(compoundTag);
|
||||
+ }
|
||||
|
||||
Reference in New Issue
Block a user