fix: improve biome setting to avoid writing directly to chunk (#2757)

* 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

* Remove self-refraction-check
This commit is contained in:
Jordan 2024-06-15 13:08:42 +02:00 committed by GitHub
parent 8aba1e6c06
commit af83b2f9c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 252 additions and 164 deletions

View File

@ -511,7 +511,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); PalettedContainer<Holder<Biome>> 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) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES, PalettedContainer.Strategy.SECTION_BIOMES,
null null
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
@ -625,15 +628,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
existingSection.getBiomes() existingSection.getBiomes()
); );
newSection = newSection = PaperweightPlatformAdapter.newChunkSection(
PaperweightPlatformAdapter.newChunkSection( layerNo,
layerNo, this::loadPrivately,
this::loadPrivately, setArr,
setArr, adapter,
adapter, biomeRegistry,
biomeRegistry, biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
biomeData );
);
if (!PaperweightPlatformAdapter.setSectionAtomic( if (!PaperweightPlatformAdapter.setSectionAtomic(
levelChunkSections, levelChunkSections,
existingSection, existingSection,
@ -845,7 +847,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -1103,9 +1105,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
final int sectionIndex, final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data final PalettedContainerRO<Holder<Biome>> data
) { ) {
BiomeType[] sectionBiomes;
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return null;
}
PalettedContainer<Holder<Biome>> biomeData; PalettedContainer<Holder<Biome>> biomeData;
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) { if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomeData = palettedContainer; biomeData = palettedContainer.copy();
} else { } else {
LOGGER.warn( LOGGER.warn(
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + "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(); 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 y = 0, index = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) { for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) { for (int x = 0; x < 4; x++, index++) {
@ -1130,10 +1132,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }

View File

@ -98,7 +98,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldTickingFluidCount; private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount; private static final Field fieldBiomes;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
@ -139,8 +139,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f")); fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "j"));
fieldNonEmptyBlockCount.setAccessible(true); fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent", "getVisibleChunkIfPresent",
@ -502,6 +502,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return new LevelChunkSection(layer, dataPaletteBlocks, biomes); return new LevelChunkSection(layer, dataPaletteBlocks, biomes);
} }
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
}
/** /**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand. * Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/ */

View File

@ -510,7 +510,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); PalettedContainer<Holder<Biome>> 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) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES PalettedContainer.Strategy.SECTION_BIOMES
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
newSection = PaperweightPlatformAdapter.newChunkSection( newSection = PaperweightPlatformAdapter.newChunkSection(
@ -623,15 +626,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
existingSection.getBiomes() existingSection.getBiomes()
); );
newSection = newSection = PaperweightPlatformAdapter.newChunkSection(
PaperweightPlatformAdapter.newChunkSection( layerNo,
layerNo, this::loadPrivately,
this::loadPrivately, setArr,
setArr, adapter,
adapter, biomeRegistry,
biomeRegistry, biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
biomeData );
);
if (!PaperweightPlatformAdapter.setSectionAtomic( if (!PaperweightPlatformAdapter.setSectionAtomic(
levelChunkSections, levelChunkSections,
existingSection, existingSection,
@ -843,7 +845,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -1100,9 +1102,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
final int sectionIndex, final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data final PalettedContainerRO<Holder<Biome>> data
) { ) {
BiomeType[] sectionBiomes;
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return null;
}
PalettedContainer<Holder<Biome>> biomeData; PalettedContainer<Holder<Biome>> biomeData;
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) { if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomeData = palettedContainer; biomeData = palettedContainer.copy();
} else { } else {
LOGGER.warn( LOGGER.warn(
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + "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(); 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 y = 0, index = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) { for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) { for (int x = 0; x < 4; x++, index++) {
@ -1127,10 +1129,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }

View File

@ -62,7 +62,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R1.CraftChunk; import org.bukkit.craftbukkit.v1_20_R1.CraftChunk;
import sun.misc.Unsafe;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -102,7 +101,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldTickingFluidCount; private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
@ -111,6 +109,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodRemoveGameEventListener;
private static final MethodHandle methodremoveTickingBlockEntity; private static final MethodHandle methodremoveTickingBlockEntity;
private static final Field fieldBiomes;
private static final Field fieldOffers; private static final Field fieldOffers;
private static final MerchantOffers OFFERS = new MerchantOffers(); private static final MerchantOffers OFFERS = new MerchantOffers();
@ -149,8 +148,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i"));
fieldNonEmptyBlockCount.setAccessible(true); fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent", "getVisibleChunkIfPresent",
@ -417,7 +416,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes); return newChunkSection(biomeRegistry, biomes);
} }
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
@ -507,7 +506,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@SuppressWarnings("deprecation") // Only deprecated in paper @SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection( private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
@ -522,6 +520,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return new LevelChunkSection(dataPaletteBlocks, biomes); return new LevelChunkSection(dataPaletteBlocks, biomes);
} }
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
}
/** /**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand. * Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/ */

