[OUTDATED] Your very first plugin!

(Moderation Edit) ** PLEASE NOTE: **

This guide is no longer updated and therefore lacking new information plus may contain (now) false information. Please head over to the SpongeDocs to get the latest information including updates.

This is the home of a guide (and a list of guides) with usage examples broken down completely to help explain how to make parts of a Sponge plugin. This post will grow over time with more and more example cases, but for now we have a generic breakdown of the main class, the base of a Sponge plugin.

##Your Very First Plugin!

package example;

import java.io.File;
import java.util.logging.Logger;

import org.spongepowered.api.Game;
import org.spongepowered.api.event.Subscribe;
import org.spongepowered.api.event.state.InitializationEvent;
import org.spongepowered.api.event.state.PostInitializationEvent;
import org.spongepowered.api.event.state.PreInitializationEvent;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.service.config.DefaultConfig;

import com.google.inject.Inject;

@Plugin(id = "example", name = "Example", version = "v0.1")
public class Example {
    
    @Inject private Logger log;
    @Inject private Game game;
    @Inject @DefaultConfig(sharedRoot = false) private File defaultConfig;
    
    @Subscribe
    public void preinit(PreInitializationEvent event) {
        
    }
    
    @Subscribe
    public void init(InitializationEvent event) {
        
    }
    
    @Subscribe
    public void postinit(PostInitializationEvent event) {
        
    }
}

Right above me is a rather large block of source code that belongs to a basic main class of a Sponge plugin. The main class is where everything is registered and directed to do whatever the plugin needs done. This is where all plugin development starts off. Let’s break all of this code down, shall we?

###The @Plugin annotation
@Plugin(id = "example", name = "Example", version = "v0.1")

The @Plugin annotation is what helps Sponge recognize the class as the main class of a plugin. It also tells it its surface information; the id, name and version of the plugin.

The ID is the internal identifier of your plugin. This is what developers read and use to differentiate your plugin from others. It follows basic variable naming rules in Java, meaning that it is usually camel cased, starting with a lowercase letter.

The Name is the human-friendly, player-readable name of the identifier of the plugin. If you were a player in the days of Bukkit, this would be the name you would see in the list of plugins when you typed in /plugins, or its alias /pl as a command. Basically, its what everyone sees as the name, what server owners and maybe players recognize as your plugin.

The Version is the marking of how far your plugin’s gone into development. This should be a self-explanatory value. It is basically a number marking where your plugin’s at in its history.

###The @Injected variables

    @Inject private Logger log;
    @Inject private Game game;
    @Inject @DefaultConfig(sharedRoot = false) private File defaultConfig;

The three variables tagged with @Inject at the top of the class body are the most commonly used parts of a Sponge plugin. The @Inject annotation lets Sponge know to replace that variable with the instance of the given type, for example the line @Inject private Game game tells Sponge to inject the Game object into the variable, since the variable is of the type Game. Full documentation on injections can be found on the wiki of Google’s Guice library.

The Logger is what you use to output things to the console. You can use this to help you debug your plugin out of all its kinks and errors, or you can use it to pass messages about your plugin to the server owner who looks at the console or its logs (messages about how your plugin’s doing, not for something like what a command would do like sending messages between people!).

The Game object is what lets you access pretty much everything Sponge has to offer to you. It is what you use to get the services handling certain parts of the server, the server itself holding the World and every Player on it, offline or offline, and etc.

The File object represents an injection of the default configuration file given to your plugin. You’ll notice there’s an extra annotation there called @DefaultConfig. This signals Sponge as to what kind of configuration directory your plugin needs. For now, all you need to know is that in this example, it is set to false, meaning that the configuration file would end up in a folder dedicated to the plugin’s files.

###The @Subscribe methods

    @Subscribe
    public void preinit(PreInitializationEvent event) {
        
    }
    
    @Subscribe
    public void init(InitializationEvent event) {
        
    }
    
    @Subscribe
    public void postinit(PostInitializationEvent event) {
        
    }

These three methods are all event handlers for specific events. The @Subscribe annotation is what tells Sponge that these are event handlers, and to call them whenever the event of the type in the parameter (the thingy in parentheses) is fired. In this example, the event handlers listen to state events, events reporting the current stage of loading the server is at.

The PreInitializationEvent is fired when the server requests all plugins perform their loading of any configurations they need to load. It is also when the server injects the instances of File and Logger, which we have tagged to be injected. Logger being one of those injections, you can start throwing logging messages to the console from here on out.

The InitializationEvent is fired when the server requests all plugins to completely prepare to be functional. This means that any command registrations and event handler registrations would go here. Things like telling the server about your new /call command or telling the server to send a Hello! message to a player when they log in.

The PostInitializationEvent is fired when the server notes that all plugins should be ready to be interfaced with by any outer plugins. This means that if your plugin lets itself be accessed by other plugins to provide common functions, it should be ready by the time the server reaches this stage of loading. Performing all actions needed to meet this condition should be done within the InitializationEvent.

###Afterword
This is the basic main class file of a plugin, generally what every Sponge plugin ever has to start with. With this full breakdown of the main class (and an in-depth look at everything else), you’ll be ready to make your own plugins in no time!

##Upcoming – Other Breakdowns and Resources

##UPDATE: This will instead become a PR to the official Sponge documentation.

18 Likes

You should include a link to the docs.

was gonna be part of that other breakdowns and resources section

1 Like

Who flagged this? It looks alright.

5 Likes

Same with @WetSponge, I have no clue why this was flagged. It doesn’t appear to be breaking any rules at all so I guess people are just abusing the flag function for some reason… :confused:

2 Likes

I think its flagged because some people don’t want tuto’s on the forums. We have to [docs][1] for that ;).
@Xemiru maybe send a PR to the docs ;).

(note: I haven’t flagged)
[1]: https://docs.spongepowered.org/en/plugin/index.html

flagged for deletion. fixes @gratimax.
pretend i haven’t posted it here; i’ll be finding some way to integrate this kind of stuffs into the docs instead

2 Likes

It was very nicely laid out, and everything seemed to be described in detail. Much better than the current Sponge Docs.

Sadly the docs are outdated on a few topics. :frowning:

@Xemiru
I’d love to See this on the docs :slight_smile:

I think the way i’ll do this is by spawning a new PR rewriting documentation for plugin development. As the docs stand, it aims more for explaining the way Sponge works and not so much how to use it, and when it does it explains in a rather less user-friendly way. I’ll probably reorganize the current explanations into a different section and rewrite new pages more aimed at explaining common cases like this one.

I’m writing this on a stupid Windows Surface tablet. Excuse me if there’re any errors but I’m too annoyed at this thing to fix them.

1 Like

There is nothing wrong about tutorials on the forums, and there is nothing bad about duplicate information.

@Owexz @FerusGrim please unflag this.

4 Likes

I definitely don’t have a problem with this topic, however the flag came from @Xemiru himself. If he wants us to do anything about this topic, he’d need to be the one to ask.

yeah, i flagged it to be deleted yesterday since i wanted to move it before it got really noticed; but now that its more out in the open i can’t really do much except edit it and restore it to view with the footnote that’s there
and i did say that i was the one who flagged it, though admittedly vaguely

I want to send a message to a player, but “import org.spongepowered.api.text.message.Messages” isn’t working. It seems, that this isn’t implemented yet? Please help. I use Eclipse (gradle).

Please open a new topic for this, as this is a tutorial thread :slight_smile:

ok^^ I thought this is only a small mistake i made during setting up my workspace.

1 Like

@ibot3 org.spongepowered.api.text.message.Messages was replaced by:

org.spongepowered.api.text.Texts

1 Like