EggSplosions EggSplained!

Let's revisit the following line of code from part 3:

    getServer().getPluginManager().registerEvents(eggs, this); 

We could have written this code like this:

  /* Declare some references */
  Server theServer;
  PluginManager thePluginManager;

  /* Assign some values to those references */
  theServer = getServer();
  thePluginManager = theServer.getPluginManager();

 /* Now we've got the plugin manager, register the events */
 thePluginManager.registerEvents (eggs, this);
Starting from the bottom up. The last line called the method registerEvents which is a method of class PluginManager. This is known as an instance method, we need to have a reference to a PluginManager object in order to call that method. Our reference is called thePluginManager and we got its value by calling getPluginManager, which was an instance method of Server. Of course, we needed a reference to a server in order to do that, so we got that by calling getServer(). But where did that come from? The line

  theServer = getServer();

could have alternatively been written

  theServer = this.getServer();

So where did the reference "this" come from? "this" is a reference which is automatically available inside any instance method. Remember, all this code is happening inside onEnable, which is an instance method of PluginTutorial. PluginTutorial inherited getServer from JavaPlugin. The API for registerEvents shows that it take two parameters, the first one is a Listener, (eggs, which we discussed in part 3). The second parameter is a Plugin. So why is it acceptable to pass "this" in here? Well PlutinTutorial extends JavaPlugin, which in turn extends PluginBase which in turn implements Plugin. So "this" is an instance of a Plugin. We have told the plugin manager about our event listener, and we have also told the plugin manager which plugin (this) it belongs to.

If none of the above makes sense then you probably need to read some of the Oracle tutorial on classes and objects. There's a lot of reading there, and I wouldn't try and take it in all at once, just try and get the basics and go back to it later when you've had a bit of practice.

Now let's break down a similar but subtly different piece of code

 PluginTutorial.getInstance().getLogger().info ("Egg!");

This could be broken down into

 PluginTutorial myFunkyPluginTutorial;
 Logger theServersLogger;

 myFunkyPluginTutorial = PluginTutorial.getInstance();
 theServersLogger = myFunkyPluginTutorial.getLogger();
 theServersLogger.info ("Egg");

This is much the same as the previous example, except for the PluginTutorial.getInstance() call, which is a static method. Static methods aren't called on object references, but directly on the class names. What this method is doing for us is getting an instance of the plugin tutorial, so that we can then call its instance methods. So how does it do that? Back in PluginTutorial.java we have the following code

   private static PluginTutorial instance;

This declares some static data, a reference to an instance of PluginTutorial. Instance data is replicated for each instance of the class (ie for each object of that class) but static data applies the whole class. Now we know that CraftBukkit is only going to create one instance of our plugin, so it's rather convenient to store a static reference to that instance. So we make that assignment in the onEnable method like so:

   instance = this; 

Then we make instance public in a read-only fashion using the static method getInstance() which is fairly self explanatory. This way, any class in our plugin has easy access to PluginTutorial.getInstance(), and therefore access to all the instance methods.

By the way, it's a good idea not to have too much static data in a CraftBukkit plugin because it all has to be cleared down on shutdown. If you don't clear down static data on shutdown, the reload command will cause a memory leak. I've never seen a decent explanation of why this problem occurs but it is to do with the fact that all the class files in the plugins directories get reloaded. Personally, my plugins only ever have one static reference, and that's the one shown here. Then all we have to do is make sure this is in onDisable:

    instance = null;

Now what about this line:

   Location impactLocation = event.getEgg().getLocation(); 

I'm sure by now you can see how that could be broken down into multiple lines. But where did event come from? event is the name we gave the parameter in the method declaration:

    public void onPlayerThrowEgg (PlayerEggThrowEvent event)

We could have called it something else. If you click on the word event on that line of code and then right-click->Refactor->Rename you can then change the name of event to something else, say "occurrence" for example. Notice how both instances of the word "event" are updated by this action. Note that the name event is local to this method. It could be used in other methods without a clash, and the refactoring operation would not change those instances.

Finally, you might be wondering about the EggSplosions object we created in onEnable, and about whether we should have deleted it in onDisable. In Java, this is all handled automatically by a process known as garbage collection. When an object is no longer referenced anywhere in the system, it is automatically removed. In this case, that will happen because the reload command will unregister all the event listeners from the plugin manager. Once the plugin manager has stopped referring to our EggSplosions object, there will be no more references to it and so it will be garbage collected. Garbage collection is discussed in some detail all over the internet, and I don't intend to dwell too much on it here.

Move to
Top