From 74ab4307281090212201e61ee78fe232dfddff6b Mon Sep 17 00:00:00 2001 From: Score_Under Date: Sat, 2 Jan 2021 10:26:39 +0000 Subject: [PATCH] [MC1.16] [Client] Performance improvements for grid view (#2705) * Make Crafting Manager AND search terms, not OR them Plus refactor getFilters to avoid passing raw lists of filters around and instead use GridFilter objects that combine conditions through OR and AND. * Don't make all items vanish if query ends in `|` * Split out Comparator and Predicate generation for GridView into 2 separate functions * Move common code up into BaseGridView; remove identical subclasses This also follows the Law of Demeter a litle better. * Avoid sorting entire grid view on single item update Instead, use binary search and insert. * Ensure crafting stack is removed/inserted to complement original stack --- .../container/CrafterManagerContainer.java | 10 +- .../network/grid/GridFluidDeltaMessage.java | 2 - .../network/grid/GridFluidUpdateMessage.java | 4 +- .../network/grid/GridItemDeltaMessage.java | 2 - .../network/grid/GridItemUpdateMessage.java | 4 +- .../grid/PortableGridFluidDeltaMessage.java | 2 - .../grid/PortableGridFluidUpdateMessage.java | 4 +- .../grid/PortableGridItemDeltaMessage.java | 2 - .../grid/PortableGridItemUpdateMessage.java | 4 +- .../screen/grid/GridScreen.java | 5 +- .../screen/grid/filtering/AndGridFilter.java | 35 ++++ .../grid/filtering/GridFilterParser.java | 12 +- .../screen/grid/filtering/OrGridFilter.java | 22 +- .../screen/grid/stack/FluidGridStack.java | 11 +- .../screen/grid/stack/IGridStack.java | 2 + .../screen/grid/stack/ItemGridStack.java | 11 +- .../screen/grid/view/BaseGridView.java | 111 ---------- .../screen/grid/view/FluidGridView.java | 69 ------- .../screen/grid/view/GridViewImpl.java | 193 ++++++++++++++++++ .../screen/grid/view/ItemGridView.java | 69 ------- 20 files changed, 285 insertions(+), 289 deletions(-) create mode 100644 src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/AndGridFilter.java delete mode 100644 src/main/java/com/refinedmods/refinedstorage/screen/grid/view/BaseGridView.java delete mode 100644 src/main/java/com/refinedmods/refinedstorage/screen/grid/view/FluidGridView.java create mode 100644 src/main/java/com/refinedmods/refinedstorage/screen/grid/view/GridViewImpl.java delete mode 100644 src/main/java/com/refinedmods/refinedstorage/screen/grid/view/ItemGridView.java diff --git a/src/main/java/com/refinedmods/refinedstorage/container/CrafterManagerContainer.java b/src/main/java/com/refinedmods/refinedstorage/container/CrafterManagerContainer.java index c1d4dbe8b..364f84726 100644 --- a/src/main/java/com/refinedmods/refinedstorage/container/CrafterManagerContainer.java +++ b/src/main/java/com/refinedmods/refinedstorage/container/CrafterManagerContainer.java @@ -74,7 +74,7 @@ public class CrafterManagerContainer extends BaseContainer { int y = 19 + 18 - screenInfoProvider.getCurrentOffset() * 18; int x = 8; - List> filters = GridFilterParser.getFilters(null, screenInfoProvider.getSearchFieldText(), Collections.emptyList()); + Predicate filters = GridFilterParser.getFilters(null, screenInfoProvider.getSearchFieldText(), Collections.emptyList()); for (Map.Entry category : containerData.entrySet()) { IItemHandlerModifiable dummy; @@ -124,11 +124,9 @@ public class CrafterManagerContainer extends BaseContainer { for (ItemStack output : pattern.getOutputs()) { ItemGridStack outputConverted = new ItemGridStack(output); - for (Predicate filter : filters) { - if (filter.test(outputConverted)) { - visible = true; - break; - } + if (filters.test(outputConverted)) { + visible = true; + break; } } } diff --git a/src/main/java/com/refinedmods/refinedstorage/network/grid/GridFluidDeltaMessage.java b/src/main/java/com/refinedmods/refinedstorage/network/grid/GridFluidDeltaMessage.java index 5f04b39d7..ebc7884fd 100644 --- a/src/main/java/com/refinedmods/refinedstorage/network/grid/GridFluidDeltaMessage.java +++ b/src/main/java/com/refinedmods/refinedstorage/network/grid/GridFluidDeltaMessage.java @@ -63,8 +63,6 @@ public class GridFluidDeltaMessage { public static void handle(GridFluidDeltaMessage message, Supplier ctx) { BaseScreen.executeLater(GridScreen.class, grid -> { message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight())); - - grid.getView().sort(); }); ctx.get().setPacketHandled(true); diff --git a/src/main/java/com/refinedmods/refinedstorage/network/grid/GridFluidUpdateMessage.java b/src/main/java/com/refinedmods/refinedstorage/network/grid/GridFluidUpdateMessage.java index 2c1d7d946..a0d0e27ae 100644 --- a/src/main/java/com/refinedmods/refinedstorage/network/grid/GridFluidUpdateMessage.java +++ b/src/main/java/com/refinedmods/refinedstorage/network/grid/GridFluidUpdateMessage.java @@ -6,7 +6,7 @@ import com.refinedmods.refinedstorage.api.util.StackListEntry; import com.refinedmods.refinedstorage.screen.BaseScreen; import com.refinedmods.refinedstorage.screen.grid.GridScreen; import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; -import com.refinedmods.refinedstorage.screen.grid.view.FluidGridView; +import com.refinedmods.refinedstorage.screen.grid.view.GridViewImpl; import com.refinedmods.refinedstorage.util.StackUtils; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fluids.FluidStack; @@ -68,7 +68,7 @@ public class GridFluidUpdateMessage { public static void handle(GridFluidUpdateMessage message, Supplier ctx) { BaseScreen.executeLater(GridScreen.class, grid -> { - grid.setView(new FluidGridView(grid, GridScreen.getDefaultSorter(), GridScreen.getSorters())); + grid.setView(new GridViewImpl(grid, GridScreen.getDefaultSorter(), GridScreen.getSorters())); grid.getView().setCanCraft(message.canCraft); grid.getView().setStacks(message.stacks); grid.getView().sort(); diff --git a/src/main/java/com/refinedmods/refinedstorage/network/grid/GridItemDeltaMessage.java b/src/main/java/com/refinedmods/refinedstorage/network/grid/GridItemDeltaMessage.java index ebbfb3916..aec3358b6 100644 --- a/src/main/java/com/refinedmods/refinedstorage/network/grid/GridItemDeltaMessage.java +++ b/src/main/java/com/refinedmods/refinedstorage/network/grid/GridItemDeltaMessage.java @@ -63,8 +63,6 @@ public class GridItemDeltaMessage { public static void handle(GridItemDeltaMessage message, Supplier ctx) { BaseScreen.executeLater(GridScreen.class, grid -> { message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight())); - - grid.getView().sort(); }); ctx.get().setPacketHandled(true); diff --git a/src/main/java/com/refinedmods/refinedstorage/network/grid/GridItemUpdateMessage.java b/src/main/java/com/refinedmods/refinedstorage/network/grid/GridItemUpdateMessage.java index 727ccbefb..b0e8e8ebd 100644 --- a/src/main/java/com/refinedmods/refinedstorage/network/grid/GridItemUpdateMessage.java +++ b/src/main/java/com/refinedmods/refinedstorage/network/grid/GridItemUpdateMessage.java @@ -6,7 +6,7 @@ import com.refinedmods.refinedstorage.api.util.StackListEntry; import com.refinedmods.refinedstorage.screen.BaseScreen; import com.refinedmods.refinedstorage.screen.grid.GridScreen; import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; -import com.refinedmods.refinedstorage.screen.grid.view.ItemGridView; +import com.refinedmods.refinedstorage.screen.grid.view.GridViewImpl; import com.refinedmods.refinedstorage.util.StackUtils; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; @@ -68,7 +68,7 @@ public class GridItemUpdateMessage { public static void handle(GridItemUpdateMessage message, Supplier ctx) { BaseScreen.executeLater(GridScreen.class, grid -> { - grid.setView(new ItemGridView(grid, GridScreen.getDefaultSorter(), GridScreen.getSorters())); + grid.setView(new GridViewImpl(grid, GridScreen.getDefaultSorter(), GridScreen.getSorters())); grid.getView().setCanCraft(message.canCraft); grid.getView().setStacks(message.stacks); grid.getView().sort(); diff --git a/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridFluidDeltaMessage.java b/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridFluidDeltaMessage.java index e40cf14ba..7694592f6 100644 --- a/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridFluidDeltaMessage.java +++ b/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridFluidDeltaMessage.java @@ -57,8 +57,6 @@ public class PortableGridFluidDeltaMessage { public static void handle(PortableGridFluidDeltaMessage message, Supplier ctx) { BaseScreen.executeLater(GridScreen.class, grid -> { message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight())); - - grid.getView().sort(); }); ctx.get().setPacketHandled(true); diff --git a/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridFluidUpdateMessage.java b/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridFluidUpdateMessage.java index 6d7d12a63..4fa6331ef 100644 --- a/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridFluidUpdateMessage.java +++ b/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridFluidUpdateMessage.java @@ -4,7 +4,7 @@ import com.refinedmods.refinedstorage.api.util.StackListEntry; import com.refinedmods.refinedstorage.screen.BaseScreen; import com.refinedmods.refinedstorage.screen.grid.GridScreen; import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; -import com.refinedmods.refinedstorage.screen.grid.view.FluidGridView; +import com.refinedmods.refinedstorage.screen.grid.view.GridViewImpl; import com.refinedmods.refinedstorage.tile.grid.portable.IPortableGrid; import com.refinedmods.refinedstorage.util.StackUtils; import net.minecraft.network.PacketBuffer; @@ -52,7 +52,7 @@ public class PortableGridFluidUpdateMessage { public static void handle(PortableGridFluidUpdateMessage message, Supplier ctx) { BaseScreen.executeLater(GridScreen.class, grid -> { - grid.setView(new FluidGridView(grid, GridScreen.getDefaultSorter(), GridScreen.getSorters())); + grid.setView(new GridViewImpl(grid, GridScreen.getDefaultSorter(), GridScreen.getSorters())); grid.getView().setStacks(message.stacks); grid.getView().sort(); }); diff --git a/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridItemDeltaMessage.java b/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridItemDeltaMessage.java index 086bc500b..fe099dc99 100644 --- a/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridItemDeltaMessage.java +++ b/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridItemDeltaMessage.java @@ -59,8 +59,6 @@ public class PortableGridItemDeltaMessage { public static void handle(PortableGridItemDeltaMessage message, Supplier ctx) { BaseScreen.executeLater(GridScreen.class, grid -> { message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight())); - - grid.getView().sort(); }); ctx.get().setPacketHandled(true); diff --git a/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridItemUpdateMessage.java b/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridItemUpdateMessage.java index a570cb594..b8e079cfd 100644 --- a/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridItemUpdateMessage.java +++ b/src/main/java/com/refinedmods/refinedstorage/network/grid/PortableGridItemUpdateMessage.java @@ -4,7 +4,7 @@ import com.refinedmods.refinedstorage.api.util.StackListEntry; import com.refinedmods.refinedstorage.screen.BaseScreen; import com.refinedmods.refinedstorage.screen.grid.GridScreen; import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; -import com.refinedmods.refinedstorage.screen.grid.view.ItemGridView; +import com.refinedmods.refinedstorage.screen.grid.view.GridViewImpl; import com.refinedmods.refinedstorage.tile.grid.portable.IPortableGrid; import com.refinedmods.refinedstorage.util.StackUtils; import net.minecraft.item.ItemStack; @@ -52,7 +52,7 @@ public class PortableGridItemUpdateMessage { public static void handle(PortableGridItemUpdateMessage message, Supplier ctx) { BaseScreen.executeLater(GridScreen.class, grid -> { - grid.setView(new ItemGridView(grid, GridScreen.getDefaultSorter(), GridScreen.getSorters())); + grid.setView(new GridViewImpl(grid, GridScreen.getDefaultSorter(), GridScreen.getSorters())); grid.getView().setStacks(message.stacks); grid.getView().sort(); }); diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/GridScreen.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/GridScreen.java index fcb2152ac..0a9970d1d 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/GridScreen.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/GridScreen.java @@ -17,9 +17,8 @@ import com.refinedmods.refinedstorage.screen.IScreenInfoProvider; import com.refinedmods.refinedstorage.screen.grid.sorting.*; import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; import com.refinedmods.refinedstorage.screen.grid.stack.ItemGridStack; -import com.refinedmods.refinedstorage.screen.grid.view.FluidGridView; +import com.refinedmods.refinedstorage.screen.grid.view.GridViewImpl; import com.refinedmods.refinedstorage.screen.grid.view.IGridView; -import com.refinedmods.refinedstorage.screen.grid.view.ItemGridView; import com.refinedmods.refinedstorage.screen.widget.CheckboxWidget; import com.refinedmods.refinedstorage.screen.widget.ScrollbarWidget; import com.refinedmods.refinedstorage.screen.widget.SearchWidget; @@ -70,7 +69,7 @@ public class GridScreen extends BaseScreen implements IScreenInfo super(container, 227, 0, inventory, title); this.grid = grid; - this.view = grid.getGridType() == GridType.FLUID ? new FluidGridView(this, getDefaultSorter(), getSorters()) : new ItemGridView(this, getDefaultSorter(), getSorters()); + this.view = new GridViewImpl(this, getDefaultSorter(), getSorters()); this.wasConnected = this.grid.isGridActive(); this.tabs = new TabListWidget<>(this, new ElementDrawers<>(this), grid::getTabs, grid::getTotalTabPages, grid::getTabPage, grid::getTabSelected, IGrid.TABS_PER_PAGE); this.tabs.addListener(new TabListWidget.ITabListListener() { diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/AndGridFilter.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/AndGridFilter.java new file mode 100644 index 000000000..ed1d376ba --- /dev/null +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/AndGridFilter.java @@ -0,0 +1,35 @@ +package com.refinedmods.refinedstorage.screen.grid.filtering; + +import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; + +import java.util.List; +import java.util.function.Predicate; + +public class AndGridFilter implements Predicate { + private final List> andPartFilters; + + private AndGridFilter(List> andPartFilters) { + this.andPartFilters = andPartFilters; + } + + @Override + public boolean test(IGridStack gridStack) { + for (Predicate part : andPartFilters) { + if (!part.test(gridStack)) { + return false; + } + } + + return true; + } + + public static Predicate of(List> filters) { + if (filters.isEmpty()) { + return t -> true; + } + if (filters.size() == 1) { + return filters.get(0); + } + return new AndGridFilter(filters); + } +} diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/GridFilterParser.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/GridFilterParser.java index a69ca3f58..75153c5b9 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/GridFilterParser.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/GridFilterParser.java @@ -13,22 +13,22 @@ public final class GridFilterParser { private GridFilterParser() { } - public static List> getFilters(@Nullable IGrid grid, String query, List filters) { + public static Predicate getFilters(@Nullable IGrid grid, String query, List filters) { List> gridFilters; String[] orParts = query.split("\\|"); if (orParts.length == 1) { - gridFilters = getFilters(query); + gridFilters = getFilters(orParts[0]); } else { - List>> orPartFilters = new LinkedList<>(); + List> orPartFilters = new LinkedList<>(); for (String orPart : orParts) { - orPartFilters.add(getFilters(orPart)); + orPartFilters.add(AndGridFilter.of(getFilters(orPart))); } gridFilters = new LinkedList<>(); - gridFilters.add(new OrGridFilter(orPartFilters)); + gridFilters.add(OrGridFilter.of(orPartFilters)); } if (grid != null) { @@ -43,7 +43,7 @@ public final class GridFilterParser { gridFilters.add(new FilterGridFilter(filters)); } - return gridFilters; + return AndGridFilter.of(gridFilters); } private static List> getFilters(String query) { diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/OrGridFilter.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/OrGridFilter.java index 4439dc07e..a5a503560 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/OrGridFilter.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/filtering/OrGridFilter.java @@ -6,22 +6,30 @@ import java.util.List; import java.util.function.Predicate; public class OrGridFilter implements Predicate { - private final List>> orPartFilters; + private final List> orPartFilters; - public OrGridFilter(List>> orPartFilters) { + private OrGridFilter(List> orPartFilters) { this.orPartFilters = orPartFilters; } @Override public boolean test(IGridStack gridStack) { - for (List> orPart : orPartFilters) { - for (Predicate part : orPart) { - if (part.test(gridStack)) { - return true; - } + for (Predicate part : orPartFilters) { + if (part.test(gridStack)) { + return true; } } return false; } + + public static Predicate of(List> filters) { + if (filters.isEmpty()) { + return t -> false; + } + if (filters.size() == 1) { + return filters.get(0); + } + return new OrGridFilter(filters); + } } diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/FluidGridStack.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/FluidGridStack.java index f9c793d3f..daefc7261 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/FluidGridStack.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/FluidGridStack.java @@ -155,7 +155,16 @@ public class FluidGridStack implements IGridStack { @Override public int getQuantity() { // The isCraftable check is needed so sorting is applied correctly - return isCraftable() ? 0 : stack.getAmount(); + return isCraftable() || zeroed ? 0 : stack.getAmount(); + } + + @Override + public void setQuantity(int amount) { + if (amount <= 0) { + setZeroed(true); + } else { + stack.setAmount(amount); + } } @Override diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/IGridStack.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/IGridStack.java index aece67380..d5905e039 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/IGridStack.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/IGridStack.java @@ -30,6 +30,8 @@ public interface IGridStack { int getQuantity(); + void setQuantity(int amount); + String getFormattedFullQuantity(); void draw(MatrixStack matrixStack, BaseScreen screen, int x, int y); diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/ItemGridStack.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/ItemGridStack.java index 0ae04af58..44dd065ee 100644 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/ItemGridStack.java +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/stack/ItemGridStack.java @@ -168,7 +168,16 @@ public class ItemGridStack implements IGridStack { @Override public int getQuantity() { // The isCraftable check is needed so sorting is applied correctly - return isCraftable() ? 0 : stack.getCount(); + return isCraftable() || zeroed ? 0 : stack.getCount(); + } + + @Override + public void setQuantity(int amount) { + if (amount <= 0) { + setZeroed(true); + } else { + stack.setCount(amount); + } } @Override diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/BaseGridView.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/BaseGridView.java deleted file mode 100644 index de76f31de..000000000 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/BaseGridView.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.refinedmods.refinedstorage.screen.grid.view; - -import com.refinedmods.refinedstorage.api.network.grid.IGrid; -import com.refinedmods.refinedstorage.screen.grid.GridScreen; -import com.refinedmods.refinedstorage.screen.grid.filtering.GridFilterParser; -import com.refinedmods.refinedstorage.screen.grid.sorting.IGridSorter; -import com.refinedmods.refinedstorage.screen.grid.sorting.SortingDirection; -import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; - -import javax.annotation.Nullable; -import java.util.*; -import java.util.function.Predicate; - -public abstract class BaseGridView implements IGridView { - private final GridScreen screen; - private boolean canCraft; - - private final IGridSorter defaultSorter; - private final List sorters; - - private List stacks = new ArrayList<>(); - protected final Map map = new HashMap<>(); - - protected BaseGridView(GridScreen screen, IGridSorter defaultSorter, List sorters) { - this.screen = screen; - this.defaultSorter = defaultSorter; - this.sorters = sorters; - } - - @Override - public List getStacks() { - return stacks; - } - - @Override - public Collection getAllStacks() { - return map.values(); - } - - @Nullable - @Override - public IGridStack get(UUID id) { - return map.get(id); - } - - @Override - public void sort() { - if (!screen.canSort()) { - return; - } - - List newStacks = new ArrayList<>(); - - if (screen.getGrid().isGridActive()) { - newStacks.addAll(map.values()); - - IGrid grid = screen.getGrid(); - - List> filters = GridFilterParser.getFilters( - grid, - screen.getSearchFieldText(), - (grid.getTabSelected() >= 0 && grid.getTabSelected() < grid.getTabs().size()) ? grid.getTabs().get(grid.getTabSelected()).getFilters() : grid.getFilters() - ); - - newStacks.removeIf(stack -> { - // If this is a crafting stack, - // and there is a regular matching stack in the view too, - // and we aren't in "view only craftables" mode, - // we don't want the duplicate stacks and we will remove this stack. - if (screen.getGrid().getViewType() != IGrid.VIEW_TYPE_CRAFTABLES && - stack.isCraftable() && - stack.getOtherId() != null && - map.containsKey(stack.getOtherId())) { - return true; - } - - for (Predicate filter : filters) { - if (!filter.test(stack)) { - return true; - } - } - - return false; - }); - - SortingDirection sortingDirection = grid.getSortingDirection() == IGrid.SORTING_DIRECTION_DESCENDING ? SortingDirection.DESCENDING : SortingDirection.ASCENDING; - - newStacks.sort((left, right) -> defaultSorter.compare(left, right, sortingDirection)); - - for (IGridSorter sorter : sorters) { - if (sorter.isApplicable(grid)) { - newStacks.sort((left, right) -> sorter.compare(left, right, sortingDirection)); - } - } - } - - this.stacks = newStacks; - - this.screen.updateScrollbar(); - } - - @Override - public void setCanCraft(boolean canCraft) { - this.canCraft = canCraft; - } - - @Override - public boolean canCraft() { - return canCraft; - } -} diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/FluidGridView.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/FluidGridView.java deleted file mode 100644 index 17aa6538c..000000000 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/FluidGridView.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.refinedmods.refinedstorage.screen.grid.view; - -import com.refinedmods.refinedstorage.screen.grid.GridScreen; -import com.refinedmods.refinedstorage.screen.grid.sorting.IGridSorter; -import com.refinedmods.refinedstorage.screen.grid.stack.FluidGridStack; -import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; - -import java.util.List; - -public class FluidGridView extends BaseGridView { - public FluidGridView(GridScreen screen, IGridSorter defaultSorter, List sorters) { - super(screen, defaultSorter, sorters); - } - - @Override - public void setStacks(List stacks) { - map.clear(); - - for (IGridStack stack : stacks) { - map.put(stack.getId(), stack); - } - } - - @Override - public void postChange(IGridStack stack, int delta) { - if (!(stack instanceof FluidGridStack)) { - return; - } - - // COMMENT 1 (about this if check in general) - // Update the other id reference if needed. - // Taking a stack out - and then re-inserting it - gives the new stack a new ID - // With that new id, the reference for the crafting stack would be outdated. - - // COMMENT 2 (about map.containsKey(stack.getOtherId())) - // This check is needed or the .updateOtherId() call will crash with a NPE in high-update environments. - // This is because we might have scenarios where we process "old" delta packets from another session when we haven't received any initial update packet from the new session. - // (This is because of the executeLater system) - // This causes the .updateOtherId() to fail with a NPE because the map is still empty or the IDs mismatch. - // We could use !map.isEmpty() here too. But if we have 2 "old" delta packets, it would rightfully ignore the first one. But this method mutates the map and would put an entry. - // This means that on the second delta packet it would still crash because the map wouldn't be empty anymore. - if (!stack.isCraftable() && - stack.getOtherId() != null && - map.containsKey(stack.getOtherId())) { - IGridStack craftingStack = map.get(stack.getOtherId()); - - craftingStack.updateOtherId(stack.getId()); - craftingStack.setTrackerEntry(stack.getTrackerEntry()); - } - - FluidGridStack existing = (FluidGridStack) map.get(stack.getId()); - - if (existing == null) { - ((FluidGridStack) stack).getStack().setAmount(delta); - - map.put(stack.getId(), stack); - } else { - if (existing.getStack().getAmount() + delta <= 0) { - existing.setZeroed(true); - - map.remove(existing.getId()); - } else { - existing.getStack().grow(delta); - } - - existing.setTrackerEntry(stack.getTrackerEntry()); - } - } -} diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/GridViewImpl.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/GridViewImpl.java new file mode 100644 index 000000000..1e84ef6c8 --- /dev/null +++ b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/GridViewImpl.java @@ -0,0 +1,193 @@ +package com.refinedmods.refinedstorage.screen.grid.view; + +import com.refinedmods.refinedstorage.api.network.grid.IGrid; +import com.refinedmods.refinedstorage.screen.grid.GridScreen; +import com.refinedmods.refinedstorage.screen.grid.filtering.GridFilterParser; +import com.refinedmods.refinedstorage.screen.grid.sorting.IGridSorter; +import com.refinedmods.refinedstorage.screen.grid.sorting.SortingDirection; +import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class GridViewImpl implements IGridView { + private final GridScreen screen; + private boolean canCraft; + + private final IGridSorter defaultSorter; + private final List sorters; + + private List stacks = new ArrayList<>(); + protected final Map map = new HashMap<>(); + + public GridViewImpl(GridScreen screen, IGridSorter defaultSorter, List sorters) { + this.screen = screen; + this.defaultSorter = defaultSorter; + this.sorters = sorters; + } + + @Override + public List getStacks() { + return stacks; + } + + @Override + public Collection getAllStacks() { + return map.values(); + } + + @Nullable + @Override + public IGridStack get(UUID id) { + return map.get(id); + } + + @Override + public void sort() { + if (!screen.canSort()) { + return; + } + + if (screen.getGrid().isGridActive()) { + this.stacks = map.values().stream() + .filter(getActiveFilters()) + .sorted(getActiveSort()) + .collect(Collectors.toList()); + } else { + this.stacks = Collections.emptyList(); + } + + this.screen.updateScrollbar(); + } + + private Comparator getActiveSort() { + IGrid grid = screen.getGrid(); + SortingDirection sortingDirection = grid.getSortingDirection() == IGrid.SORTING_DIRECTION_DESCENDING ? SortingDirection.DESCENDING : SortingDirection.ASCENDING; + return Stream.concat(Stream.of(defaultSorter), sorters.stream().filter(s -> s.isApplicable(grid))) + .map(sorter -> (Comparator) (o1, o2) -> sorter.compare(o1, o2, sortingDirection)) + .reduce((l, r) -> r.thenComparing(l)) + .orElseThrow(IllegalStateException::new); // There is at least 1 value in the stream (i.e. defaultSorter) + } + + private Predicate getActiveFilters() { + IGrid grid = screen.getGrid(); + + Predicate filters = GridFilterParser.getFilters( + grid, + screen.getSearchFieldText(), + (grid.getTabSelected() >= 0 && grid.getTabSelected() < grid.getTabs().size()) ? grid.getTabs().get(grid.getTabSelected()).getFilters() : grid.getFilters() + ); + + if (screen.getGrid().getViewType() != IGrid.VIEW_TYPE_CRAFTABLES) { + return stack -> { + // If this is a crafting stack, + // and there is a regular matching stack in the view too, + // and we aren't in "view only craftables" mode, + // we don't want the duplicate stacks and we will remove this stack. + if (stack.isCraftable() && + stack.getOtherId() != null && + map.containsKey(stack.getOtherId())) { + return false; + } + + return filters.test(stack); + }; + } else { + return filters; + } + } + + @Override + public void setStacks(List stacks) { + map.clear(); + + for (IGridStack stack : stacks) { + map.put(stack.getId(), stack); + } + } + + @Override + public void postChange(IGridStack stack, int delta) { + // COMMENT 1 (about this if check in general) + // Update the other id reference if needed. + // Taking a stack out - and then re-inserting it - gives the new stack a new ID + // With that new id, the reference for the crafting stack would be outdated. + + // COMMENT 2 (about map.containsKey(stack.getOtherId())) + // This check is needed or the .updateOtherId() call will crash with a NPE in high-update environments. + // This is because we might have scenarios where we process "old" delta packets from another session when we haven't received any initial update packet from the new session. + // (This is because of the executeLater system) + // This causes the .updateOtherId() to fail with a NPE because the map is still empty or the IDs mismatch. + // We could use !map.isEmpty() here too. But if we have 2 "old" delta packets, it would rightfully ignore the first one. But this method mutates the map and would put an entry. + // This means that on the second delta packet it would still crash because the map wouldn't be empty anymore. + IGridStack craftingStack; + if (!stack.isCraftable() && + stack.getOtherId() != null && + map.containsKey(stack.getOtherId())) { + craftingStack = map.get(stack.getOtherId()); + + craftingStack.updateOtherId(stack.getId()); + craftingStack.setTrackerEntry(stack.getTrackerEntry()); + } else { + craftingStack = null; + } + + IGridStack existing = map.get(stack.getId()); + boolean stillExists = true; + boolean shouldSort = screen.canSort(); + + if (existing == null) { + stack.setQuantity(delta); + + map.put(stack.getId(), stack); + existing = stack; + + if (craftingStack != null && shouldSort) { + stacks.remove(craftingStack); + } + } else { + if (shouldSort) { + stacks.remove(existing); + } + existing.setQuantity(existing.getQuantity() + delta); + if (existing.getQuantity() <= 0) { + map.remove(existing.getId()); + stillExists = false; + + if (craftingStack != null && shouldSort && getActiveFilters().test(craftingStack)) { + addStack(craftingStack); + } + } + + existing.setTrackerEntry(stack.getTrackerEntry()); + } + + if (shouldSort) { + if (stillExists && getActiveFilters().test(existing)) { + addStack(existing); + } + this.screen.updateScrollbar(); + } + } + + private void addStack(IGridStack stack) { + int insertionPos = Collections.binarySearch(stacks, stack, getActiveSort()); + if (insertionPos < 0) { + insertionPos = -insertionPos - 1; + } + stacks.add(insertionPos, stack); + } + + @Override + public void setCanCraft(boolean canCraft) { + this.canCraft = canCraft; + } + + @Override + public boolean canCraft() { + return canCraft; + } +} diff --git a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/ItemGridView.java b/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/ItemGridView.java deleted file mode 100644 index 3764a8761..000000000 --- a/src/main/java/com/refinedmods/refinedstorage/screen/grid/view/ItemGridView.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.refinedmods.refinedstorage.screen.grid.view; - -import com.refinedmods.refinedstorage.screen.grid.GridScreen; -import com.refinedmods.refinedstorage.screen.grid.sorting.IGridSorter; -import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack; -import com.refinedmods.refinedstorage.screen.grid.stack.ItemGridStack; - -import java.util.List; - -public class ItemGridView extends BaseGridView { - public ItemGridView(GridScreen screen, IGridSorter defaultSorter, List sorters) { - super(screen, defaultSorter, sorters); - } - - @Override - public void setStacks(List stacks) { - map.clear(); - - for (IGridStack stack : stacks) { - map.put(stack.getId(), stack); - } - } - - @Override - public void postChange(IGridStack stack, int delta) { - if (!(stack instanceof ItemGridStack)) { - return; - } - - // COMMENT 1 (about this if check in general) - // Update the other id reference if needed. - // Taking a stack out - and then re-inserting it - gives the new stack a new ID - // With that new id, the reference for the crafting stack would be outdated. - - // COMMENT 2 (about map.containsKey(stack.getOtherId())) - // This check is needed or the .updateOtherId() call will crash with a NPE in high-update environments. - // This is because we might have scenarios where we process "old" delta packets from another session when we haven't received any initial update packet from the new session. - // (This is because of the executeLater system) - // This causes the .updateOtherId() to fail with a NPE because the map is still empty or the IDs mismatch. - // We could use !map.isEmpty() here too. But if we have 2 "old" delta packets, it would rightfully ignore the first one. But this method mutates the map and would put an entry. - // This means that on the second delta packet it would still crash because the map wouldn't be empty anymore. - if (!stack.isCraftable() && - stack.getOtherId() != null && - map.containsKey(stack.getOtherId())) { - IGridStack craftingStack = map.get(stack.getOtherId()); - - craftingStack.updateOtherId(stack.getId()); - craftingStack.setTrackerEntry(stack.getTrackerEntry()); - } - - ItemGridStack existing = (ItemGridStack) map.get(stack.getId()); - - if (existing == null) { - ((ItemGridStack) stack).getStack().setCount(delta); - - map.put(stack.getId(), stack); - } else { - if (existing.getStack().getCount() + delta <= 0) { - existing.setZeroed(true); - - map.remove(existing.getId()); - } else { - existing.getStack().grow(delta); - } - - existing.setTrackerEntry(stack.getTrackerEntry()); - } - } -}