Created
December 7, 2021 15:59
-
-
Save alcatrazEscapee/424167705fbab4113ddc931bd1935ba9 to your computer and use it in GitHub Desktop.
Custom Ore Veins in 1.18, using Vanilla noise-based ore vein systems. DON'T DO THIS, JUST MAKE A FEATURE!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.minecraft.core.Registry; | |
import net.minecraft.resources.ResourceLocation; | |
import net.minecraft.util.Mth; | |
import net.minecraft.world.level.block.Blocks; | |
import net.minecraft.world.level.block.state.BlockState; | |
import net.minecraft.world.level.levelgen.*; | |
import net.minecraft.world.level.levelgen.synth.NormalNoise; | |
import org.jetbrains.annotations.Nullable; | |
/** | |
* This is an identical copy of the relevant parts of {@link NoiseSampler} and {@link NoiseChunk} | |
* In practice, this can be whatever you want. | |
*/ | |
public class CustomOreVeinNoiseSampler | |
{ | |
private final PositionalRandomFactory oreVeinsPositionalRandomFactory; | |
private final NoiseChunk.InterpolatableNoise veininess; | |
private final NoiseChunk.InterpolatableNoise veinA; | |
private final NoiseChunk.InterpolatableNoise veinB; | |
private final NormalNoise gapNoise; | |
private final BlockState ore; | |
private final BlockState rawOreBlock; | |
private final BlockState filler; | |
private final int minY; | |
private final int maxY; | |
private static NoiseChunk.InterpolatableNoise yLimitedInterpolatableNoise(NormalNoise noise, int minY, int maxY, double scale) | |
{ | |
// The createNoiseInterpolator here is needed because of how it interacts with the noise chunk | |
// The interpolator is stored on the noise chunk (this returns a factory), and then sampled efficiently later | |
return chunk -> ((NoiseChunkAccessor) chunk).call$createNoiseInterpolator((x, y, z) -> y <= maxY && y >= minY ? noise.getValue(x * scale, y * scale, z * scale) : 0); | |
} | |
public CustomOreVeinNoiseSampler(long seed, Registry<NormalNoise.NoiseParameters> parameters) | |
{ | |
// Initialize the sampler on a per-chunk-generator basis | |
// sets up any noise or other random parameters | |
this.ore = Blocks.DIAMOND_ORE.defaultBlockState(); | |
this.rawOreBlock = Blocks.COAL_ORE.defaultBlockState(); | |
this.filler = Blocks.BASALT.defaultBlockState(); | |
this.minY = -64; | |
this.maxY = 64; | |
final PositionalRandomFactory fork = new XoroshiroRandomSource(seed).forkPositional(); | |
this.oreVeinsPositionalRandomFactory = fork.fromHashOf(new ResourceLocation("ore")).forkPositional(); | |
this.veininess = yLimitedInterpolatableNoise(Noises.instantiate(parameters, fork, Noises.ORE_VEININESS), minY, maxY, 1.5D); | |
this.veinA = yLimitedInterpolatableNoise(Noises.instantiate(parameters, fork, Noises.ORE_VEIN_A), minY, maxY, 4.0D); | |
this.veinB = yLimitedInterpolatableNoise(Noises.instantiate(parameters, fork, Noises.ORE_VEIN_B), minY, maxY, 4.0D); | |
this.gapNoise = Noises.instantiate(parameters, fork, Noises.ORE_GAP); | |
} | |
public class CustomOreVeinNoiseChunk | |
{ | |
private final NoiseChunk.Sampler veininessSampler; | |
private final NoiseChunk.Sampler veinASampler; | |
private final NoiseChunk.Sampler veinBSampler; | |
public CustomOreVeinNoiseChunk(NoiseChunk chunk) | |
{ | |
// Initialize the vein on a per-chunk basis | |
// Calling into NoiseChunk.instantiate means we get these automatically trilinearly interpolated for us | |
this.veininessSampler = veininess.instantiate(chunk); | |
this.veinASampler = veinA.instantiate(chunk); | |
this.veinBSampler = veinB.instantiate(chunk); | |
} | |
@Nullable | |
public BlockState sample(int x, int y, int z) | |
{ | |
final RandomSource random = oreVeinsPositionalRandomFactory.at(x, y, z); | |
final double veininess = veininessSampler.sample(); | |
if (isVeinType(veininess, y) && random.nextFloat() < 0.7 && isVein(veinASampler.sample(), veinBSampler.sample())) | |
{ | |
double chance = Mth.clampedMap(Math.abs(veininess), 0.4, 0.6, 0.1, 0.3); | |
if (random.nextFloat() < chance && gapNoise.getValue(x, y, z) > -0.3) | |
{ | |
return random.nextFloat() < 0.02F ? rawOreBlock : ore; | |
} | |
else | |
{ | |
return filler; | |
} | |
} | |
return null; | |
} | |
private boolean isVeinType(double veininess, int y) | |
{ | |
final int belowTop = maxY - y; | |
final int aboveBottom = y - minY; | |
if (aboveBottom >= 0 && belowTop >= 0) | |
{ | |
final int delta = Math.min(belowTop, aboveBottom); | |
double clampedDelta = Mth.clampedMap(delta, 0, 20, -0.2, 0); | |
return Math.abs(veininess) + clampedDelta >= 0.4; | |
} | |
return false; | |
} | |
private boolean isVein(double veinA, double veinB) | |
{ | |
return Math.max(Math.abs(veinA) - 0.08, Math.abs(veinB) - 0.08) < 0; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.List; | |
import net.minecraft.world.level.levelgen.material.MaterialRuleList; | |
import net.minecraft.world.level.levelgen.material.WorldGenMaterialRule; | |
import org.spongepowered.asm.mixin.Mixin; | |
import org.spongepowered.asm.mixin.Mutable; | |
import org.spongepowered.asm.mixin.gen.Accessor; | |
// Both an accessor a mutator are needed because the field itself is an immutable list. | |
// This could be an AT entry instead though. | |
@Mixin(MaterialRuleList.class) | |
public interface MaterialRuleListAccessor | |
{ | |
@Mutable | |
@Accessor("materialRuleList") | |
void setMaterialRuleList(List<WorldGenMaterialRule> materialRuleList); | |
@Accessor("materialRuleList") | |
List<WorldGenMaterialRule> getMaterialRuleList(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.function.Supplier; | |
import net.minecraft.core.Registry; | |
import net.minecraft.world.level.biome.BiomeSource; | |
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; | |
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; | |
import net.minecraft.world.level.levelgen.material.WorldGenMaterialRule; | |
import net.minecraft.world.level.levelgen.synth.NormalNoise; | |
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; | |
// This hooks the creation of noise based chunk generators (all of which have the default ore veins) | |
// This modifies the rule list, and adds our effective noise sampler / noise chunk combo. | |
@Mixin(NoiseBasedChunkGenerator.class) | |
public abstract class NoiseBasedChunkGeneratorMixin | |
{ | |
@Shadow @Final private WorldGenMaterialRule materialRule; | |
@Inject(method = "<init>(Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/biome/BiomeSource;Lnet/minecraft/world/level/biome/BiomeSource;JLjava/util/function/Supplier;)V", at = @At("TAIL")) | |
private void addToMaterialRuleList(Registry<NormalNoise.NoiseParameters> noiseParameters, BiomeSource biomeSource | |
, BiomeSource runtimeBiomeSource, long seed, Supplier<NoiseGeneratorSettings> settings, CallbackInfo ci) | |
{ | |
List<WorldGenMaterialRule> list = ((MaterialRuleListAccessor) materialRule).getMaterialRuleList(); | |
list = new ArrayList<>(list); | |
// This is the money line, and it shows how we use the noise chunk to actually do the sampling. | |
list.add((chunk, x, y, z) -> ((NoiseChunkBridge) chunk).getCustomOreVeinNoiseChunk().sample(x, y, z)); | |
((MaterialRuleListAccessor) materialRule).setMaterialRuleList(list); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.minecraft.world.level.levelgen.NoiseChunk; | |
import org.spongepowered.asm.mixin.Mixin; | |
import org.spongepowered.asm.mixin.gen.Invoker; | |
// This is needed to use NoiseChunk.NoiseInterpolator. | |
// If you don't need to use vanilla perlerp then what are you doing trying to make noise additions | |
// Seriously just make a feature | |
@Mixin(NoiseChunk.class) | |
public interface NoiseChunkAccessor | |
{ | |
@Invoker("createNoiseInterpolator") | |
NoiseChunk.NoiseInterpolator call$createNoiseInterpolator(NoiseChunk.NoiseFiller filler); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Access our custom noise chunk from the vanilla noise chunk | |
public interface NoiseChunkBridge | |
{ | |
CustomOreVeinNoiseSampler.CustomOreVeinNoiseChunk getCustomOreVeinNoiseChunk(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.minecraft.world.level.levelgen.Aquifer; | |
import net.minecraft.world.level.levelgen.NoiseChunk; | |
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; | |
import net.minecraft.world.level.levelgen.NoiseSampler; | |
import net.minecraft.world.level.levelgen.blending.Blender; | |
import org.spongepowered.asm.mixin.Mixin; | |
import org.spongepowered.asm.mixin.injection.At; | |
import org.spongepowered.asm.mixin.injection.Inject; | |
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | |
// Initializes the custom ore veins noise chunk, and exposes it through NoiseChunkBridge | |
@Mixin(NoiseChunk.class) | |
public abstract class NoiseChunkMixin implements NoiseChunkBridge | |
{ | |
private CustomOreVeinNoiseSampler.CustomOreVeinNoiseChunk customOreVeinNoiseChunk; | |
@Inject(method = "<init>", at = @At("TAIL")) | |
private void initializeCustomOreVeinSamplers(int cellCountXZ, int cellCountY, int cellNoiseMinY, NoiseSampler sampler, int blockX, int blockZ, NoiseChunk.NoiseFiller beardifier, NoiseGeneratorSettings settings, Aquifer.FluidPicker globalFluidPicker, Blender oldTerrainBlender, CallbackInfo ci) | |
{ | |
customOreVeinNoiseChunk = ((NoiseSamplerBridge) sampler).getCustomOreVeinNoiseSampler().new CustomOreVeinNoiseChunk((NoiseChunk) (Object) this); | |
} | |
@Override | |
public CustomOreVeinNoiseSampler.CustomOreVeinNoiseChunk getCustomOreVeinNoiseChunk() | |
{ | |
return customOreVeinNoiseChunk; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Access our custom noise sampler from the vanilla noise sampler | |
public interface NoiseSamplerBridge | |
{ | |
CustomOreVeinNoiseSampler getCustomOreVeinNoiseSampler(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.minecraft.core.Registry; | |
import net.minecraft.world.level.levelgen.NoiseSampler; | |
import net.minecraft.world.level.levelgen.NoiseSettings; | |
import net.minecraft.world.level.levelgen.WorldgenRandom; | |
import net.minecraft.world.level.levelgen.synth.NormalNoise; | |
import org.spongepowered.asm.mixin.Mixin; | |
import org.spongepowered.asm.mixin.injection.At; | |
import org.spongepowered.asm.mixin.injection.Inject; | |
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | |
// Initialize the custom ore veins noise sampler, and exposes it through NoiseSamplerBridge | |
@Mixin(NoiseSampler.class) | |
public abstract class NoiseSamplerMixin implements NoiseSamplerBridge | |
{ | |
private CustomOreVeinNoiseSampler customOreVeinNoiseSampler; | |
@Inject(method = "<init>", at = @At("TAIL")) | |
private void setupCustomOreVeinNoiseSamplers(NoiseSettings settings, boolean noiseCavesEnabled, long seed, Registry<NormalNoise.NoiseParameters> parameters, WorldgenRandom.Algorithm algorithm, CallbackInfo ci) | |
{ | |
customOreVeinNoiseSampler = new CustomOreVeinNoiseSampler(seed, parameters); | |
} | |
@Override | |
public CustomOreVeinNoiseSampler getCustomOreVeinNoiseSampler() | |
{ | |
return customOreVeinNoiseSampler; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment