BG-Software
Search…
API
SuperiorSkyblock provides a powerful API, so you can make your own custom addons to the plugin. You can find the API here.

Basic Usage

All of the API methods can be accessed via the SuperiorSkyblockAPI class. The API contains lots of objects that are used as method parameters, and here I'll cover some of them:
SuperiorPlayer This object is used as a warpper to the known player objects of the Bukkit's API. It contains data about the player, states of modes (fly mode etc) and more. You can retrieve the object using SuperiorSkyblockAPI.getPlayer(<UUID>). Island This object is used to cache data about the islands on your server. Members, banned list, multipliers, upgrades and all of the other data is stored in this object. You can get the Island of a player by using SuperiorPlayer#getIsland(). If you want to get an Island in a specific location, you can use SuperiorSkyblockAPI.getGrid().getIslandAt(<Location>). GridManager The grid manager object handles all the islands on your server. If you want to interact with islands, get them from the top list or anything related to that, you should use this object.
Do not use methods that the Island object has (for example, the deleteIsland method), as it should only be used by the Island object itself.

Creating your own command

The API provides a way to register your own commands. This can be done by using the SuperiorSkyblockAPI.registerCommand(<SuperiorCommand>) method. In this tutorial, I will add a new command: /is near. It will return which islands are nearby, and in which direction. First of all, I will create my custom SuperiorCommand class:
1
public final class NearCommand implements SuperiorCommand {
2
3
@Override
4
public List<String> getAliases() {
5
// A list of aliases. The first argument will be the label of the subcommand.
6
return Arrays.asList("near", "nearby");
7
}
8
9
@Override
10
public String getPermission() {
11
// The required permission for the command. If you don't want a specific permission, use "".
12
return "";
13
}
14
15
@Override
16
public String getUsage(Locale locale) {
17
// The usage of the command. Should only include the label & arguments of the command.
18
return "near";
19
}
20
21
@Override
22
public String getDescription(Locale locale) {
23
// The description of the command, which will be shown in /is help.
24
return "Locate nearby islands.";
25
}
26
27
@Override
28
public int getMinArgs() {
29
// Minimum arguments for the command, including the label.
30
return 1;
31
}
32
33
@Override
34
public int getMaxArgs() {
35
// Maximum arguments for the command, including the label.
36
return 1;
37
}
38
39
@Override
40
public boolean canBeExecutedByConsole() {
41
// Whether or not the command can be executed from Console.
42
return false;
43
}
44
45
@Override
46
public boolean displayCommand() {
47
// Whether or not the command would be displayed in the /is help list.
48
return true;
49
}
50
51
@Override
52
public void execute(SuperiorSkyblock plugin, CommandSender sender, String[] args) {
53
// TODO
54
}
55
56
@Override
57
public List<String> tabComplete(SuperiorSkyblock plugin, CommandSender sender, String[] args) {
58
// TODO
59
return new ArrayList<>();
60
}
61
62
}
Copied!
That's it. The only thing that is left is to execute your code under the execute code, and implement the tab-complete. The execute() and tabComplete() methods contain 3 parameters:
    plugin: The instance of the plugin.
    sender: The command sender.
    args: The arguments from the sender.
After filling my code, the final version of the command is the following:
1
public final class NearCommand implements SuperiorCommand {
2
3
<all the other methods>
4
5
private static final int MAX_ISLAND_SIZE = 200;
6
7
@Override
8
public void execute(SuperiorSkyblock plugin, CommandSender sender, String[] args) {
9
// I know that the sender is a player, as I disabled the console from executing.
10
SuperiorPlayer superiorPlayer = SuperiorSkyblockAPI.getPlayer((Player) sender);
11
12
Island targetIsland = plugin.getGrid().getIslandAt(superiorPlayer.getLocation());
13
14
if(targetIsland == null){
15
sender.sendMessage("" + ChatColor.RED + ChatColor.BOLD + "Error | " + ChatColor.GRAY + "You must stand inside an island.");
16
return;
17
}
18
19
StringBuilder message = new StringBuilder();
20
int islandsAmount = 0;
21
22
for(BlockFace blockFace : BlockFace.values()){
23
// I want only to get north, west, east and south - I will just check if their modX is -+1 or their modZ is -+1, but not both.
24
int modXAbs = Math.abs(blockFace.getModX()), modZAbs = Math.abs(blockFace.getModZ());
25
if((modXAbs == 1 || modZAbs == 1) && modXAbs + modZAbs != 2){
26
Location targetIslandLocation = targetIsland.getCenter(World.Environment.NORMAL)
27
.add(MAX_ISLAND_SIZE * 3 * blockFace.getModX(), 0, MAX_ISLAND_SIZE * 3 * blockFace.getModZ());
28
if(plugin.getGrid().getIslandAt(targetIslandLocation) != null) {
29
islandsAmount++;
30
message.append(", ").append(blockFace.name());
31
}
32
}
33
}
34
35
String directionsMessage = message.length() == 0 ? "" : message.substring(2);
36
37
switch (islandsAmount){
38
case 0:
39
sender.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "Island | " + ChatColor.GRAY + "No islands were found.");
40
break;
41
case 1:
42
sender.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "Island | " + ChatColor.GRAY + "There is one island at " + directionsMessage + ".");
43
break;
44
default:
45
sender.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "Island | " + ChatColor.GRAY + "There are islands at " + directionsMessage + ".");
46
break;
47
}
48
}
49
50
@Override
51
public List<String> tabComplete(SuperiorSkyblock plugin, CommandSender sender, String[] args) {
52
// I don't want any tab completes for this command.
53
return new ArrayList<>();
54
}
55
56
}
Copied!
The last thing to do is to call SuperiorSkyblockAPI.registerCommand(<SuperiorCommand>), and that's it! You registered your own command! This command will be supported in all tab completes, /is help and argument restrictions! You can also register the commands without calling the method above. You can extract the class into an external jar, and put it in the commands folder of SuperiorSkyblock2.

