[Open Source] SkyBlock Minecraft Addon [gui.sk]

in #utopian-io5 years ago (edited)

2018-12-01_00.37.18.png

Hello guys!

Yesterday, i published a SkyBlock Skript to GitHub, read more about it here. Today, i continued with commits and also created a new add-on to this Skript, gui.sk, which is also published under the MIT license.

gui.sk

This skript adds minecraft inventory menu capabilities directly in skript and makes the setup for new server operators easier. Opening custom inventorys to players as a menu, fill the menus with custom items and execution on a click can be achieved fast and reliable with gui.sk.
Additional, gui.sk is very lightweight, it has only 98 lines of code.

Skript has some default capabilities to open inventories and add items to it. But there are some problems:

  1. Adding items into a new inventory with lore (the information text below the name of the item) is not working in Skript without add-ons
  2. To get this working in Skript, the server operator would have to set up events (click trigger) for the menu, code for the menu and formatting of items and also have to search for add-ons which actually work for the right version.

To make it as easy as possible for server operators, i'm making SKYBLOCK.SK as dependency free as possible by using the apis of the minecraft server software Spigot and Bukkit directly in Skript by using skript-mirror, which is a powerful reflection tool for Skript.

Now, let's look what it actually does:
Because some needed triggers aren't existing in Skript, i use skript-mirror as a add-on, which allows to use java classes and events within Skript:

import:
    java.util.ArrayList
    org.bukkit.Bukkit
    org.bukkit.event.inventory.InventoryClickEvent
    org.bukkit.event.inventory.InventoryCloseEvent
    org.bukkit.inventory.Inventory
    org.bukkit.inventory.ItemStack
    org.bukkit.inventory.meta.ItemMeta
    org.bukkit.event.inventory.InventoryType

Then i started with the first function of this skript. It opens a inventory by any available inventory type, custom size and name. Once the function is loaded, it can be called across the whole server in every skript, this allows to make clean looking skripts and wíth less code.

function opengui(player:player,size:integer,name:text,type:text=CHEST) :: boolean:
    delete {SK::GUI::items::%{_player}%::*}
    # > If {_type} is CHEST (default)
    if {_type} is "CHEST":
        set {_invtype} to InventoryType.CHEST!
    # > If it is not a chest, check the input and set the InventoryType:
    # > This is done like this to avoid errors:
    else:
        if {_type} is "ANVIL":
            set {_invtype} to InventoryType.ANVIL!
        else if {_type} is "BEACON":
            set {_invtype} to InventoryType.BEACON!
        else if {_type} is "BREWING":
            set {_invtype} to InventoryType.BREWING!
        else if {_type} is "CHEST":
            set {_invtype} to InventoryType.CHEST!
        else if {_type} is "CRAFTING":
            set {_invtype} to InventoryType.CRAFTING!
        else if {_type} is "CREATIVE":
            set {_invtype} to InventoryType.CREATIVE!
        else if {_type} is "DISPENSER":
            set {_invtype} to InventoryType.DISPENSER!
        else if {_type} is "ENCHANTING":
            set {_invtype} to InventoryType.ENCHANTING!
        else if {_type} is "ENDER_CHEST":
            set {_invtype} to InventoryType.ENDER_CHEST!
        else if {_type} is "HOPPER":
            set {_invtype} to InventoryType.HOPPER!
        else if {_type} is "MERCHANT":
            set {_invtype} to InventoryType.MERCHANT!
        else if {_type} is "PLAYER":
            set {_invtype} to InventoryType.PLAYER!
        else if {_type} is "SHULKER_BOX":
            set {_invtype} to InventoryType.SHULKER_BOX!
        else if {_type} is "WORKBENCH":
            set {_invtype} to InventoryType.WORKBENCH!
        # > If {_invtype} has been found and set go forward:
    if {_invtype} is set:
        # > Set the {_inventory} variable to a new inventory, owned by the player and set to the {_invtype}, named after {_name}
        if {_type} is "CHEST":
            set {_inventory} to Bukkit.createInventory({_player}, {_size}, {_name})
        else:
            set {_inventory} to Bukkit.createInventory({_player}, {_invtype}, {_name})
        # > Open the inventory to the player
        {_player}.openInventory({_inventory})
        # > Set the created inventory into the variable to check later, if the user clicks in the correct gui
        set {SK::GUI::inv::%{_player}%} to {_inventory}
        # > Everything went fine, return true.
        return true
    # > If not, print an error to the player who wanted to open the gui menu and stop the skript
    else:
        message "&5&lInvalid InventoryType: %{_type}%" to {_player}
        stop

