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, GroundCoverLayer
s replace stone at the surface with dirt, grass, sand, etc …
3: Global GenerationPopulator
s generate small structures.
4: For each biome, local GenerationPopulator
s generate small structures.
5: Global Populator
s generate bigger structures.
6: For each biome, local Populator
s generate bigger structures.
To fix your problem, you have to create a WorldGeneratorModifier
and to modify the GroundCoverLayer
s 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.
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 )