RyanHub – file viewer
filename: common/src/main/java/rearth/oritech/init/world/features/oil/OilSpringFeature.java
branch: 1.21
back to repo
package rearth.oritech.init.world.features.oil;

import com.mojang.serialization.Codec;
import net.minecraft.block.Blocks;
import net.minecraft.registry.Registries;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.noise.PerlinNoiseSampler;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.util.FeatureContext;
import rearth.oritech.Oritech;

public class OilSpringFeature extends Feature<OilSpringFeatureConfig> {
    public OilSpringFeature(Codec<OilSpringFeatureConfig> configCodec) {
        super(configCodec);
    }
    
    @Override
    public boolean generate(FeatureContext<OilSpringFeatureConfig> context) {
        
        var world = context.getWorld();
        var origin = context.getOrigin();
        
        if (world.isClient()) return false;
        
        
        var testPos = new BlockPos(origin);
        for (int y = 0; y < world.getHeight(); y++) {
            testPos = testPos.up();
            
            if (world.getBlockState(testPos).isIn(BlockTags.DIRT) || world.getBlockState(testPos).isIn(BlockTags.SAND)) {
                if (world.getBlockState(testPos.up()).isOf(Blocks.AIR)) {
                    placeStructure(testPos, context);
                    return true;
                }
            }
            
        }
        
        return false;
    }
    
    private void placeStructure(BlockPos surfacePos, FeatureContext<OilSpringFeatureConfig> context) {
        
        var random = context.getRandom();
        var config = context.getConfig();
        var state = Registries.BLOCK.get(config.blockId()).getDefaultState();
        var world = context.getWorld();
        
        var variation = random.nextBetween((int) (-config.number() * 0.5f), config.number());
        var height = Math.max(config.number() + variation, 13);
        var depth = height * 2;
        
        var bottomEnd = surfacePos.down(depth);
        var center = bottomEnd.add(random.nextBetween(-2, 2), random.nextBetween(-3, 3), random.nextBetween(0, height / 2));

        var perlinSampler = new PerlinNoiseSampler(random);
        
        // iterate through a cube, calculate distance from center to get a good circle
        for (int x = 0; x < depth + 2; x++) {
            for (int y = 0; y < depth + 2; y++) {
                for (int z = 0; z < depth + 2; z++) {
                    var point = new BlockPos(x - height, y - height, z - height).add(bottomEnd);
                    var distance = Math.sqrt(point.getSquaredDistance(center));
                    var noiseOffset = perlinSampler.sample(x, y, z);
                    if (distance <= height + noiseOffset - 2) {
                        world.setBlockState(point, state, 0x10);
                    } else if (distance <= height + noiseOffset) {
                        world.setBlockState(point, Blocks.STONE.getDefaultState(), 0x10);
                    }
                }
            }
        }
        
        // fountain up
        if (Oritech.CONFIG.easyFindFeatures()) {
            for (int i = 0; i < height; i++) {
                world.setBlockState(surfacePos.up(i), state, 0x10);
            }
        }
        
        // down
        for (int i = 1; i < depth + 5; i++) {
            world.setBlockState(surfacePos.down(i), state, 0x10);
        }
        
    }
}