I know, it looks a bit messy because i have to checking trough all the types and then setting the {_invtype} variable to the InventoryType, but i had troubles adding them directly. This works, it is bigger, but it works always fine.

Once the function is called, the {SK::GUI::items::%{_player}%::}* array is being deleted. You can determine arrays from variables by looking at their end, if it ends with ::*}, it's a array.
This is needed, because this array contains all items of the GUI menu, since we're opening a fresh menu without any content, this has to be empty too.

Then, it is determined what type of inventory should be opened, there are many and i'm actually pretty delighted that all of them seem to work. =) The if and else if statements are filtering out the right inventory type, i have to make this shorter in the future...

If that is done, the inventory is being created and then displayed to the player. If something went wrong, the player gets a message that the inventory type is not available. Since that is the only thing that could go wrong here. Hopefully :3.

Now, we have a empty inventory which has to be filled with stuff. To do this, i have created another function:

function setguiitem(player:player,slot:integer,item:text,amount:integer,name:text,lore:text,exec:text="",close:boolean=false):
    set {_ItemStack} to {_item} parsed as item
    set {_ItemStack} to {_ItemStack} named {_name}
    set {_ItemMeta} to {_ItemStack}.getItemMeta()
    set {_itemlore} to new ArrayList()
    {_itemlore}.add({_lore})
    {_ItemMeta}.setLore({_itemlore})
    {_ItemStack}.setItemMeta({_ItemMeta})
    set slot {_slot} of {SK::GUI::inv::%{_player}%} to {_ItemStack}
    if {_exec} != "":
        set {SK::GUI::items::%{_player}%::%{_slot}%} to {_exec}
    if {_close} is true:
        set {SK::GUI::itemsclose::%{_player}%::%{_slot}%} to true

This function has many arguments, these needed to create a new item and also needed for a click event later.
Here, the item input is set as text and then being parsed as item, which reduces errors by users, since the right item name automatically chosen. Then the ItemMeta is set into a new variable, which is used to set the lore of the item. This would not work in Skript direcly without skript-mirror or another skript add-on.
Then, the item is placed into the predefined inventory from the function above. A global variable is set to allow the server to detect, which item slot in the new menu has a command to execute code on click.

Now, we're ready for the events (trigger)!
The following event is triggered if the user clicks somewhere in the inventory, then i can get player who clicked on it to check, if the click happened within a GUI menu or not:

on InventoryClickEvent:
    set {_player} to event.getWhoClicked()
    if {SK::GUI::inv::%{_player}%} is set:
        if size of {SK::GUI::items::%{_player}%::*} is not 0:
            cancel event
            set {_slot} to event.getRawSlot()
            evaluate "%{SK::GUI::items::%{_player}%::%{_slot}%}%"
            if {SK::GUI::itemsclose::%{_player}%::%{_slot}%} is true:
                wait 1 tick
                close {_player}'s inventory

Only, if {SK::GUI::inv::%{_player}%} is set and {SK::GUI::items::%{_player}%::}* is not 0, the predefined command is being executed, thanks to evaluate, plain text can be parsed as skript code, this is very helpful at this point.

If the {SK::GUI::itemsclose::%{_player}%::%{_slot}%} variable is set to true, it is going to wait for one tick and then closing the inventory.
Closing the inventory instantly would create a display bug, that is why it is waiting for 1 tick to prevent the display bug.

Now, since we closed the inventory, we can go to the InventoryCloseEvent event, which is called, when the user is closing his inventory.

on InventoryCloseEvent:
    set {_player} to event.getPlayer()
    delete {SK::GUI::inv::%{_player}%}
    delete {SK::GUI::items::%{_player}%::*}
    delete {SK::GUI::itemsclose::%{_player}%::*}

To make sure, no data is left by a corruption or server fault, the variables are deleted on load:

on load:
    delete {SK::GUI::inv::*}
    delete {SK::GUI::items::*}
    delete {SK::GUI::itemsclose::*} 

Thats all what it needs to do.

gui.sk on GitHub

