Fixed lag when opening a Grid with lots of items by offloading the grid sorting to another thread

This commit is contained in:
raoulvdberge
2017-11-10 11:22:02 +01:00
parent 44a4820109
commit 0ad40e01b4
14 changed files with 163 additions and 105 deletions

View File

@@ -6,6 +6,7 @@
- The Crafter can now only store 1 stack size pattern per slot (raoulvdberge)
- You can now re-insert a Pattern in the pattern output slot in the Pattern Grid to modify an existing pattern (raoulvdberge)
- Fixed not being able to use JEI R and U keys on Grid with tabs (raoulvdberge)
- Fixed lag when opening a Grid with lots of items by offloading the grid sorting to another thread (raoulvdberge)
- The Refined Storage jar is now signed (raoulvdberge)
### 1.5.21

View File

@@ -41,7 +41,6 @@ public class StackListItem implements IStackList<ItemStack> {
public boolean remove(@Nonnull ItemStack stack, int size) {
for (ItemStack otherStack : stacks.get(stack.getItem())) {
if (API.instance().getComparer().isEqualNoQuantity(otherStack, stack)) {
boolean success = otherStack.getCount() - size >= 0;
otherStack.shrink(size);

View File

@@ -13,8 +13,7 @@ import com.raoulvdberge.refinedstorage.apiimpl.network.node.NetworkNodeGrid;
import com.raoulvdberge.refinedstorage.container.ContainerGrid;
import com.raoulvdberge.refinedstorage.gui.GuiBase;
import com.raoulvdberge.refinedstorage.gui.Scrollbar;
import com.raoulvdberge.refinedstorage.gui.grid.filtering.GridFilterParser;
import com.raoulvdberge.refinedstorage.gui.grid.sorting.*;
import com.raoulvdberge.refinedstorage.gui.grid.sorting.Sorter;
import com.raoulvdberge.refinedstorage.gui.grid.stack.GridStackFluid;
import com.raoulvdberge.refinedstorage.gui.grid.stack.GridStackItem;
import com.raoulvdberge.refinedstorage.gui.grid.stack.IGridStack;
@@ -44,14 +43,8 @@ import org.lwjgl.input.Keyboard;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Predicate;
public class GuiGrid extends GuiBase implements IGridDisplay {
private static final GridSorting SORTING_QUANTITY = new GridSortingQuantity();
private static final GridSorting SORTING_NAME = new GridSortingName();
private static final GridSorting SORTING_ID = new GridSortingID();
private static final GridSorting SORTING_INVENTORYTWEAKS = new GridSortingInventoryTweaks();
private static final List<String> SEARCH_HISTORY = new ArrayList<>();
public static final ListMultimap<Item, GridStackItem> ITEMS = Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
@@ -60,7 +53,8 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
public static List<IGridStack> STACKS = new ArrayList<>();
public static boolean CAN_CRAFT;
private static boolean markedForSorting;
private static boolean SCHEDULE_SORT = false;
private Queue<Sorter> sortingQueue = new ArrayDeque<>();
private boolean wasConnected;
@@ -98,10 +92,6 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
private int[] konamiOffsetsX;
private int[] konamiOffsetsY;
public static void markForSorting() {
markedForSorting = true;
}
public GuiGrid(ContainerGrid container, IGrid grid) {
super(container, grid.getType() == GridType.FLUID ? 193 : 227, 0);
@@ -169,7 +159,7 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
addSideButton(new SideButtonGridSearchBoxMode(this));
addSideButton(new SideButtonGridSize(this, grid));
sortItems();
scheduleSort();
}
@Override
@@ -181,62 +171,8 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
return grid;
}
private void sortItems() {
List<IGridStack> stacks = new ArrayList<>();
if (grid.isActive()) {
stacks.addAll(grid.getType() == GridType.FLUID ? FLUIDS.values() : ITEMS.values());
List<Predicate<IGridStack>> filters = GridFilterParser.getFilters(
grid,
searchField != null ? searchField.getText() : "",
(grid.getTabSelected() >= 0 && grid.getTabSelected() < grid.getTabs().size()) ? grid.getTabs().get(grid.getTabSelected()).getFilters() : grid.getFilters()
);
Iterator<IGridStack> t = stacks.iterator();
while (t.hasNext()) {
IGridStack stack = t.next();
for (Predicate<IGridStack> filter : filters) {
if (!filter.test(stack)) {
t.remove();
break;
}
}
}
SORTING_NAME.setSortingDirection(grid.getSortingDirection());
SORTING_QUANTITY.setSortingDirection(grid.getSortingDirection());
SORTING_ID.setSortingDirection(grid.getSortingDirection());
SORTING_INVENTORYTWEAKS.setSortingDirection(grid.getSortingDirection());
stacks.sort(SORTING_NAME);
if (grid.getSortingType() == IGrid.SORTING_TYPE_QUANTITY) {
stacks.sort(SORTING_QUANTITY);
} else if (grid.getSortingType() == IGrid.SORTING_TYPE_ID) {
stacks.sort(SORTING_ID);
} else if (grid.getSortingType() == IGrid.SORTING_TYPE_INVENTORYTWEAKS) {
stacks.sort(SORTING_INVENTORYTWEAKS);
}
}
STACKS = stacks;
if (scrollbar != null) {
scrollbar.setEnabled(getRows() > getVisibleRows());
scrollbar.setMaxOffset(getRows() - getVisibleRows());
}
if (tabPageLeft != null) {
tabPageLeft.visible = grid.getTotalTabPages() > 0;
}
if (tabPageRight != null) {
tabPageRight.visible = grid.getTotalTabPages() > 0;
}
public static void scheduleSort() {
SCHEDULE_SORT = true;
}
@Override
@@ -251,13 +187,7 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
if (wasConnected != grid.isActive()) {
wasConnected = grid.isActive();
markForSorting();
}
if (markedForSorting) {
markedForSorting = false;
sortItems();
scheduleSort();
}
boolean hasTabs = !getGrid().getTabs().isEmpty();
@@ -267,6 +197,21 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
initGui();
}
if (SCHEDULE_SORT) {
SCHEDULE_SORT = false;
sortingQueue.add(new Sorter(this));
}
Sorter sorter = sortingQueue.peek();
if (sorter != null) {
if (!sorter.isStarted()) {
sorter.start();
} else if (sorter.isDone()) {
sortingQueue.poll();
}
}
}
@Override
@@ -478,7 +423,7 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
@Override
public void drawForeground(int mouseX, int mouseY) {
drawString(7, 7 + getTabHeight(), t(grid.getGuiTitle()));
drawString(7, 7 + getTabHeight(), t(grid.getGuiTitle()) + " " + STACKS.size() + "," + sortingQueue.size());
drawString(7, getYPlayerInventory() - 12, t("container.inventory"));
if (grid.getTotalTabPages() > 0) {
@@ -585,7 +530,7 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
searchField.setText("");
searchField.setFocused(true);
sortItems();
scheduleSort();
updateJEI();
} else if (wasSearchFieldFocused != searchField.isFocused()) {
@@ -659,8 +604,8 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
// NO OP
} else if (searchField.textboxKeyTyped(character, keyCode)) {
updateJEI();
scheduleSort();
sortItems();
keyHandled = true;
} else if (searchField.isFocused() && (keyCode == Keyboard.KEY_UP || keyCode == Keyboard.KEY_DOWN || keyCode == Keyboard.KEY_RETURN)) {
if (keyCode == Keyboard.KEY_UP) {
@@ -706,7 +651,7 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
if (delta == 1) {
searchField.setText("");
sortItems();
scheduleSort();
updateJEI();
@@ -716,7 +661,7 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
searchField.setText(SEARCH_HISTORY.get(searchHistory));
sortItems();
scheduleSort();
updateJEI();
}
@@ -759,4 +704,12 @@ public class GuiGrid extends GuiBase implements IGridDisplay {
blockingPattern.setIsChecked(checked);
}
}
public GuiButton getTabPageLeft() {
return tabPageLeft;
}
public GuiButton getTabPageRight() {
return tabPageRight;
}
}

View File

@@ -0,0 +1,105 @@
package com.raoulvdberge.refinedstorage.gui.grid.sorting;
import com.raoulvdberge.refinedstorage.api.network.grid.GridType;
import com.raoulvdberge.refinedstorage.api.network.grid.IGrid;
import com.raoulvdberge.refinedstorage.gui.grid.GuiGrid;
import com.raoulvdberge.refinedstorage.gui.grid.filtering.GridFilterParser;
import com.raoulvdberge.refinedstorage.gui.grid.stack.IGridStack;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;
public class Sorter implements Runnable {
private static final GridSorting SORTING_QUANTITY = new GridSortingQuantity();
private static final GridSorting SORTING_NAME = new GridSortingName();
private static final GridSorting SORTING_ID = new GridSortingID();
private static final GridSorting SORTING_INVENTORY_TWEAKS = new GridSortingInventoryTweaks();
private boolean done;
private boolean started;
private GuiGrid gui;
public Sorter(GuiGrid gui) {
this.gui = gui;
}
@Override
public void run() {
IGrid grid = gui.getGrid();
List<IGridStack> stacks = new ArrayList<>();
if (grid.isActive()) {
stacks.addAll(grid.getType() == GridType.FLUID ? GuiGrid.FLUIDS.values() : GuiGrid.ITEMS.values());
List<Predicate<IGridStack>> filters = GridFilterParser.getFilters(
grid,
gui.getSearchField() != null ? gui.getSearchField().getText() : "",
(grid.getTabSelected() >= 0 && grid.getTabSelected() < grid.getTabs().size()) ? grid.getTabs().get(grid.getTabSelected()).getFilters() : grid.getFilters()
);
Iterator<IGridStack> t = stacks.iterator();
while (t.hasNext()) {
IGridStack stack = t.next();
for (Predicate<IGridStack> filter : filters) {
if (!filter.test(stack)) {
t.remove();
break;
}
}
}
SORTING_NAME.setSortingDirection(grid.getSortingDirection());
SORTING_QUANTITY.setSortingDirection(grid.getSortingDirection());
SORTING_ID.setSortingDirection(grid.getSortingDirection());
SORTING_INVENTORY_TWEAKS.setSortingDirection(grid.getSortingDirection());
stacks.sort(SORTING_NAME);
if (grid.getSortingType() == IGrid.SORTING_TYPE_QUANTITY) {
stacks.sort(SORTING_QUANTITY);
} else if (grid.getSortingType() == IGrid.SORTING_TYPE_ID) {
stacks.sort(SORTING_ID);
} else if (grid.getSortingType() == IGrid.SORTING_TYPE_INVENTORYTWEAKS) {
stacks.sort(SORTING_INVENTORY_TWEAKS);
}
}
GuiGrid.STACKS = stacks;
if (gui.getScrollbar() != null) {
gui.getScrollbar().setEnabled(gui.getRows() > gui.getVisibleRows());
gui.getScrollbar().setMaxOffset(gui.getRows() - gui.getVisibleRows());
}
if (gui.getTabPageLeft() != null) {
gui.getTabPageLeft().visible = grid.getTotalTabPages() > 0;
}
if (gui.getTabPageRight() != null) {
gui.getTabPageRight().visible = grid.getTotalTabPages() > 0;
}
this.done = true;
}
public void start() {
this.started = true;
new Thread(this, "RS grid sorting").start();
}
public boolean isStarted() {
return started;
}
public boolean isDone() {
return done;
}
}

View File

@@ -43,7 +43,7 @@ public class ItemHandlerFilter extends ItemHandlerBase {
}
if (FMLCommonHandler.instance().getSide() == Side.CLIENT) {
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
}

View File

@@ -48,14 +48,14 @@ public class MessageGridFluidDelta implements IMessage, IMessageHandler<MessageG
stack.getStack().amount += message.delta;
}
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
return null;
}
}
GuiGrid.FLUIDS.put(fluid, message.clientStack);
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
return null;
}

