Skip to content

Latest commit

 

History

History
653 lines (455 loc) · 39.9 KB

README.md

File metadata and controls

653 lines (455 loc) · 39.9 KB

A Data-Driven GUI Framework for Minecraft Mapmaking

AVAILABLE ON 1.21.4

CLICK HERE TO DOWNLOAD

Also available on Modrinth and Planet Minecraft. Please support the project by starring, following, etc. on the respective platforms!

Please report any bugs in the issues section.

A GUI made entirely in-game in under 5 minutes.

Overview

This datapack allows mapmakers to create and maintain complex and robust item-based GUIs in-game. This is achieved by simply dragging and dropping items with custom NBT tags in containers within a world, which the datapack can use to generate GUIs. It functions as a black box that allows each item to act as a graphical widget with predefined properties, without requiring any modifications to be made or additional code to be implemented. Two types of GUIs can be created:

  • Block Entity GUIs: Placed at a fixed position and shared by all players. These are generated upon compilation.
  • Chest Boat GUIs: Retrieved from a database and accessible anywhere by specified players only. These are obtained directly from the above by porting GUIs to players.

The datapack provides the following features:

  • NBT tag standard for quick and easy creation of advanced item-based GUIs
  • Completely in-game workflow, with the entire datapack being a black box that the mapmaker can ignore
  • Robust design, support for multiplayer, including personalized GUIs, and no interference with player inventories
  • Complete documentation, in-game tutorial and demos

Installing

After this folder has been added to the "datapacks" folder of a Minecraft world, /reload needs to be run in-game. A list of the datapack's commands is available via /function ajjgui:__help. By convention, all functions run directly by the mapmaker start with two underscores. Functions starting with a single underscore are aliases that do not give any feedback messages in the chat. These are meant to be used by the mapmaker as part of their own map's datapack. Any functions not listed here are internal and are not meant to be used.

Function Description
/function ajjgui:__compile Compiles GUI
/function ajjgui:__crediting Displays datapack crediting information
/function ajjgui:__decompile Decompiles nearest GUI
/function ajjgui:__help Displays datapack command list
/function ajjgui:__install Installs datapack
/function ajjgui:__kit Gives GUI design and compilation kit
/function ajjgui:__manual Displays datapack manual link
/function ajjgui:__open Opens ported GUI with player UUID and GUI ID
/function ajjgui:__openself Opens ported GUI of executing player with GUI ID
/function ajjgui:__port Ports nearest GUI to player with player UUID and GUI ID
/function ajjgui:__portself Ports nearest GUI to executing player with GUI ID
/function ajjgui:__reload Reloads GUIs
/function ajjgui:__tutorial Displays GUI design and compilation tutorial
/function ajjgui:__uninstall Uninstalls datapack
/function ajjgui:__version Displays datapack version
/function ajjgui:__widgetdemo/ Gives GUI demo widgets
/function ajjgui:_open Runs /function ajjgui:__open without feedback
/function ajjgui:_openself Runs /function ajjgui:__openself without feedback
/function ajjgui:_port Runs /function ajjgui:__port without feedback
/function ajjgui:_portself Runs /function ajjgui:__portself without feedback
/function ajjgui:_reload Runs /function ajjgui:__reload without feedback

The datapack can be installed by running /function ajjgui:__install at any location in the world, which generates a shulker box. This needs to be located in a loaded chunk for the datapack to be fully functional and cannot be destroyed. The shulker box can be relocated by repeating the installation command elsewhere. Any updated versions of the datapack are automatically installed at the same location upon reloading the world. The datapack can be uninstalled using /function ajjgui:__uninstall, which removes all data associated with it from the world and decompiles any existing GUIs.

Creating a GUI

The datapack adopts the concept of graphical widgets, present in real-world user interfaces. Within the scope of Minecraft's item-based GUIs, and this datapack specifically, every item in a GUI corresponds to an interactive element (e.g., a button).

There are 8 types of GUI widgets available:

