Stone on World Generation

Hello,

I’m currently triyng to create my own world generator ; which I’v successfully done.
I’ve got only one problem : if I set buffer.setBlockType(x, y, z, BlockTypes.STONE);, I see grass where it should be the stone. But if I set BlockTypes.PLANKS instead of stone, the PLANKS will appears correctly.

Why ??

Thanks for your help.

In Minecraft, world generation is organized in several stages, here is a simplified list:
1: The BaseGenerationPopulator generates a very simple world only made of stone.
2: For each biome, GroundCoverLayers replace stone at the surface with dirt, grass, sand, etc …
3: Global GenerationPopulators generate small structures.
4: For each biome, local GenerationPopulators generate small structures.
5: Global Populators generate bigger structures.
6: For each biome, local Populators generate bigger structures.

To fix your problem, you have to create a WorldGeneratorModifier and to modify the GroundCoverLayers or to use a GenerationPopulator or a Populator.

I’m using a GenerationPopulator, giving something this kind :

public class MyGenerationPopulator implements GenerationPopulator {
    @Override
    public void populate(World world, MutableBlockVolume buffer, ImmutableBiomeVolume biomes) {
        for (int x = buffer.getBlockMin().getX(); x <= buffer.getBlockMax().getX(); x++) {
            for (int z = buffer.getBlockMin().getZ(); z <= buffer.getBlockMax().getZ(); z++) {
                buffer.setBlockType(x, y, z, BlockTypes.STONE);
            }
        }
    }
}

What I am doing wrong ?

We need the complete code to help you. Your “y” variable is undefined.

The complete code :

public class FreeBuildGenerationPopulator implements GenerationPopulator {
    @Override
    public void populate(World world, MutableBlockVolume buffer, ImmutableBiomeVolume biomes) {
        for (int x = buffer.getBlockMin().getX(); x <= buffer.getBlockMax().getX(); x++) {
            for (int z = buffer.getBlockMin().getZ(); z <= buffer.getBlockMax().getZ(); z++) {
                int y = -1;
                for (Layers layer : Layers.values()) {
                    for (int i = 0; i < layer.getAmount(); i++) {
                        buffer.setBlockType(x, ++y, z, layer.getBlockType());
                    }
                }
                if (Utils.isRoad(new Location<World>(world, x, 0, z)))
                    buffer.setBlockType(x, y, z, BlockTypes.STONE);
            }
        }
    }
}

Are you using a WorldGeneratorModifier to register your populator ? If so can you show it ?

Of course :

public class FreeBuildWorldGeneratorModifier implements WorldGeneratorModifier {
    @Override
    public void modifyWorldGenerator(WorldProperties world, DataContainer settings, WorldGenerator worldGenerator) {
        for (BiomeType biomeType : Sponge.getRegistry().getAllOf(BiomeType.class)) {
            worldGenerator.getBiomeSettings(biomeType).getPopulators().clear();
        }
        worldGenerator.getGenerationPopulators().clear();
        worldGenerator.setBaseGenerationPopulator(new FreeBuildGenerationPopulator());
        worldGenerator.setBiomeGenerator(new FreeBuildBiomeGenerator());
    }
    
    @Override
    public String getId() {
        return "myplugin:mymodifier";
    }
    
    @Override
    public String getName() {
        return "MyPlugin Modifier";
    }
}

And the BiomeGenerator :

public class FreeBuildBiomeGenerator implements BiomeGenerator {
    @Override
    public void generateBiomes(MutableBiomeVolume buffer) {
        Vector3i min = buffer.getBiomeMin();
        Vector3i max = buffer.getBiomeMax();

        for (int x = min.getX(); x <= max.getX(); x++) {
            for (int z = min.getZ(); z <= max.getZ(); z++) {
                buffer.setBiome(x, 0, z, BiomeTypes.VOID);
            }
        }
    }
}

Add this line in your biome loop:
worldGenerator.getBiomeSettings(biomeType).getGroundCoverLayers().clear();
This will remove all ground cover layers such as dirt, grass, sand, etc …

Thanks, it works.
Another question: do you know how to set a block variant, as andesite ?
I tried buffer.setBlock(x, y, z, BlockTypes.STONE.getDefaultState().with(Keys.STONE_TYPE, StoneTypes.ANDESITE).get()); but it doesn’t work.

Nobody knows ? :frowning:

I’m not sure but maybe it’s because you’re doing it in the Base GenerationPopulator. The Base GenerationPopulator is supposed to create the skeleton of the world, not the details. To add details such as block variants try using a “simple” GenerationPopulator.

I mean, in theory you should have at least two classes implementing GenerationPopulator. For example in the modifier you should have something like this:

worldGenerator.setBaseGenerationPopulator(new FreeBuildGenerationPopulatorSkeleton());
worldGenerator.getGenerationPopulators().clear();
worldGenerator.getGenerationPopulators().add(new FreeBuildGenerationPopulatorDetails());

I’m not 100% sure of what I’m saying but you should try and see if it works or not.

I’ve dabbled in BiomeGenerators before when creating a plugin to create Void Worlds when Skyfactory was released…

Im surprised you are able to do buffer.setBlock() honestly… the only options my plugin shows available to me using a MutableBiomeVolume (With API 5 or API7) is buffer.setBiome…

I’ll take a look at my plugin and see if I can create a solution for your problem using a variation of my OceanWorld populator.

That’s because he is using a GenerationPopulator not only a BiomeGenerator and thus he can access a MutableBlockVolume.

Well… getting what you want is certainly possible…

I will include my code.

This is from a GenerationPopulator I made based on your code, removing things like Layer, as I have a good idea what it does, but was not provided with the code.

public class genPopStoneWorld implements GenerationPopulator {
    @Override
    public void populate(World world, MutableBlockVolume buffer, ImmutableBiomeVolume biomes) {


        for (int x = buffer.getBlockMin().getX(); x <= buffer.getBlockMax().getX(); x++) {
            for (int z = buffer.getBlockMin().getZ(); z <= buffer.getBlockMax().getZ(); z++) {
                for (int y = buffer.getBlockMin().getY(); y <= buffer.getBlockMax().getY(); y++) {
                        buffer.setBlock(x, y, z, BlockTypes.STONE.getDefaultState().with(Keys.STONE_TYPE, StoneTypes.ANDESITE).get());
                    }
                }
            }
        }
    }

After this, I created a WorldGenerationModifer:

   public class StoneWorld implements WorldGeneratorModifier {
    @Override
    public void modifyWorldGenerator(WorldProperties world, DataContainer settings, 
 WorldGenerator worldGenerator) {
    world.setGeneratorType(GeneratorTypes.OVERWORLD);
	for (BiomeType biome : Sponge.getRegistry().getAllOf(BiomeType.class)) {
		BiomeGenerationSettings biomeSettings = 
            worldGenerator.getBiomeSettings(biome);
		biomeSettings.getGenerationPopulators().clear();
		biomeSettings.getGenerationPopulators().add(new genPopStoneWorld());
	    }

	worldGenerator.setBaseGenerationPopulator((world1, buffer, biomes) -> {
	});
}


@Override
public String getId() {
    // TODO Auto-generated method stub
    return "expanse:stoneworld";
}

@Override
public String getName() {

    return "Expanse Stone OverWorld";
    }
}

Then it needs to be registered on load… The issue with the code in its current state comes from when I cleared all the populators, so you would need to go through and find the exact one you need (I can’t do all the work for you :stuck_out_tongue:)

02