[Feature] BCLStructureBuilder supports Jigsaw Structures
This commit is contained in:
parent
b69259cb4b
commit
eee0a8b9c8
6 changed files with 299 additions and 96 deletions
|
@ -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<S extends Structure, T extends BCLBaseStructureBuilder<S, T>> {
|
||||
static final ConcurrentLinkedQueue<BCLStructure.Unbound<?>> UNBOUND_STRUCTURES = new ConcurrentLinkedQueue<>();
|
||||
static final ConcurrentLinkedQueue<BCLStructure.Unbound<?>> UNBOUND_STRUCTURE_SETS = new ConcurrentLinkedQueue<>();
|
||||
|
||||
protected final ResourceLocation structureID;
|
||||
protected BCLStructure.StructureBuilder<S> structureBuilder;
|
||||
|
||||
private GenerationStep.Decoration step;
|
||||
|
||||
private StructurePlacement placement;
|
||||
|
||||
private TagKey<Biome> biomeTag;
|
||||
|
||||
private TerrainAdjustment terrainAdjustment;
|
||||
|
||||
protected BCLBaseStructureBuilder(
|
||||
ResourceLocation structureID,
|
||||
BCLStructure.StructureBuilder<S> 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<Biome> tag) {
|
||||
this.biomeTag = tag;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
protected abstract Codec<S> getCodec();
|
||||
|
||||
public BCLStructure<S> 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<Structure> context) {
|
||||
UNBOUND_STRUCTURES.forEach(s -> s.register(context));
|
||||
UNBOUND_STRUCTURES.clear();
|
||||
}
|
||||
|
||||
static void registerUnboundSets(BootstapContext<StructureSet> context) {
|
||||
UNBOUND_STRUCTURE_SETS.forEach(s -> s.registerSet(context));
|
||||
UNBOUND_STRUCTURE_SETS.clear();
|
||||
}
|
||||
}
|
|
@ -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<JigsawStructure, BCLJigsawStructureBuilder> {
|
||||
private ResourceKey<StructureTemplatePool> startPool;
|
||||
private Optional<ResourceLocation> startJigsawName;
|
||||
private int maxDepth;
|
||||
private HeightProvider startHeight;
|
||||
private boolean useExpansionHack;
|
||||
private Optional<Heightmap.Types> 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<StructureTemplatePool> pool) {
|
||||
this.startPool = pool;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Codec<JigsawStructure> getCodec() {
|
||||
return JigsawStructure.CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BCLStructure<JigsawStructure> build() {
|
||||
if (startPool == null) {
|
||||
throw new IllegalStateException("Start pool must be set for " + this.structureID);
|
||||
}
|
||||
|
||||
this.structureBuilder = (BCLStructure.StructureBuilderWithContext<JigsawStructure>) (structureSettings, ctx) -> {
|
||||
HolderGetter<StructureTemplatePool> templateGetter = ctx.lookup(Registries.TEMPLATE_POOL);
|
||||
|
||||
return new JigsawStructure(
|
||||
structureSettings,
|
||||
templateGetter.getOrThrow(startPool),
|
||||
startJigsawName,
|
||||
maxDepth,
|
||||
startHeight,
|
||||
useExpansionHack,
|
||||
projectStartToHeightmap,
|
||||
maxDistanceFromCenter
|
||||
);
|
||||
};
|
||||
|
||||
return super.build();
|
||||
}
|
||||
}
|
|
@ -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<S extends Structure> {
|
||||
public interface StructureBuilder<S extends Structure> {
|
||||
S apply(Structure.StructureSettings structureSettings);
|
||||
}
|
||||
|
||||
public interface StructureCodecProvider<S extends Structure> {
|
||||
Codec<S> getCodec();
|
||||
}
|
||||
|
||||
public interface StructureBuilderWithContext<S extends Structure> extends StructureBuilder<S> {
|
||||
default S apply(Structure.StructureSettings structureSettings) {
|
||||
return apply(structureSettings, null);
|
||||
}
|
||||
|
||||
S apply(Structure.StructureSettings structureSettings, BootstapContext<Structure> ctx);
|
||||
}
|
||||
|
||||
public static class Unbound<S extends Structure> extends BCLStructure<S> {
|
||||
private final Function<Structure.StructureSettings, S> structureBuilder;
|
||||
private final StructureBuilder<S> structureBuilder;
|
||||
private final TerrainAdjustment terrainAdjustment;
|
||||
|
||||
private Bound<S> registered;
|
||||
|
@ -36,7 +51,7 @@ public abstract class BCLStructure<S extends Structure> {
|
|||
@NotNull StructurePlacement placement,
|
||||
@NotNull Codec<S> codec,
|
||||
@NotNull TagKey<Biome> biomeTag,
|
||||
@NotNull Function<Structure.StructureSettings, S> structureBuilder,
|
||||
@NotNull StructureBuilder<S> structureBuilder,
|
||||
@NotNull TerrainAdjustment terrainAdjustment
|
||||
) {
|
||||
super(
|
||||
|
@ -58,12 +73,19 @@ public abstract class BCLStructure<S extends Structure> {
|
|||
|
||||
public Bound<S> register(BootstapContext<Structure> 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<S> sctx) {
|
||||
baseStructure = sctx.apply(settings, bootstrapContext);
|
||||
} else {
|
||||
baseStructure = structureBuilder.apply(settings);
|
||||
}
|
||||
|
||||
Holder.Reference<Structure> structure = bootstrapContext.register(structureKey, baseStructure);
|
||||
BCLStructureBuilder.UNBOUND_STRUCTURES.remove(this);
|
||||
registered = new Bound<>(
|
||||
|
|
|
@ -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<S extends Structure> {
|
||||
static final ConcurrentLinkedQueue<BCLStructure.Unbound<?>> UNBOUND_STRUCTURES = new ConcurrentLinkedQueue<>();
|
||||
static final ConcurrentLinkedQueue<BCLStructure.Unbound<?>> UNBOUND_STRUCTURE_SETS = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final ResourceLocation structureID;
|
||||
private final Function<Structure.StructureSettings, S> structureBuilder;
|
||||
|
||||
private GenerationStep.Decoration step;
|
||||
|
||||
public class BCLStructureBuilder<S extends Structure> extends BCLBaseStructureBuilder<S, BCLStructureBuilder<S>> {
|
||||
private Codec<S> codec;
|
||||
|
||||
private StructurePlacement placement;
|
||||
|
||||
private TagKey<Biome> biomeTag;
|
||||
|
||||
private TerrainAdjustment terrainAdjustment;
|
||||
|
||||
private BCLStructureBuilder(
|
||||
ResourceLocation structureID,
|
||||
Function<Structure.StructureSettings, S> structureBuilder
|
||||
BCLStructure.StructureBuilder<S> 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 <S extends Structure> BCLStructureBuilder<S> start(
|
||||
ResourceLocation structureID,
|
||||
Function<Structure.StructureSettings, S> structureBuilder
|
||||
BCLStructure.StructureBuilderWithContext<S> structureBuilder
|
||||
) {
|
||||
return new BCLStructureBuilder<>(structureID, structureBuilder);
|
||||
}
|
||||
|
||||
public BCLStructureBuilder<S> adjustment(TerrainAdjustment value) {
|
||||
this.terrainAdjustment = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BCLStructureBuilder<S> step(GenerationStep.Decoration value) {
|
||||
this.step = value;
|
||||
return this;
|
||||
public static <S extends Structure> BCLStructureBuilder<S> start(
|
||||
ResourceLocation structureID,
|
||||
BCLStructure.StructureBuilder<S> structureBuilder
|
||||
) {
|
||||
return new BCLStructureBuilder<>(structureID, structureBuilder);
|
||||
}
|
||||
|
||||
public BCLStructureBuilder<S> codec(Codec<S> value) {
|
||||
|
@ -71,59 +47,17 @@ public class BCLStructureBuilder<S extends Structure> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public BCLStructureBuilder<S> placement(StructurePlacement value) {
|
||||
this.placement = value;
|
||||
return this;
|
||||
@Override
|
||||
protected Codec<S> getCodec() {
|
||||
return codec;
|
||||
}
|
||||
|
||||
public BCLStructureBuilder<S> randomPlacement(int spacing, int separation) {
|
||||
this.placement = new RandomSpreadStructurePlacement(
|
||||
spacing,
|
||||
separation,
|
||||
RandomSpreadType.LINEAR,
|
||||
13323129 + spacing + separation + structureID.toString().hashCode() % 10000
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BCLStructureBuilder<S> biomeTag(String modID, String path) {
|
||||
this.biomeTag = TagManager.BIOMES.makeStructureTag(modID, path);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BCLStructureBuilder<S> biomeTag(TagKey<Biome> tag) {
|
||||
this.biomeTag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BCLStructure<S> 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<Structure> context) {
|
||||
UNBOUND_STRUCTURES.forEach(s -> s.register(context));
|
||||
UNBOUND_STRUCTURES.clear();
|
||||
BCLBaseStructureBuilder.registerUnbound(context);
|
||||
}
|
||||
|
||||
public static void registerUnboundSets(BootstapContext<StructureSet> context) {
|
||||
UNBOUND_STRUCTURE_SETS.forEach(s -> s.registerSet(context));
|
||||
UNBOUND_STRUCTURE_SETS.clear();
|
||||
BCLBaseStructureBuilder.registerUnboundSets(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<StructureTemplatePool> createKey(ResourceLocation id) {
|
||||
return ResourceKey.create(Registries.TEMPLATE_POOL, id);
|
||||
}
|
||||
|
||||
public static Function<StructureTemplatePool.Projection, SinglePoolElement> single(
|
||||
ResourceLocation id,
|
||||
Holder<StructureProcessorList> holder
|
||||
) {
|
||||
return (projection) -> new SinglePoolElement(Either.left(id), holder, projection);
|
||||
}
|
||||
}
|
|
@ -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 <init> ([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 <init> (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 <init> (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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue