diff --git a/paper-server/patches/features/0001-Add-explicit-flush-support-to-Log4j-AsyncAppender.patch b/paper-server/patches/features/0001-Add-explicit-flush-support-to-Log4j-AsyncAppender.patch index ea9c872a670c..441cc22de57f 100644 --- a/paper-server/patches/features/0001-Add-explicit-flush-support-to-Log4j-AsyncAppender.patch +++ b/paper-server/patches/features/0001-Add-explicit-flush-support-to-Log4j-AsyncAppender.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add explicit flush support to Log4j AsyncAppender diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java -index 639ff94cd3cdd350a0ce7bee48560baedaa3c8c3..fbad2fd2ea324fec44f27ac35024579b5436db25 100644 +index fd0a261a0492965d87e1eed9784cf73308d8a91d..dec75972dc30d954d9054f82940263506d1b82d6 100644 --- a/io/papermc/paper/FeatureHooks.java +++ b/io/papermc/paper/FeatureHooks.java @@ -246,6 +246,20 @@ public final class FeatureHooks { @@ -28,8 +28,7 @@ index 639ff94cd3cdd350a0ce7bee48560baedaa3c8c3..fbad2fd2ea324fec44f27ac35024579b + // Paper end - add explicit flush method } - } -\ No newline at end of file + public static net.minecraft.world.level.chunk.DataLayer copyLightDataLayer(Level level, net.minecraft.world.level.chunk.ChunkAccess chunk, net.minecraft.world.level.LightLayer layer, int sectionIndex) { diff --git a/org/apache/logging/log4j/core/appender/AsyncAppender.java b/org/apache/logging/log4j/core/appender/AsyncAppender.java index f84870712345cd688a90ea53ad47eb33fe658863..126a5d1bc4239ba83565600a060877c22e39e06b 100644 --- a/org/apache/logging/log4j/core/appender/AsyncAppender.java diff --git a/paper-server/patches/features/0003-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0003-Moonrise-optimisation-patches.patch index 0a83e293640c..e0e727f28876 100644 --- a/paper-server/patches/features/0003-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0003-Moonrise-optimisation-patches.patch @@ -297,7 +297,7 @@ index 0000000000000000000000000000000000000000..fff7a796a61542213bdaa417d44e25cd + } +} diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java -index 4a62c50d0b4fe82c3aacaa56b303b9699120c778..92238518c25dd765b356ff628fd373997464ea82 100644 +index aa14dd369d5d2c5c843839f289afdc39c200f0c3..76f990f150f040b1ad6d7d5b91cfb34ebd6f436a 100644 --- a/ca/spottedleaf/moonrise/paper/PaperHooks.java +++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java @@ -13,6 +13,7 @@ import net.minecraft.server.level.ChunkHolder; @@ -23676,7 +23676,7 @@ index 0000000000000000000000000000000000000000..95154636727366adfb4fb67e7db8b09f + private SaveUtil() {} +} diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java -index fbad2fd2ea324fec44f27ac35024579b5436db25..82377ee76caac220f7565cb729b9e608206a685a 100644 +index dec75972dc30d954d9054f82940263506d1b82d6..0c8fb260ea4b4d2b5732480a1556cda1fa9f8576 100644 --- a/io/papermc/paper/FeatureHooks.java +++ b/io/papermc/paper/FeatureHooks.java @@ -1,6 +1,9 @@ @@ -23908,6 +23908,34 @@ index fbad2fd2ea324fec44f27ac35024579b5436db25..82377ee76caac220f7565cb729b9e608 } public static void flushAsyncAppenders() { +@@ -263,8 +207,23 @@ public final class FeatureHooks { + } + + public static net.minecraft.world.level.chunk.DataLayer copyLightDataLayer(Level level, net.minecraft.world.level.chunk.ChunkAccess chunk, net.minecraft.world.level.LightLayer layer, int sectionIndex) { +- net.minecraft.world.level.chunk.DataLayer view = level.getLightEngine().getLayerListener(layer).getDataLayerData(net.minecraft.core.SectionPos.of(chunk.getPos(), chunk.getSectionYFromSectionIndex(sectionIndex))); +- return view == null ? null : view.copy(); ++ // Paper start - starlight ++ int sectionY = chunk.getSectionYFromSectionIndex(sectionIndex); ++ int minLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinLightSection(level); ++ int maxLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxLightSection(level); ++ if (sectionY < minLightSection || sectionY > maxLightSection) return null; ++ ++ ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] nibbles; ++ if (layer == net.minecraft.world.level.LightLayer.BLOCK) { ++ nibbles = ((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getBlockNibbles(); ++ } else { ++ if (!chunk.isLightCorrect() || !chunk.getPersistedStatus().isOrAfter(net.minecraft.world.level.chunk.status.ChunkStatus.LIGHT)) return null; ++ if (((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getSkyEmptinessMap() == null) return null; ++ ++ nibbles = ((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getSkyNibbles(); ++ } ++ return nibbles[sectionY - minLightSection].toVanillaNibble(); ++ // Paper end - starlight + } + +-} +\ No newline at end of file ++} diff --git a/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/io/papermc/paper/command/subcommands/ChunkDebugCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..d86bd11e0155f767c3bf66ac05fa4acf6d2bfccb diff --git a/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch b/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch index e4624a5d9290..9de9607875a8 100644 --- a/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch +++ b/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/io/papermc/paper/FeatureHooks.java -@@ -1,0 +_,251 @@ +@@ -1,0 +_,256 @@ +package io.papermc.paper; + +import io.papermc.paper.command.PaperSubcommand; @@ -251,4 +251,9 @@ + public static void flushAsyncAppenders() { + } + ++ public static net.minecraft.world.level.chunk.DataLayer copyLightDataLayer(Level level, net.minecraft.world.level.chunk.ChunkAccess chunk, net.minecraft.world.level.LightLayer layer, int sectionIndex) { ++ net.minecraft.world.level.chunk.DataLayer view = level.getLightEngine().getLayerListener(layer).getDataLayerData(net.minecraft.core.SectionPos.of(chunk.getPos(), chunk.getSectionYFromSectionIndex(sectionIndex))); ++ return view == null ? null : view.copy(); ++ } ++ +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index f8254b3ec264..badb033fc72c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -47,8 +47,8 @@ public class CraftChunk implements Chunk { private final int x; private final int z; private static final PalettedContainer emptyBlockIDs = FeatureHooks.emptyPalettedBlockContainer(); - private static final byte[] FULL_LIGHT = new byte[2048]; - private static final byte[] EMPTY_LIGHT = new byte[2048]; + private static final DataLayer FULL_LIGHT = new DataLayer(15); + private static final DataLayer EMPTY_LIGHT = new DataLayer(0); public CraftChunk(net.minecraft.world.level.chunk.LevelChunk chunk) { this.level = (ServerLevel) chunk.getLevel(); @@ -271,8 +271,8 @@ public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeB LevelChunkSection[] cs = chunk.getSections(); PalettedContainer[] sectionBlockIDs = new PalettedContainer[cs.length]; - byte[][] sectionSkyLights = includeLightData ? new byte[cs.length][] : null; - byte[][] sectionEmitLights = includeLightData ? new byte[cs.length][] : null; + DataLayer[] sectionSkyLights = includeLightData ? new DataLayer[cs.length] : null; + DataLayer[] sectionEmitLights = includeLightData ? new DataLayer[cs.length] : null; boolean[] sectionEmpty = new boolean[cs.length]; PalettedContainerRO>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null; @@ -288,22 +288,14 @@ public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeB // Paper end - Fix ChunkSnapshot#isSectionEmpty(int) if (includeLightData) { - LevelLightEngine lightEngine = this.level.getLightEngine(); - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(this.x, chunk.getSectionYFromSectionIndex(i), this.z)); // SPIGOT-7498: Convert section index - if (skyLightArray == null) { - sectionSkyLights[i] = this.level.dimensionType().hasSkyLight() ? CraftChunk.FULL_LIGHT : CraftChunk.EMPTY_LIGHT; + if (this.level.dimensionType().hasSkyLight()) { + sectionSkyLights[i] = FeatureHooks.copyLightDataLayer(this.level, chunk, LightLayer.SKY, i); } else { - sectionSkyLights[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, sectionSkyLights[i], 0, 2048); + sectionSkyLights[i] = CraftChunk.EMPTY_LIGHT; } - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(this.x, chunk.getSectionYFromSectionIndex(i), this.z)); // SPIGOT-7498: Convert section index - if (emitLightArray == null) { - sectionEmitLights[i] = CraftChunk.EMPTY_LIGHT; - } else { - sectionEmitLights[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, sectionEmitLights[i], 0, 2048); - } + DataLayer emitLightArray = FeatureHooks.copyLightDataLayer(this.level, chunk, LightLayer.BLOCK, i); + sectionEmitLights[i] = emitLightArray == null ? CraftChunk.EMPTY_LIGHT : emitLightArray; } if (biome != null) { @@ -377,8 +369,8 @@ public static ChunkSnapshot getEmptyChunkSnapshot(int x, int z, CraftWorld world /* Fill with empty data */ int hSection = actual.getSectionsCount(); PalettedContainer[] blockIDs = new PalettedContainer[hSection]; - byte[][] skyLight = new byte[hSection][]; - byte[][] emitLight = new byte[hSection][]; + DataLayer[] skyLight = new DataLayer[hSection]; + DataLayer[] emitLight = new DataLayer[hSection]; boolean[] empty = new boolean[hSection]; PalettedContainer>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[hSection] : null; Codec>> biomeCodec = world.getHandle().palettedContainerFactory().biomeContainerCodec(); @@ -402,8 +394,4 @@ static void validateChunkCoordinates(int minY, int maxY, int x, int y, int z) { Preconditions.checkArgument(minY <= y && y <= maxY, "y out of range (expected %s-%s, got %s)", minY, maxY, y); Preconditions.checkArgument(0 <= z && z <= 15, "z out of range (expected 0-15, got %s)", z); } - - static { - Arrays.fill(FULL_LIGHT, (byte) 0xFF); - } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java index 196816843eb7..709b692f4273 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunkSnapshot.java @@ -6,7 +6,9 @@ import net.kyori.adventure.key.Key; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; +import net.minecraft.core.SectionPos; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; @@ -28,14 +30,14 @@ public class CraftChunkSnapshot implements ChunkSnapshot { private final String worldName; private final Key worldKey; private final PalettedContainer[] blockIds; - private final byte[][] skylight; - private final byte[][] emitLight; + private final DataLayer[] skylight; + private final DataLayer[] emitLight; private final boolean[] empty; private final Heightmap heightmap; // Height map private final long captureFullTime; private final PalettedContainerRO>[] biome; - CraftChunkSnapshot(int x, int z, int minHeight, int maxHeight, int seaLevel, String worldName, Key worldKey, long fullTime, PalettedContainer[] sectionBlockIDs, byte[][] sectionSkyLights, byte[][] sectionEmitLights, boolean[] sectionEmpty, Heightmap heightmap, PalettedContainerRO>[] biome) { + CraftChunkSnapshot(int x, int z, int minHeight, int maxHeight, int seaLevel, String worldName, Key worldKey, long fullTime, PalettedContainer[] sectionBlockIDs, DataLayer[] sectionSkyLights, DataLayer[] sectionEmitLights, boolean[] sectionEmpty, Heightmap heightmap, PalettedContainerRO>[] biome) { this.x = x; this.z = z; this.minHeight = minHeight; @@ -126,8 +128,28 @@ public final int getBlockSkyLight(int x, int y, int z) { Preconditions.checkState(this.skylight != null, "ChunkSnapshot created without light data. Please call getSnapshot with includeLightData=true"); // Paper - Add getChunkSnapshot includeLightData parameter this.validateChunkCoordinates(x, y, z); - int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); - return (this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2)) & 0xF; + int sectionY = this.getSectionIndex(y); + int relativeY = SectionPos.sectionRelative(y); + + DataLayer current = this.skylight[sectionY]; + if (current != null) { + return current.get(x, relativeY, z); + } + + int highestNonEmpty = this.empty.length - 1; + while (highestNonEmpty >= 0 && this.empty[highestNonEmpty]) { + highestNonEmpty--; + } + if (sectionY > highestNonEmpty) { + return 15; + } + + for (int i = sectionY + 1; i < this.skylight.length; i++) { + DataLayer above = this.skylight[i]; + if (above != null) return above.get(x, 0, z); + } + + return 15; } @Override @@ -135,8 +157,7 @@ public final int getBlockEmittedLight(int x, int y, int z) { Preconditions.checkState(this.emitLight != null, "ChunkSnapshot created without light data. Please call getSnapshot with includeLightData=true"); // Paper - Add getChunkSnapshot includeLightData parameter this.validateChunkCoordinates(x, y, z); - int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); - return (this.emitLight[this.getSectionIndex(y)][off] >> ((x & 1) << 2)) & 0xF; + return this.emitLight[this.getSectionIndex(y)].get(x, SectionPos.sectionRelative(y), z); } @Override