An in-game tutorial on how to create a GUI is available via /function ajjgui:__tutorial. The tutorial provides the player with premade demo widgets to experiment with. Multiple examples are given, both here and in-game, to help provide a better understanding of their custom NBT tags. The following section explains all the different types of widgets available and how they can be customized. Once obtained, these items can be placed inside shulker boxes, with each shulker box corresponding to a different GUI page. The shulker boxes can be arranged based on their page number and compiled to build a functional GUI in-game. This manual can be accessed with /function ajjgui:__manual.

List of GUI Widgets

Tip

Some of the following commands are too long to fit in the chat box and need to be executed using a command block.

Warning

For custom NBT tags, it is important to check that the right data types are being used (e.g., {ajjgui:{exit:1b}} and not {ajjgui:{exit:1}}), that values are within the specified range (e.g., {ajjgui:{exit:1b}} and not {ajjgui:{exit:2b}}, where ajjgui.exit here can only be 0b or 1b). The GUI compiler is only capable of initializing required NBT tags with default values and does not correct errors. While there are cases where errors in custom NBT tags, such as incorrect data types, may be internally resolved by the datapack at later stages, this behavior is inconsistent and must not be assumed.

Note

The ajjgui.command, ajjgui.exit, ajjgui.fixed, ajjgui.page and ajjgui.relative NBT tags are covered separately in later sections.

Placeholder

The placeholder is a widget that cannot be interacted with and is used to display an item.

NBT Tag Default Type
ajjgui.fixed 0b Byte (Boolean)
ajjgui.widget Required ("placeholder" or N/A) String

Usage

/give @p <item id>[minecraft:custom_data={ajjgui:{widget:"placeholder",<optional ajjgui tags>}}]

Example

A placeholder:

/give @p minecraft:black_stained_glass_pane[minecraft:custom_data={ajjgui:{widget:"placeholder"}},minecraft:hide_tooltip={}]

Tip

If a GUI slot is empty, it is set to a light gray stained glass pane placeholder with a hidden tooltip.

Tip

If the ajjgui.widget NBT tag of any item is not specified, it is set to "placeholder" by default. Therefore, the entire ajjgui argument for any placeholder is optional.

Button

The button is a widget that changes the GUI page, exits the GUI and/or runs a GUI command when clicked. More information can be found in the following sections.

NBT Tag Default Type
ajjgui.command N/A String
ajjgui.exit 0b Byte (Boolean)
ajjgui.fixed 0b Byte (Boolean)
ajjgui.page N/A Byte
ajjgui.relative 0b Byte (Boolean)
ajjgui.widget Required ("button") String

Usage

/give @p <item id>[minecraft:custom_data={ajjgui:{widget:"button",<optional ajjgui tags>}}]

Examples

More information about changing GUI pages, exiting GUIs and running GUI commands.

Counter

The counter is a widget that changes to a different count of the same item when clicked, following a value sequence. The value sequence is specified in the ajjgui.values NBT tag. The default value is the one initially used upon creation of the widget. Once a counter in its default state is clicked, it changes to the second value in the list and so on. Hence, the first one is not used until the end of the first cycle. After one cycle, the first value is always used instead of the default one. The current state of a counter is stored in the ajjgui.state NBT tag.

NBT Tag Default Type
ajjgui.command N/A String
ajjgui.exit 0b Byte (Boolean)
ajjgui.fixed 0b Byte (Boolean)
ajjgui.page N/A Byte
ajjgui.relative 0b Byte (Boolean)
ajjgui.state 0 Int
ajjgui.values Required Int List
ajjgui.widget Required ("counter") String

Usage

/give @p <item id>[minecraft:custom_data={ajjgui:{widget:"counter",values:[<value 1>,<value 2>,…,<value N>],<optional ajjgui tags>}}] <default value>

where N is the number of states.

