[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
This commit is contained in:
@@ -74,7 +74,7 @@ public class CrafterManagerContainer extends BaseContainer {
|
|||||||
int y = 19 + 18 - screenInfoProvider.getCurrentOffset() * 18;
|
int y = 19 + 18 - screenInfoProvider.getCurrentOffset() * 18;
|
||||||
int x = 8;
|
int x = 8;
|
||||||
|
|
||||||
List<Predicate<IGridStack>> filters = GridFilterParser.getFilters(null, screenInfoProvider.getSearchFieldText(), Collections.emptyList());
|
Predicate<IGridStack> filters = GridFilterParser.getFilters(null, screenInfoProvider.getSearchFieldText(), Collections.emptyList());
|
||||||
|
|
||||||
for (Map.Entry<String, Integer> category : containerData.entrySet()) {
|
for (Map.Entry<String, Integer> category : containerData.entrySet()) {
|
||||||
IItemHandlerModifiable dummy;
|
IItemHandlerModifiable dummy;
|
||||||
@@ -124,11 +124,9 @@ public class CrafterManagerContainer extends BaseContainer {
|
|||||||
for (ItemStack output : pattern.getOutputs()) {
|
for (ItemStack output : pattern.getOutputs()) {
|
||||||
ItemGridStack outputConverted = new ItemGridStack(output);
|
ItemGridStack outputConverted = new ItemGridStack(output);
|
||||||
|
|
||||||
for (Predicate<IGridStack> filter : filters) {
|
if (filters.test(outputConverted)) {
|
||||||
if (filter.test(outputConverted)) {
|
visible = true;
|
||||||
visible = true;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ public class GridFluidDeltaMessage {
|
|||||||
public static void handle(GridFluidDeltaMessage message, Supplier<NetworkEvent.Context> ctx) {
|
public static void handle(GridFluidDeltaMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
BaseScreen.executeLater(GridScreen.class, grid -> {
|
BaseScreen.executeLater(GridScreen.class, grid -> {
|
||||||
message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight()));
|
message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight()));
|
||||||
|
|
||||||
grid.getView().sort();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.get().setPacketHandled(true);
|
ctx.get().setPacketHandled(true);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import com.refinedmods.refinedstorage.api.util.StackListEntry;
|
|||||||
import com.refinedmods.refinedstorage.screen.BaseScreen;
|
import com.refinedmods.refinedstorage.screen.BaseScreen;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.GridScreen;
|
import com.refinedmods.refinedstorage.screen.grid.GridScreen;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack;
|
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 com.refinedmods.refinedstorage.util.StackUtils;
|
||||||
import net.minecraft.network.PacketBuffer;
|
import net.minecraft.network.PacketBuffer;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
@@ -68,7 +68,7 @@ public class GridFluidUpdateMessage {
|
|||||||
|
|
||||||
public static void handle(GridFluidUpdateMessage message, Supplier<NetworkEvent.Context> ctx) {
|
public static void handle(GridFluidUpdateMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
BaseScreen.executeLater(GridScreen.class, grid -> {
|
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().setCanCraft(message.canCraft);
|
||||||
grid.getView().setStacks(message.stacks);
|
grid.getView().setStacks(message.stacks);
|
||||||
grid.getView().sort();
|
grid.getView().sort();
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ public class GridItemDeltaMessage {
|
|||||||
public static void handle(GridItemDeltaMessage message, Supplier<NetworkEvent.Context> ctx) {
|
public static void handle(GridItemDeltaMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
BaseScreen.executeLater(GridScreen.class, grid -> {
|
BaseScreen.executeLater(GridScreen.class, grid -> {
|
||||||
message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight()));
|
message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight()));
|
||||||
|
|
||||||
grid.getView().sort();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.get().setPacketHandled(true);
|
ctx.get().setPacketHandled(true);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import com.refinedmods.refinedstorage.api.util.StackListEntry;
|
|||||||
import com.refinedmods.refinedstorage.screen.BaseScreen;
|
import com.refinedmods.refinedstorage.screen.BaseScreen;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.GridScreen;
|
import com.refinedmods.refinedstorage.screen.grid.GridScreen;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack;
|
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 com.refinedmods.refinedstorage.util.StackUtils;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.network.PacketBuffer;
|
import net.minecraft.network.PacketBuffer;
|
||||||
@@ -68,7 +68,7 @@ public class GridItemUpdateMessage {
|
|||||||
|
|
||||||
public static void handle(GridItemUpdateMessage message, Supplier<NetworkEvent.Context> ctx) {
|
public static void handle(GridItemUpdateMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
BaseScreen.executeLater(GridScreen.class, grid -> {
|
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().setCanCraft(message.canCraft);
|
||||||
grid.getView().setStacks(message.stacks);
|
grid.getView().setStacks(message.stacks);
|
||||||
grid.getView().sort();
|
grid.getView().sort();
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ public class PortableGridFluidDeltaMessage {
|
|||||||
public static void handle(PortableGridFluidDeltaMessage message, Supplier<NetworkEvent.Context> ctx) {
|
public static void handle(PortableGridFluidDeltaMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
BaseScreen.executeLater(GridScreen.class, grid -> {
|
BaseScreen.executeLater(GridScreen.class, grid -> {
|
||||||
message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight()));
|
message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight()));
|
||||||
|
|
||||||
grid.getView().sort();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.get().setPacketHandled(true);
|
ctx.get().setPacketHandled(true);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.refinedmods.refinedstorage.api.util.StackListEntry;
|
|||||||
import com.refinedmods.refinedstorage.screen.BaseScreen;
|
import com.refinedmods.refinedstorage.screen.BaseScreen;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.GridScreen;
|
import com.refinedmods.refinedstorage.screen.grid.GridScreen;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack;
|
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.tile.grid.portable.IPortableGrid;
|
||||||
import com.refinedmods.refinedstorage.util.StackUtils;
|
import com.refinedmods.refinedstorage.util.StackUtils;
|
||||||
import net.minecraft.network.PacketBuffer;
|
import net.minecraft.network.PacketBuffer;
|
||||||
@@ -52,7 +52,7 @@ public class PortableGridFluidUpdateMessage {
|
|||||||
|
|
||||||
public static void handle(PortableGridFluidUpdateMessage message, Supplier<NetworkEvent.Context> ctx) {
|
public static void handle(PortableGridFluidUpdateMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
BaseScreen.executeLater(GridScreen.class, grid -> {
|
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().setStacks(message.stacks);
|
||||||
grid.getView().sort();
|
grid.getView().sort();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -59,8 +59,6 @@ public class PortableGridItemDeltaMessage {
|
|||||||
public static void handle(PortableGridItemDeltaMessage message, Supplier<NetworkEvent.Context> ctx) {
|
public static void handle(PortableGridItemDeltaMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
BaseScreen.executeLater(GridScreen.class, grid -> {
|
BaseScreen.executeLater(GridScreen.class, grid -> {
|
||||||
message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight()));
|
message.clientDeltas.forEach(p -> grid.getView().postChange(p.getLeft(), p.getRight()));
|
||||||
|
|
||||||
grid.getView().sort();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.get().setPacketHandled(true);
|
ctx.get().setPacketHandled(true);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.refinedmods.refinedstorage.api.util.StackListEntry;
|
|||||||
import com.refinedmods.refinedstorage.screen.BaseScreen;
|
import com.refinedmods.refinedstorage.screen.BaseScreen;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.GridScreen;
|
import com.refinedmods.refinedstorage.screen.grid.GridScreen;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack;
|
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.tile.grid.portable.IPortableGrid;
|
||||||
import com.refinedmods.refinedstorage.util.StackUtils;
|
import com.refinedmods.refinedstorage.util.StackUtils;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@@ -52,7 +52,7 @@ public class PortableGridItemUpdateMessage {
|
|||||||
|
|
||||||
public static void handle(PortableGridItemUpdateMessage message, Supplier<NetworkEvent.Context> ctx) {
|
public static void handle(PortableGridItemUpdateMessage message, Supplier<NetworkEvent.Context> ctx) {
|
||||||
BaseScreen.executeLater(GridScreen.class, grid -> {
|
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().setStacks(message.stacks);
|
||||||
grid.getView().sort();
|
grid.getView().sort();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,9 +17,8 @@ import com.refinedmods.refinedstorage.screen.IScreenInfoProvider;
|
|||||||
import com.refinedmods.refinedstorage.screen.grid.sorting.*;
|
import com.refinedmods.refinedstorage.screen.grid.sorting.*;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack;
|
import com.refinedmods.refinedstorage.screen.grid.stack.IGridStack;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.stack.ItemGridStack;
|
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.IGridView;
|
||||||
import com.refinedmods.refinedstorage.screen.grid.view.ItemGridView;
|
|
||||||
import com.refinedmods.refinedstorage.screen.widget.CheckboxWidget;
|
import com.refinedmods.refinedstorage.screen.widget.CheckboxWidget;
|
||||||
import com.refinedmods.refinedstorage.screen.widget.ScrollbarWidget;
|
import com.refinedmods.refinedstorage.screen.widget.ScrollbarWidget;
|
||||||
import com.refinedmods.refinedstorage.screen.widget.SearchWidget;
|
import com.refinedmods.refinedstorage.screen.widget.SearchWidget;
|
||||||
@@ -70,7 +69,7 @@ public class GridScreen extends BaseScreen<GridContainer> implements IScreenInfo
|
|||||||
super(container, 227, 0, inventory, title);
|
super(container, 227, 0, inventory, title);
|
||||||
|
|
||||||
this.grid = grid;
|
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.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 = new TabListWidget<>(this, new ElementDrawers<>(this), grid::getTabs, grid::getTotalTabPages, grid::getTabPage, grid::getTabSelected, IGrid.TABS_PER_PAGE);
|
||||||
this.tabs.addListener(new TabListWidget.ITabListListener() {
|
this.tabs.addListener(new TabListWidget.ITabListListener() {
|
||||||
|
|||||||
@@ -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<IGridStack> {
|
||||||
|
private final List<Predicate<IGridStack>> andPartFilters;
|
||||||
|
|
||||||
|
private AndGridFilter(List<Predicate<IGridStack>> andPartFilters) {
|
||||||
|
this.andPartFilters = andPartFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(IGridStack gridStack) {
|
||||||
|
for (Predicate<IGridStack> part : andPartFilters) {
|
||||||
|
if (!part.test(gridStack)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Predicate<IGridStack> of(List<Predicate<IGridStack>> filters) {
|
||||||
|
if (filters.isEmpty()) {
|
||||||
|
return t -> true;
|
||||||
|
}
|
||||||
|
if (filters.size() == 1) {
|
||||||
|
return filters.get(0);
|
||||||
|
}
|
||||||
|
return new AndGridFilter(filters);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,22 +13,22 @@ public final class GridFilterParser {
|
|||||||
private GridFilterParser() {
|
private GridFilterParser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Predicate<IGridStack>> getFilters(@Nullable IGrid grid, String query, List<IFilter> filters) {
|
public static Predicate<IGridStack> getFilters(@Nullable IGrid grid, String query, List<IFilter> filters) {
|
||||||
List<Predicate<IGridStack>> gridFilters;
|
List<Predicate<IGridStack>> gridFilters;
|
||||||
|
|
||||||
String[] orParts = query.split("\\|");
|
String[] orParts = query.split("\\|");
|
||||||
|
|
||||||
if (orParts.length == 1) {
|
if (orParts.length == 1) {
|
||||||
gridFilters = getFilters(query);
|
gridFilters = getFilters(orParts[0]);
|
||||||
} else {
|
} else {
|
||||||
List<List<Predicate<IGridStack>>> orPartFilters = new LinkedList<>();
|
List<Predicate<IGridStack>> orPartFilters = new LinkedList<>();
|
||||||
|
|
||||||
for (String orPart : orParts) {
|
for (String orPart : orParts) {
|
||||||
orPartFilters.add(getFilters(orPart));
|
orPartFilters.add(AndGridFilter.of(getFilters(orPart)));
|
||||||
}
|
}
|
||||||
|
|
||||||
gridFilters = new LinkedList<>();
|
gridFilters = new LinkedList<>();
|
||||||
gridFilters.add(new OrGridFilter(orPartFilters));
|
gridFilters.add(OrGridFilter.of(orPartFilters));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grid != null) {
|
if (grid != null) {
|
||||||
@@ -43,7 +43,7 @@ public final class GridFilterParser {
|
|||||||
gridFilters.add(new FilterGridFilter(filters));
|
gridFilters.add(new FilterGridFilter(filters));
|
||||||
}
|
}
|
||||||
|
|
||||||
return gridFilters;
|
return AndGridFilter.of(gridFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Predicate<IGridStack>> getFilters(String query) {
|
private static List<Predicate<IGridStack>> getFilters(String query) {
|
||||||
|
|||||||
@@ -6,22 +6,30 @@ import java.util.List;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class OrGridFilter implements Predicate<IGridStack> {
|
public class OrGridFilter implements Predicate<IGridStack> {
|
||||||
private final List<List<Predicate<IGridStack>>> orPartFilters;
|
private final List<Predicate<IGridStack>> orPartFilters;
|
||||||
|
|
||||||
public OrGridFilter(List<List<Predicate<IGridStack>>> orPartFilters) {
|
private OrGridFilter(List<Predicate<IGridStack>> orPartFilters) {
|
||||||
this.orPartFilters = orPartFilters;
|
this.orPartFilters = orPartFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean test(IGridStack gridStack) {
|
public boolean test(IGridStack gridStack) {
|
||||||
for (List<Predicate<IGridStack>> orPart : orPartFilters) {
|
for (Predicate<IGridStack> part : orPartFilters) {
|
||||||
for (Predicate<IGridStack> part : orPart) {
|
if (part.test(gridStack)) {
|
||||||
if (part.test(gridStack)) {
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Predicate<IGridStack> of(List<Predicate<IGridStack>> filters) {
|
||||||
|
if (filters.isEmpty()) {
|
||||||
|
return t -> false;
|
||||||
|
}
|
||||||
|
if (filters.size() == 1) {
|
||||||
|
return filters.get(0);
|
||||||
|
}
|
||||||
|
return new OrGridFilter(filters);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,16 @@ public class FluidGridStack implements IGridStack {
|
|||||||
@Override
|
@Override
|
||||||
public int getQuantity() {
|
public int getQuantity() {
|
||||||
// The isCraftable check is needed so sorting is applied correctly
|
// 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
|
@Override
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ public interface IGridStack {
|
|||||||
|
|
||||||
int getQuantity();
|
int getQuantity();
|
||||||
|
|
||||||
|
void setQuantity(int amount);
|
||||||
|
|
||||||
String getFormattedFullQuantity();
|
String getFormattedFullQuantity();
|
||||||
|
|
||||||
void draw(MatrixStack matrixStack, BaseScreen<?> screen, int x, int y);
|
void draw(MatrixStack matrixStack, BaseScreen<?> screen, int x, int y);
|
||||||
|
|||||||
@@ -168,7 +168,16 @@ public class ItemGridStack implements IGridStack {
|
|||||||
@Override
|
@Override
|
||||||
public int getQuantity() {
|
public int getQuantity() {
|
||||||
// The isCraftable check is needed so sorting is applied correctly
|
// 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
|
@Override
|
||||||
|
|||||||
@@ -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<IGridSorter> sorters;
|
|
||||||
|
|
||||||
private List<IGridStack> stacks = new ArrayList<>();
|
|
||||||
protected final Map<UUID, IGridStack> map = new HashMap<>();
|
|
||||||
|
|
||||||
protected BaseGridView(GridScreen screen, IGridSorter defaultSorter, List<IGridSorter> sorters) {
|
|
||||||
this.screen = screen;
|
|
||||||
this.defaultSorter = defaultSorter;
|
|
||||||
this.sorters = sorters;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<IGridStack> getStacks() {
|
|
||||||
return stacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<IGridStack> getAllStacks() {
|
|
||||||
return map.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public IGridStack get(UUID id) {
|
|
||||||
return map.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sort() {
|
|
||||||
if (!screen.canSort()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IGridStack> newStacks = new ArrayList<>();
|
|
||||||
|
|
||||||
if (screen.getGrid().isGridActive()) {
|
|
||||||
newStacks.addAll(map.values());
|
|
||||||
|
|
||||||
IGrid grid = screen.getGrid();
|
|
||||||
|
|
||||||
List<Predicate<IGridStack>> 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<IGridStack> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<IGridSorter> sorters) {
|
|
||||||
super(screen, defaultSorter, sorters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setStacks(List<IGridStack> 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<IGridSorter> sorters;
|
||||||
|
|
||||||
|
private List<IGridStack> stacks = new ArrayList<>();
|
||||||
|
protected final Map<UUID, IGridStack> map = new HashMap<>();
|
||||||
|
|
||||||
|
public GridViewImpl(GridScreen screen, IGridSorter defaultSorter, List<IGridSorter> sorters) {
|
||||||
|
this.screen = screen;
|
||||||
|
this.defaultSorter = defaultSorter;
|
||||||
|
this.sorters = sorters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IGridStack> getStacks() {
|
||||||
|
return stacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IGridStack> 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<IGridStack> 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<IGridStack>) (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<IGridStack> getActiveFilters() {
|
||||||
|
IGrid grid = screen.getGrid();
|
||||||
|
|
||||||
|
Predicate<IGridStack> 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<IGridStack> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<IGridSorter> sorters) {
|
|
||||||
super(screen, defaultSorter, sorters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setStacks(List<IGridStack> 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user