Register your own block-keys

The keys system is used to parse blocks and items into a comparable object, that supports both legacy & non-legacy versions. By registering custom keys, you can give your custom blocks a custom key, which will separate it from similar blocks. In this tutorial, I'll make "powerful sponges" to have custom keys.
In order to accomplish this, I'll use the SuperiorSkyblockAPI.getBlockValues().registerKeyParser() method. This method takes two parameters:
    customKeyParser: A CustomKeyParser interface, which we need to create.
    blockTypes: A list of block types which can be parsed by the parser.
First of all, I'll create my CustomKeyParser object. The interface contains two methods that needs to be implemented:
    getCustomKey(<Location>): Handles the parsing part.
    isCustomKey(<Key>): This method is used in the block counts menu, to parse the custom key into it's block form.
After creating the object and implementing basic parser, the code looks like this:
1
private static final Set<Location> powerfulSponges = new HashSet<>();
2
private static final Key SPONGE_KEY = Key.of("SPONGE");
3
private static final Key POWERFUL_SPONGE_KEY = Key.of("POWERFUL_SPONGE");
4
5
private static final class PowerfulSpongeParser implements CustomKeyParser{
6
7
@Override
8
public Key getCustomKey(Location location) {
9
/* All of my custom sponges are cached in powerfulSponges.
10
I know that the block in that location will always be SPONGE, so I can return the sponge key
11
if it's not a custom sponge. If it is, then I return my custom key. */
12
return powerfulSponges.contains(location) ? POWERFUL_SPONGE_KEY : SPONGE_KEY;
13
}
14
15
@Override
16
public boolean isCustomKey(Key key) {
17
// If the key is "POWERFUL_SPONGE", then that key was created by this parser.
18
return key.equals(POWERFUL_SPONGE_KEY);
19
}
20
21
}
Copied!
The only thing left is to register the custom parser, and set the whitelisted block types. This can be done anytime after SuperiorSkyblock was enabled. I am registering it inside a task of bukkit, so I know it happens on the first tick - after all the plugins were enabled. The final version is the following:
1
public final class PowerfulSpongesKey {
2
3
private static final Set<Location> powerfulSponges = new HashSet<>();
4
private static final Key SPONGE_KEY = Key.of("SPONGE");
5
private static final Key POWERFUL_SPONGE_KEY = Key.of("POWERFUL_SPONGE");
6
7
public static void registerKey(JavaPlugin plugin){
8
Bukkit.getScheduler().runTask(plugin, () -> {
9
SuperiorSkyblockAPI.getBlockValues().registerKeyParser(new PowerfulSpongeParser(), SPONGE_KEY);
10
});
11
}
12
13
private static final class PowerfulSpongeParser implements CustomKeyParser{
14
15
@Override
16
public Key getCustomKey(Location location) {
17
/* All of my custom sponges are cached in powerfulSponges.
18
I know that the block in that location will always be SPONGE, so I can return the sponge key
19
if it's not a custom sponge. If it is, then I return my custom key. */
20
return powerfulSponges.contains(location) ? POWERFUL_SPONGE_KEY : SPONGE_KEY;
21
}
22
23
@Override
24
public boolean isCustomKey(Key key) {
25
// If the key is "POWERFUL_SPONGE", then that key was created by this parser.
26
return key.equals(POWERFUL_SPONGE_KEY);
27
}
28
29
}
30
31
}
Copied!
That's it! Everytime I'll place a powerful sponge, it will be considered as "POWERFUL_SPONGE" instead of a regular sponge. This is supported in counts menu, values menu, worth file, levels file and everything else!
Last modified 1mo ago