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

+5
View File
@@ -350,6 +350,11 @@ Large, and Huge reuse Tiny's seeded, softly bounded regions at nominal widths
of 32, 64, 128, and 256 blocks. Every size selects three deterministic biomes
and serializes the selection, Age seed, and scale with the runtime dimension.
Version 0.2.25.1 applies biome-specific material rules without replacing an
Age's selected terrain profile. End biome columns generate from End stone;
Nether biome columns use Minecraft's Nether surface rules for netherrack,
soul sand, basalt, and nylium instead of inheriting Overworld blocks.
Version 0.2.14.0 restores the legacy Linking and Descriptive Book artwork for
inventory items and gives each book its matching open-book texture when placed
on a Book Stand. Return Linking Books created inside another Age also retain and
+1 -1
View File
@@ -35,7 +35,7 @@ mod_name=Rivencraft
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=LGPL-3.0-or-later
# The mod version. Rivencraft uses the x.y.z.b policy documented in README.md.
mod_version=0.2.25.0
mod_version=0.2.25.1
immersive_portals_version=6.0.7
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
@@ -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);