From 3ca002990dcb9618925cdbacdd66ed572e94a58b Mon Sep 17 00:00:00 2001 From: emilyploszaj Date: Sat, 23 Sep 2023 18:35:18 -0500 Subject: [PATCH] Synfav slot highlighting and various fixes --- CHANGELOG.md | 14 ++-- .../src/main/java/dev/emi/emi/api/EmiApi.java | 1 + .../dev/emi/emi/api/widget/SlotWidget.java | 5 ++ .../java/dev/emi/emi/config/EmiConfig.java | 4 ++ .../dev/emi/emi/mixin/HandledScreenMixin.java | 18 ----- .../emi/emi/registry/EmiExclusionAreas.java | 19 ++++-- .../dev/emi/emi/runtime/EmiFavorites.java | 6 +- .../java/dev/emi/emi/runtime/EmiHistory.java | 29 ++++++-- .../dev/emi/emi/screen/EmiScreenManager.java | 66 ++++++++++++++++++- .../main/resources/assets/emi/lang/en_us.json | 1 + 10 files changed, 122 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90b99baf..2142034e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,11 @@ -### Tweaks -* Made JEMI recipes without icons default to the first workstation, if present +### Additions +* Synfavs will now highlight missing items in inventories like chests, for quickly finding them +* Added a forward bind for navigating history ### Fixes -* Fixed crafting grid misplacement in misbehaving indexed storage mods #273 #280 -* Fixed cheat mode excessive logging #286 -* Fixed display of certain JEMI recipes that mutate at runtime #304 \ No newline at end of file +* Fixed getting disconnected when attempting to cheat in large nbt on vanilla servers #221 +* Fixed inventory overlay not working on screens that reimplement rendering #276 +* Fixed history navigation not working properly with non-handled screens #312 +* Fixed setting recipe defaults outside of recipe tree context #315 +* Fixed endless loop and div by zero caused by absurd abyss exclusion areas #300 +* Fixed #268 \ No newline at end of file diff --git a/xplat/src/main/java/dev/emi/emi/api/EmiApi.java b/xplat/src/main/java/dev/emi/emi/api/EmiApi.java index 92f6dbc2..cd88b30f 100644 --- a/xplat/src/main/java/dev/emi/emi/api/EmiApi.java +++ b/xplat/src/main/java/dev/emi/emi/api/EmiApi.java @@ -182,6 +182,7 @@ private static void push() { EmiHistory.push(bs); } else { EmiHistory.clear(); + EmiHistory.push(client.currentScreen); } } diff --git a/xplat/src/main/java/dev/emi/emi/api/widget/SlotWidget.java b/xplat/src/main/java/dev/emi/emi/api/widget/SlotWidget.java index 47118e44..66277136 100644 --- a/xplat/src/main/java/dev/emi/emi/api/widget/SlotWidget.java +++ b/xplat/src/main/java/dev/emi/emi/api/widget/SlotWidget.java @@ -288,6 +288,11 @@ private boolean slotInteraction(Function function) { EmiHistory.pop(); return true; } + } else { + if (function.apply(EmiConfig.defaultStack)) { + BoM.addRecipe(getStack(), getRecipe()); + return true; + } } return false; } diff --git a/xplat/src/main/java/dev/emi/emi/config/EmiConfig.java b/xplat/src/main/java/dev/emi/emi/config/EmiConfig.java index e0f57bd4..cc972364 100644 --- a/xplat/src/main/java/dev/emi/emi/config/EmiConfig.java +++ b/xplat/src/main/java/dev/emi/emi/config/EmiConfig.java @@ -375,6 +375,10 @@ public class EmiConfig { @ConfigValue("binds.back") public static EmiBind back = new EmiBind("key.emi.back", GLFW.GLFW_KEY_BACKSPACE); + @Comment("Return to the next page in EMI after going back.") + @ConfigValue("binds.forward") + public static EmiBind forward = new EmiBind("key.emi.forward", InputUtil.UNKNOWN_KEY.getCode()); + @ConfigGroup("binds.crafts") @Comment("When on a stack with an associated recipe:\n" + "Move ingredients for a single result.") diff --git a/xplat/src/main/java/dev/emi/emi/mixin/HandledScreenMixin.java b/xplat/src/main/java/dev/emi/emi/mixin/HandledScreenMixin.java index 0bdaee00..9abf3723 100644 --- a/xplat/src/main/java/dev/emi/emi/mixin/HandledScreenMixin.java +++ b/xplat/src/main/java/dev/emi/emi/mixin/HandledScreenMixin.java @@ -10,19 +10,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import dev.emi.emi.EmiPort; -import dev.emi.emi.api.stack.EmiStack; import dev.emi.emi.platform.EmiAgnos; import dev.emi.emi.runtime.EmiDrawContext; import dev.emi.emi.screen.EmiScreen; import dev.emi.emi.screen.EmiScreenManager; -import dev.emi.emi.search.EmiSearch; -import dev.emi.emi.search.EmiSearch.CompiledQuery; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.recipebook.RecipeBookProvider; import net.minecraft.client.util.Window; -import net.minecraft.screen.slot.Slot; @Mixin(HandledScreen.class) public abstract class HandledScreenMixin extends Screen implements EmiScreen { @@ -63,20 +59,6 @@ private void renderForeground(DrawContext raw, int mouseX, int mouseY, float del context.pop(); } - @Inject(at = @At("TAIL"), method = "drawSlot") - private void drawSlot(DrawContext raw, Slot slot, CallbackInfo info) { - EmiDrawContext context = EmiDrawContext.wrap(raw); - if (EmiScreenManager.search.highlight) { - CompiledQuery query = EmiSearch.compiledQuery; - if (query != null && !query.test(EmiStack.of(slot.getStack()))) { - context.push(); - context.matrices().translate(0, 0, 300); - context.fill(slot.x - 1, slot.y - 1, 18, 18, 0x77000000); - context.pop(); - } - } - } - @Override public int emi$getLeft() { if (this instanceof RecipeBookProvider provider) { diff --git a/xplat/src/main/java/dev/emi/emi/registry/EmiExclusionAreas.java b/xplat/src/main/java/dev/emi/emi/registry/EmiExclusionAreas.java index 2b3d14f2..8059e4b3 100644 --- a/xplat/src/main/java/dev/emi/emi/registry/EmiExclusionAreas.java +++ b/xplat/src/main/java/dev/emi/emi/registry/EmiExclusionAreas.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Map; +import java.util.function.Consumer; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -39,15 +40,11 @@ public static List getExclusion(Screen screen) { try { if (fromClass.containsKey(screen.getClass())) { for (EmiExclusionArea exclusion : fromClass.get(screen.getClass())) { - exclusion.addExclusionArea(screen, rect -> { - list.add((Bounds) rect); - }); + exclusion.addExclusionArea(screen, addBounds(list)); } } for (EmiExclusionArea exclusion : generic) { - exclusion.addExclusionArea(screen, rect -> { - list.add((Bounds) rect); - }); + exclusion.addExclusionArea(screen, addBounds(list)); } } catch (Exception e) { EmiLog.error("Exception thrown when adding exclusion areas"); @@ -55,4 +52,14 @@ public static List getExclusion(Screen screen) { } return list; } + + private static Consumer addBounds(List list) { + return rect -> { + // Impossible sizing, or integer overflow + if (rect.empty() || rect.right() <= rect.x() || rect.bottom() <= rect.y()) { + return; + } + list.add(rect); + }; + } } diff --git a/xplat/src/main/java/dev/emi/emi/runtime/EmiFavorites.java b/xplat/src/main/java/dev/emi/emi/runtime/EmiFavorites.java index 6486fb4e..9c330012 100644 --- a/xplat/src/main/java/dev/emi/emi/runtime/EmiFavorites.java +++ b/xplat/src/main/java/dev/emi/emi/runtime/EmiFavorites.java @@ -29,7 +29,7 @@ public class EmiFavorites { public static List favorites = Lists.newArrayList(); - public static List syntheticFavorites = Lists.newArrayList(); + public static List syntheticFavorites = Lists.newArrayList(); public static List favoriteSidebar = new CompoundList<>(favorites, syntheticFavorites); public static JsonArray save() { @@ -267,9 +267,9 @@ public static void countRecipes(Object2LongMap batches, Object2LongMa } private static class CompoundList extends AbstractList { - private List a, b; + private List a, b; - public CompoundList(List a, List b) { + public CompoundList(List a, List b) { this.a = a; this.b = b; } diff --git a/xplat/src/main/java/dev/emi/emi/runtime/EmiHistory.java b/xplat/src/main/java/dev/emi/emi/runtime/EmiHistory.java index edd55a24..ddfbeb4c 100644 --- a/xplat/src/main/java/dev/emi/emi/runtime/EmiHistory.java +++ b/xplat/src/main/java/dev/emi/emi/runtime/EmiHistory.java @@ -11,13 +11,19 @@ public class EmiHistory { private static final List HISTORIES = Lists.newArrayList(); + private static final List FORWARD_HISTORIES = Lists.newArrayList(); public static boolean isEmpty() { return HISTORIES.isEmpty(); } + public static boolean isForwardEmpty() { + return FORWARD_HISTORIES.isEmpty(); + } + public static void push(Screen history) { HISTORIES.add(history); + FORWARD_HISTORIES.clear(); } public static void pop() { @@ -28,16 +34,27 @@ public static void pop() { } int i = HISTORIES.size() - 1; HandledScreen screen = EmiApi.getHandledScreen(); - if (screen != null) { - if (i >= 0) { - client.setScreen(HISTORIES.remove(i)); - } else { - client.setScreen(screen); - } + if (i >= 0) { + Screen popped = HISTORIES.remove(i); + FORWARD_HISTORIES.add(client.currentScreen); + client.setScreen(popped); + } else if (screen != null) { + client.setScreen(screen); + } + } + + public static void forward() { + MinecraftClient client = MinecraftClient.getInstance(); + int i = FORWARD_HISTORIES.size() - 1; + if (i >= 0 && client.currentScreen != null) { + Screen popped = FORWARD_HISTORIES.remove(i); + HISTORIES.add(client.currentScreen); + client.setScreen(popped); } } public static void clear() { HISTORIES.clear(); + FORWARD_HISTORIES.clear(); } } diff --git a/xplat/src/main/java/dev/emi/emi/screen/EmiScreenManager.java b/xplat/src/main/java/dev/emi/emi/screen/EmiScreenManager.java index 1a5cdf20..6fdbcd4c 100644 --- a/xplat/src/main/java/dev/emi/emi/screen/EmiScreenManager.java +++ b/xplat/src/main/java/dev/emi/emi/screen/EmiScreenManager.java @@ -1,6 +1,7 @@ package dev.emi.emi.screen; import java.util.List; +import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -10,6 +11,7 @@ import org.lwjgl.glfw.GLFW; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.mojang.blaze3d.systems.RenderSystem; import dev.emi.emi.EmiPort; @@ -19,6 +21,8 @@ import dev.emi.emi.api.EmiFillAction; import dev.emi.emi.api.recipe.EmiPlayerInventory; import dev.emi.emi.api.recipe.EmiRecipe; +import dev.emi.emi.api.recipe.handler.EmiRecipeHandler; +import dev.emi.emi.api.recipe.handler.StandardRecipeHandler; import dev.emi.emi.api.stack.EmiIngredient; import dev.emi.emi.api.stack.EmiStack; import dev.emi.emi.api.stack.EmiStackInteraction; @@ -59,6 +63,7 @@ import dev.emi.emi.screen.widget.SidebarButtonWidget; import dev.emi.emi.screen.widget.SizedButtonWidget; import dev.emi.emi.search.EmiSearch; +import dev.emi.emi.search.EmiSearch.CompiledQuery; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.ParentElement; @@ -69,7 +74,9 @@ import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -327,7 +334,7 @@ private static void createScreenSpace(SidebarPanel panel, Screen screen, List exclusion, Bounds bounds, ScreenAlign align, int headerOffset) { for (int i = 0; i < exclusion.size(); i++) { Bounds overlap = exclusion.get(i).overlap(bounds); - if (!overlap.empty()) { + if (!overlap.empty() && !bounds.empty()) { if (overlap.top() < bounds.top() + ENTRY_SIZE + headerOffset || overlap.width() >= bounds.width() / 2 || overlap.height() >= bounds.height() / 3) { int widthFactor = overlap.width() * 10 / bounds.width(); @@ -596,6 +603,9 @@ public static void render(EmiDrawContext context, int mouseX, int mouseY, float client.getProfiler().pop(); renderExclusionAreas(context, mouseX, mouseY, delta, screen); + + client.getProfiler().swap("slots"); + renderSlotOverlays(context, mouseX, mouseY, delta, screen); client.getProfiler().pop(); RenderSystem.disableDepthTest(); @@ -773,6 +783,49 @@ private static void renderExclusionAreas(EmiDrawContext context, int mouseX, int } } + @SuppressWarnings({"rawtypes", "unchecked"}) + private static void renderSlotOverlays(EmiDrawContext context, int mouseX, int mouseY, float delta, Screen screen) { + CompiledQuery query = null; + if (EmiScreenManager.search.highlight) { + query = EmiSearch.compiledQuery; + } + Set ignoredSlots = Sets.newHashSet(); + Set synfavs = Sets.newHashSet(); + if (BoM.craftingMode && BoM.tree != null) { + List syntheticFavorites = EmiFavorites.syntheticFavorites; + for (EmiFavorite.Synthetic fav : syntheticFavorites) { + synfavs.addAll(fav.getEmiStacks()); + } + + for (EmiRecipeHandler handler : EmiRecipeFiller.getAllHandlers(EmiApi.getHandledScreen())) { + if (handler instanceof StandardRecipeHandler standard) { + ignoredSlots.addAll(standard.getInputSources(EmiApi.getHandledScreen().getScreenHandler())); + ignoredSlots.addAll(standard.getCraftingSlots(EmiApi.getHandledScreen().getScreenHandler())); + } + } + } + if (screen instanceof HandledScreen hs && screen instanceof EmiScreen emi) { + context.push(); + context.matrices().translate(emi.emi$getLeft(), emi.emi$getTop(), 0); + for (Slot slot : hs.getScreenHandler().slots) { + EmiStack stack = EmiStack.of(slot.getStack()); + context.push(); + context.matrices().translate(0, 0, 300); + if (query != null) { + if (!query.test(stack)) { + context.fill(slot.x - 1, slot.y - 1, 18, 18, 0x77000000); + } + } else if (BoM.craftingMode && BoM.tree != null) { + if (!(slot.inventory instanceof PlayerInventory) && !ignoredSlots.contains(slot) && synfavs.contains(stack)) { + context.fill(slot.x - 1, slot.y - 1, 18, 18, 0x7700BBFF); + } + } + context.pop(); + } + context.pop(); + } + } + public static void addWidgets(Screen screen) { forceRecalculate(); if (EmiConfig.centerSearchBar) { @@ -1011,6 +1064,11 @@ public static boolean genericInteraction(Function function) { EmiHistory.pop(); return true; } + } else if (function.apply(EmiConfig.forward)) { + if (!EmiHistory.isForwardEmpty()) { + EmiHistory.forward(); + return true; + } } return false; } @@ -1162,8 +1220,10 @@ private static boolean give(EmiStack stack, int amount, int mode) { command += is.getNbt().toString(); } command += " " + amount; - client.player.networkHandler.sendChatCommand(command); - return true; + if (command.length() < 256) { + client.player.networkHandler.sendChatCommand(command); + return true; + } } return false; } diff --git a/xplat/src/main/resources/assets/emi/lang/en_us.json b/xplat/src/main/resources/assets/emi/lang/en_us.json index d428cc7d..f4deb010 100644 --- a/xplat/src/main/resources/assets/emi/lang/en_us.json +++ b/xplat/src/main/resources/assets/emi/lang/en_us.json @@ -14,6 +14,7 @@ "key.emi.view_stack_tree": "View Stack Tree", "key.emi.view_tree": "View Tree", "key.emi.back": "Back", + "key.emi.forward": "Forward", "key.emi.craft_one": "Craft One", "key.emi.craft_all": "Craft All", "key.emi.craft_one_to_inventory": "Craft One to Inventory",