View File

@@ -58,7 +58,7 @@ public class MessageGridFluidUpdate implements IMessage, IMessageHandler<Message
GuiGrid.FLUIDS.put(item.getStack().getFluid(), item);
}
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
return null;
}

View File

@@ -84,7 +84,7 @@ public class MessageGridItemDelta implements IMessage, IMessageHandler<MessageGr
message.gridStacks.forEach(p -> process(p.getLeft(), p.getRight()));
}
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
return null;
}

View File

@@ -99,7 +99,7 @@ public class MessageGridItemUpdate implements IMessage, IMessageHandler<MessageG
}
}
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
return null;
}

View File

@@ -24,19 +24,19 @@ public class TileGrid extends TileNode<NetworkNodeGrid> {
t.getNode().setViewType(v);
t.getNode().markDirty();
}
}, p -> GuiGrid.markForSorting());
}, p -> GuiGrid.scheduleSort());
public static final TileDataParameter<Integer, TileGrid> SORTING_DIRECTION = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNode().getSortingDirection(), (t, v) -> {
if (IGrid.isValidSortingDirection(v)) {
t.getNode().setSortingDirection(v);
t.getNode().markDirty();
}
}, p -> GuiGrid.markForSorting());
}, p -> GuiGrid.scheduleSort());
public static final TileDataParameter<Integer, TileGrid> SORTING_TYPE = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNode().getSortingType(), (t, v) -> {
if (IGrid.isValidSortingType(v)) {
t.getNode().setSortingType(v);
t.getNode().markDirty();
}
}, p -> GuiGrid.markForSorting());
}, p -> GuiGrid.scheduleSort());
public static final TileDataParameter<Integer, TileGrid> SEARCH_BOX_MODE = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNode().getSearchBoxMode(), (t, v) -> {
if (IGrid.isValidSearchBoxMode(v)) {
t.getNode().setSearchBoxMode(v);
@@ -62,7 +62,7 @@ public class TileGrid extends TileNode<NetworkNodeGrid> {
t.getNode().markDirty();
}, p -> {
if (Minecraft.getMinecraft().currentScreen instanceof GuiGrid) {
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
});
public static final TileDataParameter<Integer, TileGrid> TAB_PAGE = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNode().getTabPage(), (t, v) -> {

View File

@@ -128,7 +128,7 @@ public class WirelessFluidGrid implements IGrid {
this.sortingType = type;
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override
@@ -137,7 +137,7 @@ public class WirelessFluidGrid implements IGrid {
this.sortingDirection = direction;
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override

View File

@@ -151,7 +151,7 @@ public class WirelessGrid implements IGrid {
this.viewType = type;
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override
@@ -160,7 +160,7 @@ public class WirelessGrid implements IGrid {
this.sortingType = type;
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override
@@ -169,7 +169,7 @@ public class WirelessGrid implements IGrid {
this.sortingDirection = direction;
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override
@@ -196,7 +196,7 @@ public class WirelessGrid implements IGrid {
RS.INSTANCE.network.sendToServer(new MessageGridSettingsUpdate(getViewType(), getSortingDirection(), getSortingType(), getSearchBoxMode(), getSize(), tabSelected, getTabPage()));
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override

View File

@@ -262,7 +262,7 @@ public class PortableGrid implements IGrid, IPortableGrid {
this.sortingType = type;
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override
@@ -271,7 +271,7 @@ public class PortableGrid implements IGrid, IPortableGrid {
this.sortingDirection = direction;
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override
@@ -298,7 +298,7 @@ public class PortableGrid implements IGrid, IPortableGrid {
RS.INSTANCE.network.sendToServer(new MessageGridSettingsUpdate(getViewType(), getSortingDirection(), getSortingType(), getSearchBoxMode(), getSize(), tabSelected, getTabPage()));
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
@Override

View File

@@ -62,13 +62,13 @@ public class TilePortableGrid extends TileBase implements IGrid, IPortableGrid,
t.setSortingDirection(v);
t.markDirty();
}
}, p -> GuiGrid.markForSorting());
}, p -> GuiGrid.scheduleSort());
public static final TileDataParameter<Integer, TilePortableGrid> SORTING_TYPE = new TileDataParameter<>(DataSerializers.VARINT, 0, TilePortableGrid::getSortingType, (t, v) -> {
if (IGrid.isValidSortingType(v)) {
t.setSortingType(v);
t.markDirty();
}
}, p -> GuiGrid.markForSorting());
}, p -> GuiGrid.scheduleSort());
public static final TileDataParameter<Integer, TilePortableGrid> SEARCH_BOX_MODE = new TileDataParameter<>(DataSerializers.VARINT, 0, TilePortableGrid::getSearchBoxMode, (t, v) -> {
if (IGrid.isValidSearchBoxMode(v)) {
t.setSearchBoxMode(v);
@@ -94,7 +94,7 @@ public class TilePortableGrid extends TileBase implements IGrid, IPortableGrid,
t.markDirty();
}, p -> {
if (Minecraft.getMinecraft().currentScreen instanceof GuiGrid) {
GuiGrid.markForSorting();
GuiGrid.scheduleSort();
}
});
public static final TileDataParameter<Integer, TilePortableGrid> TAB_PAGE = new TileDataParameter<>(DataSerializers.VARINT, 0, TilePortableGrid::getTabPage, (t, v) -> {