Examples

  1. A counter repeating the sequence 1 to 16, starting with 1. The default value is the same as the first value in ajjgui.values:

    /give @p minecraft:black_stained_glass_pane[minecraft:custom_data={ajjgui:{widget:"counter",values:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}},minecraft:custom_name='{"text":"Counter Value","italic":false}'] 1
    
  2. A counter repeating the sequence 1 to 4, starting with 1. The default value is the same as the first value in ajjgui.values:

    /give @p minecraft:black_stained_glass_pane[minecraft:custom_data={ajjgui:{widget:"counter",values:[1,2,3,4]}},minecraft:custom_name='{"text":"Counter Value","italic":false}'] 1
    
  3. A counter beginning with a default value of 64, followed by the sequence 2 to 16, that continues by repeating the sequence 1 to 16:

    /give @p minecraft:black_stained_glass_pane[minecraft:custom_data={ajjgui:{widget:"counter",values:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}},minecraft:custom_name='{"text":"Counter Value","italic":false}'] 64
    
  4. A counter repeating the sequence 1 to 16, starting with 16. The default value is the same as the first value in ajjgui.values (now rearranged). The value of ajjgui.state is set to 1 to match the states:

    /give @p minecraft:black_stained_glass_pane[minecraft:custom_data={ajjgui:{widget:"counter",values:[16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],state:1}},minecraft:custom_name='{"text":"Counter Value","italic":false}'] 16
    

Widget shown in Example 1.

Switch

The switch is a widget that changes to a different item when clicked, following an item sequence. The item sequence is specified in the ajjgui.items NBT tag. The default item is the one initially used upon creation of the widget. Once a switch in its default state is clicked, it changes to the second item in the list and so on. Hence, the first one is not used until the end of the first cycle. After one cycle, the first item is always used instead of the default one. The current state of a switch is stored in the ajjgui.state NBT tag.

NBT Tag Default Type
ajjgui.command N/A String
ajjgui.exit 0b Byte (Boolean)
ajjgui.fixed 0b Byte (Boolean)
ajjgui.items Required Compound List
ajjgui.page N/A Byte
ajjgui.relative 0b Byte (Boolean)
ajjgui.state 0 Int
ajjgui.widget Required ("switch") String

Usage

/give @p <default item id>[minecraft:custom_data={ajjgui:{widget:"switch",items:[<item 1>,<item 2>,…,<item N>],<optional ajjgui tags>}}]

where N is the number of states.

