Implement tiled biome distribution
Build / build (push) Canceled after 0s

This commit is contained in:
dnorberg committed 2026-09-22 17:04:34 -04:00
1 parent 6c1c90b171
commit 3ad518232a
5 files changed
+64 -22

No files matched your search

@@ -21,7 +21,7 @@ public record AgeDefinition(
public static final ResourceLocation RANDOM_VANILLA_PROFILE = ResourceLocation.fromNamespaceAndPath(
Rivencraft.MOD_ID, "random_vanilla"
);
public static final int CURRENT_GENERATION_VERSION = 9;
public static final int CURRENT_GENERATION_VERSION = 10;
public AgeDefinition {
Objects.requireNonNull(id, "id");
@@ -6,10 +6,12 @@ import java.util.Optional;
import java.util.OptionalLong;
import java.util.List;
import java.util.Comparator;
import java.util.Collections;
import net.dnorberg.rivencraft.Rivencraft;
import net.dnorberg.rivencraft.compat.ImmersivePortalsChunkLoaders;
import net.minecraft.core.BlockPos;
import net.minecraft.core.GlobalPos;
import net.minecraft.core.HolderSet;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
@@ -23,6 +25,7 @@ import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.CheckerboardColumnBiomeSource;
import net.minecraft.world.level.biome.FixedBiomeSource;
import net.minecraft.world.level.biome.MultiNoiseBiomeSource;
import net.minecraft.world.level.biome.MultiNoiseBiomeSourceParameterLists;
@@ -42,6 +45,7 @@ public final class AgeDimensionService {
private static final int SURFACE_SEARCH_RADIUS = 16;
private static final int FALLBACK_PLATFORM_Y = 63;
private static final int CAVE_SPAWN_SEARCH_Y = 64;
private static final int TILED_BIOME_SCALE = 4;
private AgeDimensionService() {
}
@@ -278,16 +282,22 @@ public final class AgeDimensionService {
AgeDefinition age,
net.minecraft.core.HolderGetter<net.minecraft.world.level.biome.MultiNoiseBiomeSourceParameterList> biomeParameters
) {
if (age.traits().biomeDistribution() == AgeTraits.BiomeDistribution.SINGLE) {
List<net.minecraft.core.Holder.Reference<Biome>> biomes = server.registryAccess()
.lookupOrThrow(Registries.BIOME)
.listElements()
.sorted(Comparator.comparing(holder -> holder.key().location().toString()))
.toList();
if (!biomes.isEmpty()) {
int index = Math.floorMod(Long.hashCode(age.seed() ^ 0x53494E474C454249L), biomes.size());
return new FixedBiomeSource(biomes.get(index));
}
List<net.minecraft.core.Holder.Reference<Biome>> biomes = server.registryAccess()
.lookupOrThrow(Registries.BIOME)
.listElements()
.sorted(Comparator.comparing(holder -> holder.key().location().toString()))
.toList();
if (age.traits().biomeDistribution() == AgeTraits.BiomeDistribution.SINGLE && !biomes.isEmpty()) {
int index = Math.floorMod(Long.hashCode(age.seed() ^ 0x53494E474C454249L), biomes.size());
return new FixedBiomeSource(biomes.get(index));
}
if (age.traits().biomeDistribution() == AgeTraits.BiomeDistribution.TILED && biomes.size() >= 2) {
List<net.minecraft.core.Holder.Reference<Biome>> selected = new java.util.ArrayList<>(biomes);
Collections.shuffle(selected, new java.util.Random(age.seed() ^ 0x54494C454442494FL));
return new CheckerboardColumnBiomeSource(
HolderSet.direct(List.of(selected.get(0), selected.get(1))),
TILED_BIOME_SCALE
);
}
return MultiNoiseBiomeSource.createFromPreset(
biomeParameters.getOrThrow(MultiNoiseBiomeSourceParameterLists.OVERWORLD));
@@ -155,6 +155,26 @@ public final class LinkingGameTests {
public static void legacyBaseTerrainProfilesLoadRuntimeDimensions(GameTestHelper helper) {
for (var profile : AgeGenerationProfiles.all()) {
UUID id = UUID.randomUUID();
AgeTraits selectedTraits = AgeTraits.select(id.getMostSignificantBits());
AgeTraits traits = profile.equals(AgeGenerationProfiles.STANDARD)
? new AgeTraits(
AgeTraits.BiomeDistribution.SINGLE,
AgeTraits.Lighting.NORMAL,
AgeTraits.Weather.NORMAL,
1.0D,
0.0F,
0.0F
)
: profile.equals(AgeGenerationProfiles.AMPLIFIED)
? new AgeTraits(
AgeTraits.BiomeDistribution.TILED,
selectedTraits.lighting(),
selectedTraits.weather(),
selectedTraits.celestialPeriod(),
selectedTraits.celestialAngle(),
selectedTraits.celestialPhase()
)
: selectedTraits;
AgeDefinition definition = new AgeDefinition(
id,
"Profile " + profile.getPath(),
@@ -166,16 +186,7 @@ public final class LinkingGameTests {
Rivencraft.MOD_ID, "gametest/" + profile.getPath() + "_" + id
),
null,
profile.equals(AgeGenerationProfiles.STANDARD)
? new AgeTraits(
AgeTraits.BiomeDistribution.SINGLE,
AgeTraits.Lighting.NORMAL,
AgeTraits.Weather.NORMAL,
1.0D,
0.0F,
0.0F
)
: AgeTraits.select(id.getMostSignificantBits())
traits
);
var level = AgeDimensionService.ensureLoaded(helper.getLevel().getServer(), definition);
helper.assertTrue(level != null, "The " + profile + " profile must load a runtime dimension");
@@ -192,6 +203,21 @@ public final class LinkingGameTests {
"Single Biome Distribution must expose exactly one biome"
);
}
if (profile.equals(AgeGenerationProfiles.AMPLIFIED)) {
var biomeSource = level.getChunkSource().getGenerator().getBiomeSource();
helper.assertValueEqual(
biomeSource.possibleBiomes().size(),
2,
"Tiled Biome Distribution must expose exactly two seeded biomes"
);
var origin = biomeSource.getNoiseBiome(0, 0, 0, null);
var eastTile = biomeSource.getNoiseBiome(64, 0, 0, null);
var diagonalTile = biomeSource.getNoiseBiome(64, 0, 64, null);
helper.assertFalse(origin.equals(eastTile),
"Adjacent 256-block Tiled squares must alternate biomes");
helper.assertTrue(origin.equals(diagonalTile),
"Diagonal 256-block Tiled squares must repeat the biome");
}
if (definition.traits().lighting() == AgeTraits.Lighting.DARK) {
helper.assertFalse(level.dimensionType().hasSkyLight(),
"Dark Lighting Ages must suppress dimension skylight");