You can find gui.sk here on GitHub, it is part of the SKYBLOCK.SK Skript, which allows server operators to provide a highly customized SkyBlock experience for the users with Skript without to know how Java works.

How to contribute

To contribute, you can either create a pull request on GitHub or contact us on the Skyroad Discord. Really looking forward to see more people using skript for minecraft. =)

Usage example

Now, i want to show how it works, this is a new command, which can be executed in the game by a player by typing in "/test", it opens a gui menu for the player whith the name "&6FREE STUFF" with the inventory type of a hopper.

Then it executes the second function, which adds a diamond ore to this inventory, which is named "&r&6&lFREE DIAMONDS!!!1", with a lore (text below the name) of "&r&fFREEEEEE! Click here!", the following text is the command, which is going to be executed, if the player clicks on it.

If true is set at the end, the inventory menu is going to be closed on click. Example code:

command /test:
    trigger:
        opengui(player,9,"&6FREE STUFF","HOPPER")
        setguiitem(player,0,"diamond ore",1,"&r&6&lFREE DIAMONDS!!!1","&r&fFREEEEEE! Click here!","execute console command ""give %player% diamond_ore 1""",true)

Well, thats all i have to share for now. I had much stuff to do the last couple of days for SKYBLOCK.SK, since the game started today on our server, join.skyroad.me. Feel free to test it out and leave some feedback. This is currently the only server where you can earn STEEM by playing minecraft and SkyBlock at the same time.

I made this post more code-like than the last post, hope that this is how you guys like it =). I also added more detailed comments to the skript to make it easier to understand whats happening there.

EDIT: messed up the tags, should be fixed now.^^

I wish all of you guys a great weekend,

@immanuel94

Sort:  
  • Great post, could use more pictures since the game offers such cool eye candy.
  • There are some english grammatical errors. Please do a second read before posting. Like this i have to checking or that these needed to create
  • Please post the pull request link (or the commits) that relate to the article, it allows us to easily review the code that has changed.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hey @helo! Thanks, you're doing a amazing job.
I'll try to proofread my posts better in the future.
I also going to start working with pull requests in the future to make it more easy to read. Also a good idea for myself, since changes are easier to detect.. =D
Adding some pictures is a great idea, going to do that in the future.

Thank you for your review, @helo! Keep up the good work!

Das Skyblock GUI is cool

Ja, finde ich auch! =D Mit gui.sk kann man schöne guis machen und das auch sehr schnell...^^
Vielen Dank für das Feedback.

Die GUI ist sehr schön geworden. Übersichtlich und einfach zu bedienen - so wie es sein soll. Optisch macht sie ebenfall sehr viel her und durch die kleinen Texte an den einzelnen Icons findet man sich auch sehr gut zurecht.

Vielen Dank für dein Feedback! =) Ja, finde ich auch, dass das ganz gut ist. Allerdings noch etwas zu simpel, also wenig Möglichkeiten.^^

Ich würde ja gerne die Top 10 in die GUI verschieben... =D

Die GUI des Skyblock Spielmodus ist sehr gut gelungen. Man erhält hier eine gute Übersicht, beispielsweise über das Level der eigenen Insel. Ich schäme mich allerdings Kritik melden zu müssen, der Teleport funktioniert leider noch nicht p

Ok, das muss ich mir anschauen, woran das liegt. Danke für die Info. =)

Das Menü ist übersichtlich und schön :D

Freut mich, dass es dir gefällt.^^

Finde es gut und reicht für´n Anfang. :D

Wenn du Ideen hast, kannst du diese auch gerne als Issue auf Github posten, freue mich über gute Ideen. :)

Hi @immanuel94!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your UA account score is currently 2.250 which ranks you at #20337 across all Steem accounts.
Your rank has improved 73 places in the last three days (old rank 20410).

In our last Algorithmic Curation Round, consisting of 175 contributions, your post is ranked at #154.

Evaluation of your UA score:
  • Only a few people are following you, try to convince more people with good work.
  • The readers like your work!
  • Try to work on user engagement: the more people that interact with you via the comments, the higher your UA score!

Feel free to join our @steem-ua Discord server

Hey, @immanuel94!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.36
TRX 0.12
JST 0.040
BTC 70744.80
ETH 3561.94
USDT 1.00
SBD 4.80