View File

@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent; 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.nbt.IntTag;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents; 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.BeaconBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.Logger; 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 org.bukkit.event.entity.CreatureSpawnEvent;
import javax.annotation.Nonnull; 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.Callable;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -497,7 +518,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); PalettedContainer<Holder<Biome>> 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) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES PalettedContainer.Strategy.SECTION_BIOMES
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
newSection = PaperweightPlatformAdapter.newChunkSection( newSection = PaperweightPlatformAdapter.newChunkSection(
@ -610,15 +634,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
existingSection.getBiomes() existingSection.getBiomes()
); );
newSection = newSection = PaperweightPlatformAdapter.newChunkSection(
PaperweightPlatformAdapter.newChunkSection( layerNo,
layerNo, this::loadPrivately,
this::loadPrivately, setArr,
setArr, adapter,
adapter, biomeRegistry,
biomeRegistry, biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
biomeData );
);
if (!PaperweightPlatformAdapter.setSectionAtomic( if (!PaperweightPlatformAdapter.setSectionAtomic(
levelChunkSections, levelChunkSections,
existingSection, existingSection,
@ -830,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -1087,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
final int sectionIndex, final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data final PalettedContainerRO<Holder<Biome>> data
) { ) {
BiomeType[] sectionBiomes;
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return null;
}
PalettedContainer<Holder<Biome>> biomeData; PalettedContainer<Holder<Biome>> biomeData;
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) { if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomeData = palettedContainer; biomeData = palettedContainer.copy();
} else { } else {
LOGGER.warn( LOGGER.warn(
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + "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(); 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 y = 0, index = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) { for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) { for (int x = 0; x < 4; x++, index++) {
@ -1114,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }

View File

@ -59,7 +59,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R2.CraftChunk; import org.bukkit.craftbukkit.v1_20_R2.CraftChunk;
import sun.misc.Unsafe;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -99,7 +98,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldTickingFluidCount; private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
@ -108,6 +106,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodRemoveGameEventListener;
private static final MethodHandle methodremoveTickingBlockEntity; 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 * 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
@ -143,8 +142,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i"));
fieldNonEmptyBlockCount.setAccessible(true); fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent", "getVisibleChunkIfPresent",
@ -408,7 +407,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes); return newChunkSection(biomeRegistry, biomes);
} }
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
@ -498,7 +497,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@SuppressWarnings("deprecation") // Only deprecated in paper @SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection( private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
@ -513,6 +511,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return new LevelChunkSection(dataPaletteBlocks, biomes); return new LevelChunkSection(dataPaletteBlocks, biomes);
} }
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
}
/** /**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand. * Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/ */

View File

@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent; 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.nbt.IntTag;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents; 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.BeaconBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.Logger; 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 org.bukkit.event.entity.CreatureSpawnEvent;
import javax.annotation.Nonnull; 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.Callable;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -496,7 +517,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
biomes,
setSectionIndex,
existingSection.getBiomes()
);
if (paletteBiomes != null) {
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
}
} }
} }
} }
@ -538,11 +566,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (existingSection == null) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES PalettedContainer.Strategy.SECTION_BIOMES
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
newSection = PaperweightPlatformAdapter.newChunkSection( newSection = PaperweightPlatformAdapter.newChunkSection(
@ -609,15 +633,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
existingSection.getBiomes() existingSection.getBiomes()
); );
newSection = newSection = PaperweightPlatformAdapter.newChunkSection(
PaperweightPlatformAdapter.newChunkSection( layerNo,
layerNo, this::loadPrivately,
this::loadPrivately, setArr,
setArr, adapter,
adapter, biomeRegistry,
biomeRegistry, biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
biomeData );
);
if (!PaperweightPlatformAdapter.setSectionAtomic( if (!PaperweightPlatformAdapter.setSectionAtomic(
levelChunkSections, levelChunkSections,
existingSection, existingSection,
@ -829,7 +852,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -1084,9 +1107,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
final int sectionIndex, final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data final PalettedContainerRO<Holder<Biome>> data
) { ) {
BiomeType[] sectionBiomes;
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return null;
}
PalettedContainer<Holder<Biome>> biomeData; PalettedContainer<Holder<Biome>> biomeData;
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) { if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomeData = palettedContainer; biomeData = palettedContainer.copy();
} else { } else {
LOGGER.warn( LOGGER.warn(
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + "Cannot correctly set biomes to world, existing biomes may be lost. Expected class " +
@ -1096,10 +1123,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
); );
biomeData = data.recreate(); 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 y = 0, index = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) { for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) { for (int x = 0; x < 4; x++, index++) {
@ -1111,10 +1134,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }

View File

@ -98,7 +98,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldTickingFluidCount; private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount; private static final Field fieldBiomes;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
@ -142,8 +142,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i"));
fieldNonEmptyBlockCount.setAccessible(true); fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent", "getVisibleChunkIfPresent",
@ -407,7 +407,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes); return newChunkSection(biomeRegistry, biomes);
} }
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
@ -497,7 +497,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@SuppressWarnings("deprecation") // Only deprecated in paper @SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection( private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
@ -512,6 +511,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return new LevelChunkSection(dataPaletteBlocks, biomes); return new LevelChunkSection(dataPaletteBlocks, biomes);
} }
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
}
/** /**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand. * Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/ */

