From 362e946fdbc5accf9bba6f05c016ca3971a57f01 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 2 Jun 2024 17:16:16 +0100 Subject: [PATCH] fix: improve biome setting to avoid writing directly to chunk - Removes possibility of writing to the LevelChunkSection biomes PalettedContainer whilst it is being read for sending packets - I believe this occured mostly on clipboard operations where blocks are written before biomes, so chunks are being sent whilst writing biomes - This would explain why the error reported in the below issue (and others) is/was so rare - Of course I could be completely wrong about all of this, but given the line in LevelChunkSection#write that the error seems to consistently occur on is when writing biomes to the packet, and that the only place I can find in FAWE where we write to a "live" PalettedContainer is for biomes, I am reasonably confident that this is the cause - Should address #2729 --- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 49 ++++++------ .../v1_19_R3/PaperweightPlatformAdapter.java | 21 ++++- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 49 ++++++------ .../v1_20_R1/PaperweightPlatformAdapter.java | 25 ++++-- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 76 +++++++++++------- .../v1_20_R2/PaperweightPlatformAdapter.java | 25 ++++-- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 76 +++++++++++------- .../v1_20_R3/PaperweightPlatformAdapter.java | 24 ++++-- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 80 ++++++++++++------- .../v1_20_R4/PaperweightPlatformAdapter.java | 26 ++++-- 10 files changed, 287 insertions(+), 164 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java index 744314d7b..e54f5e006 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java @@ -511,7 +511,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -553,11 +560,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES, null ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); @@ -625,15 +628,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, @@ -845,7 +847,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1103,9 +1105,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1115,10 +1121,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1130,10 +1132,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java index d0ce1c555..3b42c4378 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java @@ -97,7 +97,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; + private static final Field fieldBiomes; private static final MethodHandle methodGetVisibleChunk; @@ -138,8 +138,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); - fieldNonEmptyBlockCount.setAccessible(true); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "j" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("j"); + } + fieldBiomes = tmpFieldBiomes; + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -497,6 +504,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(layer, dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index b3e737a51..7c54c4f76 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java @@ -510,7 +510,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -552,11 +559,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -623,15 +626,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, @@ -843,7 +845,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1100,9 +1102,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1112,10 +1118,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1127,10 +1129,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java index 8083e3fde..4651db561 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java @@ -61,7 +61,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_20_R1.CraftChunk; -import sun.misc.Unsafe; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -101,7 +100,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; private static final MethodHandle methodGetVisibleChunk; @@ -110,6 +108,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldBiomes; private static final Field fieldOffers; private static final MerchantOffers OFFERS = new MerchantOffers(); @@ -148,8 +147,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); - fieldNonEmptyBlockCount.setAccessible(true); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "i" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); + } + fieldBiomes = tmpFieldBiomes; + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -412,7 +418,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); + return newChunkSection(biomeRegistry, biomes); } final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); @@ -502,7 +508,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -517,6 +522,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java index b73b54da2..5b597d36d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightGetBlocks.java @@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.IntTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; @@ -42,7 +46,14 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.Logger; @@ -52,7 +63,17 @@ import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -497,7 +518,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -539,11 +567,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -610,15 +634,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, @@ -830,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1087,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1099,10 +1126,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1114,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index 9ab6b0602..ad754293d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -58,7 +58,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_20_R2.CraftChunk; -import sun.misc.Unsafe; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -98,7 +97,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; private static final MethodHandle methodGetVisibleChunk; @@ -107,6 +105,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; + private static final Field fieldBiomes; /* * This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -142,8 +141,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); - fieldNonEmptyBlockCount.setAccessible(true); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "i" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); + } + fieldBiomes = tmpFieldBiomes; + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -403,7 +409,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); + return newChunkSection(biomeRegistry, biomes); } final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); @@ -493,7 +499,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -508,6 +513,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java index 2ee208902..e666107b8 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightGetBlocks.java @@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.IntTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; @@ -42,7 +46,14 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.Logger; @@ -52,7 +63,17 @@ import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -497,7 +518,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -539,11 +567,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -610,15 +634,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); if (!PaperweightPlatformAdapter.setSectionAtomic( levelChunkSections, existingSection, @@ -830,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1087,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1099,10 +1126,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1114,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index 23de00ade..94f343878 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -97,7 +97,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; + private static final Field fieldBiomes; private static final MethodHandle methodGetVisibleChunk; @@ -141,8 +141,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); - fieldNonEmptyBlockCount.setAccessible(true); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "i" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); + } + fieldBiomes = tmpFieldBiomes; + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -402,7 +409,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); + return newChunkSection(biomeRegistry, biomes); } final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); @@ -492,7 +499,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -507,6 +513,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */ diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java index 20da2079c..0b809b174 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightGetBlocks.java @@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import io.papermc.lib.PaperLib; import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.IdMap; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.IntTag; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ServerLevel; @@ -43,7 +47,14 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.HashMapPalette; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.LinearPalette; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.Logger; @@ -53,7 +64,17 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; import javax.annotation.Nonnull; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; @@ -499,7 +520,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } } } else { - setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); + PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( + biomes, + setSectionIndex, + existingSection.getBiomes() + ); + if (paletteBiomes != null) { + PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); + } } } } @@ -541,11 +569,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (existingSection == null) { PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId( - BiomeTypes.PLAINS)), + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), PalettedContainer.Strategy.SECTION_BIOMES ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); newSection = PaperweightPlatformAdapter.newChunkSection( @@ -612,18 +636,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc existingSection.getBiomes() ); - newSection = - PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, + newSection = PaperweightPlatformAdapter.newChunkSection( + layerNo, + this::loadPrivately, + setArr, + adapter, + biomeRegistry, + biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() + ); + if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection, newSection, getSectionIndex )) { @@ -832,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1089,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc final int sectionIndex, final PalettedContainerRO> data ) { + BiomeType[] sectionBiomes; + if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { + return null; + } PalettedContainer> biomeData; if (data instanceof PalettedContainer> palettedContainer) { - biomeData = palettedContainer; + biomeData = palettedContainer.copy(); } else { LOGGER.warn( "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + @@ -1101,10 +1126,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc ); biomeData = data.recreate(); } - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return biomeData; - } for (int y = 0, index = 0; y < 4; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++, index++) { @@ -1116,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc x, y, z, - biomeHolderIdMap.byIdOrThrow(WorldEditPlugin - .getInstance() - .getBukkitImplAdapter() - .getInternalBiomeId(biomeType)) + biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 4f934129e..94874dee5 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -10,7 +10,6 @@ import com.fastasyncworldedit.core.math.BitArrayUnstretched; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.datafixers.util.Either; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -76,7 +75,6 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -97,7 +95,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldNonEmptyBlockCount; + private static final Field fieldBiomes; private static final MethodHandle methodGetVisibleChunk; @@ -141,8 +139,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); - fieldNonEmptyBlockCount.setAccessible(true); + Field tmpFieldBiomes; + try { + // It seems to actually be biomes, but is apparently obfuscated to "i" + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); + } + fieldBiomes = tmpFieldBiomes; + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -400,7 +405,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @Nullable PalettedContainer> biomes ) { if (set == null) { - return newChunkSection(layer, biomeRegistry, biomes); + return newChunkSection(biomeRegistry, biomes); } final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); @@ -490,7 +495,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -505,6 +509,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return new LevelChunkSection(dataPaletteBlocks, biomes); } + public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer> biomes) { + try { + fieldBiomes.set(section, biomes); + } catch (IllegalAccessException e) { + LOGGER.error("Could not set biomes to chunk section", e); + } + } + /** * Create a new {@link PalettedContainer}. Should only be used if no biome container existed beforehand. */