Examples

  1. A switch changing between a "State 0" and a "State 1" state, starting with "State 0". The default item is the same as the first item in ajjgui.items:

    /give @p minecraft:gray_dye[minecraft:custom_data={ajjgui:{widget:"switch",items:[{id:"minecraft:gray_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 0","italic":false}'}},{id:"minecraft:lime_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 1","italic":false}'}}]}},minecraft:custom_name='{"text":"State 0","italic":false}']
    
  2. A switch changing between a "State 0", a "State 1" and a "State 2" state, starting with "State 0". The default item is the same as the first item in ajjgui.items:

    /give @p minecraft:gray_dye[minecraft:custom_data={ajjgui:{widget:"switch",items:[{id:"minecraft:gray_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 0","italic":false}'}},{id:"minecraft:lime_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 1","italic":false}'}},{id:"minecraft:purple_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 2","italic":false}'}}]}},minecraft:custom_name='{"text":"State 0","italic":false}']
    
  3. A switch beginning with a default state, "Default", that continues by changing between a "State 0" and a "State 1" state, starting with "State 1":

    /give @p minecraft:magenta_dye[minecraft:custom_data={ajjgui:{widget:"switch",items:[{id:"minecraft:gray_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 0","italic":false}'}},{id:"minecraft:lime_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 1","italic":false}'}}]}},minecraft:custom_name='{"text":"Default","italic":false}']
    
  4. A switch changing between a "State 0" and a "State 1" state, starting with "State 1". The default item is the same as the first item in ajjgui.items (now rearranged). The value of ajjgui.state is set to 1 to match the states:

    /give @p minecraft:lime_dye[minecraft:custom_data={ajjgui:{widget:"switch",items:[{id:"minecraft:lime_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 1","italic":false}'}},{id:"minecraft:gray_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 0","italic":false}'}},{id:"minecraft:purple_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 2","italic":false}'}}],state:1}},minecraft:custom_name='{"text":"State 1","italic":false}']
    

Widget shown in Example 1.

Radiobutton

The radiobutton is a widget that changes between a disabled and an enabled state item when clicked. It comes in groups in which only one widget can be enabled at a time, with the rest being disabled. Each item is specified in the ajjgui.disabled and ajjgui.enabled NBT tags. The default item is the one initially used upon creation of the widget. Once a radiobutton is clicked, it changes to the item corresponding to its enabled state, and all the other radiobutton widgets with the same group identifier change to their disabled state. The group identifier of a radiobutton is stored in the ajjgui.group NBT tag. The current state of a radiobutton is stored in the ajjgui.state NBT tag.

NBT Tag Default Type
ajjgui.command N/A String
ajjgui.disabled Required Compound
ajjgui.enabled Required Compound
ajjgui.exit 0b Byte (Boolean)
ajjgui.fixed 0b Byte (Boolean)
ajjgui.group 0b Byte
ajjgui.page N/A Byte
ajjgui.relative 0b Byte (Boolean)
ajjgui.state 0 Int
ajjgui.widget Required ("radiobutton") String

Usage

/give @p <default item id>[minecraft:custom_data={ajjgui:{widget:"radiobutton",off:<off item>,on:<on item>,<optional ajjgui tags>}}]

Examples

  1. A radiobutton on group 0 changing between a "Disabled" and an "Enabled" state, starting with "Disabled":

    /give @p minecraft:gray_dye[minecraft:custom_data={ajjgui:{widget:"radiobutton",disabled:{id:"minecraft:gray_dye",count:1,components:{"minecraft:custom_name":'{"text":"Disabled","italic":false}'}},enabled:{id:"minecraft:lime_dye",count:1,components:{"minecraft:custom_name":'{"text":"Enabled","italic":false}'}},group:0b}},minecraft:custom_name='{"text":"Disabled","italic":false}']
    
  2. A radiobutton on group 0 beginning with a default state, "Default", that continues by changing between a "Disabled" and an "Enabled" state, starting with "Enabled":

    /give @p minecraft:magenta_dye[minecraft:custom_data={ajjgui:{widget:"radiobutton",disabled:{id:"minecraft:gray_dye",count:1,components:{"minecraft:custom_name":'{"text":"Disabled","italic":false}'}},enabled:{id:"minecraft:lime_dye",count:1,components:{"minecraft:custom_name":'{"text":"Enabled","italic":false}'}},group:0b}},minecraft:custom_name='{"text":"Default","italic":false}']
    
  3. A radiobutton on group 0 changing between a "Disabled" and an "Enabled" state, starting with "Enabled". The value of ajjgui.state is set to 1 to match the states:

    /give @p minecraft:lime_dye[minecraft:custom_data={ajjgui:{widget:"radiobutton",disabled:{id:"minecraft:gray_dye",count:1,components:{"minecraft:custom_name":'{"text":"Disabled","italic":false}'}},enabled:{id:"minecraft:lime_dye",count:1,components:{"minecraft:custom_name":'{"text":"Enabled","italic":false}'}},group:0b,state:1}},minecraft:custom_name='{"text":"Enabled","italic":false}']
    

Widget shown in Example 1.

Itembin

The itembin is a widget that clears all items inserted by the player in a particular slot in the GUI.

NBT Tag Default Type
ajjgui.command N/A String
ajjgui.exit 0b Byte (Boolean)
ajjgui.fixed 0b Byte (Boolean)
ajjgui.page N/A Byte
ajjgui.relative 0b Byte (Boolean)
ajjgui.widget Required ("itembin") String

Usage

/give @p <item id>[minecraft:custom_data={ajjgui:{widget:"itembin",<optional ajjgui tags>}}]

Example

An itembin:

/give @p minecraft:bucket[minecraft:custom_data={ajjgui:{widget:"itembin"}},minecraft:custom_name='{"text":"Item Bin","italic":false}']

Widget shown in Example.

Important

The itembin has a built-in cooldown of 0.4s.

Itemslot

The itemslot is a widget that stores items inserted by the player in a particular slot in the GUI. Once one or more stacked items are inserted, the current ones occupying the slot (if any) are replaced and returned to the player's inventory. When the itemslot is not being used, a placeholder item occupies the slot. This is stored in the ajjgui.placeholder NBT tag. The maximum number of items in an itemslot is stored in the ajjgui.size NBT tag, which cannot be larger than 99. Any excess items are returned to the player. Whether an itemslot has an item in it is determined by the ajjgui.state NBT tag.

NBT Tag Default Type
ajjgui.command N/A String
ajjgui.exit 0b Byte (Boolean)
ajjgui.fixed 0b Byte (Boolean)
ajjgui.page N/A Byte
ajjgui.placeholder Required Compound
ajjgui.relative 0b Byte (Boolean)
ajjgui.size 99 Int
ajjgui.state 0 Int
ajjgui.widget Required ("itemslot") String

Usage

/give @p <default item or placeholder id>[minecraft:custom_data={ajjgui:{widget:"itemslot",placeholder:<placeholder item>,<optional ajjgui tags>}}]

Examples

  1. An empty itemslot with a default placeholder item identical to the one specified in ajjgui.placeholder and a stack size of 64:

    /give @p minecraft:gray_stained_glass_pane[minecraft:custom_data={ajjgui:{widget:"itemslot",placeholder:{id:"minecraft:gray_stained_glass_pane",count:1,components:{"minecraft:custom_name":'{"text":"Empty","italic":false}'}},size:64}},minecraft:custom_name='{"text":"Empty","italic":false}']
    
  2. An empty itemslot with a default placeholder item identical to the one specified in ajjgui.placeholder and a stack size of 16:

    /give @p minecraft:gray_stained_glass_pane[minecraft:custom_data={ajjgui:{widget:"itemslot",placeholder:{id:"minecraft:gray_stained_glass_pane",count:1,components:{"minecraft:custom_name":'{"text":"Empty","italic":false}'}},size:16}},minecraft:custom_name='{"text":"Empty","italic":false}']
    
  3. An empty itemslot with a default placeholder item different from the one specified in ajjgui.placeholder and a stack size of 64:

    /give @p minecraft:white_stained_glass_pane[minecraft:custom_data={ajjgui:{widget:"itemslot",placeholder:{id:"minecraft:gray_stained_glass_pane",count:1,components:{"minecraft:custom_name":'{"text":"Empty","italic":false}'}},size:64}},minecraft:custom_name='{"text":"Default","italic":false}']
    
  4. An itemslot with an item in it by default and a stack size of 64. The value of ajjgui.state is set to 1 as the slot is occupied:

    /give @p minecraft:diamond[minecraft:custom_data={ajjgui:{widget:"itemslot",placeholder:{id:"minecraft:gray_stained_glass_pane",count:1,components:{"minecraft:custom_name":'{"text":"Empty","italic":false}'}},size:64,state:1}}]
    

Widget shown in Example 1.

Important

The itemslot has a built-in cooldown of 0.4s.

Scrollbutton

The scrollbutton is a widget that cycles one or more lists of static widgets (see notes) across respective GUI slot lists when clicked. This allows for additional space in the GUI. Each widget list is specified in the ajjgui.widgets NBT tag. Within each widget list, widgets are added in the order they appear in. The slot list associated with each widget list is specified in the ajjgui.slots NBT tag. Within each slot list, slots are added in the order they are occupied by the respective widget list. The scrollbutton also contains the entire functionality of the switch, including the ajjgui.items and ajjgui.state NBT tags.

NBT Tag Default Type
ajjgui.command N/A String
ajjgui.exit 0b Byte (Boolean)
ajjgui.fixed 0b Byte (Boolean)
ajjgui.items N/A Compound List
ajjgui.page N/A Byte
ajjgui.relative 0b Byte (Boolean)
ajjgui.slots Required Byte List List
ajjgui.state 0 Int
ajjgui.widget Required ("scrollbutton") String
ajjgui.widgets Required Compound List List

Usage

/give @p <item id>[minecraft:custom_data={ajjgui:{widget:"scrollbutton",widgets:[[<widget 1,1>,<widget 1,2>,…,<widget 1,L_1>],[<widget 2,1>,<widget 2,2>,…,<widget 2,L_2>],…,[<widget N,1>,<widget N,2>,…,<widget N,L_N>]],slots:[[<slot 1,1>,<slot 1,2>,…,<slot 1,M_1>],[<slot 2,1>,<slot 2,2>,…,<slot 2,M_2>],…,[<slot N,1>,<slot N,2>,…,<slot N,M_N>]],<optional ajjgui tags>}}]

where L_x and M_y are the numbers of widgets and slots in each widget list and slot list respectively, and N is the number of widget list and slot list pairs.

Example

A scrollbutton cycling 6 buttons across GUI slots 11, 12, 13 and 14. Each button leads to a different page when clicked. There is a single widget list of length 6 and a single slot list of length 4:

/give @p minecraft:spectral_arrow[minecraft:custom_data={ajjgui:{widget:"scrollbutton",widgets:[[{id:"minecraft:paper",count:1,components:{"minecraft:custom_data":{ajjgui:{widget:"button",page:0b}},"minecraft:custom_name":'{"text":"Select","italic":false}'}},{id:"minecraft:paper",count:2,components:{"minecraft:custom_data":{ajjgui:{widget:"button",page:1b}},"minecraft:custom_name":'{"text":"Select","italic":false}'}},{id:"minecraft:paper",count:3,components:{"minecraft:custom_data":{ajjgui:{widget:"button",page:2b}},"minecraft:custom_name":'{"text":"Select","italic":false}'}},{id:"minecraft:paper",count:4,components:{"minecraft:custom_data":{ajjgui:{widget:"button",page:3b}},"minecraft:custom_name":'{"text":"Select","italic":false}'}},{id:"minecraft:paper",count:5,components:{"minecraft:custom_data":{ajjgui:{widget:"button",page:4b}},"minecraft:custom_name":'{"text":"Select","italic":false}'}},{id:"minecraft:paper",count:6,components:{"minecraft:custom_data":{ajjgui:{widget:"button",page:5b}},"minecraft:custom_name":'{"text":"Select","italic":false}'}}]],slots:[[11b,12b,13b,14b]]}},minecraft:custom_name='{"text":"Next","italic":false}']

Widget shown in Example.

Important

The scrollbutton only supports the placeholder, button and itembin widgets.

Tip

If the ajjgui.widget NBT tag of any widget is not specified, it is set to "placeholder" by default. Therefore, the entire ajjgui argument for any placeholder is optional. This, by extension, applies to a placeholder widget specified in the ajjgui.widgets NBT tag of the scrollbutton.

Changing GUI Pages

Each of the widgets discussed previously, excluding the placeholder, can be made to change the GUI page when clicked. This is done by specifying a page number in the ajjgui.page NBT tag. By default, this value is the index of the shulker box in the chest previously used to compile the GUI, where a value of 0b corresponds to the first page. If it is equal to the number of pages, the count resets back to the first page, and negative values may also be used to access pages from the end. The ajjgui.relative NBT tag can be set to 1b in order for the value of ajjgui.page to increment the page number from its current value. This, hence, assumes that the current page has an index of 0b and uses this as a reference instead of the first one.

Examples

  1. A button setting the GUI page to the first one:

    /give @p minecraft:arrow[minecraft:custom_data={ajjgui:{widget:"button",page:0b}},minecraft:custom_name='{"text":"Go to First Page","italic":false}']
    
  2. A button setting the GUI page to the last one:

    /give @p minecraft:arrow[minecraft:custom_data={ajjgui:{widget:"button",page:-1b}},minecraft:custom_name='{"text":"Go to Last Page","italic":false}']
    
  3. A button setting the GUI page to the next one:

    /give @p minecraft:arrow[minecraft:custom_data={ajjgui:{widget:"button",page:1b,relative:1b}},minecraft:custom_name='{"text":"Go to Next Page","italic":false}']
    
  4. A button setting the GUI page to the previous one:

    /give @p minecraft:arrow[minecraft:custom_data={ajjgui:{widget:"button",page:-1b,relative:1b}},minecraft:custom_name='{"text":"Go to Previous Page","italic":false}']
    

Fixed GUI Widgets

Each of the widgets discussed previously can be made to stay on display when the GUI page is changed. This is done by setting the ajjgui.fixed NBT tag to 1b. If a scrollbutton is made fixed, its widgets also obtain this property.

Example

A button staying fixed in its slot when the GUI page is changed:

/give @p minecraft:arrow[minecraft:custom_data={ajjgui:{widget:"button",page:1b,relative:1b,fixed:1b}},minecraft:custom_name='{"text":"Go to Next Page","italic":false}']

Exiting GUIs

Each of the widgets discussed previously, excluding the placeholder, can be made to exit the GUI when clicked. This is done by setting the ajjgui.exit NBT tag to 1b.

Example

A button exiting the GUI:

/give @p minecraft:barrier[minecraft:custom_data={ajjgui:{widget:"button",exit:1b}},minecraft:custom_name='{"text":"Exit","italic":false}',minecraft:rarity=common]

Porting GUIs to Players

Once a GUI is compiled, it is possible to port a copy of it to a specific player in a database using their UUID and an identifier unique to each GUI associated with them. This allows for personalized menus based on chest boats. Porting the nearest GUI is achieved with /function ajjgui:__port using the macro arguments "player" for the UUID Int array and "id" for the GUI identifier. Using the same arguments, /function ajjgui:__open gives a player access to a GUI from the database. The executing player can use their own UUID with /function ajjgui:__portself and /function ajjgui:__openself, which only require a GUI identifier as an argument.

Example

  1. A mapmaker compiles a GUI for a settings menu at coordinates 10 10 10. It is intended for each player in the map to have their own settings menu. The following command can be used to port instances of this GUI to all online players. A single underscore is used to hide command feedback:

    /execute positioned 10 10 10 as @a run function ajjgui:_portself {id:"settings"}
    

    Then, a player can open their own GUI with:

    /function ajjgui:_openself {id:"settings"}
    
  2. By specifying a UUID, offline players can be targeted, and a player can be allowed to open someone else's GUI. For example, the UUID of the player "Ajj" is [I; -1547620582, -1960489320, -1638997249, 1765947055]. The following command can be used to port the nearest GUI to Ajj. A single underscore is used to hide command feedback:

    /function ajjgui:_port {player:[I;-1547620582,-1960489320,-1638997249,1765947055],id:"settings"}
    

    Then, a player can open Ajj's GUI with:

    /function ajjgui:_open {player:[I;-1547620582,-1960489320,-1638997249,1765947055],id:"settings"}
    

Note

There is a persistent actionbar prompt instructing the user to open their inventory to view the chest boat menu and dismount to cancel. This can be modified or removed using the ajjgui:data prompt data storage NBT tag.

Important

These chest boats have an interaction entity surrounding their hitbox and preventing other players from accessing them. If other players come close enough to bypass this, the chest boat is removed (and the user needs to reopen the GUI). These measures are essential in ensuring that GUIs can only be accessed by their specified player.

Running GUI Commands and Accessing Data

Read-Only Data

Scoreboard Score Description Type
@s ajjgui.count Widget item count Int
@s ajjgui.page Page number Int
@s ajjgui.slot Widget slot Int
@s ajjgui.state Widget state Int
Data Storage NBT Tag Description Type
ajjgui:data in Itembin or itemslot item inserted Compound
ajjgui:data out Itemslot item removed Compound
ajjgui:data page Page Compound List
ajjgui:data widget Widget Compound

Modifiable Data

Scoreboard Score Description Type
@e[tag=ajjgui.gui_active,limit=1] ajjgui.page Page number Int
GUI Marker Entity NBT Tag Description Type
@e[tag=ajjgui.gui_active,limit=1] data.custom_name GUI container name String
@e[tag=ajjgui.gui_active,limit=1] data.gui GUI page list Compound List
Data Storage NBT Tag Description Type
ajjgui:data prompt Actionbar prompt for all ported GUIs String (JSON)

Each of the widgets discussed previously, excluding the the placeholder, can be made to run commands or functions when clicked. This is done by specifying a command in the ajjgui.command NBT tag. This command is executed by the player interacting with the widget. Within the command's execution, it is possible to access data exported from the GUI interaction (e.g., whether a switch is toggled on) and use it to make decisions.

Examples

  1. A button running a command referencing the player that pressed it:

    /give @p minecraft:pink_dye[minecraft:custom_data={ajjgui:{widget:"button",command:"say pressed button"}},minecraft:custom_name='{"text":"Command Button","italic":false}']
    
  2. A switch running a command based on its current state:

    /give @p minecraft:gray_dye[minecraft:custom_data={ajjgui:{widget:"switch",items:[{id:"minecraft:gray_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 0","italic":false}'}},{id:"minecraft:lime_dye",count:1,components:{"minecraft:custom_name":'{"text":"State 1","italic":false}'}}],command:"function name:func"}},minecraft:custom_name='{"text":"State 0","italic":false}']
    

    where the following commands are located in a function name:func within a map's datapack:

    execute if score @s ajjgui.state matches 0 run say set switch to State 0
    execute if score @s ajjgui.state matches 1 run say set switch to State 1
    

Advanced: Modifying GUIs Post-Compilation

There is a marker entity with the scoreboard tag "ajjgui.gui_origin" for block entity GUIs, located at the container coordinates, and "ajjgui.gui_ported" for chest boat GUIs, riding the chest boat. GUIs used at a specific tick temporarily have the "ajjgui.gui_active" scoreboard tag on their marker. This marker stores the page value in its ajjgui.page score, the container name in its data.custom_name NBT tag and the page list in its data.gui NBT tag. Each element in this list corresponds to a page, storing widgets in the same format containers use to store items. If the available widget types and tags do not already support a particular functionality, the page number and widget NBT tags may be modified post-compilation to achieve desired results. This would, for example, be needed if one wanted to modify a GUI without prior user interaction (i.e., without triggering a widget with the ajjgui.page or ajjgui.command NBT tags). If the modification command is not triggered by a player using a GUI (i.e., with the ajjgui.command NBT tag), /function ajjgui:_reload must follow in the same tick for any changes to be reflected in the GUI.

Examples

  1. A command setting the nearest block entity GUI's page to the first one:

    /scoreboard players set @n[type=minecraft:marker,tag=ajjgui.gui_origin] ajjgui.page 0
    

    Then, in the same tick (not required if the above command is run from a widget):

    /function ajjgui:_reload
    
  2. A command setting the nearest block entity GUI's first page's first slot item's id to stone:

    /data modify entity @n[type=minecraft:marker,tag=ajjgui.gui_origin] data.gui[0][{Slot:0b}].id set value "minecraft:stone"
    

    Then, in the same tick (not required if the above command is run from a widget):

    /function ajjgui:_reload
    
  3. A button running a command setting its GUI's first page's first slot item's id to stone:

    /give @p minecraft:pink_dye[minecraft:custom_data={ajjgui:{widget:"button",command:'data modify entity @e[type=minecraft:marker,tag=ajjgui.gui_active,limit=1] data.gui[0][{Slot:0b}].id set value "minecraft:stone"'}},minecraft:custom_name='{"text":"Command Button","italic":false}']
    

    In this example, /function ajjgui:_reload is not required.

Warning

If a GUI is not reloaded as specified above, the datapack assumes that a player is interacting indefinitely with it, causing other active GUIs to malfunction.

Warning

The GUI compiler adds the ajjgui.meta NBT tag to each widget. This must not be changed when modifying NBT tags post-compilation.

Warning

This section explains how widgets can be modified after compilation, when required NBT tags have already been initialized with default values. Creating widget NBT tags from scratch or changing the ajjgui.widget NBT tag is therefore not recommended.

Important

Widgets with the ajjgui.fixed NBT tag set to 1b are passed on to a new page only when it is loaded by clicking on a widget that has the ajjgui.page NBT tag. Changing a page post-compilation therefore does not properly handle fixed widgets.

Note

Decompiling a GUI resets it to its state before compilation.

Crediting

Made by Ajj and published under the MIT license. Please share the repository link.