From 4b0c6207b7f1940b299a29c650d0ad53846ab6d8 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Wed, 7 Jan 2026 19:23:59 +0200 Subject: [PATCH 01/35] feat: start inventory v2 --- .../type/generic/gui/v2/ClickContext.java | 21 +++ .../type/generic/gui/v2/Components.java | 40 +++++ .../type/generic/gui/v2/GuiComponent.java | 25 +++ .../swofty/type/generic/gui/v2/GuiLayout.java | 43 ++++++ .../type/generic/gui/v2/GuiSession.java | 146 ++++++++++++++++++ .../swofty/type/generic/gui/v2/Layouts.java | 47 ++++++ .../type/generic/gui/v2/Pagination.java | 49 ++++++ .../net/swofty/type/generic/gui/v2/View.java | 11 ++ .../generic/gui/v2/context/GuiContext.java | 16 ++ .../generic/gui/v2/event/GUIClickEvent.java | 3 + .../generic/gui/v2/event/GUICloseEvent.java | 4 + .../generic/gui/v2/event/GUIOpenEvent.java | 4 + .../generic/gui/v2/event/GUIRefreshEvent.java | 4 + .../type/generic/gui/v2/event/GuiEvent.java | 4 + .../generic/gui/v2/example/TestStateView.java | 56 +++++++ 15 files changed, 473 insertions(+) create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/ClickContext.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/Layouts.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/GuiContext.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GuiEvent.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/example/TestStateView.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ClickContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ClickContext.java new file mode 100644 index 000000000..80ec31c65 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ClickContext.java @@ -0,0 +1,21 @@ +package net.swofty.type.generic.gui.v2; + +import net.minestom.server.inventory.click.Click; +import net.swofty.type.generic.user.HypixelPlayer; + +public record ClickContext( + int slot, + Click click, + HypixelPlayer player, + S state +) { + public boolean isLeftClick() { + return click instanceof Click.Left; + } + + public boolean isRightClick() { + return click instanceof Click.Right; + } + +} + diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java new file mode 100644 index 000000000..237c4a611 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java @@ -0,0 +1,40 @@ +package net.swofty.type.generic.gui.v2; + +import net.kyori.adventure.text.Component; +import net.minestom.server.component.DataComponents; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.minestom.server.item.component.TooltipDisplay; + +public final class Components { + + public static final ItemStack FILLER = item(Material.BLACK_STAINED_GLASS_PANE, " ", true); + public static final ItemStack CLOSE_BUTTON = item(Material.BARRIER, "§cClose"); + + public static void close(GuiLayout layout, int slot) { + layout.slot(slot, (_, _) -> CLOSE_BUTTON, (_, ctx) -> ctx.player().closeInventory()); + } + + public static void back(GuiLayout layout, int slot, View target, Object targetState) { + layout.slot(slot, (_, _) -> item(Material.ARROW, "§aGo Back"), + (_, ctx) -> open(ctx, target, targetState)); + } + + @SuppressWarnings("unchecked") + public static void open(net.swofty.type.generic.gui.v2.context.GuiContext ctx, View view, Object state) { + GuiSession.open(view, ctx.player(), (T) state); + } + + public static ItemStack item(Material material, String name) { + return ItemStack.builder(material) + .set(DataComponents.CUSTOM_NAME, Component.text(name)) + .build(); + } + + public static ItemStack item(Material material, String name, boolean hideTooltip) { + var builder = ItemStack.builder(material).set(DataComponents.CUSTOM_NAME, Component.text(name)); + if (hideTooltip) builder.set(DataComponents.TOOLTIP_DISPLAY, TooltipDisplay.EMPTY); + return builder.build(); + } +} + diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java new file mode 100644 index 000000000..6a91fa851 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java @@ -0,0 +1,25 @@ +package net.swofty.type.generic.gui.v2; + +import net.minestom.server.item.ItemStack; +import net.swofty.type.generic.gui.v2.context.GuiContext; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public record GuiComponent( + int slot, + BiFunction render, + BiConsumer, GuiContext> onClick +) { + public static GuiComponent staticItem(int slot, ItemStack item) { + return new GuiComponent<>(slot, (_, _) -> item, (_, _) -> {}); + } + + public static GuiComponent clickable( + int slot, + BiFunction render, + BiConsumer, GuiContext> onClick + ) { + return new GuiComponent<>(slot, render, onClick); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java new file mode 100644 index 000000000..5cc219021 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java @@ -0,0 +1,43 @@ +package net.swofty.type.generic.gui.v2; + +import net.minestom.server.item.ItemStack; +import net.swofty.type.generic.gui.v2.context.GuiContext; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public final class GuiLayout { + + private final Map> components = new HashMap<>(); + + public void slot( + int slot, + BiFunction render, + BiConsumer, GuiContext> onClick + ) { + components.put(slot, new GuiComponent<>(slot, render, onClick)); + } + + public void slot(int slot, BiFunction render) { + slot(slot, render, (_, _) -> {}); + } + + public void filler(Collection slots, ItemStack item) { + slots.forEach(s -> + components.put(s, GuiComponent.staticItem(s, item)) + ); + } + + public void filler(Collection slots, BiFunction itemSupplier) { + slots.forEach(s -> + components.put(s, new GuiComponent<>(s, itemSupplier, (_, _) -> {})) + ); + } + + public Map> components() { + return components; + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java new file mode 100644 index 000000000..10687c960 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java @@ -0,0 +1,146 @@ +package net.swofty.type.generic.gui.v2; + +import lombok.Getter; +import lombok.experimental.Accessors; +import net.minestom.server.MinecraftServer; +import net.minestom.server.event.EventFilter; +import net.minestom.server.event.EventNode; +import net.minestom.server.event.inventory.InventoryCloseEvent; +import net.minestom.server.event.inventory.InventoryPreClickEvent; +import net.minestom.server.event.trait.InventoryEvent; +import net.minestom.server.inventory.Inventory; +import net.minestom.server.timer.TaskSchedule; +import net.swofty.type.generic.gui.v2.context.GuiContext; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.time.Duration; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.UnaryOperator; + +public final class GuiSession { + + private final View view; + @Getter + @Accessors(fluent = true) + private final HypixelPlayer player; + @Getter + @Accessors(fluent = true) + private final Inventory inventory; + private final GuiContext context; + private final EventNode eventNode; + + private S state; + private S previousState; + private GuiLayout cachedLayout; + private Consumer onCloseHandler; + private boolean closed; + + private GuiSession(View view, HypixelPlayer player, S initialState) { + this.view = view; + this.player = player; + this.state = initialState; + this.inventory = new Inventory(view.size(), ""); + this.context = new GuiContext(player, inventory, this); + this.eventNode = EventNode.type("gui-" + System.identityHashCode(this), EventFilter.INVENTORY); + + wireEvents(); + } + + public static GuiSession open(View view, HypixelPlayer player, S initialState) { + GuiSession session = new GuiSession<>(view, player, initialState); + session.render(); + player.openInventory(session.inventory); + return session; + } + + private void wireEvents() { + eventNode.addListener(InventoryPreClickEvent.class, this::onClickEvent); + eventNode.addListener(InventoryCloseEvent.class, this::onCloseEvent); + MinecraftServer.getGlobalEventHandler().addChild(eventNode); + } + + private void onClickEvent(InventoryPreClickEvent event) { + if (event.getInventory() != inventory || closed) return; + event.setCancelled(true); + + GuiComponent component = cachedLayout.components().get(event.getSlot()); + if (component == null) return; + + ClickContext click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); + component.onClick().accept(click, context); + } + + private void onCloseEvent(InventoryCloseEvent event) { + if (event.getInventory() != inventory) return; + close(CloseReason.PLAYER_EXITED); + } + + public void render() { + if (closed) return; + + cachedLayout = new GuiLayout<>(); + view.layout(cachedLayout, state, context); + + if (!Objects.equals(state, previousState)) { + inventory.setTitle(view.title(state, context)); + previousState = state; + } + + cachedLayout.components().forEach((slot, component) -> { + var item = component.render().apply(state, context); + if (!inventory.getItemStack(slot).equals(item)) { + inventory.setItemStack(slot, item); + } + }); + } + + public S state() { + return state; + } + + public void setState(S newState) { + if (Objects.equals(state, newState)) return; + this.state = newState; + render(); + } + + public void update(UnaryOperator transform) { + setState(transform.apply(state)); + } + + public GuiSession onClose(Consumer handler) { + this.onCloseHandler = handler; + return this; + } + + public GuiSession refreshEvery(Duration interval) { + MinecraftServer.getSchedulerManager().submitTask(() -> { + if (closed) return TaskSchedule.stop(); + render(); + return TaskSchedule.millis(interval.toMillis()); + }); + return this; + } + + public void close(CloseReason reason) { + if (closed) return; + closed = true; + + MinecraftServer.getGlobalEventHandler().removeChild(eventNode); + if (onCloseHandler != null) onCloseHandler.accept(reason); + if (reason != CloseReason.PLAYER_EXITED) player.closeInventory(); + } + + public boolean isClosed() { + return closed; + } + + public enum CloseReason { + PLAYER_EXITED, + SERVER_EXITED, + REPLACED + } +} + + diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Layouts.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Layouts.java new file mode 100644 index 000000000..37101e179 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Layouts.java @@ -0,0 +1,47 @@ +package net.swofty.type.generic.gui.v2; + +import java.util.List; +import java.util.stream.IntStream; + +public final class Layouts { + + public static List rectangle(int from, int to) { + int startRow = from / 9; + int endRow = to / 9; + int startCol = from % 9; + int endCol = to % 9; + + List slots = new java.util.ArrayList<>(); + + for (int row = startRow; row <= endRow; row++) { + for (int col = startCol; col <= endCol; col++) { + slots.add(row * 9 + col); + } + } + + return slots; + } + + public static List border(int from, int to) { + int startRow = from / 9; + int endRow = to / 9; + int startCol = from % 9; + int endCol = to % 9; + + List slots = new java.util.ArrayList<>(); + + for (int row = startRow; row <= endRow; row++) { + for (int col = startCol; col <= endCol; col++) { + if (row == startRow || row == endRow || col == startCol || col == endCol) { + slots.add(row * 9 + col); + } + } + } + + return slots; + } + + public static List row(int row) { + return IntStream.range(0, 9).map(i -> row * 9 + i).boxed().toList(); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java new file mode 100644 index 000000000..44e73ea11 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java @@ -0,0 +1,49 @@ +package net.swofty.type.generic.gui.v2; + +import net.minestom.server.item.ItemStack; +import net.swofty.type.generic.gui.v2.context.GuiContext; + +import java.util.List; +import java.util.function.BiFunction; + +public final class Pagination { + + public record Page(List items, int current, int total) { + public boolean hasNext() { return current < total - 1; } + public boolean hasPrev() { return current > 0; } + } + + public static Page paginate(List all, int page, int perPage) { + int totalPages = Math.max(1, (int) Math.ceil((double) all.size() / perPage)); + int start = page * perPage; + int end = Math.min(start + perPage, all.size()); + List items = start < all.size() ? all.subList(start, end) : List.of(); + return new Page<>(items, page, totalPages); + } + + public static void items( + GuiLayout layout, + List slots, + List items, + BiFunction renderer, + ClickHandler onClick + ) { + for (int i = 0; i < slots.size(); i++) { + int slot = slots.get(i); + if (i < items.size()) { + T item = items.get(i); + int index = i; + layout.slot(slot, (_, _) -> renderer.apply(item, index), + (click, ctx) -> onClick.handle(click, ctx, item, index)); + } else { + layout.slot(slot, (_, _) -> ItemStack.AIR); + } + } + } + + @FunctionalInterface + public interface ClickHandler { + void handle(ClickContext click, GuiContext ctx, T item, int index); + } +} + diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java new file mode 100644 index 000000000..758d520a3 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java @@ -0,0 +1,11 @@ +package net.swofty.type.generic.gui.v2; + +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.swofty.type.generic.gui.v2.context.GuiContext; + +public interface View { + InventoryType size(); + Component title(S state, GuiContext ctx); + void layout(GuiLayout layout, S state, GuiContext ctx); +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/GuiContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/GuiContext.java new file mode 100644 index 000000000..e3c68d55f --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/GuiContext.java @@ -0,0 +1,16 @@ +package net.swofty.type.generic.gui.v2.context; + +import net.minestom.server.inventory.Inventory; +import net.swofty.type.generic.gui.v2.GuiSession; +import net.swofty.type.generic.user.HypixelPlayer; + +public record GuiContext( + HypixelPlayer player, + Inventory inventory, + GuiSession session +) { + @SuppressWarnings("unchecked") + public GuiSession session(Class stateType) { + return (GuiSession) session; + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java new file mode 100644 index 000000000..7c4686be2 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java @@ -0,0 +1,3 @@ +package net.swofty.type.generic.gui.v2.event; + +public non-sealed interface GUIClickEvent extends GuiEvent { } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java new file mode 100644 index 000000000..9453c1554 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java @@ -0,0 +1,4 @@ +package net.swofty.type.generic.gui.v2.event; + +public non-sealed interface GUICloseEvent extends GuiEvent { +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java new file mode 100644 index 000000000..7ceb0919a --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java @@ -0,0 +1,4 @@ +package net.swofty.type.generic.gui.v2.event; + +public non-sealed interface GUIOpenEvent extends GuiEvent {} + diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java new file mode 100644 index 000000000..08f748d38 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java @@ -0,0 +1,4 @@ +package net.swofty.type.generic.gui.v2.event; + +public non-sealed interface GUIRefreshEvent extends GuiEvent {} + diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GuiEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GuiEvent.java new file mode 100644 index 000000000..d87b374f7 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GuiEvent.java @@ -0,0 +1,4 @@ +package net.swofty.type.generic.gui.v2.event; + +public sealed interface GuiEvent + permits GUIClickEvent, GUICloseEvent, GUIOpenEvent, GUIRefreshEvent {} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/example/TestStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/example/TestStateView.java new file mode 100644 index 000000000..67103ddf9 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/example/TestStateView.java @@ -0,0 +1,56 @@ +package net.swofty.type.generic.gui.v2.example; + +import net.kyori.adventure.text.Component; +import net.minestom.server.component.DataComponents; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.GuiLayout; +import net.swofty.type.generic.gui.v2.GuiSession; +import net.swofty.type.generic.gui.v2.Layouts; +import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.v2.context.GuiContext; +import net.swofty.type.generic.user.HypixelPlayer; + +public final class TestStateView implements View { + + public record State(int counter) { + public State increment() { return new State(counter + 1); } + public State decrement() { return new State(counter - 1); } + } + + @Override + public InventoryType size() { + return InventoryType.CHEST_3_ROW; + } + + @Override + public Component title(State state, GuiContext ctx) { + return Component.text("Counter: " + state.counter()); + } + + @Override + public void layout(GuiLayout layout, State state, GuiContext ctx) { + layout.filler(Layouts.border(0, 26), Components.FILLER); + + layout.slot(11, (_, _) -> item(Material.RED_WOOL, "§c-1"), + (click, c) -> c.session(State.class).update(State::decrement)); + + layout.slot(13, (s, _) -> item(Material.PAPER, "§eCounter: " + s.counter())); + + layout.slot(15, (_, _) -> item(Material.LIME_WOOL, "§a+1"), + (click, c) -> c.session(State.class).update(State::increment)); + + Components.close(layout, 22); + } + + private static ItemStack item(Material mat, String name) { + return ItemStack.builder(mat).set(DataComponents.CUSTOM_NAME, Component.text(name)).build(); + } + + public static void open(HypixelPlayer player) { + GuiSession.open(new TestStateView(), player, new State(0)); + } +} + From e2e56a433fcb816418ac87e9dd579cbe5eba2d60 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Wed, 7 Jan 2026 21:33:35 +0200 Subject: [PATCH 02/35] feat: improve states --- .../type/generic/gui/v2/Components.java | 55 +++++++++---------- .../type/generic/gui/v2/GuiComponent.java | 1 + .../swofty/type/generic/gui/v2/GuiLayout.java | 1 + .../type/generic/gui/v2/GuiSession.java | 10 ++-- .../type/generic/gui/v2/Pagination.java | 1 + .../type/generic/gui/v2/StatefulView.java | 5 ++ .../gui/v2/{ => context}/ClickContext.java | 2 +- .../v2/{example => test}/TestStateView.java | 30 ++++------ .../type/generic/user/HypixelPlayer.java | 16 ++++++ 9 files changed, 68 insertions(+), 53 deletions(-) create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java rename type.generic/src/main/java/net/swofty/type/generic/gui/v2/{ => context}/ClickContext.java (88%) rename type.generic/src/main/java/net/swofty/type/generic/gui/v2/{example => test}/TestStateView.java (53%) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java index 237c4a611..5a4d71263 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java @@ -6,35 +6,34 @@ import net.minestom.server.item.Material; import net.minestom.server.item.component.TooltipDisplay; +import java.util.Set; + public final class Components { - public static final ItemStack FILLER = item(Material.BLACK_STAINED_GLASS_PANE, " ", true); - public static final ItemStack CLOSE_BUTTON = item(Material.BARRIER, "§cClose"); - - public static void close(GuiLayout layout, int slot) { - layout.slot(slot, (_, _) -> CLOSE_BUTTON, (_, ctx) -> ctx.player().closeInventory()); - } - - public static void back(GuiLayout layout, int slot, View target, Object targetState) { - layout.slot(slot, (_, _) -> item(Material.ARROW, "§aGo Back"), - (_, ctx) -> open(ctx, target, targetState)); - } - - @SuppressWarnings("unchecked") - public static void open(net.swofty.type.generic.gui.v2.context.GuiContext ctx, View view, Object state) { - GuiSession.open(view, ctx.player(), (T) state); - } - - public static ItemStack item(Material material, String name) { - return ItemStack.builder(material) - .set(DataComponents.CUSTOM_NAME, Component.text(name)) - .build(); - } - - public static ItemStack item(Material material, String name, boolean hideTooltip) { - var builder = ItemStack.builder(material).set(DataComponents.CUSTOM_NAME, Component.text(name)); - if (hideTooltip) builder.set(DataComponents.TOOLTIP_DISPLAY, TooltipDisplay.EMPTY); - return builder.build(); - } + public static final ItemStack FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE) + .set(DataComponents.CUSTOM_NAME, Component.text(" ")) + .set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())) + .build(); + public static final ItemStack CLOSE_BUTTON = ItemStack.builder(Material.BARRIER) + .set(DataComponents.CUSTOM_NAME, Component.text("§cClose")) + .build(); + public static final ItemStack BACK_BUTTON = ItemStack.builder(Material.ARROW) + .set(DataComponents.CUSTOM_NAME, Component.text("§aGo Back")) + .build(); + + public static void close(GuiLayout layout, int slot) { + layout.slot(slot, (_, _) -> CLOSE_BUTTON, (_, ctx) -> ctx.player().closeInventory()); + } + + public static void back(GuiLayout layout, int slot, View target, Object targetState) { + layout.slot(slot, (_, _) -> BACK_BUTTON, + (_, ctx) -> open(ctx, target, targetState)); + } + + @SuppressWarnings("unchecked") + public static void open(net.swofty.type.generic.gui.v2.context.GuiContext ctx, View view, Object state) { + GuiSession.open(view, ctx.player(), (T) state); + } + } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java index 6a91fa851..3a4c1d6ef 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java @@ -1,6 +1,7 @@ package net.swofty.type.generic.gui.v2; import net.minestom.server.item.ItemStack; +import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.GuiContext; import java.util.function.BiConsumer; diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java index 5cc219021..14e5cf98e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java @@ -1,6 +1,7 @@ package net.swofty.type.generic.gui.v2; import net.minestom.server.item.ItemStack; +import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.GuiContext; import java.util.Collection; diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java index 10687c960..86a9a2fff 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java @@ -10,6 +10,7 @@ import net.minestom.server.event.trait.InventoryEvent; import net.minestom.server.inventory.Inventory; import net.minestom.server.timer.TaskSchedule; +import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.GuiContext; import net.swofty.type.generic.user.HypixelPlayer; @@ -34,7 +35,8 @@ public final class GuiSession { private S previousState; private GuiLayout cachedLayout; private Consumer onCloseHandler; - private boolean closed; + @Getter + private boolean closed; private GuiSession(View view, HypixelPlayer player, S initialState) { this.view = view; @@ -132,11 +134,7 @@ public void close(CloseReason reason) { if (reason != CloseReason.PLAYER_EXITED) player.closeInventory(); } - public boolean isClosed() { - return closed; - } - - public enum CloseReason { + public enum CloseReason { PLAYER_EXITED, SERVER_EXITED, REPLACED diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java index 44e73ea11..e49172a63 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java @@ -1,6 +1,7 @@ package net.swofty.type.generic.gui.v2; import net.minestom.server.item.ItemStack; +import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.GuiContext; import java.util.List; diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java new file mode 100644 index 000000000..c40a215dd --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java @@ -0,0 +1,5 @@ +package net.swofty.type.generic.gui.v2; + +public interface StatefulView extends View { + S initialState(); +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ClickContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java similarity index 88% rename from type.generic/src/main/java/net/swofty/type/generic/gui/v2/ClickContext.java rename to type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java index 80ec31c65..1edb0a4c8 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ClickContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java @@ -1,4 +1,4 @@ -package net.swofty.type.generic.gui.v2; +package net.swofty.type.generic.gui.v2.context; import net.minestom.server.inventory.click.Click; import net.swofty.type.generic.user.HypixelPlayer; diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/example/TestStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java similarity index 53% rename from type.generic/src/main/java/net/swofty/type/generic/gui/v2/example/TestStateView.java rename to type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java index 67103ddf9..885dbca69 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/example/TestStateView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java @@ -1,19 +1,20 @@ -package net.swofty.type.generic.gui.v2.example; +package net.swofty.type.generic.gui.v2.test; import net.kyori.adventure.text.Component; import net.minestom.server.component.DataComponents; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.v2.Components; -import net.swofty.type.generic.gui.v2.GuiLayout; -import net.swofty.type.generic.gui.v2.GuiSession; -import net.swofty.type.generic.gui.v2.Layouts; -import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; import net.swofty.type.generic.gui.v2.context.GuiContext; -import net.swofty.type.generic.user.HypixelPlayer; -public final class TestStateView implements View { +public final class TestStateView implements StatefulView { + + @Override + public State initialState() { + return new State(0); + } public record State(int counter) { public State increment() { return new State(counter + 1); } @@ -34,23 +35,16 @@ public Component title(State state, GuiContext ctx) { public void layout(GuiLayout layout, State state, GuiContext ctx) { layout.filler(Layouts.border(0, 26), Components.FILLER); - layout.slot(11, (_, _) -> item(Material.RED_WOOL, "§c-1"), + layout.slot(11, (_, _) -> ItemStackCreator.createNamedItemStack(Material.RED_WOOL, "§c-1").build(), (click, c) -> c.session(State.class).update(State::decrement)); - layout.slot(13, (s, _) -> item(Material.PAPER, "§eCounter: " + s.counter())); + layout.slot(13, (s, _) -> ItemStackCreator.createNamedItemStack(Material.PAPER, "§eCounter: " + s.counter()).build()); - layout.slot(15, (_, _) -> item(Material.LIME_WOOL, "§a+1"), + layout.slot(15, (_, _) -> ItemStackCreator.createNamedItemStack(Material.GREEN_WOOL, "§a+1").build(), (click, c) -> c.session(State.class).update(State::increment)); Components.close(layout, 22); } - private static ItemStack item(Material mat, String name) { - return ItemStack.builder(mat).set(DataComponents.CUSTOM_NAME, Component.text(name)).build(); - } - - public static void open(HypixelPlayer player) { - GuiSession.open(new TestStateView(), player, new State(0)); - } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java index 22c2c6a3b..0dd35e9e7 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java +++ b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java @@ -20,11 +20,15 @@ import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.achievement.PlayerAchievementHandler; import net.swofty.type.generic.experience.PlayerExperienceHandler; +import net.swofty.type.generic.gui.v2.GuiSession; +import net.swofty.type.generic.gui.v2.StatefulView; +import net.swofty.type.generic.gui.v2.View; import net.swofty.type.generic.quest.PlayerQuestHandler; import net.swofty.type.generic.user.categories.Rank; import org.jetbrains.annotations.NotNull; import java.util.HashMap; +import java.util.Objects; import java.util.UUID; public class HypixelPlayer extends Player { @@ -79,6 +83,18 @@ public DatapointChatType.ChatType getChatType() { return getDataHandler().get(HypixelDataHandler.Data.CHAT_TYPE, DatapointChatType.class).getValue(); } + public GuiSession openView(View view, S state) { + return GuiSession.open(view, this, state); + } + + public GuiSession openView(View view) { + Objects.requireNonNull(view, "View is null"); + if (!(view instanceof StatefulView state)) { + throw new IllegalArgumentException("View is not a StatefulView"); + } + return GuiSession.open(view, this, state.initialState()); + } + public ProxyPlayer asProxyPlayer() { return new ProxyPlayer(this); } From 537dec1ad4d966f0cec0e7d49b4489efcb043e22 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Wed, 7 Jan 2026 21:58:47 +0200 Subject: [PATCH 03/35] feat: cleaner layout --- .../type/generic/gui/v2/Components.java | 18 +++--- .../type/generic/gui/v2/GuiComponent.java | 26 --------- .../swofty/type/generic/gui/v2/GuiLayout.java | 55 +++++++++++++++---- .../type/generic/gui/v2/GuiSession.java | 24 ++++---- .../type/generic/gui/v2/Pagination.java | 8 +-- .../net/swofty/type/generic/gui/v2/View.java | 6 +- .../type/generic/gui/v2/ViewComponent.java | 26 +++++++++ .../{GuiContext.java => ViewContext.java} | 2 +- .../generic/gui/v2/event/GUIClickEvent.java | 2 +- .../generic/gui/v2/event/GUICloseEvent.java | 2 +- .../v2/event/{GuiEvent.java => GUIEvent.java} | 2 +- .../generic/gui/v2/event/GUIOpenEvent.java | 2 +- .../generic/gui/v2/event/GUIRefreshEvent.java | 2 +- .../generic/gui/v2/test/TestStateView.java | 21 ++----- 14 files changed, 110 insertions(+), 86 deletions(-) delete mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java rename type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/{GuiContext.java => ViewContext.java} (93%) rename type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/{GuiEvent.java => GUIEvent.java} (78%) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java index 5a4d71263..d902373b8 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java @@ -5,21 +5,19 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.component.TooltipDisplay; +import net.swofty.type.generic.gui.v2.context.ViewContext; import java.util.Set; public final class Components { - public static final ItemStack FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE) + public static final ItemStack.Builder FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE) .set(DataComponents.CUSTOM_NAME, Component.text(" ")) - .set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())) - .build(); - public static final ItemStack CLOSE_BUTTON = ItemStack.builder(Material.BARRIER) - .set(DataComponents.CUSTOM_NAME, Component.text("§cClose")) - .build(); - public static final ItemStack BACK_BUTTON = ItemStack.builder(Material.ARROW) - .set(DataComponents.CUSTOM_NAME, Component.text("§aGo Back")) - .build(); + .set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())); + public static final ItemStack.Builder CLOSE_BUTTON = ItemStack.builder(Material.BARRIER) + .set(DataComponents.CUSTOM_NAME, Component.text("§cClose")); + public static final ItemStack.Builder BACK_BUTTON = ItemStack.builder(Material.ARROW) + .set(DataComponents.CUSTOM_NAME, Component.text("§aGo Back")); public static void close(GuiLayout layout, int slot) { layout.slot(slot, (_, _) -> CLOSE_BUTTON, (_, ctx) -> ctx.player().closeInventory()); @@ -31,7 +29,7 @@ public static void back(GuiLayout layout, int slot, View target, Objec } @SuppressWarnings("unchecked") - public static void open(net.swofty.type.generic.gui.v2.context.GuiContext ctx, View view, Object state) { + public static void open(ViewContext ctx, View view, Object state) { GuiSession.open(view, ctx.player(), (T) state); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java deleted file mode 100644 index 3a4c1d6ef..000000000 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiComponent.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.swofty.type.generic.gui.v2; - -import net.minestom.server.item.ItemStack; -import net.swofty.type.generic.gui.v2.context.ClickContext; -import net.swofty.type.generic.gui.v2.context.GuiContext; - -import java.util.function.BiConsumer; -import java.util.function.BiFunction; - -public record GuiComponent( - int slot, - BiFunction render, - BiConsumer, GuiContext> onClick -) { - public static GuiComponent staticItem(int slot, ItemStack item) { - return new GuiComponent<>(slot, (_, _) -> item, (_, _) -> {}); - } - - public static GuiComponent clickable( - int slot, - BiFunction render, - BiConsumer, GuiContext> onClick - ) { - return new GuiComponent<>(slot, render, onClick); - } -} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java index 14e5cf98e..80434be38 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java @@ -1,44 +1,75 @@ package net.swofty.type.generic.gui.v2; +import lombok.Getter; +import lombok.experimental.Accessors; +import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.gui.v2.context.ClickContext; -import net.swofty.type.generic.gui.v2.context.GuiContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.IntStream; public final class GuiLayout { - private final Map> components = new HashMap<>(); + @Getter + @Accessors(fluent = true) + private final Map> components = new HashMap<>(); + + @Getter + @Accessors(fluent = true) + private final InventoryType inventoryType; + + public GuiLayout(InventoryType inventoryType) { + this.inventoryType = inventoryType; + } public void slot( int slot, - BiFunction render, - BiConsumer, GuiContext> onClick + BiFunction render, + BiConsumer, ViewContext> onClick ) { - components.put(slot, new GuiComponent<>(slot, render, onClick)); + components.put(slot, new ViewComponent<>(slot, render, onClick)); } - public void slot(int slot, BiFunction render) { + public void slot(int slot, BiFunction render) { slot(slot, render, (_, _) -> {}); } - public void filler(Collection slots, ItemStack item) { + public void slot(int slot, ItemStack.Builder builder, BiConsumer, ViewContext> onClick) { + components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, onClick)); + } + + public void slot(int slot, ItemStack.Builder builder, Function stateUpdater) { + components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, + (_, ctx) -> ctx.session(Object.class).updateUnchecked(stateUpdater))); + } + + public void slot(int slot, ItemStack.Builder builder) { + components.put(slot, ViewComponent.staticItem(slot, builder)); + } + + public void filler(Collection slots, ItemStack.Builder builder) { slots.forEach(s -> - components.put(s, GuiComponent.staticItem(s, item)) + components.put(s, ViewComponent.staticItem(s, builder)) ); } - public void filler(Collection slots, BiFunction itemSupplier) { + public void filler(Collection slots, BiFunction itemSupplier) { slots.forEach(s -> - components.put(s, new GuiComponent<>(s, itemSupplier, (_, _) -> {})) + components.put(s, new ViewComponent<>(s, itemSupplier, (_, _) -> {})) ); } - public Map> components() { - return components; + public void filler(ItemStack.Builder builder) { + IntStream.range(0, inventoryType.getSize()).forEach(s -> + components.put(s, ViewComponent.staticItem(s, builder)) + ); } + } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java index 86a9a2fff..3e8d6c69f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java @@ -11,12 +11,13 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.timer.TaskSchedule; import net.swofty.type.generic.gui.v2.context.ClickContext; -import net.swofty.type.generic.gui.v2.context.GuiContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; import java.time.Duration; import java.util.Objects; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.UnaryOperator; public final class GuiSession { @@ -28,9 +29,11 @@ public final class GuiSession { @Getter @Accessors(fluent = true) private final Inventory inventory; - private final GuiContext context; + private final ViewContext context; private final EventNode eventNode; + @Getter + @Accessors(fluent = true) private S state; private S previousState; private GuiLayout cachedLayout; @@ -43,7 +46,7 @@ private GuiSession(View view, HypixelPlayer player, S initialState) { this.player = player; this.state = initialState; this.inventory = new Inventory(view.size(), ""); - this.context = new GuiContext(player, inventory, this); + this.context = new ViewContext(player, inventory, this); this.eventNode = EventNode.type("gui-" + System.identityHashCode(this), EventFilter.INVENTORY); wireEvents(); @@ -66,7 +69,7 @@ private void onClickEvent(InventoryPreClickEvent event) { if (event.getInventory() != inventory || closed) return; event.setCancelled(true); - GuiComponent component = cachedLayout.components().get(event.getSlot()); + ViewComponent component = cachedLayout.components().get(event.getSlot()); if (component == null) return; ClickContext click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); @@ -81,7 +84,7 @@ private void onCloseEvent(InventoryCloseEvent event) { public void render() { if (closed) return; - cachedLayout = new GuiLayout<>(); + cachedLayout = new GuiLayout<>(view.size()); view.layout(cachedLayout, state, context); if (!Objects.equals(state, previousState)) { @@ -90,17 +93,13 @@ public void render() { } cachedLayout.components().forEach((slot, component) -> { - var item = component.render().apply(state, context); + var item = component.render().apply(state, context).build(); if (!inventory.getItemStack(slot).equals(item)) { inventory.setItemStack(slot, item); } }); } - public S state() { - return state; - } - public void setState(S newState) { if (Objects.equals(state, newState)) return; this.state = newState; @@ -111,6 +110,11 @@ public void update(UnaryOperator transform) { setState(transform.apply(state)); } + @SuppressWarnings("unchecked") + public void updateUnchecked(Function transform) { + setState(((Function) transform).apply(state)); + } + public GuiSession onClose(Consumer handler) { this.onCloseHandler = handler; return this; diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java index e49172a63..b671828e5 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java @@ -2,7 +2,7 @@ import net.minestom.server.item.ItemStack; import net.swofty.type.generic.gui.v2.context.ClickContext; -import net.swofty.type.generic.gui.v2.context.GuiContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import java.util.List; import java.util.function.BiFunction; @@ -26,7 +26,7 @@ public static void items( GuiLayout layout, List slots, List items, - BiFunction renderer, + BiFunction renderer, ClickHandler onClick ) { for (int i = 0; i < slots.size(); i++) { @@ -37,14 +37,14 @@ public static void items( layout.slot(slot, (_, _) -> renderer.apply(item, index), (click, ctx) -> onClick.handle(click, ctx, item, index)); } else { - layout.slot(slot, (_, _) -> ItemStack.AIR); + layout.slot(slot, (_, _) -> ItemStack.AIR.builder()); } } } @FunctionalInterface public interface ClickHandler { - void handle(ClickContext click, GuiContext ctx, T item, int index); + void handle(ClickContext click, ViewContext ctx, T item, int index); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java index 758d520a3..d58f39e00 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java @@ -2,10 +2,10 @@ import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; -import net.swofty.type.generic.gui.v2.context.GuiContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; public interface View { InventoryType size(); - Component title(S state, GuiContext ctx); - void layout(GuiLayout layout, S state, GuiContext ctx); + Component title(S state, ViewContext ctx); + void layout(GuiLayout layout, S state, ViewContext ctx); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java new file mode 100644 index 000000000..b4ac7c82a --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java @@ -0,0 +1,26 @@ +package net.swofty.type.generic.gui.v2; + +import net.minestom.server.item.ItemStack; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public record ViewComponent( + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick +) { + public static ViewComponent staticItem(int slot, ItemStack.Builder item) { + return new ViewComponent<>(slot, (_, _) -> item, (_, _) -> {}); + } + + public static ViewComponent clickable( + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick + ) { + return new ViewComponent<>(slot, render, onClick); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/GuiContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java similarity index 93% rename from type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/GuiContext.java rename to type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java index e3c68d55f..99cc67b71 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/GuiContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java @@ -4,7 +4,7 @@ import net.swofty.type.generic.gui.v2.GuiSession; import net.swofty.type.generic.user.HypixelPlayer; -public record GuiContext( +public record ViewContext( HypixelPlayer player, Inventory inventory, GuiSession session diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java index 7c4686be2..3abbb715e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java @@ -1,3 +1,3 @@ package net.swofty.type.generic.gui.v2.event; -public non-sealed interface GUIClickEvent extends GuiEvent { } +public non-sealed interface GUIClickEvent extends GUIEvent { } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java index 9453c1554..1dc9e20de 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java @@ -1,4 +1,4 @@ package net.swofty.type.generic.gui.v2.event; -public non-sealed interface GUICloseEvent extends GuiEvent { +public non-sealed interface GUICloseEvent extends GUIEvent { } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GuiEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIEvent.java similarity index 78% rename from type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GuiEvent.java rename to type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIEvent.java index d87b374f7..ef5a1cd0b 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GuiEvent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIEvent.java @@ -1,4 +1,4 @@ package net.swofty.type.generic.gui.v2.event; -public sealed interface GuiEvent +public sealed interface GUIEvent permits GUIClickEvent, GUICloseEvent, GUIOpenEvent, GUIRefreshEvent {} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java index 7ceb0919a..7deb229b0 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java @@ -1,4 +1,4 @@ package net.swofty.type.generic.gui.v2.event; -public non-sealed interface GUIOpenEvent extends GuiEvent {} +public non-sealed interface GUIOpenEvent extends GUIEvent {} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java index 08f748d38..e5ba056bb 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java @@ -1,4 +1,4 @@ package net.swofty.type.generic.gui.v2.event; -public non-sealed interface GUIRefreshEvent extends GuiEvent {} +public non-sealed interface GUIRefreshEvent extends GUIEvent {} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java index 885dbca69..3999c450f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java @@ -1,13 +1,11 @@ package net.swofty.type.generic.gui.v2.test; import net.kyori.adventure.text.Component; -import net.minestom.server.component.DataComponents; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.v2.*; -import net.swofty.type.generic.gui.v2.context.GuiContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; public final class TestStateView implements StatefulView { @@ -27,24 +25,17 @@ public InventoryType size() { } @Override - public Component title(State state, GuiContext ctx) { + public Component title(State state, ViewContext ctx) { return Component.text("Counter: " + state.counter()); } @Override - public void layout(GuiLayout layout, State state, GuiContext ctx) { + public void layout(GuiLayout layout, State state, ViewContext ctx) { layout.filler(Layouts.border(0, 26), Components.FILLER); - - layout.slot(11, (_, _) -> ItemStackCreator.createNamedItemStack(Material.RED_WOOL, "§c-1").build(), - (click, c) -> c.session(State.class).update(State::decrement)); - - layout.slot(13, (s, _) -> ItemStackCreator.createNamedItemStack(Material.PAPER, "§eCounter: " + s.counter()).build()); - - layout.slot(15, (_, _) -> ItemStackCreator.createNamedItemStack(Material.GREEN_WOOL, "§a+1").build(), - (click, c) -> c.session(State.class).update(State::increment)); - + layout.slot(11, ItemStackCreator.createNamedItemStack(Material.RED_WOOL, "§c-1"), State::decrement); + layout.slot(13, (s, _) -> ItemStackCreator.createNamedItemStack(Material.PAPER, "§eCounter: " + s.counter())); + layout.slot(15, ItemStackCreator.createNamedItemStack(Material.GREEN_WOOL, "§a+1"), State::increment); Components.close(layout, 22); } } - From bd203a83ccad70069db81256fe04a31e265c9d8e Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Wed, 7 Jan 2026 21:59:08 +0200 Subject: [PATCH 04/35] feat: temporary DebugViewCommand --- .../command/commands/DebugViewCommand.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java new file mode 100644 index 000000000..7e5200216 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java @@ -0,0 +1,18 @@ +package net.swofty.type.generic.command.commands; + +import net.swofty.type.generic.command.CommandParameters; +import net.swofty.type.generic.command.HypixelCommand; +import net.swofty.type.generic.gui.v2.test.TestStateView; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.user.categories.Rank; + +@CommandParameters(aliases = "debugview", usage = "/debugview", description = "opens a debug view", permission = Rank.STAFF, allowsConsole = false) +public class DebugViewCommand extends HypixelCommand { + @Override + public void registerUsage(MinestomCommand command) { + command.setDefaultExecutor((commandSender, commands) -> { + HypixelPlayer player = (HypixelPlayer) commandSender; // safe cast + player.openView(new TestStateView()); + }); + } +} From 18a48cd890583ba6db90176ea958d4f23f02ac45 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Wed, 7 Jan 2026 22:07:12 +0200 Subject: [PATCH 05/35] refactor: rename GuiLayout to ViewLayout and same for GuiSession This is great for distinction between GUIEvents and View handling --- .../swofty/type/generic/gui/v2/Components.java | 6 +++--- .../swofty/type/generic/gui/v2/Pagination.java | 2 +- .../net/swofty/type/generic/gui/v2/View.java | 2 +- .../gui/v2/{GuiLayout.java => ViewLayout.java} | 4 ++-- .../gui/v2/{GuiSession.java => ViewSession.java} | 16 ++++++++-------- .../type/generic/gui/v2/context/ViewContext.java | 8 ++++---- .../type/generic/gui/v2/test/TestStateView.java | 2 +- .../swofty/type/generic/user/HypixelPlayer.java | 11 +++++------ 8 files changed, 25 insertions(+), 26 deletions(-) rename type.generic/src/main/java/net/swofty/type/generic/gui/v2/{GuiLayout.java => ViewLayout.java} (96%) rename type.generic/src/main/java/net/swofty/type/generic/gui/v2/{GuiSession.java => ViewSession.java} (89%) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java index d902373b8..425b7cd84 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java @@ -19,18 +19,18 @@ public final class Components { public static final ItemStack.Builder BACK_BUTTON = ItemStack.builder(Material.ARROW) .set(DataComponents.CUSTOM_NAME, Component.text("§aGo Back")); - public static void close(GuiLayout layout, int slot) { + public static void close(ViewLayout layout, int slot) { layout.slot(slot, (_, _) -> CLOSE_BUTTON, (_, ctx) -> ctx.player().closeInventory()); } - public static void back(GuiLayout layout, int slot, View target, Object targetState) { + public static void back(ViewLayout layout, int slot, View target, Object targetState) { layout.slot(slot, (_, _) -> BACK_BUTTON, (_, ctx) -> open(ctx, target, targetState)); } @SuppressWarnings("unchecked") public static void open(ViewContext ctx, View view, Object state) { - GuiSession.open(view, ctx.player(), (T) state); + ViewSession.open(view, ctx.player(), (T) state); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java index b671828e5..464bad373 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java @@ -23,7 +23,7 @@ public static Page paginate(List all, int page, int perPage) { } public static void items( - GuiLayout layout, + ViewLayout layout, List slots, List items, BiFunction renderer, diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java index d58f39e00..644dbf638 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java @@ -7,5 +7,5 @@ public interface View { InventoryType size(); Component title(S state, ViewContext ctx); - void layout(GuiLayout layout, S state, ViewContext ctx); + void layout(ViewLayout layout, S state, ViewContext ctx); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java similarity index 96% rename from type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java rename to type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java index 80434be38..d87728e5a 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiLayout.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java @@ -15,7 +15,7 @@ import java.util.function.Function; import java.util.stream.IntStream; -public final class GuiLayout { +public final class ViewLayout { @Getter @Accessors(fluent = true) @@ -25,7 +25,7 @@ public final class GuiLayout { @Accessors(fluent = true) private final InventoryType inventoryType; - public GuiLayout(InventoryType inventoryType) { + public ViewLayout(InventoryType inventoryType) { this.inventoryType = inventoryType; } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java similarity index 89% rename from type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java rename to type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 3e8d6c69f..5544ebca1 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/GuiSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -20,7 +20,7 @@ import java.util.function.Function; import java.util.function.UnaryOperator; -public final class GuiSession { +public final class ViewSession { private final View view; @Getter @@ -36,12 +36,12 @@ public final class GuiSession { @Accessors(fluent = true) private S state; private S previousState; - private GuiLayout cachedLayout; + private ViewLayout cachedLayout; private Consumer onCloseHandler; @Getter private boolean closed; - private GuiSession(View view, HypixelPlayer player, S initialState) { + private ViewSession(View view, HypixelPlayer player, S initialState) { this.view = view; this.player = player; this.state = initialState; @@ -52,8 +52,8 @@ private GuiSession(View view, HypixelPlayer player, S initialState) { wireEvents(); } - public static GuiSession open(View view, HypixelPlayer player, S initialState) { - GuiSession session = new GuiSession<>(view, player, initialState); + public static ViewSession open(View view, HypixelPlayer player, S initialState) { + ViewSession session = new ViewSession<>(view, player, initialState); session.render(); player.openInventory(session.inventory); return session; @@ -84,7 +84,7 @@ private void onCloseEvent(InventoryCloseEvent event) { public void render() { if (closed) return; - cachedLayout = new GuiLayout<>(view.size()); + cachedLayout = new ViewLayout<>(view.size()); view.layout(cachedLayout, state, context); if (!Objects.equals(state, previousState)) { @@ -115,12 +115,12 @@ public void updateUnchecked(Function transform) { setState(((Function) transform).apply(state)); } - public GuiSession onClose(Consumer handler) { + public ViewSession onClose(Consumer handler) { this.onCloseHandler = handler; return this; } - public GuiSession refreshEvery(Duration interval) { + public ViewSession refreshEvery(Duration interval) { MinecraftServer.getSchedulerManager().submitTask(() -> { if (closed) return TaskSchedule.stop(); render(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java index 99cc67b71..59656d1e1 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java @@ -1,16 +1,16 @@ package net.swofty.type.generic.gui.v2.context; import net.minestom.server.inventory.Inventory; -import net.swofty.type.generic.gui.v2.GuiSession; +import net.swofty.type.generic.gui.v2.ViewSession; import net.swofty.type.generic.user.HypixelPlayer; public record ViewContext( HypixelPlayer player, Inventory inventory, - GuiSession session + ViewSession session ) { @SuppressWarnings("unchecked") - public GuiSession session(Class stateType) { - return (GuiSession) session; + public ViewSession session(Class stateType) { + return (ViewSession) session; } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java index 3999c450f..04ca4df44 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java @@ -30,7 +30,7 @@ public Component title(State state, ViewContext ctx) { } @Override - public void layout(GuiLayout layout, State state, ViewContext ctx) { + public void layout(ViewLayout layout, State state, ViewContext ctx) { layout.filler(Layouts.border(0, 26), Components.FILLER); layout.slot(11, ItemStackCreator.createNamedItemStack(Material.RED_WOOL, "§c-1"), State::decrement); layout.slot(13, (s, _) -> ItemStackCreator.createNamedItemStack(Material.PAPER, "§eCounter: " + s.counter())); diff --git a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java index 0dd35e9e7..794dc9cdb 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java +++ b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java @@ -3,7 +3,6 @@ import lombok.Getter; import lombok.Setter; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minestom.server.entity.Player; import net.minestom.server.entity.PlayerSkin; import net.minestom.server.network.player.GameProfile; @@ -20,7 +19,7 @@ import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.achievement.PlayerAchievementHandler; import net.swofty.type.generic.experience.PlayerExperienceHandler; -import net.swofty.type.generic.gui.v2.GuiSession; +import net.swofty.type.generic.gui.v2.ViewSession; import net.swofty.type.generic.gui.v2.StatefulView; import net.swofty.type.generic.gui.v2.View; import net.swofty.type.generic.quest.PlayerQuestHandler; @@ -83,16 +82,16 @@ public DatapointChatType.ChatType getChatType() { return getDataHandler().get(HypixelDataHandler.Data.CHAT_TYPE, DatapointChatType.class).getValue(); } - public GuiSession openView(View view, S state) { - return GuiSession.open(view, this, state); + public ViewSession openView(View view, S state) { + return ViewSession.open(view, this, state); } - public GuiSession openView(View view) { + public ViewSession openView(View view) { Objects.requireNonNull(view, "View is null"); if (!(view instanceof StatefulView state)) { throw new IllegalArgumentException("View is not a StatefulView"); } - return GuiSession.open(view, this, state.initialState()); + return ViewSession.open(view, this, state.initialState()); } public ProxyPlayer asProxyPlayer() { From 8a94c44deaa2425a086f43912215392f9995bd51 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Thu, 8 Jan 2026 17:52:22 +0200 Subject: [PATCH 06/35] feat: shared & container views --- .../command/commands/DebugViewCommand.java | 37 +++- .../type/generic/gui/v2/Components.java | 110 ++++++++-- .../type/generic/gui/v2/DefaultState.java | 3 + .../type/generic/gui/v2/SharedContext.java | 185 +++++++++++++++++ .../type/generic/gui/v2/SlotBehavior.java | 7 + .../generic/gui/v2/SlotChangeHandler.java | 8 + .../type/generic/gui/v2/StatefulView.java | 2 +- .../type/generic/gui/v2/StatelessView.java | 5 + .../net/swofty/type/generic/gui/v2/View.java | 26 ++- .../type/generic/gui/v2/ViewComponent.java | 54 +++-- .../type/generic/gui/v2/ViewLayout.java | 168 +++++++++------ .../type/generic/gui/v2/ViewSession.java | 192 +++++++++++++++--- .../generic/gui/v2/context/ClickContext.java | 11 +- .../generic/gui/v2/event/GUIClickEvent.java | 3 - .../generic/gui/v2/event/GUICloseEvent.java | 4 - .../type/generic/gui/v2/event/GUIEvent.java | 4 - .../generic/gui/v2/event/GUIOpenEvent.java | 4 - .../generic/gui/v2/event/GUIRefreshEvent.java | 4 - .../gui/v2/test/TestContainerView.java | 72 +++++++ .../generic/gui/v2/test/TestMixedView.java | 125 ++++++++++++ .../generic/gui/v2/test/TestNoStateView.java | 25 +++ .../gui/v2/test/TestSharedContainerView.java | 96 +++++++++ .../gui/v2/test/TestSharedStateView.java | 97 +++++++++ .../type/generic/user/HypixelPlayer.java | 10 +- 24 files changed, 1100 insertions(+), 152 deletions(-) create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/DefaultState.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotBehavior.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotChangeHandler.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatelessView.java delete mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java delete mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java delete mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIEvent.java delete mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java delete mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestNoStateView.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java index 7e5200216..9afc53f8f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java @@ -1,8 +1,9 @@ package net.swofty.type.generic.command.commands; +import net.minestom.server.command.builder.arguments.ArgumentLiteral; import net.swofty.type.generic.command.CommandParameters; import net.swofty.type.generic.command.HypixelCommand; -import net.swofty.type.generic.gui.v2.test.TestStateView; +import net.swofty.type.generic.gui.v2.test.*; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; @@ -14,5 +15,39 @@ public void registerUsage(MinestomCommand command) { HypixelPlayer player = (HypixelPlayer) commandSender; // safe cast player.openView(new TestStateView()); }); + + command.addSyntax(((sender, context) -> { + HypixelPlayer player = (HypixelPlayer) sender; // safe cast + player.openView(new TestContainerView()); + }), new ArgumentLiteral("container")); + + command.addSyntax(((sender, context) -> { + HypixelPlayer player = (HypixelPlayer) sender; // safe cast + player.openView(new TestMixedView()); + }), new ArgumentLiteral("mixedView")); + + // sharedView + command.addSyntax(((sender, context) -> { + HypixelPlayer player = (HypixelPlayer) sender; // safe cast + TestSharedContainerView.open(player, "a", "a"); + }), new ArgumentLiteral("sharedView")); + + // sharedState + command.addSyntax(((sender, context) -> { + HypixelPlayer player = (HypixelPlayer) sender; // safe cast + TestSharedStateView.openNew(player, "b"); + }), new ArgumentLiteral("sharedState")); + + // joinSharedState + command.addSyntax(((sender, context) -> { + HypixelPlayer player = (HypixelPlayer) sender; // safe cast + TestSharedStateView.join(player, "b"); + }), new ArgumentLiteral("joinSharedState")); + + // noState + command.addSyntax(((sender, context) -> { + HypixelPlayer player = (HypixelPlayer) sender; // safe cast + player.openView(new TestNoStateView()); + }), new ArgumentLiteral("noState")); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java index 425b7cd84..f66004672 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java @@ -7,31 +7,103 @@ import net.minestom.server.item.component.TooltipDisplay; import net.swofty.type.generic.gui.v2.context.ViewContext; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; public final class Components { - public static final ItemStack.Builder FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE) - .set(DataComponents.CUSTOM_NAME, Component.text(" ")) - .set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())); - public static final ItemStack.Builder CLOSE_BUTTON = ItemStack.builder(Material.BARRIER) - .set(DataComponents.CUSTOM_NAME, Component.text("§cClose")); - public static final ItemStack.Builder BACK_BUTTON = ItemStack.builder(Material.ARROW) - .set(DataComponents.CUSTOM_NAME, Component.text("§aGo Back")); + public static final ItemStack.Builder FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE) + .set(DataComponents.CUSTOM_NAME, Component.text(" ")) + .set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())); + public static final ItemStack.Builder CLOSE_BUTTON = ItemStack.builder(Material.BARRIER) + .set(DataComponents.CUSTOM_NAME, Component.text("§cClose")); + public static final ItemStack.Builder BACK_BUTTON = ItemStack.builder(Material.ARROW) + .set(DataComponents.CUSTOM_NAME, Component.text("§aGo Back")); - public static void close(ViewLayout layout, int slot) { - layout.slot(slot, (_, _) -> CLOSE_BUTTON, (_, ctx) -> ctx.player().closeInventory()); - } + public static void fill(ViewLayout layout) { + layout.filler(FILLER); + } - public static void back(ViewLayout layout, int slot, View target, Object targetState) { - layout.slot(slot, (_, _) -> BACK_BUTTON, - (_, ctx) -> open(ctx, target, targetState)); - } + public static void close(ViewLayout layout, int slot) { + layout.slot(slot, (s, c) -> CLOSE_BUTTON, (click, ctx) -> ctx.player().closeInventory()); + } - @SuppressWarnings("unchecked") - public static void open(ViewContext ctx, View view, Object state) { - ViewSession.open(view, ctx.player(), (T) state); - } + public static void back(ViewLayout layout, int slot, View target, Object targetState) { + layout.slot(slot, (s, c) -> BACK_BUTTON, (click, ctx) -> open(ctx, target, targetState)); + } -} + @SuppressWarnings("unchecked") + public static void open(ViewContext ctx, View view, Object state) { + ViewSession.open(view, ctx.player(), (T) state); + } + + public static void editableSlot(ViewLayout layout, int slot, Function itemGetter, SlotChangeHandler onChange) { + layout.editable(slot, (s, c) -> itemGetter.apply(s).builder(), onChange); + } + + public static void editableSlotFromMap(ViewLayout layout, int slot, Function> mapGetter, SlotChangeHandler onChange) { + layout.editable(slot, (s, c) -> mapGetter.apply(s).getOrDefault(slot, ItemStack.AIR).builder(), onChange); + } + + public static void editableGrid(ViewLayout layout, List slots, Function> itemsGetter, SlotChangeHandler onChange) { + for (int i = 0; i < slots.size(); i++) { + int slot = slots.get(i); + int index = i; + layout.editable(slot, (s, c) -> { + List items = itemsGetter.apply(s); + return index < items.size() ? items.get(index).builder() : ItemStack.AIR.builder(); + }, onChange); + } + } + + public static void editableGridFromMap(ViewLayout layout, Collection slots, Function> mapGetter, SlotChangeHandler onChange) { + for (int slot : slots) { + layout.editable(slot, (s, c) -> mapGetter.apply(s).getOrDefault(slot, ItemStack.AIR).builder(), onChange); + } + } + public static void containerGrid(ViewLayout layout, int startSlot, int endSlot, SlotChangeHandler onChange) { + layout.editableGrid(startSlot, endSlot, onChange); + } + + public static void sharedContainerGrid(ViewLayout layout, int startSlot, int endSlot) { + List slots = Layouts.rectangle(startSlot, endSlot); + layout.editableSlots(slots); + } + + public static void prevPage(ViewLayout layout, int slot, Function currentPageGetter, BiFunction pageUpdater) { + layout.slot(slot, (s, c) -> { + int page = currentPageGetter.apply(s); + if (page > 0) { + return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§ePrevious Page")); + } + return FILLER; + }, (click, ctx) -> { + int page = currentPageGetter.apply(click.state()); + if (page > 0) { + ctx.session(Object.class).updateUnchecked(state -> pageUpdater.apply((S) state, page - 1)); + } + }); + } + + public static void nextPage(ViewLayout layout, int slot, Function currentPageGetter, Function totalPagesGetter, BiFunction pageUpdater) { + layout.slot(slot, (s, c) -> { + int page = currentPageGetter.apply(s); + int total = totalPagesGetter.apply(s); + if (page < total - 1) { + return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§eNext Page")); + } + return FILLER; + }, (click, ctx) -> { + int page = currentPageGetter.apply(click.state()); + int total = totalPagesGetter.apply(click.state()); + if (page < total - 1) { + ctx.session(Object.class).updateUnchecked(state -> pageUpdater.apply((S) state, page + 1)); + } + }); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/DefaultState.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/DefaultState.java new file mode 100644 index 000000000..4a81b4575 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/DefaultState.java @@ -0,0 +1,3 @@ +package net.swofty.type.generic.gui.v2; + +public record DefaultState() {} \ No newline at end of file diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java new file mode 100644 index 000000000..0c7dc253e --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java @@ -0,0 +1,185 @@ +package net.swofty.type.generic.gui.v2; + +import lombok.Getter; +import lombok.experimental.Accessors; +import net.minestom.server.item.ItemStack; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.function.Consumer; + +@Getter +@Accessors(fluent = true) +public final class SharedContext { + + private static final Map> CONTEXTS = new ConcurrentHashMap<>(); + + private final String id; + private volatile S state; + private final Map slotItems; + private final Set> sessions; + private final List>> persistenceHandlers; + private final List> slotChangeListeners; + private PersistenceMode persistenceMode; + + private SharedContext(String id, S initialState) { + this.id = id; + this.state = initialState; + this.slotItems = new ConcurrentHashMap<>(); + this.sessions = new CopyOnWriteArraySet<>(); + this.persistenceHandlers = new CopyOnWriteArrayList<>(); + this.slotChangeListeners = new CopyOnWriteArrayList<>(); + this.persistenceMode = PersistenceMode.ON_CLOSE; + } + + @SuppressWarnings("unchecked") + public static SharedContext create(String id, S initialState) { + return (SharedContext) CONTEXTS.computeIfAbsent(id, k -> new SharedContext<>(id, initialState)); + } + + @SuppressWarnings("unchecked") + public static Optional> get(String id) { + return Optional.ofNullable((SharedContext) CONTEXTS.get(id)); + } + + public static void remove(String id) { + SharedContext ctx = CONTEXTS.remove(id); + if (ctx != null) ctx.closeAll(); + } + + public static boolean exists(String id) { + return CONTEXTS.containsKey(id); + } + + public void setState(S newState) { + this.state = newState; + broadcast(); + if (persistenceMode == PersistenceMode.IMMEDIATE) persist(); + } + + public ItemStack getSlotItem(int slot) { + return slotItems.getOrDefault(slot, ItemStack.AIR); + } + + public void setSlotItem(int slot, ItemStack item) { + ItemStack oldItem = slotItems.put(slot, item); + if (oldItem == null) oldItem = ItemStack.AIR; + + SlotChange change = new SlotChange(slot, oldItem, item); + slotChangeListeners.forEach(l -> l.accept(change)); + + for (ViewSession session : sessions) { + if (!session.isClosed()) { + session.inventory().setItemStack(slot, item); + } + } + + broadcastRender(); + if (persistenceMode == PersistenceMode.IMMEDIATE) persist(); + } + + public Map getAllSlotItems() { + return new HashMap<>(slotItems); + } + + public void setSlotItems(Map items) { + items.forEach(this::setSlotItem); + } + + public void clearSlotItems() { + Set slots = new HashSet<>(slotItems.keySet()); + slotItems.clear(); + for (int slot : slots) { + for (ViewSession session : sessions) { + if (!session.isClosed()) { + session.inventory().setItemStack(slot, ItemStack.AIR); + } + } + } + broadcastRender(); + } + + void registerSession(ViewSession session) { + sessions.add(session); + slotItems.forEach((slot, item) -> session.inventory().setItemStack(slot, item)); + broadcastRender(); + } + + void unregisterSession(ViewSession session) { + sessions.remove(session); + if (sessions.isEmpty()) { + if (persistenceMode == PersistenceMode.ON_CLOSE) persist(); + CONTEXTS.remove(id); + } else { + broadcastRender(); + } + } + + public void broadcast() { + for (ViewSession session : sessions) { + if (!session.isClosed()) { + session.setStateFromShared(state); + } + } + } + + public void broadcastRender() { + for (ViewSession session : sessions) { + if (!session.isClosed()) { + session.renderFromShared(); + } + } + } + + public SharedContext onPersist(Consumer> handler) { + persistenceHandlers.add(handler); + return this; + } + + public SharedContext onSlotChange(Consumer listener) { + slotChangeListeners.add(listener); + return this; + } + + public SharedContext persistenceMode(PersistenceMode mode) { + this.persistenceMode = mode; + return this; + } + + public void persist() { + persistenceHandlers.forEach(h -> h.accept(this)); + } + + public void closeAll() { + for (ViewSession session : new ArrayList<>(sessions)) { + session.close(ViewSession.CloseReason.SERVER_EXITED); + } + } + + public int sessionCount() { + return sessions.size(); + } + + public Set viewers() { + Set viewers = new HashSet<>(); + for (ViewSession session : sessions) { + if (!session.isClosed()) viewers.add(session.player()); + } + return viewers; + } + + public void broadcastMessage(String message) { + viewers().forEach(p -> p.sendMessage(message)); + } + + public record SlotChange(int slot, ItemStack oldItem, ItemStack newItem) {} + + public enum PersistenceMode { + IMMEDIATE, + ON_CLOSE, + MANUAL + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotBehavior.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotBehavior.java new file mode 100644 index 000000000..0a900e990 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotBehavior.java @@ -0,0 +1,7 @@ +package net.swofty.type.generic.gui.v2; + +public enum SlotBehavior { + UI, + EDITABLE, + NO_RENDER +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotChangeHandler.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotChangeHandler.java new file mode 100644 index 000000000..2e5139712 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotChangeHandler.java @@ -0,0 +1,8 @@ +package net.swofty.type.generic.gui.v2; + +import net.minestom.server.item.ItemStack; + +@FunctionalInterface +public interface SlotChangeHandler { + void onChange(int slot, ItemStack oldItem, ItemStack newItem, S state); +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java index c40a215dd..110f12841 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java @@ -1,5 +1,5 @@ package net.swofty.type.generic.gui.v2; public interface StatefulView extends View { - S initialState(); + S initialState(); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatelessView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatelessView.java new file mode 100644 index 000000000..cdffe6b12 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatelessView.java @@ -0,0 +1,5 @@ +package net.swofty.type.generic.gui.v2; + +public abstract class StatelessView implements View { + +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java index 644dbf638..87baf52d4 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java @@ -2,10 +2,30 @@ import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; +import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; public interface View { - InventoryType size(); - Component title(S state, ViewContext ctx); - void layout(ViewLayout layout, S state, ViewContext ctx); + InventoryType size(); + + Component title(S state, ViewContext ctx); + + void layout(ViewLayout layout, S state, ViewContext ctx); + + default void onOpen(S state, ViewContext ctx) { + } + + default void onClose(S state, ViewContext ctx, ViewSession.CloseReason reason) { + } + + default boolean onClick(ClickContext click, ViewContext ctx) { + return false; + } + + default void onRefresh(S state, ViewContext ctx) { + } + + default boolean onBottomClick(ClickContext click, ViewContext ctx) { + return false; + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java index b4ac7c82a..9e7e67efe 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java @@ -8,19 +8,45 @@ import java.util.function.BiFunction; public record ViewComponent( - int slot, - BiFunction render, - BiConsumer, ViewContext> onClick + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick, + SlotBehavior behavior, + SlotChangeHandler changeHandler ) { - public static ViewComponent staticItem(int slot, ItemStack.Builder item) { - return new ViewComponent<>(slot, (_, _) -> item, (_, _) -> {}); - } - - public static ViewComponent clickable( - int slot, - BiFunction render, - BiConsumer, ViewContext> onClick - ) { - return new ViewComponent<>(slot, render, onClick); - } + public ViewComponent(int slot, BiFunction render, + BiConsumer, ViewContext> onClick) { + this(slot, render, onClick, SlotBehavior.UI, null); + } + + public static ViewComponent staticItem(int slot, ItemStack.Builder item) { + return new ViewComponent<>(slot, (_, _) -> item, (_, _) -> { + }, SlotBehavior.UI, null); + } + + public static ViewComponent clickable( + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick + ) { + return new ViewComponent<>(slot, render, onClick, SlotBehavior.UI, null); + } + + public static ViewComponent editable( + int slot, + BiFunction initialRender, + SlotChangeHandler changeHandler + ) { + return new ViewComponent<>(slot, initialRender, (_, _) -> { + }, SlotBehavior.EDITABLE, changeHandler); + } + + public static ViewComponent editable(int slot, ItemStack.Builder initialItem, SlotChangeHandler changeHandler) { + return new ViewComponent<>(slot, (_, _) -> initialItem, (_, _) -> { + }, SlotBehavior.EDITABLE, changeHandler); + } + + public static ViewComponent editable(int slot, SlotChangeHandler changeHandler) { + return editable(slot, ItemStack.AIR.builder(), changeHandler); + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java index d87728e5a..0ec06635f 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java @@ -1,15 +1,14 @@ package net.swofty.type.generic.gui.v2; import lombok.Getter; +import lombok.Setter; import lombok.experimental.Accessors; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; @@ -17,59 +16,114 @@ public final class ViewLayout { - @Getter - @Accessors(fluent = true) - private final Map> components = new HashMap<>(); - - @Getter - @Accessors(fluent = true) - private final InventoryType inventoryType; - - public ViewLayout(InventoryType inventoryType) { - this.inventoryType = inventoryType; - } - - public void slot( - int slot, - BiFunction render, - BiConsumer, ViewContext> onClick - ) { - components.put(slot, new ViewComponent<>(slot, render, onClick)); - } - - public void slot(int slot, BiFunction render) { - slot(slot, render, (_, _) -> {}); - } - - public void slot(int slot, ItemStack.Builder builder, BiConsumer, ViewContext> onClick) { - components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, onClick)); - } - - public void slot(int slot, ItemStack.Builder builder, Function stateUpdater) { - components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, - (_, ctx) -> ctx.session(Object.class).updateUnchecked(stateUpdater))); - } - - public void slot(int slot, ItemStack.Builder builder) { - components.put(slot, ViewComponent.staticItem(slot, builder)); - } - - public void filler(Collection slots, ItemStack.Builder builder) { - slots.forEach(s -> - components.put(s, ViewComponent.staticItem(s, builder)) - ); - } - - public void filler(Collection slots, BiFunction itemSupplier) { - slots.forEach(s -> - components.put(s, new ViewComponent<>(s, itemSupplier, (_, _) -> {})) - ); - } - - public void filler(ItemStack.Builder builder) { - IntStream.range(0, inventoryType.getSize()).forEach(s -> - components.put(s, ViewComponent.staticItem(s, builder)) - ); - } + @Getter + @Accessors(fluent = true) + private final Map> components = new HashMap<>(); + @Getter + @Accessors(fluent = true) + private final InventoryType inventoryType; + + @Getter + @Setter + @Accessors(fluent = true) + private boolean allowHotkey = false; + + public ViewLayout(InventoryType inventoryType) { + this.inventoryType = inventoryType; + } + + public void slot( + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick + ) { + components.put(slot, new ViewComponent<>(slot, render, onClick)); + } + + public void slot(int slot, BiFunction render) { + slot(slot, render, (_, _) -> { + }); + } + + public void slot(int slot, ItemStack.Builder builder, BiConsumer, ViewContext> onClick) { + components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, onClick)); + } + + public void slot(int slot, ItemStack.Builder builder, Function stateUpdater) { + components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, + (_, ctx) -> ctx.session(Object.class).updateUnchecked(stateUpdater))); + } + + public void slot(int slot, ItemStack.Builder builder) { + components.put(slot, ViewComponent.staticItem(slot, builder)); + } + + public void editable(int slot, BiFunction initialRender, + SlotChangeHandler onChange) { + components.put(slot, ViewComponent.editable(slot, initialRender, onChange)); + } + + public void editable(int slot, ItemStack.Builder initialItem, SlotChangeHandler onChange) { + components.put(slot, ViewComponent.editable(slot, initialItem, onChange)); + } + + public void editable(int slot, SlotChangeHandler onChange) { + components.put(slot, ViewComponent.editable(slot, onChange)); + } + + public void editable(int slot) { + components.put(slot, ViewComponent.editable(slot, (s, o, n, st) -> { + })); + } + + public void editableSlots(Collection slots, SlotChangeHandler onChange) { + slots.forEach(slot -> editable(slot, onChange)); + } + + public void editableSlots(Collection slots) { + slots.forEach(this::editable); + } + + public void editableGrid(int startSlot, int endSlot, SlotChangeHandler onChange) { + editableSlots(Layouts.rectangle(startSlot, endSlot), onChange); + } + + public void filler(Collection slots, ItemStack.Builder builder) { + slots.forEach(s -> + components.put(s, ViewComponent.staticItem(s, builder)) + ); + } + + public void filler(Collection slots, BiFunction itemSupplier) { + slots.forEach(s -> + components.put(s, new ViewComponent<>(s, itemSupplier, (_, _) -> { + })) + ); + } + + public void filler(ItemStack.Builder builder) { + IntStream.range(0, inventoryType.getSize()).forEach(s -> + components.put(s, ViewComponent.staticItem(s, builder)) + ); + } + + public SlotBehavior getBehavior(int slot) { + ViewComponent component = components.get(slot); + return component != null ? component.behavior() : SlotBehavior.NO_RENDER; + } + + public boolean isEditable(int slot) { + return getBehavior(slot) == SlotBehavior.EDITABLE; + } + + public Set editableSlots() { + Set editable = new HashSet<>(); + components.forEach((slot, component) -> { + if (component.behavior() == SlotBehavior.EDITABLE) { + editable.add(slot); + } + }); + return editable; + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 5544ebca1..49fbd21ce 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -5,17 +5,24 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.event.EventFilter; import net.minestom.server.event.EventNode; +import net.minestom.server.event.inventory.InventoryClickEvent; import net.minestom.server.event.inventory.InventoryCloseEvent; import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.event.trait.InventoryEvent; import net.minestom.server.inventory.Inventory; +import net.minestom.server.inventory.PlayerInventory; +import net.minestom.server.item.ItemStack; +import net.minestom.server.event.inventory.InventoryOpenEvent; import net.minestom.server.timer.TaskSchedule; import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; import java.time.Duration; -import java.util.Objects; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -23,11 +30,11 @@ public final class ViewSession { private final View view; - @Getter - @Accessors(fluent = true) + @Getter + @Accessors(fluent = true) private final HypixelPlayer player; - @Getter - @Accessors(fluent = true) + @Getter + @Accessors(fluent = true) private final Inventory inventory; private final ViewContext context; private final EventNode eventNode; @@ -35,47 +42,140 @@ public final class ViewSession { @Getter @Accessors(fluent = true) private S state; - private S previousState; private ViewLayout cachedLayout; private Consumer onCloseHandler; @Getter - private boolean closed; + private boolean closed; - private ViewSession(View view, HypixelPlayer player, S initialState) { + @Getter + @Accessors(fluent = true) + private final SharedContext sharedContext; + private final Map trackedSlotItems = new HashMap<>(); + private final Set recentlyModifiedSlots = new HashSet<>(); + + private ViewSession(View view, HypixelPlayer player, S initialState, SharedContext sharedContext) { this.view = view; this.player = player; - this.state = initialState; + this.state = sharedContext != null ? sharedContext.state() : initialState; + this.sharedContext = sharedContext; this.inventory = new Inventory(view.size(), ""); this.context = new ViewContext(player, inventory, this); this.eventNode = EventNode.type("gui-" + System.identityHashCode(this), EventFilter.INVENTORY); wireEvents(); + + if (sharedContext != null) { + sharedContext.registerSession(this); + } } public static ViewSession open(View view, HypixelPlayer player, S initialState) { - ViewSession session = new ViewSession<>(view, player, initialState); + ViewSession session = new ViewSession<>(view, player, initialState, null); session.render(); player.openInventory(session.inventory); return session; } + public static ViewSession openShared(View view, HypixelPlayer player, SharedContext sharedContext) { + ViewSession session = new ViewSession<>(view, player, sharedContext.state(), sharedContext); + session.render(); + player.openInventory(session.inventory); + return session; + } + + public static ViewSession openShared(View view, HypixelPlayer player, String contextId, S initialState) { + SharedContext ctx = SharedContext.create(contextId, initialState); + return openShared(view, player, ctx); + } + + public static ViewSession joinShared(View view, HypixelPlayer player, String contextId) { + return SharedContext.get(contextId) + .map(ctx -> openShared(view, player, ctx)) + .orElseThrow(() -> new IllegalArgumentException("Shared context not found: " + contextId)); + } + private void wireEvents() { - eventNode.addListener(InventoryPreClickEvent.class, this::onClickEvent); + eventNode.addListener(InventoryPreClickEvent.class, this::onPreClickEvent); + eventNode.addListener(InventoryClickEvent.class, this::onPostClickEvent); eventNode.addListener(InventoryCloseEvent.class, this::onCloseEvent); + eventNode.addListener(InventoryOpenEvent.class, this::onOpenEvent); MinecraftServer.getGlobalEventHandler().addChild(eventNode); } - private void onClickEvent(InventoryPreClickEvent event) { + private void onOpenEvent(InventoryOpenEvent event) { if (event.getInventory() != inventory || closed) return; - event.setCancelled(true); + view.onOpen(state, context); + } + + private void onPreClickEvent(InventoryPreClickEvent event) { + if (event.getInventory() instanceof PlayerInventory) { + // if the current open inventory is this inventory + if (player.getOpenInventory() == inventory) { + ClickContext click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); + if (!view.onBottomClick(click, context)) { + event.setCancelled(true); + } + } + return; + } + if (event.getInventory() != inventory || closed) return; + + int slot = event.getSlot(); + SlotBehavior behavior = cachedLayout != null ? cachedLayout.getBehavior(slot) : SlotBehavior.UI; + + if (behavior == SlotBehavior.EDITABLE) { + trackedSlotItems.put(slot, inventory.getItemStack(slot)); + return; + } - ViewComponent component = cachedLayout.components().get(event.getSlot()); - if (component == null) return; + event.setCancelled(true); + ViewComponent component = cachedLayout != null ? cachedLayout.components().get(slot) : null; + if (component == null) { + ClickContext click = new ClickContext<>(slot, event.getClick(), player, state); + view.onClick(click, context); + return; + } - ClickContext click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); + ClickContext click = new ClickContext<>(slot, event.getClick(), player, state); component.onClick().accept(click, context); } + private void onPostClickEvent(InventoryClickEvent event) { + if (event.getInventory() != inventory || closed) return; + + int slot = event.getSlot(); + if (cachedLayout == null || !cachedLayout.isEditable(slot)) return; + + MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { + if (closed) return; + + ItemStack oldItem = trackedSlotItems.getOrDefault(slot, ItemStack.AIR); + ItemStack newItem = inventory.getItemStack(slot); + + if (!oldItem.equals(newItem)) { + handleSlotChange(slot, oldItem, newItem); + } + }); + } + + private void handleSlotChange(int slot, ItemStack oldItem, ItemStack newItem) { + trackedSlotItems.put(slot, newItem); + recentlyModifiedSlots.add(slot); + + ViewComponent component = cachedLayout.components().get(slot); + if (component != null && component.changeHandler() != null) { + component.changeHandler().onChange(slot, oldItem, newItem, state); + } + + if (sharedContext != null) { + sharedContext.setSlotItem(slot, newItem); + } else { + render(); + } + + recentlyModifiedSlots.remove(slot); + } + private void onCloseEvent(InventoryCloseEvent event) { if (event.getInventory() != inventory) return; close(CloseReason.PLAYER_EXITED); @@ -86,23 +186,54 @@ public void render() { cachedLayout = new ViewLayout<>(view.size()); view.layout(cachedLayout, state, context); - - if (!Objects.equals(state, previousState)) { - inventory.setTitle(view.title(state, context)); - previousState = state; - } + inventory.setTitle(view.title(state, context)); cachedLayout.components().forEach((slot, component) -> { + if (component.behavior() == SlotBehavior.EDITABLE) { + if (sharedContext != null) { + ItemStack contextItem = sharedContext.getSlotItem(slot); + if (!inventory.getItemStack(slot).equals(contextItem)) { + inventory.setItemStack(slot, contextItem); + } + trackedSlotItems.put(slot, contextItem); + return; + } else if (!recentlyModifiedSlots.contains(slot)) { + ItemStack currentItem = inventory.getItemStack(slot); + trackedSlotItems.put(slot, currentItem); + } + return; + } + var item = component.render().apply(state, context).build(); if (!inventory.getItemStack(slot).equals(item)) { inventory.setItemStack(slot, item); } }); + + view.onRefresh(state, context); } public void setState(S newState) { - if (Objects.equals(state, newState)) return; this.state = newState; + + if (sharedContext != null) { + sharedContext.setState(newState); + } else { + render(); + } + } + + public void setStateQuiet(S newState) { + this.state = newState; + render(); + } + + void setStateFromShared(S newState) { + this.state = newState; + render(); + } + + void renderFromShared() { render(); } @@ -110,6 +241,10 @@ public void update(UnaryOperator transform) { setState(transform.apply(state)); } + public void updateQuiet(UnaryOperator transform) { + setStateQuiet(transform.apply(state)); + } + @SuppressWarnings("unchecked") public void updateUnchecked(Function transform) { setState(((Function) transform).apply(state)); @@ -134,15 +269,22 @@ public void close(CloseReason reason) { closed = true; MinecraftServer.getGlobalEventHandler().removeChild(eventNode); + if (sharedContext != null) { + sharedContext.unregisterSession(this); + } + + view.onClose(state, context, reason); if (onCloseHandler != null) onCloseHandler.accept(reason); if (reason != CloseReason.PLAYER_EXITED) player.closeInventory(); } - public enum CloseReason { + public boolean isShared() { + return sharedContext != null; + } + + public enum CloseReason { PLAYER_EXITED, SERVER_EXITED, REPLACED } } - - diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java index 1edb0a4c8..6c773a94b 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java @@ -8,14 +8,5 @@ public record ClickContext( Click click, HypixelPlayer player, S state -) { - public boolean isLeftClick() { - return click instanceof Click.Left; - } - - public boolean isRightClick() { - return click instanceof Click.Right; - } - -} +) {} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java deleted file mode 100644 index 3abbb715e..000000000 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIClickEvent.java +++ /dev/null @@ -1,3 +0,0 @@ -package net.swofty.type.generic.gui.v2.event; - -public non-sealed interface GUIClickEvent extends GUIEvent { } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java deleted file mode 100644 index 1dc9e20de..000000000 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUICloseEvent.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.swofty.type.generic.gui.v2.event; - -public non-sealed interface GUICloseEvent extends GUIEvent { -} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIEvent.java deleted file mode 100644 index ef5a1cd0b..000000000 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIEvent.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.swofty.type.generic.gui.v2.event; - -public sealed interface GUIEvent - permits GUIClickEvent, GUICloseEvent, GUIOpenEvent, GUIRefreshEvent {} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java deleted file mode 100644 index 7deb229b0..000000000 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIOpenEvent.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.swofty.type.generic.gui.v2.event; - -public non-sealed interface GUIOpenEvent extends GUIEvent {} - diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java deleted file mode 100644 index e5ba056bb..000000000 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/GUIRefreshEvent.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.swofty.type.generic.gui.v2.event; - -public non-sealed interface GUIRefreshEvent extends GUIEvent {} - diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java new file mode 100644 index 000000000..5d51e1396 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java @@ -0,0 +1,72 @@ +package net.swofty.type.generic.gui.v2.test; + +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +import java.util.HashMap; +import java.util.Map; + +public final class TestContainerView implements StatefulView { + + private static final int[] STORAGE_SLOTS = {10, 11, 12, 13, 14, 15, 16}; + + public record State(Map items) { + public State withItem(int slot, ItemStack item) { + Map newItems = new HashMap<>(items); + if (item.isAir()) { + newItems.remove(slot); + } else { + newItems.put(slot, item); + } + return new State(newItems); + } + + public int itemCount() { + return (int) items.values().stream().filter(i -> !i.isAir()).count(); + } + } + + @Override + public State initialState() { + return new State(new HashMap<>()); + } + + @Override + public InventoryType size() { + return InventoryType.CHEST_3_ROW; + } + + @Override + public Component title(State state, ViewContext ctx) { + return Component.text("§8Personal Storage §7(§e" + state.itemCount() + " items§7)"); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + layout.filler(Layouts.border(0, 26), Components.FILLER); + + for (int slot : STORAGE_SLOTS) { + layout.editable(slot, (s, c) -> s.items().getOrDefault(slot, ItemStack.AIR).builder(), + (changedSlot, oldItem, newItem, s) -> + ctx.session(State.class).updateQuiet(current -> current.withItem(changedSlot, newItem)) + ); + } + + layout.slot(4, (s, c) -> ItemStackCreator.getStack( + "§eStorage Info", + Material.CHEST, + 1, + "§7Items stored: §f" + s.itemCount(), + "", + "§7Place or remove items below!" + )); + + Components.close(layout, 22); + layout.allowHotkey(true); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java new file mode 100644 index 000000000..7b3f347e8 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java @@ -0,0 +1,125 @@ +package net.swofty.type.generic.gui.v2.test; + +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class TestMixedView implements StatefulView { + + private static final List INPUT_SLOTS = List.of(10, 11, 12, 19, 20, 21, 28, 29, 30); + private static final int OUTPUT_SLOT = 24; + + public record State(Map inputs) { + public State withInput(int slot, ItemStack item) { + Map newInputs = new HashMap<>(inputs); + if (item.isAir()) { + newInputs.remove(slot); + } else { + newInputs.put(slot, item); + } + return new State(newInputs); + } + + public State clearInputs() { + return new State(new HashMap<>()); + } + + public int inputCount() { + return (int) inputs.values().stream().filter(i -> !i.isAir()).count(); + } + + public boolean hasOutput() { + return inputs.containsKey(20) && !inputs.get(20).isAir(); + } + } + + @Override + public State initialState() { + return new State(new HashMap<>()); + } + + @Override + public InventoryType size() { + return InventoryType.CHEST_5_ROW; + } + + @Override + public Component title(State state, ViewContext ctx) { + return Component.text("§5Crafting Station"); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + layout.filler(Components.FILLER); + + layout.slot(4, ItemStackCreator.getStack( + "§5Crafting Station", + Material.CRAFTING_TABLE, + 1, + "§7Place items in the grid", + "§7to create new items!", + "", + "§7Input items: §e" + state.inputCount() + )); + + for (int slot : INPUT_SLOTS) { + layout.editable(slot, (s, c) -> s.inputs().getOrDefault(slot, ItemStack.AIR).builder(), + (changedSlot, oldItem, newItem, s) -> + ctx.session(State.class).updateQuiet(current -> current.withInput(changedSlot, newItem)) + ); + } + + layout.slot(22, (s, c) -> ItemStackCreator.getStack( + s.hasOutput() ? "§a→ Ready!" : "§7→", + Material.ARROW, + 1, + s.hasOutput() ? "§aClick output to craft!" : "§7Place an item in the center" + )); + + layout.slot(OUTPUT_SLOT, (s, c) -> { + if (s.hasOutput()) { + return ItemStackCreator.getStack("§bCrafted Item", Material.DIAMOND, 1, "§7Click to take!"); + } + return ItemStack.AIR.builder(); + }, (click, context) -> { + State s = click.state(); + if (s.hasOutput()) { + click.player().getInventory().addItemStack(ItemStack.of(Material.DIAMOND, 1)); + click.player().sendMessage("§aYou crafted a Diamond!"); + context.session(State.class).setState(s.clearInputs()); + for (int slot : INPUT_SLOTS) { + context.inventory().setItemStack(slot, ItemStack.AIR); + } + } + }); + + layout.slot(40, (s, c) -> ItemStackCreator.getStack( + "§cClear Grid", + Material.BARRIER, + 1, + "§7Clears all input slots" + ), (click, context) -> { + context.session(State.class).setState(state.clearInputs()); + for (int slot : INPUT_SLOTS) { + context.inventory().setItemStack(slot, ItemStack.AIR); + } + click.player().sendMessage("§cGrid cleared!"); + }); + + Components.close(layout, 44); + layout.allowHotkey(true); + } + + public static void open(HypixelPlayer player) { + ViewSession.open(new TestMixedView(), player, new State(new HashMap<>())); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestNoStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestNoStateView.java new file mode 100644 index 000000000..9b2f6b8ec --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestNoStateView.java @@ -0,0 +1,25 @@ +package net.swofty.type.generic.gui.v2.test; + +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +public class TestNoStateView extends StatelessView { + + @Override + public InventoryType size() { + return InventoryType.CHEST_3_ROW; + } + + @Override + public Component title(DefaultState state, ViewContext ctx) { + return Component.text("Stateless"); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 22); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java new file mode 100644 index 000000000..dc430984c --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java @@ -0,0 +1,96 @@ +package net.swofty.type.generic.gui.v2.test; + +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.inventory.click.Click; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.Map; + +public final class TestSharedContainerView implements View { + + public record State(String teamName) {} + + @Override + public InventoryType size() { + return InventoryType.CHEST_6_ROW; + } + + @Override + public Component title(State state, ViewContext ctx) { + SharedContext shared = ctx.session(State.class).sharedContext(); + int viewers = shared != null ? shared.sessionCount() : 1; + return Component.text("§6" + state.teamName() + " §7(§e" + viewers + " viewing§7)"); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + layout.filler(Components.FILLER); + + layout.slot(4, (s, c) -> { + SharedContext shared = ctx.session(State.class).sharedContext(); + int itemCount = shared != null + ? (int) shared.getAllSlotItems().values().stream().filter(i -> !i.isAir()).count() + : 0; + + return ItemStackCreator.getStack( + "§6" + s.teamName(), + Material.CHEST, + 1, + "§7Shared team storage", + "", + "§7Items stored: §e" + itemCount, + "§7Players viewing: §e" + (shared != null ? shared.sessionCount() : 1) + ); + }); + + Components.sharedContainerGrid(layout, 10, 43); + + layout.slot(49, (s, c) -> ItemStackCreator.getStack( + "§cClear All", + Material.TNT, + 1, + "§7Clears all items from storage", + "", + "§eShift Left Click to confirm!" + ), (click, context) -> { + if (click.click() instanceof Click.LeftShift) { + SharedContext shared = context.session(State.class).sharedContext(); + if (shared != null) { + shared.clearSlotItems(); + shared.broadcastMessage("§c" + click.player().getUsername() + " cleared the team chest!"); + } + } + }); + + Components.close(layout, 53); + layout.allowHotkey(true); + } + + public static ViewSession open(HypixelPlayer player, String teamId, String teamName) { + String contextId = "team-chest-" + teamId; + + if (SharedContext.exists(contextId)) { + return ViewSession.joinShared(new TestSharedContainerView(), player, contextId); + } + + SharedContext ctx = SharedContext.create(contextId, new State(teamName)); + ctx.onPersist(context -> + System.out.println("Persisting team chest " + teamId + " with " + context.getAllSlotItems().size() + " items") + ); + ctx.onSlotChange(change -> + System.out.println("Slot " + change.slot() + " changed: " + change.oldItem().material() + " -> " + change.newItem().material()) + ); + + return ViewSession.openShared(new TestSharedContainerView(), player, ctx); + } + + public static void loadItems(String teamId, Map items) { + SharedContext.get("team-chest-" + teamId).ifPresent(ctx -> ctx.setSlotItems(items)); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java new file mode 100644 index 000000000..2fc67721c --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java @@ -0,0 +1,97 @@ +package net.swofty.type.generic.gui.v2.test; + +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; + +public final class TestSharedStateView implements StatefulView { + + public record State(int counter, String lastModifiedBy) { + public State increment(String playerName) { + return new State(counter + 1, playerName); + } + + public State decrement(String playerName) { + return new State(counter - 1, playerName); + } + + public State reset(String playerName) { + return new State(0, playerName); + } + } + + @Override + public State initialState() { + return new State(0, "None"); + } + + @Override + public InventoryType size() { + return InventoryType.CHEST_3_ROW; + } + + @Override + public Component title(State state, ViewContext ctx) { + return Component.text("§9Shared Counter: §e" + state.counter()); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + layout.filler(Components.FILLER); + + layout.slot(11, (s, c) -> ItemStackCreator.getStack( + "§c-1", + Material.RED_WOOL, + 1, + "§7Click to decrement", + "", + "§7Current: §f" + s.counter() + ), (click, context) -> + context.session(State.class).update(s -> s.decrement(click.player().getUsername())) + ); + + layout.slot(13, (s, c) -> ItemStackCreator.getStack( + "§eCounter: " + s.counter(), + Material.PAPER, + Math.max(1, Math.min(64, Math.abs(s.counter()))), + "§7Last modified by: §f" + s.lastModifiedBy(), + "", + "§7This view is shared!", + "§7All players see the same counter." + )); + + layout.slot(15, (s, c) -> ItemStackCreator.getStack( + "§a+1", + Material.GREEN_WOOL, + 1, + "§7Click to increment", + "", + "§7Current: §f" + s.counter() + ), (click, context) -> + context.session(State.class).update(s -> s.increment(click.player().getUsername())) + ); + + layout.slot(22, (s, c) -> ItemStackCreator.getStack( + "§6Reset", + Material.SUNFLOWER, + 1, + "§7Reset counter to 0" + ), (click, context) -> + context.session(State.class).update(s -> s.reset(click.player().getUsername())) + ); + + Components.close(layout, 26); + } + + public static void openNew(HypixelPlayer player, String contextId) { + ViewSession.openShared(new TestSharedStateView(), player, contextId, new State(0, player.getUsername())); + } + + public static void join(HypixelPlayer player, String contextId) { + ViewSession.joinShared(new TestSharedStateView(), player, contextId); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java index 794dc9cdb..bb2c9716d 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java +++ b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java @@ -19,6 +19,7 @@ import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.achievement.PlayerAchievementHandler; import net.swofty.type.generic.experience.PlayerExperienceHandler; +import net.swofty.type.generic.gui.v2.StatelessView; import net.swofty.type.generic.gui.v2.ViewSession; import net.swofty.type.generic.gui.v2.StatefulView; import net.swofty.type.generic.gui.v2.View; @@ -88,10 +89,13 @@ public ViewSession openView(View view, S state) { public ViewSession openView(View view) { Objects.requireNonNull(view, "View is null"); - if (!(view instanceof StatefulView state)) { - throw new IllegalArgumentException("View is not a StatefulView"); + if (view instanceof StatefulView state) { + return ViewSession.open(view, this, state.initialState()); + } else if (view instanceof StatelessView state) { + return ViewSession.open(view, this, null); + } else { + throw new IllegalArgumentException("View must be either StatefulView or StatelessView"); } - return ViewSession.open(view, this, state.initialState()); } public ProxyPlayer asProxyPlayer() { From 8cdf479a08e71d17e00552c8ccbfc5bd11c93138 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Thu, 8 Jan 2026 17:52:40 +0200 Subject: [PATCH 07/35] feat: migrate GUIClaimReward --- .../swofty/type/hub/npcs/NPCLumberJack.java | 6 +- .../gui/inventories/ClaimRewardView.java | 69 +++++++++++++++ .../gui/inventories/GUIClaimReward.java | 84 ------------------- .../MissionGiveCharlieBirchLogs.java | 6 +- .../birchpark/MissionTalkToCharlieAgain.java | 6 +- .../MissionGiveRyanDarkOakLogs.java | 1 - .../swofty/type/thepark/npcs/NPCGustave.java | 6 +- .../swofty/type/thepark/npcs/NPCKelly.java | 6 +- .../swofty/type/thepark/npcs/NPCMelody.java | 7 +- .../swofty/type/thepark/npcs/NPCMolbert.java | 6 +- .../net/swofty/type/thepark/npcs/NPCRyan.java | 7 +- 11 files changed, 93 insertions(+), 111 deletions(-) create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIClaimReward.java diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCLumberJack.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCLumberJack.java index 2e257ca71..81b4c842a 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCLumberJack.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCLumberJack.java @@ -7,7 +7,7 @@ import net.swofty.type.generic.entity.npc.NPCOption; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.missions.lumber.MissionBreakOaklog; import net.swofty.type.skyblockgeneric.mission.missions.lumber.MissionTalkToLumberjack; @@ -88,9 +88,9 @@ public void onClick(NPCInteractEvent e) { } if (!data.hasCompleted(MissionTalkToLumberjackAgain.class)) { setDialogue(player, "spoke-again").thenRun(() -> { - new GUIClaimReward(ItemType.PROMISING_AXE, () -> { + player.openView(new ClaimRewardView(), new ClaimRewardView.State(ItemType.PROMISING_AXE, () -> { data.endMission(MissionTalkToLumberjackAgain.class); - }).open(player); + })); }); return; } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java new file mode 100644 index 000000000..6a906ffc1 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java @@ -0,0 +1,69 @@ +package net.swofty.type.skyblockgeneric.gui.inventories; + +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.swofty.commons.skyblock.item.ItemType; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.List; + +public class ClaimRewardView implements View { + + public record State(ItemType rewardItem, Runnable onClaim, boolean claimed) { + public State(ItemType rewardItem, Runnable onClaim) { + this(rewardItem, onClaim, false); + } + + public State claim() { + return new State(rewardItem, onClaim, true); + } + } + + @Override + public InventoryType size() { + return InventoryType.CHEST_6_ROW; + } + + @Override + public Component title(State state, ViewContext ctx) { + return Component.text("Claim Reward"); + } + + @Override + public void layout(ViewLayout layout, ClaimRewardView.State state, ViewContext ctx) { + Components.fill(layout); + layout.slot(22, + (_, _) -> ItemStackCreator.appendLore( + new NonPlayerItemUpdater(new SkyBlockItem(state.rewardItem())).getUpdatedItem(), + List.of( + "", + "§eClick to claim!" + ) + ), + (_, viewContext) -> { + SkyBlockPlayer player = (SkyBlockPlayer) viewContext.player(); + viewContext.session(State.class).update(State::claim); + SkyBlockItem item = new SkyBlockItem(state.rewardItem()); + player.addAndUpdateItem(item); + player.sendMessage("§aYou claimed §f" + item.getDisplayName() + "§a!"); + player.closeInventory(); + } + ); + Components.close(layout, 49); + } + + @Override + public void onClose(State state, ViewContext ctx, ViewSession.CloseReason reason) { + if (state.claimed()) return; + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + state.claim(); + player.sendMessage("§aYou claimed §f" + state.rewardItem().getDisplayName() + "§a!"); + player.addAndUpdateItem(state.rewardItem()); + } + +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIClaimReward.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIClaimReward.java deleted file mode 100644 index dbf87edcd..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIClaimReward.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.swofty.type.skyblockgeneric.gui.inventories; - -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; -import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; - -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -public class GUIClaimReward extends HypixelInventoryGUI { - - private final ItemType rewardItem; - private final Runnable onClaim; - private final AtomicBoolean claimed = new AtomicBoolean(false); - - public GUIClaimReward(ItemType rewardItem, Runnable onClaim) { - super("Claim Reward", InventoryType.CHEST_6_ROW); - this.rewardItem = rewardItem; - this.onClaim = onClaim; - } - - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(FILLER_ITEM); - set(new GUIClickableItem(22) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - if (!claimed.compareAndSet(false, true)) { - return; - } - - SkyBlockPlayer player = (SkyBlockPlayer) p; - onClaim.run(); - SkyBlockItem item = new SkyBlockItem(rewardItem); - player.addAndUpdateItem(item); - player.sendMessage("§aYou claimed §f" + item.getDisplayName() + "§a!"); - p.closeInventory(); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.appendLore( - new NonPlayerItemUpdater(new SkyBlockItem(rewardItem)).getUpdatedItem(), - List.of( - "", - "§eClick to claim!" - ) - ); - } - }); - set(GUIClickableItem.getCloseItem(49)); - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - if (!claimed.compareAndSet(false, true)) { - return; // Already claimed - } - - SkyBlockPlayer player = (SkyBlockPlayer) e.getPlayer(); - onClaim.run(); - player.addAndUpdateItem(rewardItem); - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java index f250d9e7c..674c5d249 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionGiveCharlieBirchLogs.java @@ -2,7 +2,7 @@ import net.minestom.server.coordinate.Pos; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; import net.swofty.type.skyblockgeneric.mission.LocationAssociatedMission; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -33,9 +33,9 @@ public Map onStart(SkyBlockPlayer player, MissionData.ActiveMiss @Override public void onEnd(SkyBlockPlayer player, Map customData, MissionData.ActiveMission mission) { player.getMissionData().startMission(MissionClaimTheTrousers.class); - new GUIClaimReward(ItemType.CHARLIE_TROUSERS, () -> { + player.openView(new ClaimRewardView(), new ClaimRewardView.State(ItemType.CHARLIE_TROUSERS, () -> { player.getMissionData().endMission(MissionClaimTheTrousers.class); - }).open(player); + })); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlieAgain.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlieAgain.java index fac3eb988..25242b4cd 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlieAgain.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/birchpark/MissionTalkToCharlieAgain.java @@ -2,7 +2,7 @@ import net.minestom.server.coordinate.Pos; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; import net.swofty.type.skyblockgeneric.mission.LocationAssociatedMission; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.SkyBlockMission; @@ -33,9 +33,9 @@ public Map onStart(SkyBlockPlayer player, MissionData.ActiveMiss @Override public void onEnd(SkyBlockPlayer player, Map customData, MissionData.ActiveMission mission) { - new GUIClaimReward(ItemType.FORAGING_1_TRAVEL_SCROLL, () -> { + player.openView(new ClaimRewardView(), new ClaimRewardView.State(ItemType.FORAGING_1_TRAVEL_SCROLL, () -> { player.getMissionData().startMission(MissionTravelToTheSpruceWoods.class); - }).open(player); + })); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionGiveRyanDarkOakLogs.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionGiveRyanDarkOakLogs.java index f6dc804b5..5b44b77be 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionGiveRyanDarkOakLogs.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/mission/missions/thepark/darkthicket/MissionGiveRyanDarkOakLogs.java @@ -2,7 +2,6 @@ import net.minestom.server.coordinate.Pos; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; import net.swofty.type.skyblockgeneric.mission.LocationAssociatedMission; import net.swofty.type.skyblockgeneric.mission.MissionData; diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCGustave.java b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCGustave.java index ce13492f0..63cd78d08 100644 --- a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCGustave.java +++ b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCGustave.java @@ -7,7 +7,7 @@ import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.missions.thepark.spruce.race.*; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -80,9 +80,9 @@ public void onClick(NPCInteractEvent event) { } if (missionData.isCurrentlyActive(MissionTalkToGustaveAgainAgain.class)) { setDialogue(player, "completed-2").thenRun(() -> { - new GUIClaimReward(ItemType.HUNTER_KNIFE, () -> { + player.openView(new ClaimRewardView(), new ClaimRewardView.State(ItemType.HUNTER_KNIFE, () -> { missionData.endMission(MissionTalkToGustaveAgainAgain.class); - }).open(player); + })); }); return; } diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCKelly.java b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCKelly.java index 2e5cdc6c2..9e1abf5db 100644 --- a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCKelly.java +++ b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCKelly.java @@ -8,7 +8,7 @@ import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.missions.thepark.spruce.MissionCollectSpruceLogs; import net.swofty.type.skyblockgeneric.mission.missions.thepark.spruce.MissionFindKelly; @@ -93,9 +93,9 @@ public void onClick(NPCInteractEvent event) { return; } setDialogue(player, "after-collecting").thenRun(() -> { - new GUIClaimReward(ItemType.KELLY_TSHIRT, () -> { + player.openView(new ClaimRewardView(), new ClaimRewardView.State(ItemType.KELLY_TSHIRT, () -> { data.endMission(MissionGiveKellySpruceLogs.class); - }).open(player); + })); }); return; } diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCMelody.java b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCMelody.java index 263fd97d4..41afb7f0b 100644 --- a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCMelody.java +++ b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCMelody.java @@ -8,9 +8,8 @@ import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; import net.swofty.type.skyblockgeneric.mission.MissionData; -import net.swofty.type.skyblockgeneric.mission.missions.thepark.birchpark.MissionClaimTheTrousers; import net.swofty.type.skyblockgeneric.mission.missions.thepark.savanna.MissionCheckOnMelody; import net.swofty.type.skyblockgeneric.mission.missions.thepark.savanna.MissionCollectAcaciaLogs; import net.swofty.type.skyblockgeneric.mission.missions.thepark.savanna.MissionGiveMelodyAcaciaLogs; @@ -82,9 +81,9 @@ public void onClick(NPCInteractEvent event) { sendNPCMessage(player, "It seems like you don't have enough §aAcacia Logs§f with you. Please come back when you have collected enough!"); return; } - new GUIClaimReward(ItemType.MELODY_SHOES, () -> { + player.openView(new ClaimRewardView(), new ClaimRewardView.State(ItemType.MELODY_SHOES, () -> { player.getMissionData().endMission(MissionGiveMelodyAcaciaLogs.class); - }).open(player); + })); } } diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCMolbert.java b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCMolbert.java index 48219e53a..1c002931d 100644 --- a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCMolbert.java +++ b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCMolbert.java @@ -10,7 +10,7 @@ import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.missions.thepark.jungle.*; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -171,9 +171,9 @@ public void onClick(NPCInteractEvent event) { "I know that you are a mole", (p) -> { setDialogue(player, "option-iknow").thenRun(() -> { - new GUIClaimReward(ItemType.MOLE_HAT, () -> { + player.openView(new ClaimRewardView(), new ClaimRewardView.State(ItemType.MOLE_HAT, () -> { data.endMission(MissionTalkToMolbertFourth.class); - }).open(player); + })); }); } ) diff --git a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCRyan.java b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCRyan.java index d94dca616..4422224c7 100644 --- a/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCRyan.java +++ b/type.thepark/src/main/java/net/swofty/type/thepark/npcs/NPCRyan.java @@ -9,11 +9,10 @@ import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.GUIClaimReward; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.mission.missions.thepark.darkthicket.*; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import org.jspecify.annotations.NonNull; import java.util.HashMap; import java.util.List; @@ -130,9 +129,9 @@ public void onClick(NPCInteractEvent event) { return; } setDialogue(player, "give_logs").thenRun(() -> { - new GUIClaimReward(ItemType.CAMPFIRE_TALISMAN_1, () -> { + player.openView(new ClaimRewardView(), new ClaimRewardView.State(ItemType.CAMPFIRE_TALISMAN_1, () -> { player.getMissionData().endMission(MissionGiveRyanDarkOakLogs.class); - }).open(player); + })); }); return; } From 8c21405e708984c55d381096491767ce77bad86e Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Thu, 8 Jan 2026 18:30:53 +0200 Subject: [PATCH 08/35] feat: add support for String in title --- .../java/net/swofty/type/generic/gui/v2/View.java | 12 +++++++++++- .../net/swofty/type/generic/gui/v2/ViewSession.java | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java index 87baf52d4..6d16ecb72 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java @@ -8,7 +8,17 @@ public interface View { InventoryType size(); - Component title(S state, ViewContext ctx); + Object title(S state, ViewContext ctx); + + default Component getTitle(S state, ViewContext ctx) { + Object title = title(state, ctx); + if (title instanceof Component component) { + return component; + } else if (title instanceof String str) { + return Component.text(str); + } + throw new IllegalStateException("Title must be a Component or String"); + } void layout(ViewLayout layout, S state, ViewContext ctx); diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 49fbd21ce..3fec6c2bf 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -186,7 +186,7 @@ public void render() { cachedLayout = new ViewLayout<>(view.size()); view.layout(cachedLayout, state, context); - inventory.setTitle(view.title(state, context)); + inventory.setTitle(view.getTitle(state, context)); cachedLayout.components().forEach((slot, component) -> { if (component.behavior() == SlotBehavior.EDITABLE) { From 4a55d5738481ba68b9451c489e0991596e713824 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Thu, 8 Jan 2026 19:39:11 +0200 Subject: [PATCH 09/35] feat: port GUIConsumeSoulflow and view changes --- .../net/swofty/type/generic/gui/v2/View.java | 17 +- .../generic/gui/v2/ViewConfiguration.java | 53 ++ .../type/generic/gui/v2/ViewSession.java | 526 +++++++++--------- .../gui/v2/test/TestContainerView.java | 15 +- .../generic/gui/v2/test/TestMixedView.java | 16 +- .../generic/gui/v2/test/TestNoStateView.java | 10 +- .../gui/v2/test/TestSharedContainerView.java | 163 +++--- .../gui/v2/test/TestSharedStateView.java | 9 +- .../generic/gui/v2/test/TestStateView.java | 9 +- .../gui/inventories/ClaimRewardView.java | 9 +- .../gui/inventories/GUIConsumeSoulflow.java | 120 ++-- .../item/components/SoulflowComponent.java | 4 +- 12 files changed, 484 insertions(+), 467 deletions(-) create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewConfiguration.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java index 6d16ecb72..289ed1d05 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java @@ -1,24 +1,11 @@ package net.swofty.type.generic.gui.v2; -import net.kyori.adventure.text.Component; -import net.minestom.server.inventory.InventoryType; import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; public interface View { - InventoryType size(); - - Object title(S state, ViewContext ctx); - - default Component getTitle(S state, ViewContext ctx) { - Object title = title(state, ctx); - if (title instanceof Component component) { - return component; - } else if (title instanceof String str) { - return Component.text(str); - } - throw new IllegalStateException("Title must be a Component or String"); - } + + ViewConfiguration configuration(); void layout(ViewLayout layout, S state, ViewContext ctx); diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewConfiguration.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewConfiguration.java new file mode 100644 index 000000000..47cfc83f9 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewConfiguration.java @@ -0,0 +1,53 @@ +package net.swofty.type.generic.gui.v2; + +import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +import java.util.function.BiFunction; + +@Getter +public class ViewConfiguration { + + private final BiFunction titleFunction; + private final InventoryType inventoryType; + + public ViewConfiguration(Component title, InventoryType type) { + this.titleFunction = (v, c) -> title; + this.inventoryType = type; + } + + public ViewConfiguration(String title, InventoryType type) { + this.titleFunction = (v, c) -> Component.text(title); + this.inventoryType = type; + } + + public ViewConfiguration(Title title, InventoryType type) { + this.titleFunction = title::getTitle; + this.inventoryType = type; + } + + public ViewConfiguration(StringTitle title, InventoryType type) { + this.titleFunction = (v, c) -> Component.text(title.getTitle(v, c)); + this.inventoryType = type; + } + + public static ViewConfiguration withTitle(Title title, InventoryType type) { + return new ViewConfiguration<>(title, type); + } + + public static ViewConfiguration withString(StringTitle title, InventoryType type) { + return new ViewConfiguration<>(title, type); + } + + @FunctionalInterface + public interface Title { + Component getTitle(S state, ViewContext ctx); + } + + @FunctionalInterface + public interface StringTitle { + String getTitle(S state, ViewContext ctx); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 3fec6c2bf..93ffb8923 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -2,6 +2,7 @@ import lombok.Getter; import lombok.experimental.Accessors; +import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.event.EventFilter; import net.minestom.server.event.EventNode; @@ -10,281 +11,290 @@ import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.event.trait.InventoryEvent; import net.minestom.server.inventory.Inventory; +import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.event.inventory.InventoryOpenEvent; +import net.minestom.server.network.packet.server.play.OpenWindowPacket; import net.minestom.server.timer.TaskSchedule; import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; +import org.tinylog.Logger; +import java.lang.reflect.Field; import java.time.Duration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; public final class ViewSession { - private final View view; - @Getter - @Accessors(fluent = true) - private final HypixelPlayer player; - @Getter - @Accessors(fluent = true) - private final Inventory inventory; - private final ViewContext context; - private final EventNode eventNode; - - @Getter - @Accessors(fluent = true) - private S state; - private ViewLayout cachedLayout; - private Consumer onCloseHandler; - @Getter - private boolean closed; - - @Getter - @Accessors(fluent = true) - private final SharedContext sharedContext; - private final Map trackedSlotItems = new HashMap<>(); - private final Set recentlyModifiedSlots = new HashSet<>(); - - private ViewSession(View view, HypixelPlayer player, S initialState, SharedContext sharedContext) { - this.view = view; - this.player = player; - this.state = sharedContext != null ? sharedContext.state() : initialState; - this.sharedContext = sharedContext; - this.inventory = new Inventory(view.size(), ""); - this.context = new ViewContext(player, inventory, this); - this.eventNode = EventNode.type("gui-" + System.identityHashCode(this), EventFilter.INVENTORY); - - wireEvents(); - - if (sharedContext != null) { - sharedContext.registerSession(this); - } - } - - public static ViewSession open(View view, HypixelPlayer player, S initialState) { - ViewSession session = new ViewSession<>(view, player, initialState, null); - session.render(); - player.openInventory(session.inventory); - return session; - } - - public static ViewSession openShared(View view, HypixelPlayer player, SharedContext sharedContext) { - ViewSession session = new ViewSession<>(view, player, sharedContext.state(), sharedContext); - session.render(); - player.openInventory(session.inventory); - return session; - } - - public static ViewSession openShared(View view, HypixelPlayer player, String contextId, S initialState) { - SharedContext ctx = SharedContext.create(contextId, initialState); - return openShared(view, player, ctx); - } - - public static ViewSession joinShared(View view, HypixelPlayer player, String contextId) { - return SharedContext.get(contextId) - .map(ctx -> openShared(view, player, ctx)) - .orElseThrow(() -> new IllegalArgumentException("Shared context not found: " + contextId)); - } - - private void wireEvents() { - eventNode.addListener(InventoryPreClickEvent.class, this::onPreClickEvent); - eventNode.addListener(InventoryClickEvent.class, this::onPostClickEvent); - eventNode.addListener(InventoryCloseEvent.class, this::onCloseEvent); - eventNode.addListener(InventoryOpenEvent.class, this::onOpenEvent); - MinecraftServer.getGlobalEventHandler().addChild(eventNode); - } - - private void onOpenEvent(InventoryOpenEvent event) { - if (event.getInventory() != inventory || closed) return; - view.onOpen(state, context); - } - - private void onPreClickEvent(InventoryPreClickEvent event) { - if (event.getInventory() instanceof PlayerInventory) { - // if the current open inventory is this inventory - if (player.getOpenInventory() == inventory) { - ClickContext click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); - if (!view.onBottomClick(click, context)) { - event.setCancelled(true); - } - } - return; - } - if (event.getInventory() != inventory || closed) return; - - int slot = event.getSlot(); - SlotBehavior behavior = cachedLayout != null ? cachedLayout.getBehavior(slot) : SlotBehavior.UI; - - if (behavior == SlotBehavior.EDITABLE) { - trackedSlotItems.put(slot, inventory.getItemStack(slot)); - return; - } - - event.setCancelled(true); - ViewComponent component = cachedLayout != null ? cachedLayout.components().get(slot) : null; - if (component == null) { - ClickContext click = new ClickContext<>(slot, event.getClick(), player, state); - view.onClick(click, context); - return; - } - - ClickContext click = new ClickContext<>(slot, event.getClick(), player, state); - component.onClick().accept(click, context); - } - - private void onPostClickEvent(InventoryClickEvent event) { - if (event.getInventory() != inventory || closed) return; - - int slot = event.getSlot(); - if (cachedLayout == null || !cachedLayout.isEditable(slot)) return; - - MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { - if (closed) return; - - ItemStack oldItem = trackedSlotItems.getOrDefault(slot, ItemStack.AIR); - ItemStack newItem = inventory.getItemStack(slot); - - if (!oldItem.equals(newItem)) { - handleSlotChange(slot, oldItem, newItem); - } - }); - } - - private void handleSlotChange(int slot, ItemStack oldItem, ItemStack newItem) { - trackedSlotItems.put(slot, newItem); - recentlyModifiedSlots.add(slot); - - ViewComponent component = cachedLayout.components().get(slot); - if (component != null && component.changeHandler() != null) { - component.changeHandler().onChange(slot, oldItem, newItem, state); - } - - if (sharedContext != null) { - sharedContext.setSlotItem(slot, newItem); - } else { - render(); - } - - recentlyModifiedSlots.remove(slot); - } - - private void onCloseEvent(InventoryCloseEvent event) { - if (event.getInventory() != inventory) return; - close(CloseReason.PLAYER_EXITED); - } - - public void render() { - if (closed) return; - - cachedLayout = new ViewLayout<>(view.size()); - view.layout(cachedLayout, state, context); - inventory.setTitle(view.getTitle(state, context)); - - cachedLayout.components().forEach((slot, component) -> { - if (component.behavior() == SlotBehavior.EDITABLE) { - if (sharedContext != null) { - ItemStack contextItem = sharedContext.getSlotItem(slot); - if (!inventory.getItemStack(slot).equals(contextItem)) { - inventory.setItemStack(slot, contextItem); - } - trackedSlotItems.put(slot, contextItem); - return; - } else if (!recentlyModifiedSlots.contains(slot)) { - ItemStack currentItem = inventory.getItemStack(slot); - trackedSlotItems.put(slot, currentItem); - } - return; - } - - var item = component.render().apply(state, context).build(); - if (!inventory.getItemStack(slot).equals(item)) { - inventory.setItemStack(slot, item); - } - }); - - view.onRefresh(state, context); - } - - public void setState(S newState) { - this.state = newState; - - if (sharedContext != null) { - sharedContext.setState(newState); - } else { - render(); - } - } - - public void setStateQuiet(S newState) { - this.state = newState; - render(); - } - - void setStateFromShared(S newState) { - this.state = newState; - render(); - } - - void renderFromShared() { - render(); - } - - public void update(UnaryOperator transform) { - setState(transform.apply(state)); - } - - public void updateQuiet(UnaryOperator transform) { - setStateQuiet(transform.apply(state)); - } - - @SuppressWarnings("unchecked") - public void updateUnchecked(Function transform) { - setState(((Function) transform).apply(state)); - } - - public ViewSession onClose(Consumer handler) { - this.onCloseHandler = handler; - return this; - } - - public ViewSession refreshEvery(Duration interval) { - MinecraftServer.getSchedulerManager().submitTask(() -> { - if (closed) return TaskSchedule.stop(); - render(); - return TaskSchedule.millis(interval.toMillis()); - }); - return this; - } - - public void close(CloseReason reason) { - if (closed) return; - closed = true; - - MinecraftServer.getGlobalEventHandler().removeChild(eventNode); - if (sharedContext != null) { - sharedContext.unregisterSession(this); - } - - view.onClose(state, context, reason); - if (onCloseHandler != null) onCloseHandler.accept(reason); - if (reason != CloseReason.PLAYER_EXITED) player.closeInventory(); - } - - public boolean isShared() { - return sharedContext != null; - } - - public enum CloseReason { - PLAYER_EXITED, - SERVER_EXITED, - REPLACED - } + private final View view; + @Getter + @Accessors(fluent = true) + private final HypixelPlayer player; + @Getter + @Accessors(fluent = true) + private final Inventory inventory; + private final ViewContext context; + private final EventNode eventNode; + + @Getter + @Accessors(fluent = true) + private S state; + private ViewLayout cachedLayout; + private Consumer onCloseHandler; + @Getter + private boolean closed; + + @Getter + @Accessors(fluent = true) + private final SharedContext sharedContext; + private final Map trackedSlotItems = new HashMap<>(); + private final Set recentlyModifiedSlots = new HashSet<>(); + + private ViewSession(View view, HypixelPlayer player, S initialState, SharedContext sharedContext) { + this.view = view; + this.player = player; + this.state = sharedContext != null ? sharedContext.state() : initialState; + this.sharedContext = sharedContext; + this.inventory = new Inventory(view.configuration().getInventoryType(), ""); + this.context = new ViewContext(player, inventory, this); + this.eventNode = EventNode.type("gui-" + System.identityHashCode(this), EventFilter.INVENTORY); + + wireEvents(); + + if (sharedContext != null) { + sharedContext.registerSession(this); + } + } + + public static ViewSession open(View view, HypixelPlayer player, S initialState) { + ViewSession session = new ViewSession<>(view, player, initialState, null); + session.render(); + player.openInventory(session.inventory); + return session; + } + + public static ViewSession openShared(View view, HypixelPlayer player, SharedContext sharedContext) { + ViewSession session = new ViewSession<>(view, player, sharedContext.state(), sharedContext); + session.render(); + player.openInventory(session.inventory); + return session; + } + + public static ViewSession openShared(View view, HypixelPlayer player, String contextId, S initialState) { + SharedContext ctx = SharedContext.create(contextId, initialState); + return openShared(view, player, ctx); + } + + public static ViewSession joinShared(View view, HypixelPlayer player, String contextId) { + return SharedContext.get(contextId) + .map(ctx -> openShared(view, player, ctx)) + .orElseThrow(() -> new IllegalArgumentException("Shared context not found: " + contextId)); + } + + private void wireEvents() { + eventNode.addListener(InventoryPreClickEvent.class, this::onPreClickEvent); + eventNode.addListener(InventoryClickEvent.class, this::onPostClickEvent); + eventNode.addListener(InventoryCloseEvent.class, this::onCloseEvent); + eventNode.addListener(InventoryOpenEvent.class, this::onOpenEvent); + MinecraftServer.getGlobalEventHandler().addChild(eventNode); + } + + private void onOpenEvent(InventoryOpenEvent event) { + if (event.getInventory() != inventory || closed) return; + view.onOpen(state, context); + } + + private void onPreClickEvent(InventoryPreClickEvent event) { + if (event.getInventory() instanceof PlayerInventory) { + // if the current open inventory is this inventory + if (player.getOpenInventory() == inventory) { + ClickContext click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); + if (!view.onBottomClick(click, context)) { + event.setCancelled(true); + } + } + return; + } + if (event.getInventory() != inventory || closed) return; + + int slot = event.getSlot(); + SlotBehavior behavior = cachedLayout != null ? cachedLayout.getBehavior(slot) : SlotBehavior.UI; + + if (behavior == SlotBehavior.EDITABLE) { + trackedSlotItems.put(slot, inventory.getItemStack(slot)); + return; + } + + event.setCancelled(true); + ViewComponent component = cachedLayout != null ? cachedLayout.components().get(slot) : null; + if (component == null) { + ClickContext click = new ClickContext<>(slot, event.getClick(), player, state); + view.onClick(click, context); + return; + } + + ClickContext click = new ClickContext<>(slot, event.getClick(), player, state); + component.onClick().accept(click, context); + } + + private void onPostClickEvent(InventoryClickEvent event) { + if (event.getInventory() != inventory || closed) return; + + int slot = event.getSlot(); + if (cachedLayout == null || !cachedLayout.isEditable(slot)) return; + + MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { + if (closed) return; + + ItemStack oldItem = trackedSlotItems.getOrDefault(slot, ItemStack.AIR); + ItemStack newItem = inventory.getItemStack(slot); + + if (!oldItem.equals(newItem)) { + handleSlotChange(slot, oldItem, newItem); + } + }); + } + + private void handleSlotChange(int slot, ItemStack oldItem, ItemStack newItem) { + trackedSlotItems.put(slot, newItem); + recentlyModifiedSlots.add(slot); + + ViewComponent component = cachedLayout.components().get(slot); + if (component != null && component.changeHandler() != null) { + component.changeHandler().onChange(slot, oldItem, newItem, state); + } + + if (sharedContext != null) { + sharedContext.setSlotItem(slot, newItem); + } else { + render(); + } + + recentlyModifiedSlots.remove(slot); + } + + private void onCloseEvent(InventoryCloseEvent event) { + if (event.getInventory() != inventory) return; + close(CloseReason.PLAYER_EXITED); + } + + public void render() { + if (closed) return; + + ViewConfiguration config = view.configuration(); + cachedLayout = new ViewLayout<>(config.getInventoryType()); + view.layout(cachedLayout, state, context); + + @SuppressWarnings("unchecked") + BiFunction titleFunction = (BiFunction) config.getTitleFunction(); + inventory.setTitle(titleFunction.apply(state, context)); + + cachedLayout.components().forEach((slot, component) -> { + if (component.behavior() == SlotBehavior.EDITABLE) { + if (sharedContext != null) { + ItemStack contextItem = sharedContext.getSlotItem(slot); + if (!inventory.getItemStack(slot).equals(contextItem)) { + inventory.setItemStack(slot, contextItem); + } + trackedSlotItems.put(slot, contextItem); + return; + } else if (!recentlyModifiedSlots.contains(slot)) { + ItemStack currentItem = inventory.getItemStack(slot); + trackedSlotItems.put(slot, currentItem); + } + return; + } + + var item = component.render().apply(state, context).build(); + if (!inventory.getItemStack(slot).equals(item)) { + inventory.setItemStack(slot, item); + } + }); + + view.onRefresh(state, context); + } + + public void setState(S newState) { + this.state = newState; + + if (sharedContext != null) { + sharedContext.setState(newState); + } else { + render(); + } + } + + public void setStateQuiet(S newState) { + this.state = newState; + render(); + } + + void setStateFromShared(S newState) { + this.state = newState; + render(); + } + + void renderFromShared() { + render(); + } + + public void update(UnaryOperator transform) { + setState(transform.apply(state)); + } + + public void updateQuiet(UnaryOperator transform) { + setStateQuiet(transform.apply(state)); + } + + @SuppressWarnings("unchecked") + public void updateUnchecked(Function transform) { + setState(((Function) transform).apply(state)); + } + + public ViewSession onClose(Consumer handler) { + this.onCloseHandler = handler; + return this; + } + + public ViewSession refreshEvery(Duration interval) { + MinecraftServer.getSchedulerManager().submitTask(() -> { + if (closed) return TaskSchedule.stop(); + render(); + return TaskSchedule.millis(interval.toMillis()); + }); + return this; + } + + public void close(CloseReason reason) { + if (closed) return; + closed = true; + + MinecraftServer.getGlobalEventHandler().removeChild(eventNode); + if (sharedContext != null) { + sharedContext.unregisterSession(this); + } + + view.onClose(state, context, reason); + if (onCloseHandler != null) onCloseHandler.accept(reason); + if (reason != CloseReason.PLAYER_EXITED) player.closeInventory(); + } + + public boolean isShared() { + return sharedContext != null; + } + + public enum CloseReason { + PLAYER_EXITED, + SERVER_EXITED, + REPLACED + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java index 5d51e1396..8789a9f08 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java @@ -6,6 +6,7 @@ import net.minestom.server.item.Material; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import java.util.HashMap; @@ -37,13 +38,8 @@ public State initialState() { } @Override - public InventoryType size() { - return InventoryType.CHEST_3_ROW; - } - - @Override - public Component title(State state, ViewContext ctx) { - return Component.text("§8Personal Storage §7(§e" + state.itemCount() + " items§7)"); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("§8Personal Storage", InventoryType.CHEST_3_ROW); } @Override @@ -69,4 +65,9 @@ public void layout(ViewLayout layout, State state, ViewContext ctx) { Components.close(layout, 22); layout.allowHotkey(true); } + + @Override + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + return true; + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java index 7b3f347e8..4b92c6e16 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java @@ -1,11 +1,11 @@ package net.swofty.type.generic.gui.v2.test; -import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; @@ -48,13 +48,8 @@ public State initialState() { } @Override - public InventoryType size() { - return InventoryType.CHEST_5_ROW; - } - - @Override - public Component title(State state, ViewContext ctx) { - return Component.text("§5Crafting Station"); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("§5Crafting Station", InventoryType.CHEST_5_ROW); } @Override @@ -119,6 +114,11 @@ public void layout(ViewLayout layout, State state, ViewContext ctx) { layout.allowHotkey(true); } + @Override + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + return true; + } + public static void open(HypixelPlayer player) { ViewSession.open(new TestMixedView(), player, new State(new HashMap<>())); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestNoStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestNoStateView.java index 9b2f6b8ec..7106775f5 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestNoStateView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestNoStateView.java @@ -1,6 +1,5 @@ package net.swofty.type.generic.gui.v2.test; -import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; import net.swofty.type.generic.gui.v2.*; import net.swofty.type.generic.gui.v2.context.ViewContext; @@ -8,13 +7,8 @@ public class TestNoStateView extends StatelessView { @Override - public InventoryType size() { - return InventoryType.CHEST_3_ROW; - } - - @Override - public Component title(DefaultState state, ViewContext ctx) { - return Component.text("Stateless"); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Stateless", InventoryType.CHEST_3_ROW); } @Override diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java index dc430984c..faa536396 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java @@ -1,96 +1,93 @@ package net.swofty.type.generic.gui.v2.test; -import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; -import java.util.Map; - public final class TestSharedContainerView implements View { - public record State(String teamName) {} - - @Override - public InventoryType size() { - return InventoryType.CHEST_6_ROW; - } - - @Override - public Component title(State state, ViewContext ctx) { - SharedContext shared = ctx.session(State.class).sharedContext(); - int viewers = shared != null ? shared.sessionCount() : 1; - return Component.text("§6" + state.teamName() + " §7(§e" + viewers + " viewing§7)"); - } - - @Override - public void layout(ViewLayout layout, State state, ViewContext ctx) { - layout.filler(Components.FILLER); - - layout.slot(4, (s, c) -> { - SharedContext shared = ctx.session(State.class).sharedContext(); - int itemCount = shared != null - ? (int) shared.getAllSlotItems().values().stream().filter(i -> !i.isAir()).count() - : 0; - - return ItemStackCreator.getStack( - "§6" + s.teamName(), - Material.CHEST, - 1, - "§7Shared team storage", - "", - "§7Items stored: §e" + itemCount, - "§7Players viewing: §e" + (shared != null ? shared.sessionCount() : 1) - ); - }); - - Components.sharedContainerGrid(layout, 10, 43); - - layout.slot(49, (s, c) -> ItemStackCreator.getStack( - "§cClear All", - Material.TNT, - 1, - "§7Clears all items from storage", - "", - "§eShift Left Click to confirm!" - ), (click, context) -> { - if (click.click() instanceof Click.LeftShift) { - SharedContext shared = context.session(State.class).sharedContext(); - if (shared != null) { - shared.clearSlotItems(); - shared.broadcastMessage("§c" + click.player().getUsername() + " cleared the team chest!"); - } - } - }); - - Components.close(layout, 53); - layout.allowHotkey(true); - } - - public static ViewSession open(HypixelPlayer player, String teamId, String teamName) { - String contextId = "team-chest-" + teamId; - - if (SharedContext.exists(contextId)) { - return ViewSession.joinShared(new TestSharedContainerView(), player, contextId); - } - - SharedContext ctx = SharedContext.create(contextId, new State(teamName)); - ctx.onPersist(context -> - System.out.println("Persisting team chest " + teamId + " with " + context.getAllSlotItems().size() + " items") - ); - ctx.onSlotChange(change -> - System.out.println("Slot " + change.slot() + " changed: " + change.oldItem().material() + " -> " + change.newItem().material()) - ); - - return ViewSession.openShared(new TestSharedContainerView(), player, ctx); - } - - public static void loadItems(String teamId, Map items) { - SharedContext.get("team-chest-" + teamId).ifPresent(ctx -> ctx.setSlotItems(items)); - } + public record State(String teamName) { + } + + @Override + public ViewConfiguration configuration() { + + return ViewConfiguration.withString((state, ctx) -> { + SharedContext shared = ctx.session(State.class).sharedContext(); + int viewers = shared != null ? shared.sessionCount() : 1; + return "§6" + state.teamName() + " §7(§e" + viewers + " viewing§7)"; + }, InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + layout.filler(Components.FILLER); + + layout.slot(4, (s, c) -> { + SharedContext shared = ctx.session(State.class).sharedContext(); + int itemCount = shared != null + ? (int) shared.getAllSlotItems().values().stream().filter(i -> !i.isAir()).count() + : 0; + + return ItemStackCreator.getStack( + "§6" + s.teamName(), + Material.CHEST, + 1, + "§7Shared team storage", + "", + "§7Items stored: §e" + itemCount, + "§7Players viewing: §e" + (shared != null ? shared.sessionCount() : 1) + ); + }); + + Components.sharedContainerGrid(layout, 10, 43); + + layout.slot(49, (s, c) -> ItemStackCreator.getStack( + "§cClear All", + Material.TNT, + 1, + "§7Clears all items from storage", + "", + "§eShift Left Click to confirm!" + ), (click, context) -> { + if (click.click() instanceof Click.LeftShift) { + SharedContext shared = context.session(State.class).sharedContext(); + if (shared != null) { + shared.clearSlotItems(); + shared.broadcastMessage("§c" + click.player().getUsername() + " cleared the team chest!"); + } + } + }); + + Components.close(layout, 53); + layout.allowHotkey(true); + } + + public static ViewSession open(HypixelPlayer player, String teamId, String teamName) { + String contextId = "team-chest-" + teamId; + + if (SharedContext.exists(contextId)) { + return ViewSession.joinShared(new TestSharedContainerView(), player, contextId); + } + + SharedContext ctx = SharedContext.create(contextId, new State(teamName)); + ctx.onPersist(context -> + System.out.println("Persisting team chest " + teamId + " with " + context.getAllSlotItems().size() + " items") + ); + ctx.onSlotChange(change -> + System.out.println("Slot " + change.slot() + " changed: " + change.oldItem().material() + " -> " + change.newItem().material()) + ); + + return ViewSession.openShared(new TestSharedContainerView(), player, ctx); + } + + @Override + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + return true; + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java index 2fc67721c..3371ac160 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java @@ -30,13 +30,8 @@ public State initialState() { } @Override - public InventoryType size() { - return InventoryType.CHEST_3_ROW; - } - - @Override - public Component title(State state, ViewContext ctx) { - return Component.text("§9Shared Counter: §e" + state.counter()); + public ViewConfiguration configuration() { + return ViewConfiguration.withString((state, ctx) -> "§9Shared Counter: §e" + state.counter(), InventoryType.CHEST_3_ROW); } @Override diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java index 04ca4df44..8c21bf0bc 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestStateView.java @@ -20,13 +20,8 @@ public record State(int counter) { } @Override - public InventoryType size() { - return InventoryType.CHEST_3_ROW; - } - - @Override - public Component title(State state, ViewContext ctx) { - return Component.text("Counter: " + state.counter()); + public ViewConfiguration configuration() { + return ViewConfiguration.withString((view, ctx) -> "Counter: " + view.counter(), InventoryType.CHEST_3_ROW); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java index 6a906ffc1..f8733c0fa 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java @@ -25,13 +25,8 @@ public State claim() { } @Override - public InventoryType size() { - return InventoryType.CHEST_6_ROW; - } - - @Override - public Component title(State state, ViewContext ctx) { - return Component.text("Claim Reward"); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Claim Reward", InventoryType.CHEST_6_ROW); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIConsumeSoulflow.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIConsumeSoulflow.java index b37c379a4..fe57f5d3b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIConsumeSoulflow.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIConsumeSoulflow.java @@ -1,86 +1,78 @@ package net.swofty.type.skyblockgeneric.gui.inventories; -import net.minestom.server.event.inventory.InventoryPreClickEvent; +import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.swofty.type.generic.data.datapoints.DatapointInteger; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.SoulflowComponent; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -public class GUIConsumeSoulflow extends HypixelInventoryGUI { +public class GUIConsumeSoulflow implements View { - private final SkyBlockItem item; + public record State(SkyBlockItem item) { + public State { + if (!item.hasComponent(SoulflowComponent.class)) { + throw new IllegalArgumentException("Item does not have SoulflowComponent"); + } + } + } - public GUIConsumeSoulflow(SkyBlockItem item) { - super("Consume Soulflow?", InventoryType.CHEST_4_ROW); - this.item = item; + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Consume Soulflow", InventoryType.CHEST_4_ROW); + } - if (!item.hasComponent(SoulflowComponent.class)) { - throw new IllegalArgumentException("Item does not have SoulflowComponent"); - } - } + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + Components.fill(layout); - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(FILLER_ITEM); - set(new GUIClickableItem(13) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockDataHandler data = player.getSkyblockDataHandler(); - int soulflow = data.get(SkyBlockDataHandler.Data.SOULFLOW, DatapointInteger.class).getValue(); - int itemSoulflow = item.getComponent(SoulflowComponent.class).getAmount(); - int addition = item.getAmount() * itemSoulflow; + layout.slot(13, (s, viewCtx) -> { + SkyBlockPlayer player = (SkyBlockPlayer) viewCtx.player(); + SkyBlockDataHandler data = player.getSkyblockDataHandler(); + int soulflow = data.get(SkyBlockDataHandler.Data.SOULFLOW, DatapointInteger.class).getValue(); + int itemSoulflow = s.item().getComponent(SoulflowComponent.class).getAmount(); + int addition = s.item().getAmount() * itemSoulflow; - data.get(SkyBlockDataHandler.Data.SOULFLOW, DatapointInteger.class).setValue(soulflow + addition); - player.sendMessage("§bYou internalized §3+" + addition + "⸎ Soulflow §band have a total of §3" + (soulflow + addition) + "⸎§b!"); + return ItemStackCreator.getStackHead( + "§aConsume Soulflow?", + "94f0c693b85658b0bae792c9f9b717eb024ab8c4b349455648ea08358b50ddc4", + 1, + "§7Takes all the §3⸎ Soulflow §7items in", + "§7your inventory and internalizes them", + "§7to be ready for use.", + "", + "§7Internalized: §3" + soulflow + "⸎", + "", + "§7Adding from inventory: §3+" + addition + "⸎ Soulflow", + "", + "§eClick to consume!" + ); + }, + (click, viewCtx) -> { + SkyBlockPlayer player = (SkyBlockPlayer) viewCtx.player(); + SkyBlockDataHandler data = player.getSkyblockDataHandler(); + int soulflow = data.get(SkyBlockDataHandler.Data.SOULFLOW, DatapointInteger.class).getValue(); - player.getInventory().setItemStack(player.getHeldSlot(), ItemStack.AIR); - player.closeInventory(); - } + int itemSoulflow = click.state().item().getComponent(SoulflowComponent.class).getAmount(); + int addition = click.state().item().getAmount() * itemSoulflow; - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockDataHandler data = player.getSkyblockDataHandler(); - int soulflow = data.get(SkyBlockDataHandler.Data.SOULFLOW, DatapointInteger.class).getValue(); + data.get(SkyBlockDataHandler.Data.SOULFLOW, DatapointInteger.class).setValue(soulflow + addition); + player.sendMessage("§bYou internalized §3+" + addition + "⸎ Soulflow §band have a total of §3" + (soulflow + addition) + "⸎§b!"); - int itemSoulflow = item.getComponent(SoulflowComponent.class).getAmount(); - int addition = item.getAmount() * itemSoulflow; + player.getInventory().setItemStack(player.getHeldSlot(), ItemStack.AIR); + player.closeInventory(); + } + ); + Components.close(layout, 31); + } - return ItemStackCreator.getStackHead( - "§aConsume Soulflow?", - "94f0c693b85658b0bae792c9f9b717eb024ab8c4b349455648ea08358b50ddc4", - 1, - "§7Takes all the §3⸎ Soulflow §7items in", - "§7your inventory and internalizes them", - "§7to be ready for use.", - "", - "§7Internalized: §3" + soulflow + "⸎", - "", - "§7Adding from inventory: §3+" + addition + "⸎ Soulflow", - "", - "§eClick to consume!" - ); - } - }); - set(GUIClickableItem.getCloseItem(31)); - updateItemStacks(getInventory(), getPlayer()); - } + public static void open(SkyBlockPlayer player, SkyBlockItem item) { + player.openView(new GUIConsumeSoulflow(), new State(item)); + } - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/SoulflowComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/SoulflowComponent.java index 3af078377..753dd56ed 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/SoulflowComponent.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/SoulflowComponent.java @@ -19,9 +19,7 @@ public SoulflowComponent(int amount) { ), false )); addInheritedComponent( - new InteractableComponent((player, item) -> { - new GUIConsumeSoulflow(item).open(player); - }, null, null) + new InteractableComponent(GUIConsumeSoulflow::open, null, null) ); this.amount = amount; } From 93e59d44f34d22e59134f7e6f7cc6f9821fb63ec Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Thu, 8 Jan 2026 19:42:41 +0200 Subject: [PATCH 10/35] feat: remove persists --- .../type/generic/gui/v2/SharedContext.java | 27 ------------------- .../gui/v2/test/TestSharedContainerView.java | 3 --- 2 files changed, 30 deletions(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java index 0c7dc253e..53bf6e757 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java @@ -21,18 +21,14 @@ public final class SharedContext { private volatile S state; private final Map slotItems; private final Set> sessions; - private final List>> persistenceHandlers; private final List> slotChangeListeners; - private PersistenceMode persistenceMode; private SharedContext(String id, S initialState) { this.id = id; this.state = initialState; this.slotItems = new ConcurrentHashMap<>(); this.sessions = new CopyOnWriteArraySet<>(); - this.persistenceHandlers = new CopyOnWriteArrayList<>(); this.slotChangeListeners = new CopyOnWriteArrayList<>(); - this.persistenceMode = PersistenceMode.ON_CLOSE; } @SuppressWarnings("unchecked") @@ -57,7 +53,6 @@ public static boolean exists(String id) { public void setState(S newState) { this.state = newState; broadcast(); - if (persistenceMode == PersistenceMode.IMMEDIATE) persist(); } public ItemStack getSlotItem(int slot) { @@ -78,7 +73,6 @@ public void setSlotItem(int slot, ItemStack item) { } broadcastRender(); - if (persistenceMode == PersistenceMode.IMMEDIATE) persist(); } public Map getAllSlotItems() { @@ -111,7 +105,6 @@ void registerSession(ViewSession session) { void unregisterSession(ViewSession session) { sessions.remove(session); if (sessions.isEmpty()) { - if (persistenceMode == PersistenceMode.ON_CLOSE) persist(); CONTEXTS.remove(id); } else { broadcastRender(); @@ -134,25 +127,11 @@ public void broadcastRender() { } } - public SharedContext onPersist(Consumer> handler) { - persistenceHandlers.add(handler); - return this; - } - public SharedContext onSlotChange(Consumer listener) { slotChangeListeners.add(listener); return this; } - public SharedContext persistenceMode(PersistenceMode mode) { - this.persistenceMode = mode; - return this; - } - - public void persist() { - persistenceHandlers.forEach(h -> h.accept(this)); - } - public void closeAll() { for (ViewSession session : new ArrayList<>(sessions)) { session.close(ViewSession.CloseReason.SERVER_EXITED); @@ -176,10 +155,4 @@ public void broadcastMessage(String message) { } public record SlotChange(int slot, ItemStack oldItem, ItemStack newItem) {} - - public enum PersistenceMode { - IMMEDIATE, - ON_CLOSE, - MANUAL - } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java index faa536396..3990853d6 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java @@ -76,9 +76,6 @@ public static ViewSession open(HypixelPlayer player, String teamId, Strin } SharedContext ctx = SharedContext.create(contextId, new State(teamName)); - ctx.onPersist(context -> - System.out.println("Persisting team chest " + teamId + " with " + context.getAllSlotItems().size() + " items") - ); ctx.onSlotChange(change -> System.out.println("Slot " + change.slot() + " changed: " + change.oldItem().material() + " -> " + change.newItem().material()) ); From 8a5e5f57e89b0bb1716f6ccecfca81e43922a0f9 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Thu, 8 Jan 2026 20:54:29 +0200 Subject: [PATCH 11/35] feat: skyblock menu --- .../type/generic/gui/v2/ViewComponent.java | 40 +- .../type/generic/gui/v2/ViewLayout.java | 13 + .../type/generic/gui/v2/ViewSession.java | 49 +- .../gui/inventories/sbmenu/GUIPets.java | 14 +- .../inventories/sbmenu/GUISkyBlockMenu.java | 614 +++++++----------- .../sbmenu/GUISkyBlockProfile.java | 13 +- .../inventories/sbmenu/bags/GUIYourBags.java | 12 +- .../sbmenu/calendar/GUICalendar.java | 14 +- .../sbmenu/collection/GUICollections.java | 12 +- .../sbmenu/fasttravel/GUIFastTravel.java | 13 +- .../sbmenu/levels/GUISkyBlockLevels.java | 17 +- .../sbmenu/profiles/GUIProfileManagement.java | 11 +- .../sbmenu/questlog/GUIMissionLog.java | 12 +- .../sbmenu/recipe/GUIRecipeBook.java | 12 +- .../inventories/sbmenu/skills/GUISkills.java | 13 +- .../sbmenu/storage/GUIStorage.java | 12 +- .../interactable/InteractableRegistry.java | 6 +- 17 files changed, 458 insertions(+), 419 deletions(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java index 9e7e67efe..d49d7aac5 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java @@ -4,24 +4,46 @@ import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; +import java.time.Duration; +import java.util.UUID; import java.util.function.BiConsumer; import java.util.function.BiFunction; public record ViewComponent( + UUID id, int slot, BiFunction render, BiConsumer, ViewContext> onClick, SlotBehavior behavior, - SlotChangeHandler changeHandler + SlotChangeHandler changeHandler, + Duration updateInterval ) { public ViewComponent(int slot, BiFunction render, BiConsumer, ViewContext> onClick) { - this(slot, render, onClick, SlotBehavior.UI, null); + this(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, null); } public static ViewComponent staticItem(int slot, ItemStack.Builder item) { - return new ViewComponent<>(slot, (_, _) -> item, (_, _) -> { - }, SlotBehavior.UI, null); + return new ViewComponent<>(UUID.randomUUID(), slot, (_, _) -> item, (_, _) -> { + }, SlotBehavior.UI, null, null); + } + + public static ViewComponent autoUpdating( + int slot, + BiFunction render, + Duration updateInterval + ) { + return new ViewComponent<>(UUID.randomUUID(), slot, render, (_, _) -> { + }, SlotBehavior.UI, null, updateInterval); + } + + public static ViewComponent autoUpdating( + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick, + Duration updateInterval + ) { + return new ViewComponent<>(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, updateInterval); } public static ViewComponent clickable( @@ -29,7 +51,7 @@ public static ViewComponent clickable( BiFunction render, BiConsumer, ViewContext> onClick ) { - return new ViewComponent<>(slot, render, onClick, SlotBehavior.UI, null); + return new ViewComponent<>(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, null); } public static ViewComponent editable( @@ -37,13 +59,13 @@ public static ViewComponent editable( BiFunction initialRender, SlotChangeHandler changeHandler ) { - return new ViewComponent<>(slot, initialRender, (_, _) -> { - }, SlotBehavior.EDITABLE, changeHandler); + return new ViewComponent<>(UUID.randomUUID(), slot, initialRender, (_, _) -> { + }, SlotBehavior.EDITABLE, changeHandler, null); } public static ViewComponent editable(int slot, ItemStack.Builder initialItem, SlotChangeHandler changeHandler) { - return new ViewComponent<>(slot, (_, _) -> initialItem, (_, _) -> { - }, SlotBehavior.EDITABLE, changeHandler); + return new ViewComponent<>(UUID.randomUUID(), slot, (_, _) -> initialItem, (_, _) -> { + }, SlotBehavior.EDITABLE, changeHandler, null); } public static ViewComponent editable(int slot, SlotChangeHandler changeHandler) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java index 0ec06635f..bd7ed50e2 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java @@ -68,6 +68,19 @@ public void editable(int slot, ItemStack.Builder initialItem, SlotChangeHandler< components.put(slot, ViewComponent.editable(slot, initialItem, onChange)); } + public void autoUpdating(int slot, + BiFunction render, + java.time.Duration updateInterval) { + components.put(slot, ViewComponent.autoUpdating(slot, render, updateInterval)); + } + + public void autoUpdating(int slot, + BiFunction render, + BiConsumer, ViewContext> onClick, + java.time.Duration updateInterval) { + components.put(slot, ViewComponent.autoUpdating(slot, render, onClick, updateInterval)); + } + public void editable(int slot, SlotChangeHandler onChange) { components.put(slot, ViewComponent.editable(slot, onChange)); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 93ffb8923..fe676746e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -11,23 +11,17 @@ import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.event.trait.InventoryEvent; import net.minestom.server.inventory.Inventory; -import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.event.inventory.InventoryOpenEvent; -import net.minestom.server.network.packet.server.play.OpenWindowPacket; +import net.minestom.server.timer.Task; import net.minestom.server.timer.TaskSchedule; import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; -import org.tinylog.Logger; -import java.lang.reflect.Field; import java.time.Duration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; @@ -58,6 +52,8 @@ public final class ViewSession { private final SharedContext sharedContext; private final Map trackedSlotItems = new HashMap<>(); private final Set recentlyModifiedSlots = new HashSet<>(); + private final Map autoUpdateTasks = new HashMap<>(); + private final Map> componentSlots = new HashMap<>(); private ViewSession(View view, HypixelPlayer player, S initialState, SharedContext sharedContext) { this.view = view; @@ -194,6 +190,9 @@ public void render() { cachedLayout = new ViewLayout<>(config.getInventoryType()); view.layout(cachedLayout, state, context); + Set previousComponents = new HashSet<>(componentSlots.keySet()); + componentSlots.clear(); + @SuppressWarnings("unchecked") BiFunction titleFunction = (BiFunction) config.getTitleFunction(); inventory.setTitle(titleFunction.apply(state, context)); @@ -214,15 +213,40 @@ public void render() { return; } - var item = component.render().apply(state, context).build(); - if (!inventory.getItemStack(slot).equals(item)) { - inventory.setItemStack(slot, item); + renderSlot(slot, component); + if (component.updateInterval() != null) { + scheduleAutoUpdate(slot, component); + } + if (component.id() != null) { + previousComponents.remove(component.id()); } }); view.onRefresh(state, context); } + private void renderSlot(int slot, ViewComponent component) { + var item = component.render().apply(state, context).build(); + if (!inventory.getItemStack(slot).equals(item)) { + inventory.setItemStack(slot, item); + } + + if (component.id() != null) { + componentSlots.computeIfAbsent(component.id(), k -> new HashSet<>()).add(slot); + } + } + + private void scheduleAutoUpdate(int slot, ViewComponent component) { + if (autoUpdateTasks.containsKey(slot)) return; + + Task task = MinecraftServer.getSchedulerManager().submitTask(() -> { + if (closed) return TaskSchedule.stop(); + renderSlot(slot, component); + return TaskSchedule.duration(component.updateInterval()); + }); + autoUpdateTasks.put(slot, task); + } + public void setState(S newState) { this.state = newState; @@ -278,6 +302,9 @@ public void close(CloseReason reason) { if (closed) return; closed = true; + autoUpdateTasks.values().forEach(Task::cancel); + autoUpdateTasks.clear(); + MinecraftServer.getGlobalEventHandler().removeChild(eventNode); if (sharedContext != null) { sharedContext.unregisterSession(this); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java index 4cc1c80c2..eb8999fec 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java @@ -108,8 +108,18 @@ public boolean shouldFilterFromSearch(String query, SkyBlockItem item) { public void performSearch(HypixelPlayer player, String query, int page, int maxPage) { border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); set(GUIClickableItem.getCloseItem(49)); - set(createSearchItem(this, 50, query)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer p) { + p.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer p) { + return ItemStackCreator.getStack("§aGo Back", + Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); set(new GUIClickableItem(47) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java index c8d72e276..add9e47f9 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java @@ -1,17 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.ServerType; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.skyblockgeneric.calendar.CalendarEvent; import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; @@ -31,398 +27,254 @@ import net.swofty.type.skyblockgeneric.user.statistics.PlayerStatistics; import org.jspecify.annotations.NonNull; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Map; -public class GUISkyBlockMenu extends HypixelInventoryGUI { - public GUISkyBlockMenu() { - super("SkyBlock Menu", InventoryType.CHEST_6_ROW); +public class GUISkyBlockMenu extends StatelessView { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - - set(new GUIClickableItem(13) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISkyBlockProfile().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7View your equipment, stats, and more!", "§e ")); - List stats = new ArrayList<>(List.of("Health", "Defense", "Speed", "Strength", "Intelligence", - "Crit Chance", "Crit Damage", "Swing Range" - )); - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (!value.equals(statistic.getBaseAdditiveValue()) || stats.contains(statistic.getDisplayName())) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); - - lore.add("§e "); - lore.add("§eClick to view!"); - - return ItemStackCreator.getStackHead("§aYour SkyBlock Profile", - player.getPlayerSkin(), 1, - lore - ); - } - }); - - set(new GUIClickableItem(22) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISkyBlockLevels().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockLevelRequirement levelRequirement = player.getSkyBlockExperience().getLevel(); - SkyBlockLevelRequirement nextLevel = levelRequirement.getNextLevel(); - - return ItemStackCreator.getStackHead("§aSkyBlock Leveling", "3255327dd8e90afad681a19231665bea2bd06065a09d77ac1408837f9e0b242", 1, - "§7Your SkyBlock Level: §8[" + levelRequirement.getColor() + levelRequirement + "§8]", - " ", - "§7Determine how far you've", - "§7progressed in SkyBlock and earn", - "§7rewards from completing unique", - "§7tasks.", - " ", - "§7Progress to Level " + (nextLevel == null ? "§cMAX" : nextLevel), - player.getSkyBlockExperience().getNextLevelDisplay(), - " ", - "§eClick to view!" - ); - } - }); - - set(new GUIClickableItem(29) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIYourBags().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§aYour Bags", "961a918c0c49ba8d053e522cb91abc74689367b4d8aa06bfc1ba9154730985ff", 1, - "§7Different bags allow you to store", - "§7many different items inside!", - " ", - "§eClick to view!" - ); - } - }); - - set(new GUIClickableItem(30) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIPets().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aPets", Material.BONE, 1, - "§7View and manage all of your", - "§7Pets.", - " ", - "§7Level up your pets faster by", - "§7gaining XP in their favourite", - "§7skill!", - " ", - "§7Selected pet: " + (player.getPetData().getEnabledPet() == null ? "§cNone" : player.getPetData().getEnabledPet().getDisplayName()), - " ", - "§eClick to view!" - ); - } - }); - - set(new GUIClickableItem(21) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRecipeBook().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(List.of( - "§7Through your adventure, you will", - "§7unlock recipes for all kinds of", - "§7special items! You can view how to", - "§7craft these items here.", - " " - )); - - SkyBlockRecipe.getMissionDisplay(lore, player.getUuid()); - - lore.add(" "); - lore.add("§eClick to view!"); - return ItemStackCreator.getStack("§aRecipe Book", Material.BOOK, 1, lore); - } - }); - - set(new GUIClickableItem(25) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStorage().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aStorage", Material.CHEST, 1, - "§7Store global items that you", - "§7want to access at any time", - "§7from anywhere here.", - " ", - "§eClick to view!" - ); - } - }); - - set(new GUIClickableItem(23) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIMissionLog().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aQuests & Chapters", Material.WRITABLE_BOOK, 1, - "§7Each island has its own series of", - "§bChapters §7for you to complete!", - " ", - "§7Complete tasks within a Chapter to", - "§7earn small §6rewards§7, or complete", - "§7entire Chapters to earn big ones!", - " ", - "§7Some islands also have §aQuests §7for", - "§7you to complete! Some items can only", - "§7be obtained through Quests.", - " ", - "§eClick to view!" - ); - } - }); - - set(new GUIClickableItem(24) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICalendar().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aCalendar and Events", Material.CLOCK, 1, getLore()); - } - - private @NonNull List getLore() { - List currentEvents = SkyBlockCalendar.getCurrentEvents(); - boolean multipleEvents = currentEvents.size() > 1; - - List lore = new ArrayList<>(List.of("§7View the SkyBlock Calendar, upcoming", - "§7events, and event rewards!", - " ", - "§7Date: §a" + StringUtility.ntify(SkyBlockCalendar.getDay()) + " " + SkyBlockCalendar.getMonthName() + " " + SkyBlockCalendar.getYear(), - "")); - if(multipleEvents) { - lore.add("§7Current events: "); - for (CalendarEvent event : currentEvents) { - lore.add(event.getDisplayName(SkyBlockCalendar.getYear())); - } - } else if (currentEvents.size() == 1) { - CalendarEvent currentEvent = currentEvents.getFirst(); - lore.add("§7Current event: " + currentEvent.getDisplayName(SkyBlockCalendar.getYear())); - long ticksRemaining = getTicksRemaining(currentEvent); - lore.add("§7Ends in: §e" + StringUtility.formatTimeLeft(ticksRemaining * 50L)); - } else { - lore.add("§7No current events."); - } - - lore.add(" "); - - Map upcomingEvents = SkyBlockCalendar.getEventsWithDurationUntil(1); - if (!upcomingEvents.isEmpty()) { - Map.Entry entry = upcomingEvents.entrySet().iterator().next(); - SkyBlockCalendar.EventInfo info = entry.getKey(); - CalendarEvent event = entry.getValue(); - - lore.add("§7Next event: " + event.getDisplayName(info.year())); - lore.add("§7Starting in: §e" + StringUtility.formatTimeLeft(info.timeUntilBegin() * 50L)); - } else { - lore.add("§7No upcoming events."); - } - - lore.addAll( - List.of( - " ", - "§8Also accessible via /calendar", - " ", - "§eClick to view!" - ) - ); - return lore; - } + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("SkyBlock Menu", InventoryType.CHEST_6_ROW); + } - private static long getTicksRemaining(CalendarEvent currentEvent) { - long currentElapsedInYear = SkyBlockCalendar.getElapsed() % SkyBlockCalendar.YEAR; - long eventEndTime = 0; - for (Long eventStartTime : currentEvent.times()) { - if (currentElapsedInYear >= eventStartTime && currentElapsedInYear < eventStartTime + currentEvent.duration()) { - eventEndTime = eventStartTime + currentEvent.duration(); - break; - } + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + + layout.slot(13, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7View your equipment, stats, and more!", "§e ")); + List stats = new ArrayList<>(List.of("Health", "Defense", "Speed", "Strength", "Intelligence", + "Crit Chance", "Crit Damage", "Swing Range" + )); + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (!value.equals(statistic.getBaseAdditiveValue()) || stats.contains(statistic.getDisplayName())) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); } - return eventEndTime - currentElapsedInYear; - } + }); + + lore.add("§e "); + lore.add("§eClick to view!"); + + return ItemStackCreator.getStackHead("§aYour SkyBlock Profile", + player.getPlayerSkin(), 1, + lore + ); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + new GUISkyBlockProfile().open(player); }); - - set(new GUIClickableItem(19) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISkills().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aYour Skills", Material.DIAMOND_SWORD, 1, - "§7View your Skill progression and", - "§7rewards.", - " ", - "§eClick to view!" - ); - } - }); - - set(new GUIClickableItem(20) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICollections().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(List.of( - "§7View all of the items available in", - "§7SkyBlock. Collect more of an item to", - "§7unlock rewards on your way to", - "§7becoming a master of SkyBlock!", - " " - )); - - player.getCollection().getDisplay(lore); - - lore.add(" "); - lore.add("§eClick to view!"); - return ItemStackCreator.getStack("§aCollections", Material.PAINTING, 1, lore.toArray(new String[0])); - } - }); - - set(new GUIClickableItem(31) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICrafting().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aCrafting Table", Material.CRAFTING_TABLE, 1, - "§7Opens the crafting grid.", - " ", - "§eClick to open!" - ); + layout.slot(22, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockLevelRequirement levelRequirement = player.getSkyBlockExperience().getLevel(); + SkyBlockLevelRequirement nextLevel = levelRequirement.getNextLevel(); + + return ItemStackCreator.getStackHead("§aSkyBlock Leveling", "3255327dd8e90afad681a19231665bea2bd06065a09d77ac1408837f9e0b242", 1, + "§7Your SkyBlock Level: §8[" + levelRequirement.getColor() + levelRequirement + "§8]", + " ", + "§7Determine how far you've", + "§7progressed in SkyBlock and earn", + "§7rewards from completing unique", + "§7tasks.", + " ", + "§7Progress to Level " + (nextLevel == null ? "§cMAX" : nextLevel), + player.getSkyBlockExperience().getNextLevelDisplay(), + " ", + "§eClick to view!" + ); + }, (click, c) -> new GUISkyBlockLevels().open((SkyBlockPlayer) c.player())); + + layout.slot(29, (s, c) -> ItemStackCreator.getStackHead("§aYour Bags", "961a918c0c49ba8d053e522cb91abc74689367b4d8aa06bfc1ba9154730985ff", 1, + "§7Different bags allow you to store", + "§7many different items inside!", + " ", + "§eClick to view!" + ), (click, c) -> new GUIYourBags().open((SkyBlockPlayer) c.player())); + + layout.slot(30, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStack("§aPets", Material.BONE, 1, + "§7View and manage all of your", + "§7Pets.", + " ", + "§7Level up your pets faster by", + "§7gaining XP in their favourite", + "§7skill!", + " ", + "§7Selected pet: " + (player.getPetData().getEnabledPet() == null ? "§cNone" : player.getPetData().getEnabledPet().getDisplayName()), + " ", + "§eClick to view!" + ); + }, (click, c) -> new GUIPets().open((SkyBlockPlayer) c.player())); + + layout.slot(21, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(List.of( + "§7Through your adventure, you will", + "§7unlock recipes for all kinds of", + "§7special items! You can view how to", + "§7craft these items here.", + " " + )); + + SkyBlockRecipe.getMissionDisplay(lore, player.getUuid()); + + lore.add(" "); + lore.add("§eClick to view!"); + return ItemStackCreator.getStack("§aRecipe Book", Material.BOOK, 1, lore); + }, (click, c) -> new GUIRecipeBook().open((SkyBlockPlayer) c.player())); + + layout.slot(25, (s, c) -> ItemStackCreator.getStack("§aStorage", Material.CHEST, 1, + "§7Store global items that you", + "§7want to access at any time", + "§7from anywhere here.", + " ", + "§eClick to view!" + ), (click, c) -> new GUIStorage().open((SkyBlockPlayer) c.player())); + + layout.slot(23, (s, c) -> ItemStackCreator.getStack("§aQuests & Chapters", Material.WRITABLE_BOOK, 1, + "§7Each island has its own series of", + "§bChapters §7for you to complete!", + " ", + "§7Complete tasks within a Chapter to", + "§7earn small §6rewards§7, or complete", + "§7entire Chapters to earn big ones!", + " ", + "§7Some islands also have §aQuests §7for", + "§7you to complete! Some items can only", + "§7be obtained through Quests.", + " ", + "§eClick to view!" + ), (click, c) -> new GUIMissionLog().open((SkyBlockPlayer) c.player())); + + layout.autoUpdating(24, (s, c) -> ItemStackCreator.getStack("§aCalendar and Events", Material.CLOCK, 1, getCalendarLore()), + (click, c) -> new GUICalendar().open((SkyBlockPlayer) c.player()), Duration.ofSeconds(1)); + + layout.slot(19, (s, c) -> ItemStackCreator.getStack("§aYour Skills", Material.DIAMOND_SWORD, 1, + "§7View your Skill progression and", + "§7rewards.", + " ", + "§eClick to view!" + ), (click, c) -> new GUISkills().open((SkyBlockPlayer) c.player())); + + layout.slot(20, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(List.of( + "§7View all of the items available in", + "§7SkyBlock. Collect more of an item to", + "§7unlock rewards on your way to", + "§7becoming a master of SkyBlock!", + " " + )); + + player.getCollection().getDisplay(lore); + + lore.add(" "); + lore.add("§eClick to view!"); + return ItemStackCreator.getStack("§aCollections", Material.PAINTING, 1, lore.toArray(new String[0])); + }, (click, c) -> new GUICollections().open((SkyBlockPlayer) c.player())); + + layout.slot(31, (s, c) -> ItemStackCreator.getStack("§aCrafting Table", Material.CRAFTING_TABLE, 1, + "§7Opens the crafting grid.", + " ", + "§eClick to open!" + ), (click, c) -> new GUICrafting().open((SkyBlockPlayer) c.player())); + + layout.slot(47, (s, c) -> ItemStackCreator.getStackHead("§bFast Travel", "f151cffdaf303673531a7651b36637cad912ba485643158e548d59b2ead5011", 1, + "§7Teleport to islands you've already", + "§7visited.", + " ", + "§8Right-click to warp home!", + "§eClick to pick location!" + ), (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (click.click() instanceof Click.Right) { + player.closeInventory(); + player.sendTo(ServerType.SKYBLOCK_ISLAND); + return; } + new GUIFastTravel().open(player); }); - set(new GUIClickableItem(47) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (e.getClick() instanceof Click.Right) { - player.closeInventory(); - player.sendTo(ServerType.SKYBLOCK_ISLAND); - return; - } - - new GUIFastTravel().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§bFast Travel", "f151cffdaf303673531a7651b36637cad912ba485643158e548d59b2ead5011", 1, - "§7Teleport to islands you've already", - "§7visited.", - " ", - "§8Right-click to warp home!", - "§eClick to pick location!" - ); - } - }); + layout.slot(48, (s, c) -> { + HypixelPlayer player = c.player(); + return ItemStackCreator.getStack("§aProfile Management", Material.NAME_TAG, 1, + "§7You can have multiple SkyBlock", + "§7profiles at the same time.", + " ", + "§7Each profile has its own island,", + "§7inventory, quest log...", + " ", + "§7Profiles: §e" + ((SkyBlockPlayer) player).getProfiles().getProfiles().size() + "§6/§e4", + " ", + "§eClick to manage!" + ); + }, (click, c) -> new GUIProfileManagement().open((SkyBlockPlayer) c.player())); + } - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIProfileManagement().open(player); + private static @NonNull List getCalendarLore() { + List currentEvents = SkyBlockCalendar.getCurrentEvents(); + boolean multipleEvents = currentEvents.size() > 1; + + List lore = new ArrayList<>(List.of("§7View the SkyBlock Calendar, upcoming", + "§7events, and event rewards!", + " ", + "§7Date: §a" + StringUtility.ntify(SkyBlockCalendar.getDay()) + " " + SkyBlockCalendar.getMonthName() + " " + SkyBlockCalendar.getYear(), + "")); + if(multipleEvents) { + lore.add("§7Current events: "); + for (CalendarEvent event : currentEvents) { + lore.add(event.getDisplayName(SkyBlockCalendar.getYear())); } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aProfile Management", Material.NAME_TAG, 1, - "§7You can have multiple SkyBlock", - "§7profiles at the same time.", + } else if (currentEvents.size() == 1) { + CalendarEvent currentEvent = currentEvents.getFirst(); + lore.add("§7Current event: " + currentEvent.getDisplayName(SkyBlockCalendar.getYear())); + long ticksRemaining = getTicksRemaining(currentEvent); + lore.add("§7Ends in: §e" + StringUtility.formatTimeLeft(ticksRemaining * 50L)); + } else { + lore.add("§7No current events."); + } + + lore.add(" "); + + Map upcomingEvents = SkyBlockCalendar.getEventsWithDurationUntil(1); + if (!upcomingEvents.isEmpty()) { + Map.Entry entry = upcomingEvents.entrySet().iterator().next(); + SkyBlockCalendar.EventInfo info = entry.getKey(); + CalendarEvent event = entry.getValue(); + + lore.add("§7Next event: " + event.getDisplayName(info.year())); + lore.add("§7Starting in: §e" + StringUtility.formatTimeLeft(info.timeUntilBegin() * 50L)); + } else { + lore.add("§7No upcoming events."); + } + + lore.addAll( + List.of( " ", - "§7Each profile has its own island,", - "§7inventory, quest log...", + "§8Also accessible via /calendar", " ", - "§7Profiles: §e" + player.getProfiles().getProfiles().size() + "§6/§e4", - " ", - "§eClick to manage!" - ); - } - }); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - + "§eClick to view!" + ) + ); + return lore; } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + private static long getTicksRemaining(CalendarEvent currentEvent) { + long currentElapsedInYear = SkyBlockCalendar.getElapsed() % SkyBlockCalendar.YEAR; + long eventEndTime = 0; + for (Long eventStartTime : currentEvent.times()) { + if (currentElapsedInYear >= eventStartTime && currentElapsedInYear < eventStartTime + currentEvent.duration()) { + eventEndTime = eventStartTime + currentEvent.duration(); + break; + } + } + return eventEndTime - currentElapsedInYear; } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockProfile.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockProfile.java index c825a96c4..f6b62fbbb 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockProfile.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockProfile.java @@ -35,7 +35,18 @@ public GUISkyBlockProfile() { @Override public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", + Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); set(GUIClickableItem.getCloseItem(49)); set(new GUIItem(2) { //Held Item diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java index 3bc44a426..b28ece043 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java @@ -23,7 +23,17 @@ public GUIYourBags() { public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(net.minestom.server.event.inventory.InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); SkyBlockPlayer player = (SkyBlockPlayer) e.player(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/calendar/GUICalendar.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/calendar/GUICalendar.java index d4be4ad39..d328c6ab4 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/calendar/GUICalendar.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/calendar/GUICalendar.java @@ -5,8 +5,10 @@ import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; import net.swofty.type.generic.gui.inventory.item.GUIItem; import net.swofty.type.generic.user.HypixelPlayer; @@ -60,7 +62,17 @@ public ItemStack.Builder getItem(HypixelPlayer player) { } - set(GUIClickableItem.getGoBackItem(39, new GUISkyBlockMenu())); + set(new GUIClickableItem(39) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); set(GUIClickableItem.getCloseItem(40)); updateItemStacks(getInventory(), getPlayer()); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java index 9be90039d..c6c9e10c5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java @@ -34,7 +34,17 @@ public GUICollections() { public void onOpen(InventoryGUIOpenEvent e) { fill(Material.BLACK_STAINED_GLASS_PANE, ""); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); ArrayList allCategories = CollectionCategories.getCategories(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java index 403447503..283592504 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java @@ -34,7 +34,18 @@ public GUIFastTravel() { @Override public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", + Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); set(GUIClickableItem.getCloseItem(49)); boolean shouldBePaper = e.player().getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevels.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevels.java index dc3092dca..238a2f675 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevels.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevels.java @@ -31,7 +31,18 @@ public GUISkyBlockLevels() { public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", + Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); set(new GUIClickableItem(50) { @Override @@ -105,7 +116,7 @@ public ItemStack.Builder getItem(HypixelPlayer p) { "§7Your level: " + level.getColor() + level, "§7You have: §b" + Math.round(player.getSkyBlockExperience().getTotalXP()) + " XP", " ", - "§7You have completed §3" + (new DecimalFormat("##.##").format((double) completedChallenges / totalChallenges * 100)) + "% §7of the total", + "§7You have completed §3" + (new java.text.DecimalFormat("##.##").format((double) completedChallenges / totalChallenges * 100)) + "% §7of the total", "§7SkyBlock XP Tasks."); } }); @@ -256,7 +267,7 @@ public boolean allowHotkeying() { } @Override - public void onBottomClick(InventoryPreClickEvent e) { + public void onBottomClick(net.minestom.server.event.inventory.InventoryPreClickEvent e) { e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileManagement.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileManagement.java index 38051104d..4add6194a 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileManagement.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileManagement.java @@ -39,7 +39,16 @@ public GUIProfileManagement() { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(31)); - set(GUIClickableItem.getGoBackItem(30, new GUISkyBlockMenu())); + set(new GUIClickableItem(30) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); } @SneakyThrows diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java index a0d264e40..7558ffe46 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java @@ -43,7 +43,17 @@ public GUIMissionLog() { public void onOpen(InventoryGUIOpenEvent e) { border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); display(false); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java index b92e3ad72..a60424439 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java @@ -36,7 +36,17 @@ public GUIRecipeBook() { public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); ArrayList allRecipes = new ArrayList<>(); allRecipes.addAll(ShapedRecipe.CACHED_RECIPES); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java index f65bb9f61..822c53ed6 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java @@ -33,7 +33,18 @@ public GUISkills() { public void onOpen(InventoryGUIOpenEvent e) { fill(Material.BLACK_STAINED_GLASS_PANE, ""); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", + Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); SkillCategories[] allCategories = SkillCategories.values(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java index 1b0451318..6306c05a5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java @@ -32,7 +32,17 @@ public GUIStorage() { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockMenu())); + set(new GUIClickableItem(48) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISkyBlockMenu()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); + } + }); set(new GUIItem(4) { @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/interactable/InteractableRegistry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/interactable/InteractableRegistry.java index 96745274c..0ac3517f0 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/interactable/InteractableRegistry.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/handlers/interactable/InteractableRegistry.java @@ -16,12 +16,12 @@ public class InteractableRegistry { static { register("SKYBLOCK_MENU_INTERACT", InteractableItemConfig.builder().rightClickHandler( - ((skyBlockPlayer, skyBlockItem) -> new GUISkyBlockMenu().open(skyBlockPlayer)) + ((skyBlockPlayer, skyBlockItem) -> skyBlockPlayer.openView(new GUISkyBlockMenu())) ).leftClickHandler( - ((skyBlockPlayer, skyBlockItem) -> new GUISkyBlockMenu().open(skyBlockPlayer)) + ((skyBlockPlayer, skyBlockItem) -> skyBlockPlayer.openView(new GUISkyBlockMenu())) ).inventoryInteractHandler( ((skyBlockPlayer, skyBlockItem) -> { - new GUISkyBlockMenu().open(skyBlockPlayer); + skyBlockPlayer.openView(new GUISkyBlockMenu()); return false; }) ).build()); From 57309f6246b7be21d7abab9af3daffc6b56d4175 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 10 Jan 2026 01:10:29 +0200 Subject: [PATCH 12/35] feat: continue adding pagination, sbmenu, etc --- .../command/commands/DebugViewCommand.java | 10 + .../type/generic/gui/v2/Components.java | 51 +- .../type/generic/gui/v2/PaginatedView.java | 174 ++++++ .../type/generic/gui/v2/ViewNavigator.java | 149 ++++++ .../type/generic/gui/v2/ViewSession.java | 16 +- .../generic/gui/v2/context/ViewContext.java | 26 + .../gui/v2/test/TestPaginatedView.java | 108 ++++ .../type/generic/user/HypixelPlayer.java | 11 +- .../type/hub/npcs/villagers/VillagerLeo.java | 2 +- .../type/hub/npcs/villagers/VillagerTom.java | 2 +- .../commands/ViewCollectionCommand.java | 4 +- .../commands/ViewRecipeCommand.java | 3 +- .../commands/ViewSkillCommand.java | 2 +- .../gui/inventories/GUIMinion.java | 2 +- .../inventories/abiphone/AbiphoneView.java | 178 +++++++ .../abiphone/GUIContactManagementView.java | 63 +++ .../inventories/sbmenu/GUISkyBlockMenu.java | 47 +- .../sbmenu/GUISkyBlockProfile.java | 494 +++++++----------- .../sbmenu/bags/GUIAccessoryBag.java | 2 +- .../inventories/sbmenu/bags/GUIQuiver.java | 2 +- .../sbmenu/bags/GUISackOfSacks.java | 2 +- .../inventories/sbmenu/bags/GUIYourBags.java | 263 +++------- .../sbmenu/bestiary/GUIBestiary.java | 2 +- .../sbmenu/calendar/GUICalendar.java | 117 ++--- .../collection/GUICollectionCategory.java | 167 +++--- .../sbmenu/collection/GUICollectionItem.java | 145 ++--- .../collection/GUICollectionReward.java | 115 ++-- .../sbmenu/collection/GUICollections.java | 162 ++---- .../sbmenu/collection/GUICraftedMinions.java | 2 +- .../sbmenu/fasttravel/GUIFastTravel.java | 223 ++++---- .../fasttravel/GUIFastTravelSubMenu.java | 221 ++++---- .../sbmenu/questlog/GUIFairySoulsGuide.java | 173 +++--- .../sbmenu/questlog/GUIMissionLog.java | 262 ++++------ .../sbmenu/recipe/GUIMinionRecipes.java | 69 +-- .../inventories/sbmenu/recipe/GUIRecipe.java | 220 +++----- .../sbmenu/recipe/GUIRecipeBook.java | 223 +++----- .../sbmenu/recipe/GUIRecipeCategory.java | 6 +- .../sbmenu/recipe/GUIRecipeSlayers.java | 2 +- .../sbmenu/skills/GUISkillCategory.java | 228 ++++---- .../inventories/sbmenu/skills/GUISkills.java | 175 +++---- .../sbmenu/stats/GUICombatStats.java | 2 +- .../sbmenu/stats/GUIGatheringStats.java | 2 +- .../sbmenu/stats/GUIMiscStats.java | 2 +- .../sbmenu/stats/GUIWisdomStats.java | 2 +- .../item/components/AbiphoneComponent.java | 3 +- .../components/RightClickRecipeComponent.java | 2 +- .../RedisSkywarsLobbyPropagatePartyEvent.java | 2 +- 47 files changed, 2050 insertions(+), 2088 deletions(-) create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewNavigator.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestPaginatedView.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/AbiphoneView.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/GUIContactManagementView.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java index 9afc53f8f..f4ecb65d3 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/DebugViewCommand.java @@ -7,6 +7,9 @@ import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.user.categories.Rank; +import java.util.List; +import java.util.stream.IntStream; + @CommandParameters(aliases = "debugview", usage = "/debugview", description = "opens a debug view", permission = Rank.STAFF, allowsConsole = false) public class DebugViewCommand extends HypixelCommand { @Override @@ -49,5 +52,12 @@ public void registerUsage(MinestomCommand command) { HypixelPlayer player = (HypixelPlayer) sender; // safe cast player.openView(new TestNoStateView()); }), new ArgumentLiteral("noState")); + + // paginated + command.addSyntax(((sender, context) -> { + HypixelPlayer player = (HypixelPlayer) sender; // safe cast + List oneTo100 = IntStream.rangeClosed(1, 100).boxed().toList(); + player.openView(new TestPaginatedView(), new TestPaginatedView.State(oneTo100, 1, "")); + }), new ArgumentLiteral("paginated")); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java index f66004672..15f3166cc 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java @@ -6,6 +6,7 @@ import net.minestom.server.item.Material; import net.minestom.server.item.component.TooltipDisplay; import net.swofty.type.generic.gui.v2.context.ViewContext; +import org.tinylog.Logger; import java.util.Collection; import java.util.List; @@ -21,6 +22,8 @@ public final class Components { .set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())); public static final ItemStack.Builder CLOSE_BUTTON = ItemStack.builder(Material.BARRIER) .set(DataComponents.CUSTOM_NAME, Component.text("§cClose")); + + // TODO: show the name of the previous view public static final ItemStack.Builder BACK_BUTTON = ItemStack.builder(Material.ARROW) .set(DataComponents.CUSTOM_NAME, Component.text("§aGo Back")); @@ -32,13 +35,59 @@ public static void close(ViewLayout layout, int slot) { layout.slot(slot, (s, c) -> CLOSE_BUTTON, (click, ctx) -> ctx.player().closeInventory()); } + public static boolean back(ViewLayout layout, int slot, ViewContext context) { + ViewNavigator navigator = ViewNavigator.get(context.player()); + if (!navigator.hasStack()) { + Logger.info( + "Tried to add back button to view layout for player {} but there is no view to go back to! Navigator information: {}", + context.player().getUsername(), navigator + ); + return false; + } + layout.slot(slot, (s, c) -> BACK_BUTTON, (click, ctx) -> { + ViewNavigator.get(ctx.player()).pop(); + }); + return true; + } + + public static boolean back(ViewLayout layout, int slot, ViewContext context, ItemStack.Builder customButton) { + ViewNavigator navigator = ViewNavigator.get(context.player()); + if (!navigator.hasStack()) { + return false; + } + layout.slot(slot, (s, c) -> customButton, (click, ctx) -> { + ViewNavigator.get(ctx.player()).pop(); + }); + return true; + } + + public static void backAlways(ViewLayout layout, int slot) { + layout.slot(slot, (s, c) -> BACK_BUTTON, (click, ctx) -> { + ViewNavigator navigator = ViewNavigator.get(ctx.player()); + if (!navigator.pop()) { + ctx.player().closeInventory(); + } + }); + } + + public static void backOrClose(ViewLayout layout, int slot, ViewContext context) { + ViewNavigator navigator = ViewNavigator.get(context.player()); + if (navigator.hasStack()) { + layout.slot(slot, (s, c) -> BACK_BUTTON, (click, ctx) -> { + ViewNavigator.get(ctx.player()).pop(); + }); + } else { + layout.slot(slot, (s, c) -> CLOSE_BUTTON, (click, ctx) -> ctx.player().closeInventory()); + } + } + public static void back(ViewLayout layout, int slot, View target, Object targetState) { layout.slot(slot, (s, c) -> BACK_BUTTON, (click, ctx) -> open(ctx, target, targetState)); } @SuppressWarnings("unchecked") public static void open(ViewContext ctx, View view, Object state) { - ViewSession.open(view, ctx.player(), (T) state); + ViewNavigator.get(ctx.player()).push(view, (T) state); } public static void editableSlot(ViewLayout layout, int slot, Function itemGetter, SlotChangeHandler onChange) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java new file mode 100644 index 000000000..c5bc3395f --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java @@ -0,0 +1,174 @@ +package net.swofty.type.generic.gui.v2; + +import net.kyori.adventure.text.Component; +import net.minestom.server.component.DataComponents; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.minestom.server.item.component.TooltipDisplay; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.List; +import java.util.Set; + +public abstract class PaginatedView> implements View { + + protected static final ItemStack.Builder PREV_ARROW = ItemStack.builder(Material.ARROW) + .set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")); + protected static final ItemStack.Builder NEXT_ARROW = ItemStack.builder(Material.ARROW) + .set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")); + protected static final ItemStack.Builder SEARCH_ICON = ItemStack.builder(Material.BIRCH_SIGN) + .set(DataComponents.CUSTOM_NAME, Component.text("§aSearch")); + protected static final ItemStack.Builder FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE) + .set(DataComponents.CUSTOM_NAME, Component.text(" ")) + .set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())); + + public interface PaginatedState { + List items(); + int page(); + String query(); + PaginatedState withPage(int page); + PaginatedState withQuery(String query); + PaginatedState withItems(List items); + } + + @Override + public void layout(ViewLayout layout, S state, ViewContext ctx) { + layoutBackground(layout, state, ctx); + List filteredItems = getFilteredItems(state); + int[] slots = getPaginatedSlots(); + int itemsPerPage = slots.length; + int totalPages = Math.max(1, (int) Math.ceil((double) filteredItems.size() / itemsPerPage)); + int currentPage = Math.min(state.page(), totalPages - 1); + + // Calculate page boundaries + int startIndex = currentPage * itemsPerPage; + int endIndex = Math.min(startIndex + itemsPerPage, filteredItems.size()); + List pageItems = startIndex < filteredItems.size() + ? filteredItems.subList(startIndex, endIndex) + : List.of(); + + // Render paginated items + for (int i = 0; i < slots.length; i++) { + int slot = slots[i]; + if (i < pageItems.size()) { + T item = pageItems.get(i); + int itemIndex = startIndex + i; + layout.slot(slot, + (s, c) -> renderItem(item, itemIndex, ctx.player()), + (click, viewCtx) -> onItemClick(click, viewCtx, item, itemIndex)); + } else { + layout.slot(slot, (s, c) -> ItemStack.AIR.builder()); + } + } + + layoutNavigation(layout, state, ctx, currentPage, totalPages); + layoutCustom(layout, state, ctx); + } + + protected List getFilteredItems(S state) { + String query = state.query(); + if (query == null || query.isEmpty()) { + return state.items(); + } + return state.items().stream() + .filter(item -> !shouldFilterFromSearch(query, item)) + .toList(); + } + + protected void layoutBackground(ViewLayout layout, S state, ViewContext ctx) { + layout.filler(FILLER); + } + + protected void layoutNavigation(ViewLayout layout, S state, ViewContext ctx, int currentPage, int totalPages) { + int prevSlot = getPreviousPageSlot(); + int nextSlot = getNextPageSlot(); + int searchSlot = getSearchSlot(); + + if (prevSlot >= 0) { + if (currentPage > 0) { + layout.slot(prevSlot, (s, c) -> createPrevPageItem(currentPage, totalPages), + (click, viewCtx) -> viewCtx.session(Object.class).updateUnchecked(s -> { + @SuppressWarnings("unchecked") + S typedState = (S) s; + return typedState.withPage(currentPage - 1); + })); + } else { + layout.slot(prevSlot, FILLER); + } + } + + if (nextSlot >= 0) { + if (currentPage < totalPages - 1) { + layout.slot(nextSlot, (s, c) -> createNextPageItem(currentPage, totalPages), + (click, viewCtx) -> viewCtx.session(Object.class).updateUnchecked(s -> { + @SuppressWarnings("unchecked") + S typedState = (S) s; + return typedState.withPage(currentPage + 1); + })); + } else { + layout.slot(nextSlot, FILLER); + } + } + + if (searchSlot >= 0) { + layout.slot(searchSlot, (s, c) -> createSearchItem(state.query()), + this::onSearchClick); + } + } + + protected abstract int getSearchSlot(); + + protected abstract int getNextPageSlot(); + + protected abstract int getPreviousPageSlot(); + + protected void layoutCustom(ViewLayout layout, S state, ViewContext ctx) { + } + + protected ItemStack.Builder createPrevPageItem(int currentPage, int totalPages) { + return ItemStack.builder(Material.ARROW) + .set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")) + .set(DataComponents.LORE, List.of( + Component.text("§7Page " + currentPage + " of " + totalPages) + )); + } + + protected ItemStack.Builder createNextPageItem(int currentPage, int totalPages) { + return ItemStack.builder(Material.ARROW) + .set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")) + .set(DataComponents.LORE, List.of( + Component.text("§7Page " + (currentPage + 2) + " of " + totalPages) + )); + } + + protected ItemStack.Builder createSearchItem(String currentQuery) { + String queryDisplay = currentQuery.isEmpty() ? "None" : currentQuery; + return ItemStack.builder(Material.BIRCH_SIGN) + .set(DataComponents.CUSTOM_NAME, Component.text("§aSearch")) + .set(DataComponents.LORE, List.of( + Component.text("§7Query: §e" + queryDisplay), + Component.text(""), + Component.text("§eClick to search!") + )); + } + + protected void onSearchClick(ClickContext click, ViewContext ctx) { + } + + protected abstract int[] getPaginatedSlots(); + + protected abstract ItemStack.Builder renderItem(T item, int index, HypixelPlayer player); + + protected abstract void onItemClick(ClickContext click, ViewContext ctx, T item, int index); + + protected abstract boolean shouldFilterFromSearch(String query, T item); + + public static int[] createGrid(int startSlot, int endSlot) { + return Layouts.rectangle(startSlot, endSlot).stream().mapToInt(Integer::intValue).toArray(); + } + +} + + diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewNavigator.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewNavigator.java new file mode 100644 index 000000000..0036006e8 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewNavigator.java @@ -0,0 +1,149 @@ +package net.swofty.type.generic.gui.v2; + +import lombok.Getter; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public final class ViewNavigator { + + private static final Map NAVIGATORS = new ConcurrentHashMap<>(); + + private final HypixelPlayer player; + private final Deque> stack = new ArrayDeque<>(); + @Getter + private ViewSession currentSession; + + private ViewNavigator(HypixelPlayer player) { + this.player = player; + } + + public static ViewNavigator get(HypixelPlayer player) { + return NAVIGATORS.computeIfAbsent(player, ViewNavigator::new); + } + + public static Optional find(HypixelPlayer player) { + return Optional.ofNullable(NAVIGATORS.get(player)); + } + + public static void remove(HypixelPlayer player) { + ViewNavigator nav = NAVIGATORS.remove(player); + if (nav != null) { + nav.clear(); + } + } + + public ViewSession push(View view, S state) { + if (currentSession != null && !currentSession.isClosed()) { + pushCurrentToStack(); + currentSession.close(ViewSession.CloseReason.REPLACED); + } + + ViewSession session = ViewSession.open(view, player, state); + this.currentSession = session; + + session.onClose(reason -> { + if (reason == ViewSession.CloseReason.PLAYER_EXITED) { + clear(); + } + }); + + return session; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void pushCurrentToStack() { + if (currentSession == null) return; + ViewSession session = currentSession; + stack.push(new NavigationEntry(session.view(), session.state())); + } + + public ViewSession replace(View view, S state) { + if (currentSession != null && !currentSession.isClosed()) { + currentSession.close(ViewSession.CloseReason.REPLACED); + } + + ViewSession session = ViewSession.open(view, player, state); + this.currentSession = session; + + session.onClose(reason -> { + if (reason == ViewSession.CloseReason.PLAYER_EXITED) { + clear(); + } + }); + + return session; + } + + public boolean pop() { + if (stack.isEmpty()) { + if (currentSession != null && !currentSession.isClosed()) { + currentSession.close(ViewSession.CloseReason.PLAYER_EXITED); + } + currentSession = null; + return false; + } + + if (currentSession != null && !currentSession.isClosed()) { + currentSession.close(ViewSession.CloseReason.REPLACED); + } + + NavigationEntry entry = stack.pop(); + ViewSession session = openEntry(entry); + this.currentSession = session; + + session.onClose(reason -> { + if (reason == ViewSession.CloseReason.PLAYER_EXITED) { + clear(); + } + }); + + return true; + } + + private ViewSession openEntry(NavigationEntry entry) { + return ViewSession.open(entry.view(), player, entry.state()); + } + + public void popTo(int levels) { + for (int i = 0; i < levels - 1 && !stack.isEmpty(); i++) { + stack.pop(); + } + pop(); + } + + public void popToRoot() { + while (stack.size() > 1) { + stack.pop(); + } + pop(); + } + + public void clear() { + stack.clear(); + if (currentSession != null && !currentSession.isClosed()) { + currentSession.close(ViewSession.CloseReason.SERVER_EXITED); + } + currentSession = null; + } + + public boolean hasStack() { + return !stack.isEmpty(); + } + + public int depth() { + return stack.size(); + } + + public Optional> peekPrevious() { + return Optional.ofNullable((NavigationEntry) stack.peek()); + } + + record NavigationEntry(View view, S state) {} + + private static View getView(ViewSession session) { + return session.view(); + } +} + diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index fe676746e..1c68f142b 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -29,6 +29,8 @@ public final class ViewSession { + @Getter + @Accessors(fluent = true) private final View view; @Getter @Accessors(fluent = true) @@ -46,6 +48,7 @@ public final class ViewSession { private Consumer onCloseHandler; @Getter private boolean closed; + private boolean suppressCloseEvent; @Getter @Accessors(fluent = true) @@ -179,7 +182,10 @@ private void handleSlotChange(int slot, ItemStack oldItem, ItemStack newItem) { } private void onCloseEvent(InventoryCloseEvent event) { - if (event.getInventory() != inventory) return; + if (event.getInventory() != inventory || suppressCloseEvent) { + suppressCloseEvent = false; + return; + } close(CloseReason.PLAYER_EXITED); } @@ -189,8 +195,6 @@ public void render() { ViewConfiguration config = view.configuration(); cachedLayout = new ViewLayout<>(config.getInventoryType()); view.layout(cachedLayout, state, context); - - Set previousComponents = new HashSet<>(componentSlots.keySet()); componentSlots.clear(); @SuppressWarnings("unchecked") @@ -217,9 +221,6 @@ public void render() { if (component.updateInterval() != null) { scheduleAutoUpdate(slot, component); } - if (component.id() != null) { - previousComponents.remove(component.id()); - } }); view.onRefresh(state, context); @@ -300,6 +301,9 @@ public ViewSession refreshEvery(Duration interval) { public void close(CloseReason reason) { if (closed) return; + if (reason == CloseReason.REPLACED) { + suppressCloseEvent = true; + } closed = true; autoUpdateTasks.values().forEach(Task::cancel); diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java index 59656d1e1..8a6908c1d 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java @@ -1,6 +1,8 @@ package net.swofty.type.generic.gui.v2.context; import net.minestom.server.inventory.Inventory; +import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.v2.ViewNavigator; import net.swofty.type.generic.gui.v2.ViewSession; import net.swofty.type.generic.user.HypixelPlayer; @@ -13,4 +15,28 @@ public record ViewContext( public ViewSession session(Class stateType) { return (ViewSession) session; } + + public ViewNavigator navigator() { + return ViewNavigator.get(player); + } + + public ViewSession push(View view, S state) { + return navigator().push(view, state); + } + + public ViewSession push(View view) { + return navigator().push(view, null); + } + + public boolean pop() { + return navigator().pop(); + } + + public ViewSession replace(View view, S state) { + return navigator().replace(view, state); + } + + public boolean viewStack() { + return navigator().hasStack(); + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestPaginatedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestPaginatedView.java new file mode 100644 index 000000000..58176ff0d --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestPaginatedView.java @@ -0,0 +1,108 @@ +package net.swofty.type.generic.gui.v2.test; + +import net.kyori.adventure.text.Component; +import net.minestom.server.component.DataComponents; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.List; +import java.util.stream.IntStream; + +public final class TestPaginatedView extends PaginatedView { + + private static final int[] PAGINATED_SLOTS = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; + + @Override + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> "Test Paginated View - Page " + (state.page() + 1), + InventoryType.CHEST_6_ROW + ); + } + + @Override + protected int[] getPaginatedSlots() { + return PAGINATED_SLOTS; + } + + @Override + protected ItemStack.Builder renderItem(Integer item, int index, HypixelPlayer player) { + return ItemStack.builder(Material.PAPER) + .set(DataComponents.CUSTOM_NAME, Component.text("§eItem #" + item)) + .set(DataComponents.LORE, List.of( + Component.text("§7Index: §a" + index), + Component.text(""), + Component.text("§eClick to select!") + )); + } + + @Override + protected void onItemClick(ClickContext click, ViewContext ctx, Integer item, int index) { + ctx.player().sendMessage(Component.text("§aYou clicked item #" + item + " at index " + index)); + } + + @Override + protected boolean shouldFilterFromSearch(String query, Integer item) { + return !String.valueOf(item).contains(query); + } + + @Override + protected void layoutCustom(ViewLayout layout, State state, ViewContext ctx) { + Components.close(layout, 49); + if (!Components.back(layout, 48, ctx)) { + layout.slot(48, FILLER); + } + } + + @Override + protected int getPreviousPageSlot() { + return 45; + } + + @Override + protected int getNextPageSlot() { + return 53; + } + + @Override + protected int getSearchSlot() { + return -1; + } + + public record State(List items, int page, String query) implements PaginatedState { + public State(List items) { + this(items, 0, ""); + } + + public static State withItems(int count) { + return new State(IntStream.rangeClosed(1, count).boxed().toList()); + } + + @Override + public PaginatedState withPage(int page) { + return new State(items, page, query); + } + + @Override + public PaginatedState withQuery(String query) { + return new State(items, 0, query); + } + + @Override + public PaginatedState withItems(List items) { + return new State(items, page, query); + } + } + +} + diff --git a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java index a910de07b..e18a72d04 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java +++ b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java @@ -19,10 +19,7 @@ import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.achievement.PlayerAchievementHandler; import net.swofty.type.generic.experience.PlayerExperienceHandler; -import net.swofty.type.generic.gui.v2.StatelessView; -import net.swofty.type.generic.gui.v2.ViewSession; -import net.swofty.type.generic.gui.v2.StatefulView; -import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.v2.*; import net.swofty.type.generic.quest.PlayerQuestHandler; import net.swofty.type.generic.user.categories.Rank; import org.jetbrains.annotations.NotNull; @@ -81,15 +78,15 @@ public DatapointChatType.ChatType getChatType() { } public ViewSession openView(View view, S state) { - return ViewSession.open(view, this, state); + return ViewNavigator.get(this).push(view, state); } public ViewSession openView(View view) { Objects.requireNonNull(view, "View is null"); if (view instanceof StatefulView state) { - return ViewSession.open(view, this, state.initialState()); + return ViewNavigator.get(this).push(view, state.initialState()); } else if (view instanceof StatelessView state) { - return ViewSession.open(view, this, null); + return ViewNavigator.get(this).push(view, null); } else { throw new IllegalArgumentException("View must be either StatefulView or StatelessView"); } diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLeo.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLeo.java index e02c81212..54e04b67a 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLeo.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLeo.java @@ -53,7 +53,7 @@ public void onClick(NPCInteractEvent e) { if (System.currentTimeMillis() - (long) data.getMission("speak_to_villagers").getKey().getCustomData().get("last_updated") < 30) { setDialogue(player, "quest-hello").thenRun(() -> { - new GUIRecipe(ItemType.LEAFLET_CHESTPLATE, null).open(player); + //new GUIRecipe(ItemType.LEAFLET_CHESTPLATE, null).open(player); }); return; } diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerTom.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerTom.java index d11b4f387..4d44d3dc1 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerTom.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerTom.java @@ -53,7 +53,7 @@ public void onClick(NPCInteractEvent e) { if (System.currentTimeMillis() - (long) data.getMission("speak_to_villagers").getKey().getCustomData().get("last_updated") < 30) { setDialogue(player, "quest-hello").thenRun(() -> { - new GUIRecipe(ItemType.PROMISING_AXE, null).open(player); + //new GUIRecipe(ItemType.PROMISING_AXE, null).open(player); }); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewCollectionCommand.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewCollectionCommand.java index 69bc5a87a..2efa26199 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewCollectionCommand.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewCollectionCommand.java @@ -6,7 +6,7 @@ import net.swofty.type.skyblockgeneric.collection.CollectionCategories; import net.swofty.type.generic.command.CommandParameters; import net.swofty.type.generic.command.HypixelCommand; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.collection.GUICollectionItem; +import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockProfile; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.generic.user.categories.Rank; @@ -31,7 +31,7 @@ public void registerUsage(MinestomCommand command) { return; } - new GUICollectionItem(itemTypeLinker).open((SkyBlockPlayer) sender); + ((SkyBlockPlayer) sender).openView(new GUISkyBlockProfile()); }, itemArgument); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewRecipeCommand.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewRecipeCommand.java index 123c80ba2..16f11d18c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewRecipeCommand.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewRecipeCommand.java @@ -5,6 +5,7 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.command.CommandParameters; import net.swofty.type.generic.command.HypixelCommand; +import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockProfile; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe.GUIRecipe; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.generic.user.categories.Rank; @@ -23,7 +24,7 @@ public void registerUsage(MinestomCommand command) { if (!permissionCheck(sender)) return; final ItemType item = context.get(itemArgument); - new GUIRecipe(item, null).open((SkyBlockPlayer) sender); + ((SkyBlockPlayer) sender).openView(new GUIRecipe(item, null)); }, itemArgument); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewSkillCommand.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewSkillCommand.java index b5bf65c39..7597bd475 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewSkillCommand.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewSkillCommand.java @@ -23,7 +23,7 @@ public void registerUsage(MinestomCommand command) { if (!permissionCheck(sender)) return; final SkillCategories skillCategory = context.get(skillArgument); - new GUISkillCategory(skillCategory, 0).open((SkyBlockPlayer) sender); + ((SkyBlockPlayer) sender).openView(new GUISkillCategory(skillCategory, 0)); }, skillArgument); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIMinion.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIMinion.java index 3e262bd9f..ea76424aa 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIMinion.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUIMinion.java @@ -176,7 +176,7 @@ public ItemStack.Builder getItem(HypixelPlayer p) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIMinionRecipes(minion.getMinion(), GUIMinion.this).open(player); + // player.openView(new ) } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/AbiphoneView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/AbiphoneView.java new file mode 100644 index 000000000..9be928fc7 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/AbiphoneView.java @@ -0,0 +1,178 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.abiphone; + +import net.kyori.adventure.text.Component; +import net.minestom.server.MinecraftServer; +import net.minestom.server.component.DataComponents; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.inventory.click.Click; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.minestom.server.timer.TaskSchedule; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.abiphone.AbiphoneNPC; +import net.swofty.type.skyblockgeneric.abiphone.AbiphoneRegistry; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; + +import java.util.List; + +public final class AbiphoneView extends PaginatedView { + + private static final int[] PAGINATED_SLOTS = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; + + @Override + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> state.abiphone().getCleanName(), + InventoryType.CHEST_6_ROW + ); + } + + @Override + protected int[] getPaginatedSlots() { + return PAGINATED_SLOTS; + } + + @Override + protected ItemStack.Builder renderItem(AbiphoneNPC npc, int index, HypixelPlayer player) { + return ItemStackCreator.updateLore( + npc.getIcon().set(DataComponents.CUSTOM_NAME, Component.text("§f" + npc.getName())), + List.of( + "§7" + npc.getDescription(), + "", + "§8Right-click to manage!", + "§eLeft-click to call!" + ) + ); + } + + @Override + protected void onItemClick(ClickContext click, ViewContext ctx, AbiphoneNPC npc, int index) { + if (click.click() instanceof Click.Left) { + ctx.player().closeInventory(); + initiateCall(ctx.player(), npc); + } else if (click.click() instanceof Click.Right) { + ctx.push(new GUIContactManagementView(), new GUIContactManagementView.State(click.state().abiphone(), npc)); + } + } + + private void initiateCall(HypixelPlayer player, AbiphoneNPC npc) { + player.sendMessage(Component.text("§e✆ RING...")); + MinecraftServer.getSchedulerManager().buildTask(() -> { + player.sendMessage(Component.text("§e✆ RING... RING...")); + MinecraftServer.getSchedulerManager().buildTask(() -> { + player.sendMessage(Component.text("§e✆ RING... RING... RING...")); + MinecraftServer.getSchedulerManager().buildTask(() -> { + npc.onCall(player); + }).delay(TaskSchedule.seconds(1)).schedule(); + }).delay(TaskSchedule.seconds(1)).schedule(); + }).delay(TaskSchedule.seconds(1)).schedule(); + } + + @Override + protected boolean shouldFilterFromSearch(String query, AbiphoneNPC item) { + return !item.getName().toLowerCase().contains(query.toLowerCase()); + } + + @Override + protected void layoutCustom(ViewLayout layout, State state, ViewContext ctx) { + List contacts = state.abiphone().getAttributeHandler().getAbiphoneNPCs(); + Components.close(layout, 49); + layout.slot(50, (s, c) -> ItemStackCreator.getStack( + "§aSort §bTO-DO", + Material.HOPPER, + 1, + "", + "§7 First Added", + "§7 Alphabetical", + "§7 Last Called", + "§7 Most Called", + "§7 Do Not Disturb First", + "", + "§bRight-click to go backwards!", + "§eClick to switch!" + ), (click, viewCtx) -> { + // TODO: Implement sorting + }); + + layout.slot(51, (s, c) -> ItemStackCreator.getStack( + "§aContacts Directory §bTO-DO", + Material.BOOK, + 1, + "§7Browse through all NPCs in SkyBlock", + "§7which both own an Abiphone AND are", + "§7willing to add you as a contact.", + "", + "§7Your contacts: §a" + contacts.size() + "§b/" + AbiphoneRegistry.getRegisteredContactNPCs().size(), + "", + "§eClick to view contacts!" + ), (click, viewCtx) -> { + // TODO: Open contacts directory + }); + } + + @Override + protected int getPreviousPageSlot() { + return 45; + } + + @Override + protected int getNextPageSlot() { + return 53; + } + + @Override + protected int getSearchSlot() { + return -1; + } + + public record State( + SkyBlockItem abiphone, + List items, + int page, + String query, + SortType sortType + ) implements PaginatedState { + + public State(SkyBlockItem abiphone) { + this(abiphone, abiphone.getAttributeHandler().getAbiphoneNPCs(), 0, "", SortType.ALPHABETICAL); + } + + @Override + public PaginatedState withPage(int page) { + return new State(abiphone, items, page, query, sortType); + } + + @Override + public PaginatedState withQuery(String query) { + return new State(abiphone, items, 0, query, sortType); + } + + @Override + public PaginatedState withItems(List items) { + return new State(abiphone, items, page, query, sortType); + } + + public State withSortType(SortType sortType) { + return new State(abiphone, items, page, query, sortType); + } + } + + public enum SortType { + FIRST_ADDED, + ALPHABETICAL, + LAST_CALLED, + MOST_CALLED, + DO_NOT_DISTURB_FIRST + } + +} + diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/GUIContactManagementView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/GUIContactManagementView.java new file mode 100644 index 000000000..44eca50ed --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/GUIContactManagementView.java @@ -0,0 +1,63 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.abiphone; + +import net.kyori.adventure.text.Component; +import net.minestom.server.component.DataComponents; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.abiphone.AbiphoneNPC; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; + +import java.util.List; + +public final class GUIContactManagementView implements View { + + @Override + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> "Contact Management", + InventoryType.CHEST_6_ROW + ); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + layout.filler(Components.FILLER); + layout.slot(4, (s, c) -> ItemStackCreator.updateLore( + s.npc().getIcon().set(DataComponents.CUSTOM_NAME, Component.text("§f" + s.npc().getName())), + List.of("§7" + s.npc().getDescription()) + )); + + layout.slot(31, (s, c) -> ItemStackCreator.getStack( + "§cRemove Contact", + Material.FEATHER, + 1, + List.of( + "§7In case you're no longer friends, or", + "§7whatever other reason.", + " ", + "§eClick to remove!" + ) + ), (click, viewCtx) -> { + state.abiphone().getAttributeHandler().removeAbiphoneNPC(state.npc()); + viewCtx.player().sendMessage(Component.text("§c✆ Removed " + state.npc().getName() + " §cfrom your contacts!")); + + if (!viewCtx.pop()) { + viewCtx.player().closeInventory(); + } + }); + + if (!Components.back(layout, 48, ctx)) { + layout.slot(48, (s, c) -> Components.BACK_BUTTON, (click, viewCtx) -> { + ViewSession.open(new AbiphoneView(), viewCtx.player(), new AbiphoneView.State(state.abiphone())); + }); + } + + Components.close(layout, 49); + } + + public record State(SkyBlockItem abiphone, AbiphoneNPC npc) {} +} + diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java index add9e47f9..dee3113a7 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java @@ -18,6 +18,7 @@ import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.GUISkyBlockLevels; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.profiles.GUIProfileManagement; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.questlog.GUIMissionLog; +import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe.GUIRecipe; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe.GUIRecipeBook; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.skills.GUISkills; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.storage.GUIStorage; @@ -67,7 +68,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont ); }, (click, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); - new GUISkyBlockProfile().open(player); + player.openView(new GUISkyBlockProfile()); }); layout.slot(22, (s, c) -> { @@ -95,7 +96,9 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7many different items inside!", " ", "§eClick to view!" - ), (click, c) -> new GUIYourBags().open((SkyBlockPlayer) c.player())); + ), (click, c) -> { + c.player().openView(new GUIYourBags()); + }); layout.slot(30, (s, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); @@ -128,7 +131,9 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont lore.add(" "); lore.add("§eClick to view!"); return ItemStackCreator.getStack("§aRecipe Book", Material.BOOK, 1, lore); - }, (click, c) -> new GUIRecipeBook().open((SkyBlockPlayer) c.player())); + }, (click, c) -> { + c.player().openView(new GUIRecipeBook()); + }); layout.slot(25, (s, c) -> ItemStackCreator.getStack("§aStorage", Material.CHEST, 1, "§7Store global items that you", @@ -151,17 +156,17 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7be obtained through Quests.", " ", "§eClick to view!" - ), (click, c) -> new GUIMissionLog().open((SkyBlockPlayer) c.player())); + ), (click, c) -> c.player().openView(new GUIMissionLog())); layout.autoUpdating(24, (s, c) -> ItemStackCreator.getStack("§aCalendar and Events", Material.CLOCK, 1, getCalendarLore()), - (click, c) -> new GUICalendar().open((SkyBlockPlayer) c.player()), Duration.ofSeconds(1)); + (click, c) -> c.push(new GUICalendar()), Duration.ofSeconds(1)); layout.slot(19, (s, c) -> ItemStackCreator.getStack("§aYour Skills", Material.DIAMOND_SWORD, 1, "§7View your Skill progression and", "§7rewards.", " ", "§eClick to view!" - ), (click, c) -> new GUISkills().open((SkyBlockPlayer) c.player())); + ), (click, c) -> c.player().openView(new GUISkills())); layout.slot(20, (s, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); @@ -178,7 +183,10 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont lore.add(" "); lore.add("§eClick to view!"); return ItemStackCreator.getStack("§aCollections", Material.PAINTING, 1, lore.toArray(new String[0])); - }, (click, c) -> new GUICollections().open((SkyBlockPlayer) c.player())); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + player.openView(new GUICollections()); + }); layout.slot(31, (s, c) -> ItemStackCreator.getStack("§aCrafting Table", Material.CRAFTING_TABLE, 1, "§7Opens the crafting grid.", @@ -199,7 +207,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont player.sendTo(ServerType.SKYBLOCK_ISLAND); return; } - new GUIFastTravel().open(player); + player.openView(new GUIFastTravel()); }); layout.slot(48, (s, c) -> { @@ -266,15 +274,16 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont return lore; } - private static long getTicksRemaining(CalendarEvent currentEvent) { - long currentElapsedInYear = SkyBlockCalendar.getElapsed() % SkyBlockCalendar.YEAR; - long eventEndTime = 0; - for (Long eventStartTime : currentEvent.times()) { - if (currentElapsedInYear >= eventStartTime && currentElapsedInYear < eventStartTime + currentEvent.duration()) { - eventEndTime = eventStartTime + currentEvent.duration(); - break; - } - } - return eventEndTime - currentElapsedInYear; - } + private static long getTicksRemaining(CalendarEvent currentEvent) { + long currentElapsedInYear = SkyBlockCalendar.getElapsed() % SkyBlockCalendar.YEAR; + long eventEndTime = 0; + for (Long eventStartTime : currentEvent.times()) { + if (currentElapsedInYear >= eventStartTime && currentElapsedInYear < eventStartTime + currentEvent.duration().toMillis() / 50) { + eventEndTime = eventStartTime + currentEvent.duration().toMillis() / 50; + break; + } + } + return eventEndTime - currentElapsedInYear; + } + } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockProfile.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockProfile.java index f6b62fbbb..1faf9849d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockProfile.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockProfile.java @@ -1,18 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.statistics.ItemStatistic; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.stats.GUICombatStats; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.stats.GUIGatheringStats; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.stats.GUIMiscStats; @@ -26,330 +21,231 @@ import java.util.ArrayList; import java.util.List; -public class GUISkyBlockProfile extends HypixelInventoryGUI { +public class GUISkyBlockProfile extends StatelessView { - public GUISkyBlockProfile() { - super("Your Equipment and Stats", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Your Equipment and Stats", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", - Material.ARROW, 1, "§7To SkyBlock Menu"); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + // Held Item + layout.slot(2, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (!player.getItemInMainHand().isAir()) { + return ItemStackCreator.getFromStack(player.getItemInMainHand()); + } else { + return ItemStackCreator.getStack("§7Empty Held Item Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); } }); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIItem(2) { //Held Item - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!player.getItemInMainHand().isAir()) { - return ItemStackCreator.getFromStack(player.getItemInMainHand()); - } else { - return ItemStackCreator.getStack("§7Empty Held Item Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); - } + // Helmet + layout.slot(11, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (!player.getHelmet().isAir()) { + return ItemStackCreator.getFromStack(player.getHelmet()); + } else { + return ItemStackCreator.getStack("§7Empty Helmet Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); + } + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockItem cursorItem = new SkyBlockItem(player.getInventory().getCursorItem()); + if (!player.getHelmet().isAir() && player.getInventory().getCursorItem().isAir()) { + player.addAndUpdateItem(player.getHelmet()); + player.setHelmet(ItemStack.AIR); + c.player().openView(new GUISkyBlockProfile()); + } else if (cursorItem.hasComponent(StandardItemComponent.class) + && cursorItem.getComponent(StandardItemComponent.class).getType() == StandardItemComponent.StandardItemType.HELMET + && player.getHelmet().isAir()) { + player.setHelmet(player.getInventory().getCursorItem()); + c.inventory().setCursorItem(player, ItemStack.AIR); + c.player().openView(new GUISkyBlockProfile()); } }); - set(new GUIClickableItem(11) { //Helmet - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockItem item = new SkyBlockItem(p.getInventory().getCursorItem()); - if (!player.getHelmet().isAir() && p.getInventory().getCursorItem().isAir()) { - player.addAndUpdateItem(player.getHelmet()); - player.setHelmet(ItemStack.AIR); - GUISkyBlockProfile guiSkyBlockProfile = new GUISkyBlockProfile(); - guiSkyBlockProfile.open(player); - } else if (item.hasComponent(StandardItemComponent.class) - && item.getComponent(StandardItemComponent.class).getType() == StandardItemComponent.StandardItemType.HELMET - && player.getHelmet().isAir()) { - player.setHelmet(p.getInventory().getCursorItem()); - ((Inventory) e.getInventory()).setCursorItem(player, ItemStack.AIR); - GUISkyBlockProfile guiSkyBlockProfile = new GUISkyBlockProfile(); - guiSkyBlockProfile.open(player); - } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!player.getHelmet().isAir()) { - return ItemStackCreator.getFromStack(player.getHelmet()); - } else { - return ItemStackCreator.getStack("§7Empty Helmet Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); - } + // Chestplate + layout.slot(20, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (!player.getChestplate().isAir()) { + return ItemStackCreator.getFromStack(player.getChestplate()); + } else { + return ItemStackCreator.getStack("§7Empty Chestplate Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); + } + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockItem cursorItem = new SkyBlockItem(player.getInventory().getCursorItem()); + if (!player.getChestplate().isAir() && player.getInventory().getCursorItem().isAir()) { + player.addAndUpdateItem(player.getChestplate()); + player.setChestplate(ItemStack.AIR); + c.player().openView(new GUISkyBlockProfile()); + } else if (cursorItem.hasComponent(StandardItemComponent.class) + && cursorItem.getComponent(StandardItemComponent.class).getType() == StandardItemComponent.StandardItemType.CHESTPLATE + && player.getChestplate().isAir()) { + player.setChestplate(player.getInventory().getCursorItem()); + c.inventory().setCursorItem(player, ItemStack.AIR); + c.player().openView(new GUISkyBlockProfile()); } }); - set(new GUIClickableItem(20) { //Chestplate - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockItem item = new SkyBlockItem(p.getInventory().getCursorItem()); - if (!player.getChestplate().isAir() && p.getInventory().getCursorItem().isAir()) { - player.addAndUpdateItem(player.getChestplate()); - player.setChestplate(ItemStack.AIR); - GUISkyBlockProfile guiSkyBlockProfile = new GUISkyBlockProfile(); - guiSkyBlockProfile.open(player); - } else if (item.hasComponent(StandardItemComponent.class) - && item.getComponent(StandardItemComponent.class).getType() == StandardItemComponent.StandardItemType.CHESTPLATE - && player.getChestplate().isAir()) { - player.setChestplate(p.getInventory().getCursorItem()); - ((Inventory) e.getInventory()).setCursorItem(player, ItemStack.AIR); - GUISkyBlockProfile guiSkyBlockProfile = new GUISkyBlockProfile(); - guiSkyBlockProfile.open(player); - } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!player.getChestplate().isAir()) { - return ItemStackCreator.getFromStack(player.getChestplate()); - } else { - return ItemStackCreator.getStack("§7Empty Chestplate Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); - } + // Leggings + layout.slot(29, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (!player.getLeggings().isAir()) { + return ItemStackCreator.getFromStack(player.getLeggings()); + } else { + return ItemStackCreator.getStack("§7Empty Leggings Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); + } + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockItem cursorItem = new SkyBlockItem(player.getInventory().getCursorItem()); + if (!player.getLeggings().isAir() && player.getInventory().getCursorItem().isAir()) { + player.addAndUpdateItem(player.getLeggings()); + player.setLeggings(ItemStack.AIR); + c.player().openView(new GUISkyBlockProfile()); + } else if (cursorItem.hasComponent(StandardItemComponent.class) + && cursorItem.getComponent(StandardItemComponent.class).getType() == StandardItemComponent.StandardItemType.LEGGINGS + && player.getLeggings().isAir()) { + player.setLeggings(player.getInventory().getCursorItem()); + c.inventory().setCursorItem(player, ItemStack.AIR); + c.player().openView(new GUISkyBlockProfile()); } }); - set(new GUIClickableItem(29) { //Leggings - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockItem item = new SkyBlockItem(p.getInventory().getCursorItem()); - if (!player.getLeggings().isAir() && p.getInventory().getCursorItem().isAir()) { - player.addAndUpdateItem(player.getLeggings()); - player.setLeggings(ItemStack.AIR); - GUISkyBlockProfile guiSkyBlockProfile = new GUISkyBlockProfile(); - guiSkyBlockProfile.open(player); - } - - if (item.hasComponent(StandardItemComponent.class) - && item.getComponent(StandardItemComponent.class).getType() == StandardItemComponent.StandardItemType.LEGGINGS - && player.getLeggings().isAir()) { - player.setLeggings(p.getInventory().getCursorItem()); - ((Inventory) e.getInventory()).setCursorItem(player, ItemStack.AIR); - GUISkyBlockProfile guiSkyBlockProfile = new GUISkyBlockProfile(); - guiSkyBlockProfile.open(player); - } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!player.getLeggings().isAir()) { - return ItemStackCreator.getFromStack(player.getLeggings()); - } else { - return ItemStackCreator.getStack("§7Empty Leggings Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); - } + // Boots + layout.slot(38, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (!player.getBoots().isAir()) { + return ItemStackCreator.getFromStack(player.getBoots()); + } else { + return ItemStackCreator.getStack("§7Empty Boots Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); + } + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockItem cursorItem = new SkyBlockItem(player.getInventory().getCursorItem()); + if (!player.getBoots().isAir() && player.getInventory().getCursorItem().isAir()) { + player.addAndUpdateItem(player.getBoots()); + player.setBoots(ItemStack.AIR); + c.player().openView(new GUISkyBlockProfile()); + } else if (cursorItem.hasComponent(StandardItemComponent.class) + && cursorItem.getComponent(StandardItemComponent.class).getType() == StandardItemComponent.StandardItemType.BOOTS + && player.getBoots().isAir()) { + player.setBoots(player.getInventory().getCursorItem()); + c.inventory().setCursorItem(player, ItemStack.AIR); + c.player().openView(new GUISkyBlockProfile()); } }); - set(new GUIClickableItem(38) { //Boots - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockItem item = new SkyBlockItem(p.getInventory().getCursorItem()); - if (!player.getBoots().isAir() && p.getInventory().getCursorItem().isAir()) { - player.addAndUpdateItem(player.getBoots()); - player.setBoots(ItemStack.AIR); - GUISkyBlockProfile guiSkyBlockProfile = new GUISkyBlockProfile(); - guiSkyBlockProfile.open(player); - } - if (item.hasComponent(StandardItemComponent.class) - && item.getComponent(StandardItemComponent.class).getType() == StandardItemComponent.StandardItemType.BOOTS - && player.getBoots().isAir()) { - player.setBoots(p.getInventory().getCursorItem()); - ((Inventory) e.getInventory()).setCursorItem(player, ItemStack.AIR); - GUISkyBlockProfile guiSkyBlockProfile = new GUISkyBlockProfile(); - guiSkyBlockProfile.open(player); - } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!player.getBoots().isAir()) { - return ItemStackCreator.getFromStack(player.getBoots()); - } else { - return ItemStackCreator.getStack("§7Empty Boots Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); - } - } + // Pet + layout.slot(47, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (player.getPetData().getEnabledPet() != null && !player.getPetData().getEnabledPet().getItemStack().isAir()) { + SkyBlockItem pet = player.getPetData().getEnabledPet(); + return new NonPlayerItemUpdater(pet).getUpdatedItem(); + } else { + return ItemStackCreator.getStack("§7Empty Pet Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); + } + }, (click, c) -> { + //c.player().openView(new GUIPets()) }); - set(new GUIClickableItem(47) { //Pet - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIPets().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (player.getPetData().getEnabledPet() != null && !player.getPetData().getEnabledPet().getItemStack().isAir()) { - SkyBlockItem pet = player.getPetData().getEnabledPet(); - return new NonPlayerItemUpdater(pet).getUpdatedItem(); - } else { - return ItemStackCreator.getStack("§7Empty Pet Slot", Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1); + // Combat Stats + layout.slot(15, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7Gives you a better chance at", "§7fighting strong monsters. ", " ")); + List stats = List.of(ItemStatistic.HEALTH, ItemStatistic.DEFENSE, ItemStatistic.STRENGTH, ItemStatistic.INTELLIGENCE, + ItemStatistic.CRITICAL_CHANCE, ItemStatistic.CRITICAL_DAMAGE, ItemStatistic.BONUS_ATTACK_SPEED, ItemStatistic.ABILITY_DAMAGE, ItemStatistic.TRUE_DEFENSE, + ItemStatistic.FEROCITY, ItemStatistic.HEALTH_REGENERATION, ItemStatistic.VITALITY, ItemStatistic.MENDING, ItemStatistic.SWING_RANGE); + + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (stats.contains(statistic)) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); } - } - }); - - set(new GUIClickableItem(15) { //Combat Stats - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICombatStats().open(player); - } + }); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7Gives you a better chance at", "§7fighting strong monsters. ", " ")); - List stats = new ArrayList<>(List.of(ItemStatistic.HEALTH, ItemStatistic.DEFENSE, ItemStatistic.STRENGTH, ItemStatistic.INTELLIGENCE, - ItemStatistic.CRITICAL_CHANCE, ItemStatistic.CRITICAL_DAMAGE, ItemStatistic.BONUS_ATTACK_SPEED, ItemStatistic.ABILITY_DAMAGE, ItemStatistic.TRUE_DEFENSE, - ItemStatistic.FEROCITY, ItemStatistic.HEALTH_REGENERATION, ItemStatistic.VITALITY, ItemStatistic.MENDING, ItemStatistic.SWING_RANGE)); - - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (stats.contains(statistic)) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); - - lore.add(""); - lore.add("§eClick for details!"); - return ItemStackCreator.getStack("§cCombat Stats", Material.DIAMOND_SWORD, 1, - lore - ); - } + lore.add(""); + lore.add("§eClick for details!"); + return ItemStackCreator.getStack("§cCombat Stats", Material.DIAMOND_SWORD, 1, lore); + }, (click, c) -> { + //c.player().openView(new GUICombatStats())) }); - set(new GUIClickableItem(16) { //Gathering Stats - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIGatheringStats().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7Lets you collect and harvest better", "§7items, or more of them. ", " ")); - List stats = new ArrayList<>(List.of(ItemStatistic.MINING_SPEED, ItemStatistic.MINING_FORTUNE, ItemStatistic.BREAKING_POWER, - ItemStatistic.PRISTINE, ItemStatistic.FORAGING_FORTUNE, ItemStatistic.FARMING_FORTUNE, ItemStatistic.MINING_SPREAD, ItemStatistic.GEMSTONE_SPREAD, - ItemStatistic.HUNTER_FORTUNE, ItemStatistic.SWEEP, ItemStatistic.ORE_FORTUNE, ItemStatistic.BLOCK_FORTUNE, ItemStatistic.DWARVEN_METAL_FORTUNE, - ItemStatistic.GEMSTONE_FORTUNE, ItemStatistic.WHEAT_FORTUNE, ItemStatistic.POTATO_FORTUNE, ItemStatistic.CARROT_FORTUNE, ItemStatistic.PUMPKIN_FORTUNE, - ItemStatistic.MELON_FORTUNE, ItemStatistic.CACTUS_FORTUNE, ItemStatistic.NETHER_WART_FORTUNE, ItemStatistic.COCOA_BEANS_FORTUNE, ItemStatistic.MUSHROOM_FORTUNE, - ItemStatistic.SUGAR_CANE_FORTUNE, ItemStatistic.FIG_FORTUNE, ItemStatistic.MANGROVE_FORTUNE - )); - - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (stats.contains(statistic)) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); - - lore.add(""); - lore.add("§eClick for details!"); + // Gathering Stats + layout.slot(16, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7Lets you collect and harvest better", "§7items, or more of them. ", " ")); + List stats = List.of(ItemStatistic.MINING_SPEED, ItemStatistic.MINING_FORTUNE, ItemStatistic.BREAKING_POWER, + ItemStatistic.PRISTINE, ItemStatistic.FORAGING_FORTUNE, ItemStatistic.FARMING_FORTUNE, ItemStatistic.MINING_SPREAD, ItemStatistic.GEMSTONE_SPREAD, + ItemStatistic.HUNTER_FORTUNE, ItemStatistic.SWEEP, ItemStatistic.ORE_FORTUNE, ItemStatistic.BLOCK_FORTUNE, ItemStatistic.DWARVEN_METAL_FORTUNE, + ItemStatistic.GEMSTONE_FORTUNE, ItemStatistic.WHEAT_FORTUNE, ItemStatistic.POTATO_FORTUNE, ItemStatistic.CARROT_FORTUNE, ItemStatistic.PUMPKIN_FORTUNE, + ItemStatistic.MELON_FORTUNE, ItemStatistic.CACTUS_FORTUNE, ItemStatistic.NETHER_WART_FORTUNE, ItemStatistic.COCOA_BEANS_FORTUNE, ItemStatistic.MUSHROOM_FORTUNE, + ItemStatistic.SUGAR_CANE_FORTUNE, ItemStatistic.FIG_FORTUNE, ItemStatistic.MANGROVE_FORTUNE); + + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (stats.contains(statistic)) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); + } + }); - return ItemStackCreator.getStack("§eGathering Stats", Material.IRON_PICKAXE, 1, lore); - } + lore.add(""); + lore.add("§eClick for details!"); + return ItemStackCreator.getStack("§eGathering Stats", Material.IRON_PICKAXE, 1, lore); + }, (click, c) -> { + // c.player().openView(new GUIGatheringStats()); }); - set(new GUIClickableItem(24) { //Wisdom Stats - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIWisdomStats().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7Increases the §3XP §7you gain on your", "§7skills ", " ")); - List stats = new ArrayList<>(List.of(ItemStatistic.COMBAT_WISDOM, ItemStatistic.MINING_WISDOM, ItemStatistic.FARMING_WISDOM, ItemStatistic.FORAGING_WISDOM, - ItemStatistic.FISHING_WISDOM, ItemStatistic.ENCHANTING_WISDOM, ItemStatistic.ALCHEMY_WISDOM, ItemStatistic.CARPENTRY_WISDOM, ItemStatistic.RUNE_CRAFTING_WISDOM, - ItemStatistic.SOCIAL_WISDOM, ItemStatistic.TAMING_WISDOM, ItemStatistic.HUNTING_WISDOM - )); // WISDOM STATS - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (stats.contains(statistic)) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); + // Wisdom Stats + layout.slot(24, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7Increases the §3XP §7you gain on your", "§7skills ", " ")); + List stats = List.of(ItemStatistic.COMBAT_WISDOM, ItemStatistic.MINING_WISDOM, ItemStatistic.FARMING_WISDOM, ItemStatistic.FORAGING_WISDOM, + ItemStatistic.FISHING_WISDOM, ItemStatistic.ENCHANTING_WISDOM, ItemStatistic.ALCHEMY_WISDOM, ItemStatistic.CARPENTRY_WISDOM, ItemStatistic.RUNE_CRAFTING_WISDOM, + ItemStatistic.SOCIAL_WISDOM, ItemStatistic.TAMING_WISDOM, ItemStatistic.HUNTING_WISDOM); + + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (stats.contains(statistic)) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); + } + }); - lore.add(""); - lore.add("§eClick for details!"); - return ItemStackCreator.getStack("§3Wisdom Stats", Material.BOOK, 1, - lore - ); - } + lore.add(""); + lore.add("§eClick for details!"); + return ItemStackCreator.getStack("§3Wisdom Stats", Material.BOOK, 1, lore); + }, (click, c) -> { + //c.player().openView(new GUIWisdomStats()) }); - set(new GUIClickableItem(25) { //Misc Stats - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIMiscStats().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7Augments various aspects of your", "§7gameplay! ", " ")); - List stats = new ArrayList<>(List.of(ItemStatistic.SPEED, ItemStatistic.MAGIC_FIND, ItemStatistic.PET_LUCK, - ItemStatistic.COLD_RESISTANCE, ItemStatistic.BONUS_PEST_CHANCE, ItemStatistic.HEAT_RESISTANCE, ItemStatistic.FEAR, - ItemStatistic.PULL, ItemStatistic.RESPIRATION, ItemStatistic.PRESSURE_RESISTANCE - )); - - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (stats.contains(statistic)) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); + // Misc Stats + layout.slot(25, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7Augments various aspects of your", "§7gameplay! ", " ")); + List stats = List.of(ItemStatistic.SPEED, ItemStatistic.MAGIC_FIND, ItemStatistic.PET_LUCK, + ItemStatistic.COLD_RESISTANCE, ItemStatistic.BONUS_PEST_CHANCE, ItemStatistic.HEAT_RESISTANCE, ItemStatistic.FEAR, + ItemStatistic.PULL, ItemStatistic.RESPIRATION, ItemStatistic.PRESSURE_RESISTANCE); + + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (stats.contains(statistic)) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); + } + }); - lore.add(""); - lore.add("§eClick for details!"); - return ItemStackCreator.getStack("§dMisc Stats", Material.CLOCK, 1, lore); - } + lore.add(""); + lore.add("§eClick for details!"); + return ItemStackCreator.getStack("§dMisc Stats", Material.CLOCK, 1, lore); + }, (click, c) -> { + //c.player().openView(new GUIMiscStats()) }); - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(false); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIAccessoryBag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIAccessoryBag.java index 483f4cb69..881b36825 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIAccessoryBag.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIAccessoryBag.java @@ -52,7 +52,7 @@ public GUIAccessoryBag() { public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUIYourBags())); + //set(GUIClickableItem.getGoBackItem(48, new GUIYourBags())); SkyBlockPlayer player = (SkyBlockPlayer) e.player(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIQuiver.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIQuiver.java index 5e64b1d17..6d891691d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIQuiver.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIQuiver.java @@ -36,7 +36,7 @@ public void onOpen(InventoryGUIOpenEvent e) { SkyBlockPlayer player = (SkyBlockPlayer) e.player(); fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(40)); - set(GUIClickableItem.getGoBackItem(39, new GUIYourBags())); + //set(GUIClickableItem.getGoBackItem(39, new GUIYourBags())); int amountOfSlots = 0; int rawAmountOfSlots = 0; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java index 823356761..829169d6b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java @@ -47,7 +47,7 @@ public GUISackOfSacks() { public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(40)); - set(GUIClickableItem.getGoBackItem(39, new GUIYourBags())); + //set(GUIClickableItem.getGoBackItem(39, new GUIYourBags())); SkyBlockPlayer player = (SkyBlockPlayer) e.player(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java index b28ece043..37b7bf0f5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java @@ -1,218 +1,121 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bags; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.collection.CustomCollectionAward; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -public class GUIYourBags extends HypixelInventoryGUI { - public GUIYourBags() { - super("Your Bags", InventoryType.CHEST_6_ROW); - } +public class GUIYourBags extends StatelessView { @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(48) { - @Override - public void run(net.minestom.server.event.inventory.InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Your Bags", InventoryType.CHEST_6_ROW); + } - SkyBlockPlayer player = (SkyBlockPlayer) e.player(); + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); - if (player.hasCustomCollectionAward(CustomCollectionAward.SACK_OF_SACKS)) - set(new GUIClickableItem(20) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISackOfSacks().open(player); - } + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§aSack of Sacks", "80a077e248d142772ea800864f8c578b9d36885b29daf836b64a706882b6ec10", 1, - "§7A sack which contains other sacks.", - "§7Sackception!", - "", - "§eClick to open!"); - } - }); - else { - set(new GUIItem(20) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§cSack of Sacks", Material.GRAY_DYE, 1, + // Sack of Sacks + if (player.hasCustomCollectionAward(CustomCollectionAward.SACK_OF_SACKS)) { + layout.slot(20, (s, c) -> ItemStackCreator.getStackHead("§aSack of Sacks", + "80a077e248d142772ea800864f8c578b9d36885b29daf836b64a706882b6ec10", 1, "§7A sack which contains other sacks.", "§7Sackception!", "", - "§cRequires §aClownfish Collection IV§c."); - } - }); + "§eClick to open!"), + (click, c) -> new GUISackOfSacks().open((SkyBlockPlayer) c.player())); + } else { + layout.slot(20, (s, c) -> ItemStackCreator.getStack("§cSack of Sacks", Material.GRAY_DYE, 1, + "§7A sack which contains other sacks.", + "§7Sackception!", + "", + "§cRequires §aClownfish Collection IV§c.")); } - if (player.hasCustomCollectionAward(CustomCollectionAward.FISHING_BAG)) { - set(new GUIClickableItem(21) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - - } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§aFishing Bag", "eb8e297df6b8dffcf135dba84ec792d420ad8ecb458d144288572a84603b1631", 1, - "§7A useful bag which can hold all", - "§7types of fish, bait, and fishing loot!", - "", - "§eClick to open!"); - } - }); + // Fishing Bag + if (player.hasCustomCollectionAward(CustomCollectionAward.FISHING_BAG)) { + layout.slot(21, (s, c) -> ItemStackCreator.getStackHead("§aFishing Bag", + "eb8e297df6b8dffcf135dba84ec792d420ad8ecb458d144288572a84603b1631", 1, + "§7A useful bag which can hold all", + "§7types of fish, bait, and fishing loot!", + "", + "§eClick to open!")); } else { - set(new GUIItem(21) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§cFishing Bag", Material.GRAY_DYE, 1, - "§7A useful bag which can hold all", - "§7types of fish, bait, and fishing loot!", - "", - "§cRequires §aRaw Fish Collection III§c."); - } - }); + layout.slot(21, (s, c) -> ItemStackCreator.getStack("§cFishing Bag", Material.GRAY_DYE, 1, + "§7A useful bag which can hold all", + "§7types of fish, bait, and fishing loot!", + "", + "§cRequires §aRaw Fish Collection III§c.")); } - if (player.hasCustomCollectionAward(CustomCollectionAward.POTION_BAG)) { - set(new GUIClickableItem(22) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - - } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§aPotion Bag", "9f8b82427b260d0a61e6483fc3b2c35a585851e08a9a9df372548b4168cc817c", 1, - "§7A handy bag for holding your", - "§7Potions in.", - "", - "§eClick to open!"); - } - }); + // Potion Bag + if (player.hasCustomCollectionAward(CustomCollectionAward.POTION_BAG)) { + layout.slot(22, (s, c) -> ItemStackCreator.getStackHead("§aPotion Bag", + "9f8b82427b260d0a61e6483fc3b2c35a585851e08a9a9df372548b4168cc817c", 1, + "§7A handy bag for holding your", + "§7Potions in.", + "", + "§eClick to open!")); } else { - set(new GUIItem(22) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§cPotion Bag", Material.GRAY_DYE, 1, - "§7A handy bag for holding your", - "§7Potions in.", - "", - "§cRequires §aNether Wart Collection II§c."); - } - }); + layout.slot(22, (s, c) -> ItemStackCreator.getStack("§cPotion Bag", Material.GRAY_DYE, 1, + "§7A handy bag for holding your", + "§7Potions in.", + "", + "§cRequires §aNether Wart Collection II§c.")); } - if (player.hasCustomCollectionAward(CustomCollectionAward.QUIVER)) { - set(new GUIClickableItem(23) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIQuiver().open(player); - } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§aQuiver", + // Quiver + if (player.hasCustomCollectionAward(CustomCollectionAward.QUIVER)) { + layout.slot(23, (s, c) -> ItemStackCreator.getStackHead("§aQuiver", "396ce13ff6155fdf3235d8d22174c5de4bf5512f1adeda1afa3fc28180f3f7", 1, "§7A masterfully crafted Quiver which", "§7holds any kind of projectile you can", "§7think of!", " ", - "§eClick to open!"); - } - }); + "§eClick to open!"), + (click, c) -> new GUIQuiver().open((SkyBlockPlayer) c.player())); } else { - set(new GUIItem(23) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§cQuiver", Material.GRAY_DYE, 1, - "§7A masterfully crafted Quiver which", - "§7holds any kind of projectile you can", - "§7think of!", - " ", - "§cRequires §aString Collection III§c."); - } - }); + layout.slot(23, (s, c) -> ItemStackCreator.getStack("§cQuiver", Material.GRAY_DYE, 1, + "§7A masterfully crafted Quiver which", + "§7holds any kind of projectile you can", + "§7think of!", + " ", + "§cRequires §aString Collection III§c.")); } - if (player.hasCustomCollectionAward(CustomCollectionAward.ACCESSORY_BAG)) { - set(new GUIClickableItem(24) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIAccessoryBag().open(player); - } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§aAccessory Bag", - "396ce13ff6155fdf3235d8d22174c5de4bf5512f1adeda1afa3fc28180f3f7", 1, - "§7A special bag which can hold", - "§7Talismans, Rings, Artifacts, and Orbs", - "§7within it. All will still work while in this", - "§7bag!", - " ", - "§7Magical Power: §6" + StringUtility.commaify(player.getMagicalPower()), - " ", - "§eClick to open!"); - } - }); + // Accessory Bag + if (player.hasCustomCollectionAward(CustomCollectionAward.ACCESSORY_BAG)) { + layout.slot(24, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStackHead("§aAccessory Bag", + "396ce13ff6155fdf3235d8d22174c5de4bf5512f1adeda1afa3fc28180f3f7", 1, + "§7A special bag which can hold", + "§7Talismans, Rings, Artifacts, and Orbs", + "§7within it. All will still work while in this", + "§7bag!", + " ", + "§7Magical Power: §6" + StringUtility.commaify(p.getMagicalPower()), + " ", + "§eClick to open!"); + }, (click, c) -> new GUIAccessoryBag().open((SkyBlockPlayer) c.player())); } else { - set(new GUIItem(24) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§cAccessory Bag", Material.GRAY_DYE, 1, - "§7A special bag which can hold", - "§7Talismans, Rings, Artifacts, and Orbs", - "§7within it. All will still work while in this", - "§7bag!", - " ", - "§cRequires §aRedstone Collection II§c."); - } - }); + layout.slot(24, (s, c) -> ItemStackCreator.getStack("§cAccessory Bag", Material.GRAY_DYE, 1, + "§7A special bag which can hold", + "§7Talismans, Rings, Artifacts, and Orbs", + "§7within it. All will still work while in this", + "§7bag!", + " ", + "§cRequires §aRedstone Collection II§c.")); } - - updateItemStacks(e.inventory(), e.player()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiary.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiary.java index 6a7f70505..afc270eb9 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiary.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiary.java @@ -72,7 +72,7 @@ public GUIBestiary() { public void onOpen(InventoryGUIOpenEvent e) { fill(Material.BLACK_STAINED_GLASS_PANE, ""); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkillCategory(SkillCategories.COMBAT, 0))); + //set(GUIClickableItem.getGoBackItem(48, new GUISkillCategory(SkillCategories.COMBAT, 0))); set(new GUIItem(4) { @Override public ItemStack.Builder getItem(HypixelPlayer p) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/calendar/GUICalendar.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/calendar/GUICalendar.java index d328c6ab4..cc507c748 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/calendar/GUICalendar.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/calendar/GUICalendar.java @@ -2,16 +2,12 @@ import net.kyori.adventure.text.Component; import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.calendar.CalendarEvent; import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; @@ -20,70 +16,47 @@ import java.util.Map; import java.util.stream.Stream; -public class GUICalendar extends HypixelInventoryGUI { - - public GUICalendar() { - super("Calendar and Events", InventoryType.CHEST_5_ROW); - } - - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(FILLER_ITEM); - - Map events = SkyBlockCalendar.getEventsWithDurationUntil(14); - - int[] eventSlots = {10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 26}; - int index = 0; - for (Map.Entry entry : events.entrySet()) { - if (index >= eventSlots.length) break; - SkyBlockCalendar.EventInfo info = entry.getKey(); - CalendarEvent event = entry.getValue(); - set(new GUIItem(eventSlots[index]) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - List loreHeader = List.of( - Component.text("§7Starts in: §e" + StringUtility.formatTimeLeft(info.timeUntilBegin() * 50L)), - Component.text("§7Event lasts for §e" + StringUtility.formatTimeLeft(info.duration() * 50L) + "§7!"), - Component.text(" ") - ); - List loreFooter = event.description().stream() - .map(line -> (Component) Component.text(line)) - .toList(); - - List lore = Stream.concat(loreHeader.stream(), loreFooter.stream()) - .toList(); - - return event.representation().builder() - .set(DataComponents.CUSTOM_NAME, Component.text(event.getDisplayName(info.year()))) - .set(DataComponents.LORE, lore); - } - }); - index++; - } - - - set(new GUIClickableItem(39) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); - set(GUIClickableItem.getCloseItem(40)); - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - - } +public class GUICalendar extends StatelessView { + + private static final int[] EVENT_SLOTS = {10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 26}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Calendar and Events", InventoryType.CHEST_5_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 40); + Components.back(layout, 39, ctx); + + Map events = SkyBlockCalendar.getEventsWithDurationUntil(14); + + int index = 0; + for (Map.Entry entry : events.entrySet()) { + if (index >= EVENT_SLOTS.length) break; + SkyBlockCalendar.EventInfo info = entry.getKey(); + CalendarEvent event = entry.getValue(); + int slot = EVENT_SLOTS[index]; + + layout.slot(slot, (s, c) -> { + List loreHeader = List.of( + Component.text("§7Starts in: §e" + StringUtility.formatTimeLeft(info.timeUntilBegin() * 50L)), + Component.text("§7Event lasts for §e" + StringUtility.formatTimeLeft(info.duration().toMillis()) + "§7!"), + Component.text(" ") + ); + List loreFooter = event.description().stream() + .map(line -> (Component) Component.text(line)) + .toList(); + + List lore = Stream.concat(loreHeader.stream(), loreFooter.stream()).toList(); + + return event.representation().builder() + .set(DataComponents.CUSTOM_NAME, Component.text(event.getDisplayName(info.year()))) + .set(DataComponents.LORE, lore); + }); + index++; + } + } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionCategory.java index 7f70249e2..eee6c624b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionCategory.java @@ -1,17 +1,10 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.collection; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.collection.CollectionCategory; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointCollection; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -20,138 +13,98 @@ import java.util.Arrays; import java.util.List; -public class GUICollectionCategory extends HypixelPaginatedGUI { +public class GUICollectionCategory extends StatelessView { + private static final int[] PAGINATED_SLOTS = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; + private final CollectionCategory type; private final List display; + private final int page; public GUICollectionCategory(CollectionCategory category, List display) { - super(InventoryType.CHEST_6_ROW); + this(category, display, 0); + } + public GUICollectionCategory(CollectionCategory category, List display, int page) { this.type = category; this.display = display; + this.page = page; } @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } - - @Override - public int[] getPaginatedSlots() { - return new int[]{ - 10, 11, 12, 13, 14, 15, 16, - 19, 20, 21, 22, 23, 24, 25, - 28, 29, 30, 31, 32, 33, 34, - 37, 38, 39, 40, 41, 42, 43 - }; - } - - @Override - public PaginationList fillPaged(HypixelPlayer player, PaginationList paged) { - paged.addAll(Arrays.asList(type.getCollections())); - return paged; - } - - @Override - protected boolean shouldFilterFromSearch(String query, CollectionCategory.ItemCollection item) { - return false; + public ViewConfiguration configuration() { + return new ViewConfiguration<>(type.getName() + " Collections", InventoryType.CHEST_6_ROW); } @Override - public void performSearch(HypixelPlayer player, String query, int page, int maxPage) { - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUICollections())); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - List lore = new ArrayList<>(List.of( - "§7View your " + type.getName() + " Collections!", - " " - )); - - lore.addAll(display); - - return ItemStackCreator.getStack("§a" + type.getName() + " Collections", - Material.STONE_PICKAXE, 1, lore); - } + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + layout.slot(4, (s, c) -> { + List lore = new ArrayList<>(List.of( + "§7View your " + type.getName() + " Collections!", + " " + )); + lore.addAll(display); + return ItemStackCreator.getStack("§a" + type.getName() + " Collections", Material.STONE_PICKAXE, 1, lore); }); - if (page > 1) { - set(createNavigationButton(this, 45, query, page, false)); + CollectionCategory.ItemCollection[] collections = type.getCollections(); + int itemsPerPage = PAGINATED_SLOTS.length; + int totalPages = (int) Math.ceil((double) collections.length / itemsPerPage); + + // Pagination buttons + if (page > 0) { + //layout.slot(45, (s, c) -> ItemStackCreator.getStack("§aPrevious Page", Material.ARROW, 1), + // (click, c) -> new GUICollectionCategory(type, display, page - 1).open((SkyBlockPlayer) c.player())); } - if (page < maxPage) { - set(createNavigationButton(this, 53, query, page, true)); + if (page < totalPages - 1) { + //layout.slot(53, (s, c) -> ItemStackCreator.getStack("§aNext Page", Material.ARROW, 1), + // (click, c) -> new GUICollectionCategory(type, display, page + 1).open((SkyBlockPlayer) c.player())); } - } - @Override - public String getTitle(HypixelPlayer player, String query, int page, PaginationList paged) { - return type.getName() + " Collections"; - } + int startIndex = page * itemsPerPage; + for (int i = 0; i < PAGINATED_SLOTS.length && startIndex + i < collections.length; i++) { + CollectionCategory.ItemCollection item = collections[startIndex + i]; + int slot = PAGINATED_SLOTS[i]; - @Override - public GUIClickableItem createItemFor(CollectionCategory.ItemCollection item, int slot, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - DatapointCollection.PlayerCollection collection = player.getCollection(); - - if (!collection.unlocked(item.type())) { - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.sendMessage("§cYou haven't found this item yet!"); - } + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + DatapointCollection.PlayerCollection collection = player.getCollection(); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack( - "§c" + item.type().getDisplayName(), Material.GRAY_DYE, 1, + if (!collection.unlocked(item.type())) { + return ItemStackCreator.getStack("§c" + item.type().getDisplayName(), Material.GRAY_DYE, 1, "§7Find this item to add it to your", "§7collection and unlock collection", "§7rewards!"); } - }; - } - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICollectionItem(item.type()).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; List lore = new ArrayList<>(List.of( "§7View all your " + item.type().getDisplayName() + " Collection", "§7progress and rewards!", " " )); - collection.getDisplay(lore, item); - lore.add(" "); lore.add("§eClick to view!"); return ItemStackCreator.getStack("§e" + item.type().getDisplayName(), item.type().material, 1, lore); - } - }; + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + DatapointCollection.PlayerCollection collection = player.getCollection(); + + if (!collection.unlocked(item.type())) { + player.sendMessage("§cYou haven't found this item yet!"); + return; + } + //new GUICollectionItem(item.type()).open(player); + }); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionItem.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionItem.java index 5fc106131..5a7a6124e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionItem.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionItem.java @@ -1,18 +1,12 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.collection; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.collection.CollectionCategories; import net.swofty.type.skyblockgeneric.collection.CollectionCategory; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointCollection; @@ -21,114 +15,77 @@ import java.util.ArrayList; import java.util.List; -public class GUICollectionItem extends HypixelInventoryGUI { +public class GUICollectionItem extends StatelessView { private final ItemType item; private final CollectionCategory category; private final CollectionCategory.ItemCollection collection; public GUICollectionItem(ItemType item) { - super(item.getDisplayName() + " Collection", InventoryType.CHEST_6_ROW); - this.item = item; this.category = CollectionCategories.getCategory(item); this.collection = category.getCollection(item); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUICollectionCategory( - category, - ((SkyBlockPlayer) getPlayer()).getCollection().getDisplay(new ArrayList<>(), category) - ))); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§e" + item.getDisplayName(), item.material, 1, - "§7View all your " + item.getDisplayName() + " Collection", - "§7progress and rewards!", - " ", - "§7Total Collected: §e" + player.getCollection().get(item)); - } + public ViewConfiguration configuration() { + return new ViewConfiguration<>(item.getDisplayName() + " Collection", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStack("§e" + item.getDisplayName(), item.material, 1, + "§7View all your " + item.getDisplayName() + " Collection", + "§7progress and rewards!", + " ", + "§7Total Collected: §e" + player.getCollection().get(item)); }); int slot = 17; for (CollectionCategory.ItemCollectionReward reward : collection.rewards()) { slot++; + int finalSlot = slot; - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICollectionReward(item, reward).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - DatapointCollection.PlayerCollection playerCollection = player.getCollection(); - - List lore = new ArrayList<>(); - lore.add(" "); - playerCollection.getDisplay(lore, collection, reward); - lore.add(" "); - lore.add("§eClick to view rewards!"); + layout.slot(finalSlot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + DatapointCollection.PlayerCollection playerCollection = player.getCollection(); - if (playerCollection.getReward(collection) == null) { - return ItemStackCreator.getStack( - "§7" + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(collection.getPlacementOf(reward) + 1), - Material.GREEN_STAINED_GLASS_PANE, - 1, - lore - ); - } - - Material material; - String colour; - if (playerCollection.getReward(collection) == reward) { - material = Material.YELLOW_STAINED_GLASS_PANE; - colour = "§e"; - } else if (collection.getPlacementOf(playerCollection.getReward(collection)) - > collection.getPlacementOf(reward)) { - material = Material.LIME_STAINED_GLASS_PANE; - colour = "§a"; - } else { - material = Material.RED_STAINED_GLASS_PANE; - colour = "§c"; - } + List lore = new ArrayList<>(); + lore.add(" "); + playerCollection.getDisplay(lore, collection, reward); + lore.add(" "); + lore.add("§eClick to view rewards!"); + if (playerCollection.getReward(collection) == null) { return ItemStackCreator.getStack( - colour + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(collection.getPlacementOf(reward) + 1), - material, - 1, - lore - ); + "§7" + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(collection.getPlacementOf(reward) + 1), + Material.GREEN_STAINED_GLASS_PANE, 1, lore); } - }); - } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } + Material material; + String colour; + if (playerCollection.getReward(collection) == reward) { + material = Material.YELLOW_STAINED_GLASS_PANE; + colour = "§e"; + } else if (collection.getPlacementOf(playerCollection.getReward(collection)) > collection.getPlacementOf(reward)) { + material = Material.LIME_STAINED_GLASS_PANE; + colour = "§a"; + } else { + material = Material.RED_STAINED_GLASS_PANE; + colour = "§c"; + } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + return ItemStackCreator.getStack( + colour + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(collection.getPlacementOf(reward) + 1), + material, 1, lore); + }, (click, c) -> { + //new GUICollectionReward(item, reward).open((SkyBlockPlayer) c.player()) + }); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java index d81147ec8..06f903321 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java @@ -1,18 +1,12 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.collection; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.collection.CollectionCategories; import net.swofty.type.skyblockgeneric.collection.CollectionCategory; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe.GUIMinionRecipes; @@ -23,7 +17,7 @@ import java.util.*; -public class GUICollectionReward extends HypixelInventoryGUI { +public class GUICollectionReward extends StatelessView { private static final Map SLOTS = new HashMap<>(Map.of( 0, new int[]{}, 1, new int[]{22}, @@ -43,11 +37,6 @@ public class GUICollectionReward extends HypixelInventoryGUI { private final int placement; public GUICollectionReward(ItemType type, CollectionCategory.ItemCollectionReward reward) { - super(type.getDisplayName() + " " - + StringUtility.getAsRomanNumeral( - CollectionCategories.getCategory(type).getCollection(type).getPlacementOf(reward) + 1) - + " Rewards", InventoryType.CHEST_6_ROW); - this.item = type; this.category = CollectionCategories.getCategory(type).getCollection(type); this.reward = reward; @@ -55,77 +44,51 @@ public GUICollectionReward(ItemType type, CollectionCategory.ItemCollectionRewar } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUICollectionItem(item))); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(Arrays.asList( - "§7View your " + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(placement) + " Collection rewards!", - " " - )); - - player.getCollection().getDisplay(lore, category, reward); + public ViewConfiguration configuration() { + return new ViewConfiguration<>(item.getDisplayName() + " " + + StringUtility.getAsRomanNumeral(placement + 1) + " Rewards", InventoryType.CHEST_6_ROW); + } - return ItemStackCreator.getStack("§a" + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(placement), - item.material, 1, lore); - } + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(Arrays.asList( + "§7View your " + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(placement + 1) + " Collection rewards!", + " " + )); + player.getCollection().getDisplay(lore, category, reward); + return ItemStackCreator.getStack("§a" + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(placement + 1), + item.material, 1, lore); }); - int[] slots = SLOTS.get(reward.unlocks().length); - int i = 0; - for (CollectionCategory.Unlock unlock : reward.unlocks()) { + int[] slots = SLOTS.getOrDefault(reward.unlocks().length, new int[]{}); + for (int i = 0; i < reward.unlocks().length && i < slots.length; i++) { + CollectionCategory.Unlock unlock = reward.unlocks()[i]; int slot = slots[i]; - i++; - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (unlock instanceof CollectionCategory.UnlockRecipe) { - try { - SkyBlockItem skyBlockItem = ((CollectionCategory.UnlockRecipe) unlock).getRecipes().getFirst().getResult(); - if (skyBlockItem.hasComponent(MinionComponent.class)) { - new GUIMinionRecipes(skyBlockItem.getAttributeHandler().getMinionType(), new GUICollectionReward(item, reward)).open(player); - } else { - new GUIRecipe(skyBlockItem.getAttributeHandler().getPotentialType(), null).open(player); - } - } catch (NullPointerException exception) { - player.sendMessage("There is no recipe available for this item!"); + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return unlock.getDisplay(player); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (unlock instanceof CollectionCategory.UnlockRecipe) { + try { + SkyBlockItem skyBlockItem = ((CollectionCategory.UnlockRecipe) unlock).getRecipes().getFirst().getResult(); + if (skyBlockItem.hasComponent(MinionComponent.class)) { + c.player().openView(new GUIMinionRecipes(skyBlockItem.getAttributeHandler().getMinionType(), new GUICollectionReward(item, reward))); + } else { + c.player().openView(new GUIRecipe(skyBlockItem.getAttributeHandler().getPotentialType(), null)); } + } catch (NullPointerException exception) { + player.sendMessage("There is no recipe available for this item!"); } } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return unlock.getDisplay(player); - } }); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java index c6c9e10c5..90073c365 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java @@ -1,16 +1,10 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.collection; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.collection.CollectionCategories; import net.swofty.type.skyblockgeneric.collection.CollectionCategory; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; @@ -20,124 +14,72 @@ import java.util.Arrays; import java.util.List; -public class GUICollections extends HypixelInventoryGUI { - private final int[] displaySlots = { +public class GUICollections extends StatelessView { + private static final int[] DISPLAY_SLOTS = { 20, 21, 22, 23, 24, 31 }; - public GUICollections() { - super("Collections", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Collections", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(Material.BLACK_STAINED_GLASS_PANE, ""); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); - } + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(List.of( + "§7View all of the items available in", + "§7SkyBlock. Collect more of an item to", + "§7unlock rewards on your way to", + "§7becoming a master of SkyBlock!", + " " + )); + player.getCollection().getDisplay(lore); + lore.add(" "); + lore.add("§eClick to view!"); + return ItemStackCreator.getStack("§aCollections", Material.PAINTING, 1, lore.toArray(new String[0])); }); - ArrayList allCategories = CollectionCategories.getCategories(); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(List.of( - "§7View all of the items available in", - "§7SkyBlock. Collect more of an item to", - "§7unlock rewards on your way to", - "§7becoming a master of SkyBlock!", - " " - )); - - player.getCollection().getDisplay(lore); - - lore.add(" "); - lore.add("§eClick to view!"); - return ItemStackCreator.getStack("§aCollections", Material.PAINTING, 1, lore.toArray(new String[0])); - } - }); - - set(new GUIClickableItem(50) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICraftedMinions(new GUICollections()).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§aCrafted Minions", "ebcc099f3a00ece0e5c4b31d31c828e52b06348d0a4eac11f3fcbef3c05cb407", 1, + layout.slot(50, (s, c) -> ItemStackCreator.getStackHead("§aCrafted Minions", + "ebcc099f3a00ece0e5c4b31d31c828e52b06348d0a4eac11f3fcbef3c05cb407", 1, "§7View all the unique minions that you", "§7have crafted.", "", - "§eClick to view!"); - } - }); - - int index = 0; - for (int slot : displaySlots) { - CollectionCategory category = allCategories.get(index); + "§eClick to view!"), + (click, c) -> { + //new GUICraftedMinions(new GUICollections()).open((SkyBlockPlayer) c.player()) + }); - ArrayList display = new ArrayList<>(); - ((SkyBlockPlayer) getPlayer()).getCollection().getDisplay(display, category); - - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICollectionCategory(category, display).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(Arrays.asList( - "§7View your " + category.getName() + " Collections!", - " " - )); + ArrayList allCategories = CollectionCategories.getCategories(); + for (int i = 0; i < DISPLAY_SLOTS.length && i < allCategories.size(); i++) { + CollectionCategory category = allCategories.get(i); + int slot = DISPLAY_SLOTS[i]; - lore.addAll(display); + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + ArrayList display = new ArrayList<>(); + player.getCollection().getDisplay(display, category); - return ItemStackCreator.getStack( - "§a" + category.getName() + " Collections", category.getDisplayIcon(), - 1, lore); - } + ArrayList lore = new ArrayList<>(Arrays.asList( + "§7View your " + category.getName() + " Collections!", + " " + )); + lore.addAll(display); + + return ItemStackCreator.getStack("§a" + category.getName() + " Collections", + category.getDisplayIcon(), 1, lore); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + ArrayList display = new ArrayList<>(); + player.getCollection().getDisplay(display, category); + //new GUICollectionCategory(category, display).open(player); }); - - index++; } - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java index 1674bd2df..791584202 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java @@ -82,7 +82,7 @@ protected GUIClickableItem createItemFor(SkyBlockItem item, int slot, HypixelPla public void run(InventoryPreClickEvent e, HypixelPlayer p) { SkyBlockPlayer player = (SkyBlockPlayer) p; if (e.getClickedItem().material() != Material.GRAY_DYE) { - new GUIMinionRecipes(item.getAttributeHandler().getMinionType(), new GUICraftedMinions(new GUICollections())).open(player); + //new GUIMinionRecipes(item.getAttributeHandler().getMinionType(), new GUICraftedMinions(new GUICollections())).open(player); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java index 283592504..bbb9dca57 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java @@ -1,17 +1,14 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.fasttravel; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.type.generic.data.datapoints.DatapointStringList; import net.swofty.type.generic.data.datapoints.DatapointToggles; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -20,153 +17,121 @@ import java.util.ArrayList; import java.util.List; -public class GUIFastTravel extends HypixelInventoryGUI { +public class GUIFastTravel extends StatelessView { private static final int[] SLOTS = new int[]{ 10, 11, 12, 13, 14, 15, 16, - 20, 21, 22, 23, 24, - 30, 32 + 20, 21, 22, 23, 24, + 30, 32 }; - public GUIFastTravel() { - super("Fast Travel", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Fast Travel", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", - Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); - set(GUIClickableItem.getCloseItem(49)); - - boolean shouldBePaper = e.player().getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); - - set(new GUIClickableItem(53) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.getToggles().inverse(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); - new GUIFastTravel().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aPaper Icons", shouldBePaper ? Material.FILLED_MAP : Material.MAP, - 1, - "§7Use paper icons, which may load this menu", - "§7faster on your computer.", - " ", - "§7Enabled: " + (shouldBePaper ? "§aON" : "§cOFF"), - " ", - "§eClick to toggle!"); - } + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + boolean shouldBePaper = player.getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); + + layout.slot(53, (s, c) -> { + boolean isPaper = ((SkyBlockPlayer) c.player()).getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); + return ItemStackCreator.getStack("§aPaper Icons", isPaper ? Material.FILLED_MAP : Material.MAP, 1, + "§7Use paper icons, which may load this menu", + "§7faster on your computer.", + " ", + "§7Enabled: " + (isPaper ? "§aON" : "§cOFF"), + " ", + "§eClick to toggle!"); + }, (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + p.getToggles().inverse(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); + //new GUIFastTravel().open(p); }); TravelScrollIslands[] values = TravelScrollIslands.values(); - for (int i = 0; i < values.length; i++) { + for (int i = 0; i < values.length && i < SLOTS.length; i++) { TravelScrollIslands island = values[i]; + int slot = SLOTS[i]; boolean hasSubMenu = !island.getAssociatedScrolls().isEmpty(); - boolean hasUnlockedIsland = ((SkyBlockPlayer) e.player()).getSkyblockDataHandler() - .get(SkyBlockDataHandler.Data.VISITED_ISLANDS, DatapointStringList.class) - .getValue() - .contains(island.getInternalName()); - - set(new GUIClickableItem(SLOTS[i]) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!hasUnlockedIsland) { - player.sendMessage("§cYou haven't unlocked this fast travel destination!"); - return; - } - - if (!hasSubMenu) { - player.closeInventory(); - player.sendMessage("§7Warping you to " + island.getDescriptiveName() + "§7..."); - player.asProxyPlayer().transferToWithIndication(island.getServerType()).thenRun(() -> { - player.asProxyPlayer().sendMessage("§7You have been warped to " + island.getDescriptiveName() + "§7!"); - }); - return; - } - - if (e.getClick() instanceof Click.Right) { - player.closeInventory(); - player.sendMessage("§7Warping you to " + island.getDescriptiveName() + "§7..."); + layout.slot(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + boolean hasUnlockedIsland = p.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.VISITED_ISLANDS, DatapointStringList.class) + .getValue() + .contains(island.getInternalName()); + boolean isPaper = p.getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); + + List lore = new ArrayList<>(); + lore.add("§8/warp " + island.getInternalName()); + lore.add(" "); + + StringUtility.splitByWordAndLength(island.getDescription().apply(hasUnlockedIsland), 30).forEach(line -> { + lore.add("§7" + line); + }); + lore.add(" "); + + if (island.getAssociatedSkill() != null) { + lore.add("§7Main skill: §b" + island.getAssociatedSkill()); + lore.add("§7Island tier: §e" + island.getIslandTier()); + lore.add(" "); + } - player.asProxyPlayer().transferToWithIndication(island.getServerType()).thenRun(() -> { - player.asProxyPlayer().sendMessage("§7You have been warped to " + island.getDescriptiveName() + "§7!"); - }); + if (!hasUnlockedIsland) { + lore.add("§cWarp not unlocked!"); + } else { + if (hasSubMenu) { + lore.add("§8Right-Click to warp!"); + lore.add("§eLeft-Click to open!"); } else { - new GUIFastTravelSubMenu(island).open(player); + lore.add("§eClick to warp!"); } } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - List lore = new ArrayList<>(); - - lore.add("§8/warp " + island.getInternalName()); - lore.add(" "); + if (isPaper) { + return ItemStackCreator.getStack(island.getDescriptiveName(), + hasUnlockedIsland ? Material.PAPER : Material.BEDROCK, 1, lore); + } else { + return ItemStackCreator.getStackHead(island.getDescriptiveName(), + hasUnlockedIsland ? island.getTexture() : "da99b05b9a1db4d29b5e673d77ae54a77eab66818586035c8a2005aeb810602a", + 1, lore); + } + }, (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + boolean hasUnlockedIsland = p.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.VISITED_ISLANDS, DatapointStringList.class) + .getValue() + .contains(island.getInternalName()); + + if (!hasUnlockedIsland) { + p.sendMessage("§cYou haven't unlocked this fast travel destination!"); + return; + } - StringUtility.splitByWordAndLength(island.getDescription().apply(hasUnlockedIsland), 30).forEach(line -> { - lore.add("§7" + line); + if (!hasSubMenu) { + p.closeInventory(); + p.sendMessage("§7Warping you to " + island.getDescriptiveName() + "§7..."); + p.asProxyPlayer().transferToWithIndication(island.getServerType()).thenRun(() -> { + p.asProxyPlayer().sendMessage("§7You have been warped to " + island.getDescriptiveName() + "§7!"); }); - lore.add(" "); - - if (island.getAssociatedSkill() != null) { - lore.add("§7Main skill: §b" + island.getAssociatedSkill()); - lore.add("§7Island tier: §e" + island.getIslandTier()); - lore.add(" "); - } - - if (!hasUnlockedIsland) { - lore.add("§cWarp not unlocked!"); - } else { - if (hasSubMenu) { - lore.add("§8Right-Click to warp!"); - lore.add("§eLeft-Click to open!"); - } else { - lore.add("§eClick to warp!"); - } - } + return; + } - if (shouldBePaper) { - return ItemStackCreator.getStack( - island.getDescriptiveName(), - hasUnlockedIsland ? Material.PAPER : Material.BEDROCK, - 1, lore - ); - } else { - return ItemStackCreator.getStackHead( - island.getDescriptiveName(), - hasUnlockedIsland ? island.getTexture() : "da99b05b9a1db4d29b5e673d77ae54a77eab66818586035c8a2005aeb810602a", - 1, lore - ); - } + if (click.click() instanceof Click.Right) { + p.closeInventory(); + p.sendMessage("§7Warping you to " + island.getDescriptiveName() + "§7..."); + p.asProxyPlayer().transferToWithIndication(island.getServerType()).thenRun(() -> { + p.asProxyPlayer().sendMessage("§7You have been warped to " + island.getDescriptiveName() + "§7!"); + }); + } else { + //new GUIFastTravelSubMenu(island).open(p); } }); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravelSubMenu.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravelSubMenu.java index 34aac330d..908ff14bd 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravelSubMenu.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravelSubMenu.java @@ -1,16 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.fasttravel; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.type.generic.data.datapoints.DatapointStringList; import net.swofty.type.generic.data.datapoints.DatapointToggles; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.warps.ScrollUnlockReason; @@ -20,151 +17,123 @@ import java.util.ArrayList; import java.util.List; -public class GUIFastTravelSubMenu extends HypixelInventoryGUI { - private static final int[] SLOTS = new int[]{ - 20, 21, 22, 23, 24 - }; +public class GUIFastTravelSubMenu extends StatelessView { + private static final int[] SLOTS = new int[]{20, 21, 22, 23, 24}; private final TravelScrollIslands island; public GUIFastTravelSubMenu(TravelScrollIslands island) { - super(StringUtility.toNormalCase(island.getInternalName()) + " Warps", InventoryType.CHEST_5_ROW); - this.island = island; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(39, new GUIFastTravel())); - set(GUIClickableItem.getCloseItem(40)); - - boolean shouldBePaper = e.player().getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); - - set(new GUIClickableItem(13) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.closeInventory(); - player.sendMessage("§7Warping you to " + island.getDescriptiveName() + "§7..."); - - player.asProxyPlayer().transferToWithIndication(island.getServerType()).thenRun(() -> { - player.asProxyPlayer().sendMessage("§7You have been warped to " + island.getDescriptiveName() + "§7!"); - }); - } + public ViewConfiguration configuration() { + return new ViewConfiguration<>(StringUtility.toNormalCase(island.getInternalName()) + " Warps", InventoryType.CHEST_5_ROW); + } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 40); + Components.back(layout, 39, ctx); - lore.add("§8/warp " + island.getInternalName()); - lore.add(" "); + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + boolean shouldBePaper = player.getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); - StringUtility.splitByWordAndLength(island.getDescription().apply(true), 30).forEach(line -> { - lore.add("§7" + line); - }); - lore.add(" "); + // Main island warp + layout.slot(13, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + boolean isPaper = p.getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); - if (island.getAssociatedSkill() != null) { - lore.add("§7Main skill: §b" + island.getAssociatedSkill()); - lore.add("§7Island tier: §e" + island.getIslandTier()); - lore.add(" "); - } + List lore = new ArrayList<>(); + lore.add("§8/warp " + island.getInternalName()); + lore.add(" "); - lore.add("§eClick to warp!"); + StringUtility.splitByWordAndLength(island.getDescription().apply(true), 30).forEach(line -> { + lore.add("§7" + line); + }); + lore.add(" "); - if (shouldBePaper) { - return ItemStackCreator.getStack( - island.getDescriptiveName(), - Material.PAPER, - 1, lore - ); - } else { - return ItemStackCreator.getStackHead( - island.getDescriptiveName(), - island.getTexture(), - 1, lore - ); - } + if (island.getAssociatedSkill() != null) { + lore.add("§7Main skill: §b" + island.getAssociatedSkill()); + lore.add("§7Island tier: §e" + island.getIslandTier()); + lore.add(" "); } + + lore.add("§eClick to warp!"); + + if (isPaper) { + return ItemStackCreator.getStack(island.getDescriptiveName(), Material.PAPER, 1, lore); + } else { + return ItemStackCreator.getStackHead(island.getDescriptiveName(), island.getTexture(), 1, lore); + } + }, (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + p.closeInventory(); + p.sendMessage("§7Warping you to " + island.getDescriptiveName() + "§7..."); + p.asProxyPlayer().transferToWithIndication(island.getServerType()).thenRun(() -> { + p.asProxyPlayer().sendMessage("§7You have been warped to " + island.getDescriptiveName() + "§7!"); + }); }); List scrolls = island.getAssociatedScrolls(); - for (TravelScrollType scroll : scrolls) { - int slot = SLOTS[scrolls.indexOf(scroll)]; - boolean isUnlocked = ((SkyBlockPlayer) getPlayer()).getSkyblockDataHandler() - .get(SkyBlockDataHandler.Data.USED_SCROLLS, DatapointStringList.class) - .getValue() - .contains(scroll.getInternalName()); - - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!isUnlocked) { - player.sendMessage("§cYou haven't unlocked this fast travel destination!"); - return; - } - - player.closeInventory(); - player.sendMessage("§7Warping you to " + scroll.getDescription() + "§7..."); - - player.asProxyPlayer().transferToWithIndication(island.getServerType()).thenRun(() -> { - player.asProxyPlayer().sendMessage("§7You have been warped to " + scroll.getDisplayName() + "§7!"); - player.asProxyPlayer().teleport(scroll.getLocation()); - }); - } + for (int i = 0; i < scrolls.size() && i < SLOTS.length; i++) { + TravelScrollType scroll = scrolls.get(i); + int slot = SLOTS[i]; + + layout.slot(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + boolean isUnlocked = p.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.USED_SCROLLS, DatapointStringList.class) + .getValue() + .contains(scroll.getInternalName()); + boolean isPaper = p.getToggles().get(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - List lore = new ArrayList<>(); + List lore = new ArrayList<>(); + lore.add("§8/warp " + scroll.getInternalName()); + lore.add(" "); - lore.add("§8/warp " + scroll.getInternalName()); - lore.add(" "); + StringUtility.splitByWordAndLength(scroll.getDescription(), 50).forEach(line -> { + lore.add("§7" + line); + }); + lore.add(" "); - StringUtility.splitByWordAndLength(scroll.getDescription(), 50).forEach(line -> { - lore.add("§7" + line); - }); + if (!isUnlocked) { + ScrollUnlockReason unlockReason = scroll.getUnlockReason(); + lore.add(unlockReason.getTitleReason()); + lore.add(unlockReason.getSubReason()); lore.add(" "); + lore.add("§cWarp not unlocked!"); + } else { + lore.add("§eClick to warp!"); + } - if (!isUnlocked) { - ScrollUnlockReason unlockReason = scroll.getUnlockReason(); - lore.add(unlockReason.getTitleReason()); - lore.add(unlockReason.getSubReason()); - - lore.add(" "); - lore.add("§cWarp not unlocked!"); - } else { - lore.add("§eClick to warp!"); - } - - if (shouldBePaper) { - return ItemStackCreator.getStack( - scroll.getDisplayName(), - isUnlocked ? Material.PAPER : Material.BEDROCK, - 1, lore - ); - } else { - return ItemStackCreator.getStackHead( - scroll.getDisplayName(), - isUnlocked ? scroll.getHeadTexture() : "da99b05b9a1db4d29b5e673d77ae54a77eab66818586035c8a2005aeb810602a", - 1, lore - ); - } + if (isPaper) { + return ItemStackCreator.getStack(scroll.getDisplayName(), + isUnlocked ? Material.PAPER : Material.BEDROCK, 1, lore); + } else { + return ItemStackCreator.getStackHead(scroll.getDisplayName(), + isUnlocked ? scroll.getHeadTexture() : "da99b05b9a1db4d29b5e673d77ae54a77eab66818586035c8a2005aeb810602a", + 1, lore); } + }, (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + boolean isUnlocked = p.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.USED_SCROLLS, DatapointStringList.class) + .getValue() + .contains(scroll.getInternalName()); + + if (!isUnlocked) { + p.sendMessage("§cYou haven't unlocked this fast travel destination!"); + return; + } + + p.closeInventory(); + p.sendMessage("§7Warping you to " + scroll.getDescription() + "§7..."); + p.asProxyPlayer().transferToWithIndication(island.getServerType()).thenRun(() -> { + p.asProxyPlayer().sendMessage("§7You have been warped to " + scroll.getDisplayName() + "§7!"); + p.asProxyPlayer().teleport(scroll.getLocation()); + }); }); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIFairySoulsGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIFairySoulsGuide.java index 2e9d8da3e..d49fcdd8d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIFairySoulsGuide.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIFairySoulsGuide.java @@ -1,114 +1,93 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.questlog; -import lombok.Getter; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.data.monogdb.FairySoulDatabase; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.user.fairysouls.FairySoulZone; -public class GUIFairySoulsGuide extends HypixelInventoryGUI { +public class GUIFairySoulsGuide extends StatelessView { + private static final int[] LOCATION_SLOTS = { + 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28 + }; - private final int[] LOCATION_SLOTS = { - 11, 12, 13, 14, 15, 16, - 19, 20, 21, 22, 23, 24, 25, - 28 - }; + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Fairy Souls Guide", InventoryType.CHEST_5_ROW); + } - public GUIFairySoulsGuide() { - super("Fairy Souls Guide", InventoryType.CHEST_5_ROW); - } + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 40); + Components.back(layout, 39, ctx); - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(40)); - set(GUIClickableItem.getGoBackItem(39, new GUIMissionLog())); + // Miscellaneous fairy souls + layout.slot(10, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + int obtainedSouls = player.getFairySoulHandler().getFound(FairySoulZone.MISC_DUNGEONS) + + player.getFairySoulHandler().getFound(FairySoulZone.MISC_FISHING) + + player.getFairySoulHandler().getFound(FairySoulZone.MISC_GARDEN) + + player.getFairySoulHandler().getFound(FairySoulZone.MISC_PLACEABLE) + + player.getFairySoulHandler().getFound(FairySoulZone.MISC_GLACITE_MINESHAFTS); + int totalSouls = player.getFairySoulHandler().getMax(FairySoulZone.MISC_DUNGEONS) + + player.getFairySoulHandler().getMax(FairySoulZone.MISC_FISHING) + + player.getFairySoulHandler().getMax(FairySoulZone.MISC_GARDEN) + + player.getFairySoulHandler().getMax(FairySoulZone.MISC_PLACEABLE) + + player.getFairySoulHandler().getMax(FairySoulZone.MISC_GLACITE_MINESHAFTS); + return ItemStackCreator.getStackHead("§dMiscellaneous", + "126ec1ca185b47aad39f931db8b0a8500ded86a127a204886ed4b3783ad1775c", 1, + "§7Fairy Souls: §e" + obtainedSouls + "§7/§d" + totalSouls, + " §7Dungeons: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_DUNGEONS), + " §7Fishing: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_FISHING), + " §7Garden: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_GARDEN), + " §7Placeable: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_PLACEABLE), + " §7Glacite Mineshafts: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_GLACITE_MINESHAFTS)); + }); - set(new GUIItem(10) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - int optainedSouls = player.getFairySoulHandler().getFound(FairySoulZone.MISC_DUNGEONS) + player.getFairySoulHandler().getFound(FairySoulZone.MISC_FISHING) + player.getFairySoulHandler().getFound(FairySoulZone.MISC_GARDEN) + player.getFairySoulHandler().getFound(FairySoulZone.MISC_PLACEABLE) + player.getFairySoulHandler().getFound(FairySoulZone.MISC_GLACITE_MINESHAFTS); - int totalSouls = player.getFairySoulHandler().getMax(FairySoulZone.MISC_DUNGEONS) + player.getFairySoulHandler().getMax(FairySoulZone.MISC_FISHING) + player.getFairySoulHandler().getMax(FairySoulZone.MISC_GARDEN) + player.getFairySoulHandler().getMax(FairySoulZone.MISC_PLACEABLE) + player.getFairySoulHandler().getMax(FairySoulZone.MISC_GLACITE_MINESHAFTS); - return ItemStackCreator.getStackHead("§dMiscellaneous", "126ec1ca185b47aad39f931db8b0a8500ded86a127a204886ed4b3783ad1775c", 1, - "§7Fairy Souls: §e" + optainedSouls + "§7/§d" + totalSouls, - " §7Dungeons: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_DUNGEONS), - " §7Fishing: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_FISHING), - " §7Garden: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_GARDEN), - " §7Placeable: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_PLACEABLE), - " §7Glacite Mineshafts: §d" + player.getFairySoulHandler().getMax(FairySoulZone.MISC_GLACITE_MINESHAFTS) - ); - } - }); - FairySouls[] allFairySouls = FairySouls.values(); - int index = 0; - for (int slot : LOCATION_SLOTS) { - FairySouls fairySouls = allFairySouls[index]; + FairySouls[] allFairySouls = FairySouls.values(); + for (int i = 0; i < LOCATION_SLOTS.length && i < allFairySouls.length; i++) { + FairySouls fairySoul = allFairySouls[i]; + int slot = LOCATION_SLOTS[i]; - set(new GUIItem(slot) { - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§d" + fairySouls.regionName, fairySouls.texture, 1, - "§7Fairy Souls: §e" + player.getFairySoulHandler().getFound(fairySouls.zone) + "§7/§d" + player.getFairySoulHandler().getMax(fairySouls.zone)); - } - }); - index++; - } - updateItemStacks(getInventory(), getPlayer()); - } + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStackHead("§d" + fairySoul.regionName, fairySoul.texture, 1, + "§7Fairy Souls: §e" + player.getFairySoulHandler().getFound(fairySoul.zone) + + "§7/§d" + player.getFairySoulHandler().getMax(fairySoul.zone)); + }); + } + } - @Override - public boolean allowHotkeying() { - return false; - } + private enum FairySouls { + THE_END("The End", "7840b87d52271d2a755dedc82877e0ed3df67dcc42ea479ec146176b02779a5", FairySoulZone.THE_END), + THE_FARMING_ISLAND("The Farming Islands", "4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b", FairySoulZone.THE_FARMING_ISLANDS), + DWARVEN_MINES("Dwarven Mines", "6b20b23c1aa2be0270f016b4c90d6ee6b8330a17cfef87869d6ad60b2ffbf3b5", FairySoulZone.DWARVEN_MINES), + JERRYS_WORKSHOP("Jerry's Workshop", "6dd663136cafa11806fdbca6b596afd85166b4ec02142c8d5ac8941d89ab7", FairySoulZone.JERRYS_WORKSHOP), + DEEP_CAVERNS("Deep Caverns", "569a1f114151b4521373f34bc14c2963a5011cdc25a6554c48c708cd96ebfc", FairySoulZone.DEEP_CAVERNS), + CRIMSON_ISLAND("Crimson Isle", "c3687e25c632bce8aa61e0d64c24e694c3eea629ea944f4cf30dcfb4fbce071", FairySoulZone.CRIMSON_ISLE), + DUNGEON_HUB("Dungeon Hub", "9b56895b9659896ad647f58599238af532d46db9c1b0389b8bbeb70999dab33d", FairySoulZone.DUNGEON_HUB), + HUB("Hub", "686718d85e25b006f2c8f160f619b23c8fd6ae75ddf1c06308ec0f539d931703", FairySoulZone.HUB), + SPIDERS_DEN("Spider's Den", "c754318a3376f470e481dfcd6c83a59aa690ad4b4dd7577fdad1c2ef08d8aee6", FairySoulZone.SPIDERS_DEN), + THE_RIFT("The Rift", "f26192609d6c46ade73e807fc40dbc3a1a1afbb456ae165785b0fe834dd1cb57", FairySoulZone.THE_RIFT), + GOLD_MINE("Gold Mine", "73bc965d579c3c6039f0a17eb7c2e6faf538c7a5de8e60ec7a719360d0a857a9", FairySoulZone.GOLD_MINE), + THE_PARK("The Park", "a221f813dacee0fef8c59f76894dbb26415478d9ddfc44c2e708a6d3b7549b", FairySoulZone.THE_PARK), + GALATEA("Galatea", "a211ac81698c229d8ef2fae89f62a6a961b30d8b82b97161863090e90bff02a5", FairySoulZone.GALATEA), + BACKWATER_BAYOU("Backwater Bayou", "1c0cd33590f64d346d98cdd01606938742e715dda6737353306a44f81c8ba426", FairySoulZone.BACKWATER_BAYOU); - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } + private final String regionName; + private final String texture; + private final FairySoulZone zone; - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } - - @Getter - private enum FairySouls { - THE_END("The End", "7840b87d52271d2a755dedc82877e0ed3df67dcc42ea479ec146176b02779a5", FairySoulZone.THE_END), - THE_FARMING_ISLAND("The Farming Islands", "4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b", FairySoulZone.THE_FARMING_ISLANDS), - DWARVEN_MINES("Dwarven Mines", "6b20b23c1aa2be0270f016b4c90d6ee6b8330a17cfef87869d6ad60b2ffbf3b5", FairySoulZone.DWARVEN_MINES), - JERRYS_WORKSHOP("Jerry's Workshop", "6dd663136cafa11806fdbca6b596afd85166b4ec02142c8d5ac8941d89ab7", FairySoulZone.JERRYS_WORKSHOP), - DEEP_CAVERNS("Deep Caverns", "569a1f114151b4521373f34bc14c2963a5011cdc25a6554c48c708cd96ebfc", FairySoulZone.DEEP_CAVERNS), - CRIMSON_ISLAND("Crimson Isle", "c3687e25c632bce8aa61e0d64c24e694c3eea629ea944f4cf30dcfb4fbce071", FairySoulZone.CRIMSON_ISLE), - DUNGEON_HUB("Dungeon Hub", "9b56895b9659896ad647f58599238af532d46db9c1b0389b8bbeb70999dab33d", FairySoulZone.DUNGEON_HUB), - HUB("Hub", "686718d85e25b006f2c8f160f619b23c8fd6ae75ddf1c06308ec0f539d931703", FairySoulZone.HUB), - SPIDERS_DEN("Spider's Den", "c754318a3376f470e481dfcd6c83a59aa690ad4b4dd7577fdad1c2ef08d8aee6", FairySoulZone.SPIDERS_DEN), - THE_RIFT("The Rift", "f26192609d6c46ade73e807fc40dbc3a1a1afbb456ae165785b0fe834dd1cb57", FairySoulZone.THE_RIFT), - GOLD_MINE("Gold Mine", "73bc965d579c3c6039f0a17eb7c2e6faf538c7a5de8e60ec7a719360d0a857a9", FairySoulZone.GOLD_MINE), - THE_PARK("The Park", "a221f813dacee0fef8c59f76894dbb26415478d9ddfc44c2e708a6d3b7549b", FairySoulZone.THE_PARK), - GALATEA("Galatea", "a211ac81698c229d8ef2fae89f62a6a961b30d8b82b97161863090e90bff02a5", FairySoulZone.GALATEA), - BACKWATER_BAYOU("Backwater Bayou", "1c0cd33590f64d346d98cdd01606938742e715dda6737353306a44f81c8ba426", FairySoulZone.BACKWATER_BAYOU), - ; - private final String regionName; - private final String texture; - private final FairySoulZone zone; - - FairySouls(String regionName, String texture, FairySoulZone zone) { - this.regionName = regionName; - this.texture = texture; - this.zone = zone; - } - } + FairySouls(String regionName, String texture, FairySoulZone zone) { + this.regionName = regionName; + this.texture = texture; + this.zone = zone; + } + } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java index 7558ffe46..96885b292 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java @@ -1,18 +1,12 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.questlog; -import net.kyori.adventure.text.Component; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; import net.swofty.type.skyblockgeneric.data.monogdb.FairySoulDatabase; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; @@ -27,119 +21,93 @@ import java.util.List; import java.util.Map; -public class GUIMissionLog extends HypixelInventoryGUI { +public class GUIMissionLog extends StatelessView { private static final int[] MISSION_SLOTS = { - 11, 12, 13, 14, 15, 16, + 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43 }; + private final boolean showCompleted; + public GUIMissionLog() { - super("Quest Log", InventoryType.CHEST_6_ROW); + this(false); } - @Override - public void onOpen(InventoryGUIOpenEvent e) { - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); - display(false); + public GUIMissionLog(boolean showCompleted) { + this.showCompleted = showCompleted; } - public void display(boolean completed) { - getInventory().setTitle(Component.text("Quest Log " + (completed ? "(Completed)" : ""))); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aQuest Log " + (completed ? "(Completed)" : ""), Material.WRITABLE_BOOK, 1, "§7View your active quests,", "§7progress, and rewards."); - } - }); - set(new GUIClickableItem(10) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIFairySoulsGuide().open(player); - } + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Quest Log " + (showCompleted ? "(Completed)" : ""), InventoryType.CHEST_6_ROW); + } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§eFind all Fairy Souls", "b96923ad247310007f6ae5d326d847ad53864cf16c3565a181dc8e6b20be2387", 1, - "", - " §c✖ §eFound: " + player.getFairySoulHandler().getTotalFoundFairySouls() + "/" + FairySoulDatabase.getAllSouls().size(), - "", - "§7Forever ongoing quest...", - "", - "§eClick to view details!"); - } + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + layout.slot(4, (s, c) -> ItemStackCreator.getStack("§aQuest Log " + (showCompleted ? "(Completed)" : ""), + Material.WRITABLE_BOOK, 1, "§7View your active quests,", "§7progress, and rewards.")); + + // Fairy Souls + layout.slot(10, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStackHead("§eFind all Fairy Souls", + "b96923ad247310007f6ae5d326d847ad53864cf16c3565a181dc8e6b20be2387", 1, + "", + " §c✖ §eFound: " + player.getFairySoulHandler().getTotalFoundFairySouls() + "/" + FairySoulDatabase.getAllSouls().size(), + "", + "§7Forever ongoing quest...", + "", + "§eClick to view details!"); + }, (click, c) -> { + //new GUIFairySoulsGuide().open((SkyBlockPlayer) c.player()) }); - if (completed) { - set(new GUIClickableItem(50) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - display(false); - } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aOngoing Quests", Material.BOOK, 1, + // Toggle completed/ongoing + if (showCompleted) { + layout.slot(50, (s, c) -> ItemStackCreator.getStack("§aOngoing Quests", Material.BOOK, 1, "§7View quests you are currently", "§7working towards.", "§7 ", - "§eClick to view!"); - } - }); + "§eClick to view!"), + (click, c) -> { + //new GUIMissionLog(false).open((SkyBlockPlayer) c.player()) + }); } else { - set(new GUIClickableItem(50) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - display(true); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aCompleted Quests", Material.BOOK, 1, - "§7Take a peek at the past and", - "§7browse quests you've,", - "§7already completed.", - "§f ", - "§7Completed: §a" + player.getMissionData().getCompletedMissions().size(), - "§7 ", - "§eClick to view!"); - } + layout.slot(50, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStack("§aCompleted Quests", Material.BOOK, 1, + "§7Take a peek at the past and", + "§7browse quests you've,", + "§7already completed.", + "§f ", + "§7Completed: §a" + player.getMissionData().getCompletedMissions().size(), + "§7 ", + "§eClick to view!"); + }, (click, c) -> { + //new GUIMissionLog(true).open((SkyBlockPlayer) c.player()) }); } - MissionData missionData = ((SkyBlockPlayer) getPlayer()).getMissionData(); + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + MissionData missionData = player.getMissionData(); List completedMissions = new ArrayList<>(); List activeMissions = new ArrayList<>(); for (MissionSet set : MissionSet.values()) { boolean completedSet = true; - for (Class mission : set.getMissions()) { if (missionData.getMission(mission) == null || !missionData.getMission(mission).getValue()) { completedSet = false; break; } } - if (completedSet) { completedMissions.add(set); } else { @@ -147,88 +115,68 @@ public ItemStack.Builder getItem(HypixelPlayer p) { } } - Arrays.stream(MISSION_SLOTS).forEach(slot -> { - set(slot, ItemStack.builder(Material.AIR)); - }); + List toShow = showCompleted ? completedMissions : activeMissions; - List toShow = completed ? completedMissions : activeMissions; + // Clear mission slots + for (int missionSlot : MISSION_SLOTS) { + layout.slot(missionSlot, ItemStack.AIR.builder()); + } - for (int i = 0; i < toShow.size(); i++) { + for (int i = 0; i < toShow.size() && i < MISSION_SLOTS.length; i++) { MissionSet missionSet = toShow.get(i); - set(new GUIItem(MISSION_SLOTS[i]) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(List.of("§7 ")); - - Arrays.stream(missionSet.getMissions()).forEach(mission -> { - Map.Entry activeMission = missionData.getMission(mission); - - if (activeMission == null) { - try { - lore.add(" §c✖§e " + mission.newInstance().getName() + "."); - } catch (InstantiationException | IllegalAccessException e) { - throw new RuntimeException(e); - } - return; - } + int slot = MISSION_SLOTS[i]; - SkyBlockMission skyBlockMission = MissionData.getMissionClass(activeMission.getKey().getMissionID()); - SkyBlockProgressMission progressMission = missionData.getAsProgressMission(skyBlockMission.getID()); + layout.slot(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + MissionData data = p.getMissionData(); + List lore = new ArrayList<>(List.of("§7 ")); - lore.add(" " + (activeMission.getValue() ? "§a✔§f " : "§c✖§e ") + skyBlockMission.getName() - + (progressMission != null ? ". §7(§b" + activeMission.getKey().getMissionProgress() - + "§7/§b" + progressMission.getMaxProgress() + ")" : ".")); - }); - - lore.add("§7 "); - Map.Entry firstMissionInSetEntry = missionData.getMission(missionSet.getMissions()[0]); - if (firstMissionInSetEntry != null) { - MissionData.ActiveMission firstMissionInSet = firstMissionInSetEntry.getKey(); + Arrays.stream(missionSet.getMissions()).forEach(mission -> { + Map.Entry activeMission = data.getMission(mission); - lore.add("§7Started:"); - lore.add("§f " + SkyBlockCalendar.getMonthName( - SkyBlockCalendar.getMonth(firstMissionInSet.getMissionStarted())) - + " " + StringUtility.ntify(SkyBlockCalendar.getDay(firstMissionInSet.getMissionStarted()))); - lore.add("§7 " + SkyBlockCalendar.getDisplay(firstMissionInSet.getMissionStarted())); - if (completed) { - lore.add("§7 "); - lore.add("§7Completed:"); - lore.add("§f " + SkyBlockCalendar.getMonthName( - SkyBlockCalendar.getMonth(firstMissionInSet.getMissionEnded())) - + " " + StringUtility.ntify(SkyBlockCalendar.getDay(firstMissionInSet.getMissionEnded()))); - lore.add("§7 " + SkyBlockCalendar.getDisplay(firstMissionInSet.getMissionEnded())); + if (activeMission == null) { + try { + lore.add(" §c✖§e " + mission.newInstance().getName() + "."); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); } - } else { - lore.add("§7Not Yet Started"); + return; } - return ItemStackCreator.enchant( - ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(missionSet.name()), - Material.PAPER, 1, - lore)); - } - }); - } + SkyBlockMission skyBlockMission = MissionData.getMissionClass(activeMission.getKey().getMissionID()); + SkyBlockProgressMission progressMission = data.getAsProgressMission(skyBlockMission.getID()); - updateItemStacks(getInventory(), getPlayer()); - } + lore.add(" " + (activeMission.getValue() ? "§a✔§f " : "§c✖§e ") + skyBlockMission.getName() + + (progressMission != null ? ". §7(§b" + activeMission.getKey().getMissionProgress() + + "§7/§b" + progressMission.getMaxProgress() + ")" : ".")); + }); - @Override - public boolean allowHotkeying() { - return false; - } + lore.add("§7 "); + Map.Entry firstMissionInSetEntry = data.getMission(missionSet.getMissions()[0]); + if (firstMissionInSetEntry != null) { + MissionData.ActiveMission firstMissionInSet = firstMissionInSetEntry.getKey(); - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } + lore.add("§7Started:"); + lore.add("§f " + SkyBlockCalendar.getMonthName( + SkyBlockCalendar.getMonth(firstMissionInSet.getMissionStarted())) + + " " + StringUtility.ntify(SkyBlockCalendar.getDay(firstMissionInSet.getMissionStarted()))); + lore.add("§7 " + SkyBlockCalendar.getDisplay(firstMissionInSet.getMissionStarted())); - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - } + if (showCompleted) { + lore.add("§7 "); + lore.add("§7Completed:"); + lore.add("§f " + SkyBlockCalendar.getMonthName( + SkyBlockCalendar.getMonth(firstMissionInSet.getMissionEnded())) + + " " + StringUtility.ntify(SkyBlockCalendar.getDay(firstMissionInSet.getMissionEnded()))); + lore.add("§7 " + SkyBlockCalendar.getDisplay(firstMissionInSet.getMissionEnded())); + } + } else { + lore.add("§7Not Yet Started"); + } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + return ItemStackCreator.enchant(ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(missionSet.name()), + Material.PAPER, 1, lore)); + }); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java index affb88005..4350cbc66 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java @@ -1,15 +1,12 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributeMinionData; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.minion.MinionRegistry; import net.swofty.type.skyblockgeneric.minion.SkyBlockMinion; @@ -20,66 +17,48 @@ import java.util.List; import java.util.Map; -public class GUIMinionRecipes extends HypixelInventoryGUI { +public class GUIMinionRecipes extends StatelessView { private static final Map SLOTS = new HashMap<>(Map.of( 10, new int[]{11, 12, 13, 14, 15, 20, 21, 22, 23, 24}, 11, new int[]{11, 12, 13, 14, 15, 21, 22, 23, 30, 31, 32} )); - HypixelInventoryGUI previousGUI; - MinionRegistry minionRegistry; + private final MinionRegistry minionRegistry; + private final StatelessView previousView; - public GUIMinionRecipes(MinionRegistry minionRegistry, HypixelInventoryGUI previousGUI) { - super(StringUtility.toNormalCase(minionRegistry.toString()) + " Minion Recipes", InventoryType.CHEST_6_ROW); - this.previousGUI = previousGUI; + public GUIMinionRecipes(MinionRegistry minionRegistry, StatelessView previousView) { this.minionRegistry = minionRegistry; + this.previousView = previousView; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, previousGUI)); + public ViewConfiguration configuration() { + return new ViewConfiguration<>(StringUtility.toNormalCase(minionRegistry.toString()) + " Minion Recipes", + InventoryType.CHEST_6_ROW); + } - List craftableMinionTiers = new ArrayList<>(); + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + List craftableMinionTiers = new ArrayList<>(); for (SkyBlockMinion.MinionTier minionTier : minionRegistry.asSkyBlockMinion().getTiers()) { if (minionTier.craftable()) craftableMinionTiers.add(minionTier); } - int[] slots = SLOTS.get(craftableMinionTiers.size()); - int i = 0; - for (SkyBlockMinion.MinionTier minionTier : craftableMinionTiers) { + int[] slots = SLOTS.getOrDefault(craftableMinionTiers.size(), new int[]{}); + for (int i = 0; i < craftableMinionTiers.size() && i < slots.length; i++) { + SkyBlockMinion.MinionTier minionTier = craftableMinionTiers.get(i); int slot = slots[i]; - i++; + SkyBlockItem minion = new SkyBlockItem(minionRegistry.getItemType()); minion.getAttributeHandler().setMinionData(new ItemAttributeMinionData.MinionData(minionTier.tier(), 0)); - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRecipe(minion, new GUIMinionRecipes(minionRegistry, previousGUI), minionTier.tier() - 1).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStackHead(minion.getDisplayName(), minionTier.texture(), 1, - minion.getLore()); - } - }); + layout.slot(slot, (s, c) -> ItemStackCreator.getStackHead(minion.getDisplayName(), + minionTier.texture(), 1, minion.getLore()), + (click, c) -> c.player().openView(new GUIRecipe(minion, this, minionTier.tier() - 1))); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipe.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipe.java index 9532049c6..4ff2c55cd 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipe.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipe.java @@ -3,16 +3,13 @@ import lombok.SneakyThrows; import net.kyori.adventure.text.Component; import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.CraftableComponent; import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; @@ -22,173 +19,112 @@ import java.util.ArrayList; import java.util.List; -public class GUIRecipe extends HypixelInventoryGUI { +public class GUIRecipe extends StatelessView { private static final int[] CRAFT_SLOTS = new int[]{10, 11, 12, 19, 20, 21, 28, 29, 30}; - SkyBlockItem item; - HypixelInventoryGUI previousGUI; - int recipeIndex; + private final SkyBlockItem item; + private final int recipeIndex; - public GUIRecipe(ItemType type, HypixelInventoryGUI previousGUI) { - this(new SkyBlockItem(type), previousGUI, 0); + public GUIRecipe(ItemType type) { + this(new SkyBlockItem(type), 0); } - public GUIRecipe(SkyBlockItem item, HypixelInventoryGUI previousGUI) { - this(item, previousGUI, 0); + public GUIRecipe(SkyBlockItem item) { + this(item, 0); } - public GUIRecipe(SkyBlockItem item, HypixelInventoryGUI previousGUI, int recipeIndex) { - super(item.getAttributeHandler().getPotentialType().getDisplayName() + " Recipe", InventoryType.CHEST_6_ROW); - + public GUIRecipe(SkyBlockItem item, int recipeIndex) { this.item = item; - this.previousGUI = previousGUI; this.recipeIndex = recipeIndex; } + @Override + public ViewConfiguration configuration() { + ItemType type = item.getAttributeHandler().getPotentialType(); + String name = type != null ? type.getDisplayName() : "Unknown"; + return new ViewConfiguration<>(name + " Recipe", InventoryType.CHEST_6_ROW); + } + @SneakyThrows @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - if (previousGUI != null) - set(GUIClickableItem.getGoBackItem(48, previousGUI)); - set(GUIClickableItem.getCloseItem(49)); - - set(new GUIItem(23) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack( - "§aCrafting Table", Material.CRAFTING_TABLE, 1, - "§7Craft this recipe by using a", - "§7crafting table." - ); - } - }); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + layout.slot(23, (s, c) -> ItemStackCreator.getStack("§aCrafting Table", Material.CRAFTING_TABLE, 1, + "§7Craft this recipe by using a", + "§7crafting table.")); ItemType itemTypeLinker = item.getAttributeHandler().getPotentialType(); if (item.toConfigurableItem() == null) { - getPlayer().closeInventory(); - getPlayer().sendMessage("§cThis item has no associated crafting recipes!"); return; } + List> recipes = SkyBlockRecipe.getFromType(itemTypeLinker); if (recipes.isEmpty()) { - getPlayer().closeInventory(); - getPlayer().sendMessage("§cThis item has no associated crafting recipes!"); return; } - if (recipeIndex >= recipes.size()) - recipeIndex = 0; - SkyBlockRecipe recipe = recipes.get(recipeIndex); - - if (recipes.size() > recipeIndex + 1) { - set(new GUIClickableItem(32) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRecipe( - item, - GUIRecipe.this, - recipeIndex + 1 - ).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack( - "§aNext Recipe", Material.ARROW, 1, - "§7Click to view the next recipe!" - ); - } - }); + int actualRecipeIndex = recipeIndex >= recipes.size() ? 0 : recipeIndex; + SkyBlockRecipe recipe = recipes.get(actualRecipeIndex); + + // Next recipe button + if (recipes.size() > actualRecipeIndex + 1) { + layout.slot(32, (s, c) -> ItemStackCreator.getStack("§aNext Recipe", Material.ARROW, 1, + "§7Click to view the next recipe!"), + (click, c) -> { + c.push(new GUIRecipe(item, actualRecipeIndex + 1)); + }); } - if (recipeIndex > 0) { - set(new GUIClickableItem(14) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRecipe( - item, - GUIRecipe.this, - recipeIndex - 1 - ).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack( - "§aPrevious Recipe", Material.ARROW, 1, - "§7Click to view the previous recipe!" - ); - } - }); + + // Previous recipe button + if (actualRecipeIndex > 0) { + layout.slot(14, (s, c) -> ItemStackCreator.getStack("§aPrevious Recipe", Material.ARROW, 1, + "§7Click to view the previous recipe!"), + (click, c) -> { + c.push(new GUIRecipe(item, actualRecipeIndex - 1)); + }); } - set(new GUIItem(25) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return PlayerItemUpdater.playerUpdate(player, recipe.getResult().getItemStack()) - .amount(recipe.getResult().getAmount()); - } + // Result + layout.slot(25, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return PlayerItemUpdater.playerUpdate(player, recipe.getResult().getItemStack()) + .amount(recipe.getResult().getAmount()); }); + // Ingredients SkyBlockItem[] ingredients = recipe.getRecipeDisplay(); - int slot = 0; - - for (int craftSlot : CRAFT_SLOTS) { - if (slot < ingredients.length) { - SkyBlockItem ingredient = ingredients[slot]; - if (ingredient != null) { - set(new GUIClickableItem(craftSlot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!(ingredient.hasComponent(CraftableComponent.class))) - return; - - new GUIRecipe( - ingredient, - GUIRecipe.this, - 0 - ).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ItemStack.Builder builder = PlayerItemUpdater.playerUpdate(player, ingredient.getItemStack()); - - if (ingredient.hasComponent(CraftableComponent.class)) { - ArrayList lore = new ArrayList<>(builder.build().get(DataComponents.LORE)); - lore.add(Component.text(" ")); - lore.add(Component.text("§eClick to view recipe!")); - builder.set(DataComponents.LORE, lore); - } - - if (ingredient.getAttributeHandler().shouldBeEnchanted()) - ItemStackCreator.enchant(builder); - - return builder; - } - }); - } else { - set(craftSlot, ItemStack.builder(Material.AIR)); - } + for (int i = 0; i < CRAFT_SLOTS.length && i < ingredients.length; i++) { + SkyBlockItem ingredient = ingredients[i]; + int craftSlot = CRAFT_SLOTS[i]; + + if (ingredient != null) { + layout.slot(craftSlot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + ItemStack.Builder builder = PlayerItemUpdater.playerUpdate(player, ingredient.getItemStack()); + + if (ingredient.hasComponent(CraftableComponent.class)) { + List existingLore = builder.build().get(DataComponents.LORE); + ArrayList lore = existingLore != null ? new ArrayList<>(existingLore) : new ArrayList<>(); + lore.add(Component.text(" ")); + lore.add(Component.text("§eClick to view recipe!")); + builder.set(DataComponents.LORE, lore); + } + + if (ingredient.getAttributeHandler().shouldBeEnchanted()) + ItemStackCreator.enchant(builder); + + return builder; + }, (click, c) -> { + if (ingredient.hasComponent(CraftableComponent.class)) { + c.push(new GUIRecipe(ingredient, 0)); + } + }); + } else { + layout.slot(craftSlot, ItemStack.AIR.builder()); } - slot++; } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java index a60424439..e5eb51743 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java @@ -1,17 +1,11 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; import net.swofty.type.skyblockgeneric.item.crafting.ShapedRecipe; import net.swofty.type.skyblockgeneric.item.crafting.ShapelessRecipe; @@ -22,166 +16,77 @@ import java.util.Arrays; import java.util.List; -public class GUIRecipeBook extends HypixelInventoryGUI { - private final int[] categorySlots = { +public class GUIRecipeBook extends StatelessView { + private static final int[] CATEGORY_SLOTS = { 20, 21, 22, 23, 24, 29, 30, 31, 33 }; - public GUIRecipeBook() { - super("Recipe Book", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Recipe Book", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); ArrayList allRecipes = new ArrayList<>(); allRecipes.addAll(ShapedRecipe.CACHED_RECIPES); allRecipes.addAll(ShapelessRecipe.CACHED_RECIPES); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(List.of( - "§7Through your adventure, you will", - "§7unlock recipes for all kinds of", - "§7special items! You can view how to", - "§7craft these items here.", - " " - )); - - SkyBlockRecipe.getMissionDisplay(lore, player.getUuid()); - - return ItemStackCreator.getStack("§aRecipe Book", Material.BOOK, 1, lore.toArray(new String[0])); - } + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(List.of( + "§7Through your adventure, you will", + "§7unlock recipes for all kinds of", + "§7special items! You can view how to", + "§7craft these items here.", + " " + )); + SkyBlockRecipe.getMissionDisplay(lore, player.getUuid()); + return ItemStackCreator.getStack("§aRecipe Book", Material.BOOK, 1, lore.toArray(new String[0])); }); - int index = 0; - for (int slot : categorySlots) { - SkyBlockRecipe.RecipeType type = SkyBlockRecipe.RecipeType.values()[index++]; + for (int i = 0; i < CATEGORY_SLOTS.length && i < SkyBlockRecipe.RecipeType.values().length; i++) { + SkyBlockRecipe.RecipeType type = SkyBlockRecipe.RecipeType.values()[i]; + int slot = CATEGORY_SLOTS[i]; ArrayList typeRecipes = new ArrayList<>(); - ArrayList allowedRecipes = new ArrayList<>(); allRecipes.forEach(recipe -> { if (recipe.getRecipeType() == type) { typeRecipes.add(recipe); } }); - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRecipeCategory(type, new GUIRecipeBook()).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(Arrays.asList( - "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", - "§7that you have unlocked!", " ")); - - typeRecipes.forEach(recipe -> { - SkyBlockRecipe.CraftingResult result = - (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); - - if (result.allowed()) { - allowedRecipes.add(recipe); - } - }); - - String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); - lore.add("§7Recipes Unlocked: §e" + unlockedPercentage + "§6%"); - - String baseLoadingBar = "─────────────────"; - int maxBarLength = baseLoadingBar.length(); - int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); - - String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); - int formattingCodeLength = 4; // Adjust this if you add or remove formatting codes - String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( - completedLoadingBar.length() - formattingCodeLength, // Adjust for added formatting codes - maxBarLength - )); - - lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); - lore.add(" "); - lore.add("§eClick to view!"); - - return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", - type.getMaterial(), 1, lore); - } - }); - } - set(new GUIClickableItem(32) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRecipeSlayers().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - - SkyBlockRecipe.RecipeType type = SkyBlockRecipe.RecipeType.SLAYER; - - ArrayList recipeTypes = new ArrayList<>(); - recipeTypes.add(SkyBlockRecipe.RecipeType.REVENANT_HORROR); - recipeTypes.add(SkyBlockRecipe.RecipeType.TARANTULA_BROODFATHER); - recipeTypes.add(SkyBlockRecipe.RecipeType.SVEN_PACKMASTER); - recipeTypes.add(SkyBlockRecipe.RecipeType.VOIDGLOOM_SERAPH); - recipeTypes.add(SkyBlockRecipe.RecipeType.INFERNO_DEMONLORD); - - ArrayList typeRecipes = new ArrayList<>(); + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); ArrayList allowedRecipes = new ArrayList<>(); - allRecipes.forEach(recipe -> { - if (recipeTypes.contains(recipe.getRecipeType())) { - typeRecipes.add(recipe); - } - }); ArrayList lore = new ArrayList<>(Arrays.asList( "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", "§7that you have unlocked!", " ")); typeRecipes.forEach(recipe -> { - SkyBlockRecipe.CraftingResult result = - (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); - + SkyBlockRecipe.CraftingResult result = (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); if (result.allowed()) { allowedRecipes.add(recipe); } }); String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); - lore.add("§7Slayer Recipes Unlocked: §e" + unlockedPercentage + "§6%"); + lore.add("§7Recipes Unlocked: §e" + unlockedPercentage + "§6%"); String baseLoadingBar = "─────────────────"; int maxBarLength = baseLoadingBar.length(); int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); - int formattingCodeLength = 4; // Adjust this if you add or remove formatting codes + int formattingCodeLength = 4; String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( - completedLoadingBar.length() - formattingCodeLength, // Adjust for added formatting codes - maxBarLength - )); + completedLoadingBar.length() - formattingCodeLength, maxBarLength)); lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); lore.add(" "); @@ -189,28 +94,60 @@ public ItemStack.Builder getItem(HypixelPlayer p) { return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", type.getMaterial(), 1, lore); - } - }); - updateItemStacks(getInventory(), getPlayer()); - } + }, (click, c) -> { + //new GUIRecipeCategory(type, new GUIRecipeBook()).open((SkyBlockPlayer) c.player()) + }); + } - @Override - public boolean allowHotkeying() { - return false; - } + // Slayer recipes + layout.slot(32, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockRecipe.RecipeType type = SkyBlockRecipe.RecipeType.SLAYER; - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { + ArrayList recipeTypes = new ArrayList<>(); + recipeTypes.add(SkyBlockRecipe.RecipeType.REVENANT_HORROR); + recipeTypes.add(SkyBlockRecipe.RecipeType.TARANTULA_BROODFATHER); + recipeTypes.add(SkyBlockRecipe.RecipeType.SVEN_PACKMASTER); + recipeTypes.add(SkyBlockRecipe.RecipeType.VOIDGLOOM_SERAPH); + recipeTypes.add(SkyBlockRecipe.RecipeType.INFERNO_DEMONLORD); - } + ArrayList typeRecipes = new ArrayList<>(); + ArrayList allowedRecipes = new ArrayList<>(); + allRecipes.forEach(recipe -> { + if (recipeTypes.contains(recipe.getRecipeType())) { + typeRecipes.add(recipe); + } + }); - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { + ArrayList lore = new ArrayList<>(Arrays.asList( + "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", + "§7that you have unlocked!", " ")); - } + typeRecipes.forEach(recipe -> { + SkyBlockRecipe.CraftingResult result = (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); + if (result.allowed()) { + allowedRecipes.add(recipe); + } + }); - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); + lore.add("§7Slayer Recipes Unlocked: §e" + unlockedPercentage + "§6%"); + + String baseLoadingBar = "─────────────────"; + int maxBarLength = baseLoadingBar.length(); + int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); + + String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); + int formattingCodeLength = 4; + String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( + completedLoadingBar.length() - formattingCodeLength, maxBarLength)); + + lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); + lore.add(" "); + lore.add("§eClick to view!"); + + return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", + type.getMaterial(), 1, lore); + }, (click, c) -> new GUIRecipeSlayers().open((SkyBlockPlayer) c.player())); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java index 5120a1ec3..2bccbccb9 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java @@ -181,9 +181,9 @@ protected GUIClickableItem createItemFor(SkyBlockRecipe item, int slot, HypixelP @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRecipe( - item.getResult().getAttributeHandler().getPotentialType(), - GUIRecipeCategory.this).open(player); + //new GUIRecipe( + // item.getResult().getAttributeHandler().getPotentialType(), + // GUIRecipeCategory.this).open(player); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java index ec5062762..4a27988d1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java @@ -33,7 +33,7 @@ public GUIRecipeSlayers() { public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUIRecipeBook())); + //set(GUIClickableItem.getGoBackItem(48, new GUIRecipeBook())); ArrayList allRecipes = new ArrayList<>(); allRecipes.addAll(ShapedRecipe.CACHED_RECIPES); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkillCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkillCategory.java index 2d14acc8b..2cd131364 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkillCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkillCategory.java @@ -1,18 +1,12 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.skills; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.type.generic.data.datapoints.DatapointToggles; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSkills; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bestiary.GUIBestiary; import net.swofty.type.skyblockgeneric.skill.SkillCategories; @@ -22,8 +16,8 @@ import java.util.ArrayList; import java.util.List; -public class GUISkillCategory extends HypixelInventoryGUI { - private static final int[] displaySlots = { +public class GUISkillCategory extends StatelessView { + private static final int[] DISPLAY_SLOTS = { 9, 18, 27, 28, 29, 20, 11, 2, 3, 4, 13, 22, 31, 32, 33, 24, 15, 6, 7, 8, 17, 26, 35, 44, 53 }; @@ -31,160 +25,114 @@ public class GUISkillCategory extends HypixelInventoryGUI { private final int page; public GUISkillCategory(SkillCategories category, int page) { - super(category.toString() + " Skill", InventoryType.CHEST_6_ROW); - this.category = category; this.page = page; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(Material.BLACK_STAINED_GLASS_PANE, ""); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkills())); + public ViewConfiguration configuration() { + return new ViewConfiguration<>(category.toString() + " Skill", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); - DatapointSkills.PlayerSkills skills = ((SkyBlockPlayer) e.player()).getSkills(); + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + DatapointSkills.PlayerSkills skills = player.getSkills(); int level = skills.getCurrentLevel(category); Integer nextLevel = skills.getNextLevel(category); + // Bestiary button for combat if (category == SkillCategories.COMBAT && player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_BRAMASS_BEASTSLAYER)) { - set(new GUIClickableItem(39) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIBestiary().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(); - player.getBestiaryData().getTotalDisplay(lore); - lore.add(""); - lore.add("§eClick to view!"); - - return ItemStackCreator.getStack("§3Bestiary", Material.WRITTEN_BOOK, 1, lore); - } - }); + layout.slot(39, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + ArrayList lore = new ArrayList<>(); + p.getBestiaryData().getTotalDisplay(lore); + lore.add(""); + lore.add("§eClick to view!"); + return ItemStackCreator.getStack("§3Bestiary", Material.WRITTEN_BOOK, 1, lore); + }, (click, c) -> new GUIBestiary().open((SkyBlockPlayer) c.player())); } - set(new GUIItem(0) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(category.asCategory().getDescription()); - - lore.add(" "); - - if (nextLevel == null) { - lore.add("§cMAX LEVEL REACHED"); - } else { - player.getSkills().getDisplay(lore, category, category.asCategory().getReward(nextLevel).requirement(), - "§7Progress to Level " + StringUtility.getAsRomanNumeral(nextLevel) + ": "); - } + // Skill info + layout.slot(0, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(category.asCategory().getDescription()); + lore.add(" "); + + Integer next = p.getSkills().getNextLevel(category); + if (next == null) { + lore.add("§cMAX LEVEL REACHED"); + } else { + p.getSkills().getDisplay(lore, category, category.asCategory().getReward(next).requirement(), + "§7Progress to Level " + StringUtility.getAsRomanNumeral(next) + ": "); + } - lore.add(" "); - lore.add("§8Increase your " + category + " Level to"); - lore.add("§8unlock Perks, statistic bonuses, and"); - lore.add("§8more!"); + lore.add(" "); + lore.add("§8Increase your " + category + " Level to"); + lore.add("§8unlock Perks, statistic bonuses, and"); + lore.add("§8more!"); - return ItemStackCreator.getStack("§a" + category + " Skill", - category.asCategory().getDisplayIcon(), 1, lore); - } + return ItemStackCreator.getStack("§a" + category + " Skill", + category.asCategory().getDisplayIcon(), 1, lore); }); List rewards = List.of(category.asCategory().getRewards()); - // Check if there is a future page, if there is, add a next page button - if (rewards.size() > (page + 1) * displaySlots.length) { - set(new GUIClickableItem(50) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISkillCategory(category, page + 1).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aNext Page", Material.ARROW, 1, "§7Click to view the next page of rewards."); - } - }); + // Next page button + if (rewards.size() > (page + 1) * DISPLAY_SLOTS.length) { + layout.slot(50, (s, c) -> ItemStackCreator.getStack("§aNext Page", Material.ARROW, 1, + "§7Click to view the next page of rewards."), + (click, c) -> { + //new GUISkillCategory(category, page + 1).open((SkyBlockPlayer) c.player()) + }); } - // Check if there is a previous page, if there is, add a previous page button - if (page > 0) { - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISkillCategory(category, page - 1).open(player); - } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aPrevious Page", Material.ARROW, 1, "§7Click to view the previous page of rewards."); - } - }); + // Previous page button + if (page > 0) { + layout.slot(48, (s, c) -> ItemStackCreator.getStack("§aPrevious Page", Material.ARROW, 1, + "§7Click to view the previous page of rewards."), + (click, c) -> { + //new GUISkillCategory(category, page - 1).open((SkyBlockPlayer) c.player()) + }); } - - int index = 0; - // Split into pages depending on side of displaySlots - for (SkillCategory.SkillReward reward : rewards.subList(page * displaySlots.length, Math.min(rewards.size(), (page + 1) * displaySlots.length))) { - if (index >= displaySlots.length) break; - int slot = displaySlots[index]; - - set(new GUIItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - reward.getDisplay(lore); - - Material icon = Material.RED_STAINED_GLASS_PANE; - String colour = "§c"; - - if (level >= reward.level()) { - icon = Material.LIME_STAINED_GLASS_PANE; - colour = "§a"; - - lore.add(" "); - lore.add("§a§lUNLOCKED"); - } else if ((level + 1) == reward.level()) { - icon = Material.YELLOW_STAINED_GLASS_PANE; - colour = "§e"; - - lore.add(" "); - player.getSkills().getDisplay(lore, category, reward.requirement(), "§7Progress: "); - } - - return ItemStackCreator.getStack(colour + category + " Level " + StringUtility.getAsRomanNumeral(reward.level()), - icon, 1, lore); + // Rewards + int startIndex = page * DISPLAY_SLOTS.length; + int endIndex = Math.min(rewards.size(), (page + 1) * DISPLAY_SLOTS.length); + List pageRewards = rewards.subList(startIndex, endIndex); + + for (int i = 0; i < pageRewards.size() && i < DISPLAY_SLOTS.length; i++) { + SkillCategory.SkillReward reward = pageRewards.get(i); + int slot = DISPLAY_SLOTS[i]; + + layout.slot(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + int currentLevel = p.getSkills().getCurrentLevel(category); + List lore = new ArrayList<>(); + reward.getDisplay(lore); + + Material icon = Material.RED_STAINED_GLASS_PANE; + String colour = "§c"; + + if (currentLevel >= reward.level()) { + icon = Material.LIME_STAINED_GLASS_PANE; + colour = "§a"; + lore.add(" "); + lore.add("§a§lUNLOCKED"); + } else if ((currentLevel + 1) == reward.level()) { + icon = Material.YELLOW_STAINED_GLASS_PANE; + colour = "§e"; + lore.add(" "); + p.getSkills().getDisplay(lore, category, reward.requirement(), "§7Progress: "); } - }); - index++; + return ItemStackCreator.getStack(colour + category + " Level " + StringUtility.getAsRomanNumeral(reward.level()), + icon, 1, lore); + }); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java index 822c53ed6..9bd8201bc 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java @@ -1,140 +1,85 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.skills; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.skill.SkillCategories; import net.swofty.type.skyblockgeneric.skill.SkillCategory; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.ArrayList; -public class GUISkills extends HypixelInventoryGUI { - private final int[] displaySlots = { +public class GUISkills extends StatelessView { + private static final int[] DISPLAY_SLOTS = { 19, 20, 21, 22, 23, 24, 25, - 28, 29, 30, 32, 33, 34 + 28, 29, 30, 32, 33, 34 }; - public GUISkills() { - super("Your Skills", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Your Skills", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(Material.BLACK_STAINED_GLASS_PANE, ""); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", - Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); + layout.slot(4, (s, c) -> ItemStackCreator.getStack("§aYour Skills", Material.DIAMOND_SWORD, 1, + "§7View your Skill progression and", + "§7rewards.")); SkillCategories[] allCategories = SkillCategories.values(); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aYour Skills", Material.DIAMOND_SWORD, 1, - "§7View your Skill progression and", - "§7rewards."); - } - }); - updateItemStacks(getInventory(), getPlayer()); - - Thread.startVirtualThread(() -> { - int index = 0; - for (int slot : displaySlots) { - SkillCategories category = allCategories[index]; - SkillCategory skillCategory = category.asCategory(); - - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (category == SkillCategories.CARPENTRY && !player.getMissionData().hasCompleted("give_wool_to_carpenter")) return; - new GUISkillCategory(category, 0).open(player); + for (int i = 0; i < DISPLAY_SLOTS.length && i < allCategories.length; i++) { + SkillCategories category = allCategories[i]; + SkillCategory skillCategory = category.asCategory(); + int slot = DISPLAY_SLOTS[i]; + + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + ArrayList lore = new ArrayList<>(); + + if (category == SkillCategories.CARPENTRY && !player.getMissionData().hasCompleted("give_wool_to_carpenter")) { + lore.add("§7Unlock this skill by talking to the"); + lore.add("§7Carpenter."); + lore.add(""); + lore.add("§bNot unlocked!"); + } else { + lore.addAll(skillCategory.getDescription()); + lore.add(" "); + + Integer nextLevel = player.getSkills().getNextLevel(category); + + if (nextLevel != null) { + player.getSkills().getDisplay(lore, category, skillCategory.getRewards()[nextLevel - 1].requirement(), + "§7Progress to Level " + StringUtility.getAsRomanNumeral(nextLevel) + ": "); + lore.add(" "); + + SkillCategory.SkillReward[] rewards = skillCategory.getRewards(); + SkillCategory.SkillReward reward = rewards[nextLevel - 1]; + + reward.getDisplay(lore); + } else { + lore.add("§cMax Level Reached!"); } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(); - if (category == SkillCategories.CARPENTRY && !player.getMissionData().hasCompleted("give_wool_to_carpenter")) { - lore.add("§7Unlock this skill by talking to the"); - lore.add("§7Carpenter."); - lore.add(""); - lore.add("§bNot unlocked!"); - } else { - lore.addAll(skillCategory.getDescription()); - lore.add(" "); - - Integer nextLevel = player.getSkills().getNextLevel(category); - - if (nextLevel != null) { - player.getSkills().getDisplay(lore, category, skillCategory.getRewards()[nextLevel - 1].requirement(), - "§7Progress to Level " + StringUtility.getAsRomanNumeral(nextLevel) + ": "); - lore.add(" "); - - SkillCategory.SkillReward[] rewards = skillCategory.getRewards(); - SkillCategory.SkillReward reward = rewards[nextLevel - 1]; - - reward.getDisplay(lore); - } else { - lore.add("§cMax Level Reached!"); - } - - lore.add(" "); - lore.add("§eClick to view!"); - } - - return ItemStackCreator.getStack( - "§a" + skillCategory.getName() + " " + - StringUtility.getAsRomanNumeral(player.getSkills().getCurrentLevel(category)), - skillCategory.getDisplayIcon(), 1, lore); - } - }); - - updateItemStacks(getInventory(), getPlayer()); - index++; - } - }); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + lore.add(" "); + lore.add("§eClick to view!"); + } + + return ItemStackCreator.getStack( + "§a" + skillCategory.getName() + " " + + StringUtility.getAsRomanNumeral(player.getSkills().getCurrentLevel(category)), + skillCategory.getDisplayIcon(), 1, lore); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (category == SkillCategories.CARPENTRY && !player.getMissionData().hasCompleted("give_wool_to_carpenter")) return; + //new GUISkillCategory(category, 0).open(player); + }); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUICombatStats.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUICombatStats.java index 834e3e150..2093227b7 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUICombatStats.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUICombatStats.java @@ -309,7 +309,7 @@ public GUICombatStats() { @Override public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); + //set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); set(GUIClickableItem.getCloseItem(49)); set(new GUIItem(4) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIGatheringStats.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIGatheringStats.java index c69f2ab41..897bfc7a6 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIGatheringStats.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIGatheringStats.java @@ -500,7 +500,7 @@ public GUIGatheringStats() { @Override public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); + //set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); set(GUIClickableItem.getCloseItem(49)); set(new GUIItem(4) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIMiscStats.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIMiscStats.java index 4b08e9883..928a804d9 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIMiscStats.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIMiscStats.java @@ -188,7 +188,7 @@ public GUIMiscStats() { @Override public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); + //set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); set(GUIClickableItem.getCloseItem(49)); set(new GUIItem(4) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIWisdomStats.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIWisdomStats.java index ea356f1da..d9182526f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIWisdomStats.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIWisdomStats.java @@ -45,7 +45,7 @@ public GUIWisdomStats() { @Override public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); + //set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); set(GUIClickableItem.getCloseItem(49)); set(new GUIItem(4) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/AbiphoneComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/AbiphoneComponent.java index 49d610751..bb45d79ca 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/AbiphoneComponent.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/AbiphoneComponent.java @@ -3,6 +3,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.swofty.commons.StringUtility; +import net.swofty.type.skyblockgeneric.gui.inventories.abiphone.AbiphoneView; import net.swofty.type.skyblockgeneric.gui.inventories.abiphone.GUIAbiphone; import net.swofty.type.skyblockgeneric.item.SkyBlockItemComponent; @@ -37,7 +38,7 @@ public AbiphoneComponent(int maxContacts, int maxDiscs, List fe addInheritedComponent(new LoreUpdateComponent(lore, false)); addInheritedComponent(new InteractableComponent( (player, item) -> { - new GUIAbiphone(item).open(player); + player.openView(new AbiphoneView(), new AbiphoneView.State(item)); }, null, null diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/RightClickRecipeComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/RightClickRecipeComponent.java index cafacb73e..18e0266c3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/RightClickRecipeComponent.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/RightClickRecipeComponent.java @@ -12,7 +12,7 @@ public class RightClickRecipeComponent extends SkyBlockItemComponent { public RightClickRecipeComponent(String recipeItem) { this.recipeItem = ItemType.valueOf(recipeItem); addInheritedComponent(new InteractableComponent( - (player, item) -> new GUIRecipe(this.recipeItem, null).open(player), + (player, item) -> player.openView(new GUIRecipe(this.recipeItem, null)), null, null )); diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/redis/service/RedisSkywarsLobbyPropagatePartyEvent.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/redis/service/RedisSkywarsLobbyPropagatePartyEvent.java index 61ba85064..11cc01ed5 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/redis/service/RedisSkywarsLobbyPropagatePartyEvent.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/redis/service/RedisSkywarsLobbyPropagatePartyEvent.java @@ -283,7 +283,7 @@ private void handleWarpEvent(HypixelPlayer player, PartyWarpResponseEvent event) throw new RuntimeException("Couldn't find a proxy for " + warperName); } - if (warperServer.uuid() == HypixelConst.getServerUUID()) { + if (warperServer.uuid().equals(HypixelConst.getServerUUID())) { return; } From 432bf476596cb0bffc21c3aa4c552f3583f13c34 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 10 Jan 2026 20:25:25 +0200 Subject: [PATCH 13/35] feat: clean things --- .../type/generic/gui/v2/PaginatedView.java | 75 +-- .../type/generic/gui/v2/Pagination.java | 21 +- .../type/generic/gui/v2/SharedContext.java | 8 +- .../generic/gui/v2/SlotChangeHandler.java | 2 +- .../type/generic/gui/v2/StatefulView.java | 2 +- .../net/swofty/type/generic/gui/v2/View.java | 28 +- .../type/generic/gui/v2/ViewComponent.java | 106 ++-- .../generic/gui/v2/ViewConfiguration.java | 80 +-- .../type/generic/gui/v2/ViewLayout.java | 246 ++++---- .../type/generic/gui/v2/ViewNavigator.java | 123 ++-- .../type/generic/gui/v2/ViewSession.java | 597 +++++++++--------- .../generic/gui/v2/context/ClickContext.java | 11 +- .../generic/gui/v2/context/ViewContext.java | 37 +- .../generic/gui/v2/test/TestMixedView.java | 36 +- .../gui/v2/test/TestSharedContainerView.java | 153 ++--- .../gui/v2/test/TestSharedStateView.java | 62 +- .../commands/ViewRecipeCommand.java | 2 +- .../abiphone/GUIContactManagementView.java | 2 +- .../collection/GUICollectionReward.java | 2 +- .../sbmenu/recipe/GUIMinionRecipes.java | 2 +- .../components/RightClickRecipeComponent.java | 2 +- 21 files changed, 824 insertions(+), 773 deletions(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java index c5bc3395f..d5adba18e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java @@ -14,22 +14,22 @@ public abstract class PaginatedView> implements View { - protected static final ItemStack.Builder PREV_ARROW = ItemStack.builder(Material.ARROW) - .set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")); - protected static final ItemStack.Builder NEXT_ARROW = ItemStack.builder(Material.ARROW) - .set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")); - protected static final ItemStack.Builder SEARCH_ICON = ItemStack.builder(Material.BIRCH_SIGN) - .set(DataComponents.CUSTOM_NAME, Component.text("§aSearch")); - protected static final ItemStack.Builder FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE) - .set(DataComponents.CUSTOM_NAME, Component.text(" ")) - .set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())); + protected static final ItemStack.Builder PREV_ARROW = ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")); + protected static final ItemStack.Builder NEXT_ARROW = ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")); + protected static final ItemStack.Builder SEARCH_ICON = ItemStack.builder(Material.BIRCH_SIGN).set(DataComponents.CUSTOM_NAME, Component.text("§aSearch")); + protected static final ItemStack.Builder FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE).set(DataComponents.CUSTOM_NAME, Component.text(" ")).set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())); public interface PaginatedState { List items(); + int page(); + String query(); + PaginatedState withPage(int page); + PaginatedState withQuery(String query); + PaginatedState withItems(List items); } @@ -45,9 +45,7 @@ public void layout(ViewLayout layout, S state, ViewContext ctx) { // Calculate page boundaries int startIndex = currentPage * itemsPerPage; int endIndex = Math.min(startIndex + itemsPerPage, filteredItems.size()); - List pageItems = startIndex < filteredItems.size() - ? filteredItems.subList(startIndex, endIndex) - : List.of(); + List pageItems = startIndex < filteredItems.size() ? filteredItems.subList(startIndex, endIndex) : List.of(); // Render paginated items for (int i = 0; i < slots.length; i++) { @@ -55,9 +53,7 @@ public void layout(ViewLayout layout, S state, ViewContext ctx) { if (i < pageItems.size()) { T item = pageItems.get(i); int itemIndex = startIndex + i; - layout.slot(slot, - (s, c) -> renderItem(item, itemIndex, ctx.player()), - (click, viewCtx) -> onItemClick(click, viewCtx, item, itemIndex)); + layout.slot(slot, (s, c) -> renderItem(item, itemIndex, ctx.player()), (click, viewCtx) -> onItemClick(click, viewCtx, item, itemIndex)); } else { layout.slot(slot, (s, c) -> ItemStack.AIR.builder()); } @@ -72,9 +68,7 @@ protected List getFilteredItems(S state) { if (query == null || query.isEmpty()) { return state.items(); } - return state.items().stream() - .filter(item -> !shouldFilterFromSearch(query, item)) - .toList(); + return state.items().stream().filter(item -> !shouldFilterFromSearch(query, item)).toList(); } protected void layoutBackground(ViewLayout layout, S state, ViewContext ctx) { @@ -88,12 +82,10 @@ protected void layoutNavigation(ViewLayout layout, S state, ViewContext ctx, if (prevSlot >= 0) { if (currentPage > 0) { - layout.slot(prevSlot, (s, c) -> createPrevPageItem(currentPage, totalPages), - (click, viewCtx) -> viewCtx.session(Object.class).updateUnchecked(s -> { - @SuppressWarnings("unchecked") - S typedState = (S) s; - return typedState.withPage(currentPage - 1); - })); + layout.slot(prevSlot, (s, c) -> createPrevPageItem(currentPage, totalPages), (click, viewCtx) -> viewCtx.session(Object.class).updateUnchecked(s -> { + @SuppressWarnings("unchecked") S typedState = (S) s; + return typedState.withPage(currentPage - 1); + })); } else { layout.slot(prevSlot, FILLER); } @@ -101,20 +93,17 @@ protected void layoutNavigation(ViewLayout layout, S state, ViewContext ctx, if (nextSlot >= 0) { if (currentPage < totalPages - 1) { - layout.slot(nextSlot, (s, c) -> createNextPageItem(currentPage, totalPages), - (click, viewCtx) -> viewCtx.session(Object.class).updateUnchecked(s -> { - @SuppressWarnings("unchecked") - S typedState = (S) s; - return typedState.withPage(currentPage + 1); - })); + layout.slot(nextSlot, (s, c) -> createNextPageItem(currentPage, totalPages), (click, viewCtx) -> viewCtx.session(Object.class).updateUnchecked(s -> { + @SuppressWarnings("unchecked") S typedState = (S) s; + return typedState.withPage(currentPage + 1); + })); } else { layout.slot(nextSlot, FILLER); } } if (searchSlot >= 0) { - layout.slot(searchSlot, (s, c) -> createSearchItem(state.query()), - this::onSearchClick); + layout.slot(searchSlot, (s, c) -> createSearchItem(state.query()), this::onSearchClick); } } @@ -128,30 +117,16 @@ protected void layoutCustom(ViewLayout layout, S state, ViewContext ctx) { } protected ItemStack.Builder createPrevPageItem(int currentPage, int totalPages) { - return ItemStack.builder(Material.ARROW) - .set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")) - .set(DataComponents.LORE, List.of( - Component.text("§7Page " + currentPage + " of " + totalPages) - )); + return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")).set(DataComponents.LORE, List.of(Component.text("§7Page " + currentPage + " of " + totalPages))); } protected ItemStack.Builder createNextPageItem(int currentPage, int totalPages) { - return ItemStack.builder(Material.ARROW) - .set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")) - .set(DataComponents.LORE, List.of( - Component.text("§7Page " + (currentPage + 2) + " of " + totalPages) - )); + return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")).set(DataComponents.LORE, List.of(Component.text("§7Page " + (currentPage + 2) + " of " + totalPages))); } protected ItemStack.Builder createSearchItem(String currentQuery) { String queryDisplay = currentQuery.isEmpty() ? "None" : currentQuery; - return ItemStack.builder(Material.BIRCH_SIGN) - .set(DataComponents.CUSTOM_NAME, Component.text("§aSearch")) - .set(DataComponents.LORE, List.of( - Component.text("§7Query: §e" + queryDisplay), - Component.text(""), - Component.text("§eClick to search!") - )); + return ItemStack.builder(Material.BIRCH_SIGN).set(DataComponents.CUSTOM_NAME, Component.text("§aSearch")).set(DataComponents.LORE, List.of(Component.text("§7Query: §e" + queryDisplay), Component.text(""), Component.text("§eClick to search!"))); } protected void onSearchClick(ClickContext click, ViewContext ctx) { @@ -170,5 +145,3 @@ public static int[] createGrid(int startSlot, int endSlot) { } } - - diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java index 464bad373..a398b21e6 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java @@ -10,8 +10,13 @@ public final class Pagination { public record Page(List items, int current, int total) { - public boolean hasNext() { return current < total - 1; } - public boolean hasPrev() { return current > 0; } + public boolean hasNext() { + return current < total - 1; + } + + public boolean hasPrev() { + return current > 0; + } } public static Page paginate(List all, int page, int perPage) { @@ -23,11 +28,11 @@ public static Page paginate(List all, int page, int perPage) { } public static void items( - ViewLayout layout, - List slots, - List items, - BiFunction renderer, - ClickHandler onClick + ViewLayout layout, + List slots, + List items, + BiFunction renderer, + ClickHandler onClick ) { for (int i = 0; i < slots.size(); i++) { int slot = slots.get(i); @@ -35,7 +40,7 @@ public static void items( T item = items.get(i); int index = i; layout.slot(slot, (_, _) -> renderer.apply(item, index), - (click, ctx) -> onClick.handle(click, ctx, item, index)); + (click, ctx) -> onClick.handle(click, ctx, item, index)); } else { layout.slot(slot, (_, _) -> ItemStack.AIR.builder()); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java index 53bf6e757..36448aca9 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SharedContext.java @@ -36,6 +36,11 @@ public static SharedContext create(String id, S initialState) { return (SharedContext) CONTEXTS.computeIfAbsent(id, k -> new SharedContext<>(id, initialState)); } + @SuppressWarnings("unchecked") + public static SharedContext getOrCreate(String id, S initialState) { + return (SharedContext) CONTEXTS.computeIfAbsent(id, k -> new SharedContext<>(id, initialState)); + } + @SuppressWarnings("unchecked") public static Optional> get(String id) { return Optional.ofNullable((SharedContext) CONTEXTS.get(id)); @@ -154,5 +159,6 @@ public void broadcastMessage(String message) { viewers().forEach(p -> p.sendMessage(message)); } - public record SlotChange(int slot, ItemStack oldItem, ItemStack newItem) {} + public record SlotChange(int slot, ItemStack oldItem, ItemStack newItem) { + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotChangeHandler.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotChangeHandler.java index 2e5139712..88fe0de4e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotChangeHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/SlotChangeHandler.java @@ -4,5 +4,5 @@ @FunctionalInterface public interface SlotChangeHandler { - void onChange(int slot, ItemStack oldItem, ItemStack newItem, S state); + void onChange(int slot, ItemStack oldItem, ItemStack newItem, S state); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java index 110f12841..c40a215dd 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulView.java @@ -1,5 +1,5 @@ package net.swofty.type.generic.gui.v2; public interface StatefulView extends View { - S initialState(); + S initialState(); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java index 289ed1d05..2dbad3479 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/View.java @@ -5,24 +5,24 @@ public interface View { - ViewConfiguration configuration(); + ViewConfiguration configuration(); - void layout(ViewLayout layout, S state, ViewContext ctx); + void layout(ViewLayout layout, S state, ViewContext ctx); - default void onOpen(S state, ViewContext ctx) { - } + default void onOpen(S state, ViewContext ctx) { + } - default void onClose(S state, ViewContext ctx, ViewSession.CloseReason reason) { - } + default void onClose(S state, ViewContext ctx, ViewSession.CloseReason reason) { + } - default boolean onClick(ClickContext click, ViewContext ctx) { - return false; - } + default boolean onClick(ClickContext click, ViewContext ctx) { + return false; + } - default void onRefresh(S state, ViewContext ctx) { - } + default void onRefresh(S state, ViewContext ctx) { + } - default boolean onBottomClick(ClickContext click, ViewContext ctx) { - return false; - } + default boolean onBottomClick(ClickContext click, ViewContext ctx) { + return false; + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java index d49d7aac5..f5971dd69 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewComponent.java @@ -10,65 +10,65 @@ import java.util.function.BiFunction; public record ViewComponent( - UUID id, - int slot, - BiFunction render, - BiConsumer, ViewContext> onClick, - SlotBehavior behavior, - SlotChangeHandler changeHandler, - Duration updateInterval + UUID id, + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick, + SlotBehavior behavior, + SlotChangeHandler changeHandler, + Duration updateInterval ) { - public ViewComponent(int slot, BiFunction render, - BiConsumer, ViewContext> onClick) { - this(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, null); - } + public ViewComponent(int slot, BiFunction render, + BiConsumer, ViewContext> onClick) { + this(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, null); + } - public static ViewComponent staticItem(int slot, ItemStack.Builder item) { - return new ViewComponent<>(UUID.randomUUID(), slot, (_, _) -> item, (_, _) -> { - }, SlotBehavior.UI, null, null); - } + public static ViewComponent staticItem(int slot, ItemStack.Builder item) { + return new ViewComponent<>(UUID.randomUUID(), slot, (_, _) -> item, (_, _) -> { + }, SlotBehavior.UI, null, null); + } - public static ViewComponent autoUpdating( - int slot, - BiFunction render, - Duration updateInterval - ) { - return new ViewComponent<>(UUID.randomUUID(), slot, render, (_, _) -> { - }, SlotBehavior.UI, null, updateInterval); - } + public static ViewComponent autoUpdating( + int slot, + BiFunction render, + Duration updateInterval + ) { + return new ViewComponent<>(UUID.randomUUID(), slot, render, (_, _) -> { + }, SlotBehavior.UI, null, updateInterval); + } - public static ViewComponent autoUpdating( - int slot, - BiFunction render, - BiConsumer, ViewContext> onClick, - Duration updateInterval - ) { - return new ViewComponent<>(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, updateInterval); - } + public static ViewComponent autoUpdating( + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick, + Duration updateInterval + ) { + return new ViewComponent<>(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, updateInterval); + } - public static ViewComponent clickable( - int slot, - BiFunction render, - BiConsumer, ViewContext> onClick - ) { - return new ViewComponent<>(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, null); - } + public static ViewComponent clickable( + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick + ) { + return new ViewComponent<>(UUID.randomUUID(), slot, render, onClick, SlotBehavior.UI, null, null); + } - public static ViewComponent editable( - int slot, - BiFunction initialRender, - SlotChangeHandler changeHandler - ) { - return new ViewComponent<>(UUID.randomUUID(), slot, initialRender, (_, _) -> { - }, SlotBehavior.EDITABLE, changeHandler, null); - } + public static ViewComponent editable( + int slot, + BiFunction initialRender, + SlotChangeHandler changeHandler + ) { + return new ViewComponent<>(UUID.randomUUID(), slot, initialRender, (_, _) -> { + }, SlotBehavior.EDITABLE, changeHandler, null); + } - public static ViewComponent editable(int slot, ItemStack.Builder initialItem, SlotChangeHandler changeHandler) { - return new ViewComponent<>(UUID.randomUUID(), slot, (_, _) -> initialItem, (_, _) -> { - }, SlotBehavior.EDITABLE, changeHandler, null); - } + public static ViewComponent editable(int slot, ItemStack.Builder initialItem, SlotChangeHandler changeHandler) { + return new ViewComponent<>(UUID.randomUUID(), slot, (_, _) -> initialItem, (_, _) -> { + }, SlotBehavior.EDITABLE, changeHandler, null); + } - public static ViewComponent editable(int slot, SlotChangeHandler changeHandler) { - return editable(slot, ItemStack.AIR.builder(), changeHandler); - } + public static ViewComponent editable(int slot, SlotChangeHandler changeHandler) { + return editable(slot, ItemStack.AIR.builder(), changeHandler); + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewConfiguration.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewConfiguration.java index 47cfc83f9..78937ec4e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewConfiguration.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewConfiguration.java @@ -10,44 +10,44 @@ @Getter public class ViewConfiguration { - private final BiFunction titleFunction; - private final InventoryType inventoryType; - - public ViewConfiguration(Component title, InventoryType type) { - this.titleFunction = (v, c) -> title; - this.inventoryType = type; - } - - public ViewConfiguration(String title, InventoryType type) { - this.titleFunction = (v, c) -> Component.text(title); - this.inventoryType = type; - } - - public ViewConfiguration(Title title, InventoryType type) { - this.titleFunction = title::getTitle; - this.inventoryType = type; - } - - public ViewConfiguration(StringTitle title, InventoryType type) { - this.titleFunction = (v, c) -> Component.text(title.getTitle(v, c)); - this.inventoryType = type; - } - - public static ViewConfiguration withTitle(Title title, InventoryType type) { - return new ViewConfiguration<>(title, type); - } - - public static ViewConfiguration withString(StringTitle title, InventoryType type) { - return new ViewConfiguration<>(title, type); - } - - @FunctionalInterface - public interface Title { - Component getTitle(S state, ViewContext ctx); - } - - @FunctionalInterface - public interface StringTitle { - String getTitle(S state, ViewContext ctx); - } + private final BiFunction titleFunction; + private final InventoryType inventoryType; + + public ViewConfiguration(Component title, InventoryType type) { + this.titleFunction = (v, c) -> title; + this.inventoryType = type; + } + + public ViewConfiguration(String title, InventoryType type) { + this.titleFunction = (v, c) -> Component.text(title); + this.inventoryType = type; + } + + public ViewConfiguration(Title title, InventoryType type) { + this.titleFunction = title::getTitle; + this.inventoryType = type; + } + + public ViewConfiguration(StringTitle title, InventoryType type) { + this.titleFunction = (v, c) -> Component.text(title.getTitle(v, c)); + this.inventoryType = type; + } + + public static ViewConfiguration withTitle(Title title, InventoryType type) { + return new ViewConfiguration<>(title, type); + } + + public static ViewConfiguration withString(StringTitle title, InventoryType type) { + return new ViewConfiguration<>(title, type); + } + + @FunctionalInterface + public interface Title { + Component getTitle(S state, ViewContext ctx); + } + + @FunctionalInterface + public interface StringTitle { + String getTitle(S state, ViewContext ctx); + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java index bd7ed50e2..19e638102 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java @@ -16,127 +16,127 @@ public final class ViewLayout { - @Getter - @Accessors(fluent = true) - private final Map> components = new HashMap<>(); - - @Getter - @Accessors(fluent = true) - private final InventoryType inventoryType; - - @Getter - @Setter - @Accessors(fluent = true) - private boolean allowHotkey = false; - - public ViewLayout(InventoryType inventoryType) { - this.inventoryType = inventoryType; - } - - public void slot( - int slot, - BiFunction render, - BiConsumer, ViewContext> onClick - ) { - components.put(slot, new ViewComponent<>(slot, render, onClick)); - } - - public void slot(int slot, BiFunction render) { - slot(slot, render, (_, _) -> { - }); - } - - public void slot(int slot, ItemStack.Builder builder, BiConsumer, ViewContext> onClick) { - components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, onClick)); - } - - public void slot(int slot, ItemStack.Builder builder, Function stateUpdater) { - components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, - (_, ctx) -> ctx.session(Object.class).updateUnchecked(stateUpdater))); - } - - public void slot(int slot, ItemStack.Builder builder) { - components.put(slot, ViewComponent.staticItem(slot, builder)); - } - - public void editable(int slot, BiFunction initialRender, - SlotChangeHandler onChange) { - components.put(slot, ViewComponent.editable(slot, initialRender, onChange)); - } - - public void editable(int slot, ItemStack.Builder initialItem, SlotChangeHandler onChange) { - components.put(slot, ViewComponent.editable(slot, initialItem, onChange)); - } - - public void autoUpdating(int slot, - BiFunction render, - java.time.Duration updateInterval) { - components.put(slot, ViewComponent.autoUpdating(slot, render, updateInterval)); - } - - public void autoUpdating(int slot, - BiFunction render, - BiConsumer, ViewContext> onClick, - java.time.Duration updateInterval) { - components.put(slot, ViewComponent.autoUpdating(slot, render, onClick, updateInterval)); - } - - public void editable(int slot, SlotChangeHandler onChange) { - components.put(slot, ViewComponent.editable(slot, onChange)); - } - - public void editable(int slot) { - components.put(slot, ViewComponent.editable(slot, (s, o, n, st) -> { - })); - } - - public void editableSlots(Collection slots, SlotChangeHandler onChange) { - slots.forEach(slot -> editable(slot, onChange)); - } - - public void editableSlots(Collection slots) { - slots.forEach(this::editable); - } - - public void editableGrid(int startSlot, int endSlot, SlotChangeHandler onChange) { - editableSlots(Layouts.rectangle(startSlot, endSlot), onChange); - } - - public void filler(Collection slots, ItemStack.Builder builder) { - slots.forEach(s -> - components.put(s, ViewComponent.staticItem(s, builder)) - ); - } - - public void filler(Collection slots, BiFunction itemSupplier) { - slots.forEach(s -> - components.put(s, new ViewComponent<>(s, itemSupplier, (_, _) -> { - })) - ); - } - - public void filler(ItemStack.Builder builder) { - IntStream.range(0, inventoryType.getSize()).forEach(s -> - components.put(s, ViewComponent.staticItem(s, builder)) - ); - } - - public SlotBehavior getBehavior(int slot) { - ViewComponent component = components.get(slot); - return component != null ? component.behavior() : SlotBehavior.NO_RENDER; - } - - public boolean isEditable(int slot) { - return getBehavior(slot) == SlotBehavior.EDITABLE; - } - - public Set editableSlots() { - Set editable = new HashSet<>(); - components.forEach((slot, component) -> { - if (component.behavior() == SlotBehavior.EDITABLE) { - editable.add(slot); - } - }); - return editable; - } + @Getter + @Accessors(fluent = true) + private final Map> components = new HashMap<>(); + + @Getter + @Accessors(fluent = true) + private final InventoryType inventoryType; + + @Getter + @Setter + @Accessors(fluent = true) + private boolean allowHotkey = false; + + public ViewLayout(InventoryType inventoryType) { + this.inventoryType = inventoryType; + } + + public void slot( + int slot, + BiFunction render, + BiConsumer, ViewContext> onClick + ) { + components.put(slot, new ViewComponent<>(slot, render, onClick)); + } + + public void slot(int slot, BiFunction render) { + slot(slot, render, (_, _) -> { + }); + } + + public void slot(int slot, ItemStack.Builder builder, BiConsumer, ViewContext> onClick) { + components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, onClick)); + } + + public void slot(int slot, ItemStack.Builder builder, Function stateUpdater) { + components.put(slot, new ViewComponent<>(slot, (_, _) -> builder, + (_, ctx) -> ctx.session(Object.class).updateUnchecked(stateUpdater))); + } + + public void slot(int slot, ItemStack.Builder builder) { + components.put(slot, ViewComponent.staticItem(slot, builder)); + } + + public void editable(int slot, BiFunction initialRender, + SlotChangeHandler onChange) { + components.put(slot, ViewComponent.editable(slot, initialRender, onChange)); + } + + public void editable(int slot, ItemStack.Builder initialItem, SlotChangeHandler onChange) { + components.put(slot, ViewComponent.editable(slot, initialItem, onChange)); + } + + public void autoUpdating(int slot, + BiFunction render, + java.time.Duration updateInterval) { + components.put(slot, ViewComponent.autoUpdating(slot, render, updateInterval)); + } + + public void autoUpdating(int slot, + BiFunction render, + BiConsumer, ViewContext> onClick, + java.time.Duration updateInterval) { + components.put(slot, ViewComponent.autoUpdating(slot, render, onClick, updateInterval)); + } + + public void editable(int slot, SlotChangeHandler onChange) { + components.put(slot, ViewComponent.editable(slot, onChange)); + } + + public void editable(int slot) { + components.put(slot, ViewComponent.editable(slot, (s, o, n, st) -> { + })); + } + + public void editableSlots(Collection slots, SlotChangeHandler onChange) { + slots.forEach(slot -> editable(slot, onChange)); + } + + public void editableSlots(Collection slots) { + slots.forEach(this::editable); + } + + public void editableGrid(int startSlot, int endSlot, SlotChangeHandler onChange) { + editableSlots(Layouts.rectangle(startSlot, endSlot), onChange); + } + + public void filler(Collection slots, ItemStack.Builder builder) { + slots.forEach(s -> + components.put(s, ViewComponent.staticItem(s, builder)) + ); + } + + public void filler(Collection slots, BiFunction itemSupplier) { + slots.forEach(s -> + components.put(s, new ViewComponent<>(s, itemSupplier, (_, _) -> { + })) + ); + } + + public void filler(ItemStack.Builder builder) { + IntStream.range(0, inventoryType.getSize()).forEach(s -> + components.put(s, ViewComponent.staticItem(s, builder)) + ); + } + + public SlotBehavior getBehavior(int slot) { + ViewComponent component = components.get(slot); + return component != null ? component.behavior() : SlotBehavior.NO_RENDER; + } + + public boolean isEditable(int slot) { + return getBehavior(slot) == SlotBehavior.EDITABLE; + } + + public Set editableSlots() { + Set editable = new HashSet<>(); + components.forEach((slot, component) -> { + if (component.behavior() == SlotBehavior.EDITABLE) { + editable.add(slot); + } + }); + return editable; + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewNavigator.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewNavigator.java index 0036006e8..905167e27 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewNavigator.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewNavigator.java @@ -1,24 +1,25 @@ package net.swofty.type.generic.gui.v2; import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; import net.swofty.type.generic.user.HypixelPlayer; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +@ToString +@RequiredArgsConstructor public final class ViewNavigator { private static final Map NAVIGATORS = new ConcurrentHashMap<>(); private final HypixelPlayer player; private final Deque> stack = new ArrayDeque<>(); + @Getter private ViewSession currentSession; - private ViewNavigator(HypixelPlayer player) { - this.player = player; - } - public static ViewNavigator get(HypixelPlayer player) { return NAVIGATORS.computeIfAbsent(player, ViewNavigator::new); } @@ -40,42 +41,71 @@ public ViewSession push(View view, S state) { currentSession.close(ViewSession.CloseReason.REPLACED); } - ViewSession session = ViewSession.open(view, player, state); + var session = ViewSession.open(view, player, state); this.currentSession = session; + registerCloseHandler(session); + return session; + } - session.onClose(reason -> { - if (reason == ViewSession.CloseReason.PLAYER_EXITED) { - clear(); - } - }); + public ViewSession push(View view) { + S state = resolveInitialState(view); + return push(view, state); + } + public ViewSession pushShared(View view, String contextId, S initialState) { + if (currentSession != null && !currentSession.isClosed()) { + pushCurrentToStack(); + currentSession.close(ViewSession.CloseReason.REPLACED); + } + + SharedContext ctx = SharedContext.getOrCreate(contextId, initialState); + var session = ViewSession.openShared(view, player, ctx); + this.currentSession = session; + registerCloseHandler(session); return session; } - @SuppressWarnings({"unchecked", "rawtypes"}) - private void pushCurrentToStack() { - if (currentSession == null) return; - ViewSession session = currentSession; - stack.push(new NavigationEntry(session.view(), session.state())); + public ViewSession joinShared(View view, String contextId) { + return SharedContext.get(contextId).map(ctx -> { + if (currentSession != null && !currentSession.isClosed()) { + pushCurrentToStack(); + currentSession.close(ViewSession.CloseReason.REPLACED); + } + var session = ViewSession.openShared(view, player, ctx); + this.currentSession = session; + registerCloseHandler(session); + return session; + }).orElseThrow(() -> new IllegalArgumentException("Shared context not found: " + contextId)); } - public ViewSession replace(View view, S state) { + public ViewSession pushShared(View view, SharedContext sharedContext) { if (currentSession != null && !currentSession.isClosed()) { + pushCurrentToStack(); currentSession.close(ViewSession.CloseReason.REPLACED); } - ViewSession session = ViewSession.open(view, player, state); + var session = ViewSession.openShared(view, player, sharedContext); this.currentSession = session; + registerCloseHandler(session); + return session; + } - session.onClose(reason -> { - if (reason == ViewSession.CloseReason.PLAYER_EXITED) { - clear(); - } - }); + public ViewSession replace(View view, S state) { + if (currentSession != null && !currentSession.isClosed()) { + currentSession.close(ViewSession.CloseReason.REPLACED); + } + var session = ViewSession.open(view, player, state); + this.currentSession = session; + registerCloseHandler(session); return session; } + public ViewSession replace(View view) { + S state = resolveInitialState(view); + return replace(view, state); + } + public boolean pop() { if (stack.isEmpty()) { if (currentSession != null && !currentSession.isClosed()) { @@ -90,22 +120,12 @@ public boolean pop() { } NavigationEntry entry = stack.pop(); - ViewSession session = openEntry(entry); + var session = openEntry(entry); this.currentSession = session; - - session.onClose(reason -> { - if (reason == ViewSession.CloseReason.PLAYER_EXITED) { - clear(); - } - }); - + registerCloseHandler(session); return true; } - private ViewSession openEntry(NavigationEntry entry) { - return ViewSession.open(entry.view(), player, entry.state()); - } - public void popTo(int levels) { for (int i = 0; i < levels - 1 && !stack.isEmpty(); i++) { stack.pop(); @@ -136,14 +156,41 @@ public int depth() { return stack.size(); } + @SuppressWarnings("unchecked") public Optional> peekPrevious() { return Optional.ofNullable((NavigationEntry) stack.peek()); } - record NavigationEntry(View view, S state) {} + public HypixelPlayer player() { + return player; + } - private static View getView(ViewSession session) { - return session.view(); + @SuppressWarnings({"unchecked", "rawtypes"}) + private void pushCurrentToStack() { + if (currentSession == null) return; + ViewSession session = currentSession; + stack.push(new NavigationEntry(session.view(), session.state())); + } + + private ViewSession openEntry(NavigationEntry entry) { + return ViewSession.open(entry.view(), player, entry.state()); + } + + private void registerCloseHandler(ViewSession session) { + session.onClose(reason -> { + if (reason == ViewSession.CloseReason.PLAYER_EXITED) { + clear(); + } + }); } -} + private S resolveInitialState(View view) { + if (view instanceof StatefulView stateful) { + return stateful.initialState(); + } + return null; + } + + public record NavigationEntry(View view, S state) { + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 1c68f142b..445ec961d 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -24,308 +24,305 @@ import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.UnaryOperator; public final class ViewSession { - @Getter - @Accessors(fluent = true) - private final View view; - @Getter - @Accessors(fluent = true) - private final HypixelPlayer player; - @Getter - @Accessors(fluent = true) - private final Inventory inventory; - private final ViewContext context; - private final EventNode eventNode; - - @Getter - @Accessors(fluent = true) - private S state; - private ViewLayout cachedLayout; - private Consumer onCloseHandler; - @Getter - private boolean closed; - private boolean suppressCloseEvent; - - @Getter - @Accessors(fluent = true) - private final SharedContext sharedContext; - private final Map trackedSlotItems = new HashMap<>(); - private final Set recentlyModifiedSlots = new HashSet<>(); - private final Map autoUpdateTasks = new HashMap<>(); - private final Map> componentSlots = new HashMap<>(); - - private ViewSession(View view, HypixelPlayer player, S initialState, SharedContext sharedContext) { - this.view = view; - this.player = player; - this.state = sharedContext != null ? sharedContext.state() : initialState; - this.sharedContext = sharedContext; - this.inventory = new Inventory(view.configuration().getInventoryType(), ""); - this.context = new ViewContext(player, inventory, this); - this.eventNode = EventNode.type("gui-" + System.identityHashCode(this), EventFilter.INVENTORY); - - wireEvents(); - - if (sharedContext != null) { - sharedContext.registerSession(this); - } - } - - public static ViewSession open(View view, HypixelPlayer player, S initialState) { - ViewSession session = new ViewSession<>(view, player, initialState, null); - session.render(); - player.openInventory(session.inventory); - return session; - } - - public static ViewSession openShared(View view, HypixelPlayer player, SharedContext sharedContext) { - ViewSession session = new ViewSession<>(view, player, sharedContext.state(), sharedContext); - session.render(); - player.openInventory(session.inventory); - return session; - } - - public static ViewSession openShared(View view, HypixelPlayer player, String contextId, S initialState) { - SharedContext ctx = SharedContext.create(contextId, initialState); - return openShared(view, player, ctx); - } - - public static ViewSession joinShared(View view, HypixelPlayer player, String contextId) { - return SharedContext.get(contextId) - .map(ctx -> openShared(view, player, ctx)) - .orElseThrow(() -> new IllegalArgumentException("Shared context not found: " + contextId)); - } - - private void wireEvents() { - eventNode.addListener(InventoryPreClickEvent.class, this::onPreClickEvent); - eventNode.addListener(InventoryClickEvent.class, this::onPostClickEvent); - eventNode.addListener(InventoryCloseEvent.class, this::onCloseEvent); - eventNode.addListener(InventoryOpenEvent.class, this::onOpenEvent); - MinecraftServer.getGlobalEventHandler().addChild(eventNode); - } - - private void onOpenEvent(InventoryOpenEvent event) { - if (event.getInventory() != inventory || closed) return; - view.onOpen(state, context); - } - - private void onPreClickEvent(InventoryPreClickEvent event) { - if (event.getInventory() instanceof PlayerInventory) { - // if the current open inventory is this inventory - if (player.getOpenInventory() == inventory) { - ClickContext click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); - if (!view.onBottomClick(click, context)) { - event.setCancelled(true); - } - } - return; - } - if (event.getInventory() != inventory || closed) return; - - int slot = event.getSlot(); - SlotBehavior behavior = cachedLayout != null ? cachedLayout.getBehavior(slot) : SlotBehavior.UI; - - if (behavior == SlotBehavior.EDITABLE) { - trackedSlotItems.put(slot, inventory.getItemStack(slot)); - return; - } - - event.setCancelled(true); - ViewComponent component = cachedLayout != null ? cachedLayout.components().get(slot) : null; - if (component == null) { - ClickContext click = new ClickContext<>(slot, event.getClick(), player, state); - view.onClick(click, context); - return; - } - - ClickContext click = new ClickContext<>(slot, event.getClick(), player, state); - component.onClick().accept(click, context); - } - - private void onPostClickEvent(InventoryClickEvent event) { - if (event.getInventory() != inventory || closed) return; - - int slot = event.getSlot(); - if (cachedLayout == null || !cachedLayout.isEditable(slot)) return; - - MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { - if (closed) return; - - ItemStack oldItem = trackedSlotItems.getOrDefault(slot, ItemStack.AIR); - ItemStack newItem = inventory.getItemStack(slot); - - if (!oldItem.equals(newItem)) { - handleSlotChange(slot, oldItem, newItem); - } - }); - } - - private void handleSlotChange(int slot, ItemStack oldItem, ItemStack newItem) { - trackedSlotItems.put(slot, newItem); - recentlyModifiedSlots.add(slot); - - ViewComponent component = cachedLayout.components().get(slot); - if (component != null && component.changeHandler() != null) { - component.changeHandler().onChange(slot, oldItem, newItem, state); - } - - if (sharedContext != null) { - sharedContext.setSlotItem(slot, newItem); - } else { - render(); - } - - recentlyModifiedSlots.remove(slot); - } - - private void onCloseEvent(InventoryCloseEvent event) { - if (event.getInventory() != inventory || suppressCloseEvent) { - suppressCloseEvent = false; - return; - } - close(CloseReason.PLAYER_EXITED); - } - - public void render() { - if (closed) return; - - ViewConfiguration config = view.configuration(); - cachedLayout = new ViewLayout<>(config.getInventoryType()); - view.layout(cachedLayout, state, context); - componentSlots.clear(); - - @SuppressWarnings("unchecked") - BiFunction titleFunction = (BiFunction) config.getTitleFunction(); - inventory.setTitle(titleFunction.apply(state, context)); - - cachedLayout.components().forEach((slot, component) -> { - if (component.behavior() == SlotBehavior.EDITABLE) { - if (sharedContext != null) { - ItemStack contextItem = sharedContext.getSlotItem(slot); - if (!inventory.getItemStack(slot).equals(contextItem)) { - inventory.setItemStack(slot, contextItem); - } - trackedSlotItems.put(slot, contextItem); - return; - } else if (!recentlyModifiedSlots.contains(slot)) { - ItemStack currentItem = inventory.getItemStack(slot); - trackedSlotItems.put(slot, currentItem); - } - return; - } - - renderSlot(slot, component); - if (component.updateInterval() != null) { - scheduleAutoUpdate(slot, component); - } - }); - - view.onRefresh(state, context); - } - - private void renderSlot(int slot, ViewComponent component) { - var item = component.render().apply(state, context).build(); - if (!inventory.getItemStack(slot).equals(item)) { - inventory.setItemStack(slot, item); - } - - if (component.id() != null) { - componentSlots.computeIfAbsent(component.id(), k -> new HashSet<>()).add(slot); - } - } - - private void scheduleAutoUpdate(int slot, ViewComponent component) { - if (autoUpdateTasks.containsKey(slot)) return; - - Task task = MinecraftServer.getSchedulerManager().submitTask(() -> { - if (closed) return TaskSchedule.stop(); - renderSlot(slot, component); - return TaskSchedule.duration(component.updateInterval()); - }); - autoUpdateTasks.put(slot, task); - } - - public void setState(S newState) { - this.state = newState; - - if (sharedContext != null) { - sharedContext.setState(newState); - } else { - render(); - } - } - - public void setStateQuiet(S newState) { - this.state = newState; - render(); - } - - void setStateFromShared(S newState) { - this.state = newState; - render(); - } - - void renderFromShared() { - render(); - } - - public void update(UnaryOperator transform) { - setState(transform.apply(state)); - } - - public void updateQuiet(UnaryOperator transform) { - setStateQuiet(transform.apply(state)); - } - - @SuppressWarnings("unchecked") - public void updateUnchecked(Function transform) { - setState(((Function) transform).apply(state)); - } - - public ViewSession onClose(Consumer handler) { - this.onCloseHandler = handler; - return this; - } - - public ViewSession refreshEvery(Duration interval) { - MinecraftServer.getSchedulerManager().submitTask(() -> { - if (closed) return TaskSchedule.stop(); - render(); - return TaskSchedule.millis(interval.toMillis()); - }); - return this; - } - - public void close(CloseReason reason) { - if (closed) return; - if (reason == CloseReason.REPLACED) { - suppressCloseEvent = true; - } - closed = true; - - autoUpdateTasks.values().forEach(Task::cancel); - autoUpdateTasks.clear(); - - MinecraftServer.getGlobalEventHandler().removeChild(eventNode); - if (sharedContext != null) { - sharedContext.unregisterSession(this); - } - - view.onClose(state, context, reason); - if (onCloseHandler != null) onCloseHandler.accept(reason); - if (reason != CloseReason.PLAYER_EXITED) player.closeInventory(); - } - - public boolean isShared() { - return sharedContext != null; - } - - public enum CloseReason { - PLAYER_EXITED, - SERVER_EXITED, - REPLACED - } + @Getter + @Accessors(fluent = true) + private final View view; + + @Getter + @Accessors(fluent = true) + private final HypixelPlayer player; + + @Getter + @Accessors(fluent = true) + private final Inventory inventory; + + @Getter + @Accessors(fluent = true) + private final SharedContext sharedContext; + + @Getter + @Accessors(fluent = true) + private final ViewContext context; + private final EventNode eventNode; + + @Getter + @Accessors(fluent = true) + private S state; + + private ViewLayout cachedLayout; + private Consumer onCloseHandler; + + @Getter + private boolean closed; + private boolean suppressCloseEvent; + + private final Map trackedSlotItems = new HashMap<>(); + private final Set recentlyModifiedSlots = new HashSet<>(); + private final Map autoUpdateTasks = new HashMap<>(); + private final Map> componentSlots = new HashMap<>(); + + private ViewSession(View view, HypixelPlayer player, S initialState, SharedContext sharedContext) { + this.view = view; + this.player = player; + this.state = sharedContext != null ? sharedContext.state() : initialState; + this.sharedContext = sharedContext; + this.inventory = new Inventory(view.configuration().getInventoryType(), ""); + this.context = new ViewContext(player, inventory, this); + this.eventNode = EventNode.type("gui-" + System.identityHashCode(this), EventFilter.INVENTORY); + + wireEvents(); + + if (sharedContext != null) { + sharedContext.registerSession(this); + } + } + + static ViewSession open(View view, HypixelPlayer player, S initialState) { + var session = new ViewSession<>(view, player, initialState, null); + session.render(); + player.openInventory(session.inventory); + return session; + } + + static ViewSession openShared(View view, HypixelPlayer player, SharedContext sharedContext) { + var session = new ViewSession<>(view, player, sharedContext.state(), sharedContext); + session.render(); + player.openInventory(session.inventory); + return session; + } + + private void wireEvents() { + eventNode.addListener(InventoryPreClickEvent.class, this::onPreClickEvent); + eventNode.addListener(InventoryClickEvent.class, this::onPostClickEvent); + eventNode.addListener(InventoryCloseEvent.class, this::onCloseEvent); + eventNode.addListener(InventoryOpenEvent.class, this::onOpenEvent); + MinecraftServer.getGlobalEventHandler().addChild(eventNode); + } + + private void onOpenEvent(InventoryOpenEvent event) { + if (event.getInventory() != inventory || closed) return; + view.onOpen(state, context); + } + + private void onPreClickEvent(InventoryPreClickEvent event) { + if (event.getInventory() instanceof PlayerInventory) { + if (player.getOpenInventory() == inventory) { + var click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); + if (!view.onBottomClick(click, context)) { + event.setCancelled(true); + } + } + return; + } + if (event.getInventory() != inventory || closed) return; + + int slot = event.getSlot(); + SlotBehavior behavior = cachedLayout != null ? cachedLayout.getBehavior(slot) : SlotBehavior.UI; + + if (behavior == SlotBehavior.EDITABLE) { + trackedSlotItems.put(slot, inventory.getItemStack(slot)); + return; + } + + event.setCancelled(true); + ViewComponent component = cachedLayout != null ? cachedLayout.components().get(slot) : null; + var click = new ClickContext<>(slot, event.getClick(), player, state); + + if (component == null) { + view.onClick(click, context); + } else { + component.onClick().accept(click, context); + } + } + + private void onPostClickEvent(InventoryClickEvent event) { + if (event.getInventory() != inventory || closed) return; + + int slot = event.getSlot(); + if (cachedLayout == null || !cachedLayout.isEditable(slot)) return; + + MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { + if (closed) return; + + ItemStack oldItem = trackedSlotItems.getOrDefault(slot, ItemStack.AIR); + ItemStack newItem = inventory.getItemStack(slot); + + if (!oldItem.equals(newItem)) { + handleSlotChange(slot, oldItem, newItem); + } + }); + } + + private void handleSlotChange(int slot, ItemStack oldItem, ItemStack newItem) { + trackedSlotItems.put(slot, newItem); + recentlyModifiedSlots.add(slot); + + ViewComponent component = cachedLayout.components().get(slot); + if (component != null && component.changeHandler() != null) { + component.changeHandler().onChange(slot, oldItem, newItem, state); + } + + if (sharedContext != null) { + sharedContext.setSlotItem(slot, newItem); + } else { + render(); + } + + recentlyModifiedSlots.remove(slot); + } + + private void onCloseEvent(InventoryCloseEvent event) { + if (event.getInventory() != inventory || suppressCloseEvent) { + suppressCloseEvent = false; + return; + } + close(CloseReason.PLAYER_EXITED); + } + + public void render() { + if (closed) return; + + ViewConfiguration config = view.configuration(); + cachedLayout = new ViewLayout<>(config.getInventoryType()); + view.layout(cachedLayout, state, context); + componentSlots.clear(); + + @SuppressWarnings("unchecked") BiFunction titleFunction = (BiFunction) config.getTitleFunction(); + inventory.setTitle(titleFunction.apply(state, context)); + + cachedLayout.components().forEach((slot, component) -> { + if (component.behavior() == SlotBehavior.EDITABLE) { + renderEditableSlot(slot); + return; + } + + renderSlot(slot, component); + if (component.updateInterval() != null) { + scheduleAutoUpdate(slot, component); + } + }); + + view.onRefresh(state, context); + } + + private void renderEditableSlot(int slot) { + if (sharedContext != null) { + ItemStack contextItem = sharedContext.getSlotItem(slot); + if (!inventory.getItemStack(slot).equals(contextItem)) { + inventory.setItemStack(slot, contextItem); + } + trackedSlotItems.put(slot, contextItem); + } else if (!recentlyModifiedSlots.contains(slot)) { + ItemStack currentItem = inventory.getItemStack(slot); + trackedSlotItems.put(slot, currentItem); + } + } + + private void renderSlot(int slot, ViewComponent component) { + var item = component.render().apply(state, context).build(); + if (!inventory.getItemStack(slot).equals(item)) { + inventory.setItemStack(slot, item); + } + + if (component.id() != null) { + componentSlots.computeIfAbsent(component.id(), _ -> new HashSet<>()).add(slot); + } + } + + private void scheduleAutoUpdate(int slot, ViewComponent component) { + if (autoUpdateTasks.containsKey(slot)) return; + + Task task = MinecraftServer.getSchedulerManager().submitTask(() -> { + if (closed) return TaskSchedule.stop(); + renderSlot(slot, component); + return TaskSchedule.duration(component.updateInterval()); + }); + autoUpdateTasks.put(slot, task); + } + + public void setState(S newState) { + this.state = newState; + + if (sharedContext != null) { + sharedContext.setState(newState); + } else { + render(); + } + } + + public void setStateQuiet(S newState) { + this.state = newState; + render(); + } + + public void update(UnaryOperator transform) { + setState(transform.apply(state)); + } + + public void updateQuiet(UnaryOperator transform) { + setStateQuiet(transform.apply(state)); + } + + @SuppressWarnings("unchecked") + public void updateUnchecked(java.util.function.Function transform) { + setState((S) transform.apply((T) state)); + } + + void setStateFromShared(S newState) { + this.state = newState; + render(); + } + + void renderFromShared() { + render(); + } + + public ViewSession onClose(Consumer handler) { + this.onCloseHandler = handler; + return this; + } + + public ViewSession refreshEvery(Duration interval) { + MinecraftServer.getSchedulerManager().submitTask(() -> { + if (closed) return TaskSchedule.stop(); + render(); + return TaskSchedule.millis(interval.toMillis()); + }); + return this; + } + + public void close(CloseReason reason) { + if (closed) return; + if (reason == CloseReason.REPLACED) { + suppressCloseEvent = true; + } + closed = true; + + autoUpdateTasks.values().forEach(Task::cancel); + autoUpdateTasks.clear(); + + MinecraftServer.getGlobalEventHandler().removeChild(eventNode); + if (sharedContext != null) { + sharedContext.unregisterSession(this); + } + + view.onClose(state, context, reason); + if (onCloseHandler != null) onCloseHandler.accept(reason); + if (reason != CloseReason.PLAYER_EXITED) player.closeInventory(); + } + + public boolean isShared() { + return sharedContext != null; + } + + + public enum CloseReason { + PLAYER_EXITED, + SERVER_EXITED, + REPLACED + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java index 6c773a94b..2d27b390c 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ClickContext.java @@ -4,9 +4,10 @@ import net.swofty.type.generic.user.HypixelPlayer; public record ClickContext( - int slot, - Click click, - HypixelPlayer player, - S state -) {} + int slot, + Click click, + HypixelPlayer player, + S state +) { +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java index 8a6908c1d..d880435de 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/context/ViewContext.java @@ -1,16 +1,15 @@ package net.swofty.type.generic.gui.v2.context; import net.minestom.server.inventory.Inventory; -import net.swofty.type.generic.gui.v2.View; -import net.swofty.type.generic.gui.v2.ViewNavigator; -import net.swofty.type.generic.gui.v2.ViewSession; +import net.swofty.type.generic.gui.v2.*; import net.swofty.type.generic.user.HypixelPlayer; public record ViewContext( - HypixelPlayer player, - Inventory inventory, - ViewSession session + HypixelPlayer player, + Inventory inventory, + ViewSession session ) { + @SuppressWarnings("unchecked") public ViewSession session(Class stateType) { return (ViewSession) session; @@ -25,7 +24,7 @@ public ViewSession push(View view, S state) { } public ViewSession push(View view) { - return navigator().push(view, null); + return navigator().push(view); } public boolean pop() { @@ -36,7 +35,29 @@ public ViewSession replace(View view, S state) { return navigator().replace(view, state); } - public boolean viewStack() { + public ViewSession replace(View view) { + return navigator().replace(view); + } + + public ViewSession pushShared(View view, String contextId, S initialState) { + return navigator().pushShared(view, contextId, initialState); + } + + public ViewSession joinShared(View view, String contextId) { + return navigator().joinShared(view, contextId); + } + + public boolean hasBackStack() { return navigator().hasStack(); } + + public int stackDepth() { + return navigator().depth(); + } + + public void backOrClose() { + if (!pop()) { + player.closeInventory(); + } + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java index 4b92c6e16..e4258e4c5 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestMixedView.java @@ -57,27 +57,27 @@ public void layout(ViewLayout layout, State state, ViewContext ctx) { layout.filler(Components.FILLER); layout.slot(4, ItemStackCreator.getStack( - "§5Crafting Station", - Material.CRAFTING_TABLE, - 1, - "§7Place items in the grid", - "§7to create new items!", - "", - "§7Input items: §e" + state.inputCount() + "§5Crafting Station", + Material.CRAFTING_TABLE, + 1, + "§7Place items in the grid", + "§7to create new items!", + "", + "§7Input items: §e" + state.inputCount() )); for (int slot : INPUT_SLOTS) { layout.editable(slot, (s, c) -> s.inputs().getOrDefault(slot, ItemStack.AIR).builder(), - (changedSlot, oldItem, newItem, s) -> - ctx.session(State.class).updateQuiet(current -> current.withInput(changedSlot, newItem)) + (changedSlot, oldItem, newItem, s) -> + ctx.session(State.class).updateQuiet(current -> current.withInput(changedSlot, newItem)) ); } layout.slot(22, (s, c) -> ItemStackCreator.getStack( - s.hasOutput() ? "§a→ Ready!" : "§7→", - Material.ARROW, - 1, - s.hasOutput() ? "§aClick output to craft!" : "§7Place an item in the center" + s.hasOutput() ? "§a→ Ready!" : "§7→", + Material.ARROW, + 1, + s.hasOutput() ? "§aClick output to craft!" : "§7Place an item in the center" )); layout.slot(OUTPUT_SLOT, (s, c) -> { @@ -98,10 +98,10 @@ public void layout(ViewLayout layout, State state, ViewContext ctx) { }); layout.slot(40, (s, c) -> ItemStackCreator.getStack( - "§cClear Grid", - Material.BARRIER, - 1, - "§7Clears all input slots" + "§cClear Grid", + Material.BARRIER, + 1, + "§7Clears all input slots" ), (click, context) -> { context.session(State.class).setState(state.clearInputs()); for (int slot : INPUT_SLOTS) { @@ -120,6 +120,6 @@ public boolean onBottomClick(ClickContext click, ViewContext ctx) { } public static void open(HypixelPlayer player) { - ViewSession.open(new TestMixedView(), player, new State(new HashMap<>())); + ViewNavigator.get(player).push(new TestMixedView(), new State(new HashMap<>())); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java index 3990853d6..afee8ba8d 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedContainerView.java @@ -11,80 +11,81 @@ public final class TestSharedContainerView implements View { - public record State(String teamName) { - } - - @Override - public ViewConfiguration configuration() { - - return ViewConfiguration.withString((state, ctx) -> { - SharedContext shared = ctx.session(State.class).sharedContext(); - int viewers = shared != null ? shared.sessionCount() : 1; - return "§6" + state.teamName() + " §7(§e" + viewers + " viewing§7)"; - }, InventoryType.CHEST_6_ROW); - } - - @Override - public void layout(ViewLayout layout, State state, ViewContext ctx) { - layout.filler(Components.FILLER); - - layout.slot(4, (s, c) -> { - SharedContext shared = ctx.session(State.class).sharedContext(); - int itemCount = shared != null - ? (int) shared.getAllSlotItems().values().stream().filter(i -> !i.isAir()).count() - : 0; - - return ItemStackCreator.getStack( - "§6" + s.teamName(), - Material.CHEST, - 1, - "§7Shared team storage", - "", - "§7Items stored: §e" + itemCount, - "§7Players viewing: §e" + (shared != null ? shared.sessionCount() : 1) - ); - }); - - Components.sharedContainerGrid(layout, 10, 43); - - layout.slot(49, (s, c) -> ItemStackCreator.getStack( - "§cClear All", - Material.TNT, - 1, - "§7Clears all items from storage", - "", - "§eShift Left Click to confirm!" - ), (click, context) -> { - if (click.click() instanceof Click.LeftShift) { - SharedContext shared = context.session(State.class).sharedContext(); - if (shared != null) { - shared.clearSlotItems(); - shared.broadcastMessage("§c" + click.player().getUsername() + " cleared the team chest!"); - } - } - }); - - Components.close(layout, 53); - layout.allowHotkey(true); - } - - public static ViewSession open(HypixelPlayer player, String teamId, String teamName) { - String contextId = "team-chest-" + teamId; - - if (SharedContext.exists(contextId)) { - return ViewSession.joinShared(new TestSharedContainerView(), player, contextId); - } - - SharedContext ctx = SharedContext.create(contextId, new State(teamName)); - ctx.onSlotChange(change -> - System.out.println("Slot " + change.slot() + " changed: " + change.oldItem().material() + " -> " + change.newItem().material()) - ); - - return ViewSession.openShared(new TestSharedContainerView(), player, ctx); - } - - @Override - public boolean onBottomClick(ClickContext click, ViewContext ctx) { - return true; - } + public record State(String teamName) { + } + + @Override + public ViewConfiguration configuration() { + + return ViewConfiguration.withString((state, ctx) -> { + SharedContext shared = ctx.session(State.class).sharedContext(); + int viewers = shared != null ? shared.sessionCount() : 1; + return "§6" + state.teamName() + " §7(§e" + viewers + " viewing§7)"; + }, InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + layout.filler(Components.FILLER); + + layout.slot(4, (s, c) -> { + SharedContext shared = ctx.session(State.class).sharedContext(); + int itemCount = shared != null + ? (int) shared.getAllSlotItems().values().stream().filter(i -> !i.isAir()).count() + : 0; + + return ItemStackCreator.getStack( + "§6" + s.teamName(), + Material.CHEST, + 1, + "§7Shared team storage", + "", + "§7Items stored: §e" + itemCount, + "§7Players viewing: §e" + (shared != null ? shared.sessionCount() : 1) + ); + }); + + Components.sharedContainerGrid(layout, 10, 43); + + layout.slot(49, (s, c) -> ItemStackCreator.getStack( + "§cClear All", + Material.TNT, + 1, + "§7Clears all items from storage", + "", + "§eShift Left Click to confirm!" + ), (click, context) -> { + if (click.click() instanceof Click.LeftShift) { + SharedContext shared = context.session(State.class).sharedContext(); + if (shared != null) { + shared.clearSlotItems(); + shared.broadcastMessage("§c" + click.player().getUsername() + " cleared the team chest!"); + } + } + }); + + Components.close(layout, 53); + layout.allowHotkey(true); + } + + public static ViewSession open(HypixelPlayer player, String teamId, String teamName) { + String contextId = "team-chest-" + teamId; + ViewNavigator navigator = ViewNavigator.get(player); + + if (SharedContext.exists(contextId)) { + return navigator.joinShared(new TestSharedContainerView(), contextId); + } + + SharedContext ctx = SharedContext.create(contextId, new State(teamName)); + ctx.onSlotChange(change -> + System.out.println("Slot " + change.slot() + " changed: " + change.oldItem().material() + " -> " + change.newItem().material()) + ); + + return navigator.pushShared(new TestSharedContainerView(), ctx); + } + + @Override + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + return true; + } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java index 3371ac160..b7e7015a6 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestSharedStateView.java @@ -39,54 +39,54 @@ public void layout(ViewLayout layout, State state, ViewContext ctx) { layout.filler(Components.FILLER); layout.slot(11, (s, c) -> ItemStackCreator.getStack( - "§c-1", - Material.RED_WOOL, - 1, - "§7Click to decrement", - "", - "§7Current: §f" + s.counter() - ), (click, context) -> - context.session(State.class).update(s -> s.decrement(click.player().getUsername())) + "§c-1", + Material.RED_WOOL, + 1, + "§7Click to decrement", + "", + "§7Current: §f" + s.counter() + ), (click, context) -> + context.session(State.class).update(s -> s.decrement(click.player().getUsername())) ); layout.slot(13, (s, c) -> ItemStackCreator.getStack( - "§eCounter: " + s.counter(), - Material.PAPER, - Math.max(1, Math.min(64, Math.abs(s.counter()))), - "§7Last modified by: §f" + s.lastModifiedBy(), - "", - "§7This view is shared!", - "§7All players see the same counter." + "§eCounter: " + s.counter(), + Material.PAPER, + Math.max(1, Math.min(64, Math.abs(s.counter()))), + "§7Last modified by: §f" + s.lastModifiedBy(), + "", + "§7This view is shared!", + "§7All players see the same counter." )); layout.slot(15, (s, c) -> ItemStackCreator.getStack( - "§a+1", - Material.GREEN_WOOL, - 1, - "§7Click to increment", - "", - "§7Current: §f" + s.counter() - ), (click, context) -> - context.session(State.class).update(s -> s.increment(click.player().getUsername())) + "§a+1", + Material.GREEN_WOOL, + 1, + "§7Click to increment", + "", + "§7Current: §f" + s.counter() + ), (click, context) -> + context.session(State.class).update(s -> s.increment(click.player().getUsername())) ); layout.slot(22, (s, c) -> ItemStackCreator.getStack( - "§6Reset", - Material.SUNFLOWER, - 1, - "§7Reset counter to 0" - ), (click, context) -> - context.session(State.class).update(s -> s.reset(click.player().getUsername())) + "§6Reset", + Material.SUNFLOWER, + 1, + "§7Reset counter to 0" + ), (click, context) -> + context.session(State.class).update(s -> s.reset(click.player().getUsername())) ); Components.close(layout, 26); } public static void openNew(HypixelPlayer player, String contextId) { - ViewSession.openShared(new TestSharedStateView(), player, contextId, new State(0, player.getUsername())); + ViewNavigator.get(player).pushShared(new TestSharedStateView(), contextId, new State(0, player.getUsername())); } public static void join(HypixelPlayer player, String contextId) { - ViewSession.joinShared(new TestSharedStateView(), player, contextId); + ViewNavigator.get(player).joinShared(new TestSharedStateView(), contextId); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewRecipeCommand.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewRecipeCommand.java index 16f11d18c..b27a3e806 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewRecipeCommand.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ViewRecipeCommand.java @@ -24,7 +24,7 @@ public void registerUsage(MinestomCommand command) { if (!permissionCheck(sender)) return; final ItemType item = context.get(itemArgument); - ((SkyBlockPlayer) sender).openView(new GUIRecipe(item, null)); + ((SkyBlockPlayer) sender).openView(new GUIRecipe(item)); }, itemArgument); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/GUIContactManagementView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/GUIContactManagementView.java index 44eca50ed..7b9f06c20 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/GUIContactManagementView.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/GUIContactManagementView.java @@ -51,7 +51,7 @@ public void layout(ViewLayout layout, State state, ViewContext ctx) { if (!Components.back(layout, 48, ctx)) { layout.slot(48, (s, c) -> Components.BACK_BUTTON, (click, viewCtx) -> { - ViewSession.open(new AbiphoneView(), viewCtx.player(), new AbiphoneView.State(state.abiphone())); + viewCtx.push(new AbiphoneView(), new AbiphoneView.State(state.abiphone())); }); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java index 06f903321..73fb96a66 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java @@ -82,7 +82,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont if (skyBlockItem.hasComponent(MinionComponent.class)) { c.player().openView(new GUIMinionRecipes(skyBlockItem.getAttributeHandler().getMinionType(), new GUICollectionReward(item, reward))); } else { - c.player().openView(new GUIRecipe(skyBlockItem.getAttributeHandler().getPotentialType(), null)); + c.player().openView(new GUIRecipe(skyBlockItem.getAttributeHandler().getPotentialType())); } } catch (NullPointerException exception) { player.sendMessage("There is no recipe available for this item!"); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java index 4350cbc66..132f33a6f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java @@ -58,7 +58,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont layout.slot(slot, (s, c) -> ItemStackCreator.getStackHead(minion.getDisplayName(), minionTier.texture(), 1, minion.getLore()), - (click, c) -> c.player().openView(new GUIRecipe(minion, this, minionTier.tier() - 1))); + (click, c) -> c.player().openView(new GUIRecipe(minion, minionTier.tier() - 1))); } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/RightClickRecipeComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/RightClickRecipeComponent.java index 18e0266c3..9ddf5c9af 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/RightClickRecipeComponent.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/RightClickRecipeComponent.java @@ -12,7 +12,7 @@ public class RightClickRecipeComponent extends SkyBlockItemComponent { public RightClickRecipeComponent(String recipeItem) { this.recipeItem = ItemType.valueOf(recipeItem); addInheritedComponent(new InteractableComponent( - (player, item) -> player.openView(new GUIRecipe(this.recipeItem, null)), + (player, item) -> player.openView(new GUIRecipe(this.recipeItem)), null, null )); From 68ba8d4a4ebbc13a72452585955291fa98ff145b Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 10 Jan 2026 20:32:03 +0200 Subject: [PATCH 14/35] feat: don't reset mouse --- .../main/java/net/swofty/type/generic/gui/v2/ViewSession.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 445ec961d..024d624e7 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -312,7 +312,7 @@ public void close(CloseReason reason) { view.onClose(state, context, reason); if (onCloseHandler != null) onCloseHandler.accept(reason); - if (reason != CloseReason.PLAYER_EXITED) player.closeInventory(); + if (reason == CloseReason.SERVER_EXITED) player.closeInventory(); } public boolean isShared() { From e46203be0dc2b813b3ab5858526e89eb61f84eb3 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 10 Jan 2026 20:48:29 +0200 Subject: [PATCH 15/35] feat: navigator previous page name --- .../type/generic/gui/v2/Components.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java index 15f3166cc..8095251bd 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java @@ -1,17 +1,15 @@ package net.swofty.type.generic.gui.v2; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import net.minestom.server.component.DataComponents; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.component.TooltipDisplay; import net.swofty.type.generic.gui.v2.context.ViewContext; -import org.tinylog.Logger; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; @@ -23,7 +21,6 @@ public final class Components { public static final ItemStack.Builder CLOSE_BUTTON = ItemStack.builder(Material.BARRIER) .set(DataComponents.CUSTOM_NAME, Component.text("§cClose")); - // TODO: show the name of the previous view public static final ItemStack.Builder BACK_BUTTON = ItemStack.builder(Material.ARROW) .set(DataComponents.CUSTOM_NAME, Component.text("§aGo Back")); @@ -38,13 +35,16 @@ public static void close(ViewLayout layout, int slot) { public static boolean back(ViewLayout layout, int slot, ViewContext context) { ViewNavigator navigator = ViewNavigator.get(context.player()); if (!navigator.hasStack()) { - Logger.info( - "Tried to add back button to view layout for player {} but there is no view to go back to! Navigator information: {}", - context.player().getUsername(), navigator - ); return false; } - layout.slot(slot, (s, c) -> BACK_BUTTON, (click, ctx) -> { + Optional> prev = context.navigator().peekPrevious(); + Component prevTitle = prev + .map(entry -> entry.view().configuration().getTitleFunction().apply(entry.view(), context)) + .orElse(Component.text("§r§7previous page")); + layout.slot(slot, (s, c) -> BACK_BUTTON.lore( + Component.text("§7To ").append(prevTitle) + .color(NamedTextColor.GRAY).decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE) + ), (_, ctx) -> { ViewNavigator.get(ctx.player()).pop(); }); return true; From 0b8b167d08de6502596f7836b98cd68c2cdf415a Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 10 Jan 2026 21:12:25 +0200 Subject: [PATCH 16/35] feat: port GUIClaimCake.java --- .../achievement/PlayerAchievementHandler.java | 1 + .../data/datapoints/DatapointToggles.java | 1 - .../net/swofty/type/hub/gui/GUIClaimCake.java | 82 -------------- .../net/swofty/type/hub/npcs/NPCBaker.java | 30 +++--- .../gui/inventories/ClaimRewardView.java | 101 ++++++++++-------- 5 files changed, 76 insertions(+), 139 deletions(-) delete mode 100644 type.hub/src/main/java/net/swofty/type/hub/gui/GUIClaimCake.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/achievement/PlayerAchievementHandler.java b/type.generic/src/main/java/net/swofty/type/generic/achievement/PlayerAchievementHandler.java index f0b1f1bb8..2d64055b4 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/achievement/PlayerAchievementHandler.java +++ b/type.generic/src/main/java/net/swofty/type/generic/achievement/PlayerAchievementHandler.java @@ -157,6 +157,7 @@ private void onAchievementUnlocked(AchievementDefinition def, AchievementData.Ac tierText = " " + toRoman(progress.getCurrentTier()); } + // TODO: make this actually clickable to open the achievements menu Component tierHover = Component.text(def.getName() + tierText, NamedTextColor.GREEN).appendNewline() .append(Component.text(def.getDescription(), NamedTextColor.GRAY)) .appendNewline().appendNewline() diff --git a/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java b/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java index 98c02479f..d82cb3cbd 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java +++ b/type.generic/src/main/java/net/swofty/type/generic/data/datapoints/DatapointToggles.java @@ -77,7 +77,6 @@ public enum ToggleType { HAS_SPOKEN_TO_TIA(false), HAS_SPOKEN_TO_LIFT_OPERATOR(false), HAS_SPOKEN_TO_LAZY_MINER(false), - HAS_SPOKEN_TO_BAKER(false), HAS_SPOKEN_TO_RUSTY(false), HAS_SPOKEN_TO_RUSTY_ABOUT_PICKAXE(false), HAS_SPOKEN_TO_RUSTY_ABOUT_ABIPHONE(false), diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIClaimCake.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIClaimCake.java deleted file mode 100644 index e45c4ec4e..000000000 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIClaimCake.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.swofty.type.hub.gui; - -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.commons.StringUtility; -import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.data.datapoints.DatapointInteger; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.calendar.CalendarEvent; -import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; -import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; -import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; - -import java.util.List; - - -public class GUIClaimCake extends HypixelInventoryGUI { - public GUIClaimCake() { - super("Claim Reward", InventoryType.CHEST_6_ROW); - } - - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(22) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - List events = SkyBlockCalendar.getCurrentEvents(); - if (!events.contains(CalendarEvent.NEW_YEAR)) { - p.closeInventory(); - return; - } - final SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockDataHandler dataHandler = player.getSkyblockDataHandler(); - if (dataHandler.get(SkyBlockDataHandler.Data.LATEST_NEW_YEAR_CAKE_YEAR, DatapointInteger.class).getValue() >= SkyBlockCalendar.getYear()) { - p.closeInventory(); - return; - } - dataHandler.get(SkyBlockDataHandler.Data.LATEST_NEW_YEAR_CAKE_YEAR, DatapointInteger.class).setValue(SkyBlockCalendar.getYear()); - - SkyBlockItem item = new SkyBlockItem(ItemType.NEW_YEAR_CAKE); - item.getAttributeHandler().setNewYearCakeYear(SkyBlockCalendar.getYear()); - player.addAndUpdateItem(item); - p.closeInventory(); - player.sendMessage("§aYou claimed §cNew Year Cake§a!"); - player.getAchievementHandler().completeAchievement("skyblock.happy_new_year"); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§cNew Year Cake (Year " + SkyBlockCalendar.getYear() + ")", Material.CAKE, 1, List.of( - "§7Given to every player as a", - "§7celebration for the " + StringUtility.ntify(SkyBlockCalendar.getYear()) + " Skyblock", - "§7year!", - " ", - "§c§lSPECIAL", - " ", - "§eClick to claim!" - )); - } - }); - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } -} - diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBaker.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBaker.java index 7162c682f..3f8e0fa28 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBaker.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBaker.java @@ -1,16 +1,17 @@ package net.swofty.type.hub.npcs; import net.minestom.server.coordinate.Pos; +import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.data.datapoints.DatapointInteger; -import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.hub.gui.GUIBakerShop; -import net.swofty.type.hub.gui.GUIClaimCake; import net.swofty.type.skyblockgeneric.calendar.CalendarEvent; import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.skyblockgeneric.gui.inventories.ClaimRewardView; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.List; @@ -27,7 +28,8 @@ public String[] holograms(HypixelPlayer player) { List events = SkyBlockCalendar.getCurrentEvents(); if (!events.contains(CalendarEvent.NEW_YEAR)) { return new String[]{""}; - }; + } + ; return new String[]{"§fBaker", "§e§lCLICK"}; } @@ -46,7 +48,8 @@ public Pos position(HypixelPlayer player) { List events = SkyBlockCalendar.getCurrentEvents(); if (!events.contains(CalendarEvent.NEW_YEAR)) { return new Pos(-6.5, 0, -47.5, 180, 0); - }; + } + ; return new Pos(-6.5, 70, -47.5, 180, 0); } @@ -64,20 +67,21 @@ public void onClick(NPCInteractEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.player(); if (isInDialogue(player)) return; - - if(!player.getToggles().get(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_BAKER)) { - setDialogue(player, "initial-hello").thenRun(() -> { - player.getToggles().set(DatapointToggles.Toggles.ToggleType.HAS_SPOKEN_TO_BAKER, true); - }); - return; - } - SkyBlockDataHandler dataHandler = player.getSkyblockDataHandler(); if (dataHandler.get(SkyBlockDataHandler.Data.LATEST_NEW_YEAR_CAKE_YEAR, DatapointInteger.class).getValue() >= SkyBlockCalendar.getYear()) { new GUIBakerShop().open(player); return; } - new GUIClaimCake().open(player); + setDialogue(player, "initial-hello").thenRun(() -> { + SkyBlockItem item = new SkyBlockItem(ItemType.NEW_YEAR_CAKE); + item.getAttributeHandler().setNewYearCakeYear(SkyBlockCalendar.getYear()); + player.openView(new ClaimRewardView(), new ClaimRewardView.State( + item, () -> SkyBlockCalendar.getCurrentEvents().contains(CalendarEvent.NEW_YEAR) && (dataHandler.get(SkyBlockDataHandler.Data.LATEST_NEW_YEAR_CAKE_YEAR, DatapointInteger.class).getValue() < SkyBlockCalendar.getYear()), () -> { + dataHandler.get(SkyBlockDataHandler.Data.LATEST_NEW_YEAR_CAKE_YEAR, DatapointInteger.class).setValue(SkyBlockCalendar.getYear()); + player.getAchievementHandler().completeAchievement("skyblock.happy_new_year"); + } + )); + }); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java index f8733c0fa..9c3b68465 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/ClaimRewardView.java @@ -1,6 +1,5 @@ package net.swofty.type.skyblockgeneric.gui.inventories; -import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.gui.inventory.ItemStackCreator; @@ -11,54 +10,70 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.List; +import java.util.function.BooleanSupplier; public class ClaimRewardView implements View { - public record State(ItemType rewardItem, Runnable onClaim, boolean claimed) { - public State(ItemType rewardItem, Runnable onClaim) { - this(rewardItem, onClaim, false); - } + public record State(SkyBlockItem rewardItem, BooleanSupplier canClaim, Runnable onClaim, boolean claimed) { + public State(ItemType rewardItem, Runnable onClaim) { + this(new SkyBlockItem(rewardItem), () -> true, onClaim, false); + } - public State claim() { - return new State(rewardItem, onClaim, true); - } - } + public State(SkyBlockItem rewardItem, Runnable onClaim) { + this(rewardItem, () -> true, onClaim, false); + } - @Override - public ViewConfiguration configuration() { - return new ViewConfiguration<>("Claim Reward", InventoryType.CHEST_6_ROW); - } + public State(SkyBlockItem rewardItem, BooleanSupplier canClaim, Runnable onClaim) { + this(rewardItem, canClaim, onClaim, false); + } - @Override - public void layout(ViewLayout layout, ClaimRewardView.State state, ViewContext ctx) { - Components.fill(layout); - layout.slot(22, - (_, _) -> ItemStackCreator.appendLore( - new NonPlayerItemUpdater(new SkyBlockItem(state.rewardItem())).getUpdatedItem(), - List.of( - "", - "§eClick to claim!" - ) - ), - (_, viewContext) -> { - SkyBlockPlayer player = (SkyBlockPlayer) viewContext.player(); - viewContext.session(State.class).update(State::claim); - SkyBlockItem item = new SkyBlockItem(state.rewardItem()); - player.addAndUpdateItem(item); - player.sendMessage("§aYou claimed §f" + item.getDisplayName() + "§a!"); - player.closeInventory(); - } - ); - Components.close(layout, 49); - } + public State claim() { + return new State(rewardItem, canClaim, onClaim, true); + } + } - @Override - public void onClose(State state, ViewContext ctx, ViewSession.CloseReason reason) { - if (state.claimed()) return; - SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); - state.claim(); - player.sendMessage("§aYou claimed §f" + state.rewardItem().getDisplayName() + "§a!"); - player.addAndUpdateItem(state.rewardItem()); - } + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Claim Reward", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, ClaimRewardView.State state, ViewContext ctx) { + Components.fill(layout); + layout.slot(22, + (_, _) -> ItemStackCreator.appendLore( + new NonPlayerItemUpdater(state.rewardItem()).getUpdatedItem(), + List.of( + "", + "§eClick to claim!" + ) + ), + (s, viewContext) -> { + SkyBlockPlayer player = (SkyBlockPlayer) viewContext.player(); + if (!s.state().canClaim().getAsBoolean()) { + viewContext.pop(); + player.sendMessage("§cYou're unable to claim this reward at this time."); + return; + } + viewContext.session(State.class).update(State::claim); + SkyBlockItem item = state.rewardItem(); + player.addAndUpdateItem(item); + player.sendMessage("§aYou claimed §f" + item.getDisplayName() + "§a!"); + player.closeInventory(); + state.onClaim().run(); + } + ); + Components.close(layout, 49); + } + + @Override + public void onClose(State state, ViewContext ctx, ViewSession.CloseReason reason) { + if (state.claimed() || !state.canClaim().getAsBoolean()) return; + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + state.claim(); + player.sendMessage("§aYou claimed §f" + state.rewardItem().getDisplayName() + "§a!"); + player.addAndUpdateItem(state.rewardItem()); + state.onClaim().run(); + } } From f1bd5dfe01badbbdea3ab7321de1625946317d70 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sun, 11 Jan 2026 01:05:40 +0200 Subject: [PATCH 17/35] feat: ViewLayout#slots --- .../net/swofty/type/generic/gui/v2/ViewLayout.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java index 19e638102..f5db29f9e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewLayout.java @@ -59,6 +59,17 @@ public void slot(int slot, ItemStack.Builder builder) { components.put(slot, ViewComponent.staticItem(slot, builder)); } + public void slots(Collection slots, + BiFunction render, + BiConsumer, ViewContext> onClick) { + slots.forEach(slot -> slot(slot, render, onClick)); + } + + public void slots(Collection slots, + BiFunction render) { + slots.forEach(slot -> slot(slot, render)); + } + public void editable(int slot, BiFunction initialRender, SlotChangeHandler onChange) { components.put(slot, ViewComponent.editable(slot, initialRender, onChange)); From 67e2535d4b7b98825fd843a8c76256c153c7e037 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sun, 11 Jan 2026 01:05:58 +0200 Subject: [PATCH 18/35] feat: most sbmenu views --- .../net/swofty/type/hub/gui/GUIMaxwell.java | 6 +- .../player/ActionCraftingTableClick.java | 3 +- .../gui/ActionPlayerInteractWithCrafting.java | 2 +- .../gui/inventories/sbmenu/GUICrafting.java | 266 +++++-------- .../gui/inventories/sbmenu/GUIPets.java | 372 +++++++++--------- .../inventories/sbmenu/GUISkyBlockMenu.java | 16 +- .../sbmenu/bags/GUIAccessoryBag.java | 208 ++++------ .../inventories/sbmenu/bags/GUIQuiver.java | 128 +++--- .../gui/inventories/sbmenu/bags/GUISack.java | 22 +- .../sbmenu/bags/GUISackOfSacks.java | 190 ++++----- .../inventories/sbmenu/bags/GUIYourBags.java | 6 +- .../sbmenu/bestiary/GUIBestiary.java | 117 ++---- .../sbmenu/bestiary/GUIBestiaryIsland.java | 242 +++++------- .../sbmenu/bestiary/GUIBestiaryMob.java | 249 ++++++------ .../collection/GUICollectionCategory.java | 2 +- .../sbmenu/collection/GUICollections.java | 3 +- .../sbmenu/collection/GUICraftedMinions.java | 169 ++++---- .../sbmenu/fasttravel/GUIFastTravel.java | 4 +- .../sbmenu/levels/GUILevelsGuide.java | 107 ++--- .../sbmenu/levels/GUISkyBlockLevel.java | 56 +-- .../sbmenu/levels/GUISkyBlockLevels.java | 328 ++++++--------- .../sbmenu/levels/emblem/GUIEmblem.java | 151 +++---- .../sbmenu/levels/emblem/GUIEmblems.java | 88 ++--- .../levels/rewards/GUILevelEmblemRewards.java | 133 +++---- .../rewards/GUILevelFeatureRewards.java | 122 +++--- .../levels/rewards/GUILevelPrefixRewards.java | 116 +++--- .../levels/rewards/GUILevelRewards.java | 277 ++++++------- .../levels/starter/GUIStarterAccessories.java | 21 +- .../levels/starter/GUIStarterSkills.java | 19 +- .../sbmenu/profiles/GUIProfileCreate.java | 124 ++---- .../sbmenu/profiles/GUIProfileManagement.java | 168 ++------ .../sbmenu/profiles/GUIProfileSelect.java | 161 ++++---- .../sbmenu/profiles/GUIProfileSelectMode.java | 85 +--- .../sbmenu/questlog/GUIMissionLog.java | 8 +- .../sbmenu/recipe/GUIRecipeBook.java | 6 +- .../sbmenu/recipe/GUIRecipeCategory.java | 292 +++++++------- .../sbmenu/recipe/GUIRecipeSlayers.java | 249 +++++------- .../sbmenu/skills/GUISkillCategory.java | 10 +- .../inventories/sbmenu/skills/GUISkills.java | 2 +- .../sbmenu/stats/GUICombatStats.java | 114 ++---- .../sbmenu/storage/GUIStorage.java | 4 - .../skyblockgeneric/levels/LevelsGuide.java | 10 +- 42 files changed, 1915 insertions(+), 2741 deletions(-) diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIMaxwell.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIMaxwell.java index 3f936cbd1..1a0009802 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIMaxwell.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIMaxwell.java @@ -29,13 +29,11 @@ public void onOpen(InventoryGUIOpenEvent e) { set(new GUIClickableItem(47) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIAccessoryBag().open(player); + p.openView(new GUIAccessoryBag()); } @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStackHead("§aAccessory Bag Shortcut", "961a918c0c49ba8d053e522cb91abc74689367b4d8aa06bfc1ba9154730985ff", 1, "§7Quickly access your accessory bag", "§7from right here!", @@ -46,7 +44,7 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIItem(48) { @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; + SkyBlockPlayer player = (SkyBlockPlayer) p; int mythic = player.getAccessoryBag().getUniqueAccessories(Rarity.MYTHIC).size(); int legendary = player.getAccessoryBag().getUniqueAccessories(Rarity.LEGENDARY).size(); int epic = player.getAccessoryBag().getUniqueAccessories(Rarity.EPIC).size(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionCraftingTableClick.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionCraftingTableClick.java index 0ca733c9f..a57d36039 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionCraftingTableClick.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/ActionCraftingTableClick.java @@ -2,7 +2,6 @@ import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.item.Material; -import net.swofty.type.generic.HypixelConst; import net.swofty.type.generic.event.EventNodes; import net.swofty.type.generic.event.HypixelEvent; import net.swofty.type.generic.event.HypixelEventClass; @@ -20,7 +19,7 @@ public void run(PlayerBlockInteractEvent event) { } event.setBlockingItemUse(true); - new GUICrafting().open(player); + player.openView(new GUICrafting()); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerInteractWithCrafting.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerInteractWithCrafting.java index 3a63d88d2..e13d6d85b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerInteractWithCrafting.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/gui/ActionPlayerInteractWithCrafting.java @@ -24,6 +24,6 @@ public void run(InventoryPreClickEvent event) { player.getInventory().setCursorItem(ItemStack.AIR); player.getInventory().update(); - new GUICrafting().open((SkyBlockPlayer) event.getPlayer()); + player.openView(new GUICrafting()); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUICrafting.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUICrafting.java index 0d2612f61..4d6c093a6 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUICrafting.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUICrafting.java @@ -3,9 +3,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextDecoration; import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; @@ -13,207 +10,158 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.event.HypixelEventHandler; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.RefreshingGUI; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.event.custom.ItemCraftEvent; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.stream.Collectors; -public class GUICrafting extends HypixelInventoryGUI implements RefreshingGUI { +public class GUICrafting implements StatefulView { private static final ItemStack.Builder RECIPE_REQUIRED = ItemStackCreator.getStack("§cRecipe Required", Material.BARRIER, 1, "§7Add the items for a valid", "§7recipe in the crafting grid", "§7to the left!"); private static final int[] CRAFT_SLOTS = new int[]{10, 11, 12, 19, 20, 21, 28, 29, 30}; private static final int RESULT_SLOT = 23; - private int lastGridHash = 0; - private SkyBlockRecipe lastParsedRecipe = null; - - public GUICrafting() { - super("Craft Item", InventoryType.CHEST_6_ROW); - } - - private int computeGridHash(Inventory inv) { // TODO: Account for metadata - int h = 1; - for (int slot : CRAFT_SLOTS) { - ItemStack it = inv.getItemStack(slot); - h = 31 * h + it.material().id(); - h = 31 * h + it.amount(); - } - return h; - } - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE), 13, 34); - border(ItemStackCreator.createNamedItemStack(Material.RED_STAINED_GLASS_PANE)); - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE), 0, 44); - set(GUIClickableItem.getCloseItem(49)); - - set(RESULT_SLOT, RECIPE_REQUIRED); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Craft Item", InventoryType.CHEST_6_ROW); } @Override - public boolean allowHotkeying() { - return true; + public CraftingState initialState() { + return new CraftingState(0, null); } @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - Arrays.stream(CRAFT_SLOTS).forEach(slot -> { - ((SkyBlockPlayer) e.getPlayer()).addAndUpdateItem(new SkyBlockItem(e.getInventory().getItemStack(slot))); - }); - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - Arrays.stream(CRAFT_SLOTS).forEach(slot -> { - player.addAndUpdateItem(new SkyBlockItem(inventory.getItemStack(slot))); - }); - } + public void layout(ViewLayout layout, CraftingState state, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockRecipe recipe = parseCurrentRecipe(ctx); + boolean hasValidRecipe = recipe != null; + SkyBlockRecipe.CraftingResult result = hasValidRecipe ? recipe.getCanCraft().apply(player) : null; + boolean canCraft = hasValidRecipe && result != null && result.allowed(); + + Material borderMaterial = canCraft ? Material.LIME_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE; + Components.fill(layout); + layout.slots(Layouts.row(5), (s, c) -> ItemStackCreator.createNamedItemStack(borderMaterial)); + Components.close(layout, 49); + + Components.containerGrid( + layout, + 10, + 30, (slot, oldItem, newItem, state1) -> {} + ); + + if (!hasValidRecipe) { + layout.slot(RESULT_SLOT, (s, c) -> RECIPE_REQUIRED); + } else if (!canCraft) { + layout.slot(RESULT_SLOT, (s, c) -> ItemStackCreator.getStack(result.errorMessage()[0], + Material.BEDROCK, 1, + Arrays.copyOfRange(result.errorMessage(), 1, result.errorMessage().length))); + } else { + int amount = recipe.getAmount(); + SkyBlockRecipe finalRecipe = recipe; - @Override - public void onBottomClick(InventoryPreClickEvent e) { - SkyBlockItem clickedItem = new SkyBlockItem(e.getClickedItem()); - if (clickedItem.isNA() || clickedItem.getMaterial().equals(Material.AIR)) return; - } + layout.slot(RESULT_SLOT, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + ItemStack.Builder builder = PlayerItemUpdater.playerUpdate(p, finalRecipe.getResult().getItemStack()).amount(amount); - @Override - public void refreshItems(HypixelPlayer player) { - Inventory inventory = getInventory(); - int gridHash = computeGridHash(inventory); - SkyBlockRecipe recipe; + ArrayList lore = new ArrayList<>(); + var existingLore = builder.build().get(DataComponents.LORE); + if (existingLore != null) { + existingLore.stream().map(line -> "§7" + StringUtility.getTextFromComponent(line)).forEach(lore::add); + } + lore.add("§8§m------------------"); + lore.add("§7This is the item you are crafting."); + builder.set(DataComponents.LORE, lore.stream().map(line -> Component.text(line).decoration(TextDecoration.ITALIC, false)) + .collect(Collectors.toList())); - if (gridHash == lastGridHash) { - recipe = lastParsedRecipe; - } else { - lastGridHash = gridHash; - recipe = SkyBlockRecipe.parseRecipe(getCurrentRecipe(inventory)); - lastParsedRecipe = recipe; + return builder; + }, (click, c) -> handleCraft(click, c, finalRecipe, amount)); } + } - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE), 13, 34); - border(ItemStackCreator.createNamedItemStack(Material.RED_STAINED_GLASS_PANE)); - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE), 0, 44); - set(GUIClickableItem.getCloseItem(49)); - - if (recipe == null) { - set(RESULT_SLOT, RECIPE_REQUIRED); - return; + private SkyBlockRecipe parseCurrentRecipe(ViewContext ctx) { + ItemStack[] stacks = new ItemStack[9]; + for (int i = 0; i < CRAFT_SLOTS.length; i++) { + stacks[i] = ctx.inventory().getItemStack(CRAFT_SLOTS[i]); } + return SkyBlockRecipe.parseRecipe(stacks); + } - recipe = recipe.clone(); + private void handleCraft(ClickContext click, ViewContext ctx, SkyBlockRecipe recipe, int amount) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockItem cursorItem = new SkyBlockItem(player.getInventory().getCursorItem()); + ItemType cursorItemType = cursorItem.getAttributeHandler().getPotentialType(); + ItemType resultItemType = recipe.getResult().getAttributeHandler().getPotentialType(); + boolean isShift = click.click() instanceof Click.LeftShift || click.click() instanceof Click.RightShift; - SkyBlockRecipe.CraftingResult result = recipe.getCanCraft().apply((SkyBlockPlayer) player); - if (!result.allowed()) { - set(RESULT_SLOT, ItemStackCreator.getStack(result.errorMessage()[0], - Material.BEDROCK, - 1, - Arrays.copyOfRange(result.errorMessage(), 1, result.errorMessage().length))); + if (!player.getInventory().getCursorItem().isAir() && + (cursorItemType == null || !cursorItemType.equals(resultItemType))) { + player.sendMessage("§cYou must empty your cursor first!"); return; } - int amount = recipe.getAmount(); - - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE), 13, 34); - border(ItemStackCreator.createNamedItemStack(Material.LIME_STAINED_GLASS_PANE)); - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE), 0, 44); - - SkyBlockRecipe finalRecipe = recipe; - set(new GUIClickableItem(RESULT_SLOT) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockItem cursorItem = new SkyBlockItem(p.getInventory().getCursorItem()); - ItemType cursorItemType = cursorItem.getAttributeHandler().getPotentialType(); - ItemType resultItemType = finalRecipe.getResult().getAttributeHandler().getPotentialType(); - boolean isShift = e.getClick() instanceof Click.LeftShift || e.getClick() instanceof Click.RightShift; - - if (!p.getInventory().getCursorItem().isAir() && - (cursorItemType == null || !cursorItemType.equals(resultItemType))) { - e.setCancelled(true); - e.getPlayer().sendMessage("§cYou must empty your cursor first!"); - return; - } + ItemStack craftedItem = PlayerItemUpdater.playerUpdate( + player, + recipe.getResult().getItemStack()).amount(amount).build(); - ItemStack craftedItem = PlayerItemUpdater.playerUpdate( + if (isShift) { + player.addAndUpdateItem(craftedItem); + } else { + player.getInventory().setCursorItem(craftedItem); + } + HypixelEventHandler.callCustomEvent(new ItemCraftEvent(player, new SkyBlockItem(craftedItem), recipe)); + + SkyBlockItem[] currentItems = getCurrentRecipeAsItems(ctx); + SkyBlockItem[] toReplace = recipe.consume(currentItems); + for (int i = 0; i < CRAFT_SLOTS.length; i++) { + if (toReplace[i] == null || toReplace[i].getItemStack().material() == Material.BEDROCK) { + ctx.inventory().setItemStack(CRAFT_SLOTS[i], ItemStack.builder(Material.AIR).build()); + } else { + ctx.inventory().setItemStack(CRAFT_SLOTS[i], PlayerItemUpdater.playerUpdate( player, - finalRecipe.getResult().getItemStack()).amount(amount).build(); - - e.setCancelled(true); - if (isShift) { - player.addAndUpdateItem(craftedItem); - } else { - p.getInventory().setCursorItem(craftedItem); - } - HypixelEventHandler.callCustomEvent(new ItemCraftEvent(player, new SkyBlockItem(craftedItem), finalRecipe)); - - SkyBlockItem[] toReplace = finalRecipe.consume(getCurrentRecipeAsItems(inventory)); - for (int i = 0; i < CRAFT_SLOTS.length; i++) { - if (toReplace[i] == null || toReplace[i].getItemStack().material() == Material.BEDROCK) { - inventory.setItemStack(CRAFT_SLOTS[i], ItemStack.builder(Material.AIR).build()); - } else { - inventory.setItemStack(CRAFT_SLOTS[i], PlayerItemUpdater.playerUpdate( - player, - toReplace[i].getItemStack()).build()); - } - } - - if (cursorItemType != null && cursorItemType.equals(resultItemType) && !isShift) { - e.setCancelled(true); - player.addAndUpdateItem(cursorItem); - } - - player.getInventory().update(); - refreshItems(player); + toReplace[i].getItemStack()).build()); } + } - @Override - public boolean canPickup() { - return true; - } + if (cursorItemType != null && cursorItemType.equals(resultItemType) && !isShift) { + player.addAndUpdateItem(cursorItem); + } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ItemStack.Builder builder = PlayerItemUpdater.playerUpdate(player, finalRecipe.getResult().getItemStack()).amount(amount); + player.getInventory().update(); + } - ArrayList lore = new ArrayList<>(); - builder.build().get(DataComponents.LORE).stream().map(line -> "§7" + StringUtility.getTextFromComponent(line)).forEach(lore::add); - lore.add("§8§m------------------"); - lore.add("§7This is the item you are crafting."); - builder.set(DataComponents.LORE, lore.stream().map(line -> Component.text(line).decoration(TextDecoration.ITALIC, false)) - .collect(Collectors.toList())); + private SkyBlockItem[] getCurrentRecipeAsItems(ViewContext ctx) { + SkyBlockItem[] stacks = new SkyBlockItem[9]; + for (int i = 0; i < CRAFT_SLOTS.length; i++) { + stacks[i] = new SkyBlockItem(ctx.inventory().getItemStack(CRAFT_SLOTS[i])); + } + return stacks; + } - return builder; + @Override + public void onClose(CraftingState state, ViewContext ctx, ViewSession.CloseReason reason) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + Arrays.stream(CRAFT_SLOTS).forEach(slot -> { + ItemStack item = ctx.inventory().getItemStack(slot); + if (!item.isAir()) { + player.addAndUpdateItem(new SkyBlockItem(item)); } }); } @Override - public int refreshRate() { - return 5; - } - - private ItemStack[] getCurrentRecipe(Inventory inventory) { - ItemStack[] stacks = new ItemStack[9]; - for (int i = 0; i < CRAFT_SLOTS.length; i++) - stacks[i] = inventory.getItemStack(CRAFT_SLOTS[i]); - return stacks; + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + return true; } - private SkyBlockItem[] getCurrentRecipeAsItems(Inventory inventory) { - SkyBlockItem[] stacks = new SkyBlockItem[9]; - for (int i = 0; i < CRAFT_SLOTS.length; i++) - stacks[i] = new SkyBlockItem(inventory.getItemStack(CRAFT_SLOTS[i])); - return stacks; - } + public record CraftingState(int lastGridHash, SkyBlockRecipe lastParsedRecipe) {} } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java index eb8999fec..693aebae1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java @@ -1,8 +1,6 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu; -import lombok.Setter; import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; @@ -10,12 +8,11 @@ import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.Rarity; import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributePetData; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.PetComponent; import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; @@ -25,41 +22,40 @@ import java.util.ArrayList; import java.util.List; -public class GUIPets extends HypixelPaginatedGUI { - @Setter - private SortType sortType = SortType.LEVEL; - @Setter - private boolean convertToItem = false; - - public GUIPets() { - super(InventoryType.CHEST_6_ROW); - } +public class GUIPets extends PaginatedView { + private static final int[] PAGINATED_SLOTS = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; @Override - public boolean allowHotkeying() { - return false; + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> "(" + (state.page() + 1) + "/" + Math.max(1, (int) Math.ceil((double) getFilteredItems(state).size() / PAGINATED_SLOTS.length)) + ") Pets", + InventoryType.CHEST_6_ROW + ); } @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + protected int[] getPaginatedSlots() { + return PAGINATED_SLOTS; } @Override - public int[] getPaginatedSlots() { - return new int[]{ - 10, 11, 12, 13, 14, 15, 16, - 19, 20, 21, 22, 23, 24, 25, - 28, 29, 30, 31, 32, 33, 34, - 37, 38, 39, 40, 41, 42, 43 - }; - } + protected List getFilteredItems(PetsState state) { + List pets = new ArrayList<>(state.items()); + String query = state.query(); - @Override - public PaginationList fillPaged(HypixelPlayer player, PaginationList paged) { - List pets = new ArrayList<>(((SkyBlockPlayer) player).getPetData().getPetsMap().keySet().stream().toList()); + // Apply search filter first + if (query != null && !query.isEmpty()) { + pets = pets.stream().filter(item -> !shouldFilterFromSearch(query, item)).toList(); + } - switch (sortType) { + // Apply sorting + pets = new ArrayList<>(pets); + switch (state.sortType()) { case LEVEL: pets.sort((pet1, pet2) -> { ItemAttributePetData.PetData data1 = pet1.getAttributeHandler().getPetData(); @@ -94,197 +90,185 @@ public PaginationList fillPaged(HypixelPlayer player, PaginationLi break; } - paged.addAll(pets); - - return paged; + return pets; } @Override - public boolean shouldFilterFromSearch(String query, SkyBlockItem item) { - return !item.getDisplayName().toLowerCase().contains(query.toLowerCase()); + protected ItemStack.Builder renderItem(SkyBlockItem item, int index, HypixelPlayer player) { + SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; + boolean isPetEnabled = skyBlockPlayer.getPetData().getEnabledPet() == item; + + ItemStack.Builder itemStack = new NonPlayerItemUpdater(item).getUpdatedItem(); + List lore = new ArrayList<>(itemStack.build().get(DataComponents.LORE).stream().map(StringUtility::getTextFromComponent).toList()); + lore.add(" "); + if (isPetEnabled) { + ItemStackCreator.enchant(itemStack); + lore.add("§aCurrently Active!"); + lore.add("§eClick to deselect!"); + } else { + lore.add("§eClick to summon!"); + } + return ItemStackCreator.updateLore(itemStack, lore); } @Override - public void performSearch(HypixelPlayer player, String query, int page, int maxPage) { - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - p.openView(new GUISkyBlockMenu()); - } + protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockItem item, int index) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + PetsState state = click.state(); + boolean selected = player.getPetData().getEnabledPet() == item; + + if (selected) { + player.getPetData().deselectCurrent(); + player.getPetData().updatePetEntityImpl(player); + ctx.session(PetsState.class).update(s -> (PetsState) s.withItems(getPetsFromPlayer(player))); + player.sendMessage("§cDeselected pet " + item.getDisplayName() + "§c!"); + return; + } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aGo Back", - Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); - set(new GUIClickableItem(47) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.sendMessage("§aPet conversion to item is now " + (!convertToItem ? "§aENABLED" : "§cDISABLED") + "§a!"); - - convertToItem = !convertToItem; - GUIPets guiPets = new GUIPets(); - guiPets.setSortType(sortType); - guiPets.setConvertToItem(convertToItem); - guiPets.open(player); - } + if (state.convertToItem()) { + player.addAndUpdateItem(item); + player.getPetData().removePet(item.getAttributeHandler().getPotentialType()); + ctx.session(PetsState.class).update(s -> (PetsState) s.withItems(getPetsFromPlayer(player))); + player.sendMessage("§aYou have picked up your pet!"); + return; + } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ItemStack.Builder itemStack = ItemStackCreator.getStack("§aConvert to item", Material.DIAMOND, 1, - "§7Toggle between converting your pets to an item", - "§7so you can pick it up and", - "§7place it in your inventory!", - " ", - "§7Currently: " + (convertToItem ? "§aEnabled" : "§cDisabled"), - " ", - "§eClick to convert!"); - if (convertToItem) - ItemStackCreator.enchant(itemStack); - return itemStack; - } - }); + player.getPetData().setEnabled(item.getAttributeHandler().getPotentialType(), true); + player.getPetData().updatePetEntityImpl(player); + player.sendMessage("§aSelected pet " + item.getDisplayName() + "§a!"); + ctx.session(PetsState.class).update(s -> (PetsState) s.withItems(getPetsFromPlayer(player))); + } - set(new GUIClickableItem(51) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - boolean isRightClick = e.getClick() instanceof Click.Right; - - int ordinal = sortType.ordinal(); - if (isRightClick) { - ordinal--; - if (ordinal < 0) ordinal = SortType.values().length - 1; - } else { - ordinal++; - if (ordinal >= SortType.values().length) ordinal = 0; - } - - sortType = SortType.values()[ordinal]; - - GUIPets guiPets = new GUIPets(); - guiPets.setSortType(sortType); - guiPets.setConvertToItem(convertToItem); - guiPets.open(player); - } + @Override + protected boolean shouldFilterFromSearch(String query, SkyBlockItem item) { + return !item.getDisplayName().toLowerCase().contains(query.toLowerCase()); + } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add(" "); + @Override + protected void layoutCustom(ViewLayout layout, PetsState state, ViewContext ctx) { + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + // Info item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStack("§aPets", Material.BONE, 1, + "§7View and manage all of your", + "§7Pets.", + " ", + "§7Level up your pets faster by", + "§7gaining XP in their favourite", + "§7skill!", + " ", + "§7Selected pet: " + (player.getPetData().getEnabledPet() == null ? "§cNone" : player.getPetData().getEnabledPet().getDisplayName()), + " ", + "§eClick to view!"); + }); - for (SortType randomSortType : SortType.values()) { - lore.add(randomSortType == sortType ? - "§e> " + StringUtility.toNormalCase(randomSortType.name()) - : "§7> " + StringUtility.toNormalCase(randomSortType.name())); - } + // Convert to item button + layout.slot(47, (s, c) -> { + ItemStack.Builder itemStack = ItemStackCreator.getStack("§aConvert to item", Material.DIAMOND, 1, + "§7Toggle between converting your pets to an item", + "§7so you can pick it up and", + "§7place it in your inventory!", + " ", + "§7Currently: " + (s.convertToItem() ? "§aEnabled" : "§cDisabled"), + " ", + "§eClick to convert!"); + if (s.convertToItem()) + ItemStackCreator.enchant(itemStack); + return itemStack; + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + player.sendMessage("§aPet conversion to item is now " + (!click.state().convertToItem() ? "§aENABLED" : "§cDISABLED") + "§a!"); + c.session(PetsState.class).update(s -> s.withConvertToItem(!s.convertToItem())); + }); - lore.add(" "); - lore.add("§bRight-Click to go backwards!"); - lore.add("§eClick to switch sort!"); + // Sort button + layout.slot(51, (s, c) -> { + List lore = new ArrayList<>(); + lore.add(" "); - return ItemStackCreator.getStack("§aSort", Material.HOPPER, 1, lore); + for (SortType randomSortType : SortType.values()) { + lore.add(randomSortType == s.sortType() ? + "§e> " + StringUtility.toNormalCase(randomSortType.name()) + : "§7> " + StringUtility.toNormalCase(randomSortType.name())); } - }); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aPets", Material.BONE, 1, - "§7View and manage all of your", - "§7Pets.", - " ", - "§7Level up your pets faster by", - "§7gaining XP in their favourite", - "§7skill!", - " ", - "§7Selected pet: " + (player.getPetData().getEnabledPet() == null ? "§cNone" : player.getPetData().getEnabledPet().getDisplayName()), - " ", - "§eClick to view!"); + lore.add(" "); + lore.add("§bRight-Click to go backwards!"); + lore.add("§eClick to switch sort!"); + + return ItemStackCreator.getStack("§aSort", Material.HOPPER, 1, lore); + }, (click, c) -> { + boolean isRightClick = click.click() instanceof Click.Right; + + int ordinal = click.state().sortType().ordinal(); + if (isRightClick) { + ordinal--; + if (ordinal < 0) ordinal = SortType.values().length - 1; + } else { + ordinal++; + if (ordinal >= SortType.values().length) ordinal = 0; } + + SortType newSort = SortType.values()[ordinal]; + c.session(PetsState.class).update(s -> s.withSortType(newSort)); }); + } - if (page > 1) { - set(createNavigationButton(this, 45, query, page, false)); - } - if (page < maxPage) { - set(createNavigationButton(this, 53, query, page, true)); - } + @Override + protected int getPreviousPageSlot() { + return 45; } @Override - public String getTitle(HypixelPlayer player, String query, int page, PaginationList paged) { - return "(" + page + "/" + paged.getPageCount() + ") Pets"; + protected int getNextPageSlot() { + return 53; } @Override - public GUIClickableItem createItemFor(SkyBlockItem item, int slot, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - boolean isPetEnabled = player.getPetData().getEnabledPet() == item; + protected int getSearchSlot() { + return -1; + } - ItemStack.Builder itemStack = new NonPlayerItemUpdater(item).getUpdatedItem(); - List lore = new ArrayList<>(itemStack.build().get(DataComponents.LORE).stream().map(StringUtility::getTextFromComponent).toList()); - lore.add(" "); - if (isPetEnabled) { - ItemStackCreator.enchant(itemStack); + private static List getPetsFromPlayer(SkyBlockPlayer player) { + return new ArrayList<>(player.getPetData().getPetsMap().keySet().stream().toList()); + } - lore.add("§aCurrently Active!"); - lore.add("§eClick to deselect!"); - } else { - lore.add(convertToItem ? "§eClick to pick up!" : "§eClick to summon!"); + public static PetsState createInitialState(SkyBlockPlayer player) { + return new PetsState(getPetsFromPlayer(player), 0, "", SortType.LEVEL, false); + } + + public record PetsState( + List items, + int page, + String query, + SortType sortType, + boolean convertToItem + ) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new PetsState(items, page, query, sortType, convertToItem); } - itemStack = ItemStackCreator.updateLore(itemStack, lore); - - ItemStack.Builder finalItemStack = itemStack; - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - boolean selected = player.getPetData().getEnabledPet() == item; - if (selected) { - player.getPetData().deselectCurrent(); - player.getPetData().updatePetEntityImpl(player); - GUIPets guiPets = new GUIPets(); - guiPets.setSortType(sortType); - guiPets.setConvertToItem(convertToItem); - guiPets.open(player); - player.sendMessage("§cDeselected pet " + item.getDisplayName() + "§c!"); - return; - } - - if (convertToItem) { - player.addAndUpdateItem(item); - player.getPetData().removePet(item.getAttributeHandler().getPotentialType()); - GUIPets guiPets = new GUIPets(); - guiPets.setSortType(sortType); - guiPets.setConvertToItem(convertToItem); - guiPets.open(player); - player.sendMessage("§aYou have picked up your pet!"); - return; - } - - player.getPetData().setEnabled(item.getAttributeHandler().getPotentialType(), true); - player.getPetData().updatePetEntityImpl(player); - player.sendMessage("§aSelected pet " + item.getDisplayName() + "§a!"); - GUIPets guiPets = new GUIPets(); - guiPets.setSortType(sortType); - guiPets.setConvertToItem(convertToItem); - guiPets.open(player); - } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return finalItemStack; - } - }; + @Override + public PaginatedState withQuery(String query) { + return new PetsState(items, 0, query, sortType, convertToItem); + } + + @Override + public PaginatedState withItems(List items) { + return new PetsState(items, page, query, sortType, convertToItem); + } + + public PetsState withSortType(SortType sortType) { + return new PetsState(items, page, query, sortType, convertToItem); + } + + public PetsState withConvertToItem(boolean convertToItem) { + return new PetsState(items, page, query, sortType, convertToItem); + } } public enum SortType { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java index dee3113a7..1ebbc7d03 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java @@ -89,7 +89,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont " ", "§eClick to view!" ); - }, (click, c) -> new GUISkyBlockLevels().open((SkyBlockPlayer) c.player())); + }, (click, c) -> c.push(new GUISkyBlockLevels())); layout.slot(29, (s, c) -> ItemStackCreator.getStackHead("§aYour Bags", "961a918c0c49ba8d053e522cb91abc74689367b4d8aa06bfc1ba9154730985ff", 1, "§7Different bags allow you to store", @@ -97,7 +97,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont " ", "§eClick to view!" ), (click, c) -> { - c.player().openView(new GUIYourBags()); + c.push(new GUIYourBags()); }); layout.slot(30, (s, c) -> { @@ -114,7 +114,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont " ", "§eClick to view!" ); - }, (click, c) -> new GUIPets().open((SkyBlockPlayer) c.player())); + }, (click, c) -> c.push(new GUIPets(), GUIPets.createInitialState((SkyBlockPlayer) c.player()))); layout.slot(21, (s, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); @@ -132,7 +132,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont lore.add("§eClick to view!"); return ItemStackCreator.getStack("§aRecipe Book", Material.BOOK, 1, lore); }, (click, c) -> { - c.player().openView(new GUIRecipeBook()); + c.push(new GUIRecipeBook()); }); layout.slot(25, (s, c) -> ItemStackCreator.getStack("§aStorage", Material.CHEST, 1, @@ -156,7 +156,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7be obtained through Quests.", " ", "§eClick to view!" - ), (click, c) -> c.player().openView(new GUIMissionLog())); + ), (click, c) -> c.push(new GUIMissionLog())); layout.autoUpdating(24, (s, c) -> ItemStackCreator.getStack("§aCalendar and Events", Material.CLOCK, 1, getCalendarLore()), (click, c) -> c.push(new GUICalendar()), Duration.ofSeconds(1)); @@ -166,7 +166,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7rewards.", " ", "§eClick to view!" - ), (click, c) -> c.player().openView(new GUISkills())); + ), (click, c) -> c.push(new GUISkills())); layout.slot(20, (s, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); @@ -192,7 +192,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7Opens the crafting grid.", " ", "§eClick to open!" - ), (click, c) -> new GUICrafting().open((SkyBlockPlayer) c.player())); + ), (click, c) -> c.push(new GUICrafting())); layout.slot(47, (s, c) -> ItemStackCreator.getStackHead("§bFast Travel", "f151cffdaf303673531a7651b36637cad912ba485643158e548d59b2ead5011", 1, "§7Teleport to islands you've already", @@ -223,7 +223,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont " ", "§eClick to manage!" ); - }, (click, c) -> new GUIProfileManagement().open((SkyBlockPlayer) c.player())); + }, (click, c) -> c.push(new GUIProfileManagement())); } private static @NonNull List getCalendarLore() { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIAccessoryBag.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIAccessoryBag.java index 881b36825..3da5e2ea3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIAccessoryBag.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIAccessoryBag.java @@ -1,18 +1,11 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bags; -import lombok.Setter; -import net.kyori.adventure.text.Component; -import net.minestom.server.event.inventory.InventoryClickEvent; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.collection.CustomCollectionAward; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointAccessoryBag; @@ -26,7 +19,7 @@ import java.util.SortedMap; import java.util.TreeMap; -public class GUIAccessoryBag extends HypixelInventoryGUI { +public class GUIAccessoryBag implements StatefulView { private static final SortedMap SLOTS_PER_UPGRADE = new TreeMap<>(Map.of( CustomCollectionAward.ACCESSORY_BAG, 3, CustomCollectionAward.ACCESSORY_BAG_UPGRADE_1, 9, @@ -40,144 +33,97 @@ public class GUIAccessoryBag extends HypixelInventoryGUI { CustomCollectionAward.ACCESSORY_BAG_UPGRADE_9, 57 )); - @Setter - private int page = 1; - private int slotToSaveUpTo; - - public GUIAccessoryBag() { - super("Accessory Bag", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + int totalSlots = getTotalSlots(player); + int totalPages = Math.max(1, (int) Math.ceil((double) totalSlots / 45)); + return "Accessory Bag (" + (state.page() + 1) + "/" + totalPages + ")"; + }, + InventoryType.CHEST_6_ROW + ); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - //set(GUIClickableItem.getGoBackItem(48, new GUIYourBags())); + public AccessoryBagState initialState() { + return new AccessoryBagState(0); + } - SkyBlockPlayer player = (SkyBlockPlayer) e.player(); + @Override + public void layout(ViewLayout layout, AccessoryBagState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + int page = state.page(); int totalSlots = getTotalSlots(player); int slotsPerPage = 45; - int totalPages = (int) Math.ceil((double) totalSlots / slotsPerPage); - - getInventory().setTitle(Component.text("Accessory Bag (" + page + "/" + totalPages + ")")); - - int startIndex = (page - 1) * slotsPerPage; + int totalPages = Math.max(1, (int) Math.ceil((double) totalSlots / slotsPerPage)); + int startIndex = page * slotsPerPage; int endSlot = Math.min(totalSlots - startIndex, slotsPerPage); - this.slotToSaveUpTo = endSlot; + // Editable slots for accessories for (int i = 0; i < endSlot; i++) { - SkyBlockItem item = player.getAccessoryBag().getInSlot(i + startIndex); - - set(new GUIClickableItem(i) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (item == null) { - return ItemStack.builder(Material.AIR); - } else { - return PlayerItemUpdater.playerUpdate(player, item.getItemStack()); - } - } - - @Override - public boolean canPickup() { - return true; - } - - @Override - public void runPost(InventoryClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - save(player); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; + int absoluteSlot = i + startIndex; + SkyBlockItem item = player.getAccessoryBag().getInSlot(absoluteSlot); + + layout.editable(i, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + if (item == null) { + return ItemStack.builder(Material.AIR); + } else { + return PlayerItemUpdater.playerUpdate(p, item.getItemStack()); } + }, (slot, oldItem, newItem, s) -> { + // Save happens on close }); } + // Locked slots for (int i = endSlot; i < slotsPerPage; i++) { int slotIndex = i + startIndex; CustomCollectionAward nextUpgrade = getUpgradeNeededForSlotIndex(slotIndex); if (nextUpgrade != null) { - set(new GUIItem(i) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§cLocked", Material.RED_STAINED_GLASS_PANE, - 1, - "§7You need to unlock the", - "§a" + nextUpgrade.getDisplay() + " §7upgrade", - "§7to use this slot."); - } - }); + layout.slot(i, (s, c) -> ItemStackCreator.getStack("§cLocked", Material.RED_STAINED_GLASS_PANE, 1, + "§7You need to unlock the", + "§a" + nextUpgrade.getDisplay() + " §7upgrade", + "§7to use this slot.")); } } - if (page > 1) { - set(new GUIClickableItem(45) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aPrevious Page", Material.ARROW, 1); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - GUIAccessoryBag gui = new GUIAccessoryBag(); - gui.setPage(page - 1); - gui.open(player); - } - }); + // Previous page + if (page > 0) { + layout.slot(45, (s, c) -> ItemStackCreator.getStack("§aPrevious Page", Material.ARROW, 1), + (click, c) -> c.session(AccessoryBagState.class).update(s -> s.withPage(s.page() - 1))); } - if (page < totalPages) { - set(new GUIClickableItem(53) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aNext Page", Material.ARROW, 1); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - GUIAccessoryBag gui = new GUIAccessoryBag(); - gui.setPage(page + 1); - gui.open(player); - } - }); + // Next page + if (page < totalPages - 1) { + layout.slot(53, (s, c) -> ItemStackCreator.getStack("§aNext Page", Material.ARROW, 1), + (click, c) -> c.session(AccessoryBagState.class).update(s -> s.withPage(s.page() + 1))); } - - updateItemStacks(e.inventory(), e.player()); } @Override - public boolean allowHotkeying() { - return true; + public void onClose(AccessoryBagState state, ViewContext ctx, ViewSession.CloseReason reason) { + save((SkyBlockPlayer) ctx.player(), ctx, state.page()); } @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - save((SkyBlockPlayer) getPlayer()); - } + public boolean onBottomClick(net.swofty.type.generic.gui.v2.context.ClickContext click, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockItem cursorItem = new SkyBlockItem(player.getInventory().getCursorItem()); + SkyBlockItem clickedItem = new SkyBlockItem(player.getInventory().getItemStack(click.slot())); - @Override - public void onBottomClick(InventoryPreClickEvent e) { - SkyBlockItem cursorItem = new SkyBlockItem(e.getPlayer().getInventory().getCursorItem()); - SkyBlockItem clickedItem = new SkyBlockItem(e.getClickedItem()); - - if (isItemAllowed(cursorItem) && isItemAllowed(clickedItem)) { - save((SkyBlockPlayer) getPlayer()); - return; + if (isItemAllowed(cursorItem, player) && isItemAllowed(clickedItem, player)) { + return true; } - e.setCancelled(true); - getPlayer().sendMessage("§cYou cannot put this item in the Accessory Bag!"); - save((SkyBlockPlayer) getPlayer()); + player.sendMessage("§cYou cannot put this item in the Accessory Bag!"); + return false; } private int getTotalSlots(SkyBlockPlayer player) { @@ -199,39 +145,45 @@ private CustomCollectionAward getUpgradeNeededForSlotIndex(int slotIndex) { return null; } - private void save(SkyBlockPlayer player) { + private void save(SkyBlockPlayer player, ViewContext ctx, int page) { DatapointAccessoryBag.PlayerAccessoryBag accessoryBag = player.getAccessoryBag(); - for (int i = 0; i < this.slotToSaveUpTo; i++) { - int slot = i + ((page - 1) * 45); - SkyBlockItem item = new SkyBlockItem(getInventory().getItemStack(i)); + int totalSlots = getTotalSlots(player); + int slotsPerPage = 45; + int startIndex = page * slotsPerPage; + int endSlot = Math.min(totalSlots - startIndex, slotsPerPage); + + for (int i = 0; i < endSlot; i++) { + int absoluteSlot = i + startIndex; + SkyBlockItem item = new SkyBlockItem(ctx.inventory().getItemStack(i)); if (item.isNA() || item.getMaterial() == Material.AIR) { - accessoryBag.removeFromSlot(slot); + accessoryBag.removeFromSlot(absoluteSlot); } else { - accessoryBag.setInSlot(slot, item); + accessoryBag.setInSlot(absoluteSlot, item); } } - player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.ACCESSORY_BAG, DatapointAccessoryBag.class).setValue( - accessoryBag - ); + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.ACCESSORY_BAG, DatapointAccessoryBag.class).setValue(accessoryBag); } - public boolean isItemAllowed(SkyBlockItem item) { + private boolean isItemAllowed(SkyBlockItem item, SkyBlockPlayer player) { if (item.isNA()) return true; if (item.getMaterial().equals(Material.AIR)) return true; - SkyBlockPlayer player = (SkyBlockPlayer) getPlayer(); if (item.hasComponent(AccessoryComponent.class)) { DatapointAccessoryBag.PlayerAccessoryBag accessoryBag = player.getAccessoryBag(); accessoryBag.addDiscoveredAccessory(item.getAttributeHandler().getPotentialType()); - player.getSkyBlockExperience().addExperience( SkyBlockLevelCause.getAccessoryCause(item.getAttributeHandler().getPotentialType()) ); - return true; } else { return false; } } + + public record AccessoryBagState(int page) { + public AccessoryBagState withPage(int newPage) { + return new AccessoryBagState(newPage); + } + } } \ No newline at end of file diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIQuiver.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIQuiver.java index 6d891691d..2021e246c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIQuiver.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIQuiver.java @@ -1,15 +1,11 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bags; -import net.minestom.server.event.inventory.InventoryClickEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.collection.CustomCollectionAward; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointQuiver; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; @@ -18,116 +14,98 @@ import java.util.Map; -public class GUIQuiver extends HypixelInventoryGUI { +public class GUIQuiver implements StatefulView { private static final Map SLOTS_PER_UPGRADE = Map.of( CustomCollectionAward.QUIVER, 18, CustomCollectionAward.QUIVER_UPGRADE_1, 9, CustomCollectionAward.QUIVER_UPGRADE_2, 9 ); - private int slotToSaveUpTo; + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Quiver", InventoryType.CHEST_5_ROW); + } - public GUIQuiver() { - super("Quiver", InventoryType.CHEST_5_ROW); + @Override + public QuiverState initialState() { + return new QuiverState(0); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - SkyBlockPlayer player = (SkyBlockPlayer) e.player(); - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(40)); - //set(GUIClickableItem.getGoBackItem(39, new GUIYourBags())); + public void layout(ViewLayout layout, QuiverState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 40); + Components.back(layout, 39, ctx); - int amountOfSlots = 0; + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + int amountOfSlots = getUnlockedSlots(player); int rawAmountOfSlots = 0; + // Set up unlocked/locked slots for (Map.Entry entry : SLOTS_PER_UPGRADE.entrySet()) { if (player.hasCustomCollectionAward(entry.getKey())) { - amountOfSlots += entry.getValue(); + rawAmountOfSlots += entry.getValue(); } else { for (int i = 0; i < entry.getValue(); i++) { - set(new GUIItem(i + rawAmountOfSlots) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§cLocked", Material.RED_STAINED_GLASS_PANE, - 1, - "§7You must have the §a" + entry.getKey().getDisplay() + " §7upgrade", - "§7to unlock this slot."); - } - }); + int slotIndex = i + rawAmountOfSlots; + if (slotIndex < 36) { + layout.slot(slotIndex, (s, c) -> ItemStackCreator.getStack("§cLocked", Material.RED_STAINED_GLASS_PANE, 1, + "§7You must have the §a" + entry.getKey().getDisplay() + " §7upgrade", + "§7to unlock this slot.")); + } } + rawAmountOfSlots += entry.getValue(); } - rawAmountOfSlots += entry.getValue(); } - slotToSaveUpTo = amountOfSlots; + // Set up editable slots DatapointQuiver.PlayerQuiver quiver = player.getQuiver(); - for (int i = 0; i < amountOfSlots; i++) { - SkyBlockItem item = quiver.getInSlot(i); - set(new GUIClickableItem(i) { - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (item == null) { - return ItemStack.builder(Material.AIR); - } else { - return PlayerItemUpdater.playerUpdate(player, item.getItemStack()); - } - } - - @Override - public boolean canPickup() { - return true; + int slotIndex = i; + SkyBlockItem item = quiver.getInSlot(slotIndex); + + layout.editable(slotIndex, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + if (item == null) { + return ItemStack.builder(Material.AIR); + } else { + return PlayerItemUpdater.playerUpdate(p, item.getItemStack()); } - - @Override - public void runPost(InventoryClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - save(player, slotToSaveUpTo); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; + }, (slot, oldItem, newItem, s) -> { + SkyBlockItem newSkyBlockItem = new SkyBlockItem(newItem); + if (!isItemAllowed(newSkyBlockItem)) { + ctx.player().sendMessage("§cYou cannot put this item in the Quiver!"); } }); } - - updateItemStacks(e.inventory(), e.player()); } @Override - public boolean allowHotkeying() { - return false; + public void onClose(QuiverState state, ViewContext ctx, ViewSession.CloseReason reason) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + save(player, ctx.inventory(), getUnlockedSlots(player)); } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - SkyBlockItem cursorItem = new SkyBlockItem(e.getPlayer().getInventory().getCursorItem()); - SkyBlockItem clickedItem = new SkyBlockItem(e.getClickedItem()); - - if (isItemAllowed(cursorItem) && isItemAllowed(clickedItem)) { - save((SkyBlockPlayer) getPlayer(), slotToSaveUpTo); - return; + private int getUnlockedSlots(SkyBlockPlayer player) { + int amountOfSlots = 0; + for (Map.Entry entry : SLOTS_PER_UPGRADE.entrySet()) { + if (player.hasCustomCollectionAward(entry.getKey())) { + amountOfSlots += entry.getValue(); + } } - - e.setCancelled(true); - getPlayer().sendMessage("§cYou cannot put this item in the Quiver!"); + return amountOfSlots; } - public boolean isItemAllowed(SkyBlockItem item) { + private boolean isItemAllowed(SkyBlockItem item) { if (item.isNA()) return true; if (item.getMaterial().equals(Material.AIR)) return true; - return item.getMaterial() == Material.ARROW; } - public void save(SkyBlockPlayer player, int slotToSaveUpTo) { + private void save(SkyBlockPlayer player, net.minestom.server.inventory.Inventory inventory, int slotToSaveUpTo) { DatapointQuiver.PlayerQuiver quiver = player.getQuiver(); for (int i = 0; i < slotToSaveUpTo; i++) { - SkyBlockItem item = new SkyBlockItem(getInventory().getItemStack(i)); + SkyBlockItem item = new SkyBlockItem(inventory.getItemStack(i)); if (item.isNA()) { quiver.getQuiverMap().remove(i); } else { @@ -135,4 +113,6 @@ public void save(SkyBlockPlayer player, int slotToSaveUpTo) { } } } + + public record QuiverState(int placeholder) {} } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISack.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISack.java index 2bceb7fbe..c16c7ecb1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISack.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISack.java @@ -65,11 +65,23 @@ public GUISack(ItemType sack, Boolean closeGUIButton) { public void onOpen(InventoryGUIOpenEvent e) { fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); if (!closeGUIButton) { - switch (GUISack.super.size) { - case InventoryType.CHEST_4_ROW -> set(GUIClickableItem.getGoBackItem(31, new GUISackOfSacks())); - case InventoryType.CHEST_5_ROW -> set(GUIClickableItem.getGoBackItem(40, new GUISackOfSacks())); - case InventoryType.CHEST_6_ROW -> set(GUIClickableItem.getGoBackItem(49, new GUISackOfSacks())); - } + int backSlot = switch (GUISack.super.size) { + case InventoryType.CHEST_4_ROW -> 31; + case InventoryType.CHEST_5_ROW -> 40; + case InventoryType.CHEST_6_ROW -> 49; + default -> 31; + }; + set(new GUIClickableItem(backSlot) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + player.openView(new GUISackOfSacks()); + } + + @Override + public ItemStack.Builder getItem(HypixelPlayer player) { + return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To Sack of Sacks"); + } + }); } else { switch (GUISack.super.size) { case InventoryType.CHEST_4_ROW -> set(GUIClickableItem.getCloseItem(31)); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java index 829169d6b..35cc2a056 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java @@ -1,20 +1,16 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bags; -import lombok.Setter; -import net.minestom.server.event.inventory.InventoryClickEvent; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.collection.CustomCollectionAward; +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSackOfSacks; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.SackComponent; @@ -25,7 +21,7 @@ import java.util.SortedMap; import java.util.TreeMap; -public class GUISackOfSacks extends HypixelInventoryGUI { +public class GUISackOfSacks implements StatefulView { private static final SortedMap SLOTS_PER_UPGRADE = new TreeMap<>(Map.of( CustomCollectionAward.SACK_OF_SACKS, 3, CustomCollectionAward.SACK_OF_SACKS_UPGRADE_1, 6, @@ -35,133 +31,102 @@ public class GUISackOfSacks extends HypixelInventoryGUI { CustomCollectionAward.SACK_OF_SACKS_UPGRADE_5, 18 )); - @Setter - private int page = 1; - private int slotToSaveUpTo; - - public GUISackOfSacks() { - super("Sack of Sacks", InventoryType.CHEST_5_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Sack of Sacks", InventoryType.CHEST_5_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(40)); - //set(GUIClickableItem.getGoBackItem(39, new GUIYourBags())); + public SackOfSacksState initialState() { + return new SackOfSacksState(0); + } - SkyBlockPlayer player = (SkyBlockPlayer) e.player(); + @Override + public void layout(ViewLayout layout, SackOfSacksState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 40); + Components.back(layout, 39, ctx); + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); int totalSlots = getTotalSlots(player); int slotsPerPage = 45; - slotToSaveUpTo = totalSlots; + // Editable slots for sacks for (int i = 0; i < totalSlots; i++) { - SkyBlockItem item = player.getSackOfSacks().getInSlot(i); - - set(new GUIClickableItem(i) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (e.getClick() instanceof Click.Right) { - e.setCancelled(true); - SkyBlockItem skyBlockItem = new SkyBlockItem(e.getClickedItem()); - if (skyBlockItem.isNA() || skyBlockItem.isAir()) return; - new GUISack(skyBlockItem.getAttributeHandler().getPotentialType(), false).open(player); - } + int slotIndex = i; + SkyBlockItem item = player.getSackOfSacks().getInSlot(slotIndex); + + layout.slot(slotIndex, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + if (item == null) { + return ItemStack.builder(Material.AIR); + } else { + return PlayerItemUpdater.playerUpdate(p, item.getItemStack()); } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (item == null) { - return ItemStack.builder(Material.AIR); - } else { - return PlayerItemUpdater.playerUpdate(player, item.getItemStack()); - } - } - - @Override - public boolean canPickup() { - return true; + }, (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + if (click.click() instanceof Click.Right) { + SkyBlockItem skyBlockItem = new SkyBlockItem(c.inventory().getItemStack(slotIndex)); + if (skyBlockItem.isNA() || skyBlockItem.isAir()) return; + new GUISack(skyBlockItem.getAttributeHandler().getPotentialType(), false).open(p); } + }); - @Override - public void runPost(InventoryClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - save(player); - } + // Also make it editable + layout.editable(slotIndex, (slot, oldItem, newItem, s) -> { + // Will be saved on close }); } + // Locked slots for (int i = totalSlots; i < slotsPerPage; i++) { CustomCollectionAward nextUpgrade = getUpgradeNeededForSlotIndex(i); if (nextUpgrade != null) { - set(new GUIItem(i) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§cLocked", Material.RED_STAINED_GLASS_PANE, - 1, - "§7You need to unlock the", - "§a" + nextUpgrade.getDisplay() + " §7upgrade", - "§7to use this slot."); - } - }); + layout.slot(i, (s, c) -> ItemStackCreator.getStack("§cLocked", Material.RED_STAINED_GLASS_PANE, 1, + "§7You need to unlock the", + "§a" + nextUpgrade.getDisplay() + " §7upgrade", + "§7to use this slot.")); } } - set(new GUIClickableItem(38) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - int slot = 0; - for (ItemStack itemStack : player.getInventory().getItemStacks()) { - SkyBlockItem item = new SkyBlockItem(itemStack); - ItemType type = item.getAttributeHandler().getPotentialType(); - if (player.canInsertItemIntoSacks(type)) { - player.getSackItems().increase(type, item.getAmount()); - player.getInventory().setItemStack(slot, ItemStack.AIR); - } - slot++; - } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aInsert inventory", Material.CHEST, 1, + // Insert inventory button + layout.slot(38, (s, c) -> ItemStackCreator.getStack("§aInsert inventory", Material.CHEST, 1, "§7Inserts your inventory items into", "§7your sacks.", "", - "§eClick to put items in!"); - } - }); - - updateItemStacks(e.inventory(), e.player()); - } - - @Override - public boolean allowHotkeying() { - return true; + "§eClick to put items in!"), + (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + int slot = 0; + for (ItemStack itemStack : p.getInventory().getItemStacks()) { + SkyBlockItem sItem = new SkyBlockItem(itemStack); + ItemType type = sItem.getAttributeHandler().getPotentialType(); + if (p.canInsertItemIntoSacks(type)) { + p.getSackItems().increase(type, sItem.getAmount()); + p.getInventory().setItemStack(slot, ItemStack.AIR); + } + slot++; + } + }); } @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - save((SkyBlockPlayer) getPlayer()); + public void onClose(SackOfSacksState state, ViewContext ctx, ViewSession.CloseReason reason) { + save((SkyBlockPlayer) ctx.player(), ctx); } @Override - public void onBottomClick(InventoryPreClickEvent e) { - SkyBlockItem cursorItem = new SkyBlockItem(e.getPlayer().getInventory().getCursorItem()); - SkyBlockItem clickedItem = new SkyBlockItem(e.getClickedItem()); + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockItem cursorItem = new SkyBlockItem(player.getInventory().getCursorItem()); + SkyBlockItem clickedItem = new SkyBlockItem(player.getInventory().getItemStack(click.slot())); if (isItemAllowed(cursorItem) && isItemAllowed(clickedItem)) { - save((SkyBlockPlayer) getPlayer()); - return; + return true; } - e.setCancelled(true); - getPlayer().sendMessage("§cYou cannot put this item in the Sack of Sacks!"); - save((SkyBlockPlayer) getPlayer()); + player.sendMessage("§cYou cannot put this item in the Sack of Sacks!"); + return false; } private int getTotalSlots(SkyBlockPlayer player) { @@ -183,23 +148,26 @@ private CustomCollectionAward getUpgradeNeededForSlotIndex(int slotIndex) { return null; } - private void save(SkyBlockPlayer player) { - DatapointSackOfSacks.PlayerSackOfSacks sackOfSacks = player.getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.SACK_OF_SACKS, DatapointSackOfSacks.class).getValue(); - for (int i = 0; i < this.slotToSaveUpTo; i++) { - int slot = i + ((page - 1) * 45); - SkyBlockItem item = new SkyBlockItem(getInventory().getItemStack(i)); + private void save(SkyBlockPlayer player, ViewContext ctx) { + DatapointSackOfSacks.PlayerSackOfSacks sackOfSacks = player.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.SACK_OF_SACKS, DatapointSackOfSacks.class).getValue(); + int totalSlots = getTotalSlots(player); + + for (int i = 0; i < totalSlots; i++) { + SkyBlockItem item = new SkyBlockItem(ctx.inventory().getItemStack(i)); if (item.isNA() || item.getMaterial() == Material.AIR) { - sackOfSacks.removeFromSlot(slot); + sackOfSacks.removeFromSlot(i); } else { - sackOfSacks.setInSlot(slot, item); + sackOfSacks.setInSlot(i, item); } } } - public boolean isItemAllowed(SkyBlockItem item) { + private boolean isItemAllowed(SkyBlockItem item) { if (item.isNA()) return true; if (item.getMaterial().equals(Material.AIR)) return true; - return item.hasComponent(SackComponent.class); } + + public record SackOfSacksState(int placeholder) {} } \ No newline at end of file diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java index 37b7bf0f5..56beb204f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUIYourBags.java @@ -33,7 +33,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7Sackception!", "", "§eClick to open!"), - (click, c) -> new GUISackOfSacks().open((SkyBlockPlayer) c.player())); + (click, c) -> c.player().openView(new GUISackOfSacks())); } else { layout.slot(20, (s, c) -> ItemStackCreator.getStack("§cSack of Sacks", Material.GRAY_DYE, 1, "§7A sack which contains other sacks.", @@ -83,7 +83,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7think of!", " ", "§eClick to open!"), - (click, c) -> new GUIQuiver().open((SkyBlockPlayer) c.player())); + (click, c) -> c.player().openView(new GUIQuiver())); } else { layout.slot(23, (s, c) -> ItemStackCreator.getStack("§cQuiver", Material.GRAY_DYE, 1, "§7A masterfully crafted Quiver which", @@ -107,7 +107,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7Magical Power: §6" + StringUtility.commaify(p.getMagicalPower()), " ", "§eClick to open!"); - }, (click, c) -> new GUIAccessoryBag().open((SkyBlockPlayer) c.player())); + }, (click, c) -> c.player().openView(new GUIAccessoryBag())); } else { layout.slot(24, (s, c) -> ItemStackCreator.getStack("§cAccessory Bag", Material.GRAY_DYE, 1, "§7A special bag which can hold", diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiary.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiary.java index afc270eb9..efcb3c480 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiary.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiary.java @@ -1,45 +1,33 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bestiary; -import lombok.Getter; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; import net.swofty.type.generic.gui.inventory.item.GUIMaterial; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.skills.GUISkillCategory; -import net.swofty.type.skyblockgeneric.skill.SkillCategories; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.ArrayList; import java.util.List; +public class GUIBestiary extends StatelessView { -public class GUIBestiary extends HypixelInventoryGUI { - - private static final int[] displaySlots = { + private static final int[] DISPLAY_SLOTS = { 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 29, 30, 32, 33 - }; - @Getter private enum BestiaryRegions { - YOUR_ISLAND("§aYour Island", new GUIMaterial("c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56"), new GUIBestiaryIsland(BestiaryCategories.YOUR_ISLAND), "§7View all of the mobs that you've", "§7found and killed on §aYour Island§7."), - HUB("§aHub", new GUIMaterial("d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8"), new GUIBestiaryIsland(BestiaryCategories.HUB), "§7View all of the mobs that you've", "§7found and killed in the §aHub§7."), + YOUR_ISLAND("§aYour Island", new GUIMaterial("c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56"), BestiaryCategories.YOUR_ISLAND, "§7View all of the mobs that you've", "§7found and killed on §aYour Island§7."), + HUB("§aHub", new GUIMaterial("d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8"), BestiaryCategories.HUB, "§7View all of the mobs that you've", "§7found and killed in the §aHub§7."), THE_FARMING_ISLANDS("§aThe Farming Islands", new GUIMaterial("4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b"), null, "§7View all of the mobs that you've", "§7found and killed in §aThe Farming", "§aIslands§7."), GARDEN("§bGarden", new GUIMaterial("f4880d2c1e7b86e87522e20882656f45bafd42f94932b2c5e0d6ecaa490cb4c"), null, "§7View all of the §6Pests §7that you've", "§7killed on the §bGarden§7."), SPIDERS_DEN("§cSpider's Den", new GUIMaterial("c754318a3376f470e481dfcd6c83a59aa690ad4b4dd7577fdad1c2ef08d8aee6"), null, "§7View all of the mobs that you've", "§7found and killed in the §cSpider's Den§7."), THE_END("§dThe End", new GUIMaterial("7840b87d52271d2a755dedc82877e0ed3df67dcc42ea479ec146176b02779a5"), null, "§7View all of the mobs that you've", "§7found and killed in §dThe End§7."), CRIMSON_ISLE("§cCrimson Isle", new GUIMaterial("c3687e25c632bce8aa61e0d64c24e694c3eea629ea944f4cf30dcfb4fbce071"), null, "§7View all of the mobs that you've", "§7found and killed in the §cCrimson Isle§7."), - DEEP_CAVERNS("§bDeep Caverns", new GUIMaterial("569a1f114151b4521373f34bc14c2963a5011cdc25a6554c48c708cd96ebfc"), new GUIBestiaryIsland(BestiaryCategories.DEEP_CAVERNS), "§7View all of the mobs that you've", "§7found and killed in the §bDeep Caverns§7."), + DEEP_CAVERNS("§bDeep Caverns", new GUIMaterial("569a1f114151b4521373f34bc14c2963a5011cdc25a6554c48c708cd96ebfc"), BestiaryCategories.DEEP_CAVERNS, "§7View all of the mobs that you've", "§7found and killed in the §bDeep Caverns§7."), DWARVEN_MINES("§2Dwarven Mines", new GUIMaterial("6b20b23c1aa2be0270f016b4c90d6ee6b8330a17cfef87869d6ad60b2ffbf3b5"), null, "§7View all of the mobs that you've", "§7found and killed in the §2Dwarven Mines§7."), CRYSTAL_HALLOWS("§5Crystal Hallows", new GUIMaterial("21dbe30b027acbceb612563bd877cd7ebb719ea6ed1399027dcee58bb9049d4a"), null, "§7View all of the mobs that you've", "§7found and killed in the §5Crystal", "§5Hollows§7."), THE_PARK("§3The Park", new GUIMaterial("a221f813dacee0fef8c59f76894dbb26415478d9ddfc44c2e708a6d3b7549b"), null, "§7View all of the mobs that you've", "§7found and killed in §3The Park§7."), @@ -49,81 +37,52 @@ private enum BestiaryRegions { FISHING("§3Fishing", new GUIMaterial(Material.FISHING_ROD), null, "§7View all of the §3Sea Creatures §7that", "§7you've killed while fishing."), MYTHOLOGICAL_CREATURES("§bMythological Creatures", new GUIMaterial("83cc1cf672a4b2540be346ead79ac2d9ed19d95b6075bf95be0b6d0da61377be"), null, "§7View all of the §bMythological", "§bCreatures §7that you've killed."), JERRY("§6Jerry", new GUIMaterial("45f729736996a38e186fe9fe7f5a04b387ed03f3871ecc82fa78d8a2bdd31109"), null, "§7View all of the mobs that you've", "§7found and killed while fighting §6Jerry§7."), - KUUDRA("§cKuudra", new GUIMaterial("5051c83d9ebf69013f1ec8c9efc979ec2d925a921cc877ff64abe09aadd2f6cc"), null, "§7View all of the mobs that you've", "§7found and killed while fighting §cKuudra§7."), - ; + KUUDRA("§cKuudra", new GUIMaterial("5051c83d9ebf69013f1ec8c9efc979ec2d925a921cc877ff64abe09aadd2f6cc"), null, "§7View all of the mobs that you've", "§7found and killed while fighting §cKuudra§7."); + private final String regionName; private final GUIMaterial guiMaterial; - private final HypixelInventoryGUI gui; + private final BestiaryCategories category; private final String[] lore; - BestiaryRegions(String regionName, GUIMaterial guiMaterial, HypixelInventoryGUI gui, String... lore) { + BestiaryRegions(String regionName, GUIMaterial guiMaterial, BestiaryCategories category, String... lore) { this.regionName = regionName; this.guiMaterial = guiMaterial; - this.gui = gui; + this.category = category; this.lore = lore; } } - public GUIBestiary() { - super("Bestiary", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Bestiary", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(Material.BLACK_STAINED_GLASS_PANE, ""); - set(GUIClickableItem.getCloseItem(49)); - //set(GUIClickableItem.getGoBackItem(48, new GUISkillCategory(SkillCategories.COMBAT, 0))); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - player.getBestiaryData().getTotalDisplay(lore); - - return ItemStackCreator.getStack("§3Bestiary", Material.WRITTEN_BOOK, 1, lore); - } + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(); + player.getBestiaryData().getTotalDisplay(lore); + return ItemStackCreator.getStack("§3Bestiary", Material.WRITTEN_BOOK, 1, lore); }); - BestiaryRegions[] allBestiaryRegions = BestiaryRegions.values(); - int index = 0; - for (int slot : displaySlots) { - BestiaryRegions bestiaryRegion = allBestiaryRegions[index]; - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (bestiaryRegion.gui == null) return; - bestiaryRegion.gui.open(player); - } - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - GUIMaterial guiMaterial = bestiaryRegion.guiMaterial; - - return ItemStackCreator.getUsingGUIMaterial(bestiaryRegion.regionName, guiMaterial, 1, bestiaryRegion.lore); - } - }); - index++; + // Display all regions + BestiaryRegions[] allRegions = BestiaryRegions.values(); + for (int i = 0; i < DISPLAY_SLOTS.length && i < allRegions.length; i++) { + BestiaryRegions region = allRegions[i]; + int slot = DISPLAY_SLOTS[i]; + + layout.slot(slot, (s, c) -> ItemStackCreator.getUsingGUIMaterial(region.regionName, region.guiMaterial, 1, region.lore), + (click, c) -> { + if (region.category != null) { + c.player().openView(new GUIBestiaryIsland(region.category)); + } + }); } - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiaryIsland.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiaryIsland.java index 188ec9311..8e3f469ab 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiaryIsland.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiaryIsland.java @@ -1,18 +1,12 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bestiary; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; import net.swofty.type.generic.gui.inventory.item.GUIMaterial; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.bestiary.BestiaryData; import net.swofty.type.skyblockgeneric.entity.mob.BestiaryMob; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -20,154 +14,128 @@ import java.util.ArrayList; import java.util.List; -public class GUIBestiaryIsland extends HypixelInventoryGUI { +public class GUIBestiaryIsland extends StatelessView { - private static final int[] displaySlots = { + private static final int[] DISPLAY_SLOTS = { 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, }; - BestiaryData bestiaryData = new BestiaryData(); - BestiaryCategories category; + private final BestiaryCategories category; public GUIBestiaryIsland(BestiaryCategories category) { - super("Bestiary ➡ " + StringUtility.stripColor(category.getDisplayName()), InventoryType.CHEST_6_ROW); this.category = category; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(Material.BLACK_STAINED_GLASS_PANE, ""); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUIBestiary())); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - - BestiaryEntry[] entries = category.getEntries(); - int total = entries.length; - int found = 0; - int completed = 0; - - for (BestiaryEntry entry : entries) { - int kills = player.getBestiaryData().getAmount(entry.getMobs()); - if (kills > 0) { - found++; - - BestiaryMob mob = entry.getMobs().getFirst(); - int mobKills = player.getBestiaryData().getAmount(mob); - int tier = bestiaryData.getCurrentBestiaryTier(mob, mobKills); - if (tier == mob.getMaxBestiaryTier()) completed++; - } - } + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Bestiary ➡ " + StringUtility.stripColor(category.getDisplayName()), InventoryType.CHEST_6_ROW); + } - List lore = new ArrayList<>(); - lore.add("§7View all of the mobs that you've"); - lore.add("§7found and killed on " + category.getDisplayName() + "§7."); - lore.add(""); - - // Families Found - int foundPercent = (int) ((double) found / total * 100); - String foundColor = foundPercent == 100 ? "§a" : "§e"; - lore.add("§7Families Found: " + foundColor + foundPercent + "%"); - - String baseBar = "─────────────────"; - int barLength = baseBar.length(); - int filled = (int) Math.round(((double) found / total) * barLength); - String filledBar = "§3§m" + baseBar.substring(0, Math.min(filled, barLength)); - String unfilledBar = "§f§m" + baseBar.substring(Math.min(filled, barLength)); - - lore.add(filledBar + unfilledBar + "§r §b" + - StringUtility.commaify(found) + "§3/§b" + StringUtility.shortenNumber(total)); - lore.add(""); - - // Families Completed - int completedPercent = (int) ((double) completed / total * 100); - String completedColor = completedPercent == 100 ? "§a" : "§e"; - lore.add("§7Families Completed: " + completedColor + completedPercent + "%"); - - int completedFilled = (int) Math.round(((double) completed / total) * barLength); - String completedBar = "§3§m" + baseBar.substring(0, Math.min(completedFilled, barLength)); - String completedUnfilled = "§f§m" + baseBar.substring(Math.min(completedFilled, barLength)); - - lore.add(completedBar + completedUnfilled + "§r §b" + - StringUtility.commaify(completed) + "§3/§b" + StringUtility.shortenNumber(total)); - - return ItemStackCreator.getStackHead( - category.getDisplayName(), - "c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56", - 1, - lore - ); + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + BestiaryData bestiaryData = new BestiaryData(); + + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + + BestiaryEntry[] entries = category.getEntries(); + int total = entries.length; + int found = 0; + int completed = 0; + + for (BestiaryEntry entry : entries) { + int kills = player.getBestiaryData().getAmount(entry.getMobs()); + if (kills > 0) { + found++; + + BestiaryMob mob = entry.getMobs().getFirst(); + int mobKills = player.getBestiaryData().getAmount(mob); + int tier = bestiaryData.getCurrentBestiaryTier(mob, mobKills); + if (tier == mob.getMaxBestiaryTier()) completed++; + } } + + List lore = new ArrayList<>(); + lore.add("§7View all of the mobs that you've"); + lore.add("§7found and killed on " + category.getDisplayName() + "§7."); + lore.add(""); + + // Families Found + int foundPercent = (int) ((double) found / total * 100); + String foundColor = foundPercent == 100 ? "§a" : "§e"; + lore.add("§7Families Found: " + foundColor + foundPercent + "%"); + + String baseBar = "─────────────────"; + int barLength = baseBar.length(); + int filled = (int) Math.round(((double) found / total) * barLength); + String filledBar = "§3§m" + baseBar.substring(0, Math.min(filled, barLength)); + String unfilledBar = "§f§m" + baseBar.substring(Math.min(filled, barLength)); + + lore.add(filledBar + unfilledBar + "§r §b" + + StringUtility.commaify(found) + "§3/§b" + StringUtility.shortenNumber(total)); + lore.add(""); + + // Families Completed + int completedPercent = (int) ((double) completed / total * 100); + String completedColor = completedPercent == 100 ? "§a" : "§e"; + lore.add("§7Families Completed: " + completedColor + completedPercent + "%"); + + int completedFilled = (int) Math.round(((double) completed / total) * barLength); + String completedBar = "§3§m" + baseBar.substring(0, Math.min(completedFilled, barLength)); + String completedUnfilled = "§f§m" + baseBar.substring(Math.min(completedFilled, barLength)); + + lore.add(completedBar + completedUnfilled + "§r §b" + + StringUtility.commaify(completed) + "§3/§b" + StringUtility.shortenNumber(total)); + + return ItemStackCreator.getStackHead( + category.getDisplayName(), + "c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56", + 1, + lore + ); }); + // Display all mobs BestiaryEntry[] bestiaryEntries = category.getEntries(); - int index = 0; - for (int slot : displaySlots) { - if (index >= bestiaryEntries.length) break; - BestiaryEntry bestiaryEntry = bestiaryEntries[index]; + for (int i = 0; i < DISPLAY_SLOTS.length && i < bestiaryEntries.length; i++) { + BestiaryEntry bestiaryEntry = bestiaryEntries[i]; BestiaryMob mob = bestiaryEntry.getMobs().getFirst(); - int kills = ((SkyBlockPlayer) getPlayer()).getBestiaryData().getAmount(bestiaryEntry.getMobs()); - int tier = bestiaryData.getCurrentBestiaryTier(mob, kills); - if (kills > 0) { - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIBestiaryMob(category, bestiaryEntry).open(player); - } - - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(); - GUIMaterial guiMaterial = bestiaryEntry.getGuiMaterial(); - - player.getBestiaryData().getMobDisplay(lore, kills, mob, bestiaryEntry); - - lore.add("§eClick to view!"); - - return ItemStackCreator.getUsingGUIMaterial("§a" + bestiaryEntry.getName() + " " + StringUtility.getAsRomanNumeral(tier), - guiMaterial, 1, lore); - } - }); - } else { - set(new GUIItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§c" + bestiaryEntry.getName(), Material.GRAY_DYE, 1, - "§7Kill a mob belonging to this Family to", - "§7unlock it in your Bestiary!"); - } - }); - } - index++; + int slot = DISPLAY_SLOTS[i]; + + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + int kills = player.getBestiaryData().getAmount(bestiaryEntry.getMobs()); + + if (kills > 0) { + int tier = bestiaryData.getCurrentBestiaryTier(mob, kills); + ArrayList lore = new ArrayList<>(); + GUIMaterial guiMaterial = bestiaryEntry.getGuiMaterial(); + + player.getBestiaryData().getMobDisplay(lore, kills, mob, bestiaryEntry); + lore.add("§eClick to view!"); + + return ItemStackCreator.getUsingGUIMaterial("§a" + bestiaryEntry.getName() + " " + StringUtility.getAsRomanNumeral(tier), + guiMaterial, 1, lore); + } else { + return ItemStackCreator.getStack("§c" + bestiaryEntry.getName(), Material.GRAY_DYE, 1, + "§7Kill a mob belonging to this Family to", + "§7unlock it in your Bestiary!"); + } + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + int kills = player.getBestiaryData().getAmount(bestiaryEntry.getMobs()); + if (kills > 0) { + player.openView(new GUIBestiaryMob(category, bestiaryEntry)); + } + }); } - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiaryMob.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiaryMob.java index b8bdb9cbc..e35f6ea9d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiaryMob.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/GUIBestiaryMob.java @@ -1,20 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bestiary; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.Rarity; import net.swofty.commons.skyblock.statistics.ItemStatistic; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; import net.swofty.type.generic.gui.inventory.item.GUIMaterial; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.bestiary.BestiaryData; import net.swofty.type.skyblockgeneric.entity.mob.BestiaryMob; import net.swofty.type.skyblockgeneric.entity.mob.MobType; @@ -27,7 +20,7 @@ import java.util.List; import java.util.Map; -public class GUIBestiaryMob extends HypixelInventoryGUI { +public class GUIBestiaryMob extends StatelessView { private static final Map SLOTS = new HashMap<>(Map.of( 0, new int[]{}, @@ -40,172 +33,150 @@ public class GUIBestiaryMob extends HypixelInventoryGUI { 7, new int[]{19, 20, 21, 22, 23, 24, 25} )); - private static final int[] displaySlots = { + private static final int[] DISPLAY_SLOTS = { 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, }; - BestiaryData bestiaryData = new BestiaryData(); - BestiaryCategories category; - BestiaryEntry bestiaryEntry; + private final BestiaryCategories category; + private final BestiaryEntry bestiaryEntry; public GUIBestiaryMob(BestiaryCategories category, BestiaryEntry bestiaryEntry) { - super(StringUtility.stripColor(category.getDisplayName() + " ➡ " + StringUtility.stripColor(bestiaryEntry.getName())), InventoryType.CHEST_6_ROW); this.category = category; this.bestiaryEntry = bestiaryEntry; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(Material.BLACK_STAINED_GLASS_PANE, ""); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUIBestiaryIsland(category))); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(); - BestiaryMob mob = bestiaryEntry.getMobs().getFirst(); - GUIMaterial guiMaterial = bestiaryEntry.getGuiMaterial(); - int kills = ((SkyBlockPlayer) getPlayer()).getBestiaryData().getAmount(bestiaryEntry.getMobs()); - int tier = bestiaryData.getCurrentBestiaryTier(mob, kills); - - player.getBestiaryData().getMobDisplay(lore, kills, mob, bestiaryEntry); + public ViewConfiguration configuration() { + return new ViewConfiguration<>(StringUtility.stripColor(category.getDisplayName()) + " ➡ " + StringUtility.stripColor(bestiaryEntry.getName()), InventoryType.CHEST_6_ROW); + } - return ItemStackCreator.getUsingGUIMaterial("§a" + bestiaryEntry.getName() + " " + StringUtility.getAsRomanNumeral(tier), - guiMaterial, 1, lore); - } + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + BestiaryData bestiaryData = new BestiaryData(); + + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + ArrayList lore = new ArrayList<>(); + BestiaryMob mob = bestiaryEntry.getMobs().getFirst(); + GUIMaterial guiMaterial = bestiaryEntry.getGuiMaterial(); + int kills = player.getBestiaryData().getAmount(bestiaryEntry.getMobs()); + int tier = bestiaryData.getCurrentBestiaryTier(mob, kills); + + player.getBestiaryData().getMobDisplay(lore, kills, mob, bestiaryEntry); + + return ItemStackCreator.getUsingGUIMaterial("§a" + bestiaryEntry.getName() + " " + StringUtility.getAsRomanNumeral(tier), + guiMaterial, 1, lore); }); List bestiaryMobs = bestiaryEntry.getMobs(); int mobCount = bestiaryMobs.size(); - - int[] chosenSlots = SLOTS.getOrDefault(mobCount, displaySlots); + int[] chosenSlots = SLOTS.getOrDefault(mobCount, DISPLAY_SLOTS); for (int i = 0; i < bestiaryMobs.size() && i < chosenSlots.length; i++) { BestiaryMob mob = bestiaryMobs.get(i); GUIMaterial guiMaterial = mob.getGuiMaterial(); int slot = chosenSlots[i]; - set(new GUIItem(slot) { - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(); - int kills = player.getBestiaryData().getAmount(mob); - int deaths = player.getDeathData().getAmount(mob.getMobID()); - OtherLoot otherLoot = mob.getOtherLoot(); - - List commonLoot = new ArrayList<>(); - List uncommonLoot = new ArrayList<>(); - List rareLoot = new ArrayList<>(); - List legendaryLoot = new ArrayList<>(); - List rngesusLoot = new ArrayList<>(); - - List lootRecords = mob.getLootTable().getLootTable(); - - for (SkyBlockLootTable.LootRecord lootRecord : lootRecords) { - double chance = lootRecord.getChancePercent(); - if (chance <= 0.01) rngesusLoot.add(lootRecord); - else if (chance <= 0.1) legendaryLoot.add(lootRecord); - else if (chance <= 1) rareLoot.add(lootRecord); - else if (chance <= 30) uncommonLoot.add(lootRecord); - else commonLoot.add(lootRecord); - } - - List mobtypes = mob.getMobTypes(); - - if (mobtypes.size() == 1) { - lore.add("§7Mob Type: " + mobtypes.getFirst().getFullDisplayName()); - lore.add(""); - } else if (mobtypes.size() > 1) { - StringBuilder sb = new StringBuilder(); - for (MobType mobType : mobtypes) { - sb.append(mobType.getFullDisplayName()); - sb.append("§7, "); - } - sb.delete(sb.chars().sum() - 3, sb.chars().sum()); - - lore.add("§7Mob Types: " + sb); - lore.add(""); - } + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + ArrayList lore = new ArrayList<>(); + int kills = player.getBestiaryData().getAmount(mob); + int deaths = player.getDeathData().getAmount(mob.getMobID()); + OtherLoot otherLoot = mob.getOtherLoot(); + + List commonLoot = new ArrayList<>(); + List uncommonLoot = new ArrayList<>(); + List rareLoot = new ArrayList<>(); + List legendaryLoot = new ArrayList<>(); + List rngesusLoot = new ArrayList<>(); + + List lootRecords = mob.getLootTable().getLootTable(); + + for (SkyBlockLootTable.LootRecord lootRecord : lootRecords) { + double chance = lootRecord.getChancePercent(); + if (chance <= 0.01) rngesusLoot.add(lootRecord); + else if (chance <= 0.1) legendaryLoot.add(lootRecord); + else if (chance <= 1) rareLoot.add(lootRecord); + else if (chance <= 30) uncommonLoot.add(lootRecord); + else commonLoot.add(lootRecord); + } + List mobtypes = mob.getMobTypes(); - lore.add("§7Mob Stats:"); - lore.add("§7Health: " + ItemStatistic.HEALTH.getDisplayColor() + Math.round(mob.getBaseStatistics().getOverall(ItemStatistic.HEALTH).floatValue()) + ItemStatistic.HEALTH.getSymbol()); - lore.add("§7Damage: " + ItemStatistic.DAMAGE.getDisplayColor() + Math.round(mob.getBaseStatistics().getOverall(ItemStatistic.DAMAGE).floatValue()) + ItemStatistic.DAMAGE.getSymbol()); - lore.add("§7Coins per Kill: §6" + otherLoot.getCoinAmount()); - lore.add("§7" + mob.getSkillCategory().asCategory().getName() + " Exp: §3" + otherLoot.getSkillXPAmount()); - lore.add("§7XP Orbs: §3" + otherLoot.getXpOrbAmount()); + if (mobtypes.size() == 1) { + lore.add("§7Mob Type: " + mobtypes.getFirst().getFullDisplayName()); lore.add(""); - lore.add("§7Kills: §a" + kills); - lore.add("§7Deaths: §a" + deaths); + } else if (mobtypes.size() > 1) { + StringBuilder sb = new StringBuilder(); + for (MobType mobType : mobtypes) { + sb.append(mobType.getFullDisplayName()); + sb.append("§7, "); + } + sb.delete(sb.chars().sum() - 3, sb.chars().sum()); + + lore.add("§7Mob Types: " + sb); lore.add(""); + } - if (!commonLoot.isEmpty()) { - lore.add(Rarity.COMMON.getColor() + "Common Loot"); - for (SkyBlockLootTable.LootRecord lootRecord : commonLoot) { - lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName()); - } - lore.add(""); + lore.add("§7Mob Stats:"); + lore.add("§7Health: " + ItemStatistic.HEALTH.getDisplayColor() + Math.round(mob.getBaseStatistics().getOverall(ItemStatistic.HEALTH).floatValue()) + ItemStatistic.HEALTH.getSymbol()); + lore.add("§7Damage: " + ItemStatistic.DAMAGE.getDisplayColor() + Math.round(mob.getBaseStatistics().getOverall(ItemStatistic.DAMAGE).floatValue()) + ItemStatistic.DAMAGE.getSymbol()); + lore.add("§7Coins per Kill: §6" + otherLoot.getCoinAmount()); + lore.add("§7" + mob.getSkillCategory().asCategory().getName() + " Exp: §3" + otherLoot.getSkillXPAmount()); + lore.add("§7XP Orbs: §3" + otherLoot.getXpOrbAmount()); + lore.add(""); + lore.add("§7Kills: §a" + kills); + lore.add("§7Deaths: §a" + deaths); + lore.add(""); + + if (!commonLoot.isEmpty()) { + lore.add(Rarity.COMMON.getColor() + "Common Loot"); + for (SkyBlockLootTable.LootRecord lootRecord : commonLoot) { + lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName()); } - if (!uncommonLoot.isEmpty()) { - lore.add(Rarity.UNCOMMON.getColor() + "Uncommon Loot"); - for (SkyBlockLootTable.LootRecord lootRecord : uncommonLoot) { - lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName() + " §8(§a" + lootRecord.getChancePercent() + "%§8)"); - } - lore.add(""); + lore.add(""); + } + if (!uncommonLoot.isEmpty()) { + lore.add(Rarity.UNCOMMON.getColor() + "Uncommon Loot"); + for (SkyBlockLootTable.LootRecord lootRecord : uncommonLoot) { + lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName() + " §8(§a" + lootRecord.getChancePercent() + "%§8)"); } - if (!rareLoot.isEmpty()) { - lore.add(Rarity.RARE.getColor() + "Rare Loot"); - for (SkyBlockLootTable.LootRecord lootRecord : rareLoot) { - lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName() + " §8(§a" + lootRecord.getChancePercent() + "%§8)"); - } - lore.add(""); + lore.add(""); + } + if (!rareLoot.isEmpty()) { + lore.add(Rarity.RARE.getColor() + "Rare Loot"); + for (SkyBlockLootTable.LootRecord lootRecord : rareLoot) { + lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName() + " §8(§a" + lootRecord.getChancePercent() + "%§8)"); } - if (!legendaryLoot.isEmpty()) { - lore.add(Rarity.LEGENDARY.getColor() + "Legendary Loot"); - for (SkyBlockLootTable.LootRecord lootRecord : legendaryLoot) { - lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName() + " §8(§a" + lootRecord.getChancePercent() + "%§8)"); - } - lore.add(""); + lore.add(""); + } + if (!legendaryLoot.isEmpty()) { + lore.add(Rarity.LEGENDARY.getColor() + "Legendary Loot"); + for (SkyBlockLootTable.LootRecord lootRecord : legendaryLoot) { + lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName() + " §8(§a" + lootRecord.getChancePercent() + "%§8)"); } - if (!rngesusLoot.isEmpty()) { - lore.add("§dRNGesus Loot"); - for (SkyBlockLootTable.LootRecord lootRecord : rngesusLoot) { - lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName() + " §8(§a" + lootRecord.getChancePercent() + "%§8)"); - } - lore.add(""); + lore.add(""); + } + if (!rngesusLoot.isEmpty()) { + lore.add("§dRNGesus Loot"); + for (SkyBlockLootTable.LootRecord lootRecord : rngesusLoot) { + lore.add(" §8■ §f" + lootRecord.getItemType().getDisplayName() + " §8(§a" + lootRecord.getChancePercent() + "%§8)"); } + lore.add(""); + } - lore.removeLast(); + if (!lore.isEmpty()) lore.removeLast(); - return ItemStackCreator.getUsingGUIMaterial("§8[§7Lv" + mob.getLevel() + "§8] §f" + mob.getDisplayName(), guiMaterial, 1, lore); - } + return ItemStackCreator.getUsingGUIMaterial("§8[§7Lv" + mob.getLevel() + "§8] §f" + mob.getDisplayName(), guiMaterial, 1, lore); }); } - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionCategory.java index eee6c624b..15b18827d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionCategory.java @@ -103,7 +103,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont player.sendMessage("§cYou haven't found this item yet!"); return; } - //new GUICollectionItem(item.type()).open(player); + player.openView(new GUICollectionItem(item.type())); }); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java index 90073c365..31a566c3e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java @@ -53,7 +53,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "", "§eClick to view!"), (click, c) -> { - //new GUICraftedMinions(new GUICollections()).open((SkyBlockPlayer) c.player()) + c.player().openView(new GUICraftedMinions(), GUICraftedMinions.createInitialState()); }); ArrayList allCategories = CollectionCategories.getCategories(); @@ -79,6 +79,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont ArrayList display = new ArrayList<>(); player.getCollection().getDisplay(display, category); //new GUICollectionCategory(category, display).open(player); + player.openView(new GUICollectionCategory(category, display)); }); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java index 791584202..2d7f042f2 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java @@ -1,21 +1,17 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.collection; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointMinionData; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe.GUIMinionRecipes; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.MinionComponent; import net.swofty.type.skyblockgeneric.minion.MinionRegistry; @@ -23,18 +19,25 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.*; +import java.util.stream.Collectors; -public class GUICraftedMinions extends HypixelPaginatedGUI { +public class GUICraftedMinions extends PaginatedView { - HypixelInventoryGUI previousGUI; + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Crafted Minions", InventoryType.CHEST_6_ROW); + } - public GUICraftedMinions(HypixelInventoryGUI previousGUI) { - super(InventoryType.CHEST_6_ROW); - this.previousGUI = previousGUI; + public static MinionsState createInitialState() { + List minions = Arrays.stream(ItemType.values()) + .map(SkyBlockItem::new) + .filter(item -> item.hasComponent(MinionComponent.class)) + .collect(Collectors.toList()); + return new MinionsState(minions, 0, ""); } @Override - public int[] getPaginatedSlots() { + protected int[] getPaginatedSlots() { return new int[]{ 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, @@ -44,105 +47,91 @@ public int[] getPaginatedSlots() { } @Override - protected PaginationList fillPaged(HypixelPlayer player, PaginationList paged) { - paged.addAll(Arrays.stream(ItemType.values()).map(SkyBlockItem::new).toList()); - paged.removeIf(item -> !(item.hasComponent(MinionComponent.class))); - return paged; + protected int getSearchSlot() { + return -1; // No search } @Override - protected boolean shouldFilterFromSearch(String query, SkyBlockItem item) { - return false; + protected int getNextPageSlot() { + return 53; } @Override - protected void performSearch(HypixelPlayer player, String query, int page, int maxPage) { - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, previousGUI)); + protected int getPreviousPageSlot() { + return 45; + } - if (page > 1) { - set(createNavigationButton(this, 45, query, page, false)); + @Override + protected ItemStack.Builder renderItem(SkyBlockItem item, int index, HypixelPlayer player) { + SkyBlockPlayer sbPlayer = (SkyBlockPlayer) player; + MinionRegistry minionRegistry = item.getAttributeHandler().getMinionType(); + DatapointMinionData.ProfileMinionData playerData = sbPlayer.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.MINION_DATA, DatapointMinionData.class).getValue(); + + ArrayList lore = new ArrayList<>(); + List tiers = List.of(); + boolean unlocked = false; + int minionAmount = 0; + + for (Map.Entry> minion : playerData.craftedMinions()) { + if (Objects.equals(minion.getKey(), minionRegistry.name())) { + tiers = minion.getValue(); + } } - if (page < maxPage) { - set(createNavigationButton(this, 53, query, page, true)); + for (SkyBlockMinion.MinionTier minionTier : minionRegistry.asSkyBlockMinion().getTiers()) { + if (tiers.contains(minionTier.tier())) { + lore.add("§a✔ Tier " + StringUtility.getAsRomanNumeral(minionTier.tier())); + unlocked = true; + minionAmount++; + } else { + lore.add("§c✖ Tier " + StringUtility.getAsRomanNumeral(minionTier.tier())); + } } - } - @Override - protected String getTitle(HypixelPlayer player, String query, int page, PaginationList paged) { - return "Crafted Minions"; + if (unlocked) { + lore.add(""); + lore.add("§eClick to view recipes!"); + String color = (minionAmount == minionRegistry.asSkyBlockMinion().getTiers().size()) ? "§a" : "§e"; + return ItemStackCreator.getStackHead(color + StringUtility.toNormalCase(minionRegistry.name()) + " Minion", + minionRegistry.asSkyBlockMinion().getTiers().getFirst().texture(), 1, lore); + } else { + return ItemStackCreator.getStack("§c" + StringUtility.toNormalCase(minionRegistry.name()) + " Minion", + Material.GRAY_DYE, 1, "§7You haven't crafted this minion."); + } } @Override - protected GUIClickableItem createItemFor(SkyBlockItem item, int slot, HypixelPlayer player) { - - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (e.getClickedItem().material() != Material.GRAY_DYE) { - //new GUIMinionRecipes(item.getAttributeHandler().getMinionType(), new GUICraftedMinions(new GUICollections())).open(player); - } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ItemStack.Builder itemStack; - MinionRegistry minionRegistry = item.getAttributeHandler().getMinionType(); - DatapointMinionData.ProfileMinionData playerData = player.getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.MINION_DATA, DatapointMinionData.class).getValue(); - ArrayList lore = new ArrayList<>(); - List tiers = List.of(); - boolean unlocked = false; - int minionAmount = 0; - - for (Map.Entry> minion : playerData.craftedMinions()) { - if (Objects.equals(minion.getKey(), minionRegistry.name())) { - tiers = minion.getValue(); - } - } - for (SkyBlockMinion.MinionTier minionTier : minionRegistry.asSkyBlockMinion().getTiers()) { - if (tiers.contains(minionTier.tier())) { - lore.add("§a✔ Tier " + StringUtility.getAsRomanNumeral(minionTier.tier())); - unlocked = true; - minionAmount++; - } else { - lore.add("§c✖ Tier " + StringUtility.getAsRomanNumeral(minionTier.tier())); - } - } - if (unlocked) { - lore.add(""); - lore.add("§eClick to view recipes!"); - String color; - color = (minionAmount == minionRegistry.asSkyBlockMinion().getTiers().size()) ? "§a" : "§e"; - itemStack = ItemStackCreator.getStackHead(color + StringUtility.toNormalCase(minionRegistry.name()) + " Minion", - minionRegistry.asSkyBlockMinion().getTiers().getFirst().texture(), 1, lore); - } else { - itemStack = ItemStackCreator.getStack("§c" + StringUtility.toNormalCase(minionRegistry.name()) + " Minion", - Material.GRAY_DYE, 1, "§7You haven't crafted this minion."); - } - return itemStack; - } - }; + protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockItem item, int index) { + // TODO: Open minion recipes GUI when ported + // SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + // new GUIMinionRecipes(item.getAttributeHandler().getMinionType(), ...).open(player); } @Override - public boolean allowHotkeying() { + protected boolean shouldFilterFromSearch(String query, SkyBlockItem item) { return false; } @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { + protected void layoutCustom(ViewLayout layout, MinionsState state, ViewContext ctx) { + Components.close(layout, 49); + Components.back(layout, 48, ctx); } - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { + public record MinionsState(List items, int page, String query) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new MinionsState(items, page, query); + } - } + @Override + public PaginatedState withQuery(String query) { + return new MinionsState(items, page, query); + } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + @Override + public PaginatedState withItems(List items) { + return new MinionsState(items, page, query); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java index bbb9dca57..134ccf07d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/fasttravel/GUIFastTravel.java @@ -50,7 +50,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont }, (click, c) -> { SkyBlockPlayer p = (SkyBlockPlayer) c.player(); p.getToggles().inverse(DatapointToggles.Toggles.ToggleType.PAPER_ICONS); - //new GUIFastTravel().open(p); + c.replace(new GUIFastTravel()); }); TravelScrollIslands[] values = TravelScrollIslands.values(); @@ -129,7 +129,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont p.asProxyPlayer().sendMessage("§7You have been warped to " + island.getDescriptiveName() + "§7!"); }); } else { - //new GUIFastTravelSubMenu(island).open(p); + c.push(new GUIFastTravelSubMenu(island)); } }); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUILevelsGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUILevelsGuide.java index eaba36001..25274fb43 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUILevelsGuide.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUILevelsGuide.java @@ -1,104 +1,83 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.gui.inventory.item.GUIMaterial; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.levels.LevelsGuide; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.ArrayList; import java.util.List; -public class GUILevelsGuide extends HypixelInventoryGUI { +public class GUILevelsGuide extends StatelessView { private final LevelsGuide guide; - private final int[] borderSlots = { + private static final int[] BORDER_SLOTS = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 26, 27, 35, 36, 44, 45, 46, 47, 51, 52, 53 }; - private final int[] taskSlots = { + private static final int[] TASK_SLOTS = { 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43 }; public GUILevelsGuide(LevelsGuide guide) { - super("Guide -> " + StringUtility.toNormalCase(guide.name()), InventoryType.CHEST_6_ROW); this.guide = guide; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - SkyBlockPlayer player = (SkyBlockPlayer) e.player(); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockLevels())); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Guide -> " + StringUtility.toNormalCase(guide.name()), InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.close(layout, 49); + Components.back(layout, 48, ctx); - for (int slot : borderSlots) { - set(slot, ItemStackCreator.createNamedItemStack(guide.getGlassMaterial())); + // Border slots with colored glass + for (int slot : BORDER_SLOTS) { + layout.slot(slot, ItemStackCreator.createNamedItemStack(guide.getGlassMaterial())); } - set(new GUIItem(50) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§6SkyBlock Guide", Material.REDSTONE_TORCH, 1, - "§7Your §6SkyBlock Guide §7tracks the", - "§7progress you have made through", - "§7SkyBlock.", - "", - "§7Complete tasks within your current", - "§7game stage to increase your", - "§bSkyBlock Level §7and become a §dMaster", - "§7of SkyBlock!"); - } - }); - int index = 0; + // Guide info + layout.slot(50, (s, c) -> ItemStackCreator.getStack("§6SkyBlock Guide", Material.REDSTONE_TORCH, 1, + "§7Your §6SkyBlock Guide §7tracks the", + "§7progress you have made through", + "§7SkyBlock.", + "", + "§7Complete tasks within your current", + "§7game stage to increase your", + "§bSkyBlock Level §7and become a §dMaster", + "§7of SkyBlock!")); + + // Task items LevelsGuide.TasksSet[] tasks = guide.getTasksSets().toArray(new LevelsGuide.TasksSet[0]); - for (int slot : taskSlots) { - if (index >= tasks.length) break; - LevelsGuide.TasksSet task = tasks[index]; - - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - task.getGuiToOpen().open(player); - } + for (int i = 0; i < TASK_SLOTS.length && i < tasks.length; i++) { + int slot = TASK_SLOTS[i]; + LevelsGuide.TasksSet task = tasks[i]; - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(); - if (task.getCauses().size() > 1) { - lore.add("§8" + task.getCauses().size() + " Tasks"); - lore.add(""); - } + if (task.getCauses().size() > 1) { + lore.add("§8" + task.getCauses().size() + " Tasks"); + lore.add(""); + } - lore.addAll(task.getDisplay().apply(player)); + lore.addAll(task.getDisplay().apply(player)); - return ItemStackCreator.updateLore(ItemStackCreator.getFromStack(task.getMaterial().build()), lore); - } + return ItemStackCreator.updateLore(ItemStackCreator.getFromStack(task.getMaterial().build()), lore); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + player.openView(task.getGuiToOpen()); }); - index++; } - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevel.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevel.java index 9ac36ea7b..6920925c1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevel.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevel.java @@ -1,14 +1,8 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelRequirement; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelUnlock; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -17,7 +11,7 @@ import java.util.List; import java.util.Map; -public class GUISkyBlockLevel extends HypixelInventoryGUI { +public class GUISkyBlockLevel extends StatelessView { private static final Map> SLOTS_MAP = new HashMap<>( Map.of( 1, List.of(13), @@ -31,41 +25,33 @@ public class GUISkyBlockLevel extends HypixelInventoryGUI { private final SkyBlockLevelRequirement levelRequirement; public GUISkyBlockLevel(SkyBlockLevelRequirement levelRequirement) { - super("Level " + levelRequirement.asInt() + " Rewards", InventoryType.CHEST_4_ROW); - this.levelRequirement = levelRequirement; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(31)); - set(GUIClickableItem.getGoBackItem(30, new GUISkyBlockLevels())); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Level " + levelRequirement.asInt() + " Rewards", InventoryType.CHEST_4_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 31); + Components.back(layout, 30, ctx); List unlocks = levelRequirement.getUnlocks(); List slots = SLOTS_MAP.get(unlocks.size()); - for (int i = 0; i < unlocks.size(); i++) { - SkyBlockLevelUnlock unlock = unlocks.get(i); - set(new GUIItem(slots.get(i)) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; + if (slots != null) { + for (int i = 0; i < unlocks.size(); i++) { + SkyBlockLevelUnlock unlock = unlocks.get(i); + int slot = slots.get(i); + + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); return unlock.getItemDisplay(player, levelRequirement.asInt()); - } - }); + }); + } } - - updateItemStacks(e.inventory(), e.player()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevels.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevels.java index 238a2f675..2dac49281 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevels.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/GUISkyBlockLevels.java @@ -1,16 +1,11 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.type.generic.data.datapoints.DatapointToggles; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.emblem.GUIEmblems; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.rewards.GUILevelRewards; import net.swofty.type.skyblockgeneric.levels.LevelsGuide; @@ -18,119 +13,81 @@ import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelRequirement; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; -public class GUISkyBlockLevels extends HypixelInventoryGUI { - public GUISkyBlockLevels() { - super("SkyBlock Leveling", InventoryType.CHEST_6_ROW); - } +public class GUISkyBlockLevels extends StatelessView { @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", - Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); - - set(new GUIClickableItem(50) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.sendMessage(player.getToggles().get(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT) ? - "§cSkyBlock Levels in Chat is now disabled!" : - "§aSkyBlock Levels in Chat is now enabled!"); - - player.getToggles().set(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT, - !player.getToggles().get(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT)); - - getInventory().setItemStack(50, getItem(player).build()); - getInventory().update(); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§bSkyBlock Levels in Chat", - player.getToggles().get(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT) - ? Material.LIME_DYE : Material.GRAY_DYE, - 1, - "§7View other players' SkyBlock Level", - "§7and their selected emblem in their", - "§7chat messages.", - " ", - player.getToggles().get(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT) - ? "§a§lENABLED" : "§c§lDISABLED", - " ", - "§eClick to toggle!"); - } - }); - - set(new GUIClickableItem(34) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUILevelRewards().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add("§7Unlock rewards for leveling up"); - lore.add("§7your SkyBlock Level."); - lore.add(" "); - lore.addAll(GUILevelRewards.getAsDisplay(GUILevelRewards.getUnlocked(player), - GUILevelRewards.getTotalAwards())); - lore.add(" "); - lore.add("§eClick to view rewards!"); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("SkyBlock Leveling", InventoryType.CHEST_6_ROW); + } - return ItemStackCreator.getStack("§aLeveling Rewards", - Material.CHEST, 1, lore); - } + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + // Toggle SkyBlock Levels in Chat + layout.slot(50, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStack("§bSkyBlock Levels in Chat", + player.getToggles().get(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT) + ? Material.LIME_DYE : Material.GRAY_DYE, + 1, + "§7View other players' SkyBlock Level", + "§7and their selected emblem in their", + "§7chat messages.", + " ", + player.getToggles().get(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT) + ? "§a§lENABLED" : "§c§lDISABLED", + " ", + "§eClick to toggle!"); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + player.sendMessage(player.getToggles().get(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT) ? + "§cSkyBlock Levels in Chat is now disabled!" : + "§aSkyBlock Levels in Chat is now enabled!"); + player.getToggles().set(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT, + !player.getToggles().get(DatapointToggles.Toggles.ToggleType.SKYBLOCK_LEVELS_IN_CHAT)); + c.session(DefaultState.class).render(); }); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockLevelRequirement level = player.getSkyBlockExperience().getLevel(); - int completedChallenges = player.getSkyBlockExperience().getCompletedExperienceCauses().size(); - int totalChallenges = SkyBlockLevelCause.getAmountOfCauses(); - - return ItemStackCreator.getStack("§aYour SkyBlock Level Ranking", - Material.PAINTING, 1, - "§8Classic Mode", - " ", - "§7Your level: " + level.getColor() + level, - "§7You have: §b" + Math.round(player.getSkyBlockExperience().getTotalXP()) + " XP", - " ", - "§7You have completed §3" + (new java.text.DecimalFormat("##.##").format((double) completedChallenges / totalChallenges * 100)) + "% §7of the total", - "§7SkyBlock XP Tasks."); - } + // Level Rewards + layout.slot(34, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(); + lore.add("§7Unlock rewards for leveling up"); + lore.add("§7your SkyBlock Level."); + lore.add(" "); + lore.addAll(GUILevelRewards.getAsDisplay(GUILevelRewards.getUnlocked(player), + GUILevelRewards.getTotalAwards())); + lore.add(" "); + lore.add("§eClick to view rewards!"); + return ItemStackCreator.getStack("§aLeveling Rewards", Material.CHEST, 1, lore); + }, (click, c) -> c.player().openView(new GUILevelRewards())); + + // Your SkyBlock Level Ranking + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockLevelRequirement level = player.getSkyBlockExperience().getLevel(); + int completedChallenges = player.getSkyBlockExperience().getCompletedExperienceCauses().size(); + int totalChallenges = SkyBlockLevelCause.getAmountOfCauses(); + + return ItemStackCreator.getStack("§aYour SkyBlock Level Ranking", + Material.PAINTING, 1, + "§8Classic Mode", + " ", + "§7Your level: " + level.getColor() + level, + "§7You have: §b" + Math.round(player.getSkyBlockExperience().getTotalXP()) + " XP", + " ", + "§7You have completed §3" + (new java.text.DecimalFormat("##.##").format((double) completedChallenges / totalChallenges * 100)) + "% §7of the total", + "§7SkyBlock XP Tasks."); }); - set(new GUIClickableItem(25) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUILevelsGuide(LevelsGuide.STARTER).open(player); - } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aSkyBlock Guide", Material.FILLED_MAP, 1, + // SkyBlock Guide + layout.slot(25, (s, c) -> ItemStackCreator.getStack("§aSkyBlock Guide", Material.FILLED_MAP, 1, "§7Your §6SkyBlock Guide §7tracks the", "§7progress you have made through", "§7SkyBlock.", @@ -140,20 +97,11 @@ public ItemStack.Builder getItem(HypixelPlayer p) { "§bSkyBlock Level §7and become a §dMaster", "§7of SkyBlock!", " ", - "§eClick to view!"); - } - }); - set(new GUIClickableItem(43) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIEmblems().open(player); - } + "§eClick to view!"), + (click, c) -> c.player().openView(new GUILevelsGuide(LevelsGuide.STARTER))); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aPrefix Emblems", Material.NAME_TAG, 1, + // Prefix Emblems + layout.slot(43, (s, c) -> ItemStackCreator.getStack("§aPrefix Emblems", Material.NAME_TAG, 1, "§7Add some spice by having an emblem", "§7next to your name in chat and in tab!", " ", @@ -164,110 +112,72 @@ public ItemStack.Builder getItem(HypixelPlayer p) { "§7Emblems also show important data", "§7associated with them in chat!", " ", - "§eClick to view!"); - } - }); + "§eClick to view!"), + (click, c) -> c.player().openView(new GUIEmblems())); - SkyBlockLevelRequirement currentLevel = ((SkyBlockPlayer) getPlayer()).getSkyBlockExperience().getLevel(); + // Level progression slots + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockLevelRequirement currentLevel = player.getSkyBlockExperience().getLevel(); List levels = new ArrayList<>(); levels.add(currentLevel); for (int i = 0; i < 5; i++) { - if (currentLevel.getNextLevel() == null) { - break; - } + if (currentLevel.getNextLevel() == null) break; levels.add(currentLevel.getNextLevel()); currentLevel = currentLevel.getNextLevel(); } - int unlockedLevel = ((SkyBlockPlayer) getPlayer()).getSkyBlockExperience().getLevel().asInt(); - for (int i = 0; i < 5; i++) { - if (levels.get(i) == null) { - break; - } - + int unlockedLevel = player.getSkyBlockExperience().getLevel().asInt(); + for (int i = 0; i < 5 && i < levels.size(); i++) { SkyBlockLevelRequirement level = levels.get(i); - set(new GUIClickableItem(19 + i) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISkyBlockLevel(level).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - Material material = level.isMilestone() ? Material.RED_STAINED_GLASS : Material.RED_STAINED_GLASS_PANE; + if (level == null) break; + int slot = 19 + i; - if (unlockedLevel == level.asInt()) { - lore.add("§8Your Level"); - lore.add(" "); - material = level.isMilestone() ? Material.LIME_STAINED_GLASS : Material.LIME_STAINED_GLASS_PANE; - } else if (unlockedLevel + 1 == level.asInt()) { - lore.add("§8Next Level"); - lore.add(" "); - material = level.isMilestone() ? Material.YELLOW_STAINED_GLASS : Material.YELLOW_STAINED_GLASS_PANE; - } + layout.slot(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(); + Material material = level.isMilestone() ? Material.RED_STAINED_GLASS : Material.RED_STAINED_GLASS_PANE; - lore.add("§7Rewards:"); - level.getUnlocks().forEach(unlock -> { - lore.addAll(unlock.getDisplay(player, level.asInt())); - }); + if (unlockedLevel == level.asInt()) { + lore.add("§8Your Level"); lore.add(" "); - if (unlockedLevel == level.asInt()) { - lore.add("§a§lUNLOCKED"); - lore.add(" "); - } - lore.add("§eClick to view rewards!"); - - return ItemStackCreator.getStack("§7Level " + level.asInt(), - material, - 1, lore); - } - }); - } - - SkyBlockLevelRequirement currentLevelMilestone = ((SkyBlockPlayer) getPlayer()).getSkyBlockExperience().getLevel().getNextMilestoneLevel(); - if (currentLevelMilestone != null) - set(new GUIClickableItem(30) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISkyBlockLevel(currentLevelMilestone).open(player); + material = level.isMilestone() ? Material.LIME_STAINED_GLASS : Material.LIME_STAINED_GLASS_PANE; + } else if (unlockedLevel + 1 == level.asInt()) { + lore.add("§8Next Level"); + lore.add(" "); + material = level.isMilestone() ? Material.YELLOW_STAINED_GLASS : Material.YELLOW_STAINED_GLASS_PANE; } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add("§8Next Milestone Level"); - lore.add(" "); - lore.add("§7Rewards:"); - currentLevelMilestone.getUnlocks().forEach(unlock -> { - lore.addAll(unlock.getDisplay(player, currentLevelMilestone.asInt())); - }); - lore.add(" "); - lore.add("§7XP Left to Gain: §b" + (currentLevelMilestone.getCumulativeExperience() - player.getSkyBlockExperience().getTotalXP()) - + " XP §8(" + (int) (player.getSkyBlockExperience().getTotalXP() / currentLevelMilestone.getCumulativeExperience() * 100) + "%)"); + lore.add("§7Rewards:"); + level.getUnlocks().forEach(unlock -> lore.addAll(unlock.getDisplay(p, level.asInt()))); + lore.add(" "); + if (unlockedLevel == level.asInt()) { + lore.add("§a§lUNLOCKED"); lore.add(" "); - lore.add("§eClick to view rewards!"); - - return ItemStackCreator.getStack("§7Level " + currentLevelMilestone.asInt(), - Material.PURPLE_STAINED_GLASS_PANE, - 1, lore); } - }); + lore.add("§eClick to view rewards!"); - updateItemStacks(getInventory(), getPlayer()); - } + return ItemStackCreator.getStack("§7Level " + level.asInt(), material, 1, lore); + }, (click, c) -> c.player().openView(new GUISkyBlockLevel(level))); + } - @Override - public boolean allowHotkeying() { - return false; - } + // Next Milestone Level + SkyBlockLevelRequirement currentMilestone = player.getSkyBlockExperience().getLevel().getNextMilestoneLevel(); + if (currentMilestone != null) { + layout.slot(30, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(); + lore.add("§8Next Milestone Level"); + lore.add(" "); + lore.add("§7Rewards:"); + currentMilestone.getUnlocks().forEach(unlock -> lore.addAll(unlock.getDisplay(p, currentMilestone.asInt()))); + lore.add(" "); + lore.add("§7XP Left to Gain: §b" + (currentMilestone.getCumulativeExperience() - p.getSkyBlockExperience().getTotalXP()) + + " XP §8(" + (int) (p.getSkyBlockExperience().getTotalXP() / currentMilestone.getCumulativeExperience() * 100) + "%)"); + lore.add(" "); + lore.add("§eClick to view rewards!"); - @Override - public void onBottomClick(net.minestom.server.event.inventory.InventoryPreClickEvent e) { - e.setCancelled(true); + return ItemStackCreator.getStack("§7Level " + currentMilestone.asInt(), Material.PURPLE_STAINED_GLASS_PANE, 1, lore); + }, (click, c) -> c.player().openView(new GUISkyBlockLevel(currentMilestone))); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblem.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblem.java index 3f3fd6881..d310b4a1d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblem.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblem.java @@ -1,14 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.emblem; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; import net.swofty.type.skyblockgeneric.levels.SkyBlockEmblems; import net.swofty.type.skyblockgeneric.levels.abstr.CauseEmblem; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -16,27 +15,27 @@ import java.util.ArrayList; import java.util.List; -public class GUIEmblem extends HypixelPaginatedGUI { +public class GUIEmblem extends PaginatedView { private final SkyBlockEmblems emblemCategory; public GUIEmblem(SkyBlockEmblems emblemCategory) { - super(InventoryType.CHEST_5_ROW); - this.emblemCategory = emblemCategory; } @Override - public boolean allowHotkeying() { - return false; + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> "Emblems - " + emblemCategory.toString() + " (" + (state.page() + 1) + "/" + Math.max(1, (int) Math.ceil((double) state.items().size() / getPaginatedSlots().length)) + ")", + InventoryType.CHEST_5_ROW + ); } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + public static EmblemState createInitialState(SkyBlockEmblems emblemCategory) { + return new EmblemState(new ArrayList<>(emblemCategory.getEmblems()), 0, ""); } @Override - public int[] getPaginatedSlots() { + protected int[] getPaginatedSlots() { return new int[]{ 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, @@ -45,80 +44,86 @@ public int[] getPaginatedSlots() { } @Override - public PaginationList fillPaged(HypixelPlayer player, PaginationList paged) { - paged.addAll(emblemCategory.getEmblems()); - return paged; + protected int getSearchSlot() { + return -1; // No search } @Override - public boolean shouldFilterFromSearch(String query, SkyBlockEmblems.SkyBlockEmblem item) { - return !item.displayName().toLowerCase().contains(query.toLowerCase()); + protected int getNextPageSlot() { + return 44; + } + + @Override + protected int getPreviousPageSlot() { + return 36; } @Override - public void performSearch(HypixelPlayer player, String query, int page, int maxPage) { - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); - set(GUIClickableItem.getCloseItem(40)); - set(createSearchItem(this, 41, query)); - set(GUIClickableItem.getGoBackItem(39, new GUIEmblems())); - - if (page > 1) { - set(createNavigationButton(this, 36, query, page, false)); + protected ItemStack.Builder renderItem(SkyBlockEmblems.SkyBlockEmblem item, int index, HypixelPlayer player) { + SkyBlockPlayer sbPlayer = (SkyBlockPlayer) player; + boolean unlocked = sbPlayer.hasUnlockedXPCause(item.cause()); + CauseEmblem causeEmblem = (CauseEmblem) item.cause(); + + String name = (unlocked ? "§a" : "§c") + item.displayName() + " " + item.emblem(); + List lore; + if (unlocked) { + lore = new ArrayList<>(List.of( + "§8" + causeEmblem.emblemEisplayName(), + " ", + "§7Preview: " + sbPlayer.getFullDisplayName(item), + " ", + "§eClick to select!" + )); + } else { + lore = new ArrayList<>(List.of( + "§8Locked", + " ", + "§c" + causeEmblem.getEmblemRequiresMessage() + )); } - if (page < maxPage) { - set(createNavigationButton(this, 44, query, page, true)); + + return ItemStackCreator.getStack(name, unlocked ? item.displayMaterial() : Material.GRAY_DYE, 1, lore); + } + + @Override + protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockEmblems.SkyBlockEmblem item, int index) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + boolean unlocked = player.hasUnlockedXPCause(item.cause()); + + if (!unlocked) { + player.sendMessage("§cYou have not unlocked this emblem yet!"); + return; } + + player.getSkyBlockExperience().setEmblem(emblemCategory, item); + player.sendMessage("§aYou have selected the " + item.displayName() + " emblem!"); } @Override - public String getTitle(HypixelPlayer player, String query, int page, PaginationList paged) { - return "Emblems - " + emblemCategory.toString() + " (" + page + "/" + paged.getPageCount() + ")"; + protected boolean shouldFilterFromSearch(String query, SkyBlockEmblems.SkyBlockEmblem item) { + return !item.displayName().toLowerCase().contains(query.toLowerCase()); } @Override - public GUIClickableItem createItemFor(SkyBlockEmblems.SkyBlockEmblem item, int slot, HypixelPlayer player) { - boolean unlocked = ((SkyBlockPlayer) player).hasUnlockedXPCause(item.cause()); - CauseEmblem causeEmblem = (CauseEmblem) item.cause(); + protected void layoutCustom(ViewLayout layout, EmblemState state, ViewContext ctx) { + Components.close(layout, 40); + Components.back(layout, 39, ctx); + } - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!unlocked) { - player.sendMessage("§cYou have not unlocked this emblem yet!"); - return; - } - - player.getSkyBlockExperience().setEmblem(emblemCategory, item); - player.sendMessage("§aYou have selected the " + item.displayName() + " emblem!"); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - String name = (unlocked ? "§a" : "§c") + item.displayName() + " " + item.emblem(); - - List lore; - if (unlocked) { - lore = new ArrayList<>(List.of( - "§8" + causeEmblem.emblemEisplayName(), - " ", - "§7Preview: " + player.getFullDisplayName(item), - " ", - "§eClick to select!" - )); - } else { - lore = new ArrayList<>(List.of( - "§8Locked", - " ", - "§c" + causeEmblem.getEmblemRequiresMessage() - )); - } - - return ItemStackCreator.getStack(name, - unlocked ? item.displayMaterial() : Material.GRAY_DYE, - 1, lore); - } - }; + public record EmblemState(List items, int page, String query) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new EmblemState(items, page, query); + } + + @Override + public PaginatedState withQuery(String query) { + return new EmblemState(items, page, query); + } + + @Override + public PaginatedState withItems(List items) { + return new EmblemState(items, page, query); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblems.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblems.java index 32110b73e..715c6ba63 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblems.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblems.java @@ -1,74 +1,50 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.emblem; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; import net.swofty.type.generic.gui.inventory.item.GUIMaterial; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.GUISkyBlockLevels; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.levels.SkyBlockEmblems; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.ArrayList; import java.util.Arrays; -public class GUIEmblems extends HypixelInventoryGUI { - private static final int[] SLOTS = new int[]{ - 11, 12, 13, 14, 15 - }; - - public GUIEmblems() { - super("Emblems", InventoryType.CHEST_4_ROW); - } - - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(31)); - set(GUIClickableItem.getGoBackItem(30, new GUISkyBlockLevels())); - - Arrays.stream(SkyBlockEmblems.values()).forEach(emblem -> { - set(new GUIClickableItem(SLOTS[emblem.ordinal()]) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIEmblem(emblem).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - String displayName = emblem.toString(); - GUIMaterial guiMaterial = emblem.getGuiMaterial(); - ArrayList description = new ArrayList<>(emblem.getDescription()); - - ArrayList lore = new ArrayList<>(Arrays.asList( - "§8" + emblem.amountUnlocked(player) + " Unlocked", - " " - )); - lore.addAll(description); - lore.add(" "); - lore.add("§eClick to view!"); - - return ItemStackCreator.getUsingGUIMaterial("§a" + displayName, guiMaterial, 1, lore); - } - }); - }); - - updateItemStacks(getInventory(), getPlayer()); - } +public class GUIEmblems extends StatelessView { + private static final int[] SLOTS = new int[]{11, 12, 13, 14, 15}; @Override - public boolean allowHotkeying() { - return false; + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Emblems", InventoryType.CHEST_4_ROW); } @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 31); + Components.back(layout, 30, ctx); + + for (SkyBlockEmblems emblem : SkyBlockEmblems.values()) { + if (emblem.ordinal() >= SLOTS.length) break; + int slot = SLOTS[emblem.ordinal()]; + + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + String displayName = emblem.toString(); + GUIMaterial guiMaterial = emblem.getGuiMaterial(); + ArrayList description = new ArrayList<>(emblem.getDescription()); + + ArrayList lore = new ArrayList<>(Arrays.asList( + "§8" + emblem.amountUnlocked(player) + " Unlocked", + " " + )); + lore.addAll(description); + lore.add(" "); + lore.add("§eClick to view!"); + + return ItemStackCreator.getUsingGUIMaterial("§a" + displayName, guiMaterial, 1, lore); + }, (click, c) -> c.push(new GUIEmblem(emblem), GUIEmblem.createInitialState(emblem))); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelEmblemRewards.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelEmblemRewards.java index e9feafdd6..26cc880cf 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelEmblemRewards.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelEmblemRewards.java @@ -1,14 +1,10 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.rewards; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.emblem.GUIEmblems; import net.swofty.type.skyblockgeneric.levels.SkyBlockEmblems; import net.swofty.type.skyblockgeneric.levels.causes.LevelCause; @@ -17,7 +13,7 @@ import java.util.ArrayList; import java.util.List; -public class GUILevelEmblemRewards extends HypixelInventoryGUI { +public class GUILevelEmblemRewards extends StatelessView { private static final int[] SLOTS = new int[]{ 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, @@ -25,25 +21,19 @@ public class GUILevelEmblemRewards extends HypixelInventoryGUI { 37, 38, 39, 40, 41, 42, 43, }; - public GUILevelEmblemRewards() { - super("Emblem Rewards", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Emblem Rewards", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUILevelEmblemRewards())); - set(new GUIClickableItem(50) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIEmblems().open(player); - } + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aPrefix Emblems", Material.NAME_TAG, 1, + // View Emblems button + layout.slot(50, (s, c) -> ItemStackCreator.getStack("§aPrefix Emblems", Material.NAME_TAG, 1, "§7Add some spice by having an emblem", "§7next to your name in chat and in tab!", " ", @@ -54,76 +44,59 @@ public ItemStack.Builder getItem(HypixelPlayer p) { "§7Emblems also show important data", "§7associated with them in chat!", " ", - "§eClick to view!"); + "§eClick to view!"), + (click, c) -> c.player().openView(new GUIEmblems())); + + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(); + lore.add("§7Emblems to show next to your name"); + lore.add("§7that signify special achievements."); + lore.add(" "); + lore.add("§7Next Reward:"); + + List levelEmblems = SkyBlockEmblems.getEmblemsWithLevelCause(); + SkyBlockEmblems.SkyBlockEmblem nextEmblem = null; + for (SkyBlockEmblems.SkyBlockEmblem emblem : levelEmblems) { + if (player.getSkyBlockExperience().hasExperienceFor(emblem.cause())) continue; + nextEmblem = emblem; + break; } - }); - - set(new GUIItem(14) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add("§7Emblems to show next to your name"); - lore.add("§7that signify special achievements."); - lore.add(" "); - lore.add("§7Next Reward:"); - List levelEmblems = SkyBlockEmblems.getEmblemsWithLevelCause(); - SkyBlockEmblems.SkyBlockEmblem nextEmblem = null; - for (SkyBlockEmblems.SkyBlockEmblem emblem : levelEmblems) { - if (player.getSkyBlockExperience().hasExperienceFor(emblem.cause())) continue; - nextEmblem = emblem; - break; - } - - if (nextEmblem == null) { - lore.add("§cNo more rewards!"); - } else { - lore.add("§f" + nextEmblem.displayName() + " " + nextEmblem.emblem()); - lore.add("§8at Level " + ((LevelCause) nextEmblem.cause()).getLevel()); - } + if (nextEmblem == null) { + lore.add("§cNo more rewards!"); + } else { + lore.add("§f" + nextEmblem.displayName() + " " + nextEmblem.emblem()); + lore.add("§8at Level " + ((LevelCause) nextEmblem.cause()).getLevel()); + } - lore.add(" "); - lore.addAll(GUILevelRewards.getAsDisplay( - player.getSkyBlockExperience().getOfType(LevelCause.class).size(), - levelEmblems.size() - )); + lore.add(" "); + lore.addAll(GUILevelRewards.getAsDisplay( + player.getSkyBlockExperience().getOfType(LevelCause.class).size(), + levelEmblems.size() + )); - return ItemStackCreator.getStack("§aEmblem Rewards", - Material.NAME_TAG, 1, lore); - } + return ItemStackCreator.getStack("§aEmblem Rewards", Material.NAME_TAG, 1, lore); }); + // Emblem items int index = 0; for (SkyBlockEmblems.SkyBlockEmblem emblem : SkyBlockEmblems.getEmblemsWithLevelCause()) { + if (index >= SLOTS.length) break; int slot = SLOTS[index]; - set(new GUIItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack(emblem.displayName() + " " + emblem.emblem(), - Material.NAME_TAG, 1, - "§8Level " + ((LevelCause) emblem.cause()).getLevel(), - " ", - "§7Preview: " + player.getFullDisplayName(emblem), - " ", - (player.getSkyBlockExperience().hasExperienceFor(emblem.cause()) ? "§aYou have unlocked this reward!" : "§7Levels left to unlock: §3" + (((LevelCause) emblem.cause()).getLevel() - player.getSkyBlockExperience().getLevel().asInt()))); - } + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStack(emblem.displayName() + " " + emblem.emblem(), + Material.NAME_TAG, 1, + "§8Level " + ((LevelCause) emblem.cause()).getLevel(), + " ", + "§7Preview: " + player.getFullDisplayName(emblem), + " ", + (player.getSkyBlockExperience().hasExperienceFor(emblem.cause()) ? "§aYou have unlocked this reward!" : "§7Levels left to unlock: §3" + (((LevelCause) emblem.cause()).getLevel() - player.getSkyBlockExperience().getLevel().asInt()))); }); index++; } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelFeatureRewards.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelFeatureRewards.java index 1173f711b..9aab6ab54 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelFeatureRewards.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelFeatureRewards.java @@ -3,15 +3,12 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextDecoration; import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSkyBlockExperience; import net.swofty.type.skyblockgeneric.levels.CustomLevelAward; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -21,94 +18,71 @@ import java.util.List; import java.util.Map; -public class GUILevelFeatureRewards extends HypixelInventoryGUI { +public class GUILevelFeatureRewards extends StatelessView { private static final int[] SLOTS = new int[]{ - 19, 20, 21, 22, 23, 24, 25, - 31 + 19, 20, 21, 22, 23, 24, 25, 31 }; - public GUILevelFeatureRewards() { - super("Feature Rewards", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Feature Rewards", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUILevelRewards())); - - DatapointSkyBlockExperience.PlayerSkyBlockExperience experience = ((SkyBlockPlayer) getPlayer()).getSkyBlockExperience(); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add("§7Specific game features such as the"); - lore.add("§7Bazaar or Community Shop."); - lore.add(" "); - lore.add("§7Next Reward:"); - - Map.Entry> nextAward = CustomLevelAward.getNextReward( - experience.getLevel().asInt() - ); - if (nextAward == null) { - lore.add("§cNo more rewards!"); - } else { - nextAward.getValue().forEach(award -> { - lore.add("§7" + award.getDisplay()); - }); - lore.add("§8at Level " + nextAward.getKey()); - } + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + DatapointSkyBlockExperience.PlayerSkyBlockExperience experience = player.getSkyBlockExperience(); + List lore = new ArrayList<>(); + lore.add("§7Specific game features such as the"); + lore.add("§7Bazaar or Community Shop."); + lore.add(" "); + lore.add("§7Next Reward:"); + + Map.Entry> nextAward = CustomLevelAward.getNextReward(experience.getLevel().asInt()); + if (nextAward == null) { + lore.add("§cNo more rewards!"); + } else { + nextAward.getValue().forEach(award -> lore.add("§7" + award.getDisplay())); + lore.add("§8at Level " + nextAward.getKey()); + } - lore.add(" "); - lore.addAll(GUILevelRewards.getAsDisplay(CustomLevelAward.getFromLevel(experience.getLevel().asInt()).size(), - CustomLevelAward.getTotalLevelAwards())); + lore.add(" "); + lore.addAll(GUILevelRewards.getAsDisplay(CustomLevelAward.getFromLevel(experience.getLevel().asInt()).size(), + CustomLevelAward.getTotalLevelAwards())); - return ItemStackCreator.getStack("§aFeature Rewards", - Material.NETHER_STAR, 1, lore); - } + return ItemStackCreator.getStack("§aFeature Rewards", Material.NETHER_STAR, 1, lore); }); + // Award items for (Map.Entry entry : CustomLevelAward.getAwards().entrySet()) { CustomLevelAward award = entry.getKey(); Integer level = entry.getValue(); int slot = SLOTS[award.ordinal()]; - boolean unlocked = experience.getLevel().asInt() >= level; - set(new GUIItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - ItemStack.Builder item = award.getItem(); - List lore = new ArrayList<>(Arrays.asList( - "§8Level " + level, - " " - )); + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + boolean unlocked = player.getSkyBlockExperience().getLevel().asInt() >= level; - if (unlocked) { - lore.add("§aYou have unlocked this reward!"); - } else { - lore.add("§7Levels left to Unlock: §3" + (level - experience.getLevel().asInt())); - } + ItemStack.Builder item = award.getItem(); + List lore = new ArrayList<>(Arrays.asList("§8Level " + level, " ")); - return ItemStackCreator.updateLore(item, lore).set( - DataComponents.CUSTOM_NAME, - Component.text(award.getDisplay()).decoration(TextDecoration.ITALIC, false) - ); + if (unlocked) { + lore.add("§aYou have unlocked this reward!"); + } else { + lore.add("§7Levels left to Unlock: §3" + (level - player.getSkyBlockExperience().getLevel().asInt())); } + + return ItemStackCreator.updateLore(item, lore).set( + DataComponents.CUSTOM_NAME, + Component.text(award.getDisplay()).decoration(TextDecoration.ITALIC, false) + ); }); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelPrefixRewards.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelPrefixRewards.java index 6254dac6d..b65991fc5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelPrefixRewards.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelPrefixRewards.java @@ -1,14 +1,10 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.rewards; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSkyBlockExperience; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelRequirement; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -17,86 +13,70 @@ import java.util.List; import java.util.Map; -public class GUILevelPrefixRewards extends HypixelInventoryGUI { +public class GUILevelPrefixRewards extends StatelessView { private static final int[] SLOTS = new int[]{ 19, 20, 21, 22, 23, 24, 25, - 29, 30, 31, 32, 33 + 29, 30, 31, 32, 33 }; - public GUILevelPrefixRewards() { - super("Prefix Rewards", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Prefix Rewards", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(GUIClickableItem.getGoBackItem(48, new GUILevelRewards())); - - DatapointSkyBlockExperience.PlayerSkyBlockExperience experience = ((SkyBlockPlayer) getPlayer()).getSkyBlockExperience(); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add("§7New colors for your level prefix"); - lore.add("§7shown in TAB and in chat!"); - lore.add(" "); - lore.add("§7Next Reward:"); - - Map.Entry nextPrefix = experience.getLevel().getNextPrefixChange(); - if (nextPrefix == null) { - lore.add("§cNo more rewards!"); - } else { - lore.add(nextPrefix.getValue() + nextPrefix.getKey().getPrefixDisplay()); - lore.add("§8at Level " + nextPrefix.getKey().asInt()); - } - lore.add(" "); - lore.addAll(GUILevelRewards.getAsDisplay( - player.getSkyBlockExperience().getLevel().getPreviousPrefixChanges().size(), - SkyBlockLevelRequirement.getAllPrefixChanges().size() - )); - - return ItemStackCreator.getStack("§aPrefix Color Rewards", - Material.GRAY_DYE, 1, lore); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + DatapointSkyBlockExperience.PlayerSkyBlockExperience experience = player.getSkyBlockExperience(); + List lore = new ArrayList<>(); + lore.add("§7New colors for your level prefix"); + lore.add("§7shown in TAB and in chat!"); + lore.add(" "); + lore.add("§7Next Reward:"); + + Map.Entry nextPrefix = experience.getLevel().getNextPrefixChange(); + if (nextPrefix == null) { + lore.add("§cNo more rewards!"); + } else { + lore.add(nextPrefix.getValue() + nextPrefix.getKey().getPrefixDisplay()); + lore.add("§8at Level " + nextPrefix.getKey().asInt()); } + lore.add(" "); + lore.addAll(GUILevelRewards.getAsDisplay( + player.getSkyBlockExperience().getLevel().getPreviousPrefixChanges().size(), + SkyBlockLevelRequirement.getAllPrefixChanges().size() + )); + + return ItemStackCreator.getStack("§aPrefix Color Rewards", Material.GRAY_DYE, 1, lore); }); + // Prefix items int index = 0; for (Map.Entry entry : SkyBlockLevelRequirement.getAllPrefixChanges().entrySet()) { + if (index >= SLOTS.length) break; SkyBlockLevelRequirement level = entry.getKey(); int slot = SLOTS[index]; - boolean unlocked = experience.getLevel().asInt() >= level.asInt(); - - set(new GUIItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack(level.getPrefix() + level.getPrefixDisplay(), - level.getPrefixItem(), 1, - "§8Level " + level.asInt(), - " ", - "§7Preview: " + player.getFullDisplayName(level.getPrefix()), - " ", - (unlocked ? "§aYou have unlocked this reward!" : "§7Levels left to unlock: §3" + (level.asInt() - experience.getLevel().asInt()))); - } + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + boolean unlocked = player.getSkyBlockExperience().getLevel().asInt() >= level.asInt(); + + return ItemStackCreator.getStack(level.getPrefix() + level.getPrefixDisplay(), + level.getPrefixItem(), 1, + "§8Level " + level.asInt(), + " ", + "§7Preview: " + player.getFullDisplayName(level.getPrefix()), + " ", + (unlocked ? "§aYou have unlocked this reward!" : "§7Levels left to unlock: §3" + (level.asInt() - player.getSkyBlockExperience().getLevel().asInt()))); }); index++; } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelRewards.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelRewards.java index 073cbc24d..46b1878b0 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelRewards.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/rewards/GUILevelRewards.java @@ -1,16 +1,11 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.rewards; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointSkyBlockExperience; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.GUISkyBlockLevels; import net.swofty.type.skyblockgeneric.levels.CustomLevelAward; import net.swofty.type.skyblockgeneric.levels.SkyBlockEmblems; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelRequirement; @@ -21,160 +16,128 @@ import java.util.List; import java.util.Map; -public class GUILevelRewards extends HypixelInventoryGUI { - public GUILevelRewards() { - super("Leveling Rewards", InventoryType.CHEST_4_ROW); +public class GUILevelRewards extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Leveling Rewards", InventoryType.CHEST_4_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(31)); - set(GUIClickableItem.getGoBackItem(30, new GUISkyBlockLevels())); - - DatapointSkyBlockExperience.PlayerSkyBlockExperience experience = ((SkyBlockPlayer) getPlayer()).getSkyBlockExperience(); - - set(new GUIClickableItem(11) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUILevelFeatureRewards().open(player); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 31); + Components.back(layout, 30, ctx); + + // Feature Rewards + layout.slot(11, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + DatapointSkyBlockExperience.PlayerSkyBlockExperience experience = player.getSkyBlockExperience(); + List lore = new ArrayList<>(); + lore.add("§7Specific game features such as the"); + lore.add("§7Bazaar or Community Shop."); + lore.add(" "); + lore.add("§7Next Reward:"); + + Map.Entry> nextAward = CustomLevelAward.getNextReward(experience.getLevel().asInt()); + if (nextAward == null) { + lore.add("§cNo more rewards!"); + } else { + nextAward.getValue().forEach(award -> lore.add("§7" + award.getDisplay())); + lore.add("§8at Level " + nextAward.getKey()); } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add("§7Specific game features such as the"); - lore.add("§7Bazaar or Community Shop."); - lore.add(" "); - lore.add("§7Next Reward:"); - - Map.Entry> nextAward = CustomLevelAward.getNextReward( - experience.getLevel().asInt() - ); - if (nextAward == null) { - lore.add("§cNo more rewards!"); - } else { - nextAward.getValue().forEach(award -> { - lore.add("§7" + award.getDisplay()); - }); - lore.add("§8at Level " + nextAward.getKey()); - } - - lore.add(" "); - lore.addAll(getAsDisplay(CustomLevelAward.getFromLevel(experience.getLevel().asInt()).size(), - CustomLevelAward.getTotalLevelAwards())); - lore.add(" "); - lore.add("§eClick to view!"); - - return ItemStackCreator.getStack("§aFeature Rewards", - Material.NETHER_STAR, 1, lore); + lore.add(" "); + lore.addAll(getAsDisplay(CustomLevelAward.getFromLevel(experience.getLevel().asInt()).size(), + CustomLevelAward.getTotalLevelAwards())); + lore.add(" "); + lore.add("§eClick to view!"); + + return ItemStackCreator.getStack("§aFeature Rewards", Material.NETHER_STAR, 1, lore); + }, (click, c) -> c.player().openView(new GUILevelFeatureRewards())); + + // Prefix Color Rewards + layout.slot(12, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(); + lore.add("§7New colors for your level prefix"); + lore.add("§7shown in TAB and in chat!"); + lore.add(" "); + lore.add("§7Next Reward:"); + + Map.Entry nextPrefix = player.getSkyBlockExperience() + .getLevel().getNextPrefixChange(); + if (nextPrefix == null) { + lore.add("§cNo more rewards!"); + } else { + lore.add(nextPrefix.getValue() + nextPrefix.getKey().getPrefixDisplay()); + lore.add("§8at Level " + nextPrefix.getKey().asInt()); } - }); - set(new GUIClickableItem(12) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUILevelPrefixRewards().open(player); + lore.add(" "); + lore.addAll(getAsDisplay( + player.getSkyBlockExperience().getLevel().getPreviousPrefixChanges().size(), + SkyBlockLevelRequirement.getAllPrefixChanges().size() + )); + lore.add(" "); + lore.add("§eClick to view!"); + + return ItemStackCreator.getStack("§aPrefix Color Rewards", Material.GRAY_DYE, 1, lore); + }, (click, c) -> c.player().openView(new GUILevelPrefixRewards())); + + // Emblem Rewards + layout.slot(13, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(); + lore.add("§7Emblems to show next to your name"); + lore.add("§7that signify special achievements."); + lore.add(" "); + lore.add("§7Next Reward:"); + + List levelEmblems = SkyBlockEmblems.getEmblemsWithLevelCause(); + SkyBlockEmblems.SkyBlockEmblem nextEmblem = null; + for (SkyBlockEmblems.SkyBlockEmblem emblem : levelEmblems) { + if (player.getSkyBlockExperience().hasExperienceFor(emblem.cause())) continue; + nextEmblem = emblem; + break; } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add("§7New colors for your level prefix"); - lore.add("§7shown in TAB and in chat!"); - lore.add(" "); - lore.add("§7Next Reward:"); - - Map.Entry nextPrefix = player.getSkyBlockExperience() - .getLevel().getNextPrefixChange(); - if (nextPrefix == null) { - lore.add("§cNo more rewards!"); - } else { - lore.add(nextPrefix.getValue() + nextPrefix.getKey().getPrefixDisplay()); - lore.add("§8at Level " + nextPrefix.getKey().asInt()); - } - lore.add(" "); - lore.addAll(getAsDisplay( - player.getSkyBlockExperience().getLevel().getPreviousPrefixChanges().size(), - SkyBlockLevelRequirement.getAllPrefixChanges().size() - )); - lore.add(" "); - lore.add("§eClick to view!"); - - return ItemStackCreator.getStack("§aPrefix Color Rewards", - Material.GRAY_DYE, 1, lore); - } - }); - set(new GUIClickableItem(13) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUILevelEmblemRewards().open(player); + if (nextEmblem == null) { + lore.add("§cNo more rewards!"); + } else { + lore.add("§f" + nextEmblem.displayName() + " " + nextEmblem.emblem()); + lore.add("§8at Level " + ((LevelCause) nextEmblem.cause()).getLevel()); } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(); - lore.add("§7Emblems to show next to your name"); - lore.add("§7that signify special achievements."); - lore.add(" "); - lore.add("§7Next Reward:"); - - List levelEmblems = SkyBlockEmblems.getEmblemsWithLevelCause(); - SkyBlockEmblems.SkyBlockEmblem nextEmblem = null; - for (SkyBlockEmblems.SkyBlockEmblem emblem : levelEmblems) { - if (player.getSkyBlockExperience().hasExperienceFor(emblem.cause())) continue; - nextEmblem = emblem; - break; - } - - if (nextEmblem == null) { - lore.add("§cNo more rewards!"); - } else { - lore.add("§f" + nextEmblem.displayName() + " " + nextEmblem.emblem()); - lore.add("§8at Level " + ((LevelCause) nextEmblem.cause()).getLevel()); - } - - lore.add(" "); - lore.addAll(getAsDisplay( - player.getSkyBlockExperience().getOfType(LevelCause.class).size(), - levelEmblems.size() - )); - lore.add(" "); - lore.add("§eClick to view!"); - - return ItemStackCreator.getStack("§aEmblem Rewards", - Material.NAME_TAG, 1, lore); - } - }); - set(new GUIItem(14) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockLevelRequirement nextLevel = player.getSkyBlockExperience().getLevel().getNextLevel(); - - return ItemStackCreator.getStack("§aStatistic Rewards", - Material.DIAMOND_HELMET, 1, - "§7Statistic bonuses that will power you", - "§7up as you level up.", - " ", - "§7Next Reward:", - "§8+§a5 §cHealth", - "§8at Level " + (nextLevel == null ? "§cMAX" : nextLevel.asInt()), - " ", - "§7For every level:", - "§8+§a5 §cHealth", - " ", - "§7For every 5 levels:", - "§8+§a1 §cStrength"); - } + lore.add(" "); + lore.addAll(getAsDisplay( + player.getSkyBlockExperience().getOfType(LevelCause.class).size(), + levelEmblems.size() + )); + lore.add(" "); + lore.add("§eClick to view!"); + + return ItemStackCreator.getStack("§aEmblem Rewards", Material.NAME_TAG, 1, lore); + }, (click, c) -> c.player().openView(new GUILevelEmblemRewards())); + + // Statistic Rewards + layout.slot(14, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockLevelRequirement nextLevel = player.getSkyBlockExperience().getLevel().getNextLevel(); + + return ItemStackCreator.getStack("§aStatistic Rewards", Material.DIAMOND_HELMET, 1, + "§7Statistic bonuses that will power you", + "§7up as you level up.", + " ", + "§7Next Reward:", + "§8+§a5 §cHealth", + "§8at Level " + (nextLevel == null ? "§cMAX" : nextLevel.asInt()), + " ", + "§7For every level:", + "§8+§a5 §cHealth", + " ", + "§7For every 5 levels:", + "§8+§a1 §cStrength"); }); - - updateItemStacks(getInventory(), getPlayer()); } public static int getTotalAwards() { @@ -204,23 +167,13 @@ public static List getAsDisplay(int unlocked, int total) { int completedLength = (int) ((unlocked / (double) total) * maxBarLength); String completedLoadingBar = "§b§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); - int formattingCodeLength = 4; // Adjust this if you add or remove formatting codes + int formattingCodeLength = 4; String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( - completedLoadingBar.length() - formattingCodeLength, // Adjust for added formatting codes + completedLoadingBar.length() - formattingCodeLength, maxBarLength )); toReturn.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + unlocked + "§6/§e" + total); return toReturn; } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/starter/GUIStarterAccessories.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/starter/GUIStarterAccessories.java index eedd45983..4fba7b9a1 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/starter/GUIStarterAccessories.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/starter/GUIStarterAccessories.java @@ -1,31 +1,32 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.starter; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.levels.SkyBlockLevelCause; import net.swofty.type.skyblockgeneric.levels.causes.NewAccessoryLevelCause; import java.util.List; import java.util.stream.Stream; -public class GUIStarterAccessories extends HypixelInventoryGUI { - private List causes; +public class GUIStarterAccessories extends StatelessView { + private final List causes; public GUIStarterAccessories(ItemType... causes) { - super("Starter -> Accessories", InventoryType.CHEST_6_ROW); - this.causes = Stream.of(causes).map(SkyBlockLevelCause::getAccessoryCause).toList(); } @Override - public boolean allowHotkeying() { - return false; + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Starter -> Accessories", InventoryType.CHEST_6_ROW); } @Override - public void onBottomClick(InventoryPreClickEvent e) { - + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + // TODO: Add accessory-related content using causes } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/starter/GUIStarterSkills.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/starter/GUIStarterSkills.java index f0768ac50..cc9a9eee5 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/starter/GUIStarterSkills.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/starter/GUIStarterSkills.java @@ -1,21 +1,20 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.starter; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; -public class GUIStarterSkills extends HypixelInventoryGUI { - public GUIStarterSkills() { - super("Starter -> Skills", InventoryType.CHEST_6_ROW); - } +public class GUIStarterSkills extends StatelessView { @Override - public boolean allowHotkeying() { - return false; + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Starter -> Skills", InventoryType.CHEST_6_ROW); } @Override - public void onBottomClick(InventoryPreClickEvent e) { - + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileCreate.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileCreate.java index 9fcecf658..a506ba65f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileCreate.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileCreate.java @@ -1,11 +1,7 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.profiles; import lombok.SneakyThrows; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.ServerType; import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; @@ -13,10 +9,9 @@ import net.swofty.type.generic.data.mongodb.ProfilesDatabase; import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.actions.data.ActionPlayerDataSave; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointUUID; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -24,22 +19,22 @@ import java.util.UUID; -public class GUIProfileCreate extends HypixelInventoryGUI { - public GUIProfileCreate() { - super("Create a Profile", InventoryType.CHEST_3_ROW); +public class GUIProfileCreate extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Create a Profile", InventoryType.CHEST_3_ROW); } @SneakyThrows @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + String profileName = SkyBlockPlayerProfiles.getRandomName(); - set(new GUIClickableItem(11) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aCreate New Profile", Material.GREEN_TERRACOTTA, 1, + // Create New Profile + layout.slot(11, (s, c) -> ItemStackCreator.getStack("§aCreate New Profile", Material.GREEN_TERRACOTTA, 1, "§7You are creating a new SkyBlock", "§7profile.", "", @@ -50,71 +45,34 @@ public ItemStack.Builder getItem(HypixelPlayer p) { "", "§bYou are creating a SOLO profile!", "§bUse /coop to play with friends!", - "§eClick to confirm new profile!"); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockPlayerProfiles profiles = player.getProfiles(); - UUID profileId = UUID.randomUUID(); - - // Create new SkyBlock data handler with the profile ID - SkyBlockDataHandler handler = SkyBlockDataHandler.initUserWithDefaultData(player.getUuid(), profileId); - handler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).setValue(profileName); - handler.get(SkyBlockDataHandler.Data.ISLAND_UUID, DatapointUUID.class).setValue(profileId); - - // Convert to document for saving - Document document = handler.toProfileDocument(); - - profiles.addProfile(profileId); - ProfilesDatabase.collection.insertOne(document); - - player.getHookManager().registerHook(ActionPlayerDataSave.class, (nil) -> { - profiles.setCurrentlySelected(profileId); - - UserDatabase database = new UserDatabase(player.getUuid()); - database.saveProfiles(profiles); - }, false); - - player.sendTo(ServerType.SKYBLOCK_ISLAND, true); - } - }); - - set(new GUIClickableItem(15) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.createNamedItemStack(Material.RED_TERRACOTTA, "§cCancel"); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIProfileSelectMode().open(player); - } - }); - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + "§eClick to confirm new profile!"), + (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockPlayerProfiles profiles = player.getProfiles(); + UUID profileId = UUID.randomUUID(); + + // Create new SkyBlock data handler with the profile ID + SkyBlockDataHandler handler = SkyBlockDataHandler.initUserWithDefaultData(player.getUuid(), profileId); + handler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).setValue(profileName); + handler.get(SkyBlockDataHandler.Data.ISLAND_UUID, DatapointUUID.class).setValue(profileId); + + // Convert to document for saving + Document document = handler.toProfileDocument(); + + profiles.addProfile(profileId); + ProfilesDatabase.collection.insertOne(document); + + player.getHookManager().registerHook(ActionPlayerDataSave.class, (nil) -> { + profiles.setCurrentlySelected(profileId); + UserDatabase database = new UserDatabase(player.getUuid()); + database.saveProfiles(profiles); + }, false); + + player.sendTo(ServerType.SKYBLOCK_ISLAND, true); + }); + + // Cancel + layout.slot(15, (s, c) -> ItemStackCreator.createNamedItemStack(Material.RED_TERRACOTTA, "§cCancel"), + (click, c) -> c.player().openView(new GUIProfileSelectMode())); } } \ No newline at end of file diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileManagement.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileManagement.java index 4add6194a..dbaec8eb8 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileManagement.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileManagement.java @@ -1,11 +1,7 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.profiles; import lombok.SneakyThrows; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; import net.swofty.commons.StringUtility; @@ -14,13 +10,11 @@ import net.swofty.type.generic.data.datapoints.DatapointString; import net.swofty.type.generic.data.mongodb.ProfilesDatabase; import net.swofty.type.generic.data.datapoints.DatapointLong; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.monogdb.CoopDatabase; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -29,32 +23,22 @@ import java.util.List; import java.util.UUID; -public class GUIProfileManagement extends HypixelInventoryGUI { - private static final int[] PROFILE_SLOTS = { - 11, 12, 13, 14, 15 - }; +public class GUIProfileManagement extends StatelessView { + private static final int[] PROFILE_SLOTS = {11, 12, 13, 14, 15}; - public GUIProfileManagement() { - super("Profile Management", InventoryType.CHEST_4_ROW); - - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(31)); - set(new GUIClickableItem(30) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Profile Management", InventoryType.CHEST_4_ROW); } @SneakyThrows @Override - public void onOpen(InventoryGUIOpenEvent e) { - SkyBlockPlayer player = (SkyBlockPlayer) e.player(); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 31); + Components.back(layout, 30, ctx); + + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); SkyBlockPlayerProfiles profiles = player.getProfiles(); List profileIds = profiles.getProfiles(); @@ -62,12 +46,8 @@ public void onOpen(InventoryGUIOpenEvent e) { int slot = PROFILE_SLOTS[profileCount]; if (profileIds.size() <= profileCount) { - set(new GUIClickableItem(slot) { - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§eEmpty Profile Slot", Material.OAK_BUTTON, 1, + // Empty profile slot + layout.slot(slot, (s, c) -> ItemStackCreator.getStack("§eEmpty Profile Slot", Material.OAK_BUTTON, 1, "§8Available", " ", "§7Use this slot if you want to", @@ -86,16 +66,8 @@ public ItemStack.Builder getItem(HypixelPlayer p) { "§cbe considered abusive and", "§cpunished.", " ", - "§eClick to create solo profile!" - ); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIProfileSelectMode().open(player); - } - }); + "§eClick to create solo profile!"), + (click, c) -> c.player().openView(new GUIProfileSelectMode())); continue; } @@ -104,10 +76,8 @@ public void run(InventoryPreClickEvent e, HypixelPlayer p) { SkyBlockDataHandler dataHandler; if (selected) { - // Use the cached handler for the current profile dataHandler = SkyBlockDataHandler.getUser(player.getUuid()); } else { - // Load the other profile's data temporarily (not cached) try { ProfilesDatabase profileDb = new ProfilesDatabase(profileId.toString()); dataHandler = SkyBlockDataHandler.createFromProfileOnly(profileDb.getDocument()); @@ -116,84 +86,37 @@ public void run(InventoryPreClickEvent e, HypixelPlayer p) { } } + SkyBlockDataHandler finalDataHandler = dataHandler; + if (selected) { - SkyBlockDataHandler finalDataHandler = dataHandler; - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - String profileName = finalDataHandler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(); - player.sendMessage("§aYep! §e" + profileName + "§a is the profile you are playing on!"); - player.sendMessage("§cIf you want to delete this profile, switch to another one first!"); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - List lore = new ArrayList<>(Arrays.asList("§8Selected slot", " ")); - - updateLore(player.getUuid(), finalDataHandler, lore); - - lore.add(" "); - lore.add("§aYou are playing on this profile!"); - - String profileName = finalDataHandler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(); - return ItemStackCreator.getStack( - "§eProfile: §a" + profileName, - Material.EMERALD_BLOCK, 1, - lore); - } + layout.slot(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + List lore = new ArrayList<>(Arrays.asList("§8Selected slot", " ")); + updateLore(p.getUuid(), finalDataHandler, lore); + lore.add(" "); + lore.add("§aYou are playing on this profile!"); + + String profileName = finalDataHandler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(); + return ItemStackCreator.getStack("§eProfile: §a" + profileName, Material.EMERALD_BLOCK, 1, lore); + }, (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + String profileName = finalDataHandler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(); + p.sendMessage("§aYep! §e" + profileName + "§a is the profile you are playing on!"); + p.sendMessage("§cIf you want to delete this profile, switch to another one first!"); }); - continue; - } - - SkyBlockDataHandler finalDataHandler1 = dataHandler; - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIProfileSelect(profileId).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; + } else { + layout.slot(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); List lore = new ArrayList<>(Arrays.asList("§8Slot in use", " ")); - - updateLore(player.getUuid(), finalDataHandler1, lore); - + updateLore(p.getUuid(), finalDataHandler, lore); lore.add(" "); lore.add("§eClick to manage!"); - String profileName = finalDataHandler1.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(); - return ItemStackCreator.getStack( - "§eProfile: §a" + profileName, - Material.GRASS_BLOCK, 1, - lore); - } - }); + String profileName = finalDataHandler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(); + return ItemStackCreator.getStack("§eProfile: §a" + profileName, Material.GRASS_BLOCK, 1, lore); + }, (click, c) -> c.player().openView(new GUIProfileSelect(profileId))); + } } - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); } public static List updateLore(UUID playerUuid, SkyBlockDataHandler handler, List lore) { @@ -201,13 +124,8 @@ public static List updateLore(UUID playerUuid, SkyBlockDataHandler handl lore.add("§bCo-op:"); CoopDatabase.Coop coop = CoopDatabase.getFromMember(playerUuid); - coop.members().forEach(member -> { - lore.add("§7Member " + SkyBlockPlayer.getDisplayName(member)); - }); - coop.memberInvites().forEach(invite -> { - lore.add("§7Invited " + SkyBlockPlayer.getDisplayName(invite)); - }); - + coop.members().forEach(member -> lore.add("§7Member " + SkyBlockPlayer.getDisplayName(member))); + coop.memberInvites().forEach(invite -> lore.add("§7Invited " + SkyBlockPlayer.getDisplayName(invite))); lore.add(" "); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileSelect.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileSelect.java index cee86eaac..544cbe545 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileSelect.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileSelect.java @@ -1,12 +1,7 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.profiles; import com.mongodb.client.model.Filters; -import lombok.SneakyThrows; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.ServerType; import net.swofty.commons.skyblock.SkyBlockPlayerProfiles; @@ -14,123 +9,99 @@ import net.swofty.type.generic.data.mongodb.ProfilesDatabase; import net.swofty.type.generic.data.mongodb.UserDatabase; import net.swofty.type.generic.event.actions.data.ActionPlayerDataSave; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.monogdb.CoopDatabase; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.util.UUID; -public class GUIProfileSelect extends HypixelInventoryGUI { +public class GUIProfileSelect extends StatelessView { private final UUID profileUuid; public GUIProfileSelect(UUID profileUuid) { - super("Profile Management", InventoryType.CHEST_4_ROW); - this.profileUuid = profileUuid; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(31, new GUIProfileManagement())); - - set(new GUIClickableItem(11) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockPlayerProfiles profiles = player.getProfiles(); - SkyBlockPlayerProfiles toSet = new SkyBlockPlayerProfiles(); - toSet.setProfiles(profiles.getProfiles()); - - player.getHookManager().registerHook(ActionPlayerDataSave.class, (nil) -> { - UserDatabase database = new UserDatabase(player.getUuid()); - toSet.setCurrentlySelected(profileUuid); - database.saveProfiles(toSet); - }, false); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Profile Management", InventoryType.CHEST_4_ROW); + } - player.sendTo(ServerType.SKYBLOCK_ISLAND, true); + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.back(layout, 31, ctx); + + // Switch to Profile + layout.slot(11, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + String currentProfile = player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(); + String switchingTo; + try { + switchingTo = SkyBlockDataHandler.createFromProfileOnly(new ProfilesDatabase(profileUuid.toString()).getDocument()) + .get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(); + } catch (Exception e) { + switchingTo = "Unknown"; } - @SneakyThrows - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aSwitch to Profile", Material.GRASS_BLOCK, 1, - "§7Teleports you to your island on", - "§7another profile and loads your", - "§7inventory, skills, collections", - "§7and more...", - "", - "§7Current: §e" + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(), - "§7Switching to: §a" + SkyBlockDataHandler.createFromProfileOnly(new ProfilesDatabase(profileUuid.toString()).getDocument()) - .get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue(), - "", "§eClick to switch"); - } + return ItemStackCreator.getStack("§aSwitch to Profile", Material.GRASS_BLOCK, 1, + "§7Teleports you to your island on", + "§7another profile and loads your", + "§7inventory, skills, collections", + "§7and more...", + "", + "§7Current: §e" + currentProfile, + "§7Switching to: §a" + switchingTo, + "", "§eClick to switch"); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + SkyBlockPlayerProfiles profiles = player.getProfiles(); + SkyBlockPlayerProfiles toSet = new SkyBlockPlayerProfiles(); + toSet.setProfiles(profiles.getProfiles()); + + player.getHookManager().registerHook(ActionPlayerDataSave.class, (nil) -> { + UserDatabase database = new UserDatabase(player.getUuid()); + toSet.setCurrentlySelected(profileUuid); + database.saveProfiles(toSet); + }, false); + + player.sendTo(ServerType.SKYBLOCK_ISLAND, true); }); - set(new GUIClickableItem(15) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§cDelete profile", Material.RED_STAINED_GLASS, 1, + // Delete Profile + layout.slot(15, (s, c) -> ItemStackCreator.getStack("§cDelete profile", Material.RED_STAINED_GLASS, 1, "§7Clear this profile slot by", "§7deleting the profile forever.", "", "§cWarning!", "§fYou cannot revert this actions!", "", - "§eClick to continue!"); - } - - @SneakyThrows - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (CoopDatabase.getFromMemberProfile(profileUuid) != null) { - player.sendMessage("§cYou cannot delete a profile that is in a coop!"); - player.sendMessage("§eInstead run §a/coopleave §eto leave your coop."); - return; - } - - SkyBlockPlayerProfiles profiles = player.getProfiles(); - profiles.removeProfile(profileUuid); - - SkyBlockDataHandler handler = SkyBlockDataHandler.createFromProfileOnly(new ProfilesDatabase(profileUuid.toString()).getDocument()); - - player.sendMessage( - "§aDone! Your §e" + "§eClick to continue!"), + (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (CoopDatabase.getFromMemberProfile(profileUuid) != null) { + player.sendMessage("§cYou cannot delete a profile that is in a coop!"); + player.sendMessage("§eInstead run §a/coopleave §eto leave your coop."); + return; + } + + SkyBlockPlayerProfiles profiles = player.getProfiles(); + profiles.removeProfile(profileUuid); + + try { + SkyBlockDataHandler handler = SkyBlockDataHandler.createFromProfileOnly(new ProfilesDatabase(profileUuid.toString()).getDocument()); + player.sendMessage("§aDone! Your §e" + handler.get(SkyBlockDataHandler.Data.PROFILE_NAME, DatapointString.class).getValue() + " §aprofile was deleted!"); + } catch (Exception e) { + player.sendMessage("§aDone! Your profile was deleted!"); + } - ProfilesDatabase.collection.deleteOne(Filters.eq("_id", profileUuid.toString())); - - new GUIProfileManagement().open(player); - } - }); - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - + ProfilesDatabase.collection.deleteOne(Filters.eq("_id", profileUuid.toString())); + player.openView(new GUIProfileManagement()); + }); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileSelectMode.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileSelectMode.java index 17a1b05ba..67dde351a 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileSelectMode.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/profiles/GUIProfileSelectMode.java @@ -1,34 +1,26 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.profiles; -import lombok.SneakyThrows; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -public class GUIProfileSelectMode extends HypixelInventoryGUI { - public GUIProfileSelectMode() { - super("Choose a SkyBlock Mode", InventoryType.CHEST_4_ROW); +public class GUIProfileSelectMode extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Choose a SkyBlock Mode", InventoryType.CHEST_4_ROW); } - @SneakyThrows @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getGoBackItem(31, new GUIProfileManagement())); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.back(layout, 31, ctx); - set(new GUIClickableItem(11) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aClassic Profile", Material.GRASS_BLOCK, 1, + // Classic Profile + layout.slot(11, (s, c) -> ItemStackCreator.getStack("§aClassic Profile", Material.GRASS_BLOCK, 1, "§8SkyBlock Mode", "", "§7A SkyBlock adventure with the", @@ -40,57 +32,16 @@ public ItemStack.Builder getItem(HypixelPlayer p) { "§agreatest player§7 in the", "§7universe!", "", - "§eClick to play this mode!" - ); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIProfileCreate().open(player); - } - }); + "§eClick to play this mode!"), + (click, c) -> c.player().openView(new GUIProfileCreate())); - set(new GUIClickableItem(15) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§6Special Modes", Material.BLAZE_POWDER, 1, + // Special Modes + layout.slot(15, (s, c) -> ItemStackCreator.getStack("§6Special Modes", Material.BLAZE_POWDER, 1, "§7Choose a SkyBlock mode with", "§7special rules and unique", "§7mechanics.", "", - "§eClick to choose a mode!" - ); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.sendMessage("§cSpecial Modes in SkyBlock are currently unavailable. Please check back another time."); - } - }); - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + "§eClick to choose a mode!"), + (click, c) -> c.player().sendMessage("§cSpecial Modes in SkyBlock are currently unavailable. Please check back another time.")); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java index 96885b292..4e1b508dc 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java @@ -75,9 +75,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7working towards.", "§7 ", "§eClick to view!"), - (click, c) -> { - //new GUIMissionLog(false).open((SkyBlockPlayer) c.player()) - }); + (click, c) -> c.replace(new GUIMissionLog(false))); } else { layout.slot(50, (s, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); @@ -89,9 +87,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7Completed: §a" + player.getMissionData().getCompletedMissions().size(), "§7 ", "§eClick to view!"); - }, (click, c) -> { - //new GUIMissionLog(true).open((SkyBlockPlayer) c.player()) - }); + }, (click, c) -> c.replace(new GUIMissionLog(true))); } SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java index e5eb51743..1d2fc7281 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java @@ -94,9 +94,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", type.getMaterial(), 1, lore); - }, (click, c) -> { - //new GUIRecipeCategory(type, new GUIRecipeBook()).open((SkyBlockPlayer) c.player()) - }); + }, (click, c) -> c.push(new GUIRecipeCategory(type), GUIRecipeCategory.createInitialState(type))); } // Slayer recipes @@ -148,6 +146,6 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", type.getMaterial(), 1, lore); - }, (click, c) -> new GUIRecipeSlayers().open((SkyBlockPlayer) c.player())); + }, (click, c) -> c.push(new GUIRecipeSlayers())); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java index 2bccbccb9..06829d94f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java @@ -3,21 +3,16 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextDecoration; import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; import net.swofty.type.skyblockgeneric.item.crafting.ShapedRecipe; import net.swofty.type.skyblockgeneric.item.crafting.ShapelessRecipe; import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; @@ -30,66 +25,80 @@ import java.util.List; import java.util.stream.Collectors; -public class GUIRecipeCategory extends HypixelPaginatedGUI { +public class GUIRecipeCategory extends PaginatedView { + + private static final int[] PAGINATED_SLOTS = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; + private final SkyBlockRecipe.RecipeType type; - private final HypixelInventoryGUI previousGUI; - protected GUIRecipeCategory(SkyBlockRecipe.RecipeType type, HypixelInventoryGUI previousGUI) { - super(InventoryType.CHEST_6_ROW); + public GUIRecipeCategory(SkyBlockRecipe.RecipeType type) { this.type = type; - this.previousGUI = previousGUI; } @Override - public boolean allowHotkeying() { - return false; + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> "(" + (state.page() + 1) + "/" + Math.max(1, (int) Math.ceil((double) getFilteredItems(state).size() / PAGINATED_SLOTS.length)) + ") " + StringUtility.toNormalCase(type.name()) + " Recipes", + InventoryType.CHEST_6_ROW + ); } @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - + protected int[] getPaginatedSlots() { + return PAGINATED_SLOTS; } @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { + protected List getFilteredItems(RecipeCategoryState state) { + List recipes = new ArrayList<>(state.items()); + String query = state.query(); - } + if (query != null && !query.isEmpty()) { + recipes = recipes.stream().filter(item -> !shouldFilterFromSearch(query, item)).toList(); + } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + return recipes; } @Override - protected int[] getPaginatedSlots() { - return new int[]{ - 10, 11, 12, 13, 14, 15, 16, - 19, 20, 21, 22, 23, 24, 25, - 28, 29, 30, 31, 32, 33, 34, - 37, 38, 39, 40, 41, 42, 43 - }; + protected ItemStack.Builder renderItem(SkyBlockRecipe item, int index, HypixelPlayer player) { + SkyBlockRecipe.CraftingResult result = (SkyBlockRecipe.CraftingResult) item.getCanCraft().apply(player); + ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate( + (SkyBlockPlayer) player, item.getResult().getItemStack() + ); + + if (result.allowed()) { + ArrayList lore = new ArrayList<>( + itemStack.build().get(DataComponents.LORE).stream().map(StringUtility::getTextFromComponent).toList() + ); + lore.add("§e "); + lore.add("§eClick to view recipe!"); + + return itemStack.set(DataComponents.LORE, + lore.stream().map(line -> Component.text(line).decoration(TextDecoration.ITALIC, false)) + .collect(Collectors.toList())); + } else { + List lore = Arrays.asList(result.errorMessage()); + lore = lore.stream().map(line -> "§7" + line).toList(); + return ItemStackCreator.getStack("§c???", Material.GRAY_DYE, 1, lore); + } } @Override - protected PaginationList fillPaged(HypixelPlayer player, PaginationList paged) { - paged.addAll(ShapedRecipe.CACHED_RECIPES); - paged.addAll(ShapelessRecipe.CACHED_RECIPES); - - paged.removeIf(recipe -> recipe.getRecipeType() != type); - - List shownItems = new ArrayList<>(); - paged.removeIf(recipe -> { - ItemType type = recipe.getResult().getAttributeHandler().getPotentialType(); - - if (shownItems.contains(type)) { - return true; - } else { - shownItems.add(type); - return false; - } - }); + protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockRecipe item, int index) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockRecipe.CraftingResult result = (SkyBlockRecipe.CraftingResult) item.getCanCraft().apply(player); - return paged; + if (result.allowed()) { + ctx.push(new GUIRecipe(item.getResult().getAttributeHandler().getPotentialType())); + } else { + player.sendMessage("§cYou haven't unlocked that recipe!"); + } } @Override @@ -100,123 +109,114 @@ protected boolean shouldFilterFromSearch(String query, SkyBlockRecipe item) { } @Override - protected void performSearch(HypixelPlayer player, String query, int page, int maxPage) { - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(createSearchItem(this, 50, query)); - set(GUIClickableItem.getGoBackItem(48, previousGUI)); + protected void layoutCustom(ViewLayout layout, RecipeCategoryState state, ViewContext ctx) { + Components.close(layout, 49); + Components.back(layout, 48, ctx); ArrayList allRecipes = new ArrayList<>(); allRecipes.addAll(ShapedRecipe.CACHED_RECIPES); allRecipes.addAll(ShapelessRecipe.CACHED_RECIPES); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - - ArrayList typeRecipes = new ArrayList<>(); - ArrayList allowedRecipes = new ArrayList<>(); - allRecipes.forEach(recipe -> { - if (recipe.getRecipeType() == type) { - typeRecipes.add(recipe); - } - }); - - ArrayList lore = new ArrayList<>(Arrays.asList( - "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", - "§7that you have unlocked!", " ")); - - typeRecipes.forEach(recipe -> { - SkyBlockRecipe.CraftingResult result = - (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); - - if (result.allowed()) { - allowedRecipes.add(recipe); - } - }); - - String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); - lore.add("§7Recipes Unlocked: §e" + unlockedPercentage + "§6%"); - - String baseLoadingBar = "─────────────────"; - int maxBarLength = baseLoadingBar.length(); - int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); - - String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); - int formattingCodeLength = 4; // Adjust this if you add or remove formatting codes - String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( - completedLoadingBar.length() - formattingCodeLength, // Adjust for added formatting codes - maxBarLength - )); - - lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); - - return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", - type.getMaterial(), 1, lore); - } + + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + + ArrayList typeRecipes = new ArrayList<>(); + ArrayList allowedRecipes = new ArrayList<>(); + allRecipes.forEach(recipe -> { + if (recipe.getRecipeType() == type) { + typeRecipes.add(recipe); + } + }); + + ArrayList lore = new ArrayList<>(Arrays.asList( + "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", + "§7that you have unlocked!", " ")); + + typeRecipes.forEach(recipe -> { + SkyBlockRecipe.CraftingResult result = + (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); + + if (result.allowed()) { + allowedRecipes.add(recipe); + } + }); + + String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); + lore.add("§7Recipes Unlocked: §e" + unlockedPercentage + "§6%"); + + String baseLoadingBar = "─────────────────"; + int maxBarLength = baseLoadingBar.length(); + int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); + + String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); + int formattingCodeLength = 4; + String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( + completedLoadingBar.length() - formattingCodeLength, + maxBarLength + )); + + lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); + + return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", + type.getMaterial(), 1, lore); }); + } - if (page > 1) { - set(createNavigationButton(this, 45, query, page, false)); - } - if (page < maxPage) { - set(createNavigationButton(this, 53, query, page, true)); - } + @Override + protected int getPreviousPageSlot() { + return 45; } @Override - protected String getTitle(HypixelPlayer player, String query, int page, PaginationList paged) { - return "(" + page + "/" + paged.getPages().size() + ") " + StringUtility.toNormalCase(type.name()) + " Recipes"; + protected int getNextPageSlot() { + return 53; } @Override - protected GUIClickableItem createItemFor(SkyBlockRecipe item, int slot, HypixelPlayer player) { - SkyBlockRecipe.CraftingResult result = (SkyBlockRecipe.CraftingResult) item.getCanCraft().apply(player); - ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate( - (SkyBlockPlayer) player, item.getResult().getItemStack() - ); + protected int getSearchSlot() { + return 50; + } - if (result.allowed()) { - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - //new GUIRecipe( - // item.getResult().getAttributeHandler().getPotentialType(), - // GUIRecipeCategory.this).open(player); - } + public static RecipeCategoryState createInitialState(SkyBlockRecipe.RecipeType type) { + List recipes = new ArrayList<>(); + recipes.addAll(ShapedRecipe.CACHED_RECIPES); + recipes.addAll(ShapelessRecipe.CACHED_RECIPES); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - ArrayList lore = new ArrayList<>( - itemStack.build().get(DataComponents.LORE).stream().map(StringUtility::getTextFromComponent).toList() - ); + recipes.removeIf(recipe -> recipe.getRecipeType() != type); - lore.add("§e "); - lore.add("§eClick to view recipe!"); + List shownItems = new ArrayList<>(); + recipes.removeIf(recipe -> { + ItemType itemType = recipe.getResult().getAttributeHandler().getPotentialType(); + if (shownItems.contains(itemType)) { + return true; + } else { + shownItems.add(itemType); + return false; + } + }); - return itemStack.set(DataComponents.LORE, - lore.stream().map(line -> Component.text(line).decoration(TextDecoration.ITALIC, false)) - .collect(Collectors.toList())); - } - }; - } else { - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.sendMessage("§cYou haven't unlocked that recipe!"); - } + return new RecipeCategoryState(recipes, 0, ""); + } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - List lore = Arrays.asList(result.errorMessage()); - // Add gray text to the start of each line - lore = lore.stream().map(line -> "§7" + line).toList(); + public record RecipeCategoryState( + List items, + int page, + String query + ) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new RecipeCategoryState(items, page, query); + } - return ItemStackCreator.getStack("§c???", Material.GRAY_DYE, 1, lore); - } - }; + @Override + public PaginatedState withQuery(String query) { + return new RecipeCategoryState(items, 0, query); + } + + @Override + public PaginatedState withItems(List items) { + return new RecipeCategoryState(items, page, query); } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java index 4a27988d1..40cdfab0c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java @@ -1,17 +1,11 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.item.crafting.ShapedRecipe; import net.swofty.type.skyblockgeneric.item.crafting.ShapelessRecipe; import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; @@ -19,161 +13,132 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.List; -public class GUIRecipeSlayers extends HypixelInventoryGUI { - public GUIRecipeSlayers() { - super("Slayer Recipes", InventoryType.CHEST_6_ROW); - } +public class GUIRecipeSlayers extends StatelessView { + + private static final int[] CATEGORY_SLOTS = {20, 21, 22, 23, 24}; - private static final int[] categorySlots = { - 20, 21, 22, 23, 24 - }; + private static final List SLAYER_TYPES = List.of( + SkyBlockRecipe.RecipeType.REVENANT_HORROR, + SkyBlockRecipe.RecipeType.TARANTULA_BROODFATHER, + SkyBlockRecipe.RecipeType.SVEN_PACKMASTER, + SkyBlockRecipe.RecipeType.VOIDGLOOM_SERAPH, + SkyBlockRecipe.RecipeType.INFERNO_DEMONLORD + ); @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - //set(GUIClickableItem.getGoBackItem(48, new GUIRecipeBook())); + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Slayer Recipes", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); ArrayList allRecipes = new ArrayList<>(); allRecipes.addAll(ShapedRecipe.CACHED_RECIPES); allRecipes.addAll(ShapelessRecipe.CACHED_RECIPES); - ArrayList recipeTypes = new ArrayList<>(); - recipeTypes.add(SkyBlockRecipe.RecipeType.REVENANT_HORROR); - recipeTypes.add(SkyBlockRecipe.RecipeType.TARANTULA_BROODFATHER); - recipeTypes.add(SkyBlockRecipe.RecipeType.SVEN_PACKMASTER); - recipeTypes.add(SkyBlockRecipe.RecipeType.VOIDGLOOM_SERAPH); - recipeTypes.add(SkyBlockRecipe.RecipeType.INFERNO_DEMONLORD); - - int index = 0; - for (int slot : categorySlots) { + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); - SkyBlockRecipe.RecipeType type = recipeTypes.get(index++); + SkyBlockRecipe.RecipeType type = SkyBlockRecipe.RecipeType.SLAYER; ArrayList typeRecipes = new ArrayList<>(); ArrayList allowedRecipes = new ArrayList<>(); allRecipes.forEach(recipe -> { - if (recipe.getRecipeType() == type) { + if (SLAYER_TYPES.contains(recipe.getRecipeType())) { typeRecipes.add(recipe); } }); - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRecipeCategory(type, new GUIRecipeSlayers()).open(player); - } + ArrayList lore = new ArrayList<>(Arrays.asList( + "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", + "§7that you have unlocked!", " ")); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(Arrays.asList( - "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", - "§7that you have unlocked!", " ")); - - typeRecipes.forEach(recipe -> { - SkyBlockRecipe.CraftingResult result = - (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); - - if (result.allowed()) { - allowedRecipes.add(recipe); - } - }); - - String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); - lore.add("§7Recipes Unlocked: §e" + unlockedPercentage + "§6%"); - - String baseLoadingBar = "─────────────────"; - int maxBarLength = baseLoadingBar.length(); - int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); - - String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); - int formattingCodeLength = 4; // Adjust this if you add or remove formatting codes - String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( - completedLoadingBar.length() - formattingCodeLength, // Adjust for added formatting codes - maxBarLength - )); - - lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); - lore.add(" "); - lore.add("§eClick to view!"); - - return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", - type.getMaterial(), 1, lore); - } - }); - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - - SkyBlockRecipe.RecipeType type = SkyBlockRecipe.RecipeType.SLAYER; - - ArrayList typeRecipes = new ArrayList<>(); - ArrayList allowedRecipes = new ArrayList<>(); - allRecipes.forEach(recipe -> { - if (recipeTypes.contains(recipe.getRecipeType())) { - typeRecipes.add(recipe); - } - }); - - ArrayList lore = new ArrayList<>(Arrays.asList( - "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", - "§7that you have unlocked!", " ")); - - typeRecipes.forEach(recipe -> { - SkyBlockRecipe.CraftingResult result = - (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); - - if (result.allowed()) { - allowedRecipes.add(recipe); - } - }); - - String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); - lore.add("§7Slayer Recipes Unlocked: §e" + unlockedPercentage + "§6%"); - - String baseLoadingBar = "─────────────────"; - int maxBarLength = baseLoadingBar.length(); - int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); - - String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); - int formattingCodeLength = 4; // Adjust this if you add or remove formatting codes - String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( - completedLoadingBar.length() - formattingCodeLength, // Adjust for added formatting codes - maxBarLength - )); - - lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); - - return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", - type.getMaterial(), 1, lore); + typeRecipes.forEach(recipe -> { + SkyBlockRecipe.CraftingResult result = + (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); + + if (result.allowed()) { + allowedRecipes.add(recipe); } }); - } - updateItemStacks(getInventory(), getPlayer()); - - } - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); + lore.add("§7Slayer Recipes Unlocked: §e" + unlockedPercentage + "§6%"); + + String baseLoadingBar = "─────────────────"; + int maxBarLength = baseLoadingBar.length(); + int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); + + String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); + int formattingCodeLength = 4; + String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( + completedLoadingBar.length() - formattingCodeLength, + maxBarLength + )); + + lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); + + return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", + type.getMaterial(), 1, lore); + }); + + // Category items + for (int i = 0; i < CATEGORY_SLOTS.length && i < SLAYER_TYPES.size(); i++) { + SkyBlockRecipe.RecipeType type = SLAYER_TYPES.get(i); + int slot = CATEGORY_SLOTS[i]; + + layout.slot(slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + + ArrayList typeRecipes = new ArrayList<>(); + ArrayList allowedRecipes = new ArrayList<>(); + allRecipes.forEach(recipe -> { + if (recipe.getRecipeType() == type) { + typeRecipes.add(recipe); + } + }); + + ArrayList lore = new ArrayList<>(Arrays.asList( + "§7View all of the " + StringUtility.toNormalCase(type.name()) + " Recipes", + "§7that you have unlocked!", " ")); + + typeRecipes.forEach(recipe -> { + SkyBlockRecipe.CraftingResult result = + (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); + + if (result.allowed()) { + allowedRecipes.add(recipe); + } + }); + + String unlockedPercentage = String.format("%.2f", (allowedRecipes.size() / (double) typeRecipes.size()) * 100); + lore.add("§7Recipes Unlocked: §e" + unlockedPercentage + "§6%"); + + String baseLoadingBar = "─────────────────"; + int maxBarLength = baseLoadingBar.length(); + int completedLength = (int) ((allowedRecipes.size() / (double) typeRecipes.size()) * maxBarLength); + + String completedLoadingBar = "§2§m" + baseLoadingBar.substring(0, Math.min(completedLength, maxBarLength)); + int formattingCodeLength = 4; + String uncompletedLoadingBar = "§7§m" + baseLoadingBar.substring(Math.min( + completedLoadingBar.length() - formattingCodeLength, + maxBarLength + )); + + lore.add(completedLoadingBar + uncompletedLoadingBar + "§r §e" + allowedRecipes.size() + "§6/§e" + typeRecipes.size()); + lore.add(" "); + lore.add("§eClick to view!"); + + return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", + type.getMaterial(), 1, lore); + }, (click, c) -> c.push(new GUIRecipeCategory(type), GUIRecipeCategory.createInitialState(type))); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkillCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkillCategory.java index 2cd131364..a83b37797 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkillCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkillCategory.java @@ -54,7 +54,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont lore.add(""); lore.add("§eClick to view!"); return ItemStackCreator.getStack("§3Bestiary", Material.WRITTEN_BOOK, 1, lore); - }, (click, c) -> new GUIBestiary().open((SkyBlockPlayer) c.player())); + }, (click, c) -> c.push(new GUIBestiary())); } // Skill info @@ -86,18 +86,14 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont if (rewards.size() > (page + 1) * DISPLAY_SLOTS.length) { layout.slot(50, (s, c) -> ItemStackCreator.getStack("§aNext Page", Material.ARROW, 1, "§7Click to view the next page of rewards."), - (click, c) -> { - //new GUISkillCategory(category, page + 1).open((SkyBlockPlayer) c.player()) - }); + (click, c) -> c.replace(new GUISkillCategory(category, page + 1))); } // Previous page button if (page > 0) { layout.slot(48, (s, c) -> ItemStackCreator.getStack("§aPrevious Page", Material.ARROW, 1, "§7Click to view the previous page of rewards."), - (click, c) -> { - //new GUISkillCategory(category, page - 1).open((SkyBlockPlayer) c.player()) - }); + (click, c) -> c.replace(new GUISkillCategory(category, page - 1))); } // Rewards diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java index 9bd8201bc..4ad26366f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/skills/GUISkills.java @@ -78,7 +78,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont }, (click, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); if (category == SkillCategories.CARPENTRY && !player.getMissionData().hasCompleted("give_wool_to_carpenter")) return; - //new GUISkillCategory(category, 0).open(player); + c.push(new GUISkillCategory(category, 0)); }); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUICombatStats.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUICombatStats.java index 2093227b7..637d9cf3f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUICombatStats.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUICombatStats.java @@ -1,20 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.stats; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.statistics.ItemStatistic; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; import net.swofty.type.generic.gui.inventory.item.GUIMaterial; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockProfile; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.user.statistics.PlayerStatistics; @@ -22,7 +15,7 @@ import java.util.List; import java.util.function.Function; -public class GUICombatStats extends HypixelInventoryGUI { +public class GUICombatStats extends StatelessView { private enum CombatStat { HEALTH(10, ItemStatistic.HEALTH, new GUIMaterial(Material.GOLDEN_APPLE), @@ -282,90 +275,57 @@ private enum CombatStat { public List buildLore(SkyBlockPlayer player) { List lore = new ArrayList<>(baseLoreProvider.apply(player)); - double value = player.getStatistics().allStatistics().getOverall(statistic); if (value == 0D) { lore.add("§8You have none of this stat!"); } lore.add("§eClick to view!"); - return lore; } - - public ItemStack.Builder buildItemStack(SkyBlockPlayer player) { - double value = player.getStatistics().allStatistics().getOverall(statistic); - String title = statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 1); - List lore = buildLore(player); - - return ItemStackCreator.getUsingGUIMaterial(title, guiMaterial, 1, lore); - } } - public GUICombatStats() { - super("Your Stats Breakdown", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Your Stats Breakdown", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - //set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); - set(GUIClickableItem.getCloseItem(49)); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7Gives you a better chance at", "§7fighting strong monsters. ", " ")); - List stats = new ArrayList<>(List.of(ItemStatistic.HEALTH, ItemStatistic.DEFENSE, ItemStatistic.STRENGTH, ItemStatistic.INTELLIGENCE, - ItemStatistic.CRITICAL_CHANCE, ItemStatistic.CRITICAL_DAMAGE, ItemStatistic.BONUS_ATTACK_SPEED, ItemStatistic.ABILITY_DAMAGE, ItemStatistic.TRUE_DEFENSE, - ItemStatistic.FEROCITY, ItemStatistic.HEALTH_REGENERATION, ItemStatistic.VITALITY, ItemStatistic.MENDING, ItemStatistic.SWING_RANGE)); - - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (stats.contains(statistic)) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + Components.back(layout, 48, ctx); + + // Title item + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7Gives you a better chance at", "§7fighting strong monsters. ", " ")); + List stats = new ArrayList<>(List.of(ItemStatistic.HEALTH, ItemStatistic.DEFENSE, ItemStatistic.STRENGTH, ItemStatistic.INTELLIGENCE, + ItemStatistic.CRITICAL_CHANCE, ItemStatistic.CRITICAL_DAMAGE, ItemStatistic.BONUS_ATTACK_SPEED, ItemStatistic.ABILITY_DAMAGE, ItemStatistic.TRUE_DEFENSE, + ItemStatistic.FEROCITY, ItemStatistic.HEALTH_REGENERATION, ItemStatistic.VITALITY, ItemStatistic.MENDING, ItemStatistic.SWING_RANGE)); + + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (stats.contains(statistic)) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); + } + }); - return ItemStackCreator.getStack("§cCombat Stats", Material.DIAMOND_SWORD, 1, lore); - } + return ItemStackCreator.getStack("§cCombat Stats", Material.DIAMOND_SWORD, 1, lore); }); + // Combat stat items for (CombatStat stat : CombatStat.values()) { - set(new GUIClickableItem(stat.slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.sendMessage("§aUnder construction!"); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return stat.buildItemStack((SkyBlockPlayer) p); - } + layout.slot(stat.slot, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + double value = player.getStatistics().allStatistics().getOverall(stat.statistic); + String title = stat.statistic.getFullDisplayName() + " §f" + StringUtility.decimalify(value, 1); + List lore = stat.buildLore(player); + return ItemStackCreator.getUsingGUIMaterial(title, stat.guiMaterial, 1, lore); + }, (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + player.sendMessage("§aUnder construction!"); }); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(false); } } \ No newline at end of file diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java index 6306c05a5..3c9957b36 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java @@ -47,7 +47,6 @@ public ItemStack.Builder getItem(HypixelPlayer player) { set(new GUIItem(4) { @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§aEnder Chest", Material.ENDER_CHEST, 1, "§7Store global items you can", "§7access anywhere in your ender", @@ -57,7 +56,6 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIItem(22) { @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§aBackpacks", Material.CHEST, 1, "§7Place backpack items in these slots", "§7to use them as additional storage", @@ -96,7 +94,6 @@ public void run(InventoryPreClickEvent e, HypixelPlayer p) { @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; if (!storage.hasPage(page)) return ItemStackCreator.getStack("§cLocked Page", Material.RED_STAINED_GLASS_PANE, 1, "§7Unlock more Ender Chest pages in", @@ -125,7 +122,6 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIItem(backpack_slot) { @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§cLocked Backpack Slot " + slot, Material.GRAY_DYE, 1, "§7Talk to Tia the Fairy to unlock more", diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/levels/LevelsGuide.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/levels/LevelsGuide.java index 2e7ceb161..7aece91c2 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/levels/LevelsGuide.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/levels/LevelsGuide.java @@ -4,7 +4,7 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; +import net.swofty.type.generic.gui.v2.View; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.starter.GUIStarterAccessories; import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.levels.starter.GUIStarterSkills; @@ -64,20 +64,20 @@ public enum LevelsGuide { public static class TasksSet { private Map causes; private ItemStack.Builder material; - private HypixelInventoryGUI guiToOpen; + private View guiToOpen; private Function> display; - public static Builder builder(ItemStack.Builder material, HypixelInventoryGUI guiToOpen, Function> display) { + public static Builder builder(ItemStack.Builder material, View guiToOpen, Function> display) { return new Builder(material, guiToOpen, display); } public static class Builder { private final Map causes = new HashMap<>(); private final ItemStack.Builder material; - private final HypixelInventoryGUI guiToOpen; + private final View guiToOpen; private final Function> display; - public Builder(ItemStack.Builder material, HypixelInventoryGUI guiToOpen, Function> display) { + public Builder(ItemStack.Builder material, View guiToOpen, Function> display) { this.material = material; this.guiToOpen = guiToOpen; this.display = display; From 1dc5d57a8121f54b76cd679990dc27b480e1232d Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sun, 11 Jan 2026 01:52:58 +0200 Subject: [PATCH 19/35] fix: GUIAuctionBrowser uses wrong click method --- .../gui/inventories/auction/GUIAuctionBrowser.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionBrowser.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionBrowser.java index eaf2e55c2..bce35673e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionBrowser.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/auction/GUIAuctionBrowser.java @@ -9,7 +9,7 @@ import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.inventory.click.ClickType; +import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.ServiceType; @@ -136,8 +136,7 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIClickableItem(52) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (e.getClick().equals(ClickType.RIGHT_CLICK)) { + if (e.getClick() instanceof Click.Right) { AuctionsFilter nextFilter = filter.previous(); setFilter(nextFilter); From da66f1548fa13d5e5e9cf8e9cd9f65d41d924a27 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sun, 11 Jan 2026 13:01:41 +0200 Subject: [PATCH 20/35] feat: ShapedRecipe with optimized ingredient handling --- .../item/crafting/ShapedRecipe.java | 377 +++++++++++++----- 1 file changed, 268 insertions(+), 109 deletions(-) diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/crafting/ShapedRecipe.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/crafting/ShapedRecipe.java index 3f3465203..b926892aa 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/crafting/ShapedRecipe.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/crafting/ShapedRecipe.java @@ -15,21 +15,31 @@ public class ShapedRecipe extends SkyBlockRecipe { public static final List CACHED_RECIPES = new ArrayList<>(); - private final Map ingredientMap; - private final Map> extraRequirements = new HashMap<>(); - private final List pattern; private final char[][] patternArray; private final int height; private final int width; + private static final int GRID_SIZE = 9; + private static final int CHAR_SPACE = 256; // index by (char & 0xFF) + private final ItemQuantifiable[] ingredientByChar; + + private final Function[] extraReqByChar; + private final char[] patternFlat; + private final int[] requiredPatternIdx; + private final char[] requiredSymbols; + private final boolean[] symbolHasExtraReq; + private final int[] airMaskByOffset; + private final int[][] requiredGridIdxByOffset; + private final char[][] requiredSymByOffset; + private final int recipeSize; + public ShapedRecipe(RecipeType type, SkyBlockItem result, Map ingredientMap, List pattern, Function canCraft) { super(result, type, canCraft); - this.ingredientMap = new HashMap<>(ingredientMap); if (pattern == null || pattern.isEmpty()) { throw new IllegalArgumentException("Pattern must have at least one element"); @@ -40,8 +50,92 @@ public ShapedRecipe(RecipeType type, this.width = this.pattern.stream().mapToInt(String::length).max().orElse(0); this.patternArray = toCharArray(this.pattern, height, width); - this.ingredientMap.putIfAbsent(' ', new ItemQuantifiable(ItemType.AIR, 0)); - this.ingredientMap.putIfAbsent('O', new ItemQuantifiable(ItemType.AIR, 0)); + this.ingredientByChar = new ItemQuantifiable[CHAR_SPACE]; + for (Map.Entry e : ingredientMap.entrySet()) { + this.ingredientByChar[e.getKey() & 0xFF] = e.getValue(); + } + this.ingredientByChar[' ' & 0xFF] = new ItemQuantifiable(ItemType.AIR, 0); + this.ingredientByChar['O' & 0xFF] = new ItemQuantifiable(ItemType.AIR, 0); + + @SuppressWarnings("unchecked") + Function[] tmp = (Function[]) new Function[CHAR_SPACE]; + this.extraReqByChar = tmp; + this.symbolHasExtraReq = new boolean[CHAR_SPACE]; + + this.patternFlat = new char[height * width]; + for (int r = 0; r < height; r++) { + if (width >= 0) System.arraycopy(patternArray[r], 0, patternFlat, r * width, width); + } + + int reqCount = 0; + for (char sym : patternFlat) { + ItemQuantifiable iq = ingredientByChar[sym & 0xFF]; + if (iq != null && iq.getItem().getMaterial() != Material.AIR) { + reqCount++; + } + } + this.requiredPatternIdx = new int[reqCount]; + this.requiredSymbols = new char[reqCount]; + int w = 0; + for (int i = 0; i < patternFlat.length; i++) { + char sym = patternFlat[i]; + ItemQuantifiable iq = ingredientByChar[sym & 0xFF]; + if (iq != null && iq.getItem().getMaterial() != Material.AIR) { + requiredPatternIdx[w] = i; + requiredSymbols[w] = sym; + w++; + } + } + + int offsetRows = 3 - height + 1; + int offsetCols = 3 - width + 1; + int offsets = offsetRows * offsetCols; + this.airMaskByOffset = new int[offsets]; + this.requiredGridIdxByOffset = new int[offsets][]; + this.requiredSymByOffset = new char[offsets][]; + + for (int startRow = 0; startRow < offsetRows; startRow++) { + for (int startCol = 0; startCol < offsetCols; startCol++) { + int offsetIndex = offsetIndex(startRow, startCol, offsetCols); + + int airMask = 0; + for (int gr = 0; gr < 3; gr++) { + for (int gc = 0; gc < 3; gc++) { + int idx = gr * 3 + gc; + int pr = gr - startRow; + int pc = gc - startCol; + if (pr < 0 || pr >= height || pc < 0 || pc >= width) { + airMask |= (1 << idx); + continue; + } + + char sym = patternArray[pr][pc]; + ItemQuantifiable iq = ingredientByChar[sym & 0xFF]; + if (sym == 'O' || iq == null || iq.getItem().getMaterial() == Material.AIR) { + airMask |= (1 << idx); + } + } + } + airMaskByOffset[offsetIndex] = airMask; + + int[] reqGrid = new int[requiredPatternIdx.length]; // upper bound + char[] reqSym = new char[requiredPatternIdx.length]; + int count = 0; + for (int i = 0; i < requiredPatternIdx.length; i++) { + int pi = requiredPatternIdx[i]; + int pr = pi / width; + int pc = pi - pr * width; + int gridIdx = (startRow + pr) * 3 + (startCol + pc); + reqGrid[count] = gridIdx; + reqSym[count] = requiredSymbols[i]; + count++; + } + requiredGridIdxByOffset[offsetIndex] = Arrays.copyOf(reqGrid, count); + requiredSymByOffset[offsetIndex] = Arrays.copyOf(reqSym, count); + } + } + + this.recipeSize = height * width; } public ShapedRecipe(RecipeType type, @@ -51,6 +145,10 @@ public ShapedRecipe(RecipeType type, this(type, result, ingredientMap, pattern, (_) -> new CraftingResult(true, new String[]{})); } + private static int offsetIndex(int startRow, int startCol, int offsetCols) { + return startRow * offsetCols + startCol; + } + private List normalizedPatternList(List pattern) { int maxLength = pattern.stream().mapToInt(String::length).max().orElse(0); List out = new ArrayList<>(pattern.size()); @@ -76,7 +174,8 @@ private char[][] toCharArray(List paddedPattern, int h, int w) { } public void addExtraRequirement(char patternChar, Function requirement) { - extraRequirements.put(patternChar, requirement); + extraReqByChar[patternChar & 0xFF] = requirement; + symbolHasExtraReq[patternChar & 0xFF] = true; } @Override @@ -90,38 +189,51 @@ public void init() { CACHED_RECIPES.add(this); } - private boolean matchesAtPosition(ItemStack[] stacks, int startRow, int startCol) { - for (int row = 0; row < 3; row++) { - int patternRow = row - startRow; - for (int col = 0; col < 3; col++) { - int index = row * 3 + col; - char symbol = 'O'; - - int patternCol = col - startCol; - if (patternRow >= 0 && patternRow < height && patternCol >= 0 && patternCol < width) { - symbol = patternArray[patternRow][patternCol]; - } - - ItemQuantifiable expected = ingredientMap.get(symbol); - ItemQuantifiable actual = ItemQuantifiable.of(stacks[index]); - - if (symbol == 'O' || expected == null || expected.getItem().getMaterial() == Material.AIR) { - if (actual.getItem().getMaterial() != Material.AIR) return false; - continue; - } - - if (actual.getAmount() < expected.getAmount()) return false; + private static int nonAirMask(ItemStack[] stacks) { + int mask = 0; + for (int i = 0; i < GRID_SIZE; i++) { + ItemStack s = stacks[i]; + if (s != null && s.material() != Material.AIR) { + mask |= (1 << i); + } + } + return mask; + } - if (actual.getItem().getMaterial() == Material.AIR) return false; - if (!actual.matchesType(expected.getItem())) { - if (!ExchangeableType.isExchangeable( - actual.getItem().getAttributeHandler().getPotentialType(), - expected.getItem().getAttributeHandler().getPotentialType())) { - return false; - } + private boolean matchesAtPosition(ItemStack[] stacks, int startRow, int startCol) { + int offsetRows = 3 - height + 1; + int offsetCols = 3 - width + 1; + if (startRow < 0 || startCol < 0 || startRow >= offsetRows || startCol >= offsetCols) return false; + + int offset = offsetIndex(startRow, startCol, offsetCols); + int nonAir = nonAirMask(stacks); + if ((nonAir & airMaskByOffset[offset]) != 0) return false; + + int[] reqIdx = requiredGridIdxByOffset[offset]; + char[] reqSym = requiredSymByOffset[offset]; + + for (int i = 0; i < reqIdx.length; i++) { + int idx = reqIdx[i]; + ItemStack actualStack = stacks[idx]; + if (actualStack == null || actualStack.material() == Material.AIR) return false; + + char sym = reqSym[i]; + ItemQuantifiable expected = ingredientByChar[sym & 0xFF]; + if (expected == null) return false; // should not happen for required + + if (actualStack.amount() < expected.getAmount()) return false; + + SkyBlockItem expectedItem = expected.getItem(); + SkyBlockItem actualItem = new SkyBlockItem(actualStack); + if (!expected.matchesType(actualItem)) { + if (!ExchangeableType.isExchangeable( + actualItem.getAttributeHandler().getPotentialType(), + expectedItem.getAttributeHandler().getPotentialType())) { + return false; } } } + return true; } @@ -130,30 +242,34 @@ public SkyBlockItem[] consume(SkyBlockItem[] stacks) { ItemStack[] rawStacks = new ItemStack[stacks.length]; for (int i = 0; i < stacks.length; i++) rawStacks[i] = (stacks[i] != null) ? stacks[i].getItemStack() : null; - for (int startRow = 0; startRow <= 3 - height; startRow++) { - for (int startCol = 0; startCol <= 3 - width; startCol++) { - if (matchesAtPosition(rawStacks, startRow, startCol)) { - SkyBlockItem[] resultStacks = Arrays.copyOf(stacks, stacks.length); - - for (int r = 0; r < height; r++) { - for (int c = 0; c < width; c++) { - char symbol = patternArray[r][c]; - ItemQuantifiable required = ingredientMap.get(symbol); - if (required == null || required.getItem().getMaterial() == Material.AIR) continue; - - int index = (startRow + r) * 3 + (startCol + c); - SkyBlockItem slot = resultStacks[index]; - - if (slot != null && slot.getMaterial() != Material.AIR) { - int newAmount = slot.getAmount() - required.getAmount(); - resultStacks[index] = (newAmount > 0) ? - new SkyBlockItem(slot.getItemStack().withAmount(newAmount)) - : null; - } - } - } - return resultStacks; + int offsetRows = 3 - height + 1; + int offsetCols = 3 - width + 1; + + for (int startRow = 0; startRow < offsetRows; startRow++) { + for (int startCol = 0; startCol < offsetCols; startCol++) { + if (!matchesAtPosition(rawStacks, startRow, startCol)) continue; + + SkyBlockItem[] resultStacks = Arrays.copyOf(stacks, stacks.length); + int offset = offsetIndex(startRow, startCol, offsetCols); + int[] reqIdx = requiredGridIdxByOffset[offset]; + char[] reqSym = requiredSymByOffset[offset]; + + for (int i = 0; i < reqIdx.length; i++) { + int idx = reqIdx[i]; + char sym = reqSym[i]; + ItemQuantifiable required = ingredientByChar[sym & 0xFF]; + if (required == null) continue; + + SkyBlockItem slot = resultStacks[idx]; + if (slot == null || slot.getMaterial() == Material.AIR) continue; + + int newAmount = slot.getAmount() - required.getAmount(); + resultStacks[idx] = (newAmount > 0) ? + new SkyBlockItem(slot.getItemStack().withAmount(newAmount)) + : null; } + + return resultStacks; } } @@ -163,14 +279,16 @@ public SkyBlockItem[] consume(SkyBlockItem[] stacks) { @Override public SkyBlockItem[] getRecipeDisplay() { SkyBlockItem[] display = new SkyBlockItem[9]; - for (int r = 0; r < height; r++) { for (int c = 0; c < width; c++) { char symbol = patternArray[r][c]; - ItemQuantifiable itemQ = ingredientMap.get(symbol); + ItemQuantifiable itemQ = ingredientByChar[symbol & 0xFF]; - if (itemQ != null && itemQ.getItem() != null && itemQ.getItem().getMaterial() != Material.AIR) { - display[r * 3 + c] = itemQ.getItem().clone(); + if (itemQ != null) { + SkyBlockItem item = itemQ.getItem(); + if (item != null && item.getMaterial() != Material.AIR) { + display[r * 3 + c] = item.clone(); + } } } } @@ -181,51 +299,91 @@ public SkyBlockItem[] getRecipeDisplay() { @Override public SkyBlockRecipe clone() { List patternCopy = new ArrayList<>(this.pattern); - return new ShapedRecipe(recipeType, result.clone(), new HashMap<>(ingredientMap), patternCopy, canCraft); + Map ingredientMapCopy = new HashMap<>(); + for (int i = 0; i < CHAR_SPACE; i++) { + ItemQuantifiable iq = ingredientByChar[i]; + if (iq != null) ingredientMapCopy.put((char) i, iq); + } + + ShapedRecipe cloned = new ShapedRecipe(recipeType, result.clone(), ingredientMapCopy, patternCopy, canCraft); + for (int i = 0; i < CHAR_SPACE; i++) { + Function req = extraReqByChar[i]; + if (req != null) cloned.addExtraRequirement((char) i, req); + } + cloned.amount = this.amount; + return cloned; } public static ShapedRecipe parseShapedRecipe(ItemStack[] stacks) { ShapedRecipe best = null; int bestSize = -1; + int nonAir = nonAirMask(stacks); + for (ShapedRecipe recipe : CACHED_RECIPES) { - int size = recipe.height * recipe.width; - - outerRow: - for (int row = 0; row <= 3 - recipe.height; row++) { - for (int col = 0; col <= 3 - recipe.width; col++) { - if (!recipe.matchesAtPosition(stacks, row, col)) continue; - - Map> positions = new HashMap<>(); - for (int r = 0; r < recipe.height; r++) { - for (int c = 0; c < recipe.width; c++) { - char symbol = recipe.patternArray[r][c]; - ItemQuantifiable expected = recipe.ingredientMap.get(symbol); - if (expected != null && expected.getItem().getMaterial() != Material.AIR) { - int index = (row + r) * 3 + (col + c); - positions.computeIfAbsent(symbol, k -> new ArrayList<>()).add(index); - } - } + // size = height*width (kept consistent with previous scoring). + int size = recipe.recipeSize; + if (size <= bestSize) { + // still need to allow ties? previous code used > only, so skip. + continue; + } + + int offsetRows = 3 - recipe.height + 1; + int offsetCols = 3 - recipe.width + 1; + int offsets = offsetRows * offsetCols; + + for (int offset = 0; offset < offsets; offset++) { + if ((nonAir & recipe.airMaskByOffset[offset]) != 0) continue; + + int[] reqIdx = recipe.requiredGridIdxByOffset[offset]; + char[] reqSym = recipe.requiredSymByOffset[offset]; + + boolean ok = true; + for (int i = 0; i < reqIdx.length; i++) { + int idx = reqIdx[i]; + ItemStack actualStack = stacks[idx]; + if (actualStack == null || actualStack.material() == Material.AIR) { + ok = false; + break; } - for (Map.Entry> entry : positions.entrySet()) { - Function req = recipe.extraRequirements.get(entry.getKey()); - if (req == null) continue; + char sym = reqSym[i]; + ItemQuantifiable expected = recipe.ingredientByChar[sym & 0xFF]; + if (expected == null) { + ok = false; + break; + } - for (int idx : entry.getValue()) { - SkyBlockItem sbi = (stacks[idx] != null) ? new SkyBlockItem(stacks[idx]) : null; - if (sbi == null || !req.apply(sbi)) { - continue outerRow; // this offset fails -> try next offset - } + if (actualStack.amount() < expected.getAmount()) { + ok = false; + break; + } + + SkyBlockItem expectedItem = expected.getItem(); + SkyBlockItem actualItem = new SkyBlockItem(actualStack); + + if (!expected.matchesType(actualItem)) { + if (!ExchangeableType.isExchangeable( + actualItem.getAttributeHandler().getPotentialType(), + expectedItem.getAttributeHandler().getPotentialType())) { + ok = false; + break; } } - // this recipe+offset passed all checks -> consider as candidate - if (size > bestSize) { - best = recipe; - bestSize = size; + if (recipe.symbolHasExtraReq[sym & 0xFF]) { + Function req = recipe.extraReqByChar[sym & 0xFF]; + if (req != null && !req.apply(actualItem)) { + ok = false; + break; + } } } + + if (ok) { + best = recipe; + bestSize = size; + } } } @@ -235,21 +393,23 @@ public static ShapedRecipe parseShapedRecipe(ItemStack[] stacks) { public Map> getPositionsOfItems(ItemStack[] stacks) { Map> positions = new HashMap<>(); - for (int startRow = 0; startRow <= 3 - height; startRow++) { - for (int startCol = 0; startCol <= 3 - width; startCol++) { - if (matchesAtPosition(stacks, startRow, startCol)) { - for (int r = 0; r < height; r++) { - for (int c = 0; c < width; c++) { - int index = (startRow + r) * 3 + (startCol + c); - char symbol = patternArray[r][c]; - ItemQuantifiable expected = ingredientMap.get(symbol); - - if (expected != null && expected.getItem().getMaterial() != Material.AIR) { - positions.computeIfAbsent(symbol, k -> new ArrayList<>()).add(index); - } - } - } - } + int nonAir = nonAirMask(stacks); + int offsetRows = 3 - height + 1; + int offsetCols = 3 - width + 1; + int offsets = offsetRows * offsetCols; + + for (int offset = 0; offset < offsets; offset++) { + if ((nonAir & airMaskByOffset[offset]) != 0) continue; + + int[] reqIdx = requiredGridIdxByOffset[offset]; + char[] reqSym = requiredSymByOffset[offset]; + + int startRow = offset / offsetCols; + int startCol = offset - startRow * offsetCols; + if (!matchesAtPosition(stacks, startRow, startCol)) continue; + + for (int i = 0; i < reqIdx.length; i++) { + positions.computeIfAbsent(reqSym[i], k -> new ArrayList<>()).add(reqIdx[i]); } } @@ -262,10 +422,9 @@ public String toString() { return "ShapedRecipe{" + "recipeType=" + recipeType + ", result=" + result + - ", ingredientMap=" + ingredientMap + ", pattern=" + pattern + ", canCraft=" + canCraft + ", amount=" + amount + '}'; } -} \ No newline at end of file +} From 7db50aec98040f326647533ab4d8678878f3e383 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sun, 11 Jan 2026 13:30:14 +0200 Subject: [PATCH 21/35] feat: guicrafting stuff --- type.generic/build.gradle.kts | 1 + .../type/generic/gui/v2/ViewSession.java | 171 +++++++++++++----- .../player/region/ActionRegionBlockPlace.java | 1 - .../gui/inventories/sbmenu/GUICrafting.java | 125 ++++++++++--- 4 files changed, 226 insertions(+), 72 deletions(-) diff --git a/type.generic/build.gradle.kts b/type.generic/build.gradle.kts index 6151532ec..cbad6c68f 100644 --- a/type.generic/build.gradle.kts +++ b/type.generic/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { } implementation("dev.hollowcube:polar:1.15.0") implementation("org.yaml:snakeyaml:2.2") + implementation("it.unimi.dsi:fastutil:8.5.18") } tasks.test { diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 024d624e7..5c462b193 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -1,5 +1,7 @@ package net.swofty.type.generic.gui.v2; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import lombok.Getter; import lombok.experimental.Accessors; import net.kyori.adventure.text.Component; @@ -12,6 +14,7 @@ import net.minestom.server.event.trait.InventoryEvent; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.PlayerInventory; +import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; import net.minestom.server.event.inventory.InventoryOpenEvent; import net.minestom.server.timer.Task; @@ -19,6 +22,7 @@ import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; +import org.jspecify.annotations.NonNull; import java.time.Duration; import java.util.*; @@ -54,17 +58,22 @@ public final class ViewSession { private S state; private ViewLayout cachedLayout; + private boolean layoutDirty = true; private Consumer onCloseHandler; @Getter private boolean closed; private boolean suppressCloseEvent; - private final Map trackedSlotItems = new HashMap<>(); + private final Int2ObjectOpenHashMap trackedSlotItems = new Int2ObjectOpenHashMap<>(); private final Set recentlyModifiedSlots = new HashSet<>(); private final Map autoUpdateTasks = new HashMap<>(); private final Map> componentSlots = new HashMap<>(); + private final Int2ObjectOpenHashMap pendingOldItems = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectOpenHashMap pendingNewItems = new Int2ObjectOpenHashMap<>(); + private boolean flushScheduled; + private ViewSession(View view, HypixelPlayer player, S initialState, SharedContext sharedContext) { this.view = view; this.player = player; @@ -123,11 +132,34 @@ private void onPreClickEvent(InventoryPreClickEvent event) { int slot = event.getSlot(); SlotBehavior behavior = cachedLayout != null ? cachedLayout.getBehavior(slot) : SlotBehavior.UI; + if (behavior == SlotBehavior.EDITABLE) { + if (event.getClick() instanceof Click.LeftShift) { + ItemStack oldItem = inventory.getItemStack(slot); + + MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { + ItemStack newItem = inventory.getItemStack(slot); + + if (!oldItem.equals(newItem)) { + queueSlotChange(slot, oldItem, newItem); + } + }); + } trackedSlotItems.put(slot, inventory.getItemStack(slot)); return; } + if (event.getClick() instanceof Click.LeftDrag(List slots)) { + for (int dragSlot : slots) { + if (cachedLayout == null || !cachedLayout.isEditable(dragSlot)) { + event.setCancelled(true); + return; + } + trackedSlotItems.put(dragSlot, inventory.getItemStack(dragSlot)); + } + return; + } + event.setCancelled(true); ViewComponent component = cachedLayout != null ? cachedLayout.components().get(slot) : null; var click = new ClickContext<>(slot, event.getClick(), player, state); @@ -139,40 +171,73 @@ private void onPreClickEvent(InventoryPreClickEvent event) { } } - private void onPostClickEvent(InventoryClickEvent event) { + private void onPostClickEvent(@NonNull InventoryClickEvent event) { if (event.getInventory() != inventory || closed) return; + if (cachedLayout == null) return; - int slot = event.getSlot(); - if (cachedLayout == null || !cachedLayout.isEditable(slot)) return; - - MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { - if (closed) return; - - ItemStack oldItem = trackedSlotItems.getOrDefault(slot, ItemStack.AIR); - ItemStack newItem = inventory.getItemStack(slot); + for (Int2ObjectMap.Entry entry : trackedSlotItems.int2ObjectEntrySet()) { + int trackedSlot = entry.getIntKey(); + if (!cachedLayout.isEditable(trackedSlot)) continue; + ItemStack oldItem = entry.getValue(); + ItemStack newItem = inventory.getItemStack(trackedSlot); if (!oldItem.equals(newItem)) { - handleSlotChange(slot, oldItem, newItem); + queueSlotChange(trackedSlot, oldItem, newItem); } - }); + } } - private void handleSlotChange(int slot, ItemStack oldItem, ItemStack newItem) { + private void queueSlotChange(int slot, ItemStack oldItem, ItemStack newItem) { + if (!pendingOldItems.containsKey(slot)) { + pendingOldItems.put(slot, oldItem); + } + pendingNewItems.put(slot, newItem); trackedSlotItems.put(slot, newItem); - recentlyModifiedSlots.add(slot); - ViewComponent component = cachedLayout.components().get(slot); - if (component != null && component.changeHandler() != null) { - component.changeHandler().onChange(slot, oldItem, newItem, state); + if (!flushScheduled) { + flushScheduled = true; + MinecraftServer.getSchedulerManager().submitTask(() -> { + flushPendingSlotChanges(); + return TaskSchedule.stop(); + }); + } + } + + private void flushPendingSlotChanges() { + if (closed) return; + flushScheduled = false; + if (pendingNewItems.isEmpty()) return; + + recentlyModifiedSlots.addAll(pendingNewItems.keySet()); + + boolean anyChanged = false; + for (Int2ObjectMap.Entry entry : pendingNewItems.int2ObjectEntrySet()) { + int slot = entry.getIntKey(); + ItemStack newItem = entry.getValue(); + ItemStack oldItem = pendingOldItems.getOrDefault(slot, ItemStack.AIR); + + ViewComponent component = cachedLayout != null ? cachedLayout.components().get(slot) : null; + if (component != null && component.changeHandler() != null) { + component.changeHandler().onChange(slot, oldItem, newItem, state); + } + anyChanged = true; + + if (sharedContext != null) { + sharedContext.setSlotItem(slot, newItem); + } } + pendingOldItems.clear(); + pendingNewItems.clear(); + recentlyModifiedSlots.clear(); + + if (!anyChanged) return; + if (sharedContext != null) { - sharedContext.setSlotItem(slot, newItem); + sharedContext.broadcastRender(); } else { render(); } - - recentlyModifiedSlots.remove(slot); } private void onCloseEvent(InventoryCloseEvent event) { @@ -187,8 +252,32 @@ public void render() { if (closed) return; ViewConfiguration config = view.configuration(); - cachedLayout = new ViewLayout<>(config.getInventoryType()); - view.layout(cachedLayout, state, context); + + if (cachedLayout == null || layoutDirty) { + cachedLayout = new ViewLayout<>(config.getInventoryType()); + view.layout(cachedLayout, state, context); + layoutDirty = false; + componentSlots.clear(); + + @SuppressWarnings("unchecked") BiFunction titleFunction = (BiFunction) config.getTitleFunction(); + inventory.setTitle(titleFunction.apply(state, context)); + + cachedLayout.components().forEach((slot, component) -> { + if (component.behavior() == SlotBehavior.EDITABLE) { + renderEditableSlot(slot); + return; + } + + renderSlot(slot, component); + if (component.updateInterval() != null) { + scheduleAutoUpdate(slot, component); + } + }); + + view.onRefresh(state, context); + return; + } + componentSlots.clear(); @SuppressWarnings("unchecked") BiFunction titleFunction = (BiFunction) config.getTitleFunction(); @@ -199,11 +288,7 @@ public void render() { renderEditableSlot(slot); return; } - renderSlot(slot, component); - if (component.updateInterval() != null) { - scheduleAutoUpdate(slot, component); - } }); view.onRefresh(state, context); @@ -246,6 +331,7 @@ private void scheduleAutoUpdate(int slot, ViewComponent component) { public void setState(S newState) { this.state = newState; + layoutDirty = true; if (sharedContext != null) { sharedContext.setState(newState); @@ -256,29 +342,31 @@ public void setState(S newState) { public void setStateQuiet(S newState) { this.state = newState; + layoutDirty = true; render(); } - public void update(UnaryOperator transform) { - setState(transform.apply(state)); + void setStateFromShared(S newState) { + this.state = newState; + layoutDirty = true; + render(); } - public void updateQuiet(UnaryOperator transform) { - setStateQuiet(transform.apply(state)); + void renderFromShared() { + render(); } - @SuppressWarnings("unchecked") - public void updateUnchecked(java.util.function.Function transform) { - setState((S) transform.apply((T) state)); + public void update(UnaryOperator updater) { + setState(updater.apply(state)); } - void setStateFromShared(S newState) { - this.state = newState; - render(); + public void updateQuiet(UnaryOperator updater) { + setStateQuiet(updater.apply(state)); } - void renderFromShared() { - render(); + @SuppressWarnings("unchecked") + public void updateUnchecked(java.util.function.Function updater) { + setState((S) updater.apply((T) state)); } public ViewSession onClose(Consumer handler) { @@ -310,16 +398,13 @@ public void close(CloseReason reason) { sharedContext.unregisterSession(this); } + flushPendingSlotChanges(); + view.onClose(state, context, reason); if (onCloseHandler != null) onCloseHandler.accept(reason); if (reason == CloseReason.SERVER_EXITED) player.closeInventory(); } - public boolean isShared() { - return sharedContext != null; - } - - public enum CloseReason { PLAYER_EXITED, SERVER_EXITED, diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockPlace.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockPlace.java index ade6f02d5..7eba8c51a 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockPlace.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/region/ActionRegionBlockPlace.java @@ -24,7 +24,6 @@ public void run(PlayerBlockPlaceEvent event) { if (!HypixelConst.isIslandServer()) { event.setCancelled(true); - player.sendMessage("§cYou can't build here!"); return; } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUICrafting.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUICrafting.java index 4d6c093a6..e917e26bd 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUICrafting.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUICrafting.java @@ -19,10 +19,11 @@ import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.tinylog.Logger; -import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.Objects; import java.util.stream.Collectors; public class GUICrafting implements StatefulView { @@ -43,7 +44,12 @@ public CraftingState initialState() { @Override public void layout(ViewLayout layout, CraftingState state, ViewContext ctx) { SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); - SkyBlockRecipe recipe = parseCurrentRecipe(ctx); + + int currentHash = computeGridHash(ctx); + SkyBlockRecipe recipe = (state.lastParsedRecipe() != null && state.lastGridHash() == currentHash) + ? state.lastParsedRecipe() + : parseCurrentRecipe(ctx); + boolean hasValidRecipe = recipe != null; SkyBlockRecipe.CraftingResult result = hasValidRecipe ? recipe.getCanCraft().apply(player) : null; boolean canCraft = hasValidRecipe && result != null && result.allowed(); @@ -56,7 +62,17 @@ public void layout(ViewLayout layout, CraftingState state, ViewCo Components.containerGrid( layout, 10, - 30, (slot, oldItem, newItem, state1) -> {} + 30, (slot, oldItem, newItem, state1) -> { + Logger.info("Container grid changed at slot " + slot); + Logger.info("Old Item: " + oldItem); + Logger.info("New Item: " + newItem); + int newHash = computeGridHash(ctx); + SkyBlockRecipe newRecipe = SkyBlockRecipe.parseRecipe(getCurrentRecipeStacks(ctx)); + if (state1.lastGridHash() == newHash && Objects.equals(state1.lastParsedRecipe(), newRecipe)) { + return; + } + ctx.session(CraftingState.class).setState(new CraftingState(newHash, newRecipe)); + } ); if (!hasValidRecipe) { @@ -88,55 +104,106 @@ public void layout(ViewLayout layout, CraftingState state, ViewCo } } - private SkyBlockRecipe parseCurrentRecipe(ViewContext ctx) { + private ItemStack[] getCurrentRecipeStacks(ViewContext ctx) { ItemStack[] stacks = new ItemStack[9]; for (int i = 0; i < CRAFT_SLOTS.length; i++) { stacks[i] = ctx.inventory().getItemStack(CRAFT_SLOTS[i]); } - return SkyBlockRecipe.parseRecipe(stacks); + return stacks; + } + + private int computeGridHash(ViewContext ctx) { + // Stable & cheap hash: material id + amount per slot (no streams/allocations beyond the 9 reads). + int hash = 1; + for (int slot : CRAFT_SLOTS) { + ItemStack item = ctx.inventory().getItemStack(slot); + int mat = item.material().id(); + hash = 31 * hash + (mat * 37 + item.amount()); + } + return hash; + } + + private SkyBlockRecipe parseCurrentRecipe(ViewContext ctx) { + return SkyBlockRecipe.parseRecipe(getCurrentRecipeStacks(ctx)); } private void handleCraft(ClickContext click, ViewContext ctx, SkyBlockRecipe recipe, int amount) { SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); - SkyBlockItem cursorItem = new SkyBlockItem(player.getInventory().getCursorItem()); + ItemStack cursorItemStack = player.getInventory().getCursorItem(); + SkyBlockItem cursorItem = new SkyBlockItem(cursorItemStack); ItemType cursorItemType = cursorItem.getAttributeHandler().getPotentialType(); ItemType resultItemType = recipe.getResult().getAttributeHandler().getPotentialType(); boolean isShift = click.click() instanceof Click.LeftShift || click.click() instanceof Click.RightShift; - if (!player.getInventory().getCursorItem().isAir() && - (cursorItemType == null || !cursorItemType.equals(resultItemType))) { - player.sendMessage("§cYou must empty your cursor first!"); + if (!cursorItemStack.isAir() && (cursorItemType == null || !cursorItemType.equals(resultItemType))) { return; } - ItemStack craftedItem = PlayerItemUpdater.playerUpdate( - player, - recipe.getResult().getItemStack()).amount(amount).build(); + ItemStack craftedItem = PlayerItemUpdater.playerUpdate(player, recipe.getResult().getItemStack()) + .amount(amount) + .build(); + int maxStackSize = craftedItem.material().maxStackSize(); if (isShift) { - player.addAndUpdateItem(craftedItem); + int expectedGridHash = computeGridHash(ctx); + + while (true) { + if (computeGridHash(ctx) != expectedGridHash) { + break; + } + + SkyBlockRecipe.CraftingResult craftResult = recipe.getCanCraft().apply(player); + if (craftResult == null || !craftResult.allowed()) { + break; + } + if (!player.canFitItem(craftedItem)) { + break; + } + + SkyBlockItem[] currentItems = getCurrentRecipeAsItems(ctx); + SkyBlockItem[] toReplace; + try { + toReplace = recipe.consume(currentItems); + } catch (Exception e) { + break; + } + + applyConsumedGrid(player, ctx, toReplace); + expectedGridHash = computeGridHash(ctx); + + player.addAndUpdateItem(craftedItem); + HypixelEventHandler.callCustomEvent( + new ItemCraftEvent(player, new SkyBlockItem(craftedItem), recipe)); + } } else { - player.getInventory().setCursorItem(craftedItem); + int currentCursorAmount = cursorItemStack.isAir() ? 0 : cursorItemStack.amount(); + int newAmount = currentCursorAmount + amount; + if (newAmount > maxStackSize) { + return; + } + ItemStack newCursorItem = craftedItem.withAmount(newAmount); + player.getInventory().setCursorItem(newCursorItem); + + HypixelEventHandler.callCustomEvent(new ItemCraftEvent(player, new SkyBlockItem(craftedItem), recipe)); + SkyBlockItem[] currentItems = getCurrentRecipeAsItems(ctx); + SkyBlockItem[] toReplace = recipe.consume(currentItems); + applyConsumedGrid(player, ctx, toReplace); } - HypixelEventHandler.callCustomEvent(new ItemCraftEvent(player, new SkyBlockItem(craftedItem), recipe)); - SkyBlockItem[] currentItems = getCurrentRecipeAsItems(ctx); - SkyBlockItem[] toReplace = recipe.consume(currentItems); + player.getInventory().update(); + } + + private void applyConsumedGrid(SkyBlockPlayer player, ViewContext ctx, SkyBlockItem[] toReplace) { for (int i = 0; i < CRAFT_SLOTS.length; i++) { if (toReplace[i] == null || toReplace[i].getItemStack().material() == Material.BEDROCK) { - ctx.inventory().setItemStack(CRAFT_SLOTS[i], ItemStack.builder(Material.AIR).build()); + ctx.inventory().setItemStack(CRAFT_SLOTS[i], ItemStack.AIR); } else { - ctx.inventory().setItemStack(CRAFT_SLOTS[i], PlayerItemUpdater.playerUpdate( - player, - toReplace[i].getItemStack()).build()); + ctx.inventory().setItemStack( + CRAFT_SLOTS[i], + PlayerItemUpdater.playerUpdate(player, toReplace[i].getItemStack()).build() + ); } } - - if (cursorItemType != null && cursorItemType.equals(resultItemType) && !isShift) { - player.addAndUpdateItem(cursorItem); - } - - player.getInventory().update(); } private SkyBlockItem[] getCurrentRecipeAsItems(ViewContext ctx) { @@ -163,5 +230,7 @@ public boolean onBottomClick(ClickContext click, ViewContext ctx) return true; } - public record CraftingState(int lastGridHash, SkyBlockRecipe lastParsedRecipe) {} + public record CraftingState(int lastGridHash, SkyBlockRecipe lastParsedRecipe) { + } } + From b7f5999eb4111555d6706c84258715ba2735ce54 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 13 Jan 2026 17:47:35 +0200 Subject: [PATCH 22/35] feat: continue sbmenu port --- .../type/generic/gui/v2/PaginatedView.java | 37 ++--- .../gui/v2/test/TestPaginatedView.java | 20 +-- .../inventories/abiphone/AbiphoneView.java | 14 +- .../gui/inventories/sbmenu/GUIPets.java | 21 +-- .../sbmenu/collection/GUICollectionItem.java | 2 +- .../collection/GUICollectionReward.java | 4 +- .../sbmenu/collection/GUICraftedMinions.java | 17 +-- .../sbmenu/levels/emblem/GUIEmblem.java | 14 +- .../sbmenu/recipe/GUIMinionRecipes.java | 4 +- .../sbmenu/recipe/GUIRecipeBook.java | 20 ++- .../sbmenu/recipe/GUIRecipeCategory.java | 63 +++----- .../sbmenu/recipe/GUISearchRecipe.java | 140 ++++++++++++++++++ 12 files changed, 205 insertions(+), 151 deletions(-) create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUISearchRecipe.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java index d5adba18e..131ed61fe 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java @@ -14,9 +14,13 @@ public abstract class PaginatedView> implements View { - protected static final ItemStack.Builder PREV_ARROW = ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")); - protected static final ItemStack.Builder NEXT_ARROW = ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")); - protected static final ItemStack.Builder SEARCH_ICON = ItemStack.builder(Material.BIRCH_SIGN).set(DataComponents.CUSTOM_NAME, Component.text("§aSearch")); + protected static final int[] DEFAULT_SLOTS = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; + protected static final ItemStack.Builder FILLER = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE).set(DataComponents.CUSTOM_NAME, Component.text(" ")).set(DataComponents.TOOLTIP_DISPLAY, new TooltipDisplay(true, Set.of())); public interface PaginatedState { @@ -24,12 +28,8 @@ public interface PaginatedState { int page(); - String query(); - PaginatedState withPage(int page); - PaginatedState withQuery(String query); - PaginatedState withItems(List items); } @@ -64,11 +64,7 @@ public void layout(ViewLayout layout, S state, ViewContext ctx) { } protected List getFilteredItems(S state) { - String query = state.query(); - if (query == null || query.isEmpty()) { - return state.items(); - } - return state.items().stream().filter(item -> !shouldFilterFromSearch(query, item)).toList(); + return state.items().stream().filter(item -> !shouldFilterFromSearch(state, item)).toList(); } protected void layoutBackground(ViewLayout layout, S state, ViewContext ctx) { @@ -78,7 +74,6 @@ protected void layoutBackground(ViewLayout layout, S state, ViewContext ctx) protected void layoutNavigation(ViewLayout layout, S state, ViewContext ctx, int currentPage, int totalPages) { int prevSlot = getPreviousPageSlot(); int nextSlot = getNextPageSlot(); - int searchSlot = getSearchSlot(); if (prevSlot >= 0) { if (currentPage > 0) { @@ -101,14 +96,8 @@ protected void layoutNavigation(ViewLayout layout, S state, ViewContext ctx, layout.slot(nextSlot, FILLER); } } - - if (searchSlot >= 0) { - layout.slot(searchSlot, (s, c) -> createSearchItem(state.query()), this::onSearchClick); - } } - protected abstract int getSearchSlot(); - protected abstract int getNextPageSlot(); protected abstract int getPreviousPageSlot(); @@ -124,21 +113,13 @@ protected ItemStack.Builder createNextPageItem(int currentPage, int totalPages) return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")).set(DataComponents.LORE, List.of(Component.text("§7Page " + (currentPage + 2) + " of " + totalPages))); } - protected ItemStack.Builder createSearchItem(String currentQuery) { - String queryDisplay = currentQuery.isEmpty() ? "None" : currentQuery; - return ItemStack.builder(Material.BIRCH_SIGN).set(DataComponents.CUSTOM_NAME, Component.text("§aSearch")).set(DataComponents.LORE, List.of(Component.text("§7Query: §e" + queryDisplay), Component.text(""), Component.text("§eClick to search!"))); - } - - protected void onSearchClick(ClickContext click, ViewContext ctx) { - } - protected abstract int[] getPaginatedSlots(); protected abstract ItemStack.Builder renderItem(T item, int index, HypixelPlayer player); protected abstract void onItemClick(ClickContext click, ViewContext ctx, T item, int index); - protected abstract boolean shouldFilterFromSearch(String query, T item); + protected abstract boolean shouldFilterFromSearch(S state, T item); public static int[] createGrid(int startSlot, int endSlot) { return Layouts.rectangle(startSlot, endSlot).stream().mapToInt(Integer::intValue).toArray(); diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestPaginatedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestPaginatedView.java index 58176ff0d..9f8428810 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestPaginatedView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestPaginatedView.java @@ -25,7 +25,7 @@ public final class TestPaginatedView extends PaginatedView configuration() { return ViewConfiguration.withString( - (state, ctx) -> "Test Paginated View - Page " + (state.page() + 1), + (state, _) -> "Test Paginated View - Page " + (state.page() + 1), InventoryType.CHEST_6_ROW ); } @@ -52,8 +52,8 @@ protected void onItemClick(ClickContext click, ViewContext ctx, Integer i } @Override - protected boolean shouldFilterFromSearch(String query, Integer item) { - return !String.valueOf(item).contains(query); + protected boolean shouldFilterFromSearch(State state, Integer item) { + return !String.valueOf(item).contains(state.query); } @Override @@ -74,30 +74,16 @@ protected int getNextPageSlot() { return 53; } - @Override - protected int getSearchSlot() { - return -1; - } - public record State(List items, int page, String query) implements PaginatedState { public State(List items) { this(items, 0, ""); } - public static State withItems(int count) { - return new State(IntStream.rangeClosed(1, count).boxed().toList()); - } - @Override public PaginatedState withPage(int page) { return new State(items, page, query); } - @Override - public PaginatedState withQuery(String query) { - return new State(items, 0, query); - } - @Override public PaginatedState withItems(List items) { return new State(items, page, query); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/AbiphoneView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/AbiphoneView.java index 9be928fc7..ec4ec7dde 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/AbiphoneView.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/abiphone/AbiphoneView.java @@ -78,8 +78,8 @@ private void initiateCall(HypixelPlayer player, AbiphoneNPC npc) { } @Override - protected boolean shouldFilterFromSearch(String query, AbiphoneNPC item) { - return !item.getName().toLowerCase().contains(query.toLowerCase()); + protected boolean shouldFilterFromSearch(State state, AbiphoneNPC item) { + return !item.getName().toLowerCase().contains(state.query.toLowerCase()); } @Override @@ -129,11 +129,6 @@ protected int getNextPageSlot() { return 53; } - @Override - protected int getSearchSlot() { - return -1; - } - public record State( SkyBlockItem abiphone, List items, @@ -151,11 +146,6 @@ public PaginatedState withPage(int page) { return new State(abiphone, items, page, query, sortType); } - @Override - public PaginatedState withQuery(String query) { - return new State(abiphone, items, 0, query, sortType); - } - @Override public PaginatedState withItems(List items) { return new State(abiphone, items, page, query, sortType); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java index 693aebae1..d02bbdb8c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUIPets.java @@ -46,12 +46,7 @@ protected int[] getPaginatedSlots() { @Override protected List getFilteredItems(PetsState state) { List pets = new ArrayList<>(state.items()); - String query = state.query(); - - // Apply search filter first - if (query != null && !query.isEmpty()) { - pets = pets.stream().filter(item -> !shouldFilterFromSearch(query, item)).toList(); - } + pets = pets.stream().filter(item -> !shouldFilterFromSearch(state, item)).toList(); // Apply sorting pets = new ArrayList<>(pets); @@ -140,8 +135,8 @@ protected void onItemClick(ClickContext click, ViewContext ctx, SkyBl } @Override - protected boolean shouldFilterFromSearch(String query, SkyBlockItem item) { - return !item.getDisplayName().toLowerCase().contains(query.toLowerCase()); + protected boolean shouldFilterFromSearch(PetsState state, SkyBlockItem item) { + return !item.getDisplayName().toLowerCase().contains(state.query.toLowerCase()); } @Override @@ -227,11 +222,6 @@ protected int getNextPageSlot() { return 53; } - @Override - protected int getSearchSlot() { - return -1; - } - private static List getPetsFromPlayer(SkyBlockPlayer player) { return new ArrayList<>(player.getPetData().getPetsMap().keySet().stream().toList()); } @@ -252,11 +242,6 @@ public PaginatedState withPage(int page) { return new PetsState(items, page, query, sortType, convertToItem); } - @Override - public PaginatedState withQuery(String query) { - return new PetsState(items, 0, query, sortType, convertToItem); - } - @Override public PaginatedState withItems(List items) { return new PetsState(items, page, query, sortType, convertToItem); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionItem.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionItem.java index 5a7a6124e..912905d61 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionItem.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionItem.java @@ -84,7 +84,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont colour + item.getDisplayName() + " " + StringUtility.getAsRomanNumeral(collection.getPlacementOf(reward) + 1), material, 1, lore); }, (click, c) -> { - //new GUICollectionReward(item, reward).open((SkyBlockPlayer) c.player()) + ctx.push(new GUICollectionReward(item, reward)); }); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java index 73fb96a66..e23056e65 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollectionReward.java @@ -80,9 +80,9 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont try { SkyBlockItem skyBlockItem = ((CollectionCategory.UnlockRecipe) unlock).getRecipes().getFirst().getResult(); if (skyBlockItem.hasComponent(MinionComponent.class)) { - c.player().openView(new GUIMinionRecipes(skyBlockItem.getAttributeHandler().getMinionType(), new GUICollectionReward(item, reward))); + c.push(new GUIMinionRecipes(skyBlockItem.getAttributeHandler().getMinionType())); } else { - c.player().openView(new GUIRecipe(skyBlockItem.getAttributeHandler().getPotentialType())); + c.push(new GUIRecipe(skyBlockItem.getAttributeHandler().getPotentialType())); } } catch (NullPointerException exception) { player.sendMessage("There is no recipe available for this item!"); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java index 2d7f042f2..27bd00578 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICraftedMinions.java @@ -12,6 +12,7 @@ import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointMinionData; +import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe.GUIMinionRecipes; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.MinionComponent; import net.swofty.type.skyblockgeneric.minion.MinionRegistry; @@ -46,11 +47,6 @@ protected int[] getPaginatedSlots() { }; } - @Override - protected int getSearchSlot() { - return -1; // No search - } - @Override protected int getNextPageSlot() { return 53; @@ -102,13 +98,11 @@ protected ItemStack.Builder renderItem(SkyBlockItem item, int index, HypixelPlay @Override protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockItem item, int index) { - // TODO: Open minion recipes GUI when ported - // SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); - // new GUIMinionRecipes(item.getAttributeHandler().getMinionType(), ...).open(player); + ctx.push(new GUIMinionRecipes(item.getAttributeHandler().getMinionType())); } @Override - protected boolean shouldFilterFromSearch(String query, SkyBlockItem item) { + protected boolean shouldFilterFromSearch(MinionsState state, SkyBlockItem item) { return false; } @@ -124,11 +118,6 @@ public PaginatedState withPage(int page) { return new MinionsState(items, page, query); } - @Override - public PaginatedState withQuery(String query) { - return new MinionsState(items, page, query); - } - @Override public PaginatedState withItems(List items) { return new MinionsState(items, page, query); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblem.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblem.java index d310b4a1d..05c4bd35f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblem.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/levels/emblem/GUIEmblem.java @@ -43,11 +43,6 @@ protected int[] getPaginatedSlots() { }; } - @Override - protected int getSearchSlot() { - return -1; // No search - } - @Override protected int getNextPageSlot() { return 44; @@ -100,8 +95,8 @@ protected void onItemClick(ClickContext click, ViewContext ctx, Sky } @Override - protected boolean shouldFilterFromSearch(String query, SkyBlockEmblems.SkyBlockEmblem item) { - return !item.displayName().toLowerCase().contains(query.toLowerCase()); + protected boolean shouldFilterFromSearch(EmblemState state, SkyBlockEmblems.SkyBlockEmblem item) { + return !item.displayName().toLowerCase().contains(state.query.toLowerCase()); } @Override @@ -116,11 +111,6 @@ public PaginatedState withPage(int page) { return new EmblemState(items, page, query); } - @Override - public PaginatedState withQuery(String query) { - return new EmblemState(items, page, query); - } - @Override public PaginatedState withItems(List items) { return new EmblemState(items, page, query); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java index 132f33a6f..b14e2f2cc 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIMinionRecipes.java @@ -24,11 +24,9 @@ public class GUIMinionRecipes extends StatelessView { )); private final MinionRegistry minionRegistry; - private final StatelessView previousView; - public GUIMinionRecipes(MinionRegistry minionRegistry, StatelessView previousView) { + public GUIMinionRecipes(MinionRegistry minionRegistry) { this.minionRegistry = minionRegistry; - this.previousView = previousView; } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java index 1d2fc7281..c86fda0f7 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java @@ -3,10 +3,10 @@ import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; +import net.swofty.type.generic.gui.HypixelSignGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.v2.*; import net.swofty.type.generic.gui.v2.context.ViewContext; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; import net.swofty.type.skyblockgeneric.item.crafting.ShapedRecipe; import net.swofty.type.skyblockgeneric.item.crafting.ShapelessRecipe; import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; @@ -37,6 +37,24 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont allRecipes.addAll(ShapedRecipe.CACHED_RECIPES); allRecipes.addAll(ShapelessRecipe.CACHED_RECIPES); + layout.slot(51, (_, _) -> ItemStackCreator.getStack("§aSearch Recipes", Material.OAK_SIGN, 1, List.of( + "§8/recipe ", + "", + "§7Search all recipes in SkyBlock. May", + "§7include recipes with aren't in the", + "§7recipe book.", + "", + "§eClick to search!" + )), (_, c) -> { + new HypixelSignGUI(c.player()).open(new String[]{"Enter query", ""}).thenAccept(line -> { + if (line == null) { + return; + } + + c.push(new GUISearchRecipe(), GUISearchRecipe.createInitialState(line)); + }); + }); + layout.slot(4, (s, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); List lore = new ArrayList<>(List.of( diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java index 06829d94f..1a0798c7d 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java @@ -23,9 +23,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; -public class GUIRecipeCategory extends PaginatedView { +public class GUIRecipeCategory extends PaginatedView, GUIRecipeCategory.RecipeCategoryState> { private static final int[] PAGINATED_SLOTS = { 10, 11, 12, 13, 14, 15, 16, @@ -54,27 +55,16 @@ protected int[] getPaginatedSlots() { } @Override - protected List getFilteredItems(RecipeCategoryState state) { - List recipes = new ArrayList<>(state.items()); - String query = state.query(); - - if (query != null && !query.isEmpty()) { - recipes = recipes.stream().filter(item -> !shouldFilterFromSearch(query, item)).toList(); - } - - return recipes; - } - - @Override - protected ItemStack.Builder renderItem(SkyBlockRecipe item, int index, HypixelPlayer player) { - SkyBlockRecipe.CraftingResult result = (SkyBlockRecipe.CraftingResult) item.getCanCraft().apply(player); + protected ItemStack.Builder renderItem(SkyBlockRecipe item, int index, HypixelPlayer p) { + SkyBlockPlayer player = (SkyBlockPlayer) p; + SkyBlockRecipe.CraftingResult result = item.getCanCraft().apply(player); ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate( - (SkyBlockPlayer) player, item.getResult().getItemStack() + player, item.getResult().getItemStack() ); if (result.allowed()) { ArrayList lore = new ArrayList<>( - itemStack.build().get(DataComponents.LORE).stream().map(StringUtility::getTextFromComponent).toList() + Objects.requireNonNull(itemStack.build().get(DataComponents.LORE)).stream().map(StringUtility::getTextFromComponent).toList() ); lore.add("§e "); lore.add("§eClick to view recipe!"); @@ -90,9 +80,9 @@ protected ItemStack.Builder renderItem(SkyBlockRecipe item, int index, HypixelPl } @Override - protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockRecipe item, int index) { + protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockRecipe item, int index) { SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); - SkyBlockRecipe.CraftingResult result = (SkyBlockRecipe.CraftingResult) item.getCanCraft().apply(player); + SkyBlockRecipe.CraftingResult result = item.getCanCraft().apply(player); if (result.allowed()) { ctx.push(new GUIRecipe(item.getResult().getAttributeHandler().getPotentialType())); @@ -102,10 +92,8 @@ protected void onItemClick(ClickContext click, ViewContext } @Override - protected boolean shouldFilterFromSearch(String query, SkyBlockRecipe item) { - return !StringUtility.getTextFromComponent(new NonPlayerItemUpdater( - item.getResult() - ).getUpdatedItem().build().get(DataComponents.CUSTOM_NAME)).toLowerCase().contains(query.toLowerCase()); + protected boolean shouldFilterFromSearch(RecipeCategoryState query, SkyBlockRecipe item) { + return false; } @Override @@ -113,7 +101,7 @@ protected void layoutCustom(ViewLayout layout, RecipeCatego Components.close(layout, 49); Components.back(layout, 48, ctx); - ArrayList allRecipes = new ArrayList<>(); + ArrayList> allRecipes = new ArrayList<>(); allRecipes.addAll(ShapedRecipe.CACHED_RECIPES); allRecipes.addAll(ShapelessRecipe.CACHED_RECIPES); @@ -121,8 +109,8 @@ protected void layoutCustom(ViewLayout layout, RecipeCatego layout.slot(4, (s, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); - ArrayList typeRecipes = new ArrayList<>(); - ArrayList allowedRecipes = new ArrayList<>(); + ArrayList> typeRecipes = new ArrayList<>(); + ArrayList> allowedRecipes = new ArrayList<>(); allRecipes.forEach(recipe -> { if (recipe.getRecipeType() == type) { typeRecipes.add(recipe); @@ -134,8 +122,7 @@ protected void layoutCustom(ViewLayout layout, RecipeCatego "§7that you have unlocked!", " ")); typeRecipes.forEach(recipe -> { - SkyBlockRecipe.CraftingResult result = - (SkyBlockRecipe.CraftingResult) recipe.getCanCraft().apply(player); + SkyBlockRecipe.CraftingResult result = recipe.getCanCraft().apply(player); if (result.allowed()) { allowedRecipes.add(recipe); @@ -173,13 +160,8 @@ protected int getNextPageSlot() { return 53; } - @Override - protected int getSearchSlot() { - return 50; - } - public static RecipeCategoryState createInitialState(SkyBlockRecipe.RecipeType type) { - List recipes = new ArrayList<>(); + List> recipes = new ArrayList<>(); recipes.addAll(ShapedRecipe.CACHED_RECIPES); recipes.addAll(ShapelessRecipe.CACHED_RECIPES); @@ -200,22 +182,17 @@ public static RecipeCategoryState createInitialState(SkyBlockRecipe.RecipeType t } public record RecipeCategoryState( - List items, + List> items, int page, String query - ) implements PaginatedState { + ) implements PaginatedState> { @Override - public PaginatedState withPage(int page) { + public PaginatedState> withPage(int page) { return new RecipeCategoryState(items, page, query); } @Override - public PaginatedState withQuery(String query) { - return new RecipeCategoryState(items, 0, query); - } - - @Override - public PaginatedState withItems(List items) { + public PaginatedState> withItems(List> items) { return new RecipeCategoryState(items, page, query); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUISearchRecipe.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUISearchRecipe.java new file mode 100644 index 000000000..bb70546d2 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUISearchRecipe.java @@ -0,0 +1,140 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.recipe; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextDecoration; +import net.minestom.server.component.DataComponents; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.commons.StringUtility; +import net.swofty.type.generic.gui.HypixelSignGUI; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; +import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class GUISearchRecipe extends PaginatedView, GUISearchRecipe.SearchState> { + @Override + protected int getPreviousPageSlot() { + return 45; + } + + @Override + protected int getNextPageSlot() { + return 53; + } + + @Override + protected int[] getPaginatedSlots() { + return DEFAULT_SLOTS; + } + + @Override + protected ItemStack.Builder renderItem(SkyBlockRecipe item, int index, HypixelPlayer p) { + SkyBlockPlayer player = (SkyBlockPlayer) p; + SkyBlockRecipe.CraftingResult result = item.getCanCraft().apply(player); + ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate( + player, item.getResult().getItemStack() + ); + + if (result.allowed()) { + ArrayList lore = new ArrayList<>( + itemStack.build().get(DataComponents.LORE).stream().map(StringUtility::getTextFromComponent).toList() + ); + lore.add("§e "); + lore.add("§eClick to view recipe!"); + + return itemStack.set(DataComponents.LORE, + lore.stream().map(line -> Component.text(line).decoration(TextDecoration.ITALIC, false)) + .collect(Collectors.toList())); + } else { + List lore = Arrays.asList(result.errorMessage()); + lore = lore.stream().map(line -> "§7" + line).toList(); + return ItemStackCreator.getStack("§c???", Material.GRAY_DYE, 1, lore); + } + } + + @Override + protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockRecipe item, int index) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockRecipe.CraftingResult result = item.getCanCraft().apply(player); + + if (result.allowed()) { + ctx.push(new GUIRecipe(item.getResult().getAttributeHandler().getPotentialType())); + } else { + player.sendMessage("§cYou haven't unlocked that recipe!"); + } + } + + @Override + public void layout(ViewLayout layout, SearchState state, ViewContext ctx) { + layout.filler(Layouts.border(0, 53), FILLER); + Components.back(layout, 48, ctx); + Components.close(layout, 49); + + layout.slot(50, (_, _) -> ItemStackCreator.getStack("§aSearch Recipes", Material.OAK_SIGN, 1, List.of( + "§8/recipe ", + "", + "§7Search all recipes in SkyBlock. May", + "§7include recipes with aren't in the", + "§7recipe book.", + "", + "§eClick to search!" + )), (_, c) -> { + new HypixelSignGUI(c.player()).open(new String[]{"Enter query"}).thenAccept(line -> { + if (line == null) { + return; + } + + c.replace(new GUISearchRecipe(), GUISearchRecipe.createInitialState(line)); + }); + }); + + // if no results + if (state.items().isEmpty()) { + layout.slot(22, (searchState, _) -> { + return ItemStackCreator.getStack("§cNo Results", Material.BARRIER, 1, List.of( + "§7Could not find any SkyBlock recipes", + "§7matching the query '" + searchState.query() + "'." + )); + }); + } + } + + @Override + protected boolean shouldFilterFromSearch(SearchState state, SkyBlockRecipe item) { + return false; + } + + @Override + public ViewConfiguration configuration() { + return ViewConfiguration.withString((state, ctx) -> "\"" + state.query() + "\" Recipes (" + state.page + "/" + + (int) Math.ceil((double) state.items().size() / DEFAULT_SLOTS.length) + ")", InventoryType.CHEST_6_ROW); + } + + public static SearchState createInitialState(String query) { + return new SearchState(List.of(), 0, query); + } + + public record SearchState(List> items, int page, String query) implements PaginatedState> { + @Override + public PaginatedState> withPage(int page) { + return new SearchState(items, page, query); + } + + @Override + public PaginatedState> withItems(List> items) { + return new SearchState(this.items, page, query); + } + } + +} From 18d499251e271982b16daf789eca0d2dd9ab517f Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:00:19 +0200 Subject: [PATCH 23/35] fix: pass state instead of view --- .../main/java/net/swofty/type/generic/gui/v2/Components.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java index 8095251bd..8021d9dd9 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Components.java @@ -39,7 +39,7 @@ public static boolean back(ViewLayout layout, int slot, ViewContext conte } Optional> prev = context.navigator().peekPrevious(); Component prevTitle = prev - .map(entry -> entry.view().configuration().getTitleFunction().apply(entry.view(), context)) + .map(entry -> entry.view().configuration().getTitleFunction().apply(entry.state(), context)) .orElse(Component.text("§r§7previous page")); layout.slot(slot, (s, c) -> BACK_BUTTON.lore( Component.text("§7To ").append(prevTitle) From b2075ce77970fb5dc7394d551b455749266b77cb Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:09:28 +0200 Subject: [PATCH 24/35] feat: recipes search actual state --- .../sbmenu/recipe/GUIRecipeBook.java | 2 +- .../sbmenu/recipe/GUIRecipeCategory.java | 7 +++--- .../sbmenu/recipe/GUIRecipeSlayers.java | 2 +- .../sbmenu/recipe/GUISearchRecipe.java | 23 ++++++++++++++++++- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java index c86fda0f7..a92094ee6 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeBook.java @@ -112,7 +112,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", type.getMaterial(), 1, lore); - }, (click, c) -> c.push(new GUIRecipeCategory(type), GUIRecipeCategory.createInitialState(type))); + }, (_, c) -> c.push(new GUIRecipeCategory(type), GUIRecipeCategory.createInitialState((SkyBlockPlayer) c.player(), type))); } // Slayer recipes diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java index 1a0798c7d..050e1d059 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeCategory.java @@ -160,7 +160,7 @@ protected int getNextPageSlot() { return 53; } - public static RecipeCategoryState createInitialState(SkyBlockRecipe.RecipeType type) { + public static RecipeCategoryState createInitialState(SkyBlockPlayer player, SkyBlockRecipe.RecipeType type) { List> recipes = new ArrayList<>(); recipes.addAll(ShapedRecipe.CACHED_RECIPES); recipes.addAll(ShapelessRecipe.CACHED_RECIPES); @@ -174,11 +174,12 @@ public static RecipeCategoryState createInitialState(SkyBlockRecipe.RecipeType t return true; } else { shownItems.add(itemType); - return false; + SkyBlockRecipe.CraftingResult result = recipe.getCanCraft().apply(player); + return !result.allowed(); } }); - return new RecipeCategoryState(recipes, 0, ""); + return new RecipeCategoryState(List.of(), 0, ""); } public record RecipeCategoryState( diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java index 40cdfab0c..3fab635b2 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUIRecipeSlayers.java @@ -138,7 +138,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont return ItemStackCreator.getStack("§a" + StringUtility.toNormalCase(type.name()) + " Recipes", type.getMaterial(), 1, lore); - }, (click, c) -> c.push(new GUIRecipeCategory(type), GUIRecipeCategory.createInitialState(type))); + }, (_, c) -> c.push(new GUIRecipeCategory(type), GUIRecipeCategory.createInitialState((SkyBlockPlayer) c.player(), type))); } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUISearchRecipe.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUISearchRecipe.java index bb70546d2..a96316392 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUISearchRecipe.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/recipe/GUISearchRecipe.java @@ -7,12 +7,15 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; +import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.generic.gui.HypixelSignGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.v2.*; import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.item.crafting.ShapedRecipe; +import net.swofty.type.skyblockgeneric.item.crafting.ShapelessRecipe; import net.swofty.type.skyblockgeneric.item.crafting.SkyBlockRecipe; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -122,7 +125,25 @@ public ViewConfiguration configuration() { } public static SearchState createInitialState(String query) { - return new SearchState(List.of(), 0, query); + List> recipes = new ArrayList<>(); + recipes.addAll(ShapedRecipe.CACHED_RECIPES); + recipes.addAll(ShapelessRecipe.CACHED_RECIPES); + + recipes.removeIf(recipe -> recipe.getResult().getCleanName().toLowerCase().startsWith(query.toLowerCase())); + + List shownItems = new ArrayList<>(); + recipes.removeIf(recipe -> { + ItemType itemType = recipe.getResult().getAttributeHandler().getPotentialType(); + if (shownItems.contains(itemType)) { + return true; + } else { + shownItems.add(itemType); + return false; + } + }); + + + return new SearchState(recipes, 0, query); } public record SearchState(List> items, int page, String query) implements PaginatedState> { From 9597fd3d9a2da32ef242848da4f8467aa3c6d997 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:17:43 +0200 Subject: [PATCH 25/35] feat: actually expose some views --- .../net/swofty/type/hub/npcs/villagers/VillagerLeo.java | 2 +- .../net/swofty/type/hub/npcs/villagers/VillagerTom.java | 2 +- .../gui/inventories/sbmenu/collection/GUICollections.java | 4 ++-- .../gui/inventories/sbmenu/questlog/GUIMissionLog.java | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLeo.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLeo.java index 54e04b67a..c0a746929 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLeo.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLeo.java @@ -53,7 +53,7 @@ public void onClick(NPCInteractEvent e) { if (System.currentTimeMillis() - (long) data.getMission("speak_to_villagers").getKey().getCustomData().get("last_updated") < 30) { setDialogue(player, "quest-hello").thenRun(() -> { - //new GUIRecipe(ItemType.LEAFLET_CHESTPLATE, null).open(player); + player.openView(new GUIRecipe(ItemType.LEAFLET_CHESTPLATE)); }); return; } diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerTom.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerTom.java index 4d44d3dc1..a04a2ab00 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerTom.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerTom.java @@ -53,7 +53,7 @@ public void onClick(NPCInteractEvent e) { if (System.currentTimeMillis() - (long) data.getMission("speak_to_villagers").getKey().getCustomData().get("last_updated") < 30) { setDialogue(player, "quest-hello").thenRun(() -> { - //new GUIRecipe(ItemType.PROMISING_AXE, null).open(player); + player.openView(new GUIRecipe(ItemType.PROMISING_AXE)); }); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java index 31a566c3e..7c57eba68 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/collection/GUICollections.java @@ -74,11 +74,11 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont return ItemStackCreator.getStack("§a" + category.getName() + " Collections", category.getDisplayIcon(), 1, lore); - }, (click, c) -> { + }, (_, c) -> { SkyBlockPlayer player = (SkyBlockPlayer) c.player(); ArrayList display = new ArrayList<>(); player.getCollection().getDisplay(display, category); - //new GUICollectionCategory(category, display).open(player); + player.openView(new GUICollectionCategory(category, display)); }); } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java index 4e1b508dc..d7f965c7c 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/questlog/GUIMissionLog.java @@ -64,8 +64,8 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7Forever ongoing quest...", "", "§eClick to view details!"); - }, (click, c) -> { - //new GUIFairySoulsGuide().open((SkyBlockPlayer) c.player()) + }, (_, c) -> { + c.push(new GUIFairySoulsGuide()); }); // Toggle completed/ongoing @@ -87,7 +87,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7Completed: §a" + player.getMissionData().getCompletedMissions().size(), "§7 ", "§eClick to view!"); - }, (click, c) -> c.replace(new GUIMissionLog(true))); + }, (_, c) -> c.replace(new GUIMissionLog(true))); } SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); From 6154b1397c373919cc226c1a51ed8262bab5c8e3 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:15:39 +0200 Subject: [PATCH 26/35] feat: storage views --- .../net/swofty/commons/StringUtility.java | 4 +- .../type/generic/gui/v2/ViewSession.java | 42 ++- .../inventories/sbmenu/GUISkyBlockMenu.java | 2 +- .../gui/inventories/sbmenu/bags/GUISack.java | 213 ++++++------- .../sbmenu/bags/GUISackOfSacks.java | 2 +- .../sbmenu/bestiary/BestiaryEntry.java | 1 - .../sbmenu/stats/GUIGatheringStats.java | 104 ++---- .../sbmenu/stats/GUIMiscStats.java | 102 ++---- .../sbmenu/stats/GUIWisdomStats.java | 139 ++++---- .../sbmenu/storage/GUIStorage.java | 301 ++++++++---------- .../storage/GUIStorageBackpackPage.java | 222 ++++++------- .../storage/GUIStorageIconSelection.java | 153 ++++----- .../sbmenu/storage/GUIStoragePage.java | 208 +++++------- .../item/components/SackComponent.java | 2 +- 14 files changed, 636 insertions(+), 859 deletions(-) diff --git a/commons/src/main/java/net/swofty/commons/StringUtility.java b/commons/src/main/java/net/swofty/commons/StringUtility.java index f713b5165..8ae3e1aa5 100644 --- a/commons/src/main/java/net/swofty/commons/StringUtility.java +++ b/commons/src/main/java/net/swofty/commons/StringUtility.java @@ -167,8 +167,10 @@ public static String getAsRomanNumeral(int num) { } public static String getTextFromComponent(Component component) { + if (component == null) + throw new IllegalArgumentException("Component cannot be null"); if (!(component instanceof TextComponent)) - throw new IllegalArgumentException("Component must be a TextComponent"); + throw new IllegalArgumentException("Component must be a TextComponent, but got: " + component.getClass().getSimpleName()); return PlainTextComponentSerializer.plainText().serialize(component); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 5c462b193..a01ee256c 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -67,6 +67,7 @@ public final class ViewSession { private final Int2ObjectOpenHashMap trackedSlotItems = new Int2ObjectOpenHashMap<>(); private final Set recentlyModifiedSlots = new HashSet<>(); + private final Set initializedEditableSlots = new HashSet<>(); private final Map autoUpdateTasks = new HashMap<>(); private final Map> componentSlots = new HashMap<>(); @@ -248,6 +249,11 @@ private void onCloseEvent(InventoryCloseEvent event) { close(CloseReason.PLAYER_EXITED); } + public void refresh() { + layoutDirty = true; + render(); + } + public void render() { if (closed) return; @@ -264,7 +270,7 @@ public void render() { cachedLayout.components().forEach((slot, component) -> { if (component.behavior() == SlotBehavior.EDITABLE) { - renderEditableSlot(slot); + renderEditableSlot(slot, component); return; } @@ -285,7 +291,7 @@ public void render() { cachedLayout.components().forEach((slot, component) -> { if (component.behavior() == SlotBehavior.EDITABLE) { - renderEditableSlot(slot); + renderEditableSlot(slot, component); return; } renderSlot(slot, component); @@ -294,16 +300,40 @@ public void render() { view.onRefresh(state, context); } - private void renderEditableSlot(int slot) { + private void renderEditableSlot(int slot, ViewComponent component) { if (sharedContext != null) { ItemStack contextItem = sharedContext.getSlotItem(slot); + if (!initializedEditableSlots.contains(slot)) { + if (contextItem.isAir()) { + ItemStack initialItem = component.render().apply(state, context).build(); + if (!initialItem.isAir()) { + inventory.setItemStack(slot, initialItem); + sharedContext.setSlotItem(slot, initialItem); + contextItem = initialItem; + } + } + initializedEditableSlots.add(slot); + } if (!inventory.getItemStack(slot).equals(contextItem)) { inventory.setItemStack(slot, contextItem); } trackedSlotItems.put(slot, contextItem); - } else if (!recentlyModifiedSlots.contains(slot)) { - ItemStack currentItem = inventory.getItemStack(slot); - trackedSlotItems.put(slot, currentItem); + } else { + if (!initializedEditableSlots.contains(slot)) { + ItemStack currentItem = inventory.getItemStack(slot); + if (currentItem.isAir()) { + ItemStack initialItem = component.render().apply(state, context).build(); + if (!initialItem.isAir()) { + inventory.setItemStack(slot, initialItem); + currentItem = initialItem; + } + } + initializedEditableSlots.add(slot); + trackedSlotItems.put(slot, currentItem); + } else if (!recentlyModifiedSlots.contains(slot)) { + ItemStack currentItem = inventory.getItemStack(slot); + trackedSlotItems.put(slot, currentItem); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java index 1ebbc7d03..a76c22bc3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/GUISkyBlockMenu.java @@ -141,7 +141,7 @@ public void layout(ViewLayout layout, DefaultState state, ViewCont "§7from anywhere here.", " ", "§eClick to view!" - ), (click, c) -> new GUIStorage().open((SkyBlockPlayer) c.player())); + ), (click, c) -> c.push(new GUIStorage())); layout.slot(23, (s, c) -> ItemStackCreator.getStack("§aQuests & Chapters", Material.WRITABLE_BOOK, 1, "§7Each island has its own series of", diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISack.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISack.java index 4c30b9a74..652310c64 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISack.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISack.java @@ -1,18 +1,15 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bags; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.SackComponent; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; @@ -22,9 +19,10 @@ import java.util.Comparator; import java.util.List; -public class GUISack extends HypixelInventoryGUI { - ItemType itemTypeLinker; - Boolean closeGUIButton; +public class GUISack implements StatefulView { + private final ItemType itemTypeLinker; + private final boolean closeGUIButton; + private final SackSize sackSize; private static final List SACK_SIZES = List.of( new SackSize(14, InventoryType.CHEST_4_ROW, List.of( @@ -54,40 +52,38 @@ private static SackSize getSackSize(ItemType sack) { .orElse(SACK_SIZES.getLast()); } - public GUISack(ItemType sack, Boolean closeGUIButton) { - super(StringUtility.toNormalCase(sack.name()), getSackSize(sack).getInventoryType()); + public GUISack(ItemType sack, boolean closeGUIButton) { this.itemTypeLinker = sack; this.closeGUIButton = closeGUIButton; + this.sackSize = getSackSize(sack); } + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>(StringUtility.toNormalCase(itemTypeLinker.name()), sackSize.getInventoryType()); + } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - if (!closeGUIButton) { - int backSlot = switch (GUISack.super.size) { - case InventoryType.CHEST_4_ROW -> 31; - case InventoryType.CHEST_5_ROW -> 40; - case InventoryType.CHEST_6_ROW -> 49; - default -> 31; - }; - set(new GUIClickableItem(backSlot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISackOfSacks()); - } + public SackState initialState() { + return new SackState(); + } - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To Sack of Sacks"); - } - }); + @Override + public void layout(ViewLayout layout, SackState state, ViewContext ctx) { + Components.fill(layout); + + int backSlot = switch (sackSize.getInventoryType()) { + case InventoryType.CHEST_4_ROW -> 31; + case InventoryType.CHEST_5_ROW -> 40; + case InventoryType.CHEST_6_ROW -> 49; + default -> 31; + }; + + if (!closeGUIButton) { + layout.slot(backSlot, (s, c) -> ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To Sack of Sacks"), + (click, c) -> c.player().openView(new GUISackOfSacks())); } else { - switch (GUISack.super.size) { - case InventoryType.CHEST_4_ROW -> set(GUIClickableItem.getCloseItem(31)); - case InventoryType.CHEST_5_ROW -> set(GUIClickableItem.getCloseItem(40)); - case InventoryType.CHEST_6_ROW -> set(GUIClickableItem.getCloseItem(49)); - } + Components.close(layout, backSlot); } List sackItems = new ArrayList<>(); @@ -100,99 +96,78 @@ public ItemStack.Builder getItem(HypixelPlayer player) { } } - int index = 0; - for (Integer slot : getSackSize(itemTypeLinker).getSlots()) { - int finalMaxStorage = ((SkyBlockPlayer) e.player()).getMaxSackStorage(itemTypeLinker); - int finalIndex = index; + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + int finalMaxStorage = player.getMaxSackStorage(itemTypeLinker); - if (finalIndex < sackItems.size()) { + int index = 0; + for (Integer slot : sackSize.getSlots()) { + if (index < sackItems.size()) { SkyBlockItem skyBlockItem = sackItems.get(index); ItemType linker = skyBlockItem.getAttributeHandler().getPotentialType(); - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - Integer amount = player.getSackItems().getAmount(linker); - if (e.getClick() instanceof Click.Right) { - if (amount == 0) return; - if (amount >= 64) { - player.getSackItems().decrease(linker, 64); - SkyBlockItem itemAdded = new SkyBlockItem(linker); - itemAdded.setAmount(64); - player.addAndUpdateItem(itemAdded); - new GUISack(itemTypeLinker, closeGUIButton).open(player); - } else { - player.getSackItems().decrease(linker, amount); - SkyBlockItem itemAdded = new SkyBlockItem(linker); - itemAdded.setAmount(amount); - player.addAndUpdateItem(itemAdded); - new GUISack(itemTypeLinker, closeGUIButton).open(player); - } - } else if (e.getClick() instanceof Click.Left) { - int airSlots = 0; - for (ItemStack itemStack : player.getInventory().getItemStacks()) { - if (itemStack.isAir()) airSlots++; - } - int maxSpace = 64 * airSlots; - if (amount >= maxSpace) { - player.getSackItems().decrease(linker, maxSpace); - SkyBlockItem itemAdded = new SkyBlockItem(linker); - itemAdded.setAmount(64); - for (int i = 0; i < airSlots; i++) { - player.addAndUpdateItem(itemAdded); - } - new GUISack(itemTypeLinker, closeGUIButton).open(player); - } else { - player.getSackItems().decrease(linker, amount); - SkyBlockItem itemAdded = new SkyBlockItem(linker); - itemAdded.setAmount(amount); - player.addAndUpdateItem(itemAdded); - new GUISack(itemTypeLinker, closeGUIButton).open(player); - } - } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ItemStack.Builder builder = PlayerItemUpdater.playerUpdate(player, skyBlockItem.getItemStack()); - ArrayList lore = new ArrayList<>(); - Integer amount = player.getSackItems().getAmount(linker); - String color = (amount == finalMaxStorage) ? "§a" : "§e"; - lore.add(""); - lore.add("§7Stored: " + color + amount + "§7/" + StringUtility.shortenNumber(StringUtility.roundTo(finalMaxStorage, 0))); - lore.add(""); - if (amount != 0) { - lore.add("§bRight-Click for stack!"); - lore.add("§eClick to pickup!"); - } else { - lore.add("§8Empty sack!"); - } - return ItemStackCreator.updateLore(builder, lore); + int finalIndex = index; + + layout.slot(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + ItemStack.Builder builder = PlayerItemUpdater.playerUpdate(p, skyBlockItem.getItemStack()); + ArrayList lore = new ArrayList<>(); + Integer amount = p.getSackItems().getAmount(linker); + String color = (amount == finalMaxStorage) ? "§a" : "§e"; + lore.add(""); + lore.add("§7Stored: " + color + amount + "§7/" + StringUtility.shortenNumber(StringUtility.roundTo(finalMaxStorage, 0))); + lore.add(""); + if (amount != 0) { + lore.add("§bRight-Click for stack!"); + lore.add("§eClick to pickup!"); + } else { + lore.add("§8Empty sack!"); } - }); + return ItemStackCreator.updateLore(builder, lore); + }, (click, c) -> handleSackItemClick(click, c, linker)); } index++; } - updateItemStacks(getInventory(), getPlayer()); } - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - + private void handleSackItemClick(ClickContext click, ViewContext ctx, ItemType linker) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + Integer amount = player.getSackItems().getAmount(linker); + + if (click.click() instanceof Click.Right) { + if (amount == 0) return; + if (amount >= 64) { + player.getSackItems().decrease(linker, 64); + SkyBlockItem itemAdded = new SkyBlockItem(linker); + itemAdded.setAmount(64); + player.addAndUpdateItem(itemAdded); + } else { + player.getSackItems().decrease(linker, amount); + SkyBlockItem itemAdded = new SkyBlockItem(linker); + itemAdded.setAmount(amount); + player.addAndUpdateItem(itemAdded); + } + ctx.session(SackState.class).refresh(); + } else if (click.click() instanceof Click.Left) { + int airSlots = 0; + for (ItemStack itemStack : player.getInventory().getItemStacks()) { + if (itemStack.isAir()) airSlots++; + } + int maxSpace = 64 * airSlots; + if (amount >= maxSpace) { + player.getSackItems().decrease(linker, maxSpace); + SkyBlockItem itemAdded = new SkyBlockItem(linker); + itemAdded.setAmount(64); + for (int i = 0; i < airSlots; i++) { + player.addAndUpdateItem(itemAdded); + } + } else { + player.getSackItems().decrease(linker, amount); + SkyBlockItem itemAdded = new SkyBlockItem(linker); + itemAdded.setAmount(amount); + player.addAndUpdateItem(itemAdded); + } + ctx.session(SackState.class).refresh(); + } } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } + public record SackState() {} } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java index 35cc2a056..ea277cc92 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bags/GUISackOfSacks.java @@ -68,7 +68,7 @@ public void layout(ViewLayout layout, SackOfSacksState state, if (click.click() instanceof Click.Right) { SkyBlockItem skyBlockItem = new SkyBlockItem(c.inventory().getItemStack(slotIndex)); if (skyBlockItem.isNA() || skyBlockItem.isAir()) return; - new GUISack(skyBlockItem.getAttributeHandler().getPotentialType(), false).open(p); + c.push(new GUISack(skyBlockItem.getAttributeHandler().getPotentialType(), true)); } }); diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/BestiaryEntry.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/BestiaryEntry.java index d9367c016..efde68aad 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/BestiaryEntry.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/bestiary/BestiaryEntry.java @@ -1,6 +1,5 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.bestiary; -import net.minestom.server.item.Material; import net.swofty.type.generic.gui.inventory.item.GUIMaterial; import net.swofty.type.skyblockgeneric.entity.mob.BestiaryMob; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIGatheringStats.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIGatheringStats.java index 897bfc7a6..080a4253f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIGatheringStats.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIGatheringStats.java @@ -1,20 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.stats; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.statistics.ItemStatistic; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; import net.swofty.type.generic.gui.inventory.item.GUIMaterial; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockProfile; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.user.statistics.PlayerStatistics; @@ -22,7 +15,7 @@ import java.util.List; import java.util.function.Function; -public class GUIGatheringStats extends HypixelInventoryGUI { +public class GUIGatheringStats extends StatelessView { private static final String[] multiplesMap = new String[]{ "§adouble", @@ -483,7 +476,7 @@ public List buildLore(SkyBlockPlayer player) { return lore; } - public ItemStack.Builder buildItemStack(SkyBlockPlayer player) { + public net.minestom.server.item.ItemStack.Builder buildItemStack(SkyBlockPlayer player) { double value = player.getStatistics().allStatistics().getOverall(statistic); String title = statistic.getFullDisplayName() + " §f" + StringUtility.decimalify(value, 1); @@ -493,75 +486,48 @@ public ItemStack.Builder buildItemStack(SkyBlockPlayer player) { } } - public GUIGatheringStats() { - super("Your Stats Breakdown", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Your Stats Breakdown", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - //set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); - set(GUIClickableItem.getCloseItem(49)); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7Lets you collect and harvest better", "§7items, or more of them. ", " ")); - List stats = new ArrayList<>(List.of(ItemStatistic.MINING_SPEED, ItemStatistic.MINING_FORTUNE, ItemStatistic.BREAKING_POWER, - ItemStatistic.PRISTINE, ItemStatistic.FORAGING_FORTUNE, ItemStatistic.FARMING_FORTUNE, ItemStatistic.MINING_SPREAD, ItemStatistic.GEMSTONE_SPREAD, - ItemStatistic.HUNTER_FORTUNE, ItemStatistic.SWEEP, ItemStatistic.ORE_FORTUNE, ItemStatistic.BLOCK_FORTUNE, ItemStatistic.DWARVEN_METAL_FORTUNE, - ItemStatistic.GEMSTONE_FORTUNE, ItemStatistic.WHEAT_FORTUNE, ItemStatistic.POTATO_FORTUNE, ItemStatistic.CARROT_FORTUNE, ItemStatistic.PUMPKIN_FORTUNE, - ItemStatistic.MELON_FORTUNE, ItemStatistic.CACTUS_FORTUNE, ItemStatistic.NETHER_WART_FORTUNE, ItemStatistic.COCOA_BEANS_FORTUNE, ItemStatistic.MUSHROOM_FORTUNE, - ItemStatistic.SUGAR_CANE_FORTUNE, ItemStatistic.FIG_FORTUNE, ItemStatistic.MANGROVE_FORTUNE - )); - - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (stats.contains(statistic)) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.back(layout, 48, ctx); + Components.close(layout, 49); + + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7Lets you collect and harvest better", "§7items, or more of them. ", " ")); + List stats = new ArrayList<>(List.of(ItemStatistic.MINING_SPEED, ItemStatistic.MINING_FORTUNE, ItemStatistic.BREAKING_POWER, + ItemStatistic.PRISTINE, ItemStatistic.FORAGING_FORTUNE, ItemStatistic.FARMING_FORTUNE, ItemStatistic.MINING_SPREAD, ItemStatistic.GEMSTONE_SPREAD, + ItemStatistic.HUNTER_FORTUNE, ItemStatistic.SWEEP, ItemStatistic.ORE_FORTUNE, ItemStatistic.BLOCK_FORTUNE, ItemStatistic.DWARVEN_METAL_FORTUNE, + ItemStatistic.GEMSTONE_FORTUNE, ItemStatistic.WHEAT_FORTUNE, ItemStatistic.POTATO_FORTUNE, ItemStatistic.CARROT_FORTUNE, ItemStatistic.PUMPKIN_FORTUNE, + ItemStatistic.MELON_FORTUNE, ItemStatistic.CACTUS_FORTUNE, ItemStatistic.NETHER_WART_FORTUNE, ItemStatistic.COCOA_BEANS_FORTUNE, ItemStatistic.MUSHROOM_FORTUNE, + ItemStatistic.SUGAR_CANE_FORTUNE, ItemStatistic.FIG_FORTUNE, ItemStatistic.MANGROVE_FORTUNE + )); + + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (stats.contains(statistic)) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); + } + }); - return ItemStackCreator.getStack("§eGathering Stats", Material.IRON_PICKAXE, 1, lore); - } + return ItemStackCreator.getStack("§eGathering Stats", Material.IRON_PICKAXE, 1, lore); }); for (GatheringStat stat : GatheringStat.values()) { - set(new GUIClickableItem(stat.slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.sendMessage("§aUnder construction!"); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return stat.buildItemStack((SkyBlockPlayer) p); - } - }); + layout.slot(stat.slot, (s, c) -> stat.buildItemStack((SkyBlockPlayer) c.player()), + (click, c) -> ((SkyBlockPlayer) c.player()).sendMessage("§aUnder construction!")); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { } @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(false); + public boolean onBottomClick(net.swofty.type.generic.gui.v2.context.ClickContext click, ViewContext ctx) { + return true; } private static void addFormateNumberLore(double value, String type, ItemStatistic statistic, List lore) { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIMiscStats.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIMiscStats.java index 928a804d9..7d9da98b4 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIMiscStats.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIMiscStats.java @@ -1,20 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.stats; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.statistics.ItemStatistic; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; import net.swofty.type.generic.gui.inventory.item.GUIMaterial; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockProfile; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.user.statistics.PlayerStatistics; @@ -22,7 +15,7 @@ import java.util.List; import java.util.function.Function; -public class GUIMiscStats extends HypixelInventoryGUI { +public class GUIMiscStats extends StatelessView { private enum MiscStat { SPEED(10, ItemStatistic.SPEED, new GUIMaterial(Material.SUGAR), @@ -171,7 +164,7 @@ public List buildLore(SkyBlockPlayer player) { return lore; } - public ItemStack.Builder buildItemStack(SkyBlockPlayer player) { + public net.minestom.server.item.ItemStack.Builder buildItemStack(SkyBlockPlayer player) { double value = player.getStatistics().allStatistics().getOverall(statistic); String title = statistic.getFullDisplayName() + " §f" + StringUtility.decimalify(value, 1); @@ -181,73 +174,46 @@ public ItemStack.Builder buildItemStack(SkyBlockPlayer player) { } } - public GUIMiscStats() { - super("Your Stats Breakdown", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Your Stats Breakdown", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - //set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); - set(GUIClickableItem.getCloseItem(49)); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7Augments various aspects of your", "§7gameplay! ", " ")); - List stats = new ArrayList<>(List.of( - ItemStatistic.SPEED, ItemStatistic.MAGIC_FIND, ItemStatistic.PET_LUCK, - ItemStatistic.COLD_RESISTANCE, ItemStatistic.BONUS_PEST_CHANCE, - ItemStatistic.HEAT_RESISTANCE, ItemStatistic.FEAR, ItemStatistic.PULL, - ItemStatistic.RESPIRATION, ItemStatistic.PRESSURE_RESISTANCE - )); - - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (stats.contains(statistic)) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.back(layout, 48, ctx); + Components.close(layout, 49); + + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7Augments various aspects of your", "§7gameplay! ", " ")); + List stats = new ArrayList<>(List.of( + ItemStatistic.SPEED, ItemStatistic.MAGIC_FIND, ItemStatistic.PET_LUCK, + ItemStatistic.COLD_RESISTANCE, ItemStatistic.BONUS_PEST_CHANCE, + ItemStatistic.HEAT_RESISTANCE, ItemStatistic.FEAR, ItemStatistic.PULL, + ItemStatistic.RESPIRATION, ItemStatistic.PRESSURE_RESISTANCE + )); + + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (stats.contains(statistic)) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); + } + }); - return ItemStackCreator.getStack("§dMisc Stats", Material.CLOCK, 1, lore); - } + return ItemStackCreator.getStack("§dMisc Stats", Material.CLOCK, 1, lore); }); for (MiscStat stat : MiscStat.values()) { - set(new GUIClickableItem(stat.slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.sendMessage("§aUnder construction!"); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return stat.buildItemStack((SkyBlockPlayer) p); - } - }); + layout.slot(stat.slot, (s, c) -> stat.buildItemStack((SkyBlockPlayer) c.player()), + (click, c) -> ((SkyBlockPlayer) c.player()).sendMessage("§aUnder construction!")); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { } @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(false); + public boolean onBottomClick(net.swofty.type.generic.gui.v2.context.ClickContext click, ViewContext ctx) { + return true; } } \ No newline at end of file diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIWisdomStats.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIWisdomStats.java index d9182526f..c05a80e68 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIWisdomStats.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/stats/GUIWisdomStats.java @@ -1,19 +1,12 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.stats; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.statistics.ItemStatistic; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockProfile; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.skyblockgeneric.user.statistics.PlayerStatistics; @@ -21,7 +14,7 @@ import java.util.List; import java.util.Map; -public class GUIWisdomStats extends HypixelInventoryGUI { +public class GUIWisdomStats extends StatelessView { private static final Map displaySlots = Map.ofEntries( Map.entry(10, ItemStatistic.COMBAT_WISDOM), @@ -38,94 +31,70 @@ public class GUIWisdomStats extends HypixelInventoryGUI { Map.entry(23, ItemStatistic.HUNTING_WISDOM) ); - public GUIWisdomStats() { - super("Your Stats Breakdown", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Your Stats Breakdown", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - //set(GUIClickableItem.getGoBackItem(48, new GUISkyBlockProfile())); - set(GUIClickableItem.getCloseItem(49)); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - PlayerStatistics statistics = player.getStatistics(); - List lore = new ArrayList<>(List.of("§7Increases the §3XP §7you gain on your", "§7skills ", " ")); - List stats = new ArrayList<>(List.of(ItemStatistic.COMBAT_WISDOM, ItemStatistic.MINING_WISDOM, ItemStatistic.FARMING_WISDOM, ItemStatistic.FORAGING_WISDOM, - ItemStatistic.FISHING_WISDOM, ItemStatistic.ENCHANTING_WISDOM, ItemStatistic.ALCHEMY_WISDOM, ItemStatistic.CARPENTRY_WISDOM, ItemStatistic.RUNE_CRAFTING_WISDOM, - ItemStatistic.SOCIAL_WISDOM, ItemStatistic.TAMING_WISDOM, ItemStatistic.HUNTING_WISDOM - )); // WISDOM STATS - statistics.allStatistics().getOverall().forEach((statistic, value) -> { - if (stats.contains(statistic)) { - lore.add(" " + statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 2) + statistic.getSuffix()); - } - }); + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.close(layout, 49); + + layout.slot(4, (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + PlayerStatistics statistics = player.getStatistics(); + List lore = new ArrayList<>(List.of("§7Increases the §3XP §7you gain on your", "§7skills ", " ")); + List stats = new ArrayList<>(List.of(ItemStatistic.COMBAT_WISDOM, ItemStatistic.MINING_WISDOM, ItemStatistic.FARMING_WISDOM, ItemStatistic.FORAGING_WISDOM, + ItemStatistic.FISHING_WISDOM, ItemStatistic.ENCHANTING_WISDOM, ItemStatistic.ALCHEMY_WISDOM, ItemStatistic.CARPENTRY_WISDOM, ItemStatistic.RUNE_CRAFTING_WISDOM, + ItemStatistic.SOCIAL_WISDOM, ItemStatistic.TAMING_WISDOM, ItemStatistic.HUNTING_WISDOM + )); + statistics.allStatistics().getOverall().forEach((statistic, value) -> { + if (stats.contains(statistic)) { + lore.add(" " + statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 2) + statistic.getSuffix()); + } + }); - return ItemStackCreator.getStack("§3Wisdom Stats", Material.BOOK, 1, lore); - } + return ItemStackCreator.getStack("§3Wisdom Stats", Material.BOOK, 1, lore); }); for (Map.Entry entry : displaySlots.entrySet()) { - set(new GUIClickableItem(entry.getKey()) { - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ItemStatistic statistic = entry.getValue(); - double value = player.getStatistics().allStatistics().getOverall(statistic); - double multiplier = 1D + value / 100D; - List lore = new ArrayList<>(); - - lore.add("§7" + statistic.getDisplayName() + " increases how much"); - lore.add("§7" + statistic.getDisplayName().split(" ")[0] + " Skill XP that you gain."); - lore.add(" "); - - if (value == 0D) { - lore.add("§8You aren't learning any faster, yet!"); - } else { - lore.add("§7XP Multiplier: " + statistic.getDisplayColor() - + StringUtility.decimalify(multiplier, 2) + "x"); - } - - lore.add(" "); - - if (value == 0D) lore.add("§8You have none of this stat!"); - lore.add("§eClick to view!"); - return ItemStackCreator.getStack(statistic.getFullDisplayName() + " §f" + - StringUtility.decimalify(value, 1), - Material.WRITABLE_BOOK, 1, lore - ); + ItemStatistic statistic = entry.getValue(); + + layout.slot(entry.getKey(), (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + double value = player.getStatistics().allStatistics().getOverall(statistic); + double multiplier = 1D + value / 100D; + List lore = new ArrayList<>(); + + lore.add("§7" + statistic.getDisplayName() + " increases how much"); + lore.add("§7" + statistic.getDisplayName().split(" ")[0] + " Skill XP that you gain."); + lore.add(" "); + + if (value == 0D) { + lore.add("§8You aren't learning any faster, yet!"); + } else { + lore.add("§7XP Multiplier: " + statistic.getDisplayColor() + + StringUtility.decimalify(multiplier, 2) + "x"); } - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.sendMessage("§aUnder construction!"); - } + lore.add(" "); + + if (value == 0D) lore.add("§8You have none of this stat!"); + lore.add("§eClick to view!"); + return ItemStackCreator.getStack(statistic.getFullDisplayName() + " §f" + + StringUtility.decimalify(value, 1), + Material.WRITABLE_BOOK, 1, lore + ); + }, (click, c) -> { + ((SkyBlockPlayer) c.player()).sendMessage("§aUnder construction!"); }); } - - updateItemStacks(getInventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { } @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(false); + public boolean onBottomClick(net.swofty.type.generic.gui.v2.context.ClickContext click, ViewContext ctx) { + return true; } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java index 3c9957b36..fc27834d2 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorage.java @@ -1,23 +1,17 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.storage; -import net.minestom.server.event.inventory.InventoryClickEvent; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.UnderstandableSkyBlockItem; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointBackpacks; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointStorage; -import net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.GUISkyBlockMenu; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.BackpackComponent; import net.swofty.type.skyblockgeneric.item.components.SkullHeadComponent; @@ -26,47 +20,31 @@ import java.util.Map; -public class GUIStorage extends HypixelInventoryGUI { - public GUIStorage() { - super("Storage", InventoryType.CHEST_6_ROW); +public class GUIStorage extends StatelessView { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); - set(GUIClickableItem.getCloseItem(49)); - set(new GUIClickableItem(48) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.openView(new GUISkyBlockMenu()); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To SkyBlock Menu"); - } - }); - - set(new GUIItem(4) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aEnder Chest", Material.ENDER_CHEST, 1, - "§7Store global items you can", - "§7access anywhere in your ender", - "§7chest."); - } - }); - set(new GUIItem(22) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§aBackpacks", Material.CHEST, 1, - "§7Place backpack items in these slots", - "§7to use them as additional storage", - "§7that can be accessed anywhere."); - } - }); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Storage", InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - DatapointStorage.PlayerStorage storage = ((SkyBlockPlayer) getPlayer()).getSkyblockDataHandler().get( + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + Components.fill(layout); + Components.back(layout, 48, ctx); + Components.close(layout, 49); + + layout.slot(4, (s, c) -> ItemStackCreator.getStack("§aEnder Chest", Material.ENDER_CHEST, 1, + "§7Store global items you can", + "§7access anywhere in your ender", + "§7chest.")); + + layout.slot(22, (s, c) -> ItemStackCreator.getStack("§aBackpacks", Material.CHEST, 1, + "§7Place backpack items in these slots", + "§7to use them as additional storage", + "§7that can be accessed anywhere.")); + + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + DatapointStorage.PlayerStorage storage = player.getSkyblockDataHandler().get( SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class ).getValue(); @@ -76,179 +54,152 @@ public void onOpen(InventoryGUIOpenEvent e) { storage.addPage(2); } - for (int ender_slot = 9; ender_slot < 18; ender_slot++) { - int page = ender_slot - 8; - - set(new GUIClickableItem(ender_slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!storage.hasPage(page)) return; - - if (e.getClick() instanceof Click.Right) { - new GUIStorageIconSelection(page, GUIStorage.this).open(player); - } else { - new GUIStoragePage(page).open(player); - } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - if (!storage.hasPage(page)) - return ItemStackCreator.getStack("§cLocked Page", Material.RED_STAINED_GLASS_PANE, 1, - "§7Unlock more Ender Chest pages in", - "§7the community shop!"); - - Material material = storage.getPage(page).display; - - return ItemStackCreator.getStack("§aEnder Chest Page " + (page), material, page, - " ", - "§eLeft-click to open!", - "§eRight-click to change icon!"); + // Ender chest pages (slots 9-17) + for (int enderSlot = 9; enderSlot < 18; enderSlot++) { + int page = enderSlot - 8; + + layout.slot(enderSlot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + DatapointStorage.PlayerStorage playerStorage = p.getSkyblockDataHandler().get( + SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class + ).getValue(); + + if (!playerStorage.hasPage(page)) + return ItemStackCreator.getStack("§cLocked Page", Material.RED_STAINED_GLASS_PANE, 1, + "§7Unlock more Ender Chest pages in", + "§7the community shop!"); + + Material material = playerStorage.getPage(page).display; + + return ItemStackCreator.getStack("§aEnder Chest Page " + page, material, page, + " ", + "§eLeft-click to open!", + "§eRight-click to change icon!"); + }, (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + DatapointStorage.PlayerStorage playerStorage = p.getSkyblockDataHandler().get( + SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class + ).getValue(); + + if (!playerStorage.hasPage(page)) return; + + if (click.click() instanceof Click.Right) { + p.openView(new GUIStorageIconSelection(page), GUIStorageIconSelection.initialState()); + } else { + p.openView(new GUIStoragePage(page)); } }); } - DatapointBackpacks.PlayerBackpacks backpacks = ((SkyBlockPlayer) getPlayer()).getSkyblockDataHandler().get( + // Backpack slots (slots 27-44) + DatapointBackpacks.PlayerBackpacks backpacks = player.getSkyblockDataHandler().get( SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class ).getValue(); Map backpackItems = backpacks.getBackpacks(); - for (int backpack_slot = 27; backpack_slot <= 44; backpack_slot++) { - int slot = backpack_slot - 26; + for (int backpackSlot = 27; backpackSlot <= 44; backpackSlot++) { + int slot = backpackSlot - 26; if (backpacks.getUnlockedSlots() < slot) { - set(new GUIItem(backpack_slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§cLocked Backpack Slot " + slot, - Material.GRAY_DYE, 1, - "§7Talk to Tia the Fairy to unlock more", - "§7Backpack Slots!"); - } - }); + layout.slot(backpackSlot, (s, c) -> ItemStackCreator.getStack("§cLocked Backpack Slot " + slot, + Material.GRAY_DYE, 1, + "§7Talk to Tia the Fairy to unlock more", + "§7Backpack Slots!")); continue; } if (!backpackItems.containsKey(slot)) { - set(new GUIClickableItem(backpack_slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockItem item = new SkyBlockItem(p.getInventory().getCursorItem()); - - if (item.isNA()) return; - if (!(item.hasComponent(BackpackComponent.class))) return; - - e.setCancelled(false); - } - - @Override - public void runPost(InventoryClickEvent e2, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockItem item = new SkyBlockItem(e2.getCursorItem()); - - if (item.isNA()) return; - if (!(item.hasComponent(BackpackComponent.class))) return; - - backpackItems.put(slot, item.toUnderstandable()); - player.getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).setValue( - new DatapointBackpacks.PlayerBackpacks(backpackItems, backpacks.getUnlockedSlots()) - ); - - player.sendMessage("§ePlacing backpack in slot " + slot + "..."); - player.sendMessage("§aSuccess!"); - p.getInventory().setCursorItem(ItemStack.AIR); - - onOpen(e); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack("§eEmpty Backpack Slot " + slot, + layout.slot(backpackSlot, (s, c) -> ItemStackCreator.getStack("§eEmpty Backpack Slot " + slot, Material.BROWN_STAINED_GLASS_PANE, slot, " ", "§eLeft-click a backpack item on this", - "§eslot to place it!"); - } - }); + "§eslot to place it!"), + (click, c) -> handleEmptyBackpackSlotClick(click, c, slot)); continue; } SkyBlockItem item = new SkyBlockItem(backpackItems.get(slot)); - set(new GUIClickableItem(backpack_slot) { - @Override - public void run(InventoryPreClickEvent e2, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (e2.getClick() instanceof Click.Right) { - if (!item.getAttributeHandler().getBackpackData().items().isEmpty() - && !item.getAttributeHandler().getBackpackData().items() - .stream() - .map(SkyBlockItem::new).allMatch(SkyBlockItem::isNA)) { - player.sendMessage("§cThe backpack in slot " + slot + " is not empty! Please empty it before removing it."); - return; - } - - player.sendMessage("§aRemoved backpack from slot " + slot + "!"); - p.getInventory().setCursorItem(PlayerItemUpdater.playerUpdate(player, item.getItemStack()).build()); - e2.setCancelled(true); - - backpackItems.remove(slot); - onOpen(e); + layout.slot(backpackSlot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + return ItemStackCreator.getStackHead("§6Backpack Slot " + slot, + item.getComponent(SkullHeadComponent.class).getSkullTexture(item), slot, + item.getAttributeHandler().getRarity().getColor() + + item.getAttributeHandler().getPotentialType().getDisplayName(), + "§7This backpack has §a" + (item.getComponent(BackpackComponent.class).getRows() * 9) + " §7slots.", + " ", + "§eLeft-click to open!", + "§eRight-click to remove!"); + }, (click, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + DatapointBackpacks.PlayerBackpacks playerBackpacks = p.getSkyblockDataHandler().get( + SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class + ).getValue(); + Map playerBackpackItems = playerBackpacks.getBackpacks(); + SkyBlockItem backpackItem = new SkyBlockItem(playerBackpackItems.get(slot)); + + if (click.click() instanceof Click.Right) { + if (!backpackItem.getAttributeHandler().getBackpackData().items().isEmpty() + && !backpackItem.getAttributeHandler().getBackpackData().items() + .stream() + .map(SkyBlockItem::new).allMatch(SkyBlockItem::isNA)) { + p.sendMessage("§cThe backpack in slot " + slot + " is not empty! Please empty it before removing it."); return; } - new GUIStorageBackpackPage(slot, item).open(player); - } + p.sendMessage("§aRemoved backpack from slot " + slot + "!"); + p.getInventory().setCursorItem(PlayerItemUpdater.playerUpdate(p, backpackItem.getItemStack()).build()); - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStackHead("§6Backpack Slot " + slot, - item.getComponent(SkullHeadComponent.class).getSkullTexture(item), slot, - item.getAttributeHandler().getRarity().getColor() + - item.getAttributeHandler().getPotentialType().getDisplayName(), - "§7This backpack has §a" + (item.getComponent(BackpackComponent.class).getRows() * 9) + " §7slots.", - " ", - "§eLeft-click to open!", - "§eRight-click to remove!"); + playerBackpackItems.remove(slot); + c.session(DefaultState.class).refresh(); + return; } + + p.openView(new GUIStorageBackpackPage(slot, backpackItem)); }); } - - updateItemStacks(getInventory(), getPlayer()); } - @Override - public boolean allowHotkeying() { - return false; - } + private void handleEmptyBackpackSlotClick(ClickContext click, ViewContext ctx, int slot) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockItem item = new SkyBlockItem(player.getInventory().getCursorItem()); - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { + if (item.isNA()) return; + if (!(item.hasComponent(BackpackComponent.class))) return; - } + DatapointBackpacks.PlayerBackpacks backpacks = player.getSkyblockDataHandler().get( + SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class + ).getValue(); + Map backpackItems = backpacks.getBackpacks(); - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { + backpackItems.put(slot, item.toUnderstandable()); + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).setValue( + new DatapointBackpacks.PlayerBackpacks(backpackItems, backpacks.getUnlockedSlots()) + ); + player.sendMessage("§ePlacing backpack in slot " + slot + "..."); + player.sendMessage("§aSuccess!"); + player.getInventory().setCursorItem(ItemStack.AIR); + + ctx.session(DefaultState.class).refresh(); } @Override - public void onBottomClick(InventoryPreClickEvent e) { - ItemStack cursorItem = e.getPlayer().getInventory().getCursorItem(); + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + ItemStack cursorItem = player.getInventory().getCursorItem(); SkyBlockItem cursorItemAsItem = new SkyBlockItem(cursorItem); - if (cursorItemAsItem.isNA()) return; - if (cursorItemAsItem.hasComponent(BackpackComponent.class)) return; + if (cursorItemAsItem.isNA()) return false; + if (cursorItemAsItem.hasComponent(BackpackComponent.class)) return true; - ItemStack clickedItem = e.getClickedItem(); + ItemStack clickedItem = player.getInventory().getItemStack(click.slot()); SkyBlockItem clickedItemAsItem = new SkyBlockItem(clickedItem); - if (clickedItemAsItem.isNA()) return; - if (clickedItemAsItem.hasComponent(BackpackComponent.class)) return; + if (clickedItemAsItem.isNA()) return false; + if (clickedItemAsItem.hasComponent(BackpackComponent.class)) return true; - e.setCancelled(true); + return false; } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorageBackpackPage.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorageBackpackPage.java index 5c71142e9..e20ba92b3 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorageBackpackPage.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorageBackpackPage.java @@ -1,17 +1,14 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.storage; import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; +import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.utility.MathUtility; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointBackpacks; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; @@ -20,148 +17,131 @@ import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import java.util.concurrent.atomic.AtomicInteger; - -public class GUIStorageBackpackPage extends HypixelInventoryGUI { - public int page; - public int slots; - public SkyBlockItem item; +public class GUIStorageBackpackPage extends StatelessView { + private final int page; + private final int slots; + private final SkyBlockItem item; + private final String title; + private final InventoryType inventoryType; public GUIStorageBackpackPage(int page, SkyBlockItem item) { - super(StringUtility.getTextFromComponent(new NonPlayerItemUpdater(item).getUpdatedItem().build() - .get(DataComponents.CUSTOM_NAME)) - + " (Slot #" + page + ")", - MathUtility.getFromSize(9 + item.getComponent(BackpackComponent.class).getRows() * 9)); - - this.slots = item.getComponent(BackpackComponent.class).getRows() * 9; this.page = page; this.item = item; + this.slots = item.getComponent(BackpackComponent.class).getRows() * 9; + this.title = StringUtility.getTextFromComponent(new NonPlayerItemUpdater(item).getUpdatedItem().build() + .get(DataComponents.CUSTOM_NAME)) + " (Slot #" + page + ")"; + this.inventoryType = MathUtility.getFromSize(9 + slots); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - SkyBlockPlayer player = (SkyBlockPlayer) getPlayer(); - DatapointBackpacks.PlayerBackpacks data = player.getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).getValue(); - - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE), 0, 8); + public ViewConfiguration configuration() { + return new ViewConfiguration<>(title, inventoryType); + } - set(GUIClickableItem.getCloseItem(0)); - set(GUIClickableItem.getGoBackItem(1, new GUIStorage())); + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + DatapointBackpacks.PlayerBackpacks data = player.getSkyblockDataHandler() + .get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).getValue(); + + // Fill top row with glass panes + for (int i = 0; i < 9; i++) { + layout.slot(i, ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); + } - if (page != data.getHighestBackpackSlot()) { - set(new GUIClickableItem(8) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStorageBackpackPage(data.getHighestBackpackSlot(), - new SkyBlockItem(data.getBackpacks().get(data.getHighestBackpackSlot())) - ).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStackHead("§eLast Page >>", - "1ceb50d0d79b9fb790a7392660bc296b7ad2f856c5cbe1c566d99cfec191e668"); - } - }); + Components.close(layout, 0); - if (data.getBackpacks().containsKey(page + 1)) - set(new GUIClickableItem(7) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStorageBackpackPage(page + 1, new SkyBlockItem(data.getBackpacks().get(page + 1))).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStackHead("§aNext Page >>", - "848ca732a6e35dafd15e795ebc10efedd9ef58ff2df9b17af6e3d807bdc0708b"); - } + layout.slot(1, (s, c) -> ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To Storage"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + c.player().openView(new GUIStorage()); }); + + if (page != data.getHighestBackpackSlot()) { + layout.slot(8, (s, c) -> ItemStackCreator.getStackHead("§eLast Page >>", + "1ceb50d0d79b9fb790a7392660bc296b7ad2f856c5cbe1c566d99cfec191e668"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + DatapointBackpacks.PlayerBackpacks playerData = p.getSkyblockDataHandler() + .get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).getValue(); + p.openView(new GUIStorageBackpackPage(playerData.getHighestBackpackSlot(), + new SkyBlockItem(playerData.getBackpacks().get(playerData.getHighestBackpackSlot())))); + }); + + if (data.getBackpacks().containsKey(page + 1)) { + layout.slot(7, (s, c) -> ItemStackCreator.getStackHead("§aNext Page >>", + "848ca732a6e35dafd15e795ebc10efedd9ef58ff2df9b17af6e3d807bdc0708b"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + DatapointBackpacks.PlayerBackpacks playerData = p.getSkyblockDataHandler() + .get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).getValue(); + p.openView(new GUIStorageBackpackPage(page + 1, new SkyBlockItem(playerData.getBackpacks().get(page + 1)))); + }); + } } - if (page != data.getLowestBackpackSlot()) { - set(new GUIClickableItem(5) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStorageBackpackPage(data.getLowestBackpackSlot(), new SkyBlockItem(data.getBackpacks().get(data.getLowestBackpackSlot()))).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStackHead("§e< First Page", - "8af22a97292de001079a5d98a0ae3a82c427172eabc370ed6d4a31c7e3a0024f"); - } - }); - if (data.getBackpacks().containsKey(page - 1)) - set(new GUIClickableItem(6) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStorageBackpackPage(page - 1, new SkyBlockItem(data.getBackpacks().get(page - 1))).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§a< Previous Page", - "9c042597eda9f061794fe11dacf78926d247f9eea8ddef39dfbe6022989b8395"); - } - }); + if (page != data.getLowestBackpackSlot()) { + layout.slot(5, (s, c) -> ItemStackCreator.getStackHead("§e< First Page", + "8af22a97292de001079a5d98a0ae3a82c427172eabc370ed6d4a31c7e3a0024f"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + DatapointBackpacks.PlayerBackpacks playerData = p.getSkyblockDataHandler() + .get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).getValue(); + p.openView(new GUIStorageBackpackPage(playerData.getLowestBackpackSlot(), + new SkyBlockItem(playerData.getBackpacks().get(playerData.getLowestBackpackSlot())))); + }); + + if (data.getBackpacks().containsKey(page - 1)) { + layout.slot(6, (s, c) -> ItemStackCreator.getStackHead("§a< Previous Page", + "9c042597eda9f061794fe11dacf78926d247f9eea8ddef39dfbe6022989b8395"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + DatapointBackpacks.PlayerBackpacks playerData = p.getSkyblockDataHandler() + .get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).getValue(); + p.openView(new GUIStorageBackpackPage(page - 1, new SkyBlockItem(playerData.getBackpacks().get(page - 1)))); + }); + } } - AtomicInteger slot = new AtomicInteger(9); - item.getAttributeHandler().getBackpackData().items().forEach(item -> { - set(new GUIItem(slot.getAndIncrement()) { - @Override - public boolean canPickup() { - return true; - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (item == null || new SkyBlockItem(item).isNA()) - return ItemStackCreator.createNamedItemStack(Material.AIR); - return PlayerItemUpdater.playerUpdate(player, new SkyBlockItem(item).getItemStack()); - } + // Backpack content slots + var backpackItems = item.getAttributeHandler().getBackpackData().items(); + for (int itemIndex = 0; itemIndex < slots; itemIndex++) { + int slot = itemIndex + 9; + var itemData = itemIndex < backpackItems.size() ? backpackItems.get(itemIndex) : null; + + layout.editable(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + if (itemData == null || new SkyBlockItem(itemData).isNA()) + return ItemStack.builder(Material.AIR); + return PlayerItemUpdater.playerUpdate(p, new SkyBlockItem(itemData).getItemStack()); + }, (slotNum, oldItem, newItem, s) -> { }); - }); - - updateItemStacks(getInventory(), player); - } - - @Override - public boolean allowHotkeying() { - return false; + } } @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - item.getAttributeHandler().getBackpackData().items().clear(); - - for (int i = 9; i < slots + 9; i++) { - item.getAttributeHandler().getBackpackData().items().add(new SkyBlockItem(getInventory().getItemStack(i)).toUnderstandable()); - } - - ((SkyBlockPlayer) getPlayer()).getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).getValue().getBackpacks().put(page, item.toUnderstandable()); + public void onClose(DefaultState state, ViewContext ctx, ViewSession.CloseReason reason) { + saveItems((SkyBlockPlayer) ctx.player(), ctx); } - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { + private void saveItems(SkyBlockPlayer player, ViewContext ctx) { item.getAttributeHandler().getBackpackData().items().clear(); for (int i = 9; i < slots + 9; i++) { - item.getAttributeHandler().getBackpackData().items().add(new SkyBlockItem(getInventory().getItemStack(i)).toUnderstandable()); + item.getAttributeHandler().getBackpackData().items().add(new SkyBlockItem(ctx.inventory().getItemStack(i)).toUnderstandable()); } - ((SkyBlockPlayer) getPlayer()).getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class).getValue().getBackpacks().put(page, item.toUnderstandable()); + player.getSkyblockDataHandler() + .get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.BACKPACKS, DatapointBackpacks.class) + .getValue().getBackpacks().put(page, item.toUnderstandable()); } @Override - public void onBottomClick(InventoryPreClickEvent e) { - + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + return true; } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorageIconSelection.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorageIconSelection.java index 18e4317a7..7c9f8828f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorageIconSelection.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStorageIconSelection.java @@ -1,19 +1,15 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.storage; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointStorage; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -21,113 +17,104 @@ import java.util.ArrayList; import java.util.List; -public class GUIStorageIconSelection extends HypixelPaginatedGUI { - private final int page; - private final HypixelInventoryGUI previous; +public class GUIStorageIconSelection extends PaginatedView { + private static final int[] PAGINATED_SLOTS = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; - protected GUIStorageIconSelection(int page, HypixelInventoryGUI previous) { - super(InventoryType.CHEST_6_ROW); + private final int page; + public GUIStorageIconSelection(int page) { this.page = page; - this.previous = previous; } @Override - public boolean allowHotkeying() { - return false; + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> { + int totalPages = Math.max(1, (int) Math.ceil((double) getFilteredItems(state).size() / PAGINATED_SLOTS.length)); + return "Choose an Icon (" + (state.page() + 1) + "/" + totalPages + ")"; + }, + InventoryType.CHEST_6_ROW + ); } - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } + public static IconSelectionState initialState() { + List items = new ArrayList<>(); + items.add(Material.BARRIER); - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { + List vanilla = new ArrayList<>(Material.values().stream().toList()); + vanilla.removeIf((element) -> ItemType.isVanillaReplaced(element.name())); + items.addAll(vanilla); + return new IconSelectionState(items, 0); } @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + protected int[] getPaginatedSlots() { + return PAGINATED_SLOTS; } @Override - protected int[] getPaginatedSlots() { - return new int[]{ - 10, 11, 12, 13, 14, 15, 16, - 19, 20, 21, 22, 23, 24, 25, - 28, 29, 30, 31, 32, 33, 34, - 37, 38, 39, 40, 41, 42, 43 - }; + protected int getNextPageSlot() { + return 53; } @Override - protected PaginationList fillPaged(HypixelPlayer player, PaginationList paged) { - paged.add(Material.BARRIER); - - List vanilla = new ArrayList<>(Material.values().stream().toList()); - vanilla.removeIf((element) -> ItemType.isVanillaReplaced(element.name())); - paged.addAll(vanilla); - - return paged; + protected int getPreviousPageSlot() { + return 45; } @Override - protected boolean shouldFilterFromSearch(String query, Material item) { - return !item.name().toLowerCase().contains(query.replaceAll(" ", "_").toLowerCase()); + protected ItemStack.Builder renderItem(Material item, int index, HypixelPlayer player) { + return ItemStackCreator.getStack( + (item == Material.BARRIER ? "§cReset" : + StringUtility.toNormalCase(item.name().replace("minecraft:", ""))), + item, 1, + "§7Ender Chest icons replace the glass", + "§7panes in the navigation bar.", + " ", + "§eClick to select!"); } @Override - protected void performSearch(HypixelPlayer player, String query, int page, int maxPage) { - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); - set(GUIClickableItem.getCloseItem(49)); - if (previous != null) - set(GUIClickableItem.getGoBackItem(48, previous)); - set(createSearchItem(this, 50, query)); - - if (page > 1) { - set(createNavigationButton(this, 45, query, page, false)); - } - if (page < maxPage) { - set(createNavigationButton(this, 53, query, page, true)); + protected void onItemClick(ClickContext click, ViewContext ctx, Material item, int index) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + DatapointStorage.PlayerStorage storage = player.getSkyblockDataHandler() + .get(SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class).getValue(); + + if (item == Material.BARRIER) { + storage.setDisplay(page, Material.PURPLE_STAINED_GLASS_PANE); + } else { + storage.setDisplay(page, item); } + + player.openView(new GUIStorage()); } @Override - protected String getTitle(HypixelPlayer player, String query, int page, PaginationList paged) { - return "Choose an Icon (" + page + "/" + paged.getPageCount() + ")"; + protected boolean shouldFilterFromSearch(IconSelectionState state, Material item) { + return false; } @Override - protected GUIClickableItem createItemFor(Material item, int slot, HypixelPlayer player) { - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - DatapointStorage.PlayerStorage storage = player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class).getValue(); - - if (item == Material.BARRIER) { - storage.setDisplay(page, Material.PURPLE_STAINED_GLASS_PANE); - new GUIStorage().open(player); - return; - } - - storage.setDisplay(page, item); - new GUIStorage().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - return ItemStackCreator.getStack( - (item == Material.BARRIER ? "§cReset" : - StringUtility.toNormalCase(item.name().replace("minecraft:", ""))), - item, 1, - "§7Ender Chest icons replace the glass", - "§7panes in the navigation bar.", - " ", - "§eClick to select!"); - } - }; + protected void layoutCustom(ViewLayout layout, IconSelectionState state, ViewContext ctx) { + Components.close(layout, 49); + Components.back(layout, 48, ctx); + } + + public record IconSelectionState(List items, int page) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new IconSelectionState(items, page); + } + + @Override + public PaginatedState withItems(List items) { + return new IconSelectionState(items, page); + } } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStoragePage.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStoragePage.java index 924ab8aaf..e58eb76ae 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStoragePage.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/sbmenu/storage/GUIStoragePage.java @@ -1,174 +1,126 @@ package net.swofty.type.skyblockgeneric.gui.inventories.sbmenu.storage; -import net.kyori.adventure.text.Component; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointStorage; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicInteger; - -public class GUIStoragePage extends HypixelInventoryGUI { - public int page; +public class GUIStoragePage extends StatelessView { + private final int page; public GUIStoragePage(int page) { - super("Ender Chest", InventoryType.CHEST_6_ROW); - this.page = page; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - SkyBlockPlayer player = (SkyBlockPlayer) getPlayer(); - int highestPage = player.getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class) + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (_, ctx) -> { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + int highestPage = player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class) + .getValue().getHighestPage(); + return "Ender Chest (" + page + "/" + highestPage + ")"; + }, + InventoryType.CHEST_6_ROW + ); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + int highestPage = player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class) .getValue().getHighestPage(); - e.inventory().setTitle(Component.text( - "Ender Chest (" + page + "/" + highestPage + ")" - )); + // Fill top row with glass panes + for (int i = 0; i < 9; i++) { + layout.slot(i, ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE)); + } - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE), 0, 8); + Components.close(layout, 0); - set(GUIClickableItem.getCloseItem(0)); - set(GUIClickableItem.getGoBackItem(1, new GUIStorage())); + layout.slot(1, (s, c) -> ItemStackCreator.getStack("§aGo Back", Material.ARROW, 1, "§7To Storage"), + (_, c) -> c.player().openView(new GUIStorage())); if (page != highestPage) { - set(new GUIClickableItem(8) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStoragePage(highestPage).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§eLast Page >>", - "1ceb50d0d79b9fb790a7392660bc296b7ad2f856c5cbe1c566d99cfec191e668"); - } - }); - - set(new GUIClickableItem(7) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStoragePage(page + 1).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§aNext Page >>", - "848ca732a6e35dafd15e795ebc10efedd9ef58ff2df9b17af6e3d807bdc0708b"); - } - }); + layout.slot(8, (s, c) -> ItemStackCreator.getStackHead("§eLast Page >>", + "1ceb50d0d79b9fb790a7392660bc296b7ad2f856c5cbe1c566d99cfec191e668"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + c.player().openView(new GUIStoragePage(highestPage)); + }); + + layout.slot(7, (s, c) -> ItemStackCreator.getStackHead("§aNext Page >>", + "848ca732a6e35dafd15e795ebc10efedd9ef58ff2df9b17af6e3d807bdc0708b"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + c.player().openView(new GUIStoragePage(page + 1)); + }); } if (page != 1) { - set(new GUIClickableItem(5) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStoragePage(1).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§e< First Page", - "8af22a97292de001079a5d98a0ae3a82c427172eabc370ed6d4a31c7e3a0024f"); - } - }); - - set(new GUIClickableItem(6) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStoragePage(page - 1).open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStackHead("§a< Previous Page", - "9c042597eda9f061794fe11dacf78926d247f9eea8ddef39dfbe6022989b8395"); - } - }); + layout.slot(5, (s, c) -> ItemStackCreator.getStackHead("§e< First Page", + "8af22a97292de001079a5d98a0ae3a82c427172eabc370ed6d4a31c7e3a0024f"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + c.player().openView(new GUIStoragePage(1)); + }); + + layout.slot(6, (s, c) -> ItemStackCreator.getStackHead("§a< Previous Page", + "9c042597eda9f061794fe11dacf78926d247f9eea8ddef39dfbe6022989b8395"), + (click, c) -> { + saveItems((SkyBlockPlayer) c.player(), c); + c.player().openView(new GUIStoragePage(page - 1)); + }); } - DatapointStorage.PlayerStorage storage = ((SkyBlockPlayer) getPlayer()) - .getSkyblockDataHandler() + DatapointStorage.PlayerStorage storage = player.getSkyblockDataHandler() .get(SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class).getValue(); - AtomicInteger slot = new AtomicInteger(9); - Arrays.stream(storage.getPage(page).getItems()).forEach(item -> { - set(new GUIItem(slot.getAndIncrement()) { - @Override - public boolean canPickup() { - return true; - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (item == null || item.isNA()) - return ItemStackCreator.createNamedItemStack(Material.AIR); - return PlayerItemUpdater.playerUpdate(player, item.getItemStack()); - } + // Storage slots (9-53) + SkyBlockItem[] items = storage.getPage(page).getItems(); + for (int i = 0; i < 45; i++) { + int slot = i + 9; + SkyBlockItem item = items[i]; + + layout.editable(slot, (s, c) -> { + SkyBlockPlayer p = (SkyBlockPlayer) c.player(); + if (item == null || item.isNA()) + return ItemStack.builder(Material.AIR); + return PlayerItemUpdater.playerUpdate(p, item.getItemStack()); + }, (_, _, _, _) -> { }); - }); + } - updateItemStacks(getInventory(), player); + layout.allowHotkey(true); } @Override - public boolean allowHotkeying() { - return true; + public void onClose(DefaultState state, ViewContext ctx, ViewSession.CloseReason reason) { + saveItems((SkyBlockPlayer) ctx.player(), ctx); } - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - DatapointStorage.PlayerStorage storage = ((SkyBlockPlayer) getPlayer()) - .getSkyblockDataHandler() + private void saveItems(SkyBlockPlayer player, ViewContext ctx) { + DatapointStorage.PlayerStorage storage = player.getSkyblockDataHandler() .get(SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class).getValue(); - storage.setItems(page, getItemsInInventory()); - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - DatapointStorage.PlayerStorage storage = ((SkyBlockPlayer) getPlayer()) - .getSkyblockDataHandler() - .get(SkyBlockDataHandler.Data.STORAGE, DatapointStorage.class).getValue(); - - storage.setItems(page, getItemsInInventory()); - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - - } - - public SkyBlockItem[] getItemsInInventory() { SkyBlockItem[] items = new SkyBlockItem[45]; - for (int i = 9; i < 54; i++) { - items[i - 9] = new SkyBlockItem(getInventory().getItemStack(i)); + items[i - 9] = new SkyBlockItem(ctx.inventory().getItemStack(i)); } - return items; + storage.setItems(page, items); + } + + @Override + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + return true; } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/SackComponent.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/SackComponent.java index 45a9fa33c..2ad68ebfe 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/SackComponent.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/item/components/SackComponent.java @@ -25,6 +25,6 @@ public SackComponent(List items, int maxCapacity) { } private void onInteract(SkyBlockPlayer player, SkyBlockItem item) { - new GUISack(item.getItemType(), false).open(player); + player.openView(new GUISack(item.getItemType(), false)); } } From 20f2973bd9b22d96e34528ccf074d467e3be6ad5 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:37:17 +0200 Subject: [PATCH 27/35] refactor: parity with Hypixel page items --- .../java/net/swofty/type/generic/gui/v2/PaginatedView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java index 131ed61fe..4243e19aa 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/PaginatedView.java @@ -106,11 +106,11 @@ protected void layoutCustom(ViewLayout layout, S state, ViewContext ctx) { } protected ItemStack.Builder createPrevPageItem(int currentPage, int totalPages) { - return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")).set(DataComponents.LORE, List.of(Component.text("§7Page " + currentPage + " of " + totalPages))); + return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aPrevious Page")).set(DataComponents.LORE, List.of(Component.text("§ePage " + currentPage))); } protected ItemStack.Builder createNextPageItem(int currentPage, int totalPages) { - return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")).set(DataComponents.LORE, List.of(Component.text("§7Page " + (currentPage + 2) + " of " + totalPages))); + return ItemStack.builder(Material.ARROW).set(DataComponents.CUSTOM_NAME, Component.text("§aNext Page")).set(DataComponents.LORE, List.of(Component.text("§ePage " + (currentPage + 2)))); } protected abstract int[] getPaginatedSlots(); From 6531cd9e3c7274a412b84dfd06bb4699bc301283 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:37:31 +0200 Subject: [PATCH 28/35] feat: port GUICreative --- .../commands/ItemListCommand.java | 4 +- .../gui/inventories/GUICreative.java | 183 ++++++++++-------- 2 files changed, 103 insertions(+), 84 deletions(-) diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ItemListCommand.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ItemListCommand.java index 92a700e45..24b092f03 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ItemListCommand.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/commands/ItemListCommand.java @@ -18,7 +18,7 @@ public void registerUsage(MinestomCommand command) { command.addSyntax((sender, context) -> { if (!permissionCheck(sender)) return; - new GUICreative().open((SkyBlockPlayer) sender); + ((SkyBlockPlayer) sender).openView(new GUICreative(), GUICreative.createInitialState()); }); ArgumentString lookup = new ArgumentString("lookup"); @@ -26,7 +26,7 @@ public void registerUsage(MinestomCommand command) { if (!permissionCheck(sender)) return; String lookupValue = context.get(lookup); - new GUICreative().open((SkyBlockPlayer) sender, lookupValue, 1); + ((SkyBlockPlayer) sender).openView(new GUICreative(), GUICreative.createInitialState(lookupValue, 0)); }, lookup); } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUICreative.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUICreative.java index e90a631da..3e73e9874 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUICreative.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUICreative.java @@ -3,19 +3,17 @@ import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; +import net.swofty.type.generic.gui.HypixelSignGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.components.TrackedUniqueComponent; import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; @@ -25,114 +23,135 @@ import java.util.Arrays; import java.util.List; -public class GUICreative extends HypixelPaginatedGUI { - - public GUICreative() { - super(InventoryType.CHEST_6_ROW); - } +public class GUICreative extends PaginatedView { @Override - public int[] getPaginatedSlots() { - return new int[]{ - 10, 11, 12, 13, 14, 15, 16, - 19, 20, 21, 22, 23, 24, 25, - 28, 29, 30, 31, 32, 33, 34, - 37, 38, 39, 40, 41, 42, 43 - }; + public ViewConfiguration configuration() { + return ViewConfiguration.withString( + (state, ctx) -> { + int totalPages = Math.max(1, (int) Math.ceil((double) getFilteredItems(state).size() / DEFAULT_SLOTS.length)); + return "Creative Menu | Page " + (state.page() + 1) + "/" + totalPages; + }, + InventoryType.CHEST_6_ROW + ); } - @Override - public PaginationList fillPaged(HypixelPlayer player, PaginationList paged) { - paged.addAll(Arrays.stream(ItemType.values()).map(SkyBlockItem::new).toList()); + public static CreativeState createInitialState() { + return createInitialState("", 0); + } + public static CreativeState createInitialState(String query, int pageZeroBased) { + List items = new ArrayList<>(Arrays.stream(ItemType.values()).map(SkyBlockItem::new).toList()); List vanilla = new ArrayList<>(Material.values().stream().map(SkyBlockItem::new).toList()); vanilla.removeIf((element) -> ItemType.isVanillaReplaced(element.getAttributeHandler().getTypeAsString())); - paged.addAll(vanilla); + items.addAll(vanilla); - return paged; + return new CreativeState(items, Math.max(0, pageZeroBased), query == null ? "" : query); } @Override - public boolean shouldFilterFromSearch(String query, SkyBlockItem item) { - return !item.getAttributeHandler().getTypeAsString().toLowerCase().contains(query.replaceAll(" ", "_").toLowerCase()); + protected int[] getPaginatedSlots() { + return DEFAULT_SLOTS; } @Override - protected void performSearch(HypixelPlayer player, String query, int page, int maxPage) { - border(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); - set(GUIClickableItem.getCloseItem(50)); - set(createSearchItem(this, 48, query)); - - if (page > 1) { - set(createNavigationButton(this, 45, query, page, false)); - } - if (page < maxPage) { - set(createNavigationButton(this, 53, query, page, true)); - } + protected int getNextPageSlot() { + return 53; } @Override - public String getTitle(HypixelPlayer player, String query, int page, PaginationList paged) { - return "Creative Menu | Page " + page + "/" + paged.getPageCount(); + protected int getPreviousPageSlot() { + return 45; } @Override - protected GUIClickableItem createItemFor(SkyBlockItem skyBlockItem, int slot, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate( - player, skyBlockItem.getItemStack() - ); + protected void layoutBackground(ViewLayout layout, CreativeState state, ViewContext ctx) { + Components.fill(layout); + layout.filler(Layouts.border(0, 53), ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); + } - boolean stackable = !(skyBlockItem.hasComponent(TrackedUniqueComponent.class)); - - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); - - if (e.getClick() instanceof Click.Right && stackable) { - skyBlockItem.setAmount(64); - player.addAndUpdateItem(skyBlockItem); - player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); - player.sendMessage(Component.text("§aYou have been given §7x64 " + skyBlockItem.getDisplayName() + "§a.")); - } else { - skyBlockItem.setAmount(1); - player.addAndUpdateItem(skyBlockItem); - player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); - player.sendMessage(Component.text("§aYou have been given §7x1 " + skyBlockItem.getDisplayName() + "§a.")); + @Override + protected void layoutCustom(ViewLayout layout, CreativeState state, ViewContext ctx) { + layout.slot(49, (s, c) -> ItemStackCreator.getStack("§cClose", Material.BARRIER, 1), + (_, c) -> c.player().closeInventory()); + + layout.slot(50, (_, _) -> ItemStackCreator.getStack("§aSearch Items", Material.OAK_SIGN, 1, List.of( + "§8/itemlist ", + "", + "§7Search all items in SkyBlock.", + "", + "§eClick to search!" + )), (_, c) -> { + new HypixelSignGUI(c.player()).open(new String[]{"Enter query", ""}).thenAccept(line -> { + if (line == null) { + return; } - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - ArrayList lore = new ArrayList<>(skyBlockItem.getLore()); - lore.add(" "); - if (stackable) lore.add("§bRight Click for §7x64 §eof this item."); - lore.add("§eLeft Click for §7x1 §eof this item."); - - return ItemStackCreator.updateLore(itemStack, lore); - } - }; + + c.replace(new GUICreative(), GUICreative.createInitialState(line, 0)); + }); + }); } @Override - public boolean allowHotkeying() { - return false; + protected ItemStack.Builder renderItem(SkyBlockItem skyBlockItem, int index, HypixelPlayer player) { + SkyBlockPlayer sbPlayer = (SkyBlockPlayer) player; + + SkyBlockItem displayItem = skyBlockItem.getAttributeHandler().getPotentialType() != null + ? new SkyBlockItem(skyBlockItem.getAttributeHandler().getPotentialType()) + : new SkyBlockItem(skyBlockItem.getMaterial()); + + ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate(sbPlayer, displayItem.getItemStack()); + + boolean stackable = !(displayItem.hasComponent(TrackedUniqueComponent.class)); + + ArrayList lore = new ArrayList<>(displayItem.getLore()); + lore.add(" "); + lore.add("§eClick to retrieve!"); + if (stackable) lore.add("§eRight-click for a stack!"); + + return ItemStackCreator.updateLore(itemStack, lore); } @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { + protected void onItemClick(ClickContext click, ViewContext ctx, SkyBlockItem skyBlockItem, int index) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + + SkyBlockItem toGive = skyBlockItem.getAttributeHandler().getPotentialType() != null + ? new SkyBlockItem(skyBlockItem.getAttributeHandler().getPotentialType()) + : new SkyBlockItem(skyBlockItem.getMaterial()); + + boolean stackable = !(toGive.hasComponent(TrackedUniqueComponent.class)); + + player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); + + if (click.click() instanceof Click.Right && stackable) { + toGive.setAmount(64); + player.addAndUpdateItem(toGive); + player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); + player.sendMessage(Component.text("§aYou have been given a stack of " + toGive.getDisplayName() + "§a.")); + } else { + toGive.setAmount(1); + player.addAndUpdateItem(toGive); + player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); + player.sendMessage(Component.text("§aYou have been given a " + toGive.getDisplayName() + "§a.")); + } } @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - + protected boolean shouldFilterFromSearch(CreativeState state, SkyBlockItem item) { + if (state.query().isEmpty()) return false; + return !item.getAttributeHandler().getTypeAsString().toLowerCase().contains(state.query().replaceAll(" ", "_").toLowerCase()); } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + public record CreativeState(List items, int page, String query) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new CreativeState(items, page, query); + } + + @Override + public PaginatedState withItems(List items) { + return new CreativeState(items, page, query); + } } } From 1267a61bfbb084a35ca7b2bda4cda2efcd30bbbe Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Wed, 14 Jan 2026 17:29:28 +0200 Subject: [PATCH 29/35] feat: ShopView --- .../type/deepcaverns/gui/GUIShopWalter.java | 6 +- .../type/deepcaverns/npcs/NPCWalter.java | 2 +- .../type/dwarvenmines/gui/GUIShopLumina.java | 6 +- .../type/dwarvenmines/npcs/NPCLumina.java | 2 +- .../generic/gui/v2/StatefulPaginatedView.java | 5 + .../type/generic/user/HypixelPlayer.java | 21 +- .../type/goldmine/gui/GUIShopGoldForger.java | 6 +- .../type/goldmine/gui/GUIShopIronForger.java | 6 +- .../type/goldmine/npcs/NPCGoldForger.java | 2 +- .../type/goldmine/npcs/NPCIronForger.java | 3 +- .../net/swofty/type/hub/gui/GUIBakerShop.java | 6 +- .../java/net/swofty/type/hub/gui/GUIJax.java | 6 +- .../type/hub/gui/GUIShopAdventurer.java | 6 +- .../swofty/type/hub/gui/GUIShopAlchemist.java | 6 +- .../swofty/type/hub/gui/GUIShopBartender.java | 6 +- .../net/swofty/type/hub/gui/GUIShopBea.java | 8 +- .../type/hub/gui/GUIShopFarmMerchant.java | 6 +- .../type/hub/gui/GUIShopFishMerchant.java | 6 +- .../swofty/type/hub/gui/GUIShopLibrarian.java | 6 +- .../type/hub/gui/GUIShopLumberMerchant.java | 6 +- .../hub/gui/GUIShopMadRedstoneEngineer.java | 6 +- .../type/hub/gui/GUIShopMineMerchant.java | 6 +- .../net/swofty/type/hub/gui/GUIShopPat.java | 6 +- .../type/hub/gui/GUIShopWeaponsmith.java | 6 +- .../type/hub/gui/GUIShopWoolWeaverCool.java | 37 +- .../hub/gui/GUIShopWoolWeaverVibrant.java | 29 +- .../net/swofty/type/hub/gui/GUIShopZog.java | 6 +- .../type/hub/gui/rosetta/GUICelesteArmor.java | 6 +- .../hub/gui/rosetta/GUIMercenaryArmor.java | 6 +- .../type/hub/gui/rosetta/GUIRosetta.java | 33 +- .../type/hub/gui/rosetta/GUIRosettaArmor.java | 6 +- .../hub/gui/rosetta/GUIRosettaIronArmor.java | 6 +- .../type/hub/gui/rosetta/GUISquireArmor.java | 6 +- .../hub/gui/rosetta/GUIStarlightArmor.java | 14 +- .../swofty/type/hub/npcs/NPCAdventurer.java | 3 +- .../swofty/type/hub/npcs/NPCAlchemist.java | 3 +- .../net/swofty/type/hub/npcs/NPCAlda.java | 4 +- .../net/swofty/type/hub/npcs/NPCBaker.java | 3 +- .../swofty/type/hub/npcs/NPCBartender.java | 4 +- .../java/net/swofty/type/hub/npcs/NPCBea.java | 3 +- .../swofty/type/hub/npcs/NPCFarmMerchant.java | 2 +- .../swofty/type/hub/npcs/NPCFishMerchant.java | 3 +- .../java/net/swofty/type/hub/npcs/NPCJax.java | 3 +- .../type/hub/npcs/NPCLumberMerchant.java | 3 +- .../type/hub/npcs/NPCMadRedstoneEngineer.java | 3 +- .../swofty/type/hub/npcs/NPCMineMerchant.java | 3 +- .../java/net/swofty/type/hub/npcs/NPCPat.java | 3 +- .../swofty/type/hub/npcs/NPCWeaponsmith.java | 2 +- .../swofty/type/hub/npcs/NPCWoolWeaver.java | 2 +- .../java/net/swofty/type/hub/npcs/NPCZog.java | 3 +- .../hub/npcs/villagers/VillagerLibrarian.java | 3 +- .../abiphone/impl/AbiphoneAlda.java | 4 +- .../type/skyblockgeneric/gui/ShopView.java | 366 +++++++++++++++ .../skyblockgeneric/gui/SkyBlockShopGUI.java | 415 ------------------ .../gui/inventories/builder/GUIBuilder.java | 8 +- .../builder/GUIShopBuilderGreenThumb.java | 6 +- .../builder/GUIShopBuilderRocksBricks.java | 6 +- .../builder/GUIShopBuilderVariety.java | 6 +- .../builder/GUIShopBuilderWoodworking.java | 6 +- .../rusty/GUIRustyMiscellaneous.java | 16 - .../rusty/GUIRustyPetsAndPetItems.java | 16 - .../inventories/rusty/GUIRustySubMenu.java | 4 +- .../rusty/GUIRustyWeaponsAndGear.java | 16 - .../gui/inventories/shop/ConfirmBuyView.java | 60 +++ .../gui/inventories/shop/GUIConfirmBuy.java | 81 ---- .../shop/GUIGenericTradingOptions.java | 128 ------ .../gui/inventories/shop/GUIShopAlda.java | 18 +- .../inventories/shop/TradingOptionsView.java | 102 +++++ 68 files changed, 737 insertions(+), 865 deletions(-) create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulPaginatedView.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/ShopView.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/SkyBlockShopGUI.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/ConfirmBuyView.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIConfirmBuy.java delete mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIGenericTradingOptions.java create mode 100644 type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/TradingOptionsView.java diff --git a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/gui/GUIShopWalter.java b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/gui/GUIShopWalter.java index 8858da4c3..120ecc70b 100644 --- a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/gui/GUIShopWalter.java +++ b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/gui/GUIShopWalter.java @@ -1,13 +1,13 @@ package net.swofty.type.deepcaverns.gui; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopWalter extends SkyBlockShopGUI { +public class GUIShopWalter extends ShopView { public GUIShopWalter() { - super("Walter", 1, SINGLE_SLOT); + super("Walter", SINGLE_SLOT); } @Override diff --git a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/npcs/NPCWalter.java b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/npcs/NPCWalter.java index 332e09e17..9dbffbb55 100644 --- a/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/npcs/NPCWalter.java +++ b/type.deepcaverns/src/main/java/net/swofty/type/deepcaverns/npcs/NPCWalter.java @@ -50,7 +50,7 @@ public void onClick(NPCInteractEvent event) { if (isInDialogue(player)) return; setDialogue(player, "none").thenRun(() -> { - MathUtility.delay(() -> new GUIShopWalter().open(player), 20); + MathUtility.delay(() -> player.openView(new GUIShopWalter()), 20); }); } diff --git a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/gui/GUIShopLumina.java b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/gui/GUIShopLumina.java index 9678258d8..d99642d9c 100644 --- a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/gui/GUIShopLumina.java +++ b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/gui/GUIShopLumina.java @@ -1,13 +1,13 @@ package net.swofty.type.dwarvenmines.gui; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopLumina extends SkyBlockShopGUI { +public class GUIShopLumina extends ShopView { public GUIShopLumina() { - super("Lumina", 1, DEFAULT); + super("Lumina", DEFAULT); } @Override diff --git a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/npcs/NPCLumina.java b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/npcs/NPCLumina.java index a07d4206f..dd88036e9 100644 --- a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/npcs/NPCLumina.java +++ b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/npcs/NPCLumina.java @@ -46,6 +46,6 @@ public boolean looking(HypixelPlayer player) { public void onClick(NPCInteractEvent event) { SkyBlockPlayer player = (SkyBlockPlayer) event.getPlayer(); - new GUIShopLumina().open(player); + player.openView(new GUIShopLumina()); } } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulPaginatedView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulPaginatedView.java new file mode 100644 index 000000000..045c8d864 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/StatefulPaginatedView.java @@ -0,0 +1,5 @@ +package net.swofty.type.generic.gui.v2; + +public abstract class StatefulPaginatedView> extends PaginatedView { + public abstract S initialState(); +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java index e18a72d04..eb6e21eb0 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java +++ b/type.generic/src/main/java/net/swofty/type/generic/user/HypixelPlayer.java @@ -83,13 +83,20 @@ public ViewSession openView(View view, S state) { public ViewSession openView(View view) { Objects.requireNonNull(view, "View is null"); - if (view instanceof StatefulView state) { - return ViewNavigator.get(this).push(view, state.initialState()); - } else if (view instanceof StatelessView state) { - return ViewNavigator.get(this).push(view, null); - } else { - throw new IllegalArgumentException("View must be either StatefulView or StatelessView"); - } + switch (view) { + case StatefulView state -> { + return ViewNavigator.get(this).push(view, state.initialState()); + } + case StatelessView _ -> { + return ViewNavigator.get(this).push(view, null); + } + case StatefulPaginatedView state -> { + @SuppressWarnings("unchecked") + S initialState = (S) state.initialState(); + return ViewNavigator.get(this).push(view, initialState); + } + default -> throw new IllegalArgumentException("View must be either StatefulView or StatelessView"); + } } public ProxyPlayer asProxyPlayer() { diff --git a/type.goldmine/src/main/java/net/swofty/type/goldmine/gui/GUIShopGoldForger.java b/type.goldmine/src/main/java/net/swofty/type/goldmine/gui/GUIShopGoldForger.java index a396c1645..610e7db89 100644 --- a/type.goldmine/src/main/java/net/swofty/type/goldmine/gui/GUIShopGoldForger.java +++ b/type.goldmine/src/main/java/net/swofty/type/goldmine/gui/GUIShopGoldForger.java @@ -4,16 +4,16 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.ItemAttributeHandler; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; import java.util.Map; -public class GUIShopGoldForger extends SkyBlockShopGUI { +public class GUIShopGoldForger extends ShopView { public GUIShopGoldForger() { - super("Gold Forger", 1, DEFAULT); + super("Gold Forger", DEFAULT); } private SkyBlockItem applyEnchantment (SkyBlockItem item, Map enchantments) { diff --git a/type.goldmine/src/main/java/net/swofty/type/goldmine/gui/GUIShopIronForger.java b/type.goldmine/src/main/java/net/swofty/type/goldmine/gui/GUIShopIronForger.java index 5b84d6040..7ec899330 100644 --- a/type.goldmine/src/main/java/net/swofty/type/goldmine/gui/GUIShopIronForger.java +++ b/type.goldmine/src/main/java/net/swofty/type/goldmine/gui/GUIShopIronForger.java @@ -4,16 +4,16 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.ItemAttributeHandler; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; import java.util.Map; -public class GUIShopIronForger extends SkyBlockShopGUI { +public class GUIShopIronForger extends ShopView { public GUIShopIronForger() { - super("Iron Forger", 1, DEFAULT); + super("Iron Forger", DEFAULT); } private SkyBlockItem applyEnchantment (SkyBlockItem item, Map enchantments) { diff --git a/type.goldmine/src/main/java/net/swofty/type/goldmine/npcs/NPCGoldForger.java b/type.goldmine/src/main/java/net/swofty/type/goldmine/npcs/NPCGoldForger.java index 217faeef3..f43dcb79d 100644 --- a/type.goldmine/src/main/java/net/swofty/type/goldmine/npcs/NPCGoldForger.java +++ b/type.goldmine/src/main/java/net/swofty/type/goldmine/npcs/NPCGoldForger.java @@ -54,7 +54,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopGoldForger().open(player); + player.openView(new GUIShopGoldForger()); } @Override diff --git a/type.goldmine/src/main/java/net/swofty/type/goldmine/npcs/NPCIronForger.java b/type.goldmine/src/main/java/net/swofty/type/goldmine/npcs/NPCIronForger.java index 36756de94..a94cabb9d 100644 --- a/type.goldmine/src/main/java/net/swofty/type/goldmine/npcs/NPCIronForger.java +++ b/type.goldmine/src/main/java/net/swofty/type/goldmine/npcs/NPCIronForger.java @@ -5,6 +5,7 @@ import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.goldmine.gui.GUIShopGoldForger; import net.swofty.type.goldmine.gui.GUIShopIronForger; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -54,7 +55,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopIronForger().open(player); + player.openView(new GUIShopIronForger()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIBakerShop.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIBakerShop.java index 9062d874c..1ce003b49 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIBakerShop.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIBakerShop.java @@ -1,15 +1,15 @@ package net.swofty.type.hub.gui; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIBakerShop extends SkyBlockShopGUI { +public class GUIBakerShop extends ShopView { public GUIBakerShop() { - super("Baker", 1, DEFAULT); + super("Baker", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIJax.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIJax.java index 202f941d3..8292d230c 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIJax.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIJax.java @@ -2,14 +2,14 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIJax extends SkyBlockShopGUI { +public class GUIJax extends ShopView { public GUIJax() { - super("Adventurer", 1, DEFAULT); + super("Adventurer", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopAdventurer.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopAdventurer.java index c5a47620a..c05b25644 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopAdventurer.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopAdventurer.java @@ -2,14 +2,14 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopAdventurer extends SkyBlockShopGUI { +public class GUIShopAdventurer extends ShopView { public GUIShopAdventurer() { - super("Adventurer", 1, DEFAULT); + super("Adventurer", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopAlchemist.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopAlchemist.java index 83445c367..bb0720e2a 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopAlchemist.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopAlchemist.java @@ -2,13 +2,13 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopAlchemist extends SkyBlockShopGUI{ +public class GUIShopAlchemist extends ShopView { public GUIShopAlchemist() { - super("Alchemist", 1, DEFAULT); + super("Alchemist", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopBartender.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopBartender.java index ee4599e17..eeabdb3e1 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopBartender.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopBartender.java @@ -1,14 +1,14 @@ package net.swofty.type.hub.gui; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopBartender extends SkyBlockShopGUI { +public class GUIShopBartender extends ShopView { public GUIShopBartender() { - super("Bartender", 1, DEFAULT); + super("Bartender", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopBea.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopBea.java index 320ffbc13..7b92c88f9 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopBea.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopBea.java @@ -3,7 +3,7 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.commons.skyblock.item.Rarity; import net.swofty.commons.skyblock.item.attribute.attributes.ItemAttributePetData; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; import net.swofty.type.skyblockgeneric.shop.type.CombinedShopPrice; @@ -12,9 +12,9 @@ import java.util.ArrayList; import java.util.List; -public class GUIShopBea extends SkyBlockShopGUI { +public class GUIShopBea extends ShopView { public GUIShopBea() { - super("Pea", 1, DEFAULT); + super("Pea", DEFAULT); } @Override @@ -59,7 +59,7 @@ public void attachBeePet(Rarity rarity, CombinedShopPrice price) { lore.add("§cThis is a preview of Lvl 100"); lore.add("§cNew pets are lowest level!"); - bee.setDisplayLore(lore); + bee.setLore(lore); bee.setDisplayName(beeDisplayItem.getDisplayName()); attachItem(bee); } diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopFarmMerchant.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopFarmMerchant.java index 83dde7aef..55da96cd1 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopFarmMerchant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopFarmMerchant.java @@ -2,13 +2,13 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopFarmMerchant extends SkyBlockShopGUI { +public class GUIShopFarmMerchant extends ShopView { public GUIShopFarmMerchant() { - super("Farm Merchant", 1, DEFAULT); + super("Farm Merchant", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopFishMerchant.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopFishMerchant.java index 6cc4d2ca3..b8b79c3a6 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopFishMerchant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopFishMerchant.java @@ -2,13 +2,13 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopFishMerchant extends SkyBlockShopGUI{ +public class GUIShopFishMerchant extends ShopView { public GUIShopFishMerchant() { - super("Fish Merchant", 1, DEFAULT); + super("Fish Merchant", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopLibrarian.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopLibrarian.java index 2c2e9dc59..fc61feb57 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopLibrarian.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopLibrarian.java @@ -4,13 +4,13 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopLibrarian extends SkyBlockShopGUI { +public class GUIShopLibrarian extends ShopView { public GUIShopLibrarian() { - super("Librarian", 1, DEFAULT); + super("Librarian", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopLumberMerchant.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopLumberMerchant.java index 98a79198b..4bd7cf6ad 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopLumberMerchant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopLumberMerchant.java @@ -2,13 +2,13 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopLumberMerchant extends SkyBlockShopGUI { +public class GUIShopLumberMerchant extends ShopView { public GUIShopLumberMerchant() { - super("Lumber Merchant", 1, DEFAULT); + super("Lumber Merchant", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopMadRedstoneEngineer.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopMadRedstoneEngineer.java index 0e2144286..8f93c325d 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopMadRedstoneEngineer.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopMadRedstoneEngineer.java @@ -1,13 +1,13 @@ package net.swofty.type.hub.gui; import net.minestom.server.item.Material; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopMadRedstoneEngineer extends SkyBlockShopGUI { +public class GUIShopMadRedstoneEngineer extends ShopView { public GUIShopMadRedstoneEngineer() { - super("Mad Redstone Engineer", 1, DEFAULT); + super("Mad Redstone Engineer", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopMineMerchant.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopMineMerchant.java index fa6e92557..5165f1d76 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopMineMerchant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopMineMerchant.java @@ -2,14 +2,14 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; import net.swofty.type.skyblockgeneric.shop.type.ItemShopPrice; -public class GUIShopMineMerchant extends SkyBlockShopGUI{ +public class GUIShopMineMerchant extends ShopView { public GUIShopMineMerchant() { - super("Mine Merchant", 1, DEFAULT); + super("Mine Merchant", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopPat.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopPat.java index 40ac380ff..238da62bd 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopPat.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopPat.java @@ -1,13 +1,13 @@ package net.swofty.type.hub.gui; import net.minestom.server.item.Material; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopPat extends SkyBlockShopGUI { +public class GUIShopPat extends ShopView { public GUIShopPat() { - super("Pat", 1, DEFAULT); + super("Pat", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWeaponsmith.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWeaponsmith.java index 0f162338d..d54513f10 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWeaponsmith.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWeaponsmith.java @@ -2,14 +2,14 @@ import net.minestom.server.item.Material; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopWeaponsmith extends SkyBlockShopGUI{ +public class GUIShopWeaponsmith extends ShopView { public GUIShopWeaponsmith() { - super("Weaponsmith", 1, DEFAULT); + super("Weaponsmith", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWoolWeaverCool.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWoolWeaverCool.java index 5233029ef..5c9cecc0c 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWoolWeaverCool.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWoolWeaverCool.java @@ -1,36 +1,31 @@ package net.swofty.type.hub.gui; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import net.swofty.type.generic.user.HypixelPlayer; -public class GUIShopWoolWeaverCool extends SkyBlockShopGUI { +public class GUIShopWoolWeaverCool extends ShopView { public GUIShopWoolWeaverCool() { - super("Wool Weaver (Cool)", 1, WOOLWEAVER_COOL); + super("Wool Weaver (Cool)", WOOLWEAVER_COOL); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - set(new GUIClickableItem(45) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIShopWoolWeaverVibrant().open(player); - } + public void onOpen(State state, ViewContext ctx) { + super.onOpen(state, ctx); + } - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aPrevious Page", Material.ARROW, 1, "§ePage 1"); - } - }); + @Override + protected void layoutCustom(ViewLayout layout, State state, ViewContext ctx) { + super.layoutCustom(layout, state, ctx); + layout.slot(45, (s, c) -> { + return ItemStackCreator.getStack("§aPrevious Page", Material.ARROW, 1, "§ePage 1"); + }, ((stateClickContext, context) -> { + context.pop(); + })); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWoolWeaverVibrant.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWoolWeaverVibrant.java index 2d9bf8d66..212a51651 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWoolWeaverVibrant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopWoolWeaverVibrant.java @@ -4,33 +4,28 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import net.swofty.type.generic.user.HypixelPlayer; -public class GUIShopWoolWeaverVibrant extends SkyBlockShopGUI { +public class GUIShopWoolWeaverVibrant extends ShopView { public GUIShopWoolWeaverVibrant() { - super("Wool Weaver (Vibrant)", 1, WOOLWEAVER_VIBRANT); + super("Wool Weaver (Vibrant)", WOOLWEAVER_VIBRANT); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - set(new GUIClickableItem(53) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIShopWoolWeaverCool().open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.getStack("§aNext Page", Material.ARROW, 1, "§ePage 2"); - } - }); + protected void layoutCustom(ViewLayout layout, State state, ViewContext ctx) { + super.layoutCustom(layout, state, ctx); + layout.slot( + 53, + (_, _) -> ItemStackCreator.getStack("§aNext Page", Material.ARROW, 1, "§ePage 2"), + ((_, context) -> context.push(new GUIShopWoolWeaverCool())) + ); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopZog.java b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopZog.java index 46fb7ac8d..dc9b424a1 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopZog.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/GUIShopZog.java @@ -1,13 +1,13 @@ package net.swofty.type.hub.gui; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopZog extends SkyBlockShopGUI { +public class GUIShopZog extends ShopView { public GUIShopZog() { - super("Zog", 1, DEFAULT); + super("Zog", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUICelesteArmor.java b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUICelesteArmor.java index 030ee89a8..ef8fc90f7 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUICelesteArmor.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUICelesteArmor.java @@ -1,13 +1,13 @@ package net.swofty.type.hub.gui.rosetta; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUICelesteArmor extends SkyBlockShopGUI { +public class GUICelesteArmor extends ShopView { public GUICelesteArmor() { - super("Celeste Armor", 1, DEFAULT); + super("Celeste Armor", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIMercenaryArmor.java b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIMercenaryArmor.java index 1dcb8b2f8..e18c0c064 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIMercenaryArmor.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIMercenaryArmor.java @@ -1,13 +1,13 @@ package net.swofty.type.hub.gui.rosetta; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIMercenaryArmor extends SkyBlockShopGUI { +public class GUIMercenaryArmor extends ShopView { public GUIMercenaryArmor() { - super("Mercenary Armor", 1, DEFAULT); + super("Mercenary Armor", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosetta.java b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosetta.java index 892f56add..338fcc723 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosetta.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosetta.java @@ -23,13 +23,13 @@ public void onOpen(InventoryGUIOpenEvent e) { set(new GUIClickableItem(19) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRosettaIronArmor().open(player); + SkyBlockPlayer player = (SkyBlockPlayer) p; + player.openView(new GUIRosettaIronArmor()); } @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; + SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§eIron Armor", Material.IRON_HELMET, 1, "§7Plain old iron armor.", "", @@ -40,13 +40,13 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIClickableItem(21) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIRosettaArmor().open(player); + SkyBlockPlayer player = (SkyBlockPlayer) p; + player.openView(new GUIRosettaArmor()); } @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; + SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§eRosetta's Armor", Material.DIAMOND_HELMET, 1, "§7Custom-designed and", "§7hand-crafted diamond armor.", @@ -58,13 +58,12 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIClickableItem(14) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUISquireArmor().open(player); + SkyBlockPlayer player = (SkyBlockPlayer) p; + player.openView(new GUISquireArmor()); } @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§eSquire Armor", Material.CHAINMAIL_HELMET, 1, "§7Solid set to venture into the", "§7deep caverns.", @@ -76,13 +75,13 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIClickableItem(16) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIMercenaryArmor().open(player); + SkyBlockPlayer player = (SkyBlockPlayer) p; + player.openView(new GUIMercenaryArmor()); } @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; + SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§eMercenary Armor", Material.IRON_HELMET, 1, "§7Kickstart your warrior", "§7journey!", @@ -94,13 +93,12 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIClickableItem(32) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUICelesteArmor().open(player); + SkyBlockPlayer player = (SkyBlockPlayer) p; + player.openView(new GUICelesteArmor()); } @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§eCeleste Armor", Material.LEATHER_HELMET, 1, "§7Dip a toe into the world of", "§7magic.", @@ -112,13 +110,12 @@ public ItemStack.Builder getItem(HypixelPlayer p) { set(new GUIClickableItem(34) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIStarlightArmor().open(player); + SkyBlockPlayer player = (SkyBlockPlayer) p; + player.openView(new GUIStarlightArmor()); } @Override public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; return ItemStackCreator.getStack("§eStarlight Armor", Material.GOLDEN_HELMET, 1, "§7This set was designed with the", "§7help of Barry the Wizard.", diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosettaArmor.java b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosettaArmor.java index 54f126934..2e0b27942 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosettaArmor.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosettaArmor.java @@ -3,16 +3,16 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.ItemAttributeHandler; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; import java.util.Map; -public class GUIRosettaArmor extends SkyBlockShopGUI { +public class GUIRosettaArmor extends ShopView { public GUIRosettaArmor() { - super("Rosetta's Armor", 1, DEFAULT); + super("Rosetta's Armor", DEFAULT); } private SkyBlockItem applyEnchantment (SkyBlockItem item, Map enchantments) { diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosettaIronArmor.java b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosettaIronArmor.java index e846c036b..a913c99d9 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosettaIronArmor.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIRosettaIronArmor.java @@ -3,16 +3,16 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.ItemAttributeHandler; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; import java.util.Map; -public class GUIRosettaIronArmor extends SkyBlockShopGUI { +public class GUIRosettaIronArmor extends ShopView { public GUIRosettaIronArmor() { - super("Iron Armor", 1, DEFAULT); + super("Iron Armor", DEFAULT); } private SkyBlockItem applyEnchantment (SkyBlockItem item, Map enchantments) { diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUISquireArmor.java b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUISquireArmor.java index 395ae6f7b..6404ff2e4 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUISquireArmor.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUISquireArmor.java @@ -1,13 +1,13 @@ package net.swofty.type.hub.gui.rosetta; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUISquireArmor extends SkyBlockShopGUI { +public class GUISquireArmor extends ShopView { public GUISquireArmor() { - super("Squire Armor", 1, DEFAULT); + super("Squire Armor", DEFAULT); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIStarlightArmor.java b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIStarlightArmor.java index 3dbc2da0a..db18d03ba 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIStarlightArmor.java +++ b/type.hub/src/main/java/net/swofty/type/hub/gui/rosetta/GUIStarlightArmor.java @@ -1,20 +1,20 @@ package net.swofty.type.hub.gui.rosetta; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIStarlightArmor extends SkyBlockShopGUI { +public class GUIStarlightArmor extends ShopView { public GUIStarlightArmor() { - super("Starlight Armor", 1, DEFAULT); + super("Starlight Armor", DEFAULT); } @Override public void initializeShopItems() { - attachItem(SkyBlockShopGUI.ShopItem.Single(new SkyBlockItem(ItemType.STARLIGHT_HELMET), 1, new CoinShopPrice(35000))); - attachItem(SkyBlockShopGUI.ShopItem.Single(new SkyBlockItem(ItemType.STARLIGHT_CHESTPLATE), 1, new CoinShopPrice(70000))); - attachItem(SkyBlockShopGUI.ShopItem.Single(new SkyBlockItem(ItemType.STARLIGHT_LEGGINGS), 1, new CoinShopPrice(45000))); - attachItem(SkyBlockShopGUI.ShopItem.Single(new SkyBlockItem(ItemType.STARLIGHT_BOOTS), 1, new CoinShopPrice(30000))); + attachItem(ShopItem.Single(new SkyBlockItem(ItemType.STARLIGHT_HELMET), 1, new CoinShopPrice(35000))); + attachItem(ShopItem.Single(new SkyBlockItem(ItemType.STARLIGHT_CHESTPLATE), 1, new CoinShopPrice(70000))); + attachItem(ShopItem.Single(new SkyBlockItem(ItemType.STARLIGHT_LEGGINGS), 1, new CoinShopPrice(45000))); + attachItem(ShopItem.Single(new SkyBlockItem(ItemType.STARLIGHT_BOOTS), 1, new CoinShopPrice(30000))); } } diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAdventurer.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAdventurer.java index 06a5e0d56..74c3c5a9f 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAdventurer.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAdventurer.java @@ -8,6 +8,7 @@ import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.event.custom.NPCInteractEvent; +import net.swofty.type.hub.gui.GUIShopLibrarian; public class NPCAdventurer extends HypixelNPC { public NPCAdventurer() { @@ -52,7 +53,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopAdventurer().open(player); + player.openView(new GUIShopAdventurer()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAlchemist.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAlchemist.java index 806d2378b..db772f0e0 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAlchemist.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAlchemist.java @@ -6,6 +6,7 @@ import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.AnimalConfiguration; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.hub.gui.GUIShopAdventurer; import net.swofty.type.hub.gui.GUIShopAlchemist; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -55,7 +56,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopAlchemist().open(player); + player.openView(new GUIShopAlchemist()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAlda.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAlda.java index a275c0412..a8c24af42 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAlda.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCAlda.java @@ -7,6 +7,7 @@ import net.swofty.type.generic.event.custom.NPCInteractEvent; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.skyblockgeneric.gui.inventories.shop.GUIShopAlda; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; public class NPCAlda extends HypixelNPC implements NPCAbiphoneTrait { @@ -41,7 +42,8 @@ public boolean looking(HypixelPlayer player) { @Override public void onClick(NPCInteractEvent event) { - new GUIShopAlda().open(event.player()); + SkyBlockPlayer player = (SkyBlockPlayer) event.player(); + player.openView(new GUIShopAlda()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBaker.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBaker.java index 3f8e0fa28..300551165 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBaker.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBaker.java @@ -7,6 +7,7 @@ import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.hub.gui.GUIBakerShop; +import net.swofty.type.hub.gui.GUIShopLumberMerchant; import net.swofty.type.skyblockgeneric.calendar.CalendarEvent; import net.swofty.type.skyblockgeneric.calendar.SkyBlockCalendar; import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; @@ -69,7 +70,7 @@ public void onClick(NPCInteractEvent event) { if (isInDialogue(player)) return; SkyBlockDataHandler dataHandler = player.getSkyblockDataHandler(); if (dataHandler.get(SkyBlockDataHandler.Data.LATEST_NEW_YEAR_CAKE_YEAR, DatapointInteger.class).getValue() >= SkyBlockCalendar.getYear()) { - new GUIBakerShop().open(player); + player.openView(new GUIBakerShop()); return; } setDialogue(player, "initial-hello").thenRun(() -> { diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBartender.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBartender.java index 25c05bb66..b7ff82b27 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBartender.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBartender.java @@ -4,6 +4,7 @@ import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.hub.gui.GUIShopAlchemist; import net.swofty.type.hub.gui.GUIShopBartender; import net.swofty.type.skyblockgeneric.mission.missions.MissionKillZombies; import net.swofty.type.skyblockgeneric.mission.missions.MissionTalkToBartender; @@ -63,7 +64,8 @@ public void onClick(NPCInteractEvent e) { player.getMissionData().endMission(MissionTalkToBartender.class); }); } - new GUIShopBartender().open(player); + + player.openView(new GUIShopBartender()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBea.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBea.java index f3471e485..99a85ed41 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBea.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCBea.java @@ -5,6 +5,7 @@ import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.hub.gui.GUIShopBartender; import net.swofty.type.hub.gui.GUIShopBea; import java.util.stream.Stream; @@ -53,7 +54,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopBea().open(e.player()); + e.player().openView(new GUIShopBea()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFarmMerchant.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFarmMerchant.java index 18ca4ad54..9a0d076e2 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFarmMerchant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFarmMerchant.java @@ -54,7 +54,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopFarmMerchant().open(player); + player.openView(new GUIShopFarmMerchant()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishMerchant.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishMerchant.java index fdc7cd68a..70158bc2f 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishMerchant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCFishMerchant.java @@ -5,6 +5,7 @@ import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.hub.gui.GUIShopFarmMerchant; import net.swofty.type.hub.gui.GUIShopFishMerchant; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -53,7 +54,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopFishMerchant().open(player); + player.openView(new GUIShopFishMerchant()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCJax.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCJax.java index b492dd05f..9022aed48 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCJax.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCJax.java @@ -6,6 +6,7 @@ import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.hub.gui.GUIJax; +import net.swofty.type.hub.gui.GUIShopFishMerchant; import net.swofty.type.skyblockgeneric.data.datapoints.DatapointArcheryPractice; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -64,7 +65,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIJax().open(player); + player.openView(new GUIJax()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCLumberMerchant.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCLumberMerchant.java index 0ee6e0517..1ac3ed2c1 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCLumberMerchant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCLumberMerchant.java @@ -5,6 +5,7 @@ import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.hub.gui.GUIJax; import net.swofty.type.hub.gui.GUIShopLumberMerchant; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -53,7 +54,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopLumberMerchant().open(player); + player.openView(new GUIShopLumberMerchant()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCMadRedstoneEngineer.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCMadRedstoneEngineer.java index 0fe5671b6..830baad3f 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCMadRedstoneEngineer.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCMadRedstoneEngineer.java @@ -5,6 +5,7 @@ import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.hub.gui.GUIBakerShop; import net.swofty.type.hub.gui.GUIShopMadRedstoneEngineer; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -54,7 +55,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopMadRedstoneEngineer().open(player); + player.openView(new GUIShopMadRedstoneEngineer()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCMineMerchant.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCMineMerchant.java index 0ea445929..e95734402 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCMineMerchant.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCMineMerchant.java @@ -5,6 +5,7 @@ import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.hub.gui.GUIShopMadRedstoneEngineer; import net.swofty.type.hub.gui.GUIShopMineMerchant; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -53,7 +54,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopMineMerchant().open(player); + player.openView(new GUIShopMineMerchant()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCPat.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCPat.java index 7c08b169b..28ef9005e 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCPat.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCPat.java @@ -4,6 +4,7 @@ import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.hub.gui.GUIShopMineMerchant; import net.swofty.type.hub.gui.GUIShopPat; import net.swofty.type.generic.event.custom.NPCInteractEvent; @@ -41,7 +42,7 @@ public boolean looking(HypixelPlayer player) { @Override public void onClick(NPCInteractEvent e) { - new GUIShopPat().open(e.player()); + e.player().openView(new GUIShopPat()); } } diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCWeaponsmith.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCWeaponsmith.java index 5ccdfc2fa..19dc10466 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCWeaponsmith.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCWeaponsmith.java @@ -53,7 +53,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopWeaponsmith().open(player); + player.openView(new GUIShopWeaponsmith()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCWoolWeaver.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCWoolWeaver.java index 43d990828..5a7521e42 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCWoolWeaver.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCWoolWeaver.java @@ -54,7 +54,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopWoolWeaverVibrant().open(player); + player.openView(new GUIShopWoolWeaverVibrant()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCZog.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCZog.java index ea5333435..c22357a62 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCZog.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/NPCZog.java @@ -3,6 +3,7 @@ import net.minestom.server.coordinate.Pos; import net.swofty.type.generic.entity.npc.HypixelNPC; import net.swofty.type.generic.entity.npc.configuration.HumanConfiguration; +import net.swofty.type.hub.gui.GUIShopWeaponsmith; import net.swofty.type.hub.gui.GUIShopZog; import net.swofty.type.generic.data.datapoints.DatapointToggles; import net.swofty.type.generic.user.HypixelPlayer; @@ -54,7 +55,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopZog().open(player); + player.openView(new GUIShopZog()); } @Override diff --git a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLibrarian.java b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLibrarian.java index eda391d8c..87bd9d1a2 100644 --- a/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLibrarian.java +++ b/type.hub/src/main/java/net/swofty/type/hub/npcs/villagers/VillagerLibrarian.java @@ -6,6 +6,7 @@ import net.swofty.type.generic.entity.npc.configuration.VillagerConfiguration; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.hub.gui.GUIShopLibrarian; +import net.swofty.type.hub.gui.rosetta.GUIStarlightArmor; import net.swofty.type.skyblockgeneric.mission.MissionData; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -52,7 +53,7 @@ public void onClick(NPCInteractEvent e) { return; } - new GUIShopLibrarian().open(player); + player.openView(new GUIShopLibrarian()); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/abiphone/impl/AbiphoneAlda.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/abiphone/impl/AbiphoneAlda.java index ed6263a12..ac704efd7 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/abiphone/impl/AbiphoneAlda.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/abiphone/impl/AbiphoneAlda.java @@ -2,6 +2,7 @@ import net.minestom.server.item.ItemStack; import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.ViewNavigator; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.skyblockgeneric.abiphone.AbiphoneNPC; import net.swofty.type.skyblockgeneric.gui.inventories.shop.GUIShopAlda; @@ -14,7 +15,7 @@ public AbiphoneAlda() { @Override public void onCall(HypixelPlayer player) { - new GUIShopAlda().open(player); + player.openView(new GUIShopAlda()); } @Override @@ -22,4 +23,3 @@ public ItemStack.Builder getIcon() { return ItemStackCreator.getStackHead("db5647f93fd8e1da9cdb151dd9bdf4f48bb59a1d11748f1918c136c86804b2"); } } - diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/ShopView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/ShopView.java new file mode 100644 index 000000000..d7ddd8f4d --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/ShopView.java @@ -0,0 +1,366 @@ +package net.swofty.type.skyblockgeneric.gui; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextDecoration; +import net.minestom.server.component.DataComponents; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.inventory.click.Click; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.commons.StringUtility; +import net.swofty.type.generic.data.datapoints.DatapointDouble; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; +import net.swofty.type.skyblockgeneric.gui.inventories.shop.TradingOptionsView; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.components.SellableComponent; +import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; +import net.swofty.type.skyblockgeneric.shop.ShopPrice; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; +import org.tinylog.Logger; + +import java.util.ArrayList; +import java.util.List; + +public abstract class ShopView extends StatefulPaginatedView { + + public static final int[] DEFAULT = new int[]{ + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; + public static final int[] WOOLWEAVER_VIBRANT = new int[]{ + 1, 2, 3, 4, 5, 6, 7, 8, + 10, 11, 12, 13, 14, 15, 16, 17, + 19, 20, 21, 22, 23, 24, 25, 26, + 28, 29, 30, 31, 32, 33, 34, 35, + 37, 38, 39, 40, 41, 42, 43, 44 + }; + public static final int[] WOOLWEAVER_COOL = new int[]{ + 0, 1, 2, 3, 4, 5, 6, 7, + 9, 10, 11, 12, 13, 14, 15, 16, + 18, 19, 20, 21, 22, 23, 24, 25, + 17, 28, 29, 30, 31, 32, 33, 34, + 26, 37, 38, 39, 40, 41, 42, 43, + }; + public static final int[] UPPER5ROWS = new int[]{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44 + }; + public static final int[] GREENTHUMB = new int[]{ + 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, + 38, 39, 40, 41, 42 + }; + public static final int[] VARIETY = new int[]{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42 + }; + public static final int[] SINGLE_SLOT = new int[]{22}; + + private final String title; + private final int[] interiorSlots; + + public ShopView(String title, int[] interiorSlots) { + this.title = title; + this.interiorSlots = interiorSlots; + } + + public final void attachItem(ShopItem item) { + itemsToAttach.add(item); + } + + private final List itemsToAttach = new ArrayList<>(); + + public abstract void initializeShopItems(); + + @Override + public State initialState() { + if (itemsToAttach.isEmpty()) { + initializeShopItems(); + } + return new State(new ArrayList<>(itemsToAttach), 0); + } + + @Override + public ViewConfiguration configuration() { + return ViewConfiguration.withString((state, _) -> { + int totalPages = Math.max(1, (int) Math.ceil((double) getFilteredItems(state).size() / interiorSlots.length)); + return title + " | Page " + (state.page() + 1) + "/" + totalPages; + }, InventoryType.CHEST_6_ROW); + } + + @Override + protected int[] getPaginatedSlots() { + return interiorSlots; + } + + @Override + protected int getNextPageSlot() { + return 53; + } + + @Override + protected int getPreviousPageSlot() { + return 45; + } + + @Override + protected void layoutBackground(ViewLayout layout, State state, ViewContext ctx) { + Components.fill(layout); + for (int slot : interiorSlots) { + layout.slot(slot, ItemStack.AIR.builder()); + } + } + + @Override + protected void layoutCustom(ViewLayout layout, State state, ViewContext ctx) { + layoutBuyback(layout, ctx); + } + + private void layoutBuyback(ViewLayout layout, ViewContext ctx) { + layout.slot(49, + (s, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (!player.getShoppingData().hasAnythingToBuyback()) { + return ItemStackCreator.getStack("§aSell Item", Material.HOPPER, 1, + "§7Click items in your inventory to", + "§7sell them to this Shop!"); + } + + SkyBlockItem last = new SkyBlockItem(player.getShoppingData().lastBuyback().getKey()); + int amountOfLast = player.getShoppingData().lastBuyback().getValue(); + ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate(player, last.getItemStackBuilder().build()); + + double buyBackPrice = last.getComponent(SellableComponent.class).getSellValue() * amountOfLast; + + List lore = new ArrayList<>(itemStack.build().get(DataComponents.LORE) + .stream().map(StringUtility::getTextFromComponent).toList()); + lore.add(""); + lore.add("§7Cost"); + lore.add("§6" + StringUtility.commaify(buyBackPrice) + " Coin" + (buyBackPrice != 1 ? "s" : "")); + lore.add(""); + lore.add("§eClick to buyback!"); + + itemStack.amount(amountOfLast); + return ItemStackCreator.updateLore(itemStack, lore); + }, + (click, c) -> { + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (!player.getShoppingData().hasAnythingToBuyback()) return; + + SkyBlockItem last = new SkyBlockItem(player.getShoppingData().lastBuyback().getKey()); + int amountOfLast = player.getShoppingData().lastBuyback().getValue(); + + ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate(player, last.getItemStackBuilder().build()); + itemStack.amount(amountOfLast); + + double value = last.getComponent(SellableComponent.class).getSellValue() * amountOfLast; + double playerCoins = player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.COINS, DatapointDouble.class).getValue(); + + if (playerCoins < value) { + player.sendMessage("§cYou don't have enough coins!"); + return; + } + + player.addAndUpdateItem(new SkyBlockItem(itemStack.build())); + player.playSuccessSound(); + player.getShoppingData().popBuyback(); + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.COINS, DatapointDouble.class).setValue(playerCoins - value); + + c.session(Object.class).refresh(); + } + ); + } + + @Override + protected ItemStack.Builder renderItem(ShopItem item, int index, HypixelPlayer p) { + SkyBlockPlayer player = (SkyBlockPlayer) p; + + try { + SkyBlockItem sbItem = item.item; + ShopPrice price = item.price; + + ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate(player, sbItem.getItemStackBuilder().build()); + itemStack.amount(item.amount); + + if (item.getDisplayName() != null) { + itemStack.set(DataComponents.CUSTOM_NAME, Component.text(item.getDisplayName()) + .decoration(TextDecoration.ITALIC, false)); + } + + List lore; + if (item.getLore() != null) { + lore = new ArrayList<>(item.lore); + } else { + lore = new ArrayList<>(itemStack.build().get(DataComponents.LORE) + .stream().map(StringUtility::getTextFromComponent).toList()); + } + + lore.add(""); + lore.add("§7Cost"); + lore.addAll(price.getGUIDisplay()); + lore.add(""); + + if (item.hasStock) { + lore.add("§7Stock"); + lore.add("§6" + player.getShoppingData().getStock(item.getItem().toUnderstandable()) + " §7remaining"); + lore.add(""); + } + + lore.add("§eClick to trade!"); + if (item.stackable) { + lore.add("§eRight-click for more trading options!"); + } + + return ItemStackCreator.updateLore(itemStack, lore); + } catch (Exception e) { + p.sendMessage("§cThere was an error processing item " + item.getItem().getDisplayName() + "!"); + Logger.error(e, "Error loading shop view"); + return ItemStackCreator.getStack("§cError", Material.BARRIER, 1); + } + } + + @Override + protected void onItemClick(ClickContext click, ViewContext ctx, ShopItem item, int index) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + + if (item.isHasStock() && !player.getShoppingData().canPurchase(item.item.toUnderstandable(), item.amount)) { + player.sendMessage("§cYou have reached the maximum amount of items you can buy!"); + return; + } + + ShopPrice price = item.price; + ShopPrice stackPrice = item.price.divide(item.amount); + + if (item.isStackable() && click.click() instanceof Click.Right) { + ctx.navigator().push(new TradingOptionsView(), new TradingOptionsView.State(item, stackPrice)); + return; + } + + if (!price.canAfford(player)) { + player.sendMessage("§cYou don't have enough " + price.getNamePlural() + "!"); + return; + } + + price.processPurchase(player); + + SkyBlockItem toGive = item.item; + toGive.setAmount(item.amount); + player.addAndUpdateItem(toGive); + player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); + + if (item.hasStock) { + player.getShoppingData().documentPurchase(item.getItem().toUnderstandable(), item.amount); + } + + ctx.session(Object.class).refresh(); + } + + @Override + protected boolean shouldFilterFromSearch(State state, ShopItem item) { + return false; + } + + @Override + public void onClose(State state, ViewContext ctx, net.swofty.type.generic.gui.v2.ViewSession.CloseReason reason) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + SkyBlockDataHandler.Data.INVENTORY.onLoad.accept( + player, SkyBlockDataHandler.Data.INVENTORY.onQuit.apply(player) + ); + } + + @Override + public boolean onBottomClick(ClickContext click, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + + ItemStack stack = player.getInventory().getItemStack(click.slot()); + if (stack.material().equals(Material.AIR)) return true; + + SkyBlockItem item = new SkyBlockItem(stack); + if (!item.hasComponent(SellableComponent.class)) { + player.sendMessage("§cYou can't sell this item!"); + return true; + } + + SellableComponent sellable = item.getComponent(SellableComponent.class); + double sellPrice = sellable.getSellValue() * stack.amount(); + + player.getShoppingData().pushBuyback(item.toUnderstandable(), stack.amount()); + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.COINS, DatapointDouble.class).setValue( + player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.COINS, DatapointDouble.class).getValue() + sellPrice + ); + + player.sendMessage( + "§aYou sold §f" + StringUtility.getTextFromComponent(stack.get(DataComponents.CUSTOM_NAME)) + "§a for §6" + + StringUtility.commaify(sellPrice) + " Coin" + (sellPrice != 1 ? "s" : "") + "§a!" + ); + + player.getInventory().setItemStack(click.slot(), ItemStack.AIR); + ctx.session(Object.class).refresh(); + return true; + } + + public record State(List items, int page) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new State(items, page); + } + + @Override + public PaginatedState withItems(List items) { + return new State(items, page); + } + } + + @Getter + @AllArgsConstructor + @RequiredArgsConstructor + public static class ShopItem { + private final SkyBlockItem item; + private final int amount; + private final ShopPrice price; + private final boolean stackable; + @Setter + private List lore = null; + @Setter + private String displayName = null; + private boolean hasStock = true; + + public ShopItem(SkyBlockItem item, int amount, ShopPrice price, boolean stackable, boolean hasStock) { + this.item = item; + this.amount = amount; + this.price = price; + this.stackable = stackable; + this.hasStock = hasStock; + } + + public static ShopItem Stackable(SkyBlockItem item, int amount, ShopPrice price) { + return new ShopItem(item, amount, price, true); + } + + public static ShopItem Single(SkyBlockItem item, int amount, ShopPrice price) { + return new ShopItem(item, amount, price, false); + } + + } + +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/SkyBlockShopGUI.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/SkyBlockShopGUI.java deleted file mode 100644 index 11c893673..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/SkyBlockShopGUI.java +++ /dev/null @@ -1,415 +0,0 @@ -package net.swofty.type.skyblockgeneric.gui; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import net.kyori.adventure.key.Key; -import net.kyori.adventure.sound.Sound; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.TextDecoration; -import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.inventory.click.Click; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.commons.StringUtility; -import net.swofty.type.generic.data.datapoints.DatapointDouble; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; -import net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler; -import net.swofty.type.skyblockgeneric.gui.inventories.shop.GUIGenericTradingOptions; -import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.item.components.SellableComponent; -import net.swofty.type.skyblockgeneric.item.updater.PlayerItemUpdater; -import net.swofty.type.skyblockgeneric.shop.ShopPrice; -import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import org.tinylog.Logger; - -import java.util.ArrayList; -import java.util.List; - -public abstract class SkyBlockShopGUI extends HypixelInventoryGUI { - - public static final int[] DEFAULT = new int[]{ - 10, 11, 12, 13, 14, 15, 16, - 19, 20, 21, 22, 23, 24, 25, - 28, 29, 30, 31, 32, 33, 34, - 37, 38, 39, 40, 41, 42, 43 - }; - public static final int[] WOOLWEAVER_VIBRANT = new int[]{ - 1, 2, 3, 4, 5, 6, 7, 8, - 10, 11, 12, 13, 14, 15, 16, 17, - 19, 20, 21, 22, 23, 24, 25, 26, - 28, 29, 30, 31, 32, 33, 34, 35, - 37, 38, 39, 40, 41, 42, 43, 44 - }; - public static final int[] WOOLWEAVER_COOL = new int[]{ - 0, 1, 2, 3, 4, 5, 6, 7, - 9, 10, 11, 12, 13, 14, 15, 16, - 18, 19, 20, 21, 22, 23, 24, 25, - 17, 28, 29, 30, 31, 32, 33, 34, - 26, 37, 38, 39, 40, 41, 42, 43, - }; - public static final int[] UPPER5ROWS = new int[]{ - 0, 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44 - }; - public static final int[] GREENTHUMB = new int[]{ - 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, - 38, 39, 40, 41, 42 - }; - public static final int[] VARIETY = new int[]{ - 0, 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42 - }; - public static final int[] SINGLE_SLOT = new int[]{ - 22 - }; - - private final List shopItemList; - private final int[] INTERIOR; - private int page; - - public SkyBlockShopGUI(String title, int page, int[] guiFormat) { - super(title, InventoryType.CHEST_6_ROW); - this.shopItemList = new ArrayList<>(); - this.page = page; - this.INTERIOR = guiFormat; - initializeShopItems(); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - SkyBlockPlayer player = (SkyBlockPlayer) e.getPlayer(); - - SkyBlockDataHandler.Data.INVENTORY.onLoad.accept( - player, SkyBlockDataHandler.Data.INVENTORY.onQuit.apply(player) - ); - } - - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, " ")); - for (int slot : INTERIOR) { - set(slot, ItemStackCreator.createNamedItemStack(Material.AIR)); - } - PaginationList paginatedItems = new PaginationList<>(INTERIOR.length); - paginatedItems.addAll(shopItemList); - - SkyBlockPlayer player = (SkyBlockPlayer) getPlayer(); - for (int slot = 0; slot < 36; slot++) { - ItemStack stack = player.getInventory().getItemStack(slot); - - if (stack.material().equals(Material.AIR)) continue; - - SkyBlockItem item = new SkyBlockItem(stack); - if (item.hasComponent(SellableComponent.class)) { - ItemStack.Builder toReplace = PlayerItemUpdater.playerUpdate( - player, stack - ); - - double sellPrice = item.getComponent(SellableComponent.class).getSellValue() * stack.amount(); - List lore = new ArrayList<>(toReplace.build().get(DataComponents.LORE) - .stream() - .map(StringUtility::getTextFromComponent) - .toList()); - - lore.add(""); - lore.add("§7Sell Price"); - lore.add("§6" + StringUtility.commaify(sellPrice) + " Coin" + (sellPrice != 1 ? "s" : "")); - lore.add(""); - lore.add("§eClick to sell!"); - - toReplace = ItemStackCreator.updateLore(toReplace, lore); - toReplace.set(DataComponents.CUSTOM_NAME, Component.text( - "§a" + StringUtility.getTextFromComponent(toReplace.build().get(DataComponents.CUSTOM_NAME)) + - " §8x" + stack.amount() - ).decoration(TextDecoration.ITALIC, false)); - - player.getInventory().setItemStack(slot, toReplace.build()); - } - } - - if (paginatedItems.isEmpty()) page = 0; - if (page > 1) - set(new GUIClickableItem(45) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockShopGUI.this.page -= 1; - SkyBlockShopGUI.this.open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.createNamedItemStack(Material.ARROW, "§a<-"); - } - }); - - if (page != paginatedItems.getPageCount()) - set(new GUIClickableItem(53) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - SkyBlockShopGUI.this.page += 1; - SkyBlockShopGUI.this.open(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - return ItemStackCreator.createNamedItemStack(Material.ARROW, "§a->"); - } - }); - - /* - Buyback item - */ - set(new GUIClickableItem(49) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!player.getShoppingData().hasAnythingToBuyback()) - return; - - SkyBlockItem last = new SkyBlockItem(player.getShoppingData().lastBuyback().getKey()); - int amountOfLast = player.getShoppingData().lastBuyback().getValue(); - ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate( - player, last.getItemStackBuilder().build() - ); - itemStack.amount(amountOfLast); - - double value = last.getComponent(SellableComponent.class).getSellValue() * amountOfLast; - - double playerCoins = player.getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.COINS, DatapointDouble.class).getValue(); - if (playerCoins < value) { - player.sendMessage("§cYou don't have enough coins!"); - return; - } - - player.addAndUpdateItem(new SkyBlockItem(itemStack.build())); - player.playSuccessSound(); - player.getShoppingData().popBuyback(); - player.getSkyblockDataHandler().get(net.swofty.type.skyblockgeneric.data.SkyBlockDataHandler.Data.COINS, DatapointDouble.class).setValue(playerCoins - value); - updateThis(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!player.getShoppingData().hasAnythingToBuyback()) { - return ItemStackCreator.getStack("§aSell Item", Material.HOPPER, 1, - "§7Click items in your inventory to", - "§7sell them to this Shop!"); - } - - SkyBlockItem last = new SkyBlockItem(player.getShoppingData().lastBuyback().getKey()); - int amountOfLast = player.getShoppingData().lastBuyback().getValue(); - ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate( - player, last.getItemStackBuilder().build() - ); - - double buyBackPrice = last.getComponent(SellableComponent.class).getSellValue() * amountOfLast; - - List lore = new ArrayList<>(itemStack.build().get(DataComponents.LORE) - .stream() - .map(StringUtility::getTextFromComponent) - .toList()); - lore.add(""); - lore.add("§7Cost"); - lore.add("§6" + StringUtility.commaify(buyBackPrice) + " Coin" + (buyBackPrice != 1 ? "s" : "")); - lore.add(""); - lore.add("§eClick to buyback!"); - - itemStack.amount(amountOfLast); - return ItemStackCreator.updateLore(itemStack, lore); - } - }); - - List p = paginatedItems.getPage(page); - if (p == null) return; - for (int i = 0; i < p.size(); i++) { - int slot = INTERIOR[i]; - ShopItem item = p.get(i); - SkyBlockItem sbItem = item.item; - - ShopPrice price = item.price; - ShopPrice stackPrice = item.price.divide(item.amount); - - set(new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (item.isHasStock() && !player.getShoppingData().canPurchase(item.item.toUnderstandable(), item.amount)) { - player.sendMessage("§cYou have reached the maximum amount of items you can buy!"); - return; - } - - if (item.isStackable() && e.getClick() instanceof Click.Right) { - new GUIGenericTradingOptions(item, SkyBlockShopGUI.this, stackPrice).open(player); - return; - } - - if (!price.canAfford(player)) { - player.sendMessage("§cYou don't have enough " + price.getNamePlural() + "!"); - return; - } - - price.processPurchase(player); - - sbItem.setAmount(item.amount); - player.addAndUpdateItem(sbItem); - player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); - - if (item.hasStock) - player.getShoppingData().documentPurchase(item.getItem().toUnderstandable(), item.amount); - - updateThis(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - try { - ItemStack.Builder itemStack = PlayerItemUpdater.playerUpdate( - player, sbItem.getItemStackBuilder().build() - ); - itemStack.amount(item.amount); - - if (item.getDisplayName() != null) - itemStack.set(DataComponents.CUSTOM_NAME, Component.text(item.getDisplayName()) - .decoration(TextDecoration.ITALIC, false)); - - List lore; - - if (item.getLore() != null) { - lore = item.lore; - } else { - lore = new ArrayList<>(itemStack.build().get(DataComponents.LORE) - .stream() - .map(StringUtility::getTextFromComponent) - .toList()); - } - - lore.add(""); - lore.add("§7Cost"); - lore.addAll(price.getGUIDisplay()); - lore.add(""); - if (item.hasStock) { - lore.add("§7Stock"); - lore.add("§6" + player.getShoppingData().getStock(item.getItem().toUnderstandable()) + " §7remaining"); - lore.add(""); - } - lore.add("§eClick to trade!"); - - if (item.stackable) - lore.add("§eRight-click for more trading options!"); - - return ItemStackCreator.updateLore(itemStack, lore); - } catch (Exception e) { - getPlayer().sendMessage("§cThere was an error processing item " + item.getItem().getDisplayName() + "!"); - Logger.error(e, "Error loading shop GUI"); - return ItemStackCreator.getStack("§cError", Material.BARRIER, 1); - } - } - }); - } - updateItemStacks(e.inventory(), getPlayer()); - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - SkyBlockPlayer player = (SkyBlockPlayer) e.getPlayer(); - ItemStack stack = e.getClickedItem(); - e.setCancelled(true); - if (stack.material().equals(Material.AIR)) return; - SkyBlockItem item = new SkyBlockItem(stack); - - SellableComponent sellable; - if (item.hasComponent(SellableComponent.class)) { - sellable = item.getComponent(SellableComponent.class); - } else { - player.sendMessage("§cYou can't sell this item!"); - return; - } - - double sellPrice = sellable.getSellValue() * stack.amount(); - - player.getShoppingData().pushBuyback(item.toUnderstandable(), stack.amount()); - player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.COINS, DatapointDouble.class).setValue( - player.getSkyblockDataHandler().get(SkyBlockDataHandler.Data.COINS, DatapointDouble.class).getValue() + sellPrice - ); - player.sendMessage( - "§aYou sold §f" + StringUtility.getTextFromComponent(stack.get(DataComponents.CUSTOM_NAME)) + "§a for §6" - + StringUtility.commaify(sellPrice) + " Coin" + (sellPrice != 1 ? "s" : "") + "§a!" - ); - - player.getInventory().setItemStack(e.getSlot(), ItemStack.AIR); - updateThis(player); - } - - public abstract void initializeShopItems(); - - public void attachItem(ShopItem i) { - shopItemList.add(i); - } - - public void updateThis(SkyBlockPlayer player) { - SkyBlockShopGUI.this.open(player); - } - - @RequiredArgsConstructor - @AllArgsConstructor - @Getter - public static class ShopItem { - private final SkyBlockItem item; - private final int amount; - private final ShopPrice price; - private final boolean stackable; - private List lore = null; - @Setter - private String displayName = null; - private boolean hasStock = true; - - public ShopItem(SkyBlockItem item, int amount, ShopPrice price, boolean stackable, boolean hasStock) { - this.item = item; - this.amount = amount; - this.price = price; - this.stackable = stackable; - this.hasStock = hasStock; - } - - public static ShopItem Stackable(SkyBlockItem item, int amount, ShopPrice price) { - return new ShopItem(item, amount, price, true); - } - - public static ShopItem Single(SkyBlockItem item, int amount, ShopPrice price) { - return new ShopItem(item, amount, price, false); - } - - public void setDisplayLore(List lores) { - this.lore = lores; - } - - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIBuilder.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIBuilder.java index 85c7773f4..1b3ae1fc2 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIBuilder.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIBuilder.java @@ -23,7 +23,7 @@ public void onOpen(InventoryGUIOpenEvent e) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIShopBuilderWoodworking().open(player); + player.openView(new GUIShopBuilderWoodworking()); } @Override @@ -36,7 +36,7 @@ public ItemStack.Builder getItem(HypixelPlayer p) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIShopBuilderRocksBricks().open(player); + player.openView(new GUIShopBuilderRocksBricks()); } @Override @@ -51,7 +51,7 @@ public ItemStack.Builder getItem(HypixelPlayer p) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIShopBuilderGreenThumb().open(player); + player.openView(new GUIShopBuilderGreenThumb()); } @Override @@ -66,7 +66,7 @@ public ItemStack.Builder getItem(HypixelPlayer p) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer p) { SkyBlockPlayer player = (SkyBlockPlayer) p; - new GUIShopBuilderVariety().open(player); + player.openView(new GUIShopBuilderVariety()); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderGreenThumb.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderGreenThumb.java index f7e5e2e87..b415152aa 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderGreenThumb.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderGreenThumb.java @@ -1,13 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.builder; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopBuilderGreenThumb extends SkyBlockShopGUI { +public class GUIShopBuilderGreenThumb extends ShopView { public GUIShopBuilderGreenThumb() { - super("Green Thumb", 1, GREENTHUMB); + super("Green Thumb", GREENTHUMB); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderRocksBricks.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderRocksBricks.java index 59c3f4e50..e89664bd7 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderRocksBricks.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderRocksBricks.java @@ -1,13 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.builder; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopBuilderRocksBricks extends SkyBlockShopGUI { +public class GUIShopBuilderRocksBricks extends ShopView { public GUIShopBuilderRocksBricks() { - super("Rocks & Bricks", 1, UPPER5ROWS); + super("Rocks & Bricks", UPPER5ROWS); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderVariety.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderVariety.java index 6343e8f91..d23b7c470 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderVariety.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderVariety.java @@ -1,13 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.builder; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopBuilderVariety extends SkyBlockShopGUI { +public class GUIShopBuilderVariety extends ShopView { public GUIShopBuilderVariety() { - super("Variety", 1, VARIETY); + super("Variety", VARIETY); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderWoodworking.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderWoodworking.java index b87f4fb53..9725dda8e 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderWoodworking.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/builder/GUIShopBuilderWoodworking.java @@ -1,13 +1,13 @@ package net.swofty.type.skyblockgeneric.gui.inventories.builder; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopBuilderWoodworking extends SkyBlockShopGUI { +public class GUIShopBuilderWoodworking extends ShopView { public GUIShopBuilderWoodworking() { - super("Woodworking", 1, UPPER5ROWS); + super("Woodworking", UPPER5ROWS); } @Override diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyMiscellaneous.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyMiscellaneous.java index 8c995853f..757e2bf0f 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyMiscellaneous.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyMiscellaneous.java @@ -1,28 +1,12 @@ package net.swofty.type.skyblockgeneric.gui.inventories.rusty; -import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.commons.StringUtility; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.generic.data.datapoints.DatapointToggles; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; import net.swofty.type.skyblockgeneric.enchantment.EnchantmentType; import net.swofty.type.skyblockgeneric.enchantment.SkyBlockEnchantment; -import net.swofty.type.skyblockgeneric.gui.inventories.shop.GUIConfirmBuy; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; import net.swofty.type.skyblockgeneric.mission.missions.goldmine.lazyminer.MissionFindLazyMinerPickaxe; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import java.util.ArrayList; import java.util.List; import java.util.function.Function; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyPetsAndPetItems.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyPetsAndPetItems.java index 6eea53145..26fc2741b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyPetsAndPetItems.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyPetsAndPetItems.java @@ -1,24 +1,8 @@ package net.swofty.type.skyblockgeneric.gui.inventories.rusty; -import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.commons.StringUtility; -import net.swofty.type.generic.data.datapoints.DatapointToggles; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; -import net.swofty.type.skyblockgeneric.gui.inventories.shop.GUIConfirmBuy; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import java.util.ArrayList; import java.util.List; import java.util.function.Function; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustySubMenu.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustySubMenu.java index a4237d43a..bb4c1a210 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustySubMenu.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustySubMenu.java @@ -13,7 +13,7 @@ import net.swofty.type.generic.gui.inventory.item.GUIItem; import net.swofty.type.generic.user.HypixelPlayer; import net.swofty.type.generic.utility.PaginationList; -import net.swofty.type.skyblockgeneric.gui.inventories.shop.GUIConfirmBuy; +import net.swofty.type.skyblockgeneric.gui.inventories.shop.ConfirmBuyView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; @@ -187,7 +187,7 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { if (player.getToggles() .get(DatapointToggles.Toggles.ToggleType.RUSTY_PURCHASE_CONFIRMATION) && price >= 1_000_000) { - new GUIConfirmBuy(item, price).open(player); + player.openView(new ConfirmBuyView(), new ConfirmBuyView.State(item, price)); return; } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyWeaponsAndGear.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyWeaponsAndGear.java index eac628fcd..eba02569a 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyWeaponsAndGear.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/rusty/GUIRustyWeaponsAndGear.java @@ -1,24 +1,8 @@ package net.swofty.type.skyblockgeneric.gui.inventories.rusty; -import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.commons.StringUtility; -import net.swofty.type.generic.data.datapoints.DatapointToggles; -import net.swofty.type.generic.gui.inventory.HypixelPaginatedGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.generic.utility.PaginationList; -import net.swofty.type.skyblockgeneric.gui.inventories.shop.GUIConfirmBuy; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import java.util.ArrayList; import java.util.List; import java.util.function.Function; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/ConfirmBuyView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/ConfirmBuyView.java new file mode 100644 index 000000000..a94b82f4b --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/ConfirmBuyView.java @@ -0,0 +1,60 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.shop; + +import net.kyori.adventure.text.Component; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.inventory.click.Click; +import net.minestom.server.item.Material; +import net.swofty.commons.StringUtility; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.ArrayList; + +public final class ConfirmBuyView implements View { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>(Component.text("Confirm"), InventoryType.CHEST_3_ROW); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + Components.fill(layout); + + layout.slot(12, + (_, __) -> { + ArrayList lore = new ArrayList<>(); + lore.add("§7Buying: " + state.item.getDisplayItem()); + lore.add("§7Cost: §6" + StringUtility.commaify(state.price) + " Coins"); + return ItemStackCreator.getStack("§aConfirm", Material.LIME_TERRACOTTA, 1, lore); + }, + (click, c) -> { + if (!(click.click() instanceof Click.Left || click.click() instanceof Click.Right)) return; + + SkyBlockPlayer player = (SkyBlockPlayer) c.player(); + if (player.getCoins() >= state.price) { + player.addAndUpdateItem(state.item); + player.removeCoins(state.price); + player.sendMessage("§aYou bought " + state.item.getDisplayName() + " §afor §6" + state.price + " Coins§a!"); + } else { + player.sendMessage("§4You don't have enough coins!"); + } + player.closeInventory(); + } + ); + + layout.slot(16, + (_, __) -> ItemStackCreator.getStack("§4Cancel", Material.RED_TERRACOTTA, 1), + (_, c) -> c.player().closeInventory() + ); + } + + public record State(SkyBlockItem item, int price) { + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIConfirmBuy.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIConfirmBuy.java deleted file mode 100644 index 4b7c342c7..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIConfirmBuy.java +++ /dev/null @@ -1,81 +0,0 @@ -package net.swofty.type.skyblockgeneric.gui.inventories.shop; - -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; - -import java.util.ArrayList; - -public class GUIConfirmBuy extends HypixelInventoryGUI { - private final SkyBlockItem item; - private final int price; - - public GUIConfirmBuy(SkyBlockItem item, int price) { - super("Confirm", InventoryType.CHEST_3_ROW); - this.item = item; - this.price = price; - } - - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, " ")); - - set(new GUIClickableItem(12) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - SkyBlockPlayer skyBlockPlayer = (SkyBlockPlayer) player; - - if (skyBlockPlayer.getCoins() >= price) { - skyBlockPlayer.addAndUpdateItem(item); - skyBlockPlayer.removeCoins(price); - - skyBlockPlayer.sendMessage("§aYou bought " + item.getDisplayName() + " §afor §6" + price + " Coins§a!"); - } else { - skyBlockPlayer.sendMessage("§4You don't have enough coins!"); - } - skyBlockPlayer.closeInventory(); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - ArrayList lore = new ArrayList<>(); - lore.add("§7Buying: " + item.getDisplayItem()); - lore.add("§7Cost: §6" + StringUtility.commaify(price) + " Coins"); - - return ItemStackCreator.getStack("§aConfirm", Material.LIME_TERRACOTTA, 1, lore); - } - }); - - set(new GUIClickableItem(16) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - player.closeInventory(); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack("§4Cancel", Material.RED_TERRACOTTA, 1); - } - }); - - updateItemStacks(e.inventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIGenericTradingOptions.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIGenericTradingOptions.java deleted file mode 100644 index 3935358ed..000000000 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIGenericTradingOptions.java +++ /dev/null @@ -1,128 +0,0 @@ -package net.swofty.type.skyblockgeneric.gui.inventories.shop; - -import net.kyori.adventure.key.Key; -import net.kyori.adventure.sound.Sound; -import net.kyori.adventure.text.Component; -import net.minestom.server.component.DataComponents; -import net.minestom.server.event.inventory.InventoryCloseEvent; -import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.inventory.Inventory; -import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.swofty.commons.StringUtility; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; -import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.user.HypixelPlayer; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; -import net.swofty.type.skyblockgeneric.item.SkyBlockItem; -import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; -import net.swofty.type.skyblockgeneric.shop.ShopPrice; -import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; - -import java.util.ArrayList; -import java.util.List; - -public final class GUIGenericTradingOptions extends HypixelInventoryGUI { - private final SkyBlockShopGUI.ShopItem item; - private final SkyBlockShopGUI retPointer; - private final ShopPrice stackPrice; - - public GUIGenericTradingOptions(SkyBlockShopGUI.ShopItem item, SkyBlockShopGUI retPoint, ShopPrice stackPrice) { - super("Shop Trading Options", InventoryType.CHEST_6_ROW); - this.item = item; - this.retPointer = retPoint; - this.stackPrice = stackPrice; - } - - @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, " ")); - set(createTradeItem(item, 20, 1, (SkyBlockPlayer) getPlayer(), stackPrice)); - set(createTradeItem(item, 21, 5, (SkyBlockPlayer) getPlayer(), stackPrice)); - set(createTradeItem(item, 22, 10, (SkyBlockPlayer) getPlayer(), stackPrice)); - set(createTradeItem(item, 23, 32, (SkyBlockPlayer) getPlayer(), stackPrice)); - set(createTradeItem(item, 24, 64, (SkyBlockPlayer) getPlayer(), stackPrice)); - - set(GUIClickableItem.getGoBackItem(49, retPointer)); - - updateItemStacks(e.inventory(), getPlayer()); - } - - private GUIClickableItem createTradeItem(SkyBlockShopGUI.ShopItem item, int slot, int amount, SkyBlockPlayer player, ShopPrice stackprice) { - stackprice = stackprice.multiply(amount); - - SkyBlockItem sbItem = item.getItem(); - ItemStack.Builder itemStack = new NonPlayerItemUpdater(sbItem).getUpdatedItem(); - - List lore = new ArrayList<>(itemStack.build() - .get(DataComponents.LORE).stream().map(StringUtility::getTextFromComponent).toList()); - - lore.add(""); - lore.add("§7Cost"); - lore.addAll(stackprice.getGUIDisplay()); - lore.add(""); - lore.add("§7Stock"); - lore.add("§6 " + player.getShoppingData().getStock(item.getItem().toUnderstandable()) + " §7remaining"); - lore.add(""); - lore.add("§eClick to purchase!"); - - ShopPrice finalStackprice = stackprice; - return new GUIClickableItem(slot) { - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer p) { - SkyBlockPlayer player = (SkyBlockPlayer) p; - if (!player.getShoppingData().canPurchase(item.getItem().toUnderstandable(), amount)) { - player.sendMessage("§cYou have reached the maximum amount of items you can buy!"); - return; - } - - if (!finalStackprice.canAfford(player)) { - player.sendMessage("§cYou don't have enough " + stackPrice.getNamePlural() + "!"); - return; - } - - finalStackprice.processPurchase(player); - - ItemStack.Builder cleanStack = new NonPlayerItemUpdater(sbItem).getUpdatedItem(); - cleanStack.amount(amount); - player.addAndUpdateItem(cleanStack.build()); - player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); - player.getShoppingData().documentPurchase(item.getItem().toUnderstandable(), amount); - updateThis(player); - } - - @Override - public ItemStack.Builder getItem(HypixelPlayer p) { - String displayName = StringUtility.getTextFromComponent(itemStack.build().get(DataComponents.CUSTOM_NAME) - .append(Component.text(" §8x" + amount))); - return ItemStackCreator.getStack(displayName, itemStack.build().material(), amount, lore); - } - }; - } - - private void updateThis(SkyBlockPlayer player) { - this.open(player); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onClose(InventoryCloseEvent e, CloseReason reason) { - - } - - @Override - public void suddenlyQuit(Inventory inventory, HypixelPlayer player) { - - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - - } -} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIShopAlda.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIShopAlda.java index e0255ba7f..240c54095 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIShopAlda.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/GUIShopAlda.java @@ -1,17 +1,17 @@ package net.swofty.type.skyblockgeneric.gui.inventories.shop; import net.swofty.commons.skyblock.item.ItemType; -import net.swofty.type.skyblockgeneric.gui.SkyBlockShopGUI; +import net.swofty.type.skyblockgeneric.gui.ShopView; import net.swofty.type.skyblockgeneric.item.SkyBlockItem; import net.swofty.type.skyblockgeneric.shop.type.CoinShopPrice; -public class GUIShopAlda extends SkyBlockShopGUI { - public GUIShopAlda() { - super("Alda", 1, SINGLE_SLOT); - } +public class GUIShopAlda extends ShopView { + public GUIShopAlda() { + super("Alda", SINGLE_SLOT); + } - @Override - public void initializeShopItems() { - attachItem(ShopItem.Single(new SkyBlockItem(ItemType.ABIPHONE_BASIC), 1, new CoinShopPrice(100000))); - } + @Override + public void initializeShopItems() { + attachItem(ShopItem.Single(new SkyBlockItem(ItemType.ABIPHONE_BASIC), 1, new CoinShopPrice(100000))); + } } diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/TradingOptionsView.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/TradingOptionsView.java new file mode 100644 index 000000000..b1c109116 --- /dev/null +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/shop/TradingOptionsView.java @@ -0,0 +1,102 @@ +package net.swofty.type.skyblockgeneric.gui.inventories.shop; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.text.Component; +import net.minestom.server.component.DataComponents; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.swofty.commons.StringUtility; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.skyblockgeneric.gui.ShopView; +import net.swofty.type.skyblockgeneric.item.SkyBlockItem; +import net.swofty.type.skyblockgeneric.item.updater.NonPlayerItemUpdater; +import net.swofty.type.skyblockgeneric.shop.ShopPrice; +import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; + +import java.util.ArrayList; +import java.util.List; + +public final class TradingOptionsView implements View { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Shop Trading Options", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + Components.fill(layout); + + layout.slot(20, (s, c) -> createTradeItem(s.item, 1, (SkyBlockPlayer) c.player(), s.stackPrice), (_, c) -> attemptBuy(state, 1, c)); + layout.slot(21, (s, c) -> createTradeItem(s.item, 5, (SkyBlockPlayer) c.player(), s.stackPrice), (_, c) -> attemptBuy(state, 5, c)); + layout.slot(22, (s, c) -> createTradeItem(s.item, 10, (SkyBlockPlayer) c.player(), s.stackPrice), (_, c) -> attemptBuy(state, 10, c)); + layout.slot(23, (s, c) -> createTradeItem(s.item, 32, (SkyBlockPlayer) c.player(), s.stackPrice), (_, c) -> attemptBuy(state, 32, c)); + layout.slot(24, (s, c) -> createTradeItem(s.item, 64, (SkyBlockPlayer) c.player(), s.stackPrice), (_, c) -> attemptBuy(state, 64, c)); + + Components.backOrClose(layout, 49, ctx); + } + + private ItemStack.Builder createTradeItem(ShopView.ShopItem item, int amount, SkyBlockPlayer player, ShopPrice perOnePrice) { + ShopPrice totalPrice = perOnePrice.multiply(amount); + + SkyBlockItem sbItem = item.getItem(); + ItemStack.Builder itemStack = new NonPlayerItemUpdater(sbItem).getUpdatedItem(); + + List existingLoreComponents = itemStack.build().get(DataComponents.LORE); + List lore = new ArrayList<>((existingLoreComponents == null ? List.of() : existingLoreComponents) + .stream().map(StringUtility::getTextFromComponent).toList()); + + lore.add(""); + lore.add("§7Cost"); + lore.addAll(totalPrice.getGUIDisplay()); + lore.add(""); + lore.add("§7Stock"); + lore.add("§6 " + player.getShoppingData().getStock(item.getItem().toUnderstandable()) + " §7remaining"); + lore.add(""); + lore.add("§eClick to purchase!"); + + Component baseName = itemStack.build().get(DataComponents.CUSTOM_NAME); + if (baseName == null) { + baseName = Component.text(sbItem.getDisplayName()); + } + + String displayName = StringUtility.getTextFromComponent(baseName.append(Component.text(" §8x" + amount))); + + return ItemStackCreator.getStack(displayName, itemStack.build().material(), amount, lore); + } + + private void attemptBuy(State state, int amount, ViewContext ctx) { + SkyBlockPlayer player = (SkyBlockPlayer) ctx.player(); + + if (!player.getShoppingData().canPurchase(state.item.getItem().toUnderstandable(), amount)) { + player.sendMessage("§cYou have reached the maximum amount of items you can buy!"); + return; + } + + ShopPrice totalPrice = state.stackPrice.multiply(amount); + if (!totalPrice.canAfford(player)) { + player.sendMessage("§cYou don't have enough " + state.stackPrice.getNamePlural() + "!"); + return; + } + + totalPrice.processPurchase(player); + + SkyBlockItem sbItem = state.item.getItem(); + ItemStack.Builder cleanStack = new NonPlayerItemUpdater(sbItem).getUpdatedItem(); + cleanStack.amount(amount); + player.addAndUpdateItem(cleanStack.build()); + player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); + player.getShoppingData().documentPurchase(state.item.getItem().toUnderstandable(), amount); + + ctx.session(Object.class).refresh(); + } + + public record State(ShopView.ShopItem item, ShopPrice stackPrice) { + } +} From 9e1cf64061e212e462cdce75f449a59ad0febbbf Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Wed, 14 Jan 2026 18:32:06 +0200 Subject: [PATCH 30/35] feat: soul well migration --- .../events/ActionSoulWellInteract.java | 2 +- .../type/skywarslobby/gui/GUISkyWarsMenu.java | 2 +- .../type/skywarslobby/gui/GUISoulWell.java | 336 +++++++------- .../skywarslobby/gui/GUISoulWellConfirm.java | 159 +++---- .../skywarslobby/gui/GUISoulWellRolling.java | 410 +++++++----------- 5 files changed, 382 insertions(+), 527 deletions(-) diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionSoulWellInteract.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionSoulWellInteract.java index e87e6967d..55bc00b3e 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionSoulWellInteract.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/events/ActionSoulWellInteract.java @@ -30,7 +30,7 @@ public void run(PlayerBlockInteractEvent event) { Block block = event.getBlock(); if (block.compare(Block.END_PORTAL_FRAME)) { event.setCancelled(true); - new GUISoulWell().open(player); + player.openView(new GUISoulWell()); } } } diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISkyWarsMenu.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISkyWarsMenu.java index ab54bfaf7..8c2ed670e 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISkyWarsMenu.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISkyWarsMenu.java @@ -140,7 +140,7 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public void run(InventoryPreClickEvent e, HypixelPlayer player) { - new GUISoulWell().open(player); + player.openView(new GUISoulWell()); } }); diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWell.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWell.java index 39a4497b6..76c901f85 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWell.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWell.java @@ -1,18 +1,16 @@ package net.swofty.type.skywarslobby.gui; -import net.minestom.server.event.inventory.InventoryPreClickEvent; +import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.click.Click; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.type.generic.data.datapoints.DatapointLong; import net.swofty.type.generic.data.datapoints.DatapointSoulWellUpgrades; import net.swofty.type.generic.data.handlers.SkywarsDataHandler; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skywarslobby.soulwell.SoulWellMessages; import net.swofty.type.skywarslobby.soulwell.SoulWellUpgrade; import net.swofty.type.skywarslobby.soulwell.SoulWellUpgradeRegistry; @@ -22,18 +20,20 @@ import java.util.List; import java.util.Locale; -public class GUISoulWell extends HypixelInventoryGUI { - private static final int BASE_ROLL_COST = 2; // Cost per wheel +public class GUISoulWell extends StatelessView { + private static final int BASE_ROLL_COST = 2; - public GUISoulWell() { - super("Soul Well", InventoryType.CHEST_6_ROW); + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>(Component.text("Soul Well"), InventoryType.CHEST_6_ROW); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - HypixelPlayer player = e.player(); - SkywarsDataHandler handler = SkywarsDataHandler.getUser(player); - long souls = handler != null ? handler.get(SkywarsDataHandler.Data.SOULS, DatapointLong.class).getValue() : 0; + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + layout.allowHotkey(false); + layout.filler(Components.FILLER); + + SkywarsDataHandler handler = SkywarsDataHandler.getUser(ctx.player()); long coins = handler != null ? handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).getValue() : 0; DatapointSoulWellUpgrades.SoulWellUpgrades playerUpgrades = handler != null ? handler.get(SkywarsDataHandler.Data.SOUL_WELL_UPGRADES, DatapointSoulWellUpgrades.class).getValue() @@ -43,10 +43,8 @@ public void onOpen(InventoryGUIOpenEvent e) { int rollCost = wheelCount * BASE_ROLL_COST; // Roll Soul Well button (slot 12) - set(new GUIClickableItem(12) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack( + layout.slot(12, + (_, _) -> ItemStackCreator.getStack( "§aRoll Soul Well", Material.END_PORTAL_FRAME, 1, @@ -56,116 +54,96 @@ public ItemStack.Builder getItem(HypixelPlayer player) { "§7Cost: §b" + rollCost + " Souls", "", "§eClick to roll!" - ); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - if (handler == null) return; - long currentSouls = handler.get(SkywarsDataHandler.Data.SOULS, DatapointLong.class).getValue(); - if (currentSouls < rollCost) { - player.sendMessage("§cYou don't have enough souls!"); - return; - } - - // Deduct souls - handler.get(SkywarsDataHandler.Data.SOULS, DatapointLong.class).setValue(currentSouls - rollCost); + ), + (_, c) -> { + if (handler == null) return; + long currentSouls = handler.get(SkywarsDataHandler.Data.SOULS, DatapointLong.class).getValue(); + if (currentSouls < rollCost) { + c.player().sendMessage("§cYou don't have enough souls!"); + return; + } - // Open rolling GUI - new GUISoulWellRolling(wheelCount).open(player); - } - }); + handler.get(SkywarsDataHandler.Data.SOULS, DatapointLong.class).setValue(currentSouls - rollCost); - // Soul Well Wheels setting (slot 14) - set(new GUIClickableItem(14) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - int wheels = getWheelCount(handler); - int cost = wheels * BASE_ROLL_COST; - String decreaseText = wheels > 1 ? "§eRight-click to decrease!" : ""; - String increaseText = wheels < 5 ? "§eLeft-click to increase!" : ""; - - List lore = new ArrayList<>(); - lore.add("§8Setting"); - lore.add(""); - lore.add("§7Change the number of wheels your"); - lore.add("§bSoul Well §7will spin each roll. §8(max 5)"); - lore.add(""); - lore.add("§7# of Wheels: §a" + wheels + " §8(" + cost + " Souls)"); - lore.add(""); - if (!increaseText.isEmpty()) lore.add(increaseText); - if (!decreaseText.isEmpty()) lore.add(decreaseText); - - return ItemStackCreator.getStack("§6Soul Well Wheels", Material.ENCHANTING_TABLE, 1, lore); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - if (handler == null) return; - int currentWheels = getWheelCount(handler); - - if (e.getClick() instanceof Click.Left && currentWheels < 5) { - setWheelCount(handler, currentWheels + 1); - } else if (e.getClick() instanceof Click.Right && currentWheels > 1) { - setWheelCount(handler, currentWheels - 1); + c.push(new GUISoulWellRolling(wheelCount)); } + ); - // Refresh GUI - new GUISoulWell().open(player); - } - }); - - // Xezbeth Luck (slot 28) - setUpgradeItem(28, "xezbeth_luck", playerUpgrades, coins, handler); - - // Harvesting Season (slot 30) - setUpgradeItem(30, "harvesting_season", playerUpgrades, coins, handler); - - // Angel of Death (slot 32) - setUpgradeItem(32, "angel_of_death", playerUpgrades, coins, handler); + // Soul Well Wheels setting (slot 14) + layout.slot(14, + (_, _) -> { + int wheels = getWheelCount(handler); + int cost = wheels * BASE_ROLL_COST; + String decreaseText = wheels > 1 ? "§eRight-click to decrease!" : ""; + String increaseText = wheels < 5 ? "§eLeft-click to increase!" : ""; + + List lore = new ArrayList<>(); + lore.add("§8Setting"); + lore.add(""); + lore.add("§7Change the number of wheels your"); + lore.add("§bSoul Well §7will spin each roll. §8(max 5)"); + lore.add(""); + lore.add("§7# of Wheels: §a" + wheels + " §8(" + cost + " Souls)"); + lore.add(""); + if (!increaseText.isEmpty()) lore.add(increaseText); + if (!decreaseText.isEmpty()) lore.add(decreaseText); + + return ItemStackCreator.getStack("§6Soul Well Wheels", Material.ENCHANTING_TABLE, 1, lore); + }, + (click, c) -> { + if (handler == null) return; + int currentWheels = getWheelCount(handler); + + if (click.click() instanceof Click.Left && currentWheels < 5) { + setWheelCount(handler, currentWheels + 1); + } else if (click.click() instanceof Click.Right && currentWheels > 1) { + setWheelCount(handler, currentWheels - 1); + } - // Head Collection (slot 34) - Skipped per user request - set(new GUIItem(34) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack( - "§cHead Collection", - Material.CHEST, - 1, - "§7View your collection of §cHeads§7.", - "", - "§7Players drop their §cHeads §7when killed", - "§7in §5Corrupted Games§7!", - "", - "§7Total Heads: §a0", - "", - "§8Coming soon..." - ); - } - }); + c.session(Object.class).refresh(); + } + ); + + // Upgrade items + layoutUpgradeItem(layout, 28, "xezbeth_luck", playerUpgrades, coins); + layoutUpgradeItem(layout, 30, "harvesting_season", playerUpgrades, coins); + layoutUpgradeItem(layout, 32, "angel_of_death", playerUpgrades, coins); + + // Head Collection placeholder (slot 34) + layout.slot(34, (_, _) -> ItemStackCreator.getStack( + "§cHead Collection", + Material.CHEST, + 1, + "§7View your collection of §cHeads§7.", + "", + "§7Players drop their §cHeads §7when killed", + "§7in §5Corrupted Games§7!", + "", + "§7Total Heads: §a0", + "", + "§8Coming soon..." + )); // Total Coins display (slot 50) - set(new GUIItem(50) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - String formattedCoins = NumberFormat.getNumberInstance(Locale.US).format(coins); - return ItemStackCreator.getStack( - "§7Total Coins: §6" + formattedCoins, - Material.EMERALD, - 1, - "§6https://store.hypixel.net" - ); - } + layout.slot(50, (_, _) -> { + String formattedCoins = NumberFormat.getNumberInstance(Locale.US).format(coins); + return ItemStackCreator.getStack( + "§7Total Coins: §6" + formattedCoins, + Material.EMERALD, + 1, + "§6https://store.hypixel.net" + ); }); // Close button (slot 49) - set(GUIClickableItem.getCloseItem(49)); - - updateItemStacks(getInventory(), getPlayer()); + Components.close(layout, 49); } - private void setUpgradeItem(int slot, String upgradeId, DatapointSoulWellUpgrades.SoulWellUpgrades playerUpgrades, - long coins, SkywarsDataHandler handler) { + private void layoutUpgradeItem(ViewLayout layout, + int slot, + String upgradeId, + DatapointSoulWellUpgrades.SoulWellUpgrades playerUpgrades, + long coins) { SoulWellUpgrade upgrade = SoulWellUpgradeRegistry.getUpgrade(upgradeId); if (upgrade == null) return; @@ -173,79 +151,71 @@ private void setUpgradeItem(int slot, String upgradeId, DatapointSoulWellUpgrade boolean isMaxed = upgrade.isMaxed(currentLevel); SoulWellUpgrade.SoulWellUpgradeTier nextTier = upgrade.getNextTier(currentLevel); - set(new GUIClickableItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - List lore = new ArrayList<>(); - lore.add("§8Permanent Upgrade"); - lore.add(""); - lore.add("§7" + upgrade.baseDescription()); - lore.add(""); - - String colorCode = upgrade.color(); - - if (isMaxed) { - // Maxed out - SoulWellUpgrade.SoulWellUpgradeTier currentTier = upgrade.getTier(currentLevel); - if (currentTier != null) { - lore.add("§7Current: §" + colorCode + currentTier.newEffect() + " §7" + currentTier.effectDescription()); - } + layout.slot(slot, + (_, _) -> { + List lore = new ArrayList<>(); + lore.add("§8Permanent Upgrade"); lore.add(""); - lore.add("§aMAXED OUT!"); - - return ItemStackCreator.getStack( - "§" + colorCode + upgrade.name() + " " + SoulWellMessages.toRoman(currentLevel), - upgrade.material(), - 1, - lore - ); - } else if (nextTier != null) { - // Can upgrade - lore.add(nextTier.getEffectChangeLine()); + lore.add("§7" + upgrade.baseDescription()); lore.add(""); - String formattedCost = NumberFormat.getNumberInstance(Locale.US).format(nextTier.cost()); - boolean canAfford = coins >= nextTier.cost(); + String colorCode = upgrade.color(); + + if (isMaxed) { + SoulWellUpgrade.SoulWellUpgradeTier currentTier = upgrade.getTier(currentLevel); + if (currentTier != null) { + lore.add("§7Current: §" + colorCode + currentTier.newEffect() + " §7" + currentTier.effectDescription()); + } + lore.add(""); + lore.add("§aMAXED OUT!"); + + return ItemStackCreator.getStack( + "§" + colorCode + upgrade.name() + " " + SoulWellMessages.toRoman(currentLevel), + upgrade.material(), + 1, + lore + ); + } - lore.add("§7Cost: §6" + formattedCost); - lore.add(""); + if (nextTier != null) { + lore.add(nextTier.getEffectChangeLine()); + lore.add(""); - if (canAfford) { - lore.add("§eClick to purchase!"); - } else { - lore.add("§cYou can't afford this!"); - } + String formattedCost = NumberFormat.getNumberInstance(Locale.US).format(nextTier.cost()); + boolean canAfford = coins >= nextTier.cost(); - String displayName; - if (currentLevel == 0) { - displayName = "§" + colorCode + upgrade.name(); - } else { - displayName = "§" + colorCode + upgrade.name() + " " + SoulWellMessages.toRoman(currentLevel) - + " §l→ §" + colorCode + SoulWellMessages.toRoman(currentLevel + 1); - } + lore.add("§7Cost: §6" + formattedCost); + lore.add(""); - return ItemStackCreator.getStack(displayName, upgrade.material(), 1, lore); - } + if (canAfford) lore.add("§eClick to purchase!"); + else lore.add("§cYou can't afford this!"); - return ItemStackCreator.getStack("§7" + upgrade.name(), upgrade.material(), 1, lore); - } + String displayName; + if (currentLevel == 0) { + displayName = "§" + colorCode + upgrade.name(); + } else { + displayName = "§" + colorCode + upgrade.name() + " " + SoulWellMessages.toRoman(currentLevel) + + " §l→ §" + colorCode + SoulWellMessages.toRoman(currentLevel + 1); + } - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - if (isMaxed) { - player.sendMessage("§cThis upgrade is already maxed out!"); - return; - } + return ItemStackCreator.getStack(displayName, upgrade.material(), 1, lore); + } - if (nextTier == null) { - player.sendMessage("§cNo upgrade tier found!"); - return; - } + return ItemStackCreator.getStack("§7" + upgrade.name(), upgrade.material(), 1, lore); + }, + (_, c) -> { + if (isMaxed) { + c.player().sendMessage("§cThis upgrade is already maxed out!"); + return; + } + if (nextTier == null) { + c.player().sendMessage("§cNo upgrade tier found!"); + return; + } - // Open confirmation GUI - new GUISoulWellConfirm(upgrade, nextTier, currentLevel + 1).open(player); - } - }); + c.push(new GUISoulWellConfirm(upgrade, nextTier, currentLevel + 1)); + } + ); } private int getWheelCount(SkywarsDataHandler handler) { @@ -261,14 +231,4 @@ private void setWheelCount(SkywarsDataHandler handler, int count) { SkywarsDataHandler.Data.SOUL_WELL_UPGRADES, DatapointSoulWellUpgrades.class).getValue(); upgrades.setWheelCount(count); } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); - } } diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWellConfirm.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWellConfirm.java index bf3bdeb0c..726e0e4ff 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWellConfirm.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWellConfirm.java @@ -1,79 +1,79 @@ package net.swofty.type.skywarslobby.gui; -import net.minestom.server.event.inventory.InventoryPreClickEvent; +import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.swofty.type.generic.data.datapoints.DatapointLong; import net.swofty.type.generic.data.datapoints.DatapointSoulWellUpgrades; import net.swofty.type.generic.data.handlers.SkywarsDataHandler; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skywarslobby.soulwell.SoulWellMessages; import net.swofty.type.skywarslobby.soulwell.SoulWellUpgrade; import java.text.NumberFormat; import java.util.Locale; -public class GUISoulWellConfirm extends HypixelInventoryGUI { +public class GUISoulWellConfirm extends StatelessView { + private final SoulWellUpgrade upgrade; private final SoulWellUpgrade.SoulWellUpgradeTier tier; private final int newLevel; public GUISoulWellConfirm(SoulWellUpgrade upgrade, SoulWellUpgrade.SoulWellUpgradeTier tier, int newLevel) { - super("Are you sure?", InventoryType.CHEST_3_ROW); this.upgrade = upgrade; this.tier = tier; this.newLevel = newLevel; } @Override - public void onOpen(InventoryGUIOpenEvent e) { - fill(ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, " ")); + public ViewConfiguration configuration() { + return new ViewConfiguration<>(Component.text("Are you sure?"), InventoryType.CHEST_3_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + layout.allowHotkey(false); + layout.filler(Components.FILLER); - HypixelPlayer player = e.player(); - SkywarsDataHandler handler = SkywarsDataHandler.getUser(player); + SkywarsDataHandler handler = SkywarsDataHandler.getUser(ctx.player()); long coins = handler != null ? handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).getValue() : 0; String formattedCost = NumberFormat.getNumberInstance(Locale.US).format(tier.cost()); boolean canAfford = coins >= tier.cost(); - // Display item in the middle (slot 13) - set(new GUIItem(13) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - String colorCode = upgrade.color(); - return ItemStackCreator.getStack( - "§" + colorCode + upgrade.name() + " " + SoulWellMessages.toRoman(newLevel), - upgrade.material(), - 1, - "§8Permanent Upgrade", - "", - "§7" + upgrade.baseDescription(), - "", - tier.getEffectChangeLine(), - "", - "§7Cost: §6" + formattedCost - ); - } + layout.slot(13, (_, __) -> { + String colorCode = upgrade.color(); + return ItemStackCreator.getStack( + "§" + colorCode + upgrade.name() + " " + SoulWellMessages.toRoman(newLevel), + upgrade.material(), + 1, + "§8Permanent Upgrade", + "", + "§7" + upgrade.baseDescription(), + "", + tier.getEffectChangeLine(), + "", + "§7Cost: §6" + formattedCost + ); }); - // Confirm button (slot 11) - set(new GUIClickableItem(11) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - if (canAfford) { - return ItemStackCreator.getStack( - "§aConfirm", - Material.LIME_TERRACOTTA, - 1, - "§7Click to purchase §" + upgrade.color() + upgrade.name(), - "§7for §6" + formattedCost + " Coins§7." - ); - } else { + layout.slot(11, + (_, __) -> { + if (canAfford) { + return ItemStackCreator.getStack( + "§aConfirm", + Material.LIME_TERRACOTTA, + 1, + "§7Click to purchase §" + upgrade.color() + upgrade.name(), + "§7for §6" + formattedCost + " Coins§7." + ); + } return ItemStackCreator.getStack( "§cCannot Afford", Material.GRAY_TERRACOTTA, @@ -83,64 +83,39 @@ public ItemStack.Builder getItem(HypixelPlayer player) { "", "§cYou don't have enough coins!" ); - } - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - if (!canAfford) { - player.sendMessage("§cYou don't have enough coins to purchase this upgrade!"); - return; - } + }, + (_, c) -> { + SkywarsDataHandler dataHandler = SkywarsDataHandler.getUser(c.player()); + if (dataHandler == null) return; - SkywarsDataHandler dataHandler = SkywarsDataHandler.getUser(player); - if (dataHandler == null) return; + DatapointLong coinsDatapoint = dataHandler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class); + long currentCoins = coinsDatapoint.getValue(); + if (currentCoins < tier.cost()) { + c.player().sendMessage("§cYou don't have enough coins to purchase this upgrade!"); + c.session(Object.class).refresh(); + return; + } - // Deduct coins - DatapointLong coinsDatapoint = dataHandler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class); - coinsDatapoint.setValue(coinsDatapoint.getValue() - tier.cost()); + coinsDatapoint.setValue(currentCoins - tier.cost()); - // Upgrade the player's upgrade level - DatapointSoulWellUpgrades upgradesDatapoint = dataHandler.get( - SkywarsDataHandler.Data.SOUL_WELL_UPGRADES, DatapointSoulWellUpgrades.class); - upgradesDatapoint.getValue().setUpgradeLevel(upgrade.id(), newLevel); + DatapointSoulWellUpgrades upgradesDatapoint = dataHandler.get( + SkywarsDataHandler.Data.SOUL_WELL_UPGRADES, DatapointSoulWellUpgrades.class); + upgradesDatapoint.getValue().setUpgradeLevel(upgrade.id(), newLevel); - // Send centered purchase message - SoulWellMessages.sendPurchaseMessage(player, upgrade, tier, newLevel); + SoulWellMessages.sendPurchaseMessage(c.player(), upgrade, tier, newLevel); - // Return to Soul Well GUI - new GUISoulWell().open(player); - } - }); + c.replace(new GUISoulWell()); + } + ); - // Cancel button (slot 15) - set(new GUIClickableItem(15) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack( + layout.slot(15, + (_, __) -> ItemStackCreator.getStack( "§cCancel", Material.RED_TERRACOTTA, 1, "§7Click to go back." - ); - } - - @Override - public void run(InventoryPreClickEvent e, HypixelPlayer player) { - new GUISoulWell().open(player); - } - }); - - updateItemStacks(e.inventory(), getPlayer()); - } - - @Override - public boolean allowHotkeying() { - return false; - } - - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + ), + (_, c) -> c.replace(new GUISoulWell()) + ); } } diff --git a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWellRolling.java b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWellRolling.java index 10b0501b6..1dc2a6cae 100644 --- a/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWellRolling.java +++ b/type.skywarslobby/src/main/java/net/swofty/type/skywarslobby/gui/GUISoulWellRolling.java @@ -1,344 +1,264 @@ package net.swofty.type.skywarslobby.gui; +import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; -import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.timer.Task; import net.minestom.server.timer.TaskSchedule; -import net.swofty.commons.skywars.SoulWellRewardType; import net.swofty.type.generic.data.datapoints.DatapointLong; import net.swofty.type.generic.data.datapoints.DatapointSkywarsUnlocks; import net.swofty.type.generic.data.handlers.SkywarsDataHandler; -import net.swofty.type.generic.gui.inventory.HypixelInventoryGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; -import net.swofty.type.generic.gui.inventory.item.GUIItem; -import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.skywarslobby.kit.SkywarsKit; import net.swofty.type.skywarslobby.kit.SkywarsKitRegistry; import net.swofty.type.skywarslobby.perk.SkywarsPerk; import net.swofty.type.skywarslobby.perk.SkywarsPerkRegistry; +import java.time.Duration; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Random; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Set; -public class GUISoulWellRolling extends HypixelInventoryGUI { +public class GUISoulWellRolling implements StatefulView { private static final Random RANDOM = new Random(); - private static final Material[] GLASS_COLORS = { - Material.PINK_STAINED_GLASS_PANE, - Material.LIME_STAINED_GLASS_PANE, - Material.LIGHT_BLUE_STAINED_GLASS_PANE, - Material.ORANGE_STAINED_GLASS_PANE, - Material.YELLOW_STAINED_GLASS_PANE, - Material.MAGENTA_STAINED_GLASS_PANE - }; - - // Wheel column positions centered for different wheel counts - // 1 wheel: center column (4) - private static final int[][] WHEEL_SLOTS_1 = { - {4, 13, 22, 31, 40} // Center column - }; - - // 2 wheels: columns 3 and 5 - private static final int[][] WHEEL_SLOTS_2 = { - {3, 12, 21, 30, 39}, // Left of center - {5, 14, 23, 32, 41} // Right of center - }; - - // 3 wheels: columns 2, 4, 6 - private static final int[][] WHEEL_SLOTS_3 = { - {2, 11, 20, 29, 38}, // Left - {4, 13, 22, 31, 40}, // Center - {6, 15, 24, 33, 42} // Right - }; - - // 4 wheels: columns 1, 3, 5, 7 - private static final int[][] WHEEL_SLOTS_4 = { - {1, 10, 19, 28, 37}, // Column 1 - {3, 12, 21, 30, 39}, // Column 3 - {5, 14, 23, 32, 41}, // Column 5 - {7, 16, 25, 34, 43} // Column 7 - }; - - // 5 wheels: columns 0, 2, 4, 6, 8 - private static final int[][] WHEEL_SLOTS_5 = { - {0, 9, 18, 27, 36}, // Column 0 - {2, 11, 20, 29, 38}, // Column 2 - {4, 13, 22, 31, 40}, // Column 4 - {6, 15, 24, 33, 42}, // Column 6 - {8, 17, 26, 35, 44} // Column 8 - }; + private static final Material[] GLASS_COLORS = {Material.PINK_STAINED_GLASS_PANE, Material.LIME_STAINED_GLASS_PANE, Material.LIGHT_BLUE_STAINED_GLASS_PANE, Material.ORANGE_STAINED_GLASS_PANE, Material.YELLOW_STAINED_GLASS_PANE, Material.MAGENTA_STAINED_GLASS_PANE}; + + private static final int TOTAL_TICKS = 40; + private static final int CLOSE_DELAY_MILLIS = 15000; private final int wheelCount; private final List finalRewards; private final List> wheelItems; - private boolean rewardsProcessed = false; + private final int[][] wheelSlots; public GUISoulWellRolling(int wheelCount) { - super("Soul Well", InventoryType.CHEST_5_ROW); this.wheelCount = Math.min(5, Math.max(1, wheelCount)); this.finalRewards = new ArrayList<>(); this.wheelItems = new ArrayList<>(); - // Generate rewards for each wheel for (int i = 0; i < this.wheelCount; i++) { finalRewards.add(generateRandomReward()); wheelItems.add(generateWheelItems()); } + + this.wheelSlots = calculateWheelSlots(this.wheelCount); } @Override - public void onOpen(InventoryGUIOpenEvent e) { - HypixelPlayer player = e.player(); - - // Fill all slots with random glass initially - for (int i = 0; i < 45; i++) { - final int slot = i; - set(new GUIItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack( - "§8Rolling...", - getRandomGlass(), - 1 - ); - } - }); - } - - updateItemStacks(getInventory(), getPlayer()); - - // Start the rolling animation - startRollingAnimation(player); + public ViewConfiguration configuration() { + return new ViewConfiguration<>(Component.text("Soul Well"), InventoryType.CHEST_5_ROW); } - private void startRollingAnimation(HypixelPlayer player) { - AtomicInteger tickCount = new AtomicInteger(0); - int totalTicks = 40; - int[][] wheelSlots = getWheelSlots(wheelCount); - int actualWheelCount = wheelSlots.length; + @Override + public void onOpen(State state, ViewContext ctx) { + MinecraftServer.getSchedulerManager().scheduleNextTick(() -> startRolling(ctx)); + } - MinecraftServer.getSchedulerManager().buildTask(() -> { - int tick = tickCount.getAndIncrement(); + private void startRolling(ViewContext ctx) { + ViewSession session = ctx.session(State.class); - if (!player.isOnline() || getInventory() == null) { + final Task[] task = new Task[1]; + task[0] = MinecraftServer.getSchedulerManager().buildTask(() -> { + if (session.isClosed()) { + task[0].cancel(); return; } - // Update each wheel - for (int wheel = 0; wheel < actualWheelCount; wheel++) { - int[] slots = wheelSlots[wheel]; - List items = wheelItems.get(wheel); - SoulWellReward finalReward = finalRewards.get(wheel); - - // Calculate how far through the animation we are - double progress = (double) tick / totalTicks; - - // Wheels stop at different times - int stopTick = totalTicks - (actualWheelCount - wheel - 1) * 5; - - if (tick >= stopTick) { - // This wheel has stopped - show final reward in center - for (int i = 0; i < slots.length; i++) { - int slot = slots[i]; - if (i == 2) { // Center slot (index 2 of 5) - setRewardItem(slot, finalReward); - } else { - // Show nearby items - int offset = i - 2; - int itemIndex = (items.size() / 2 + offset + items.size()) % items.size(); - setRewardItem(slot, items.get(itemIndex)); - } - } - } else { - // Still rolling - cycle through items - int offset = tick % items.size(); - for (int i = 0; i < slots.length; i++) { - int slot = slots[i]; - int itemIndex = (offset + i) % items.size(); - setRewardItem(slot, items.get(itemIndex)); - } + State s = session.state(); + int nextTick = s.tick + 1; + + // Check which wheels should stop this tick and give rewards + Set newlyStopped = new HashSet<>(s.stoppedWheels); + for (int wheel = 0; wheel < wheelCount; wheel++) { + int stopTick = getStopTick(wheel); + if (nextTick >= stopTick && !s.stoppedWheels.contains(wheel)) { + newlyStopped.add(wheel); + giveReward(ctx, finalRewards.get(wheel)); } } - // Fill remaining slots with glass - for (int i = 0; i < 45; i++) { - boolean isWheelSlot = false; - for (int wheel = 0; wheel < actualWheelCount; wheel++) { - int[] slots = wheelSlots[wheel]; - for (int slot : slots) { - if (slot == i) { - isWheelSlot = true; - break; - } + session.update(_ -> new State(nextTick, newlyStopped)); + if (newlyStopped.size() >= wheelCount) { + task[0].cancel(); + MinecraftServer.getSchedulerManager().buildTask(() -> { + if (!session.isClosed()) ctx.player().closeInventory(); + }).delay(TaskSchedule.millis(CLOSE_DELAY_MILLIS)).schedule(); + } + }).delay(TaskSchedule.millis(50)).repeat(TaskSchedule.millis(100)).schedule(); + + session.onClose(_ -> task[0].cancel()); + } + + @Override + public void layout(ViewLayout layout, State state, ViewContext ctx) { + layout.allowHotkey(false); + for (int slot = 0; slot < 45; slot++) { + int finalSlot = slot; + layout.autoUpdating(finalSlot, (s, _) -> renderSlot(finalSlot, s), Duration.ofMillis(100)); + } + } + + private ItemStack.Builder renderSlot(int slot, State state) { + for (int wheel = 0; wheel < wheelSlots.length; wheel++) { + int[] slots = wheelSlots[wheel]; + + // Check adjacent columns for black glass + int wheelCol = slots[0] % 9; + int slotCol = slot % 9; + int slotRow = slot / 9; + + // Left side of wheel column's middle position + if (slotCol == wheelCol - 1 && slotRow == 2) { + return ItemStackCreator.getStack(" ", Material.BLACK_STAINED_GLASS_PANE, 1); + } + // Right side of wheel column's middle position + if (slotCol == wheelCol + 1 && slotRow == 2) { + return ItemStackCreator.getStack(" ", Material.BLACK_STAINED_GLASS_PANE, 1); + } + + for (int i = 0; i < slots.length; i++) { + if (slots[i] != slot) continue; + + boolean stopped = state.stoppedWheels.contains(wheel); + + if (stopped) { + if (i == 2) { + return finalRewards.get(wheel).toItemStack(); } - if (isWheelSlot) break; + return ItemStackCreator.getStack(" ", Material.AIR, 1); } - if (!isWheelSlot) { - final int slot = i; - set(new GUIItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return ItemStackCreator.getStack( - "§8Rolling...", - getRandomGlass(), - 1 - ); - } - }); - } + List items = wheelItems.get(wheel); + int itemIndex = (state.tick + i) % items.size(); + return items.get(itemIndex).toItemStack(); } + } - updateItemStacks(getInventory(), getPlayer()); + boolean allStopped = state.stoppedWheels.size() >= wheelCount; + if (allStopped) { + return ItemStackCreator.getStack(" ", Material.AIR, 1); + } + return ItemStackCreator.getStack(" ", GLASS_COLORS[RANDOM.nextInt(GLASS_COLORS.length)], 1); + } - // Animation complete - if (tick >= totalTicks && !rewardsProcessed) { - rewardsProcessed = true; - // Process rewards and close after a short delay - MinecraftServer.getSchedulerManager().buildTask(() -> { - processRewards(player); - player.closeInventory(); - }).delay(TaskSchedule.millis(1500)).schedule(); - } - }).delay(TaskSchedule.millis(50)).repeat(TaskSchedule.millis(100)).schedule(); + private int getStopTick(int wheel) { + return TOTAL_TICKS - (wheelCount - wheel - 1) * 5; } - private void setRewardItem(int slot, SoulWellReward reward) { - set(new GUIItem(slot) { - @Override - public ItemStack.Builder getItem(HypixelPlayer player) { - return reward.toItemStack(); + private static int[][] calculateWheelSlots(int count) { + int[][] slots = new int[count][5]; + int[] columns = switch (count) { + case 1 -> new int[]{4}; + case 2 -> new int[]{3, 5}; + case 3 -> new int[]{2, 4, 6}; + case 4 -> new int[]{1, 3, 5, 7}; + default -> new int[]{0, 2, 4, 6, 8}; + }; + + for (int wheel = 0; wheel < count; wheel++) { + int col = columns[wheel]; + for (int row = 0; row < 5; row++) { + slots[wheel][row] = row * 9 + col; } - }); + } + return slots; } - private void processRewards(HypixelPlayer player) { - SkywarsDataHandler handler = SkywarsDataHandler.getUser(player); + private void giveReward(ViewContext ctx, SoulWellReward reward) { + SkywarsDataHandler handler = SkywarsDataHandler.getUser(ctx.player()); if (handler == null) return; - for (SoulWellReward reward : finalRewards) { - switch (reward.type) { - case COINS_SMALL -> { - int amount = 100 + RANDOM.nextInt(401); - long currentCoins = handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).getValue(); - handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).setValue(currentCoins + amount); - player.sendMessage("§6§lSOUL WELL! §7You received §6" + amount + " Coins§7!"); - } - case COINS_MEDIUM -> { - int amount = 300 + RANDOM.nextInt(701); - long currentCoins = handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).getValue(); - handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).setValue(currentCoins + amount); - player.sendMessage("§9§lSOUL WELL! §7You received §9" + amount + " Coins§7!"); - } - case COINS_LARGE -> { - int amount = 500 + RANDOM.nextInt(1501); - long currentCoins = handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).getValue(); - handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).setValue(currentCoins + amount); - player.sendMessage("§6§lSOUL WELL! §7You received §6" + amount + " Coins§7!"); - } - case KIT -> { - if (reward.kit != null) { - DatapointSkywarsUnlocks.SkywarsUnlocks unlocks = handler.get( - SkywarsDataHandler.Data.UNLOCKS, - DatapointSkywarsUnlocks.class - ).getValue(); - unlocks.unlockKit(reward.kit.getId()); - player.sendMessage("§a§lSOUL WELL! §7You unlocked the §a" + reward.kit.getName() + " Kit§7!"); - } + switch (reward.type) { + case COINS_SMALL -> { + int amount = 100 + RANDOM.nextInt(401); + long coins = handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).getValue(); + handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).setValue(coins + amount); + ctx.player().sendMessage("§6§lSOUL WELL! §7You received §6" + amount + " Coins§7!"); + } + case COINS_MEDIUM -> { + int amount = 300 + RANDOM.nextInt(701); + long coins = handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).getValue(); + handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).setValue(coins + amount); + ctx.player().sendMessage("§9§lSOUL WELL! §7You received §9" + amount + " Coins§7!"); + } + case COINS_LARGE -> { + int amount = 500 + RANDOM.nextInt(1501); + long coins = handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).getValue(); + handler.get(SkywarsDataHandler.Data.COINS, DatapointLong.class).setValue(coins + amount); + ctx.player().sendMessage("§6§lSOUL WELL! §7You received §6" + amount + " Coins§7!"); + } + case KIT -> { + if (reward.kit != null) { + var unlocks = handler.get(SkywarsDataHandler.Data.UNLOCKS, DatapointSkywarsUnlocks.class).getValue(); + unlocks.unlockKit(reward.kit.getId()); + ctx.player().sendMessage("§a§lSOUL WELL! §7You unlocked the §a" + reward.kit.getName() + " Kit§7!"); } - case PERK -> { - if (reward.perk != null) { - DatapointSkywarsUnlocks.SkywarsUnlocks unlocks = handler.get( - SkywarsDataHandler.Data.UNLOCKS, - DatapointSkywarsUnlocks.class - ).getValue(); - unlocks.unlockPerk(reward.perk.getId()); - player.sendMessage("§a§lSOUL WELL! §7You unlocked the §a" + reward.perk.getName() + " Perk§7!"); - } + } + case PERK -> { + if (reward.perk != null) { + var unlocks = handler.get(SkywarsDataHandler.Data.UNLOCKS, DatapointSkywarsUnlocks.class).getValue(); + unlocks.unlockPerk(reward.perk.getId()); + ctx.player().sendMessage("§a§lSOUL WELL! §7You unlocked the §a" + reward.perk.getName() + " Perk§7!"); } } } } - private SoulWellReward generateRandomReward() { + private static SoulWellReward generateRandomReward() { int roll = RANDOM.nextInt(100); - - if (roll < 30) { - // 30% - Small coins - return new SoulWellReward(RewardType.COINS_SMALL, null, null, "Small bag of coins"); - } else if (roll < 50) { - // 20% - Medium coins - return new SoulWellReward(RewardType.COINS_MEDIUM, null, null, "Medium bag of coins"); - } else if (roll < 60) { - // 10% - Large coins - return new SoulWellReward(RewardType.COINS_LARGE, null, null, "Large bag of coins"); - } else if (roll < 80) { - // 20% - Kit (only Soul Well droppable kits) + if (roll < 30) return new SoulWellReward(RewardType.COINS_SMALL, null, null, "Small bag of coins"); + if (roll < 50) return new SoulWellReward(RewardType.COINS_MEDIUM, null, null, "Medium bag of coins"); + if (roll < 60) return new SoulWellReward(RewardType.COINS_LARGE, null, null, "Large bag of coins"); + if (roll < 80) { List kits = SkywarsKitRegistry.getSoulWellKits(); if (!kits.isEmpty()) { SkywarsKit kit = kits.get(RANDOM.nextInt(kits.size())); return new SoulWellReward(RewardType.KIT, kit, null, kit.getName() + " Kit"); } } else { - // 20% - Perk (only Soul Well droppable perks) List perks = SkywarsPerkRegistry.getSoulWellPerks(); if (!perks.isEmpty()) { SkywarsPerk perk = perks.get(RANDOM.nextInt(perks.size())); return new SoulWellReward(RewardType.PERK, null, perk, perk.getName() + " Perk"); } } - - // Fallback to coins return new SoulWellReward(RewardType.COINS_SMALL, null, null, "Small bag of coins"); } - private List generateWheelItems() { + private static List generateWheelItems() { List items = new ArrayList<>(); - - // Add a mix of items to the wheel - for (int i = 0; i < 15; i++) { - items.add(generateRandomReward()); - } - + for (int i = 0; i < 15; i++) items.add(generateRandomReward()); return items; } - private Material getRandomGlass() { - return GLASS_COLORS[RANDOM.nextInt(GLASS_COLORS.length)]; - } - - private int[][] getWheelSlots(int count) { - return switch (count) { - case 1 -> WHEEL_SLOTS_1; - case 2 -> WHEEL_SLOTS_2; - case 3 -> WHEEL_SLOTS_3; - case 4 -> WHEEL_SLOTS_4; - default -> WHEEL_SLOTS_5; - }; + @Override + public boolean onClick(ClickContext click, ViewContext ctx) { + return true; } @Override - public boolean allowHotkeying() { - return false; + public State initialState() { + return new State(); } - @Override - public void onBottomClick(InventoryPreClickEvent e) { - e.setCancelled(true); + public record State(int tick, Set stoppedWheels) { + public State() { + this(0, new HashSet<>()); + } } - private enum RewardType { - COINS_SMALL, - COINS_MEDIUM, - COINS_LARGE, - KIT, - PERK + public enum RewardType { + COINS_SMALL, COINS_MEDIUM, COINS_LARGE, KIT, PERK } - private record SoulWellReward(RewardType type, SkywarsKit kit, SkywarsPerk perk, String displayName) { + public record SoulWellReward(RewardType type, SkywarsKit kit, SkywarsPerk perk, String displayName) { public ItemStack.Builder toItemStack() { return switch (type) { case COINS_SMALL -> ItemStackCreator.getStack("§aSmall bag of coins", Material.SUNFLOWER, 1); From 1f3aa949a3a71f9487f4572e7a37e5d7481722a4 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:56:42 +0200 Subject: [PATCH 31/35] chore: remove unused Pagination in favor of PaginationView --- .../type/generic/gui/v2/Pagination.java | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java deleted file mode 100644 index a398b21e6..000000000 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Pagination.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.swofty.type.generic.gui.v2; - -import net.minestom.server.item.ItemStack; -import net.swofty.type.generic.gui.v2.context.ClickContext; -import net.swofty.type.generic.gui.v2.context.ViewContext; - -import java.util.List; -import java.util.function.BiFunction; - -public final class Pagination { - - public record Page(List items, int current, int total) { - public boolean hasNext() { - return current < total - 1; - } - - public boolean hasPrev() { - return current > 0; - } - } - - public static Page paginate(List all, int page, int perPage) { - int totalPages = Math.max(1, (int) Math.ceil((double) all.size() / perPage)); - int start = page * perPage; - int end = Math.min(start + perPage, all.size()); - List items = start < all.size() ? all.subList(start, end) : List.of(); - return new Page<>(items, page, totalPages); - } - - public static void items( - ViewLayout layout, - List slots, - List items, - BiFunction renderer, - ClickHandler onClick - ) { - for (int i = 0; i < slots.size(); i++) { - int slot = slots.get(i); - if (i < items.size()) { - T item = items.get(i); - int index = i; - layout.slot(slot, (_, _) -> renderer.apply(item, index), - (click, ctx) -> onClick.handle(click, ctx, item, index)); - } else { - layout.slot(slot, (_, _) -> ItemStack.AIR.builder()); - } - } - } - - @FunctionalInterface - public interface ClickHandler { - void handle(ClickContext click, ViewContext ctx, T item, int index); - } -} - From 24cc6da24727ce4421936c1b834ab6ba8d7a4741 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:57:59 +0200 Subject: [PATCH 32/35] refactor: import instead --- .../type/dwarvenmines/commission/CommissionMilestone.java | 5 ++++- .../main/java/net/swofty/type/generic/gui/v2/Layouts.java | 5 +++-- .../swofty/type/generic/gui/v2/test/TestContainerView.java | 1 - .../type/skyblockgeneric/bazaar/BazaarConnector.java | 5 +++-- .../type/skyblockgeneric/loottable/SkyBlockLootTable.java | 7 ++----- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/commission/CommissionMilestone.java b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/commission/CommissionMilestone.java index f075dd298..00e7f7618 100644 --- a/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/commission/CommissionMilestone.java +++ b/type.dwarvenmines/src/main/java/net/swofty/type/dwarvenmines/commission/CommissionMilestone.java @@ -2,6 +2,9 @@ import lombok.Getter; +import java.util.ArrayList; +import java.util.List; + @Getter public enum CommissionMilestone { TIER_1(1, 5, 100_000, 20, true, false, false, false, false, false), @@ -58,7 +61,7 @@ public static CommissionMilestone getNextMilestone(int totalCompleted) { } public String[] getRewardDescriptions() { - java.util.List rewards = new java.util.ArrayList<>(); + List rewards = new ArrayList<>(); if (unlocksEmissaries) { rewards.add("§7- §aEmissaries"); diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Layouts.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Layouts.java index 37101e179..009f12bc4 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Layouts.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/Layouts.java @@ -1,5 +1,6 @@ package net.swofty.type.generic.gui.v2; +import java.util.ArrayList; import java.util.List; import java.util.stream.IntStream; @@ -11,7 +12,7 @@ public static List rectangle(int from, int to) { int startCol = from % 9; int endCol = to % 9; - List slots = new java.util.ArrayList<>(); + List slots = new ArrayList<>(); for (int row = startRow; row <= endRow; row++) { for (int col = startCol; col <= endCol; col++) { @@ -28,7 +29,7 @@ public static List border(int from, int to) { int startCol = from % 9; int endCol = to % 9; - List slots = new java.util.ArrayList<>(); + List slots = new ArrayList<>(); for (int row = startRow; row <= endRow; row++) { for (int col = startCol; col <= endCol; col++) { diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java index 8789a9f08..165695ae1 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/test/TestContainerView.java @@ -1,6 +1,5 @@ package net.swofty.type.generic.gui.v2.test; -import net.kyori.adventure.text.Component; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarConnector.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarConnector.java index bcd33f815..58500d297 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarConnector.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/bazaar/BazaarConnector.java @@ -7,6 +7,7 @@ import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; import java.text.DecimalFormat; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -261,8 +262,8 @@ private CompletableFuture processTransactions(List successfulIds = new java.util.ArrayList<>(); - List failedIds = new java.util.ArrayList<>(); + List successfulIds = new ArrayList<>(); + List failedIds = new ArrayList<>(); for (PendingTransaction tx : transactions) { try { diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/loottable/SkyBlockLootTable.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/loottable/SkyBlockLootTable.java index 3ce723aa3..175cfc71b 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/loottable/SkyBlockLootTable.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/loottable/SkyBlockLootTable.java @@ -7,10 +7,7 @@ import net.swofty.commons.skyblock.item.ItemType; import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Function; public abstract class SkyBlockLootTable { @@ -22,7 +19,7 @@ public int makeAmountBetween(int min, int max) { } public @NonNull List getLootTableItems() { - List items = new java.util.ArrayList<>(); + List items = new ArrayList<>(); for (LootRecord record : getLootTable()) { items.add(record.itemType); } From 17b940ceceb2a30978ce86619b0cc057a6491cc8 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 17 Jan 2026 12:49:30 +0200 Subject: [PATCH 33/35] feat: add eventNode to inventory's eventNode --- .../main/java/net/swofty/type/generic/gui/v2/ViewSession.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index a01ee256c..96ca1d1ca 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -110,7 +110,7 @@ private void wireEvents() { eventNode.addListener(InventoryClickEvent.class, this::onPostClickEvent); eventNode.addListener(InventoryCloseEvent.class, this::onCloseEvent); eventNode.addListener(InventoryOpenEvent.class, this::onOpenEvent); - MinecraftServer.getGlobalEventHandler().addChild(eventNode); + inventory.eventNode().addChild(eventNode); } private void onOpenEvent(InventoryOpenEvent event) { From 8f09d5fa7d7f6e1389d3fc983f528770229a6210 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 17 Jan 2026 13:11:31 +0200 Subject: [PATCH 34/35] feat: move events out of ViewSession --- .../swofty/type/generic/event/EventNodes.java | 1 + .../type/generic/gui/v2/ViewSession.java | 39 +++++-------------- .../gui/v2/event/ActionInventoryClose.java | 26 +++++++++++++ .../gui/v2/event/ActionInventoryOpen.java | 18 +++++++++ .../v2/event/ActionInventoryPostClick.java | 18 +++++++++ .../gui/v2/event/ActionInventoryPreClick.java | 20 ++++++++++ 6 files changed, 92 insertions(+), 30 deletions(-) create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryClose.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryOpen.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPostClick.java create mode 100644 type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPreClick.java diff --git a/type.generic/src/main/java/net/swofty/type/generic/event/EventNodes.java b/type.generic/src/main/java/net/swofty/type/generic/event/EventNodes.java index d9132f7b9..62fb02282 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/event/EventNodes.java +++ b/type.generic/src/main/java/net/swofty/type/generic/event/EventNodes.java @@ -14,6 +14,7 @@ public enum EventNodes { PLAYER_DATA(EventNode.type("player-data", EventFilter.PLAYER).setPriority(1)), ITEM(EventNode.type("item-listener", EventFilter.PLAYER)), PING(EventNode.type("ping-listener", EventFilter.ALL)), + INVENTORY(EventNode.type("inventory-listener", EventFilter.INVENTORY)), ALL(EventNode.all("all-listener")), // Player nodes diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java index 96ca1d1ca..466dafa72 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/ViewSession.java @@ -3,15 +3,12 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import lombok.Getter; +import lombok.Setter; import lombok.experimental.Accessors; import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; -import net.minestom.server.event.EventFilter; -import net.minestom.server.event.EventNode; import net.minestom.server.event.inventory.InventoryClickEvent; -import net.minestom.server.event.inventory.InventoryCloseEvent; import net.minestom.server.event.inventory.InventoryPreClickEvent; -import net.minestom.server.event.trait.InventoryEvent; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.inventory.click.Click; @@ -28,6 +25,7 @@ import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.UnaryOperator; public final class ViewSession { @@ -51,7 +49,6 @@ public final class ViewSession { @Getter @Accessors(fluent = true) private final ViewContext context; - private final EventNode eventNode; @Getter @Accessors(fluent = true) @@ -63,6 +60,9 @@ public final class ViewSession { @Getter private boolean closed; + + @Getter + @Setter private boolean suppressCloseEvent; private final Int2ObjectOpenHashMap trackedSlotItems = new Int2ObjectOpenHashMap<>(); @@ -82,9 +82,6 @@ private ViewSession(View view, HypixelPlayer player, S initialState, SharedCo this.sharedContext = sharedContext; this.inventory = new Inventory(view.configuration().getInventoryType(), ""); this.context = new ViewContext(player, inventory, this); - this.eventNode = EventNode.type("gui-" + System.identityHashCode(this), EventFilter.INVENTORY); - - wireEvents(); if (sharedContext != null) { sharedContext.registerSession(this); @@ -105,20 +102,12 @@ static ViewSession openShared(View view, HypixelPlayer player, SharedC return session; } - private void wireEvents() { - eventNode.addListener(InventoryPreClickEvent.class, this::onPreClickEvent); - eventNode.addListener(InventoryClickEvent.class, this::onPostClickEvent); - eventNode.addListener(InventoryCloseEvent.class, this::onCloseEvent); - eventNode.addListener(InventoryOpenEvent.class, this::onOpenEvent); - inventory.eventNode().addChild(eventNode); - } - - private void onOpenEvent(InventoryOpenEvent event) { + public void onOpenEvent(@NonNull InventoryOpenEvent event) { if (event.getInventory() != inventory || closed) return; view.onOpen(state, context); } - private void onPreClickEvent(InventoryPreClickEvent event) { + public void onPreClickEvent(@NonNull InventoryPreClickEvent event) { if (event.getInventory() instanceof PlayerInventory) { if (player.getOpenInventory() == inventory) { var click = new ClickContext<>(event.getSlot(), event.getClick(), player, state); @@ -133,7 +122,6 @@ private void onPreClickEvent(InventoryPreClickEvent event) { int slot = event.getSlot(); SlotBehavior behavior = cachedLayout != null ? cachedLayout.getBehavior(slot) : SlotBehavior.UI; - if (behavior == SlotBehavior.EDITABLE) { if (event.getClick() instanceof Click.LeftShift) { ItemStack oldItem = inventory.getItemStack(slot); @@ -172,7 +160,7 @@ private void onPreClickEvent(InventoryPreClickEvent event) { } } - private void onPostClickEvent(@NonNull InventoryClickEvent event) { + public void onPostClickEvent(@NonNull InventoryClickEvent event) { if (event.getInventory() != inventory || closed) return; if (cachedLayout == null) return; @@ -241,14 +229,6 @@ private void flushPendingSlotChanges() { } } - private void onCloseEvent(InventoryCloseEvent event) { - if (event.getInventory() != inventory || suppressCloseEvent) { - suppressCloseEvent = false; - return; - } - close(CloseReason.PLAYER_EXITED); - } - public void refresh() { layoutDirty = true; render(); @@ -395,7 +375,7 @@ public void updateQuiet(UnaryOperator updater) { } @SuppressWarnings("unchecked") - public void updateUnchecked(java.util.function.Function updater) { + public void updateUnchecked(Function updater) { setState((S) updater.apply((T) state)); } @@ -423,7 +403,6 @@ public void close(CloseReason reason) { autoUpdateTasks.values().forEach(Task::cancel); autoUpdateTasks.clear(); - MinecraftServer.getGlobalEventHandler().removeChild(eventNode); if (sharedContext != null) { sharedContext.unregisterSession(this); } diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryClose.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryClose.java new file mode 100644 index 000000000..aa1a08285 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryClose.java @@ -0,0 +1,26 @@ +package net.swofty.type.generic.gui.v2.event; + +import net.minestom.server.event.inventory.InventoryCloseEvent; +import net.swofty.type.generic.event.EventNodes; +import net.swofty.type.generic.event.HypixelEvent; +import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.gui.v2.ViewNavigator; +import net.swofty.type.generic.gui.v2.ViewSession; +import net.swofty.type.generic.user.HypixelPlayer; + +public class ActionInventoryClose implements HypixelEventClass { + + @HypixelEvent(node = EventNodes.INVENTORY, requireDataLoaded = false) + public void onPlayerInventoryClose(InventoryCloseEvent event) { + HypixelPlayer player = (HypixelPlayer) event.getPlayer(); + ViewNavigator.find(player).ifPresent(navigator -> { + ViewSession session = navigator.getCurrentSession(); + if (event.getInventory() != session.inventory() || session.isSuppressCloseEvent()) { + session.setSuppressCloseEvent(false); + return; + } + session.close(ViewSession.CloseReason.PLAYER_EXITED); + }); + } + +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryOpen.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryOpen.java new file mode 100644 index 000000000..dccc78d1d --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryOpen.java @@ -0,0 +1,18 @@ +package net.swofty.type.generic.gui.v2.event; + +import net.minestom.server.event.inventory.InventoryOpenEvent; +import net.swofty.type.generic.event.EventNodes; +import net.swofty.type.generic.event.HypixelEvent; +import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.gui.v2.ViewNavigator; +import net.swofty.type.generic.user.HypixelPlayer; + +public class ActionInventoryOpen implements HypixelEventClass { + + @HypixelEvent(node = EventNodes.INVENTORY, requireDataLoaded = false) + public void onPlayerInventoryOpen(InventoryOpenEvent event) { + HypixelPlayer player = (HypixelPlayer) event.getPlayer(); + ViewNavigator.find(player).ifPresent(navigator -> navigator.getCurrentSession().onOpenEvent(event)); + } + +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPostClick.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPostClick.java new file mode 100644 index 000000000..40e0029cd --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPostClick.java @@ -0,0 +1,18 @@ +package net.swofty.type.generic.gui.v2.event; + +import net.minestom.server.event.inventory.InventoryClickEvent; +import net.swofty.type.generic.event.EventNodes; +import net.swofty.type.generic.event.HypixelEvent; +import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.gui.v2.ViewNavigator; +import net.swofty.type.generic.user.HypixelPlayer; + +public class ActionInventoryPostClick implements HypixelEventClass { + + @HypixelEvent(node = EventNodes.INVENTORY, requireDataLoaded = false) + public void onInventoryPostClick(InventoryClickEvent event) { + HypixelPlayer player = (HypixelPlayer) event.getPlayer(); + ViewNavigator.find(player).ifPresent(navigator -> navigator.getCurrentSession().onPostClickEvent(event)); + } + +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPreClick.java b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPreClick.java new file mode 100644 index 000000000..81343f72b --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/v2/event/ActionInventoryPreClick.java @@ -0,0 +1,20 @@ +package net.swofty.type.generic.gui.v2.event; + +import net.minestom.server.event.inventory.InventoryPreClickEvent; +import net.swofty.type.generic.event.EventNodes; +import net.swofty.type.generic.event.HypixelEvent; +import net.swofty.type.generic.event.HypixelEventClass; +import net.swofty.type.generic.gui.v2.ViewNavigator; +import net.swofty.type.generic.user.HypixelPlayer; + +public class ActionInventoryPreClick implements HypixelEventClass { + + @HypixelEvent(node = EventNodes.INVENTORY, requireDataLoaded = false) + public void onActionPlayerInventoryPreClick(InventoryPreClickEvent event) { + HypixelPlayer player = (HypixelPlayer) event.getPlayer(); + ViewNavigator.find(player).ifPresent(navigator -> { + navigator.getCurrentSession().onPreClickEvent(event); + }); + } + +} From 0cb127176bdfb4a7d153f7720ded1be060edcbb8 Mon Sep 17 00:00:00 2001 From: ArikSquad <75741608+ArikSquad@users.noreply.github.com> Date: Sat, 17 Jan 2026 13:18:41 +0200 Subject: [PATCH 35/35] feat: HypixelInventoryGUI as deprecated --- .../swofty/type/generic/gui/inventory/HypixelInventoryGUI.java | 1 + .../swofty/type/generic/gui/inventory/HypixelPaginatedGUI.java | 1 + .../net/swofty/type/generic/gui/inventory/RefreshingGUI.java | 1 + .../net/swofty/type/generic/gui/inventory/SharedInventory.java | 1 + 4 files changed, 4 insertions(+) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/HypixelInventoryGUI.java b/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/HypixelInventoryGUI.java index eb890bf67..164ada17e 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/HypixelInventoryGUI.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/HypixelInventoryGUI.java @@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentHashMap; @Getter +@Deprecated public abstract class HypixelInventoryGUI { public static final Map GUI_MAP = new ConcurrentHashMap<>(); public static final ItemStack.Builder FILLER_ITEM = ItemStack.builder(Material.BLACK_STAINED_GLASS_PANE) diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/HypixelPaginatedGUI.java b/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/HypixelPaginatedGUI.java index 0c2802184..1d949f624 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/HypixelPaginatedGUI.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/HypixelPaginatedGUI.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Objects; +@Deprecated public abstract class HypixelPaginatedGUI extends HypixelInventoryGUI { protected PaginationList latestPaged; diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/RefreshingGUI.java b/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/RefreshingGUI.java index 90e8563fc..ea2e41ce4 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/RefreshingGUI.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/RefreshingGUI.java @@ -2,6 +2,7 @@ import net.swofty.type.generic.user.HypixelPlayer; +@Deprecated public interface RefreshingGUI { /** * If the GUI implements this method, this is the method that should be using in setting all the items diff --git a/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/SharedInventory.java b/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/SharedInventory.java index 434b967b7..83bd4d32a 100644 --- a/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/SharedInventory.java +++ b/type.generic/src/main/java/net/swofty/type/generic/gui/inventory/SharedInventory.java @@ -11,6 +11,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.function.Consumer; +@Deprecated public abstract class SharedInventory extends HypixelInventoryGUI { private static final Map SHARED_CONTEXTS = new ConcurrentHashMap<>();