浏览代码

Optimise scrolled entry list with a lot of entries

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 4 年之前
父节点
当前提交
342a799eb9

+ 36 - 12
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java

@@ -29,6 +29,8 @@ import com.google.common.collect.Lists;
 import com.mojang.blaze3d.vertex.PoseStack;
 import com.mojang.blaze3d.vertex.PoseStack;
 import com.mojang.blaze3d.vertex.Tesselator;
 import com.mojang.blaze3d.vertex.Tesselator;
 import com.mojang.math.Matrix4f;
 import com.mojang.math.Matrix4f;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
 import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
 import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
 import it.unimi.dsi.fastutil.ints.IntSet;
 import it.unimi.dsi.fastutil.ints.IntSet;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
@@ -61,12 +63,13 @@ import org.apache.commons.lang3.mutable.MutableLong;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;
 
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Comparator;
 import java.util.List;
 import java.util.List;
 import java.util.concurrent.*;
 import java.util.concurrent.*;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 
 @ApiStatus.Internal
 @ApiStatus.Internal
 public class EntryListWidget extends WidgetWithBounds {
 public class EntryListWidget extends WidgetWithBounds {
@@ -260,38 +263,59 @@ public class EntryListWidget extends WidgetWithBounds {
         long totalTimeStart = debugTime ? System.nanoTime() : 0;
         long totalTimeStart = debugTime ? System.nanoTime() : 0;
         boolean fastEntryRendering = ConfigObject.getInstance().doesFastEntryRendering();
         boolean fastEntryRendering = ConfigObject.getInstance().doesFastEntryRendering();
         if (ConfigObject.getInstance().isEntryListWidgetScrolled()) {
         if (ConfigObject.getInstance().isEntryListWidgetScrolled()) {
-            for (EntryListEntry entry : entries)
-                entry.clearStacks();
             ScissorsHandler.INSTANCE.scissor(bounds);
             ScissorsHandler.INSTANCE.scissor(bounds);
             
             
             int skip = Math.max(0, Mth.floor(scrolling.scrollAmount / (float) entrySize()));
             int skip = Math.max(0, Mth.floor(scrolling.scrollAmount / (float) entrySize()));
             int nextIndex = skip * innerBounds.width / entrySize();
             int nextIndex = skip * innerBounds.width / entrySize();
-            int[] i = {nextIndex};
+            int i = nextIndex;
+            int cont = nextIndex;
             blockedCount = 0;
             blockedCount = 0;
             
             
-            Stream<EntryListEntry> entryStream = this.entries.stream().skip(nextIndex).filter(entry -> {
+            Int2ObjectMap<List<EntryListEntry>> grouping = new Int2ObjectOpenHashMap<>();
+            List<EntryListEntry> toRender = new ArrayList<>();
+            Consumer<EntryListEntry> add;
+            
+            if (fastEntryRendering) {
+                add = entry -> {
+                    int hash = OptimalEntryStack.groupingHashFrom(entry.getCurrentEntry());
+                    List<EntryListEntry> entries = grouping.get(hash);
+                    
+                    if (entries == null) {
+                        grouping.put(hash, entries = new ArrayList<>());
+                    }
+                    
+                    entries.add(entry);
+                };
+            } else {
+                add = toRender::add;
+            }
+            
+            for (; cont < entries.size(); cont++) {
+                EntryListEntry entry = entries.get(cont);
+                
                 Rectangle entryBounds = entry.getBounds();
                 Rectangle entryBounds = entry.getBounds();
                 
                 
                 entryBounds.y = (int) (entry.backupY - scrolling.scrollAmount);
                 entryBounds.y = (int) (entry.backupY - scrolling.scrollAmount);
-                if (entryBounds.y > this.bounds.getMaxY()) return false;
+                if (entryBounds.y > this.bounds.getMaxY()) break;
+                if (allStacks.size() <= i) break;
                 if (notSteppingOnExclusionZones(entryBounds.x, entryBounds.y, entryBounds.width, entryBounds.height, innerBounds)) {
                 if (notSteppingOnExclusionZones(entryBounds.x, entryBounds.y, entryBounds.width, entryBounds.height, innerBounds)) {
-                    EntryStack stack = allStacks.get(i[0]++);
+                    EntryStack stack = allStacks.get(i++);
                     if (!stack.isEmpty()) {
                     if (!stack.isEmpty()) {
+                        entry.clearStacks();
                         entry.entry(stack);
                         entry.entry(stack);
-                        return true;
+                        add.accept(entry);
                     }
                     }
                 } else {
                 } else {
                     blockedCount++;
                     blockedCount++;
                 }
                 }
-                return false;
-            }).limit(Math.max(0, allStacks.size() - i[0]));
+            }
             
             
             if (fastEntryRendering) {
             if (fastEntryRendering) {
-                for (List<EntryListEntry> entries : entryStream.collect(Collectors.groupingBy(entryListEntry -> OptimalEntryStack.groupingHashFrom(entryListEntry.getCurrentEntry()))).values()) {
+                for (List<EntryListEntry> entries : grouping.values()) {
                     renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, entries);
                     renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, entries);
                 }
                 }
             } else {
             } else {
-                renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, entryStream.collect(Collectors.toList()));
+                renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, toRender);
             }
             }
             
             
             updatePosition(delta);
             updatePosition(delta);

+ 15 - 3
RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryWidget.java

@@ -226,7 +226,7 @@ public class EntryWidget extends Slot {
     }
     }
     
     
     public EntryWidget clearStacks() {
     public EntryWidget clearStacks() {
-        entryStacks.clear();
+        entryStacks = Collections.emptyList();
         return this;
         return this;
     }
     }
     
     
@@ -239,14 +239,26 @@ public class EntryWidget extends Slot {
     @NotNull
     @NotNull
     @Override
     @Override
     public EntryWidget entry(EntryStack stack) {
     public EntryWidget entry(EntryStack stack) {
-        entryStacks.add(stack);
+        if (entryStacks.isEmpty()) {
+            entryStacks = Collections.singletonList(stack);
+        } else {
+            if (!(entryStacks instanceof ArrayList)) {
+                entryStacks = new ArrayList<>(entryStacks);
+            }
+            entryStacks.add(stack);
+        }
         return this;
         return this;
     }
     }
     
     
     @NotNull
     @NotNull
     @Override
     @Override
     public EntryWidget entries(Collection<EntryStack> stacks) {
     public EntryWidget entries(Collection<EntryStack> stacks) {
-        entryStacks.addAll(stacks);
+        if (!stacks.isEmpty()) {
+            if (!(entryStacks instanceof ArrayList)) {
+                entryStacks = new ArrayList<>(entryStacks);
+            }
+            entryStacks.addAll(stacks);
+        }
         return this;
         return this;
     }
     }
     
     

+ 1 - 1
gradle.properties

@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx3G
 org.gradle.jvmargs=-Xmx3G
-mod_version=5.9.1
+mod_version=5.9.2
 supported_version=1.16.2/3/4/5
 supported_version=1.16.2/3/4/5
 minecraft_version=1.16.4
 minecraft_version=1.16.4
 fabricloader_version=0.10.6+build.214
 fabricloader_version=0.10.6+build.214