For a long time now, I’ve always found it a little bit weird that in Minecraft, only the person who gets the last swipe on the ender dragon actually earns the advancement “Free the End”.

So, after a suggestion from a friend, I decided to code a little plugin that would grant the advancement to every player who was involved with the fight.

Coding the Plugin

Before starting, you’ll have to install a fantastic IntelliJ plugin called Minecraft Development, which will set up our project architecture very easily for us.

With the plugin installed, I fired up IntelliJ and created a new project. Then I selected “minecraft”, then “spigot plugin”, so the plugin would work on my spigot server.

Setup image

After that, you’ll need to enter a GroupId and ArtifactId.

Firstly, your GroupId should be your domain name backwards. So, if you have an actual domain name, you can enter it like com.yourdomainname (if it ends with .com). However, if you don’t have a domain name, you can always use your github pages subdomain. For example, my GroupId was io.github.olinjohnson.

Then, your ArtifactId should be whatever the name of your plugin is going to be.

After that, you’ll have the option to enter some additional (but not required) information, then you can click Next again, name you project, and click Create.

Finally, IntelliJ will open a window for you to begin developing your plugin.

In the project’s file architecture, there is a directory called src. Inside src -> main -> java there will be a java package with the title yourGroupId.yourArtifactId. Inside this package is where the core class for the project is. If we open up the java class, we can see a couple important methods.

package io.github.olinjohnson.fenderender;

import org.bukkit.plugin.java.JavaPlugin;

public final class FenderEnder extends JavaPlugin {

    @Override
    public void onEnable(){
    }

    @Override
    public void onDisable()
    }
}

The onEnable() method is called when the plugin is loaded, and onDisable is called when the plugin is terminated.

For now, we’re going to leave these two methods alone and create a new class inside the package called EnderDragonController.

My original thought process for creating this plugin was that the plugin should start by containing an event listener for whenever any entity dies. Then, it should check if the recently deceased entity is the ender dragon. If so, then it should award the “Free the End” advancement to any player in the end dimension.

So, lets begin by creating the event listener. We’ll want our class EnderDragonController to implement the Bukkit Listener class.

package io.github.olinjohnson.fenderender;

import org.bukkit.Bukkit;
import org.bukkit.event.Listener;

public class EnderDragonController implements Listener {

}

Then, we’ll create a method to listen for an entity death events.

package io.github.olinjohnson.fenderender;

import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDeathEvent;

public class EnderDragonController implements Listener {

    @EventHandler
    public void onEnderDragonDeath(EntityDeathEvent event){

    }

}

However, right now, this method is called whenever any entity dies. We only want it to run when the ender dragon dies. So, we’ll add a check to see if it was the ender dragon that died.

package io.github.olinjohnson.fenderender;

import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EnderDragon;

public class EnderDragonController implements Listener {

    @EventHandler
    public void onEnderDragonDeath(EntityDeathEvent event){

        Entity entity = event.getEntity();
        if(entity instanceof EnderDragon){

        }

    }

}

In the code, we can use the instanceof keyword to compare the entity in question and check if it is the ender dragon. This checks to see if the entity is an instance of the EnderDragon class.

Now that we’ve detected the death of the ender dragon, we need to reward all players in the end dimension with the advancement. We’ll start by retrieving a list of all the online players with Bukkit.getOnlinePlayers(). This returns a Java collection, which we can iterate over in a for loop.

package io.github.olinjohnson.fenderender;

import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Player;

public class EnderDragonController implements Listener {

    @EventHandler
    public void onEnderDragonDeath(EntityDeathEvent event){

        Entity entity = event.getEntity();
        if(entity instanceof EnderDragon){

            for(Player p: Bukkit.getOnlinePlayers()){

            }

        }

    }

}

Then, we’ll add a check to see which players in the collection are in the end dimension.

package io.github.olinjohnson.fenderender;

import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EnderDragon;
import org.bukkit.World;

public class EnderDragonController implements Listener {

    @EventHandler
    public void onEnderDragonDeath(EntityDeathEvent event){

        Entity entity = event.getEntity();
        if(entity instanceof EnderDragon){

            for(Player p: Bukkit.getOnlinePlayers()){

                if(p.getWorld().getEnvironment() == World.Environment.THE_END){

                }

            }

        }

    }

}

Finally, now that we’ve compiled a collection of players who were in the end while the ender dragon was killed, we need to reward them all with the advancement “Free the End”.

We’ll start by storing a reference to the advancement name in an instance of Bukkit’s NamespacedKey class. Then, we’ll get a reference to the player’s progress towards the advancement.

// Reference to the advancement name
NamespacedKey key = NamespacedKey.minecraft("end/kill_dragon");
// Get the player's current progress
AdvancementProgress progress = p.getAdvancementProgress(Bukkit.getAdvancement(key));

Then, we’ll evaluate every remaining criteria that a player has to complete to fulfill this advancement. We’ll update any incomplete criteria to be complete.

// Reference to the advancement name
NamespacedKey key = NamespacedKey.minecraft("end/kill_dragon");
// Get the player's current progress
AdvancementProgress progress = p.getAdvancementProgress(Bukkit.getAdvancement(key));
// Iterate over remaining criteria
for(String stuff_left: progress.getRemainingCriteria()){
    // Grant progress towards the advancement
    progress.awardCriteria(left);
}

This will award a player with the advancement.

Finally, all your code in the EnderDragonController class should look similar to this:

package io.github.olinjohnson.fenderender;

import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Player;
import org.bukkit.World;
import org.bukkit.NamespacedKey;
import org.bukkit.advancement.AdvancementProgress;

public class EnderDragonController implements Listener {

    @EventHandler
    public void onEnderDragonDeath(EntityDeathEvent event){

        Entity entity = event.getEntity();
        if(entity instanceof EnderDragon){

            for(Player p: Bukkit.getOnlinePlayers()){

                if(p.getWorld().getEnvironment() == World.Environment.THE_END){

                    NamespacedKey key = NamespacedKey.minecraft("end/kill_dragon");
                    AdvancementProgress progress = p.getAdvancementProgress(Bukkit.getAdvancement(key));

                    for(String stuff_left: progress.getRemainingCriteria()){

                        progress.awardCriteria(stuff_left);

                    }

                }

            }

        }

    }

}

Alright! We’re almost done. Just one more small thing to do.

Navigate back to your core class, the one with the same name as the title of your project.

In the onEnable() method, we need to initialize our EnderDragonController class, so it knows to actually listen for events.

package io.github.olinjohnson.fenderender;

import org.bukkit.plugin.java.JavaPlugin;

public final class FenderEnder extends JavaPlugin {

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

    @Override
    public void onDisable() {}
}

Now we’re done!

You can package your plugin into a jar file by selecting Build -> Build Project, using CTRL + F9, or by running mvn package from the root level of your project.

This will create a jar file in your project’s target directory, which you can then import into your server’s plugins directory to see it in action!

The final code for this project can be viewed here on GitHub.