diff options
9 files changed, 177 insertions, 48 deletions
diff --git a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/AutoTransferHandler.java b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/AutoTransferHandler.java index c6082e5a7..5b217df48 100644 --- a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/AutoTransferHandler.java +++ b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/AutoTransferHandler.java @@ -48,6 +48,7 @@ public interface AutoTransferHandler { @NotNull Result handle(@NotNull Context context); + @ApiStatus.NonExtendable interface Result { /** * Creates a successful result, no further handlers will be called. @@ -169,6 +170,7 @@ public interface AutoTransferHandler { IntList getIntegers(); } + @ApiStatus.NonExtendable interface Context { static Context create(boolean actuallyCrafting, ContainerScreen<?> containerScreen, RecipeDisplay recipeDisplay) { return new ContextImpl(actuallyCrafting, containerScreen, () -> recipeDisplay); diff --git a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ClickAreaHandler.java b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ClickAreaHandler.java new file mode 100644 index 000000000..bb628d9a7 --- /dev/null +++ b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ClickAreaHandler.java @@ -0,0 +1,68 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.api; + +import me.shedaniel.math.Point; +import me.shedaniel.rei.impl.Internals; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.util.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +import java.util.stream.Stream; + +@FunctionalInterface +public interface ClickAreaHandler<T extends Screen> { + Result handle(ClickAreaContext<T> context); + + @ApiStatus.NonExtendable + interface ClickAreaContext<T extends Screen> { + T getScreen(); + + Point getMousePosition(); + } + + @ApiStatus.NonExtendable + interface Result { + static Result success() { + return Internals.createClickAreaHandlerResult(true); + } + + static Result fail() { + return Internals.createClickAreaHandlerResult(false); + } + + Result category(ResourceLocation category); + + default Result categories(Iterable<ResourceLocation> categories) { + for (ResourceLocation category : categories) { + category(category); + } + return this; + } + + boolean isSuccessful(); + + Stream<ResourceLocation> getCategories(); + } +} diff --git a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/RecipeHelper.java b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/RecipeHelper.java index d889beacd..d46d94415 100644 --- a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/RecipeHelper.java +++ b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/RecipeHelper.java @@ -36,6 +36,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -302,17 +303,33 @@ public interface RecipeHelper { */ <T extends Screen> void registerClickArea(ScreenClickAreaProvider<T> rectangleSupplier, Class<T> screenClass, ResourceLocation... categories); + /** + * Registers a click area handler for a screen. A handler allows more specific implementation of click areas. + * + * @param screenClass The class of the screen. + * @param handler The click area handler that is offset to the window's top left corner. + * @param <T> The screen type to be registered to. + * @see #registerClickArea(ScreenClickAreaProvider, Class, ResourceLocation...) for a simpler way to handle areas without custom categories. + */ + <T extends Screen> void registerClickArea(Class<T> screenClass, ClickAreaHandler<T> handler); + <T extends IRecipe<?>> void registerRecipes(ResourceLocation category, Class<T> recipeClass, Function<T, RecipeDisplay> mappingFunction); <T extends IRecipe<?>> void registerRecipes(ResourceLocation category, Function<IRecipe, Boolean> recipeFilter, Function<T, RecipeDisplay> mappingFunction); @ApiStatus.Internal - List<RecipeHelper.ScreenClickArea> getScreenClickAreas(); + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "6.0") + default List<RecipeHelper.ScreenClickArea> getScreenClickAreas() { + return Collections.emptyList(); + } @ApiStatus.Internal boolean arePluginsLoading(); @ApiStatus.Internal + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "6.0") interface ScreenClickArea { Class<? extends Screen> getScreenClass(); diff --git a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ScreenClickAreaProvider.java b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ScreenClickAreaProvider.java index 8f9989b9e..5f13a3cdc 100644 --- a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ScreenClickAreaProvider.java +++ b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/api/ScreenClickAreaProvider.java @@ -25,10 +25,22 @@ package me.shedaniel.rei.api; import me.shedaniel.math.Rectangle; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.util.ResourceLocation; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; +import java.util.function.Supplier; + @FunctionalInterface public interface ScreenClickAreaProvider<T extends Screen> { @NotNull Rectangle provide(@NotNull T screen); + + default ClickAreaHandler<T> toHandler(Supplier<ResourceLocation[]> categories) { + return context -> { + return provide(context.getScreen()).contains(context.getMousePosition()) + ? ClickAreaHandler.Result.success().categories(Arrays.asList(categories.get())) + : ClickAreaHandler.Result.fail(); + }; + } } diff --git a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/impl/Internals.java b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/impl/Internals.java index b87d5e767..379c33397 100644 --- a/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/impl/Internals.java +++ b/RoughlyEnoughItems-api/src/main/java/me/shedaniel/rei/impl/Internals.java @@ -44,6 +44,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; import java.util.Collection; import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Supplier; @ApiStatus.Internal @@ -59,6 +60,7 @@ public final class Internals { private static Supplier<DisplayHelper> displayHelper = Internals::throwNotSetup; private static Supplier<WidgetsProvider> widgetsProvider = Internals::throwNotSetup; private static Supplier<ClientHelper.ViewSearchBuilder> viewSearchBuilder = Internals::throwNotSetup; + private static Function<@NotNull Boolean, ClickAreaHandler.Result> clickAreaHandlerResult = (result) -> throwNotSetup(); private static BiFunction<@Nullable Point, Collection<ITextComponent>, Tooltip> tooltipProvider = (point, texts) -> throwNotSetup(); private static Supplier<BuiltinPlugin> builtinPlugin = Internals::throwNotSetup; @@ -123,6 +125,11 @@ public final class Internals { } @NotNull + public static ClickAreaHandler.Result createClickAreaHandlerResult(boolean applicable) { + return clickAreaHandlerResult.apply(applicable); + } + + @NotNull public static Tooltip createTooltip(@Nullable Point point, Collection<ITextComponent> texts) { return tooltipProvider.apply(point, texts); } diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index a475cb6bf..54aeb15e4 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java @@ -82,6 +82,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Stream; import static me.shedaniel.rei.impl.Internals.attachInstance; @@ -170,6 +172,25 @@ public class RoughlyEnoughItemsCore { } }, Internals.WidgetsProvider.class); attachInstance((BiFunction<@Nullable Point, Collection<ITextComponent>, Tooltip>) QueuedTooltip::create, "tooltipProvider"); + attachInstance((Function<@Nullable Boolean, ClickAreaHandler.Result>) successful -> new ClickAreaHandler.Result() { + private List<ResourceLocation> categories = Lists.newArrayList(); + + @Override + public ClickAreaHandler.Result category(ResourceLocation category) { + this.categories.add(category); + return this; + } + + @Override + public boolean isSuccessful() { + return successful; + } + + @Override + public Stream<ResourceLocation> getCategories() { + return categories.stream(); + } + }, "clickAreaHandlerResult"); } /** diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java index f86a74c47..0ecdb0d1b 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java @@ -39,10 +39,7 @@ import me.shedaniel.rei.gui.modules.Menu; import me.shedaniel.rei.gui.modules.entries.GameModeMenuEntry; import me.shedaniel.rei.gui.modules.entries.WeatherMenuEntry; import me.shedaniel.rei.gui.widget.*; -import me.shedaniel.rei.impl.ClientHelperImpl; -import me.shedaniel.rei.impl.InternalWidgets; -import me.shedaniel.rei.impl.ScreenHelper; -import me.shedaniel.rei.impl.Weather; +import me.shedaniel.rei.impl.*; import me.shedaniel.rei.utils.CollectionUtils; import net.minecraft.block.Blocks; import net.minecraft.client.MainWindow; @@ -75,6 +72,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.stream.Collectors; @ApiStatus.Internal public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverlay { @@ -530,13 +528,27 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) { List<ResourceLocation> categories = null; Screen screen = Minecraft.getInstance().screen; - for (RecipeHelper.ScreenClickArea area : RecipeHelper.getInstance().getScreenClickAreas()) - if (area.getScreenClass().equals(screen.getClass())) - if (area.getRectangle().contains(mouseX, mouseY)) { + ClickAreaHandler.ClickAreaContext context = new ClickAreaHandler.ClickAreaContext<Screen>() { + @Override + public Screen getScreen() { + return screen; + } + + @Override + public Point getMousePosition() { + return new Point(mouseX, mouseY); + } + }; + for (Map.Entry<Class<? extends Screen>, ClickAreaHandler<?>> area : ((RecipeHelperImpl) RecipeHelper.getInstance()).getClickAreas().entries()) { + if (area.getKey().equals(screen.getClass())) { + ClickAreaHandler.Result result = area.getValue().handle(context); + if (result.isSuccessful()) { if (categories == null) { - categories = new ArrayList<>(Arrays.asList(area.getCategories())); - } else categories.addAll(Arrays.asList(area.getCategories())); + categories = result.getCategories().collect(Collectors.toList()); + } else categories.addAll(result.getCategories().collect(Collectors.toList())); } + } + } if (categories != null && !categories.isEmpty()) { String collect = CollectionUtils.mapAndJoinToString(categories, identifier -> RecipeHelper.getInstance().getCategory(identifier).getCategoryName(), ", "); Tooltip.create(new TranslationTextComponent("text.rei.view_recipes_for", collect)).queue(); @@ -772,13 +784,27 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) { List<ResourceLocation> categories = null; Screen screen = Minecraft.getInstance().screen; - for (RecipeHelper.ScreenClickArea area : RecipeHelper.getInstance().getScreenClickAreas()) - if (area.getScreenClass().equals(screen.getClass())) - if (area.getRectangle().contains(mouseX, mouseY)) { + ClickAreaHandler.ClickAreaContext context = new ClickAreaHandler.ClickAreaContext<Screen>() { + @Override + public Screen getScreen() { + return screen; + } + + @Override + public Point getMousePosition() { + return new Point(mouseX, mouseY); + } + }; + for (Map.Entry<Class<? extends Screen>, ClickAreaHandler<?>> area : ((RecipeHelperImpl) RecipeHelper.getInstance()).getClickAreas().entries()) { + if (area.getKey().equals(screen.getClass())) { + ClickAreaHandler.Result result = area.getValue().handle(context); + if (result.isSuccessful()) { if (categories == null) { - categories = new ArrayList<>(Arrays.asList(area.getCategories())); - } else categories.addAll(Arrays.asList(area.getCategories())); + categories = result.getCategories().collect(Collectors.toList()); + } else categories.addAll(result.getCategories().collect(Collectors.toList())); } + } + } if (categories != null && !categories.isEmpty()) { ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addCategories(categories).fillPreferredOpenedCategory()); Minecraft.getInstance().getSoundManager().play(SimpleSound.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java index be60be5cb..c7537772f 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java @@ -53,7 +53,6 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -69,7 +68,7 @@ public class RecipeHelperImpl implements RecipeHelper { private final List<FocusedStackProvider> focusedStackProviders = Lists.newArrayList(); private final List<AutoTransferHandler> autoTransferHandlers = Lists.newArrayList(); private final List<RecipeFunction> recipeFunctions = Lists.newArrayList(); - private final List<ScreenClickArea> screenClickAreas = Lists.newArrayList(); + private final Multimap<Class<? extends Screen>, ClickAreaHandler<?>> screenClickAreas = HashMultimap.create(); private final int[] recipeCount = {0}; private final Map<ResourceLocation, List<RecipeDisplay>> recipeDisplays = Maps.newHashMap(); private final BiMap<RecipeCategory<?>, ResourceLocation> categories = HashBiMap.create(); @@ -606,7 +605,12 @@ public class RecipeHelperImpl implements RecipeHelper { @Override public <T extends Screen> void registerClickArea(ScreenClickAreaProvider<T> rectangleSupplier, Class<T> screenClass, ResourceLocation... categories) { - this.screenClickAreas.add(new ScreenClickAreaImpl(screenClass, () -> rectangleSupplier.provide((T) Minecraft.getInstance().screen), categories)); + registerClickArea(screenClass, rectangleSupplier.toHandler(() -> categories)); + } + + @Override + public <T extends Screen> void registerClickArea(Class<T> screenClass, ClickAreaHandler<T> handler) { + this.screenClickAreas.put(screenClass, handler); } @Override @@ -631,38 +635,10 @@ public class RecipeHelperImpl implements RecipeHelper { liveRecipeGenerators.add((LiveRecipeGenerator<RecipeDisplay>) liveRecipeGenerator); } - @Override - public List<ScreenClickArea> getScreenClickAreas() { + public Multimap<Class<? extends Screen>, ClickAreaHandler<?>> getClickAreas() { return screenClickAreas; } - private static class ScreenClickAreaImpl implements ScreenClickArea { - private Class<? extends Screen> screenClass; - private Supplier<Rectangle> rectangleSupplier; - private ResourceLocation[] categories; - - private ScreenClickAreaImpl(Class<? extends Screen> screenClass, Supplier<Rectangle> rectangleSupplier, ResourceLocation[] categories) { - this.screenClass = screenClass; - this.rectangleSupplier = rectangleSupplier; - this.categories = categories; - } - - @Override - public Class<? extends Screen> getScreenClass() { - return screenClass; - } - - @Override - public Rectangle getRectangle() { - return rectangleSupplier.get(); - } - - @Override - public ResourceLocation[] getCategories() { - return categories; - } - } - @SuppressWarnings("rawtypes") private static class RecipeFunction { private ResourceLocation category; diff --git a/gradle.properties b/gradle.properties index 2a553eacc..b817bf56a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ org.gradle.jvmargs=-Xmx3G -mod_version=5.5.1 +mod_version=5.6.0 supported_version=1.16.2/3 minecraft_version=1.16.2 forge_version=33.0.37 |
