From 0a07f30ae1ff517277cfca84f434bb0aedf42c03 Mon Sep 17 00:00:00 2001 From: "Joseph T. McQuigg" Date: Sat, 4 May 2024 06:59:35 -0400 Subject: [PATCH] Backport Support for The End (#164) * Added support for end biomes * Added support for end surface rules * Reduce the blockiness of end biomes * Fixed end pillar generation * Fix crashing with BCLib. Closes #149 --------- Co-authored-by: Adubbz --- .../terrablender/api/EndBiomeRegistry.java | 120 ++++++++ .../terrablender/api/SurfaceRuleManager.java | 5 +- .../main/java/terrablender/config/Config.java | 281 ++++++++++-------- .../config/TerraBlenderConfig.java | 45 ++- .../terrablender/mixin/MixinBiomeSource.java | 18 +- .../mixin/MixinNoiseGeneratorSettings.java | 19 +- .../mixin/MixinParameterList.java | 5 + .../mixin/MixinTheEndBiomeSource.java | 159 ++++++++++ .../java/terrablender/util/LevelUtils.java | 28 +- .../terrablender/util/WeightedRandomList.java | 52 ++++ .../IExtendedNoiseGeneratorSettings.java | 11 +- .../IExtendedTheEndBiomeSource.java} | 34 +-- .../worldgen/TBSurfaceRuleData.java | 5 + .../worldgen/noise/BiomeInitialLayer.java | 46 +++ .../worldgen/noise/InitialLayer.java | 64 +--- .../worldgen/noise/LayeredNoiseUtil.java | 22 +- .../worldgen/noise/WeightedRandomLayer.java | 46 +++ .../main/resources/terrablender.mixins.json | 3 +- gradle.properties | 2 +- 19 files changed, 718 insertions(+), 247 deletions(-) create mode 100644 Common/src/main/java/terrablender/api/EndBiomeRegistry.java create mode 100644 Common/src/main/java/terrablender/mixin/MixinTheEndBiomeSource.java create mode 100644 Common/src/main/java/terrablender/util/WeightedRandomList.java rename Common/src/main/java/terrablender/{config/ConfigFile.java => worldgen/IExtendedTheEndBiomeSource.java} (54%) create mode 100644 Common/src/main/java/terrablender/worldgen/noise/BiomeInitialLayer.java create mode 100644 Common/src/main/java/terrablender/worldgen/noise/WeightedRandomLayer.java diff --git a/Common/src/main/java/terrablender/api/EndBiomeRegistry.java b/Common/src/main/java/terrablender/api/EndBiomeRegistry.java new file mode 100644 index 0000000..5c89fd6 --- /dev/null +++ b/Common/src/main/java/terrablender/api/EndBiomeRegistry.java @@ -0,0 +1,120 @@ +/** + * Copyright (C) Glitchfiend + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package terrablender.api; + +import com.google.common.collect.ImmutableList; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.random.WeightedEntry; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import terrablender.core.TerraBlender; + +import java.util.ArrayList; +import java.util.List; + +public class EndBiomeRegistry +{ + private static final List>> highlandsBiomes = new ArrayList<>(); + private static final List>> midlandsBiomes = new ArrayList<>(); + private static final List>> edgeBiomes = new ArrayList<>(); + private static final List>> islandBiomes = new ArrayList<>(); + + /** + * Registers a biome to generate in the highlands of the end. + * @param biome the biome to register. + * @param weight the biome weight. + */ + public static void registerHighlandsBiome(ResourceKey biome, int weight) + { + highlandsBiomes.add(WeightedEntry.wrap(biome, weight)); + } + + /** + * Registers a biome to generate in the midlands of the end. + * @param biome the biome to register. + * @param weight the biome weight. + */ + public static void registerMidlandsBiome(ResourceKey biome, int weight) + { + midlandsBiomes.add(WeightedEntry.wrap(biome, weight)); + } + + /** + * Registers a biome to generate in the outer edges of islands in the end. + * @param biome the biome to register. + * @param weight the biome weight. + */ + public static void registerEdgeBiome(ResourceKey biome, int weight) + { + edgeBiomes.add(WeightedEntry.wrap(biome, weight)); + } + + /** + * Registers a biome to generate as a small island of the end. + * @param biome the biome to register. + * @param weight the biome weight. + */ + public static void registerIslandBiome(ResourceKey biome, int weight) + { + islandBiomes.add(WeightedEntry.wrap(biome, weight)); + } + + /** + * Gets the biomes to generate in the highlands of the end. + * @return the biomes to generate. + */ + public static List>> getHighlandsBiomes() + { + return ImmutableList.copyOf(highlandsBiomes); + } + + /** + * Gets the biomes to generate in the midlands of the end. + * @return the biomes to generate. + */ + public static List>> getMidlandsBiomes() + { + return ImmutableList.copyOf(midlandsBiomes); + } + + /** + * Gets the biomes to generate in the outer edges of islands in the end. + * @return the biomes to generate. + */ + public static List>> getEdgeBiomes() + { + return ImmutableList.copyOf(edgeBiomes); + } + + /** + * Gets the biomes to generate as a small island of the end. + * @return the biomes to generate. + */ + public static List>> getIslandBiomes() + { + return ImmutableList.copyOf(islandBiomes); + } + + static + { + registerHighlandsBiome(Biomes.END_HIGHLANDS, TerraBlender.CONFIG.vanillaEndHighlandsWeight); + registerMidlandsBiome(Biomes.END_MIDLANDS, TerraBlender.CONFIG.vanillaEndMidlandsWeight); + registerEdgeBiome(Biomes.END_BARRENS, TerraBlender.CONFIG.vanillaEndBarrensWeight); + registerIslandBiome(Biomes.SMALL_END_ISLANDS, TerraBlender.CONFIG.vanillaSmallEndIslandsWeight); + } +} diff --git a/Common/src/main/java/terrablender/api/SurfaceRuleManager.java b/Common/src/main/java/terrablender/api/SurfaceRuleManager.java index 58b1016..124d6b6 100644 --- a/Common/src/main/java/terrablender/api/SurfaceRuleManager.java +++ b/Common/src/main/java/terrablender/api/SurfaceRuleManager.java @@ -116,6 +116,9 @@ public static SurfaceRules.RuleSource getDefaultSurfaceRules(RuleCategory catego if (category == RuleCategory.NETHER) return TBSurfaceRuleData.nether(); + else if (category == RuleCategory.END) { + return TBSurfaceRuleData.end(); + } return TBSurfaceRuleData.overworld(); } @@ -125,7 +128,7 @@ public static SurfaceRules.RuleSource getDefaultSurfaceRules(RuleCategory catego */ public enum RuleCategory { - OVERWORLD, NETHER + OVERWORLD, NETHER, END } /** diff --git a/Common/src/main/java/terrablender/config/Config.java b/Common/src/main/java/terrablender/config/Config.java index 9421664..94fb81c 100644 --- a/Common/src/main/java/terrablender/config/Config.java +++ b/Common/src/main/java/terrablender/config/Config.java @@ -17,171 +17,218 @@ */ package terrablender.config; -import com.electronwill.nightconfig.core.CommentedConfig; -import com.electronwill.nightconfig.core.file.CommentedFileConfig; +import com.electronwill.nightconfig.core.*; import com.electronwill.nightconfig.core.io.WritingMode; import com.electronwill.nightconfig.toml.TomlFormat; -import com.electronwill.nightconfig.toml.TomlWriter; -import net.minecraft.util.StringRepresentable; +import com.google.common.base.Predicates; +import terrablender.core.TerraBlender; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; +import java.util.Set; +import java.util.function.Predicate; -public class Config +public abstract class Config implements UnmodifiableConfig, CommentedConfig { - private final CommentedConfig config; + private CommentedConfig config; + private final Path path; - public Config(CommentedConfig config) + protected Config(Path path) { - this.config = config; + this(path, readToml(path)); } - public List addList(String comment, String key, List defaultValue) + protected Config(Path path, String toml) { - if (config.get(key) == null) - { - config.set(key, defaultValue); - } + this.parse(toml); + this.path = path; + this.load(); + this.write(); + } - if (config.getComment(key) == null) - { - config.setComment(key, comment); - } - return config.get(key); + public T add(String key, T defaultValue, String comment) + { + return this.add(key, defaultValue, comment, Predicates.alwaysTrue()); } - public Config addSubConfig(String comment, String key, Config defaultValue) + public T add(String key, T defaultValue, String comment, Predicate validator) { - if (config.get(key) == null) - { - config.set(key, sortConfig(defaultValue.config)); - } + var value = config.getOrElse(key, defaultValue); - CommentedConfig subConfig = config.get(key); - String commentValue = config.getComment(key); - if (commentValue == null) + // Revert to default if validation fails + if (!validator.test(value)) { - config.setComment(key, comment); + TerraBlender.LOGGER.warn("Invalid value {} for key {}. Reverting to default", value, key); + value = defaultValue; } - return new Config(subConfig); + config.set(key, value); + config.setComment(key, comment); + return value; } - public Map addMap(String comment, String key, Map defaultValue) + public > T addNumber(String key, T defaultValue, T min, T max, String comment) { - if (config.get(key) == null) - { - CommentedConfig subConfig = config.createSubConfig(); - defaultValue.forEach((a, b) -> { - String subConfigKey = a.toString(); - if (subConfig.get(a.toString()) == null) - { - subConfig.set(subConfigKey, b); - } - }); - config.set(key, subConfig); - } + return this.add(key, defaultValue, comment, (v) -> v.compareTo(max) <= 0 && v.compareTo(min) >= 0); + } - CommentedConfig subConfig = config.get(key); - String commentValue = config.getComment(key); - if (commentValue == null) - { - config.setComment(key, comment); - } + public abstract void load(); - return subConfig.valueMap(); + public void parse(String toml) + { + this.config = TomlFormat.instance().createParser().parse(toml); } - public T add(String comment, String key, T defaultValue) + public void read() { - if (config.get(key) == null) - { - config.set(key, defaultValue); - } + this.parse(readToml(this.path)); + } - if (config.getComment(key) == null) - { - config.setComment(key, comment); - } - return config.get(key); + public void write() + { + TomlFormat.instance().createWriter().write(this.config, this.path, WritingMode.REPLACE); } - public > T addNumber(String comment, String key, T defaultValue, T min, T max) + public String encode() { - if (config.get(key) == null) - { - config.set(key, defaultValue); - } + return TomlFormat.instance().createWriter().writeToString(this.config); + } - if (config.getComment(key) == null) - { - config.setComment(key, comment + String.format("\nRange: %s-%s", min, max)); - } - T value = config.get(key); - return value.compareTo(max) > 0 ? max : value.compareTo(min) < 0 ? min : value; + public Path getPath() + { + return this.path; } - public > T addEnum(String comment, String key, T defaultValue) + private static String readToml(Path path) { - if (config.get(key) == null) - { - config.set(key, defaultValue); - } + // Create parent directories as needed + path.getParent().toFile().mkdirs(); - if (config.getComment(key) == null) - { - StringBuilder builder = new StringBuilder().append("Values: ").append(defaultValue instanceof StringRepresentable ? "\n" : ""); - for (T value : defaultValue.getDeclaringClass().getEnumConstants()) - { - if (defaultValue instanceof StringRepresentable) - { - builder.append(((StringRepresentable) value).getSerializedName()).append("\n"); - } - else - { - builder.append(value.name()).append(", "); - } - } - - config.setComment(key, comment + "\n" + builder.toString()); - } + try { + return Files.readString(path); + } catch (Exception ignored) {} + return ""; + } - String value = config.get(key).toString(); - return T.valueOf(defaultValue.getDeclaringClass(), value); + @Override + public T getRaw(List path) { + return config.getRaw(path); } - public T getValue(String key) - { - return this.config.get(key); + @Override + public Map valueMap() { + return config.valueMap(); } - public Config getSubConfig(String key) - { - CommentedConfig sub = this.config.get(key); - return new Config(sub != null ? sub : CommentedConfig.inMemory()); + @Override + public boolean contains(List path) { + return config.contains(path); } - protected CommentedConfig getConfig() - { - return this.config; + @Override + public int size() { + return config.size(); } - protected static CommentedConfig sortConfig(CommentedConfig config) - { - CommentedConfig newConfig = CommentedConfig.of(com.electronwill.nightconfig.core.Config.getDefaultMapCreator(false, true), TomlFormat.instance()); + @Override + public boolean isEmpty() { + return config.isEmpty(); + } - List> organizedCollection = config.valueMap().entrySet().stream().sorted(Comparator.comparing(Objects::toString)).collect(Collectors.toList()); - organizedCollection.forEach((stringObjectEntry -> { - newConfig.add(stringObjectEntry.getKey(), stringObjectEntry.getValue()); - })); + @Override + public boolean equals(Object obj) { + return config.equals(obj); + } + + @Override + public int hashCode() { + return config.hashCode(); + } + + @Override + public ConfigFormat configFormat() { + return config.configFormat(); + } + + @Override + public T set(List path, Object value) { + return config.set(path, value); + } + + @Override + public boolean add(List path, Object value) { + return config.add(path, value); + } + + @Override + public T remove(List path) { + return config.remove(path); + } + + @Override + public void clear() { + config.clear(); + } + + @Override + public String getComment(List path) { + return config.getComment(path); + } + + @Override + public boolean containsComment(List path) { + return config.containsComment(path); + } + + @Override + public String setComment(List path, String comment) { + return config.setComment(path, comment); + } + + @Override + public String removeComment(List path) { + return config.removeComment(path); + } + + @Override + public Map commentMap() { + return config.commentMap(); + } + + @Override + public Set entrySet() { + return config.entrySet(); + } + + @Override + public void clearComments() { + config.clearComments(); + } + + @Override + public void putAllComments(Map comments) { + config.putAllComments(comments); + } + + @Override + public void putAllComments(UnmodifiableCommentedConfig commentedConfig) { + config.putAllComments(commentedConfig); + } + + @Override + public Map getComments() { + return config.getComments(); + } + + @Override + public CommentedConfig createSubConfig() { + return config.createSubConfig(); + } - newConfig.commentMap().putAll(config.commentMap()); - return newConfig; + @Override + public String toString() { + return getClass().getSimpleName() + ':' + config; } -} +} \ No newline at end of file diff --git a/Common/src/main/java/terrablender/config/TerraBlenderConfig.java b/Common/src/main/java/terrablender/config/TerraBlenderConfig.java index e00fdb1..b33028f 100644 --- a/Common/src/main/java/terrablender/config/TerraBlenderConfig.java +++ b/Common/src/main/java/terrablender/config/TerraBlenderConfig.java @@ -19,27 +19,42 @@ import java.nio.file.Path; -public class TerraBlenderConfig extends ConfigFile +public class TerraBlenderConfig extends Config { - public final int overworldRegionSize; - public final int netherRegionSize; - public final int vanillaOverworldRegionWeight; - public final int vanillaNetherRegionWeight; + public int overworldRegionSize; + public int netherRegionSize; + public int vanillaOverworldRegionWeight; + public int vanillaNetherRegionWeight; + + public int endHighlandsBiomeSize; + public int endMidlandsBiomeSize; + public int endEdgeBiomeSize; + public int endIslandBiomeSize; + public int vanillaEndHighlandsWeight; + public int vanillaEndMidlandsWeight; + public int vanillaEndBarrensWeight; + public int vanillaSmallEndIslandsWeight; public TerraBlenderConfig(Path path) { super(path); + } - Config generalConfig = this.getSubConfig("general"); - this.addSubConfig("General settings", "general", generalConfig); - - Config generationSettings = this.getSubConfig("generation_settings"); - this.overworldRegionSize = generationSettings.addNumber("The size of overworld biome regions from each mod that uses TerraBlender.", "overworld_region_size", 3, 2, 6); - this.netherRegionSize = generationSettings.addNumber("The size of nether biome regions from each mod that uses TerraBlender.", "nether_region_size", 2, 2, 6); - this.vanillaOverworldRegionWeight = generationSettings.addNumber("The weighting of vanilla biome regions in the overworld.", "vanilla_overworld_region_weight", 10, 0, Integer.MAX_VALUE); - this.vanillaNetherRegionWeight = generationSettings.addNumber("The weighting of vanilla biome regions in the nether.", "vanilla_nether_region_weight", 10, 0, Integer.MAX_VALUE); - this.addSubConfig("Generation settings", "generation_settings", generationSettings); + @Override + public void load() + { + this.overworldRegionSize = addNumber("general.overworld_region_size", 3, 2, 6, "The size of overworld biome regions from each mod that uses TerraBlender."); + this.netherRegionSize = addNumber("general.nether_region_size", 2, 2, 6, "The size of nether biome regions from each mod that uses TerraBlender."); + this.vanillaOverworldRegionWeight = addNumber("general.vanilla_overworld_region_weight", 10, 0, Integer.MAX_VALUE, "The weighting of vanilla biome regions in the overworld."); + this.vanillaNetherRegionWeight = addNumber("general.vanilla_nether_region_weight", 10, 0, Integer.MAX_VALUE, "The weighting of vanilla biome regions in the nether."); - this.save(); + this.endHighlandsBiomeSize = addNumber("end.highlands_biome_size", 4, 2, 6, "The size of highlands end biomes."); + this.endMidlandsBiomeSize = addNumber("end.midlands_biome_size", 4, 2, 6, "The size of midlands end biomes."); + this.endEdgeBiomeSize = addNumber("end.edge_biome_size", 3, 2, 6, "The size of edge end biomes."); + this.endIslandBiomeSize = addNumber("end.island_biome_size", 2, 2, 6, "The size of island end biomes."); + this.vanillaEndHighlandsWeight = addNumber("end.vanilla_end_highlands_weight", 10, 0, Integer.MAX_VALUE, "The weight of Vanilla end highlands biomes."); + this.vanillaEndMidlandsWeight = addNumber("end.vanilla_end_midlands_weight", 10, 0, Integer.MAX_VALUE, "The weight of Vanilla end midlands biomes."); + this.vanillaEndBarrensWeight = addNumber("end.vanilla_end_barrens_weight", 10, 0, Integer.MAX_VALUE, "The weight of Vanilla end barrens biomes."); + this.vanillaSmallEndIslandsWeight = addNumber("end.vanilla_small_end_islands_weight", 10, 0, Integer.MAX_VALUE, "The weight of Vanilla small end islands biomes."); } } diff --git a/Common/src/main/java/terrablender/mixin/MixinBiomeSource.java b/Common/src/main/java/terrablender/mixin/MixinBiomeSource.java index 30df4d4..4c26c4a 100644 --- a/Common/src/main/java/terrablender/mixin/MixinBiomeSource.java +++ b/Common/src/main/java/terrablender/mixin/MixinBiomeSource.java @@ -17,23 +17,21 @@ */ package terrablender.mixin; -import com.google.common.collect.ImmutableList; import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import net.minecraft.core.Holder; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeResolver; import net.minecraft.world.level.biome.BiomeSource; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.Unique; import terrablender.worldgen.IExtendedBiomeSource; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.function.Supplier; +import java.util.stream.Collectors; @Mixin(BiomeSource.class) public abstract class MixinBiomeSource implements BiomeResolver, IExtendedBiomeSource @@ -41,6 +39,7 @@ public abstract class MixinBiomeSource implements BiomeResolver, IExtendedBiomeS @Shadow public Supplier>> possibleBiomes; + @Unique private boolean hasAppended = false; @Override @@ -51,12 +50,11 @@ public void appendDeferredBiomesList(List> biomesToAppend) return; } - ImmutableList.Builder> builder = ImmutableList.builder(); - builder.addAll(this.possibleBiomes.get()); - builder.addAll(biomesToAppend); - ImmutableList> biomeList = builder.build().stream().distinct().collect(ImmutableList.toImmutableList()); + List> possibleBiomes = new ArrayList<>(); + possibleBiomes.addAll(this.possibleBiomes.get()); + possibleBiomes.addAll(biomesToAppend); - this.possibleBiomes = () -> new ObjectLinkedOpenHashSet<>(biomeList); + this.possibleBiomes = () -> new ObjectLinkedOpenHashSet<>(possibleBiomes.stream().distinct().collect(Collectors.toList())); this.hasAppended = true; } } diff --git a/Common/src/main/java/terrablender/mixin/MixinNoiseGeneratorSettings.java b/Common/src/main/java/terrablender/mixin/MixinNoiseGeneratorSettings.java index fe7916b..eedf02d 100644 --- a/Common/src/main/java/terrablender/mixin/MixinNoiseGeneratorSettings.java +++ b/Common/src/main/java/terrablender/mixin/MixinNoiseGeneratorSettings.java @@ -21,6 +21,7 @@ import net.minecraft.world.level.levelgen.SurfaceRules; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -35,30 +36,26 @@ public class MixinNoiseGeneratorSettings implements IExtendedNoiseGeneratorSetti @Shadow private SurfaceRules.RuleSource surfaceRule; - private RegionType regionType = null; + @Unique + private SurfaceRuleManager.RuleCategory ruleCategory = null; + @Unique private SurfaceRules.RuleSource namespacedSurfaceRuleSource = null; @Inject(method = "surfaceRule", at = @At("HEAD"), cancellable = true) private void surfaceRule(CallbackInfoReturnable cir) { - if (this.regionType != null) + if (this.ruleCategory != null) { if (this.namespacedSurfaceRuleSource == null) - this.namespacedSurfaceRuleSource = regionType == RegionType.NETHER ? SurfaceRuleManager.getNamespacedRules(SurfaceRuleManager.RuleCategory.NETHER, this.surfaceRule) : SurfaceRuleManager.getNamespacedRules(SurfaceRuleManager.RuleCategory.OVERWORLD, this.surfaceRule); + this.namespacedSurfaceRuleSource = SurfaceRuleManager.getNamespacedRules(this.ruleCategory, this.surfaceRule); cir.setReturnValue(this.namespacedSurfaceRuleSource); } } @Override - public void setRegionType(RegionType regionType) + public void setRuleCategory(SurfaceRuleManager.RuleCategory ruleCategory) { - this.regionType = regionType; - } - - @Override - public RegionType getRegionType() - { - return this.regionType; + this.ruleCategory = ruleCategory; } } diff --git a/Common/src/main/java/terrablender/mixin/MixinParameterList.java b/Common/src/main/java/terrablender/mixin/MixinParameterList.java index 4d941f3..a8602d2 100644 --- a/Common/src/main/java/terrablender/mixin/MixinParameterList.java +++ b/Common/src/main/java/terrablender/mixin/MixinParameterList.java @@ -28,6 +28,7 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import terrablender.api.Region; import terrablender.api.RegionType; import terrablender.api.Regions; @@ -47,9 +48,13 @@ public abstract class MixinParameterList implements IExtendedParameterList @Shadow public abstract T findValue(Climate.TargetPoint target); + @Unique private boolean initialized = false; + @Unique private boolean treesPopulated = false; + @Unique private Area uniqueness; + @Unique private Climate.RTree[] uniqueTrees; @Override diff --git a/Common/src/main/java/terrablender/mixin/MixinTheEndBiomeSource.java b/Common/src/main/java/terrablender/mixin/MixinTheEndBiomeSource.java new file mode 100644 index 0000000..669b228 --- /dev/null +++ b/Common/src/main/java/terrablender/mixin/MixinTheEndBiomeSource.java @@ -0,0 +1,159 @@ +/** + * Copyright (C) Glitchfiend + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package terrablender.mixin; + + +import com.google.common.collect.ImmutableSet; +import net.minecraft.core.*; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.random.WeightedEntry; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.biome.Climate; +import net.minecraft.world.level.biome.TheEndBiomeSource; +import net.minecraft.world.level.levelgen.DensityFunction; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import terrablender.api.EndBiomeRegistry; +import terrablender.core.TerraBlender; +import terrablender.worldgen.IExtendedTheEndBiomeSource; +import terrablender.worldgen.noise.Area; +import terrablender.worldgen.noise.LayeredNoiseUtil; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Mixin(TheEndBiomeSource.class) +public class MixinTheEndBiomeSource implements IExtendedTheEndBiomeSource +{ + @Shadow + @Final + private Holder end; + + @Unique + private boolean tbInitialized = false; + + @Unique + private Registry biomeRegistry; + @Unique + private Set> tbPossibleBiomes; + @Unique + private Area highlandsArea; + @Unique + private Area midlandsArea; + @Unique + private Area edgeArea; + @Unique + private Area islandsArea; + + @Override + public void initializeForTerraBlender(RegistryAccess registryAccess, long seed) + { + this.biomeRegistry = registryAccess.registryOrThrow(Registries.BIOME); + + var highlands = EndBiomeRegistry.getHighlandsBiomes(); + var midlands = EndBiomeRegistry.getMidlandsBiomes(); + var edge = EndBiomeRegistry.getEdgeBiomes(); + var islands = EndBiomeRegistry.getIslandBiomes(); + + // Create a set of all biomes + var builder = ImmutableSet.>builder(); + builder.addAll(highlands.stream().map(WeightedEntry.Wrapper::getData).toList()); + builder.addAll(midlands.stream().map(WeightedEntry.Wrapper::getData).toList()); + builder.addAll(edge.stream().map(WeightedEntry.Wrapper::getData).toList()); + builder.addAll(islands.stream().map(WeightedEntry.Wrapper::getData).toList()); + builder.add(Biomes.THE_END); + Set> allBiomes = builder.build(); + + // Ensure all biomes are registered + allBiomes.forEach(key -> { + if (!biomeRegistry.containsKey(key)) + throw new RuntimeException("Biome " + key + " has not been registered!"); + }); + + this.tbPossibleBiomes = allBiomes.stream().map(biomeRegistry::getHolderOrThrow).collect(Collectors.toSet()); + this.highlandsArea = LayeredNoiseUtil.biomeArea(registryAccess, seed, TerraBlender.CONFIG.endHighlandsBiomeSize, highlands); + this.midlandsArea = LayeredNoiseUtil.biomeArea(registryAccess, seed, TerraBlender.CONFIG.endMidlandsBiomeSize, midlands); + this.edgeArea = LayeredNoiseUtil.biomeArea(registryAccess, seed, TerraBlender.CONFIG.endEdgeBiomeSize, edge); + this.islandsArea = LayeredNoiseUtil.biomeArea(registryAccess, seed, TerraBlender.CONFIG.endIslandBiomeSize, edge); + + // This may not be initialized with e.g. BCLib + this.tbInitialized = true; + } + + @Inject(method = "collectPossibleBiomes", at=@At("RETURN"), cancellable = true) + protected void onCollectPossibleBiomes(CallbackInfoReturnable>> cir) + { + if (!this.tbInitialized) + return; + + var builder = ImmutableSet.>builder(); + builder.addAll(cir.getReturnValue().collect(Collectors.toSet())); + builder.addAll(this.tbPossibleBiomes); + cir.setReturnValue(builder.build().stream()); + } + + @Inject(method = "getNoiseBiome", at=@At("HEAD"), cancellable = true) + public void onGetNoiseBiome(int x, int y, int z, Climate.Sampler sampler, CallbackInfoReturnable> cir) + { + if (!this.tbInitialized) + return; + + int blockX = QuartPos.toBlock(x); + int blockY = QuartPos.toBlock(y); + int blockZ = QuartPos.toBlock(z); + + int sectionX = SectionPos.blockToSectionCoord(blockX); + int sectionZ = SectionPos.blockToSectionCoord(blockZ); + + if ((long)sectionX * (long)sectionX + (long)sectionZ * (long)sectionZ <= 4096L) + { + cir.setReturnValue(this.end); + } + else + { + double heightNoise = sampler.erosion().compute(new DensityFunction.SinglePointContext(blockX, blockY, blockZ)); + + if (heightNoise > 0.25) + { + cir.setReturnValue(this.getBiomeHolder(this.highlandsArea.get(x, z))); + } + else if (heightNoise >= -0.0625) + { + cir.setReturnValue(this.getBiomeHolder(this.midlandsArea.get(x, z))); + } + else + { + cir.setReturnValue(heightNoise < -0.21875 ? this.getBiomeHolder(this.islandsArea.get(x, z)) : this.getBiomeHolder(this.edgeArea.get(x, z))); + } + } + } + + @Unique + private Holder getBiomeHolder(int id) + { + return this.biomeRegistry.getHolder(id).orElseThrow(); + } +} diff --git a/Common/src/main/java/terrablender/util/LevelUtils.java b/Common/src/main/java/terrablender/util/LevelUtils.java index 0c9e5f9..10e6fdc 100644 --- a/Common/src/main/java/terrablender/util/LevelUtils.java +++ b/Common/src/main/java/terrablender/util/LevelUtils.java @@ -24,10 +24,7 @@ import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.Climate; -import net.minecraft.world.level.biome.MultiNoiseBiomeSource; +import net.minecraft.world.level.biome.*; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; @@ -36,10 +33,12 @@ import terrablender.DimensionTypeTags; import terrablender.api.RegionType; import terrablender.api.Regions; +import terrablender.api.SurfaceRuleManager; import terrablender.core.TerraBlender; import terrablender.worldgen.IExtendedBiomeSource; import terrablender.worldgen.IExtendedNoiseGeneratorSettings; import terrablender.worldgen.IExtendedParameterList; +import terrablender.worldgen.IExtendedTheEndBiomeSource; import java.util.Map; @@ -77,12 +76,20 @@ public static RegionType getRegionTypeForDimension(Holder dimensi public static void initializeBiomes(RegistryAccess registryAccess, Holder dimensionType, ResourceKey levelResourceKey, ChunkGenerator chunkGenerator, long seed) { - if (!shouldApplyToChunkGenerator(chunkGenerator)) + if (!(chunkGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator)) return; - RegionType regionType = getRegionTypeForDimension(dimensionType); - NoiseBasedChunkGenerator noiseBasedChunkGenerator = (NoiseBasedChunkGenerator)chunkGenerator; NoiseGeneratorSettings generatorSettings = noiseBasedChunkGenerator.generatorSettings().value(); + + if (chunkGenerator.getBiomeSource() instanceof TheEndBiomeSource) + { + ((IExtendedTheEndBiomeSource)chunkGenerator.getBiomeSource()).initializeForTerraBlender(registryAccess, seed); + ((IExtendedNoiseGeneratorSettings)(Object)generatorSettings).setRuleCategory(SurfaceRuleManager.RuleCategory.END); + return; + } + else if (!shouldApplyToBiomeSource(chunkGenerator.getBiomeSource())) return; + + RegionType regionType = getRegionTypeForDimension(dimensionType); MultiNoiseBiomeSource biomeSource = (MultiNoiseBiomeSource)chunkGenerator.getBiomeSource(); IExtendedBiomeSource biomeSourceEx = (IExtendedBiomeSource)biomeSource; @@ -91,7 +98,12 @@ public static void initializeBiomes(RegistryAccess registryAccess, Holder SurfaceRuleManager.RuleCategory.OVERWORLD; + case NETHER -> SurfaceRuleManager.RuleCategory.NETHER; + default -> throw new IllegalArgumentException("Attempted to get surface rule category for unsupported region type " + regionType); + }; + ((IExtendedNoiseGeneratorSettings)(Object)generatorSettings).setRuleCategory(ruleCategory); Climate.ParameterList parameters = biomeSource.parameters(); IExtendedParameterList parametersEx = (IExtendedParameterList)parameters; diff --git a/Common/src/main/java/terrablender/util/WeightedRandomList.java b/Common/src/main/java/terrablender/util/WeightedRandomList.java new file mode 100644 index 0000000..e13ca19 --- /dev/null +++ b/Common/src/main/java/terrablender/util/WeightedRandomList.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2024, the Glitchfiend Team. + * All rights reserved. + ******************************************************************************/ +package terrablender.util; + +import com.google.common.collect.ImmutableList; +import net.minecraft.util.random.WeightedEntry; +import net.minecraft.util.random.WeightedRandom; +import terrablender.worldgen.noise.AreaContext; +import terrablender.worldgen.noise.WeightedRandomLayer; + +import java.util.List; +import java.util.Optional; + +public class WeightedRandomList +{ + private final int totalWeight; + private final ImmutableList items; + + WeightedRandomList(List items) + { + this.items = ImmutableList.copyOf(items); + this.totalWeight = WeightedRandom.getTotalWeight(items); + } + + public static WeightedRandomList create() + { + return new WeightedRandomList<>(ImmutableList.of()); + } + + @SafeVarargs + public static WeightedRandomList create(E... entries) + { + return new WeightedRandomList<>(ImmutableList.copyOf(entries)); + } + + public static WeightedRandomList create(List entries) + { + return new WeightedRandomList<>(entries); + } + + public Optional getRandom(AreaContext context) + { + if (this.totalWeight == 0) { + return Optional.empty(); + } else { + int i = context.nextRandom(this.totalWeight); + return WeightedRandom.getWeightedItem(this.items, i); + } + } +} diff --git a/Common/src/main/java/terrablender/worldgen/IExtendedNoiseGeneratorSettings.java b/Common/src/main/java/terrablender/worldgen/IExtendedNoiseGeneratorSettings.java index f7afb72..5c37325 100644 --- a/Common/src/main/java/terrablender/worldgen/IExtendedNoiseGeneratorSettings.java +++ b/Common/src/main/java/terrablender/worldgen/IExtendedNoiseGeneratorSettings.java @@ -1,7 +1,3 @@ -package terrablender.worldgen; - -import terrablender.api.RegionType; - /** * Copyright (C) Glitchfiend *

@@ -19,8 +15,11 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +package terrablender.worldgen; + +import terrablender.api.SurfaceRuleManager; + public interface IExtendedNoiseGeneratorSettings { - void setRegionType(RegionType regionType); - RegionType getRegionType(); + void setRuleCategory(SurfaceRuleManager.RuleCategory ruleCategory); } diff --git a/Common/src/main/java/terrablender/config/ConfigFile.java b/Common/src/main/java/terrablender/worldgen/IExtendedTheEndBiomeSource.java similarity index 54% rename from Common/src/main/java/terrablender/config/ConfigFile.java rename to Common/src/main/java/terrablender/worldgen/IExtendedTheEndBiomeSource.java index 9255b6f..ebc0b9e 100644 --- a/Common/src/main/java/terrablender/config/ConfigFile.java +++ b/Common/src/main/java/terrablender/worldgen/IExtendedTheEndBiomeSource.java @@ -1,41 +1,27 @@ /** * Copyright (C) Glitchfiend - * + *

* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + *

* You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package terrablender.config; +package terrablender.worldgen; -import com.electronwill.nightconfig.core.file.CommentedFileConfig; -import com.electronwill.nightconfig.core.io.WritingMode; -import com.electronwill.nightconfig.toml.TomlWriter; +import net.minecraft.core.RegistryAccess; +import net.minecraft.world.level.biome.Climate; +import terrablender.api.RegionType; -import java.nio.file.Path; - -public class ConfigFile extends Config +public interface IExtendedTheEndBiomeSource { - private final Path path; - - public ConfigFile(Path path) - { - super(CommentedFileConfig.builder(path).sync().autosave().build()); - this.path = path; - ((CommentedFileConfig)this.getConfig()).load(); - } - - public void save() - { - (new TomlWriter()).write(sortConfig(this.getConfig()), this.path.toFile(), WritingMode.REPLACE); - } -} + void initializeForTerraBlender(RegistryAccess registryAccess, long seed); +} \ No newline at end of file diff --git a/Common/src/main/java/terrablender/worldgen/TBSurfaceRuleData.java b/Common/src/main/java/terrablender/worldgen/TBSurfaceRuleData.java index c36e853..3c8290f 100644 --- a/Common/src/main/java/terrablender/worldgen/TBSurfaceRuleData.java +++ b/Common/src/main/java/terrablender/worldgen/TBSurfaceRuleData.java @@ -650,6 +650,11 @@ public static SurfaceRules.RuleSource nether() return SurfaceRules.sequence(builder.build().toArray(SurfaceRules.RuleSource[]::new)); } + public static SurfaceRules.RuleSource end() + { + return ENDSTONE; + } + public static SurfaceRules.RuleSource air() { return AIR; diff --git a/Common/src/main/java/terrablender/worldgen/noise/BiomeInitialLayer.java b/Common/src/main/java/terrablender/worldgen/noise/BiomeInitialLayer.java new file mode 100644 index 0000000..aeca98f --- /dev/null +++ b/Common/src/main/java/terrablender/worldgen/noise/BiomeInitialLayer.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2024, the Glitchfiend Team. + * All rights reserved. + ******************************************************************************/ +package terrablender.worldgen.noise; + +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.random.WeightedEntry; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; + +import java.util.List; + +public class BiomeInitialLayer extends WeightedRandomLayer>> +{ + private final Registry biomeRegistry; + + public BiomeInitialLayer(RegistryAccess registryAccess, List>> entries) + { + super(entries); + this.biomeRegistry = registryAccess.registryOrThrow(Registries.BIOME); + } + + @Override + protected int getEntryIndex(WeightedEntry.Wrapper> entry) + { + return this.resolveId(entry.getData()); + } + + @Override + protected int getDefaultIndex() + { + return this.resolveId(Biomes.OCEAN); + } + + private int resolveId(ResourceKey key) + { + if (!this.biomeRegistry.containsKey(key)) + throw new RuntimeException("Attempted to resolve id for unregistered biome " + key); + + return this.biomeRegistry.getId(this.biomeRegistry.get(key)); + } +} diff --git a/Common/src/main/java/terrablender/worldgen/noise/InitialLayer.java b/Common/src/main/java/terrablender/worldgen/noise/InitialLayer.java index bbdc35b..916c5ed 100644 --- a/Common/src/main/java/terrablender/worldgen/noise/InitialLayer.java +++ b/Common/src/main/java/terrablender/worldgen/noise/InitialLayer.java @@ -32,65 +32,31 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; -public class InitialLayer implements AreaTransformer0 +public class InitialLayer extends WeightedRandomLayer> { private final RegionType regionType; - private final WeightedRandomList> weightedEntries; - public InitialLayer(RegistryAccess registryAccess, RegionType type) + public InitialLayer(RegistryAccess registryAccess, RegionType regionType) { - Registry biomeRegistry = registryAccess.registryOrThrow(Registries.BIOME); - this.regionType = type; - this.weightedEntries = WeightedRandomList.create(Regions.get(this.regionType).stream().filter(region -> { - AtomicBoolean biomesAdded = new AtomicBoolean(false); - region.addBiomes(biomeRegistry, pair -> biomesAdded.set(true)); - - // Filter out irrelevant regions or regions without any biomes - return region.getType() == type && biomesAdded.get(); - }).map(region -> WeightedEntry.wrap(region, region.getWeight())).collect(ImmutableList.toImmutableList())); + super(createEntries(registryAccess, regionType)); + this.regionType = regionType; } @Override - public int apply(AreaContext context, int x, int y) + protected int getEntryIndex(WeightedEntry.Wrapper entry) { - Optional> entry = weightedEntries.getRandom(context); - return entry.isPresent() ? Regions.getIndex(this.regionType, entry.get().getData().getName()) : 0; + return Regions.getIndex(this.regionType, entry.getData().getName()); } - private static class WeightedRandomList + private static List> createEntries(RegistryAccess registryAccess, RegionType regionType) { - private final int totalWeight; - private final ImmutableList items; - - WeightedRandomList(List items) - { - this.items = ImmutableList.copyOf(items); - this.totalWeight = WeightedRandom.getTotalWeight(items); - } - - public static WeightedRandomList create() { - return new WeightedRandomList<>(ImmutableList.of()); - } - - @SafeVarargs - public static WeightedRandomList create(E... entries) - { - return new WeightedRandomList<>(ImmutableList.copyOf(entries)); - } - - public static WeightedRandomList create(List entries) - { - return new WeightedRandomList<>(entries); - } + Registry biomeRegistry = registryAccess.registryOrThrow(Registries.BIOME); + return Regions.get(regionType).stream().filter(region -> { + AtomicBoolean biomesAdded = new AtomicBoolean(false); + region.addBiomes(biomeRegistry, pair -> biomesAdded.set(true)); - public Optional getRandom(AreaContext context) - { - if (this.totalWeight == 0) { - return Optional.empty(); - } else { - int i = context.nextRandom(this.totalWeight); - return WeightedRandom.getWeightedItem(this.items, i); - } - } + // Filter out irrelevant regions or regions without any biomes + return region.getType() == regionType && biomesAdded.get(); + }).map(region -> WeightedEntry.wrap(region, region.getWeight())).collect(ImmutableList.toImmutableList()); } -} +} \ No newline at end of file diff --git a/Common/src/main/java/terrablender/worldgen/noise/LayeredNoiseUtil.java b/Common/src/main/java/terrablender/worldgen/noise/LayeredNoiseUtil.java index 0389f77..cbc870d 100644 --- a/Common/src/main/java/terrablender/worldgen/noise/LayeredNoiseUtil.java +++ b/Common/src/main/java/terrablender/worldgen/noise/LayeredNoiseUtil.java @@ -18,25 +18,39 @@ package terrablender.worldgen.noise; import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.random.WeightedEntry; +import net.minecraft.world.level.biome.Biome; import terrablender.api.RegionType; import terrablender.core.TerraBlender; +import java.util.List; import java.util.function.LongFunction; public class LayeredNoiseUtil { - public static Area uniqueness(RegistryAccess registryAccess, RegionType regionType, long worldSeed) + public static Area uniqueness(RegistryAccess registryAccess, RegionType regionType, long seed) { int numZooms = TerraBlender.CONFIG.overworldRegionSize; if (regionType == RegionType.NETHER) numZooms = TerraBlender.CONFIG.netherRegionSize; - LongFunction contextFactory = (seedModifier) -> new AreaContext(25, worldSeed, seedModifier); - AreaFactory factory = new InitialLayer(registryAccess, regionType).run(contextFactory.apply(1L)); + return createZoomedArea(seed, numZooms, new InitialLayer(registryAccess, regionType)); + } + + public static Area biomeArea(RegistryAccess registryAccess, long seed, int size, List>> entries) + { + return createZoomedArea(seed, size, new BiomeInitialLayer(registryAccess, entries)); + } + + public static Area createZoomedArea(long seed, int zooms, AreaTransformer0 initialTransformer) + { + LongFunction contextFactory = (seedModifier) -> new AreaContext(25, seed, seedModifier); + AreaFactory factory = initialTransformer.run(contextFactory.apply(1L)); factory = ZoomLayer.FUZZY.run(contextFactory.apply(2000L), factory); factory = zoom(2001L, ZoomLayer.NORMAL, factory, 3, contextFactory); - factory = zoom(1001L, ZoomLayer.NORMAL, factory, numZooms, contextFactory); + factory = zoom(1001L, ZoomLayer.NORMAL, factory, zooms, contextFactory); return factory.make(); } diff --git a/Common/src/main/java/terrablender/worldgen/noise/WeightedRandomLayer.java b/Common/src/main/java/terrablender/worldgen/noise/WeightedRandomLayer.java new file mode 100644 index 0000000..c260a75 --- /dev/null +++ b/Common/src/main/java/terrablender/worldgen/noise/WeightedRandomLayer.java @@ -0,0 +1,46 @@ +/** + * Copyright (C) Glitchfiend + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package terrablender.worldgen.noise; + +import net.minecraft.util.random.WeightedEntry; +import terrablender.util.WeightedRandomList; + +import java.util.List; + +public abstract class WeightedRandomLayer implements AreaTransformer0 +{ + private final WeightedRandomList weightedEntries; + + public WeightedRandomLayer(List entries) + { + this.weightedEntries = WeightedRandomList.create(entries); + } + + @Override + public int apply(AreaContext context, int x, int y) + { + return this.weightedEntries.getRandom(context).map(this::getEntryIndex).orElse(getDefaultIndex()); + } + + protected abstract int getEntryIndex(T entry); + + protected int getDefaultIndex() + { + return 0; + } +} diff --git a/Common/src/main/resources/terrablender.mixins.json b/Common/src/main/resources/terrablender.mixins.json index 0ee92dc..135d086 100644 --- a/Common/src/main/resources/terrablender.mixins.json +++ b/Common/src/main/resources/terrablender.mixins.json @@ -9,7 +9,8 @@ "MixinMultiNoiseBiomeSource", "MixinNoiseGeneratorSettings", "MixinParameterList", - "MixinPrimaryLevelData" + "MixinPrimaryLevelData", + "MixinTheEndBiomeSource" ], "client": [ "MixinWorldOpenFlows" diff --git a/gradle.properties b/gradle.properties index 1d891d2..3aee4ea 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ forge_ats_enabled=true # Fabric fabric_version=0.83.1+1.20.1 -fabric_loader_version=0.14.21 +fabric_loader_version=0.15.0 # Mod options mod_name=TerraBlender