3131import com .mojang .serialization .DataResult ;
3232import com .mojang .serialization .JsonOps ;
3333import com .mojang .serialization .Lifecycle ;
34+ import com .sk89q .worldedit .EditSession ;
35+ import com .sk89q .worldedit .MaxChangedBlocksException ;
3436import com .sk89q .worldedit .WorldEditException ;
3537import com .sk89q .worldedit .blocks .BaseItem ;
3638import com .sk89q .worldedit .blocks .BaseItemStack ;
6567import com .sk89q .worldedit .world .block .BlockType ;
6668import com .sk89q .worldedit .world .block .BlockTypes ;
6769import com .sk89q .worldedit .world .entity .EntityTypes ;
70+ import com .sk89q .worldedit .world .generation .ConfiguredFeatureType ;
71+ import com .sk89q .worldedit .world .generation .StructureType ;
6872import com .sk89q .worldedit .world .item .ItemType ;
6973import net .minecraft .SharedConstants ;
7074import net .minecraft .Util ;
7175import net .minecraft .core .BlockPos ;
7276import net .minecraft .core .Holder ;
7377import net .minecraft .core .HolderSet ;
7478import net .minecraft .core .Registry ;
79+ import net .minecraft .core .SectionPos ;
7580import net .minecraft .core .component .DataComponentPatch ;
7681import net .minecraft .core .registries .Registries ;
7782import net .minecraft .nbt .ByteArrayTag ;
99104import net .minecraft .server .level .ChunkResult ;
100105import net .minecraft .server .level .ServerChunkCache ;
101106import net .minecraft .server .level .ServerLevel ;
107+ import net .minecraft .util .RandomSource ;
102108import net .minecraft .util .thread .BlockableEventLoop ;
103109import net .minecraft .world .Clearable ;
104110import net .minecraft .world .InteractionHand ;
122128import net .minecraft .world .level .chunk .status .ChunkStatus ;
123129import net .minecraft .world .level .dimension .LevelStem ;
124130import net .minecraft .world .level .levelgen .WorldOptions ;
131+ import net .minecraft .world .level .levelgen .feature .ConfiguredFeature ;
132+ import net .minecraft .world .level .levelgen .structure .BoundingBox ;
133+ import net .minecraft .world .level .levelgen .structure .Structure ;
134+ import net .minecraft .world .level .levelgen .structure .StructureStart ;
125135import net .minecraft .world .level .storage .LevelStorageSource ;
126136import net .minecraft .world .level .storage .PrimaryLevelData ;
127137import net .minecraft .world .level .storage .TagValueOutput ;
@@ -200,6 +210,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
200210 private final PaperweightDataConverters dataFixer ;
201211 private final Watchdog watchdog ;
202212
213+ private static final RandomSource random = RandomSource .create ();
214+
203215 private static final String WRONG_VERSION =
204216 """
205217 This version of FastAsyncWorldEdit has not been tested with the current Minecraft version.
@@ -894,6 +906,20 @@ public void initializeRegistries() {
894906 }
895907 }
896908
909+ // Features
910+ for (ResourceLocation name : server .registryAccess ().lookupOrThrow (Registries .CONFIGURED_FEATURE ).keySet ()) {
911+ if (ConfiguredFeatureType .REGISTRY .get (name .toString ()) == null ) {
912+ ConfiguredFeatureType .REGISTRY .register (name .toString (), new ConfiguredFeatureType (name .toString ()));
913+ }
914+ }
915+
916+ // Structures
917+ for (ResourceLocation name : server .registryAccess ().lookupOrThrow (Registries .STRUCTURE ).keySet ()) {
918+ if (StructureType .REGISTRY .get (name .toString ()) == null ) {
919+ StructureType .REGISTRY .register (name .toString (), new StructureType (name .toString ()));
920+ }
921+ }
922+
897923 // BiomeCategories
898924 Registry <Biome > biomeRegistry = server .registryAccess ().lookupOrThrow (Registries .BIOME );
899925 biomeRegistry .getTags ().forEach (tag -> {
@@ -912,6 +938,60 @@ public void initializeRegistries() {
912938 });
913939 }
914940
941+ public boolean generateFeature (ConfiguredFeatureType type , World world , EditSession session , BlockVector3 pt ) {
942+ ServerLevel originalWorld = ((CraftWorld ) world ).getHandle ();
943+ ConfiguredFeature <?, ?> feature = originalWorld .registryAccess ().lookupOrThrow (Registries .CONFIGURED_FEATURE ).getValue (ResourceLocation .tryParse (type .id ()));
944+ ServerChunkCache chunkManager = originalWorld .getChunkSource ();
945+ try (PaperweightServerLevelDelegateProxy .LevelAndProxy proxyLevel =
946+ PaperweightServerLevelDelegateProxy .newInstance (session , originalWorld , this )) {
947+ return feature != null && feature .place (proxyLevel .level (), chunkManager .getGenerator (), random , new BlockPos (pt .x (), pt .y (), pt .z ()));
948+ } catch (MaxChangedBlocksException e ) {
949+ throw new RuntimeException (e );
950+ }
951+ }
952+
953+ public boolean generateStructure (StructureType type , World world , EditSession session , BlockVector3 pt ) {
954+ ServerLevel originalWorld = ((CraftWorld ) world ).getHandle ();
955+ Registry <Structure > structureRegistry = originalWorld .registryAccess ().lookupOrThrow (Registries .STRUCTURE );
956+ Structure structure = structureRegistry .getValue (ResourceLocation .tryParse (type .id ()));
957+ if (structure == null ) {
958+ return false ;
959+ }
960+
961+ ServerChunkCache chunkManager = originalWorld .getChunkSource ();
962+ try (PaperweightServerLevelDelegateProxy .LevelAndProxy proxyLevel =
963+ PaperweightServerLevelDelegateProxy .newInstance (session , originalWorld , this )) {
964+ ChunkPos chunkPos = new ChunkPos (new BlockPos (pt .x (), pt .y (), pt .z ()));
965+ StructureStart structureStart = structure .generate (
966+ structureRegistry .wrapAsHolder (structure ), originalWorld .dimension (), originalWorld .registryAccess (),
967+ chunkManager .getGenerator (), chunkManager .getGenerator ().getBiomeSource (), chunkManager .randomState (),
968+ originalWorld .getStructureManager (), originalWorld .getSeed (), chunkPos , 0 ,
969+ proxyLevel .level (), biome -> true
970+ );
971+
972+ if (!structureStart .isValid ()) {
973+ return false ;
974+ } else {
975+ BoundingBox boundingBox = structureStart .getBoundingBox ();
976+ ChunkPos min = new ChunkPos (SectionPos .blockToSectionCoord (boundingBox .minX ()), SectionPos .blockToSectionCoord (boundingBox .minZ ()));
977+ ChunkPos max = new ChunkPos (SectionPos .blockToSectionCoord (boundingBox .maxX ()), SectionPos .blockToSectionCoord (boundingBox .maxZ ()));
978+ ChunkPos .rangeClosed (min , max ).forEach ((chunkPosx ) ->
979+ structureStart .placeInChunk (
980+ proxyLevel .level (), originalWorld .structureManager (), chunkManager .getGenerator (),
981+ originalWorld .getRandom (),
982+ new BoundingBox (
983+ chunkPosx .getMinBlockX (), originalWorld .getMinY (), chunkPosx .getMinBlockZ (),
984+ chunkPosx .getMaxBlockX (), originalWorld .getMaxY (), chunkPosx .getMaxBlockZ ()
985+ ), chunkPosx
986+ )
987+ );
988+ return true ;
989+ }
990+ } catch (MaxChangedBlocksException e ) {
991+ throw new RuntimeException (e );
992+ }
993+ }
994+
915995 @ Override
916996 public void sendBiomeUpdates (World world , Iterable <BlockVector2 > chunks ) {
917997 ServerLevel originalWorld = ((CraftWorld ) world ).getHandle ();
0 commit comments