-
Notifications
You must be signed in to change notification settings - Fork 0
GUI For Developers
This section is dedicated to developers. If you are looking for the admins' page, click here
Many of the fields referenced on this page might be or require platform-specific values. Check the glossary
GUIs are the main focus and the reason why this library has been created. They offer an easy to use, fast and reliable system to create and manage user menus. There are many types of GUIs available, which will be later introduced.
If you want to store or load data on files, you will need to import the serializer module
and use GUIYAGLParser#addAllParsers()
JUST ONCE before starting any IO operation
(it also includes calls to WrappersYAGLParser#addAllParsers()
and ItemYAGLParser#addAllParsers()
so you are not required to specify that).
To actually open the GUI in Minecraft Bukkit, the bukkit module will need to be imported. The most important class introduced by this submodule is GUIAdapter, which provides various conversion methods from YAGL to Bukkit.
It is important to note that the target of methods like openGUI
is not Player, but rather
Viewer.
The Viewer is a wrapper class for the actual player, that is necessary to YAGL for implementing most of its features, like permission checking, forced command execution, play of sounds and more.
To obtain an instance, a
BukkitViewer
is provided with the newViewer(HumanEntity)
function.
After a quick glance on GUI submodules,
it is now time to actually learn all the contents and features the base
module offers.
The following is a summary table of this page:
Table of Contents |
---|
Contents |
Title |
Size |
Movable Slots |
Variables |
Actions |
Types |
Assuming a GUI object is already been created, it can be populated using many contents. These describe the elements of the GUI, they can be user-defined and are interchangeable.
In particular, a GUI is divided into slots for which one can specify one or more contents that will be displayed accordingly based on certain criteria.
GUI gui;
Item first;
Item second;
/* ... */
// Second will be displayed as first
gui.setContents(0, ItemGUIContent.newInstance(first).setPriority(0))
.setContents(0, ItemGUIContent.newInstance(second).setPriority(10));
There is a full guide dedicated to contents that is highly advised to better understand how to properly configure this section.
The title is the name that will appear on top of the GUI. Colored names with the & character can be used.
GUI gui;
/* ... */
gui.setTitle("&cSuper GUI");
The size of the GUI represents how many slots are present in the GUI. It is defined upon creating the GUI, it is usually a number multiple of 9 and not higher than 54 (there are exceptions) and **cannot be changed after creating the GUI (unless a Resizable GUI is used).
When adding a content to the GUI, by default they will be set as unmovable. This means that, upon interacting, the viewer will not be able to pick up the item and move it around. To change this, movable slots are introduced. A GUI can have one, some or all its slots set as movable (which will effectively convert it to an inventory).
GUI gui;
/* ... */
gui.setMovable(3, true).setMovable(7, false);
// In case every slot should be movable
gui.setAllMovable();
NOTE: even though it is specified per slots, the movable attribute is bound to the contents. This means that when a movable element is moved to a non-movable slot, it will retain its mobility. In other words, non-movable elements remain non-movable and viceversa.
Variables allow to define internal parameters in the GUI. This is extremely helpful for two reasons:
- to avoid repetition of strings and ease changing them (think of the server or player name, or even an event);
- to allow the developer to use dynamic values inside their GUIs.
Think of a GUI that should change its title based on the player's name.
This can be easily done thanks to the use of variables.
public void openPlayerMoneyGUI(Viewer viewer, Player target) { GUI gui; /* ... */ // The "<player>" string will be replaced with target's actual name gui.setTitle("<player>'s balance") .setVariable("player", target.getName()) .open(viewer); }
This is also very helpful when working with more advanced GUIs. To view the default variables, please check out the Glossary.
Actions represent functions that are executed in response to certain events happening. They can be controlled using lambda functions in association with each method. There are currently four supported events:
-
opening the GUI: it is triggered upon opening the GUI.
It can be controlled using the
GUI#onOpenGUI
method:GUI gui; /* ... */ // g is the GUI that triggered the action gui.onOpenGUI((viewer, g) -> viewer.executeCommand("say Opened the GUI!")); // Or, less verbose gui.onOpenGUI("say Opened the GUI!");
-
closing the GUI: it is triggered upon closing the GUI.
It can be controlled using the
GUI#onCloseGUI
method:GUI gui; /* ... */ // g is the GUI that triggered the action gui.onCloseGUI((viewer, g) -> viewer.executeCommand("say Closed the GUI!")); // Or, less verbose gui.onCloseGUI("say Closed the GUI!");
-
clicking outside the GUI: it is triggered upon clicking outside the GUI.
It can be controlled using the
GUI#onClickOutside
method:GUI gui; /* ... */ // g is the GUI that triggered the action gui.onClickOutside((viewer, g) -> viewer.executeCommand("say Clicked outside the GUI!")); // Or, less verbose gui.onClickOutside("say Clicked outside the GUI!");
-
changing the GUI: it is triggered upon closing the GUI because another one is being opened.
This can happen when, clicking on a certain content, redirects to another page.
It can be controlled using the
GUI#onChangeGUI
method:GUI gui; /* ... */ // g1 is the GUI being closed, g2 is the one being opened gui.onChangeGUI((viewer, g1, g2) -> viewer.executeCommand("say I am changing GUIs")); // Or, less verbose gui.onChangeGUI("say I am changing GUIs");
- clicking on a content (check the dedicated section).
NOTE: when saving the GUI on file, YAGL will try to serialize the lambda functions, but this process might fail. If the action is the execution of a command, it is preferred to use the String version of the methods shown above, to avoid errors and ensure a correct saving method (and also help the admin with the configuration):
// NO!
gui.onOpen((v, g) -> v.executeCommand("say Hello"));
// Prefer this instead
gui.onOpen("say Hello");
The result will be:
gui:
open-gui-action:
type: GUI_COMMAND
content: "say Hello"
After looking at all the different common features that GUIs offer, it is now time to learn how to properly initialize them. There are several versions of GUIs which are all described in the following section.
Table of Contents |
---|
Default |
Resizable |
Type |
Pageable |
Data |
As the name suggests, this is the default regular type of menus in Minecraft, corresponding to a chest inventory. It requires the size to be a multiple of 9 not higher than 54.
GUI gui = GUI.newGUI(9);
This GUI is an extension of the default one offering a new feature: the ability to resize it as the developer pleases. The bounds for the new size are still the same (multiple of 9 not higher than 54).
GUI gui = GUI.newResizableGUI(9).resize(27);
This GUI is a special menu from one of the inventories already present in game. This is useful for creating custom anvils, workbenches, furnaces, hoppers and more. Check out the glossary to see all the available special GUI types.
GUI gui = GUI.newGUI(GUIType.ANVIL);
Pageable is the most interesting and useful type of GUI present in the library. It allows creating multiple GUIs as seen before, and linking them like the pages of a book. It is possible to define one general GUI with common contents, title, size and type for all the pages. Then, the developer might add different specific content for each page.
GUIContent content1;
GUIContent content2;
/* ... */
// Initialize a new GUI of size 9
PageableGUI pageableGUI = PageableGUI.newGUI(9)
// Set the title for ALL pages
.setTitle("Pageable GUI")
// Set the variable "hello"="friend" for ALL pages
.setVariable("hello", "friend")
// Set content1 to slot 1 for ALL pages
.setContents(1, content1)
// Add four pages
.setPages(4);
// Set the title just for the FIRST page.
// This will NOT alter the other pages title.
pageableGUI.getPage(0).setTitle("First page");
// Set content2 to slot2 ONLY FOR the SECOND page.
pageableGUI.getPage(1).setContents(2, content2);
// Set the variable "hello"="world" ONLY FOR the THIRD page.
// This means that every other page will still retain the value "friend".
pageableGUI.getPage(2).setVariable("hello", "world");
// Set the slot 3 movable JUST FOR the FOURTH page.
pageableGUI.getPage(3).setMovable(3, true);
NOTE: to access the previous or next page, it is possible to define two special contents named next page and previous page. Keep in mind that if the viewer is at the first page, the previous page element will not appear, if they are at the last page, the next page element will not be present:
GUIContent previousPage;
GUIContent nextPage;
/* ... */
pageableGUI.setPreviousPage(3, previousPage).setNextPage(5, nextPage);
Data GUIs are an expansion of the Pageable GUI that ease the creation of menus associated with collection. To be more precise, Data GUIs help displaying groups of objects without the pain of manually creating contents for each one of them.
To better understand this type of GUI, let's make an example: imagine a menu that allows banning online players by simply clicking on them. The menu should be structured so that the head of each online player should appear as contents of the GUI.
Instead of using a loop for each player to create the content, it is possible to use the Data GUI:
DataGUI<Player> dataGUI = DataGUI.newGUI(27, player -> {
return ItemGUIContent.newInstance("PLAYER_HEAD")
.setDisplayName("&e" + player.getName())
.onClickItem("ban " + player.getName() + " The ban hammer has spoken");
}, onlinePlayers);
The DataGUI#newGUI
function requires three parameters:
-
size|type
: to define the type of GUI (as previously seen); -
dataConverter
: a function that converts an object from the group to a gui content; -
data
: the group itself.
When opening the GUI, it will automatically fill any empty slots with data from the group converted using the converter
function,
allowing the developer to focus on the layout of the GUI rather than the position of every element of it.