aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2022-06-21 23:38:52 +0800
committershedaniel <daniel@shedaniel.me>2022-06-28 03:21:12 +0800
commitd7ac83de715a29714d4d5764f1aedb17ae967c73 (patch)
tree8890c0c8fdce20bef23e2e6721d253047d81a174 /runtime
parentfbf63f0d545597676aae46729739b1b13f41452f (diff)
downloadRoughlyEnoughItems-d7ac83de715a29714d4d5764f1aedb17ae967c73.tar.gz
RoughlyEnoughItems-d7ac83de715a29714d4d5764f1aedb17ae967c73.tar.bz2
RoughlyEnoughItems-d7ac83de715a29714d4d5764f1aedb17ae967c73.zip
Primitive implementation of collapsible entries
Diffstat (limited to 'runtime')
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java6
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsingEntryListWidget.java107
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java56
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListStackEntry.java29
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java6
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/PaginatedEntryListWidget.java30
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/ScrolledEntryListWidget.java31
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsedStack.java49
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsibleEntryRegistryImpl.java92
11 files changed, 381 insertions, 31 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
index 923903369..6c16acdfc 100644
--- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
+++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
@@ -76,6 +76,7 @@ import me.shedaniel.rei.impl.client.subsets.SubsetsRegistryImpl;
import me.shedaniel.rei.impl.client.transfer.TransferHandlerRegistryImpl;
import me.shedaniel.rei.impl.client.view.ViewsImpl;
import me.shedaniel.rei.impl.common.entry.type.EntryRegistryImpl;
+import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsibleEntryRegistryImpl;
import me.shedaniel.rei.impl.common.entry.type.types.EmptyEntryDefinition;
import me.shedaniel.rei.impl.common.plugins.PluginManagerImpl;
import me.shedaniel.rei.impl.common.util.IssuesDetector;
@@ -225,6 +226,7 @@ public class RoughlyEnoughItemsCoreClient {
new SearchProviderImpl(),
new ConfigManagerImpl(),
new EntryRegistryImpl(),
+ new CollapsibleEntryRegistryImpl(),
new CategoryRegistryImpl(),
new DisplayRegistryImpl(),
new ScreenRegistryImpl(),
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java
index 94523a83b..94bc5a085 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java
@@ -282,7 +282,11 @@ public class EntryWidget extends Slot implements DraggableStackProviderWidget {
return EntryStack.empty();
if (size == 1)
return entryStacks.get(0);
- return entryStacks.get(Mth.floor(((System.currentTimeMillis() + stackDisplayOffset) / 1000 % (double) size)));
+ return entryStacks.get(Mth.floor(((System.currentTimeMillis() + stackDisplayOffset) / getCyclingInterval() % (double) size)));
+ }
+
+ protected long getCyclingInterval() {
+ return 1000;
}
@Override
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsingEntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsingEntryListWidget.java
new file mode 100644
index 000000000..77e59d6f4
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsingEntryListWidget.java
@@ -0,0 +1,107 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.client.gui.widget.entrylist;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
+import me.shedaniel.rei.api.common.entry.EntryStack;
+import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public abstract class CollapsingEntryListWidget extends EntryListWidget {
+ private List</*EntryStack<?> | CollapsedStack*/ Object> collapsedStacks = new ArrayList<>();
+ private Int2ObjectMap<CollapsedStack> collapsedStackIndexed = new Int2ObjectOpenHashMap<>();
+ protected int updatedCount;
+ protected int lastUpdatedCount;
+
+ public abstract List</*EntryStack<?> | List<EntryStack<?>>*/ Object> getStacks();
+
+ protected abstract void setStacks(List</*EntryStack<?> | List<EntryStack<?>>*/ Object> stacks);
+
+ protected final Int2ObjectMap<CollapsedStack> getCollapsedStackIndexed() {
+ return collapsedStackIndexed;
+ }
+
+ @Override
+ public List</*EntryStack<?> | CollapsedStack*/ Object> getCollapsedStacks() {
+ return collapsedStacks;
+ }
+
+ @Override
+ protected void setCollapsedStacks(List</*EntryStack<?> | CollapsedStack*/ Object> stacks) {
+ this.collapsedStacks = stacks;
+ updateStacks();
+ }
+
+ @Override
+ public void updateEntriesPosition() {
+ if (updatedCount != lastUpdatedCount) {
+ updateStacks();
+ }
+
+ super.updateEntriesPosition();
+ }
+
+ private void updateStacks() {
+ lastUpdatedCount = updatedCount;
+
+ List</*EntryStack<?> | List<EntryStack<?>>*/ Object> stacks = new ArrayList<>((int) (collapsedStacks.size() * 1.5));
+ Map</*EntryStack<?> | List<EntryStack<?>>*/ Object, CollapsedStack> collapsedStackMap = new Reference2ObjectOpenHashMap<>();
+ Int2ObjectMap<CollapsedStack> collapsedStackIndexed = new Int2ObjectOpenHashMap<>();
+
+ for (Object obj : collapsedStacks) {
+ if (obj instanceof EntryStack<?> stack) {
+ stacks.add(stack);
+ } else if (obj instanceof CollapsedStack stack) {
+ List<EntryStack<?>> ingredient = stack.getIngredient();
+ if (stack.isExpanded()) {
+ stacks.addAll(ingredient);
+ collapsedStackMap.put(ingredient.get(0), stack);
+ } else {
+ stacks.add(ingredient);
+ collapsedStackMap.put(ingredient, stack);
+ }
+ }
+ }
+
+ setStacks(stacks);
+
+ int index = 0;
+ for (/*EntryStack<?> | EntryIngredient*/ Object stack : stacks) {
+ CollapsedStack collapsedStack = collapsedStackMap.get(stack);
+
+ if (collapsedStack != null) {
+ collapsedStackIndexed.put(index, collapsedStack);
+ }
+
+ index++;
+ }
+
+ this.collapsedStackIndexed = collapsedStackIndexed;
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java
index da8c4a34b..c1b094c02 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java
@@ -27,17 +27,19 @@ import com.google.common.base.Stopwatch;
import me.shedaniel.rei.RoughlyEnoughItemsCore;
import me.shedaniel.rei.api.client.config.ConfigObject;
import me.shedaniel.rei.api.client.gui.config.EntryPanelOrdering;
+import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry;
import me.shedaniel.rei.api.common.entry.EntryStack;
import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
+import me.shedaniel.rei.api.common.util.EntryStacks;
import me.shedaniel.rei.impl.client.search.AsyncSearchManager;
+import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack;
+import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsibleEntryRegistryImpl;
import net.minecraft.client.Minecraft;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
+import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import java.util.*;
import java.util.function.Consumer;
public class EntryListSearchManager {
@@ -55,13 +57,13 @@ public class EntryListSearchManager {
private AsyncSearchManager searchManager = AsyncSearchManager.createDefault();
- public void update(String searchTerm, boolean ignoreLastSearch, Consumer<List<EntryStack<?>>> update) {
+ public void update(String searchTerm, boolean ignoreLastSearch, Consumer<List</*EntryStack<?> | CollapsedStack*/ Object>> update) {
Stopwatch stopwatch = Stopwatch.createStarted();
if (ignoreLastSearch) searchManager.markDirty();
searchManager.updateFilter(searchTerm);
if (searchManager.isDirty()) {
searchManager.getAsync(list -> {
- List<EntryStack<?>> finalList = copyAndOrder(list);
+ List</*EntryStack<?> | CollapsedStack*/ Object> finalList = collapse(copyAndOrder(list));
if (ConfigObject.getInstance().doDebugSearchTimeRequired()) {
RoughlyEnoughItemsCore.LOGGER.info("Search Used: %s", stopwatch.stop().toString());
@@ -88,6 +90,48 @@ public class EntryListSearchManager {
return list;
}
+ private List</*EntryStack<?> | CollapsedStack*/ Object> collapse(List<EntryStack<?>> stacks) {
+ CollapsibleEntryRegistryImpl collapsibleRegistry = (CollapsibleEntryRegistryImpl) CollapsibleEntryRegistry.getInstance();
+ Map<CollapsibleEntryRegistryImpl.Matcher, @Nullable CollapsedStack> matchers = new HashMap<>();
+
+ for (CollapsibleEntryRegistryImpl.Matcher matcher : collapsibleRegistry.getMatchers()) {
+ matchers.put(matcher, null);
+ }
+
+ List</*EntryStack<?> | CollapsedStack*/ Object> list = new ArrayList<>();
+
+ for (EntryStack<?> stack : stacks) {
+ long hashExact = EntryStacks.hashExact(stack);
+ boolean matchedAny = false;
+
+ for (Map.Entry<CollapsibleEntryRegistryImpl.Matcher, @Nullable CollapsedStack> entry : matchers.entrySet()) {
+ CollapsibleEntryRegistryImpl.Matcher matcher = entry.getKey();
+
+ if (matcher.matches(stack, hashExact)) {
+ CollapsedStack collapsed = entry.getValue();
+
+ if (collapsed == null) {
+ List<EntryStack<?>> ingredient = new ArrayList<>();
+ ingredient.add(stack);
+ collapsed = new CollapsedStack(ingredient);
+ entry.setValue(collapsed);
+ list.add(collapsed);
+ } else {
+ collapsed.getIngredient().add(stack);
+ }
+
+ matchedAny = true;
+ }
+ }
+
+ if (!matchedAny) {
+ list.add(stack);
+ }
+ }
+
+ return list;
+ }
+
public boolean matches(EntryStack<?> stack) {
return searchManager.matches(stack);
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListStackEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListStackEntry.java
index c229015f5..2e24d959d 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListStackEntry.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListStackEntry.java
@@ -28,19 +28,22 @@ import me.shedaniel.clothconfig2.api.animator.NumberAnimator;
import me.shedaniel.clothconfig2.api.animator.ValueAnimator;
import me.shedaniel.math.Point;
import me.shedaniel.math.impl.PointHelper;
+import me.shedaniel.rei.api.client.gui.widgets.Widgets;
import me.shedaniel.rei.api.common.entry.EntryStack;
import me.shedaniel.rei.impl.client.gui.widget.CachedEntryListRender;
import me.shedaniel.rei.impl.client.gui.widget.DisplayedEntryWidget;
+import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack;
import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize;
@SuppressWarnings("UnstableApiUsage")
public class EntryListStackEntry extends DisplayedEntryWidget {
- private final EntryListWidget parent;
+ private final CollapsingEntryListWidget parent;
public EntryStack<?> our;
private NumberAnimator<Double> size = null;
+ private CollapsedStack collapsedStack = null;
- public EntryListStackEntry(EntryListWidget parent, int x, int y, int entrySize, boolean zoomed) {
+ public EntryListStackEntry(CollapsingEntryListWidget parent, int x, int y, int entrySize, boolean zoomed) {
super(new Point(x, y), entrySize);
this.parent = parent;
if (zoomed) {
@@ -84,4 +87,26 @@ public class EntryListStackEntry extends DisplayedEntryWidget {
public boolean containsMouse(double mouseX, double mouseY) {
return super.containsMouse(mouseX, mouseY) && parent.containsChecked(mouseX, mouseY, true);
}
+
+ @Override
+ protected boolean doAction(double mouseX, double mouseY, int button) {
+ if (collapsedStack != null) {
+ parent.updatedCount++;
+ collapsedStack.setExpanded(!collapsedStack.isExpanded());
+ parent.updateEntriesPosition();
+ Widgets.produceClickSound();
+ return true;
+ }
+
+ return super.doAction(mouseX, mouseY, button);
+ }
+
+ public void collapsed(CollapsedStack collapsedStack) {
+ this.collapsedStack = collapsedStack;
+ }
+
+ @Override
+ protected long getCyclingInterval() {
+ return 100;
+ }
} \ No newline at end of file
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java
index 1204cc0f8..53ecc3e79 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java
@@ -287,13 +287,13 @@ public abstract class EntryListWidget extends WidgetWithBounds implements Overla
protected abstract void updateEntries(int entrySize, boolean zoomed);
- public abstract List<EntryStack<?>> getStacks();
+ public abstract List</*EntryStack<?> | CollapsedStack*/ Object> getCollapsedStacks();
- protected abstract void setStacks(List<EntryStack<?>> stacks);
+ protected abstract void setCollapsedStacks(List</*EntryStack<?> | CollapsedStack*/ Object> stacks);
public void updateSearch(String searchTerm, boolean ignoreLastSearch) {
EntryListSearchManager.INSTANCE.update(searchTerm, ignoreLastSearch, stacks -> {
- setStacks(stacks);
+ setCollapsedStacks(stacks);
updateEntriesPosition();
});
debugger.debugTime = ConfigObject.getInstance().doDebugRenderTimeRequired();
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/PaginatedEntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/PaginatedEntryListWidget.java
index 926c8726f..74afab82e 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/PaginatedEntryListWidget.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/PaginatedEntryListWidget.java
@@ -26,27 +26,27 @@ package me.shedaniel.rei.impl.client.gui.widget.entrylist;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import me.shedaniel.math.Rectangle;
import me.shedaniel.rei.api.client.config.ConfigObject;
import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer;
import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
import me.shedaniel.rei.api.client.gui.widgets.TooltipContext;
-import me.shedaniel.rei.api.client.gui.widgets.Widget;
import me.shedaniel.rei.api.client.util.ClientEntryStacks;
import me.shedaniel.rei.api.common.entry.EntryStack;
import me.shedaniel.rei.impl.client.gui.widget.BatchedEntryRendererManager;
import me.shedaniel.rei.impl.client.gui.widget.CachedEntryListRender;
import me.shedaniel.rei.impl.client.gui.widget.EntryWidget;
+import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack;
import net.minecraft.util.Mth;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
-public class PaginatedEntryListWidget extends EntryListWidget {
- private List<EntryStack<?>> stacks = new ArrayList<>();
+public class PaginatedEntryListWidget extends CollapsingEntryListWidget {
+ private List</*EntryStack<?> | EntryIngredient*/ Object> stacks = new ArrayList<>();
private int page;
@Override
@@ -110,21 +110,33 @@ public class PaginatedEntryListWidget extends EntryListWidget {
}
}
page = Math.max(Math.min(page, getTotalPages() - 1), 0);
- List<EntryStack<?>> subList = stacks.stream().skip(Math.max(0, page * entries.size())).limit(Math.max(0, entries.size() - Math.max(0, -page * entries.size()))).collect(Collectors.toList());
+ int skip = Math.max(0, page * entries.size());
+ List</*EntryStack<?> | List<EntryStack<?>>*/ Object> subList = stacks.stream().skip(skip).limit(Math.max(0, entries.size() - Math.max(0, -page * entries.size()))).toList();
+ Int2ObjectMap<CollapsedStack> indexedCollapsedStack = getCollapsedStackIndexed();
for (int i = 0; i < subList.size(); i++) {
- EntryStack<?> stack = subList.get(i);
- entries.get(i + Math.max(0, -page * entries.size())).clearStacks().entry(stack);
+ /*EntryStack<?> | List<EntryStack<?>>*/
+ Object stack = subList.get(i);
+ EntryListStackEntry entry = entries.get(i + Math.max(0, -page * entries.size()));
+ entry.clearStacks();
+
+ if (stack instanceof EntryStack<?> entryStack) {
+ entry.entry(entryStack);
+ } else {
+ entry.entries((List<EntryStack<?>>) stack);
+ }
+
+ entry.collapsed(indexedCollapsedStack.get(i + skip));
}
this.entries = entries;
}
@Override
- public List<EntryStack<?>> getStacks() {
+ public List</*EntryStack<?> | List<EntryStack<?>>*/ Object> getStacks() {
return stacks;
}
@Override
- public void setStacks(List<EntryStack<?>> stacks) {
+ public void setStacks(List</*EntryStack<?> | List<EntryStack<?>>*/ Object> stacks) {
this.stacks = stacks;
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/ScrolledEntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/ScrolledEntryListWidget.java
index 2edde5a34..a42beca17 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/ScrolledEntryListWidget.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/ScrolledEntryListWidget.java
@@ -26,6 +26,7 @@ package me.shedaniel.rei.impl.client.gui.widget.entrylist;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.vertex.PoseStack;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import me.shedaniel.clothconfig2.ClothConfigInitializer;
import me.shedaniel.clothconfig2.api.ScissorsHandler;
import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer;
@@ -34,6 +35,7 @@ import me.shedaniel.rei.api.client.REIRuntime;
import me.shedaniel.rei.api.common.entry.EntryStack;
import me.shedaniel.rei.impl.client.gui.widget.BatchedEntryRendererManager;
import me.shedaniel.rei.impl.client.gui.widget.EntryWidget;
+import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.util.Mth;
@@ -41,8 +43,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
-public class ScrolledEntryListWidget extends EntryListWidget {
- private List<EntryStack<?>> stacks = new ArrayList<>();
+public class ScrolledEntryListWidget extends CollapsingEntryListWidget {
+ private List</*EntryStack<?> | EntryIngredient*/ Object> stacks = new ArrayList<>();
protected int blockedCount;
protected final ScrollingContainer scrolling = new ScrollingContainer() {
@Override
@@ -64,6 +66,7 @@ public class ScrolledEntryListWidget extends EntryListWidget {
int nextIndex = skip * innerBounds.width / entrySize();
this.blockedCount = 0;
BatchedEntryRendererManager helper = new BatchedEntryRendererManager();
+ Int2ObjectMap<CollapsedStack> indexedCollapsedStack = getCollapsedStackIndexed();
int i = nextIndex;
for (int cont = nextIndex; cont < entries.size(); cont++) {
@@ -74,12 +77,24 @@ public class ScrolledEntryListWidget extends EntryListWidget {
if (entryBounds.y > this.bounds.getMaxY()) break;
if (stacks.size() <= i) break;
if (notSteppingOnExclusionZones(entryBounds.x, entryBounds.y, entryBounds.width, entryBounds.height)) {
- EntryStack<?> stack = stacks.get(i++);
+ /*EntryStack<?> | List<EntryStack<?>>*/
+ Object stack = stacks.get(i++);
entry.clearStacks();
- if (!stack.isEmpty()) {
- entry.entry(stack);
- helper.add(entry);
+
+ if (stack instanceof EntryStack<?> entryStack) {
+ if (!entryStack.isEmpty()) {
+ entry.entry(entryStack);
+ helper.add(entry);
+ }
+ } else {
+ List<EntryStack<?>> ingredient = (List<EntryStack<?>>) stack;
+ if (!ingredient.isEmpty()) {
+ entry.entries(ingredient);
+ helper.add(entry);
+ }
}
+
+ entry.collapsed(indexedCollapsedStack.get(i - 1));
} else {
blockedCount++;
}
@@ -154,12 +169,12 @@ public class ScrolledEntryListWidget extends EntryListWidget {
}
@Override
- public List<EntryStack<?>> getStacks() {
+ public List</*EntryStack<?> | List<EntryStack<?>>*/ Object> getStacks() {
return stacks;
}
@Override
- public void setStacks(List<EntryStack<?>> stacks) {
+ public void setStacks(List</*EntryStack<?> | List<EntryStack<?>>*/ Object> stacks) {
this.stacks = stacks;
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java
index 08ede73c4..bed536c9c 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java
@@ -94,7 +94,7 @@ public class OverlaySearchField extends TextFieldWidget implements TextFieldWidg
return TextTransformations.forwardWithTransformation(text, (s, charIndex, c) -> {
byte arg = highlighter.highlighted[charIndex + index];
Style style = Style.EMPTY;
- if (isMain && ScreenOverlayImpl.getEntryListWidget().getStacks().isEmpty() && !getText().isEmpty()) {
+ if (isMain && ScreenOverlayImpl.getEntryListWidget().getCollapsedStacks().isEmpty() && !getText().isEmpty()) {
style = ERROR_STYLE;
}
if (arg > 0) {
@@ -239,7 +239,7 @@ public class OverlaySearchField extends TextFieldWidget implements TextFieldWidg
int borderColor;
if (isMain && isHighlighting) {
borderColor = 0xfff2ff0c;
- } else if (isMain && ScreenOverlayImpl.getEntryListWidget().getStacks().isEmpty() && !getText().isEmpty()) {
+ } else if (isMain && ScreenOverlayImpl.getEntryListWidget().getCollapsedStacks().isEmpty() && !getText().isEmpty()) {
borderColor = 0xffff5555;
} else {
super.renderBorder(matrices);
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsedStack.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsedStack.java
new file mode 100644
index 000000000..7aa7670ef
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsedStack.java
@@ -0,0 +1,49 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.common.entry.type.collapsed;
+
+import me.shedaniel.rei.api.common.entry.EntryStack;
+
+import java.util.List;
+
+public class CollapsedStack {
+ private final List<EntryStack<?>> ingredient;
+ private boolean expanded;
+
+ public CollapsedStack(List<EntryStack<?>> ingredient) {
+ this.ingredient = ingredient;
+ }
+
+ public List<EntryStack<?>> getIngredient() {
+ return ingredient;
+ }
+
+ public boolean isExpanded() {
+ return expanded;
+ }
+
+ public void setExpanded(boolean expanded) {
+ this.expanded = expanded;
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsibleEntryRegistryImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsibleEntryRegistryImpl.java
new file mode 100644
index 000000000..338c1a8a4
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsibleEntryRegistryImpl.java
@@ -0,0 +1,92 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.common.entry.type.collapsed;
+
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import me.shedaniel.rei.api.client.plugins.REIClientPlugin;
+import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry;
+import me.shedaniel.rei.api.common.entry.EntryStack;
+import me.shedaniel.rei.api.common.util.EntryStacks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+public class CollapsibleEntryRegistryImpl implements CollapsibleEntryRegistry {
+ private final List<Matcher> matchers = new ArrayList<>();
+
+ @Override
+ public <T> void group(List<? extends EntryStack<? extends T>> stacks) {
+ Objects.requireNonNull(stacks, "stacks");
+ this.matchers.add(new ListMatcher(stacks));
+ }
+
+ @Override
+ public void group(Predicate<? extends EntryStack<?>> predicate) {
+ Objects.requireNonNull(predicate, "predicate");
+ this.matchers.add((stack, hashExact) -> ((Predicate<EntryStack<?>>) predicate).test(stack));
+ }
+
+ @Override
+ public void startReload() {
+ this.matchers.clear();
+ }
+
+ @Override
+ public void acceptPlugin(REIClientPlugin plugin) {
+ plugin.registerCollapsibleEntries(this);
+ }
+
+ public List<Matcher> getMatchers() {
+ return matchers;
+ }
+
+ @FunctionalInterface
+ public interface Matcher {
+ boolean matches(EntryStack<?> stack, long hashExact);
+ }
+
+ private static class ListMatcher implements Matcher {
+ private final Long2ObjectMap<EntryStack<?>> stacks;
+
+ public ListMatcher(List<? extends EntryStack<?>> stacks) {
+ this.stacks = new Long2ObjectOpenHashMap<>(stacks.size() + 1);
+ for (EntryStack<?> stack : stacks) {
+ this.stacks.put(EntryStacks.hashExact(stack), stack);
+ }
+ }
+
+ @Override
+ public boolean matches(EntryStack<?> stack, long hashExact) {
+ EntryStack<?> entryStack = stacks.get(hashExact);
+
+ if (entryStack == null)
+ return false;
+
+ return EntryStacks.equalsExact(entryStack, stack);
+ }
+ }
+}