Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion .github/workflows/Publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ on: [workflow_dispatch]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup JDK 21
uses: actions/setup-java@v4
with:
Expand All @@ -19,4 +24,29 @@ jobs:
run: ./gradlew publish
env:
PUBLISH_USER: ${{ secrets.PUBLISH_USER }}
PUBLISH_PASSWORD: ${{ secrets.PUBLISH_PASSWORD }}
PUBLISH_PASSWORD: ${{ secrets.PUBLISH_PASSWORD }}

- name: Extract Version
run: |
VERSION=$(grep "^version =" build.gradle | awk -F"'" '{print $2}')
echo "VERSION=$VERSION" >> $GITHUB_ENV

- name: Generate Release Notes
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
echo "No previous tags found. Using full history."
git log --pretty=format:"- %s" > release_notes.txt
else
echo "Generating notes since $LAST_TAG"
git log ${LAST_TAG}..HEAD --pretty=format:"- %s" > release_notes.txt
fi

- name: Create Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "$VERSION" \
--title "$VERSION" \
--notes-file release_notes.txt \
build/libs/*.jar
6 changes: 6 additions & 0 deletions bin/main/plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: MinecraftGUI
version: '1.0.0'
main: me.touchie771.minecraftGUI.MinecraftGUI
api-version: '1.21'
authors: [ Touchie771 ]
description: Minecraft library for creating GUIs more easily.
7 changes: 7 additions & 0 deletions src/main/java/me/touchie771/minecraftGUI/api/Menu.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ public void onClose(@NotNull Consumer<InventoryCloseEvent> closeHandler) {
public void removeCloseHandler() {
clickHandler.removeCloseHandler();
}

/**
* Removes all click handlers and the close handler.
*/
public void clearHandlers() {
clickHandler.clear();
}

/**
* Registers this menu's event handlers with Bukkit.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package me.touchie771.minecraftGUI.api.presets;

import me.touchie771.minecraftGUI.api.ClickHandler;
import me.touchie771.minecraftGUI.api.Menu;
import me.touchie771.minecraftGUI.api.SlotItem;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Material;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;

/**
* A preset menu for confirmation dialogs.
* Provides a simple "Confirm" vs "Cancel" choice.
*/
public class ConfirmationMenu {

private static final int SIZE = 27;
private static final int CONFIRM_SLOT = 11;
private static final int CANCEL_SLOT = 15;

/**
* Creates a generic confirmation menu.
*
* @param plugin The plugin instance
* @param title The title of the menu
* @param onConfirm The action to run when confirmed
* @param onCancel The action to run when canceled
* @return A configured Menu instance
*/
public static Menu create(@NotNull Plugin plugin, @NotNull Component title, @NotNull Runnable onConfirm, @NotNull Runnable onCancel) {
SlotItem confirmItem = new SlotItem(
Component.text("Confirm", NamedTextColor.GREEN),
(short) CONFIRM_SLOT,
Material.LIME_WOOL,
1
);

SlotItem cancelItem = new SlotItem(
Component.text("Cancel", NamedTextColor.RED),
(short) CANCEL_SLOT,
Material.RED_WOOL,
1
);

ClickHandler confirmHandler = ClickHandler.newBuilder()
.callback(event -> {
event.getWhoClicked().closeInventory();
onConfirm.run();
})
.autoCancel(true)
.build();

ClickHandler cancelHandler = ClickHandler.newBuilder()
.callback(event -> {
event.getWhoClicked().closeInventory();
onCancel.run();
})
.autoCancel(true)
.build();

return Menu.newBuilder()
.plugin(plugin)
.size(SIZE)
.title(title)
.items(confirmItem, cancelItem)
.onClick(CONFIRM_SLOT, confirmHandler)
.onClick(CANCEL_SLOT, cancelHandler)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package me.touchie771.minecraftGUI.api.presets;

import me.touchie771.minecraftGUI.api.ClickHandler;
import me.touchie771.minecraftGUI.api.Menu;
import me.touchie771.minecraftGUI.api.SlotItem;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
* A preset for a paginated menu.
* Supports navigation between pages of items.
*/
public class PaginationMenu {

private final Menu menu;
private final List<PageItem> items;
private int currentPage = 0;

// Standard layout: 6 rows (54 slots).
// Slots 0-44 for content.
// Slot 45: Previous, Slot 53: Next.
private static final int SIZE = 54;
private static final int ITEMS_PER_PAGE = 45;
private static final int PREV_SLOT = 45;
private static final int NEXT_SLOT = 53;

/**
* Creates a new PaginationMenu.
*
* @param plugin The plugin instance
* @param title The menu title
* @param items The list of items to display across pages
*/
public PaginationMenu(@NotNull Plugin plugin, @NotNull Component title, @NotNull List<PageItem> items) {
this.items = new ArrayList<>(items);

this.menu = Menu.newBuilder()
.plugin(plugin)
.size(SIZE)
.title(title)
.build();

update();
}

/**
* Opens the menu for the specified player.
*
* @param player The player to open the menu for
*/
public void open(@NotNull Player player) {
player.openInventory(menu.getInventory());
}

private void update() {
menu.clear();
menu.clearHandlers();

int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
if (totalPages == 0) totalPages = 1;

if (currentPage < 0) currentPage = 0;
if (currentPage >= totalPages) currentPage = totalPages - 1;

int startIndex = currentPage * ITEMS_PER_PAGE;
int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());

for (int i = startIndex; i < endIndex; i++) {
PageItem item = items.get(i);
int slot = i - startIndex;

menu.addItems(new SlotItem(item.name(), (short) slot, item.material(), item.quantity()));

if (item.action() != null) {
menu.onClick(slot, ClickHandler.newBuilder()
.callback(item.action())
.autoCancel(true)
.build());
}
}

if (currentPage > 0) {
menu.addItems(new SlotItem(
Component.text("Previous Page", NamedTextColor.YELLOW),
(short) PREV_SLOT,
Material.ARROW,
1
));
menu.onClick(PREV_SLOT, ClickHandler.newBuilder()
.callback(e -> {
currentPage--;
update();
})
.autoCancel(true)
.build());
}

if (currentPage < totalPages - 1) {
menu.addItems(new SlotItem(
Component.text("Next Page", NamedTextColor.YELLOW),
(short) NEXT_SLOT,
Material.ARROW,
1
));
menu.onClick(NEXT_SLOT, ClickHandler.newBuilder()
.callback(e -> {
currentPage++;
update();
})
.autoCancel(true)
.build());
}
}

/**
* Represents an item in a paginated menu.
*
* @param name The display name
* @param material The material
* @param quantity The quantity
* @param action The action to perform when clicked (optional)
*/
public record PageItem(@NotNull Component name, @NotNull Material material, int quantity, @Nullable Consumer<InventoryClickEvent> action) {}
}