View File

@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import io.papermc.paper.event.block.BeaconDeactivatedEvent; 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.nbt.IntTag;
import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel; 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.BeaconBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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.levelgen.Heightmap;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -53,7 +64,17 @@ import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import javax.annotation.Nonnull; 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.Callable;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -499,7 +520,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
} }
} else { } else {
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes()); PalettedContainer<Holder<Biome>> 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) { if (existingSection == null) {
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>( PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
biomeHolderIdMap, biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES PalettedContainer.Strategy.SECTION_BIOMES
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
newSection = PaperweightPlatformAdapter.newChunkSection( newSection = PaperweightPlatformAdapter.newChunkSection(
@ -612,18 +636,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
existingSection.getBiomes() existingSection.getBiomes()
); );
newSection = newSection = PaperweightPlatformAdapter.newChunkSection(
PaperweightPlatformAdapter.newChunkSection( layerNo,
layerNo, this::loadPrivately,
this::loadPrivately, setArr,
setArr, adapter,
adapter, biomeRegistry,
biomeRegistry, biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
biomeData );
); if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection,
if (!PaperweightPlatformAdapter.setSectionAtomic(
levelChunkSections,
existingSection,
newSection, newSection,
getSectionIndex getSectionIndex
)) { )) {
@ -832,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
if (callback == null) { if (callback == null) {
if (finalizer != null) { if (finalizer != null) {
finalizer.run(); queueHandler.async(finalizer, null);
} }
return null; return null;
} else { } else {
@ -1089,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
final int sectionIndex, final int sectionIndex,
final PalettedContainerRO<Holder<Biome>> data final PalettedContainerRO<Holder<Biome>> data
) { ) {
BiomeType[] sectionBiomes;
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
return null;
}
PalettedContainer<Holder<Biome>> biomeData; PalettedContainer<Holder<Biome>> biomeData;
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) { if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
biomeData = palettedContainer; biomeData = palettedContainer.copy();
} else { } else {
LOGGER.warn( LOGGER.warn(
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " + "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(); 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 y = 0, index = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) { for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) { for (int x = 0; x < 4; x++, index++) {
@ -1116,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
x, x,
y, y,
z, z,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType))
); );
} }
} }

View File

@ -10,7 +10,6 @@ import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils; import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TaskManager;
import com.mojang.datafixers.util.Either;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.bukkit.adapter.Refraction;
@ -77,7 +76,6 @@ import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -98,7 +96,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
private static final Field fieldTickingFluidCount; private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount; private static final Field fieldBiomes;
private static final MethodHandle methodGetVisibleChunk; private static final MethodHandle methodGetVisibleChunk;
@ -142,8 +140,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
fieldTickingFluidCount.setAccessible(true); fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
fieldTickingBlockCount.setAccessible(true); fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e")); fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i"));
fieldNonEmptyBlockCount.setAccessible(true); fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent", "getVisibleChunkIfPresent",
@ -405,7 +403,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
if (set == null) { if (set == null) {
return newChunkSection(layer, biomeRegistry, biomes); return newChunkSection(biomeRegistry, biomes);
} }
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get(); final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get(); final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
@ -495,7 +493,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
@SuppressWarnings("deprecation") // Only deprecated in paper @SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection( private static LevelChunkSection newChunkSection(
int layer,
Registry<Biome> biomeRegistry, Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes @Nullable PalettedContainer<Holder<Biome>> biomes
) { ) {
@ -510,6 +507,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return new LevelChunkSection(dataPaletteBlocks, biomes); return new LevelChunkSection(dataPaletteBlocks, biomes);
} }
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
}
/** /**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand. * Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/ */