aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk
diff options
context:
space:
mode:
Diffstat (limited to 'patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk')
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkAccess.java.patch102
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkGenerator.java.patch74
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch1
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkStatus.java.patch15
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/DataLayer.java.patch1
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/LevelChunk.java.patch185
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/LevelChunkSection.java.patch37
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/ChunkSerializer.java.patch94
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/ChunkStorage.java.patch91
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/RegionFile.java.patch1
-rw-r--r--patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch72
11 files changed, 673 insertions, 0 deletions
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkAccess.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkAccess.java.patch
new file mode 100644
index 0000000000..ecc6a59334
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkAccess.java.patch
@@ -0,0 +1,102 @@
+--- a/net/minecraft/world/level/chunk/ChunkAccess.java
++++ b/net/minecraft/world/level/chunk/ChunkAccess.java
+@@ -82,25 +82,34 @@
+ protected final LevelHeightAccessor levelHeightAccessor;
+ protected final LevelChunkSection[] sections;
+
+- public ChunkAccess(ChunkPos chunkpos, UpgradeData upgradedata, LevelHeightAccessor levelheightaccessor, Registry<Biome> registry, long i, @Nullable LevelChunkSection[] alevelchunksection, @Nullable BlendingData blendingdata) {
+- this.chunkPos = chunkpos;
+- this.upgradeData = upgradedata;
+- this.levelHeightAccessor = levelheightaccessor;
+- this.sections = new LevelChunkSection[levelheightaccessor.getSectionsCount()];
+- this.inhabitedTime = i;
+- this.postProcessing = new ShortList[levelheightaccessor.getSectionsCount()];
+- this.blendingData = blendingdata;
+- this.skyLightSources = new ChunkSkyLightSources(levelheightaccessor);
+- if (alevelchunksection != null) {
+- if (this.sections.length == alevelchunksection.length) {
+- System.arraycopy(alevelchunksection, 0, this.sections, 0, this.sections.length);
++ // CraftBukkit start - SPIGOT-6814: move to IChunkAccess to account for 1.17 to 1.18 chunk upgrading.
++ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
++ public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(DATA_TYPE_REGISTRY);
++ // CraftBukkit end
++
++ public ChunkAccess(ChunkPos chunkPos, UpgradeData upgradeData, LevelHeightAccessor levelHeightAccessor, Registry<Biome> biomeRegistry, long inhabitedTime, @Nullable LevelChunkSection[] achunksection, @Nullable BlendingData sections) {
++ this.chunkPos = chunkPos;
++ this.upgradeData = upgradeData;
++ this.levelHeightAccessor = levelHeightAccessor;
++ this.sections = new LevelChunkSection[levelHeightAccessor.getSectionsCount()];
++ this.inhabitedTime = inhabitedTime;
++ this.postProcessing = new ShortList[levelHeightAccessor.getSectionsCount()];
++ this.blendingData = sections;
++ this.skyLightSources = new ChunkSkyLightSources(levelHeightAccessor);
++ if (achunksection != null) {
++ if (this.sections.length == achunksection.length) {
++ System.arraycopy(achunksection, 0, this.sections, 0, this.sections.length);
+ } else {
+ ChunkAccess.LOGGER.warn("Could not set level chunk sections, array length is {} instead of {}", alevelchunksection.length, this.sections.length);
+ }
+ }
+
+- replaceMissingSections(registry, this.sections);
++ replaceMissingSections(biomeRegistry, this.sections);
++ // CraftBukkit start
++ this.biomeRegistry = biomeRegistry;
+ }
++ public final Registry<Biome> biomeRegistry;
++ // CraftBukkit end
+
+ private static void replaceMissingSections(Registry<Biome> registry, LevelChunkSection[] alevelchunksection) {
+ for (int i = 0; i < alevelchunksection.length; ++i) {
+@@ -267,12 +270,13 @@
+ return true;
+ }
+
+- public void setUnsaved(boolean flag) {
+- this.unsaved = flag;
++ public void setUnsaved(boolean unsaved) {
++ this.unsaved = unsaved;
++ if (!unsaved) this.persistentDataContainer.dirty(false); // CraftBukkit - SPIGOT-6814: chunk was saved, pdc is no longer dirty
+ }
+
+ public boolean isUnsaved() {
+- return this.unsaved;
++ return this.unsaved || this.persistentDataContainer.dirty(); // CraftBukkit - SPIGOT-6814: chunk is unsaved if pdc was mutated
+ }
+
+ public abstract ChunkStatus getStatus();
+@@ -445,12 +445,33 @@
+ CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting biome");
+ CrashReportCategory crashreportcategory = crashreport.addCategory("Biome being got");
+
+- crashreportcategory.setDetail("Location", () -> {
++ crashreportsystemdetails.setDetail("Location", () -> {
++ return CrashReportCategory.formatLocation(this, x, y, z);
++ });
++ throw new ReportedException(crashreport);
++ }
++ }
++
++ // CraftBukkit start
++ public void setBiome(int i, int j, int k, Holder<Biome> biome) {
++ try {
++ int l = QuartPos.fromBlock(this.getMinBuildHeight());
++ int i1 = l + QuartPos.fromBlock(this.getHeight()) - 1;
++ int j1 = Mth.clamp(j, l, i1);
++ int k1 = this.getSectionIndex(QuartPos.toBlock(j1));
++
++ this.sections[k1].setBiome(i & 3, j1 & 3, k & 3, biome);
++ } catch (Throwable throwable) {
++ CrashReport crashreport = CrashReport.forThrowable(throwable, "Setting biome");
++ CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Biome being set");
++
++ crashreportsystemdetails.setDetail("Location", () -> {
+ return CrashReportCategory.formatLocation(this, i, j, k);
+ });
+ throw new ReportedException(crashreport);
+ }
+ }
++ // CraftBukkit end
+
+ public void fillBiomesFromNoise(BiomeResolver biomeresolver, Climate.Sampler climate_sampler) {
+ ChunkPos chunkpos = this.getPos();
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkGenerator.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkGenerator.java.patch
new file mode 100644
index 0000000000..5e896beacf
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkGenerator.java.patch
@@ -0,0 +1,74 @@
+--- a/net/minecraft/world/level/chunk/ChunkGenerator.java
++++ b/net/minecraft/world/level/chunk/ChunkGenerator.java
+@@ -307,8 +306,8 @@
+ }
+ }
+
+- public void applyBiomeDecoration(WorldGenLevel worldgenlevel, ChunkAccess chunkaccess, StructureManager structuremanager) {
+- ChunkPos chunkpos = chunkaccess.getPos();
++ public void addVanillaDecorations(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { // CraftBukkit
++ ChunkPos chunkcoordintpair = ichunkaccess.getPos();
+
+ if (!SharedConstants.debugVoidTerrain(chunkpos)) {
+ SectionPos sectionpos = SectionPos.of(chunkpos, worldgenlevel.getMinSection());
+@@ -440,11 +439,38 @@
+ }
+ }
+
+- private static BoundingBox getWritableArea(ChunkAccess chunkaccess) {
+- ChunkPos chunkpos = chunkaccess.getPos();
+- int i = chunkpos.getMinBlockX();
+- int j = chunkpos.getMinBlockZ();
+- LevelHeightAccessor levelheightaccessor = chunkaccess.getHeightAccessorForGeneration();
++ // CraftBukkit start
++ public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) {
++ applyBiomeDecoration(level, chunk, structureManager, true);
++ }
++
++ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
++ if (vanilla) {
++ addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
++ }
++
++ org.bukkit.World world = generatoraccessseed.getMinecraftWorld().getWorld();
++ // only call when a populator is present (prevents unnecessary entity conversion)
++ if (!world.getPopulators().isEmpty()) {
++ org.bukkit.craftbukkit.generator.CraftLimitedRegion limitedRegion = new org.bukkit.craftbukkit.generator.CraftLimitedRegion(generatoraccessseed, ichunkaccess.getPos());
++ int x = ichunkaccess.getPos().x;
++ int z = ichunkaccess.getPos().z;
++ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
++ WorldgenRandom seededrandom = new WorldgenRandom(new net.minecraft.world.level.levelgen.LegacyRandomSource(generatoraccessseed.getSeed()));
++ seededrandom.setDecorationSeed(generatoraccessseed.getSeed(), x, z);
++ populator.populate(world, new org.bukkit.craftbukkit.util.RandomSourceWrapper.RandomWrapper(seededrandom), x, z, limitedRegion);
++ }
++ limitedRegion.saveEntities();
++ limitedRegion.breakLink();
++ }
++ }
++ // CraftBukkit end
++
++ private static BoundingBox getWritableArea(ChunkAccess chunk) {
++ ChunkPos chunkcoordintpair = chunk.getPos();
++ int i = chunkcoordintpair.getMinBlockX();
++ int j = chunkcoordintpair.getMinBlockZ();
++ LevelHeightAccessor levelheightaccessor = chunk.getHeightAccessorForGeneration();
+ int k = levelheightaccessor.getMinBuildHeight() + 1;
+ int l = levelheightaccessor.getMaxBuildHeight() - 1;
+
+@@ -577,7 +603,15 @@
+ StructureStart structurestart = structure.generate(registryaccess, this, this.biomeSource, randomstate, structuretemplatemanager, i, chunkpos, j, chunkaccess, predicate);
+
+ if (structurestart.isValid()) {
+- structuremanager.setStartForStructure(sectionpos, structure, structurestart, chunkaccess);
++ // CraftBukkit start
++ BoundingBox box = structurestart.getBoundingBox();
++ org.bukkit.event.world.AsyncStructureSpawnEvent event = new org.bukkit.event.world.AsyncStructureSpawnEvent(structureManager.level.getMinecraftWorld().getWorld(), org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(structure, registryAccess), new org.bukkit.util.BoundingBox(box.minX(), box.minY(), box.minZ(), box.maxX(), box.maxY(), box.maxZ()), chunk.x, chunk.z);
++ org.bukkit.Bukkit.getPluginManager().callEvent(event);
++ if (event.isCancelled()) {
++ return true;
++ }
++ // CraftBukkit end
++ structureManager.setStartForStructure(chunkPos, structure, structurestart, ichunkaccess);
+ return true;
+ } else {
+ return false;
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch
@@ -0,0 +1 @@
+
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkStatus.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkStatus.java.patch
new file mode 100644
index 0000000000..2e317e64ea
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/ChunkStatus.java.patch
@@ -0,0 +1,15 @@
+--- a/net/minecraft/world/level/chunk/ChunkStatus.java
++++ b/net/minecraft/world/level/chunk/ChunkStatus.java
+@@ -38,9 +38,9 @@
+ };
+ public static final ChunkStatus EMPTY = registerSimple("empty", (ChunkStatus) null, -1, ChunkStatus.PRE_FEATURES, ChunkStatus.ChunkType.PROTOCHUNK, (chunkstatus, serverlevel, chunkgenerator, list, chunkaccess) -> {
+ });
+- public static final ChunkStatus STRUCTURE_STARTS = register("structure_starts", ChunkStatus.EMPTY, 0, false, ChunkStatus.PRE_FEATURES, ChunkStatus.ChunkType.PROTOCHUNK, (chunkstatus, executor, serverlevel, chunkgenerator, structuretemplatemanager, threadedlevellightengine, function, list, chunkaccess) -> {
+- if (serverlevel.getServer().getWorldData().worldGenOptions().generateStructures()) {
+- chunkgenerator.createStructures(serverlevel.registryAccess(), serverlevel.getChunkSource().getGeneratorState(), serverlevel.structureManager(), chunkaccess, structuretemplatemanager);
++ public static final ChunkStatus STRUCTURE_STARTS = register("structure_starts", ChunkStatus.EMPTY, 0, false, ChunkStatus.PRE_FEATURES, ChunkStatus.Type.PROTOCHUNK, (chunkstatus, executor, worldserver, chunkgenerator, structuretemplatemanager, lightenginethreaded, function, list, ichunkaccess) -> {
++ if (worldserver.serverLevelData.worldGenOptions().generateStructures()) { // CraftBukkit
++ chunkgenerator.createStructures(worldserver.registryAccess(), worldserver.getChunkSource().getGeneratorState(), worldserver.structureManager(), ichunkaccess, structuretemplatemanager);
+ }
+
+ serverlevel.onStructureStartsAvailable(chunkaccess);
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/DataLayer.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/DataLayer.java.patch
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/DataLayer.java.patch
@@ -0,0 +1 @@
+
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/LevelChunk.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/LevelChunk.java.patch
new file mode 100644
index 0000000000..dc92d39044
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/LevelChunk.java.patch
@@ -0,0 +1,185 @@
+--- a/net/minecraft/world/level/chunk/LevelChunk.java
++++ b/net/minecraft/world/level/chunk/LevelChunk.java
+@@ -78,8 +74,8 @@
+ }
+ };
+ private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel;
+- private boolean loaded;
+- final Level level;
++ public boolean loaded;
++ public final ServerLevel level; // CraftBukkit - type
+ @Nullable
+ private Supplier<FullChunkStatus> fullStatus;
+ @Nullable
+@@ -95,7 +91,7 @@
+ public LevelChunk(Level level, ChunkPos chunkpos, UpgradeData upgradedata, LevelChunkTicks<Block> levelchunkticks, LevelChunkTicks<Fluid> levelchunkticks1, long i, @Nullable LevelChunkSection[] alevelchunksection, @Nullable LevelChunk.PostLoadProcessor levelchunk_postloadprocessor, @Nullable BlendingData blendingdata) {
+ super(chunkpos, upgradedata, level, level.registryAccess().registryOrThrow(Registries.BIOME), i, alevelchunksection, blendingdata);
+ this.tickersInLevel = Maps.newHashMap();
+- this.level = level;
++ this.level = (ServerLevel) level; // CraftBukkit - type
+ this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap();
+ Heightmap.Types[] aheightmap_types = Heightmap.Types.values();
+ int j = aheightmap_types.length;
+@@ -113,9 +109,10 @@
+ this.fluidTicks = levelchunkticks1;
+ }
+
+- public LevelChunk(ServerLevel serverlevel, ProtoChunk protochunk, @Nullable LevelChunk.PostLoadProcessor levelchunk_postloadprocessor) {
+- this(serverlevel, protochunk.getPos(), protochunk.getUpgradeData(), protochunk.unpackBlockTicks(), protochunk.unpackFluidTicks(), protochunk.getInhabitedTime(), protochunk.getSections(), levelchunk_postloadprocessor, protochunk.getBlendingData());
+- Iterator iterator = protochunk.getBlockEntities().values().iterator();
++ // CraftBukkit start
++ public boolean mustNotSave;
++ public boolean needsDecoration;
++ // CraftBukkit end
+
+ while (iterator.hasNext()) {
+ BlockEntity blockentity = (BlockEntity) iterator.next();
+@@ -144,6 +145,10 @@
+ this.skyLightSources = protochunk.skyLightSources;
+ this.setLightCorrect(protochunk.isLightCorrect());
+ this.unsaved = true;
++ this.needsDecoration = true; // CraftBukkit
++ // CraftBukkit start
++ this.persistentDataContainer = chunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading.
++ // CraftBukkit end
+ }
+
+ @Override
+@@ -254,6 +253,7 @@
+ }
+ }
+
++ // CraftBukkit start
+ @Nullable
+ @Override
+ @Override
+@@ -262,7 +260,14 @@
+ LevelChunkSection levelchunksection = this.getSection(this.getSectionIndex(i));
+ boolean flag1 = levelchunksection.hasOnlyAir();
+
+- if (flag1 && blockstate.isAir()) {
++ @Nullable
++ public IBlockData setBlockState(BlockPos blockposition, IBlockData iblockdata, boolean flag, boolean doPlace) {
++ // CraftBukkit end
++ int i = blockposition.getY();
++ LevelChunkSection chunksection = this.getSection(this.getSectionIndex(i));
++ boolean flag1 = chunksection.hasOnlyAir();
++
++ if (flag1 && iblockdata.isAir()) {
+ return null;
+ } else {
+ int j = blockpos.getX() & 15;
+@@ -306,8 +311,9 @@
+ if (!levelchunksection.getBlockState(j, k, l).is(block)) {
+ return null;
+ } else {
+- if (!this.level.isClientSide) {
+- blockstate.onPlace(this.level, blockpos, blockstate1, flag);
++ // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
++ if (!this.level.isClientSide && doPlace && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) {
++ iblockdata.onPlace(this.level, blockposition, iblockdata1, flag);
+ }
+
+ if (blockstate.hasBlockEntity()) {
+@@ -352,8 +356,13 @@
+ }
+
+ @Nullable
+- public BlockEntity getBlockEntity(BlockPos blockpos, LevelChunk.EntityCreationType levelchunk_entitycreationtype) {
+- BlockEntity blockentity = (BlockEntity) this.blockEntities.get(blockpos);
++ public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EnumTileEntityState creationType) {
++ // CraftBukkit start
++ BlockEntity tileentity = level.capturedTileEntities.get(pos);
++ if (tileentity == null) {
++ tileentity = (BlockEntity) this.blockEntities.get(pos);
++ }
++ // CraftBukkit end
+
+ if (blockentity == null) {
+ CompoundTag compoundtag = (CompoundTag) this.pendingBlockEntities.remove(blockpos);
+@@ -432,6 +440,13 @@
+ blockentity1.setRemoved();
+ }
+
++ // CraftBukkit start
++ } else {
++ System.out.println("Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + "," + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
++ + " (" + getBlockState(blockposition) + ") where there was no entity tile!");
++ System.out.println("Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
++ new Exception().printStackTrace();
++ // CraftBukkit end
+ }
+ }
+
+@@ -463,8 +476,11 @@
+ if (this.isInLevel()) {
+ BlockEntity blockentity = (BlockEntity) this.blockEntities.remove(blockpos);
+
+- if (blockentity != null) {
+- Level level = this.level;
++ // CraftBukkit start - SPIGOT-5561: Also remove from pending map
++ if (!pendingBlockEntities.isEmpty()) {
++ pendingBlockEntities.remove(pos);
++ }
++ // CraftBukkit end
+
+ if (level instanceof ServerLevel) {
+ ServerLevel serverlevel = (ServerLevel) level;
+@@ -516,6 +535,57 @@
+
+ }
+
++ // CraftBukkit start
++ public void loadCallback() {
++ org.bukkit.Server server = this.level.getCraftServer();
++ 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.
++ */
++ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
++ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration));
++
++ if (this.needsDecoration) {
++ this.needsDecoration = false;
++ java.util.Random random = new java.util.Random();
++ random.setSeed(level.getSeed());
++ long xRand = random.nextLong() / 2L * 2L + 1L;
++ long zRand = random.nextLong() / 2L * 2L + 1L;
++ random.setSeed((long) this.chunkPos.x * xRand + (long) this.chunkPos.z * zRand ^ level.getSeed());
++
++ org.bukkit.World world = this.level.getWorld();
++ if (world != null) {
++ this.level.populating = true;
++ try {
++ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
++ populator.populate(world, random, bukkitChunk);
++ }
++ } finally {
++ this.level.populating = false;
++ }
++ }
++ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk));
++ }
++ }
++ }
++
++ public void unloadCallback() {
++ org.bukkit.Server server = this.level.getCraftServer();
++ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
++ org.bukkit.event.world.ChunkUnloadEvent unloadEvent = new org.bukkit.event.world.ChunkUnloadEvent(bukkitChunk, this.isUnsaved());
++ server.getPluginManager().callEvent(unloadEvent);
++ // note: saving can be prevented, but not forced if no saving is actually required
++ this.mustNotSave = !unloadEvent.isSaveChunk();
++ }
++
++ @Override
++ public boolean isUnsaved() {
++ return super.isUnsaved() && !this.mustNotSave;
++ }
++ // CraftBukkit end
++
+ public boolean isEmpty() {
+ return false;
+ }
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/LevelChunkSection.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/LevelChunkSection.java.patch
new file mode 100644
index 0000000000..87bf8fcc9d
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/LevelChunkSection.java.patch
@@ -0,0 +1,37 @@
+--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
++++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
+@@ -22,11 +22,13 @@
+ private short nonEmptyBlockCount;
+ private short tickingBlockCount;
+ private short tickingFluidCount;
+- private final PalettedContainer<BlockState> states;
+- private PalettedContainerRO<Holder<Biome>> biomes;
++ private final PalettedContainer<IBlockData> states;
++ // CraftBukkit start - read/write
++ private PalettedContainer<Holder<Biome>> biomes;
+
+- public LevelChunkSection(PalettedContainer<BlockState> palettedcontainer, PalettedContainerRO<Holder<Biome>> palettedcontainerro) {
+- this.states = palettedcontainer;
++ public LevelChunkSection(PalettedContainer<IBlockData> datapaletteblock, PalettedContainer<Holder<Biome>> palettedcontainerro) {
++ // CraftBukkit end
++ this.states = datapaletteblock;
+ this.biomes = palettedcontainerro;
+ this.recalcBlockCounts();
+ }
+@@ -189,8 +190,14 @@
+ return (Holder) this.biomes.get(i, j, k);
+ }
+
+- public void fillBiomesFromNoise(BiomeResolver biomeresolver, Climate.Sampler climate_sampler, int i, int j, int k) {
+- PalettedContainer<Holder<Biome>> palettedcontainer = this.biomes.recreate();
++ // CraftBukkit start
++ public void setBiome(int i, int j, int k, Holder<Biome> biome) {
++ this.biomes.set(i, j, k, biome);
++ }
++ // CraftBukkit end
++
++ public void fillBiomesFromNoise(BiomeResolver biomeResolver, Climate.Sampler climateSampler, int x, int y, int z) {
++ PalettedContainer<Holder<Biome>> datapaletteblock = this.biomes.recreate();
+ boolean flag = true;
+
+ for (int l = 0; l < 4; ++l) {
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/ChunkSerializer.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/ChunkSerializer.java.patch
new file mode 100644
index 0000000000..1f6ebd7010
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/ChunkSerializer.java.patch
@@ -0,0 +1,94 @@
+--- a/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
++++ b/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
+@@ -93,16 +93,16 @@
+ ChunkSerializer.LOGGER.error("Chunk file at {} is in the wrong location; relocating. (Expected {}, got {})", new Object[]{chunkpos, chunkpos, chunkpos1});
+ }
+
+- UpgradeData upgradedata = compoundtag.contains("UpgradeData", 10) ? new UpgradeData(compoundtag.getCompound("UpgradeData"), serverlevel) : UpgradeData.EMPTY;
+- boolean flag = compoundtag.getBoolean("isLightOn");
+- ListTag listtag = compoundtag.getList("sections", 10);
+- int i = serverlevel.getSectionsCount();
+- LevelChunkSection[] alevelchunksection = new LevelChunkSection[i];
+- boolean flag1 = serverlevel.dimensionType().hasSkyLight();
+- ServerChunkCache serverchunkcache = serverlevel.getChunkSource();
+- LevelLightEngine levellightengine = serverchunkcache.getLightEngine();
+- Registry<Biome> registry = serverlevel.registryAccess().registryOrThrow(Registries.BIOME);
+- Codec<PalettedContainerRO<Holder<Biome>>> codec = makeBiomeCodec(registry);
++ UpgradeData chunkconverter = tag.contains("UpgradeData", 10) ? new UpgradeData(tag.getCompound("UpgradeData"), level) : UpgradeData.EMPTY;
++ boolean flag = tag.getBoolean("isLightOn");
++ ListTag nbttaglist = tag.getList("sections", 10);
++ int i = level.getSectionsCount();
++ LevelChunkSection[] achunksection = new LevelChunkSection[i];
++ boolean flag1 = level.dimensionType().hasSkyLight();
++ ServerChunkCache chunkproviderserver = level.getChunkSource();
++ LevelLightEngine levellightengine = chunkproviderserver.getLightEngine();
++ Registry<Biome> iregistry = level.registryAccess().registryOrThrow(Registries.BIOME);
++ Codec<PalettedContainer<Holder<Biome>>> codec = makeBiomeCodecRW(iregistry); // CraftBukkit - read/write
+ boolean flag2 = false;
+
+ DataResult dataresult;
+@@ -127,7 +127,7 @@
+ palettedcontainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
+ }
+
+- Object object;
++ PalettedContainer object; // CraftBukkit - read/write
+
+ if (compoundtag1.contains("biomes", 10)) {
+ dataresult = codec.parse(NbtOps.INSTANCE, compoundtag1.getCompound("biomes")).promotePartial((s) -> {
+@@ -140,7 +140,7 @@
+ object = new PalettedContainer<>(registry.asHolderIdMap(), registry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
+ }
+
+- LevelChunkSection levelchunksection = new LevelChunkSection(palettedcontainer, (PalettedContainerRO) object);
++ LevelChunkSection chunksection = new LevelChunkSection(datapaletteblock, (PalettedContainer) object); // CraftBukkit - read/write
+
+ alevelchunksection[k] = levelchunksection;
+ SectionPos sectionpos = SectionPos.of(chunkpos, b0);
+@@ -221,6 +221,13 @@
+ }
+ }
+
++ // CraftBukkit start - load chunk persistent data from nbt - SPIGOT-6814: Already load PDC here to account for 1.17 to 1.18 chunk upgrading.
++ net.minecraft.nbt.Tag persistentBase = tag.get("ChunkBukkitValues");
++ if (persistentBase instanceof CompoundTag) {
++ ((ChunkAccess) object1).persistentDataContainer.putAll((CompoundTag) persistentBase);
++ }
++ // CraftBukkit end
++
+ ((ChunkAccess) object1).setLightCorrect(flag);
+ CompoundTag compoundtag2 = compoundtag.getCompound("Heightmaps");
+ EnumSet<Heightmap.Types> enumset = EnumSet.noneOf(Heightmap.Types.class);
+@@ -300,9 +307,11 @@
+ return PalettedContainer.codecRO(registry.asHolderIdMap(), registry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, registry.getHolderOrThrow(Biomes.PLAINS));
+ }
+
+- public static CompoundTag write(ServerLevel serverlevel, ChunkAccess chunkaccess) {
+- ChunkPos chunkpos = chunkaccess.getPos();
+- CompoundTag compoundtag = NbtUtils.addCurrentDataVersion(new CompoundTag());
++ // CraftBukkit start - read/write
++ private static Codec<PalettedContainer<Holder<Biome>>> makeBiomeCodecRW(Registry<Biome> iregistry) {
++ return PalettedContainer.codecRW(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getHolderOrThrow(Biomes.PLAINS));
++ }
++ // CraftBukkit end
+
+ compoundtag.putInt("xPos", chunkpos.x);
+ compoundtag.putInt("yPos", chunkaccess.getMinSection());
+@@ -439,9 +452,14 @@
+ }
+ }
+
+- compoundtag.put("Heightmaps", compoundtag3);
+- compoundtag.put("structures", packStructureData(StructurePieceSerializationContext.fromLevel(serverlevel), chunkpos, chunkaccess.getAllStarts(), chunkaccess.getAllReferences()));
+- return compoundtag;
++ nbttagcompound.put("Heightmaps", nbttagcompound3);
++ nbttagcompound.put("structures", packStructureData(StructurePieceSerializationContext.fromLevel(level), chunkcoordintpair, chunk.getAllStarts(), chunk.getAllReferences()));
++ // CraftBukkit start - store chunk persistent data in nbt
++ if (!chunk.persistentDataContainer.isEmpty()) { // SPIGOT-6814: Always save PDC to account for 1.17 to 1.18 chunk upgrading.
++ nbttagcompound.put("ChunkBukkitValues", chunk.persistentDataContainer.toTagCompound());
++ }
++ // CraftBukkit end
++ return nbttagcompound;
+ }
+
+ private static void saveTicks(ServerLevel serverlevel, CompoundTag compoundtag, ChunkAccess.TicksToSave chunkaccess_tickstosave) {
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/ChunkStorage.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/ChunkStorage.java.patch
new file mode 100644
index 0000000000..b8f6e2e997
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/ChunkStorage.java.patch
@@ -0,0 +1,91 @@
+--- a/net/minecraft/world/level/chunk/storage/ChunkStorage.java
++++ b/net/minecraft/world/level/chunk/storage/ChunkStorage.java
+@@ -16,6 +18,10 @@
+ import net.minecraft.world.level.ChunkPos;
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.chunk.ChunkGenerator;
++// CraftBukkit start
++import java.util.concurrent.ExecutionException;
++import net.minecraft.world.level.chunk.ChunkStatus;
++import net.minecraft.world.level.dimension.LevelStem;
+ import net.minecraft.world.level.levelgen.structure.LegacyStructureDataHandler;
+ import net.minecraft.world.level.storage.DimensionDataStorage;
+
+@@ -36,9 +42,53 @@
+ return this.worker.isOldChunkAround(chunkpos, i);
+ }
+
+- public CompoundTag upgradeChunkTag(ResourceKey<Level> resourcekey, Supplier<DimensionDataStorage> supplier, CompoundTag compoundtag, Optional<ResourceKey<Codec<? extends ChunkGenerator>>> optional) {
+- int i = getVersion(compoundtag);
++ // CraftBukkit start
++ private boolean check(ServerChunkCache cps, int x, int z) {
++ ChunkPos pos = new ChunkPos(x, z);
++ if (cps != null) {
++ com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread");
++ if (cps.hasChunk(x, z)) {
++ return true;
++ }
++ }
+
++ CompoundTag nbt;
++ try {
++ nbt = read(pos).get().orElse(null);
++ } catch (InterruptedException | ExecutionException ex) {
++ throw new RuntimeException(ex);
++ }
++ if (nbt != null) {
++ CompoundTag level = nbt.getCompound("Level");
++ if (level.getBoolean("TerrainPopulated")) {
++ return true;
++ }
++
++ ChunkStatus status = ChunkStatus.byName(level.getString("Status"));
++ if (status != null && status.isOrAfter(ChunkStatus.FEATURES)) {
++ return true;
++ }
++ }
++
++ return false;
++ }
++
++ public CompoundTag upgradeChunkTag(ResourceKey<LevelStem> resourcekey, Supplier<DimensionDataStorage> supplier, CompoundTag nbttagcompound, Optional<ResourceKey<Codec<? extends ChunkGenerator>>> optional, ChunkPos pos, @Nullable LevelAccessor generatoraccess) {
++ // CraftBukkit end
++ int i = getVersion(nbttagcompound);
++
++ // CraftBukkit start
++ if (i < 1466) {
++ CompoundTag level = nbttagcompound.getCompound("Level");
++ if (level.getBoolean("TerrainPopulated") && !level.getBoolean("LightPopulated")) {
++ ServerChunkCache cps = (generatoraccess == null) ? null : ((ServerLevel) generatoraccess).getChunkSource();
++ if (check(cps, pos.x - 1, pos.z) && check(cps, pos.x - 1, pos.z - 1) && check(cps, pos.x, pos.z - 1)) {
++ level.putBoolean("LightPopulated", true);
++ }
++ }
++ }
++ // CraftBukkit end
++
+ if (i < 1493) {
+ compoundtag = DataFixTypes.CHUNK.update(this.fixerUpper, compoundtag, i, 1493);
+ if (compoundtag.getCompound("Level").getBoolean("hasLegacyStructureData")) {
+@@ -58,8 +108,8 @@
+ return compoundtag;
+ }
+
+- private LegacyStructureDataHandler getLegacyStructureHandler(ResourceKey<Level> resourcekey, Supplier<DimensionDataStorage> supplier) {
+- LegacyStructureDataHandler legacystructuredatahandler = this.legacyStructureHandler;
++ private LegacyStructureDataHandler getLegacyStructureHandler(ResourceKey<LevelStem> level, Supplier<DimensionDataStorage> storage) { // CraftBukkit
++ LegacyStructureDataHandler persistentstructurelegacy = this.legacyStructureHandler;
+
+ if (legacystructuredatahandler == null) {
+ synchronized (this) {
+@@ -73,8 +123,8 @@
+ return legacystructuredatahandler;
+ }
+
+- public static void injectDatafixingContext(CompoundTag compoundtag, ResourceKey<Level> resourcekey, Optional<ResourceKey<Codec<? extends ChunkGenerator>>> optional) {
+- CompoundTag compoundtag1 = new CompoundTag();
++ public static void injectDatafixingContext(CompoundTag chunkData, ResourceKey<LevelStem> levelKey, Optional<ResourceKey<Codec<? extends ChunkGenerator>>> chunkGeneratorKey) { // CraftBukkit
++ CompoundTag nbttagcompound1 = new CompoundTag();
+
+ compoundtag1.putString("dimension", resourcekey.location().toString());
+ optional.ifPresent((resourcekey1) -> {
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/RegionFile.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/RegionFile.java.patch
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/RegionFile.java.patch
@@ -0,0 +1 @@
+
diff --git a/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch
new file mode 100644
index 0000000000..ce9acb3765
--- /dev/null
+++ b/patch-remap/mache-spigotflower-stripped/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch
@@ -0,0 +1,72 @@
+--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
++++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+@@ -30,8 +30,8 @@
+ this.sync = flag;
+ }
+
+- private RegionFile getRegionFile(ChunkPos chunkpos) throws IOException {
+- long i = ChunkPos.asLong(chunkpos.getRegionX(), chunkpos.getRegionZ());
++ private RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit
++ long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ());
+ RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i);
+
+ if (regionfile != null) {
+@@ -43,8 +43,9 @@
+
+ FileUtil.createDirectoriesSafe(this.folder);
+ Path path = this.folder;
+- int j = chunkpos.getRegionX();
+- Path path1 = path.resolve("r." + j + "." + chunkpos.getRegionZ() + ".mca");
++ int j = chunkcoordintpair.getRegionX();
++ Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca");
++ if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit
+ RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync);
+
+ this.regionCache.putAndMoveToFirst(i, regionfile1);
+@@ -53,9 +54,14 @@
+ }
+
+ @Nullable
+- public CompoundTag read(ChunkPos chunkpos) throws IOException {
+- RegionFile regionfile = this.getRegionFile(chunkpos);
+- DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkpos);
++ public CompoundTag read(ChunkPos chunkPos) throws IOException {
++ // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
++ RegionFile regionfile = this.getRegionFile(chunkPos, true);
++ if (regionfile == null) {
++ return null;
++ }
++ // CraftBukkit end
++ DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkPos);
+
+ CompoundTag compoundtag;
+ label43:
+@@ -93,9 +99,14 @@
+ return compoundtag;
+ }
+
+- public void scanChunk(ChunkPos chunkpos, StreamTagVisitor streamtagvisitor) throws IOException {
+- RegionFile regionfile = this.getRegionFile(chunkpos);
+- DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkpos);
++ public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException {
++ // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
++ RegionFile regionfile = this.getRegionFile(chunkPos, true);
++ if (regionfile == null) {
++ return;
++ }
++ // CraftBukkit end
++ DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkPos);
+
+ try {
+ if (datainputstream != null) {
+@@ -119,8 +130,8 @@
+
+ }
+
+- protected void write(ChunkPos chunkpos, @Nullable CompoundTag compoundtag) throws IOException {
+- RegionFile regionfile = this.getRegionFile(chunkpos);
++ protected void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException {
++ RegionFile regionfile = this.getRegionFile(chunkPos, false); // CraftBukkit
+
+ if (compoundtag == null) {
+ regionfile.clear(chunkpos);