diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLBaseStructureBuilder.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLBaseStructureBuilder.java new file mode 100644 index 00000000..71422dc1 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLBaseStructureBuilder.java @@ -0,0 +1,119 @@ +package org.betterx.bclib.api.v2.levelgen.structures; + +import org.betterx.worlds.together.tag.v3.TagManager; + +import com.mojang.serialization.Codec; +import net.minecraft.data.worldgen.BootstapContext; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureSet; +import net.minecraft.world.level.levelgen.structure.TerrainAdjustment; +import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement; +import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadType; +import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; + +import java.util.concurrent.ConcurrentLinkedQueue; + +abstract class BCLBaseStructureBuilder> { + static final ConcurrentLinkedQueue> UNBOUND_STRUCTURES = new ConcurrentLinkedQueue<>(); + static final ConcurrentLinkedQueue> UNBOUND_STRUCTURE_SETS = new ConcurrentLinkedQueue<>(); + + protected final ResourceLocation structureID; + protected BCLStructure.StructureBuilder structureBuilder; + + private GenerationStep.Decoration step; + + private StructurePlacement placement; + + private TagKey biomeTag; + + private TerrainAdjustment terrainAdjustment; + + protected BCLBaseStructureBuilder( + ResourceLocation structureID, + BCLStructure.StructureBuilder structureBuilder + ) { + this.structureID = structureID; + this.structureBuilder = structureBuilder; + + this.step = GenerationStep.Decoration.SURFACE_STRUCTURES; + this.terrainAdjustment = TerrainAdjustment.NONE; + this.placement = null; + this.biomeTag = null; + } + + public T adjustment(TerrainAdjustment value) { + this.terrainAdjustment = value; + return (T) this; + } + + public T step(GenerationStep.Decoration value) { + this.step = value; + return (T) this; + } + + public T placement(StructurePlacement value) { + this.placement = value; + return (T) this; + } + + public T randomPlacement(int spacing, int separation) { + this.placement = new RandomSpreadStructurePlacement( + spacing, + separation, + RandomSpreadType.LINEAR, + 13323129 + spacing + separation + structureID.toString().hashCode() % 10000 + ); + return (T) this; + } + + public T biomeTag(String modID, String path) { + this.biomeTag = TagManager.BIOMES.makeStructureTag(modID, path); + return (T) this; + } + + public T biomeTag(TagKey tag) { + this.biomeTag = tag; + return (T) this; + } + + protected abstract Codec getCodec(); + + public BCLStructure build() { + if (placement == null) { + throw new IllegalStateException("Placement needs to be defined for " + this.structureID); + } + + if (structureBuilder == null) { + throw new IllegalStateException("A structure builder needs to be defined for " + this.structureID); + } + + if (biomeTag == null) biomeTag(structureID.getNamespace(), structureID.getPath()); + + var res = new BCLStructure.Unbound<>( + structureID, + step, + placement, + getCodec(), + biomeTag, + structureBuilder, + terrainAdjustment + ); + UNBOUND_STRUCTURES.add(res); + UNBOUND_STRUCTURE_SETS.add(res); + return res; + } + + static void registerUnbound(BootstapContext context) { + UNBOUND_STRUCTURES.forEach(s -> s.register(context)); + UNBOUND_STRUCTURES.clear(); + } + + static void registerUnboundSets(BootstapContext context) { + UNBOUND_STRUCTURE_SETS.forEach(s -> s.registerSet(context)); + UNBOUND_STRUCTURE_SETS.clear(); + } +} diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLJigsawStructureBuilder.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLJigsawStructureBuilder.java new file mode 100644 index 00000000..cc5b1344 --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLJigsawStructureBuilder.java @@ -0,0 +1,101 @@ +package org.betterx.bclib.api.v2.levelgen.structures; + +import com.mojang.serialization.Codec; +import net.minecraft.core.HolderGetter; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.VerticalAnchor; +import net.minecraft.world.level.levelgen.heightproviders.ConstantHeight; +import net.minecraft.world.level.levelgen.heightproviders.HeightProvider; +import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; +import net.minecraft.world.level.levelgen.structure.structures.JigsawStructure; + +import java.util.Optional; + +public class BCLJigsawStructureBuilder extends BCLBaseStructureBuilder { + private ResourceKey startPool; + private Optional startJigsawName; + private int maxDepth; + private HeightProvider startHeight; + private boolean useExpansionHack; + private Optional projectStartToHeightmap; + private int maxDistanceFromCenter; + + public BCLJigsawStructureBuilder( + ResourceLocation structureID + ) { + super(structureID, null); + this.maxDepth = 6; + this.startHeight = ConstantHeight.of(VerticalAnchor.absolute(0)); + this.maxDistanceFromCenter = 80; + this.useExpansionHack = true; + this.startJigsawName = Optional.empty(); + this.projectStartToHeightmap = Optional.empty(); + } + + public BCLJigsawStructureBuilder projectStartToHeightmap(Heightmap.Types value) { + this.projectStartToHeightmap = Optional.of(value); + return this; + } + + public BCLJigsawStructureBuilder maxDistanceFromCenter(int value) { + this.maxDistanceFromCenter = value; + return this; + } + + public BCLJigsawStructureBuilder startJigsawName(ResourceLocation value) { + this.startJigsawName = Optional.of(value); + return this; + } + + public BCLJigsawStructureBuilder useExpansionHack(boolean value) { + this.useExpansionHack = value; + return this; + } + + public BCLJigsawStructureBuilder maxDepth(int value) { + this.maxDepth = value; + return this; + } + + public BCLJigsawStructureBuilder startHeight(HeightProvider value) { + this.startHeight = value; + return this; + } + + public BCLJigsawStructureBuilder startPool(ResourceKey pool) { + this.startPool = pool; + return this; + } + + @Override + protected Codec getCodec() { + return JigsawStructure.CODEC; + } + + @Override + public BCLStructure build() { + if (startPool == null) { + throw new IllegalStateException("Start pool must be set for " + this.structureID); + } + + this.structureBuilder = (BCLStructure.StructureBuilderWithContext) (structureSettings, ctx) -> { + HolderGetter templateGetter = ctx.lookup(Registries.TEMPLATE_POOL); + + return new JigsawStructure( + structureSettings, + templateGetter.getOrThrow(startPool), + startJigsawName, + maxDepth, + startHeight, + useExpansionHack, + projectStartToHeightmap, + maxDistanceFromCenter + ); + }; + + return super.build(); + } +} diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLStructure.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLStructure.java index 09cef8a5..3bfab0e5 100644 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLStructure.java +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLStructure.java @@ -20,12 +20,27 @@ import com.google.common.collect.Lists; import java.util.List; import java.util.Map; -import java.util.function.Function; import org.jetbrains.annotations.NotNull; public abstract class BCLStructure { + public interface StructureBuilder { + S apply(Structure.StructureSettings structureSettings); + } + + public interface StructureCodecProvider { + Codec getCodec(); + } + + public interface StructureBuilderWithContext extends StructureBuilder { + default S apply(Structure.StructureSettings structureSettings) { + return apply(structureSettings, null); + } + + S apply(Structure.StructureSettings structureSettings, BootstapContext ctx); + } + public static class Unbound extends BCLStructure { - private final Function structureBuilder; + private final StructureBuilder structureBuilder; private final TerrainAdjustment terrainAdjustment; private Bound registered; @@ -36,7 +51,7 @@ public abstract class BCLStructure { @NotNull StructurePlacement placement, @NotNull Codec codec, @NotNull TagKey biomeTag, - @NotNull Function structureBuilder, + @NotNull StructureBuilder structureBuilder, @NotNull TerrainAdjustment terrainAdjustment ) { super( @@ -58,12 +73,19 @@ public abstract class BCLStructure { public Bound register(BootstapContext bootstrapContext) { if (registered != null) return registered; - S baseStructure = structureBuilder.apply(structure( + final Structure.StructureSettings settings = structure( bootstrapContext, this.biomeTag, this.featureStep, terrainAdjustment - )); + ); + S baseStructure; + if (structureBuilder instanceof StructureBuilderWithContext sctx) { + baseStructure = sctx.apply(settings, bootstrapContext); + } else { + baseStructure = structureBuilder.apply(settings); + } + Holder.Reference structure = bootstrapContext.register(structureKey, baseStructure); BCLStructureBuilder.UNBOUND_STRUCTURES.remove(this); registered = new Bound<>( diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLStructureBuilder.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLStructureBuilder.java index cd930060..403a7c0b 100644 --- a/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLStructureBuilder.java +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/BCLStructureBuilder.java @@ -1,69 +1,45 @@ package org.betterx.bclib.api.v2.levelgen.structures; -import org.betterx.worlds.together.tag.v3.TagManager; - import com.mojang.serialization.Codec; import net.minecraft.data.worldgen.BootstapContext; import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagKey; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.levelgen.GenerationStep; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.StructureSet; -import net.minecraft.world.level.levelgen.structure.TerrainAdjustment; -import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement; -import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadType; -import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement; - -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.function.Function; - -public class BCLStructureBuilder { - static final ConcurrentLinkedQueue> UNBOUND_STRUCTURES = new ConcurrentLinkedQueue<>(); - static final ConcurrentLinkedQueue> UNBOUND_STRUCTURE_SETS = new ConcurrentLinkedQueue<>(); - - private final ResourceLocation structureID; - private final Function structureBuilder; - - private GenerationStep.Decoration step; +public class BCLStructureBuilder extends BCLBaseStructureBuilder> { private Codec codec; - private StructurePlacement placement; - - private TagKey biomeTag; - - private TerrainAdjustment terrainAdjustment; - private BCLStructureBuilder( ResourceLocation structureID, - Function structureBuilder + BCLStructure.StructureBuilder structureBuilder ) { - this.structureID = structureID; - this.structureBuilder = structureBuilder; + super(structureID, structureBuilder); - this.step = GenerationStep.Decoration.SURFACE_STRUCTURES; - this.terrainAdjustment = TerrainAdjustment.NONE; - this.codec = null; - this.placement = null; - this.biomeTag = null; + if (structureBuilder instanceof BCLStructure.StructureCodecProvider sctx) { + this.codec = sctx.getCodec(); + } else { + this.codec = Structure.simpleCodec((settings) -> structureBuilder.apply(settings)); + } + } + + public static BCLJigsawStructureBuilder jigsaw( + ResourceLocation structureID + ) { + return new BCLJigsawStructureBuilder(structureID); } public static BCLStructureBuilder start( ResourceLocation structureID, - Function structureBuilder + BCLStructure.StructureBuilderWithContext structureBuilder ) { return new BCLStructureBuilder<>(structureID, structureBuilder); } - public BCLStructureBuilder adjustment(TerrainAdjustment value) { - this.terrainAdjustment = value; - return this; - } - - public BCLStructureBuilder step(GenerationStep.Decoration value) { - this.step = value; - return this; + public static BCLStructureBuilder start( + ResourceLocation structureID, + BCLStructure.StructureBuilder structureBuilder + ) { + return new BCLStructureBuilder<>(structureID, structureBuilder); } public BCLStructureBuilder codec(Codec value) { @@ -71,59 +47,17 @@ public class BCLStructureBuilder { return this; } - public BCLStructureBuilder placement(StructurePlacement value) { - this.placement = value; - return this; + @Override + protected Codec getCodec() { + return codec; } - public BCLStructureBuilder randomPlacement(int spacing, int separation) { - this.placement = new RandomSpreadStructurePlacement( - spacing, - separation, - RandomSpreadType.LINEAR, - 13323129 + spacing + separation + structureID.toString().hashCode() % 10000 - ); - return this; - } - - public BCLStructureBuilder biomeTag(String modID, String path) { - this.biomeTag = TagManager.BIOMES.makeStructureTag(modID, path); - return this; - } - - public BCLStructureBuilder biomeTag(TagKey tag) { - this.biomeTag = tag; - return this; - } - - public BCLStructure build() { - if (placement == null) { - throw new IllegalStateException("Placement needs to be defined for " + this.structureID); - } - if (codec == null) codec(Structure.simpleCodec(structureBuilder)); - if (biomeTag == null) biomeTag(structureID.getNamespace(), structureID.getPath()); - - var res = new BCLStructure.Unbound<>( - structureID, - step, - placement, - codec, - biomeTag, - structureBuilder, - terrainAdjustment - ); - UNBOUND_STRUCTURES.add(res); - UNBOUND_STRUCTURE_SETS.add(res); - return res; - } public static void registerUnbound(BootstapContext context) { - UNBOUND_STRUCTURES.forEach(s -> s.register(context)); - UNBOUND_STRUCTURES.clear(); + BCLBaseStructureBuilder.registerUnbound(context); } public static void registerUnboundSets(BootstapContext context) { - UNBOUND_STRUCTURE_SETS.forEach(s -> s.registerSet(context)); - UNBOUND_STRUCTURE_SETS.clear(); + BCLBaseStructureBuilder.registerUnboundSets(context); } } diff --git a/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/StructurePools.java b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/StructurePools.java new file mode 100644 index 00000000..e04bfb8f --- /dev/null +++ b/src/main/java/org/betterx/bclib/api/v2/levelgen/structures/StructurePools.java @@ -0,0 +1,25 @@ +package org.betterx.bclib.api.v2.levelgen.structures; + +import com.mojang.datafixers.util.Either; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement; +import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList; + +import java.util.function.Function; + +public class StructurePools { + public static ResourceKey createKey(ResourceLocation id) { + return ResourceKey.create(Registries.TEMPLATE_POOL, id); + } + + public static Function single( + ResourceLocation id, + Holder holder + ) { + return (projection) -> new SinglePoolElement(Either.left(id), holder, projection); + } +} diff --git a/src/main/resources/bclib.accesswidener b/src/main/resources/bclib.accesswidener index 92a0e4f2..00ffd25d 100644 --- a/src/main/resources/bclib.accesswidener +++ b/src/main/resources/bclib.accesswidener @@ -16,6 +16,7 @@ accessible class net/minecraft/server/dedicated/DedicatedServerProperties$Wo accessible class net/minecraft/client/resources/model/AtlasSet$AtlasEntry extendable class net/minecraft/world/level/block/state/properties/WoodType + #Methods accessible method net/minecraft/world/level/storage/loot/LootPool ([Lnet/minecraft/world/level/storage/loot/entries/LootPoolEntryContainer;[Lnet/minecraft/world/level/storage/loot/predicates/LootItemCondition;[Lnet/minecraft/world/level/storage/loot/functions/LootItemFunction;Lnet/minecraft/world/level/storage/loot/providers/number/NumberProvider;Lnet/minecraft/world/level/storage/loot/providers/number/NumberProvider;)V accessible method net/minecraft/world/entity/ai/village/poi/PoiTypes register (Lnet/minecraft/core/Registry;Lnet/minecraft/resources/ResourceKey;Ljava/util/Set;II)Lnet/minecraft/world/entity/ai/village/poi/PoiType; @@ -32,6 +33,7 @@ accessible method net/minecraft/advancements/Advancement$Builder (Z)V accessible method net/minecraft/world/level/block/Blocks ocelotOrParrot (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean; accessible method net/minecraft/world/level/block/Blocks never (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean; accessible method net/minecraft/world/level/block/Blocks never (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z +accessible method net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement (Lcom/mojang/datafixers/util/Either;Lnet/minecraft/core/Holder;Lnet/minecraft/world/level/levelgen/structure/pools/StructureTemplatePool$Projection;)V #Fields accessible field net/minecraft/world/entity/ai/village/poi/PoiTypes TYPE_BY_STATE Ljava/util/Map;