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 b3eb30c0e..14c6f1d7b 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 @@ -494,7 +494,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); + } } } } @@ -536,11 +543,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); @@ -608,15 +611,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, @@ -828,7 +830,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1086,9 +1088,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 " + @@ -1098,10 +1104,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++) { @@ -1113,10 +1115,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 0a7453578..ccd6ed982 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 @@ -98,7 +98,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; @@ -139,8 +139,8 @@ 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); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "j")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -502,6 +502,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 f8ca98d7d..1fc8fa71b 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 @@ -493,7 +493,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); + } } } } @@ -535,11 +542,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( @@ -606,15 +609,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, @@ -826,7 +828,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1083,9 +1085,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 " + @@ -1095,10 +1101,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++) { @@ -1110,10 +1112,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 74eec9195..999dd3646 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 @@ -62,7 +62,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; @@ -102,7 +101,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; @@ -111,6 +109,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(); @@ -149,8 +148,8 @@ 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); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -417,7 +416,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(); @@ -507,7 +506,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -522,6 +520,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 f50dc5755..63e006cac 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 @@ -31,7 +31,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; @@ -44,7 +48,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; @@ -54,7 +65,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; @@ -479,7 +500,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); + } } } } @@ -521,11 +549,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( @@ -592,15 +616,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, @@ -812,7 +835,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1069,9 +1092,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 " + @@ -1081,10 +1108,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++) { @@ -1096,10 +1119,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 29d7278a5..721758c3e 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 @@ -59,7 +59,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; @@ -99,7 +98,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; @@ -108,6 +106,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 @@ -143,8 +142,8 @@ 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); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -408,7 +407,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(); @@ -498,7 +497,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -513,6 +511,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 467dade08..c82e23d19 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 @@ -31,7 +31,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; @@ -44,7 +48,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; @@ -54,7 +65,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; @@ -478,7 +499,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); + } } } } @@ -520,11 +548,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( @@ -591,15 +615,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, @@ -811,7 +834,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1066,9 +1089,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 " + @@ -1078,10 +1105,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++) { @@ -1093,10 +1116,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 2f25bc6f1..fb655322b 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 @@ -98,7 +98,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; @@ -142,8 +142,8 @@ 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); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -407,7 +407,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(); @@ -497,7 +497,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -512,6 +511,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 b92348d6f..956fb7e64 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 @@ -31,7 +31,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; @@ -45,7 +49,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; @@ -54,7 +65,16 @@ import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.event.entity.CreatureSpawnEvent; -import java.util.*; +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; @@ -479,7 +499,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); + } } } } @@ -521,11 +548,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( @@ -592,18 +615,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 )) { @@ -812,7 +832,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } if (callback == null) { if (finalizer != null) { - finalizer.run(); + queueHandler.async(finalizer, null); } return null; } else { @@ -1069,9 +1089,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 " + @@ -1081,10 +1105,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++) { @@ -1096,10 +1116,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 76a7a9025..6c0f72590 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; @@ -77,7 +76,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; @@ -98,7 +96,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; @@ -142,8 +140,8 @@ 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); + fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", @@ -405,7 +403,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(); @@ -495,7 +493,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { @SuppressWarnings("deprecation") // Only deprecated in paper private static LevelChunkSection newChunkSection( - int layer, Registry biomeRegistry, @Nullable PalettedContainer> biomes ) { @@ -510,6 +507,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-core/src/main/java/com/fastasyncworldedit/core/extension/factory/TransformFactory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/TransformFactory.java index 06122c705..5cd2743ca 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/TransformFactory.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/TransformFactory.java @@ -21,22 +21,17 @@ import com.sk89q.worldedit.internal.registry.AbstractFactory; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import java.util.ArrayList; import java.util.List; public class TransformFactory extends AbstractFactory { - private final RichTransformParser richTransformParser; - /** * Create a new factory. * * @param worldEdit the WorldEdit instance */ public TransformFactory(WorldEdit worldEdit) { - super(worldEdit, new NullTransformParser(worldEdit)); - - richTransformParser = new RichTransformParser(worldEdit); + super(worldEdit, new NullTransformParser(worldEdit), new RichTransformParser(worldEdit)); // split and parse each sub-transform register(new RandomTransformParser(worldEdit)); @@ -51,68 +46,7 @@ public class TransformFactory extends AbstractFactory { } @Override - public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException { - List transforms = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - ResettableExtent match = richTransformParser.parseFromInput(component, context); - if (match != null) { - transforms.add(match); - continue; - } - parseFromParsers(context, transforms, component); - } - - return getResettableExtent(input, transforms); - } - - private void parseFromParsers( - final ParserContext context, - final List transforms, - final String component - ) { - ResettableExtent match = null; - for (InputParser parser : getParsers()) { - match = parser.parseFromInput(component, context); - - if (match != null) { - break; - } - } - if (match == null) { - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); - } - transforms.add(match); - } - - /** - * Parses a transform without considering parsing through the {@link RichTransformParser}, therefore not accepting - * "richer" parsing where & and , are used. Exists to prevent stack overflows. - * - * @param input input string - * @param context input context - * @return parsed result - * @throws InputParseException if no result found - */ - public ResettableExtent parseWithoutRich(String input, ParserContext context) throws InputParseException { - List transforms = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - parseFromParsers(context, transforms, component); - } - - return getResettableExtent(input, transforms); - } - - private ResettableExtent getResettableExtent(final String input, final List transforms) { + protected ResettableExtent getParsed(final String input, final List transforms) { switch (transforms.size()) { case 0: throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java index 11d33ef67..08dd05ad1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/FaweParser.java @@ -37,14 +37,14 @@ public abstract class FaweParser extends InputParser implements AliasedPar for (int i = 0; i < toParse.length(); i++) { char c = toParse.charAt(i); switch (c) { - case ',', '&' -> { + case ',', '&', ' ' -> { if (expression) { continue; } String result = toParse.substring(last, i); if (!result.isEmpty()) { inputs.add(result); - and.add(c == '&'); + and.add(c == '&' || c == ' '); } else { throw new InputParseException(Caption.of("fawe.error.parse.invalid-dangling-character", c)); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java index c1f129112..91fb75495 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java @@ -19,7 +19,6 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BaseBlock; @@ -174,27 +173,23 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { ArrayList> palette = new ArrayList<>(); for (BlockVector3 point : region) { BlockState block = clipboard.getBlock(point); - int combined = block.getInternalId(); + char ordinal = block.getOrdinalChar(); BlockType type = block.getBlockType(); - if (type == BlockTypes.STRUCTURE_VOID || indexes.containsKey(combined)) { + if (type == BlockTypes.STRUCTURE_VOID || indexes.containsKey(ordinal)) { continue; } - indexes.put(combined, (Integer) palette.size()); + indexes.put(ordinal, palette.size()); HashMap paletteEntry = new HashMap<>(); paletteEntry.put("Name", type.id()); if (block.getInternalId() != type.getInternalId()) { Map properties = null; - for (AbstractProperty property : (List>) type.getProperties()) { - int propIndex = property.getIndex(block.getInternalId()); - if (propIndex != 0) { - if (properties == null) { - properties = new HashMap<>(); - } - Object value = property.getValues().get(propIndex); - properties.put(property.getName(), value.toString()); + for (Map.Entry, Object> entry : block.getStates().entrySet()) { + if (properties == null) { + properties = new HashMap<>(); } + properties.put(entry.getKey().getName(), entry.getValue().toString()); } if (properties != null) { paletteEntry.put("Properties", properties); @@ -211,16 +206,23 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { for (BlockVector3 point : region) { BaseBlock block = clipboard.getFullBlock(point); if (block.getBlockType() != BlockTypes.STRUCTURE_VOID) { - int combined = block.getInternalId(); - int index = indexes.get(combined); - List pos = Arrays.asList(point.x() - min.x(), - point.y() - min.y(), point.z() - min.z() + char ordinal = block.getOrdinalChar(); + int index = indexes.get(ordinal); + List pos = Arrays.asList( + point.x() - min.x(), + point.y() - min.y(), + point.z() - min.z() ); if (!block.hasNbtData()) { blocks.add(FaweCache.INSTANCE.asMap("state", index, "pos", pos)); } else { + Map tag = new HashMap<>(block.getNbtData().getValue()); + tag.remove("x"); + tag.remove("y"); + tag.remove("z"); + CompoundTag cTag = new CompoundTag(tag); blocks.add( - FaweCache.INSTANCE.asMap("state", index, "pos", pos, "nbt", block.getNbtData())); + FaweCache.INSTANCE.asMap("state", index, "pos", pos, "nbt", cTag)); } } } @@ -231,8 +233,16 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { ArrayList> entities = new ArrayList<>(); for (Entity entity : clipboard.getEntities()) { Location loc = entity.getLocation(); - List pos = Arrays.asList(loc.x(), loc.y(), loc.z()); - List blockPos = Arrays.asList(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + List pos = Arrays.asList( + loc.x() - min.x(), + loc.y() - min.y(), + loc.z() - min.z() + ); + List blockPos = Arrays.asList( + loc.getBlockX() - min.x(), + loc.getBlockY() - min.y(), + loc.getBlockZ() - min.z() + ); BaseEntity state = entity.getState(); if (state != null) { CompoundTag nbt = state.getNbtData(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java index 14ecb48f1..f436ce576 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java @@ -23,11 +23,16 @@ import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.parser.DefaultBlockParser; import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.world.block.BaseBlock; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -67,4 +72,21 @@ public class BlockFactory extends AbstractFactory { return blocks; } + //FAWE start + @Override + public BaseBlock parseFromInput(String input, ParserContext context) throws InputParseException { + BaseBlock match; + + for (InputParser parser : parsers) { + match = parser.parseFromInput(input, context); + + if (match != null) { + return match; + } + } + + throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input))); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java index b1858a12d..8c907f42a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java @@ -22,7 +22,13 @@ package com.sk89q.worldedit.extension.factory; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.extension.factory.parser.DefaultItemParser; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; public class ItemFactory extends AbstractFactory { @@ -35,4 +41,21 @@ public class ItemFactory extends AbstractFactory { super(worldEdit, new DefaultItemParser(worldEdit)); } + //FAWE start + @Override + public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException { + BaseItem match; + + for (InputParser parser : parsers) { + match = parser.parseFromInput(input, context); + + if (match != null) { + return match; + } + } + + throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input))); + } + //FAWE end + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java index cf126560e..3440b009c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -53,16 +53,13 @@ import com.sk89q.worldedit.extension.factory.parser.mask.NoiseMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.OffsetMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.RegionMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.SolidMaskParser; -import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.MaskIntersection; import com.sk89q.worldedit.internal.registry.AbstractFactory; -import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -75,21 +72,13 @@ import java.util.stream.Collectors; */ public final class MaskFactory extends AbstractFactory { - //FAWE start - rich mask parsing - private final RichMaskParser richMaskParser; - //FAWE end - /** * Create a new mask registry. * * @param worldEdit the WorldEdit instance */ public MaskFactory(WorldEdit worldEdit) { - super(worldEdit, new BlocksMaskParser(worldEdit)); - - //FAWE start - rich mask parsing - richMaskParser = new RichMaskParser(worldEdit); - //FAWE end + super(worldEdit, new BlocksMaskParser(worldEdit), new RichMaskParser(worldEdit)); register(new ExistingMaskParser(worldEdit)); register(new AirMaskParser(worldEdit)); @@ -125,7 +114,6 @@ public final class MaskFactory extends AbstractFactory { register(new ZAxisMaskParser(worldEdit)); register(new SurfaceAngleMaskParser(worldEdit)); //FAWE end - } @Override @@ -133,85 +121,24 @@ public final class MaskFactory extends AbstractFactory { final String[] split = input.split(" "); if (split.length > 1) { String prev = input.substring(0, input.lastIndexOf(" ")) + " "; - return super.getSuggestions(split[split.length - 1], parserContext).stream().map(s -> prev + s).collect(Collectors.toList()); + return super + .getSuggestions(split[split.length - 1], parserContext) + .stream() + .map(s -> prev + s) + .collect(Collectors.toList()); } return super.getSuggestions(input, parserContext); } - @Override - public Mask parseFromInput(String input, ParserContext context) throws InputParseException { - List masks = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - //FAWE start - rich mask parsing - Mask match = richMaskParser.parseFromInput(component, context); - if (match != null) { - masks.add(match); - continue; - } - parseFromParsers(context, masks, component); - //FAWE end - } - - return getMask(input, masks); - } - //FAWE start - rich mask parsing - private void parseFromParsers( - final ParserContext context, - final List masks, - final String component - ) { - Mask match = null; - for (InputParser parser : getParsers()) { - match = parser.parseFromInput(component, context); - if (match != null) { - break; - } - } - if (match == null) { - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); - } - masks.add(match); - } - - /** - * Parses a mask without considering parsing through the {@link RichMaskParser}, therefore not accepting - * "richer" parsing where & and , are used. Exists to prevent stack overflows. - * - * @param input input string - * @param context input context - * @return parsed result - * @throws InputParseException if no result found - */ - public Mask parseWithoutRich(String input, ParserContext context) throws InputParseException { - List masks = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - parseFromParsers(context, masks, component); - } - - return getMask(input, masks); - } - - private Mask getMask(final String input, final List masks) { - switch (masks.size()) { - case 0: - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); - case 1: - return masks.get(0).optimize(); - default: - return new MaskIntersection(masks).optimize(); - } + @Override + protected Mask getParsed(final String input, final List masks) { + return switch (masks.size()) { + case 0 -> throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); + case 1 -> masks.get(0).optimize(); + default -> new MaskIntersection(masks).optimize(); + }; } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index b31d801b3..25955adee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.extension.factory; import com.fastasyncworldedit.core.configuration.Caption; -import com.fastasyncworldedit.core.extension.factory.parser.mask.HotbarMaskParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.AngleColorPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.AverageColorPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.BiomePatternParser; @@ -44,8 +43,6 @@ import com.fastasyncworldedit.core.extension.factory.parser.pattern.OffsetPatter import com.fastasyncworldedit.core.extension.factory.parser.pattern.PerlinPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomFullClipboardPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomOffsetPatternParser; -import com.fastasyncworldedit.core.extension.factory.parser.pattern.TypeSwapPatternParser; -import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RelativePatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RichPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.RidgedMultiFractalPatternParser; @@ -53,24 +50,22 @@ import com.fastasyncworldedit.core.extension.factory.parser.pattern.SaturatePatt import com.fastasyncworldedit.core.extension.factory.parser.pattern.SimplexPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.SolidRandomOffsetPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.SurfaceRandomOffsetPatternParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.TypeSwapPatternParser; import com.fastasyncworldedit.core.extension.factory.parser.pattern.VoronoiPatternParser; import com.fastasyncworldedit.core.math.random.TrueRandom; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser; +import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser; -import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; -import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.registry.AbstractFactory; -import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import java.util.ArrayList; import java.util.List; /** @@ -82,20 +77,14 @@ import java.util.List; */ public final class PatternFactory extends AbstractFactory { - //FAWE start - rich pattern parsing - private final RichPatternParser richPatternParser; - //FAWE end - /** * Create a new instance. * * @param worldEdit the WorldEdit instance */ public PatternFactory(WorldEdit worldEdit) { - super(worldEdit, new SingleBlockPatternParser(worldEdit)); - //FAWE start - rich pattern parsing - richPatternParser = new RichPatternParser(worldEdit); + super(worldEdit, new SingleBlockPatternParser(worldEdit), new RichPatternParser(worldEdit)); //FAWE end // split and parse each sub-pattern @@ -139,75 +128,10 @@ public final class PatternFactory extends AbstractFactory { register(new SurfaceRandomOffsetPatternParser(worldEdit)); register(new TypeSwapPatternParser(worldEdit)); register(new VoronoiPatternParser(worldEdit)); - //FAWE end } @Override - public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { - List patterns = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - //FAWE start - rich pattern parsing - Pattern match = richPatternParser.parseFromInput(component, context); - if (match != null) { - patterns.add(match); - continue; - } - parseFromParsers(context, patterns, component); - //FAWE end - } - - return getPattern(input, patterns); - } - - //FAWE start - rich pattern parsing - private void parseFromParsers( - final ParserContext context, - final List patterns, - final String component - ) { - Pattern match = null; - for (InputParser parser : getParsers()) { - match = parser.parseFromInput(component, context); - - if (match != null) { - break; - } - } - if (match == null) { - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); - } - patterns.add(match); - } - - /** - * Parses a pattern without considering parsing through the {@link RichPatternParser}, therefore not accepting - * "richer" parsing where & and , are used. Exists to prevent stack overflows. - * - * @param input input string - * @param context input context - * @return parsed result - * @throws InputParseException if no result found - */ - public Pattern parseWithoutRich(String input, ParserContext context) throws InputParseException { - List patterns = new ArrayList<>(); - - for (String component : input.split(" ")) { - if (component.isEmpty()) { - continue; - } - - parseFromParsers(context, patterns, component); - } - - return getPattern(input, patterns); - } - - private Pattern getPattern(final String input, final List patterns) { + protected Pattern getParsed(final String input, final List patterns) { switch (patterns.size()) { case 0: throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index 237dd1c4c..0934627b9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -21,6 +21,9 @@ package com.sk89q.worldedit.internal.registry; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extension.factory.parser.AliasedParser; +import com.fastasyncworldedit.core.extension.factory.parser.FaweParser; +import com.fastasyncworldedit.core.extension.factory.parser.pattern.RichPatternParser; +import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; @@ -43,7 +46,10 @@ import static com.google.common.base.Preconditions.checkNotNull; public abstract class AbstractFactory { protected final WorldEdit worldEdit; - private final List> parsers = new ArrayList<>(); + //FAWE start + protected final List> parsers = new ArrayList<>(); + private final FaweParser richParser; + //FWAE end /** * Create a new factory. @@ -52,11 +58,26 @@ public abstract class AbstractFactory { * @param defaultParser the parser to fall back to */ protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser) { + //FAWE start + this(worldEdit, defaultParser, null); + } + + /** + * Create a new factory with a given rich parser for FAWE rich parsing + * + * @param worldEdit the WorldEdit instance + * @param defaultParser the parser to fall back to + * @param richParser the rich parser + * @since TODO + */ + protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser, FaweParser richParser) { checkNotNull(worldEdit); checkNotNull(defaultParser); this.worldEdit = worldEdit; this.parsers.add(defaultParser); + this.richParser = richParser; } + //FAWE end /** * Gets an immutable list of parsers. @@ -71,7 +92,7 @@ public abstract class AbstractFactory { return Collections.unmodifiableList(parsers); } - //FAWE start - javadoc + //FAWE start /** * Parse a string and context to each {@link InputParser} added to this factory. If no result found, throws {@link InputParseException} @@ -81,20 +102,26 @@ public abstract class AbstractFactory { * @return parsed result * @throws InputParseException if no result found */ - //FAWE end public E parseFromInput(String input, ParserContext context) throws InputParseException { - E match; - - for (InputParser parser : parsers) { - match = parser.parseFromInput(input, context); - - if (match != null) { - return match; + List parsed = new ArrayList<>(); + for (String component : StringUtil.split(input,' ', '[', ']')) { + if (component.isEmpty()) { + continue; } + + if (richParser != null) { + E match = richParser.parseFromInput(component, context); + if (match != null) { + parsed.add(match); + continue; + } + } + parseFromParsers(context, parsed, component); } - throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); + return getParsed(input, parsed); } + //FAWE end @Deprecated public List getSuggestions(String input) { @@ -133,4 +160,48 @@ public abstract class AbstractFactory { }); } + //FAWE start + protected void parseFromParsers(final ParserContext context, final List parsed, final String component) { + E match = null; + for (InputParser parser : getParsers()) { + match = parser.parseFromInput(component, context); + + if (match != null) { + break; + } + } + if (match == null) { + throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component))); + } + parsed.add(match); + } + + /** + * Parses a pattern without considering parsing through the {@link RichPatternParser}, therefore not accepting + * "richer" parsing where & and , are used. Exists to prevent stack overflows. + * + * @param input input string + * @param context input context + * @return parsed result + * @throws InputParseException if no result found + */ + public E parseWithoutRich(String input, ParserContext context) throws InputParseException { + List parsed = new ArrayList<>(); + + for (String component : StringUtil.split(input, ' ', '[', ']')) { + if (component.isEmpty()) { + continue; + } + + parseFromParsers(context, parsed, component); + } + + return getParsed(input, parsed); + } + + protected E getParsed(final String input, final List parsed) { + return parsed.isEmpty() ? null : parsed.get(0); + } + //FAWE end + }