Notice: This tutorial is under revision, and subject to change at any time.
First, you'll need to include MGLib on your classpath so you can use its methods. This is done in the same way that one might include a library such as bukkit.jar. Alternatively, you can add it as a dependency in your pom.xml. Here's a page describing how to do so.
You'll also need to set a dependency or soft dependency in your plugin.yml. This is accomplished by adding the line
depend: [MGLib] or
softdepend: [MGLib] to your plugin.yml file. If you use a soft dependency, be sure to disable your plugin in your onEnable() if MGLib is not installed (
if (!Bukkit.getPluginManager().isPluginEnabled("MGLib"))). Once you have that done, you can start coding.
You'll need to get an instance of MGLib's API in order to use the library. To do this, first create a global
Minigame object in your main class, but don't assign it yet. This can be done with the code
public static Minigame mg;
Then, in your
onEnable(), create and assign a new
Minigame object with the code
mg = Minigame.registerPlugin(this);
name represents an instance of your main class. This will call an API method which will create a new API instance for your plugin (your plugin being defined by the keyword
All classes necessary to create a minigame plugin are contained by the package
net.amigocraft.mglib.api. Below is a description of each class and its function:
This class contains most of MGLib's core methods. All methods other than ones which return instances of the class are non-static; i.e. they must be called from an instance of the class linked to your plugin (the global object you created at the beginning).
All methods pertaining to a specific round in a minigame are contained by this class. Because all methods apply to a single round, they are all non-static.
This class contains methods pertaining to a specific player in a minigame round. Again, all of its methods are non-static. Many of its methods may also be found in the
Round classes, though typically with different parameters.
This is a class I'm rather proud of. Each instance is linked to a specific arena, and it is used to configure it. The nice thing about this class is that most methods return the instance of the class they're called from, meaning you can call them in one long string (e.g.
factory.addSpawn().setMinBound().setMaxBound() is completely valid). Additionally, it will only save the new configuration to disk once per tick, and will wait until you're finished using it to do so.
This class contains methods pertaining to a specific lobby sign in the world. You probably won't need to use it much, since the lobby system is fully automated, but it's there if you need it. Like the other classes, most of its methods are non-static.
This class contains methods necessary to configure your plugin. Most configuration options are managed on a per-round basis, and in those cases, the values in this class serve as defaults. However, some options are global, and in that case, this class is the only way to set them.
This is a relatively new class, and is only present in MGLib v0.3.0 or higher. It's a straightforward localization implementation, which allows you to register your plugin with it and then retrieve messages based on locale files in your plugin's JAR or data folder. I'll add a section about it once 0.3.0 is available on DBO.
Creating arenas in MGLib is extremely easy, and can be done with a single API call.This is done with the code
mg.createArena(name, spawn, corner1, corner2);
It should be noted that
corner2 are optional, and may be omitted.
name represents the name of the arena (which can be pretty much whatever you want). It is used as an identifier when joining or managing the arena.
spawn represents the initial spawn of the arena. More may be added is desired via the
corner2 represent the borders of the arena. (Note to self: make sure spawns are within the borders. I don't feel like opening up Eclipse right now and I know I'll forget it later.) Players will be confined to this area if these parameters are included or set via the
ArenaFactory class. They will be teleported back if they cross it.
Now we move onto arena deletion. Deleting an arena is even easier than creating one. Simply call
name is the name of the arena, of course.
Configuration of an arena after creation is done exclusively through the
ArenaFactory class. Because its methods are non-static, you will need to obtain an instance of it. This may be done with the code
ArenaFactory.createArenaFactory(plugin, name, world);
plugin is the name of the calling plugin (your minigame plugin),
arena is the name of the arena to be configured, and
world is the name of the world containing the arena. Once an instance is prepared, you may call any number of its methods in one line of code as mentioned before, because they all return the object they were called from. So, for example, one could use the following:
Of course, the objects referenced would need to be created beforehand, but you get the point. I highly suggest you read the Javadoc for the class if you want a complete list of its methods. I've written documentation detailing what each one does, so you should be able to run with that.
Round creation is quite simple. All you need to do is use this code:
arenaName represents the name of the arena you want to start a round in. This method will return a
Round object, which can then be used to manage the round. Most of the methods are just getters and setters, so I won't bother going over those. Since they're fully doocumented, I won't waste time explaining them here. If you'd like to read more about them, have a look at the class's Javadoc. What I will go over is starting and stopping rounds. To start a round, simply call
round is an instance of the
Round class. This will automatically start the round's timer and change its stage to
Stage.PREPARING, unless the preparation time is less than or equal to 0, in which case it will immediately change to
Stage.PLAYING. Once the timer reaches its limit (which may be set to a value less than or equal to zero to remove the limit), the round will automatically be stopped, reset, and set to
MGLib's timer system is worth mentioning. Unlike the typical implementation, its timer ticks up instead of down. It starts at zero, and continues until the limit is reached or the round is ended by external means. This was implemented in this way in order to allow for timer-based actions by hooking plugins in rounds without a time limit, as well as to make it easier to do so in rounds with a limit.
If you wish, you may stop a round manually by calling
This will stop the round, reset its players and lobby signs, roll it back, and reset its stage.
MGLib includes a discrete class to represent a player in a minigame, called
MGPlayer. Most methods used to manage the player are contained by this. However, methods involving a round often have an implementation in the
Round class as well, so as to allow for flexibility. For example, to add a player to a round, one could call
mgPlayer is an instance of the
MGPlayer class and
round is an instance of the
Similarly, removal of a player from a round may also be done from either class, with
Most other methods in the class are fairly well-documented, so I won't go over them here. However, a method worth mentioning is
What this does is render the player invisible and cancel all PlayerInteractEvents by them, effectively putting them in a "ghost"-like state, so that they may spectate an active round without interacting with it. You may call this method as you see fit, and additionally, MGLib includes a configuration option which will automatically call it upon a player entering a round in progress.
As previously mentioned, MGLib includes a class called
ConfigManager designed specifically to make configuration as easy as possible. It's filled to the brim with getters and setters, and as such, somewhat thoroughly-documented. And so again, I must refer you to the class's Javadoc if you want to learn more about it.
MGLib contains a fully automated lobby system, with a few configurables as well. As of v0.1.0, you may customize the color of the sign's lines and keywords via the
ConfigManager class. You may also configure the word used to trigger the creation of a lobby sign. By default, it is set to your plugin's name in square brackets ([PluginName]). To create a lobby sign, set the first line of a sign to this string. Then, set the second line to the sign type. There are presently two types:
status signs will display the stage, player count, and remaining time of a round.
players signs will display a portion of the players in an arena.
Set the third line to the name of the arena which you want the sign to monitor, and finally, set the fourth line to the sign's index. This applies only to
players signs. Basically, if you set the index to 1, the first four players in a round will be displayed. If you set it to 2, the second group of four players will be displayed. And so on and so forth.
Once your sign is complete, MGLib will detect it and register a lobby sign at its location. This sign will persist through reloads, and will be removed only if it is shift+left-clicked by a player with permission to remove it. This leads me to the next topic:
MGLib presently uses two permission nodes per plugin. For the sake of simplicity, let's say your plugin is called "Spleef." The two permission nodes would be
spleef.lobby.destroy. The former allows anyone with the node to create lobby signs, and the latter to destroy them. Pretty simple stuff.
MGLib includes an event system designed to give you full control over rounds in your minigame. Events are fired for things such as a player joining/leaving a round, a round starting/stopping/resetting, and a round ticking (once per second). A full list of events may be found on the Javadocs, under the package
net.amigocraft.mglib.event. You may listen to these from your plugin and take appropriate action.
Additionally, there's no need to check that a particular event pertains to your plugin. Your plugin will only receive its own events, and its events will be sent to it only.
MGLib includes a few exceptions which are designed to pass any issues onto your plugin so that you may handle them as you wish. Exceptions are thrown for such things as a player being offline, not present in a particular round, or a location not being valid. A full list is available on the Javadocs under the package
net.amigocraft.mglib.exception. All custom exceptions extend the
Exception class, and so when a method throws them, it must be within a try-catch block. It is worth mentioning that some methods throw
IllegalArgumentExceptions, which are not checked and therefore not required to be caught. However, you should be aware when one may be thrown. All methods which throw one are labeled appropriately on the Javadocs.
I highly recommend referencing MGLib's JavaDocs while creating your plugin. It contains nearly complete documentation for the entire API.
Additionally, you may find it helpful to have a look at MGLib's source code. I've tried to comment it as I write it, so it may give you a deeper understanding of how the library works. Hey, by the way, if you find a bug or want a feature added, feel absolutely free to create a pull request for it. You'd make my job a lot easier.
Well, that hopefully concludes this tutorial. I'm almost positive I've forgotten something, but it's late, and I'll probably remember eventually. Thanks for using MGLib, and have fun!
On a side note: if you've built a plugin with the library, let me know and I'll link to it from the plugin's DBO page!