mirror of
https://github.com/FabricMC/fabric.git
synced 2024-12-11 16:51:29 -05:00
End Biomes Api [1.16] Take Two (#1164)
* Create EndBiomes.java * Revert "Create EndBiomes.java" This reverts commit4d1736fad9
. * Revert "Revert "Create EndBiomes.java"" This reverts commit673c508d82
. * Rename ContinentalBiomeEntry to WeightedBiomeEntry * Complete API for adding biomes to the end * Mixin to end biome source * Revert "Rename ContinentalBiomeEntry to WeightedBiomeEntry" This reverts commit 849197e15d18c26af2a6f2aa1766b7d73d9a7144. * Revert "Revert "Rename ContinentalBiomeEntry to WeightedBiomeEntry"" This reverts commit c2aa4ab097eb3daed71e82d4e77142671ed04316. * Create SimpleLayerRandomnessSource for use with end biome source mixin * Renamed MAIN region to MAIN_ISLANDS * Create test mod * Added pickFromNoise method to WeightedBiomePicker * Javadoc and licensing info * Comply with checkstyle * Internalize EndRegion * Added stretching when getting the biome for the end * Rename EndBiomes to TheEndBiomes to be consistent with yarn mappings * Fix typo Courtesy of i509VBC Co-authored-by: i509VCB <i509vcb@gmail.com> * Add @Unique to private fields in MixinTheEndBiomeSource * Made end test biome consistent in style with previous test Courtesy of i509VBC Co-authored-by: i509VCB <i509vcb@gmail.com> * Fix imports * Didn't know test mods needed to follow the checkstyle * SimpleLayerRandomnessSource's random is now use to instantiate its noise sampler * A very important note * Update javadoc for adding biomes to the Main Island region * Remove method that is leftover from when EndRegion was part of the API * Ported 1.16.1 biomes-api-v1 to 1.16.2. Public API changes: - Removed flagging biomes as suitable for player spawns since that is now handled in the Biome Builder. - Changed API over to RegistryKey's, not because it's necessary, but because it is more ergonomic since Vanilla Biomes in BuiltInBiomes are now all exposed as keys, rather than instances. * Increase memory size to fix build failures. * Add the ability to add modded dimensions to the regions of the end. * Hopefully fixed everything that went wrong during the rebase * Update fabric-biome-api-v1.mixins.json * Finally got custom end biomes to generate * Thanks for nothing, GitHub Desktop * Bad GitHub Desktop * Bad newline no cookie * Got everything to follow the checkstyle * Bring branch up-to-date with main repo (#11) * Revert "Bring branch up-to-date with main repo (#11)" This reverts commitdc47106241
. * Remove some stuff that's not supposed to be there * Fix git silliness * Update FabricBiomeTest.java * TheEndBiomes is now Deprecated to match OverworldBiomes and NetherBiomes * Update some checkNotNull messages * Change the noise scale when replacing end biomes * Bad space no cookie * Remove unnecessary code * Remove unused imports * Set up InternalBiomeData to treat End Midlands and End Barrens as border biomes * Changed the API to reflect midlands and barrens biomes being considered border biomes * Start work on getting the new system fully working * Finally got everything working and cleaned up the Javadoc * Fixed checkstyle violations * Fix checkstyle violations again * Drop fabric_ prefix * Calling SimpleLayerRandomnessSource#nextInt() now throws an exception * If the midlands or barrens biome picker is null, the replacement key defaults to the vanilla one * Fix usage of vanilla identifier * Update MixinTheEndBiomeSource.java * Fix checkstyle violations Co-authored-by: i509VCB <i509vcb@gmail.com> Co-authored-by: Sebastian Hartte <sebastian@hartte.de>
This commit is contained in:
parent
6a2618f55c
commit
18f3e47f61
9 changed files with 348 additions and 13 deletions
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.biome.v1;
|
||||
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeKeys;
|
||||
|
||||
import net.fabricmc.fabric.impl.biome.InternalBiomeData;
|
||||
|
||||
/**
|
||||
* API that exposes some internals of the minecraft default biome source for The End.
|
||||
*
|
||||
* @deprecated Experimental feature, may be removed or changed without further notice.
|
||||
* Because of the volatility of world generation in Minecraft 1.16, this API is marked experimental
|
||||
* since it is likely to change in future Minecraft versions.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class TheEndBiomes {
|
||||
private TheEndBiomes() { }
|
||||
|
||||
/**
|
||||
* <p>Adds the biome as a main end island biome with the specified weight; note that this includes the main island
|
||||
* and some of the land encircling the empty space. Note that adding a biome to this region could potentially mess
|
||||
* with the generation of the center island and cause it to generate incorrectly; this method only exists for
|
||||
* consistency.</p>
|
||||
*
|
||||
* @param biome the biome to be added
|
||||
* @param weight the weight of the entry. The weight in this method corresponds to its selection likelihood, with
|
||||
* heavier biomes being more likely to be selected and lighter biomes being selected with less likelihood.
|
||||
* Vanilla biomes have a weight of 1.0
|
||||
*/
|
||||
public static void addMainIslandBiome(RegistryKey<Biome> biome, double weight) {
|
||||
InternalBiomeData.addEndBiomeReplacement(BiomeKeys.THE_END, biome, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Adds the biome as an end highlands biome with the specified weight. End Highlands biomes make up the
|
||||
* center region of the large outer islands in The End.</p>
|
||||
*
|
||||
* @param biome the biome to be added
|
||||
* @param weight the weight of the entry. The weight in this method corresponds to its selection likelihood, with
|
||||
* heavier biomes being more likely to be selected and lighter biomes being selected with less likelihood.
|
||||
* The vanilla biome has a weight of 1.0.
|
||||
*/
|
||||
public static void addHighlandsBiome(RegistryKey<Biome> biome, double weight) {
|
||||
InternalBiomeData.addEndBiomeReplacement(BiomeKeys.END_HIGHLANDS, biome, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Adds a custom biome as a small end islands biome with the specified weight; small end island biomes
|
||||
* make up the smaller islands in between the larger islands of the end.</p>
|
||||
*
|
||||
* @param biome the biome to be added
|
||||
* @param weight the weight of the entry. The weight in this method corresponds to its selection likelihood, with
|
||||
* heavier biomes being more likely to be selected and lighter biomes being selected with less likelihood.
|
||||
* The vanilla biome has a weight of 1.0.
|
||||
*/
|
||||
public static void addSmallIslandsBiome(RegistryKey<Biome> biome, double weight) {
|
||||
InternalBiomeData.addEndBiomeReplacement(BiomeKeys.SMALL_END_ISLANDS, biome, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Adds the biome as an end midlands of the parent end highlands biome. End Midlands make up the area on
|
||||
* the large outer islands between the highlands and the barrens and are similar to edge biomes in the
|
||||
* overworld. If you don't call this method, the vanilla biome will be used by default.</p>
|
||||
*
|
||||
* @param highlands The highlands biome to where the midlands biome is added
|
||||
* @param midlands the biome to be added as a midlands biome
|
||||
* @param weight the weight of the entry. The weight in this method corresponds to its selection likelihood, with
|
||||
* heavier biomes being more likely to be selected and lighter biomes being selected with less likelihood.
|
||||
* The vanilla biome has a weight of 1.0.
|
||||
*/
|
||||
public static void addMidlandsBiome(RegistryKey<Biome> highlands, RegistryKey<Biome> midlands, double weight) {
|
||||
InternalBiomeData.addEndMidlandsReplacement(highlands, midlands, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Adds the biome as an end barrens of the parent end highlands biome. End Midlands make up the area on
|
||||
* the edge of the large outer islands and are similar to edge biomes in the overworld. If you don't call
|
||||
* this method, the vanilla biome will be used by default.</p>
|
||||
*
|
||||
* @param highlands The highlands biome to where the barrends biome is added
|
||||
* @param barrens the biome to be added as a barrens biome
|
||||
* @param weight the weight of the entry. The weight in this method corresponds to its selection likelihood, with
|
||||
* heavier biomes being more likely to be selected and lighter biomes being selected with less likelihood.
|
||||
* The vanilla biome has a weight of 1.0.
|
||||
*/
|
||||
public static void addBarrensBiome(RegistryKey<Biome> highlands, RegistryKey<Biome> barrens, double weight) {
|
||||
InternalBiomeData.addEndBarrensReplacement(highlands, barrens, weight);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
|||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -48,15 +49,28 @@ public final class InternalBiomeData {
|
|||
}
|
||||
|
||||
private static final EnumMap<OverworldClimate, WeightedBiomePicker> OVERWORLD_MODDED_CONTINENTAL_BIOME_PICKERS = new EnumMap<>(OverworldClimate.class);
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> OVERWORLD_HILLS_MAP = new HashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> OVERWORLD_SHORE_MAP = new HashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> OVERWORLD_EDGE_MAP = new HashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, VariantTransformer> OVERWORLD_VARIANT_TRANSFORMERS = new HashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, RegistryKey<Biome>> OVERWORLD_RIVER_MAP = new HashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> OVERWORLD_HILLS_MAP = new IdentityHashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> OVERWORLD_SHORE_MAP = new IdentityHashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> OVERWORLD_EDGE_MAP = new IdentityHashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, VariantTransformer> OVERWORLD_VARIANT_TRANSFORMERS = new IdentityHashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, RegistryKey<Biome>> OVERWORLD_RIVER_MAP = new IdentityHashMap<>();
|
||||
|
||||
private static final Set<RegistryKey<Biome>> NETHER_BIOMES = new HashSet<>();
|
||||
private static final Map<RegistryKey<Biome>, Biome.MixedNoisePoint> NETHER_BIOME_NOISE_POINTS = new HashMap<>();
|
||||
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> END_BIOMES_MAP = new IdentityHashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> END_MIDLANDS_MAP = new IdentityHashMap<>();
|
||||
private static final Map<RegistryKey<Biome>, WeightedBiomePicker> END_BARRENS_MAP = new IdentityHashMap<>();
|
||||
|
||||
static {
|
||||
END_BIOMES_MAP.computeIfAbsent(BiomeKeys.THE_END, key -> new WeightedBiomePicker()).addBiome(BiomeKeys.THE_END, 1.0);
|
||||
END_BIOMES_MAP.computeIfAbsent(BiomeKeys.END_HIGHLANDS, key -> new WeightedBiomePicker()).addBiome(BiomeKeys.END_HIGHLANDS, 1.0);
|
||||
END_BIOMES_MAP.computeIfAbsent(BiomeKeys.SMALL_END_ISLANDS, key -> new WeightedBiomePicker()).addBiome(BiomeKeys.SMALL_END_ISLANDS, 1.0);
|
||||
|
||||
END_MIDLANDS_MAP.computeIfAbsent(BiomeKeys.END_HIGHLANDS, key -> new WeightedBiomePicker()).addBiome(BiomeKeys.END_MIDLANDS, 1.0);
|
||||
END_BARRENS_MAP.computeIfAbsent(BiomeKeys.END_HIGHLANDS, key -> new WeightedBiomePicker()).addBiome(BiomeKeys.END_BARRENS, 1.0);
|
||||
}
|
||||
|
||||
public static void addOverworldContinentalBiome(OverworldClimate climate, RegistryKey<Biome> biome, double weight) {
|
||||
Preconditions.checkArgument(climate != null, "Climate is null");
|
||||
Preconditions.checkArgument(biome != null, "Biome is null");
|
||||
|
@ -144,6 +158,27 @@ public final class InternalBiomeData {
|
|||
NETHER_BIOMES.clear(); // Reset cached overall biome list
|
||||
}
|
||||
|
||||
public static void addEndBiomeReplacement(RegistryKey<Biome> replaced, RegistryKey<Biome> variant, double weight) {
|
||||
Preconditions.checkNotNull(replaced, "replaced biome is null");
|
||||
Preconditions.checkNotNull(variant, "variant biome is null");
|
||||
Preconditions.checkArgument(weight > 0.0, "Weight is less than or equal to 0.0 (got %s)", weight);
|
||||
END_BIOMES_MAP.computeIfAbsent(replaced, key -> new WeightedBiomePicker()).addBiome(variant, weight);
|
||||
}
|
||||
|
||||
public static void addEndMidlandsReplacement(RegistryKey<Biome> highlands, RegistryKey<Biome> midlands, double weight) {
|
||||
Preconditions.checkNotNull(highlands, "highlands biome is null");
|
||||
Preconditions.checkNotNull(midlands, "midlands biome is null");
|
||||
Preconditions.checkArgument(weight > 0.0, "Weight is less than or equal to 0.0 (got %s)", weight);
|
||||
END_MIDLANDS_MAP.computeIfAbsent(highlands, key -> new WeightedBiomePicker()).addBiome(midlands, weight);
|
||||
}
|
||||
|
||||
public static void addEndBarrensReplacement(RegistryKey<Biome> highlands, RegistryKey<Biome> barrens, double weight) {
|
||||
Preconditions.checkNotNull(highlands, "highlands biome is null");
|
||||
Preconditions.checkNotNull(barrens, "midlands biome is null");
|
||||
Preconditions.checkArgument(weight > 0.0, "Weight is less than or equal to 0.0 (got %s)", weight);
|
||||
END_BARRENS_MAP.computeIfAbsent(highlands, key -> new WeightedBiomePicker()).addBiome(barrens, weight);
|
||||
}
|
||||
|
||||
public static Map<RegistryKey<Biome>, WeightedBiomePicker> getOverworldHills() {
|
||||
return OVERWORLD_HILLS_MAP;
|
||||
}
|
||||
|
@ -184,6 +219,18 @@ public final class InternalBiomeData {
|
|||
return NETHER_BIOMES.contains(biome);
|
||||
}
|
||||
|
||||
public static Map<RegistryKey<Biome>, WeightedBiomePicker> getEndBiomesMap() {
|
||||
return END_BIOMES_MAP;
|
||||
}
|
||||
|
||||
public static Map<RegistryKey<Biome>, WeightedBiomePicker> getEndMidlandsMap() {
|
||||
return END_MIDLANDS_MAP;
|
||||
}
|
||||
|
||||
public static Map<RegistryKey<Biome>, WeightedBiomePicker> getEndBarrensMap() {
|
||||
return END_BARRENS_MAP;
|
||||
}
|
||||
|
||||
private static class DefaultHillsData {
|
||||
private static final ImmutableMap<RegistryKey<Biome>, RegistryKey<Biome>> DEFAULT_HILLS;
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public final class InternalBiomeUtils {
|
|||
return biome != null && biome.getCategory() == Biome.Category.OCEAN;
|
||||
}
|
||||
|
||||
public static int searchForBiome(double reqWeightSum, int vanillaArrayWeight, List<ContinentalBiomeEntry> moddedBiomes) {
|
||||
public static int searchForBiome(double reqWeightSum, int vanillaArrayWeight, List<WeightedBiomeEntry> moddedBiomes) {
|
||||
reqWeightSum -= vanillaArrayWeight;
|
||||
int low = 0;
|
||||
int high = moddedBiomes.size() - 1;
|
||||
|
@ -152,7 +152,7 @@ public final class InternalBiomeUtils {
|
|||
} else {
|
||||
// Modded biome; use a binary search, and then transform accordingly.
|
||||
|
||||
ContinentalBiomeEntry found = picker.search(reqWeightSum - vanillaArrayWeight);
|
||||
WeightedBiomeEntry found = picker.search(reqWeightSum - vanillaArrayWeight);
|
||||
|
||||
result.accept(transformBiome(random, found.getBiome(), climate));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.biome;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.util.math.noise.PerlinNoiseSampler;
|
||||
import net.minecraft.world.biome.layer.util.LayerRandomnessSource;
|
||||
|
||||
public class SimpleLayerRandomnessSource implements LayerRandomnessSource {
|
||||
private final PerlinNoiseSampler sampler;
|
||||
|
||||
public SimpleLayerRandomnessSource(long seed) {
|
||||
Random random = new Random(seed);
|
||||
this.sampler = new PerlinNoiseSampler(random);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextInt(int bound) {
|
||||
throw new UnsupportedOperationException("SimpleLayerRandomnessSource does not support calling nextInt(int).");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PerlinNoiseSampler getNoiseSampler() {
|
||||
return sampler;
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ import net.minecraft.world.biome.Biome;
|
|||
/**
|
||||
* Represents a biome and its corresponding weight.
|
||||
*/
|
||||
final class ContinentalBiomeEntry {
|
||||
final class WeightedBiomeEntry {
|
||||
private final RegistryKey<Biome> biome;
|
||||
private final double weight;
|
||||
private final double upperWeightBound;
|
||||
|
@ -32,7 +32,7 @@ final class ContinentalBiomeEntry {
|
|||
* @param weight how often a biome will be chosen
|
||||
* @param upperWeightBound the upper weight bound within the context of the other entries, used for the binary search
|
||||
*/
|
||||
ContinentalBiomeEntry(final RegistryKey<Biome> biome, final double weight, final double upperWeightBound) {
|
||||
WeightedBiomeEntry(final RegistryKey<Biome> biome, final double weight, final double upperWeightBound) {
|
||||
this.biome = biome;
|
||||
this.weight = weight;
|
||||
this.upperWeightBound = upperWeightBound;
|
|
@ -30,7 +30,7 @@ import net.minecraft.world.biome.layer.util.LayerRandomnessSource;
|
|||
*/
|
||||
public final class WeightedBiomePicker {
|
||||
private double currentTotal;
|
||||
private List<ContinentalBiomeEntry> entries;
|
||||
private final List<WeightedBiomeEntry> entries;
|
||||
|
||||
WeightedBiomePicker() {
|
||||
currentTotal = 0;
|
||||
|
@ -40,7 +40,7 @@ public final class WeightedBiomePicker {
|
|||
void addBiome(final RegistryKey<Biome> biome, final double weight) {
|
||||
currentTotal += weight;
|
||||
|
||||
entries.add(new ContinentalBiomeEntry(biome, weight, currentTotal));
|
||||
entries.add(new WeightedBiomeEntry(biome, weight, currentTotal));
|
||||
}
|
||||
|
||||
double getCurrentWeightTotal() {
|
||||
|
@ -53,13 +53,19 @@ public final class WeightedBiomePicker {
|
|||
return search(target).getBiome();
|
||||
}
|
||||
|
||||
public RegistryKey<Biome> pickFromNoise(LayerRandomnessSource source, double x, double y, double z) {
|
||||
double target = Math.abs(source.getNoiseSampler().sample(x, y, z, 0.0, 0.0)) * getCurrentWeightTotal();
|
||||
|
||||
return search(target).getBiome();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches with the specified target value.
|
||||
*
|
||||
* @param target The target value, must satisfy the constraint 0 <= target <= currentTotal
|
||||
* @return The result of the search
|
||||
*/
|
||||
ContinentalBiomeEntry search(final double target) {
|
||||
WeightedBiomeEntry search(final double target) {
|
||||
// Sanity checks, fail fast if stuff is going wrong.
|
||||
Preconditions.checkArgument(target <= currentTotal, "The provided target value for biome selection must be less than or equal to the weight total");
|
||||
Preconditions.checkArgument(target >= 0, "The provided target value for biome selection cannot be negative");
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.biome;
|
||||
|
||||
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 net.minecraft.world.biome.BiomeKeys;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.biome.layer.util.LayerRandomnessSource;
|
||||
import net.minecraft.world.biome.source.TheEndBiomeSource;
|
||||
|
||||
import net.fabricmc.fabric.impl.biome.InternalBiomeData;
|
||||
import net.fabricmc.fabric.impl.biome.SimpleLayerRandomnessSource;
|
||||
import net.fabricmc.fabric.impl.biome.WeightedBiomePicker;
|
||||
|
||||
@Mixin(TheEndBiomeSource.class)
|
||||
public class MixinTheEndBiomeSource {
|
||||
@Shadow
|
||||
@Final
|
||||
private Registry<Biome> biomeRegistry;
|
||||
@Shadow
|
||||
@Final
|
||||
private long seed;
|
||||
@Unique
|
||||
private LayerRandomnessSource randomnessSource = new SimpleLayerRandomnessSource(seed);
|
||||
|
||||
@Inject(method = "getBiomeForNoiseGen", at = @At("RETURN"), cancellable = true)
|
||||
private void getWeightedEndBiome(int biomeX, int biomeY, int biomeZ, CallbackInfoReturnable<Biome> cir) {
|
||||
Biome vanillaBiome = cir.getReturnValue();
|
||||
|
||||
// Since all vanilla biomes are added to the registry, this will never fail.
|
||||
RegistryKey<Biome> vanillaKey = biomeRegistry.getKey(vanillaBiome).get();
|
||||
RegistryKey<Biome> replacementKey;
|
||||
|
||||
// The x and z of the biome are divided by 64 to ensure custom biomes are large enough; going larger than this]
|
||||
// seems to make custom biomes too hard to find.
|
||||
if (vanillaKey == BiomeKeys.END_MIDLANDS || vanillaKey == BiomeKeys.END_BARRENS) {
|
||||
// Since the highlands picker is statically populated by InternalBiomeData, picker will never be null.
|
||||
WeightedBiomePicker highlandsPicker = InternalBiomeData.getEndBiomesMap().get(BiomeKeys.END_HIGHLANDS);
|
||||
RegistryKey<Biome> highlandsKey = highlandsPicker.pickFromNoise(randomnessSource, biomeX/64.0, 0, biomeZ/64.0);
|
||||
|
||||
if (vanillaKey == BiomeKeys.END_MIDLANDS) {
|
||||
WeightedBiomePicker midlandsPicker = InternalBiomeData.getEndMidlandsMap().get(highlandsKey);
|
||||
replacementKey = (midlandsPicker == null) ? vanillaKey : midlandsPicker.pickFromNoise(randomnessSource, biomeX/64.0, 0, biomeZ/64.0);
|
||||
} else {
|
||||
WeightedBiomePicker barrensPicker = InternalBiomeData.getEndBarrensMap().get(highlandsKey);
|
||||
replacementKey = (barrensPicker == null) ? vanillaKey : barrensPicker.pickFromNoise(randomnessSource, biomeX/64.0, 0, biomeZ/64.0);
|
||||
}
|
||||
} else {
|
||||
// Since the main island and small islands pickers are statically populated by InternalBiomeData, picker will never be null.
|
||||
WeightedBiomePicker picker = InternalBiomeData.getEndBiomesMap().get(vanillaKey);
|
||||
replacementKey = picker.pickFromNoise(randomnessSource, biomeX/64.0, 0, biomeZ/64.0);
|
||||
}
|
||||
|
||||
cir.setReturnValue(biomeRegistry.get(replacementKey));
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
"MixinAddRiversLayer",
|
||||
"MixinMultiNoiseBiomeSource",
|
||||
"MixinSetBaseBiomesLayer",
|
||||
"MixinTheEndBiomeSource",
|
||||
"MultiNoiseBiomeSourceAccessor",
|
||||
"VanillaLayeredBiomeSourceAccessor"
|
||||
],
|
||||
|
|
|
@ -16,14 +16,28 @@
|
|||
|
||||
package net.fabricmc.fabric.test.biome;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.sound.BiomeMoodSound;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.BuiltinRegistries;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeEffects;
|
||||
import net.minecraft.world.biome.BiomeKeys;
|
||||
import net.minecraft.world.biome.DefaultBiomeCreator;
|
||||
import net.minecraft.world.biome.GenerationSettings;
|
||||
import net.minecraft.world.biome.SpawnSettings;
|
||||
import net.minecraft.world.gen.GenerationStep;
|
||||
import net.minecraft.world.gen.feature.ConfiguredFeatures;
|
||||
import net.minecraft.world.gen.feature.ConfiguredStructureFeatures;
|
||||
import net.minecraft.world.gen.feature.DefaultBiomeFeatures;
|
||||
import net.minecraft.world.gen.surfacebuilder.ConfiguredSurfaceBuilders;
|
||||
import net.minecraft.world.gen.surfacebuilder.ConfiguredSurfaceBuilder;
|
||||
import net.minecraft.world.gen.surfacebuilder.SurfaceBuilder;
|
||||
import net.minecraft.world.gen.surfacebuilder.SurfaceConfig;
|
||||
import net.minecraft.world.gen.surfacebuilder.TernarySurfaceConfig;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
|
||||
|
@ -32,6 +46,7 @@ import net.fabricmc.fabric.api.biome.v1.ModificationPhase;
|
|||
import net.fabricmc.fabric.api.biome.v1.NetherBiomes;
|
||||
import net.fabricmc.fabric.api.biome.v1.OverworldBiomes;
|
||||
import net.fabricmc.fabric.api.biome.v1.OverworldClimate;
|
||||
import net.fabricmc.fabric.api.biome.v1.TheEndBiomes;
|
||||
|
||||
/**
|
||||
* <b>NOTES FOR TESTING:</b>
|
||||
|
@ -47,8 +62,13 @@ public class FabricBiomeTest implements ModInitializer {
|
|||
public static final String MOD_ID = "fabric-biome-api-v1-testmod";
|
||||
|
||||
private static final RegistryKey<Biome> TEST_CRIMSON_FOREST = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_crimson_forest"));
|
||||
|
||||
private static final RegistryKey<Biome> CUSTOM_PLAINS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "custom_plains"));
|
||||
private static final RegistryKey<Biome> TEST_END_HIGHLANDS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_highlands"));
|
||||
private static final RegistryKey<Biome> TEST_END_MIDLANDS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_midlands"));
|
||||
private static final RegistryKey<Biome> TEST_END_BARRRENS = RegistryKey.of(Registry.BIOME_KEY, new Identifier(MOD_ID, "test_end_barrens"));
|
||||
|
||||
private static BlockState STONE = Blocks.STONE.getDefaultState();
|
||||
private static ConfiguredSurfaceBuilder<TernarySurfaceConfig> TEST_END_SURFACE_BUILDER = registerTestSurfaceBuilder(new Identifier(MOD_ID, "end"), SurfaceBuilder.DEFAULT.withConfig(new TernarySurfaceConfig(STONE, STONE, STONE)));
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
|
@ -60,6 +80,15 @@ public class FabricBiomeTest implements ModInitializer {
|
|||
Registry.register(BuiltinRegistries.BIOME, CUSTOM_PLAINS.getValue(), DefaultBiomeCreator.createPlains(false));
|
||||
OverworldBiomes.addBiomeVariant(BiomeKeys.PLAINS, CUSTOM_PLAINS, 1);
|
||||
|
||||
Registry.register(BuiltinRegistries.BIOME, TEST_END_HIGHLANDS.getValue(), createEndHighlands());
|
||||
Registry.register(BuiltinRegistries.BIOME, TEST_END_MIDLANDS.getValue(), createEndMidlands());
|
||||
Registry.register(BuiltinRegistries.BIOME, TEST_END_BARRRENS.getValue(), createEndBarrens());
|
||||
// TESTING HINT: to get to the end:
|
||||
// /execute in minecraft:the_end run tp @s 0 90 0
|
||||
TheEndBiomes.addHighlandsBiome(TEST_END_HIGHLANDS, 5.0);
|
||||
TheEndBiomes.addMidlandsBiome(TEST_END_HIGHLANDS, TEST_END_MIDLANDS, 1.0);
|
||||
TheEndBiomes.addBarrensBiome(TEST_END_HIGHLANDS, TEST_END_BARRRENS, 1.0);
|
||||
|
||||
OverworldBiomes.addEdgeBiome(BiomeKeys.PLAINS, BiomeKeys.END_BARRENS, 0.9);
|
||||
|
||||
OverworldBiomes.addShoreBiome(BiomeKeys.FOREST, BiomeKeys.NETHER_WASTES, 0.9);
|
||||
|
@ -80,4 +109,30 @@ public class FabricBiomeTest implements ModInitializer {
|
|||
context.getGenerationSettings().setBuiltInSurfaceBuilder(ConfiguredSurfaceBuilders.CRIMSON_FOREST);
|
||||
});
|
||||
}
|
||||
|
||||
// These are used for testing the spacing of custom end biomes.
|
||||
private static Biome createEndHighlands() {
|
||||
GenerationSettings.Builder builder = (new GenerationSettings.Builder()).surfaceBuilder(TEST_END_SURFACE_BUILDER).structureFeature(ConfiguredStructureFeatures.END_CITY).feature(GenerationStep.Feature.SURFACE_STRUCTURES, ConfiguredFeatures.END_GATEWAY).feature(GenerationStep.Feature.VEGETAL_DECORATION, ConfiguredFeatures.CHORUS_PLANT);
|
||||
return composeEndSpawnSettings(builder);
|
||||
}
|
||||
|
||||
public static Biome createEndMidlands() {
|
||||
GenerationSettings.Builder builder = (new GenerationSettings.Builder()).surfaceBuilder(TEST_END_SURFACE_BUILDER).structureFeature(ConfiguredStructureFeatures.END_CITY);
|
||||
return composeEndSpawnSettings(builder);
|
||||
}
|
||||
|
||||
public static Biome createEndBarrens() {
|
||||
GenerationSettings.Builder builder = (new GenerationSettings.Builder()).surfaceBuilder(TEST_END_SURFACE_BUILDER);
|
||||
return composeEndSpawnSettings(builder);
|
||||
}
|
||||
|
||||
private static Biome composeEndSpawnSettings(GenerationSettings.Builder builder) {
|
||||
SpawnSettings.Builder builder2 = new SpawnSettings.Builder();
|
||||
DefaultBiomeFeatures.addEndMobs(builder2);
|
||||
return (new Biome.Builder()).precipitation(Biome.Precipitation.NONE).category(Biome.Category.THEEND).depth(0.1F).scale(0.2F).temperature(0.5F).downfall(0.5F).effects((new BiomeEffects.Builder()).waterColor(4159204).waterFogColor(329011).fogColor(10518688).skyColor(0).moodSound(BiomeMoodSound.CAVE).build()).spawnSettings(builder2.build()).generationSettings(builder.build()).build();
|
||||
}
|
||||
|
||||
private static <SC extends SurfaceConfig> ConfiguredSurfaceBuilder<SC> registerTestSurfaceBuilder(Identifier id, ConfiguredSurfaceBuilder<SC> configuredSurfaceBuilder) {
|
||||
return BuiltinRegistries.add(BuiltinRegistries.CONFIGURED_SURFACE_BUILDER, id, configuredSurfaceBuilder);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue