rutgerkok / WorldGeneratorApi

Minecraft Spigot plugin that enables other plugins to customize world generation
MIT License
96 stars 9 forks source link

How can I keep the original generation, but use the API to just make some changes #31

Closed dadusakyt closed 3 years ago

dadusakyt commented 3 years ago

First of all I'd like to apologize for being a noob, so if you could explain everything step by step and in detail that would be highly appreciated!

So I've been experimenting with your API but I can't figure out how to use it to just make changes to the normal terrain generation, let me give you 2 examples:

1) I want to make a plugin that removes some Y levels and only keeps a few, like let's say every 10th Y level is kept, everything else is removed. I want the default generator to create the terrain and then remove the Y levels, how would you go about this?

2) Even more simple, how can I randomly change X% (let's say 50%) of all blocks to TNT (or any other block), keeping the default generator and just changing those random blocks?

Thanks for making this API and for replying to my beginner questions!

rutgerkok commented 3 years ago

I haven't tested it, but here's a quick example on how to remove all blocks at y = 9:

worldGenerator.getWorldDecorator().withCustomDecoration(DecorationType.TOP_LAYER_MODIFICATION, new Decoration() {
    public void decorate(DecorationArea area, Random random) {
        // This sets all blocks at y=9 to air
        int globalX = area.getCenterX();
        int globalZ = area.getCenterZ();
        for (int localX = 0; localX < 16; localX++) {
            for (int localZ = 0; localZ < 16; localZ++) {
                area.setBlock(globalX + localX, 9, globalZ + localZ, Material.AIR);
            }
        }
    }
}

For setting blocks at more y levels, use a loop over the y variable.

For setting TNT, you can use the same approach, but then something like this:

worldGenerator.getWorldDecorator().withCustomDecoration(DecorationType.TOP_LAYER_MODIFICATION, new Decoration() {
    public void decorate(DecorationArea area, Random random) {
        // This sets all blocks at y=9 to air
        int globalX = area.getCenterX();
        int globalZ = area.getCenterZ();
        for (int i = 0; i < 50; i++) {  // 50 spawn attempts
             int x = globalX + random.nextInt(16);
             int y = 5 + random.nextInt(50); // Random number from 5 to 5+50
             int z = globalZ + random.nextInt(16);
             area.setBlock(x, y, z, Material.TNT);
        }
    }
}

You might want to first check whether the block is stone before you please TNT, but that's up to you.

Hope that helps!

dadusakyt commented 3 years ago

First of all thanks for taking the time to respond, I can imagine how frustrating it can be replying to beginners like myself.

Personally I don't struggle with writing the algorithms which take care of what blocks to change / remove / ... Where I usually get stuck is the syntax. So for example I took your code and did the good old copy-paste and sure enough it gave me a syntax error, now I've looked through the Tutorials, even the one on Decorations but I'm still very much clueless on what to do now.

I've attached 2 images of the issue, but I would like to actually learn where to put what and why. Because currently I'm very confused and I'm sure it's most likely due to my lack of understanding.

git02 git01

Again, thanks for responding and working on this API.

rutgerkok commented 3 years ago

In Java, (although with some specific exceptions) all code statements needs to be in methods, and methods need to be in classes. In your screenshot, the code statements are placed directly in a class file, which won't work. You can do something like this, where you use the onEnable method to listen for events, which includes the WorldGeneratorInitEvent.

package me.dadusak.StripesWithAPI;

// Imports omitted, but your IDE should be able to fix those

public class Main extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public void onWorldGeneratorInit(WorldGeneratorInitEvent event) {
        WorldGenerator worldGenerator = event.getWorldGenerator();
        // Paste the code snippets here
    }

}

Hopefully that helps!

dadusakyt commented 3 years ago

It worked as intended.

Now I'm getting this error: image

Is this because I don't have the "public ChunkGenerator getDefaultWorldGenerator" method that you use in your Pancake tutorial? If so, how can I implement it with the default generator, because as I mentioned in the original post, I want to use the default generator, just change some things up.

Thanks for being so responsive, hopefully this project takes off!

rutgerkok commented 3 years ago

You don't need to change the generator of the world in bukkit.yml. That setting is only for when you do intend to overhaul the world generator. So just leave it blank, as if it were a vanilla world.

If you want to restrict your world generation changes to a specific world, check the world name in your onWorldGeneratorInit method. Normally, this method is called once for each world, so your changes take effect to all worlds on the server.

dadusakyt commented 3 years ago

Thanks for your help, everything seems to be working!