2828import com .google .common .util .concurrent .Futures ;
2929import com .mojang .serialization .Codec ;
3030import com .mojang .serialization .Lifecycle ;
31+ import com .sk89q .worldedit .EditSession ;
32+ import com .sk89q .worldedit .MaxChangedBlocksException ;
3133import com .sk89q .worldedit .WorldEditException ;
3234import com .sk89q .worldedit .blocks .BaseItem ;
3335import com .sk89q .worldedit .blocks .BaseItemStack ;
6163import com .sk89q .worldedit .world .block .BlockType ;
6264import com .sk89q .worldedit .world .block .BlockTypes ;
6365import com .sk89q .worldedit .world .entity .EntityTypes ;
66+ import com .sk89q .worldedit .world .generation .ConfiguredFeatureType ;
67+ import com .sk89q .worldedit .world .generation .StructureType ;
6468import com .sk89q .worldedit .world .item .ItemType ;
6569import net .minecraft .SharedConstants ;
6670import net .minecraft .Util ;
6771import net .minecraft .core .BlockPos ;
6872import net .minecraft .core .Holder ;
6973import net .minecraft .core .HolderSet ;
7074import net .minecraft .core .Registry ;
75+ import net .minecraft .core .SectionPos ;
7176import net .minecraft .core .component .DataComponentPatch ;
7277import net .minecraft .core .registries .Registries ;
7378import net .minecraft .nbt .CompoundTag ;
8287import net .minecraft .server .level .ServerChunkCache ;
8388import net .minecraft .server .level .ServerLevel ;
8489import net .minecraft .server .level .progress .ChunkProgressListener ;
90+ import net .minecraft .util .RandomSource ;
8591import net .minecraft .util .thread .BlockableEventLoop ;
8692import net .minecraft .world .Clearable ;
8793import net .minecraft .world .InteractionHand ;
105111import net .minecraft .world .level .chunk .status .ChunkStatus ;
106112import net .minecraft .world .level .dimension .LevelStem ;
107113import net .minecraft .world .level .levelgen .WorldOptions ;
114+ import net .minecraft .world .level .levelgen .feature .ConfiguredFeature ;
115+ import net .minecraft .world .level .levelgen .structure .BoundingBox ;
116+ import net .minecraft .world .level .levelgen .structure .Structure ;
117+ import net .minecraft .world .level .levelgen .structure .StructureStart ;
108118import net .minecraft .world .level .storage .LevelStorageSource ;
109119import net .minecraft .world .level .storage .PrimaryLevelData ;
110120import net .minecraft .world .phys .BlockHitResult ;
@@ -178,6 +188,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
178188 private final PaperweightDataConverters dataFixer ;
179189 private final Watchdog watchdog ;
180190
191+ private static final RandomSource random = RandomSource .create ();
192+
181193 // ------------------------------------------------------------------------
182194 // Code that may break between versions of Minecraft
183195 // ------------------------------------------------------------------------
@@ -480,7 +492,6 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
480492 );
481493 }
482494
483- @ Nullable
484495 @ Override
485496 public org .bukkit .entity .Entity createEntity (Location location , BaseEntity state ) {
486497 checkNotNull (location );
@@ -489,48 +500,27 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state
489500 CraftWorld craftWorld = ((CraftWorld ) location .getWorld ());
490501 ServerLevel worldServer = craftWorld .getHandle ();
491502
492- String entityId = state .getType ().id ();
493-
494- LinCompoundTag nativeTag = state .getNbt ();
495- net .minecraft .nbt .CompoundTag tag ;
496- if (nativeTag != null ) {
497- tag = (net .minecraft .nbt .CompoundTag ) fromNativeLin (nativeTag );
498- removeUnwantedEntityTagsRecursively (tag );
499- } else {
500- tag = new net .minecraft .nbt .CompoundTag ();
501- }
503+ Entity createdEntity = createEntityFromId (state .getType ().id (), craftWorld .getHandle ());
502504
503- tag .putString ("id" , entityId );
505+ if (createdEntity != null ) {
506+ LinCompoundTag nativeTag = state .getNbt ();
507+ if (nativeTag != null ) {
508+ net .minecraft .nbt .CompoundTag tag = (net .minecraft .nbt .CompoundTag ) fromNativeLin (nativeTag );
509+ for (String name : Constants .NO_COPY_ENTITY_NBT_FIELDS ) {
510+ tag .remove (name );
511+ }
512+ readTagIntoEntity (tag , createdEntity );
513+ }
504514
505- Entity createdEntity = EntityType .loadEntityRecursive (tag , craftWorld .getHandle (), EntitySpawnReason .COMMAND , (loadedEntity ) -> {
506- loadedEntity .absMoveTo (location .getX (), location .getY (), location .getZ (), location .getYaw (), location .getPitch ());
507- return loadedEntity ;
508- });
515+ createdEntity .absMoveTo (location .getX (), location .getY (), location .getZ (), location .getYaw (), location .getPitch ());
509516
510- if (createdEntity != null ) {
511- worldServer .addFreshEntityWithPassengers (createdEntity , SpawnReason .CUSTOM );
517+ worldServer .addFreshEntity (createdEntity , SpawnReason .CUSTOM );
512518 return createdEntity .getBukkitEntity ();
513519 } else {
514520 return null ;
515521 }
516522 }
517523
518- // This removes all unwanted tags from the main entity and all its passengers
519- private void removeUnwantedEntityTagsRecursively (net .minecraft .nbt .CompoundTag tag ) {
520- for (String name : Constants .NO_COPY_ENTITY_NBT_FIELDS ) {
521- tag .remove (name );
522- }
523-
524- // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive
525- if (tag .contains ("Passengers" , LinTagId .LIST .id ())) {
526- net .minecraft .nbt .ListTag nbttaglist = tag .getList ("Passengers" , LinTagId .COMPOUND .id ());
527-
528- for (int i = 0 ; i < nbttaglist .size (); ++i ) {
529- removeUnwantedEntityTagsRecursively (nbttaglist .getCompound (i ));
530- }
531- }
532- }
533-
534524 @ Override
535525 public Component getRichBlockName (BlockType blockType ) {
536526 return TranslatableComponent .of (getBlockFromType (blockType ).getDescriptionId ());
@@ -877,6 +867,20 @@ public void initializeRegistries() {
877867 }
878868 }
879869
870+ // Features
871+ for (ResourceLocation name : server .registryAccess ().lookupOrThrow (Registries .CONFIGURED_FEATURE ).keySet ()) {
872+ if (ConfiguredFeatureType .REGISTRY .get (name .toString ()) == null ) {
873+ ConfiguredFeatureType .REGISTRY .register (name .toString (), new ConfiguredFeatureType (name .toString ()));
874+ }
875+ }
876+
877+ // Structures
878+ for (ResourceLocation name : server .registryAccess ().lookupOrThrow (Registries .STRUCTURE ).keySet ()) {
879+ if (StructureType .REGISTRY .get (name .toString ()) == null ) {
880+ StructureType .REGISTRY .register (name .toString (), new StructureType (name .toString ()));
881+ }
882+ }
883+
880884 // BiomeCategories
881885 Registry <Biome > biomeRegistry = server .registryAccess ().lookupOrThrow (Registries .BIOME );
882886 biomeRegistry .getTags ().forEach (tag -> {
@@ -906,6 +910,60 @@ public void sendBiomeUpdates(World world, Iterable<BlockVector2> chunks) {
906910 originalWorld .getChunkSource ().chunkMap .resendBiomesForChunks (nativeChunks );
907911 }
908912
913+ public boolean generateFeature (ConfiguredFeatureType type , World world , EditSession session , BlockVector3 pt ) {
914+ ServerLevel originalWorld = ((CraftWorld ) world ).getHandle ();
915+ ConfiguredFeature <?, ?> feature = originalWorld .registryAccess ().lookupOrThrow (Registries .CONFIGURED_FEATURE ).getValue (ResourceLocation .tryParse (type .id ()));
916+ ServerChunkCache chunkManager = originalWorld .getChunkSource ();
917+ try (PaperweightServerLevelDelegateProxy .LevelAndProxy proxyLevel =
918+ PaperweightServerLevelDelegateProxy .newInstance (session , originalWorld , this )) {
919+ return feature != null && feature .place (proxyLevel .level (), chunkManager .getGenerator (), random , new BlockPos (pt .x (), pt .y (), pt .z ()));
920+ } catch (MaxChangedBlocksException e ) {
921+ throw new RuntimeException (e );
922+ }
923+ }
924+
925+ public boolean generateStructure (StructureType type , World world , EditSession session , BlockVector3 pt ) {
926+ ServerLevel originalWorld = ((CraftWorld ) world ).getHandle ();
927+ Registry <Structure > structureRegistry = originalWorld .registryAccess ().lookupOrThrow (Registries .STRUCTURE );
928+ Structure structure = structureRegistry .getValue (ResourceLocation .tryParse (type .id ()));
929+ if (structure == null ) {
930+ return false ;
931+ }
932+
933+ ServerChunkCache chunkManager = originalWorld .getChunkSource ();
934+ try (PaperweightServerLevelDelegateProxy .LevelAndProxy proxyLevel =
935+ PaperweightServerLevelDelegateProxy .newInstance (session , originalWorld , this )) {
936+ ChunkPos chunkPos = new ChunkPos (new BlockPos (pt .x (), pt .y (), pt .z ()));
937+ StructureStart structureStart = structure .generate (
938+ structureRegistry .wrapAsHolder (structure ), originalWorld .dimension (), originalWorld .registryAccess (),
939+ chunkManager .getGenerator (), chunkManager .getGenerator ().getBiomeSource (), chunkManager .randomState (),
940+ originalWorld .getStructureManager (), originalWorld .getSeed (), chunkPos , 0 ,
941+ proxyLevel .level (), biome -> true
942+ );
943+
944+ if (!structureStart .isValid ()) {
945+ return false ;
946+ } else {
947+ BoundingBox boundingBox = structureStart .getBoundingBox ();
948+ ChunkPos min = new ChunkPos (SectionPos .blockToSectionCoord (boundingBox .minX ()), SectionPos .blockToSectionCoord (boundingBox .minZ ()));
949+ ChunkPos max = new ChunkPos (SectionPos .blockToSectionCoord (boundingBox .maxX ()), SectionPos .blockToSectionCoord (boundingBox .maxZ ()));
950+ ChunkPos .rangeClosed (min , max ).forEach ((chunkPosx ) ->
951+ structureStart .placeInChunk (
952+ proxyLevel .level (), originalWorld .structureManager (), chunkManager .getGenerator (),
953+ originalWorld .getRandom (),
954+ new BoundingBox (
955+ chunkPosx .getMinBlockX (), originalWorld .getMinY (), chunkPosx .getMinBlockZ (),
956+ chunkPosx .getMaxBlockX (), originalWorld .getMaxY (), chunkPosx .getMaxBlockZ ()
957+ ), chunkPosx
958+ )
959+ );
960+ return true ;
961+ }
962+ } catch (MaxChangedBlocksException e ) {
963+ throw new RuntimeException (e );
964+ }
965+ }
966+
909967 // ------------------------------------------------------------------------
910968 // Code that is less likely to break
911969 // ------------------------------------------------------------------------
0 commit comments