Apply End and Nether biome materials
Build / build (push) Canceled after 0s

This commit is contained in:
dnorberg committed 2026-09-22 22:19:14 -04:00
1 parent 5336eb46b9
commit 88af167f62
4 files changed
+119 -4

No files matched your search

@@ -11,7 +11,9 @@ 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.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.data.worldgen.SurfaceRuleData;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
@@ -37,6 +39,7 @@ import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.SurfaceRules;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
import net.neoforged.fml.ModList;
@@ -273,9 +276,47 @@ public final class AgeDimensionService {
// Island/Skylands uses uniform floating-island density without the
// End's central dragon island. Both use the Overworld environment.
// random_vanilla is retained as a migration alias for existing Ages.
return new NoiseBasedChunkGenerator(
createBiomeSource(server, age, biomeParameters),
noiseSettings.getOrThrow(settingsKey)
BiomeSource biomeSource = createBiomeSource(server, age, biomeParameters);
NoiseGeneratorSettings baseSettings = noiseSettings.getOrThrow(settingsKey).value();
return new NoiseBasedChunkGenerator(biomeSource, Holder.direct(withBiomeMaterialRules(baseSettings)));
}
private static NoiseGeneratorSettings withBiomeMaterialRules(NoiseGeneratorSettings base) {
SurfaceRules.RuleSource biomeMaterials = SurfaceRules.sequence(
SurfaceRules.ifTrue(
SurfaceRules.isBiome(
Biomes.THE_END,
Biomes.END_HIGHLANDS,
Biomes.END_MIDLANDS,
Biomes.SMALL_END_ISLANDS,
Biomes.END_BARRENS
),
SurfaceRuleData.end()
),
SurfaceRules.ifTrue(
SurfaceRules.isBiome(
Biomes.NETHER_WASTES,
Biomes.SOUL_SAND_VALLEY,
Biomes.CRIMSON_FOREST,
Biomes.WARPED_FOREST,
Biomes.BASALT_DELTAS
),
SurfaceRuleData.nether()
),
base.surfaceRule()
);
return new NoiseGeneratorSettings(
base.noiseSettings(),
base.defaultBlock(),
base.defaultFluid(),
base.noiseRouter(),
biomeMaterials,
base.spawnTarget(),
base.seaLevel(),
base.disableMobGeneration(),
base.isAquifersEnabled(),
base.oreVeinsEnabled(),
base.useLegacyRandomSource()
);
}
@@ -22,6 +22,7 @@ import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.Vec3;
import java.util.UUID;
@@ -347,9 +348,77 @@ public final class LinkingGameTests {
distribution + " Biome Distribution must use its Legacy scale"
);
}
assertSingleBiomeSurfaceMaterial(helper, Biomes.THE_END, Blocks.END_STONE);
assertSingleBiomeSurfaceMaterial(helper, Biomes.NETHER_WASTES, Blocks.NETHERRACK);
helper.succeed();
}
private static void assertSingleBiomeSurfaceMaterial(
GameTestHelper helper,
net.minecraft.resources.ResourceKey<net.minecraft.world.level.biome.Biome> biome,
net.minecraft.world.level.block.Block expectedBlock
) {
var biomeRegistry = helper.getLevel().registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BIOME);
var sortedBiomes = biomeRegistry.listElements()
.sorted(java.util.Comparator.comparing(holder -> holder.key().location().toString()))
.toList();
int targetIndex = -1;
for (int index = 0; index < sortedBiomes.size(); index++) {
if (sortedBiomes.get(index).is(biome)) {
targetIndex = index;
break;
}
}
helper.assertTrue(targetIndex >= 0, "The requested material-test biome must be registered");
long seed = 0L;
while (Math.floorMod(Long.hashCode(seed ^ 0x53494E474C454249L), sortedBiomes.size()) != targetIndex) {
seed++;
}
UUID id = UUID.randomUUID();
AgeDefinition definition = new AgeDefinition(
id,
"Material " + biome.location(),
seed,
AgeGenerationProfiles.STANDARD,
AgeDefinition.CURRENT_GENERATION_VERSION,
helper.getLevel().getGameTime(),
net.minecraft.resources.ResourceLocation.fromNamespaceAndPath(
Rivencraft.MOD_ID, "gametest/material_" + biome.location().getPath() + "_" + id
),
null,
new AgeTraits(
AgeTraits.BiomeDistribution.SINGLE,
AgeTraits.Lighting.NORMAL,
AgeTraits.Weather.NORMAL,
1.0D,
0.0F,
0.0F
)
);
var level = AgeDimensionService.ensureLoaded(helper.getLevel().getServer(), definition);
helper.assertTrue(level != null, biome.location() + " material test Age must load");
if (level == null) {
return;
}
helper.assertTrue(level.getChunkSource().getGenerator().getBiomeSource().possibleBiomes().stream().allMatch(holder -> holder.is(biome)),
"The material test Age must select " + biome.location());
// Sample away from the generated arrival platform around the Age spawn.
int sampleX = 64;
int sampleZ = 64;
level.getChunk(sampleX >> 4, sampleZ >> 4);
int surfaceY = level.getHeight(
net.minecraft.world.level.levelgen.Heightmap.Types.OCEAN_FLOOR_WG,
sampleX,
sampleZ
) - 1;
var surfaceState = level.getBlockState(new BlockPos(sampleX, surfaceY, sampleZ));
helper.assertTrue(surfaceState.is(expectedBlock),
biome.location() + " terrain must expose " + expectedBlock.getDescriptionId()
+ " at the surface, found " + surfaceState);
}
@GameTest(template = "empty")
public static void travelUsesLeafyDestinationWithoutFloor(GameTestHelper helper) {
helper.setBlock(ORIGIN.below(), Blocks.AIR);