Add memoization support and implement equals/hashCode methods
All checks were successful
SteamWarCI Build successful

This commit is contained in:
2025-04-21 23:20:15 +02:00
parent 4cb0ff292e
commit ea0bb44416
9 changed files with 168 additions and 44 deletions

View File

@@ -26,6 +26,7 @@ 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;
@@ -38,6 +39,7 @@ 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 {
@@ -49,6 +51,9 @@ public abstract class UIInventory {
private Player currentRender;
private final int playerSlots;
private List<MemoHookMeta<?>> memoHooks = new ArrayList<>();
private int buildHookCount = 0;
protected UIInventory() {
this(0);
}
@@ -63,6 +68,31 @@ public abstract class UIInventory {
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));
@@ -92,7 +122,9 @@ public abstract class UIInventory {
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) {
@@ -199,4 +231,12 @@ public abstract class UIInventory {
onClose();
}
}
@Getter
@Setter
@AllArgsConstructor
private class MemoHookMeta<T> {
private List<Object> dependencies;
private T value;
}
}

View File

@@ -52,10 +52,14 @@ public class ActionBar extends UIFragment {
@Override
public UIComponent build(RenderContext context) {
UIComponent[] components = new UIComponent[context.getContainerSize().getWidth()];
for (int i = 0; i < components.length; i++) {
components[i] = actionBar.getOrDefault(i, filler);
}
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));
}

View File

@@ -64,24 +64,28 @@ public class HorizontalScrollLayout extends UIFragment {
boolean hasPrev = scroll > 0;
boolean hasNext = data.size() - scroll > 9;
Map<Integer, UIComponent> actionBar = new HashMap<>(this.actionBar);
Map<Integer, UIComponent> actionBar = context.useMemo(() -> {
Map<Integer, UIComponent> content = new HashMap<>(this.actionBar);
actionBar.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;
}
}));
actionBar.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;
}
}));
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),

View File

@@ -55,35 +55,44 @@ public class PageLayout<T> extends UIFragment {
@Override
public UIComponent build(RenderContext context) {
List<UIComponent> uiItems = new ArrayList<>();
int itemsOnPage = context.getContainerSize().getWidth() * (context.getContainerSize().getHeight() - 1);
int ipageLimit = items.size() - page * itemsOnPage;
if (ipageLimit > itemsOnPage) {
ipageLimit = itemsOnPage;
}
List<UIComponent> uiItems = context.useMemo(() -> {
int i = page * itemsOnPage;
int i = page * itemsOnPage;
for (int ipage = 0; ipage < ipageLimit; ipage++) {
UIListEntry<T> e = items.get(i);
int ipageLimit = items.size() - page * itemsOnPage;
if (ipageLimit > itemsOnPage) {
ipageLimit = itemsOnPage;
}
uiItems.add(new UIItem(e.item).onClickNoUpdate(inventoryClickEvent -> callback.clicked(inventoryClickEvent.getClick(), e.object)));
i++;
}
List<UIComponent> pageItems = new ArrayList<>();
for (int ipage = 0; ipage < ipageLimit; ipage++) {
UIListEntry<T> e = items.get(i);
Map<Integer, UIComponent> uiBar = new HashMap<>(itemsOnBar);
pageItems.add(new UIItem(e.item).onClickNoUpdate(inventoryClickEvent -> callback.clicked(inventoryClickEvent.getClick(), e.object)));
i++;
}
if (page != 0) {
uiBar.put(0, new UIItem(ItemBuilder.color(DyeColor.LIME).message(Core.MESSAGE).translateName("SWLISINV_PREVIOUS_PAGE_ACTIVE")).onClick(inventoryClickEvent -> page--));
} else {
uiBar.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)) {
uiBar.put(8, new UIItem(ItemBuilder.color(DyeColor.LIME).message(Core.MESSAGE).translateName("SWLISINV_NEXT_PAGE_ACTIVE")).onClick(inventoryClickEvent -> page++));
} else {
uiBar.put(8, new UIItem(ItemBuilder.color(DyeColor.GRAY).message(Core.MESSAGE).translateName("SWLISINV_NEXT_PAGE_INACTIVE")).cancelOnClick());
}
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),

View File

@@ -183,4 +183,23 @@ public class ItemBuilder {
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 +
'}';
}
}

View File

@@ -26,7 +26,6 @@ import de.steamwar.inventory.ui.util.RenderItem;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Consumer;
import java.util.function.Function;
public class OnClick implements UIComponent {
@@ -56,4 +55,20 @@ public class OnClick implements UIComponent {
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);
}
}

View File

@@ -34,4 +34,9 @@ public class Space implements UIComponent {
new Size(1, 1)
);
}
@Override
public boolean equals(Object obj) {
return obj instanceof Space;
}
}

View File

@@ -21,9 +21,11 @@ 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 {
@@ -44,4 +46,19 @@ public class UIItem implements UIComponent {
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);
}
}

View File

@@ -23,10 +23,21 @@ 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);
}
}