diff options
| author | Unknown <shekwancheung0528@gmail.com> | 2019-01-31 15:32:33 +0800 |
|---|---|---|
| committer | Unknown <shekwancheung0528@gmail.com> | 2019-01-31 15:32:33 +0800 |
| commit | 2f95b698dee3368666cefe8890a015eb098dd77b (patch) | |
| tree | 994981d645051f5360ea29dc0d7701a83cd1858a /src/main/java/me/shedaniel/rei/client | |
| parent | 40d345b6b0f0bea1e4313ad9cdb789762e160f8d (diff) | |
| download | RoughlyEnoughItems-2.2.0.15.tar.gz RoughlyEnoughItems-2.2.0.15.tar.bz2 RoughlyEnoughItems-2.2.0.15.zip | |
Update to v2.2.0.15 & Fix Optifinev2.2.0.15
Fix #16
Diffstat (limited to 'src/main/java/me/shedaniel/rei/client')
6 files changed, 97 insertions, 95 deletions
diff --git a/src/main/java/me/shedaniel/rei/client/ClientHelper.java b/src/main/java/me/shedaniel/rei/client/ClientHelper.java index 84ecdd0ba..e4347b85b 100644 --- a/src/main/java/me/shedaniel/rei/client/ClientHelper.java +++ b/src/main/java/me/shedaniel/rei/client/ClientHelper.java @@ -2,15 +2,12 @@ package me.shedaniel.rei.client; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; -import io.netty.buffer.Unpooled; import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.api.IRecipeCategory; import me.shedaniel.rei.api.IRecipeDisplay; import me.shedaniel.rei.gui.ContainerGuiOverlay; import me.shedaniel.rei.gui.widget.ConfigWidget; -import me.shedaniel.rei.gui.widget.RecipeViewingWidget; -import me.shedaniel.rei.listeners.ClientLoaded; -import me.shedaniel.rei.listeners.IMixinGuiContainer; +import me.shedaniel.rei.gui.widget.RecipeViewingWidgetGui; import me.shedaniel.rei.network.CreateItemsPacket; import me.shedaniel.rei.network.DeleteItemsPacket; import net.minecraft.client.Minecraft; @@ -32,7 +29,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class ClientHelper implements ClientLoaded { +public class ClientHelper { private static List<ItemStack> itemList; private static boolean cheating = false; @@ -48,13 +45,11 @@ public class ClientHelper implements ClientLoaded { String modid = location.getNamespace(); if (modid.equalsIgnoreCase("minecraft")) return "Minecraft"; - return RiftLoader.instance.getMods().stream() - .filter(modInfo -> modInfo.id.equals(modid) || (modInfo.name != null && modInfo.name.equals(modid))) - .findFirst().map(modInfo -> { - if (modInfo.name != null) - return modInfo.name; - return modid; - }).orElse(modid); + return RiftLoader.instance.getMods().stream().filter(modInfo -> modInfo.id.equals(modid) || (modInfo.name != null && modInfo.name.equals(modid))).findFirst().map(modInfo -> { + if (modInfo.name != null) + return modInfo.name; + return modid; + }).orElse(modid); } return ""; } @@ -100,27 +95,25 @@ public class ClientHelper implements ClientLoaded { } else { ResourceLocation location = IRegistry.ITEM.getKey(cheatedStack.getItem()); String tagMessage = cheatedStack.copy().getTag() != null && !cheatedStack.copy().getTag().isEmpty() ? cheatedStack.copy().getTag().toString() : ""; - String madeUpCommand = RoughlyEnoughItemsCore.getConfigHelper().getGiveCommandPrefix() + " " + Minecraft.getInstance().player.getScoreboardName() + " " + - location.toString() + tagMessage + (cheatedStack.getCount() != 1 ? " " + cheatedStack.getCount() : ""); + String madeUpCommand = RoughlyEnoughItemsCore.getConfigHelper().getGiveCommandPrefix() + " " + Minecraft.getInstance().player.getScoreboardName() + " " + location.toString() + tagMessage + (cheatedStack.getCount() != 1 ? " " + cheatedStack.getCount() : ""); if (madeUpCommand.length() > 256) - madeUpCommand = RoughlyEnoughItemsCore.getConfigHelper().getGiveCommandPrefix() + " " + Minecraft.getInstance().player.getScoreboardName() + " " + - location.toString() + (cheatedStack.getCount() != 1 ? " " + cheatedStack.getCount() : ""); + madeUpCommand = RoughlyEnoughItemsCore.getConfigHelper().getGiveCommandPrefix() + " " + Minecraft.getInstance().player.getScoreboardName() + " " + location.toString() + (cheatedStack.getCount() != 1 ? " " + cheatedStack.getCount() : ""); Minecraft.getInstance().player.sendChatMessage(madeUpCommand); return true; } } - public static boolean executeRecipeKeyBind(ContainerGuiOverlay overlay, ItemStack stack, IMixinGuiContainer parent) { - Map<IRecipeCategory, List<IRecipeDisplay>> map = RecipeHelper.getRecipesFor(stack); + public static boolean executeRecipeKeyBind(ContainerGuiOverlay overlay, ItemStack stack) { + Map<IRecipeCategory, List<IRecipeDisplay>> map = RecipeHelper.getInstance().getRecipesFor(stack); if (map.keySet().size() > 0) - Minecraft.getInstance().displayGuiScreen(new RecipeViewingWidget(Minecraft.getInstance().mainWindow, parent, map)); + Minecraft.getInstance().displayGuiScreen(new RecipeViewingWidgetGui(Minecraft.getInstance().mainWindow, map)); return map.keySet().size() > 0; } - public static boolean executeUsageKeyBind(ContainerGuiOverlay overlay, ItemStack stack, IMixinGuiContainer parent) { - Map<IRecipeCategory, List<IRecipeDisplay>> map = RecipeHelper.getUsagesFor(stack); + public static boolean executeUsageKeyBind(ContainerGuiOverlay overlay, ItemStack stack) { + Map<IRecipeCategory, List<IRecipeDisplay>> map = RecipeHelper.getInstance().getUsagesFor(stack); if (map.keySet().size() > 0) - Minecraft.getInstance().displayGuiScreen(new RecipeViewingWidget(Minecraft.getInstance().mainWindow, parent, map)); + Minecraft.getInstance().displayGuiScreen(new RecipeViewingWidgetGui(Minecraft.getInstance().mainWindow, map)); return map.keySet().size() > 0; } @@ -129,8 +122,7 @@ public class ClientHelper implements ClientLoaded { } public static List<ItemStack> getInventoryItemsTypes() { - List<NonNullList<ItemStack>> field_7543 = ImmutableList.of(Minecraft.getInstance().player.inventory.mainInventory, Minecraft.getInstance().player.inventory.armorInventory - , Minecraft.getInstance().player.inventory.offHandInventory); + List<NonNullList<ItemStack>> field_7543 = ImmutableList.of(Minecraft.getInstance().player.inventory.mainInventory, Minecraft.getInstance().player.inventory.armorInventory, Minecraft.getInstance().player.inventory.offHandInventory); List<ItemStack> inventoryStacks = new ArrayList<>(); field_7543.forEach(itemStacks -> itemStacks.forEach(itemStack -> { if (!itemStack.getItem().equals(Items.AIR)) @@ -139,7 +131,6 @@ public class ClientHelper implements ClientLoaded { return inventoryStacks; } - @Override public void clientLoaded() { IRegistry.ITEM.forEach(item -> { if (!item.equals(Items.ENCHANTED_BOOK)) diff --git a/src/main/java/me/shedaniel/rei/client/GuiHelper.java b/src/main/java/me/shedaniel/rei/client/GuiHelper.java index 4b228b3a6..253a51480 100644 --- a/src/main/java/me/shedaniel/rei/client/GuiHelper.java +++ b/src/main/java/me/shedaniel/rei/client/GuiHelper.java @@ -3,17 +3,22 @@ package me.shedaniel.rei.client; import com.google.common.collect.Lists; import me.shedaniel.rei.gui.ContainerGuiOverlay; import me.shedaniel.rei.gui.widget.TextFieldWidget; +import me.shedaniel.rei.listeners.IMixinGuiContainer; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.item.ItemStack; +import org.dimdev.rift.listener.client.ClientTickable; import java.util.List; -public class GuiHelper { +public class GuiHelper implements ClientTickable { public static TextFieldWidget searchField; public static List<ItemStack> inventoryStacks = Lists.newArrayList(); private static boolean overlayVisible = true; private static ContainerGuiOverlay overlay; + private static GuiContainer lastGuiContainer; + private static IMixinGuiContainer lastMixinGuiContainer; public static boolean isOverlayVisible() { return overlayVisible; @@ -23,14 +28,6 @@ public class GuiHelper { overlayVisible = !overlayVisible; } - public static ContainerGuiOverlay getOverlay(GuiContainer lastGui) { - if (overlay == null) { - overlay = new ContainerGuiOverlay(lastGui); - overlay.onInitialized(); - } - return overlay; - } - public static ContainerGuiOverlay getLastOverlay() { return overlay; } @@ -40,8 +37,28 @@ public class GuiHelper { overlay.onInitialized(); } - public static void resetOverlay() { - overlay = null; + public static GuiContainer getLastGuiContainer() { + return lastGuiContainer; + } + + public static void setLastGuiContainer(GuiContainer lastGuiContainer) { + GuiHelper.lastGuiContainer = lastGuiContainer; + } + + public static IMixinGuiContainer getLastMixinGuiContainer() { + return lastMixinGuiContainer; + } + + public static void setLastMixinGuiContainer(IMixinGuiContainer lastMixinGuiContainer) { + GuiHelper.lastMixinGuiContainer = lastMixinGuiContainer; + } + + @Override + public void clientTick(Minecraft client) { + if (client.currentScreen instanceof GuiContainer && lastGuiContainer != client.currentScreen) { + GuiHelper.lastGuiContainer = (GuiContainer) client.currentScreen; + GuiHelper.lastMixinGuiContainer = (IMixinGuiContainer) lastGuiContainer; + } } } diff --git a/src/main/java/me/shedaniel/rei/client/KeyBindHelper.java b/src/main/java/me/shedaniel/rei/client/KeyBindHelper.java index 65ce788a1..6c253360d 100644 --- a/src/main/java/me/shedaniel/rei/client/KeyBindHelper.java +++ b/src/main/java/me/shedaniel/rei/client/KeyBindHelper.java @@ -5,7 +5,6 @@ import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.listeners.IMixinKeyBinding; import net.minecraft.client.settings.KeyBinding; import net.minecraft.client.util.InputMappings; -import net.minecraft.util.ResourceLocation; import org.dimdev.rift.listener.client.KeyBindingAdder; import java.util.Collection; @@ -13,9 +12,9 @@ import java.util.List; public class KeyBindHelper implements KeyBindingAdder { - private static final ResourceLocation RECIPE_KEYBIND = new ResourceLocation("roughlyenoughitems", "recipe_keybind"); - private static final ResourceLocation USAGE_KEYBIND = new ResourceLocation("roughlyenoughitems", "usage_keybind"); - private static final ResourceLocation HIDE_KEYBIND = new ResourceLocation("roughlyenoughitems", "hide_keybind"); + private static final String RECIPE_KEYBIND = "roughlyenoughitems:recipe_keybind"; + private static final String USAGE_KEYBIND = "roughlyenoughitems:usage_keybind"; + private static final String HIDE_KEYBIND = "roughlyenoughitems:hide_keybind"; public static KeyBinding RECIPE, USAGE, HIDE; @Override @@ -34,9 +33,9 @@ public class KeyBindHelper implements KeyBindingAdder { ((IMixinKeyBinding) keyBinding).addCategory(category); } - private KeyBinding createKeyBinding(ResourceLocation location, InputMappings.Type inputType, int keyCode, String category) { - RoughlyEnoughItemsCore.LOGGER.info("Registering: key." + location.toString().replaceAll(":", ".") + " in " + category); - return new KeyBinding("key." + location.toString().replaceAll(":", "."), inputType, keyCode, category); + private KeyBinding createKeyBinding(String resourceLocation, InputMappings.Type inputType, int keyCode, String category) { + RoughlyEnoughItemsCore.LOGGER.info("Registering: key." + resourceLocation.replaceAll(":", ".") + " in " + category); + return new KeyBinding("key." + resourceLocation.replaceAll(":", "."), inputType, keyCode, category); } } diff --git a/src/main/java/me/shedaniel/rei/client/REIConfig.java b/src/main/java/me/shedaniel/rei/client/REIConfig.java index db14b282f..49ccb1dec 100644 --- a/src/main/java/me/shedaniel/rei/client/REIConfig.java +++ b/src/main/java/me/shedaniel/rei/client/REIConfig.java @@ -3,13 +3,9 @@ package me.shedaniel.rei.client; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import java.awt.event.KeyEvent; - public class REIConfig { - public static Gson GSON = new GsonBuilder() - .setPrettyPrinting() - .create(); + public static Gson GSON = new GsonBuilder().setPrettyPrinting().create(); public REIItemListOrdering itemListOrdering = REIItemListOrdering.REGISTRY; public boolean isAscending = true; diff --git a/src/main/java/me/shedaniel/rei/client/REIItemListOrdering.java b/src/main/java/me/shedaniel/rei/client/REIItemListOrdering.java index b0167d352..8f9e317eb 100644 --- a/src/main/java/me/shedaniel/rei/client/REIItemListOrdering.java +++ b/src/main/java/me/shedaniel/rei/client/REIItemListOrdering.java @@ -4,9 +4,7 @@ import com.google.gson.annotations.SerializedName; public enum REIItemListOrdering { - @SerializedName("registry") REGISTRY("ordering.rei.registry"), - @SerializedName("name") NAME("ordering.rei.name"), - @SerializedName("item_groups") ITEM_GROUPS("ordering.rei.item_groups"); + @SerializedName("registry") REGISTRY("ordering.rei.registry"), @SerializedName("name") NAME("ordering.rei.name"), @SerializedName("item_groups") ITEM_GROUPS("ordering.rei.item_groups"); private String nameTranslationKey; diff --git a/src/main/java/me/shedaniel/rei/client/RecipeHelper.java b/src/main/java/me/shedaniel/rei/client/RecipeHelper.java index d5a360ee0..eec9f4bbc 100644 --- a/src/main/java/me/shedaniel/rei/client/RecipeHelper.java +++ b/src/main/java/me/shedaniel/rei/client/RecipeHelper.java @@ -5,7 +5,6 @@ import com.google.common.collect.Maps; import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.RoughlyEnoughItemsPlugin; import me.shedaniel.rei.api.*; -import me.shedaniel.rei.listeners.RecipeSync; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.RecipeManager; import net.minecraft.util.ResourceLocation; @@ -15,22 +14,19 @@ import java.util.*; import java.util.List; import java.util.stream.Collectors; -public class RecipeHelper implements RecipeSync { - - private static Map<ResourceLocation, List<IRecipeDisplay>> recipeCategoryListMap; - private static List<IRecipeCategory> categories; - private static RecipeManager recipeManager; - private static Map<ResourceLocation, SpeedCraftAreaSupplier> speedCraftAreaSupplierMap; - private static Map<ResourceLocation, List<SpeedCraftFunctional>> speedCraftFunctionalMap; - - public RecipeHelper() { - this.recipeCategoryListMap = Maps.newHashMap(); - this.categories = Lists.newArrayList(); - this.speedCraftAreaSupplierMap = Maps.newHashMap(); - this.speedCraftFunctionalMap = Maps.newHashMap(); +public class RecipeHelper { + + private final Map<ResourceLocation, List<IRecipeDisplay>> recipeCategoryListMap = Maps.newHashMap(); + private final List<IRecipeCategory> categories = Lists.newArrayList(); + private RecipeManager recipeManager; + private final Map<ResourceLocation, SpeedCraftAreaSupplier> speedCraftAreaSupplierMap = Maps.newHashMap(); + private final Map<ResourceLocation, List<SpeedCraftFunctional>> speedCraftFunctionalMap = Maps.newHashMap(); + + public static RecipeHelper getInstance() { + return RoughlyEnoughItemsCore.getRecipeHelper(); } - public static List<ItemStack> findCraftableByItems(List<ItemStack> inventoryItems) { + public List<ItemStack> findCraftableByItems(List<ItemStack> inventoryItems) { List<ItemStack> craftables = new ArrayList<>(); for(List<IRecipeDisplay> value : recipeCategoryListMap.values()) for(IRecipeDisplay recipeDisplay : value) { @@ -59,47 +55,53 @@ public class RecipeHelper implements RecipeSync { return craftables.stream().distinct().collect(Collectors.toList()); } - public static void registerCategory(IRecipeCategory category) { + public void registerCategory(IRecipeCategory category) { categories.add(category); - recipeCategoryListMap.put(category.getResourceLocation(), Lists.newArrayList()); + recipeCategoryListMap.put(category.getResourceLocation(), Lists.newLinkedList()); } - public static void registerRecipe(ResourceLocation categoryIdentifier, IRecipeDisplay display) { + public void registerRecipe(ResourceLocation categoryIdentifier, IRecipeDisplay display) { if (!recipeCategoryListMap.containsKey(categoryIdentifier)) return; recipeCategoryListMap.get(categoryIdentifier).add(display); } - public static Map<IRecipeCategory, List<IRecipeDisplay>> getRecipesFor(ItemStack stack) { + public Map<IRecipeCategory, List<IRecipeDisplay>> getRecipesFor(ItemStack stack) { Map<ResourceLocation, List<IRecipeDisplay>> categoriesMap = new HashMap<>(); - categories.forEach(f -> categoriesMap.put(f.getResourceLocation(), new LinkedList<>())); - for(List<IRecipeDisplay> value : recipeCategoryListMap.values()) - for(IRecipeDisplay recipeDisplay : value) + categories.forEach(f -> categoriesMap.put(f.getResourceLocation(), Lists.newArrayList())); + for(Map.Entry<ResourceLocation, List<IRecipeDisplay>> entry : recipeCategoryListMap.entrySet()) { + IRecipeCategory category = getCategory(entry.getKey()); + for(IRecipeDisplay recipeDisplay : entry.getValue()) for(ItemStack outputStack : (List<ItemStack>) recipeDisplay.getOutput()) - if (ItemStack.areItemsEqual(stack, outputStack)) + if (category.checkTags() ? ItemStack.areItemStacksEqual(stack, outputStack) : ItemStack.areItemsEqual(stack, outputStack)) categoriesMap.get(recipeDisplay.getRecipeCategory()).add(recipeDisplay); - categoriesMap.keySet().removeIf(f -> categoriesMap.get(f).isEmpty()); - Map<IRecipeCategory, List<IRecipeDisplay>> recipeCategoryListMap = Maps.newHashMap(); + } + Map<IRecipeCategory, List<IRecipeDisplay>> recipeCategoryListMap = Maps.newLinkedHashMap(); categories.forEach(category -> { - if (categoriesMap.containsKey(category.getResourceLocation())) + if (categoriesMap.containsKey(category.getResourceLocation()) && !categoriesMap.get(category.getResourceLocation()).isEmpty()) recipeCategoryListMap.put(category, categoriesMap.get(category.getResourceLocation())); }); return recipeCategoryListMap; } - public static RecipeManager getRecipeManager() { + private IRecipeCategory getCategory(ResourceLocation resourceLocation) { + return categories.stream().filter(category -> category.getResourceLocation().equals(resourceLocation)).findFirst().orElse(null); + } + + public RecipeManager getRecipeManager() { return recipeManager; } - public static Map<IRecipeCategory, List<IRecipeDisplay>> getUsagesFor(ItemStack stack) { + public Map<IRecipeCategory, List<IRecipeDisplay>> getUsagesFor(ItemStack stack) { Map<ResourceLocation, List<IRecipeDisplay>> categoriesMap = new HashMap<>(); - categories.forEach(f -> categoriesMap.put(f.getResourceLocation(), new LinkedList<>())); - for(List<IRecipeDisplay> value : recipeCategoryListMap.values()) - for(IRecipeDisplay recipeDisplay : value) { + categories.forEach(f -> categoriesMap.put(f.getResourceLocation(), Lists.newArrayList())); + for(Map.Entry<ResourceLocation, List<IRecipeDisplay>> entry : recipeCategoryListMap.entrySet()) { + IRecipeCategory category = getCategory(entry.getKey()); + for(IRecipeDisplay recipeDisplay : entry.getValue()) { boolean found = false; for(List<ItemStack> input : (List<List<ItemStack>>) recipeDisplay.getInput()) { for(ItemStack itemStack : input) { - if (ItemStack.areItemsEqual(itemStack, stack)) { + if (category.checkTags() ? ItemStack.areItemStacksEqual(itemStack, stack) : ItemStack.areItemsEqual(itemStack, stack)) { categoriesMap.get(recipeDisplay.getRecipeCategory()).add(recipeDisplay); found = true; break; @@ -109,20 +111,20 @@ public class RecipeHelper implements RecipeSync { break; } } - categoriesMap.keySet().removeIf(f -> categoriesMap.get(f).isEmpty()); - Map<IRecipeCategory, List<IRecipeDisplay>> recipeCategoryListMap = Maps.newHashMap(); + } + Map<IRecipeCategory, List<IRecipeDisplay>> recipeCategoryListMap = Maps.newLinkedHashMap(); categories.forEach(category -> { - if (categoriesMap.containsKey(category.getResourceLocation())) + if (categoriesMap.containsKey(category.getResourceLocation()) && !categoriesMap.get(category.getResourceLocation()).isEmpty()) recipeCategoryListMap.put(category, categoriesMap.get(category.getResourceLocation())); }); return recipeCategoryListMap; } - public static List<IRecipeCategory> getCategories() { - return categories; + public List<IRecipeCategory> getCategories() { + return new LinkedList<>(categories); } - public static SpeedCraftAreaSupplier getSpeedCraftButtonArea(IRecipeCategory category) { + public SpeedCraftAreaSupplier getSpeedCraftButtonArea(IRecipeCategory category) { if (!speedCraftAreaSupplierMap.containsKey(category.getResourceLocation())) return bounds -> { return new Rectangle((int) bounds.getMaxX() - 16, (int) bounds.getMaxY() - 16, 10, 10); @@ -130,23 +132,22 @@ public class RecipeHelper implements RecipeSync { return speedCraftAreaSupplierMap.get(category.getResourceLocation()); } - public static void registerSpeedCraftButtonArea(ResourceLocation category, SpeedCraftAreaSupplier rectangle) { + public void registerSpeedCraftButtonArea(ResourceLocation category, SpeedCraftAreaSupplier rectangle) { speedCraftAreaSupplierMap.put(category, rectangle); } - public static List<SpeedCraftFunctional> getSpeedCraftFunctional(IRecipeCategory category) { + public List<SpeedCraftFunctional> getSpeedCraftFunctional(IRecipeCategory category) { if (speedCraftFunctionalMap.get(category.getResourceLocation()) == null) return Lists.newArrayList(); return speedCraftFunctionalMap.get(category.getResourceLocation()); } - public static void registerSpeedCraftFunctional(ResourceLocation category, SpeedCraftFunctional functional) { + public void registerSpeedCraftFunctional(ResourceLocation category, SpeedCraftFunctional functional) { List<SpeedCraftFunctional> list = speedCraftFunctionalMap.containsKey(category) ? new LinkedList<>(speedCraftFunctionalMap.get(category)) : Lists.newLinkedList(); list.add(functional); speedCraftFunctionalMap.put(category, list); } - @Override public void recipesLoaded(RecipeManager recipeManager) { this.recipeManager = recipeManager; this.recipeCategoryListMap.clear(); @@ -158,8 +159,8 @@ public class RecipeHelper implements RecipeSync { return second.getPriority() - first.getPriority(); }); RoughlyEnoughItemsCore.LOGGER.info("Loading %d REI plugins: %s", plugins.size(), String.join(", ", plugins.stream().map(plugin -> { - ResourceLocation ResourceLocation = RoughlyEnoughItemsPlugin.getPluginResourceLocation(plugin); - return ResourceLocation == null ? "NULL" : ResourceLocation.toString(); + String resourceLocation = RoughlyEnoughItemsPlugin.getPluginResourceLocation(plugin); + return resourceLocation == null ? "NULL" : resourceLocation; }).collect(Collectors.toList()))); Collections.reverse(plugins); plugins.forEach(plugin -> { |
