Compare commits
3 Commits
Lobby/refa
...
sw-ui
| Author | SHA1 | Date | |
|---|---|---|---|
| ea0bb44416 | |||
| 4cb0ff292e | |||
| ee9eb995f5 |
@@ -24,6 +24,7 @@ import de.steamwar.Reflection;
|
|||||||
import de.steamwar.command.*;
|
import de.steamwar.command.*;
|
||||||
import de.steamwar.core.authlib.AuthlibInjector;
|
import de.steamwar.core.authlib.AuthlibInjector;
|
||||||
import de.steamwar.core.events.*;
|
import de.steamwar.core.events.*;
|
||||||
|
import de.steamwar.inventory.ui.test.TestInvCommand;
|
||||||
import de.steamwar.message.Message;
|
import de.steamwar.message.Message;
|
||||||
import de.steamwar.network.NetworkReceiver;
|
import de.steamwar.network.NetworkReceiver;
|
||||||
import de.steamwar.network.handlers.ServerDataHandler;
|
import de.steamwar.network.handlers.ServerDataHandler;
|
||||||
@@ -67,6 +68,7 @@ public class Core extends JavaPlugin{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
new TestInvCommand();
|
||||||
errorHandler = new ErrorHandler();
|
errorHandler = new ErrorHandler();
|
||||||
crashDetector = new CrashDetector();
|
crashDetector = new CrashDetector();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.util.UpdateStream;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public abstract class StatefulUIInventory<T> extends UIInventory implements UpdateStream.Subscriber<T> {
|
||||||
|
|
||||||
|
private T state;
|
||||||
|
private final UpdateStream<T> stream;
|
||||||
|
private UpdateStream.Unsubscriber unsubscriber;
|
||||||
|
|
||||||
|
protected abstract UIComponent render(T state);
|
||||||
|
protected abstract void update(T state);
|
||||||
|
|
||||||
|
public StatefulUIInventory(UpdateStream<T> stateObservable, int playerSlots) {
|
||||||
|
super(playerSlots);
|
||||||
|
this.stream = stateObservable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatefulUIInventory(UpdateStream<T> stateObservable) {
|
||||||
|
super();
|
||||||
|
this.stream = stateObservable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
unsubscriber.unsubscribe();
|
||||||
|
this.unsubscriber = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UIComponent render() {
|
||||||
|
return render(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdate(T current) {
|
||||||
|
state = current;
|
||||||
|
update(current);
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void onClose() {
|
||||||
|
if (viewers.isEmpty()) {
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addViewer(Player... players) {
|
||||||
|
if (viewers.isEmpty()) {
|
||||||
|
unsubscriber = stream.subscribe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.addViewer(players);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.item.Enchanted;
|
||||||
|
import de.steamwar.inventory.ui.item.OnClick;
|
||||||
|
import de.steamwar.inventory.ui.layout.FixedSizeContainer;
|
||||||
|
import de.steamwar.inventory.ui.util.*;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public interface UIComponent {
|
||||||
|
ComponentRender render(RenderContext context);
|
||||||
|
|
||||||
|
default UIComponent onClick(Consumer<InventoryClickEvent> event) {
|
||||||
|
return onClick(false, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent onClick(boolean allowDoubleClick, Consumer<InventoryClickEvent> event) {
|
||||||
|
return new OnClick(this, allowDoubleClick, inventoryClickEvent -> {
|
||||||
|
event.accept(inventoryClickEvent);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent onClickWithUpdate(Function<InventoryClickEvent, Boolean> event) {
|
||||||
|
return onClickWithUpdate(false, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent onClickWithUpdate(boolean allowDoubleClick, Function<InventoryClickEvent, Boolean> event) {
|
||||||
|
return new OnClick(this, allowDoubleClick, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent onClickNoUpdate(Consumer<InventoryClickEvent> event) {
|
||||||
|
return onClickNoUpdate(false, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent onClickNoUpdate(boolean allowDoubleClick, Consumer<InventoryClickEvent> event) {
|
||||||
|
return new OnClick(this, allowDoubleClick, inventoryClickEvent -> {
|
||||||
|
event.accept(inventoryClickEvent);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent cancelOnClick() {
|
||||||
|
return new OnClick(this, true, inventoryClickEvent -> false);
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent enchanted() {
|
||||||
|
return new Enchanted(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent enchanted(boolean enchanted) {
|
||||||
|
if (enchanted)
|
||||||
|
return enchanted();
|
||||||
|
else
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
default UIComponent size(Size size) {
|
||||||
|
return new FixedSizeContainer(size, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
|
||||||
|
public abstract class UIFragment implements UIComponent {
|
||||||
|
|
||||||
|
abstract public UIComponent build(RenderContext context);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
return build(context).render(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui;
|
||||||
|
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderItem;
|
||||||
|
import de.steamwar.inventory.ui.util.Size;
|
||||||
|
import de.steamwar.message.Message;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public abstract class UIInventory {
|
||||||
|
protected final List<Player> viewers = new ArrayList<>();
|
||||||
|
private final Map<Player, OpenPlayerInventory> callbacks = new HashMap<>();
|
||||||
|
private final Map<Player, ItemStack[]> originalItems = new HashMap<>();
|
||||||
|
|
||||||
|
private UIInventory parent;
|
||||||
|
private Player currentRender;
|
||||||
|
private final int playerSlots;
|
||||||
|
|
||||||
|
private List<MemoHookMeta<?>> memoHooks = new ArrayList<>();
|
||||||
|
private int buildHookCount = 0;
|
||||||
|
|
||||||
|
protected UIInventory() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected UIInventory(int playerSlots) {
|
||||||
|
this.playerSlots = playerSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract UIComponent render();
|
||||||
|
public abstract Inventory createInventory(Player player);
|
||||||
|
public abstract Message getMessages();
|
||||||
|
|
||||||
|
void onClose() { }
|
||||||
|
|
||||||
|
public <T> T useMemo(Supplier<T> supplier, List<Object> dependencies) {
|
||||||
|
int currentHook = buildHookCount++;
|
||||||
|
|
||||||
|
if (currentHook >= memoHooks.size()) {
|
||||||
|
T value = supplier.get();
|
||||||
|
memoHooks.add(new MemoHookMeta<>(dependencies, value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoHookMeta<T> hook = (MemoHookMeta<T>) memoHooks.get(currentHook);
|
||||||
|
|
||||||
|
if (!hook.getDependencies().equals(dependencies)) {
|
||||||
|
hook.setDependencies(dependencies);
|
||||||
|
T value = supplier.get();
|
||||||
|
hook.setValue(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T useMemo(Supplier<T> supplier) {
|
||||||
|
return useMemo(supplier, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addViewer(Player... players) {
|
||||||
|
viewers.addAll(Arrays.asList(players));
|
||||||
|
|
||||||
|
for (Player player : players) {
|
||||||
|
openInventory(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openInventory(Player player) {
|
||||||
|
if (playerSlots > 0) {
|
||||||
|
originalItems.put(player, player.getInventory().getContents());
|
||||||
|
}
|
||||||
|
Inventory inventory = createInventory(player);
|
||||||
|
renderPlayer(player, inventory);
|
||||||
|
InventoryView view = player.openInventory(inventory);
|
||||||
|
Core.getInstance().getLogger().info("[UIINV] Opened " + view.getTitle() + " for " + player.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderPlayer(Player player, Inventory inventory) {
|
||||||
|
int width = Math.min(inventory.getSize(), 9);
|
||||||
|
if (width < 9 && playerSlots > 0) {
|
||||||
|
throw new IllegalArgumentException("Player Inventory is only supported in Chests");
|
||||||
|
}
|
||||||
|
|
||||||
|
int inventoryHeight = Math.max(inventory.getSize() / 9, 1);
|
||||||
|
int height = inventoryHeight + playerSlots;
|
||||||
|
int invSize = inventoryHeight * width;
|
||||||
|
|
||||||
|
currentRender = player;
|
||||||
|
buildHookCount = 0;
|
||||||
|
ComponentRender render = render().render(new RenderContext(new Size(width, height), new Size(width, height), this));
|
||||||
|
buildHookCount = -1;
|
||||||
|
currentRender = null;
|
||||||
|
|
||||||
|
if (render.getSize().getWidth() > width || render.getSize().getHeight() > height) {
|
||||||
|
throw new IllegalArgumentException("The UIComponent does not fit in the inventory");
|
||||||
|
}
|
||||||
|
|
||||||
|
Message message = getMessages();
|
||||||
|
|
||||||
|
ItemStack[] itemStacks = new ItemStack[inventory.getSize()];
|
||||||
|
ItemStack[] playerStacks = new ItemStack[playerSlots > 0 ? 4 * 9 : 0];
|
||||||
|
|
||||||
|
for (RenderItem item : render.getItems()) {
|
||||||
|
int slot = item.getX() + item.getY() * 9;
|
||||||
|
if (slot < invSize) {
|
||||||
|
itemStacks[item.getX() + item.getY() * 9] = item.getItemStack().message(message).build(player);
|
||||||
|
} else {
|
||||||
|
playerStacks[(item.getX() + item.getY() * 9) - invSize] = item.getItemStack().message(message).build(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.setContents(itemStacks);
|
||||||
|
if (playerSlots > 0) {
|
||||||
|
ItemStack[] lastRow = new ItemStack[9];
|
||||||
|
System.arraycopy(playerStacks, playerStacks.length - 9, lastRow, 0, 9);
|
||||||
|
System.arraycopy(playerStacks, 0, playerStacks, 9, playerStacks.length - 9);
|
||||||
|
System.arraycopy(lastRow, 0, playerStacks, 0, 9);
|
||||||
|
|
||||||
|
// TODO: Update to Client-Side Only Update
|
||||||
|
player.getInventory().setContents(playerStacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, Function<InventoryClickEvent, Boolean>> clickEventMap = render.getItems().stream()
|
||||||
|
.filter(item -> item.getClickEvent() != null)
|
||||||
|
.collect(Collectors.toMap(renderItem -> renderItem.getX() + renderItem.getY() * 9, RenderItem::getClickEvent));
|
||||||
|
|
||||||
|
callbacks.computeIfAbsent(player, p -> new OpenPlayerInventory(p, clickEventMap).register()).setCallbacks(clickEventMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateTitle(String title, Object... params) {
|
||||||
|
if (currentRender != null) {
|
||||||
|
currentRender.getOpenInventory().setTitle(getMessages().parse(title, currentRender, params));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateUI() {
|
||||||
|
viewers.forEach(player -> renderPlayer(player, player.getOpenInventory().getTopInventory()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void push(Player player, UIInventory inventory) {
|
||||||
|
inventory.parent = this;
|
||||||
|
inventory.addViewer(player);
|
||||||
|
viewers.remove(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void pop(Player player) {
|
||||||
|
if(parent == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
parent.addViewer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Setter
|
||||||
|
private class OpenPlayerInventory implements Listener {
|
||||||
|
private final Player player;
|
||||||
|
private Map<Integer, Function<InventoryClickEvent, Boolean>> callbacks;
|
||||||
|
|
||||||
|
OpenPlayerInventory register() {
|
||||||
|
Core.getInstance().getServer().getPluginManager().registerEvents(this, Core.getInstance());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInventoryClick(InventoryClickEvent e) {
|
||||||
|
if (!player.equals(e.getWhoClicked()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (callbacks.containsKey(e.getRawSlot()) && callbacks.get(e.getRawSlot()) != null) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
Core.getInstance().getLogger().info("[UIINV] " + e.getWhoClicked().getName() + " " + e.getClick().name() + " clicked " + e.getRawSlot() + " on " + (e.getCurrentItem() != null ? e.getCurrentItem().getItemMeta().getDisplayName() : "[EMPTY]") + " in " + e.getView().getTitle());
|
||||||
|
if (callbacks.get(e.getRawSlot()).apply(e)) {
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInventoryClose(InventoryCloseEvent e){
|
||||||
|
if(!player.equals(e.getPlayer()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
InventoryClickEvent.getHandlerList().unregister(this);
|
||||||
|
InventoryCloseEvent.getHandlerList().unregister(this);
|
||||||
|
Core.getInstance().getLogger().info("[UIINV] " + player.getName() + " closed " + e.getView().getTitle());
|
||||||
|
if(callbacks.containsKey(-1))
|
||||||
|
callbacks.get(-1).apply(null);
|
||||||
|
|
||||||
|
viewers.remove(player);
|
||||||
|
UIInventory.this.callbacks.remove(player);
|
||||||
|
if (playerSlots > 0) {
|
||||||
|
player.getInventory().setContents(originalItems.remove(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
private class MemoHookMeta<T> {
|
||||||
|
private List<Object> dependencies;
|
||||||
|
private T value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.fragments;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.UIFragment;
|
||||||
|
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||||
|
import de.steamwar.inventory.ui.item.UIItem;
|
||||||
|
import de.steamwar.inventory.ui.layout.Row;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import de.steamwar.inventory.ui.util.Size;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ActionBar extends UIFragment {
|
||||||
|
private static final UIComponent DEFAULT_FILLER = new UIItem(ItemBuilder.of(Material.GRAY_STAINED_GLASS_PANE).displayName("§e")).cancelOnClick();
|
||||||
|
|
||||||
|
private final Map<Integer, UIComponent> actionBar;
|
||||||
|
private UIComponent filler = DEFAULT_FILLER;
|
||||||
|
|
||||||
|
public ActionBar(Map<Integer, UIComponent> actionBar) {
|
||||||
|
this.actionBar = actionBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionBar filler(UIComponent filler) {
|
||||||
|
this.filler = filler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UIComponent build(RenderContext context) {
|
||||||
|
UIComponent[] components = context.useMemo(() -> {
|
||||||
|
UIComponent[] cmp = new UIComponent[context.getContainerSize().getWidth()];
|
||||||
|
for (int i = 0; i < cmp.length; i++) {
|
||||||
|
cmp[i] = actionBar.getOrDefault(i, filler);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmp;
|
||||||
|
}, Arrays.asList(actionBar));
|
||||||
|
|
||||||
|
return new Row(Arrays.asList(components)).size(new Size(context.getContainerSize().getWidth(), 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.fragments;
|
||||||
|
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.UIFragment;
|
||||||
|
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||||
|
import de.steamwar.inventory.ui.item.UIItem;
|
||||||
|
import de.steamwar.inventory.ui.layout.Column;
|
||||||
|
import de.steamwar.inventory.ui.layout.FixedSizeContainer;
|
||||||
|
import de.steamwar.inventory.ui.layout.Row;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.bukkit.DyeColor;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
public class HorizontalScrollLayout extends UIFragment {
|
||||||
|
private List<UIComponent> data;
|
||||||
|
private int scroll = 0;
|
||||||
|
private final Map<Integer, UIComponent> actionBar = new HashMap<>();
|
||||||
|
|
||||||
|
public HorizontalScrollLayout(List<UIComponent> data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int maxScroll() {
|
||||||
|
return Math.max(0, Math.min(scroll, data.size() - 9 + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public HorizontalScrollLayout actionBar(Map<Integer, UIComponent> actionBar) {
|
||||||
|
this.actionBar.clear();
|
||||||
|
this.actionBar.putAll(actionBar);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HorizontalScrollLayout data(List<UIComponent> data) {
|
||||||
|
this.data = data;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UIComponent build(RenderContext context) {
|
||||||
|
scroll = maxScroll();
|
||||||
|
boolean hasPrev = scroll > 0;
|
||||||
|
boolean hasNext = data.size() - scroll > 9;
|
||||||
|
|
||||||
|
Map<Integer, UIComponent> actionBar = context.useMemo(() -> {
|
||||||
|
Map<Integer, UIComponent> content = new HashMap<>(this.actionBar);
|
||||||
|
|
||||||
|
content.put(0, new UIItem(ItemBuilder.color(hasPrev ? DyeColor.LIME : DyeColor.GRAY).message(Core.MESSAGE).translateName(hasPrev ? "SWLISINV_PREVIOUS_PAGE_ACTIVE" : "SWLISINV_PREVIOUS_PAGE_INACTIVE")).onClickWithUpdate(inventoryClickEvent -> {
|
||||||
|
if (scroll > 0) {
|
||||||
|
scroll = Math.max(0, scroll - 9);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
content.put(8, new UIItem(ItemBuilder.color(hasNext ? DyeColor.LIME : DyeColor.GRAY).message(Core.MESSAGE).translateName(hasNext ? "SWLISINV_NEXT_PAGE_ACTIVE" : "SWLISINV_NEXT_PAGE_INACTIVE")).onClickWithUpdate(inventoryClickEvent -> {
|
||||||
|
if (hasNext) {
|
||||||
|
scroll = Math.min(scroll + 9, data.size() - 9);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}, Arrays.asList(hasPrev, hasNext));
|
||||||
|
|
||||||
|
return new Column(
|
||||||
|
new FixedSizeContainer(context.getContainerSize().shrink(0, 1),
|
||||||
|
new Row(data.subList(scroll, Math.min(data.size(), scroll + 9)))
|
||||||
|
),
|
||||||
|
new ActionBar(actionBar)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.fragments;
|
||||||
|
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.UIFragment;
|
||||||
|
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||||
|
import de.steamwar.inventory.ui.item.UIItem;
|
||||||
|
import de.steamwar.inventory.ui.layout.Column;
|
||||||
|
import de.steamwar.inventory.ui.layout.FixedSizeContainer;
|
||||||
|
import de.steamwar.inventory.ui.layout.Grid;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.bukkit.DyeColor;
|
||||||
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class PageLayout<T> extends UIFragment {
|
||||||
|
|
||||||
|
private final List<UIListEntry<T>> items;
|
||||||
|
private final UIListCallback<T> callback;
|
||||||
|
private int page = 0;
|
||||||
|
private Consumer<Integer> onPageChange = null;
|
||||||
|
private Map<Integer, UIItem> itemsOnBar = Collections.emptyMap();
|
||||||
|
|
||||||
|
public PageLayout(List<UIListEntry<T>> items, UIListCallback<T> callback) {
|
||||||
|
System.out.println(items.size());
|
||||||
|
this.items = items;
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UIComponent build(RenderContext context) {
|
||||||
|
|
||||||
|
int itemsOnPage = context.getContainerSize().getWidth() * (context.getContainerSize().getHeight() - 1);
|
||||||
|
|
||||||
|
List<UIComponent> uiItems = context.useMemo(() -> {
|
||||||
|
int i = page * itemsOnPage;
|
||||||
|
|
||||||
|
int ipageLimit = items.size() - page * itemsOnPage;
|
||||||
|
if (ipageLimit > itemsOnPage) {
|
||||||
|
ipageLimit = itemsOnPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<UIComponent> pageItems = new ArrayList<>();
|
||||||
|
for (int ipage = 0; ipage < ipageLimit; ipage++) {
|
||||||
|
UIListEntry<T> e = items.get(i);
|
||||||
|
|
||||||
|
pageItems.add(new UIItem(e.item).onClickNoUpdate(inventoryClickEvent -> callback.clicked(inventoryClickEvent.getClick(), e.object)));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pageItems;
|
||||||
|
}, Arrays.asList(page, items.size(), itemsOnPage));
|
||||||
|
|
||||||
|
Map<Integer, UIComponent> uiBar = context.useMemo(() -> {
|
||||||
|
Map<Integer, UIComponent> content = new HashMap<>(itemsOnBar);
|
||||||
|
|
||||||
|
if (page != 0) {
|
||||||
|
content.put(0, new UIItem(ItemBuilder.color(DyeColor.LIME).message(Core.MESSAGE).translateName("SWLISINV_PREVIOUS_PAGE_ACTIVE")).onClick(inventoryClickEvent -> page--));
|
||||||
|
} else {
|
||||||
|
content.put(0, new UIItem(ItemBuilder.color(DyeColor.GRAY).message(Core.MESSAGE).translateName("SWLISINV_PREVIOUS_PAGE_INACTIVE")).cancelOnClick());
|
||||||
|
}
|
||||||
|
if (page < items.size() / itemsOnPage - (items.size() % itemsOnPage == 0 ? 1 : 0)) {
|
||||||
|
content.put(8, new UIItem(ItemBuilder.color(DyeColor.LIME).message(Core.MESSAGE).translateName("SWLISINV_NEXT_PAGE_ACTIVE")).onClick(inventoryClickEvent -> page++));
|
||||||
|
} else {
|
||||||
|
content.put(8, new UIItem(ItemBuilder.color(DyeColor.GRAY).message(Core.MESSAGE).translateName("SWLISINV_NEXT_PAGE_INACTIVE")).cancelOnClick());
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}, Arrays.asList(page, items.size(), itemsOnPage));
|
||||||
|
|
||||||
|
return new Column(
|
||||||
|
new FixedSizeContainer(context.getContainerSize().shrink(0, 1),
|
||||||
|
new Grid(uiItems)),
|
||||||
|
new ActionBar(uiBar)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface UIListCallback<T>{
|
||||||
|
void clicked(ClickType click, T element);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class UIListEntry<T>{
|
||||||
|
final ItemBuilder item;
|
||||||
|
final T object;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.item;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderItem;
|
||||||
|
|
||||||
|
public class Enchanted implements UIComponent {
|
||||||
|
private final UIComponent children;
|
||||||
|
|
||||||
|
public Enchanted(UIComponent children) {
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
ComponentRender render = children.render(context);
|
||||||
|
|
||||||
|
for (RenderItem item : render.getItems()) {
|
||||||
|
item.getItemStack().enchanted();
|
||||||
|
}
|
||||||
|
|
||||||
|
return render;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.item;
|
||||||
|
|
||||||
|
import de.steamwar.core.FlatteningWrapper;
|
||||||
|
import de.steamwar.core.TrickyTrialsWrapper;
|
||||||
|
import de.steamwar.inventory.SWItem;
|
||||||
|
import de.steamwar.message.Message;
|
||||||
|
import de.steamwar.message.SubMessage;
|
||||||
|
import org.bukkit.DyeColor;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemFlag;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ItemBuilder {
|
||||||
|
private static final Map<DyeColor, Integer> DYE_COLOR_INTEGER_MAP = new EnumMap<>(DyeColor.class);
|
||||||
|
|
||||||
|
static {
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.BLACK, 16);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.RED, 1);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.GREEN, 2);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.BROWN, 3);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.BLUE, 4);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.PURPLE, 5);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.CYAN, 6);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.LIGHT_GRAY, 7);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.GRAY, 8);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.PINK, 9);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.LIME, 10);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.YELLOW, 11);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.LIGHT_BLUE, 12);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.MAGENTA, 13);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.ORANGE, 14);
|
||||||
|
DYE_COLOR_INTEGER_MAP.put(DyeColor.WHITE, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ItemStack itemStack;
|
||||||
|
private final ItemMeta itemMeta;
|
||||||
|
private Message message = null;
|
||||||
|
private SubMessage translateName = null;
|
||||||
|
private List<SubMessage> translateLore = null;
|
||||||
|
|
||||||
|
private ItemBuilder(Material material) {
|
||||||
|
this(new ItemStack(material));
|
||||||
|
}
|
||||||
|
private ItemBuilder(ItemStack item) {
|
||||||
|
this.itemStack = item;
|
||||||
|
this.itemMeta = itemStack.getItemMeta();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemBuilder of(Material material) {
|
||||||
|
return new ItemBuilder(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemBuilder of(ItemStack itemStack) {
|
||||||
|
return new ItemBuilder(itemStack.getType()).amount(itemStack.getAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ItemBuilder of(Material material, Byte meta) {
|
||||||
|
ItemStack itemStack;
|
||||||
|
try {
|
||||||
|
itemStack = new ItemStack(material, 1, (short)0, meta);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
itemStack = new ItemStack(material, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ItemBuilder(itemStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemBuilder color(DyeColor color) {
|
||||||
|
return ItemBuilder.of(SWItem.getDye(DYE_COLOR_INTEGER_MAP.get(color)), DYE_COLOR_INTEGER_MAP.get(color).byteValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemBuilder skull(OfflinePlayer player) {
|
||||||
|
return skull(player.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemBuilder skull(String name) {
|
||||||
|
return ItemBuilder.of(FlatteningWrapper.impl.setSkullOwner(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder message(Message message) {
|
||||||
|
if (this.message == null) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack build(Player player) {
|
||||||
|
if (message != null) {
|
||||||
|
if (translateName != null) {
|
||||||
|
itemMeta.setDisplayName(message.parse(translateName.getMessage(), player, translateName.getParams()));
|
||||||
|
}
|
||||||
|
if (translateLore != null) {
|
||||||
|
itemMeta.setLore(translateLore.stream().map(subMessage -> message.parse(subMessage.getMessage(), player, subMessage.getParams())).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemStack.setItemMeta(itemMeta);
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder amount(int amount) {
|
||||||
|
itemStack.setAmount(amount);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder displayName(String name) {
|
||||||
|
itemMeta.setDisplayName(name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder lore(String... lore) {
|
||||||
|
if (itemMeta.hasLore()) {
|
||||||
|
List<String> loreList = itemMeta.getLore();
|
||||||
|
loreList.addAll(Arrays.asList(lore));
|
||||||
|
itemMeta.setLore(loreList);
|
||||||
|
} else {
|
||||||
|
itemMeta.setLore(Arrays.asList(lore));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder translateName(String name, Object... params) {
|
||||||
|
this.translateName = new SubMessage(name, params);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder addTranslateLore(SubMessage... lore) {
|
||||||
|
if (this.translateLore == null) {
|
||||||
|
this.translateLore = Arrays.asList(lore);
|
||||||
|
} else {
|
||||||
|
this.translateLore.addAll(Arrays.asList(lore));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder enchanted() {
|
||||||
|
itemMeta.addEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment(), 10, true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder enchanted(boolean enchanted) {
|
||||||
|
if(enchanted) {
|
||||||
|
return enchanted();
|
||||||
|
} else {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder hideFlags() {
|
||||||
|
for (ItemFlag flag : EnumSet.allOf(ItemFlag.class)) {
|
||||||
|
itemMeta.addItemFlags(flag);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemBuilder customModel(int modelData) {
|
||||||
|
itemMeta.setCustomModelData(modelData);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
ItemBuilder that = (ItemBuilder) o;
|
||||||
|
return Objects.equals(itemStack, that.itemStack) && Objects.equals(itemMeta, that.itemMeta) && Objects.equals(message, that.message) && Objects.equals(translateName, that.translateName) && Objects.equals(translateLore, that.translateLore);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ItemBuilder{" +
|
||||||
|
"itemStack=" + itemStack +
|
||||||
|
", itemMeta=" + itemMeta +
|
||||||
|
", message=" + message +
|
||||||
|
", translateName=" + translateName +
|
||||||
|
", translateLore=" + translateLore +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.item;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderItem;
|
||||||
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class OnClick implements UIComponent {
|
||||||
|
private final UIComponent children;
|
||||||
|
private final boolean allowDoubleClick;
|
||||||
|
private final Function<InventoryClickEvent, Boolean> event;
|
||||||
|
|
||||||
|
public OnClick(UIComponent children, boolean allowDoubleClick, Function<InventoryClickEvent, Boolean> event) {
|
||||||
|
this.children = children;
|
||||||
|
this.allowDoubleClick = allowDoubleClick;
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
ComponentRender render = children.render(context);
|
||||||
|
|
||||||
|
for (RenderItem item : render.getItems()) {
|
||||||
|
item.setClickEvent(ev -> {
|
||||||
|
if (ev.getClick() != ClickType.DOUBLE_CLICK || allowDoubleClick) {
|
||||||
|
return event.apply(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return render;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "OnClick{" +
|
||||||
|
"children=" + children +
|
||||||
|
", allowDoubleClick=" + allowDoubleClick +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
OnClick onClick = (OnClick) o;
|
||||||
|
return allowDoubleClick == onClick.allowDoubleClick && children.equals(onClick.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.item;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import de.steamwar.inventory.ui.util.Size;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Space implements UIComponent {
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
return new ComponentRender(
|
||||||
|
new ArrayList<>(),
|
||||||
|
new Size(1, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj instanceof Space;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.item;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.util.*;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class UIItem implements UIComponent {
|
||||||
|
|
||||||
|
private final ItemBuilder itemStack;
|
||||||
|
|
||||||
|
public UIItem(ItemStack itemStack) {
|
||||||
|
this(ItemBuilder.of(itemStack));
|
||||||
|
}
|
||||||
|
|
||||||
|
public UIItem(ItemBuilder itemStack) {
|
||||||
|
this.itemStack = itemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
return new ComponentRender(
|
||||||
|
Arrays.asList(new RenderItem(0, 0, itemStack, null)),
|
||||||
|
new Size(1, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "UIItem{" +
|
||||||
|
"itemStack=" + itemStack +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
UIItem uiItem = (UIItem) o;
|
||||||
|
return Objects.equals(itemStack, uiItem.itemStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.layout;
|
||||||
|
|
||||||
|
public enum Alignment {
|
||||||
|
START,
|
||||||
|
CENTER,
|
||||||
|
END,
|
||||||
|
BETWEEN
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.layout;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.util.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Column implements UIComponent {
|
||||||
|
|
||||||
|
private final List<UIComponent> components;
|
||||||
|
|
||||||
|
private Alignment alignment;
|
||||||
|
private boolean shrinkWrap = false;
|
||||||
|
|
||||||
|
public Column(UIComponent... components) {
|
||||||
|
this(Arrays.asList(components));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Column(List<UIComponent> components) {
|
||||||
|
this.components = components;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Column centered() {
|
||||||
|
this.alignment = Alignment.CENTER;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Column setShrinkWrap(boolean shrinkWrap) {
|
||||||
|
this.shrinkWrap = shrinkWrap;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
List<RenderItem> renderItems = new ArrayList<>();
|
||||||
|
|
||||||
|
int height = 0;
|
||||||
|
int maxWidth = 0;
|
||||||
|
|
||||||
|
for (UIComponent component : components) {
|
||||||
|
ComponentRender render = component.render(context.withContainerSize(context.getContainerSize().withHeight(context.getContainerSize().getHeight() - height)));
|
||||||
|
for(RenderItem item : render.getItems()){
|
||||||
|
renderItems.add(item.shift(0, height));
|
||||||
|
}
|
||||||
|
maxWidth = Math.max(maxWidth, render.getSize().getWidth());
|
||||||
|
height += render.getSize().getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignment == Alignment.CENTER) {
|
||||||
|
int shiftAmount = (context.getContainerSize().getHeight() - height) / 2;
|
||||||
|
for (RenderItem item : renderItems) {
|
||||||
|
item.shift(0, shiftAmount);
|
||||||
|
}
|
||||||
|
} else if (alignment == Alignment.BETWEEN) {
|
||||||
|
int shiftAmount = (context.getContainerSize().getHeight() - height) / (components.size() - 1);
|
||||||
|
for (int i = 0; i < components.size() - 1; i++) {
|
||||||
|
RenderItem item = renderItems.get(i);
|
||||||
|
item.shift(0, shiftAmount * i);
|
||||||
|
}
|
||||||
|
} else if (alignment == Alignment.END) {
|
||||||
|
int shiftAmount = (context.getContainerSize().getHeight() - height);
|
||||||
|
for (RenderItem item : renderItems) {
|
||||||
|
item.shift(0, shiftAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ComponentRender(
|
||||||
|
renderItems,
|
||||||
|
new Size(maxWidth, shrinkWrap ? height : context.getContainerSize().getHeight())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.layout;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import de.steamwar.inventory.ui.util.Size;
|
||||||
|
|
||||||
|
public class FixedSizeContainer implements UIComponent {
|
||||||
|
private final UIComponent children;
|
||||||
|
private final Size size;
|
||||||
|
|
||||||
|
public FixedSizeContainer(Size size, UIComponent children) {
|
||||||
|
this.children = children;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
return children.render(context.withContainerSize(size)).withSize(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.layout;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.util.ComponentRender;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderContext;
|
||||||
|
import de.steamwar.inventory.ui.util.RenderItem;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Grid implements UIComponent {
|
||||||
|
private final List<UIComponent> children;
|
||||||
|
|
||||||
|
public Grid(UIComponent... children) {
|
||||||
|
this(Arrays.asList(children));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Grid(List<UIComponent> children) {
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
List<RenderItem> renderItems = new ArrayList<>();
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int currentRowMaxHeight = 0;
|
||||||
|
|
||||||
|
for (UIComponent child : children) {
|
||||||
|
ComponentRender render = child.render(context.withContainerSize(
|
||||||
|
context.getContainerSize()
|
||||||
|
.withWidth(context.getContainerSize().getWidth() - x)
|
||||||
|
.withHeight(context.getContainerSize().getHeight() - y)));
|
||||||
|
currentRowMaxHeight = Math.max(currentRowMaxHeight, render.getSize().getHeight());
|
||||||
|
for (RenderItem item : render.getItems()) {
|
||||||
|
renderItems.add(item.shift(x, y));
|
||||||
|
}
|
||||||
|
x += render.getSize().getWidth();
|
||||||
|
if(x >= context.getContainerSize().getWidth()){
|
||||||
|
x = 0;
|
||||||
|
y += currentRowMaxHeight;
|
||||||
|
currentRowMaxHeight = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ComponentRender(renderItems, context.getContainerSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.layout;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.util.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Row implements UIComponent {
|
||||||
|
|
||||||
|
private final List<UIComponent> components;
|
||||||
|
|
||||||
|
private Alignment alignment;
|
||||||
|
private boolean shrinkWrap = false;
|
||||||
|
|
||||||
|
public Row(UIComponent... components) {
|
||||||
|
this(Arrays.asList(components));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Row(List<UIComponent> components) {
|
||||||
|
this.components = components;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Row centered() {
|
||||||
|
this.alignment = Alignment.CENTER;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Row alignment(Alignment alignment) {
|
||||||
|
this.alignment = alignment;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Row setShrinkWrap(boolean shrinkWrap) {
|
||||||
|
this.shrinkWrap = shrinkWrap;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentRender render(RenderContext context) {
|
||||||
|
List<RenderItem> renderItems = new ArrayList<>();
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
int maxHeight = 0;
|
||||||
|
|
||||||
|
for (UIComponent component : components) {
|
||||||
|
ComponentRender render = component.render(context.withContainerSize(context.getContainerSize().withWidth(context.getContainerSize().getWidth() - width)));
|
||||||
|
for(RenderItem item : render.getItems()){
|
||||||
|
renderItems.add(item.shift(width, 0));
|
||||||
|
}
|
||||||
|
maxHeight = Math.max(maxHeight, render.getSize().getHeight());
|
||||||
|
width += render.getSize().getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignment == Alignment.CENTER) {
|
||||||
|
int shiftAmount = (context.getContainerSize().getWidth() - width) / 2;
|
||||||
|
for (RenderItem item : renderItems) {
|
||||||
|
item.shift(shiftAmount, 0);
|
||||||
|
}
|
||||||
|
} else if (alignment == Alignment.BETWEEN) {
|
||||||
|
int shiftAmount = (context.getContainerSize().getWidth() - width) / (components.size() - 1);
|
||||||
|
for (int i = 0; i < components.size() - 1; i++) {
|
||||||
|
RenderItem item = renderItems.get(i);
|
||||||
|
item.shift(shiftAmount * i, 0);
|
||||||
|
}
|
||||||
|
} else if (alignment == Alignment.END) {
|
||||||
|
int shiftAmount = (context.getContainerSize().getWidth() - width);
|
||||||
|
for (RenderItem item : renderItems) {
|
||||||
|
item.shift(shiftAmount, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ComponentRender(
|
||||||
|
renderItems,
|
||||||
|
new Size(shrinkWrap ? width : context.getContainerSize().getWidth(), maxHeight)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.test;
|
||||||
|
|
||||||
|
import de.steamwar.command.SWCommand;
|
||||||
|
import de.steamwar.inventory.ui.util.UpdateStream;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TestInvCommand extends SWCommand {
|
||||||
|
|
||||||
|
public static final UpdateStream<List<Integer>> STREAM = new UpdateStream<>(new ArrayList<>());
|
||||||
|
|
||||||
|
public TestInvCommand() {
|
||||||
|
super("testinv");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void run(Player player) {
|
||||||
|
new TestInventory(STREAM).addViewer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.test;
|
||||||
|
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import de.steamwar.inventory.ui.StatefulUIInventory;
|
||||||
|
import de.steamwar.inventory.ui.UIComponent;
|
||||||
|
import de.steamwar.inventory.ui.fragments.HorizontalScrollLayout;
|
||||||
|
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||||
|
import de.steamwar.inventory.ui.item.UIItem;
|
||||||
|
import de.steamwar.inventory.ui.util.UpdateStream;
|
||||||
|
import de.steamwar.message.Message;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static de.steamwar.inventory.ui.test.TestInvCommand.STREAM;
|
||||||
|
|
||||||
|
public class TestInventory extends StatefulUIInventory<List<Integer>> {
|
||||||
|
|
||||||
|
private HorizontalScrollLayout scrollLayout;
|
||||||
|
private static int counter = 1;
|
||||||
|
|
||||||
|
public TestInventory(UpdateStream<List<Integer>> stateObservable) {
|
||||||
|
super(stateObservable);
|
||||||
|
scrollLayout = new HorizontalScrollLayout(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected UIComponent render(List<Integer> state) {
|
||||||
|
return scrollLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void update(List<Integer> state) {
|
||||||
|
System.out.println("Update");
|
||||||
|
List<UIComponent> items = state.stream().map(integer -> new UIItem(ItemBuilder.of(Material.ACACIA_PLANKS).displayName(String.valueOf(integer))).onClickNoUpdate(inventoryClickEvent -> STREAM.update(current -> {
|
||||||
|
current.remove(integer);
|
||||||
|
return current;
|
||||||
|
}))).collect(Collectors.toList());
|
||||||
|
items.add(new UIItem(ItemBuilder.of(Material.BUCKET).displayName("Add")).onClickNoUpdate(inventoryClickEvent -> STREAM.update(current -> {
|
||||||
|
current.add(counter++);
|
||||||
|
return current;
|
||||||
|
})));
|
||||||
|
scrollLayout = scrollLayout.data(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Inventory createInventory(Player player) {
|
||||||
|
return Bukkit.createInventory(null, 9 * 6, "Test Inventory");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message getMessages() {
|
||||||
|
return Core.MESSAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.util;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.With;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@With
|
||||||
|
public class ComponentRender {
|
||||||
|
private final List<RenderItem> items;
|
||||||
|
private final Size size;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.util;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.UIInventory;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.With;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@With
|
||||||
|
public class RenderContext {
|
||||||
|
private final Size inventorySize;
|
||||||
|
private final Size containerSize;
|
||||||
|
private final UIInventory inventory;
|
||||||
|
|
||||||
|
public <T> T useMemo(Supplier<T> supplier, List<Object> dependencies) {
|
||||||
|
return inventory.useMemo(supplier, dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T useMemo(Supplier<T> supplier) {
|
||||||
|
return inventory.useMemo(supplier);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.util;
|
||||||
|
|
||||||
|
import de.steamwar.inventory.ui.item.ItemBuilder;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.With;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@With
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RenderItem {
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
private ItemBuilder itemStack;
|
||||||
|
private Function<InventoryClickEvent, Boolean> clickEvent;
|
||||||
|
|
||||||
|
public RenderItem shift(int deltaX, int deltaY) {
|
||||||
|
return withX(x + deltaX).withY(y + deltaY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.util;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.With;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@With
|
||||||
|
public class Size {
|
||||||
|
private final int width;
|
||||||
|
private final int height;
|
||||||
|
|
||||||
|
public Size shrink(int width, int height) {
|
||||||
|
return new Size(this.width - width, this.height - height);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.inventory.ui.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UpdateStream<T> {
|
||||||
|
|
||||||
|
private T current;
|
||||||
|
|
||||||
|
private final List<Subscriber<T>> subscribers = new ArrayList<>();
|
||||||
|
|
||||||
|
public UpdateStream(T current) {
|
||||||
|
this.current = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Unsubscriber subscribe(Subscriber<T> subscriber) {
|
||||||
|
subscribers.add(subscriber);
|
||||||
|
subscriber.onUpdate(current);
|
||||||
|
return () -> subscribers.remove(subscriber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void emit(T newCurrent) {
|
||||||
|
current = newCurrent;
|
||||||
|
subscribers.forEach(subscriber -> subscriber.onUpdate(newCurrent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(Updater<T> updater) {
|
||||||
|
current = updater.update(current);
|
||||||
|
subscribers.forEach(subscriber -> subscriber.onUpdate(current));
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Subscriber<T> {
|
||||||
|
void onUpdate(T current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Unsubscriber {
|
||||||
|
void unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Updater<T> {
|
||||||
|
T update(T current);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user