diff --git a/.github/workflows/curseforge.yml b/.github/workflows/curseforge.yml index be653f15d..82a6755eb 100644 --- a/.github/workflows/curseforge.yml +++ b/.github/workflows/curseforge.yml @@ -14,7 +14,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: macos-latest if: "!contains(github.event.head_commit.message, 'ci skip')" steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 60cb21cce..600458d1b 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -4,7 +4,7 @@ on: [push] jobs: build: - runs-on: ubuntu-latest + runs-on: macos-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 17 diff --git a/api/build.gradle b/api/build.gradle deleted file mode 100644 index 23ee2975c..000000000 --- a/api/build.gradle +++ /dev/null @@ -1,58 +0,0 @@ -import net.fabricmc.loom.task.RemapJarTask - -archivesBaseName = rootProject.name + "-" + project.name - -dependencies { - modCompileOnly("net.fabricmc:fabric-loader:${project.fabricloader_version}") - modApi("me.shedaniel.cloth:cloth-config:${cloth_config_version}") - modApi("dev.architectury:architectury:${architectury_version}") -} - -architectury { - common(forgeEnabled.toBoolean()) -} - -remapJar { - classifier "raw" -} - -task fakeJar(type: Jar, dependsOn: remapJar) { - from remapJar.archiveFile.map { zipTree(it) } - from(rootProject.file("fake/fabric.mod.json")) { - into "" - } - classifier null -} - -task fakeForgeJar(type: Jar, dependsOn: jar) { - from jar.archiveFile.map { zipTree(it) } - from(rootProject.file("fake/mods.toml")) { - into "META-INF" - } - ["REIPlugin", "REIPluginClient", "REIPluginCommon", "REIPluginDedicatedServer", - "REIPluginLoader", "REIPluginLoaderClient", "REIPluginLoaderCommon", "REIPluginLoaderDedicatedServer"].each { - from(rootProject.file("fake/$it.class")) { - into "me/shedaniel/rei/forge" - } - } - classifier "fake-forge" -} - -artifacts { - apiElements(fakeJar) - runtimeElements(fakeJar) -} - -afterEvaluate { - configurations.apiElements.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.remapJar) } - configurations.runtimeElements.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.remapJar) } -} - -publishing { - publications { - mavenCommon(MavenPublication) { - artifactId = rootProject.name + "-" + project.name - from components.java - } - } -} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/ClientHelper.java b/api/src/main/java/me/shedaniel/rei/api/client/ClientHelper.java index 2e1be6030..5eb95053b 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/ClientHelper.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/ClientHelper.java @@ -24,11 +24,14 @@ package me.shedaniel.rei.api.client; import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.view.ViewSearchBuilder; import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; import me.shedaniel.rei.api.common.util.FormattingUtils; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.ChatFormatting; @@ -56,7 +59,9 @@ static ClientHelper getInstance() { * * @return whether cheating is enabled */ - boolean isCheating(); + default boolean isCheating() { + return ConfigObject.getInstance().isCheating(); + } /** * Sets current cheating mode @@ -64,7 +69,10 @@ static ClientHelper getInstance() { * * @param cheating the new cheating mode */ - void setCheating(boolean cheating); + default void setCheating(boolean cheating) { + ConfigObject.getInstance().setCheating(cheating); + ConfigManager.getInstance().saveConfig(); + } /** * Tries to cheat stack using either packets or commands. @@ -200,5 +208,8 @@ default String getModFromIdentifier(ResourceLocation identifier) { * * @return whether the client can use move items packets */ - boolean canUseMovePackets(); + @Deprecated(forRemoval = true) + default boolean canUseMovePackets() { + return NetworkingHelper.getInstance().canUse(NetworkModule.TRANSFER); + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/REIRuntime.java b/api/src/main/java/me/shedaniel/rei/api/client/REIRuntime.java index a17751703..41e0870d3 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/REIRuntime.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/REIRuntime.java @@ -24,10 +24,12 @@ package me.shedaniel.rei.api.client; import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; import me.shedaniel.rei.api.client.gui.widgets.TextField; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipQueue; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.common.plugins.PluginManager; @@ -60,12 +62,17 @@ static REIRuntime getInstance() { * * @return whether the overlay is visible */ - boolean isOverlayVisible(); + default boolean isOverlayVisible() { + return ConfigObject.getInstance().isOverlayVisible(); + } /** * Toggles the visibility of the overlay. */ - void toggleOverlayVisible(); + default void toggleOverlayVisible() { + ConfigObject.getInstance().setOverlayVisible(!ConfigObject.getInstance().isOverlayVisible()); + ConfigManager.getInstance().saveConfig(); + } /** * Returns the screen overlay of REI, if available and constructed. @@ -126,7 +133,9 @@ default Optional getOverlay(boolean reset) { * @return whether dark mode is enabled * @see ConfigObject#isUsingDarkTheme() */ - boolean isDarkThemeEnabled(); + default boolean isDarkThemeEnabled() { + return ConfigObject.getInstance().isUsingDarkTheme(); + } /** * Returns the text field used for searching, if constructed. @@ -134,7 +143,9 @@ default Optional getOverlay(boolean reset) { * @return the text field used for searching, or {@code null} if none */ @Nullable - TextField getSearchTextField(); + default TextField getSearchTextField() { + return getOverlay().map(ScreenOverlay::getSearchField).orElse(null); + } /** * Queues a tooltip to be displayed. @@ -142,7 +153,11 @@ default Optional getOverlay(boolean reset) { * @param tooltip the tooltip to display, or {@code null} * @see Tooltip#queue() */ - void queueTooltip(@Nullable Tooltip tooltip); + default void queueTooltip(@Nullable Tooltip tooltip) { + if (getOverlay(false, false).isEmpty()) { + TooltipQueue.getInstance().queue(tooltip); + } + } /** * Clear all queued tooltips. @@ -151,7 +166,11 @@ default Optional getOverlay(boolean reset) { * @since 8.3 */ @ApiStatus.Experimental - void clearTooltips(); + default void clearTooltips() { + if (getOverlay(false, false).isEmpty()) { + TooltipQueue.getInstance().clear(); + } + } /** * Returns the texture location of the default display background. @@ -160,7 +179,9 @@ default Optional getOverlay(boolean reset) { * * @return the texture location of the default display background */ - ResourceLocation getDefaultDisplayTexture(); + default ResourceLocation getDefaultDisplayTexture() { + return getDefaultDisplayTexture(isDarkThemeEnabled()); + } /** * Returns the texture location of the default display background. diff --git a/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringResult.java b/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringResult.java index 4d4392ae9..d523a650f 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringResult.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringResult.java @@ -24,13 +24,10 @@ package me.shedaniel.rei.api.client.entry.filtering; import me.shedaniel.rei.api.common.entry.EntryStack; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; import org.jetbrains.annotations.ApiStatus; import java.util.Collection; -@Environment(EnvType.CLIENT) @ApiStatus.Experimental public interface FilteringResult { FilteringResult hide(EntryStack stack); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringRule.java b/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringRule.java index 1f3cb5b50..67fa66b0c 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringRule.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringRule.java @@ -63,4 +63,4 @@ default Cache prepareCache(boolean async) { * @return the result of the processing */ FilteringResult processFilteredStacks(FilteringContext context, FilteringResultFactory resultFactory, Cache cache, boolean async); -} \ No newline at end of file +} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringRuleTypeRegistry.java b/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringRuleTypeRegistry.java index 16638a828..781b31f88 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringRuleTypeRegistry.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/entry/filtering/FilteringRuleTypeRegistry.java @@ -24,7 +24,7 @@ package me.shedaniel.rei.api.client.entry.filtering; import me.shedaniel.rei.api.client.entry.filtering.base.BasicFilteringRule; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.resources.ResourceLocation; diff --git a/api/src/main/java/me/shedaniel/rei/api/client/entry/renderer/EntryRenderer.java b/api/src/main/java/me/shedaniel/rei/api/client/entry/renderer/EntryRenderer.java index c51309603..2aa203aa9 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/entry/renderer/EntryRenderer.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/entry/renderer/EntryRenderer.java @@ -29,7 +29,7 @@ import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.api.common.entry.type.BuiltinEntryTypes; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import org.jetbrains.annotations.ApiStatus; @@ -46,7 +46,7 @@ @Environment(EnvType.CLIENT) public interface EntryRenderer extends EntryRendererProvider { static EntryRenderer empty() { - return ClientInternals.getEmptyEntryRenderer(); + return (EntryRenderer) BuiltinEntryTypes.EMPTY.getDefinition().getRenderer(); } @Environment(EnvType.CLIENT) diff --git a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java index 6c5415910..e1f18684d 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntry.java @@ -29,7 +29,7 @@ import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.util.ClientEntryStacks; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.nbt.CompoundTag; diff --git a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntryType.java b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntryType.java index 35a5e8f96..d80c567b0 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntryType.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/favorites/FavoriteEntryType.java @@ -80,7 +80,7 @@ interface Section { default void add(FavoriteEntry... entries) { add(false, entries); } - + @ApiStatus.Experimental void add(boolean defaultFavorited, FavoriteEntry... entries); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java index 92646aa0d..2270a8ab9 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java @@ -66,9 +66,9 @@ protected SimpleDisplayRenderer(List input, List !stack.isEmpty())) - .disableBackground() - .disableHighlight() - .disableTooltips(); + .noBackground() + .noHighlight() + .noTooltips(); } public static List simplify(List original) { @@ -123,10 +123,10 @@ public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, int xx = bounds.x + 4, yy = bounds.y + 2; int j = 0; int itemsPerLine = getItemsPerLine(); - for (Slot entryWidget : inputWidgets) { - entryWidget.setZ(getZ() + 50); - entryWidget.getBounds().setLocation(xx, yy); - entryWidget.render(matrices, mouseX, mouseY, delta); + for (Slot slot : inputWidgets) { + slot.setZ(getZ() + 50); + slot.getBounds().setLocation(xx, yy); + slot.render(matrices, mouseX, mouseY, delta); xx += 18; j++; if (j >= getItemsPerLine() - 2) { diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/BatchedSlots.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/BatchedSlots.java new file mode 100644 index 000000000..6cead07dd --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/BatchedSlots.java @@ -0,0 +1,40 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.client.gui.widgets; + +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.mutable.MutableLong; + +import java.util.Collection; +import java.util.List; + +public abstract class BatchedSlots extends Widget implements List { + public abstract void addUnbatched(Slot slot); + + public abstract void addAllUnbatched(Collection slots); + + public abstract boolean isBatched(); + + public abstract void addDebugger(MutableInt size, MutableLong time); +} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidget.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidget.java index e4ff00b7b..aa91c9b76 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidget.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidget.java @@ -39,6 +39,10 @@ public DelegateWidget(Widget widget) { this.widget = widget; } + public DelegateWidget() { + this(Widgets.noOp()); + } + protected Widget delegate() { return widget; } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidgetWithBounds.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidgetWithBounds.java index 593a62588..e7f00d773 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidgetWithBounds.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/DelegateWidgetWithBounds.java @@ -36,6 +36,18 @@ public DelegateWidgetWithBounds(Widget widget, Supplier bounds) { this.bounds = bounds; } + public DelegateWidgetWithBounds(Supplier bounds) { + this(Widgets.noOp(), bounds); + } + + public DelegateWidgetWithBounds(Rectangle bounds) { + this(Widgets.noOp(), () -> bounds); + } + + public DelegateWidgetWithBounds() { + this(new Rectangle()); + } + @Override public Rectangle getBounds() { return bounds.get(); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Label.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Label.java index 856e696de..b423dd5ae 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Label.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Label.java @@ -26,6 +26,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Point; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.TextComponent; @@ -331,7 +332,7 @@ public final Label shadow(boolean hasShadow) { public abstract void setColor(int color); public Label color(int lightModeColor, int darkModeColor) { - return color(REIRuntime.getInstance().isDarkThemeEnabled() ? darkModeColor : lightModeColor); + return color(ConfigObject.getInstance().isUsingDarkTheme() ? darkModeColor : lightModeColor); } public final Label color(int color) { @@ -344,7 +345,7 @@ public final Label color(int color) { public abstract void setHoveredColor(int hoveredColor); public final Label hoveredColor(int lightModeColor, int darkModeColor) { - return hoveredColor(REIRuntime.getInstance().isDarkThemeEnabled() ? darkModeColor : lightModeColor); + return hoveredColor(ConfigObject.getInstance().isUsingDarkTheme() ? darkModeColor : lightModeColor); } public final Label hoveredColor(int color) { diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Panel.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Panel.java index f1adf8b06..875931202 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Panel.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Panel.java @@ -24,6 +24,7 @@ package me.shedaniel.rei.api.client.gui.widgets; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import java.util.function.Predicate; @@ -56,7 +57,7 @@ public final Panel color(int color) { } public final Panel color(int lightColor, int darkColor) { - return color(REIRuntime.getInstance().isDarkThemeEnabled() ? darkColor : lightColor); + return color(ConfigObject.getInstance().isUsingDarkTheme() ? darkColor : lightColor); } public abstract Predicate getRendering(); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Slot.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Slot.java index f0b2842e6..71fa8f49c 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Slot.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Slot.java @@ -23,20 +23,27 @@ package me.shedaniel.rei.api.client.gui.widgets; +import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.common.entry.EntryStack; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; +import java.util.function.*; public abstract class Slot extends WidgetWithBounds { public static final byte UN_MARKED = 0; public static final byte INPUT = 1; public static final byte OUTPUT = 2; + @ApiStatus.Experimental + public static final byte FAVORITE = 4; - public Slot unmarkInputOrOutput() { + public final Slot unmarkInputOrOutput() { setNoticeMark(UN_MARKED); return this; } @@ -51,6 +58,14 @@ public final Slot markOutput() { return this; } + public final void size(float size) { + this.getBounds().setSize(size, size); + } + + public final void size(float width, float height) { + this.getBounds().setSize(width, height); + } + public abstract void setNoticeMark(byte mark); public abstract byte getNoticeMark(); @@ -59,7 +74,7 @@ public final Slot markOutput() { public abstract boolean isInteractable(); - public Slot interactable(boolean interactable) { + public final Slot interactable(boolean interactable) { setInteractable(interactable); return this; } @@ -68,6 +83,7 @@ public final Slot noInteractable() { return interactable(false); } + @Deprecated(forRemoval = true) public final Slot notInteractable() { return interactable(false); } @@ -76,7 +92,7 @@ public final Slot notInteractable() { public abstract boolean isInteractableFavorites(); - public Slot interactableFavorites(boolean interactableFavorites) { + public final Slot interactableFavorites(boolean interactableFavorites) { setInteractableFavorites(interactableFavorites); return this; } @@ -85,11 +101,16 @@ public final Slot noFavoritesInteractable() { return interactableFavorites(false); } + @Deprecated(forRemoval = true) public final Slot notFavoritesInteractable() { return interactableFavorites(false); } - public abstract void setHighlightEnabled(boolean highlights); + public final void setHighlightEnabled(boolean highlights) { + setHighlightEnabled(slot -> highlights); + } + + public abstract void setHighlightEnabled(Predicate highlights); public abstract boolean isHighlightEnabled(); @@ -98,11 +119,27 @@ public final Slot highlightEnabled(boolean highlight) { return this; } + public abstract Slot highlightEnabled(Predicate highlight); + + public final Slot noHighlight() { + return highlightEnabled(false); + } + + public final Slot noHighlightIfEmpty() { + setHighlightEnabled(slot -> !slot.isEmpty()); + return this; + } + + @Deprecated(forRemoval = true) public final Slot disableHighlight() { return highlightEnabled(false); } - public abstract void setTooltipsEnabled(boolean tooltipsEnabled); + public void setTooltipsEnabled(boolean tooltipsEnabled) { + setTooltipsEnabled(slot -> tooltipsEnabled); + } + + public abstract void setTooltipsEnabled(Predicate tooltipsEnabled); public abstract boolean isTooltipsEnabled(); @@ -111,11 +148,22 @@ public final Slot tooltipsEnabled(boolean tooltipsEnabled) { return this; } + public abstract Slot tooltipsEnabled(Predicate tooltipsEnabled); + + public final Slot noTooltips() { + return tooltipsEnabled(false); + } + + @Deprecated(forRemoval = true) public final Slot disableTooltips() { return tooltipsEnabled(false); } - public abstract void setBackgroundEnabled(boolean backgroundEnabled); + public void setBackgroundEnabled(boolean backgroundEnabled) { + setBackgroundEnabled(slot -> backgroundEnabled); + } + + public abstract void setBackgroundEnabled(Predicate backgroundEnabled); public abstract boolean isBackgroundEnabled(); @@ -124,10 +172,26 @@ public final Slot backgroundEnabled(boolean backgroundEnabled) { return this; } + public abstract Slot backgroundEnabled(Predicate backgroundEnabled); + + public final Slot noBackground() { + return backgroundEnabled(false); + } + + @Deprecated(forRemoval = true) public final Slot disableBackground() { return backgroundEnabled(false); } + public abstract void setCyclingInterval(long cyclingInterval); + + public abstract long getCyclingInterval(); + + public final Slot cyclingInterval(long cyclingInterval) { + setCyclingInterval(cyclingInterval); + return this; + } + public abstract Slot clearEntries(); public abstract Slot entry(EntryStack stack); @@ -138,10 +202,48 @@ public final Slot disableBackground() { public abstract List> getEntries(); + public final boolean isEmpty() { + return getEntries().isEmpty(); + } + public abstract Rectangle getInnerBounds(); + public abstract void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta); + @Nullable + @Deprecated(forRemoval = true) public Tooltip getCurrentTooltip(Point point) { + return getCurrentTooltip(TooltipContext.of(point)); + } + + public abstract void drawExtra(PoseStack matrices, int mouseX, int mouseY, float delta); + + @Nullable + public Tooltip getCurrentTooltip(TooltipContext context) { return null; } + + public abstract void drawHighlighted(PoseStack matrices, int mouseX, int mouseY, float delta); + + public abstract void tooltipProcessor(UnaryOperator operator); + + public abstract void action(ActionPredicate predicate); + + @ApiStatus.Experimental + public abstract void setFavoriteEntryFunction(Function, FavoriteEntry> function); + + @ApiStatus.Experimental + public abstract Function, FavoriteEntry> getFavoriteEntryFunction(); + + @ApiStatus.Experimental + public abstract void setContainsPointFunction(BiPredicate function); + + @ApiStatus.Experimental + public abstract void appendContainsPointFunction(BiPredicate function); + + public interface ActionPredicate { + boolean doMouse(Slot slot, double mouseX, double mouseY, int button); + + boolean doKey(Slot slot, int keyCode, int scanCode, int modifiers); + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TextField.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TextField.java index 7002ad26f..4b062c6bd 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TextField.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TextField.java @@ -23,7 +23,28 @@ package me.shedaniel.rei.api.client.gui.widgets; -public interface TextField { +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import me.shedaniel.clothconfig2.api.TickableWidget; +import net.minecraft.network.chat.Style; +import net.minecraft.util.FormattedCharSequence; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Function; + +import static me.shedaniel.rei.api.client.gui.widgets.Widget.mouse; + +public interface TextField extends TickableWidget { + void setFormatter(TextFormatter formatter); + + TextFormatter getFormatter(); + + void setSuggestionRenderer(SuggestionRenderer renderer); + + SuggestionRenderer getSuggestionRenderer(); + String getText(); void setText(String text); @@ -57,4 +78,39 @@ public interface TextField { boolean isFocused(); void setFocused(boolean focused); + + void setFocusedFromKey(boolean focused, InputConstants.Key key); + + void setResponder(Consumer responder); + + void setFocusedResponder(BooleanConsumer responder); + + void setTextTransformer(Function textTransformer); + + @Nullable + String getSuggestion(); + + void setSuggestion(@Nullable String suggestion); + + void setBorderColorProvider(BorderColorProvider borderColorProvider); + + WidgetWithBounds asWidget(); + + interface TextFormatter { + TextFormatter DEFAULT = (text, index) -> { + return FormattedCharSequence.forward(text, Style.EMPTY); + }; + + FormattedCharSequence format(String text, int index); + } + + interface SuggestionRenderer { + void renderSuggestion(PoseStack matrices, int x, int y, int color); + } + + interface BorderColorProvider { + BorderColorProvider DEFAULT = textField -> textField.asWidget().containsMouse(mouse()) || textField.isFocused() ? 0xffffffff : 0xffa0a0a0; + + int getBorderColor(TextField textField); + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Tooltip.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Tooltip.java index dad0e9d59..e2d3511f1 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Tooltip.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Tooltip.java @@ -29,7 +29,7 @@ import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; @@ -66,8 +66,16 @@ static Tooltip create(@Nullable Point point, Component... texts) { return create(point, Arrays.asList(texts)); } + static Tooltip create(@Nullable TooltipContext context, Collection texts) { + return from(context, CollectionUtils.map(texts, Tooltip::entry)); + } + + static Tooltip create(@Nullable TooltipContext context, Component... texts) { + return create(context, Arrays.asList(texts)); + } + static Tooltip create(Collection texts) { - return create(null, texts); + return create((TooltipContext) null, texts); } static Tooltip create(Component... texts) { @@ -82,8 +90,16 @@ static Tooltip from(@Nullable Point point, Entry... entries) { return from(point, Arrays.asList(entries)); } + static Tooltip from(@Nullable TooltipContext context, Collection entries) { + return ClientInternals.createTooltip(context == null ? null : context.getPoint(), entries); + } + + static Tooltip from(@Nullable TooltipContext context, Entry... entries) { + return from(context, Arrays.asList(entries)); + } + static Tooltip from(Collection entries) { - return from(null, entries); + return from((TooltipContext) null, entries); } static Tooltip from(Entry... entries) { @@ -158,6 +174,9 @@ default Tooltip addAllTexts(Iterable text) { Tooltip withContextStack(EntryStack stack); + /** + * Queues this tooltip to be displayed. + */ default void queue() { EnvExecutor.runInEnv(Env.CLIENT, () -> () -> REIRuntime.getInstance().queueTooltip(this)); } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TooltipContext.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TooltipContext.java index 598bbc292..b2cabe322 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TooltipContext.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TooltipContext.java @@ -25,7 +25,7 @@ import me.shedaniel.math.Point; import me.shedaniel.math.impl.PointHelper; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.world.item.TooltipFlag; @@ -52,7 +52,7 @@ static TooltipContext of(Point point, @Nullable TooltipFlag flag, boolean isSear } static TooltipContext ofMouse() { - return TooltipContext.of(PointHelper.ofMouse()); + return TooltipContext.of(Widget.mouse()); } TooltipFlag getFlag(); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TooltipQueue.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TooltipQueue.java new file mode 100644 index 000000000..007cd777c --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/TooltipQueue.java @@ -0,0 +1,42 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.client.gui.widgets; + +import me.shedaniel.rei.impl.client.ClientInternals; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Experimental +public interface TooltipQueue { + static TooltipQueue getInstance() { + return ClientInternals.getTooltipQueue(); + } + + void queue(@Nullable Tooltip tooltip); + + void clear(); + + @Nullable + Tooltip get(); +} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widget.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widget.java index 2e683f51a..9f7fe44b9 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widget.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widget.java @@ -57,18 +57,18 @@ public abstract class Widget extends AbstractContainerEventHandler implements ne * The font for rendering text */ protected final Font font = minecraft.font; - private static final Stack mouseStack = new Stack<>(); + private static final Stack MOUSE_STACK = new Stack<>(); public static Point mouse() { - return mouseStack.empty() ? PointHelper.ofMouse() : mouseStack.peek(); + return MOUSE_STACK.empty() ? PointHelper.ofMouse() : MOUSE_STACK.peek(); } public static Point pushMouse(Point mouse) { - return mouseStack.push(mouse); + return MOUSE_STACK.push(mouse); } public static Point popMouse() { - return mouseStack.pop(); + return MOUSE_STACK.pop(); } public static Point translateMouse(PoseStack poses) { diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java index 028947c34..0183b480e 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java @@ -31,7 +31,7 @@ import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.DrawableConsumer; import me.shedaniel.rei.api.client.gui.Renderer; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -260,11 +260,7 @@ private static boolean shouldRecipeBaseRender(Panel panel) { public static Panel createSlotBase(Rectangle rectangle) { - return ClientInternals.getWidgetsProvider().createPanelWidget(rectangle).yTextureOffset(-66).rendering(Widgets::shouldSlotBaseRender); - } - - private static boolean shouldSlotBaseRender(Panel panel) { - return true; + return ClientInternals.getWidgetsProvider().createPanelWidget(rectangle).yTextureOffset(-66); } public static Panel createSlotBase(Rectangle rectangle, int color) { @@ -327,8 +323,17 @@ public static WidgetWithBounds padded(int padLeft, int padRight, int padTop, int return ClientInternals.getWidgetsProvider().wrapPadded(padLeft, padRight, padTop, padBottom, widget); } + public static TextField createTextField(Rectangle bounds) { + return ClientInternals.getWidgetsProvider().createTextField(bounds); + } + + @ApiStatus.Experimental + public static BatchedSlots createBatchedSlots() { + return ClientInternals.getWidgetsProvider().createBatchedSlots(); + } + public static Widget delegate(Supplier supplier) { - return new DelegateWidget(Widgets.noOp()) { + return new DelegateWidget() { @Override protected Widget delegate() { return supplier.get(); @@ -337,7 +342,7 @@ protected Widget delegate() { } public static WidgetWithBounds delegateWithBounds(Supplier supplier) { - return new DelegateWidgetWithBounds(Widgets.noOp(), Rectangle::new) { + return new DelegateWidgetWithBounds() { @Override protected WidgetWithBounds delegate() { return supplier.get(); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/overlay/OverlayListWidget.java b/api/src/main/java/me/shedaniel/rei/api/client/overlay/OverlayListWidget.java index 1fa784806..f72952d17 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/overlay/OverlayListWidget.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/overlay/OverlayListWidget.java @@ -54,4 +54,9 @@ public interface OverlayListWidget { * @return whether the mouse is within the overlay list widget */ boolean containsMouse(Point point); + + /** + * Queues reload of the search result. + */ + void queueReloadSearch(); } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/overlay/ScreenOverlay.java b/api/src/main/java/me/shedaniel/rei/api/client/overlay/ScreenOverlay.java index f7f5c481e..55f63b1b7 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/overlay/ScreenOverlay.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/overlay/ScreenOverlay.java @@ -23,24 +23,143 @@ package me.shedaniel.rei.api.client.overlay; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; +import me.shedaniel.rei.api.client.gui.widgets.TextField; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.client.search.SearchFilter; +import me.shedaniel.rei.api.common.display.Display; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; import java.util.Optional; @Environment(EnvType.CLIENT) public abstract class ScreenOverlay extends WidgetWithBounds { + public static Optional getInstance() { + return REIRuntime.getInstance().getOverlay(); + } + + /** + * Queues reload of the overlay. + */ public abstract void queueReloadOverlay(); + /** + * Queues reload of the search result. + */ public abstract void queueReloadSearch(); + /** + * Returns whether the overlay is queued to be reloaded. + * + * @return whether the overlay is queued to be reloaded + */ + public abstract boolean isOverlayReloadQueued(); + + /** + * Returns whether the search result is queued to be reloaded. + * + * @return whether the search result is queued to be reloaded + */ + public abstract boolean isSearchReloadQueued(); + + /** + * Returns the current dragging context. + * + * @return the current dragging context + */ public abstract DraggingContext getDraggingContext(); + /** + * Returns whether a specified point is within the bounds of the overlay. + * + * @param mouseX the x coordinate of the mouse + * @param mouseY the y coordinate of the mouse + * @return whether the point is within the bounds of the overlay + */ public abstract boolean isNotInExclusionZones(double mouseX, double mouseY); + /** + * Returns whether a specified bounds is within the bounds of the overlay. + * + * @param bounds the bounds to test + * @return whether the bounds is within the bounds of the overlay + */ + public boolean isNotInExclusionZones(Rectangle bounds) { + return isNotInExclusionZones(bounds.x, bounds.y) && + isNotInExclusionZones(bounds.getMaxX(), bounds.y) && + isNotInExclusionZones(bounds.x, bounds.getMaxY()) && + isNotInExclusionZones(bounds.getMaxX(), bounds.getMaxY()); + } + + /** + * Returns the entry list of the overlay. + * + * @return the entry list of the overlay + */ public abstract OverlayListWidget getEntryList(); + /** + * Returns the favorites list of the overlay. + * + * @return the favorites list of the overlay, or {@code null} if favorites are not enabled + */ public abstract Optional getFavoritesList(); + + /** + * Returns the search field of the overlay. + * + * @return the search field of the overlay + */ + public abstract TextField getSearchField(); + + /** + * Returns the current search filter. + * + * @return the current search filter + */ + @ApiStatus.Experimental + @Nullable + public abstract SearchFilter getCurrentSearchFilter(); + + /** + * Renders a tooltip. + * + * @param matrices the matrices transform + * @param tooltip the tooltip + */ + public abstract void renderTooltip(PoseStack matrices, Tooltip tooltip); + + /** + * Returns whether slot highlighting is on for the current search filter. + * + * @return whether slot highlighting is on for the current search filter. + */ + public abstract boolean isHighlighting(); + + /** + * Submits a display to the overlay history. + * + * @param display the display to submit + * @param fromBounds the bounds of the display + * @return whether the display was submitted + */ + @ApiStatus.Experimental + public abstract boolean submitDisplayHistory(Display display, @Nullable Rectangle fromBounds); + + /** + * Renders the late widgets. + * + * @param matrices the matrices transform + * @param mouseX the x-coordinate of the mouse + * @param mouseY the y-coordinate of the mouse + * @param delta the tick delta + */ + public abstract void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta); } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/registry/display/DisplayCategoryView.java b/api/src/main/java/me/shedaniel/rei/api/client/registry/display/DisplayCategoryView.java index 47f3b9803..e78ac4ff4 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/registry/display/DisplayCategoryView.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/registry/display/DisplayCategoryView.java @@ -66,7 +66,7 @@ public interface DisplayCategoryView { * for how the tooltip is resolved. *

* It is recommended to mark these slots for I/O using {@link Slot#markInput()} and {@link Slot#markOutput()}, - * and the background of the slots may be disabled using {@link Slot#disableBackground()}. + * and the background of the slots may be disabled using {@link Slot#noBackground()}. *

* Arbitrary text may be added to the widgets list with {@link Widgets#createLabel(Point, Component)}, * you may configure the horizontal alignment of the text using {@link Label#centered()}, diff --git a/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/CollapsibleEntry.java b/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/CollapsibleEntry.java new file mode 100644 index 000000000..a3623970a --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/CollapsibleEntry.java @@ -0,0 +1,42 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.client.registry.entry; + +import me.shedaniel.rei.api.common.entry.EntryStack; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental +public interface CollapsibleEntry { + ResourceLocation getId(); + + Component getName(); + + boolean matches(EntryStack stack, long hashExact); + + boolean isExpanded(); + + void setExpanded(boolean expanded); +} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/CollapsibleEntryRegistry.java b/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/CollapsibleEntryRegistry.java index c24ca5e2a..4de3468eb 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/CollapsibleEntryRegistry.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/CollapsibleEntryRegistry.java @@ -44,7 +44,7 @@ * and collect tags together. */ @ApiStatus.Experimental -public interface CollapsibleEntryRegistry extends Reloadable { +public interface CollapsibleEntryRegistry extends Reloadable, List { /** * @return the {@link CollapsibleEntryRegistry} instance */ diff --git a/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/EntryRegistry.java b/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/EntryRegistry.java index 63ed14d72..49dec73bb 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/EntryRegistry.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/EntryRegistry.java @@ -83,7 +83,9 @@ static EntryRegistry getInstance() { * @return the unmodifiable list of filtered entry stacks, * only available after plugins reload. */ - List> getPreFilteredList(); + default List> getPreFilteredList() { + return PreFilteredEntryList.getInstance().getList(); + } /** * Applies the filtering rules to the entry list, is rather computational expensive. @@ -154,7 +156,9 @@ default void addEntries(Collection> stacks) { // TODO Re-evaluate the need for this @ApiStatus.Internal - Collection> refilterNew(boolean warn, Collection> entries); + default Collection> refilterNew(boolean warn, Collection> entries) { + return PreFilteredEntryList.getInstance().refilterNew(warn, entries); + } /** * Checks if a stack is already registered. diff --git a/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/PreFilteredEntryList.java b/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/PreFilteredEntryList.java new file mode 100644 index 000000000..f05db2347 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/client/registry/entry/PreFilteredEntryList.java @@ -0,0 +1,50 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.client.registry.entry; + +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.registry.Reloadable; +import me.shedaniel.rei.impl.client.ClientInternals; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Collection; +import java.util.List; + +@ApiStatus.Experimental +public interface PreFilteredEntryList extends Reloadable { + static PreFilteredEntryList getInstance() { + return ClientInternals.getPreFilteredEntryList(); + } + + // TODO Re-evaluate the need for this + @ApiStatus.Internal + Collection> refilterNew(boolean warn, Collection> entries); + + /** + * @return the unmodifiable list of filtered entry stacks, + * only available after plugins reload. + */ + List> getList(); +} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/registry/screen/ClickArea.java b/api/src/main/java/me/shedaniel/rei/api/client/registry/screen/ClickArea.java index 3f6803d97..97d46001e 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/registry/screen/ClickArea.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/registry/screen/ClickArea.java @@ -25,7 +25,7 @@ import me.shedaniel.math.Point; import me.shedaniel.rei.api.common.category.CategoryIdentifier; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.screens.Screen; @@ -44,6 +44,20 @@ public interface ClickArea { @ApiStatus.NonExtendable interface ClickAreaContext { + static ClickAreaContext of(T screen, Point mouse) { + return new ClickAreaContext<>() { + @Override + public T getScreen() { + return screen; + } + + @Override + public Point getMousePosition() { + return mouse; + } + }; + } + T getScreen(); Point getMousePosition(); diff --git a/api/src/main/java/me/shedaniel/rei/api/client/registry/screen/ScreenRegistry.java b/api/src/main/java/me/shedaniel/rei/api/client/registry/screen/ScreenRegistry.java index d43b96be6..45d32737d 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/registry/screen/ScreenRegistry.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/registry/screen/ScreenRegistry.java @@ -25,6 +25,7 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.gui.config.DisplayPanelLocation; import me.shedaniel.rei.api.client.gui.drag.DraggableStackProvider; import me.shedaniel.rei.api.client.gui.drag.DraggableStackProviderWidget; @@ -49,14 +50,12 @@ import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.InteractionResult; import net.minecraft.world.inventory.AbstractContainerMenu; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; /** @@ -289,4 +288,20 @@ default boolean executeClickArea(Class screenClass, ClickA return false; } + + default boolean shouldDisplay(Screen screen) { + if (REIRuntime.getInstance().getOverlay().isEmpty()) return false; + if (screen == null) return false; + if (screen != Minecraft.getInstance().screen) return false; + try { + for (OverlayDecider decider : getDeciders(screen)) { + InteractionResult result = decider.shouldScreenBeOverlaid(screen); + if (result != InteractionResult.PASS) { + return result != InteractionResult.FAIL && REIRuntime.getInstance().getPreviousScreen() != null; + } + } + } catch (ConcurrentModificationException ignored) { + } + return false; + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/registry/transfer/TransferHandler.java b/api/src/main/java/me/shedaniel/rei/api/client/registry/transfer/TransferHandler.java index ec32d75aa..3945e9c63 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/registry/transfer/TransferHandler.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/registry/transfer/TransferHandler.java @@ -27,7 +27,7 @@ import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryIngredient; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; diff --git a/api/src/main/java/me/shedaniel/rei/api/client/search/SearchFilter.java b/api/src/main/java/me/shedaniel/rei/api/client/search/SearchFilter.java index 80b4987df..0bc7f8fff 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/search/SearchFilter.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/search/SearchFilter.java @@ -23,9 +23,12 @@ package me.shedaniel.rei.api.client.search; +import it.unimi.dsi.fastutil.ints.IntIntPair; import me.shedaniel.rei.api.common.entry.EntryStack; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.network.chat.Style; +import org.jetbrains.annotations.ApiStatus; import java.util.Collection; import java.util.function.Predicate; @@ -80,4 +83,21 @@ public boolean test(EntryStack entryStack) { */ default void prepareFilter(Collection> stacks) { } + + /** + * Processes the decoration of the search filter. + * + * @param sink the decoration sink + */ + @ApiStatus.Experimental + default void processDecoration(ParseDecorationSink sink) { + } + + interface ParseDecorationSink { + void addQuote(int index); + + void addSplitter(int index); + + void addPart(IntIntPair range, Style style, boolean usingGrammar, Collection grammarRanges, int index); + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/search/SearchProvider.java b/api/src/main/java/me/shedaniel/rei/api/client/search/SearchProvider.java index a337e5e17..9ec3af0b1 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/search/SearchProvider.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/search/SearchProvider.java @@ -58,4 +58,18 @@ default SearchFilter createFilter(String filter) { */ @ApiStatus.Experimental SearchFilter createFilter(String filter, InputMethod inputMethod); + + /** + * Clears the search cache. + */ + @ApiStatus.Experimental + void clearCache(); + + /** + * Returns whether the search provider has cached. + * + * @return whether the search provider has cached + */ + @ApiStatus.Experimental + boolean hasCache(); } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/view/ViewSearchBuilder.java b/api/src/main/java/me/shedaniel/rei/api/client/view/ViewSearchBuilder.java index 1afa8f04d..985048b7a 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/view/ViewSearchBuilder.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/view/ViewSearchBuilder.java @@ -31,7 +31,7 @@ import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import me.shedaniel.rei.impl.display.DisplaySpec; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -219,6 +219,21 @@ default ViewSearchBuilder addAllCategories() { */ ViewSearchBuilder processingVisibilityHandlers(boolean processingVisibilityHandlers); + /** + * Force-all displays to the view search builder. + * + * @param displays the displays to add + * @return the {@link ViewSearchBuilder} for chaining + */ + ViewSearchBuilder addDisplays(Collection displays); + + /** + * Returns the collection of additional displays to show. + * + * @return the collection of additional displays to show. + */ + Collection getAdditionalDisplays(); + /** * Opens the view after the search is complete. * diff --git a/api/src/main/java/me/shedaniel/rei/api/client/view/Views.java b/api/src/main/java/me/shedaniel/rei/api/client/view/Views.java index 407e4dfde..8855adcd9 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/view/Views.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/view/Views.java @@ -24,6 +24,7 @@ package me.shedaniel.rei.api.client.view; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.plugins.PluginManager; import me.shedaniel.rei.api.common.registry.Reloadable; @@ -31,6 +32,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; +import java.util.List; public interface Views extends Reloadable { /** @@ -45,6 +47,12 @@ static Views getInstance() { @ApiStatus.Experimental ViewSearchBuilder getContext(); + @ApiStatus.Experimental + boolean isRecipesFor(List> stacks, Display display); + + @ApiStatus.Experimental + boolean isUsagesFor(List> stacks, Display display); + /** * Returns all craftable items from materials. * diff --git a/api/src/main/java/me/shedaniel/rei/api/common/category/CategoryIdentifier.java b/api/src/main/java/me/shedaniel/rei/api/common/category/CategoryIdentifier.java index 8fd2136c0..001517a5c 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/category/CategoryIdentifier.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/category/CategoryIdentifier.java @@ -25,7 +25,7 @@ import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.util.Identifiable; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.Internals; import net.minecraft.ResourceLocationException; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; diff --git a/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryIngredient.java b/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryIngredient.java index fd6302218..27f37f620 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryIngredient.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryIngredient.java @@ -24,7 +24,7 @@ package me.shedaniel.rei.api.common.entry; import me.shedaniel.rei.api.common.entry.type.EntryDefinition; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.Internals; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import org.jetbrains.annotations.ApiStatus; diff --git a/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryStack.java b/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryStack.java index 0dcb10eda..2d2f3ca15 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryStack.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryStack.java @@ -37,7 +37,7 @@ import me.shedaniel.rei.api.common.entry.type.EntryType; import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry; import me.shedaniel.rei.api.common.util.TextRepresentable; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.Internals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.nbt.CompoundTag; diff --git a/api/src/main/java/me/shedaniel/rei/api/common/entry/comparison/EntryComparator.java b/api/src/main/java/me/shedaniel/rei/api/common/entry/comparison/EntryComparator.java index e24d41327..c30fb7aa7 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/entry/comparison/EntryComparator.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/entry/comparison/EntryComparator.java @@ -24,7 +24,7 @@ package me.shedaniel.rei.api.common.entry.comparison; import dev.architectury.fluid.FluidStack; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.Internals; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.world.item.ItemStack; diff --git a/api/src/main/java/me/shedaniel/rei/api/common/entry/type/EntryType.java b/api/src/main/java/me/shedaniel/rei/api/common/entry/type/EntryType.java index 6db72c191..69834c070 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/entry/type/EntryType.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/entry/type/EntryType.java @@ -25,7 +25,7 @@ import me.shedaniel.rei.api.client.entry.type.BuiltinClientEntryTypes; import me.shedaniel.rei.api.common.util.Identifiable; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.Internals; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; diff --git a/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkModule.java b/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkModule.java new file mode 100644 index 000000000..fd8e644d1 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkModule.java @@ -0,0 +1,54 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.common.networking; + +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Unit; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; +import java.util.Map; + +@ApiStatus.Experimental +public interface NetworkModule { + NetworkModuleKey DELETE_ITEM = new NetworkModuleKey<>() {}; + NetworkModuleKey CHEAT_GIVE = new NetworkModuleKey<>() {}; + NetworkModuleKey> CHEAT_HOTBAR = new NetworkModuleKey<>() {}; + NetworkModuleKey CHEAT_GRAB = new NetworkModuleKey<>() {}; + NetworkModuleKey> CHEAT_STATUS_REPLY = new NetworkModuleKey<>() {}; + NetworkModuleKey>> NOT_ENOUGH_ITEMS = new NetworkModuleKey<>() {}; + NetworkModuleKey TRANSFER = new NetworkModuleKey<>() {}; + + NetworkModuleKey getKey(); + + boolean canUse(Object target); + + void onInitialize(); + + void send(Object target, T data); + + record TransferData(CategoryIdentifier categoryIdentifier, boolean stacked, CompoundTag displayTag) {} +} diff --git a/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkModuleKey.java b/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkModuleKey.java new file mode 100644 index 000000000..155aff65a --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkModuleKey.java @@ -0,0 +1,27 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.common.networking; + +public interface NetworkModuleKey { +} diff --git a/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkingHelper.java b/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkingHelper.java new file mode 100644 index 000000000..5c1b7e9b9 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/common/networking/NetworkingHelper.java @@ -0,0 +1,63 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.common.networking; + +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.REIServerPlugin; +import me.shedaniel.rei.api.common.registry.Reloadable; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.server.level.ServerPlayer; + +import java.util.Objects; + +public interface NetworkingHelper extends Reloadable { + static NetworkingHelper getInstance() { + return PluginManager.getServerInstance().get(NetworkingHelper.class); + } + + boolean has(NetworkModuleKey moduleKey); + + boolean canUse(NetworkModuleKey moduleKey); + + boolean canPlayerUse(ServerPlayer player, NetworkModuleKey moduleKey); + + void send(Object target, NetworkModuleKey moduleKey, T data); + + default void sendToServer(NetworkModuleKey moduleKey, T data) { + send(null, moduleKey, data); + } + + default void sendToPlayer(ServerPlayer player, NetworkModuleKey moduleKey, T data) { + send(Objects.requireNonNull(player, "player"), moduleKey, data); + } + + @Environment(EnvType.CLIENT) + Client client(); + + @Environment(EnvType.CLIENT) + interface Client { + boolean hasOperatorPermission(); + } +} diff --git a/api/src/main/java/me/shedaniel/rei/api/common/plugins/PluginManager.java b/api/src/main/java/me/shedaniel/rei/api/common/plugins/PluginManager.java index a5b84b570..b42a5d8f5 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/plugins/PluginManager.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/plugins/PluginManager.java @@ -28,8 +28,8 @@ import me.shedaniel.rei.api.common.registry.ParentReloadable; import me.shedaniel.rei.api.common.registry.Reloadable; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.ClientInternals; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.common.Internals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import org.jetbrains.annotations.ApiStatus; @@ -63,6 +63,10 @@ static boolean areAnyReloading() { return CollectionUtils.anyMatch(getActiveInstances(), PluginManager::isReloading); } + static void reloadAll() { + Internals.reloadREI(); + } + boolean isReloading(); > T get(Class reloadableClass); diff --git a/api/src/main/java/me/shedaniel/rei/api/common/plugins/PluginView.java b/api/src/main/java/me/shedaniel/rei/api/common/plugins/PluginView.java index ff5584789..bda9797ca 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/plugins/PluginView.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/plugins/PluginView.java @@ -25,12 +25,14 @@ import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.common.registry.ReloadStage; -import me.shedaniel.rei.impl.ClientInternals; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.common.Internals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import org.jetbrains.annotations.ApiStatus; +import java.util.List; + @ApiStatus.Internal public interface PluginView

> { @Environment(EnvType.CLIENT) @@ -70,10 +72,17 @@ public void pre(ReloadStage stage) { public void post(ReloadStage stage) { PluginView.this.post(stage); } + + @Override + public List getObservedStages() { + return PluginView.this.getObservedStages(); + } }; } void pre(ReloadStage stage); void post(ReloadStage stage); + + List getObservedStages(); } diff --git a/api/src/main/java/me/shedaniel/rei/api/common/registry/ParentReloadable.java b/api/src/main/java/me/shedaniel/rei/api/common/registry/ParentReloadable.java index 44039e240..a6bfcea38 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/registry/ParentReloadable.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/registry/ParentReloadable.java @@ -24,6 +24,7 @@ package me.shedaniel.rei.api.common.registry; import me.shedaniel.rei.api.common.plugins.REIPlugin; +import me.shedaniel.rei.impl.common.Internals; import java.util.List; @@ -32,6 +33,10 @@ public interface ParentReloadable

> extends Reloadable

void registerReloadable(Reloadable reloadable); + default > void registerReloadable(Class reloadableClass) { + registerReloadable(Internals.resolveService(reloadableClass)); + } + @Override default void startReload() { for (ReloadStage stage : ReloadStage.values()) { diff --git a/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java b/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java index 1251f3728..365fc02f8 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/util/CollectionUtils.java @@ -489,6 +489,10 @@ public static Ingredient toIngredient(Iterable stacks) { @SafeVarargs public static List concatUnmodifiable(List... lists) { + return new ListConcatenationView<>(Arrays.asList(lists)); + } + + public static List concatUnmodifiable(Iterable> lists) { return new ListConcatenationView<>(lists); } @@ -496,10 +500,9 @@ public static List concatUnmodifiable(List... lists) { * A list which acts as view of the concatenation of a number of lists. */ private static class ListConcatenationView extends AbstractList { - private final List[] lists; + private final Iterable> lists; - @SafeVarargs - public ListConcatenationView(List... lists) { + public ListConcatenationView(Iterable> lists) { this.lists = lists; } diff --git a/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java b/api/src/main/java/me/shedaniel/rei/impl/client/ClientInternals.java similarity index 55% rename from api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java rename to api/src/main/java/me/shedaniel/rei/impl/client/ClientInternals.java index 2f4a8f45c..183452028 100644 --- a/api/src/main/java/me/shedaniel/rei/impl/ClientInternals.java +++ b/api/src/main/java/me/shedaniel/rei/impl/client/ClientInternals.java @@ -21,32 +21,28 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl; +package me.shedaniel.rei.impl.client; -import com.mojang.math.Matrix4f; import com.mojang.serialization.DataResult; import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.ClientHelper; import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleTypeRegistry; -import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.gui.DrawableConsumer; -import me.shedaniel.rei.api.client.gui.Renderer; -import me.shedaniel.rei.api.client.gui.widgets.*; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; +import me.shedaniel.rei.api.client.gui.widgets.TooltipQueue; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.entry.PreFilteredEntryList; import me.shedaniel.rei.api.client.registry.screen.ClickArea; import me.shedaniel.rei.api.client.view.ViewSearchBuilder; +import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.plugins.PluginManager; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import me.shedaniel.rei.impl.client.provider.*; +import me.shedaniel.rei.impl.common.Internals; +import net.minecraft.ReportedException; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.FormattedText; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.TooltipFlag; import org.apache.commons.lang3.function.TriFunction; @@ -54,31 +50,45 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; import java.util.Collection; import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Supplier; +import java.util.function.*; @ApiStatus.Internal public final class ClientInternals { - private static Supplier clientHelper = ClientInternals::throwNotSetup; - private static Supplier widgetsProvider = ClientInternals::throwNotSetup; - private static Supplier viewSearchBuilder = ClientInternals::throwNotSetup; - private static Supplier> clientPluginManager = ClientInternals::throwNotSetup; - private static Supplier> emptyEntryRenderer = ClientInternals::throwNotSetup; - private static Supplier filteringRuleTypeRegistry = ClientInternals::throwNotSetup; - private static BiFunction>, Supplier, FavoriteEntry> delegateFavoriteEntry = (supplier, toJson) -> throwNotSetup(); + private static final ClientHelper CLIENT_HELPER = resolveService(ClientHelper.class); + private static final WidgetsProvider WIDGETS_PROVIDER = resolveService(WidgetsProvider.class); + private static final ViewSearchBuilder VIEW_SEARCH_BUILDER = resolveService(ViewSearchBuilder.class); + private static final PluginManager CLIENT_PLUGIN_MANAGER = Internals.createPluginManager( + REIClientPlugin.class, + UnaryOperator.identity()); + private static final DelegatingFavoriteEntryProvider DELEGATE_FAVORITE_ENTRY = resolveService(DelegatingFavoriteEntryProvider.class); + private static final FavoritesEntriesListProvider FAVORITES_ENTRIES_LIST = resolveService(FavoritesEntriesListProvider.class); + private static final List OVERLAY_TICKERS = resolveServices(OverlayTicker.class); + private static final AutoCraftingEvaluator AUTO_CRAFTING_EVALUATOR = resolveService(AutoCraftingEvaluator.class); + private static final TooltipQueue TOOLTIP_QUEUE = resolveService(TooltipQueue.class); + private static final TooltipRenderer TOOLTIP_RENDERER = resolveService(TooltipRenderer.class); + private static final OverlayProvider SCREEN_OVERLAY_PROVIDER = resolveService(OverlayProvider.class); + private static final FilteringRuleTypeRegistry FILTERING_RULE_TYPE_REGISTRY = resolveService(FilteringRuleTypeRegistry.class); private static Function> favoriteEntryFromJson = (object) -> throwNotSetup(); private static Function clickAreaHandlerResult = (result) -> throwNotSetup(); - private static BiConsumer, TooltipComponent> clientTooltipComponentProvider = (tooltip, result) -> throwNotSetup(); private static BiFunction<@Nullable Point, Collection, Tooltip> tooltipProvider = (point, texts) -> throwNotSetup(); private static TriFunction tooltipContextProvider = (point, texts, search) -> throwNotSetup(); private static Function tooltipEntryProvider = (component) -> throwNotSetup(); private static Supplier> jeiCompatMods = ClientInternals::throwNotSetup; private static Supplier builtinClientPlugin = ClientInternals::throwNotSetup; - private static Function, TooltipComponent> missingTooltip = (stacks) -> throwNotSetup(); + private static final MissingStacksTooltipProvider MISSING_TOOLTIP = resolveService(MissingStacksTooltipProvider.class); + private static BiConsumer crashHandler = (exception, component) -> throwNotSetup(); + private static Supplier preFilteredEntryList = ClientInternals::throwNotSetup; + + public static T resolveService(Class serviceClass) { + return Internals.resolveService(serviceClass); + } + + public static List resolveServices(Class serviceClass) { + return Internals.resolveServices(serviceClass); + } private static T throwNotSetup() { throw new AssertionError("REI Internals have not been initialized!"); @@ -86,7 +96,18 @@ private static T throwNotSetup() { @ApiStatus.Internal public static void attachInstance(T instance, Class clazz) { - attachInstanceSupplier(instance, clazz.getSimpleName()); + try { + for (Field field : ClientInternals.class.getDeclaredFields()) { + if (field.getGenericType() instanceof ParameterizedType && ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0] == clazz) { + field.setAccessible(true); + field.set(null, (Supplier) () -> instance); + return; + } + } + throw new RuntimeException("Failed to attach " + instance + " with field type: " + clazz); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } } @ApiStatus.Internal @@ -110,15 +131,15 @@ public static void attachInstance(T instance, String name) { } public static ClientHelper getClientHelper() { - return clientHelper.get(); + return CLIENT_HELPER; } public static WidgetsProvider getWidgetsProvider() { - return widgetsProvider.get(); + return WIDGETS_PROVIDER; } public static ViewSearchBuilder createViewSearchBuilder() { - return viewSearchBuilder.get(); + return VIEW_SEARCH_BUILDER; } public static Object getBuiltinPlugin() { @@ -129,14 +150,18 @@ public static ClickArea.Result createClickAreaHandlerResult(boolean applicable) return clickAreaHandlerResult.apply(applicable); } - public static void getClientTooltipComponent(List tooltip, TooltipComponent component) { - clientTooltipComponentProvider.accept(tooltip, component); - } - public static Tooltip createTooltip(@Nullable Point point, Collection texts) { return tooltipProvider.apply(point, texts); } + public static TooltipRenderer getTooltipRenderer() { + return TOOLTIP_RENDERER; + } + + public static ScreenOverlay getNewOverlay() { + return SCREEN_OVERLAY_PROVIDER.provide(); + } + public static TooltipContext createTooltipContext(Point point, @Nullable TooltipFlag flag, boolean isSearch) { return tooltipContextProvider.apply(point, flag, isSearch); } @@ -146,15 +171,27 @@ public static Tooltip.Entry createTooltipEntry(Object component) { } public static FavoriteEntry delegateFavoriteEntry(Supplier> supplier, Supplier toJoin) { - return delegateFavoriteEntry.apply(supplier, toJoin); + return DELEGATE_FAVORITE_ENTRY.delegate(supplier, toJoin); } - public static DataResult favoriteEntryFromJson(CompoundTag tag) { - return favoriteEntryFromJson.apply(tag); + public static List getFavoritesEntriesList() { + return FAVORITES_ENTRIES_LIST.get(); + } + + public static List getOverlayTickers() { + return OVERLAY_TICKERS; + } + + public static AutoCraftingEvaluator.Builder getAutoCraftingEvaluator(Display display) { + return AUTO_CRAFTING_EVALUATOR.builder(display); } - public static EntryRenderer getEmptyEntryRenderer() { - return emptyEntryRenderer.get().cast(); + public static TooltipQueue getTooltipQueue() { + return TOOLTIP_QUEUE; + } + + public static DataResult favoriteEntryFromJson(CompoundTag tag) { + return favoriteEntryFromJson.apply(tag); } public static List getJeiCompatMods() { @@ -162,55 +199,22 @@ public static List getJeiCompatMods() { } public static PluginManager getPluginManager() { - return clientPluginManager.get(); + return CLIENT_PLUGIN_MANAGER; } public static TooltipComponent createMissingTooltip(List stacks) { - return missingTooltip.apply(stacks); + return MISSING_TOOLTIP.provide(stacks); + } + + public static PreFilteredEntryList getPreFilteredEntryList() { + return preFilteredEntryList.get(); } public static FilteringRuleTypeRegistry getFilteringRuleTypeRegistry() { - return filteringRuleTypeRegistry.get(); - } - - @Environment(EnvType.CLIENT) - public interface WidgetsProvider { - boolean isRenderingPanel(Panel panel); - - Widget wrapVanillaWidget(GuiEventListener element); - - WidgetWithBounds wrapRenderer(Supplier bounds, Renderer renderer); - - WidgetWithBounds withTranslate(WidgetWithBounds widget, Supplier translate); - - Widget createDrawableWidget(DrawableConsumer drawable); - - Slot createSlot(Point point); - - Slot createSlot(Rectangle bounds); - - Button createButton(Rectangle bounds, Component text); - - Panel createPanelWidget(Rectangle bounds); - - Label createLabel(Point point, FormattedText text); - - Arrow createArrow(Rectangle rectangle); - - BurningFire createBurningFire(Rectangle rectangle); - - DrawableConsumer createTexturedConsumer(ResourceLocation texture, int x, int y, int width, int height, float u, float v, int uWidth, int vHeight, int textureWidth, int textureHeight); - - DrawableConsumer createFillRectangleConsumer(Rectangle rectangle, int color); - - Widget createShapelessIcon(Point point); - - Widget concatWidgets(List widgets); - - WidgetWithBounds noOp(); - - WidgetWithBounds wrapOverflow(Rectangle bounds, WidgetWithBounds widget); - - WidgetWithBounds wrapPadded(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget); + return FILTERING_RULE_TYPE_REGISTRY; + } + + public static void crash(ReportedException exception, String component) { + crashHandler.accept(exception, component); } } diff --git a/api/src/main/java/me/shedaniel/rei/impl/client/provider/AutoCraftingEvaluator.java b/api/src/main/java/me/shedaniel/rei/impl/client/provider/AutoCraftingEvaluator.java new file mode 100644 index 000000000..413c13d8c --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/client/provider/AutoCraftingEvaluator.java @@ -0,0 +1,103 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.provider; + +import me.shedaniel.math.Point; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRenderer; +import me.shedaniel.rei.api.common.display.Display; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +public interface AutoCraftingEvaluator { + Builder builder(Display display); + + interface Builder { + Builder actuallyCraft(); + + default Builder actuallyCraft(boolean build) { + if (build) { + return actuallyCraft(); + } else { + return this; + } + } + + Builder stacked(); + + default Builder stacked(boolean build) { + if (build) { + return stacked(); + } else { + return this; + } + } + + Builder ids(@Nullable Collection ids); + + Builder buildRenderer(); + + default Builder buildRenderer(boolean build) { + if (build) { + return buildRenderer(); + } else { + return this; + } + } + + Builder buildTooltipRenderer(); + + default Builder buildTooltipRenderer(boolean build) { + if (build) { + return buildTooltipRenderer(); + } else { + return this; + } + } + + Result get(); + } + + interface Result { + int getTint(); + + boolean isSuccessful(); + + @Nullable + TransferHandler getSuccessfulHandler(); + + boolean isApplicable(); + + @Nullable + TransferHandlerRenderer getRenderer(); + + @Nullable + BiConsumer> getTooltipRenderer(); + } +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/client/provider/DelegatingFavoriteEntryProvider.java b/api/src/main/java/me/shedaniel/rei/impl/client/provider/DelegatingFavoriteEntryProvider.java new file mode 100644 index 000000000..48a773dca --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/client/provider/DelegatingFavoriteEntryProvider.java @@ -0,0 +1,37 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.provider; + +import com.mojang.serialization.DataResult; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import net.minecraft.nbt.CompoundTag; +import org.jetbrains.annotations.ApiStatus; +import org.spongepowered.asm.mixin.injection.Inject; + +import java.util.function.Supplier; + +@ApiStatus.Internal +public interface DelegatingFavoriteEntryProvider { + FavoriteEntry delegate(Supplier> result, Supplier tag); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/client/provider/FavoritesEntriesListProvider.java b/api/src/main/java/me/shedaniel/rei/impl/client/provider/FavoritesEntriesListProvider.java new file mode 100644 index 000000000..05205b1da --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/client/provider/FavoritesEntriesListProvider.java @@ -0,0 +1,34 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.provider; + +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; + +@ApiStatus.Internal +public interface FavoritesEntriesListProvider { + List get(); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/client/provider/MissingStacksTooltipProvider.java b/api/src/main/java/me/shedaniel/rei/impl/client/provider/MissingStacksTooltipProvider.java new file mode 100644 index 000000000..1d07c370f --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/client/provider/MissingStacksTooltipProvider.java @@ -0,0 +1,35 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.provider; + +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; + +@ApiStatus.Internal +public interface MissingStacksTooltipProvider { + TooltipComponent provide(List stacks); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/client/provider/OverlayProvider.java b/api/src/main/java/me/shedaniel/rei/impl/client/provider/OverlayProvider.java new file mode 100644 index 000000000..4d06bd4bd --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/client/provider/OverlayProvider.java @@ -0,0 +1,32 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.provider; + +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public interface OverlayProvider { + ScreenOverlay provide(); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/client/provider/OverlayTicker.java b/api/src/main/java/me/shedaniel/rei/impl/client/provider/OverlayTicker.java new file mode 100644 index 000000000..5f8fd1877 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/client/provider/OverlayTicker.java @@ -0,0 +1,31 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.provider; + +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public interface OverlayTicker { + void tick(); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/client/provider/TooltipRenderer.java b/api/src/main/java/me/shedaniel/rei/impl/client/provider/TooltipRenderer.java new file mode 100644 index 000000000..df510bee7 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/client/provider/TooltipRenderer.java @@ -0,0 +1,34 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.provider; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public interface TooltipRenderer { + void renderTooltip(Screen screen, PoseStack matrices, Tooltip tooltip, int mouseX, int mouseY); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/client/provider/WidgetsProvider.java b/api/src/main/java/me/shedaniel/rei/impl/client/provider/WidgetsProvider.java new file mode 100644 index 000000000..28d38c24c --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/client/provider/WidgetsProvider.java @@ -0,0 +1,84 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.provider; + +import com.mojang.math.Matrix4f; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.DrawableConsumer; +import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.gui.widgets.*; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; +import java.util.function.Supplier; + +@ApiStatus.Internal +public interface WidgetsProvider { + boolean isRenderingPanel(Panel panel); + + Widget wrapVanillaWidget(GuiEventListener element); + + WidgetWithBounds wrapRenderer(Supplier bounds, Renderer renderer); + + WidgetWithBounds withTranslate(WidgetWithBounds widget, Supplier translate); + + Widget createDrawableWidget(DrawableConsumer drawable); + + Slot createSlot(Point point); + + Slot createSlot(Rectangle bounds); + + Button createButton(Rectangle bounds, Component text); + + Panel createPanelWidget(Rectangle bounds); + + Label createLabel(Point point, FormattedText text); + + Arrow createArrow(Rectangle rectangle); + + BurningFire createBurningFire(Rectangle rectangle); + + DrawableConsumer createTexturedConsumer(ResourceLocation texture, int x, int y, int width, int height, float u, float v, int uWidth, int vHeight, int textureWidth, int textureHeight); + + DrawableConsumer createFillRectangleConsumer(Rectangle rectangle, int color); + + Widget createShapelessIcon(Point point); + + Widget concatWidgets(List widgets); + + WidgetWithBounds noOp(); + + WidgetWithBounds wrapOverflow(Rectangle bounds, WidgetWithBounds widget); + + WidgetWithBounds wrapPadded(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget); + + TextField createTextField(Rectangle bounds); + + BatchedSlots createBatchedSlots(); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/common/InternalLogger.java b/api/src/main/java/me/shedaniel/rei/impl/common/InternalLogger.java index 40f81129c..02cd5e4f2 100644 --- a/api/src/main/java/me/shedaniel/rei/impl/common/InternalLogger.java +++ b/api/src/main/java/me/shedaniel/rei/impl/common/InternalLogger.java @@ -23,7 +23,6 @@ package me.shedaniel.rei.impl.common; -import me.shedaniel.rei.impl.Internals; import org.apache.logging.log4j.Level; import org.jetbrains.annotations.ApiStatus; diff --git a/api/src/main/java/me/shedaniel/rei/impl/Internals.java b/api/src/main/java/me/shedaniel/rei/impl/common/Internals.java similarity index 53% rename from api/src/main/java/me/shedaniel/rei/impl/Internals.java rename to api/src/main/java/me/shedaniel/rei/impl/common/Internals.java index 1e64c2c57..b874aa7a2 100644 --- a/api/src/main/java/me/shedaniel/rei/impl/Internals.java +++ b/api/src/main/java/me/shedaniel/rei/impl/common/Internals.java @@ -21,51 +21,68 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl; +package me.shedaniel.rei.impl.common; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; -import me.shedaniel.rei.api.common.entry.EntryIngredient; -import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.comparison.EntryComparator; -import me.shedaniel.rei.api.common.entry.type.EntryDefinition; import me.shedaniel.rei.api.common.entry.type.EntryType; import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.PluginView; import me.shedaniel.rei.api.common.plugins.REIPlugin; import me.shedaniel.rei.api.common.plugins.REIServerPlugin; -import me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry; -import me.shedaniel.rei.impl.common.InternalLogger; +import me.shedaniel.rei.impl.common.provider.*; import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Unit; import org.jetbrains.annotations.ApiStatus; import java.lang.reflect.Field; -import java.util.function.Function; +import java.util.List; +import java.util.ServiceLoader; import java.util.function.Supplier; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; @ApiStatus.Internal public final class Internals { - private static Supplier entryStackProvider = Internals::throwNotSetup; - private static Supplier entryIngredientProvider = Internals::throwNotSetup; - private static Function> entryTypeDeferred = (object) -> throwNotSetup(); - private static Supplier>> commonPluginManager = Internals::throwNotSetup; - private static Supplier> serverPluginManager = Internals::throwNotSetup; - private static Supplier nbtHasherProvider = Internals::throwNotSetup; - private static Function> categoryIdentifier = (object) -> throwNotSetup(); - private static Supplier stubMenuInfoRegistry = Internals::throwNotSetup; + private static final EntryStackProvider ENTRY_STACK_PROVIDER = resolveService(EntryStackProvider.class); + private static final EntryIngredientProvider ENTRY_INGREDIENT_PROVIDER = resolveService(EntryIngredientProvider.class); + private static final DeferringEntryTypeProvider ENTRY_TYPE_DEFERRED = resolveService(DeferringEntryTypeProvider.class); + private static final PluginManagerConstructor PLUGIN_MANAGER_CONSTRUCTOR = resolveService(PluginManagerConstructor.class); + private static final PluginManager> COMMON_PLUGIN_MANAGER = createPluginManager( + (Class>) (Class) REIPlugin.class, + UnaryOperator.identity()); + private static final PluginManager SERVER_PLUGIN_MANAGER = createPluginManager( + REIServerPlugin.class, + view -> view.then(COMMON_PLUGIN_MANAGER.view())); + private static final NbtHasherProvider NBT_HASHER_PROVIDER = resolveService(NbtHasherProvider.class); + private static final CategoryIdentifierConstructor CATEGORY_IDENTIFIER_CONSTRUCTOR = resolveService(CategoryIdentifierConstructor.class); private static Supplier logger = Internals::throwNotSetup; + private static Runnable reloadREI = Internals::throwNotSetup; private static T throwNotSetup() { throw new AssertionError("REI Internals have not been initialized!"); } - @ApiStatus.Internal - public static void attachInstance(T instance, Class clazz) { - attachInstanceSupplier(instance, clazz.getSimpleName()); + public static T resolveService(Class serviceClass) { + ServiceLoader loader = ServiceLoader.load(serviceClass); + List> providers = loader.stream().toList(); + if (providers.isEmpty()) { + throw new IllegalArgumentException("No service providers found for class " + serviceClass.getName()); + } else if (providers.size() > 1) { + throw new IllegalArgumentException("Multiple service providers found for class " + serviceClass.getName() + ": " + + providers.stream().map(provider -> provider.type().getName()) + .collect(Collectors.joining(", "))); + } else { + return providers.get(0).get(); + } + } + + public static List resolveServices(Class serviceClass) { + ServiceLoader loader = ServiceLoader.load(serviceClass); + return loader.stream().map(ServiceLoader.Provider::get).toList(); } - @ApiStatus.Internal public static void attachInstanceSupplier(T instance, String name) { attachInstance((Supplier) () -> instance, name); } @@ -86,58 +103,42 @@ public static void attachInstance(T instance, String name) { } public static EntryStackProvider getEntryStackProvider() { - return entryStackProvider.get(); + return ENTRY_STACK_PROVIDER; } public static EntryIngredientProvider getEntryIngredientProvider() { - return entryIngredientProvider.get(); + return ENTRY_INGREDIENT_PROVIDER; } public static EntryType deferEntryType(ResourceLocation id) { - return entryTypeDeferred.apply(id); + return ENTRY_TYPE_DEFERRED.get(id); + } + + public static

> PluginManager

createPluginManager(Class

clazz, UnaryOperator> constructor) { + return PLUGIN_MANAGER_CONSTRUCTOR.create(clazz, constructor); } public static PluginManager> getPluginManager() { - return commonPluginManager.get(); + return COMMON_PLUGIN_MANAGER; } public static PluginManager getServerPluginManager() { - return serverPluginManager.get(); + return SERVER_PLUGIN_MANAGER; } public static EntryComparator getNbtHasher(String[] ignoredKeys) { - return nbtHasherProvider.get().provide(ignoredKeys); + return NBT_HASHER_PROVIDER.provide(ignoredKeys); } public static CategoryIdentifier getCategoryIdentifier(String location) { - return (CategoryIdentifier) categoryIdentifier.apply(location); + return CATEGORY_IDENTIFIER_CONSTRUCTOR.create(location); } public static InternalLogger getInternalLogger() { return logger.get(); } - public interface EntryStackProvider { - EntryStack empty(); - - EntryStack of(EntryDefinition definition, T value); - } - - public interface EntryIngredientProvider { - EntryIngredient empty(); - - EntryIngredient of(EntryStack stack); - - EntryIngredient of(EntryStack... stacks); - - EntryIngredient of(Iterable> stacks); - - EntryIngredient.Builder builder(); - - EntryIngredient.Builder builder(int initialCapacity); - } - - public interface NbtHasherProvider { - EntryComparator provide(String... ignoredKeys); + public static void reloadREI() { + reloadREI.run(); } } diff --git a/api/src/main/java/me/shedaniel/rei/impl/common/provider/CategoryIdentifierConstructor.java b/api/src/main/java/me/shedaniel/rei/impl/common/provider/CategoryIdentifierConstructor.java new file mode 100644 index 000000000..a316f7605 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/common/provider/CategoryIdentifierConstructor.java @@ -0,0 +1,33 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.provider; + +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.display.Display; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public interface CategoryIdentifierConstructor { + CategoryIdentifier create(String location); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/common/provider/DeferringEntryTypeProvider.java b/api/src/main/java/me/shedaniel/rei/impl/common/provider/DeferringEntryTypeProvider.java new file mode 100644 index 000000000..eb2240988 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/common/provider/DeferringEntryTypeProvider.java @@ -0,0 +1,33 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.provider; + +import me.shedaniel.rei.api.common.entry.type.EntryType; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public interface DeferringEntryTypeProvider { + EntryType get(ResourceLocation id); +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuEntry.java b/api/src/main/java/me/shedaniel/rei/impl/common/provider/EntryIngredientProvider.java similarity index 72% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuEntry.java rename to api/src/main/java/me/shedaniel/rei/impl/common/provider/EntryIngredientProvider.java index c2cf89925..5d86576a1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuEntry.java +++ b/api/src/main/java/me/shedaniel/rei/impl/common/provider/EntryIngredientProvider.java @@ -21,24 +21,23 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules; +package me.shedaniel.rei.impl.common.provider; -import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.api.common.entry.EntryStack; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal -public abstract class MenuEntry extends Widget { - @ApiStatus.Internal - @Deprecated - Menu parent = null; +public interface EntryIngredientProvider { + EntryIngredient empty(); - public final Menu getParent() { - return parent; - } + EntryIngredient of(EntryStack stack); - public abstract int getEntryWidth(); + EntryIngredient of(EntryStack... stacks); - public abstract int getEntryHeight(); + EntryIngredient of(Iterable> stacks); - public abstract void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width); + EntryIngredient.Builder builder(); + + EntryIngredient.Builder builder(int initialCapacity); } diff --git a/api/src/main/java/me/shedaniel/rei/impl/common/provider/EntryStackProvider.java b/api/src/main/java/me/shedaniel/rei/impl/common/provider/EntryStackProvider.java new file mode 100644 index 000000000..91629b0ae --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/common/provider/EntryStackProvider.java @@ -0,0 +1,36 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.provider; + +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.entry.type.EntryDefinition; +import net.minecraft.util.Unit; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public interface EntryStackProvider { + EntryStack empty(); + + EntryStack of(EntryDefinition definition, T value); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/common/provider/NbtHasherProvider.java b/api/src/main/java/me/shedaniel/rei/impl/common/provider/NbtHasherProvider.java new file mode 100644 index 000000000..8cd56cc6e --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/common/provider/NbtHasherProvider.java @@ -0,0 +1,33 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.provider; + +import me.shedaniel.rei.api.common.entry.comparison.EntryComparator; +import net.minecraft.nbt.Tag; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public interface NbtHasherProvider { + EntryComparator provide(String... ignoredKeys); +} diff --git a/api/src/main/java/me/shedaniel/rei/impl/common/provider/PluginManagerConstructor.java b/api/src/main/java/me/shedaniel/rei/impl/common/provider/PluginManagerConstructor.java new file mode 100644 index 000000000..ce530af90 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/common/provider/PluginManagerConstructor.java @@ -0,0 +1,36 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.provider; + +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.PluginView; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.UnaryOperator; + +@ApiStatus.Internal +public interface PluginManagerConstructor { +

> PluginManager

create(Class

clazz, UnaryOperator> constructor); +} diff --git a/build.gradle b/build.gradle index 3fefac531..501dcb541 100755 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,16 @@ +//file:noinspection UnnecessaryQualifiedReference +buildscript { + repositories { + maven { url "https://maven.architectury.dev/" } + mavenCentral() + } + + dependencies { + classpath "com.guardsquare:proguard-gradle:7.2.1" + classpath "dev.architectury:architectury-transformer:5.2.68" + } +} + plugins { id("architectury-plugin") version("3.4-SNAPSHOT") id("dev.architectury.loom") version("0.12.0-SNAPSHOT") apply false @@ -13,6 +26,44 @@ version = rootProject.base_version + "." + runNumber + (rootProject.unstable.toB group = "me.shedaniel" +allprojects { + ext { + runtimeEngines = [ + ":runtime-engine:logging", + ":runtime-engine:entry-types", + ":runtime-engine:entry-stacks", + ":runtime-engine:categories", + ":runtime-engine:configs", + ":runtime-engine:displays", + ":runtime-engine:filtering-entries", + ":runtime-engine:entries", + ":runtime-engine:screens", + ":runtime-engine:favorites", + ":runtime-engine:search", + ":runtime-engine:subsets", + ":runtime-engine:transfer-handlers", + ":runtime-engine:menu-info", + ":runtime-engine:plugins", + ":runtime-engine:views", + ":runtime-engine:default-runtime-plugin", + ":runtime-engine:initialization", + ":runtime-engine:networking", + ":runtime-frontend:widgets", + ":runtime-frontend:filtering", + ":runtime-frontend:display", + ":runtime-frontend:overlay", + ":runtime-frontend:overlay-entries", + ":runtime-frontend:favorites-entries", + ] + depProjects = [ + ":api", + ":shared-internals", + ":runtime", + ":default-plugin", + ] + runtimeEngines + } +} + subprojects { apply plugin: "me.shedaniel.unified-publishing" apply plugin: "java" @@ -53,7 +104,6 @@ subprojects { mods { main { // to match the default mod generated for Forge sourceSet project.sourceSets.main - def depProjects = [":api", ":runtime", ":default-plugin"] depProjects.each { sourceSet project(it).sourceSets.main } @@ -94,14 +144,88 @@ allprojects { } } -["api", "default-plugin", "runtime"].forEach { +subprojects { + if (project.path in depProjects) { + loom { + if (project.path != ":api") { + accessWidenerPath = gradle.rootProject.project("fabric").file("src/main/resources/roughlyenoughitems.accessWidener") + } + } + + architectury { + common(forgeEnabled.toBoolean() ? ["forge", "fabric"] : ["fabric"]) + } + + dependencies { + modCompileOnly("net.fabricmc:fabric-loader:${project.fabricloader_version}") + modApi("me.shedaniel.cloth:cloth-config:${cloth_config_version}") + modApi("dev.architectury:architectury:${architectury_version}") + + if (project.path != ":api") { + compileClasspath(project(path: ":api", configuration: "namedElements")) + + if (project.path != ":shared-internals") { + compileClasspath(project(path: ":shared-internals", configuration: "namedElements")) + } + } + } + + remapJar { + classifier "raw" + } + + task fakeJar(type: Jar, dependsOn: remapJar) { + from remapJar.archiveFile.map { zipTree(it) } + from(rootProject.file("fake/fabric.mod.json")) { + into "" + } + classifier null + } + + task fakeForgeJar(type: Jar, dependsOn: remapJar) { + from remapJar.archiveFile.map { zipTree(it) } + from(rootProject.file("fake/fabric.mod.json")) { + into "" + } + from(rootProject.file("fake/REIPlugin.class")) { + into "me/shedaniel/rei/forge" + } + classifier "fake-forge" + } + + artifacts { + apiElements(fakeJar) + runtimeElements(fakeJar) + } + + afterEvaluate { + configurations.apiElements.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.remapJar) } + configurations.runtimeElements.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.remapJar) } + } + + publishing { + publications { + mavenCommon(MavenPublication) { + artifactId = rootProject.name + "-" + project.name + from components.java + } + } + } + } + + sourcesJar { + duplicatesStrategy DuplicatesStrategy.WARN + } +} + +depProjects.forEach { project(":fabric").evaluationDependsOn(":$it") } subprojects { group = rootProject.group version = rootProject.version - archivesBaseName = rootProject.name + archivesBaseName = rootProject.name + "-" + project.name publishing { repositories { @@ -158,3 +282,146 @@ task releaseOnCf { dependsOn project("fabric").tasks.getByName("publishUnified") } } + +def randomString(len) { + def AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + def rnd = new java.security.SecureRandom() + return (0..len).toList().collect { AB.charAt(rnd.nextInt(AB.length())) }.join("") +} + +rootProject.file(".gradle/proguard-dictionary.txt").delete() +rootProject.file(".gradle/proguard-dictionary.txt").write((0..1000).toList().collect { randomString(10) }.join("\n")) + +["fabric", "forge"].each { loader -> + project(":$loader") { + afterEvaluate { + def proguardJarOut = file(tasks.getByName("shadowJar").archiveFile.get().getAsFile().absolutePath.replace(".jar", "-min.jar")) + + task proguardJar(type: proguard.gradle.ProGuardTask, dependsOn: ["shadowJar"]) { + doFirst { + if (proguardJarOut.exists()) { + proguardJarOut.delete() + } + } + + verbose() + injars tasks.getByName("shadowJar").archiveFile.get().getAsFile() + outjars proguardJarOut + libraryjars files(configurations.compileClasspath) + libraryjars "${System.getProperty('java.home')}/jmods/java.base.jmod", jarfilter: '!**.jar', filter: '!module-info.class' + dontshrink() + keep "class me.shedaniel.rei.api.** { *; }" + keep "class me.shedaniel.rei.plugin.** { *; }" + keepclassmembers "class * { void onInitialize(); void onInitializeClient(); }" + keepclassmembers "class * { @net.minecraft.obfuscate.DontObfuscate ; @net.minecraft.obfuscate.DontObfuscate ; }" + keepclassmembers "class me.shedaniel.rei.impl.*Internals { ; }" + keepclassmembers "class me.shedaniel.rei.impl.client.config.ConfigObjectImpl* { ; }" + dontwarn "me.shedaniel.rei.impl.init.RoughlyEnoughItemsInitializer" + dontwarn "me.shedaniel.rei.plugin.client.DefaultClientPlugin" + obfuscationdictionary rootProject.file(".gradle/proguard-dictionary.txt") + classobfuscationdictionary rootProject.file(".gradle/proguard-dictionary.txt") + repackageclasses "me.shedaniel.rei.impl.${randomString(10)}" + keep "class me.shedaniel.rei.mixin.$loader.** { *; }" + keepattributes "Signature,SourceFile,LineNumberTable,Exceptions,InnerClasses,*Annotation*" + printmapping file(".gradle/proguard-mapping.txt") + optimizationpasses 5 + optimizations "**" + allowaccessmodification() + + doLast { + try (def access = dev.architectury.transformer.input.OpenedFileAccess.ofJar(proguardJarOut.toPath())) { + dev.architectury.transformer.Transform.runTransformers( + new dev.architectury.transformer.transformers.base.edit.SimpleTransformerContext(args -> { throw new IllegalStateException(); }, + true, false, true), + dev.architectury.transformer.transformers.ClasspathProvider.of(files(configurations.compileClasspath).collect { it.toPath() }), + proguardJarOut.name, + access, transformers(loader)) + } + } + } + + tasks.prepareRemapJar { + inputFile.set proguardJarOut + dependsOn proguardJar + } + + tasks.remapJar { + input.set proguardJarOut + dependsOn proguardJar + } + } + } +} + +def transformers(loader) { + def map = new HashMap(); + file(".gradle/proguard-mapping.txt").eachLine { + if (!it.startsWith(" ")) { + map[it.split(" -> ")[0]] = it.split(" -> ")[1].split(":")[0] + } + } + return [new dev.architectury.transformer.transformers.base.ClassEditTransformer() { + @Override + dev.architectury.transformer.shadowed.impl.org.objectweb.asm.tree.ClassNode doEdit(String name, dev.architectury.transformer.shadowed.impl.org.objectweb.asm.tree.ClassNode node) { + if (dev.architectury.transformer.Transform.trimSlashes(name).startsWith("me/shedaniel/rei/impl")) { + if (node.invisibleAnnotations == null || !node.invisibleAnnotations.any { it.desc == "Lorg/jetbrains/annotations/ApiStatus\$Internal;" }) { + if (node.invisibleAnnotations == null) node.invisibleAnnotations = new ArrayList<>() + node.invisibleAnnotations.add(new dev.architectury.transformer.shadowed.impl.org.objectweb.asm.tree.AnnotationNode("Lorg/jetbrains/annotations/ApiStatus\$Internal;")) + } + } + + node.methods.forEach { method -> + method.instructions.forEach { insn -> + if (insn.opcode == dev.architectury.transformer.shadowed.impl.org.objectweb.asm.Opcodes.LDC + && insn instanceof dev.architectury.transformer.shadowed.impl.org.objectweb.asm.tree.LdcInsnNode + && insn.cst instanceof String) { + if (insn.cst.contains("%s")) { + def replaced = insn.cst.replace("%s", loader) + + if (map.containsKey(replaced)) { + insn.cst = map[replaced] + } + } else { + insn.cst = map.getOrDefault(insn.cst, insn.cst) + } + } + } + } + + return node + } + }, new dev.architectury.transformer.transformers.base.AssetEditTransformer() { + @Override + void doEdit(dev.architectury.transformer.transformers.base.edit.TransformerContext context, dev.architectury.transformer.input.FileAccess output) throws Exception { + def renames = [] + output.handle((java.util.function.Consumer) { String name -> + def trimmed = dev.architectury.transformer.Transform.trimSlashes(name) + if (trimmed.startsWith("META-INF/services/")) { + output.modifyFile(trimmed) { bytes -> + new String(bytes).split("\n").collect { map[it] ?: it }.join("\n").bytes + } + + def remapped = map[trimmed.substring("META-INF/services/".length())] + if (remapped != null) { + renames << [trimmed, "META-INF/services/$remapped"] + } + } + }) + renames.each { + output.addFile(it[1], output.getFile(it[0])) + output.deleteFile(it[0]) + } + + output.modifyFile("fabric.mod.json") { bytes -> + new String(bytes).split("\n").collect { + map.forEach { k, v -> + it = it.replace("\"$k\"", "\"$v\"") + it = it.replace("\"$k::onInitialize\"", "\"$v::onInitialize\"") + it = it.replace("\"$k::onInitializeClient\"", "\"$v::onInitializeClient\"") + } + it + }.join("\n").bytes + } + } + }] +} diff --git a/default-plugin/build.gradle b/default-plugin/build.gradle deleted file mode 100644 index c47536992..000000000 --- a/default-plugin/build.gradle +++ /dev/null @@ -1,61 +0,0 @@ -archivesBaseName = rootProject.name + "-" + project.name - -loom { - accessWidenerPath = gradle.rootProject.project("fabric").file("src/main/resources/roughlyenoughitems.accessWidener") -} - -dependencies { - modCompileOnly("net.fabricmc:fabric-loader:${project.fabricloader_version}") - modApi("me.shedaniel.cloth:cloth-config:${cloth_config_version}") - modApi("dev.architectury:architectury:${architectury_version}") - compileClasspath(project(path: ":api", configuration: "namedElements")) -} - -architectury { - common(forgeEnabled.toBoolean()) -} - -remapJar { - classifier "raw" -} - -task fakeJar(type: Jar, dependsOn: remapJar) { - from remapJar.archiveFile.map { zipTree(it) } - from(rootProject.file("fake/fabric.mod.json")) { - into "" - } - classifier null -} - -task fakeForgeJar(type: Jar, dependsOn: jar) { - from jar.archiveFile.map { zipTree(it) } - from(rootProject.file("fake/mods.toml")) { - into "META-INF" - } - ["REIPlugin", "REIPluginClient", "REIPluginCommon", "REIPluginDedicatedServer", - "REIPluginLoader", "REIPluginLoaderClient", "REIPluginLoaderCommon", "REIPluginLoaderDedicatedServer"].each { - from(rootProject.file("fake/$it.class")) { - into "me/shedaniel/rei/forge" - } - } - classifier "fake-forge" -} - -artifacts { - apiElements(fakeJar) - runtimeElements(fakeJar) -} - -afterEvaluate { - configurations.apiElements.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.remapJar) } - configurations.runtimeElements.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.remapJar) } -} - -publishing { - publications { - mavenCommon(MavenPublication) { - artifactId = rootProject.name + "-" + project.name - from components.java - } - } -} diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/autocrafting/recipebook/DefaultRecipeBookHandler.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/autocrafting/recipebook/DefaultRecipeBookHandler.java index f6d23677c..d4790e4b4 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/autocrafting/recipebook/DefaultRecipeBookHandler.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/autocrafting/recipebook/DefaultRecipeBookHandler.java @@ -23,15 +23,15 @@ package me.shedaniel.rei.plugin.autocrafting.recipebook; -import me.shedaniel.rei.api.client.ClientHelper; import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.display.SimpleGridMenuDisplay; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; import me.shedaniel.rei.plugin.common.displays.cooking.DefaultCookingDisplay; import me.shedaniel.rei.plugin.common.displays.crafting.DefaultCraftingDisplay; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.recipebook.RecipeUpdateListener; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.inventory.CraftingMenu; @@ -43,7 +43,7 @@ public class DefaultRecipeBookHandler implements TransferHandler { @Override public Result handle(Context context) { - if (context.getDisplay() instanceof SimpleGridMenuDisplay && ClientHelper.getInstance().canUseMovePackets()) + if (context.getDisplay() instanceof SimpleGridMenuDisplay && NetworkingHelper.getInstance().canUse(NetworkModule.TRANSFER)) return Result.createNotApplicable(); Display display = context.getDisplay(); if (!(context.getMenu() instanceof RecipeBookMenu container)) diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/BuiltinClientPlugin.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/BuiltinClientPlugin.java index 74c3f3440..0b5ff391f 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/BuiltinClientPlugin.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/BuiltinClientPlugin.java @@ -25,7 +25,7 @@ import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import me.shedaniel.rei.plugin.common.BuiltinPlugin; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientPlugin.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientPlugin.java index 179d9937a..1c83c8050 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientPlugin.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientPlugin.java @@ -26,13 +26,23 @@ import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; import dev.architectury.platform.Platform; import it.unimi.dsi.fastutil.objects.Object2FloatMap; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import it.unimi.dsi.fastutil.objects.ReferenceSet; import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.ClientHelper; +import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.client.gui.AbstractRenderer; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProviderWidget; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitorWidget; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; @@ -40,11 +50,12 @@ import me.shedaniel.rei.api.client.registry.screen.ExclusionZones; import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; +import me.shedaniel.rei.api.client.util.ClientEntryStacks; import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.EntryIngredients; import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import me.shedaniel.rei.plugin.autocrafting.recipebook.DefaultRecipeBookHandler; import me.shedaniel.rei.plugin.client.categories.*; import me.shedaniel.rei.plugin.client.categories.anvil.DefaultAnvilCategory; @@ -55,6 +66,7 @@ import me.shedaniel.rei.plugin.client.categories.tag.DefaultTagCategory; import me.shedaniel.rei.plugin.client.exclusionzones.DefaultPotionEffectExclusionZones; import me.shedaniel.rei.plugin.client.exclusionzones.DefaultRecipeBookExclusionZones; +import me.shedaniel.rei.plugin.client.favorites.EntryStackFavoriteEntry; import me.shedaniel.rei.plugin.client.favorites.GameModeFavoriteEntry; import me.shedaniel.rei.plugin.client.favorites.TimeFavoriteEntry; import me.shedaniel.rei.plugin.client.favorites.WeatherFavoriteEntry; @@ -77,6 +89,7 @@ import net.minecraft.client.gui.screens.recipebook.RecipeUpdateListener; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.BlockTags; @@ -97,7 +110,9 @@ import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import java.time.LocalDateTime; import java.util.*; import java.util.function.Supplier; import java.util.function.UnaryOperator; @@ -135,6 +150,24 @@ public void registerEntries(EntryRegistry registry) { registry.addEntry(EntryStacks.of(fluid)); } } + + if (LocalDateTime.now().getMonthValue() == 4 && LocalDateTime.now().getDayOfMonth() == 1) { + registry.addEntry(ClientEntryStacks.of(new AbstractRenderer() { + private final ResourceLocation id = new ResourceLocation("roughlyenoughitems", "textures/gui/kirb.png"); + + @Override + public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { + RenderSystem.setShaderTexture(0, id); + innerBlit(matrices.last().pose(), bounds.x, bounds.getMaxX(), bounds.y, bounds.getMaxY(), getBlitOffset(), 0, 1, 0, 1); + } + + @Override + @Nullable + public Tooltip getTooltip(TooltipContext context) { + return Tooltip.create(context, new TextComponent("Kirby"), ClientHelper.getInstance().getFormattedModFromModId("Dream Land")); + } + })); + } } @Override @@ -327,7 +360,6 @@ public void registerDisplays(DisplayRegistry registry) { } protected void registerForgePotions(DisplayRegistry registry, BuiltinClientPlugin clientPlugin) { - } @Override @@ -344,6 +376,17 @@ public void registerScreens(ScreenRegistry registry) { registry.registerContainerClickArea(new Rectangle(78, 32, 28, 23), FurnaceScreen.class, SMELTING); registry.registerContainerClickArea(new Rectangle(78, 32, 28, 23), SmokerScreen.class, SMOKING); registry.registerContainerClickArea(new Rectangle(78, 32, 28, 23), BlastFurnaceScreen.class, BLASTING); + + registry.registerDraggableComponentProvider(DraggableComponentProviderWidget.from(context -> { + if (!ScreenRegistry.getInstance().shouldDisplay(context.getScreen()) || !REIRuntime.getInstance().isOverlayVisible()) + return Collections.emptyList(); + return Widgets.walk(REIRuntime.getInstance().getOverlay().get().children(), DraggableComponentProviderWidget.class::isInstance); + })); + registry.registerDraggableComponentVisitor(DraggableComponentVisitorWidget.from(context -> { + if (!ScreenRegistry.getInstance().shouldDisplay(context.getScreen()) || !REIRuntime.getInstance().isOverlayVisible()) + return Collections.emptyList(); + return Widgets.walk(REIRuntime.getInstance().getOverlay().get().children(), DraggableComponentVisitorWidget.class::isInstance); + })); } @Override @@ -353,6 +396,7 @@ public void registerTransferHandlers(TransferHandlerRegistry registry) { @Override public void registerFavorites(FavoriteEntryType.Registry registry) { + registry.register(FavoriteEntryType.ENTRY_STACK, EntryStackFavoriteEntry.Type.INSTANCE); registry.register(GameModeFavoriteEntry.ID, GameModeFavoriteEntry.Type.INSTANCE); registry.getOrCrateSection(new TranslatableComponent(GameModeFavoriteEntry.TRANSLATION_KEY)) .add(Stream.concat( diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultBrewingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultBrewingCategory.java index 9e020da89..d52357628 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultBrewingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultBrewingCategory.java @@ -74,12 +74,12 @@ public List setupDisplay(DefaultBrewingDisplay display, Rectangle bounds int width = Mth.ceil(System.currentTimeMillis() / 250d % 18d); helper.blit(matrices, startPoint.x + 44, startPoint.y + 28, 103, 163, width, 4); })); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 1, startPoint.y + 1)).entry(EntryStacks.of(Items.BLAZE_POWDER)).disableBackground().markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 40, startPoint.y + 1)).entries(display.getInputEntries().get(0)).disableBackground().markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 63, startPoint.y + 1)).entries(display.getInputEntries().get(1)).disableBackground().markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 40, startPoint.y + 35)).entries(display.getOutput(0)).disableBackground().markOutput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 63, startPoint.y + 42)).entries(display.getOutput(1)).disableBackground().markOutput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 86, startPoint.y + 35)).entries(display.getOutput(2)).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 1, startPoint.y + 1)).entry(EntryStacks.of(Items.BLAZE_POWDER)).noBackground().markInput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 40, startPoint.y + 1)).entries(display.getInputEntries().get(0)).noBackground().markInput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 63, startPoint.y + 1)).entries(display.getInputEntries().get(1)).noBackground().markInput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 40, startPoint.y + 35)).entries(display.getOutput(0)).noBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 63, startPoint.y + 42)).entries(display.getOutput(1)).noBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 86, startPoint.y + 35)).entries(display.getOutput(2)).noBackground().markOutput()); return widgets; } } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCampfireCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCampfireCategory.java index 9b88ec83f..7f8aaf7b5 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCampfireCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCampfireCategory.java @@ -70,7 +70,7 @@ public List setupDisplay(DefaultCampfireDisplay display, Rectangle bound new TranslatableComponent("category.rei.campfire.time", df.format(cookingTime / 20d))).noShadow().rightAligned().color(0xFF404040, 0xFFBBBBBB)); widgets.add(Widgets.createArrow(new Point(startPoint.x + 24, startPoint.y + 8)).animationDurationTicks(cookingTime)); widgets.add(Widgets.createSlot(new Point(startPoint.x + 1, startPoint.y + 1)).entries(display.getInputEntries().get(0)).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 9)).entries(display.getOutputEntries().get(0)).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 9)).entries(display.getOutputEntries().get(0)).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCompostingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCompostingCategory.java index aa402a34d..5ba549ce7 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCompostingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCompostingCategory.java @@ -109,7 +109,7 @@ public List setupDisplay(DefaultCompostingDisplay display, Rectangle bou } widgets.add(Widgets.createArrow(new Point(startingPoint.x - 1 - 5, startingPoint.y + 7 - 5))); widgets.add(Widgets.createResultSlotBackground(new Point(startingPoint.x + 33 - 5, startingPoint.y + 8 - 5))); - widgets.add(Widgets.createSlot(new Point(startingPoint.x + 33 - 5, startingPoint.y + 8 - 5)).entries(display.getOutputEntries().get(0)).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startingPoint.x + 33 - 5, startingPoint.y + 8 - 5)).entries(display.getOutputEntries().get(0)).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultFuelCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultFuelCategory.java index e2f4b05ad..dd968253c 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultFuelCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultFuelCategory.java @@ -88,7 +88,7 @@ public List setupDisplay(DefaultFuelDisplay display, Rectangle bounds) { @Override public DisplayRenderer getDisplayRenderer(DefaultFuelDisplay display) { - Slot slot = Widgets.createSlot(new Point(0, 0)).entries(display.getInputEntries().get(0)).disableBackground().disableHighlight(); + Slot slot = Widgets.createSlot(new Point(0, 0)).entries(display.getInputEntries().get(0)).noBackground().noHighlight(); String burnItems = DECIMAL_FORMAT.format(display.getFuelTime() / 200d); return new DisplayRenderer() { private TranslatableComponent text = new TranslatableComponent("category.rei.fuel.time_short.items", burnItems); diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultInformationCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultInformationCategory.java index d7b6332d8..d104410c1 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultInformationCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultInformationCategory.java @@ -32,6 +32,7 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.AbstractRenderer; import me.shedaniel.rei.api.client.gui.DisplayRenderer; import me.shedaniel.rei.api.client.gui.Renderer; @@ -198,7 +199,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { int currentY = -scrolling.scrollAmountInt() + innerBounds.y; for (FormattedCharSequence text : texts) { if (text != null && currentY + font.lineHeight >= innerBounds.y && currentY <= innerBounds.getMaxY()) { - font.draw(matrices, text, innerBounds.x + 2, currentY + 2, REIRuntime.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : 0xFF090909); + font.draw(matrices, text, innerBounds.x + 2, currentY + 2, ConfigObject.getInstance().isUsingDarkTheme() ? 0xFFBBBBBB : 0xFF090909); } currentY += text == null ? 4 : font.lineHeight; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultOxidationScrapingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultOxidationScrapingCategory.java index 4f5d1e849..079393311 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultOxidationScrapingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultOxidationScrapingCategory.java @@ -66,7 +66,7 @@ public List setupDisplay(DefaultOxidationScrapingDisplay display, Rectan widgets.add(Widgets.createArrow(new Point(startPoint.x + 27, startPoint.y + 4))); widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getIn()).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultOxidizingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultOxidizingCategory.java index a33ef331c..b35ae2628 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultOxidizingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultOxidizingCategory.java @@ -66,7 +66,7 @@ public List setupDisplay(DefaultOxidizingDisplay display, Rectangle boun widgets.add(Widgets.createArrow(new Point(startPoint.x + 27, startPoint.y + 4))); widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getIn()).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultPathingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultPathingCategory.java index e207046ff..dbcb2d401 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultPathingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultPathingCategory.java @@ -64,7 +64,7 @@ public List setupDisplay(DefaultPathingDisplay display, Rectangle bounds widgets.add(Widgets.createArrow(new Point(startPoint.x + 27, startPoint.y + 4))); widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getIn()).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultSmithingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultSmithingCategory.java index b62dc7f4d..aa44902d0 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultSmithingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultSmithingCategory.java @@ -65,7 +65,7 @@ public List setupDisplay(DefaultSmithingDisplay display, Rectangle bound widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4 - 22, startPoint.y + 5)).entries(display.getInputEntries().get(0)).markInput()); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getInputEntries().get(1)).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOutputEntries().get(0)).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOutputEntries().get(0)).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultStoneCuttingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultStoneCuttingCategory.java index 0a9ae4aba..9015231e5 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultStoneCuttingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultStoneCuttingCategory.java @@ -65,7 +65,7 @@ public List setupDisplay(DefaultStoneCuttingDisplay display, Rectangle b widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)) .entries(display.getOutputEntries().get(0)) - .disableBackground() + .noBackground() .markOutput()); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)) .entries(display.getInputEntries().get(0)).markInput()); diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultStrippingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultStrippingCategory.java index 8c0c6740f..3a5e87d50 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultStrippingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultStrippingCategory.java @@ -64,7 +64,7 @@ public List setupDisplay(DefaultStrippingDisplay display, Rectangle boun widgets.add(Widgets.createArrow(new Point(startPoint.x + 27, startPoint.y + 4))); widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getIn()).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultTillingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultTillingCategory.java index be0b862ba..a219e7c47 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultTillingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultTillingCategory.java @@ -64,7 +64,7 @@ public List setupDisplay(DefaultTillingDisplay display, Rectangle bounds widgets.add(Widgets.createArrow(new Point(startPoint.x + 27, startPoint.y + 4))); widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getIn()).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultWaxScrapingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultWaxScrapingCategory.java index 96c487fb2..a5003f836 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultWaxScrapingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultWaxScrapingCategory.java @@ -66,7 +66,7 @@ public List setupDisplay(DefaultWaxScrapingDisplay display, Rectangle bo widgets.add(Widgets.createArrow(new Point(startPoint.x + 27, startPoint.y + 4))); widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getIn()).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultWaxingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultWaxingCategory.java index fa95d2659..d40fce021 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultWaxingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultWaxingCategory.java @@ -66,7 +66,7 @@ public List setupDisplay(DefaultWaxingDisplay display, Rectangle bounds) widgets.add(Widgets.createArrow(new Point(startPoint.x + 27, startPoint.y + 4))); widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getIn()).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOut()).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/anvil/DefaultAnvilCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/anvil/DefaultAnvilCategory.java index b49249961..859d3d8d3 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/anvil/DefaultAnvilCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/anvil/DefaultAnvilCategory.java @@ -65,7 +65,7 @@ public List setupDisplay(DefaultAnvilDisplay display, Rectangle bounds) widgets.add(Widgets.createResultSlotBackground(new Point(startPoint.x + 61, startPoint.y + 5))); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4 - 22, startPoint.y + 5)).entries(display.getInputEntries().get(0)).markInput()); widgets.add(Widgets.createSlot(new Point(startPoint.x + 4, startPoint.y + 5)).entries(display.getInputEntries().get(1)).markInput()); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOutputEntries().get(0)).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 5)).entries(display.getOutputEntries().get(0)).noBackground().markOutput()); return widgets; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/beacon/DefaultBeaconBaseCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/beacon/DefaultBeaconBaseCategory.java index 5d2b668e6..d8d9af666 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/beacon/DefaultBeaconBaseCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/beacon/DefaultBeaconBaseCategory.java @@ -30,6 +30,7 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.DisplayRenderer; import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.gui.widgets.*; @@ -87,7 +88,7 @@ public List setupDisplay(DefaultBeaconBaseDisplay display, Rectangle bou widgets.add(Widgets.createSlot(new Point(bounds.getCenterX() - 8, bounds.y + 3)).entry(EntryStacks.of(Blocks.BEACON))); Rectangle rectangle = new Rectangle(bounds.getCenterX() - (bounds.width / 2) - 1, bounds.y + 23, bounds.width + 2, bounds.height - 28); widgets.add(Widgets.createSlotBase(rectangle)); - widgets.add(new ScrollableSlotsWidget(rectangle, CollectionUtils.map(display.getEntries(), t -> Widgets.createSlot(new Point(0, 0)).disableBackground().entry(t)))); + widgets.add(new ScrollableSlotsWidget(rectangle, CollectionUtils.map(display.getEntries(), t -> Widgets.createSlot(new Point(0, 0)).noBackground().entry(t)))); return widgets; } @@ -167,7 +168,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { } } try (CloseableScissors scissors = scissor(matrices, scrolling.getBounds())) { - scrolling.renderScrollBar(0xff000000, 1, REIRuntime.getInstance().isDarkThemeEnabled() ? 0.8f : 1f); + scrolling.renderScrollBar(0xff000000, 1, ConfigObject.getInstance().isUsingDarkTheme() ? 0.8f : 1f); } } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/beacon/DefaultBeaconPaymentCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/beacon/DefaultBeaconPaymentCategory.java index 17071e68d..b5a5b64e5 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/beacon/DefaultBeaconPaymentCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/beacon/DefaultBeaconPaymentCategory.java @@ -30,6 +30,7 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.DisplayRenderer; import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.gui.widgets.*; @@ -87,7 +88,7 @@ public List setupDisplay(DefaultBeaconPaymentDisplay display, Rectangle widgets.add(Widgets.createSlot(new Point(bounds.getCenterX() - 8, bounds.y + 3)).entry(EntryStacks.of(Blocks.BEACON))); Rectangle rectangle = new Rectangle(bounds.getCenterX() - (bounds.width / 2) - 1, bounds.y + 23, bounds.width + 2, bounds.height - 28); widgets.add(Widgets.createSlotBase(rectangle)); - widgets.add(new ScrollableSlotsWidget(rectangle, CollectionUtils.map(display.getEntries(), t -> Widgets.createSlot(new Point(0, 0)).disableBackground().entry(t)))); + widgets.add(new ScrollableSlotsWidget(rectangle, CollectionUtils.map(display.getEntries(), t -> Widgets.createSlot(new Point(0, 0)).noBackground().entry(t)))); return widgets; } @@ -167,7 +168,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { } } try (CloseableScissors scissors = scissor(matrices, scrolling.getBounds())) { - scrolling.renderScrollBar(0xff000000, 1, REIRuntime.getInstance().isDarkThemeEnabled() ? 0.8f : 1f); + scrolling.renderScrollBar(0xff000000, 1, ConfigObject.getInstance().isUsingDarkTheme() ? 0.8f : 1f); } } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/cooking/DefaultCookingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/cooking/DefaultCookingCategory.java index 5e8b4c0a2..7e609774c 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/cooking/DefaultCookingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/cooking/DefaultCookingCategory.java @@ -72,7 +72,7 @@ public List setupDisplay(DefaultCookingDisplay display, Rectangle bounds .animationDurationTicks(cookingTime)); widgets.add(Widgets.createSlot(new Point(startPoint.x + 61, startPoint.y + 9)) .entries(display.getOutputEntries().get(0)) - .disableBackground() + .noBackground() .markOutput()); widgets.add(Widgets.createSlot(new Point(startPoint.x + 1, startPoint.y + 1)) .entries(display.getInputEntries().get(0)) diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/crafting/DefaultCraftingCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/crafting/DefaultCraftingCategory.java index 55f0ba48a..5e348ce3e 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/crafting/DefaultCraftingCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/crafting/DefaultCraftingCategory.java @@ -80,7 +80,7 @@ public List setupDisplay(DefaultCraftingDisplay display, Rectangle bo slots.get(ingredient.getIndex()).entries(ingredient.get()); } widgets.addAll(slots); - widgets.add(Widgets.createSlot(new Point(startPoint.x + 95, startPoint.y + 19)).entries(display.getOutputEntries().get(0)).disableBackground().markOutput()); + widgets.add(Widgets.createSlot(new Point(startPoint.x + 95, startPoint.y + 19)).entries(display.getOutputEntries().get(0)).noBackground().markOutput()); if (display.isShapeless()) { widgets.add(Widgets.createShapelessIcon(bounds)); } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/DefaultTagCategory.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/DefaultTagCategory.java index 1b1ac544e..1ab934333 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/DefaultTagCategory.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/DefaultTagCategory.java @@ -31,6 +31,7 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.AbstractRenderer; import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.gui.widgets.*; @@ -143,13 +144,13 @@ public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, Font font = instance.font; String text = "?"; int width = font.width(text); - font.draw(matrices, text, bounds.getCenterX() - width / 2f + 0.2f, bounds.getCenterY() - font.lineHeight / 2f + 1f, REIRuntime.getInstance().isDarkThemeEnabled() ? -4473925 : -12566464); + font.draw(matrices, text, bounds.getCenterX() - width / 2f + 0.2f, bounds.getCenterY() - font.lineHeight / 2f + 1f, ConfigObject.getInstance().isUsingDarkTheme() ? -4473925 : -12566464); } @Override @Nullable public Tooltip getTooltip(TooltipContext context) { - return Tooltip.create(context.getPoint(), new TextComponent(holder.unwrapKey().map(key -> key.location().toString()).orElse("null"))); + return Tooltip.create(context, new TextComponent(holder.unwrapKey().map(key -> key.location().toString()).orElse("null"))); } }); } @@ -179,19 +180,16 @@ public Tooltip getTooltip(TooltipContext context) { } }) .tooltipLine(new TranslatableComponent("text.rei.tag.copy.clipboard"))); - widgets.add(Widgets.withTranslate(new DelegateWidget(Widgets.noOp()) { - @Override - protected Widget delegate() { - ResourceLocation expandTexture = !expanded[0] ? new ResourceLocation("roughlyenoughitems", "textures/gui/expand.png") - : new ResourceLocation("roughlyenoughitems", "textures/gui/shrink.png"); - return Widgets.concat( - Widgets.createTexturedWidget(expandTexture, - new Rectangle(recipeBounds.x + 5 + 2, recipeBounds.y + 6 + 2, 13 - 4, 13 - 4), 0, 0, 9, 9), - Widgets.createTexturedWidget(new ResourceLocation("roughlyenoughitems", "textures/gui/clipboard.png"), - new Rectangle(recipeBounds.x + 5 + 2, recipeBounds.getMaxY() - 6 - 13 + 2, 13 - 4, 13 - 4), 0, 0, 9, 9) - ); - } - }, 0, 0, 10)); + widgets.add(Widgets.withTranslate(Widgets.delegate(() -> { + ResourceLocation expandTexture = !expanded[0] ? new ResourceLocation("roughlyenoughitems", "textures/gui/expand.png") + : new ResourceLocation("roughlyenoughitems", "textures/gui/shrink.png"); + return Widgets.concat( + Widgets.createTexturedWidget(expandTexture, + new Rectangle(recipeBounds.x + 5 + 2, recipeBounds.y + 6 + 2, 13 - 4, 13 - 4), 0, 0, 9, 9), + Widgets.createTexturedWidget(new ResourceLocation("roughlyenoughitems", "textures/gui/clipboard.png"), + new Rectangle(recipeBounds.x + 5 + 2, recipeBounds.getMaxY() - 6 - 13 + 2, 13 - 4, 13 - 4), 0, 0, 9, 9) + ); + }), 0, 0, 10)); Matrix4f translateMatrix = Matrix4f.createTranslateMatrix(0, 0, 200); Matrix4f identity = new Matrix4f(); diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ReferenceTagNodeWidget.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ReferenceTagNodeWidget.java index 019e4f3d2..f98bfb805 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ReferenceTagNodeWidget.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ReferenceTagNodeWidget.java @@ -55,9 +55,9 @@ public ReferenceTagNodeWidget(TagNode node, Function, EntryStack this.overflowBounds = overflowBounds; this.bounds = new Rectangle(0, 0, 24, 23); this.slot = Widgets.createSlot(new Rectangle(0, 0, 18, 18)) - .disableBackground() - .disableHighlight() - .disableTooltips() + .noBackground() + .noHighlight() + .noTooltips() .entries(EntryIngredients.ofTag(node.getReference(), mapper)); this.children = Collections.singletonList(this.slot); } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ValueTagNodeWidget.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ValueTagNodeWidget.java index 5936e1842..f53fd92d9 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ValueTagNodeWidget.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/tag/ValueTagNodeWidget.java @@ -66,7 +66,7 @@ public ValueTagNodeWidget(TagNode node, Function, EntryStack> ma int y = i / width; Slot slot = Widgets.createSlot(new Rectangle(x * 16 + 5, y * 16 + 5, 18, 18)) .entry(mapper.apply(holder)) - .disableBackground(); + .noBackground(); this.widgets.add(slot); i++; } diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/favorites/EntryStackFavoriteEntry.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/favorites/EntryStackFavoriteEntry.java new file mode 100644 index 000000000..885b1e18a --- /dev/null +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/client/favorites/EntryStackFavoriteEntry.java @@ -0,0 +1,116 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.plugin.client.favorites; + +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Lifecycle; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryStacks; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; + +import java.util.function.Function; + +public class EntryStackFavoriteEntry extends FavoriteEntry { + private static final Function, String> CANCEL_FLUID_AMOUNT = s -> null; + private final EntryStack stack; + private final long hash; + + public EntryStackFavoriteEntry(EntryStack stack) { + this.stack = stack.normalize(); + this.hash = EntryStacks.hashExact(this.stack); + } + + @Override + public boolean isInvalid() { + return this.stack.isEmpty(); + } + + @Override + public Renderer getRenderer(boolean showcase) { + return this.stack; + } + + @Override + public boolean doAction(int button) { + return false; + } + + @Override + public long hashIgnoreAmount() { + return hash; + } + + @Override + public FavoriteEntry copy() { + return new EntryStackFavoriteEntry(stack.normalize()); + } + + @Override + public ResourceLocation getType() { + return FavoriteEntryType.ENTRY_STACK; + } + + @Override + public boolean isSame(FavoriteEntry other) { + if (!(other instanceof EntryStackFavoriteEntry that)) return false; + return EntryStacks.equalsExact(stack, that.stack); + } + + public enum Type implements FavoriteEntryType { + INSTANCE; + + private final String key = "data"; + + @Override + public DataResult read(CompoundTag object) { + EntryStack stack; + try { + stack = EntryStack.read(object.getCompound(key)); + } catch (Throwable throwable) { + return DataResult.error(throwable.getMessage()); + } + return DataResult.success(new EntryStackFavoriteEntry(stack), Lifecycle.stable()); + } + + @Override + public DataResult fromArgs(Object... args) { + if (args.length == 0) return DataResult.error("Cannot create EntryStackFavoriteEntry from empty args!"); + if (!(args[0] instanceof EntryStack stack)) + return DataResult.error("Creation of EntryStackFavoriteEntry from args expected EntryStack as the first argument!"); + if (!stack.supportSaving()) + return DataResult.error("Creation of EntryStackFavoriteEntry from an unserializable stack!"); + return DataResult.success(new EntryStackFavoriteEntry(stack), Lifecycle.stable()); + } + + @Override + public CompoundTag save(EntryStackFavoriteEntry entry, CompoundTag tag) { + tag.put(key, entry.stack.saveStack()); + return tag; + } + } +} \ No newline at end of file diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/DefaultCraftingDisplay.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/DefaultCraftingDisplay.java index 84f4b50e1..8e897ef48 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/DefaultCraftingDisplay.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/DefaultCraftingDisplay.java @@ -68,7 +68,8 @@ public DefaultCraftingDisplay(List inputs, List detectClientPlugins() { return () -> () -> { loadPlugin(REIClientPlugin.class, ((PluginView) PluginManager.getClientInstance())::registerPlugin); - Supplier method = Suppliers.memoize(() -> { - String methodName = FabricLoader.getInstance().getMappingResolver().mapMethodName("intermediary", "net.minecraft.class_437", "method_32635", "(Ljava/util/List;Lnet/minecraft/class_5632;)V"); - try { - Method declaredMethod = Screen.class.getDeclaredMethod(methodName, List.class, TooltipComponent.class); - if (declaredMethod != null) declaredMethod.setAccessible(true); - return declaredMethod; - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - }); - ClientInternals.attachInstance((BiConsumer, TooltipComponent>) (lines, component) -> { - try { - method.get().invoke(null, lines, component); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - }, "clientTooltipComponentProvider"); }; } } diff --git a/fabric/src/main/java/me/shedaniel/rei/impl/client/gui/credits/fabric/CreditsScreenImpl.java b/fabric/src/main/java/me/shedaniel/rei/impl/client/gui/credits/fabric/CreditsScreenImpl.java index f148272e0..82425b64b 100644 --- a/fabric/src/main/java/me/shedaniel/rei/impl/client/gui/credits/fabric/CreditsScreenImpl.java +++ b/fabric/src/main/java/me/shedaniel/rei/impl/client/gui/credits/fabric/CreditsScreenImpl.java @@ -27,6 +27,7 @@ import me.shedaniel.rei.impl.client.gui.credits.CreditsScreen; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.CustomValue; +import net.minecraft.obfuscate.DontObfuscate; import net.minecraft.util.Tuple; import java.util.Comparator; @@ -34,6 +35,7 @@ import java.util.stream.Collectors; public class CreditsScreenImpl { + @DontObfuscate public static void fillTranslators(Exception[] exception, List>> translators) { FabricLoader.getInstance().getModContainer("roughlyenoughitems").ifPresent(rei -> { try { diff --git a/fabric/src/main/java/me/shedaniel/rei/impl/client/gui/fabric/ScreenOverlayImplFabric.java b/fabric/src/main/java/me/shedaniel/rei/impl/client/gui/fabric/TooltipRendererImpl.java similarity index 75% rename from fabric/src/main/java/me/shedaniel/rei/impl/client/gui/fabric/ScreenOverlayImplFabric.java rename to fabric/src/main/java/me/shedaniel/rei/impl/client/gui/fabric/TooltipRendererImpl.java index 9c2ba36f3..df7fdaddb 100644 --- a/fabric/src/main/java/me/shedaniel/rei/impl/client/gui/fabric/ScreenOverlayImplFabric.java +++ b/fabric/src/main/java/me/shedaniel/rei/impl/client/gui/fabric/TooltipRendererImpl.java @@ -23,11 +23,12 @@ package me.shedaniel.rei.impl.client.gui.fabric; +import com.google.common.base.Suppliers; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.impl.ClientInternals; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.widget.QueuedTooltip; +import me.shedaniel.rei.impl.client.gui.widget.TooltipImpl; +import me.shedaniel.rei.impl.client.provider.TooltipRenderer; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; @@ -37,13 +38,26 @@ import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.inventory.tooltip.TooltipComponent; +import java.lang.reflect.Method; import java.util.List; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -public class ScreenOverlayImplFabric extends ScreenOverlayImpl { +public class TooltipRendererImpl implements TooltipRenderer { + private final Supplier method = Suppliers.memoize(() -> { + String methodName = FabricLoader.getInstance().getMappingResolver().mapMethodName("intermediary", "net.minecraft.class_437", "method_32635", "(Ljava/util/List;Lnet/minecraft/class_5632;)V"); + try { + Method declaredMethod = Screen.class.getDeclaredMethod(methodName, List.class, TooltipComponent.class); + if (declaredMethod != null) declaredMethod.setAccessible(true); + return declaredMethod; + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + }); + @Override - public void renderTooltipInner(Screen screen, PoseStack matrices, Tooltip tooltip, int mouseX, int mouseY) { + public void renderTooltip(Screen screen, PoseStack matrices, Tooltip tooltip, int mouseX, int mouseY) { List lines = tooltip.entries().stream() .flatMap(component -> { if (component.isText()) { @@ -51,7 +65,7 @@ public void renderTooltipInner(Screen screen, PoseStack matrices, Tooltip toolti Stream sequenceStream = texts.isEmpty() ? Stream.of(component.getAsText().getVisualOrderText()) : texts.stream().map(Language.getInstance()::getVisualOrder); return sequenceStream.map(ClientTooltipComponent::create); - } else if (((QueuedTooltip.TooltipEntryImpl) component).isClientComponent()) { + } else if (((TooltipImpl.TooltipEntryImpl) component).isClientComponent()) { return Stream.of(component.getAsComponent()); } else { return Stream.empty(); @@ -65,7 +79,7 @@ public void renderTooltipInner(Screen screen, PoseStack matrices, Tooltip toolti if (component instanceof ClientTooltipComponent) break; try { - ClientInternals.getClientTooltipComponent(lines, component); + method.get().invoke(lines, component); } catch (Throwable exception) { throw new IllegalArgumentException("Failed to add tooltip component! " + component + ", Class: " + (component == null ? null : component.getClass().getCanonicalName()), exception); } diff --git a/fabric/src/main/java/me/shedaniel/rei/mixin/fabric/MixinClientPacketListener.java b/fabric/src/main/java/me/shedaniel/rei/mixin/fabric/MixinClientPacketListener.java index c98edb2c9..63ff50dec 100644 --- a/fabric/src/main/java/me/shedaniel/rei/mixin/fabric/MixinClientPacketListener.java +++ b/fabric/src/main/java/me/shedaniel/rei/mixin/fabric/MixinClientPacketListener.java @@ -23,7 +23,7 @@ package me.shedaniel.rei.mixin.fabric; -import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; +import me.shedaniel.rei.impl.client.init.CoreClientInitialization; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket; import net.minecraft.world.item.crafting.RecipeManager; @@ -40,6 +40,6 @@ public class MixinClientPacketListener { @Inject(method = "handleUpdateRecipes", at = @At("HEAD")) private void handleUpdateRecipes(ClientboundUpdateRecipesPacket clientboundUpdateRecipesPacket, CallbackInfo ci) { - RoughlyEnoughItemsCoreClient.PRE_UPDATE_RECIPES.invoker().update(recipeManager); + CoreClientInitialization.PRE_UPDATE_RECIPES.invoker().update(recipeManager); } } \ No newline at end of file diff --git a/fabric/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/fabric/DefaultCraftingDisplayImpl.java b/fabric/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/fabric/DefaultCraftingDisplayImpl.java index 60dff699b..06faa9f47 100644 --- a/fabric/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/fabric/DefaultCraftingDisplayImpl.java +++ b/fabric/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/fabric/DefaultCraftingDisplayImpl.java @@ -23,7 +23,10 @@ package me.shedaniel.rei.plugin.common.displays.crafting.fabric; +import net.minecraft.obfuscate.DontObfuscate; + public class DefaultCraftingDisplayImpl { + @DontObfuscate public static void registerPlatformSizeProvider() { } } diff --git a/fabric/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.TooltipRenderer b/fabric/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.TooltipRenderer new file mode 100644 index 000000000..42a143652 --- /dev/null +++ b/fabric/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.TooltipRenderer @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.fabric.TooltipRendererImpl \ No newline at end of file diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index afaac37a6..f0a7e00e9 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -28,7 +28,10 @@ ], "rei_client": [ "me.shedaniel.rei.plugin.client.DefaultClientPlugin", - "me.shedaniel.rei.plugin.client.runtime.DefaultClientRuntimePlugin" + "me.shedaniel.rei.plugin.client.runtime.DefaultClientRuntimePlugin", + "me.shedaniel.rei.plugin.client.runtime.DefaultRuntimeInputMethodPlugin", + "me.shedaniel.rei.plugin.autocrafting.DefaultClientTransferCategoryPlugin", + "me.shedaniel.rei.impl.client.gui.widget.plugin.FavoritesEntriesBuiltinPlugin" ] }, "accessWidener": "roughlyenoughitems.accessWidener", diff --git a/forge/build.gradle b/forge/build.gradle index 8fa846574..584222009 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -54,8 +54,6 @@ loom { } } -def depProjects = [":api", ":runtime", ":default-plugin"] - dependencies { forge("net.minecraftforge:forge:${rootProject.minecraft_version}-${rootProject.forge_version}") modApi("me.shedaniel.cloth:cloth-config-forge:${cloth_config_version}") diff --git a/forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java b/forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java index 2681299da..6b432b932 100644 --- a/forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java +++ b/forge/src/main/java/me/shedaniel/rei/forge/PluginDetectorImpl.java @@ -32,9 +32,12 @@ import me.shedaniel.rei.api.common.plugins.PluginView; import me.shedaniel.rei.api.common.plugins.REIPluginProvider; import me.shedaniel.rei.api.common.plugins.REIServerPlugin; +import me.shedaniel.rei.impl.client.gui.widget.plugin.FavoritesEntriesBuiltinPlugin; import me.shedaniel.rei.impl.init.PluginDetector; +import me.shedaniel.rei.plugin.autocrafting.DefaultClientTransferCategoryPlugin; import me.shedaniel.rei.plugin.client.forge.DefaultClientPluginImpl; import me.shedaniel.rei.plugin.client.runtime.DefaultClientRuntimePlugin; +import me.shedaniel.rei.plugin.client.runtime.DefaultRuntimeInputMethodPlugin; import me.shedaniel.rei.plugin.common.forge.DefaultPluginImpl; import me.shedaniel.rei.plugin.common.runtime.DefaultRuntimePlugin; import net.minecraftforge.api.distmarker.Dist; @@ -178,6 +181,9 @@ public Supplier detectClientPlugins() { return () -> () -> { PluginView.getClientInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new DefaultClientPluginImpl())); PluginView.getClientInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new DefaultClientRuntimePlugin())); + PluginView.getClientInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new DefaultRuntimeInputMethodPlugin())); + PluginView.getClientInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new DefaultClientTransferCategoryPlugin())); + PluginView.getClientInstance().registerPlugin(wrapPlugin(Collections.singletonList("roughlyenoughitems"), new FavoritesEntriesBuiltinPlugin())); // Legacy Annotation AnnotationUtils.scanAnnotation(REIPlugin.class, REIClientPlugin.class::isAssignableFrom, (modId, plugin, clazz) -> { diff --git a/forge/src/main/java/me/shedaniel/rei/impl/client/gui/credits/forge/CreditsScreenImpl.java b/forge/src/main/java/me/shedaniel/rei/impl/client/gui/credits/forge/CreditsScreenImpl.java index ef53fe3b1..bbbb37bc1 100644 --- a/forge/src/main/java/me/shedaniel/rei/impl/client/gui/credits/forge/CreditsScreenImpl.java +++ b/forge/src/main/java/me/shedaniel/rei/impl/client/gui/credits/forge/CreditsScreenImpl.java @@ -24,11 +24,13 @@ package me.shedaniel.rei.impl.client.gui.credits.forge; import me.shedaniel.rei.impl.client.gui.credits.CreditsScreen; +import net.minecraft.obfuscate.DontObfuscate; import net.minecraft.util.Tuple; import java.util.List; public class CreditsScreenImpl { + @DontObfuscate public static void fillTranslators(Exception[] exception, List>> translators) { } } diff --git a/forge/src/main/java/me/shedaniel/rei/impl/client/gui/forge/ScreenOverlayImplForge.java b/forge/src/main/java/me/shedaniel/rei/impl/client/gui/forge/TooltipRendererImpl.java similarity index 90% rename from forge/src/main/java/me/shedaniel/rei/impl/client/gui/forge/ScreenOverlayImplForge.java rename to forge/src/main/java/me/shedaniel/rei/impl/client/gui/forge/TooltipRendererImpl.java index e18ba2e23..d957d2642 100644 --- a/forge/src/main/java/me/shedaniel/rei/impl/client/gui/forge/ScreenOverlayImplForge.java +++ b/forge/src/main/java/me/shedaniel/rei/impl/client/gui/forge/TooltipRendererImpl.java @@ -28,20 +28,19 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; +import me.shedaniel.rei.impl.client.provider.TooltipRenderer; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.network.chat.Component; -import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.ItemStack; import net.minecraftforge.client.ForgeHooksClient; import java.util.ArrayList; import java.util.List; -public class ScreenOverlayImplForge extends ScreenOverlayImpl { +public class TooltipRendererImpl implements TooltipRenderer { @Override - public void renderTooltipInner(Screen screen, PoseStack matrices, Tooltip tooltip, int mouseX, int mouseY) { + public void renderTooltip(Screen screen, PoseStack matrices, Tooltip tooltip, int mouseX, int mouseY) { matrices.pushPose(); EntryStack stack = tooltip.getContextStack(); ItemStack itemStack = stack.getType() == VanillaEntryTypes.ITEM ? stack.castValue() : ItemStack.EMPTY; diff --git a/forge/src/main/java/me/shedaniel/rei/mixin/forge/MixinClientPacketListener.java b/forge/src/main/java/me/shedaniel/rei/mixin/forge/MixinClientPacketListener.java index 252a365b6..6efe7beb2 100644 --- a/forge/src/main/java/me/shedaniel/rei/mixin/forge/MixinClientPacketListener.java +++ b/forge/src/main/java/me/shedaniel/rei/mixin/forge/MixinClientPacketListener.java @@ -23,7 +23,7 @@ package me.shedaniel.rei.mixin.forge; -import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; +import me.shedaniel.rei.impl.client.init.CoreClientInitialization; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket; import net.minecraft.world.item.crafting.RecipeManager; @@ -40,6 +40,6 @@ public class MixinClientPacketListener { @Inject(method = "handleUpdateRecipes", at = @At("HEAD")) private void handleUpdateRecipes(ClientboundUpdateRecipesPacket clientboundUpdateRecipesPacket, CallbackInfo ci) { - RoughlyEnoughItemsCoreClient.PRE_UPDATE_RECIPES.invoker().update(recipeManager); + CoreClientInitialization.PRE_UPDATE_RECIPES.invoker().update(recipeManager); } } \ No newline at end of file diff --git a/forge/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/forge/DefaultCraftingDisplayImpl.java b/forge/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/forge/DefaultCraftingDisplayImpl.java index 9f5faa713..b2debc199 100644 --- a/forge/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/forge/DefaultCraftingDisplayImpl.java +++ b/forge/src/main/java/me/shedaniel/rei/plugin/common/displays/crafting/forge/DefaultCraftingDisplayImpl.java @@ -25,9 +25,11 @@ import me.shedaniel.rei.plugin.common.displays.crafting.CraftingRecipeSizeProvider; import me.shedaniel.rei.plugin.common.displays.crafting.DefaultCraftingDisplay; +import net.minecraft.obfuscate.DontObfuscate; import net.minecraftforge.common.crafting.IShapedRecipe; public class DefaultCraftingDisplayImpl { + @DontObfuscate public static void registerPlatformSizeProvider() { DefaultCraftingDisplay.registerSizeProvider(recipe -> { if (recipe instanceof IShapedRecipe) { diff --git a/forge/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.TooltipRenderer b/forge/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.TooltipRenderer new file mode 100644 index 000000000..0285d5690 --- /dev/null +++ b/forge/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.TooltipRenderer @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.forge.TooltipRendererImpl \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 4b70945bf..bae4eecc8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,6 @@ -org.gradle.jvmargs=-Xmx6G -base_version=8.3 +org.gradle.java.home=C:\\Program Files\\OpenJDK\\jdk-17.0.2 +org.gradle.jvmargs=-Xmx14G +base_version=8.4 unstable=false supported_version=1.18.2 minecraft_version=1.18.2 diff --git a/runtime-engine/build.gradle b/runtime-engine/build.gradle new file mode 100644 index 000000000..4d96de5ac --- /dev/null +++ b/runtime-engine/build.gradle @@ -0,0 +1,7 @@ +dependencies { + depProjects.forEach { + if (it.startsWith(":runtime-engine:")) { + compileClasspath(project(path: it, configuration: "namedElements")) { transitive false } + } + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java b/runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java rename to runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java index 9ddbe76b1..27746d96c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java +++ b/runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/client/registry/category/CategoryRegistryImpl.java @@ -106,7 +106,7 @@ public void configure(CategoryIdentifier category, Consum @Override public Iterator> iterator() { - return (Iterator) categories.values().iterator(); + return (Iterator>) (Iterator) categories.values().iterator(); } @Override diff --git a/runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierConstructorImpl.java b/runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierConstructorImpl.java new file mode 100644 index 000000000..a3eb2ae2f --- /dev/null +++ b/runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierConstructorImpl.java @@ -0,0 +1,45 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.category; + +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.impl.common.provider.CategoryIdentifierConstructor; +import net.minecraft.resources.ResourceLocation; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class CategoryIdentifierConstructorImpl implements CategoryIdentifierConstructor { + private static final Map> CACHE = new ConcurrentHashMap<>(); + + @Override + public CategoryIdentifier create(String location) { + CategoryIdentifier identifier = CACHE.get(location); + if (identifier != null) return identifier.cast(); + identifier = new CategoryIdentifierImpl<>(new ResourceLocation(location)); + CACHE.put(location, identifier); + return identifier.cast(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierImpl.java b/runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierImpl.java similarity index 73% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierImpl.java rename to runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierImpl.java index 283a0fd40..46aab7972 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierImpl.java +++ b/runtime-engine/categories/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierImpl.java @@ -25,19 +25,17 @@ import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; -import me.shedaniel.rei.impl.Internals; import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; -import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -public class CategoryIdentifierImpl implements CategoryIdentifier { +@ApiStatus.Internal +final class CategoryIdentifierImpl implements CategoryIdentifier { private final ResourceLocation location; private final int hashCode; - public CategoryIdentifierImpl(ResourceLocation location) { + CategoryIdentifierImpl(ResourceLocation location) { this.location = Objects.requireNonNull(location); this.hashCode = location.hashCode(); } @@ -66,15 +64,4 @@ public boolean equals(Object obj) { public String toString() { return location.toString(); } - - public static void attach() { - Map> cache = new ConcurrentHashMap<>(); - Internals.attachInstance((Function>) id -> { - CategoryIdentifier identifier = cache.get(id); - if (identifier != null) return identifier; - identifier = new CategoryIdentifierImpl<>(new ResourceLocation(id)); - cache.put(id, identifier); - return identifier; - }, "categoryIdentifier"); - } } diff --git a/runtime-engine/categories/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.category.CategoryRegistry b/runtime-engine/categories/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.category.CategoryRegistry new file mode 100644 index 000000000..61b3a5741 --- /dev/null +++ b/runtime-engine/categories/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.category.CategoryRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.registry.category.CategoryRegistryImpl \ No newline at end of file diff --git a/runtime-engine/categories/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.CategoryIdentifierConstructor b/runtime-engine/categories/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.CategoryIdentifierConstructor new file mode 100644 index 000000000..6909538ca --- /dev/null +++ b/runtime-engine/categories/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.CategoryIdentifierConstructor @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.category.CategoryIdentifierConstructorImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java similarity index 76% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java index ce3e6159c..ed0e2eb2c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java @@ -23,12 +23,12 @@ package me.shedaniel.rei.impl.client.config; -import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.util.Pair; import dev.architectury.hooks.client.screen.ScreenHooks; import me.shedaniel.autoconfig.AutoConfig; import me.shedaniel.autoconfig.annotation.ConfigEntry; @@ -63,12 +63,10 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; +import me.shedaniel.rei.impl.common.Internals; import me.shedaniel.rei.impl.client.config.addon.ConfigAddonRegistryImpl; import me.shedaniel.rei.impl.client.config.entries.*; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; import me.shedaniel.rei.impl.client.gui.credits.CreditsScreen; -import me.shedaniel.rei.impl.client.gui.performance.entry.PerformanceEntry; import me.shedaniel.rei.impl.common.InternalLogger; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -88,15 +86,16 @@ import net.minecraft.world.InteractionResult; import org.jetbrains.annotations.ApiStatus; +import java.lang.reflect.Field; import java.util.*; -import java.util.function.Consumer; +import java.util.function.Supplier; import static me.shedaniel.autoconfig.util.Utils.getUnsafely; import static me.shedaniel.autoconfig.util.Utils.setUnsafely; @ApiStatus.Internal @Environment(EnvType.CLIENT) -public class ConfigManagerImpl implements ConfigManager { +public class ConfigManagerImpl implements ConfigManagerInternal { private boolean craftableOnly = false; private final Gson gson = new GsonBuilder().create(); private ConfigObjectImpl object; @@ -123,30 +122,9 @@ public ConfigManagerImpl() { guiRegistry.registerAnnotationProvider((i13n, field, config, defaults, guiProvider) -> Collections.singletonList(new SearchFilterSyntaxHighlightingEntry(new TranslatableComponent(i13n), getUnsafely(field, config, SyntaxHighlightingMode.COLORFUL), getUnsafely(field, defaults), type -> setUnsafely(field, config, type))) , (field) -> field.getType() == SyntaxHighlightingMode.class, ConfigObjectImpl.UseSpecialSearchFilterSyntaxHighlightingScreen.class); - guiRegistry.registerAnnotationProvider((i13n, field, config, defaults, guiProvider) -> { - List> value = CollectionUtils.map(Utils.>>getUnsafely(field, config, new ArrayList<>()), EntryStackProvider::provide); - List> defaultValue = CollectionUtils.map(Utils.>>getUnsafely(field, defaults), EntryStackProvider::provide); - Consumer>> saveConsumer = (newValue) -> { - setUnsafely(field, config, CollectionUtils.map(newValue, EntryStackProvider::ofStack)); - }; - return REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().getRecipeManager() == null ? - Collections.singletonList(new NoFilteringEntry(220, value, defaultValue, saveConsumer)) - : - Collections.singletonList(new FilteringEntry(220, value, ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules, defaultValue, saveConsumer, list -> ((ConfigObjectImpl.Advanced.Filtering) config).filteringRules = Lists.newArrayList(list))); - } - , (field) -> field.getType() == List.class, ConfigObjectImpl.UseFilteringScreen.class); - guiRegistry.registerAnnotationProvider((i13n, field, config, defaults, guiProvider) -> { - Map, Boolean> value = Utils., Boolean>>getUnsafely(field, config, new HashMap<>()); - Map, Boolean> defaultValue = Utils.getUnsafely(field, defaults); - Consumer, Boolean>> saveConsumer = (newValue) -> { - setUnsafely(field, config, newValue); - }; - return REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().getRecipeManager() == null ? - Collections.singletonList(new NoFilteringCategoriesEntry(new TranslatableComponent(i13n), value, defaultValue, saveConsumer)) - : - Collections.singletonList(new FilteringCategoriesEntry(new TranslatableComponent(i13n), value, defaultValue, saveConsumer)); - } - , (field) -> field.getType() == Map.class, ConfigObjectImpl.UseFilteringCategoriesScreen.class); + for (SystemSetup setup : Internals.resolveServices(SystemSetup.class)) { + setup.setup(guiRegistry); + } InternalLogger.getInstance().info("Config loaded"); saveConfig(); } @@ -246,32 +224,6 @@ private static Jankson buildJankson(Jankson.Builder builder) { } }); - // FilteringRule - builder.registerSerializer(FilteringRule.class, (value, marshaller) -> { - try { - return marshaller.serialize(FilteringRuleType.save(value, new CompoundTag())); - } catch (Exception e) { - e.printStackTrace(); - return JsonNull.INSTANCE; - } - }); - builder.registerDeserializer(Tag.class, FilteringRule.class, (value, marshaller) -> { - try { - return FilteringRuleType.read((CompoundTag) value); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - }); - builder.registerDeserializer(String.class, FilteringRule.class, (value, marshaller) -> { - try { - return FilteringRuleType.read(TagParser.parseTag(value)); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - }); - // FavoriteEntry builder.registerSerializer(FavoriteEntry.class, (value, marshaller) -> { try { @@ -294,17 +246,9 @@ private static Jankson buildJankson(Jankson.Builder builder) { } }); - // CategoryIdentifier - builder.registerSerializer(CategoryIdentifier.class, (value, marshaller) -> { - return marshaller.serialize(value.toString()); - }); - builder.registerDeserializer(String.class, CategoryIdentifier.class, (value, marshaller) -> { - try { - return CategoryIdentifier.of(value); - } catch (ResourceLocationException e) { - throw new DeserializationException(e); - } - }); + for (SystemSetup setup : Internals.resolveServices(SystemSetup.class)) { + setup.setup(builder); + } return builder.build(); } @@ -319,11 +263,6 @@ public static ConfigManagerImpl getInstance() { @Override public void saveConfig() { - for (FilteringRuleType type : FilteringRuleTypeRegistry.getInstance()) { - if (type.isSingular() && getConfig().getFilteringRules().stream().noneMatch(filteringRule -> filteringRule.getType().equals(type))) { - getConfig().getFilteringRules().add(type.createNew()); - } - } AutoConfig.getConfigHolder(ConfigObjectImpl.class).registerLoadListener((configHolder, configObject) -> { object = configObject; return InteractionResult.PASS; @@ -350,48 +289,9 @@ public void toggleCraftableOnly() { craftableOnly = !craftableOnly; } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "rawtypes", "UnstableApiUsage"}) @Override public Screen getConfigScreen(Screen parent) { - class EmptyEntry extends AbstractConfigListEntry { - private final int height; - - public EmptyEntry(int height) { - super(new TextComponent(UUID.randomUUID().toString()), false); - this.height = height; - } - - public int getItemHeight() { - return this.height; - } - - public Object getValue() { - return null; - } - - public Optional getDefaultValue() { - return Optional.empty(); - } - - public boolean isMouseInside(int mouseX, int mouseY, int x, int y, int entryWidth, int entryHeight) { - return false; - } - - public void save() { - } - - public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { - } - - public List children() { - return Collections.emptyList(); - } - - public List narratables() { - return Collections.emptyList(); - } - } - try { ConfigScreenProvider provider = (ConfigScreenProvider) AutoConfig.getConfigScreen(ConfigObjectImpl.class, parent); provider.setI13nFunction(manager -> "config.roughlyenoughitems"); @@ -413,7 +313,7 @@ public List narratables() { ).build(); builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.advanced")).getEntries().add(0, feedbackEntry); builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.advanced")).getEntries().add(0, new ReloadPluginsEntry(220)); - builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.advanced")).getEntries().add(0, new PerformanceEntry(220)); + builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.advanced")).getEntries().addAll(0, CollectionUtils.flatMap(Internals.resolveServices(SystemSetup.class), SystemSetup::collectAdvanced)); } return builder.setAfterInitConsumer(screen -> { ConfigAddonRegistryImpl addonRegistry = (ConfigAddonRegistryImpl) ConfigAddonRegistry.getInstance(); @@ -453,8 +353,8 @@ public List narratables() { saveConfig(); EntryRegistry.getInstance().refilter(); REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); - if (REIRuntimeImpl.getSearchField() != null) { - ScreenOverlayImpl.getEntryListWidget().updateSearch(REIRuntimeImpl.getSearchField().getText(), true); + if (REIRuntime.getInstance().getSearchTextField() != null) { + REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadSearch); } }).build(); }); @@ -464,4 +364,96 @@ public List narratables() { } return null; } + + private static class EmptyEntry extends AbstractConfigListEntry { + private final int height; + + public EmptyEntry(int height) { + super(new TextComponent(UUID.randomUUID().toString()), false); + this.height = height; + } + + public int getItemHeight() { + return this.height; + } + + public Object getValue() { + return null; + } + + public Optional getDefaultValue() { + return Optional.empty(); + } + + public boolean isMouseInside(int mouseX, int mouseY, int x, int y, int entryWidth, int entryHeight) { + return false; + } + + public void save() { + } + + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { + } + + public List children() { + return Collections.emptyList(); + } + + public List narratables() { + return Collections.emptyList(); + } + } + + @Override + public Object get(String fieldKey) { + Pair, Field> pair = locateField(fieldKey); + try { + return pair.getSecond().get(pair.getFirst().get()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean set(String fieldKey, Object value) { + try { + Pair, Field> pair = locateField(fieldKey); + pair.getSecond().set(pair.getFirst().get(), value); + ConfigManager.getInstance().saveConfig(); + REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); + return true; + } catch (Throwable e) { + return false; + } + } + + private static final Map, Field>> FIELD_CACHE = new HashMap<>(); + + private Pair, Field> locateField(String fieldKey) { + return FIELD_CACHE.computeIfAbsent(fieldKey, key -> { + // resolve dot separated field names + String[] fieldNames = key.split("\\."); + try { + Supplier owner = this::getConfig; + Field field = ConfigObjectImpl.class.getDeclaredField(fieldNames[0]); + field.setAccessible(true); + for (int i = 1; i < fieldNames.length; i++) { + Supplier previousOwner = owner; + Field previousField = field; + owner = () -> { + try { + return previousField.get(previousOwner.get()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }; + field = field.getType().getDeclaredField(fieldNames[i]); + field.setAccessible(true); + } + return new Pair<>(owner, field); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + }); + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java similarity index 92% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java index a18d7aeab..8d6f6a417 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/ConfigObjectImpl.java @@ -37,7 +37,7 @@ import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.config.*; import me.shedaniel.rei.api.common.category.CategoryIdentifier; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesEntriesManager; +import me.shedaniel.rei.impl.client.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -57,6 +57,7 @@ import java.util.List; import java.util.Map; +@SuppressWarnings("FieldMayBeFinal") @ApiStatus.Internal @Config(name = "roughlyenoughitems/config") @Environment(EnvType.CLIENT) @@ -111,10 +112,6 @@ public boolean isUsingDarkTheme() { return appearance.theme == AppearanceTheme.DARK; } - public void setUsingDarkTheme(boolean dark) { - appearance.theme = dark ? AppearanceTheme.DARK : AppearanceTheme.LIGHT; - } - @Override public boolean isGrabbingItems() { return basics.cheatingStyle == ItemCheatingStyle.GRAB; @@ -135,10 +132,6 @@ public boolean isEntryListWidgetScrolled() { return appearance.scrollingEntryListWidget; } - public void setEntryListWidgetScrolled(boolean scrollingEntryListWidget) { - appearance.scrollingEntryListWidget = scrollingEntryListWidget; - } - @Override public boolean shouldAppendModNames() { return advanced.tooltips.appendModNames; @@ -159,28 +152,16 @@ public SearchFieldLocation getSearchFieldLocation() { return appearance.layout.searchFieldLocation; } - public void setSearchFieldLocation(SearchFieldLocation location) { - appearance.layout.searchFieldLocation = location; - } - @Override public DisplayPanelLocation getDisplayPanelLocation() { return advanced.accessibility.displayPanelLocation; } - public void setDisplayPanelLocation(DisplayPanelLocation location) { - advanced.accessibility.displayPanelLocation = location; - } - @Override public boolean isCraftableFilterEnabled() { return appearance.layout.showCraftableOnlyButton; } - public void setCraftableFilterEnabled(boolean enabled) { - appearance.layout.showCraftableOnlyButton = enabled; - } - @Override public String getGamemodeCommand() { return advanced.commands.gamemodeCommand; @@ -217,19 +198,11 @@ public ResourceLocation getInputMethodId() { return functionality.inputMethod; } - public void setInputMethodId(@Nullable ResourceLocation id) { - functionality.inputMethod = id; - } - @Override public boolean doesDisableRecipeBook() { return functionality.disableRecipeBook; } - public void setDisableRecipeBook(boolean disableRecipeBook) { - functionality.disableRecipeBook = disableRecipeBook; - } - @Override public boolean doesFixTabCloseContainer() { return functionality.disableRecipeBook; @@ -240,10 +213,6 @@ public boolean isLeftSideMobEffects() { return functionality.leftSideMobEffects; } - public void setLeftSideMobEffects(boolean leftSideMobEffects) { - functionality.leftSideMobEffects = leftSideMobEffects; - } - @Override public boolean areClickableRecipeArrowsEnabled() { return advanced.miscellaneous.clickableRecipeArrows; @@ -289,10 +258,6 @@ public boolean doesCacheEntryRendering() { return advanced.miscellaneous.cachingFastEntryRendering; } - public void setDoesCacheEntryRendering(boolean doesCacheEntryRendering) { - advanced.miscellaneous.cachingFastEntryRendering = doesCacheEntryRendering; - } - @Override public boolean doDebugRenderTimeRequired() { return advanced.layout.debugRenderTimeRequired; @@ -363,11 +328,6 @@ public double getEntrySize() { return advanced.accessibility.entrySize; } - public boolean setEntrySize(double entrySize) { - double original = advanced.accessibility.entrySize; - return (advanced.accessibility.entrySize = Mth.clamp(entrySize, 0.25, 4)) != original; - } - @Override public boolean isUsingCompactTabs() { return advanced.accessibility.useCompactTabs; @@ -385,7 +345,7 @@ public boolean isLowerConfigButton() { @Override public List getFavoriteEntries() { - return FavoritesEntriesManager.INSTANCE.asListView(); + return ClientInternals.getFavoritesEntriesList(); } public List getConfigFavoriteEntries() { @@ -411,11 +371,6 @@ public boolean shouldFilterDisplays() { return advanced.filtering.shouldFilterDisplays; } - @ApiStatus.Internal - public List> getFilteringRules() { - return advanced.filtering.filteringRules; - } - @ApiStatus.Experimental @Override public Map, Boolean> getFilteringQuickCraftCategories() { @@ -501,10 +456,6 @@ public SyntaxHighlightingMode getSyntaxHighlightingMode() { return appearance.syntaxHighlightingMode; } - public void setSyntaxHighlightingMode(SyntaxHighlightingMode mode) { - appearance.syntaxHighlightingMode = mode; - } - @Override public boolean isFocusModeZoomed() { return appearance.isFocusModeZoomed; @@ -535,10 +486,6 @@ public boolean isJEICompatibilityLayerEnabled() { return Platform.isForge() && advanced.enableJeiCompatibilityLayer; } - public void setJEICompatibilityLayerEnabled(boolean value) { - advanced.enableJeiCompatibilityLayer = value; - } - @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) @interface DontApplyFieldName {} @@ -721,7 +668,7 @@ public static class Miscellaneous { public static class Filtering { @UseFilteringScreen private List> filteredStacks = new ArrayList<>(); public boolean shouldFilterDisplays = true; - @ConfigEntry.Gui.Excluded public List> filteringRules = new ArrayList<>(); + @ConfigEntry.Gui.Excluded public List filteringRules = new ArrayList<>(); @UseFilteringCategoriesScreen public Map, Boolean> filteringQuickCraftCategories = new HashMap<>(); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonRegistryImpl.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonRegistryImpl.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonRegistryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonsScreen.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonsScreen.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonsScreen.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonsScreen.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java index 017201a14..f05a4c98e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java @@ -44,11 +44,11 @@ @ApiStatus.Internal public class ConfigAddonsEntry extends AbstractConfigListEntry { - private int width; - private AbstractWidget buttonWidget = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> { + private final int width; + private final AbstractWidget buttonWidget = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> { Minecraft.getInstance().setScreen(new ConfigAddonsScreen(Minecraft.getInstance().screen)); }); - private List children = ImmutableList.of(buttonWidget); + private final List children = ImmutableList.of(buttonWidget); public ConfigAddonsEntry(int width) { super(NarratorChatListener.NO_TITLE, false); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/RecipeScreenTypeEntry.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/RecipeScreenTypeEntry.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/RecipeScreenTypeEntry.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/RecipeScreenTypeEntry.java index bc37f2a35..514f8bd3f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/RecipeScreenTypeEntry.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/RecipeScreenTypeEntry.java @@ -28,7 +28,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.gui.entries.TooltipListEntry; import me.shedaniel.rei.api.client.gui.config.DisplayScreenType; -import me.shedaniel.rei.impl.client.gui.screen.UncertainDisplayViewingScreen; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.chat.NarratorChatListener; import net.minecraft.client.gui.components.AbstractWidget; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java similarity index 92% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java index 7b09548c7..64da5ac42 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java @@ -27,11 +27,9 @@ import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; -import me.shedaniel.rei.RoughlyEnoughItemsCore; -import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; +import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.common.plugins.PluginManager; import me.shedaniel.rei.impl.client.gui.screen.ConfigReloadingScreen; -import me.shedaniel.rei.impl.client.search.argument.Argument; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.chat.NarratorChatListener; import net.minecraft.client.gui.components.AbstractWidget; @@ -50,8 +48,7 @@ public class ReloadPluginsEntry extends AbstractConfigListEntry { private int width; private AbstractWidget reloadPluginsButton = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> { - RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear(); - RoughlyEnoughItemsCoreClient.reloadPlugins(null, null); + PluginManager.reloadAll(); }) { @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { @@ -64,7 +61,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { } }; private AbstractWidget reloadSearchButton = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> { - Argument.SEARCH_CACHE.clear(); + SearchProvider.getInstance().clearCache(); }); private List children = ImmutableList.of(reloadPluginsButton, reloadSearchButton); @@ -99,7 +96,7 @@ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, this.reloadPluginsButton.setWidth(width / 2 - 2); this.reloadPluginsButton.x = x + entryWidth / 2 - width / 2; this.reloadPluginsButton.render(matrices, mouseX, mouseY, delta); - this.reloadSearchButton.active = this.isEditable() && !Argument.SEARCH_CACHE.isEmpty(); + this.reloadSearchButton.active = this.isEditable() && SearchProvider.getInstance().hasCache(); this.reloadSearchButton.y = y; this.reloadSearchButton.setWidth(width / 2 - 2); this.reloadSearchButton.x = x + entryWidth / 2 + 2; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/SearchFilterSyntaxHighlightingEntry.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/SearchFilterSyntaxHighlightingEntry.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/SearchFilterSyntaxHighlightingEntry.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/SearchFilterSyntaxHighlightingEntry.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/TitleTextEntry.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/TitleTextEntry.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/TitleTextEntry.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/TitleTextEntry.java index 3e2bdc48a..049753e9e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/TitleTextEntry.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/TitleTextEntry.java @@ -39,7 +39,7 @@ @ApiStatus.Internal public class TitleTextEntry extends AbstractConfigListEntry { - private Component text; + private final Component text; public TitleTextEntry(Component text) { super(NarratorChatListener.NO_TITLE, false); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/UncertainDisplayViewingScreen.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/UncertainDisplayViewingScreen.java index e9c71f7cd..d8e07bc3d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/UncertainDisplayViewingScreen.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/UncertainDisplayViewingScreen.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.screen; +package me.shedaniel.rei.impl.client.config.entries; import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; @@ -36,11 +36,8 @@ import me.shedaniel.clothconfig2.impl.EasingMethod; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.RoughlyEnoughItemsCore; -import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import me.shedaniel.rei.api.client.ClientHelper; import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.DisplayScreenType; import me.shedaniel.rei.api.client.gui.widgets.Button; @@ -48,8 +45,8 @@ import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; -import me.shedaniel.rei.impl.ClientInternals; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.chat.NarratorChatListener; @@ -79,12 +76,12 @@ public class UncertainDisplayViewingScreen extends Screen { private boolean original; private double frame = 0; private double target = 0; - private BooleanConsumer callback; + private final BooleanConsumer callback; private Button button; - private Screen parent; + private final Screen parent; private Widget slider; - private boolean showTips; - public NumberAnimator scroll = ValueAnimator.ofDouble(); + private final boolean showTips; + public final NumberAnimator scroll = ValueAnimator.ofDouble(); private List allModsUsingJEI = null; private boolean jeiEnabled = false; @@ -148,10 +145,7 @@ public void init() { if (scroll.target() == 0 && allModsUsingJEI != null) { scroll.setTo(200, 450); } else if (allModsUsingJEI != null && jeiEnabled) { - ConfigManagerImpl.getInstance().getConfig().setJEICompatibilityLayerEnabled(jeiEnabled); - ConfigManager.getInstance().saveConfig(); - RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear(); - RoughlyEnoughItemsCoreClient.reloadPlugins(null, null); + ConfigManagerInternal.getInstance().set("advanced.enableJeiCompatibilityLayer", jeiEnabled); Minecraft.getInstance().setScreen(REIRuntime.getInstance().getPreviousScreen()); } else { callback.accept(original); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java index 9a576014c..2182f01f2 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java @@ -25,7 +25,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.gui.widget.DynamicSmoothScrollingEntryListWidget; -import me.shedaniel.rei.impl.client.gui.text.TextTransformations; +import me.shedaniel.rei.impl.client.util.TextTransformations; import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.client.Minecraft; @@ -97,7 +97,7 @@ public List narratables() { } public static class TextCreditsItem extends CreditsItem { - private Component text; + private final Component text; public TextCreditsItem(Component text) { this.text = text; @@ -120,9 +120,9 @@ public boolean changeFocus(boolean boolean_1) { } public static class TranslationCreditsItem extends CreditsItem { - private Component language; - private List translators; - private int maxWidth; + private final Component language; + private final List translators; + private final int maxWidth; public TranslationCreditsItem(Component language, Component translators, int width, int maxWidth) { this.language = language; @@ -152,11 +152,11 @@ public boolean changeFocus(boolean boolean_1) { } public static class LinkItem extends CreditsItem { - private Component text; - private List textSplit; - private String link; + private final Component text; + private final List textSplit; + private final String link; private boolean contains; - private boolean rainbow; + private final boolean rainbow; public LinkItem(Component text, String link, int width, boolean rainbow) { this.text = text; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java rename to runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java index 8ca4fe7ef..379e6edc2 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java @@ -36,7 +36,6 @@ import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.resources.language.I18n; -import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; @@ -50,7 +49,7 @@ @ApiStatus.Internal public class CreditsScreen extends Screen { - private Screen parent; + private final Screen parent; private AbstractButton buttonDone; private CreditsEntryListWidget entryListWidget; @@ -135,7 +134,8 @@ public void init() { private static void fillTranslators(Exception[] exception, List>> translators) { try { - Class.forName("me.shedaniel.rei.impl.client.gui.credits.%s.CreditsScreenImpl".formatted(Platform.isForge() ? "forge" : "fabric")) + String s = "me.shedaniel.rei.impl.client.gui.credits.%s.CreditsScreenImpl"; + Class.forName(s.contains("%s") ? s.formatted(Platform.isForge() ? "forge" : "fabric") : s) .getDeclaredMethod("fillTranslators", Exception[].class, List.class) .invoke(null, exception, translators); } catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) { diff --git a/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.ConfigManager b/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.ConfigManager new file mode 100644 index 000000000..0ad21ca34 --- /dev/null +++ b/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.ConfigManager @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.config.ConfigManagerImpl \ No newline at end of file diff --git a/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.ConfigObject b/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.ConfigObject new file mode 100644 index 000000000..01599338f --- /dev/null +++ b/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.ConfigObject @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.config.ConfigObjectImpl \ No newline at end of file diff --git a/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry b/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry new file mode 100644 index 000000000..02353547f --- /dev/null +++ b/runtime-engine/configs/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.config.addon.ConfigAddonRegistryImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/BomopofoInputMethod.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/BomopofoInputMethod.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/BomopofoInputMethod.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/BomopofoInputMethod.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/JyutpingInputMethod.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/JyutpingInputMethod.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/JyutpingInputMethod.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/JyutpingInputMethod.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/PinyinInputMethod.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/PinyinInputMethod.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/PinyinInputMethod.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/PinyinInputMethod.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/UniHanInputMethod.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/UniHanInputMethod.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/UniHanInputMethod.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/UniHanInputMethod.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/UniHanManager.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/UniHanManager.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/UniHanManager.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/impl/client/search/method/unihan/UniHanManager.java diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java diff --git a/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultRuntimeInputMethodPlugin.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultRuntimeInputMethodPlugin.java new file mode 100644 index 000000000..f5434a0ad --- /dev/null +++ b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultRuntimeInputMethodPlugin.java @@ -0,0 +1,45 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.plugin.client.runtime; + +import dev.architectury.platform.Platform; +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; +import me.shedaniel.rei.impl.client.search.method.unihan.BomopofoInputMethod; +import me.shedaniel.rei.impl.client.search.method.unihan.JyutpingInputMethod; +import me.shedaniel.rei.impl.client.search.method.unihan.PinyinInputMethod; +import me.shedaniel.rei.impl.client.search.method.unihan.UniHanManager; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public class DefaultRuntimeInputMethodPlugin implements REIClientPlugin { + @Override + public void registerInputMethods(InputMethodRegistry registry) { + UniHanManager manager = new UniHanManager(Platform.getConfigFolder().resolve("roughlyenoughitems/unihan.zip")); + registry.add(new ResourceLocation("rei:pinyin"), new PinyinInputMethod(manager)); + registry.add(new ResourceLocation("rei:jyutping"), new JyutpingInputMethod(manager)); + registry.add(new ResourceLocation("rei:bomopofo"), new BomopofoInputMethod(manager)); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java index 482b0f2ec..533af546a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java +++ b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java @@ -40,8 +40,6 @@ @ApiStatus.Internal public class DefaultRuntimePlugin implements REIServerPlugin { - public static final ResourceLocation PLUGIN = new ResourceLocation("roughlyenoughitems", "default_runtime_plugin"); - @Override public void registerEntryTypes(EntryTypeRegistry registry) { registry.register(VanillaEntryTypes.ITEM, new ItemEntryDefinition()); diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java rename to runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java b/runtime-engine/displays/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java rename to runtime-engine/displays/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/registry/RecipeManagerContextImpl.java b/runtime-engine/displays/src/main/java/me/shedaniel/rei/impl/common/registry/RecipeManagerContextImpl.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/registry/RecipeManagerContextImpl.java rename to runtime-engine/displays/src/main/java/me/shedaniel/rei/impl/common/registry/RecipeManagerContextImpl.java index 0a2167f40..fd6392fcf 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/registry/RecipeManagerContextImpl.java +++ b/runtime-engine/displays/src/main/java/me/shedaniel/rei/impl/common/registry/RecipeManagerContextImpl.java @@ -42,6 +42,10 @@ public class RecipeManagerContextImpl

> implements RecipeM private final Supplier recipeManager; private List> sortedRecipes = null; + public RecipeManagerContextImpl() { + this(supplier()); + } + public RecipeManagerContextImpl(Supplier recipeManager) { this.recipeManager = recipeManager; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/display/DisplaySerializerRegistryImpl.java b/runtime-engine/displays/src/main/java/me/shedaniel/rei/impl/common/registry/display/DisplaySerializerRegistryImpl.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/display/DisplaySerializerRegistryImpl.java rename to runtime-engine/displays/src/main/java/me/shedaniel/rei/impl/common/registry/display/DisplaySerializerRegistryImpl.java index 98b9f6b46..c8a9bcf04 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/display/DisplaySerializerRegistryImpl.java +++ b/runtime-engine/displays/src/main/java/me/shedaniel/rei/impl/common/registry/display/DisplaySerializerRegistryImpl.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.display; +package me.shedaniel.rei.impl.common.registry.display; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; diff --git a/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.display.DisplayRegistry b/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.display.DisplayRegistry new file mode 100644 index 000000000..0da433b23 --- /dev/null +++ b/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.display.DisplayRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.registry.display.DisplayRegistryImpl \ No newline at end of file diff --git a/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.display.DisplaySerializerRegistry b/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.display.DisplaySerializerRegistry new file mode 100644 index 000000000..e908432e2 --- /dev/null +++ b/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.display.DisplaySerializerRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.registry.display.DisplaySerializerRegistryImpl \ No newline at end of file diff --git a/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.registry.RecipeManagerContext b/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.registry.RecipeManagerContext new file mode 100644 index 000000000..1989d999c --- /dev/null +++ b/runtime-engine/displays/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.registry.RecipeManagerContext @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.registry.RecipeManagerContextImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java rename to runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java index af9f4ddb3..6b59b2418 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryImpl.java +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type; +package me.shedaniel.rei.impl.client.entry.type; import com.google.common.collect.Lists; import it.unimi.dsi.fastutil.longs.LongArrayList; @@ -39,6 +39,7 @@ import me.shedaniel.rei.api.common.registry.ReloadStage; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.common.Internals; import me.shedaniel.rei.impl.common.InternalLogger; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -57,8 +58,7 @@ @ApiStatus.Internal @Environment(EnvType.CLIENT) public class EntryRegistryImpl implements EntryRegistry { - public List listeners = Lists.newCopyOnWriteArrayList(); - private PreFilteredEntryList preFilteredList; + private final List listeners = Lists.newCopyOnWriteArrayList(); private EntryRegistryList registryList; private LongSet entriesHash; private boolean reloading; @@ -66,8 +66,10 @@ public class EntryRegistryImpl implements EntryRegistry { public EntryRegistryImpl() { registryList = new NormalEntryRegistryList(); entriesHash = new LongOpenHashSet(); - preFilteredList = new PreFilteredEntryList(this); - listeners.add(preFilteredList); + listeners.addAll(Internals.resolveServices(EntryRegistryListener.class)); + for (EntryRegistryListener listener : listeners) { + listener.attachRegistry(this); + } } @Override @@ -82,11 +84,8 @@ public ReloadStage getStage() { @Override public void startReload() { - listeners.clear(); registryList = new ReloadingEntryRegistryList(); entriesHash = new LongOpenHashSet(); - preFilteredList = new PreFilteredEntryList(this); - listeners.add(preFilteredList); reloading = true; } @@ -117,11 +116,6 @@ public Stream> getEntryStacks() { return registryList.stream(); } - @Override - public List> getPreFilteredList() { - return Collections.unmodifiableList(preFilteredList.getList()); - } - @Override public void refilter() { List> stacks = registryList.collect(); @@ -158,12 +152,6 @@ public List appendStacksForItem(Item item) { return list; } - @ApiStatus.Internal - @Override - public Collection> refilterNew(boolean warn, Collection> entries) { - return preFilteredList.refilterNew(warn, entries); - } - @Override public boolean alreadyContain(EntryStack stack) { return entriesHash.contains(EntryStacks.hashExact(stack)); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryList.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryList.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryList.java rename to runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryList.java index 2672b077a..401bf61a9 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryList.java +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryList.java @@ -21,16 +21,18 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type; +package me.shedaniel.rei.impl.client.entry.type; import it.unimi.dsi.fastutil.longs.LongList; import me.shedaniel.rei.api.common.entry.EntryStack; +import org.jetbrains.annotations.ApiStatus; import java.util.List; import java.util.function.LongPredicate; import java.util.function.Predicate; import java.util.stream.Stream; +@ApiStatus.Internal public interface EntryRegistryList { int size(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryListener.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryListener.java similarity index 89% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryListener.java rename to runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryListener.java index e7b99493c..2e93ed8c2 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryRegistryListener.java +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryListener.java @@ -21,16 +21,21 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type; +package me.shedaniel.rei.impl.client.entry.type; import it.unimi.dsi.fastutil.longs.LongList; +import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.common.entry.EntryStack; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Predicate; +@ApiStatus.Internal public interface EntryRegistryListener { + default void attachRegistry(EntryRegistry registry) {} + default void addEntryAfter(@Nullable EntryStack afterEntry, EntryStack stack, long stackHashExact) {} default void addEntriesAfter(@Nullable EntryStack afterEntry, List> stacks, @Nullable LongList hashes) {} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryTypeRegistryImpl.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryTypeRegistryImpl.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryTypeRegistryImpl.java rename to runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryTypeRegistryImpl.java index 90ec141ba..ad5a6261d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryTypeRegistryImpl.java +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryTypeRegistryImpl.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type; +package me.shedaniel.rei.impl.client.entry.type; import com.google.common.collect.BiMap; import com.google.common.collect.HashBasedTable; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/NormalEntryRegistryList.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/NormalEntryRegistryList.java similarity index 96% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/NormalEntryRegistryList.java rename to runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/NormalEntryRegistryList.java index a6e752c6e..73f378c0f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/NormalEntryRegistryList.java +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/NormalEntryRegistryList.java @@ -21,11 +21,12 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type; +package me.shedaniel.rei.impl.client.entry.type; import it.unimi.dsi.fastutil.longs.LongList; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.EntryStacks; +import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; import java.util.List; @@ -34,6 +35,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +@ApiStatus.Internal public class NormalEntryRegistryList implements EntryRegistryList { private List> list = new ArrayList<>(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/ReloadingEntryRegistryList.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/ReloadingEntryRegistryList.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/ReloadingEntryRegistryList.java rename to runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/ReloadingEntryRegistryList.java index 44211ce2c..53f21406b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/ReloadingEntryRegistryList.java +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/ReloadingEntryRegistryList.java @@ -21,13 +21,14 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type; +package me.shedaniel.rei.impl.client.entry.type; import it.unimi.dsi.fastutil.longs.LongList; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import net.minecraft.core.Registry; +import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; import java.util.List; @@ -35,6 +36,7 @@ import java.util.function.Predicate; import java.util.stream.Stream; +@ApiStatus.Internal public class ReloadingEntryRegistryList implements EntryRegistryList { private List list = new ArrayList<>(Registry.ITEM.keySet().size() + 100); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsibleEntryRegistryImpl.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/collapsed/CollapsibleEntryRegistryImpl.java similarity index 78% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsibleEntryRegistryImpl.java rename to runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/collapsed/CollapsibleEntryRegistryImpl.java index 69b86f397..f5222f864 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsibleEntryRegistryImpl.java +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/collapsed/CollapsibleEntryRegistryImpl.java @@ -21,38 +21,43 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type.collapsed; +package me.shedaniel.rei.impl.client.entry.type.collapsed; +import com.google.common.collect.ForwardingList; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntry; import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.common.InternalLogger; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Collectors; -public class CollapsibleEntryRegistryImpl implements CollapsibleEntryRegistry { +@ApiStatus.Internal +public class CollapsibleEntryRegistryImpl extends ForwardingList implements CollapsibleEntryRegistry { private final List entries = new ArrayList<>(); @Override public void group(ResourceLocation id, Component name, List> stacks) { Objects.requireNonNull(stacks, "stacks"); - this.entries.add(new Entry(id.getNamespace(), name, new ListMatcher(stacks))); + this.entries.add(new Entry(id, name, new ListMatcher(stacks))); InternalLogger.getInstance().debug("Added collapsible entry group [%s] %s with %d entries", id, name.getString(), stacks.size()); } @Override public void group(ResourceLocation id, Component name, Predicate> predicate) { Objects.requireNonNull(predicate, "predicate"); - this.entries.add(new Entry(id.getNamespace(), name, (stack, hashExact) -> ((Predicate>) predicate).test(stack))); + this.entries.add(new Entry(id, name, (stack, hashExact) -> ((Predicate>) predicate).test(stack))); InternalLogger.getInstance().debug("Added collapsible entry group [%s] %s with dynamic predicate", id, name.getString()); } @@ -72,38 +77,44 @@ public void acceptPlugin(REIClientPlugin plugin) { plugin.registerCollapsibleEntries(this); } - public List getEntries() { - return entries; + @Override + protected List delegate() { + return (List) (List) Collections.unmodifiableList(this.entries); } - public static class Entry { - private final String modId; + public static class Entry implements CollapsibleEntry { + private final ResourceLocation id; private final Component name; private final Matcher matcher; private boolean expanded; - public Entry(String modId, Component name, Matcher matcher) { - this.modId = modId; + public Entry(ResourceLocation id, Component name, Matcher matcher) { + this.id = id; this.name = name; this.matcher = matcher; } - public String getModId() { - return modId; + @Override + public ResourceLocation getId() { + return id; } + @Override public Component getName() { return name; } - public Matcher getMatcher() { - return matcher; + @Override + public boolean matches(EntryStack stack, long hashExact) { + return matcher.matches(stack, hashExact); } + @Override public boolean isExpanded() { return expanded; } + @Override public void setExpanded(boolean expanded) { this.expanded = expanded; } diff --git a/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry b/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry new file mode 100644 index 000000000..3210bfe57 --- /dev/null +++ b/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.entry.type.collapsed.CollapsibleEntryRegistryImpl \ No newline at end of file diff --git a/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.EntryRegistry b/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.EntryRegistry new file mode 100644 index 000000000..e199e1429 --- /dev/null +++ b/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.EntryRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.entry.type.EntryRegistryImpl \ No newline at end of file diff --git a/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry b/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry new file mode 100644 index 000000000..22783a762 --- /dev/null +++ b/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.entry.type.EntryTypeRegistryImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java rename to runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java index 2a512718d..4da98dd58 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java @@ -26,8 +26,9 @@ import com.google.common.collect.Iterators; import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.provider.EntryIngredientProvider; import net.minecraft.nbt.ListTag; +import org.jetbrains.annotations.ApiStatus; import java.util.*; import java.util.function.Consumer; @@ -35,9 +36,8 @@ import java.util.function.UnaryOperator; import java.util.stream.StreamSupport; -public enum EntryIngredientImpl implements Internals.EntryIngredientProvider { - INSTANCE; - +@ApiStatus.Internal +public class EntryIngredientImpl implements EntryIngredientProvider { @Override public EntryIngredient empty() { return EmptyEntryIngredient.EMPTY; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/settings/EntrySettingsAdapterRegistryImpl.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/settings/EntrySettingsAdapterRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/settings/EntrySettingsAdapterRegistryImpl.java rename to runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/settings/EntrySettingsAdapterRegistryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/AbstractEntryStack.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java rename to runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/AbstractEntryStack.java index d67beed02..9bfe7bfb5 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/AbstractEntryStack.java +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/AbstractEntryStack.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry; +package me.shedaniel.rei.impl.common.entry.stack; import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; @@ -54,7 +54,7 @@ import java.util.stream.Stream; @ApiStatus.Internal -public abstract class AbstractEntryStack implements EntryStack, Renderer { +abstract class AbstractEntryStack implements EntryStack, Renderer { private static final Short2ObjectMap EMPTY_SETTINGS = Short2ObjectMaps.emptyMap(); private Short2ObjectMap settings = null; @Environment(EnvType.CLIENT) diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EmptyEntryStack.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EmptyEntryStack.java similarity index 90% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EmptyEntryStack.java rename to runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EmptyEntryStack.java index 030a17b09..43030eb92 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EmptyEntryStack.java +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EmptyEntryStack.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry; +package me.shedaniel.rei.impl.common.entry.stack; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.BuiltinEntryTypes; @@ -30,8 +30,8 @@ import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal -public class EmptyEntryStack extends AbstractEntryStack { - public static final EntryStack EMPTY = new EmptyEntryStack(); +class EmptyEntryStack extends AbstractEntryStack { + static final EntryStack EMPTY = new EmptyEntryStack(); @Override public EntryDefinition getDefinition() { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EntryStackProviderImpl.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EntryStackProviderImpl.java similarity index 88% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EntryStackProviderImpl.java rename to runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EntryStackProviderImpl.java index b1cd2d932..3cf510df6 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/EntryStackProviderImpl.java +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EntryStackProviderImpl.java @@ -21,19 +21,19 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry; +package me.shedaniel.rei.impl.common.entry.stack; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.BuiltinEntryTypes; import me.shedaniel.rei.api.common.entry.type.EntryDefinition; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.provider.EntryStackProvider; import net.minecraft.util.Unit; +import org.jetbrains.annotations.ApiStatus; import java.util.Objects; -public enum EntryStackProviderImpl implements Internals.EntryStackProvider { - INSTANCE; - +@ApiStatus.Internal +public class EntryStackProviderImpl implements EntryStackProvider { @Override public EntryStack empty() { return EmptyEntryStack.EMPTY; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/TypedEntryStack.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/TypedEntryStack.java similarity index 91% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/TypedEntryStack.java rename to runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/TypedEntryStack.java index 5d159d79b..41003fc9d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/TypedEntryStack.java +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/TypedEntryStack.java @@ -21,17 +21,17 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry; +package me.shedaniel.rei.impl.common.entry.stack; import me.shedaniel.rei.api.common.entry.type.EntryDefinition; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal -public class TypedEntryStack extends AbstractEntryStack { +class TypedEntryStack extends AbstractEntryStack { private final EntryDefinition definition; private T value; - public TypedEntryStack(EntryDefinition definition, T value) { + TypedEntryStack(EntryDefinition definition, T value) { this.definition = definition; this.value = value; if (!definition.acceptsNull()) { diff --git a/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.settings.EntrySettingsAdapterRegistry b/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.settings.EntrySettingsAdapterRegistry new file mode 100644 index 000000000..bc736692e --- /dev/null +++ b/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.settings.EntrySettingsAdapterRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.entry.settings.EntrySettingsAdapterRegistryImpl \ No newline at end of file diff --git a/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.EntryIngredientProvider b/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.EntryIngredientProvider new file mode 100644 index 000000000..9349d031d --- /dev/null +++ b/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.EntryIngredientProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.entry.EntryIngredientImpl \ No newline at end of file diff --git a/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.EntryStackProvider b/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.EntryStackProvider new file mode 100644 index 000000000..2ef298128 --- /dev/null +++ b/runtime-engine/entry-stacks/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.EntryStackProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.entry.stack.EntryStackProviderImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/renderer/EntryRendererRegistryImpl.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/client/entry/renderer/EntryRendererRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/renderer/EntryRendererRegistryImpl.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/client/entry/renderer/EntryRendererRegistryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/EntryComparatorRegistryImpl.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/EntryComparatorRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/EntryComparatorRegistryImpl.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/EntryComparatorRegistryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/FluidComparatorRegistryImpl.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/FluidComparatorRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/FluidComparatorRegistryImpl.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/FluidComparatorRegistryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/ItemComparatorRegistryImpl.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/ItemComparatorRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/ItemComparatorRegistryImpl.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/ItemComparatorRegistryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/NbtHasherProviderImpl.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/NbtHasherProviderImpl.java similarity index 96% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/NbtHasherProviderImpl.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/NbtHasherProviderImpl.java index 83b8c171e..4e5d02b2f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/NbtHasherProviderImpl.java +++ b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/comparison/NbtHasherProviderImpl.java @@ -26,7 +26,7 @@ import com.google.common.base.Predicates; import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext; import me.shedaniel.rei.api.common.entry.comparison.EntryComparator; -import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.provider.NbtHasherProvider; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; @@ -35,8 +35,7 @@ import java.util.*; import java.util.function.Predicate; -public enum NbtHasherProviderImpl implements Internals.NbtHasherProvider { - INSTANCE; +public class NbtHasherProviderImpl implements NbtHasherProvider { private final EntryComparator defaultHasher = _provide(); @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/BuiltinEntryDefinition.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/BuiltinEntryDefinition.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/BuiltinEntryDefinition.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/BuiltinEntryDefinition.java index d87a94300..1a175cfec 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/BuiltinEntryDefinition.java +++ b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/BuiltinEntryDefinition.java @@ -46,7 +46,7 @@ import java.util.stream.Stream; @ApiStatus.Internal -public class BuiltinEntryDefinition implements EntryDefinition, EntrySerializer { +class BuiltinEntryDefinition implements EntryDefinition, EntrySerializer { private final Class clazz; private final EntryType type; private final boolean empty; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryTypeDeferred.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/DeferredEntryTypeImpl.java similarity index 91% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryTypeDeferred.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/DeferredEntryTypeImpl.java index cb563f6fa..bc4a8cb32 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/EntryTypeDeferred.java +++ b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/DeferredEntryTypeImpl.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type; +package me.shedaniel.rei.impl.common.entry.type.types; import me.shedaniel.rei.api.common.entry.type.EntryDefinition; import me.shedaniel.rei.api.common.entry.type.EntryType; @@ -32,12 +32,12 @@ import java.lang.ref.WeakReference; @ApiStatus.Internal -public class EntryTypeDeferred implements EntryType { +class DeferredEntryTypeImpl implements EntryType { private final ResourceLocation id; private final int hashCode; private WeakReference> reference; - public EntryTypeDeferred(ResourceLocation id) { + DeferredEntryTypeImpl(ResourceLocation id) { this.id = id; this.hashCode = id.hashCode(); } @@ -67,7 +67,7 @@ public EntryDefinition getDefinition() { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof EntryTypeDeferred that)) return false; + if (!(o instanceof DeferredEntryTypeImpl that)) return false; return hashCode == that.hashCode && id.equals(that.id); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/DeferringEntryTypeProviderImpl.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/DeferringEntryTypeProviderImpl.java similarity index 50% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/DeferringEntryTypeProviderImpl.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/DeferringEntryTypeProviderImpl.java index 84ff3ff7c..bf671635a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/DeferringEntryTypeProviderImpl.java +++ b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/DeferringEntryTypeProviderImpl.java @@ -21,88 +21,88 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry; +package me.shedaniel.rei.impl.common.entry.type.types; +import com.google.common.base.Suppliers; import dev.architectury.platform.Platform; import dev.architectury.utils.Env; import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.common.entry.type.BuiltinEntryTypes; import me.shedaniel.rei.api.common.entry.type.EntryDefinition; import me.shedaniel.rei.api.common.entry.type.EntryType; -import me.shedaniel.rei.impl.client.entry.type.types.RenderingEntryDefinition; -import me.shedaniel.rei.impl.common.entry.type.EntryTypeDeferred; -import me.shedaniel.rei.impl.common.entry.type.types.EmptyEntryDefinition; +import me.shedaniel.rei.impl.common.provider.DeferringEntryTypeProvider; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Unit; +import org.jetbrains.annotations.ApiStatus; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; +import java.util.function.Supplier; -public enum DeferringEntryTypeProviderImpl implements Function> { - INSTANCE; - ResourceLocation RENDERING_ID = new ResourceLocation("rendering"); - private Map> typeCache = new ConcurrentHashMap<>(); - private EntryType empty; +@ApiStatus.Internal +public class DeferringEntryTypeProviderImpl implements DeferringEntryTypeProvider { + private static final ResourceLocation RENDERING_ID = new ResourceLocation("rendering"); + private final Map> typeCache = new ConcurrentHashMap<>(); + private final Supplier> empty = Suppliers.memoize(() -> emptyType(BuiltinEntryTypes.EMPTY_ID)); @Environment(EnvType.CLIENT) - private EntryType render; + private Supplier> render; + + public DeferringEntryTypeProviderImpl() { + if (Platform.getEnvironment() == Env.CLIENT) { + render = Suppliers.memoize(() -> renderingType(RENDERING_ID)); + } + } @Override - public EntryType apply(ResourceLocation id) { + public EntryType get(ResourceLocation id) { if (id.equals(BuiltinEntryTypes.EMPTY_ID)) { - return typeCache.computeIfAbsent(id, this::emptyType); + return typeCache.computeIfAbsent(id, $ -> empty.get()); } else if (id.equals(RENDERING_ID) && Platform.getEnvironment() == Env.CLIENT) { - return typeCache.computeIfAbsent(id, this::renderingType); + return typeCache.computeIfAbsent(id, $ -> render.get()); } - return typeCache.computeIfAbsent(id, EntryTypeDeferred::new); + return typeCache.computeIfAbsent(id, DeferredEntryTypeImpl::new); } public EntryType emptyType(ResourceLocation id) { - if (empty == null) { - int hashCode = id.hashCode(); - empty = new EntryType<>() { - @Override - public ResourceLocation getId() { - return id; - } - - @Override - public EntryDefinition getDefinition() { - return EmptyEntryDefinition.EMPTY; - } - - @Override - public int hashCode() { - return hashCode; - } - }; - } - return empty; + int hashCode = id.hashCode(); + return new EntryType<>() { + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public EntryDefinition getDefinition() { + return EmptyEntryDefinition.EMPTY; + } + + @Override + public int hashCode() { + return hashCode; + } + }; } @Environment(EnvType.CLIENT) public EntryType renderingType(ResourceLocation id) { - if (render == null) { - int hashCode = id.hashCode(); - render = new EntryType<>() { - @Override - public ResourceLocation getId() { - return id; - } - - @Override - public EntryDefinition getDefinition() { - return RenderingEntryDefinition.RENDERING; - } - - @Override - public int hashCode() { - return hashCode; - } - }; - } - return render; + int hashCode = id.hashCode(); + return new EntryType<>() { + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public EntryDefinition getDefinition() { + return RenderingEntryDefinition.RENDERING; + } + + @Override + public int hashCode() { + return hashCode; + } + }; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/EmptyEntryDefinition.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/EmptyEntryDefinition.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/EmptyEntryDefinition.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/EmptyEntryDefinition.java index 249ba04ed..1ea22b720 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/EmptyEntryDefinition.java +++ b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/EmptyEntryDefinition.java @@ -26,7 +26,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.BuiltinEntryTypes; import me.shedaniel.rei.api.common.entry.type.EntryDefinition; @@ -34,17 +33,17 @@ import net.fabricmc.api.Environment; import net.minecraft.util.Unit; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; @ApiStatus.Internal public class EmptyEntryDefinition { - public static final EntryDefinition EMPTY = new BuiltinEntryDefinition<>(Unit.class, BuiltinEntryTypes.EMPTY, true, () -> Unit.INSTANCE, () -> () -> new EmptyRenderer()); + public static final EntryDefinition EMPTY = new BuiltinEntryDefinition<>(Unit.class, BuiltinEntryTypes.EMPTY, true, () -> Unit.INSTANCE, () -> () -> EmptyRenderer.INSTANCE); @Environment(EnvType.CLIENT) public static class EmptyRenderer implements EntryRenderer { + private static final EmptyRenderer INSTANCE = new EmptyRenderer(); + @Override public void render(EntryStack entry, PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { - } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/type/types/RenderingEntryDefinition.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/RenderingEntryDefinition.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/type/types/RenderingEntryDefinition.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/RenderingEntryDefinition.java index a67cfe78e..d8d934abe 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/type/types/RenderingEntryDefinition.java +++ b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/entry/type/types/RenderingEntryDefinition.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.entry.type.types; +package me.shedaniel.rei.impl.common.entry.type.types; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Rectangle; @@ -32,7 +32,6 @@ import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.EntryDefinition; -import me.shedaniel.rei.impl.common.entry.type.types.BuiltinEntryDefinition; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.chat.Component; @@ -41,7 +40,7 @@ @ApiStatus.Internal @Environment(EnvType.CLIENT) -public class RenderingEntryDefinition { +class RenderingEntryDefinition { public static final EntryDefinition RENDERING = new BuiltinEntryDefinition(Renderer.class, BuiltinClientEntryTypes.RENDERING, false, RenderingEntryDefinition::throwRendering, () -> () -> DeferredRenderer.INSTANCE) { @Override public Component asFormattedText(EntryStack entry, Renderer value) { @@ -55,7 +54,7 @@ public Component asFormattedText(EntryStack entry, Renderer value) { } return super.asFormattedText(entry, value); } - + @Override public Component asFormattedText(EntryStack entry, Renderer value, TooltipContext context) { Tooltip tooltip = value.getTooltip(context); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/fluid/FluidSupportProviderImpl.java b/runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/fluid/FluidSupportProviderImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/fluid/FluidSupportProviderImpl.java rename to runtime-engine/entry-types/src/main/java/me/shedaniel/rei/impl/common/fluid/FluidSupportProviderImpl.java diff --git a/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.entry.renderer.EntryRendererRegistry b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.entry.renderer.EntryRendererRegistry new file mode 100644 index 000000000..b28d3384d --- /dev/null +++ b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.entry.renderer.EntryRendererRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.entry.renderer.EntryRendererRegistryImpl \ No newline at end of file diff --git a/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.comparison.FluidComparatorRegistry b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.comparison.FluidComparatorRegistry new file mode 100644 index 000000000..094bb8aae --- /dev/null +++ b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.comparison.FluidComparatorRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.entry.comparison.FluidComparatorRegistryImpl \ No newline at end of file diff --git a/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry new file mode 100644 index 000000000..a7c730390 --- /dev/null +++ b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.entry.comparison.ItemComparatorRegistryImpl \ No newline at end of file diff --git a/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.fluid.FluidSupportProvider b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.fluid.FluidSupportProvider new file mode 100644 index 000000000..99e36c9f4 --- /dev/null +++ b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.fluid.FluidSupportProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.fluid.FluidSupportProviderImpl \ No newline at end of file diff --git a/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.DeferringEntryTypeProvider b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.DeferringEntryTypeProvider new file mode 100644 index 000000000..95aeea47d --- /dev/null +++ b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.DeferringEntryTypeProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.entry.type.types.DeferringEntryTypeProviderImpl \ No newline at end of file diff --git a/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.NbtHasherProvider b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.NbtHasherProvider new file mode 100644 index 000000000..5f9b83304 --- /dev/null +++ b/runtime-engine/entry-types/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.NbtHasherProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.entry.comparison.NbtHasherProviderImpl \ No newline at end of file diff --git a/runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java b/runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java new file mode 100644 index 000000000..39b866599 --- /dev/null +++ b/runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java @@ -0,0 +1,125 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.favorites; + +import com.mojang.serialization.DataResult; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.impl.client.provider.DelegatingFavoriteEntryProvider; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; + +import java.util.Collection; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Supplier; + +public class DelegatingFavoriteEntryProviderImpl implements DelegatingFavoriteEntryProvider { + @Override + public FavoriteEntry delegate(Supplier> result, Supplier tag) { + return new DelegatedFavoriteEntry(result, tag); + } + + private static class DelegatedFavoriteEntry extends FavoriteEntry { + private final Supplier> supplier; + private final Supplier toJson; + private FavoriteEntry value = null; + + public DelegatedFavoriteEntry(Supplier> supplier, Supplier toJson) { + this.supplier = supplier; + this.toJson = toJson; + } + + @Override + public FavoriteEntry getUnwrapped() { + synchronized (this) { + if (this.value == null) { + DataResult result = supplier.get(); + this.value = result.getOrThrow(false, error -> {}); + } + } + return Objects.requireNonNull(value).getUnwrapped(); + } + + @Override + public UUID getUuid() { + return getUnwrapped().getUuid(); + } + + @Override + public boolean isInvalid() { + try { + return getUnwrapped().isInvalid(); + } catch (Exception e) { + return true; + } + } + + @Override + public Renderer getRenderer(boolean showcase) { + return getUnwrapped().getRenderer(showcase); + } + + @Override + public boolean doAction(int button) { + return getUnwrapped().doAction(button); + } + + @Override + public Optional>> getMenuEntries() { + return getUnwrapped().getMenuEntries(); + } + + @Override + public long hashIgnoreAmount() { + return getUnwrapped().hashIgnoreAmount(); + } + + @Override + public FavoriteEntry copy() { + return FavoriteEntry.delegateResult(supplier, toJson); + } + + @Override + public ResourceLocation getType() { + return getUnwrapped().getType(); + } + + @Override + public CompoundTag save(CompoundTag tag) { + if (toJson == null) { + return getUnwrapped().save(tag); + } + + return tag.merge(toJson.get()); + } + + @Override + public boolean isSame(FavoriteEntry other) { + return getUnwrapped().isSame(other.getUnwrapped()); + } + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/FavoriteEntryTypeRegistryImpl.java b/runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/favorites/FavoriteEntryTypeRegistryImpl.java similarity index 85% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/FavoriteEntryTypeRegistryImpl.java rename to runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/favorites/FavoriteEntryTypeRegistryImpl.java index fbd5f3330..6cd8ffb24 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/FavoriteEntryTypeRegistryImpl.java +++ b/runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/favorites/FavoriteEntryTypeRegistryImpl.java @@ -35,12 +35,10 @@ import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.common.registry.ReloadStage; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; +import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesEntriesManager; import me.shedaniel.rei.impl.common.InternalLogger; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; -import org.apache.commons.lang3.mutable.MutableLong; -import org.apache.commons.lang3.tuple.Triple; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -51,7 +49,6 @@ @ApiStatus.Internal public class FavoriteEntryTypeRegistryImpl implements FavoriteEntryType.Registry { private final BiMap> registry = HashBiMap.create(); - private final List, MutableLong, List>> systemFavorites = Lists.newArrayList(); private final Map sections = Maps.newConcurrentMap(); private final List sectionsList = Lists.newCopyOnWriteArrayList(); @@ -98,18 +95,11 @@ public Iterable sections() { @Override public void registerSystemFavorites(SystemFavoriteEntryProvider provider) { - this.systemFavorites.add(Triple.of(provider, new MutableLong(-1), new ArrayList<>())); - InternalLogger.getInstance().debug("Added system favorites: %s", provider); - } - - public List, MutableLong, List>> getSystemProviders() { - return this.systemFavorites; } @Override public void startReload() { this.registry.clear(); - this.systemFavorites.clear(); this.sections.clear(); this.sectionsList.clear(); } @@ -117,8 +107,8 @@ public void startReload() { @Override public void endReload() { if (ConfigObject.getInstance().isFavoritesEnabled()) { - ConfigManagerImpl.getInstance().getConfig().getConfigFavoriteEntries().removeIf(FavoriteEntry::isInvalid); - ConfigManagerImpl.getInstance().getConfig().getHiddenFavoriteEntries().removeIf(FavoriteEntry::isInvalid); + FavoritesEntriesManager.getConfigFavoriteEntries().removeIf(FavoriteEntry::isInvalid); + FavoritesEntriesManager.getConfigHiddenFavoriteEntries().removeIf(FavoriteEntry::isInvalid); ConfigManager.getInstance().saveConfig(); } diff --git a/runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesEntriesManager.java b/runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesEntriesManager.java new file mode 100644 index 000000000..6f01cb29b --- /dev/null +++ b/runtime-engine/favorites/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesEntriesManager.java @@ -0,0 +1,155 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget.favorites; + +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.client.overlay.OverlayListWidget; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; +import me.shedaniel.rei.impl.client.favorites.MutableFavoritesList; +import me.shedaniel.rei.impl.client.provider.FavoritesEntriesListProvider; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public class FavoritesEntriesManager implements FavoritesEntriesListProvider { + + public static List getConfigFavoriteEntries() { + ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); + return (List) manager.get("basics.favorites"); + } + + public static List getConfigHiddenFavoriteEntries() { + ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); + return (List) manager.get("basics.hiddenFavorites"); + } + + private static Stream getDefaultFavorites() { + return StreamSupport.stream(FavoriteEntryType.registry().sections().spliterator(), false) + .flatMap(section -> section.getDefaultEntries().stream()); + } + + public static List getFavorites() { + List defaultFavorites = getDefaultFavorites().collect(Collectors.toList()); + defaultFavorites.removeAll(getConfigHiddenFavoriteEntries()); + + List favorites = new ArrayList<>(getConfigFavoriteEntries()); + defaultFavorites.removeAll(favorites); + favorites.addAll(0, defaultFavorites); + favorites.removeIf(FavoriteEntry::isInvalid); + return favorites; + } + + public static void remove(FavoriteEntry entry) { + getConfigFavoriteEntries().remove(entry); + if (getDefaultFavorites().anyMatch(e -> e.equals(entry)) && !getConfigHiddenFavoriteEntries().contains(entry)) { + getConfigHiddenFavoriteEntries().add(entry); + } + + ConfigManager.getInstance().saveConfig(); + REIRuntime.getInstance().getOverlay().flatMap(ScreenOverlay::getFavoritesList).ifPresent(OverlayListWidget::queueReloadSearch); + } + + public static void add(FavoriteEntry entry) { + List defaultFavorites = getDefaultFavorites().toList(); + + getConfigFavoriteEntries().remove(entry); + if (CollectionUtils.anyMatch(defaultFavorites, e -> e.equals(entry)) && !getConfigHiddenFavoriteEntries().contains(entry)) { + getConfigHiddenFavoriteEntries().add(entry); + } + + for (int i = defaultFavorites.size() - 1; i >= 0; i--) { + FavoriteEntry e = defaultFavorites.get(i); + if (!getConfigFavoriteEntries().contains(e) && !getConfigHiddenFavoriteEntries().contains(e)) { + getConfigFavoriteEntries().add(0, e); + } + } + + getConfigHiddenFavoriteEntries().remove(entry); + if (!CollectionUtils.anyMatch(defaultFavorites, e -> e.equals(entry))) { + getConfigFavoriteEntries().add(entry); + } + + ConfigManager.getInstance().saveConfig(); + REIRuntime.getInstance().getOverlay().flatMap(ScreenOverlay::getFavoritesList).ifPresent(OverlayListWidget::queueReloadSearch); + } + + public static void setEntries(List entries) { + List defaultFavorites = getDefaultFavorites().toList(); + List hiddenDefaultFavorites = new ArrayList<>(defaultFavorites); + hiddenDefaultFavorites.removeAll(entries); + getConfigHiddenFavoriteEntries().clear(); + getConfigHiddenFavoriteEntries().addAll(hiddenDefaultFavorites); + getConfigFavoriteEntries().clear(); + getConfigFavoriteEntries().addAll(entries); + + ConfigManager.getInstance().saveConfig(); + REIRuntime.getInstance().getOverlay().flatMap(ScreenOverlay::getFavoritesList).ifPresent(OverlayListWidget::queueReloadSearch); + } + + @Override + public List get() { + return new ListView(); + } + + private static class ListView extends AbstractList implements MutableFavoritesList { + @Override + public FavoriteEntry get(int index) { + return getFavorites().get(index); + } + + @Override + public int size() { + return getFavorites().size(); + } + + @Override + public void add(int index, FavoriteEntry entry) { + FavoritesEntriesManager.add(entry); + } + + @Override + public boolean remove(Object o) { + if (o instanceof FavoriteEntry) { + FavoritesEntriesManager.remove((FavoriteEntry) o); + return true; + } else { + return false; + } + } + + @Override + public void setAll(List entries) { + FavoritesEntriesManager.setEntries(entries); + } + } +} diff --git a/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.favorites.FavoriteEntryType$Registry b/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.favorites.FavoriteEntryType$Registry new file mode 100644 index 000000000..29074a209 --- /dev/null +++ b/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.favorites.FavoriteEntryType$Registry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.favorites.FavoriteEntryTypeRegistryImpl \ No newline at end of file diff --git a/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.DelegatingFavoriteEntryProvider b/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.DelegatingFavoriteEntryProvider new file mode 100644 index 000000000..8e9e48206 --- /dev/null +++ b/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.DelegatingFavoriteEntryProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.favorites.DelegatingFavoriteEntryProviderImpl \ No newline at end of file diff --git a/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.FavoritesEntriesListProvider b/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.FavoritesEntriesListProvider new file mode 100644 index 000000000..6b97f7540 --- /dev/null +++ b/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.FavoritesEntriesListProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesEntriesManager \ No newline at end of file diff --git a/runtime-engine/filtering-entries/build.gradle b/runtime-engine/filtering-entries/build.gradle new file mode 100644 index 000000000..e25abac53 --- /dev/null +++ b/runtime-engine/filtering-entries/build.gradle @@ -0,0 +1,3 @@ +dependencies { + compileClasspath(project(path: ":runtime-engine:entries", configuration: "namedElements")) +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringAddRuleScreen.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringAddRuleScreen.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringAddRuleScreen.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringAddRuleScreen.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesEntry.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesEntry.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesEntry.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesEntry.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesScreen.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesScreen.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesScreen.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringCategoriesScreen.java diff --git a/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringConfigEntries.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringConfigEntries.java new file mode 100644 index 000000000..0739d1894 --- /dev/null +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringConfigEntries.java @@ -0,0 +1,127 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.config.entries; + +import com.google.common.collect.Lists; +import me.shedaniel.autoconfig.gui.registry.GuiRegistry; +import me.shedaniel.autoconfig.util.Utils; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Jankson; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.JsonNull; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.api.DeserializationException; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRule; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleType; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; +import net.minecraft.ResourceLocationException; +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.nbt.TagParser; +import net.minecraft.network.chat.TranslatableComponent; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Consumer; + +import static me.shedaniel.autoconfig.util.Utils.setUnsafely; + +public class FilteringConfigEntries implements ConfigManagerInternal.SystemSetup { + @Override + public void setup(GuiRegistry registry) { + registry.registerPredicateProvider((i13n, field, config, defaults, guiProvider) -> { + List> value = CollectionUtils.map(Utils.>>getUnsafely(field, config, new ArrayList<>()), EntryStackProvider::provide); + List> defaultValue = CollectionUtils.map(Utils.>>getUnsafely(field, defaults), EntryStackProvider::provide); + Consumer>> saveConsumer = (newValue) -> { + setUnsafely(field, config, CollectionUtils.map(newValue, EntryStackProvider::ofStack)); + }; + try { + Field filteringRules = config.getClass().getDeclaredField("filteringRules"); + return REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().getRecipeManager() == null ? + Collections.singletonList(new NoFilteringEntry(220, value, defaultValue, saveConsumer)) + : + Collections.singletonList(new FilteringEntry(220, value, Utils.getUnsafely(filteringRules, config), defaultValue, saveConsumer, list -> setUnsafely(filteringRules, config, Lists.newArrayList(list)))); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + , (field) -> field.getType() == List.class && field.getName().equals("filteredStacks")); + registry.registerPredicateProvider((i13n, field, config, defaults, guiProvider) -> { + Map, Boolean> value = Utils., Boolean>>getUnsafely(field, config, new HashMap<>()); + Map, Boolean> defaultValue = Utils.getUnsafely(field, defaults); + Consumer, Boolean>> saveConsumer = (newValue) -> { + setUnsafely(field, config, newValue); + }; + return REIRuntime.getInstance().getPreviousContainerScreen() == null || Minecraft.getInstance().getConnection() == null || Minecraft.getInstance().getConnection().getRecipeManager() == null ? + Collections.singletonList(new NoFilteringCategoriesEntry(new TranslatableComponent(i13n), value, defaultValue, saveConsumer)) + : + Collections.singletonList(new FilteringCategoriesEntry(new TranslatableComponent(i13n), value, defaultValue, saveConsumer)); + } + , (field) -> field.getType() == Map.class && field.getName().equals("filteringQuickCraftCategories")); + } + + @Override + public void setup(Jankson.Builder builder) { + // FilteringRule + builder.registerSerializer(FilteringRule.class, (value, marshaller) -> { + try { + return marshaller.serialize(FilteringRuleType.save(value, new CompoundTag())); + } catch (Exception e) { + e.printStackTrace(); + return JsonNull.INSTANCE; + } + }); + builder.registerDeserializer(Tag.class, FilteringRule.class, (value, marshaller) -> { + try { + return FilteringRuleType.read((CompoundTag) value); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + }); + builder.registerDeserializer(String.class, FilteringRule.class, (value, marshaller) -> { + try { + return FilteringRuleType.read(TagParser.parseTag(value)); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + }); + + // CategoryIdentifier + builder.registerSerializer(CategoryIdentifier.class, (value, marshaller) -> { + return marshaller.serialize(value.toString()); + }); + builder.registerDeserializer(String.class, CategoryIdentifier.class, (value, marshaller) -> { + try { + return CategoryIdentifier.of(value); + } catch (ResourceLocationException e) { + throw new DeserializationException(e); + } + }); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringEntry.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringEntry.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringEntry.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringEntry.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java index 0f69cdaa3..608173db8 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRuleOptionsScreen.java @@ -23,8 +23,6 @@ package me.shedaniel.rei.impl.client.config.entries; -import com.google.common.collect.Collections2; -import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; @@ -122,13 +120,13 @@ protected int getScrollbarPosition() { } public static abstract class RuleEntry extends DynamicElementListWidget.ElementEntry { - private final FilteringRule rule; + private final FilteringRule rule; - public RuleEntry(FilteringRule rule) { + public RuleEntry(FilteringRule rule) { this.rule = rule; } - public FilteringRule getRule() { + public FilteringRule getRule() { return rule; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringRulesScreen.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java similarity index 86% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java index 68751f5d6..f5d790219 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringScreen.java @@ -35,16 +35,13 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.math.impl.PointHelper; import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.common.entry.EntrySerializer; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.widget.BatchedEntryRendererManager; -import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; -import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; @@ -64,15 +61,13 @@ import java.util.Set; import java.util.function.Predicate; -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; - @ApiStatus.Internal public class FilteringScreen extends Screen { protected List> selected = Lists.newArrayList(); protected final ScrollingContainer scrolling = new ScrollingContainer() { @Override public int getMaxScrollHeight() { - return Mth.ceil(entryStacks.size() / (innerBounds.width / (float) entrySize())) * entrySize() + 28; + return Mth.ceil(entryStacks.size() / (innerBounds.width / 18.0F)) * 18 + 28; } @Override @@ -98,7 +93,7 @@ private record PointPair(Point firstPoint, @Nullable Point secondPoint) {} private List points = new ArrayList<>(); - private OverlaySearchField searchField; + private TextField searchField; private Button selectAllButton; private Button selectNoneButton; private Button hideButton; @@ -111,7 +106,7 @@ private record PointPair(Point firstPoint, @Nullable Point secondPoint) {} public FilteringScreen(FilteringEntry filteringEntry) { super(new TranslatableComponent("config.roughlyenoughitems.filteringScreen")); this.filteringEntry = filteringEntry; - this.searchField = new OverlaySearchField(0, 0, 0, 0); + this.searchField = Widgets.createTextField(new Rectangle()); { Component selectAllText = new TranslatableComponent("config.roughlyenoughitems.filteredEntries.selectAll"); this.selectAllButton = new Button(0, 0, Minecraft.getInstance().font.width(selectAllText) + 10, 20, selectAllText, button -> { @@ -161,12 +156,11 @@ public FilteringScreen(FilteringEntry filteringEntry) { this.parent = null; }); } - this.searchField.isMain = false; } private static Rectangle updateInnerBounds(Rectangle bounds) { - int width = Math.max(Mth.floor((bounds.width - 2 - 6) / (float) entrySize()), 1); - return new Rectangle((int) (bounds.getCenterX() - width * entrySize() / 2f), bounds.y + 5, width * entrySize(), bounds.height); + int width = Math.max(Mth.floor((bounds.width - 2 - 6) / 18.0F), 1); + return new Rectangle((int) (bounds.getCenterX() - width * 18 / 2f), bounds.y + 5, width * 18, bounds.height); } public Rectangle getBounds() { @@ -183,7 +177,7 @@ public void init() { this.selectNoneButton.x = 4 + selectAllButton.getWidth(); this.selectNoneButton.y = bounds.getMaxY() - 22; int searchFieldWidth = Math.max(bounds.width - (selectNoneButton.x + selectNoneButton.getWidth() + hideButton.getWidth() + showButton.getWidth() + 12), 100); - this.searchField.getBounds().setBounds(selectNoneButton.x + selectNoneButton.getWidth() + 4, bounds.getMaxY() - 21, searchFieldWidth, 18); + this.searchField.asWidget().getBounds().setBounds(selectNoneButton.x + selectNoneButton.getWidth() + 4, bounds.getMaxY() - 21, searchFieldWidth, 18); this.hideButton.x = bounds.getMaxX() - hideButton.getWidth() - showButton.getWidth() - 4; this.hideButton.y = bounds.getMaxY() - 22; this.showButton.x = bounds.getMaxX() - showButton.getWidth() - 2; @@ -219,27 +213,27 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { return; ScissorsHandler.INSTANCE.scissor(bounds); for (FilteringListEntry entry : entries) - entry.clearStacks(); - int skip = Math.max(0, Mth.floor(scrolling.scrollAmount() / (float) entrySize())); - int nextIndex = skip * innerBounds.width / entrySize(); + entry.slot.clearEntries(); + int skip = Math.max(0, Mth.floor(scrolling.scrollAmount() / 18.0F)); + int nextIndex = skip * innerBounds.width / 18; int i = nextIndex; - BatchedEntryRendererManager manager = new BatchedEntryRendererManager(); + BatchedSlots slots = Widgets.createBatchedSlots(); for (; i < entryStacks.size(); i++) { EntryStack stack = entryStacks.get(i); FilteringListEntry entry = entries.get(nextIndex); entry.getBounds().y = entry.backupY - scrolling.scrollAmountInt(); if (entry.getBounds().y > bounds.getMaxY()) break; - entry.entry(stack); - manager.add(entry); + entry.slot.entry(stack); + slots.add(entry.slot); nextIndex++; } - manager.render(matrices, mouseX, mouseY, delta); + slots.render(matrices, mouseX, mouseY, delta); updatePosition(delta); - scrolling.renderScrollBar(0, 1.0F, REIRuntime.getInstance().isDarkThemeEnabled() ? 0.8F : 1F); + scrolling.renderScrollBar(0, 1.0F, ConfigObject.getInstance().isUsingDarkTheme() ? 0.8F : 1F); matrices.pushPose(); matrices.translate(0, 0, 300); - this.searchField.laterRender(matrices, mouseX, mouseY, delta); + this.searchField.asWidget().render(matrices, mouseX, mouseY, delta); this.selectAllButton.render(matrices, mouseX, mouseY, delta); this.selectNoneButton.render(matrices, mouseX, mouseY, delta); this.hideButton.render(matrices, mouseX, mouseY, delta); @@ -267,7 +261,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { this.backButton.render(matrices, mouseX, mouseY, delta); if (tooltip != null) { - ((ScreenOverlayImpl) REIRuntime.getInstance().getOverlay().get()).renderTooltip(matrices, tooltip); + REIRuntime.getInstance().getOverlay().get().renderTooltip(matrices, tooltip); } this.font.drawShadow(matrices, this.title.getVisualOrderText(), this.width / 2.0F - this.font.width(this.title) / 2.0F, 12.0F, -1); @@ -331,18 +325,17 @@ public boolean matches(EntryStack stack) { } public void updateEntriesPosition() { - int entrySize = entrySize(); this.innerBounds = updateInnerBounds(getBounds()); - int width = innerBounds.width / entrySize; - int pageHeight = innerBounds.height / entrySize; + int width = innerBounds.width / 18; + int pageHeight = innerBounds.height / 18; int slotsToPrepare = Math.max(entryStacks.size() * 3, width * pageHeight * 3); int currentX = 0; int currentY = 0; List entries = Lists.newArrayList(); for (int i = 0; i < slotsToPrepare; i++) { - int xPos = currentX * entrySize + innerBounds.x; - int yPos = currentY * entrySize + innerBounds.y; - entries.add(new FilteringListEntry(xPos, yPos, entrySize)); + int xPos = currentX * 18 + innerBounds.x; + int yPos = currentY * 18 + innerBounds.y; + entries.add(new FilteringListEntry(xPos, yPos)); currentX++; if (currentX >= width) { currentX = 0; @@ -351,7 +344,7 @@ public void updateEntriesPosition() { } this.entries = entries; this.elements = Lists.newArrayList(entries); - this.elements.add(searchField); + this.elements.add(searchField.asWidget()); } @Override @@ -365,7 +358,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { return true; if (getBounds().contains(mouseX, mouseY)) { - if (searchField.mouseClicked(mouseX, mouseY, button)) { + if (searchField.asWidget().mouseClicked(mouseX, mouseY, button)) { this.points.clear(); return true; } else if (selectAllButton.mouseClicked(mouseX, mouseY, button)) { @@ -450,32 +443,36 @@ public boolean mouseScrolled(double double_1, double double_2, double double_3) return true; } - private class FilteringListEntry extends EntryWidget { + private class FilteringListEntry extends DelegateWidget { + private final Slot slot; private int backupY; private boolean filtered = false; private boolean dirty = true; - private FilteringListEntry(int x, int y, int entrySize) { - super(new Point(x, y)); + private FilteringListEntry(int x, int y) { + super(Widgets.createSlot(new Point(x, y)) + .noFavoritesInteractable() + .noInteractable() + .noBackground() + .noTooltips() + .noHighlight()); + this.slot = (Slot) widget; this.backupY = y; - getBounds().width = getBounds().height = entrySize; - interactableFavorites(false); - interactable(false); - noHighlight(); - } - - @Override - public boolean containsMouse(double mouseX, double mouseY) { - return super.containsMouse(mouseX, mouseY) && FilteringScreen.this.getBounds().contains(mouseX, mouseY); } @Override - protected void drawExtra(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (isSelected()) { - Rectangle bounds = getBounds(); - RenderSystem.disableDepthTest(); - fillGradient(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), 0x896b70fa, 0x896b70fa); - RenderSystem.enableDepthTest(); + public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { + drawBackground(poseStack, mouseX, mouseY, delta); + super.render(poseStack, mouseX, mouseY, delta); + drawExtra(poseStack, mouseX, mouseY, delta); + + if (searchField.asWidget().containsMouse(mouseX, mouseY)) + return; + if (containsMouse(mouseX, mouseY)) { + Tooltip tooltip = slot.getCurrentTooltip(new Point(mouseX, mouseY)); + if (tooltip != null) { + FilteringScreen.this.tooltip = tooltip; + } } } @@ -485,29 +482,27 @@ public boolean isSelected() { public boolean isFiltered() { if (dirty) { - filtered = filteringEntry.configFiltered.contains(getCurrentEntry()); + filtered = filteringEntry.configFiltered.contains(slot.getCurrentEntry()); dirty = false; } return filtered; } - @Override - protected void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (isFiltered()) { + private void drawExtra(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (isSelected()) { Rectangle bounds = getBounds(); RenderSystem.disableDepthTest(); - fillGradient(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), 0xffff0000, 0xffff0000); + fillGradient(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), 0x896b70fa, 0x896b70fa); RenderSystem.enableDepthTest(); } } - @Override - protected void queueTooltip(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (searchField.containsMouse(mouseX, mouseY)) - return; - Tooltip tooltip = getCurrentTooltip(new Point(mouseX, mouseY)); - if (tooltip != null) { - FilteringScreen.this.tooltip = tooltip; + private void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (isFiltered()) { + Rectangle bounds = getBounds(); + RenderSystem.disableDepthTest(); + fillGradient(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), 0xffff0000, 0xffff0000); + RenderSystem.enableDepthTest(); } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringCategoriesEntry.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringCategoriesEntry.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringCategoriesEntry.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringCategoriesEntry.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringEntry.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringEntry.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringEntry.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/NoFilteringEntry.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextType.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextType.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextType.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextType.java index 0c69dc0e9..b9e00cd88 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextType.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringContextType.java @@ -23,6 +23,9 @@ package me.shedaniel.rei.impl.client.entry.filtering; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Experimental public enum FilteringContextType { SHOWN, DEFAULT, diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringResultImpl.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringResultImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringResultImpl.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringResultImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleType.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleType.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/BasicFilteringRuleType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/FilteringRuleTypeRegistryImpl.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/FilteringRuleTypeRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/FilteringRuleTypeRegistryImpl.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/FilteringRuleTypeRegistryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRule.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRuleType.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRuleType.java similarity index 99% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRuleType.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRuleType.java index 7ffd89dae..709ad2e0e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRuleType.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRuleType.java @@ -60,4 +60,4 @@ public ManualFilteringRule createNew() { public boolean isSingular() { return true; } -} +} \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java similarity index 99% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java index 7ab70acb3..035f0f868 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRule.java @@ -41,7 +41,6 @@ import java.util.concurrent.*; import java.util.function.Supplier; -@Environment(EnvType.CLIENT) public class SearchFilteringRule implements FilteringRule { private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-SearchFiltering").asService(); String filterStr; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java similarity index 87% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java index a230ac4b7..473042b92 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java @@ -27,13 +27,14 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleType; +import me.shedaniel.rei.api.client.gui.widgets.BatchedSlots; +import me.shedaniel.rei.api.client.gui.widgets.Slot; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.impl.client.config.entries.FilteringRuleOptionsScreen; -import me.shedaniel.rei.impl.client.gui.widget.BatchedEntryRendererManager; -import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -52,8 +53,6 @@ import java.util.function.Supplier; import java.util.stream.Collectors; -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; - public enum SearchFilteringRuleType implements FilteringRuleType { INSTANCE; @@ -92,7 +91,7 @@ public Function createEntryScreen(SearchFilteringRule rule) { return screen -> new FilteringRuleOptionsScreen<>(rule, screen) { TextFieldRuleEntry entry = null; BooleanRuleEntry show = null; - List entryStacks = new ArrayList<>(); + List entryStacks = new ArrayList<>(); @Override public void addEntries(Consumer entryConsumer) { @@ -105,7 +104,7 @@ public void addEntries(Consumer entryConsumer) { entryStacks = EntryRegistry.getInstance().getEntryStacks().parallel() .filter(filter) .map(EntryStack::normalize) - .map(stack -> new EntryWidget(new Rectangle(0, 0, 18, 18)).noBackground().entry(stack)) + .map(stack -> Widgets.createSlot(new Rectangle(0, 0, 18, 18)).noBackground().entry(stack)) .collect(Collectors.toList()); }); if (entry != null) widget.setValue(entry.getWidget().getValue()); @@ -136,29 +135,28 @@ public boolean isSingular() { } public static class EntryStacksRuleEntry extends FilteringRuleOptionsScreen.RuleEntry { - private final Supplier> entryStacks; + private final Supplier> entryStacks; private int totalHeight; - public EntryStacksRuleEntry(SearchFilteringRule rule, Supplier> entryStacks, FilteringRuleOptionsScreen.TextFieldRuleEntry entry, FilteringRuleOptionsScreen.BooleanRuleEntry show) { + public EntryStacksRuleEntry(SearchFilteringRule rule, Supplier> entryStacks, FilteringRuleOptionsScreen.TextFieldRuleEntry entry, FilteringRuleOptionsScreen.BooleanRuleEntry show) { super(rule); this.entryStacks = entryStacks; } @Override public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { - BatchedEntryRendererManager manager = new BatchedEntryRendererManager(); - int entrySize = entrySize(); - int width = entryWidth / entrySize; + BatchedSlots slots = Widgets.createBatchedSlots(); + int width = entryWidth / 18; int i = 0; - for (EntryWidget stack : entryStacks.get()) { - stack.getBounds().setLocation(x + (i % width) * entrySize, y + (i / width) * entrySize); + for (Slot stack : entryStacks.get()) { + stack.getBounds().setLocation(x + (i % width) * 18, y + (i / width) * 18); if (stack.getBounds().getMaxY() >= 0 && stack.getBounds().getY() <= Minecraft.getInstance().getWindow().getGuiScaledHeight()) { - manager.add(stack); + slots.add(stack); } i++; } - manager.render(matrices, mouseX, mouseY, delta); - totalHeight = (i / width + 1) * entrySize; + slots.render(matrices, mouseX, mouseY, delta); + totalHeight = (i / width + 1) * 18; } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/PreFilteredEntryList.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/PreFilteredEntryListImpl.java similarity index 84% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/PreFilteredEntryList.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/PreFilteredEntryListImpl.java index 977a33066..9bb5804da 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/PreFilteredEntryList.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/PreFilteredEntryListImpl.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type; +package me.shedaniel.rei.impl.client.entry.type; import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; @@ -30,29 +30,40 @@ import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; import me.shedaniel.rei.api.client.entry.filtering.FilteringRule; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleType; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleTypeRegistry; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; +import me.shedaniel.rei.api.client.registry.entry.PreFilteredEntryList; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import me.shedaniel.rei.impl.client.entry.filtering.FilteringContextImpl; import me.shedaniel.rei.impl.client.entry.filtering.FilteringContextType; import me.shedaniel.rei.impl.client.entry.filtering.FilteringResultImpl; import me.shedaniel.rei.impl.common.InternalLogger; import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import org.apache.commons.lang3.mutable.MutableLong; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; -public class PreFilteredEntryList implements EntryRegistryListener { - private final EntryRegistry registry; +@ApiStatus.Internal +public class PreFilteredEntryListImpl implements EntryRegistryListener, PreFilteredEntryList { private final MutableLong lastRefilterWarning = new MutableLong(-1); + private EntryRegistry registry; private List> preFilteredList = Lists.newCopyOnWriteArrayList(); - public PreFilteredEntryList(EntryRegistry registry) { + public PreFilteredEntryListImpl() { + ClientInternals.attachInstanceSupplier(this, "preFilteredEntryList"); + } + + @Override + public void attachRegistry(EntryRegistry registry) { this.registry = registry; } @@ -135,7 +146,10 @@ public void onReFilter(List> stacks) { FilteringContextImpl context = new FilteringContextImpl(stacks); Map, Object> cache = new HashMap<>(); - List> rules = ((ConfigObjectImpl) ConfigObject.getInstance()).getFilteringRules(); + List> rules = CollectionUtils.concatUnmodifiable( + CollectionUtils.filterAndMap(FilteringRuleTypeRegistry.getInstance(), FilteringRuleType::isSingular, FilteringRuleType::createNew), + (List>) ConfigManagerInternal.getInstance().get("advanced.filtering.filteringRules") + ); Stopwatch innerStopwatch = Stopwatch.createStarted(); for (int i = rules.size() - 1; i >= 0; i--) { innerStopwatch.reset().start(); @@ -161,6 +175,7 @@ public void onReFilter(List> stacks) { InternalLogger.getInstance().debug("Refiltered %d entries with %d rules in %s.", stacks.size() - preFilteredList.size(), rules.size(), stopwatch.stop().toString()); } + @Override public Collection> refilterNew(boolean warn, Collection> entries) { if (lastRefilterWarning != null && warn) { if (lastRefilterWarning.getValue() > 0 && System.currentTimeMillis() - lastRefilterWarning.getValue() > 5000) { @@ -171,7 +186,10 @@ public Collection> refilterNew(boolean warn, Collection, Object> cache = new HashMap<>(); - List> rules = ((ConfigObjectImpl) ConfigObject.getInstance()).getFilteringRules(); + List> rules = CollectionUtils.concatUnmodifiable( + CollectionUtils.filterAndMap(FilteringRuleTypeRegistry.getInstance(), FilteringRuleType::isSingular, FilteringRuleType::createNew), + (List>) ConfigManagerInternal.getInstance().get("advanced.filtering.filteringRules") + ); for (int i = rules.size() - 1; i >= 0; i--) { FilteringRule rule = rules.get(i); cache.put(rule, rule.prepareCache(entries.size() > 100)); @@ -196,7 +214,12 @@ private void queueSearchUpdate() { REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadSearch); } + @Override public List> getList() { - return preFilteredList; + return Collections.unmodifiableList(preFilteredList); + } + + @Override + public void startReload() { } } diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/FilteredStacksVisibilityHandler.java b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/plugin/client/runtime/FilteredStacksVisibilityHandler.java similarity index 69% rename from runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/FilteredStacksVisibilityHandler.java rename to runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/plugin/client/runtime/FilteredStacksVisibilityHandler.java index 923a416c2..a59370687 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/FilteredStacksVisibilityHandler.java +++ b/runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/plugin/client/runtime/FilteredStacksVisibilityHandler.java @@ -30,15 +30,21 @@ import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.entry.filtering.FilteringRule; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleType; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleTypeRegistry; +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; import me.shedaniel.rei.api.client.registry.display.visibility.DisplayVisibilityPredicate; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryIngredient; -import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import me.shedaniel.rei.impl.client.entry.filtering.FilteringContextImpl; import me.shedaniel.rei.impl.client.entry.filtering.FilteringContextType; import me.shedaniel.rei.impl.client.entry.filtering.FilteringResultImpl; +import me.shedaniel.rei.impl.client.entry.type.EntryRegistryListener; import me.shedaniel.rei.impl.common.InternalLogger; import java.util.ArrayList; @@ -47,28 +53,22 @@ import java.util.Map; import java.util.function.Predicate; -public class FilteredStacksVisibilityHandler implements DisplayVisibilityPredicate { - private boolean checkHiddenStacks; - private Reference2BooleanMap visible = Reference2BooleanMaps.synchronize(new Reference2BooleanOpenHashMap<>()); - private List> filteringRules; - private Map, Object> cache = new HashMap<>(); - private final Predicate displayPredicate = this::checkHiddenStacks; +public class FilteredStacksVisibilityHandler implements REIClientPlugin, EntryRegistryListener { + private static boolean checkHiddenStacks; + private static Reference2BooleanMap visible = Reference2BooleanMaps.synchronize(new Reference2BooleanOpenHashMap<>()); + private static List> filteringRules; + private static Map, Object> cache = new HashMap<>(); + private static final Predicate displayPredicate = FilteredStacksVisibilityHandler::checkHiddenStacks; - @Override - public EventResult handleDisplay(DisplayCategory category, Display display) { - if (checkHiddenStacks) { - return visible.computeBooleanIfAbsent(display, displayPredicate) ? EventResult.pass() : EventResult.interruptFalse(); - } - - return EventResult.pass(); - } - - public void reset() { + public static void reset() { checkHiddenStacks = ConfigObject.getInstance().shouldFilterDisplays(); visible = Reference2BooleanMaps.synchronize(new Reference2BooleanOpenHashMap<>()); if (checkHiddenStacks) { - filteringRules = ((ConfigObjectImpl) ConfigObject.getInstance()).getFilteringRules(); + filteringRules = CollectionUtils.concatUnmodifiable( + CollectionUtils.filterAndMap(FilteringRuleTypeRegistry.getInstance(), FilteringRuleType::isSingular, FilteringRuleType::createNew), + (List>) ConfigManagerInternal.getInstance().get("advanced.filtering.filteringRules") + ); cache = new HashMap<>(); for (int i = filteringRules.size() - 1; i >= 0; i--) { FilteringRule rule = filteringRules.get(i); @@ -82,7 +82,7 @@ public void reset() { } } - public void cacheExisting() { + public static void cacheExisting() { Stopwatch stopwatch = Stopwatch.createStarted(); DisplayRegistry.getInstance().getAll().values().parallelStream().map(displays -> { Reference2BooleanMap current = new Reference2BooleanOpenHashMap<>(); @@ -96,7 +96,7 @@ public void cacheExisting() { InternalLogger.getInstance().debug("Computed existing filtered displays with %d rules in %s", filteringRules.size(), stopwatch.stop()); } - private boolean checkHiddenStacks(Display display) { + private static boolean checkHiddenStacks(Display display) { for (EntryIngredient ingredient : display.getInputEntries()) { if (!ingredient.isEmpty() && isEntryIngredientAllHidden(ingredient, cache, filteringRules)) { return false; @@ -121,4 +121,26 @@ private static boolean isEntryIngredientAllHidden(EntryIngredient ingredient, Ma } return context.stacks.get(FilteringContextType.SHOWN).isEmpty() && context.stacks.get(FilteringContextType.DEFAULT).isEmpty(); } + + @Override + public void onReFilter(List> stacks) { + reset(); + } + + @Override + public void registerDisplays(DisplayRegistry registry) { + reset(); + registry.registerVisibilityPredicate(new DisplayPredicate()); + } + + private class DisplayPredicate implements DisplayVisibilityPredicate { + @Override + public EventResult handleDisplay(DisplayCategory category, Display display) { + if (checkHiddenStacks) { + return visible.computeIfAbsent(display, displayPredicate) ? EventResult.pass() : EventResult.interruptFalse(); + } + + return EventResult.pass(); + } + } } diff --git a/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.entry.filtering.FilteringRuleTypeRegistry b/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.entry.filtering.FilteringRuleTypeRegistry new file mode 100644 index 000000000..83cc8bf5c --- /dev/null +++ b/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.entry.filtering.FilteringRuleTypeRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.entry.filtering.rules.FilteringRuleTypeRegistryImpl \ No newline at end of file diff --git a/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.plugins.REIClientPlugin b/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.plugins.REIClientPlugin new file mode 100644 index 000000000..bb2ecffc1 --- /dev/null +++ b/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.plugins.REIClientPlugin @@ -0,0 +1 @@ +me.shedaniel.rei.plugin.client.runtime.FilteredStacksVisibilityHandler \ No newline at end of file diff --git a/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.config.ConfigManagerInternal$SystemSetup b/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.config.ConfigManagerInternal$SystemSetup new file mode 100644 index 000000000..5815b20d8 --- /dev/null +++ b/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.config.ConfigManagerInternal$SystemSetup @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.config.entries.FilteringConfigEntries \ No newline at end of file diff --git a/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.entry.type.EntryRegistryListener b/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.entry.type.EntryRegistryListener new file mode 100644 index 000000000..4be342477 --- /dev/null +++ b/runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.entry.type.EntryRegistryListener @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.entry.type.PreFilteredEntryListImpl \ No newline at end of file diff --git a/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/client/init/CoreClientInitialization.java b/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/client/init/CoreClientInitialization.java new file mode 100644 index 000000000..46e321e73 --- /dev/null +++ b/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/client/init/CoreClientInitialization.java @@ -0,0 +1,160 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.init; + +import dev.architectury.event.Event; +import dev.architectury.event.EventFactory; +import dev.architectury.event.EventResult; +import dev.architectury.event.events.client.ClientGuiEvent; +import dev.architectury.event.events.client.ClientRecipeUpdateEvent; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleTypeRegistry; +import me.shedaniel.rei.api.client.entry.renderer.EntryRendererRegistry; +import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; +import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; +import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry; +import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; +import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; +import me.shedaniel.rei.api.client.search.SearchProvider; +import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; +import me.shedaniel.rei.api.client.subsets.SubsetsRegistry; +import me.shedaniel.rei.api.client.view.Views; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.PluginView; +import me.shedaniel.rei.api.common.plugins.REIPluginProvider; +import me.shedaniel.rei.api.common.registry.ReloadStage; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.common.InternalLogger; +import me.shedaniel.rei.impl.common.init.CoreInitialization; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import org.apache.commons.lang3.mutable.MutableLong; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.concurrent.*; + +@ApiStatus.Internal +public class CoreClientInitialization { + public static final Event PRE_UPDATE_RECIPES = EventFactory.createLoop(); + private static final ExecutorService RELOAD_PLUGINS = Executors.newSingleThreadScheduledExecutor(task -> { + Thread thread = new Thread(task, "REI-ReloadPlugins"); + thread.setDaemon(true); + thread.setUncaughtExceptionHandler(($, exception) -> { + InternalLogger.getInstance().throwException(exception); + }); + return thread; + }); + private static final List> RELOAD_TASKS = new CopyOnWriteArrayList<>(); + + public void onInitializeClient() { + attachClientInternals(); + loadTestPlugins(); + + MutableLong startReload = new MutableLong(-1); + MutableLong endReload = new MutableLong(-1); + PRE_UPDATE_RECIPES.register(recipeManager -> { + CoreInitialization.reloadPlugins(startReload, ReloadStage.START); + }); + ClientRecipeUpdateEvent.EVENT.register(recipeManager -> { + CoreInitialization.reloadPlugins(endReload, ReloadStage.END); + }); + ClientGuiEvent.INIT_PRE.register((screen, access) -> { + List stages = PluginManager.getInstance().view().getObservedStages(); + + if (Minecraft.getInstance().level != null && Minecraft.getInstance().player != null && stages.contains(ReloadStage.START) + && !stages.contains(ReloadStage.END) && !PluginManager.areAnyReloading() && screen instanceof AbstractContainerScreen) { + for (Future task : RELOAD_TASKS) { + if (!task.isDone()) { + return EventResult.pass(); + } + } + + InternalLogger.getInstance().error("Detected missing stage: END! This is possibly due to issues during client recipe reload! REI will force a reload of the recipes now!"); + CoreInitialization.reloadPlugins(endReload, ReloadStage.END); + } + + return EventResult.pass(); + }); + } + + public static void attachClientInternals() { + PluginManager manager = ClientInternals.getPluginManager(); + manager.registerReloadable(EntryRendererRegistry.class); + manager.registerReloadable(Views.class); + manager.registerReloadable(InputMethodRegistry.class); + manager.registerReloadable(SearchProvider.class); + manager.registerReloadable(ConfigManager.class); + manager.registerReloadable(EntryRegistry.class); + manager.registerReloadable(CollapsibleEntryRegistry.class); + manager.registerReloadable(FilteringRuleTypeRegistry.getInstance().basic()); + manager.registerReloadable(CategoryRegistry.class); + manager.registerReloadable(DisplayRegistry.class); + manager.registerReloadable(ScreenRegistry.class); + manager.registerReloadable(FavoriteEntryType.Registry.class); + manager.registerReloadable(SubsetsRegistry.class); + manager.registerReloadable(TransferHandlerRegistry.class); + manager.registerReloadable(REIRuntime.class); + manager.registerReloadable(ConfigAddonRegistry.class); + } + + private void loadTestPlugins() { + if (System.getProperty("rei.test", "false").equals("true")) { + try { + PluginView.getClientInstance().registerPlugin((REIPluginProvider) Class.forName("me.shedaniel.rei.plugin.test.REITestPlugin") + .getDeclaredConstructor() + .newInstance()); + } catch (InstantiationException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + + public static boolean reloadPluginsClient(@Nullable ReloadStage start) { + if (ConfigObject.getInstance().doesRegisterRecipesInAnotherThread()) { + Future[] futures = new Future[1]; + CompletableFuture future = CompletableFuture.runAsync(() -> CoreInitialization._reloadPlugins(start), RELOAD_PLUGINS) + .whenComplete((unused, throwable) -> { + // Remove the future from the list of futures + if (futures[0] != null) { + RELOAD_TASKS.remove(futures[0]); + futures[0] = null; + } + }); + futures[0] = future; + RELOAD_TASKS.add(future); + return true; + } + + return false; + } +} diff --git a/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/common/init/CoreInitialization.java b/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/common/init/CoreInitialization.java new file mode 100644 index 000000000..22cad60d2 --- /dev/null +++ b/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/common/init/CoreInitialization.java @@ -0,0 +1,116 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.init; + +import dev.architectury.platform.Platform; +import dev.architectury.registry.ReloadListenerRegistry; +import dev.architectury.utils.Env; +import me.shedaniel.rei.api.common.display.DisplaySerializerRegistry; +import me.shedaniel.rei.api.common.entry.comparison.FluidComparatorRegistry; +import me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry; +import me.shedaniel.rei.api.common.entry.settings.EntrySettingsAdapterRegistry; +import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry; +import me.shedaniel.rei.api.common.fluid.FluidSupportProvider; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import me.shedaniel.rei.api.common.plugins.REIServerPlugin; +import me.shedaniel.rei.api.common.registry.RecipeManagerContext; +import me.shedaniel.rei.api.common.registry.ReloadStage; +import me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry; +import me.shedaniel.rei.impl.client.init.CoreClientInitialization; +import me.shedaniel.rei.impl.common.InternalLogger; +import me.shedaniel.rei.impl.common.Internals; +import net.minecraft.client.Minecraft; +import net.minecraft.server.packs.PackType; +import net.minecraft.util.Unit; +import org.apache.commons.lang3.mutable.MutableLong; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public class CoreInitialization { + public void onInitialize() { + attachCommonInternals(); + + if (Platform.getEnvironment() == Env.SERVER) { + MutableLong lastReload = new MutableLong(-1); + ReloadListenerRegistry.register(PackType.SERVER_DATA, (preparationBarrier, resourceManager, profilerFiller, profilerFiller2, executor, executor2) -> { + return preparationBarrier.wait(Unit.INSTANCE).thenRunAsync(PluginManager::reloadAll, executor2); + }); + } + } + + public static void attachCommonInternals() { + PluginManager> manager = PluginManager.getInstance(); + manager.registerReloadable(EntryTypeRegistry.class); + manager.registerReloadable(EntrySettingsAdapterRegistry.class); + manager.registerReloadable(RecipeManagerContext.class); + manager.registerReloadable(ItemComparatorRegistry.class); + manager.registerReloadable(FluidComparatorRegistry.class); + manager.registerReloadable(DisplaySerializerRegistry.class); + manager.registerReloadable(FluidSupportProvider.class); + PluginManager serverManager = PluginManager.getServerInstance(); + serverManager.registerReloadable(NetworkingHelper.class); + serverManager.registerReloadable(MenuInfoRegistry.class); + Internals.attachInstance((Runnable) () -> reloadPlugins(null, null), "reloadREI"); + } + + public static void _reloadPlugins(@Nullable ReloadStage stage) { + if (stage == null) { + for (ReloadStage reloadStage : ReloadStage.values()) { + _reloadPlugins(reloadStage); + } + return; + } + try { + for (PluginManager> instance : PluginManager.getActiveInstances()) { + instance.view().pre(stage); + } + for (PluginManager> instance : PluginManager.getActiveInstances()) { + instance.startReload(stage); + } + for (PluginManager> instance : PluginManager.getActiveInstances()) { + instance.view().post(stage); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + public static void reloadPlugins(MutableLong lastReload, @Nullable ReloadStage start) { + if (Minecraft.getInstance().level == null) return; + if (lastReload != null) { + if (lastReload.getValue() > 0 && System.currentTimeMillis() - lastReload.getValue() <= 5000) { + InternalLogger.getInstance().warn("Suppressing Reload Plugins of stage " + start); + return; + } + lastReload.setValue(System.currentTimeMillis()); + } + if (Platform.getEnvironment() == Env.CLIENT) { + if (CoreClientInitialization.reloadPluginsClient(start)) return; + } + _reloadPlugins(start); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/FileLogger.java b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/FileLogger.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/logging/FileLogger.java rename to runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/FileLogger.java index b1eb4fe62..3e7d88eec 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/FileLogger.java +++ b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/FileLogger.java @@ -26,6 +26,7 @@ import me.shedaniel.rei.impl.common.InternalLogger; import org.apache.commons.io.output.NullOutputStream; import org.apache.logging.log4j.Level; +import org.jetbrains.annotations.ApiStatus; import java.io.*; import java.nio.charset.StandardCharsets; @@ -34,6 +35,7 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +@ApiStatus.Internal public class FileLogger implements InternalLogger { private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); private final Writer writer; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/FilteringLogger.java b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/FilteringLogger.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/logging/FilteringLogger.java rename to runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/FilteringLogger.java index 59effd6ea..2e40beee8 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/FilteringLogger.java +++ b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/FilteringLogger.java @@ -25,7 +25,9 @@ import me.shedaniel.rei.impl.common.InternalLogger; import org.apache.logging.log4j.Level; +import org.jetbrains.annotations.ApiStatus; +@ApiStatus.Internal public class FilteringLogger implements InternalLogger { private final InternalLogger logger; private final Level minLevel; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/Log4JLogger.java b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/Log4JLogger.java similarity index 96% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/logging/Log4JLogger.java rename to runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/Log4JLogger.java index 1db77dfe7..3dfd8d395 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/Log4JLogger.java +++ b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/Log4JLogger.java @@ -25,7 +25,9 @@ import me.shedaniel.rei.impl.common.InternalLogger; import org.apache.logging.log4j.Level; +import org.jetbrains.annotations.ApiStatus; +@ApiStatus.Internal public class Log4JLogger implements InternalLogger { private final org.apache.logging.log4j.Logger logger; diff --git a/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/LoggerInitializer.java b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/LoggerInitializer.java new file mode 100644 index 000000000..fa482e83f --- /dev/null +++ b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/LoggerInitializer.java @@ -0,0 +1,43 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.logging; + +import com.google.common.collect.ImmutableList; +import dev.architectury.platform.Platform; +import me.shedaniel.rei.impl.common.Internals; +import me.shedaniel.rei.impl.common.InternalLogger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; + +public class LoggerInitializer { + private static final InternalLogger LOGGER = new TransformingLogger(new MultiLogger(ImmutableList.of( + new FileLogger(Platform.getGameFolder().resolve("logs/rei.log")), + new FilteringLogger(new FileLogger(Platform.getGameFolder().resolve("logs/rei-issues.log")), Level.WARN), + new Log4JLogger(LogManager.getFormatterLogger("REI")) + )), message -> "[REI] " + message); + + public void onInitialize() { + Internals.attachInstanceSupplier(LOGGER, "logger"); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/MultiLogger.java b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/MultiLogger.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/logging/MultiLogger.java rename to runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/MultiLogger.java index 9f3d6fbda..92a11e3bc 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/MultiLogger.java +++ b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/MultiLogger.java @@ -25,7 +25,9 @@ import me.shedaniel.rei.impl.common.InternalLogger; import org.apache.logging.log4j.Level; +import org.jetbrains.annotations.ApiStatus; +@ApiStatus.Internal public class MultiLogger implements InternalLogger { private final Iterable loggers; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/TransformingLogger.java b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/TransformingLogger.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/logging/TransformingLogger.java rename to runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/TransformingLogger.java index ed9678c00..0540d8baa 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/TransformingLogger.java +++ b/runtime-engine/logging/src/main/java/me/shedaniel/rei/impl/common/logging/TransformingLogger.java @@ -25,9 +25,11 @@ import me.shedaniel.rei.impl.common.InternalLogger; import org.apache.logging.log4j.Level; +import org.jetbrains.annotations.ApiStatus; import java.util.function.UnaryOperator; +@ApiStatus.Internal public class TransformingLogger implements InternalLogger { private final InternalLogger logger; private final UnaryOperator transformer; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java similarity index 92% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java rename to runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java index bb195a8f5..e8a252389 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java +++ b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java @@ -27,6 +27,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.entry.InputIngredient; import me.shedaniel.rei.api.common.transfer.RecipeFinder; import me.shedaniel.rei.api.common.transfer.info.MenuInfo; import me.shedaniel.rei.api.common.transfer.info.MenuInfoContext; @@ -36,17 +37,15 @@ import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.Container; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import org.jetbrains.annotations.Nullable; import java.util.Iterator; -import java.util.List; import java.util.Objects; -public class InputSlotCrafter implements MenuInfoContext { +public class InputSlotCrafter implements MenuInfoContext { protected CategoryIdentifier category; protected T container; protected MenuInfo menuInfo; @@ -63,8 +62,8 @@ public void setMenuInfo(MenuInfo menuInfo) { this.menuInfo = menuInfo; } - public static InputSlotCrafter start(CategoryIdentifier category, T menu, ServerPlayer player, CompoundTag display, boolean hasShift) { - InputSlotCrafter crafter = new InputSlotCrafter<>(category, menu); + public static InputSlotCrafter start(CategoryIdentifier category, T menu, ServerPlayer player, CompoundTag display, boolean hasShift) { + InputSlotCrafter crafter = new InputSlotCrafter<>(category, menu); MenuInfo menuInfo = Objects.requireNonNull(MenuInfoRegistry.getInstance().get(category, menu, crafter, display), "Container Info does not exist on the server!"); crafter.setMenuInfo(menuInfo); crafter.fillInputSlots(player, hasShift); @@ -82,8 +81,8 @@ private void fillInputSlots(ServerPlayer player, boolean hasShift) { RecipeFinder recipeFinder = new RecipeFinder(); this.menuInfo.getRecipeFinderPopulator().populate(this, recipeFinder); NonNullList ingredients = NonNullList.create(); - for (List itemStacks : this.menuInfo.getInputs(this, true)) { - ingredients.add(CollectionUtils.toIngredient(itemStacks)); + for (InputIngredient itemStacks : this.menuInfo.getInputsIndexed(this, true)) { + ingredients.add(CollectionUtils.toIngredient(itemStacks.get())); } if (recipeFinder.findRecipe(ingredients, null)) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java rename to runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java diff --git a/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/TransferNetworkModule.java b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/TransferNetworkModule.java new file mode 100644 index 000000000..fe7cde2f7 --- /dev/null +++ b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/impl/common/transfer/TransferNetworkModule.java @@ -0,0 +1,104 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.transfer; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.transformers.SplitPacketTransformer; +import io.netty.buffer.Unpooled; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.inventory.RecipeBookMenu; + +import java.util.Collections; + +public class TransferNetworkModule implements NetworkModule { + public static final ResourceLocation ID = new ResourceLocation("roughlyenoughitems", "move_items"); + + @Override + public NetworkModuleKey getKey() { + return NetworkModule.TRANSFER; + } + + @Override + public boolean canUse(Object target) { + return NetworkManager.canServerReceive(TransferNetworkModule.ID); + } + + @Override + public void onInitialize() { + NetworkManager.registerReceiver(NetworkManager.c2s(), ID, Collections.singletonList(new SplitPacketTransformer()), (packetByteBuf, context) -> { + ServerPlayer player = (ServerPlayer) context.getPlayer(); + CategoryIdentifier category = CategoryIdentifier.of(packetByteBuf.readResourceLocation()); + AbstractContainerMenu container = player.containerMenu; + InventoryMenu playerContainer = player.inventoryMenu; + try { + boolean shift = packetByteBuf.readBoolean(); + try { + InputSlotCrafter crafter = InputSlotCrafter.start(category, container, player, packetByteBuf.readAnySizeNbt(), shift); + } catch (InputSlotCrafter.NotEnoughMaterialsException e) { + if (!(container instanceof RecipeBookMenu)) { + return; + } + // TODO Implement Ghost Recipes + /*FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeInt(input.size()); + for (List stacks : input) { + buf.writeInt(stacks.size()); + for (ItemStack stack : stacks) { + buf.writeItem(stack); + } + } + NetworkManager.sendToPlayer(player, NOT_ENOUGH_ITEMS_PACKET, buf);*/ + } catch (IllegalStateException e) { + player.sendMessage(new TranslatableComponent(e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); + } catch (Exception e) { + player.sendMessage(new TranslatableComponent("error.rei.internal.error", e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); + e.printStackTrace(); + } + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + @Override + public void send(Object target, TransferData data) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeResourceLocation(data.categoryIdentifier().getIdentifier()); + buf.writeBoolean(data.stacked()); + + buf.writeNbt(data.displayTag()); + NetworkManager.sendToServer(TransferNetworkModule.ID, buf); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java similarity index 92% rename from runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java rename to runtime-engine/menu-info/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java index 3c1f69b29..14f685906 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java +++ b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java @@ -23,18 +23,16 @@ package me.shedaniel.rei.plugin.autocrafting; -import dev.architectury.networking.NetworkManager; -import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntSet; -import me.shedaniel.rei.RoughlyEnoughItemsNetwork; -import me.shedaniel.rei.api.client.ClientHelper; import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.InputIngredient; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; import me.shedaniel.rei.api.common.transfer.RecipeFinder; import me.shedaniel.rei.api.common.transfer.info.MenuInfo; import me.shedaniel.rei.api.common.transfer.info.MenuInfoContext; @@ -47,7 +45,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.gui.screens.recipebook.RecipeUpdateListener; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -96,7 +93,7 @@ public Result handle(Context context) { }) .tooltipMissing(CollectionUtils.map(missing, ingredient -> EntryIngredients.ofItemStacks(ingredient.get()))); } - if (!ClientHelper.getInstance().canUseMovePackets()) { + if (!NetworkingHelper.getInstance().canUse(NetworkModule.TRANSFER)) { return Result.createFailed(new TranslatableComponent("error.rei.not.on.server")); } if (!context.isActuallyCrafting()) { @@ -107,12 +104,10 @@ public Result handle(Context context) { if (containerScreen instanceof RecipeUpdateListener listener) { listener.getRecipeBookComponent().ghostRecipe.clear(); } - FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); - buf.writeResourceLocation(display.getCategoryIdentifier().getIdentifier()); - buf.writeBoolean(context.isStackedCrafting()); - - buf.writeNbt(menuInfo.save(menuInfoContext, display)); - NetworkManager.sendToServer(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET, buf); + NetworkingHelper.getInstance().sendToServer(NetworkModule.TRANSFER, + new NetworkModule.TransferData(display.getCategoryIdentifier(), + context.isStackedCrafting(), + menuInfo.save(menuInfoContext, display))); return Result.createSuccessful(); } diff --git a/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultClientTransferCategoryPlugin.java b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultClientTransferCategoryPlugin.java new file mode 100644 index 000000000..ac2f97861 --- /dev/null +++ b/runtime-engine/menu-info/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultClientTransferCategoryPlugin.java @@ -0,0 +1,39 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.plugin.autocrafting; + +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import org.jetbrains.annotations.ApiStatus; + +@Environment(EnvType.CLIENT) +@ApiStatus.Internal +public class DefaultClientTransferCategoryPlugin implements REIClientPlugin { + @Override + public void registerTransferHandlers(TransferHandlerRegistry registry) { + registry.register(new DefaultCategoryHandler()); + } +} diff --git a/runtime-engine/menu-info/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkModule b/runtime-engine/menu-info/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkModule new file mode 100644 index 000000000..86049f550 --- /dev/null +++ b/runtime-engine/menu-info/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkModule @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.transfer.TransferNetworkModule \ No newline at end of file diff --git a/runtime-engine/menu-info/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry b/runtime-engine/menu-info/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry new file mode 100644 index 000000000..da0b762f6 --- /dev/null +++ b/runtime-engine/menu-info/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.transfer.MenuInfoRegistryImpl \ No newline at end of file diff --git a/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/client/networking/modules/CheatItemStatusNetworkModule.java b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/client/networking/modules/CheatItemStatusNetworkModule.java new file mode 100644 index 000000000..45c687cdf --- /dev/null +++ b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/client/networking/modules/CheatItemStatusNetworkModule.java @@ -0,0 +1,78 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.networking.modules; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.transformers.SplitPacketTransformer; +import dev.architectury.utils.Env; +import dev.architectury.utils.EnvExecutor; +import io.netty.buffer.Unpooled; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import me.shedaniel.rei.api.common.util.EntryStacks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; + +import java.util.Collections; +import java.util.Map; + +public class CheatItemStatusNetworkModule implements NetworkModule> { + public static final ResourceLocation ID = new ResourceLocation("roughlyenoughitems", "ci_msg"); + + @Override + public NetworkModuleKey> getKey() { + return NetworkModule.CHEAT_STATUS_REPLY; + } + + @Override + public boolean canUse(Object target) { + return NetworkManager.canPlayerReceive((ServerPlayer) target, CheatItemStatusNetworkModule.ID); + } + + @Override + public void onInitialize() { + EnvExecutor.runInEnv(Env.CLIENT, () -> () -> { + NetworkManager.registerReceiver(NetworkManager.c2s(), ID, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { + ItemStack stack = buf.readItem(); + String player = buf.readUtf(32767); + if (Minecraft.getInstance().player != null) { + Minecraft.getInstance().player.displayClientMessage(new TextComponent(I18n.get("text.rei.cheat_items").replaceAll("\\{item_name}", EntryStacks.of(stack.copy()).asFormattedText().getString()).replaceAll("\\{item_count}", stack.copy().getCount() + "").replaceAll("\\{player_name}", player)), false); + } + }); + }); + } + + @Override + public void send(Object target, Map.Entry data) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeItem(data.getKey().copy()); + buf.writeUtf(data.getValue(), 32767); + NetworkManager.sendToServer(CheatItemStatusNetworkModule.ID, buf); + } +} diff --git a/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/client/networking/modules/NotEnoughItemsNetworkModule.java b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/client/networking/modules/NotEnoughItemsNetworkModule.java new file mode 100644 index 000000000..c135eb921 --- /dev/null +++ b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/client/networking/modules/NotEnoughItemsNetworkModule.java @@ -0,0 +1,111 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.networking.modules; + +import com.google.common.collect.Lists; +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.transformers.SplitPacketTransformer; +import dev.architectury.utils.Env; +import dev.architectury.utils.EnvExecutor; +import io.netty.buffer.Unpooled; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.CraftingScreen; +import net.minecraft.client.gui.screens.recipebook.GhostRecipe; +import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.inventory.CraftingMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; + +import java.util.Collections; +import java.util.List; + +public class NotEnoughItemsNetworkModule implements NetworkModule>> { + public static final ResourceLocation ID = new ResourceLocation("roughlyenoughitems", "og_not_enough"); + + @Override + public NetworkModuleKey>> getKey() { + return NetworkModule.NOT_ENOUGH_ITEMS; + } + + @Override + public boolean canUse(Object target) { + return NetworkManager.canPlayerReceive((ServerPlayer) target, NotEnoughItemsNetworkModule.ID); + } + + @Override + public void onInitialize() { + EnvExecutor.runInEnv(Env.CLIENT, () -> () -> { + NetworkManager.registerReceiver(NetworkManager.c2s(), ID, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { + Screen currentScreen = Minecraft.getInstance().screen; + if (currentScreen instanceof CraftingScreen craftingScreen) { + RecipeBookComponent recipeBookGui = craftingScreen.getRecipeBookComponent(); + GhostRecipe ghostSlots = recipeBookGui.ghostRecipe; + ghostSlots.clear(); + + List> input = Lists.newArrayList(); + int mapSize = buf.readInt(); + for (int i = 0; i < mapSize; i++) { + List list = Lists.newArrayList(); + int count = buf.readInt(); + for (int j = 0; j < count; j++) { + list.add(buf.readItem()); + } + input.add(list); + } + + ghostSlots.addIngredient(Ingredient.of(Items.STONE), 381203812, 12738291); + CraftingMenu container = craftingScreen.getMenu(); + for (int i = 0; i < input.size(); i++) { + List stacks = input.get(i); + if (!stacks.isEmpty()) { + Slot slot = container.getSlot(i + container.getResultSlotIndex() + 1); + ghostSlots.addIngredient(Ingredient.of(stacks.toArray(new ItemStack[0])), slot.x, slot.y); + } + } + } + }); + }); + } + + @Override + public void send(Object target, List> data) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeInt(data.size()); + for (List stacks : data) { + buf.writeInt(stacks.size()); + for (ItemStack stack : stacks) { + buf.writeItem(stack); + } + } + NetworkManager.sendToServer(NotEnoughItemsNetworkModule.ID, buf); + } +} diff --git a/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/NetworkingHelperImpl.java b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/NetworkingHelperImpl.java new file mode 100644 index 000000000..bb3e7a6fa --- /dev/null +++ b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/NetworkingHelperImpl.java @@ -0,0 +1,89 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.networking; + +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; +import me.shedaniel.rei.impl.common.Internals; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.Minecraft; +import net.minecraft.server.level.ServerPlayer; + +import java.util.HashMap; +import java.util.Map; + +public class NetworkingHelperImpl implements NetworkingHelper { + private static final Map, NetworkModule> MODULES = new HashMap<>(); + + static { + for (NetworkModule module : Internals.resolveServices(NetworkModule.class)) { + MODULES.put(module.getKey(), module); + } + } + + @Override + public boolean has(NetworkModuleKey moduleKey) { + return MODULES.containsKey(moduleKey); + } + + @Override + public boolean canUse(NetworkModuleKey moduleKey) { + return has(moduleKey) && MODULES.get(moduleKey).canUse(null); + } + + @Override + public boolean canPlayerUse(ServerPlayer player, NetworkModuleKey moduleKey) { + return has(moduleKey) && MODULES.get(moduleKey).canUse(player); + } + + @Override + public void send(Object target, NetworkModuleKey moduleKey, T data) { + if (canUse(moduleKey)) { + ((NetworkModule) MODULES.get(moduleKey)).send(target, data); + } + } + + @SuppressWarnings("Convert2Lambda") + @Override + @Environment(EnvType.CLIENT) + public Client client() { + return new Client() { + @Environment(EnvType.CLIENT) + @Override + public boolean hasOperatorPermission() { + try { + return Minecraft.getInstance().getConnection().getSuggestionsProvider().hasPermission(1); + } catch (NullPointerException e) { + return true; + } + } + }; + } + + @Override + public void startReload() { + } +} diff --git a/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemGiveNetworkModule.java b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemGiveNetworkModule.java new file mode 100644 index 000000000..b503e7811 --- /dev/null +++ b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemGiveNetworkModule.java @@ -0,0 +1,78 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.networking.modules; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.transformers.SplitPacketTransformer; +import io.netty.buffer.Unpooled; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; +import net.minecraft.ChatFormatting; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; + +import java.util.AbstractMap; +import java.util.Collections; + +public class CheatItemGiveNetworkModule implements NetworkModule { + public static final ResourceLocation ID = new ResourceLocation("roughlyenoughitems", "create_item"); + + @Override + public NetworkModuleKey getKey() { + return NetworkModule.CHEAT_GIVE; + } + + @Override + public boolean canUse(Object target) { + return NetworkManager.canServerReceive(CheatItemGiveNetworkModule.ID); + } + + @Override + public void onInitialize() { + NetworkManager.registerReceiver(NetworkManager.c2s(), ID, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { + ServerPlayer player = (ServerPlayer) context.getPlayer(); + if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { + player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); + return; + } + ItemStack stack = buf.readItem(); + if (player.getInventory().add(stack.copy())) { + NetworkingHelper.getInstance().sendToPlayer(player, NetworkModule.CHEAT_STATUS_REPLY, new AbstractMap.SimpleEntry<>(stack.copy(), player.getScoreboardName())); + } else { + player.displayClientMessage(new TranslatableComponent("text.rei.failed_cheat_items"), false); + } + }); + } + + @Override + public void send(Object target, ItemStack data) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeItem(data.copy()); + NetworkManager.sendToServer(CheatItemGiveNetworkModule.ID, buf); + } +} diff --git a/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemGrabNetworkModule.java b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemGrabNetworkModule.java new file mode 100644 index 000000000..0c76f1e14 --- /dev/null +++ b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemGrabNetworkModule.java @@ -0,0 +1,86 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.networking.modules; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.transformers.SplitPacketTransformer; +import io.netty.buffer.Unpooled; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; +import net.minecraft.ChatFormatting; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; + +import java.util.AbstractMap; +import java.util.Collections; + +public class CheatItemGrabNetworkModule implements NetworkModule { + public static final ResourceLocation ID = new ResourceLocation("roughlyenoughitems", "create_item_grab"); + + @Override + public NetworkModuleKey getKey() { + return NetworkModule.CHEAT_GRAB; + } + + @Override + public boolean canUse(Object target) { + return NetworkManager.canServerReceive(CheatItemGrabNetworkModule.ID); + } + + @Override + public void onInitialize() { + NetworkManager.registerReceiver(NetworkManager.c2s(), ID, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { + ServerPlayer player = (ServerPlayer) context.getPlayer(); + if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { + player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); + return; + } + + AbstractContainerMenu menu = player.containerMenu; + ItemStack itemStack = buf.readItem(); + ItemStack stack = itemStack.copy(); + if (!menu.getCarried().isEmpty() && ItemStack.isSameIgnoreDurability(menu.getCarried(), stack) && ItemStack.tagMatches(menu.getCarried(), stack)) { + stack.setCount(Mth.clamp(stack.getCount() + menu.getCarried().getCount(), 1, stack.getMaxStackSize())); + } else if (!menu.getCarried().isEmpty()) { + return; + } + menu.setCarried(stack.copy()); + menu.broadcastChanges(); + NetworkingHelper.getInstance().sendToPlayer(player, NetworkModule.CHEAT_STATUS_REPLY, new AbstractMap.SimpleEntry<>(stack.copy(), player.getScoreboardName())); + }); + } + + @Override + public void send(Object target, ItemStack data) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeItem(data.copy()); + NetworkManager.sendToServer(CheatItemGrabNetworkModule.ID, buf); + } +} diff --git a/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemHotbarNetworkModule.java b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemHotbarNetworkModule.java new file mode 100644 index 000000000..01c406901 --- /dev/null +++ b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/CheatItemHotbarNetworkModule.java @@ -0,0 +1,85 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.networking.modules; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.transformers.SplitPacketTransformer; +import io.netty.buffer.Unpooled; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; +import net.minecraft.ChatFormatting; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; + +import java.util.AbstractMap; +import java.util.Collections; +import java.util.Map; + +public class CheatItemHotbarNetworkModule implements NetworkModule> { + public static final ResourceLocation ID = new ResourceLocation("roughlyenoughitems", "create_item_hotbar"); + + @Override + public NetworkModuleKey> getKey() { + return NetworkModule.CHEAT_HOTBAR; + } + + @Override + public boolean canUse(Object target) { + return NetworkManager.canServerReceive(CheatItemHotbarNetworkModule.ID); + } + + @Override + public void onInitialize() { + NetworkManager.registerReceiver(NetworkManager.c2s(), ID, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { + ServerPlayer player = (ServerPlayer) context.getPlayer(); + if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { + player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); + return; + } + ItemStack stack = buf.readItem(); + int hotbarSlotId = buf.readVarInt(); + if (hotbarSlotId >= 0 && hotbarSlotId < 9) { + AbstractContainerMenu menu = player.containerMenu; + player.getInventory().items.set(hotbarSlotId, stack.copy()); + menu.broadcastChanges(); + NetworkingHelper.getInstance().sendToPlayer(player, NetworkModule.CHEAT_STATUS_REPLY, new AbstractMap.SimpleEntry<>(stack.copy(), player.getScoreboardName())); + } else { + player.displayClientMessage(new TranslatableComponent("text.rei.failed_cheat_items"), false); + } + }); + } + + @Override + public void send(Object target, Map.Entry data) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeItem(data.getKey().copy()); + buf.writeVarInt(data.getValue()); + NetworkManager.sendToServer(CheatItemHotbarNetworkModule.ID, buf); + } +} diff --git a/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/DeleteItemNetworkModule.java b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/DeleteItemNetworkModule.java new file mode 100644 index 000000000..af5c40889 --- /dev/null +++ b/runtime-engine/networking/src/main/java/me/shedaniel/rei/impl/common/networking/modules/DeleteItemNetworkModule.java @@ -0,0 +1,76 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.networking.modules; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.transformers.SplitPacketTransformer; +import io.netty.buffer.Unpooled; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import net.minecraft.ChatFormatting; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Unit; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; + +import java.util.Collections; + +public class DeleteItemNetworkModule implements NetworkModule { + public static final ResourceLocation ID = new ResourceLocation("roughlyenoughitems", "delete_item"); + + @Override + public NetworkModuleKey getKey() { + return NetworkModule.DELETE_ITEM; + } + + @Override + public boolean canUse(Object target) { + return NetworkManager.canServerReceive(DeleteItemNetworkModule.ID); + } + + @Override + public void onInitialize() { + NetworkManager.registerReceiver(NetworkManager.c2s(), ID, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { + ServerPlayer player = (ServerPlayer) context.getPlayer(); + if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { + player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); + return; + } + AbstractContainerMenu menu = player.containerMenu; + if (!menu.getCarried().isEmpty()) { + menu.setCarried(ItemStack.EMPTY); + menu.broadcastChanges(); + } + }); + } + + @Override + public void send(Object target, Unit data) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + NetworkManager.sendToServer(DeleteItemNetworkModule.ID, buf); + } +} diff --git a/runtime-engine/networking/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkModule b/runtime-engine/networking/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkModule new file mode 100644 index 000000000..df413c4d9 --- /dev/null +++ b/runtime-engine/networking/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkModule @@ -0,0 +1,6 @@ +me.shedaniel.rei.impl.client.networking.modules.CheatItemStatusNetworkModule +me.shedaniel.rei.impl.client.networking.modules.NotEnoughItemsNetworkModule +me.shedaniel.rei.impl.common.networking.modules.CheatItemGiveNetworkModule +me.shedaniel.rei.impl.common.networking.modules.CheatItemGrabNetworkModule +me.shedaniel.rei.impl.common.networking.modules.CheatItemHotbarNetworkModule +me.shedaniel.rei.impl.common.networking.modules.DeleteItemNetworkModule \ No newline at end of file diff --git a/runtime-engine/networking/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkingHelper b/runtime-engine/networking/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkingHelper new file mode 100644 index 000000000..1020dd0a4 --- /dev/null +++ b/runtime-engine/networking/src/main/resources/META-INF/services/me.shedaniel.rei.api.common.networking.NetworkingHelper @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.networking.NetworkingHelperImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java rename to runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java index 048a20bce..bdbd7f02e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java +++ b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/PerformanceScreen.java @@ -26,11 +26,11 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.datafixers.util.Pair; import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; -import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.api.common.plugins.REIPlugin; import me.shedaniel.rei.api.common.plugins.REIPluginProvider; import me.shedaniel.rei.impl.client.gui.performance.entry.PerformanceEntryImpl; import me.shedaniel.rei.impl.client.gui.performance.entry.SubCategoryListEntry; +import me.shedaniel.rei.impl.common.plugins.PluginReloaderImpl; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -146,7 +146,7 @@ public void init() { } list = new PerformanceEntryListWidget(); long[] totalTime = {0}; - RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.getStages().forEach((stage, inner) -> { + PluginReloaderImpl.PERFORMANCE_LOGGER.getStages().forEach((stage, inner) -> { List entries = new ArrayList<>(); inner.times().forEach((obj, time) -> { entries.add(new PerformanceEntryImpl(new TextComponent(obj instanceof Pair ? ((Pair, REIPlugin>) obj).getFirst().getPluginProviderName() : Objects.toString(obj)), time)); diff --git a/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceConfigEntries.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceConfigEntries.java new file mode 100644 index 000000000..56c47c7d9 --- /dev/null +++ b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceConfigEntries.java @@ -0,0 +1,37 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.performance.entry; + +import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; + +import java.util.Collection; +import java.util.List; + +public class PerformanceConfigEntries implements ConfigManagerInternal.SystemSetup { + @Override + public Collection> collectAdvanced() { + return List.of(new PerformanceEntry(200)); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntry.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntry.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntry.java rename to runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntry.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntryImpl.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntryImpl.java rename to runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/PerformanceEntryImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java rename to runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/client/gui/performance/entry/SubCategoryListEntry.java diff --git a/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerConstructorImpl.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerConstructorImpl.java new file mode 100644 index 000000000..18da7ee23 --- /dev/null +++ b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerConstructorImpl.java @@ -0,0 +1,38 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.plugins; + +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.PluginView; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import me.shedaniel.rei.impl.common.provider.PluginManagerConstructor; + +import java.util.function.UnaryOperator; + +public class PluginManagerConstructorImpl implements PluginManagerConstructor { + @Override + public

> PluginManager

create(Class

clazz, UnaryOperator> constructor) { + return new PluginManagerImpl<>(clazz, constructor); + } +} diff --git a/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java new file mode 100644 index 000000000..39b1e5a10 --- /dev/null +++ b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java @@ -0,0 +1,165 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.common.plugins; + +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Iterables; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.PluginView; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import me.shedaniel.rei.api.common.plugins.REIPluginProvider; +import me.shedaniel.rei.api.common.registry.ReloadStage; +import me.shedaniel.rei.api.common.registry.Reloadable; +import me.shedaniel.rei.impl.common.InternalLogger; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.UnaryOperator; + +import static me.shedaniel.rei.impl.common.plugins.PluginReloaderImpl.name; + +@ApiStatus.Internal +public class PluginManagerImpl

> implements PluginManager

, PluginView

{ + private final List> reloadables = new ArrayList<>(); + private final Map>, Reloadable> cache = new ConcurrentHashMap<>(); + private final Class

pluginClass; + private final UnaryOperator> view; + private final List> plugins = new ArrayList<>(); + private final PluginReloaderImpl

reloader = new PluginReloaderImpl<>(); + + @SafeVarargs + public PluginManagerImpl(Class

pluginClass, UnaryOperator> view, Class>... reloadables) { + this.pluginClass = pluginClass; + this.view = view; + for (Class> reloadable : reloadables) { + registerReloadable(reloadable); + } + } + + @Override + public void registerReloadable(Reloadable reloadable) { + this.reloadables.add((Reloadable

) reloadable); + InternalLogger.getInstance().info("Registered reloadable into plugin manager [%s]: " + reloadable.getClass().getName(), pluginClass.getSimpleName()); + } + + @Override + public boolean isReloading() { + return this.reloader.isReloading(); + } + + @Override + public > T get(Class reloadableClass) { + Reloadable reloadable = this.cache.get(reloadableClass); + if (reloadable != null) return (T) reloadable; + + for (Reloadable

r : reloadables) { + if (reloadableClass.isInstance(r)) { + this.cache.put((Class>) reloadableClass, r); + return (T) r; + } + } + throw new IllegalArgumentException("Unknown reloadable type! " + reloadableClass.getName()); + } + + @Override + public List> getReloadables() { + return Collections.unmodifiableList(reloadables); + } + + @Override + public PluginView

view() { + return view.apply(this); + } + + @Override + public void registerPlugin(REIPluginProvider plugin) { + plugins.add((REIPluginProvider

) plugin); + InternalLogger.getInstance().info("Registered plugin provider %s for %s", plugin.getPluginProviderName(), name(pluginClass)); + } + + @Override + public void pre(ReloadStage stage) { + this.reloader.pre(this, pluginClass, getPluginWrapped().toList(), stage); + } + + @Override + public void post(ReloadStage stage) { + this.reloader.post(this, pluginClass, getPluginWrapped().toList(), stage); + } + + @Override + public void startReload(ReloadStage stage) { + this.reloader.startReload(this, pluginClass, getPluginWrapped().toList(), stage); + } + + @Override + public List> getPluginProviders() { + return Collections.unmodifiableList(plugins); + } + + @Override + public FluentIterable

getPlugins() { + return FluentIterable.concat(Iterables.transform(plugins, REIPluginProvider::provide)); + } + + @SuppressWarnings({"RedundantTypeArguments", "UnstableApiUsage"}) + public FluentIterable> getPluginWrapped() { + return FluentIterable.>concat(Iterables., Iterable>>transform(plugins, input -> Iterables.>transform(input.provide(), + plugin -> new PluginWrapper<>(plugin, input)))); + } + + @Override + public List getObservedStages() { + return Collections.unmodifiableList(reloader.getObservedStages()); + } + + public PluginReloaderImpl

getReloader() { + return reloader; + } + + record PluginWrapper

>(P plugin, REIPluginProvider

provider) { + + public double getPriority() { + return plugin.getPriority(); + } + + public String getPluginProviderName() { + String providerName = provider.getPluginProviderName(); + + if (provider.provide().size() >= 1) { + String pluginName = plugin.getPluginProviderName(); + + if (!providerName.equals(pluginName)) { + providerName = pluginName + " of " + providerName; + } + } + + return providerName; + } + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginReloaderImpl.java similarity index 63% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java rename to runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginReloaderImpl.java index c7ab9fcc3..693969a9e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginManagerImpl.java +++ b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/PluginReloaderImpl.java @@ -24,140 +24,47 @@ package me.shedaniel.rei.impl.common.plugins; import com.google.common.base.Stopwatch; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.Iterables; import com.mojang.datafixers.util.Pair; import dev.architectury.platform.Platform; import dev.architectury.utils.Env; import dev.architectury.utils.EnvExecutor; import dev.architectury.utils.GameInstance; -import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.api.common.plugins.PluginManager; -import me.shedaniel.rei.api.common.plugins.PluginView; import me.shedaniel.rei.api.common.plugins.REIPlugin; -import me.shedaniel.rei.api.common.plugins.REIPluginProvider; import me.shedaniel.rei.api.common.registry.ReloadStage; import me.shedaniel.rei.api.common.registry.Reloadable; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.common.InternalLogger; -import me.shedaniel.rei.impl.common.logging.performance.PerformanceLogger; +import me.shedaniel.rei.impl.common.plugins.performance.PerformanceLogger; +import me.shedaniel.rei.impl.common.plugins.performance.PerformanceLoggerImpl; import net.minecraft.client.Minecraft; import net.minecraft.server.MinecraftServer; import org.apache.commons.lang3.tuple.MutablePair; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.io.Closeable; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; import java.util.function.BiConsumer; -import java.util.function.UnaryOperator; -@ApiStatus.Internal -public class PluginManagerImpl

> implements PluginManager

, PluginView

{ - private final List> reloadables = new ArrayList<>(); - private final Map>, Reloadable> cache = new ConcurrentHashMap<>(); - private final Class

pluginClass; - private final UnaryOperator> view; +public class PluginReloaderImpl

> { + public static final PerformanceLogger PERFORMANCE_LOGGER = new PerformanceLoggerImpl(); @Nullable private ReloadStage reloading = null; private List observedStages = new ArrayList<>(); - private final List> plugins = new ArrayList<>(); private final Stopwatch reloadStopwatch = Stopwatch.createUnstarted(); private boolean forcedMainThread; private final Stopwatch forceMainThreadStopwatch = Stopwatch.createUnstarted(); - @SafeVarargs - public PluginManagerImpl(Class

pluginClass, UnaryOperator> view, Reloadable... reloadables) { - this.pluginClass = pluginClass; - this.view = view; - for (Reloadable reloadable : reloadables) { - registerReloadable(reloadable); - } - } - - @Override - public void registerReloadable(Reloadable reloadable) { - this.reloadables.add((Reloadable

) reloadable); - } - - @Override public boolean isReloading() { return reloading != null; } - @Override - public > T get(Class reloadableClass) { - Reloadable reloadable = this.cache.get(reloadableClass); - if (reloadable != null) return (T) reloadable; - - for (Reloadable

r : reloadables) { - if (reloadableClass.isInstance(r)) { - this.cache.put((Class>) reloadableClass, r); - return (T) r; - } - } - throw new IllegalArgumentException("Unknown reloadable type! " + reloadableClass.getName()); - } - - @Override - public List> getReloadables() { - return Collections.unmodifiableList(reloadables); - } - - @Override - public PluginView

view() { - return view.apply(this); - } - - @Override - public void registerPlugin(REIPluginProvider plugin) { - plugins.add((REIPluginProvider

) plugin); - InternalLogger.getInstance().info("Registered plugin provider %s for %s", plugin.getPluginProviderName(), name(pluginClass)); - } - - @Override - public List> getPluginProviders() { - return Collections.unmodifiableList(plugins); - } - - @Override - public FluentIterable

getPlugins() { - return FluentIterable.concat(Iterables.transform(plugins, REIPluginProvider::provide)); - } - - private static class PluginWrapper

> { - private final P plugin; - private final REIPluginProvider

provider; - - public PluginWrapper(P plugin, REIPluginProvider

provider) { - this.plugin = plugin; - this.provider = provider; - } - - public double getPriority() { - return plugin.getPriority(); - } - - public String getPluginProviderName() { - String providerName = provider.getPluginProviderName(); - - if (provider.provide().size() >= 1) { - String pluginName = plugin.getPluginProviderName(); - - if (!providerName.equals(pluginName)) { - providerName = pluginName + " of " + providerName; - } - } - - return providerName; - } - } - - @SuppressWarnings("RedundantTypeArguments") - public FluentIterable> getPluginWrapped() { - return FluentIterable.>concat(Iterables., Iterable>>transform(plugins, input -> Iterables.>transform(input.provide(), - plugin -> new PluginWrapper(plugin, input)))); + @FunctionalInterface + private interface SectionPluginSink { + void accept(boolean respectMainThread, Runnable task); } private static class SectionClosable implements Closeable { @@ -185,16 +92,11 @@ private SectionClosable section(ReloadStage stage, String section) { return new SectionClosable(stage, section); } - @FunctionalInterface - private interface SectionPluginSink { - void accept(boolean respectMainThread, Runnable task); - } - - private void pluginSection(ReloadStage stage, String sectionName, List> list, @Nullable Reloadable reloadable, BiConsumer, SectionPluginSink> consumer) { - for (PluginWrapper

wrapper : list) { + private void pluginSection(ReloadStage stage, String sectionName, List> list, @Nullable Reloadable reloadable, BiConsumer, SectionPluginSink> consumer) { + for (PluginManagerImpl.PluginWrapper

wrapper : list) { try (SectionClosable section = section(stage, sectionName + wrapper.getPluginProviderName() + "/")) { consumer.accept(wrapper, (respectMainThread, runnable) -> { - if (!respectMainThread || reloadable == null || !wrapper.plugin.shouldBeForcefullyDoneOnMainThread(reloadable)) { + if (!respectMainThread || reloadable == null || !wrapper.plugin().shouldBeForcefullyDoneOnMainThread(reloadable)) { runnable.run(); } else { try { @@ -228,22 +130,25 @@ private void queueExecutionClient(Runnable runnable) { Minecraft.getInstance().executeBlocking(runnable); } - @Override - public void pre(ReloadStage stage) { + public void pre(PluginManager

manager, Class

pluginClass, List> plugins, ReloadStage stage) { + if (stage == ReloadStage.START && manager == PluginManager.getActiveInstances().get(0)) { + PERFORMANCE_LOGGER.clear(); + } + this.forcedMainThread = false; this.forceMainThreadStopwatch.reset(); this.reloadStopwatch.reset().start(); this.observedStages.clear(); this.observedStages.add(stage); - List> plugins = new ArrayList<>(getPluginWrapped().toList()); - plugins.sort(Comparator.comparingDouble(PluginWrapper

::getPriority).reversed()); + plugins = new ArrayList<>(plugins); + plugins.sort(Comparator.comparingDouble(PluginManagerImpl.PluginWrapper

::getPriority).reversed()); Collections.reverse(plugins); try (SectionClosable preRegister = section(stage, "pre-register/"); - PerformanceLogger.Plugin perfLogger = RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.stage("Pre Registration")) { + PerformanceLogger.Plugin perfLogger = PERFORMANCE_LOGGER.stage("Pre Registration")) { pluginSection(stage, "pre-register/", plugins, null, (plugin, sink) -> { - try (PerformanceLogger.Plugin.Inner inner = perfLogger.plugin(new Pair<>(plugin.provider, plugin.plugin))) { + try (PerformanceLogger.Plugin.Inner inner = perfLogger.plugin(new Pair<>(plugin.provider(), plugin.plugin()))) { sink.accept(false, () -> { - ((REIPlugin

) plugin.plugin).preStage(this, stage); + ((REIPlugin

) plugin.plugin()).preStage(manager, stage); }); } }); @@ -253,18 +158,17 @@ public void pre(ReloadStage stage) { this.reloadStopwatch.stop(); } - @Override - public void post(ReloadStage stage) { + public void post(PluginManager

manager, Class

pluginClass, List> plugins, ReloadStage stage) { this.reloadStopwatch.start(); - List> plugins = new ArrayList<>(getPluginWrapped().toList()); - plugins.sort(Comparator.comparingDouble(PluginWrapper

::getPriority).reversed()); + plugins = new ArrayList<>(plugins); + plugins.sort(Comparator.comparingDouble(PluginManagerImpl.PluginWrapper

::getPriority).reversed()); Collections.reverse(plugins); try (SectionClosable postRegister = section(stage, "post-register/"); - PerformanceLogger.Plugin perfLogger = RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.stage("Post Registration")) { + PerformanceLogger.Plugin perfLogger = PERFORMANCE_LOGGER.stage("Post Registration")) { pluginSection(stage, "post-register/", plugins, null, (plugin, sink) -> { - try (PerformanceLogger.Plugin.Inner inner = perfLogger.plugin(new Pair<>(plugin.provider, plugin.plugin))) { + try (PerformanceLogger.Plugin.Inner inner = perfLogger.plugin(new Pair<>(plugin.provider(), plugin.plugin()))) { sink.accept(false, () -> { - ((REIPlugin

) plugin.plugin).postStage(this, stage); + ((REIPlugin

) plugin.plugin()).postStage(manager, stage); }); } }); @@ -278,22 +182,15 @@ public void post(ReloadStage stage) { } } - private static String name(Class clazz) { - String simpleName = clazz.getSimpleName(); - if (simpleName.isEmpty()) return clazz.getName(); - return simpleName; - } - - @Override - public void startReload(ReloadStage stage) { + public void startReload(PluginManager

manager, Class

pluginClass, List> plugins, ReloadStage stage) { try { this.reloadStopwatch.start(); reloading = stage; // Pre Reload try (SectionClosable startReloadAll = section(stage, "start-reload/"); - PerformanceLogger.Plugin perfLogger = RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.stage("Reload Initialization")) { - for (Reloadable

reloadable : reloadables) { + PerformanceLogger.Plugin perfLogger = PERFORMANCE_LOGGER.stage("Reload Initialization")) { + for (Reloadable

reloadable : manager.getReloadables()) { Class reloadableClass = reloadable.getClass(); try (SectionClosable startReload = section(stage, "start-reload/" + name(reloadableClass) + "/"); PerformanceLogger.Plugin.Inner inner = perfLogger.stage(name(reloadableClass))) { @@ -305,18 +202,18 @@ public void startReload(ReloadStage stage) { } // Sort Plugins - List> plugins = new ArrayList<>(getPluginWrapped().toList()); - plugins.sort(Comparator.comparingDouble(PluginWrapper

::getPriority).reversed()); - InternalLogger.getInstance().info("Reloading Plugin Manager [%s] stage [%s], registered %d plugins: %s", name(pluginClass), stage.toString(), plugins.size(), CollectionUtils.mapAndJoinToString(plugins, PluginWrapper::getPluginProviderName, ", ")); + plugins = new ArrayList<>(plugins); + plugins.sort(Comparator.comparingDouble(PluginManagerImpl.PluginWrapper

::getPriority).reversed()); + InternalLogger.getInstance().info("Reloading Plugin Manager [%s] stage [%s], registered %d plugins: %s", name(pluginClass), stage.toString(), plugins.size(), CollectionUtils.mapAndJoinToString(plugins, PluginManagerImpl.PluginWrapper::getPluginProviderName, ", ")); Collections.reverse(plugins); // Reload - for (Reloadable

reloadable : getReloadables()) { + for (Reloadable

reloadable : manager.getReloadables()) { Class reloadableClass = reloadable.getClass(); try (SectionClosable reloadablePlugin = section(stage, "reloadable-plugin/" + name(reloadableClass) + "/"); - PerformanceLogger.Plugin perfLogger = RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.stage(name(reloadableClass))) { + PerformanceLogger.Plugin perfLogger = PERFORMANCE_LOGGER.stage(name(reloadableClass))) { try (PerformanceLogger.Plugin.Inner inner = perfLogger.stage("reloadable-plugin/" + name(reloadableClass) + "/prompt-others-before")) { - for (Reloadable

listener : reloadables) { + for (Reloadable

listener : manager.getReloadables()) { try { listener.beforeReloadable(stage, reloadable); } catch (Throwable throwable) { @@ -326,22 +223,22 @@ public void startReload(ReloadStage stage) { } pluginSection(stage, "reloadable-plugin/" + name(reloadableClass) + "/", plugins, reloadable, (plugin, sink) -> { - try (PerformanceLogger.Plugin.Inner inner = perfLogger.plugin(new Pair<>(plugin.provider, plugin.plugin))) { + try (PerformanceLogger.Plugin.Inner inner = perfLogger.plugin(new Pair<>(plugin.provider(), plugin.plugin()))) { sink.accept(true, () -> { - for (Reloadable

listener : reloadables) { + for (Reloadable

listener : manager.getReloadables()) { try { - listener.beforeReloadablePlugin(stage, reloadable, plugin.plugin); + listener.beforeReloadablePlugin(stage, reloadable, plugin.plugin()); } catch (Throwable throwable) { throwable.printStackTrace(); } } try { - reloadable.acceptPlugin(plugin.plugin, stage); + reloadable.acceptPlugin(plugin.plugin(), stage); } finally { - for (Reloadable

listener : reloadables) { + for (Reloadable

listener : manager.getReloadables()) { try { - listener.afterReloadablePlugin(stage, reloadable, plugin.plugin); + listener.afterReloadablePlugin(stage, reloadable, plugin.plugin()); } catch (Throwable throwable) { throwable.printStackTrace(); } @@ -352,7 +249,7 @@ public void startReload(ReloadStage stage) { }); try (PerformanceLogger.Plugin.Inner inner = perfLogger.stage("reloadable-plugin/" + name(reloadableClass) + "/prompt-others-after")) { - for (Reloadable

listener : reloadables) { + for (Reloadable

listener : manager.getReloadables()) { try { listener.afterReloadable(stage, reloadable); } catch (Throwable throwable) { @@ -365,8 +262,8 @@ public void startReload(ReloadStage stage) { // Post Reload try (SectionClosable endReloadAll = section(stage, "end-reload/"); - PerformanceLogger.Plugin perfLogger = RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.stage("Reload Finalization")) { - for (Reloadable

reloadable : reloadables) { + PerformanceLogger.Plugin perfLogger = PERFORMANCE_LOGGER.stage("Reload Finalization")) { + for (Reloadable

reloadable : manager.getReloadables()) { Class reloadableClass = reloadable.getClass(); try (SectionClosable endReload = section(stage, "end-reload/" + name(reloadableClass) + "/"); PerformanceLogger.Plugin.Inner inner = perfLogger.stage(name(reloadableClass))) { @@ -385,6 +282,24 @@ public void startReload(ReloadStage stage) { } } + static String name(Class clazz) { + for (Class anInterface : clazz.getInterfaces()) { + if (!anInterface.getName().startsWith("me.shedaniel.rei.impl")) { + return _name(anInterface); + } + } + + return _name(clazz); + } + + static String _name(Class clazz) { + String name = clazz.getName(); + if (name.contains(".")) { + name = name.substring(name.lastIndexOf(".") + 1); + } + return name.replace('$', '.'); + } + public List getObservedStages() { return observedStages; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLogger.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/performance/PerformanceLogger.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLogger.java rename to runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/performance/PerformanceLogger.java index 94832a20d..1a620d1c8 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLogger.java +++ b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/performance/PerformanceLogger.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.logging.performance; +package me.shedaniel.rei.impl.common.plugins.performance; import com.mojang.datafixers.util.Pair; import me.shedaniel.rei.api.common.plugins.REIPlugin; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLoggerImpl.java b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/performance/PerformanceLoggerImpl.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLoggerImpl.java rename to runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/performance/PerformanceLoggerImpl.java index 25a0dfc87..fc4e7a68f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/logging/performance/PerformanceLoggerImpl.java +++ b/runtime-engine/plugins/src/main/java/me/shedaniel/rei/impl/common/plugins/performance/PerformanceLoggerImpl.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.logging.performance; +package me.shedaniel.rei.impl.common.plugins.performance; import com.google.common.base.Stopwatch; import com.google.common.collect.Maps; diff --git a/runtime-engine/plugins/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.config.ConfigManagerInternal$SystemSetup b/runtime-engine/plugins/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.config.ConfigManagerInternal$SystemSetup new file mode 100644 index 000000000..b758181a9 --- /dev/null +++ b/runtime-engine/plugins/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.config.ConfigManagerInternal$SystemSetup @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.performance.entry.PerformanceConfigEntries \ No newline at end of file diff --git a/runtime-engine/plugins/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.PluginManagerConstructor b/runtime-engine/plugins/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.PluginManagerConstructor new file mode 100644 index 000000000..816ec424b --- /dev/null +++ b/runtime-engine/plugins/src/main/resources/META-INF/services/me.shedaniel.rei.impl.common.provider.PluginManagerConstructor @@ -0,0 +1 @@ +me.shedaniel.rei.impl.common.plugins.PluginManagerConstructorImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ExclusionZonesImpl.java b/runtime-engine/screens/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ExclusionZonesImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ExclusionZonesImpl.java rename to runtime-engine/screens/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ExclusionZonesImpl.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ScreenRegistryImpl.java b/runtime-engine/screens/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ScreenRegistryImpl.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ScreenRegistryImpl.java rename to runtime-engine/screens/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ScreenRegistryImpl.java index 89b3cfe67..99532e670 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ScreenRegistryImpl.java +++ b/runtime-engine/screens/src/main/java/me/shedaniel/rei/impl/client/registry/screen/ScreenRegistryImpl.java @@ -37,6 +37,7 @@ import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProviderWidget; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitor; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitorWidget; +import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.screen.*; @@ -45,7 +46,6 @@ import me.shedaniel.rei.api.common.registry.ReloadStage; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.impl.client.gui.screen.AbstractDisplayViewingScreen; import me.shedaniel.rei.impl.common.InternalLogger; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -288,15 +288,15 @@ public double getPriority() { return -10.0; } }); - registerDecider(new DisplayBoundsProvider() { + registerDecider(new DisplayBoundsProvider() { @Override - public Rectangle getScreenBounds(AbstractDisplayViewingScreen screen) { + public Rectangle getScreenBounds(DisplayScreen screen) { return screen.getBounds(); } @Override public boolean isHandingScreen(Class screen) { - return AbstractDisplayViewingScreen.class.isAssignableFrom(screen); + return DisplayScreen.class.isAssignableFrom(screen); } @Override diff --git a/runtime-engine/screens/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.screen.ScreenRegistry b/runtime-engine/screens/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.screen.ScreenRegistry new file mode 100644 index 000000000..68f879709 --- /dev/null +++ b/runtime-engine/screens/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.screen.ScreenRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.registry.screen.ScreenRegistryImpl \ No newline at end of file diff --git a/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/IntRange.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/IntRange.java new file mode 100644 index 000000000..94c259b8c --- /dev/null +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/IntRange.java @@ -0,0 +1,27 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.search; + +public record IntRange(int min, int max) { +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java index c56d30b26..894153ddc 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java @@ -53,6 +53,16 @@ public SearchFilter createFilter(String filter, InputMethod inputMethod) { return new SearchFilterImpl(filter, inputMethod); } + @Override + public void clearCache() { + Argument.SEARCH_CACHE.clear(); + } + + @Override + public boolean hasCache() { + return !Argument.SEARCH_CACHE.isEmpty(); + } + public static class SearchFilterImpl implements SearchFilter { private final String filter; private final InputMethod inputMethod; @@ -93,6 +103,11 @@ public void prepareFilter(Collection> stacks) { Argument.prepareFilter(stacks, argumentTypes.get()); } + @Override + public void processDecoration(ParseDecorationSink sink) { + Argument.bakeArguments(filter, sink); + } + @Override public String getFilter() { return filter; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/AlternativeArgument.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/AlternativeArgument.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/AlternativeArgument.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/AlternativeArgument.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java index f38b9c9aa..d4bd7b6e1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java @@ -38,12 +38,12 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.SearchMode; +import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.search.method.CharacterUnpackingInputMethod; import me.shedaniel.rei.api.client.search.method.InputMethod; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.impl.client.search.IntRange; import me.shedaniel.rei.impl.client.search.argument.type.ArgumentType; import me.shedaniel.rei.impl.client.search.argument.type.ArgumentTypesRegistry; import me.shedaniel.rei.impl.client.search.result.ArgumentApplicableResult; @@ -99,19 +99,11 @@ public int end() { return end; } - public interface ProcessedSink { - void addQuote(int index); - - void addSplitter(int index); - - void addPart(Argument argument, boolean usingGrammar, Collection grammarRanges, int index); - } - public static List bakeArguments(String filter) { return bakeArguments(filter, null); } - public static List bakeArguments(String filter, @Nullable ProcessedSink sink) { + public static List bakeArguments(String filter, @Nullable SearchFilter.ParseDecorationSink sink) { List compoundArguments = Lists.newArrayList(); int tokenStartIndex = 0; @@ -157,7 +149,7 @@ private static void prepareSearchFilter(List compoundArguments } } - private static void applyArgument(ArgumentType type, String filter, Matcher terms, int tokenStartIndex, AlternativeArgument.Builder alternativeBuilder, boolean forceGrammar, @Nullable ProcessedSink sink) { + private static void applyArgument(ArgumentType type, String filter, Matcher terms, int tokenStartIndex, AlternativeArgument.Builder alternativeBuilder, boolean forceGrammar, @Nullable SearchFilter.ParseDecorationSink sink) { String term = MoreObjects.firstNonNull(terms.group(1), terms.group(2)); if (type.getSearchMode() == SearchMode.NEVER) return; ArgumentApplicableResult result = type.checkApplicable(term, forceGrammar); @@ -174,7 +166,8 @@ private static void applyArgument(ArgumentType type, String filter, Matche sink.addQuote(terms.end() - 1 + tokenStartIndex); } } - sink.addPart(argument, result.isUsingGrammar(), result.grammarRanges(), terms.start() + tokenStartIndex); + sink.addPart(IntIntPair.of(argument.start(), argument.end()), argument.argumentType.getHighlightedStyle(), result.isUsingGrammar(), + CollectionUtils.map(result.grammarRanges(), range -> IntIntPair.of(range.min(), range.max())), terms.start() + tokenStartIndex); } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/CompoundArgument.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/CompoundArgument.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/CompoundArgument.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/CompoundArgument.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/IndexSet.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/IndexSet.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/IndexSet.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/IndexSet.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/InputMethodMatcher.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/InputMethodMatcher.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/InputMethodMatcher.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/InputMethodMatcher.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/AlwaysMatchingArgumentType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/AlwaysMatchingArgumentType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/AlwaysMatchingArgumentType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/AlwaysMatchingArgumentType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentTypesRegistry.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentTypesRegistry.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentTypesRegistry.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ArgumentTypesRegistry.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/IdentifierArgumentType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/IdentifierArgumentType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/IdentifierArgumentType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/IdentifierArgumentType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/MatchType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/MatchType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/MatchType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/MatchType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ModArgumentType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ModArgumentType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ModArgumentType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/ModArgumentType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/RegexArgumentType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/RegexArgumentType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/RegexArgumentType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/RegexArgumentType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TagArgumentType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TagArgumentType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TagArgumentType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TagArgumentType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TextArgumentType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TextArgumentType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TextArgumentType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TextArgumentType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TooltipArgumentType.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TooltipArgumentType.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TooltipArgumentType.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/argument/type/TooltipArgumentType.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/DefaultInputMethod.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/DefaultInputMethod.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/DefaultInputMethod.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/DefaultInputMethod.java index 944c0b8d6..52c85853c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/DefaultInputMethod.java +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/DefaultInputMethod.java @@ -34,7 +34,7 @@ import java.util.concurrent.Executor; @ApiStatus.Internal -public enum DefaultInputMethod implements InputMethod { +enum DefaultInputMethod implements InputMethod { INSTANCE; public static final ResourceLocation ID = new ResourceLocation("rei", "default"); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java similarity index 92% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java index ca2e79e77..0a04608be 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/method/InputMethodRegistryImpl.java @@ -28,7 +28,7 @@ import me.shedaniel.rei.api.client.search.method.InputMethod; import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import me.shedaniel.rei.impl.common.InternalLogger; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; @@ -70,6 +70,7 @@ public Map> getAll() { @Override public void startReload() { this.inputMethods.clear(); + add(DefaultInputMethod.ID, DefaultInputMethod.INSTANCE); } @Override @@ -78,14 +79,14 @@ public void endReload() { String languageCode = Minecraft.getInstance().options.languageCode; if (!CollectionUtils.anyMatch(active.getMatchingLocales(), locale -> locale.code().equals(languageCode))) { InternalLogger.getInstance().error("Reset active input method because the language code {} is not supported by the active input method.", languageCode); - ConfigManagerImpl.getInstance().getConfig().setInputMethodId(new ResourceLocation("rei:default")); + ConfigManagerInternal.getInstance().set("functionality.inputMethod", new ResourceLocation("rei:default")); return; } ExecutorService service = Executors.newSingleThreadExecutor(); active.prepare(service).whenComplete((unused, throwable) -> { if (throwable != null) { InternalLogger.getInstance().error("Failed to prepare input method", throwable); - ConfigManagerImpl.getInstance().getConfig().setInputMethodId(new ResourceLocation("rei:default")); + ConfigManagerInternal.getInstance().set("functionality.inputMethod", new ResourceLocation("rei:default")); ExecutorService service2 = Executors.newSingleThreadExecutor(); active.dispose(service2).whenComplete((unused2, throwable2) -> { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/result/ArgumentApplicableResult.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/result/ArgumentApplicableResult.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/result/ArgumentApplicableResult.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/result/ArgumentApplicableResult.java index a443f0010..37127e4df 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/result/ArgumentApplicableResult.java +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/impl/client/search/result/ArgumentApplicableResult.java @@ -78,7 +78,7 @@ public List grammarRanges() { public ArgumentApplicableResult grammar(int start, int end) { if (end - 1 >= start) { - this.grammarRanges.add(IntRange.of(start, end - 1)); + this.grammarRanges.add(new IntRange(start, end - 1)); } return this; } diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java b/runtime-engine/search/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java rename to runtime-engine/search/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java index 77a36f55c..3d03165ae 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java +++ b/runtime-engine/search/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchFilterPrepareWatcher.java @@ -29,6 +29,7 @@ import me.shedaniel.math.Point; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.impl.client.gui.hints.HintProvider; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; import me.shedaniel.rei.impl.client.search.argument.Argument; import net.minecraft.Util; import net.minecraft.network.chat.Component; @@ -85,7 +86,7 @@ public Color getColor() { } @Override - public List getButtons() { + public List getButtons(MenuAccess access) { return Collections.emptyList(); } } diff --git a/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.search.SearchProvider b/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.search.SearchProvider new file mode 100644 index 000000000..cf4392ae4 --- /dev/null +++ b/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.search.SearchProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.search.SearchProviderImpl \ No newline at end of file diff --git a/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.search.method.InputMethodRegistry b/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.search.method.InputMethodRegistry new file mode 100644 index 000000000..34296fd12 --- /dev/null +++ b/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.search.method.InputMethodRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.search.method.InputMethodRegistryImpl \ No newline at end of file diff --git a/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider b/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider new file mode 100644 index 000000000..c8655abae --- /dev/null +++ b/runtime-engine/search/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider @@ -0,0 +1 @@ +me.shedaniel.rei.plugin.client.runtime.SearchFilterPrepareWatcher \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/subsets/SubsetsRegistryImpl.java b/runtime-engine/subsets/src/main/java/me/shedaniel/rei/impl/client/subsets/SubsetsRegistryImpl.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/subsets/SubsetsRegistryImpl.java rename to runtime-engine/subsets/src/main/java/me/shedaniel/rei/impl/client/subsets/SubsetsRegistryImpl.java diff --git a/runtime-engine/subsets/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.subsets.SubsetsRegistry b/runtime-engine/subsets/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.subsets.SubsetsRegistry new file mode 100644 index 000000000..a0bf0b39a --- /dev/null +++ b/runtime-engine/subsets/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.subsets.SubsetsRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.subsets.SubsetsRegistryImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java b/runtime-engine/transfer-handlers/src/main/java/me/shedaniel/rei/impl/client/transfer/AutoCraftingEvaluatorImpl.java similarity index 69% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java rename to runtime-engine/transfer-handlers/src/main/java/me/shedaniel/rei/impl/client/transfer/AutoCraftingEvaluatorImpl.java index 94ead5360..b694eaf91 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java +++ b/runtime-engine/transfer-handlers/src/main/java/me/shedaniel/rei/impl/client/transfer/AutoCraftingEvaluatorImpl.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.transfer; import me.shedaniel.math.Point; import me.shedaniel.rei.api.client.REIRuntime; @@ -33,6 +33,7 @@ import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRenderer; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.provider.AutoCraftingEvaluator; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; @@ -41,6 +42,7 @@ import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -48,23 +50,101 @@ import java.util.Locale; import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Supplier; -public class AutoCraftingEvaluator { - public static class AutoCraftingResult { +public class AutoCraftingEvaluatorImpl implements AutoCraftingEvaluator { + @Override + public Builder builder(Display display) { + return new Builder() { + private boolean actuallyCraft = false; + private boolean stacked = false; + @Nullable + private Collection ids = display.provideInternalDisplayIds(); + private boolean buildRenderer = false; + private boolean buildTooltipRenderer = false; + + @Override + public Builder actuallyCraft() { + this.actuallyCraft = true; + return this; + } + + @Override + public Builder stacked() { + this.stacked = true; + return this; + } + + @Override + public Builder ids(@Nullable Collection ids) { + this.ids = ids; + return this; + } + + @Override + public Builder buildRenderer() { + this.buildRenderer = true; + return this; + } + + @Override + public Builder buildTooltipRenderer() { + this.buildTooltipRenderer = true; + return this; + } + + @Override + public Result get() { + return evaluateAutoCrafting(actuallyCraft, stacked, display, buildRenderer, buildTooltipRenderer, ids); + } + }; + } + + public static class AutoCraftingResult implements AutoCraftingEvaluator.Result { public int tint = 0; public boolean successful = false; public TransferHandler successfulHandler; public boolean hasApplicable = false; public TransferHandlerRenderer renderer; public BiConsumer> tooltipRenderer; + + @Override + public int getTint() { + return tint; + } + + @Override + public boolean isSuccessful() { + return successful; + } + + @Override + public TransferHandler getSuccessfulHandler() { + return successfulHandler; + } + + @Override + public boolean isApplicable() { + return hasApplicable; + } + + @Override + public TransferHandlerRenderer getRenderer() { + return renderer; + } + + @Override + public BiConsumer> getTooltipRenderer() { + return tooltipRenderer; + } } - public static AutoCraftingResult evaluateAutoCrafting(boolean actuallyCrafting, boolean stackedCrafting, Display display, Supplier> idsSupplier) { + public static AutoCraftingResult evaluateAutoCrafting(boolean actuallyCrafting, boolean stackedCrafting, Display display, + boolean buildRenderer, boolean buildTooltipRenderer, + @Nullable Collection ids) { AbstractContainerScreen containerScreen = REIRuntime.getInstance().getPreviousContainerScreen(); AutoCraftingResult result = new AutoCraftingResult(); final List errorTooltip = new ArrayList<>(); - result.tooltipRenderer = (pos, sink) -> { + result.tooltipRenderer = !buildTooltipRenderer ? null : (pos, sink) -> { List str = new ArrayList<>(errorTooltip); if (ConfigObject.getInstance().isFavoritesEnabled()) { @@ -72,17 +152,14 @@ public static AutoCraftingResult evaluateAutoCrafting(boolean actuallyCrafting, str.add(Tooltip.entry(new TranslatableComponent("text.rei.save.recipes", new TextComponent(ConfigObject.getInstance().getFavoriteKeyCode().getLocalizedName().getString().toUpperCase(Locale.ROOT)).withStyle(ChatFormatting.BOLD)).withStyle(ChatFormatting.GRAY))); } - if (Minecraft.getInstance().options.advancedItemTooltips && idsSupplier != null) { - Collection locations = idsSupplier.get(); - if (!locations.isEmpty()) { - str.add(Tooltip.entry(new TextComponent(" "))); - for (ResourceLocation location : locations) { - String t = I18n.get("text.rei.recipe_id", "", location.toString()); - if (t.startsWith("\n")) { - t = t.substring("\n".length()); - } - str.add(Tooltip.entry(new TextComponent(t).withStyle(ChatFormatting.GRAY))); + if (Minecraft.getInstance().options.advancedItemTooltips && ids != null && !ids.isEmpty()) { + str.add(Tooltip.entry(new TextComponent(" "))); + for (ResourceLocation location : ids) { + String t = I18n.get("text.rei.recipe_id", "", location.toString()); + if (t.startsWith("\n")) { + t = t.substring("\n".length()); } + str.add(Tooltip.entry(new TextComponent(t).withStyle(ChatFormatting.GRAY))); } } @@ -115,12 +192,14 @@ public static AutoCraftingResult evaluateAutoCrafting(boolean actuallyCrafting, result.hasApplicable = true; result.tint = transferResult.getColor(); - TransferHandlerRenderer transferHandlerRenderer = transferResult.getRenderer(transferHandler, context); - if (transferHandlerRenderer != null) { - result.renderer = transferHandlerRenderer; + if (buildRenderer) { + TransferHandlerRenderer transferHandlerRenderer = transferResult.getRenderer(transferHandler, context); + if (transferHandlerRenderer != null) { + result.renderer = transferHandlerRenderer; + } } - if (transferResult.getTooltipRenderer() != null) { + if (buildTooltipRenderer && transferResult.getTooltipRenderer() != null) { BiConsumer tooltipRenderer = transferResult.getTooltipRenderer(); result.tooltipRenderer = (point, tooltipConsumer) -> tooltipRenderer.accept(point, tooltipConsumer::accept); } @@ -144,6 +223,8 @@ public static AutoCraftingResult evaluateAutoCrafting(boolean actuallyCrafting, } } + if (!buildTooltipRenderer) return result; + if (!result.hasApplicable) { errorTooltip.clear(); errorTooltip.add(Tooltip.entry(new TranslatableComponent("error.rei.not.supported.move.items").withStyle(ChatFormatting.RED))); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/TransferHandlerRegistryImpl.java b/runtime-engine/transfer-handlers/src/main/java/me/shedaniel/rei/impl/client/transfer/TransferHandlerRegistryImpl.java similarity index 88% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/TransferHandlerRegistryImpl.java rename to runtime-engine/transfer-handlers/src/main/java/me/shedaniel/rei/impl/client/transfer/TransferHandlerRegistryImpl.java index 93cffb1fe..e0b9fe05d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/TransferHandlerRegistryImpl.java +++ b/runtime-engine/transfer-handlers/src/main/java/me/shedaniel/rei/impl/client/transfer/TransferHandlerRegistryImpl.java @@ -27,17 +27,13 @@ import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; -import me.shedaniel.rei.api.common.entry.EntryIngredient; -import me.shedaniel.rei.impl.ClientInternals; import me.shedaniel.rei.impl.common.InternalLogger; -import net.minecraft.world.inventory.tooltip.TooltipComponent; import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.function.Function; @ApiStatus.Internal public class TransferHandlerRegistryImpl implements TransferHandlerRegistry { @@ -69,8 +65,4 @@ public void register(TransferHandler handler) { public Iterator iterator() { return Iterators.unmodifiableIterator(handlers.iterator()); } - - static { - ClientInternals.attachInstance((Function, TooltipComponent>) MissingStacksTooltip::new, "missingTooltip"); - } } diff --git a/runtime-engine/transfer-handlers/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry b/runtime-engine/transfer-handlers/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry new file mode 100644 index 000000000..606fb61d4 --- /dev/null +++ b/runtime-engine/transfer-handlers/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.transfer.TransferHandlerRegistryImpl \ No newline at end of file diff --git a/runtime-engine/transfer-handlers/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.AutoCraftingEvaluator b/runtime-engine/transfer-handlers/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.AutoCraftingEvaluator new file mode 100644 index 000000000..53e00b26e --- /dev/null +++ b/runtime-engine/transfer-handlers/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.AutoCraftingEvaluator @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.transfer.AutoCraftingEvaluatorImpl \ No newline at end of file diff --git a/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/AbstractViewSearchBuilder.java b/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/AbstractViewSearchBuilder.java new file mode 100644 index 000000000..f814bf078 --- /dev/null +++ b/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/AbstractViewSearchBuilder.java @@ -0,0 +1,50 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.view; + +import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; +import me.shedaniel.rei.api.client.view.ViewSearchBuilder; +import me.shedaniel.rei.impl.display.DisplaySpec; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; + +import java.util.Collection; +import java.util.stream.Stream; + +abstract class AbstractViewSearchBuilder implements ViewSearchBuilder { + public ViewSearchBuilder fillPreferredOpenedCategory() { + if (getPreferredOpenedCategory() == null) { + Screen currentScreen = Minecraft.getInstance().screen; + if (currentScreen instanceof DisplayScreen displayScreen) { + setPreferredOpenedCategory(displayScreen.getCurrentCategoryId()); + } + } + return this; + } + + @Override + public Stream streamDisplays() { + return buildMapInternal().values().stream().flatMap(Collection::stream); + } +} diff --git a/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/ViewSearchBuilderImpl.java b/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/ViewSearchBuilderImpl.java new file mode 100644 index 000000000..0d8640ac5 --- /dev/null +++ b/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/ViewSearchBuilderImpl.java @@ -0,0 +1,156 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.view; + +import com.google.common.base.Suppliers; +import me.shedaniel.rei.api.client.registry.display.DisplayCategory; +import me.shedaniel.rei.api.client.view.ViewSearchBuilder; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.impl.display.DisplaySpec; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.Supplier; + +public final class ViewSearchBuilderImpl extends AbstractViewSearchBuilder { + private final Set> filteringCategories = new HashSet<>(); + private final Set> categories = new HashSet<>(); + private final List> recipesFor = new ArrayList<>(); + private final List> usagesFor = new ArrayList<>(); + private final List additionalDisplays = new ArrayList<>(); + @Nullable + private CategoryIdentifier preferredOpenedCategory = null; + private boolean mergeDisplays = true; + private boolean processVisibilityHandlers = true; + private final Supplier, List>> map = Suppliers.memoize(() -> ViewsImpl.buildMapFor(this)); + + @Override + public ViewSearchBuilder addCategory(CategoryIdentifier category) { + this.categories.add(category); + return this; + } + + @Override + public ViewSearchBuilder addCategories(Collection> categories) { + this.categories.addAll(categories); + return this; + } + + @Override + public Set> getCategories() { + return categories; + } + + @Override + public ViewSearchBuilder addRecipesFor(EntryStack stack) { + this.recipesFor.add(stack); + return this; + } + + @Override + public List> getRecipesFor() { + return recipesFor; + } + + @Override + public ViewSearchBuilder addUsagesFor(EntryStack stack) { + this.usagesFor.add(stack); + return this; + } + + @Override + public List> getUsagesFor() { + return usagesFor; + } + + @Override + public ViewSearchBuilder setPreferredOpenedCategory(@Nullable CategoryIdentifier category) { + this.preferredOpenedCategory = category; + return this; + } + + @Override + @Nullable + public CategoryIdentifier getPreferredOpenedCategory() { + return this.preferredOpenedCategory; + } + + @Override + public ViewSearchBuilder filterCategory(CategoryIdentifier category) { + this.filteringCategories.add(category); + return this; + } + + @Override + public ViewSearchBuilder filterCategories(Collection> categories) { + this.filteringCategories.addAll(categories); + return this; + } + + @Override + public Set> getFilteringCategories() { + return filteringCategories; + } + + @Override + public Map, List> buildMapInternal() { + fillPreferredOpenedCategory(); + return this.map.get(); + } + + @Override + public boolean isMergingDisplays() { + return mergeDisplays; + } + + @Override + public ViewSearchBuilder mergingDisplays(boolean mergingDisplays) { + this.mergeDisplays = mergingDisplays; + return this; + } + + @Override + public boolean isProcessingVisibilityHandlers() { + return processVisibilityHandlers; + } + + @Override + public ViewSearchBuilder processingVisibilityHandlers(boolean processingVisibilityHandlers) { + this.processVisibilityHandlers = processingVisibilityHandlers; + return this; + } + + @Override + public ViewSearchBuilder addDisplays(Collection displays) { + this.additionalDisplays.addAll(displays); + return this; + } + + @Override + public List getAdditionalDisplays() { + return Collections.unmodifiableList(additionalDisplays); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java b/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java rename to runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java index 1c579e2e5..a2400eb32 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java +++ b/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java @@ -53,9 +53,10 @@ import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryIngredients; import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.impl.client.gui.craftable.CraftableFilter; -import me.shedaniel.rei.impl.client.gui.widget.AutoCraftingEvaluator; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.client.provider.AutoCraftingEvaluator; import me.shedaniel.rei.impl.client.util.CrashReportUtils; +import me.shedaniel.rei.impl.client.view.craftable.CraftableFilter; import me.shedaniel.rei.impl.common.InternalLogger; import me.shedaniel.rei.impl.display.DisplaySpec; import net.minecraft.CrashReport; @@ -87,13 +88,13 @@ public static Map, List> buildMapFor(ViewSearchB BUILDER.set(builder); try { - return _buildMapFor(builder); + return ((ViewsImpl) Views.getInstance())._buildMapFor(builder); } finally { BUILDER.remove(); } } - private static Map, List> _buildMapFor(ViewSearchBuilder builder) { + private Map, List> _buildMapFor(ViewSearchBuilder builder) { if (PluginManager.areAnyReloading()) { InternalLogger.getInstance().info("Cancelled Views buildMap since plugins have not finished reloading."); return Maps.newLinkedHashMap(); @@ -210,6 +211,12 @@ private static Map, List> _buildMapFor(ViewSearc generateLiveDisplays(displayRegistry, wrapForError(generator), builder, displayConsumer); } + for (Display display : builder.getAdditionalDisplays()) { + if (!processingVisibilityHandlers || displayRegistry.isDisplayVisible(display)) { + displayConsumer.accept(display); + } + } + Map, List> resultSpeced = (Map, List>) (Map) new LinkedHashMap<>(result); // optimize displays if (builder.isMergingDisplays() && ConfigObject.getInstance().doMergeDisplayUnderOne()) { @@ -290,11 +297,13 @@ public void add(Display display) { return resultSpeced; } - public static boolean isRecipesFor(List> stacks, Display display) { + @Override + public boolean isRecipesFor(List> stacks, Display display) { return checkUsages(stacks, display, display.getOutputEntries()); } - public static boolean isUsagesFor(List> stacks, Display display) { + @Override + public boolean isUsagesFor(List> stacks, Display display) { return checkUsages(stacks, display, display.getInputEntries()); } @@ -317,11 +326,11 @@ private static Iterable sortAutoCrafting(List displays) { Set applicableDisplays = new LinkedHashSet<>(); for (Display display : displays) { - AutoCraftingEvaluator.AutoCraftingResult result = AutoCraftingEvaluator.evaluateAutoCrafting(false, false, display, null); + AutoCraftingEvaluator.Result result = ClientInternals.getAutoCraftingEvaluator(display).get(); - if (result.successful) { + if (result.isSuccessful()) { successfulDisplays.add(display); - } else if (result.hasApplicable) { + } else if (result.isApplicable()) { applicableDisplays.add(display); } } @@ -449,7 +458,7 @@ public CategoryIdentifier getCategoryIdentifier() { int slotsCraftable = 0; boolean containsNonEmpty = false; List requiredInput = display.getRequiredEntries(); - Long2LongMap invCount = new Long2LongOpenHashMap(info == null ? CraftableFilter.INSTANCE.getInvStacks() : Long2LongMaps.EMPTY_MAP); + Long2LongMap invCount = new Long2LongOpenHashMap(info == null ? CraftableFilter.getInvStacks() : Long2LongMaps.EMPTY_MAP); for (SlotAccessor inputSlot : inputSlots) { ItemStack stack = inputSlot.getItemStack(); diff --git a/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/craftable/CraftableFilter.java b/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/craftable/CraftableFilter.java new file mode 100644 index 000000000..56be8000c --- /dev/null +++ b/runtime-engine/views/src/main/java/me/shedaniel/rei/impl/client/view/craftable/CraftableFilter.java @@ -0,0 +1,130 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.view.craftable; + +import it.unimi.dsi.fastutil.longs.Long2LongMap; +import it.unimi.dsi.fastutil.longs.Long2LongMaps; +import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext; +import me.shedaniel.rei.api.common.entry.type.EntryDefinition; +import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.impl.client.provider.OverlayTicker; +import net.minecraft.client.Minecraft; +import net.minecraft.core.NonNullList; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Optional; + +public class CraftableFilter implements OverlayTicker { + private static Long2LongMap invStacks = new Long2LongOpenHashMap(); + private static Long2LongMap containerStacks = new Long2LongOpenHashMap(); + + @Override + public void tick() { + if (Minecraft.getInstance().player == null || PluginManager.areAnyReloading() || Minecraft.getInstance().player.tickCount % 5 != 0) { + return; + } + + Optional overlay = REIRuntime.getInstance().getOverlay(); + if (overlay.isEmpty() || overlay.get().isSearchReloadQueued()) return; + if (!ConfigManager.getInstance().isCraftableOnlyEnabled()) return; + Long2LongMap currentStacks; + try { + currentStacks = getInventoryItemsTypes(); + } catch (Throwable throwable) { + throwable.printStackTrace(); + currentStacks = Long2LongMaps.EMPTY_MAP; + } + if (!currentStacks.equals(CraftableFilter.invStacks)) { + invStacks = currentStacks; + overlay.ifPresent(ScreenOverlay::queueReloadSearch); + return; + } + + try { + currentStacks = getContainerItemsTypes(); + } catch (Throwable throwable) { + throwable.printStackTrace(); + currentStacks = Long2LongMaps.EMPTY_MAP; + } + if (!currentStacks.equals(CraftableFilter.containerStacks)) { + containerStacks = currentStacks; + overlay.ifPresent(ScreenOverlay::queueReloadSearch); + } + } + + public static Long2LongMap getInvStacks() { + return invStacks; + } + + @ApiStatus.Internal + public static Long2LongMap getInventoryItemsTypes() { + EntryDefinition definition; + try { + definition = VanillaEntryTypes.ITEM.getDefinition(); + } catch (NullPointerException e) { + return Long2LongMaps.EMPTY_MAP; + } + Long2LongOpenHashMap map = new Long2LongOpenHashMap(); + for (NonNullList compartment : Minecraft.getInstance().player.getInventory().compartments) { + for (ItemStack stack : compartment) { + long hash = definition.hash(null, stack, ComparisonContext.FUZZY); + long newCount = map.getOrDefault(hash, 0) + Math.max(0, stack.getCount()); + map.put(hash, newCount); + } + } + return map; + } + + @ApiStatus.Internal + public static Long2LongMap getContainerItemsTypes() { + EntryDefinition definition; + try { + definition = VanillaEntryTypes.ITEM.getDefinition(); + } catch (NullPointerException e) { + return Long2LongMaps.EMPTY_MAP; + } + Long2LongOpenHashMap map = new Long2LongOpenHashMap(); + AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; + if (menu != null) { + for (Slot slot : menu.slots) { + ItemStack stack = slot.getItem(); + + if (!stack.isEmpty()) { + long hash = definition.hash(null, stack, ComparisonContext.FUZZY); + long newCount = map.getOrDefault(hash, 0) + Math.max(0, stack.getCount()); + map.put(hash, newCount); + } + } + } + return map; + } +} diff --git a/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.view.ViewSearchBuilder b/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.view.ViewSearchBuilder new file mode 100644 index 000000000..7e0e424e7 --- /dev/null +++ b/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.view.ViewSearchBuilder @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.view.ViewSearchBuilderImpl \ No newline at end of file diff --git a/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.view.Views b/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.view.Views new file mode 100644 index 000000000..37c806a3c --- /dev/null +++ b/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.view.Views @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.view.ViewsImpl \ No newline at end of file diff --git a/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.OverlayTicker b/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.OverlayTicker new file mode 100644 index 000000000..fd16783b5 --- /dev/null +++ b/runtime-engine/views/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.OverlayTicker @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.view.craftable.CraftableFilter \ No newline at end of file diff --git a/runtime-frontend/favorites-entries/build.gradle b/runtime-frontend/favorites-entries/build.gradle new file mode 100644 index 000000000..0ce416375 --- /dev/null +++ b/runtime-frontend/favorites-entries/build.gradle @@ -0,0 +1,3 @@ +dependencies { + compileClasspath(project(path: ":runtime-frontend:overlay", configuration: "namedElements")) +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidgetImpl.java similarity index 63% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidgetImpl.java index de8391e41..ecc652dd1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidgetImpl.java @@ -28,12 +28,8 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; -import me.shedaniel.rei.api.client.favorites.SystemFavoriteEntryProvider; -import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggedAcceptorResult; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; @@ -42,65 +38,50 @@ import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.client.overlay.OverlayListWidget; -import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.plugins.PluginManager; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; -import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; -import me.shedaniel.rei.impl.client.favorites.FavoriteEntryTypeRegistryImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; +import me.shedaniel.rei.impl.client.gui.overlay.entries.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.ScaleIndicatorWidget; import me.shedaniel.rei.impl.client.gui.widget.favorites.history.DisplayHistoryManager; import me.shedaniel.rei.impl.client.gui.widget.favorites.history.DisplayHistoryWidget; import me.shedaniel.rei.impl.client.gui.widget.favorites.listeners.FavoritesRegionListener; -import me.shedaniel.rei.impl.client.gui.widget.favorites.listeners.FavoritesSystemRegionListener; import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesPanel; import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesTogglePanelButton; import me.shedaniel.rei.impl.client.gui.widget.favorites.trash.TrashWidget; import me.shedaniel.rei.impl.client.gui.widget.region.EntryStacksRegionWidget; -import me.shedaniel.rei.impl.client.gui.widget.region.RealRegionEntry; -import me.shedaniel.rei.impl.client.gui.widget.region.RegionDraggableStack; import me.shedaniel.rei.impl.common.util.RectangleUtils; import net.minecraft.client.gui.screens.Screen; -import org.apache.commons.lang3.mutable.MutableLong; -import org.apache.commons.lang3.tuple.Triple; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.stream.Stream; @ApiStatus.Internal -public class FavoritesListWidget extends WidgetWithBounds implements DraggableComponentProviderWidget, DraggableComponentVisitorWidget, OverlayListWidget { +public class FavoritesListWidgetImpl extends WidgetWithBounds implements FavoritesListWidget, DraggableComponentProviderWidget, DraggableComponentVisitorWidget, OverlayListWidget { public Rectangle fullBounds; public Rectangle excludedBounds; public Rectangle favoritesBounds; - private EntryStacksRegionWidget systemRegion = new EntryStacksRegionWidget<>(new FavoritesSystemRegionListener()); - private EntryStacksRegionWidget region = new EntryStacksRegionWidget<>(new FavoritesRegionListener(this)); - private List lastSystemEntries = new ArrayList<>(); + private final EntryStacksRegionWidget region = new EntryStacksRegionWidget<>(new FavoritesRegionListener(this)); - public final FavoritesPanel favoritePanel = new FavoritesPanel(this); + public final FavoritesPanel favoritePanel = new FavoritesPanel(this, region); public final TrashWidget trash = new TrashWidget(this); public final DisplayHistoryWidget displayHistory = new DisplayHistoryWidget(this); public final FavoritesTogglePanelButton togglePanelButton = new FavoritesTogglePanelButton(this); - private List children = ImmutableList.of(favoritePanel, togglePanelButton, systemRegion, region); + private final List children = ImmutableList.of(favoritePanel, togglePanelButton, region); + private final ScaleIndicatorWidget scaleIndicator = new ScaleIndicatorWidget(); @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { if (fullBounds.contains(mouseX, mouseY)) { if (Screen.hasControlDown()) { - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); - ScreenOverlayImpl.getEntryListWidget().scaleIndicator.setAs(10.0D); - if (config.setEntrySize(config.getEntrySize() + amount * 0.075)) { - ConfigManager.getInstance().saveConfig(); - REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); - return true; - } + ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); + manager.set("advanced.accessibility.entrySize", manager.getConfig().getEntrySize() + amount * 0.075); + scaleIndicator.set(); } else if (favoritePanel.mouseScrolled(mouseX, mouseY, amount)) { return true; } else if (displayHistory.mouseScrolled(mouseX, mouseY, amount)) { @@ -119,17 +100,11 @@ public EntryStacksRegionWidget getRegion() { return region; } - public EntryStacksRegionWidget getSystemRegion() { - return systemRegion; - } - @Override @Nullable public DraggableComponent getHovered(DraggingContext context, double mouseX, double mouseY) { DraggableComponent stack = region.getHoveredStack(context, mouseX, mouseY); if (stack != null) return (DraggableComponent) stack; - stack = systemRegion.getHoveredStack(context, mouseX, mouseY); - if (stack != null) return (DraggableComponent) stack; if (favoritePanel.containsMouse(mouseX, mouseY)) { stack = favoritePanel.getHoveredStack(mouseX, mouseY); if (stack != null) return (DraggableComponent) stack; @@ -146,7 +121,7 @@ public DraggedAcceptorResult acceptDragged(DraggingContext context, Drag context.renderToVoid(stack); return DraggedAcceptorResult.CONSUMED; } - return Stream.of(region, systemRegion, displayHistory) + return Stream.of(region, displayHistory) .map(visitor -> visitor.acceptDragged(context, stack)) .filter(result -> result != DraggedAcceptorResult.PASS) .findFirst() @@ -158,8 +133,6 @@ public EntryStack getFocusedStack() { Point mouse = mouse(); EntryStack stack = region.getFocusedStack(); if (stack != null && !stack.isEmpty()) return stack; - stack = systemRegion.getFocusedStack(); - if (stack != null && !stack.isEmpty()) return stack; if (favoritePanel.containsMouse(mouse)) { EntryStack focusedStack = favoritePanel.getFocusedStack(mouse); @@ -183,24 +156,12 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { this.trash.render(matrices, mouseX, mouseY, delta); double trashHeight = this.trash.getHeight(); - if (!PluginManager.areAnyReloading()) { - updateSystemRegion(); - } - boolean draggingDisplay = DraggingContext.getInstance().isDraggingComponent() && DraggingContext.getInstance().getDragged().get() instanceof Display; int topOffsetHeight = 0; this.favoritesBounds = DisplayHistoryManager.INSTANCE.getEntries(displayHistory).isEmpty() && !draggingDisplay ? fullBounds : RectangleUtils.excludeZones(this.fullBounds, Stream.of(displayHistory.createBounds(this.excludedBounds))); - systemRegion.getBounds().setBounds(this.favoritesBounds.x, this.favoritesBounds.y + 1, this.favoritesBounds.width, Math.max(1, systemRegion.scrolling.getMaxScrollHeight())); - int systemHeight = systemRegion.getBounds().getHeight(); - if (systemHeight > 1 && !region.isEmpty()) { - Rectangle innerBounds = systemRegion.getInnerBounds(); - fillGradient(matrices, innerBounds.x + 1, this.favoritesBounds.y + systemHeight + 2, innerBounds.getMaxX() - 1, this.favoritesBounds.y + systemHeight + 3, 0xFF777777, 0xFF777777); - topOffsetHeight += systemHeight + 4; - } - displayHistory.render(matrices, mouseX, mouseY, delta); if (favoritePanel.getBounds().height > 20) { @@ -210,51 +171,11 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { region.getBounds().setBounds(this.favoritesBounds.x, this.favoritesBounds.y + topOffsetHeight, this.favoritesBounds.width, this.favoritesBounds.height - topOffsetHeight - (Math.round(trashHeight) <= 0 ? 0 : trashHeight + 24)); } - systemRegion.render(matrices, mouseX, mouseY, delta); region.render(matrices, mouseX, mouseY, delta); renderAddFavorite(matrices, mouseX, mouseY, delta); - } - - private void updateSystemRegion() { - boolean updated = false; - List, MutableLong, List>> providers = ((FavoriteEntryTypeRegistryImpl) FavoriteEntryType.registry()).getSystemProviders(); - - for (Triple, MutableLong, List> pair : providers) { - SystemFavoriteEntryProvider provider = pair.getLeft(); - MutableLong mutableLong = pair.getMiddle(); - List entries = pair.getRight(); - - if (mutableLong.getValue() == -1 || mutableLong.getValue() < System.currentTimeMillis()) { - mutableLong.setValue(System.currentTimeMillis() + provider.updateInterval()); - List provide = (List) provider.provide(); - if (!provide.equals(entries)) { - entries.clear(); - entries.addAll(provide); - updated = true; - } - } - } - if (updated) { - lastSystemEntries = CollectionUtils.flatMap(providers, Triple::getRight); - setSystemRegionEntries(null); - } - } - - public void setSystemRegionEntries(@Nullable RealRegionEntry removed) { - systemRegion.setEntries(CollectionUtils.filterToList(lastSystemEntries, entry -> { - if (region.has(entry)) return false; - if (DraggingContext.getInstance().isDraggingStack()) { - DraggableStack currentStack = DraggingContext.getInstance().getCurrentStack(); - if (currentStack instanceof RegionDraggableStack) { - RegionDraggableStack stack = (RegionDraggableStack) currentStack; - - if (removed != null && stack.getEntry() == removed) return true; - return stack.getEntry().region != region || !Objects.equals(stack.getEntry().getEntry(), entry); - } - } - return true; - }), EntryStacksRegionWidget.RemovalMode.DISAPPEAR); + this.scaleIndicator.setCenter(favoritesBounds.getCenterX(), favoritesBounds.getCenterY()); + this.scaleIndicator.render(matrices, mouseX, mouseY, delta); } private void renderAddFavorite(PoseStack matrices, int mouseX, int mouseY, float delta) { @@ -273,15 +194,22 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { return false; } - public void updateFavoritesBounds(@Nullable String searchTerm) { + @Override + public void initBounds() { this.fullBounds = REIRuntime.getInstance().calculateFavoritesListArea(); this.excludedBounds = RectangleUtils.excludeZones(this.fullBounds, ScreenRegistry.getInstance().exclusionZones().getExclusionZones(minecraft.screen).stream()); this.favoritesBounds = RectangleUtils.excludeZones(this.fullBounds, Stream.of(displayHistory.createBounds(this.fullBounds, null))); + this.updateSearch(); + } + + @Override + public void queueReloadSearch() { + updateSearch(); } public void updateSearch() { if (ConfigObject.getInstance().isFavoritesEnabled()) { - region.setEntries(CollectionUtils.map(FavoritesEntriesManager.INSTANCE.getFavorites(), FavoriteEntry::copy), EntryStacksRegionWidget.RemovalMode.DISAPPEAR); + region.setEntries(CollectionUtils.map(ConfigObject.getInstance().getFavoriteEntries(), FavoriteEntry::copy), EntryStacksRegionWidget.RemovalMode.DISAPPEAR); } else region.setEntries(Collections.emptyList(), EntryStacksRegionWidget.RemovalMode.DISAPPEAR); } @@ -292,7 +220,7 @@ public List children() { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (systemRegion.mouseClicked(mouseX, mouseY, button) || region.mouseClicked(mouseX, mouseY, button)) + if (region.mouseClicked(mouseX, mouseY, button)) return true; for (Widget widget : children()) if (widget.mouseClicked(mouseX, mouseY, button)) @@ -313,4 +241,19 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { return true; return false; } + + @Override + public Widget asWidget() { + return this; + } + + @Override + public Rectangle getFavoritesBounds() { + return favoritesBounds; + } + + @Override + public void submitDisplayHistory(Display display, @Nullable Rectangle fromBounds) { + displayHistory.addDisplay(fromBounds, display); + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayEntry.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayEntry.java similarity index 90% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayEntry.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayEntry.java index 3076b5cb8..7af1d8a8b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayEntry.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayEntry.java @@ -34,10 +34,11 @@ import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; +import me.shedaniel.rei.api.client.view.ViewSearchBuilder; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; -import me.shedaniel.rei.impl.client.ClientHelperImpl; -import me.shedaniel.rei.impl.client.gui.widget.AutoCraftingEvaluator; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.client.provider.AutoCraftingEvaluator; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.TextComponent; @@ -45,9 +46,9 @@ import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.UUID; +@SuppressWarnings("UnstableApiUsage") public class DisplayEntry extends WidgetWithBounds { private final LazyResettable> widgets = new LazyResettable<>(this::setupWidgets); private final DisplayHistoryWidget parent; @@ -171,22 +172,25 @@ public void render(PoseStack poses, int mouseX, int mouseY, float delta) { Vector4f mouse = new Vector4f((float) mouseX, (float) mouseY, 0, 1); mouse.transform(poses.last().pose()); - AutoCraftingEvaluator.AutoCraftingResult result = AutoCraftingEvaluator.evaluateAutoCrafting(false, false, display, display::provideInternalDisplayIds); + AutoCraftingEvaluator.Result result = ClientInternals.getAutoCraftingEvaluator(display) + .buildRenderer() + .buildTooltipRenderer() + .get(); - plusButton.setEnabled(result.successful); - plusButton.setTint(result.tint); + plusButton.setEnabled(result.isSuccessful()); + plusButton.setTint(result.getTint()); plusButton.getBounds().setBounds(new Rectangle(bounds.getMaxX() - 14, bounds.getMaxY() - 14, 10, 10)); - if (result.hasApplicable) { + if (result.isApplicable()) { plusButton.setText(new TextComponent("+")); plusButton.render(poses, Math.round(mouse.x()), Math.round(mouse.y()), delta); poses.popPose(); - if (plusButton.containsMouse(Math.round(mouse.x()), Math.round(mouse.y()))) { - result.tooltipRenderer.accept(new Point(mouseX, mouseY), Tooltip::queue); + if (plusButton.containsMouse(Math.round(mouse.x()), Math.round(mouse.y())) && result.getTooltipRenderer() != null) { + result.getTooltipRenderer().accept(new Point(mouseX, mouseY), Tooltip::queue); } - if (result.renderer != null) { + if (result.getRenderer() != null) { poses.pushPose(); if (!stable || !target.equals(bounds)) { poses.translate(0, 0, 600); @@ -194,7 +198,7 @@ public void render(PoseStack poses, int mouseX, int mouseY, float delta) { poses.translate(xOffset(), yOffset(), 0); poses.scale(xScale(), yScale(), 1.0F); - result.renderer.render(poses, mouseX, mouseY, delta, widgets.get(), getBounds(), display); + result.getRenderer().render(poses, mouseX, mouseY, delta, widgets.get(), getBounds(), display); poses.popPose(); } } else { @@ -226,14 +230,15 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { } if (button == 0 && plusButton.containsMouse(mouseX + xOffset, mouseY)) { - AutoCraftingEvaluator.evaluateAutoCrafting(true, Screen.hasShiftDown(), display, display::provideInternalDisplayIds); + ClientInternals.getAutoCraftingEvaluator(display) + .actuallyCraft() + .stacked(Screen.hasShiftDown()) + .get(); Widgets.produceClickSound(); return true; } - ClientHelperImpl.getInstance() - .openDisplayViewingScreen(Map.of(CategoryRegistry.getInstance().get(display.getCategoryIdentifier()).getCategory(), List.of(display)), - null, List.of(), List.of()); + ViewSearchBuilder.builder().addDisplays(List.of(display)).open(); Widgets.produceClickSound(); return true; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryManager.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryManager.java similarity index 91% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryManager.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryManager.java index 87ef93cbe..d115190ff 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryManager.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryManager.java @@ -25,12 +25,13 @@ import com.google.common.collect.Iterables; import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.display.DisplaySerializerRegistry; import me.shedaniel.rei.api.common.plugins.PluginManager; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import me.shedaniel.rei.impl.common.InternalLogger; import net.minecraft.Util; import net.minecraft.nbt.CompoundTag; @@ -43,6 +44,10 @@ public class DisplayHistoryManager { private Map entries = new LinkedHashMap<>(); private long lastCheckTime = -1; + private List getDisplayHistory() { + return (List) ConfigManagerInternal.getInstance().get("basics.displayHistory"); + } + public Collection getEntries(DisplayHistoryWidget parent) { if ((lastCheckTime == -1 || Util.getMillis() - lastCheckTime > 4000) && !PluginManager.areAnyReloading()) { updateEntries(parent); @@ -53,7 +58,7 @@ public Collection getEntries(DisplayHistoryWidget parent) { } private void updateEntries(DisplayHistoryWidget parent) { - List displayHistory = ConfigManagerImpl.getInstance().getConfig().getDisplayHistory(); + List displayHistory = getDisplayHistory(); Map copy = new LinkedHashMap<>(entries); entries.clear(); for (CompoundTag tag : displayHistory) { @@ -80,13 +85,13 @@ private void updateEntries(DisplayHistoryWidget parent) { public void removeEntry(DisplayEntry entry) { this.entries.remove(entry.getUuid().toString()); - List displayHistory = ConfigManagerImpl.getInstance().getConfig().getDisplayHistory(); + List displayHistory = getDisplayHistory(); displayHistory.removeIf(tag -> tag.getString("DisplayHistoryUUID").equals(entry.getUuid().toString())); save(); } public void addEntry(DisplayHistoryWidget parent, @Nullable Rectangle bounds, Display display) { - List displayHistory = ConfigManagerImpl.getInstance().getConfig().getDisplayHistory(); + List displayHistory = getDisplayHistory(); Iterator iterator = this.entries.values().iterator(); while (iterator.hasNext()) { DisplayEntry entry = iterator.next(); @@ -116,7 +121,7 @@ public void addEntry(DisplayHistoryWidget parent, @Nullable Rectangle bounds, Di } private void save() { - List displayHistory = ConfigManagerImpl.getInstance().getConfig().getDisplayHistory(); + List displayHistory = getDisplayHistory(); for (CompoundTag compoundTag : displayHistory) { String uuid = compoundTag.getString("DisplayHistoryUUID"); DisplayEntry entry = entries.get(uuid); @@ -137,6 +142,6 @@ private void save() { } } - ConfigManagerImpl.getInstance().saveConfig(); + ConfigManager.getInstance().saveConfig(); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryWidget.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryWidget.java similarity index 88% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryWidget.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryWidget.java index ba5b470f0..14523a20d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryWidget.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/history/DisplayHistoryWidget.java @@ -40,11 +40,11 @@ import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProviderWidget; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitorWidget; +import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.common.display.Display; -import me.shedaniel.rei.impl.client.gui.widget.DisplayCompositeWidget; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidgetImpl; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.GameRenderer; @@ -58,14 +58,14 @@ @SuppressWarnings("UnstableApiUsage") public class DisplayHistoryWidget extends WidgetWithBounds implements DraggableComponentVisitorWidget, DraggableComponentProviderWidget { - private final FavoritesListWidget parent; + private final FavoritesListWidgetImpl parent; private final Rectangle bounds = new Rectangle(); private final NumberAnimator height; private boolean ignoreNextMouse; private final NumberAnimator scroll = ValueAnimator.ofDouble(); - public DisplayHistoryWidget(FavoritesListWidget parent) { + public DisplayHistoryWidget(FavoritesListWidgetImpl parent) { this.parent = parent; this.height = ValueAnimator.ofDouble().withConvention(() -> { boolean draggingDisplay = DraggingContext.getInstance().isDraggingComponent() @@ -297,7 +297,7 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { DisplayHistoryManager.INSTANCE.removeEntry(entry); scroll.setAs(scroll.target() - getBounds().getWidth()); scroll.setTo(scroll.target() + getBounds().getWidth(), 800); - DisplayCompositeWidget.DisplayDraggableComponent component = new DisplayCompositeWidget.DisplayDraggableComponent(Widgets.concat(entry.getWidgets()), entry.getDisplay(), + DisplayDraggableComponent component = new DisplayDraggableComponent(Widgets.concat(entry.getWidgets()), entry.getDisplay(), entry.getBounds().clone(), new Rectangle(0, 0, entry.getSize().width, entry.getSize().height)); DraggingContext.getInstance().renderToVoid(component); @@ -330,7 +330,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { DisplayHistoryManager.INSTANCE.removeEntry(entry); scroll.setAs(scroll.target() - getBounds().getWidth()); scroll.setTo(scroll.target() + getBounds().getWidth(), 800); - DisplayCompositeWidget.DisplayDraggableComponent component = new DisplayCompositeWidget.DisplayDraggableComponent(Widgets.concat(entry.getWidgets()), entry.getDisplay(), + DisplayDraggableComponent component = new DisplayDraggableComponent(Widgets.concat(entry.getWidgets()), entry.getDisplay(), entry.getBounds().clone(), new Rectangle(0, 0, entry.getSize().width, entry.getSize().height)); DraggingContext.getInstance().renderToVoid(component); @@ -380,7 +380,7 @@ public DraggableComponent getHovered(DraggingContext context, do } } - return (DraggableComponent) (DraggableComponent) new DisplayCompositeWidget.DisplayDraggableComponent(Widgets.concat(entry.getWidgets()), entry.getDisplay(), + return (DraggableComponent) (DraggableComponent) new DisplayDraggableComponent(Widgets.concat(entry.getWidgets()), entry.getDisplay(), entry.getBounds().clone(), new Rectangle(0, 0, entry.getSize().width, entry.getSize().height)) { @Override @@ -404,4 +404,55 @@ public void release(DraggedAcceptorResult result) { return null; } + + public static class DisplayDraggableComponent implements DraggableComponent { + private final Widget widget; + private final Display display; + private final Rectangle originBounds; + private final Rectangle bounds; + + public DisplayDraggableComponent(Widget widget, Display display, Rectangle originBounds, Rectangle bounds) { + this.widget = widget; + this.display = display; + this.originBounds = originBounds; + this.bounds = bounds; + } + + @Override + public int getWidth() { + return bounds.width; + } + + @Override + public int getHeight() { + return bounds.height; + } + + @Override + public Display get() { + return display; + } + + @Override + public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { + matrices.pushPose(); + matrices.translate(bounds.getX(), bounds.getY(), 0); + matrices.scale(bounds.width / (float) this.bounds.getWidth(), bounds.height / (float) this.bounds.getHeight(), 1); + matrices.translate(-this.bounds.getX(), -this.bounds.getY(), 0); + widget.render(matrices, -1000, -1000, delta); + matrices.popPose(); + } + + @Override + public void release(DraggedAcceptorResult result) { + if (result == DraggedAcceptorResult.PASS) { + DraggingContext.getInstance().renderBack(this, DraggingContext.getInstance().getCurrentBounds(), () -> originBounds); + } + } + + @Override + public Rectangle getOriginBounds(Point mouse) { + return originBounds.clone(); + } + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java similarity index 86% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java index d9c211ec4..af361942a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java @@ -27,8 +27,8 @@ import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesEntriesManager; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; +import me.shedaniel.rei.impl.client.favorites.MutableFavoritesList; +import me.shedaniel.rei.impl.client.gui.overlay.entries.FavoritesListWidget; import me.shedaniel.rei.impl.client.gui.widget.region.RealRegionEntry; import me.shedaniel.rei.impl.client.gui.widget.region.RegionEntryWidget; import me.shedaniel.rei.impl.client.gui.widget.region.RegionListener; @@ -47,20 +47,19 @@ public class FavoritesRegionListener implements RegionListener { @Override public void onDrop(Stream entries) { if (ConfigObject.getInstance().isFavoritesEnabled()) { - FavoritesEntriesManager.INSTANCE.setEntries(entries.collect(Collectors.toList())); + ((MutableFavoritesList) ConfigObject.getInstance().getFavoriteEntries()).setAll(entries.collect(Collectors.toList())); } } @Override public void onRemove(RealRegionEntry entry) { if (ConfigObject.getInstance().isFavoritesEnabled()) { - FavoritesEntriesManager.INSTANCE.remove(entry.getEntry()); + ConfigObject.getInstance().getFavoriteEntries().remove(entry.getEntry()); } } @Override public void onConsumed(RealRegionEntry entry) { - favoritesListWidget.setSystemRegionEntries(entry); } @Override @@ -71,6 +70,5 @@ public FavoriteEntry convertDraggableStack(DraggingContext context, Drag @Override public void onSetNewEntries(List> regionEntryListEntries) { - favoritesListWidget.setSystemRegionEntries(null); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java index 4652ec53e..e2cbcf461 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FadingFavoritesPanelButton.java @@ -30,7 +30,7 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidgetImpl; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.renderer.MultiBufferSource; @@ -39,13 +39,13 @@ @SuppressWarnings("UnstableApiUsage") public abstract class FadingFavoritesPanelButton extends WidgetWithBounds { - protected final FavoritesListWidget parent; + protected final FavoritesListWidgetImpl parent; public boolean wasClicked = false; public final NumberAnimator alpha = ValueAnimator.ofDouble(0); public final Rectangle bounds = new Rectangle(); - public FadingFavoritesPanelButton(FavoritesListWidget parent) { + public FadingFavoritesPanelButton(FavoritesListWidgetImpl parent) { this.parent = parent; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java index f23bb2c10..7d6327fd3 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java @@ -38,8 +38,9 @@ import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.overlay.entries.FavoritesListWidget; import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.rows.*; +import me.shedaniel.rei.impl.client.gui.widget.region.EntryStacksRegionWidget; import net.minecraft.client.gui.components.events.GuiEventListener; import org.jetbrains.annotations.Nullable; @@ -49,6 +50,7 @@ @SuppressWarnings("UnstableApiUsage") public class FavoritesPanel extends WidgetWithBounds { private final FavoritesListWidget parent; + private final EntryStacksRegionWidget region; public final ProgressValueAnimator expendState = ValueAnimator.ofBoolean(0.1, false); private final Rectangle bounds = new Rectangle(); private final Rectangle innerBounds = new Rectangle(); @@ -75,8 +77,9 @@ public int getMaxScrollHeight() { } }; - public FavoritesPanel(FavoritesListWidget parent) { + public FavoritesPanel(FavoritesListWidget parent, EntryStacksRegionWidget region) { this.parent = parent; + this.region = region; } public void resetRows() { @@ -85,7 +88,7 @@ public void resetRows() { @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - this.bounds.setBounds(updatePanelArea(parent.favoritesBounds)); + this.bounds.setBounds(updatePanelArea(parent.getFavoritesBounds())); this.innerBounds.setBounds(bounds.x + 4, bounds.y + 4, bounds.width - 8, bounds.height - 20); this.expendState.update(delta); int buttonColor = 0xFFFFFF | (Math.round(0x34 * Math.min((float) expendState.progress() * 2, 1)) << 24); @@ -135,6 +138,10 @@ public FavoritesListWidget getParent() { return parent; } + public EntryStacksRegionWidget getRegion() { + return region; + } + public Rectangle getInnerBounds() { return innerBounds; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java index 32415069b..70743a7fb 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesTogglePanelButton.java @@ -28,13 +28,13 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidgetImpl; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.TranslatableComponent; @SuppressWarnings("UnstableApiUsage") public class FavoritesTogglePanelButton extends FadingFavoritesPanelButton { - public FavoritesTogglePanelButton(FavoritesListWidget parent) { + public FavoritesTogglePanelButton(FavoritesListWidgetImpl parent) { super(parent); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEmptyRow.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEmptyRow.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEmptyRow.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEmptyRow.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java similarity index 73% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java index 9f68a8d72..9f281e022 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java @@ -29,16 +29,18 @@ import me.shedaniel.math.FloatingPoint; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; -import me.shedaniel.math.impl.PointHelper; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; +import me.shedaniel.rei.api.client.gui.widgets.Slot; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.util.ClientEntryStacks; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; -import me.shedaniel.rei.impl.client.gui.widget.DisplayedEntryWidget; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.DisplayedEntryWidget; import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesPanel; import me.shedaniel.rei.impl.client.gui.widget.region.RealRegionEntry; import me.shedaniel.rei.impl.client.gui.widget.region.RegionDraggableStack; @@ -47,11 +49,11 @@ import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; +import java.util.AbstractList; import java.util.List; import java.util.function.Predicate; -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.notSteppingOnExclusionZones; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; @SuppressWarnings("UnstableApiUsage") public class FavoritesPanelEntriesRow extends FavoritesPanelRow { @@ -65,7 +67,7 @@ public FavoritesPanelEntriesRow(FavoritesPanel panel, List entrie this.panel = panel; this.entries = entries; int entrySize = entrySize(); - this.widgets = CollectionUtils.map(this.entries, entry -> new SectionFavoriteWidget(new Point(0, 0), entrySize, entry)); + this.widgets = CollectionUtils.map(this.entries, entry -> new SectionFavoriteWidget(Widgets.createSlot(new Point(0, 0)), entrySize, entry)); for (SectionFavoriteWidget widget : this.widgets) { widget.size.setTo(entrySize * 100, 300); @@ -89,18 +91,29 @@ public void render(PoseStack matrices, Rectangle innerBounds, int x, int y, int updateEntriesPosition(entry -> true); for (SectionFavoriteWidget widget : widgets) { widget.update(delta); + Slot slot = widget.slot; - if (widget.getBounds().getMaxY() > lastY && widget.getBounds().getY() <= lastY + rowHeight) { - if (widget.getCurrentEntry().isEmpty()) + if (slot.getBounds().getMaxY() > lastY && slot.getBounds().getY() <= lastY + rowHeight) { + if (slot.getCurrentEntry().isEmpty()) continue; - widget.render(matrices, mouseX, mouseY, delta); + slot.render(matrices, mouseX, mouseY, delta); } } } @Override public List children() { - return widgets; + return new AbstractList() { + @Override + public GuiEventListener get(int index) { + return widgets.get(index).slot; + } + + @Override + public int size() { + return widgets.size(); + } + }; } @Override @@ -121,10 +134,10 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { @Nullable public DraggableStack getHoveredStack(double mouseX, double mouseY) { for (SectionFavoriteWidget widget : widgets) { - if (widget.containsMouse(mouseX, mouseY + panel.getScrolledAmount())) { - RealRegionEntry entry = new RealRegionEntry<>(panel.getParent().getRegion(), widget.entry.copy(), entrySize()); + if (widget.slot.containsMouse(mouseX, mouseY + panel.getScrolledAmount())) { + RealRegionEntry entry = new RealRegionEntry<>(panel.getRegion(), widget.entry.copy(), entrySize()); entry.size.setAs(entrySize() * 100); - return new RegionDraggableStack<>(entry, widget); + return new RegionDraggableStack<>(entry, widget.slot); } } @@ -134,7 +147,7 @@ public DraggableStack getHoveredStack(double mouseX, double mouseY) { @Nullable public EntryStack getFocusedStack(Point mouse) { for (SectionFavoriteWidget widget : widgets) { - if (widget.containsMouse(mouse)) { + if (widget.slot.containsMouse(mouse)) { return ClientEntryStacks.of(widget.entry.getRenderer(false)).copy(); } } @@ -143,15 +156,17 @@ public EntryStack getFocusedStack(Point mouse) { } private class SectionFavoriteWidget extends DisplayedEntryWidget { - private ValueAnimator pos = ValueAnimator.ofFloatingPoint(); - private NumberAnimator size = ValueAnimator.ofDouble(); - private FavoriteEntry entry; + private final ValueAnimator pos = ValueAnimator.ofFloatingPoint(); + private final NumberAnimator size = ValueAnimator.ofDouble(); + private final FavoriteEntry entry; - protected SectionFavoriteWidget(Point point, int entrySize, FavoriteEntry entry) { - super(point, entrySize); + protected SectionFavoriteWidget(Slot slot, int entrySize, FavoriteEntry entry) { + super(slot); this.entry = entry; - entry(ClientEntryStacks.of(entry.getRenderer(true))); - noBackground(); + slot.size(entrySize); + slot.entry(ClientEntryStacks.of(entry.getRenderer(true))); + slot.appendContainsPointFunction((s, point) -> panel.getInnerBounds().contains(point)); + slot.noBackground(); } public void moveTo(boolean animated, int xPos, int yPos) { @@ -161,22 +176,17 @@ public void moveTo(boolean animated, int xPos, int yPos) { public void update(float delta) { this.pos.update(delta); this.size.update(delta); - this.getBounds().width = this.getBounds().height = (int) Math.round(this.size.doubleValue() / 100); + slot.getBounds().width = slot.getBounds().height = (int) Math.round(this.size.doubleValue() / 100); double offsetSize = (entrySize() - this.size.doubleValue() / 100) / 2; - this.getBounds().x = (int) Math.round(pos.value().x + offsetSize); - this.getBounds().y = (int) Math.round(pos.value().y + offsetSize) + lastY; + slot.getBounds().x = (int) Math.round(pos.value().x + offsetSize); + slot.getBounds().y = (int) Math.round(pos.value().y + offsetSize) + lastY; } @Override - @Nullable - public Tooltip getCurrentTooltip(Point point) { - point = PointHelper.ofMouse(); - if (!panel.getInnerBounds().contains(point)) return null; - Tooltip tooltip = super.getCurrentTooltip(point); - if (tooltip != null) { - tooltip.add(ImmutableTextComponent.EMPTY); - tooltip.add(new TranslatableComponent("tooltip.rei.drag_to_add_favorites")); - } + public Tooltip apply(Tooltip tooltip) { + tooltip = super.apply(tooltip); + tooltip.add(ImmutableTextComponent.EMPTY); + tooltip.add(new TranslatableComponent("tooltip.rei.drag_to_add_favorites")); return tooltip; } } @@ -200,7 +210,7 @@ public void updateEntriesPosition(Predicate animated) { currentY++; } - if (notSteppingOnExclusionZones(xPos, yPos + lastY - panel.getScrolledAmountInt(), entrySize, entrySize)) { + if (ScreenOverlay.getInstance().get().isNotInExclusionZones(new Rectangle(xPos, yPos + lastY - panel.getScrolledAmountInt(), entrySize, entrySize))) { widget.moveTo(animated.test(widget), xPos, yPos); break; } else { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelRow.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelRow.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelRow.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelRow.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSectionRow.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSectionRow.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSectionRow.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSectionRow.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSeparatorRow.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSeparatorRow.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSeparatorRow.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelSeparatorRow.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java index a93ea9b77..7ce5f7e6a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/trash/TrashWidget.java @@ -29,7 +29,7 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidgetImpl; import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesPanel; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.network.chat.Component; @@ -42,11 +42,11 @@ @SuppressWarnings("UnstableApiUsage") public class TrashWidget extends WidgetWithBounds { private final Rectangle bounds = new Rectangle(); - private final FavoritesListWidget parent; + private final FavoritesListWidgetImpl parent; private final NumberAnimator height; private double lastProgress; - public TrashWidget(FavoritesListWidget parent) { + public TrashWidget(FavoritesListWidgetImpl parent) { this.parent = parent; this.height = ValueAnimator.ofDouble().withConvention(() -> { Rectangle fullBounds = this.parent.favoritesBounds; diff --git a/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/plugin/FavoritesEntriesBuiltinPlugin.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/plugin/FavoritesEntriesBuiltinPlugin.java new file mode 100644 index 000000000..418d45d93 --- /dev/null +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/plugin/FavoritesEntriesBuiltinPlugin.java @@ -0,0 +1,52 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget.plugin; + +import me.shedaniel.rei.api.client.overlay.OverlayListWidget; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.screen.ExclusionZones; +import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidgetImpl; +import net.minecraft.client.gui.screens.Screen; + +import java.util.Collections; +import java.util.List; + +public class FavoritesEntriesBuiltinPlugin implements REIClientPlugin { + @Override + public void registerScreens(ScreenRegistry registry) { + ExclusionZones zones = registry.exclusionZones(); + zones.register(Screen.class, screen -> { + if (ScreenOverlay.getInstance().isEmpty()) return List.of(); + OverlayListWidget widget = ScreenOverlay.getInstance().get().getFavoritesList().orElse(null); + if (widget instanceof FavoritesListWidgetImpl impl) { + if (impl.togglePanelButton.isVisible()) { + return Collections.singletonList(impl.togglePanelButton.bounds); + } + } + return Collections.emptyList(); + }); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java index 57c80090c..942e7d8cf 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java @@ -34,17 +34,13 @@ import me.shedaniel.math.FloatingPoint; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.entry.region.RegionEntry; import me.shedaniel.rei.api.client.gui.drag.*; -import me.shedaniel.rei.api.client.gui.widgets.Widget; -import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.common.entry.EntrySerializer; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.gui.widget.BatchedEntryRendererManager; -import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; import net.minecraft.client.gui.screens.Screen; import net.minecraft.util.Mth; import net.minecraft.util.Tuple; @@ -60,7 +56,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; public class EntryStacksRegionWidget> extends WidgetWithBounds implements DraggableStackProviderWidget, DraggableStackVisitorWidget { public final RegionListener listener; @@ -123,14 +119,19 @@ public void render(PoseStack poses, int mouseX, int mouseY, float delta) { ScissorsHandler.INSTANCE.scissor(bounds); - Stream> entryStream = this.entriesList.stream() - .filter(entry -> entry.getBounds().getMaxY() >= this.bounds.getY() && entry.getBounds().y <= this.bounds.getMaxY()); + Iterable> entryIterable = Iterables.filter(entriesList, + entry -> entry.slot.getBounds().getMaxY() >= this.bounds.getY() && entry.slot.getBounds().y <= this.bounds.getMaxY()); - new BatchedEntryRendererManager(entryStream.collect(Collectors.toList())) - .render(poses, mouseX, mouseY, delta); + BatchedSlots slots = Widgets.createBatchedSlots(); + for (RegionEntryWidget entry : entryIterable) { + entry.renderExtra(poses, mouseX, mouseY, delta); + slots.add(entry.slot); + } + + slots.render(poses, mouseX, mouseY, delta); updatePosition(delta); - scrolling.renderScrollBar(0, 1, REIRuntime.getInstance().isDarkThemeEnabled() ? 0.8f : 1f); + scrolling.renderScrollBar(0, 1, ConfigObject.getInstance().isUsingDarkTheme() ? 0.8f : 1f); ScissorsHandler.INSTANCE.removeLastScissor(); } @@ -181,7 +182,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { public DraggableStack getHoveredStack(DraggingContext context, double mouseX, double mouseY) { if (innerBounds.contains(mouseX, mouseY)) { for (RealRegionEntry entry : entries.values()) { - if (entry.getWidget().containsMouse(mouseX, mouseY) && listener.canBeDragged(entry)) { + if (entry.getSlot().containsMouse(mouseX, mouseY) && listener.canBeDragged(entry)) { return new RegionDraggableStack<>(entry, null); } } @@ -193,8 +194,8 @@ public EntryStack getFocusedStack() { Point mouse = mouse(); if (innerBounds.contains(mouse)) { for (RealRegionEntry entry : entries.values()) { - if (entry.getWidget().containsMouse(mouse)) { - return entry.getWidget().getCurrentEntry().copy(); + if (entry.getSlot().containsMouse(mouse)) { + return entry.getSlot().getCurrentEntry().copy(); } } } @@ -203,8 +204,9 @@ public EntryStack getFocusedStack() { public Stream> getEntries() { return (Stream>) (Stream>) entriesList.stream() + .map(entry -> entry.slot) .filter(entry -> entry.getBounds().getMaxY() >= this.bounds.getY() && entry.getBounds().y <= this.bounds.getMaxY()) - .map(EntryWidget::getCurrentEntry) + .map(Slot::getCurrentEntry) .filter(entry -> !entry.isEmpty()); } @@ -305,8 +307,8 @@ public boolean isEmpty() { public void applyNewEntriesList() { this.entriesList = Stream.concat(entries.values().stream().map(RealRegionEntry::getWidget), removedEntries.values().stream().map(RealRegionEntry::getWidget)).collect(Collectors.toList()); this.children = Stream.>of( - entries.values().stream().map(RealRegionEntry::getWidget), - removedEntries.values().stream().map(RealRegionEntry::getWidget) + entries.values().stream().map(RealRegionEntry::getSlot), + removedEntries.values().stream().map(RealRegionEntry::getSlot) ).flatMap(Function.identity()).collect(Collectors.toList()); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RealRegionEntry.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RealRegionEntry.java similarity index 81% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RealRegionEntry.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RealRegionEntry.java index 792982fd7..062e2bfbc 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RealRegionEntry.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RealRegionEntry.java @@ -28,12 +28,14 @@ import me.shedaniel.math.FloatingPoint; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.entry.region.RegionEntry; +import me.shedaniel.rei.api.client.gui.widgets.Slot; -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; +@SuppressWarnings("UnstableApiUsage") public class RealRegionEntry> { public EntryStacksRegionWidget region; - private T entry; + private final T entry; private final RegionEntryWidget widget; private boolean hidden; public ValueAnimator pos = ValueAnimator.ofFloatingPoint(); @@ -42,7 +44,7 @@ public class RealRegionEntry> { public RealRegionEntry(EntryStacksRegionWidget region, T entry, int entrySize) { this.region = region; this.entry = entry; - this.widget = (RegionEntryWidget) new RegionEntryWidget<>(this, 0, 0, entrySize).noBackground(); + this.widget = RegionEntryWidget.createSlot(this, 0, 0, entrySize); } public void remove() { @@ -56,16 +58,20 @@ public void remove() { public void update(double delta) { this.pos.update(delta); this.size.update(delta); - this.getWidget().getBounds().width = this.getWidget().getBounds().height = (int) Math.round(this.size.doubleValue() / 100); + this.getSlot().getBounds().width = this.getSlot().getBounds().height = (int) Math.round(this.size.doubleValue() / 100); double offsetSize = (entrySize() - this.size.doubleValue() / 100) / 2; - this.getWidget().getBounds().x = (int) Math.round(pos.value().x + offsetSize); - this.getWidget().getBounds().y = (int) Math.round(pos.value().y + offsetSize) - (int) region.getScrollAmount(); + this.getSlot().getBounds().x = (int) Math.round(pos.value().x + offsetSize); + this.getSlot().getBounds().y = (int) Math.round(pos.value().y + offsetSize) - (int) region.getScrollAmount(); } public RegionEntryWidget getWidget() { return widget; } + public Slot getSlot() { + return widget.slot; + } + public boolean isHidden() { return hidden; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java diff --git a/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionEntryWidget.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionEntryWidget.java new file mode 100644 index 000000000..2df833fcf --- /dev/null +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionEntryWidget.java @@ -0,0 +1,89 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget.region; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.math.FloatingPoint; +import me.shedaniel.math.Point; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.entry.region.RegionEntry; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.api.client.gui.widgets.Slot; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.AbstractScreenOverlay; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.DisplayedEntryWidget; + +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Supplier; + +@SuppressWarnings("UnstableApiUsage") +public class RegionEntryWidget> extends DisplayedEntryWidget { + private final RealRegionEntry entry; + + RegionEntryWidget(RealRegionEntry entry, Slot slot, int entrySize) { + super(slot); + this.entry = entry; + slot.size(entrySize); + slot.entry(entry.getEntry().toStack()); + slot.setFavoriteEntryFunction(stack -> asFavoriteEntry()); + slot.setNoticeMark(Slot.FAVORITE); + slot.noBackground(); + } + + public static > RegionEntryWidget createSlot(RealRegionEntry entry, int x, int y, int entrySize) { + return new RegionEntryWidget<>(entry, Widgets.createSlot(new Point(x, y)), entrySize); + } + + protected FavoriteEntry asFavoriteEntry() { + return entry.region.listener.asFavorite(entry); + } + + public void renderExtra(PoseStack matrices, int mouseX, int mouseY, float delta) { + Optional overlayOptional = REIRuntime.getInstance().getOverlay(); + Optional>> menuEntries = entry.getEntry().getMenuEntries(); + FloatingPoint value = entry.pos.value(); + FloatingPoint target = entry.pos.target(); + if (Math.abs(value.x - target.x) < 1 && Math.abs(value.y - target.y) < 1 && overlayOptional.isPresent() && menuEntries.isPresent()) { + AbstractScreenOverlay overlay = (AbstractScreenOverlay) overlayOptional.get(); + MenuAccess access = overlay.menuAccess(); + UUID uuid = entry.getEntry().getUuid(); + + access.openOrClose(uuid, slot.getBounds(), menuEntries.get()); + } + } + + @Override + public boolean doMouse(Slot slot, double mouseX, double mouseY, int button) { + return entry.getEntry().doAction(button) || super.doMouse(slot, mouseX, mouseY, button); + } + + public RealRegionEntry getEntry() { + return entry; + } +} \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java similarity index 92% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java rename to runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java index 7ef8917ed..4f77e9782 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java +++ b/runtime-frontend/favorites-entries/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java @@ -23,11 +23,12 @@ package me.shedaniel.rei.impl.client.gui.widget.region; +import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.entry.region.RegionEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; -import me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import net.minecraft.client.gui.screens.Screen; import org.jetbrains.annotations.Nullable; @@ -70,6 +71,6 @@ default void onSetNewEntries(Stream entries) {} default void onConsumed(RealRegionEntry entry) {} default boolean notSteppingOnExclusionZones(int left, int top, int width, int height) { - return EntryListWidget.notSteppingOnExclusionZones(left, top, width, height); + return ScreenOverlay.getInstance().get().isNotInExclusionZones(new Rectangle(left, top, width, height)); } } diff --git a/runtime-frontend/overlay-entries/build.gradle b/runtime-frontend/overlay-entries/build.gradle new file mode 100644 index 000000000..0ce416375 --- /dev/null +++ b/runtime-frontend/overlay-entries/build.gradle @@ -0,0 +1,3 @@ +dependencies { + compileClasspath(project(path: ":runtime-frontend:overlay", configuration: "namedElements")) +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsedEntriesTooltip.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedEntriesTooltip.java similarity index 92% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsedEntriesTooltip.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedEntriesTooltip.java index 44d848b8e..9521c2e5b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsedEntriesTooltip.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedEntriesTooltip.java @@ -21,13 +21,12 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.entrylist; +package me.shedaniel.rei.impl.client.gui.overlay.entries; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; @@ -38,6 +37,8 @@ import net.minecraft.util.Mth; import net.minecraft.world.inventory.tooltip.TooltipComponent; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; + public class CollapsedEntriesTooltip implements ClientTooltipComponent, TooltipComponent { private static final int MAX_WIDTH = 140; private final CollapsedStack stack; @@ -48,14 +49,14 @@ public CollapsedEntriesTooltip(CollapsedStack stack) { @Override public int getHeight() { - int entrySize = EntryListWidget.entrySize(); + int entrySize = entrySize(); int w = Math.max(1, MAX_WIDTH / entrySize); return Math.min(3, Mth.ceil(stack.getIngredient().size() / (float) w)) * entrySize + 2; } @Override public int getWidth(Font font) { - int entrySize = EntryListWidget.entrySize(); + int entrySize = entrySize(); int w = Math.max(1, MAX_WIDTH / entrySize); int size = stack.getIngredient().size(); return Math.min(size, w) * entrySize; @@ -63,7 +64,7 @@ public int getWidth(Font font) { @Override public void renderImage(Font font, int x, int y, PoseStack poses, ItemRenderer renderer, int z) { - int entrySize = EntryListWidget.entrySize(); + int entrySize = entrySize(); int w = Math.max(1, MAX_WIDTH / entrySize); int i = 0; poses.pushPose(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsedStack.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedStack.java similarity index 89% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsedStack.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedStack.java index 348b3a0f2..c48de3d5f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/entry/type/collapsed/CollapsedStack.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsedStack.java @@ -21,8 +21,9 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.entry.type.collapsed; +package me.shedaniel.rei.impl.client.gui.overlay.entries; +import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntry; import me.shedaniel.rei.api.common.entry.EntryStack; import net.minecraft.network.chat.Component; @@ -30,9 +31,9 @@ public class CollapsedStack { private final List> ingredient; - private final CollapsibleEntryRegistryImpl.Entry entry; + private final CollapsibleEntry entry; - public CollapsedStack(List> ingredient, CollapsibleEntryRegistryImpl.Entry entry) { + public CollapsedStack(List> ingredient, CollapsibleEntry entry) { this.ingredient = ingredient; this.entry = entry; } @@ -54,6 +55,6 @@ public Component getName() { } public String getModId() { - return entry.getModId(); + return entry.getId().getNamespace(); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsingEntryListWidget.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsingEntryListWidget.java similarity index 87% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsingEntryListWidget.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsingEntryListWidget.java index fe2d8b7e8..735905f21 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CollapsingEntryListWidget.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/CollapsingEntryListWidget.java @@ -21,23 +21,19 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.entrylist; +package me.shedaniel.rei.impl.client.gui.overlay.entries; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack; import java.util.ArrayList; import java.util.List; import java.util.Map; -public abstract class CollapsingEntryListWidget extends EntryListWidget { - private List | CollapsedStack*/ Object> collapsedStacks = new ArrayList<>(); +public abstract class CollapsingEntryListWidget extends EntryListWidgetImpl { private Int2ObjectMap collapsedStackIndexed = new Int2ObjectOpenHashMap<>(); - protected int updatedCount; - protected int lastUpdatedCount; public abstract List | List>*/ Object> getStacks(); @@ -47,17 +43,6 @@ protected final Int2ObjectMap getCollapsedStackIndexed() { return collapsedStackIndexed; } - @Override - public boolean isEmpty() { - return collapsedStacks.isEmpty(); - } - - @Override - protected void setCollapsedStacks(List | CollapsedStack*/ Object> stacks) { - this.collapsedStacks = stacks; - updateStacks(); - } - @Override public void updateEntriesPosition() { if (updatedCount != lastUpdatedCount) { @@ -70,6 +55,8 @@ public void updateEntriesPosition() { private void updateStacks() { lastUpdatedCount = updatedCount; + List | CollapsedStack*/ Object> collapsedStacks = EntryListEntries.INSTANCE.getCollapsedStacks(); + List | List>*/ Object> stacks = new ArrayList<>((int) (collapsedStacks.size() * 1.5)); Map | List>*/ Object, CollapsedStack> collapsedStackMap = new Reference2ObjectOpenHashMap<>(); Int2ObjectMap collapsedStackIndexed = new Int2ObjectOpenHashMap<>(); diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/DefaultEntryListProvider.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/DefaultEntryListProvider.java new file mode 100644 index 000000000..5d3410f09 --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/DefaultEntryListProvider.java @@ -0,0 +1,47 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.entries; + +import com.google.common.base.Suppliers; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.impl.client.gui.overlay.entries.paginated.PaginatedEntryListWidget; +import me.shedaniel.rei.impl.client.gui.overlay.entries.scrolled.ScrolledEntryListWidget; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +public class DefaultEntryListProvider implements EntryListProvider { + private final Supplier paginated = Suppliers.memoize(PaginatedEntryListWidget::new); + private final Supplier scrolled = Suppliers.memoize(ScrolledEntryListWidget::new); + + @Override + @Nullable + public EntryListWidget getEntryList() { + if (ConfigObject.getInstance().isEntryListWidgetScrolled()) { + return scrolled.get(); + } else { + return paginated.get(); + } + } +} diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListEntries.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListEntries.java new file mode 100644 index 000000000..daecf616d --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListEntries.java @@ -0,0 +1,48 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.entries; + +import java.util.ArrayList; +import java.util.List; + +public class EntryListEntries { + public static final EntryListEntries INSTANCE = new EntryListEntries(); + private List | CollapsedStack*/ Object> collapsedStacks = new ArrayList<>(); + + public void updateSearch(String searchTerm, boolean ignoreLastSearch, EntriesCallback callback) { + EntryListSearchManager.INSTANCE.update(searchTerm, ignoreLastSearch, stacks -> { + collapsedStacks = stacks; + callback.updateStacks(); + }); + } + + public List | CollapsedStack*/ Object> getCollapsedStacks() { + return collapsedStacks; + } + + @FunctionalInterface + public interface EntriesCallback { + void updateStacks(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListSearchManager.java similarity index 84% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListSearchManager.java index d8c11ab1a..da2ab2eaf 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListSearchManager.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.entrylist; +package me.shedaniel.rei.impl.client.gui.overlay.entries; import com.google.common.base.Stopwatch; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; @@ -29,6 +29,7 @@ import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.EntryPanelOrdering; +import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntry; import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.view.Views; @@ -36,9 +37,8 @@ import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.search.AsyncSearchManager; +import me.shedaniel.rei.impl.client.search.SearchManager; import me.shedaniel.rei.impl.common.InternalLogger; -import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack; -import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsibleEntryRegistryImpl; import net.minecraft.client.Minecraft; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; @@ -62,7 +62,7 @@ public class EntryListSearchManager { public static final EntryListSearchManager INSTANCE = new EntryListSearchManager(); - private AsyncSearchManager searchManager = new AsyncSearchManager(EntryRegistry.getInstance()::getPreFilteredList, () -> { + private final SearchManager searchManager = new AsyncSearchManager(EntryRegistry.getInstance()::getPreFilteredList, () -> { boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled(); LongSet workingItems = checkCraftable ? new LongOpenHashSet() : null; if (checkCraftable) { @@ -80,14 +80,14 @@ public void update(String searchTerm, boolean ignoreLastSearch, Consumer { if (!filter.getFilter().equals(searchTerm)) return; - if (searchManager.filter() == null || searchManager.filter() != filter) return; + if (searchManager.getSearchFilter() == null || searchManager.getSearchFilter() != filter) return; InternalLogger.getInstance().log(ConfigObject.getInstance().doDebugSearchTimeRequired() ? Level.INFO : Level.TRACE, "Search \"%s\" Used [%s]: %s", filter.getFilter(), Thread.currentThread().toString(), stopwatch.toString()); - List | CollapsedStack*/ Object> finalList = collapse(copyAndOrder(list), () -> searchManager.filter() != null && searchManager.filter() == filter); + List | CollapsedStack*/ Object> finalList = collapse(copyAndOrder(list), () -> searchManager.getSearchFilter() != null && searchManager.getSearchFilter() == filter); InternalLogger.getInstance().log(ConfigObject.getInstance().doDebugSearchTimeRequired() ? Level.INFO : Level.TRACE, "Search \"%s\" Used and Applied [%s]: %s", filter.getFilter(), Thread.currentThread().toString(), stopwatch.stop().toString()); Minecraft.getInstance().submit(() -> { - if (searchManager.filter() == null || searchManager.filter() != filter) return; + if (searchManager.getSearchFilter() == null || searchManager.getSearchFilter() != filter) return; update.accept(finalList); }); }); @@ -109,10 +109,10 @@ private List> copyAndOrder(List> list) { } private List | CollapsedStack*/ Object> collapse(List> stacks, BooleanSupplier isValid) { - CollapsibleEntryRegistryImpl collapsibleRegistry = (CollapsibleEntryRegistryImpl) CollapsibleEntryRegistry.getInstance(); - Map entries = new HashMap<>(); + CollapsibleEntryRegistry collapsibleRegistry = CollapsibleEntryRegistry.getInstance(); + Map entries = new HashMap<>(); - for (CollapsibleEntryRegistryImpl.Entry entry : collapsibleRegistry.getEntries()) { + for (CollapsibleEntry entry : collapsibleRegistry) { entries.put(entry, null); } @@ -126,10 +126,10 @@ private List> copyAndOrder(List> list) { long hashExact = EntryStacks.hashExact(stack); boolean matchedAny = false; - for (Map.Entry mapEntry : entries.entrySet()) { - CollapsibleEntryRegistryImpl.Entry entry = mapEntry.getKey(); + for (Map.Entry mapEntry : entries.entrySet()) { + CollapsibleEntry entry = mapEntry.getKey(); - if (entry.getMatcher().matches(stack, hashExact)) { + if (entry.matches(stack, hashExact)) { CollapsedStack collapsed = mapEntry.getValue(); if (collapsed == null) { @@ -159,4 +159,8 @@ private List> copyAndOrder(List> list) { public boolean matches(EntryStack stack) { return searchManager.matches(stack); } + + public SearchManager getSearchManager() { + return searchManager; + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListStackEntry.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListStackEntry.java similarity index 59% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListStackEntry.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListStackEntry.java index f0b0424d1..c9d868c29 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListStackEntry.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListStackEntry.java @@ -21,26 +21,29 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.entrylist; +package me.shedaniel.rei.impl.client.gui.overlay.entries; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.api.animator.NumberAnimator; import me.shedaniel.clothconfig2.api.animator.ValueAnimator; -import me.shedaniel.math.FloatingPoint; import me.shedaniel.math.FloatingRectangle; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.math.impl.PointHelper; import me.shedaniel.rei.api.client.ClientHelper; +import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; +import me.shedaniel.rei.api.client.gui.widgets.Slot; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.util.ClientEntryStacks; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.client.gui.widget.CachedEntryListRender; -import me.shedaniel.rei.impl.client.gui.widget.DisplayedEntryWidget; -import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack; +import me.shedaniel.rei.impl.client.gui.overlay.entries.cache.CachedEntryListRender; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.DisplayedEntryWidget; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.util.Mth; import net.minecraft.world.inventory.tooltip.TooltipComponent; @@ -48,108 +51,104 @@ import java.util.List; -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; @SuppressWarnings("UnstableApiUsage") public class EntryListStackEntry extends DisplayedEntryWidget { private final CollapsingEntryListWidget parent; public EntryStack our; + public Widget extra; private NumberAnimator size = null; private CollapsedStack collapsedStack = null; private List collapsedBounds = null; - public EntryListStackEntry(CollapsingEntryListWidget parent, int x, int y, int entrySize, boolean zoomed) { - super(new Point(x, y), entrySize); + public EntryListStackEntry(CollapsingEntryListWidget parent, Slot slot, int entrySize, boolean zoomed) { + super(slot); this.parent = parent; + slot.size(entrySize); + slot.noBackground(); + slot.cyclingInterval(100L); + slot.appendContainsPointFunction((s, point) -> parent.containsChecked(point.x, point.y, true)); + if (zoomed) { - noHighlight(); + slot.noHighlight(); size = ValueAnimator.ofDouble(1f) .withConvention(() -> { double mouseX = PointHelper.getMouseFloatingX(); double mouseY = PointHelper.getMouseFloatingY(); - int x1 = getBounds().getCenterX() - entrySize / 2; - int y1 = getBounds().getCenterY() - entrySize / 2; + int x1 = slot.getBounds().getCenterX() - entrySize / 2; + int y1 = slot.getBounds().getCenterY() - entrySize / 2; boolean hovering = mouseX >= x1 && mouseX < x1 + entrySize && mouseY >= y1 && mouseY < y1 + entrySize; return hovering ? 1.5 : 1.0; }, 200); } + + this.extra = new Widget() { + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + drawBackground(poses, mouseX, mouseY, delta); + drawExtra(poses, mouseX, mouseY, delta); + } + + @Override + public List children() { + return List.of(); + } + }; } - @Override - protected void drawExtra(PoseStack matrices, int mouseX, int mouseY, float delta) { + public static EntryListStackEntry createSlot(CollapsingEntryListWidget parent, int x, int y, int entrySize, boolean zoomed) { + return new EntryListStackEntry(parent, Widgets.createSlot(new Point(x, y)), entrySize, zoomed); + } + + private void drawExtra(PoseStack matrices, int mouseX, int mouseY, float delta) { if (size != null) { size.update(delta); - int centerX = getBounds().getCenterX(); - int centerY = getBounds().getCenterY(); + int centerX = slot.getBounds().getCenterX(); + int centerY = slot.getBounds().getCenterY(); int entrySize = (int) Math.round(entrySize() * size.value()); - getBounds().setBounds(centerX - entrySize / 2, centerY - entrySize / 2, entrySize, entrySize); - } - super.drawExtra(matrices, mouseX, mouseY, delta); - } - - @Override - public EntryStack getCurrentEntry() { - if (our != null) { - if (CachedEntryListRender.cachedTextureLocation != null) { - return our; - } + slot.getBounds().setBounds(centerX - entrySize / 2, centerY - entrySize / 2, entrySize, entrySize); } - - return super.getCurrentEntry(); } - @Override - public boolean containsMouse(double mouseX, double mouseY) { - return super.containsMouse(mouseX, mouseY) && parent.containsChecked(mouseX, mouseY, true); - } - - @Override - protected void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta) { - Rectangle bounds = getBounds(); + private void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta) { + Rectangle bounds = slot.getBounds(); if (collapsedStack != null) { fillGradient(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), 0x34FFFFFF, 0x34FFFFFF); } - - super.drawBackground(matrices, mouseX, mouseY, delta); } - @Override - protected void drawCurrentEntry(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (collapsedStack != null && !collapsedStack.isExpanded()) { - Rectangle bounds = getBounds(); - List> stacks = collapsedStack.getIngredient(); - float fullSize = bounds.getWidth(); - - matrices.pushPose(); - matrices.translate(0, 0, 10); + protected void drawCollapsedStack(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { + List> stacks = collapsedStack.getIngredient(); + float fullSize = bounds.getWidth(); + + matrices.pushPose(); + matrices.translate(0, 0, 10); + + for (int i = stacks.size() - 1; i >= 0; i--) { + EntryStack stack = stacks.get(i); - for (int i = stacks.size() - 1; i >= 0; i--) { - EntryStack stack = stacks.get(i); - - if (i >= collapsedBounds.size()) { - continue; - } - - FloatingRectangle value = collapsedBounds.get(i); - double x = bounds.x + value.x * fullSize; - double y = bounds.y + value.y * fullSize; - - double scaledSize = value.width * fullSize; - - stack.render(matrices, new Rectangle(x - scaledSize / 2, y - scaledSize / 2, scaledSize, scaledSize), mouseX, mouseY, delta); - - matrices.translate(0, 0, 10); + if (i >= collapsedBounds.size()) { + continue; } - matrices.popPose(); - } else { - super.drawCurrentEntry(matrices, mouseX, mouseY, delta); + FloatingRectangle value = collapsedBounds.get(i); + double x = bounds.x + value.x * fullSize; + double y = bounds.y + value.y * fullSize; + + double scaledSize = value.width * fullSize; + + stack.render(matrices, new Rectangle(x - scaledSize / 2, y - scaledSize / 2, scaledSize, scaledSize), mouseX, mouseY, delta); + + matrices.translate(0, 0, 10); } + + matrices.popPose(); } @Override - protected boolean doAction(double mouseX, double mouseY, int button) { + public boolean doMouse(Slot slot, double mouseX, double mouseY, int button) { if (collapsedStack != null && button == 0 && Screen.hasAltDown()) { parent.updatedCount++; collapsedStack.setExpanded(!collapsedStack.isExpanded()); @@ -158,7 +157,7 @@ protected boolean doAction(double mouseX, double mouseY, int button) { return true; } - return super.doAction(mouseX, mouseY, button); + return super.doMouse(slot, mouseX, mouseY, button); } public void collapsed(CollapsedStack collapsedStack) { @@ -178,11 +177,10 @@ else if (ingredient.size() == 1) { } @Override - @Nullable - public Tooltip getCurrentTooltip(Point point) { + public Tooltip apply(Tooltip tooltip) { if (this.collapsedStack != null) { if (!this.collapsedStack.isExpanded()) { - Tooltip tooltip = Tooltip.create(point, new TranslatableComponent("text.rei.collapsed.entry", collapsedStack.getName())); + tooltip = Tooltip.create(new Point(tooltip.getX(), tooltip.getY()), new TranslatableComponent("text.rei.collapsed.entry", collapsedStack.getName())); tooltip.add((TooltipComponent) new CollapsedEntriesTooltip(collapsedStack)); tooltip.add(new TranslatableComponent(Minecraft.ON_OSX ? "text.rei.collapsed.entry.hint.expand.macos" : "text.rei.collapsed.entry.hint.expand", collapsedStack.getName(), collapsedStack.getIngredient().size()) .withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC)); @@ -191,8 +189,8 @@ public Tooltip getCurrentTooltip(Point point) { } } - Tooltip tooltip = super.getCurrentTooltip(point); - if (tooltip != null && this.collapsedStack != null) { + tooltip = super.apply(tooltip); + if (this.collapsedStack != null) { tooltip.entries().add(Mth.clamp(tooltip.entries().size() - 1, 0, tooltip.entries().size() - 1), Tooltip.entry(new TranslatableComponent(Minecraft.ON_OSX ? "text.rei.collapsed.entry.hint.collapse.macos" : "text.rei.collapsed.entry.hint.collapse", collapsedStack.getName(), collapsedStack.getIngredient().size()) .withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC))); } @@ -204,8 +202,18 @@ public CollapsedStack getCollapsedStack() { return collapsedStack; } - @Override - protected long getCyclingInterval() { - return 100; + public void updateEntries() { + if (collapsedStack != null && !collapsedStack.isExpanded()) { + EntryStack rewrap = slot.getCurrentEntry().rewrap(); + slot.clearEntries(); + slot.entry(ClientEntryStacks.setRenderer(rewrap, (EntryRenderer) (entry, matrices, bounds, mouseX, mouseY, delta) -> { + drawCollapsedStack(matrices, bounds, mouseX, mouseY, delta); + })); + } else if (our != null) { + if (CachedEntryListRender.cachedTextureLocation != null) { + slot.clearEntries(); + slot.entry(our); + } + } } } \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidgetImpl.java similarity index 65% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidgetImpl.java index 30aa0de60..66b47ffdb 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListWidget.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidgetImpl.java @@ -21,16 +21,13 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.entrylist; +package me.shedaniel.rei.impl.client.gui.overlay.entries; import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.clothconfig2.api.animator.NumberAnimator; -import me.shedaniel.clothconfig2.api.animator.ValueAnimator; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.ClientHelper; import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggableStackVisitorWidget; @@ -41,68 +38,43 @@ import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import me.shedaniel.rei.api.client.overlay.OverlayListWidget; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.registry.screen.OverlayDecider; import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.impl.client.ClientHelperImpl; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; -import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; -import me.shedaniel.rei.impl.client.gui.widget.region.RegionRenderingDebugger; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.RegionRenderingDebugger; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.ScaleIndicatorWidget; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.util.Mth; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; import java.util.List; -@SuppressWarnings("UnstableApiUsage") +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; + @ApiStatus.Internal -public abstract class EntryListWidget extends WidgetWithBounds implements OverlayListWidget, DraggableStackVisitorWidget { - private static final int SIZE = 18; +public abstract class EntryListWidgetImpl extends WidgetWithBounds implements EntryListWidget, DraggableStackVisitorWidget { protected final RegionRenderingDebugger debugger = new RegionRenderingDebugger(); protected Rectangle bounds, innerBounds; - public final NumberAnimator scaleIndicator = ValueAnimator.ofDouble(0.0D) - .withConvention(() -> 0.0D, 8000); - - public static int entrySize() { - return Mth.ceil(SIZE * ConfigObject.getInstance().getEntrySize()); - } + protected int updatedCount; + protected int lastUpdatedCount; + private final ScaleIndicatorWidget scaleIndicator = new ScaleIndicatorWidget(); public static boolean notSteppingOnExclusionZones(int left, int top, int width, int height) { - Minecraft instance = Minecraft.getInstance(); - for (OverlayDecider decider : ScreenRegistry.getInstance().getDeciders(instance.screen)) { - InteractionResult fit = canItemSlotWidgetFit(left, top, width, height, decider); - if (fit != InteractionResult.PASS) - return fit == InteractionResult.SUCCESS; - } - return true; - } - - private static InteractionResult canItemSlotWidgetFit(int left, int top, int width, int height, OverlayDecider decider) { - InteractionResult fit; - fit = decider.isInZone(left, top); - if (fit != InteractionResult.PASS) - return fit; - fit = decider.isInZone(left + width, top); - if (fit != InteractionResult.PASS) - return fit; - fit = decider.isInZone(left, top + height); - if (fit != InteractionResult.PASS) - return fit; - fit = decider.isInZone(left + width, top + height); - return fit; + ScreenOverlay overlay = ScreenOverlay.getInstance().get(); + return overlay.isNotInExclusionZones(new Rectangle(left, top, width, height)); } private boolean containsChecked(Point point, boolean inner) { @@ -171,13 +143,9 @@ public DraggedAcceptorResult acceptDraggedStack(DraggingContext context, public boolean mouseScrolled(double mouseX, double mouseY, double amount) { if (containsChecked(mouseX, mouseY, false)) { if (Screen.hasControlDown()) { - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); - scaleIndicator.setAs(10.0D); - if (config.setEntrySize(config.getEntrySize() + amount * 0.075)) { - ConfigManager.getInstance().saveConfig(); - REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); - return true; - } + ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); + manager.set("advanced.accessibility.entrySize", manager.getConfig().getEntrySize() + amount * 0.075); + scaleIndicator.set(); } } @@ -198,15 +166,15 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { debugger.render(matrices, bounds.x, bounds.y, delta); - if (containsChecked(mouseX, mouseY, false) && ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen) && !minecraft.player.containerMenu.getCarried().isEmpty() && ClientHelperImpl.getInstance().canDeleteItems()) { + if (containsChecked(mouseX, mouseY, false) && ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen) && !minecraft.player.containerMenu.getCarried().isEmpty() && (NetworkingHelper.getInstance().has(NetworkModule.DELETE_ITEM) || Minecraft.getInstance().gameMode.hasInfiniteItems())) { EntryStack stack = EntryStacks.of(minecraft.player.containerMenu.getCarried().copy()); if (stack.getType() != VanillaEntryTypes.ITEM) { EntryStack cheatsAs = stack.cheatsAs(); stack = cheatsAs.isEmpty() ? stack : cheatsAs; } - for (Widget child : children()) { - if (child.containsMouse(mouseX, mouseY) && child instanceof EntryWidget widget) { - if (widget.cancelDeleteItems(stack)) { + for (Slot slot : getSlots()) { + if (slot.containsMouse(mouseX, mouseY)) { + if (cancelDeleteItems(slot, stack)) { return; } } @@ -214,18 +182,8 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { Tooltip.create(new TranslatableComponent("text.rei.delete_items")).queue(); } - scaleIndicator.update(delta); - if (scaleIndicator.value() > 0.04) { - matrices.pushPose(); - matrices.translate(0, 0, 500); - TextComponent component = new TextComponent(Math.round(ConfigObject.getInstance().getEntrySize() * 100) + "%"); - int width = font.width(component); - int backgroundColor = ((int) Math.round(0xa0 * Mth.clamp(scaleIndicator.value(), 0.0, 1.0))) << 24; - int textColor = ((int) Math.round(0xdd * Mth.clamp(scaleIndicator.value(), 0.0, 1.0))) << 24; - fillGradient(matrices, bounds.getCenterX() - width / 2 - 2, bounds.getCenterY() - 6, bounds.getCenterX() + width / 2 + 2, bounds.getCenterY() + 6, backgroundColor, backgroundColor); - font.draw(matrices, component, bounds.getCenterX() - width / 2, bounds.getCenterY() - 4, 0xFFFFFF | textColor); - matrices.popPose(); - } + this.scaleIndicator.setCenter(bounds.getCenterX(), bounds.getCenterY()); + this.scaleIndicator.render(matrices, mouseX, mouseY, delta); } protected abstract void renderEntries(boolean fastEntryRendering, PoseStack matrices, int mouseX, int mouseY, float delta); @@ -233,23 +191,16 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (containsChecked(mouse(), false)) - for (Widget widget : getEntryWidgets()) + for (Widget widget : getSlots()) if (widget.keyPressed(keyCode, scanCode, modifiers)) return true; return false; } - public void updateArea(Rectangle bounds, String searchTerm) { + @Override + public void initBounds(Rectangle bounds) { this.bounds = REIRuntime.getInstance().calculateEntryListArea(bounds); - FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); - if (favoritesListWidget != null) { - favoritesListWidget.updateFavoritesBounds(searchTerm); - } - if (ConfigObject.getInstance().isFavoritesEnabled() && favoritesListWidget == null) { - updateSearch(searchTerm, true); - } else { - updateEntriesPosition(); - } + updateEntriesPosition(); } public boolean hasSpace() { @@ -264,34 +215,22 @@ public void updateEntriesPosition() { boolean zoomed = ConfigObject.getInstance().isFocusModeZoomed(); this.innerBounds = updateInnerBounds(bounds); updateEntries(entrySize, zoomed); - FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); - if (favoritesListWidget != null) { - favoritesListWidget.getSystemRegion().updateEntriesPosition(entry -> true); - favoritesListWidget.getRegion().updateEntriesPosition(entry -> true); - } } protected abstract void updateEntries(int entrySize, boolean zoomed); - public abstract boolean isEmpty(); - - protected abstract void setCollapsedStacks(List | CollapsedStack*/ Object> stacks); - - public void updateSearch(String searchTerm, boolean ignoreLastSearch) { - EntryListSearchManager.INSTANCE.update(searchTerm, ignoreLastSearch, stacks -> { - setCollapsedStacks(stacks); + @Override + public void initSearch(String searchTerm, boolean ignorePrevious) { + EntryListEntries.INSTANCE.updateSearch(searchTerm, ignorePrevious, () -> { + updatedCount++; updateEntriesPosition(); }); debugger.debugTime = ConfigObject.getInstance().doDebugRenderTimeRequired(); - FavoritesListWidget favorites = ScreenOverlayImpl.getFavoritesListWidget(); - if (favorites != null) { - favorites.updateSearch(); - } } @Override public List children() { - return getEntryWidgets(); + return getSlots(); } @Override @@ -307,7 +246,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { public boolean mouseReleased(double mouseX, double mouseY, int button) { if (containsChecked(mouseX, mouseY, false)) { LocalPlayer player = minecraft.player; - if (ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen) && player != null && player.containerMenu != null && !player.containerMenu.getCarried().isEmpty() && ClientHelperImpl.getInstance().canDeleteItems()) { + if (ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen) && player != null && player.containerMenu != null && !player.containerMenu.getCarried().isEmpty() && (NetworkingHelper.getInstance().has(NetworkModule.DELETE_ITEM) || Minecraft.getInstance().gameMode.hasInfiniteItems())) { EntryStack stack = EntryStacks.of(minecraft.player.containerMenu.getCarried().copy()); if (stack.getType() != VanillaEntryTypes.ITEM) { EntryStack cheatsAs = stack.cheatsAs(); @@ -315,9 +254,9 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { } boolean canDelete = true; - for (Widget child : children()) { - if (child.containsMouse(mouseX, mouseY) && child instanceof EntryWidget widget) { - if (widget.cancelDeleteItems(stack)) { + for (Slot slot : getSlots()) { + if (slot.containsMouse(mouseX, mouseY)) { + if (cancelDeleteItems(slot, stack)) { canDelete = false; break; } @@ -336,11 +275,27 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { return false; } + private boolean cancelDeleteItems(Slot slot, EntryStack stack) { + if (!slot.isInteractable() || !ConfigObject.getInstance().isGrabbingItems()) + return false; + if (ClientHelper.getInstance().isCheating() && !Screen.hasControlDown() && !(Minecraft.getInstance().screen instanceof DisplayScreen)) { + EntryStack entry = slot.getCurrentEntry().copy(); + if (!entry.isEmpty()) { + if (entry.getType() != VanillaEntryTypes.ITEM) { + EntryStack cheatsAs = entry.cheatsAs(); + entry = cheatsAs.isEmpty() ? entry : cheatsAs; + } + return EntryStacks.equalsExact(entry, stack); + } + } + return false; + } + @Override public EntryStack getFocusedStack() { Point mouse = mouse(); if (containsChecked(mouse, false)) { - for (Slot entry : getEntryWidgets()) { + for (Slot entry : getSlots()) { EntryStack currentEntry = entry.getCurrentEntry(); if (!currentEntry.isEmpty() && entry.containsMouse(mouse)) { return currentEntry.copy(); @@ -350,8 +305,24 @@ public EntryStack getFocusedStack() { return EntryStack.empty(); } - protected abstract List getEntryWidgets(); + protected abstract List getSlots(); - public void init(ScreenOverlayImpl overlay) { + public void init(ScreenOverlay overlay) { + } + + @Override + public void queueReloadSearch() { + initSearch(REIRuntime.getInstance().getSearchTextField().getText(), true); + } + + @Override + public Widget asWidget() { + return this; + } + + @Override + @Nullable + public SearchFilter getSearchFilter() { + return EntryListSearchManager.INSTANCE.getSearchManager().getSearchFilter(); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CachedEntryListRender.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/cache/CachedEntryListRender.java similarity index 91% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CachedEntryListRender.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/cache/CachedEntryListRender.java index 60c7b98ce..a10a7c70e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CachedEntryListRender.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/cache/CachedEntryListRender.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.overlay.entries.cache; import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.platform.Lighting; @@ -41,6 +41,9 @@ import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.registry.ReloadStage; +import me.shedaniel.rei.api.common.registry.Reloadable; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.common.InternalLogger; import net.minecraft.client.Minecraft; @@ -66,6 +69,24 @@ public class CachedEntryListRender { .setShaderState(new RenderStateShard.ShaderStateShard(GameRenderer::getPositionTexShader)) .createCompositeState(false))); + static { + PluginManager.getInstance().registerReloadable(new Reloadable<>() { + @Override + public void startReload() { + startReload(null); + } + + @Override + public void startReload(ReloadStage stage) { + if (!RenderSystem.isOnRenderThread()) { + RenderSystem.recordRenderCall(CachedEntryListRender::refresh); + } else { + CachedEntryListRender.refresh(); + } + } + }); + } + public static class Sprite { public final float u0; public final float u1; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CachingEntryRenderer.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/cache/CachingEntryRenderer.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CachingEntryRenderer.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/cache/CachingEntryRenderer.java index 78ae8e365..f29d78bdc 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/CachingEntryRenderer.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/cache/CachingEntryRenderer.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.entrylist; +package me.shedaniel.rei.impl.client.gui.overlay.entries.cache; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; @@ -32,7 +32,6 @@ import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.client.gui.widget.CachedEntryListRender; import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.MultiBufferSource; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/PaginatedEntryListWidget.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/paginated/PaginatedEntryListWidget.java similarity index 76% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/PaginatedEntryListWidget.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/paginated/PaginatedEntryListWidget.java index fb7c864c5..12516999d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/PaginatedEntryListWidget.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/paginated/PaginatedEntryListWidget.java @@ -21,8 +21,9 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.entrylist; +package me.shedaniel.rei.impl.client.gui.overlay.entries.paginated; +import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; @@ -31,32 +32,25 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; -import me.shedaniel.rei.api.client.gui.widgets.Button; -import me.shedaniel.rei.api.client.gui.widgets.Widget; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.gui.widgets.*; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.util.ClientEntryStacks; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.ClientHelperImpl; import me.shedaniel.rei.impl.client.gui.InternalTextures; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.changelog.ChangelogLoader; -import me.shedaniel.rei.impl.client.gui.widget.BatchedEntryRendererManager; -import me.shedaniel.rei.impl.client.gui.widget.CachedEntryListRender; -import me.shedaniel.rei.impl.client.gui.widget.DefaultDisplayChoosePageWidget; -import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; -import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack; -import net.minecraft.ChatFormatting; +import me.shedaniel.rei.impl.client.gui.overlay.entries.CollapsedStack; +import me.shedaniel.rei.impl.client.gui.overlay.entries.CollapsingEntryListWidget; +import me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListStackEntry; +import me.shedaniel.rei.impl.client.gui.overlay.entries.cache.CachedEntryListRender; +import me.shedaniel.rei.impl.client.gui.overlay.entries.cache.CachingEntryRenderer; import net.minecraft.client.gui.chat.NarratorChatListener; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.util.Mth; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; +import java.time.LocalDateTime; +import java.util.*; import java.util.stream.Stream; public class PaginatedEntryListWidget extends CollapsingEntryListWidget { @@ -87,29 +81,45 @@ protected void renderEntries(boolean fastEntryRendering, PoseStack matrices, int } if (entry.our == null) { - CachedEntryListRender.Sprite sprite = CachedEntryListRender.get(entry.getCurrentEntry()); + CachedEntryListRender.Sprite sprite = CachedEntryListRender.get(entry.slot.getCurrentEntry()); if (sprite != null) { CachingEntryRenderer renderer = new CachingEntryRenderer(sprite, this::getBlitOffset); - entry.our = ClientEntryStacks.setRenderer(entry.getCurrentEntry().copy().cast(), stack -> renderer); + entry.our = ClientEntryStacks.setRenderer(entry.slot.getCurrentEntry().copy().cast(), stack -> renderer); } } } } - BatchedEntryRendererManager manager = new BatchedEntryRendererManager(); - if (manager.isFastEntryRendering()) { + BatchedSlots slots = Widgets.createBatchedSlots(); + if (slots.isBatched()) { for (EntryListStackEntry entry : entries) { CollapsedStack collapsedStack = entry.getCollapsedStack(); if (collapsedStack != null && !collapsedStack.isExpanded()) { - manager.addSlow(entry); + slots.addUnbatched(entry.slot); } else { - manager.add(entry); + slots.add(entry.slot); } } } else { - manager.addAllSlow(entries); + slots.addAllUnbatched(new AbstractCollection<>() { + @Override + public Iterator iterator() { + return Iterators.transform(entries.iterator(), entry -> entry.slot); + } + + @Override + public int size() { + return entries.size(); + } + }); + } + + for (EntryListStackEntry entry : entries) { + entry.extra.render(matrices, mouseX, mouseY, delta); } - manager.render(debugger.debugTime, debugger.size, debugger.time, matrices, mouseX, mouseY, delta); + + if (debugger.debugTime) slots.addDebugger(debugger.size, debugger.time); + slots.render(matrices, mouseX, mouseY, delta); for (Widget widget : additionalWidgets) { widget.render(matrices, mouseX, mouseY, delta); @@ -131,7 +141,7 @@ protected void updateEntries(int entrySize, boolean zoomed) { int slotX = currentX * entrySize + innerBounds.x; int slotY = currentY * entrySize + innerBounds.y; if (notSteppingOnExclusionZones(slotX - 1, slotY - 1, entrySize, entrySize)) { - entries.add((EntryListStackEntry) new EntryListStackEntry(this, slotX, slotY, entrySize, zoomed).noBackground()); + entries.add(EntryListStackEntry.createSlot(this, slotX, slotY, entrySize, zoomed)); } } } @@ -143,14 +153,17 @@ protected void updateEntries(int entrySize, boolean zoomed) { /*EntryStack | List>*/ Object stack = subList.get(i); EntryListStackEntry entry = entries.get(i + Math.max(0, -page * entries.size())); - entry.clearStacks(); + Slot slot = entry.slot; + slot.clearEntries(); if (stack instanceof EntryStack entryStack) { - entry.entry(entryStack); + slot.entry(entryStack); } else { - entry.entries((List>) stack); + slot.entries((List>) stack); } + entry.updateEntries(); + CollapsedStack collapsedStack = indexedCollapsedStack.get(i + skip); if (collapsedStack != null && collapsedStack.getIngredient().size() > 1) { entry.collapsed(collapsedStack); @@ -173,12 +186,22 @@ public void setStacks(List | List>*/ Object> stack @Override public Stream> getEntries() { - return entries.stream().map(EntryWidget::getCurrentEntry); + return entries.stream().map(entry -> entry.slot.getCurrentEntry()); } @Override - protected List getEntryWidgets() { - return entries; + protected List getSlots() { + return new AbstractList<>() { + @Override + public int size() { + return entries.size(); + } + + @Override + public Slot get(int index) { + return entries.get(index).slot; + } + }; } @Override @@ -187,7 +210,7 @@ public List children() { } @Override - public void init(ScreenOverlayImpl overlay) { + public void init(ScreenOverlay overlay) { Rectangle overlayBounds = overlay.getBounds(); this.additionalWidgets = new ArrayList<>(); this.leftButton = Widgets.createButton(new Rectangle(overlayBounds.x, overlayBounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TextComponent("")) @@ -210,15 +233,15 @@ public void init(ScreenOverlayImpl overlay) { matrices.popPose(); helper.setBlitOffset(helper.getBlitOffset() - 1); })); - this.changelogButton = Widgets.createButton(new Rectangle(overlayBounds.getMaxX() - 18 - 18, overlayBounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TextComponent("")) + /*this.changelogButton = Widgets.createButton(new Rectangle(overlayBounds.getMaxX() - 18 - 18, overlayBounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TextComponent("")) .onClick(button -> { ChangelogLoader.show(); }) .containsMousePredicate((button, point) -> button.getBounds().contains(point) && overlay.isNotInExclusionZones(point.x, point.y)) .tooltipLine(new TranslatableComponent("text.rei.changelog.title")) - .focusable(false); - this.additionalWidgets.add(changelogButton); - this.additionalWidgets.add(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { + .focusable(false);*/ + // this.additionalWidgets.add(changelogButton); + /*this.additionalWidgets.add(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { helper.setBlitOffset(helper.getBlitOffset() + 1); RenderSystem.setShaderTexture(0, InternalTextures.CHEST_GUI_TEXTURE); Rectangle bounds = changelogButton.getBounds(); @@ -227,7 +250,7 @@ public void init(ScreenOverlayImpl overlay) { helper.blit(matrices, bounds.x + 1, bounds.y + 2, !ChangelogLoader.hasVisited() ? 28 : 14, 0, 14, 14); matrices.popPose(); helper.setBlitOffset(helper.getBlitOffset() - 1); - })); + }));*/ this.rightButton = Widgets.createButton(new Rectangle(overlayBounds.getMaxX() - 18, overlayBounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TextComponent("")) .onClick(button -> { setPage(getPage() + 1); @@ -248,20 +271,13 @@ public void init(ScreenOverlayImpl overlay) { matrices.popPose(); helper.setBlitOffset(helper.getBlitOffset() - 1); })); - this.additionalWidgets.add(Widgets.createClickableLabel(new Point(overlayBounds.x + ((overlayBounds.width - 18) / 2), overlayBounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 10), NarratorChatListener.NO_TITLE, label -> { - if (!Screen.hasShiftDown()) { - setPage(0); - updateEntriesPosition(); - } else { - ScreenOverlayImpl.getInstance().choosePageWidget = new DefaultDisplayChoosePageWidget(page -> { - setPage(page); - updateEntriesPosition(); - }, getPage(), getTotalPages()); - } - }).tooltip(new TranslatableComponent("text.rei.go_back_first_page"), new TextComponent(" "), new TranslatableComponent("text.rei.shift_click_to", new TranslatableComponent("text.rei.choose_page")).withStyle(ChatFormatting.GRAY)).focusable(false).onRender((matrices, label) -> { + this.additionalWidgets.add(Widgets.createClickableLabel(new Point(overlayBounds.x + ((overlayBounds.width/* - 18*/) / 2), overlayBounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 10), NarratorChatListener.NO_TITLE, label -> { + setPage(0); + updateEntriesPosition(); + }).tooltip(new TranslatableComponent("text.rei.go_back_first_page")).focusable(false).onRender((matrices, label) -> { label.setClickable(getTotalPages() > 1); label.setMessage(new TextComponent(String.format("%s/%s", getPage() + 1, Math.max(getTotalPages(), 1)))); - }).rainbow(new Random().nextFloat() < 1.0E-4D || ClientHelperImpl.getInstance().isAprilFools.get())); + }).rainbow(new Random().nextFloat() < 1.0E-4D || (LocalDateTime.now().getMonthValue() == 4 && LocalDateTime.now().getDayOfMonth() == 1))); } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/ScrolledEntryListWidget.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/scrolled/ScrolledEntryListWidget.java similarity index 77% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/ScrolledEntryListWidget.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/scrolled/ScrolledEntryListWidget.java index fda8ec704..cda032b0d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/ScrolledEntryListWidget.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/scrolled/ScrolledEntryListWidget.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.entrylist; +package me.shedaniel.rei.impl.client.gui.overlay.entries.scrolled; import com.google.common.base.Predicates; import com.google.common.collect.Lists; @@ -31,19 +31,25 @@ import me.shedaniel.clothconfig2.api.ScissorsHandler; import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.widgets.BatchedSlots; +import me.shedaniel.rei.api.client.gui.widgets.Slot; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.client.gui.widget.BatchedEntryRendererManager; -import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; -import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack; +import me.shedaniel.rei.impl.client.gui.overlay.entries.CollapsedStack; +import me.shedaniel.rei.impl.client.gui.overlay.entries.CollapsingEntryListWidget; +import me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListStackEntry; import net.minecraft.client.gui.screens.Screen; import net.minecraft.util.Mth; +import java.util.AbstractList; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Stream; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; + public class ScrolledEntryListWidget extends CollapsingEntryListWidget { private List | EntryIngredient*/ Object> stacks = new ArrayList<>(); protected List entries = Collections.emptyList(); @@ -67,13 +73,14 @@ protected void renderEntries(boolean fastEntryRendering, PoseStack matrices, int int skip = Math.max(0, Mth.floor(scrolling.scrollAmount() / (float) entrySize())); int nextIndex = skip * innerBounds.width / entrySize(); this.blockedCount = 0; - BatchedEntryRendererManager helper = new BatchedEntryRendererManager(); + BatchedSlots slots = Widgets.createBatchedSlots(); Int2ObjectMap indexedCollapsedStack = getCollapsedStackIndexed(); int i = nextIndex; for (int cont = nextIndex; cont < entries.size(); cont++) { EntryListStackEntry entry = entries.get(cont); - Rectangle entryBounds = entry.getBounds(); + Slot slot = entry.slot; + Rectangle entryBounds = slot.getBounds(); entryBounds.y = entry.backupY - scrolling.scrollAmountInt(); if (entryBounds.y > this.bounds.getMaxY()) break; @@ -81,38 +88,43 @@ protected void renderEntries(boolean fastEntryRendering, PoseStack matrices, int if (notSteppingOnExclusionZones(entryBounds.x, entryBounds.y, entryBounds.width, entryBounds.height)) { /*EntryStack | List>*/ Object stack = stacks.get(i++); - entry.clearStacks(); + slot.clearEntries(); if (stack instanceof EntryStack entryStack) { if (!entryStack.isEmpty()) { - entry.entry(entryStack); - helper.add(entry); + slot.entry(entryStack); + slots.add(slot); } } else { List> ingredient = (List>) stack; if (!ingredient.isEmpty()) { - entry.entries(ingredient); - helper.addSlow(entry); + slot.entries(ingredient); + slots.addUnbatched(slot); } } + entry.updateEntries(); + CollapsedStack collapsedStack = indexedCollapsedStack.get(i - 1); if (collapsedStack != null && collapsedStack.getIngredient().size() > 1) { entry.collapsed(collapsedStack); } else { entry.collapsed(null); } + + entry.extra.render(matrices, mouseX, mouseY, delta); } else { blockedCount++; } } - helper.render(debugger.debugTime, debugger.size, debugger.time, matrices, mouseX, mouseY, delta); + if (debugger.debugTime) slots.addDebugger(debugger.size, debugger.time); + slots.render(matrices, mouseX, mouseY, delta); scrolling.updatePosition(delta); ScissorsHandler.INSTANCE.removeLastScissor(); if (scrolling.getMaxScroll() > 0) { - scrolling.renderScrollBar(0, 1, REIRuntime.getInstance().isDarkThemeEnabled() ? 0.8f : 1f); + scrolling.renderScrollBar(0, 1, ConfigObject.getInstance().isUsingDarkTheme() ? 0.8f : 1f); } } @@ -127,7 +139,7 @@ protected void updateEntries(int entrySize, boolean zoomed) { for (int i = 0; i < slotsToPrepare; i++) { int xPos = currentX * entrySize + innerBounds.x; int yPos = currentY * entrySize + innerBounds.y; - entries.add((EntryListStackEntry) new EntryListStackEntry(this, xPos, yPos, entrySize, zoomed).noBackground()); + entries.add(EntryListStackEntry.createSlot(this, xPos, yPos, entrySize, zoomed)); currentX++; if (currentX >= width) { currentX = 0; @@ -178,13 +190,23 @@ public Stream> getEntries() { int nextIndex = skip * innerBounds.width / entrySize(); return (Stream>) (Stream>) entries.stream() .skip(nextIndex) - .filter(entry -> entry.getBounds().y <= this.bounds.getMaxY()) - .map(EntryWidget::getCurrentEntry) + .filter(entry -> entry.slot.getBounds().y <= this.bounds.getMaxY()) + .map(entry -> entry.slot.getCurrentEntry()) .filter(Predicates.not(EntryStack::isEmpty)); } @Override - protected List getEntryWidgets() { - return entries; + protected List getSlots() { + return new AbstractList<>() { + @Override + public int size() { + return entries.size(); + } + + @Override + public Slot get(int index) { + return entries.get(index).slot; + } + }; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/ConfigButtonWidget.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidgetProvider.java similarity index 76% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/ConfigButtonWidget.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidgetProvider.java index 5ce1e3270..032b76d46 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/ConfigButtonWidget.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ConfigButtonWidgetProvider.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.overlay.widgets; import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.RenderSystem; @@ -30,21 +30,21 @@ import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.api.client.gui.config.AppearanceTheme; import me.shedaniel.rei.api.client.gui.config.DisplayPanelLocation; import me.shedaniel.rei.api.client.gui.config.SyntaxHighlightingMode; import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; import me.shedaniel.rei.api.client.gui.widgets.Button; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.Widgets; -import me.shedaniel.rei.impl.client.ClientHelperImpl; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; -import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import me.shedaniel.rei.impl.client.gui.InternalTextures; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.modules.MenuAccess; -import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; -import me.shedaniel.rei.impl.client.gui.modules.entries.*; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.chat.NarratorChatListener; import net.minecraft.client.gui.screens.Screen; @@ -54,12 +54,16 @@ import java.util.List; import java.util.UUID; -public class ConfigButtonWidget { +public class ConfigButtonWidgetProvider implements OverlayWidgetProvider { private static final UUID CONFIG_MENU_UUID = UUID.fromString("4357bc36-0a4e-47d2-8e07-ddc220df4a0f"); - public static Widget create(ScreenOverlayImpl overlay) { + @Override + public void provide(ScreenOverlay overlay, MenuAccess access, WidgetSink sink) { + sink.acceptLateRendered(create(overlay, access)); + } + + public static Widget create(ScreenOverlay overlay, MenuAccess access) { Rectangle bounds = getConfigButtonBounds(); - MenuAccess access = overlay.menuAccess(); Button configButton = Widgets.createButton(bounds, NarratorChatListener.NO_TITLE) .onClick(button -> { if (Screen.hasShiftDown() || Screen.hasControlDown()) { @@ -69,13 +73,13 @@ public static Widget create(ScreenOverlayImpl overlay) { ConfigManager.getInstance().openConfigScreen(REIRuntime.getInstance().getPreviousScreen()); }) .onRender((matrices, button) -> { - if (ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen) && ClientHelperImpl.getInstance().hasOperatorPermission()) { - button.setTint(ClientHelperImpl.getInstance().hasPermissionToUsePackets() ? 721354752 : 1476440063); + if (ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen) && NetworkingHelper.getInstance().client().hasOperatorPermission()) { + button.setTint(NetworkingHelper.getInstance().canUse(NetworkModule.CHEAT_GIVE) ? 721354752 : 1476440063); } else { button.removeTint(); } - access.openOrClose(CONFIG_MENU_UUID, button.getBounds(), ConfigButtonWidget::menuEntries); + access.openOrClose(CONFIG_MENU_UUID, button.getBounds(), ConfigButtonWidgetProvider::menuEntries); }) .focusable(false) .containsMousePredicate((button, point) -> button.getBounds().contains(point) && overlay.isNotInExclusionZones(point.x, point.y)); @@ -85,11 +89,12 @@ public static Widget create(ScreenOverlayImpl overlay) { helper.blit(matrices, bounds.x + 3, bounds.y + 3, 0, 0, 14, 14); helper.setBlitOffset(helper.getBlitOffset() - 1); }); - return InternalWidgets.wrapLateRenderable(Widgets.concat(configButton, overlayWidget)); + return Widgets.concat(configButton, overlayWidget); } - private static Collection menuEntries() { - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); + private static Collection menuEntries() { + ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); + ConfigObject config = ConfigObject.getInstance(); return List.of( ToggleMenuEntry.of(new TranslatableComponent("text.rei.cheating"), config::isCheating, @@ -99,11 +104,11 @@ private static Collection menuEntries() { new TextMenuEntry(() -> { if (!ClientHelper.getInstance().isCheating()) return new TranslatableComponent("text.rei.cheating_disabled"); - else if (!ClientHelperImpl.getInstance().hasOperatorPermission()) { + else if (!NetworkingHelper.getInstance().client().hasOperatorPermission()) { if (Minecraft.getInstance().gameMode.hasInfiniteItems()) return new TranslatableComponent("text.rei.cheating_limited_creative_enabled"); else return new TranslatableComponent("text.rei.cheating_enabled_no_perms"); - } else if (ClientHelperImpl.getInstance().hasPermissionToUsePackets()) + } else if (NetworkingHelper.getInstance().canUse(NetworkModule.CHEAT_GIVE)) return new TranslatableComponent("text.rei.cheating_enabled"); else return new TranslatableComponent("text.rei.cheating_limited_enabled"); @@ -112,19 +117,19 @@ else if (!ClientHelperImpl.getInstance().hasOperatorPermission()) { ToggleMenuEntry.ofDeciding(new TranslatableComponent("text.rei.config.menu.dark_theme"), config::isUsingDarkTheme, dark -> { - config.setUsingDarkTheme(dark); + manager.set("appearance.theme", dark ? AppearanceTheme.DARK : AppearanceTheme.LIGHT); return false; } ), ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.craftable_filter"), config::isCraftableFilterEnabled, - config::setCraftableFilterEnabled + bool -> manager.set("appearance.layout.showCraftableOnlyButton", bool) ), new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.display"), List.of( ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.remove_recipe_book"), config::doesDisableRecipeBook, disableRecipeBook -> { - config.setDisableRecipeBook(disableRecipeBook); + manager.set("functionality.disableRecipeBook", disableRecipeBook); Screen screen = Minecraft.getInstance().screen; if (screen != null) { @@ -135,7 +140,7 @@ else if (!ClientHelperImpl.getInstance().hasOperatorPermission()) { ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.left_side_mob_effects"), config::isLeftSideMobEffects, disableRecipeBook -> { - config.setLeftSideMobEffects(disableRecipeBook); + manager.set("functionality.leftSideMobEffects", disableRecipeBook); Screen screen = Minecraft.getInstance().screen; if (screen != null) { @@ -145,21 +150,21 @@ else if (!ClientHelperImpl.getInstance().hasOperatorPermission()) { ), ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.left_side_panel"), config::isLeftHandSidePanel, - bool -> config.setDisplayPanelLocation(bool ? DisplayPanelLocation.LEFT : DisplayPanelLocation.RIGHT) + bool -> manager.set("advanced.accessibility.displayPanelLocation", bool ? DisplayPanelLocation.LEFT : DisplayPanelLocation.RIGHT) ), ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.scrolling_side_panel"), config::isEntryListWidgetScrolled, - config::setEntryListWidgetScrolled + bool -> manager.set("appearance.scrollingEntryListWidget", bool) ), new SeparatorMenuEntry(), ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.caching_entry_rendering"), config::doesCacheEntryRendering, - config::setDoesCacheEntryRendering + bool -> manager.set("advanced.miscellaneous.cachingFastEntryRendering", bool) ), new SeparatorMenuEntry(), ToggleMenuEntry.of(new TranslatableComponent("text.rei.config.menu.display.syntax_highlighting"), () -> config.getSyntaxHighlightingMode() == SyntaxHighlightingMode.COLORFUL || config.getSyntaxHighlightingMode() == SyntaxHighlightingMode.COLORFUL_UNDERSCORED, - bool -> config.setSyntaxHighlightingMode(bool ? SyntaxHighlightingMode.COLORFUL : SyntaxHighlightingMode.PLAIN_UNDERSCORED) + bool -> manager.set("appearance.syntaxHighlightingMode", bool ? SyntaxHighlightingMode.COLORFUL : SyntaxHighlightingMode.PLAIN_UNDERSCORED) ) )), new SeparatorMenuEntry(), @@ -174,7 +179,7 @@ else if (!ClientHelperImpl.getInstance().hasOperatorPermission()) { private static Rectangle getConfigButtonBounds() { if (ConfigObject.getInstance().isLowerConfigButton()) { - Rectangle area = REIRuntimeImpl.getSearchField().getBounds().clone(); + Rectangle area = REIRuntime.getInstance().getSearchTextField().asWidget().getBounds().clone(); area.setLocation(area.x + area.width + (ConfigObject.getInstance().isCraftableFilterEnabled() ? 26 : 4), area.y - 1); area.setSize(20, 20); return area; diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidgetProvider.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidgetProvider.java new file mode 100644 index 000000000..121c0e964 --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/CraftableFilterButtonWidgetProvider.java @@ -0,0 +1,138 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.widgets; + +import com.mojang.math.Vector4f; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; +import me.shedaniel.rei.api.client.gui.widgets.Button; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.overlay.OverlayListWidget; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.SeparatorMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.SubMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.ToggleMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.provider.OverlayMenuEntryProvider; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.chat.NarratorChatListener; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Blocks; + +import java.util.*; + +public class CraftableFilterButtonWidgetProvider implements OverlayWidgetProvider { + public static final UUID FILTER_MENU_UUID = UUID.fromString("2839e998-1679-4f9e-a257-37411d16f1e6"); + + @Override + public void provide(ScreenOverlay overlay, MenuAccess access, WidgetSink sink) { + if (ConfigObject.getInstance().isCraftableFilterEnabled()) { + sink.acceptLateRendered(create(overlay, access)); + } + } + + private static Widget create(ScreenOverlay overlay, MenuAccess access) { + Rectangle bounds = getCraftableFilterBounds(); + ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); + ItemStack icon = new ItemStack(Blocks.CRAFTING_TABLE); + Button filterButton = Widgets.createButton(bounds, NarratorChatListener.NO_TITLE) + .focusable(false) + .onClick(button -> { + ConfigManager.getInstance().toggleCraftableOnly(); + REIRuntime.getInstance().getOverlay().map(ScreenOverlay::getEntryList).ifPresent(OverlayListWidget::queueReloadSearch); + }) + .onRender((matrices, button) -> { + button.setTint(ConfigManager.getInstance().isCraftableOnlyEnabled() ? 0x3800d907 : 0x38ff0000); + + access.openOrClose(FILTER_MENU_UUID, button.getBounds(), CraftableFilterButtonWidgetProvider::menuEntries); + }) + .containsMousePredicate((button, point) -> button.getBounds().contains(point) && overlay.isNotInExclusionZones(point.x, point.y)) + .tooltipLineSupplier(button -> new TranslatableComponent(ConfigManager.getInstance().isCraftableOnlyEnabled() ? "text.rei.showing_craftable" : "text.rei.showing_all")); + Widget overlayWidget = Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { + Vector4f vector = new Vector4f(bounds.x + 2, bounds.y + 2, helper.getBlitOffset() - 10, 1.0F); + vector.transform(matrices.last().pose()); + itemRenderer.blitOffset = vector.z(); + itemRenderer.renderGuiItem(icon, (int) vector.x(), (int) vector.y()); + itemRenderer.blitOffset = 0.0F; + }); + return Widgets.concat(filterButton, overlayWidget); + } + + private static Collection menuEntries() { + ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); + ConfigObject config = ConfigObject.getInstance(); + ArrayList entries = new ArrayList<>(List.of( + new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.search_field.position"), Arrays.stream(SearchFieldLocation.values()) + .map(location -> ToggleMenuEntry.of(new TextComponent(location.toString()), + () -> config.getSearchFieldLocation() == location, + bool -> manager.set("appearance.layout.searchFieldLocation", location)) + .withActive(() -> config.getSearchFieldLocation() != location) + ) + .toList()) + )); + + List> additionalEntries = new ArrayList<>(); + + for (OverlayMenuEntryProvider provider : OverlayMenuEntryProvider.PROVIDERS) { + List provided = provider.provide(OverlayMenuEntryProvider.Type.CRAFTABLE_FILTER); + + if (provided != null && !provided.isEmpty()) { + additionalEntries.add(provided); + } + } + + for (List additionalEntryList : additionalEntries) { + if (additionalEntryList.size() > 1) { + entries.add(new SeparatorMenuEntry()); + entries.addAll(additionalEntryList); + } + } + + List singleEntries = CollectionUtils.flatMap(CollectionUtils.filterToList(additionalEntries, list -> list.size() == 1), list -> list); + + if (!singleEntries.isEmpty()) { + entries.add(new SeparatorMenuEntry()); + entries.addAll(singleEntries); + } + + return entries; + } + + private static Rectangle getCraftableFilterBounds() { + Rectangle area = REIRuntime.getInstance().getSearchTextField().asWidget().getBounds().clone(); + area.setLocation(area.x + area.width + 4, area.y - 1); + area.setSize(20, 20); + return area; + } +} diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/SearchFieldWidgetProvider.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/SearchFieldWidgetProvider.java new file mode 100644 index 000000000..c1197074e --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/SearchFieldWidgetProvider.java @@ -0,0 +1,74 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.widgets; + +import com.mojang.blaze3d.platform.Window; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchField; +import net.minecraft.client.Minecraft; + +public class SearchFieldWidgetProvider implements OverlayWidgetProvider { + private OverlaySearchField searchField; + + @Override + public void provide(ScreenOverlay overlay, MenuAccess access, WidgetSink sink) { + if (searchField == null) { + searchField = new OverlaySearchField(access); + } + + searchField.getBounds().setBounds(getSearchFieldArea(overlay)); + sink.acceptTextField(searchField, searchField::isHighlighting); + } + + private Rectangle getSearchFieldArea(ScreenOverlay overlay) { + int widthRemoved = 1; + if (ConfigObject.getInstance().isCraftableFilterEnabled()) widthRemoved += 22; + if (ConfigObject.getInstance().isLowerConfigButton()) widthRemoved += 22; + return switch (REIRuntime.getInstance().getContextualSearchFieldLocation()) { + case TOP_SIDE -> getTopSideSearchFieldArea(overlay, widthRemoved); + case BOTTOM_SIDE -> getBottomSideSearchFieldArea(overlay, widthRemoved); + case CENTER -> getCenterSearchFieldArea(overlay, widthRemoved); + }; + } + + private Rectangle getTopSideSearchFieldArea(ScreenOverlay overlay, int widthRemoved) { + return new Rectangle(overlay.getBounds().x + 2, 4, overlay.getBounds().width - 6 - widthRemoved, 18); + } + + private Rectangle getBottomSideSearchFieldArea(ScreenOverlay overlay, int widthRemoved) { + Window window = Minecraft.getInstance().getWindow(); + return new Rectangle(overlay.getBounds().x + 2, window.getGuiScaledHeight() - 22, overlay.getBounds().width - 6 - widthRemoved, 18); + } + + private Rectangle getCenterSearchFieldArea(ScreenOverlay overlay, int widthRemoved) { + Window window = Minecraft.getInstance().getWindow(); + Rectangle screenBounds = ScreenRegistry.getInstance().getScreenBounds(Minecraft.getInstance().screen); + return new Rectangle(screenBounds.x, window.getGuiScaledHeight() - 22, screenBounds.width - widthRemoved, 18); + } +} diff --git a/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/DelegateTextField.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/DelegateTextField.java new file mode 100644 index 000000000..d52764bff --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/DelegateTextField.java @@ -0,0 +1,182 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.widgets.search; + +import com.mojang.blaze3d.platform.InputConstants; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import me.shedaniel.rei.api.client.gui.widgets.TextField; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Function; + +public interface DelegateTextField extends TextField { + TextField delegateTextField(); + + @Override + default void setFocusedResponder(BooleanConsumer responder) { + delegateTextField().setFocusedResponder(responder); + } + + @Override + @Nullable + default String getSuggestion() { + return delegateTextField().getSuggestion(); + } + + @Override + default void setSuggestion(@Nullable String suggestion) { + delegateTextField().setSuggestion(suggestion); + } + + @Override + default void setBorderColorProvider(BorderColorProvider borderColorProvider) { + delegateTextField().setBorderColorProvider(borderColorProvider); + } + + @Override + default void setFormatter(TextFormatter formatter) { + delegateTextField().setFormatter(formatter); + } + + @Override + default TextFormatter getFormatter() { + return delegateTextField().getFormatter(); + } + + @Override + default void setSuggestionRenderer(SuggestionRenderer renderer) { + delegateTextField().setSuggestionRenderer(renderer); + } + + @Override + default SuggestionRenderer getSuggestionRenderer() { + return delegateTextField().getSuggestionRenderer(); + } + + @Override + default void setTextTransformer(Function textTransformer) { + delegateTextField().setTextTransformer(textTransformer); + } + + @Override + default void setResponder(Consumer responder) { + delegateTextField().setResponder(responder); + } + + @Override + default String getText() { + return delegateTextField().getText(); + } + + @Override + default void setText(String text) { + delegateTextField().setText(text); + } + + @Override + default String getSelectedText() { + return delegateTextField().getSelectedText(); + } + + @Override + default void addText(String text) { + delegateTextField().addText(text); + } + + @Override + default void moveCursorTo(int cursor) { + delegateTextField().moveCursorTo(cursor); + } + + @Override + default void moveCursorToStart() { + delegateTextField().moveCursorToStart(); + } + + @Override + default void moveCursorToEnd() { + delegateTextField().moveCursorToEnd(); + } + + @Override + default int getMaxLength() { + return delegateTextField().getMaxLength(); + } + + @Override + default void setMaxLength(int maxLength) { + delegateTextField().setMaxLength(maxLength); + } + + @Override + default int getCursor() { + return delegateTextField().getCursor(); + } + + @Override + default void setCursorPosition(int cursor) { + delegateTextField().setCursorPosition(cursor); + } + + @Override + default boolean hasBorder() { + return delegateTextField().hasBorder(); + } + + @Override + default void setHasBorder(boolean hasBorder) { + delegateTextField().setHasBorder(hasBorder); + } + + @Override + default void setEditableColor(int editableColor) { + delegateTextField().setEditableColor(editableColor); + } + + @Override + default void setNotEditableColor(int notEditableColor) { + delegateTextField().setNotEditableColor(notEditableColor); + } + + @Override + default boolean isFocused() { + return delegateTextField().isFocused(); + } + + @Override + default void setFocused(boolean focused) { + delegateTextField().setFocused(focused); + } + + @Override + default void setFocusedFromKey(boolean focused, InputConstants.Key key) { + delegateTextField().setFocusedFromKey(focused, key); + } + + @Override + default void tick() { + delegateTextField().tick(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchField.java similarity index 66% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchField.java index 4168b1916..8428270d6 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchField.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchField.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.search; +package me.shedaniel.rei.impl.client.gui.overlay.widgets.search; import com.google.common.collect.Lists; import com.mojang.blaze3d.platform.InputConstants; @@ -38,19 +38,20 @@ import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.SyntaxHighlightingMode; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.gui.widgets.*; +import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; +import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.gui.hints.HintProvider; -import me.shedaniel.rei.impl.client.gui.text.TextTransformations; -import me.shedaniel.rei.impl.client.gui.widget.basewidgets.TextFieldWidget; -import me.shedaniel.rei.impl.client.search.argument.type.ArgumentType; -import me.shedaniel.rei.impl.client.search.argument.type.ArgumentTypesRegistry; -import me.shedaniel.rei.impl.client.search.argument.type.TextArgumentType; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchFieldSyntaxHighlighter.HighlightInfo; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchFieldSyntaxHighlighter.PartHighlightInfo; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchFieldSyntaxHighlighter.QuoteHighlightInfo; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.search.OverlaySearchFieldSyntaxHighlighter.SplitterHighlightInfo; +import me.shedaniel.rei.impl.client.util.TextTransformations; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.resources.language.I18n; import net.minecraft.client.resources.sounds.SimpleSoundInstance; @@ -60,6 +61,7 @@ import net.minecraft.sounds.SoundEvents; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Tuple; +import net.minecraft.world.inventory.Slot; import org.jetbrains.annotations.ApiStatus; import org.lwjgl.glfw.GLFW; @@ -68,14 +70,17 @@ import java.util.OptionalDouble; import java.util.function.Consumer; +@SuppressWarnings("UnstableApiUsage") @ApiStatus.Internal -public class OverlaySearchField extends TextFieldWidget implements TextFieldWidget.TextFormatter { - public static boolean isHighlighting = false; +public class OverlaySearchField extends DelegateWidget implements DelegateTextField, TextField.TextFormatter, TextField.SuggestionRenderer, TextField.BorderColorProvider { private static final Style SPLITTER_STYLE = Style.EMPTY.withColor(ChatFormatting.GRAY); private static final Style QUOTES_STYLE = Style.EMPTY.withColor(ChatFormatting.GOLD); private static final Style ERROR_STYLE = Style.EMPTY.withColor(TextColor.fromRgb(0xff5555)); + private boolean isHighlighting = false; + private final TextField textField; + private final MenuAccess access; private boolean previouslyClicking = false; - private final OverlaySearchFieldSyntaxHighlighter highlighter = new OverlaySearchFieldSyntaxHighlighter(getText()); + private final OverlaySearchFieldSyntaxHighlighter highlighter; public long keybindFocusTime = -1; public int keybindFocusKey = -1; public boolean isMain = true; @@ -83,56 +88,64 @@ public class OverlaySearchField extends TextFieldWidget implements TextFieldWidg private List history = Lists.newArrayListWithCapacity(100); private final NumberAnimator progress = ValueAnimator.ofDouble(); - public OverlaySearchField(int x, int y, int width, int height) { - super(x, y, width, height); - setMaxLength(10000); - setFormatter(this); - super.setResponder(highlighter); + public OverlaySearchField(MenuAccess access) { + super(Widgets.noOp()); + this.access = access; + this.textField = Widgets.createTextField(new Rectangle()); + this.textField.setMaxLength(1000); + this.textField.setFormatter(this); + this.textField.setSuggestionRenderer(this); + this.textField.setFocusedResponder(this::focused); + this.textField.setBorderColorProvider(this); + this.highlighter = new OverlaySearchFieldSyntaxHighlighter(textField.getText()); + this.textField.setResponder(highlighter); } @Override - public FormattedCharSequence format(TextFieldWidget widget, String text, int index) { + protected Widget delegate() { + return this.textField.asWidget(); + } + + @Override + public TextField delegateTextField() { + return this.textField; + } + + @Override + public FormattedCharSequence format(String text, int index) { boolean isPlain = ConfigObject.getInstance().getSyntaxHighlightingMode() == SyntaxHighlightingMode.PLAIN || ConfigObject.getInstance().getSyntaxHighlightingMode() == SyntaxHighlightingMode.PLAIN_UNDERSCORED; boolean hasUnderscore = ConfigObject.getInstance().getSyntaxHighlightingMode() == SyntaxHighlightingMode.PLAIN_UNDERSCORED || ConfigObject.getInstance().getSyntaxHighlightingMode() == SyntaxHighlightingMode.COLORFUL_UNDERSCORED; return TextTransformations.forwardWithTransformation(text, (s, charIndex, c) -> { - byte arg = highlighter.highlighted[charIndex + index]; + HighlightInfo arg = highlighter.highlighted[charIndex + index]; Style style = Style.EMPTY; - if (isMain && ScreenOverlayImpl.getEntryListWidget().isEmpty() && !getText().isEmpty()) { + if (isMain && REIRuntime.getInstance().getOverlay().get().getEntryList().getEntries().findAny().isEmpty() && !textField.getText().isEmpty()) { style = ERROR_STYLE; } - if (arg > 0) { - ArgumentType argumentType = ArgumentTypesRegistry.ARGUMENT_TYPE_LIST.get((arg - 1) / 2); + if (arg instanceof PartHighlightInfo part) { if (!isPlain) { - style = argumentType.getHighlightedStyle(); + style = part.style(); } - if (!(argumentType instanceof TextArgumentType) && hasUnderscore && arg % 2 == 1) { + if (part.style() != Style.EMPTY && hasUnderscore && part.grammar()) { style = style.withUnderlined(true); } } else if (!isPlain) { - if (arg == -1) { + if (arg == SplitterHighlightInfo.INSTANCE) { style = SPLITTER_STYLE; - } else if (arg == -2) { + } else if (arg == QuoteHighlightInfo.INSTANCE) { style = QUOTES_STYLE; } } - if (containsMouse(PointHelper.ofMouse()) || isFocused()) { + if (containsMouse(PointHelper.ofMouse()) || textField.isFocused()) { return style; } return style.withColor(TextColor.fromRgb(Color.ofOpaque(style.getColor() == null ? -1 : style.getColor().getValue()).brighter(0.75).getColor())); }); } - @Override - public void setResponder(Consumer responder) { - super.setResponder(highlighter.andThen(responder)); - } - - @Override - public void setFocused(boolean focused) { - if (isFocused() != focused && isMain) - addToHistory(getText()); - super.setFocused(focused); + public void focused(boolean focused) { + if (textField.isFocused() != focused && isMain) + addToHistory(textField.getText()); } @ApiStatus.Internal @@ -145,15 +158,6 @@ public void addToHistory(String text) { } } - public void laterRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - progress.update(delta); - RenderSystem.disableDepthTest(); - if (isMain) drawHint(matrices, mouseX, mouseY); - setSuggestion(!isFocused() && getText().isEmpty() ? I18n.get("text.rei.search.field.suggestion") : null); - super.render(matrices, mouseX, mouseY, delta); - RenderSystem.enableDepthTest(); - } - private void drawHint(PoseStack poses, int mouseX, int mouseY) { boolean mouseDown = GLFW.glfwGetMouseButton(Minecraft.getInstance().getWindow().getWindow(), GLFW.GLFW_MOUSE_BUTTON_LEFT) != 0; boolean clicking = false; @@ -162,7 +166,7 @@ private void drawHint(PoseStack poses, int mouseX, int mouseY) { clicking = mouseDown; } - List hintProviders = REIRuntimeImpl.getInstance().getHintProviders(); + List hintProviders = HintProvider.PROVIDERS; List> hints = CollectionUtils.flatMap(hintProviders, provider -> CollectionUtils.map(provider.provide(), component -> new Pair<>(provider, component))); if (hints.isEmpty()) return; @@ -172,7 +176,7 @@ private void drawHint(PoseStack poses, int mouseX, int mouseY) { OptionalDouble progress = hintProviders.stream().map(HintProvider::getProgress).filter(Objects::nonNull).mapToDouble(Double::doubleValue) .average(); List buttons = hints.stream().map(Pair::getFirst).distinct() - .map(HintProvider::getButtons) + .map(provider -> provider.getButtons(access)) .flatMap(List::stream) .toList(); boolean hasProgress = progress.isPresent(); @@ -227,8 +231,8 @@ private void drawHint(PoseStack poses, int mouseX, int mouseY) { if (new Rectangle(x + 3, y + 3 + font.lineHeight * i, lineWidth, font.lineHeight).contains(mouseX, mouseY)) { Tooltip tooltip = pair.getFirst().provideTooltip(new Point(mouseX, mouseY)); if (tooltip != null) { - ScreenOverlayImpl.getInstance().clearTooltips(); - ScreenOverlayImpl.getInstance().renderTooltip(poses, tooltip); + REIRuntime.getInstance().clearTooltips(); + REIRuntime.getInstance().getOverlay().get().renderTooltip(poses, tooltip); } } } @@ -254,34 +258,28 @@ private void drawHint(PoseStack poses, int mouseX, int mouseY) { } @Override - protected void renderSuggestion(PoseStack matrices, int x, int y) { + public void renderSuggestion(PoseStack matrices, int x, int y, int color) { matrices.pushPose(); matrices.translate(0, 0, 400); - int color; - if (containsMouse(PointHelper.ofMouse()) || isFocused()) { + if (containsMouse(PointHelper.ofMouse()) || textField.isFocused()) { color = 0xddeaeaea; } else { color = -6250336; } - this.font.drawShadow(matrices, this.font.plainSubstrByWidth(this.getSuggestion(), this.getWidth()), x, y, color); + this.font.drawShadow(matrices, this.font.plainSubstrByWidth(textField.getSuggestion(), textField.asWidget().getBounds().getWidth()), x, y, color); matrices.popPose(); } @Override - public void renderBorder(PoseStack matrices) { + public int getBorderColor(TextField textField) { isHighlighting = isHighlighting && ConfigObject.getInstance().isInventoryHighlightingAllowed(); - int borderColor; if (isMain && isHighlighting) { - borderColor = 0xfff2ff0c; - } else if (isMain && ScreenOverlayImpl.getEntryListWidget().isEmpty() && !getText().isEmpty()) { - borderColor = 0xffff5555; + return 0xfff2ff0c; + } else if (isMain && REIRuntime.getInstance().getOverlay().get().getEntryList().getEntries().findAny().isEmpty() && !textField.getText().isEmpty()) { + return 0xffff5555; } else { - super.renderBorder(matrices); - return; + return TextField.BorderColorProvider.DEFAULT.getBorderColor(textField); } - fill(matrices, this.getBounds().x - 1, this.getBounds().y - 1, this.getBounds().x + this.getBounds().width + 1, this.getBounds().y + this.getBounds().height + 1, 0xff000000); - fill(matrices, this.getBounds().x, this.getBounds().y, this.getBounds().x + this.getBounds().width, this.getBounds().y + this.getBounds().height, borderColor); - fill(matrices, this.getBounds().x + 1, this.getBounds().y + 1, this.getBounds().x + this.getBounds().width - 1, this.getBounds().y + this.getBounds().height - 1, 0xff000000); } public int getManhattanDistance(Point point1, Point point2) { @@ -293,8 +291,8 @@ public int getManhattanDistance(Point point1, Point point2) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { boolean contains = containsMouse(mouseX, mouseY); - if (isVisible() && contains && button == 1) - setText(""); + if (contains && button == 1) + textField.setText(""); if (contains && button == 0 && isMain && ConfigObject.getInstance().isInventoryHighlightingAllowed()) if (lastClickedDetails == null) lastClickedDetails = new Tuple<>(System.currentTimeMillis(), new Point(mouseX, mouseY)); @@ -312,27 +310,27 @@ else if (getManhattanDistance(lastClickedDetails.getB(), new Point(mouseX, mouse @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (this.isVisible() && this.isFocused() && isMain) + if (textField.isFocused() && isMain) if (keyCode == 257 || keyCode == 335) { - addToHistory(getText()); + addToHistory(textField.getText()); setFocused(false); return true; } else if (keyCode == 265) { - int i = history.indexOf(getText()) - 1; - if (i < -1 && getText().isEmpty()) + int i = history.indexOf(textField.getText()) - 1; + if (i < -1 && textField.getText().isEmpty()) i = history.size() - 1; else if (i < -1) { - addToHistory(getText()); + addToHistory(textField.getText()); i = history.size() - 2; } if (i >= 0) { - setText(history.get(i)); + textField.setText(history.get(i)); return true; } } else if (keyCode == 264) { - int i = history.indexOf(getText()) + 1; + int i = history.indexOf(textField.getText()) + 1; if (i > 0) { - setText(i < history.size() ? history.get(i) : ""); + textField.setText(i < history.size() ? history.get(i) : ""); return true; } } @@ -341,7 +339,7 @@ else if (i < -1) { @Override public boolean keyReleased(int keyCode, int scanCode, int modifiers) { - if (this.isVisible() && this.isFocused() && isMain && keybindFocusKey != -1) { + if (textField.isFocused() && isMain && keybindFocusKey != -1) { keybindFocusTime = -1; keybindFocusKey = -1; return true; @@ -359,6 +357,18 @@ public boolean charTyped(char character, int modifiers) { return super.charTyped(character, modifiers); } + @Override + public void setFocusedFromKey(boolean focused, InputConstants.Key key) { + DelegateTextField.super.setFocusedFromKey(focused, key); + if (focused && key.getType() == InputConstants.Type.KEYSYM) { + keybindFocusTime = System.currentTimeMillis(); + keybindFocusKey = key.getValue(); + } else { + keybindFocusTime = -1; + keybindFocusKey = -1; + } + } + @Override public boolean containsMouse(double mouseX, double mouseY) { return (!isMain || REIRuntime.getInstance().getOverlay().get().isNotInExclusionZones(mouseX, mouseY)) && super.containsMouse(mouseX, mouseY); @@ -366,5 +376,59 @@ public boolean containsMouse(double mouseX, double mouseY) { @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + progress.update(delta); + RenderSystem.disableDepthTest(); + if (isMain) drawHint(matrices, mouseX, mouseY); + textField.setSuggestion(!textField.isFocused() && textField.getText().isEmpty() ? I18n.get("text.rei.search.field.suggestion") : null); + super.render(matrices, mouseX, mouseY, delta); + RenderSystem.enableDepthTest(); + if (isMain && isHighlighting) { + renderEntryHighlighting(matrices); + } + } + + @Override + public void setResponder(Consumer responder) { + DelegateTextField.super.setResponder(highlighter.andThen(responder)); + } + + @Override + public WidgetWithBounds asWidget() { + return this; + } + + public static void renderEntryHighlighting(PoseStack matrices) { + RenderSystem.disableDepthTest(); + RenderSystem.colorMask(true, true, true, false); + SearchFilter filter = REIRuntime.getInstance().getOverlay().get().getCurrentSearchFilter(); + if (filter == null) return; + if (Minecraft.getInstance().screen instanceof AbstractContainerScreen containerScreen) { + int x = containerScreen.leftPos, y = containerScreen.topPos; + for (Slot slot : containerScreen.getMenu().slots) { + if (!slot.hasItem() || !filter.test(EntryStacks.of(slot.getItem()))) { + matrices.pushPose(); + matrices.translate(0, 0, 500f); + fillGradient(matrices, x + slot.x, y + slot.y, x + slot.x + 16, y + slot.y + 16, 0xdc202020, 0xdc202020, 0); + matrices.popPose(); + } else { + matrices.pushPose(); + matrices.translate(0, 0, 200f); + fillGradient(matrices, x + slot.x, y + slot.y, x + slot.x + 16, y + slot.y + 16, 0x345fff3b, 0x345fff3b, 0); + + fillGradient(matrices, x + slot.x - 1, y + slot.y - 1, x + slot.x, y + slot.y + 16 + 1, 0xff5fff3b, 0xff5fff3b, 0); + fillGradient(matrices, x + slot.x + 16, y + slot.y - 1, x + slot.x + 16 + 1, y + slot.y + 16 + 1, 0xff5fff3b, 0xff5fff3b, 0); + fillGradient(matrices, x + slot.x - 1, y + slot.y - 1, x + slot.x + 16, y + slot.y, 0xff5fff3b, 0xff5fff3b, 0); + fillGradient(matrices, x + slot.x - 1, y + slot.y + 16, x + slot.x + 16, y + slot.y + 16 + 1, 0xff5fff3b, 0xff5fff3b, 0); + + matrices.popPose(); + } + } + } + RenderSystem.colorMask(true, true, true, true); + RenderSystem.enableDepthTest(); + } + + public boolean isHighlighting() { + return isHighlighting; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchFieldSyntaxHighlighter.java b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchFieldSyntaxHighlighter.java similarity index 54% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchFieldSyntaxHighlighter.java rename to runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchFieldSyntaxHighlighter.java index 24e63c253..33fc128de 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchFieldSyntaxHighlighter.java +++ b/runtime-frontend/overlay-entries/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/search/OverlaySearchFieldSyntaxHighlighter.java @@ -21,11 +21,12 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.search; +package me.shedaniel.rei.impl.client.gui.overlay.widgets.search; -import me.shedaniel.rei.impl.client.search.IntRange; -import me.shedaniel.rei.impl.client.search.argument.Argument; -import me.shedaniel.rei.impl.client.search.argument.type.ArgumentTypesRegistry; +import it.unimi.dsi.fastutil.ints.IntIntPair; +import me.shedaniel.rei.api.client.search.SearchFilter; +import me.shedaniel.rei.api.client.search.SearchProvider; +import net.minecraft.network.chat.Style; import org.jetbrains.annotations.ApiStatus; import java.util.Collection; @@ -33,7 +34,7 @@ @ApiStatus.Internal public class OverlaySearchFieldSyntaxHighlighter implements Consumer { - public byte[] highlighted; + public HighlightInfo[] highlighted; public OverlaySearchFieldSyntaxHighlighter(String text) { this.accept(text); @@ -41,32 +42,46 @@ public OverlaySearchFieldSyntaxHighlighter(String text) { @Override public void accept(String text) { - this.highlighted = new byte[text.length()]; - Argument.bakeArguments(text, new Argument.ProcessedSink() { + this.highlighted = new HighlightInfo[text.length()]; + SearchProvider.getInstance().createFilter(text).processDecoration(new SearchFilter.ParseDecorationSink() { @Override public void addQuote(int index) { - highlighted[index] = -2; + highlighted[index] = QuoteHighlightInfo.INSTANCE; } @Override public void addSplitter(int index) { - highlighted[index] = -1; + highlighted[index] = SplitterHighlightInfo.INSTANCE; } @Override - public void addPart(Argument argument, boolean usingGrammar, Collection grammarRanges, int index) { + public void addPart(IntIntPair range, Style style, boolean usingGrammar, Collection grammarRanges, int index) { if (usingGrammar) { - int argIndex = ArgumentTypesRegistry.ARGUMENT_TYPE_LIST.indexOf(argument.getArgument()) * 2 + 1; - for (int i = argument.start(); i < argument.end(); i++) { - highlighted[i] = (byte) argIndex; + PartHighlightInfo base = new PartHighlightInfo(style, false); + PartHighlightInfo grammar = new PartHighlightInfo(style, true); + for (int i = range.leftInt(); i < range.rightInt(); i++) { + highlighted[i] = base; } - for (IntRange grammarRange : grammarRanges) { - for (int i = grammarRange.min(); i <= grammarRange.max(); i++) { - highlighted[i + index] = (byte) (argIndex + 1); + for (IntIntPair grammarRange : grammarRanges) { + for (int i = grammarRange.leftInt(); i <= grammarRange.rightInt(); i++) { + highlighted[i + index] = grammar; } } } } }); } + + public sealed interface HighlightInfo { + } + + public record PartHighlightInfo(Style style, boolean grammar) implements HighlightInfo {} + + public enum QuoteHighlightInfo implements HighlightInfo { + INSTANCE, + } + + public enum SplitterHighlightInfo implements HighlightInfo { + INSTANCE, + } } diff --git a/runtime-frontend/overlay-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListProvider b/runtime-frontend/overlay-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListProvider new file mode 100644 index 000000000..efb8be84a --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.overlay.entries.DefaultEntryListProvider \ No newline at end of file diff --git a/runtime-frontend/overlay-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.widgets.OverlayWidgetProvider b/runtime-frontend/overlay-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.widgets.OverlayWidgetProvider new file mode 100644 index 000000000..9d6ab17dd --- /dev/null +++ b/runtime-frontend/overlay-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.widgets.OverlayWidgetProvider @@ -0,0 +1,3 @@ +me.shedaniel.rei.impl.client.gui.overlay.widgets.ConfigButtonWidgetProvider +me.shedaniel.rei.impl.client.gui.overlay.widgets.CraftableFilterButtonWidgetProvider +me.shedaniel.rei.impl.client.gui.overlay.widgets.SearchFieldWidgetProvider \ No newline at end of file diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/AbstractScreenOverlay.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/AbstractScreenOverlay.java new file mode 100644 index 000000000..d1c3a5f22 --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/AbstractScreenOverlay.java @@ -0,0 +1,330 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.math.impl.PointHelper; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.gui.drag.DraggingContext; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProvider; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitor; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipQueue; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.registry.screen.ClickArea; +import me.shedaniel.rei.api.client.registry.screen.OverlayDecider; +import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.api.client.view.ViewSearchBuilder; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.client.gui.overlay.dragging.DraggingContextImpl; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.menu.MenuAccessImpl; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionResult; + +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractScreenOverlay extends ScreenOverlay { + private final List widgets = new ArrayList<>(); + private final DraggingContextImpl draggingContext = new DraggingContextImpl(); + private final MenuAccessImpl menuAccess = new MenuAccessImpl(); + private final Rectangle bounds = new Rectangle(); + private boolean shouldReload = false; + private boolean shouldReloadSearch = false; + + @Override + public void queueReloadOverlay() { + shouldReload = true; + } + + @Override + public void queueReloadSearch() { + shouldReloadSearch = true; + } + + @Override + public boolean isOverlayReloadQueued() { + return shouldReload; + } + + @Override + public boolean isSearchReloadQueued() { + return shouldReloadSearch || shouldReload; + } + + @Override + public DraggingContext getDraggingContext() { + return draggingContext; + } + + @Override + public List children() { + return widgets; + } + + @Override + public Rectangle getBounds() { + return bounds; + } + + protected boolean hasSpace() { + return !this.bounds.isEmpty(); + } + + public void init() { + this.draggingContext.set(DraggableComponentProvider.from(ScreenRegistry.getInstance()::getDraggableComponentProviders), + DraggableComponentVisitor.from(ScreenRegistry.getInstance()::getDraggableComponentVisitors)); + + this.shouldReload = false; + this.shouldReloadSearch = false; + this.bounds.setBounds(InternalOverlayBounds.calculateOverlayBounds()); + this.widgets.clear(); + this.widgets.add(draggingContext); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (shouldReload || !InternalOverlayBounds.calculateOverlayBounds().equals(bounds)) { + init(); + updateSearch(); + } else { + for (OverlayDecider decider : ScreenRegistry.getInstance().getDeciders(minecraft.screen)) { + if (decider != null && decider.shouldRecalculateArea(ConfigObject.getInstance().getDisplayPanelLocation(), bounds)) { + init(); + break; + } + } + } + if (shouldReloadSearch) { + shouldReloadSearch = false; + updateSearch(); + } + if (!hasSpace()) return; + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + this.renderWidgets(matrices, mouseX, mouseY, delta); + if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) { + Screen screen = Minecraft.getInstance().screen; + ClickArea.ClickAreaContext context = ClickArea.ClickAreaContext.of(screen, new Point(mouseX, mouseY)); + List clickAreaTooltips = ScreenRegistry.getInstance().getClickAreaTooltips((Class) screen.getClass(), context); + if (clickAreaTooltips != null && !clickAreaTooltips.isEmpty()) { + Tooltip.create(clickAreaTooltips).queue(); + } + } + } + + public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (REIRuntime.getInstance().isOverlayVisible() && hasSpace()) { + getSearchField().asWidget().render(matrices, mouseX, mouseY, delta); + for (Widget widget : widgets) { + if (widget instanceof LateRenderable && widget != menuAccess.widget()) + widget.render(matrices, mouseX, mouseY, delta); + } + matrices.pushPose(); + matrices.translate(0, 0, 500); + menuAccess.lateRender(matrices, mouseX, mouseY, delta); + matrices.popPose(); + } + + Tooltip tooltip = TooltipQueue.getInstance().get(); + if (tooltip != null) { + renderTooltip(matrices, tooltip); + } + + TooltipQueue.getInstance().clear(); + if (REIRuntime.getInstance().isOverlayVisible()) { + menuAccess.afterRender(); + } + } + + @Override + public void renderTooltip(PoseStack matrices, Tooltip tooltip) { + ClientInternals.getTooltipRenderer().renderTooltip(minecraft.screen, matrices, tooltip, tooltip.getX(), tooltip.getY()); + } + + public void renderWidgets(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (!REIRuntime.getInstance().isOverlayVisible()) + return; + for (Widget widget : widgets) { + if (!(widget instanceof LateRenderable)) + widget.render(matrices, mouseX, mouseY, delta); + } + } + + protected abstract void updateSearch(); + + public MenuAccess menuAccess() { + return menuAccess; + } + + public boolean isInside(double mouseX, double mouseY) { + return bounds.contains(mouseX, mouseY) && isNotInExclusionZones(mouseX, mouseY); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + boolean visible = REIRuntime.getInstance().isOverlayVisible(); + if (!hasSpace()) return false; + if (ConfigObject.getInstance().getHideKeybind().matchesMouse(button)) { + REIRuntime.getInstance().toggleOverlayVisible(); + return REIRuntime.getInstance().isOverlayVisible(); + } + EntryStack stack = ScreenRegistry.getInstance().getFocusedStack(Minecraft.getInstance().screen, PointHelper.ofMouse()); + if (stack != null && !stack.isEmpty()) { + stack = stack.copy(); + if (ConfigObject.getInstance().getRecipeKeybind().matchesMouse(button)) { + return ViewSearchBuilder.builder().addRecipesFor(stack).open(); + } else if (ConfigObject.getInstance().getUsageKeybind().matchesMouse(button)) { + return ViewSearchBuilder.builder().addUsagesFor(stack).open(); + } else if (visible && ConfigObject.getInstance().getFavoriteKeyCode().matchesMouse(button)) { + FavoriteEntry favoriteEntry = FavoriteEntry.fromEntryStack(stack); + ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry); + return true; + } + } + if (visible) { + Widget menuWidget = menuAccess.widget(); + if (menuWidget != null && menuWidget.mouseClicked(mouseX, mouseY, button)) { + this.setFocused(menuWidget); + if (button == 0) + this.setDragging(true); + return true; + } + } + if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) { + Screen screen = Minecraft.getInstance().screen; + ClickArea.ClickAreaContext context = ClickArea.ClickAreaContext.of(screen, new Point(mouseX, mouseY)); + if (ScreenRegistry.getInstance().executeClickArea((Class) screen.getClass(), context)) { + return true; + } + } + if (!visible) { + return false; + } + for (GuiEventListener element : widgets) { + if (element != menuAccess.widget() && element.mouseClicked(mouseX, mouseY, button)) { + this.setFocused(element); + if (button == 0) + this.setDragging(true); + return true; + } + } + return false; + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + if (!REIRuntime.getInstance().isOverlayVisible()) + return false; + if (menuAccess.mouseScrolled(mouseX, mouseY, amount)) + return true; + for (Widget widget : widgets) + if (widget != menuAccess.widget() + && widget.mouseScrolled(mouseX, mouseY, amount)) + return true; + return false; + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (!REIRuntime.getInstance().isOverlayVisible()) + return false; + if (!hasSpace()) return false; + return (this.getFocused() != null && this.isDragging() && button == 0) && this.getFocused().mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (!hasSpace()) return false; + if (REIRuntime.getInstance().isOverlayVisible()) { + for (GuiEventListener listener : widgets) + if (listener.keyPressed(keyCode, scanCode, modifiers)) + return true; + } + if (ConfigObject.getInstance().getHideKeybind().matchesKey(keyCode, scanCode)) { + REIRuntime.getInstance().toggleOverlayVisible(); + return true; + } + EntryStack stack = ScreenRegistry.getInstance().getFocusedStack(Minecraft.getInstance().screen, PointHelper.ofMouse()); + if (stack != null && !stack.isEmpty()) { + stack = stack.copy(); + if (ConfigObject.getInstance().getRecipeKeybind().matchesKey(keyCode, scanCode)) { + return ViewSearchBuilder.builder().addRecipesFor(stack).open(); + } else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(keyCode, scanCode)) { + return ViewSearchBuilder.builder().addUsagesFor(stack).open(); + } else if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) { + FavoriteEntry favoriteEntry = FavoriteEntry.fromEntryStack(stack); + ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry); + return true; + } + } + return false; + } + + @Override + public boolean keyReleased(int keyCode, int scanCode, int modifiers) { + if (!hasSpace()) return false; + if (REIRuntime.getInstance().isOverlayVisible()) { + for (GuiEventListener listener : widgets) + if (listener == getFocused() && listener.keyReleased(keyCode, scanCode, modifiers)) + return true; + } + return false; + } + + @Override + public boolean charTyped(char character, int modifiers) { + if (!REIRuntime.getInstance().isOverlayVisible()) + return false; + if (!hasSpace()) return false; + for (GuiEventListener listener : widgets) + if (listener.charTyped(character, modifiers)) + return true; + return false; + } + + @Override + public boolean isNotInExclusionZones(double mouseX, double mouseY) { + for (OverlayDecider decider : ScreenRegistry.getInstance().getDeciders(Minecraft.getInstance().screen)) { + InteractionResult in = decider.isInZone(mouseX, mouseY); + if (in != InteractionResult.PASS) + return in == InteractionResult.SUCCESS; + } + return true; + } + + public boolean isInside(Point point) { + return isInside(point.getX(), point.getY()); + } +} diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/InternalOverlayBounds.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/InternalOverlayBounds.java new file mode 100644 index 000000000..bf98c858f --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/InternalOverlayBounds.java @@ -0,0 +1,50 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay; + +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.config.DisplayPanelLocation; +import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.impl.client.util.InternalEntryBounds; +import net.minecraft.client.Minecraft; + +public class InternalOverlayBounds { + static Rectangle calculateOverlayBounds() { + Rectangle bounds = ScreenRegistry.getInstance().getOverlayBounds(ConfigObject.getInstance().getDisplayPanelLocation(), Minecraft.getInstance().screen); + + int widthReduction = (int) Math.round(bounds.width * (1 - ConfigObject.getInstance().getHorizontalEntriesBoundariesPercentage())); + if (ConfigObject.getInstance().getDisplayPanelLocation() == DisplayPanelLocation.RIGHT) + bounds.x += widthReduction; + bounds.width -= widthReduction; + int maxWidth = (int) Math.ceil(InternalEntryBounds.entrySize() * ConfigObject.getInstance().getHorizontalEntriesBoundariesColumns() + InternalEntryBounds.entrySize() * 0.75); + if (bounds.width > maxWidth) { + if (ConfigObject.getInstance().getDisplayPanelLocation() == DisplayPanelLocation.RIGHT) + bounds.x += bounds.width - maxWidth; + bounds.width = maxWidth; + } + + return bounds; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/LateRenderable.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/LateRenderable.java similarity index 96% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/LateRenderable.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/LateRenderable.java index 2a8fc5644..6bfdb0e9a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/LateRenderable.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/LateRenderable.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.overlay; import org.jetbrains.annotations.ApiStatus; diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayImpl.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayImpl.java new file mode 100644 index 000000000..6245a1730 --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayImpl.java @@ -0,0 +1,215 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay; + +import com.mojang.blaze3d.platform.InputConstants; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.widgets.DelegateWidget; +import me.shedaniel.rei.api.client.gui.widgets.TextField; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.overlay.OverlayListWidget; +import me.shedaniel.rei.api.client.search.SearchFilter; +import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListProvider; +import me.shedaniel.rei.impl.client.gui.overlay.entries.EntryListWidget; +import me.shedaniel.rei.impl.client.gui.overlay.entries.FavoritesListProvider; +import me.shedaniel.rei.impl.client.gui.overlay.entries.FavoritesListWidget; +import me.shedaniel.rei.impl.client.gui.overlay.widgets.OverlayWidgetProvider; +import me.shedaniel.rei.impl.common.InternalLogger; +import net.minecraft.client.gui.components.events.GuiEventListener; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.BooleanSupplier; + +@ApiStatus.Internal +public final class ScreenOverlayImpl extends AbstractScreenOverlay { + private EntryListWidget entryListWidget = null; + private FavoritesListWidget favoritesListWidget = null; + private TextField searchField = null; + private BooleanSupplier isHighlighted = null; + + @Override + public void init() { + super.init(); + + this.searchField = null; + this.isHighlighted = null; + + FavoritesListWidget favoritesListWidget = getFavoritesListNullable(); + + if (favoritesListWidget != null) { + this.children().add(favoritesListWidget.asWidget()); + } + + EntryListWidget entryListWidget = getEntryList(); + entryListWidget.initBounds(this.getBounds()); + this.children().add(entryListWidget.asWidget()); + entryListWidget.init(this); + + for (OverlayWidgetProvider provider : OverlayWidgetProvider.PROVIDERS) { + provider.provide(this, menuAccess(), new OverlayWidgetProvider.WidgetSink() { + @Override + public void accept(Widget widget) { + ScreenOverlayImpl.this.children().add(widget); + } + + @Override + public void acceptLateRendered(Widget widget) { + accept(new LateRenderableWidget(widget)); + } + + @Override + public void acceptTextField(TextField textField, BooleanSupplier isHighlighted) { + ScreenOverlayImpl.this.searchField = textField; + ScreenOverlayImpl.this.isHighlighted = isHighlighted; + } + }); + } + + if (this.searchField != null) { + this.children().add(new LateRenderableWidget(this.searchField.asWidget())); + this.searchField.setResponder(s -> entryListWidget.initSearch(s, false)); + entryListWidget.initSearch(searchField.getText(), true); + } else { + InternalLogger.getInstance().warn("Search Field is not found! This might cause problems!"); + entryListWidget.initSearch("", true); + } + } + + private static class LateRenderableWidget extends DelegateWidget implements LateRenderable { + private LateRenderableWidget(Widget widget) { + super(widget); + } + } + + @Override + protected void updateSearch() { + getEntryList().initSearch(getSearchField().getText(), true); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (super.keyPressed(keyCode, scanCode, modifiers)) return true; + if (!hasSpace()) return false; + if (!REIRuntime.getInstance().isOverlayVisible()) return false; + if (ConfigObject.getInstance().getFocusSearchFieldKeybind().matchesKey(keyCode, scanCode)) { + getSearchField().setFocusedFromKey(true, InputConstants.getKey(keyCode, scanCode)); + setFocused(getSearchField().asWidget()); + return true; + } + return false; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) return true; + boolean visible = REIRuntime.getInstance().isOverlayVisible(); + if (!hasSpace() || !visible) return false; + if (ConfigObject.getInstance().getFocusSearchFieldKeybind().matchesMouse(button)) { + getSearchField().setFocusedFromKey(true, InputConstants.Type.MOUSE.getOrCreate(button)); + setFocused(getSearchField().asWidget()); + return true; + } + return false; + } + + @Override + public void setFocused(@Nullable GuiEventListener focused) { + super.setFocused(focused); + getSearchField().setFocused(focused == getSearchField().asWidget()); + } + + @Override + public EntryListWidget getEntryList() { + EntryListWidget current = null; + for (EntryListProvider provider : EntryListProvider.PROVIDERS) { + current = provider.getEntryList(); + if (current != null) break; + } + if (current == null) throw new IllegalStateException("No Entry List available!"); + if (current != entryListWidget) { + entryListWidget = current; + current.initBounds(Objects.requireNonNullElse(getBounds(), new Rectangle())); + current.initSearch(getSearchField().getText(), true); + } + return entryListWidget; + } + + @Override + public Optional getFavoritesList() { + return Optional.ofNullable(getFavoritesListNullable()); + } + + private FavoritesListWidget getFavoritesListNullable() { + if (ConfigObject.getInstance().isFavoritesEnabled()) { + FavoritesListWidget current = null; + for (FavoritesListProvider provider : FavoritesListProvider.PROVIDERS) { + current = provider.getFavoritesList(); + if (current != null) break; + } + if (current != null) throw new IllegalStateException("No Entry List available!"); + if (current != favoritesListWidget) { + favoritesListWidget = current; + current.initBounds(); + } + return favoritesListWidget; + } else { + return favoritesListWidget = null; + } + } + + @Override + public TextField getSearchField() { + return Objects.requireNonNullElseGet(searchField, () -> Widgets.createTextField(new Rectangle())); + } + + @Override + @Nullable + public SearchFilter getCurrentSearchFilter() { + return getEntryList().getSearchFilter(); + } + + @Override + public boolean isHighlighting() { + return this.isHighlighted != null && this.isHighlighted.getAsBoolean(); + } + + @Override + public boolean submitDisplayHistory(Display display, @Nullable Rectangle fromBounds) { + FavoritesListWidget favoritesListWidget = getFavoritesListNullable(); + + if (favoritesListWidget != null) { + favoritesListWidget.submitDisplayHistory(display, fromBounds); + return true; + } else { + return false; + } + } +} diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayProviderImpl.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayProviderImpl.java new file mode 100644 index 000000000..e844ebafc --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/ScreenOverlayProviderImpl.java @@ -0,0 +1,34 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay; + +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.impl.client.provider.OverlayProvider; + +public class ScreenOverlayProviderImpl implements OverlayProvider { + @Override + public ScreenOverlay provide() { + return new ScreenOverlayImpl(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesSystemRegionListener.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/TooltipQueueImpl.java similarity index 57% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesSystemRegionListener.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/TooltipQueueImpl.java index 634b0853a..de285ef68 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesSystemRegionListener.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/TooltipQueueImpl.java @@ -21,36 +21,37 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.favorites.listeners; +package me.shedaniel.rei.impl.client.gui.overlay; -import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.gui.drag.DraggableStack; -import me.shedaniel.rei.api.client.gui.drag.DraggingContext; -import me.shedaniel.rei.impl.client.gui.widget.region.RealRegionEntry; -import me.shedaniel.rei.impl.client.gui.widget.region.RegionListener; -import net.minecraft.client.gui.screens.Screen; +import com.google.common.collect.Lists; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipQueue; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -public class FavoritesSystemRegionListener implements RegionListener { - @Override - @Nullable - public FavoriteEntry convertDraggableStack(DraggingContext context, DraggableStack stack) { - return FavoriteEntry.fromEntryStack(stack.getStack().copy()); - } +import java.util.List; +import java.util.Objects; + +@ApiStatus.Internal +public final class TooltipQueueImpl implements TooltipQueue { + private final List tooltips = Lists.newArrayList(); @Override - public boolean canAcceptDrop(RealRegionEntry entry) { - return false; + public void queue(@Nullable Tooltip tooltip) { + if (tooltip != null) + tooltips.add(tooltip); } @Override - @Nullable - public FavoriteEntry asFavorite(RealRegionEntry entry) { - return null; + public void clear() { + tooltips.clear(); } @Override - public boolean removeOnDrag() { - return false; + @Nullable + public Tooltip get() { + return tooltips.stream().filter(Objects::nonNull) + .reduce((tooltip, tooltip2) -> tooltip2) + .orElse(null); } -} \ No newline at end of file +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/dragging/DraggingContextImpl.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/dragging/DraggingContextImpl.java index 72b6b3074..3e579a207 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/dragging/DraggingContextImpl.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.dragging; +package me.shedaniel.rei.impl.client.gui.overlay.dragging; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.api.animator.NumberAnimator; @@ -29,7 +29,6 @@ import me.shedaniel.math.FloatingRectangle; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import me.shedaniel.rei.api.client.gui.drag.DraggableBoundsProvider; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggedAcceptorResult; @@ -38,7 +37,7 @@ import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProvider; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitor; import me.shedaniel.rei.api.client.gui.widgets.Widget; -import me.shedaniel.rei.impl.client.gui.widget.LateRenderable; +import me.shedaniel.rei.impl.client.gui.InternalCursorState; import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -51,7 +50,7 @@ import java.util.function.Supplier; @SuppressWarnings("UnstableApiUsage") -public class CurrentDraggingStack extends Widget implements LateRenderable, DraggingContext { +public class DraggingContextImpl extends Widget implements DraggingContext { private DraggableComponentProvider provider; private DraggableComponentVisitor visitor; @Nullable @@ -101,7 +100,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { hash = shapeBounds.hash; } - if (!RoughlyEnoughItemsCoreClient.isLeftMousePressed) { + if (!InternalCursorState.isLeftMousePressed) { drop(); } } @@ -260,7 +259,7 @@ private DraggableEntry(DraggableComponent component, Point start) { public DraggableBoundsProvider getBoundsProvider() { if (boundsProvider == null) { - boundsProvider = DraggableBoundsProvider.concat(visitor.getDraggableAcceptingBounds(CurrentDraggingStack.this, component).toList()); + boundsProvider = DraggableBoundsProvider.concat(visitor.getDraggableAcceptingBounds(DraggingContextImpl.this, component).toList()); } return boundsProvider; @@ -268,9 +267,9 @@ public DraggableBoundsProvider getBoundsProvider() { } private static class ShapeBounds { - private VoxelShape shape; - private NumberAnimator alpha; - private int hash; + private final VoxelShape shape; + private final NumberAnimator alpha; + private final int hash; public ShapeBounds(VoxelShape shape) { this.shape = shape; @@ -298,8 +297,8 @@ public void update(double delta) { private static class RenderBackEntry { private final DraggableComponent component; private final Supplier position; - private ValueAnimator bounds = ValueAnimator.ofFloatingRectangle(); - private int lastDestination = -1; + private final ValueAnimator bounds = ValueAnimator.ofFloatingRectangle(); + private final int lastDestination = -1; public RenderBackEntry(DraggableComponent component, Rectangle initialPosition, Supplier position) { this.component = component; diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListProvider.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListProvider.java new file mode 100644 index 000000000..7e47f29e7 --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListProvider.java @@ -0,0 +1,38 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.entries; + +import me.shedaniel.rei.impl.client.ClientInternals; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +@ApiStatus.Internal +public interface EntryListProvider { + List PROVIDERS = ClientInternals.resolveServices(EntryListProvider.class); + + @Nullable + EntryListWidget getEntryList(); +} diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidget.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidget.java new file mode 100644 index 000000000..6f3001116 --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/EntryListWidget.java @@ -0,0 +1,44 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.entries; + +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.overlay.OverlayListWidget; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.search.SearchFilter; +import org.jetbrains.annotations.Nullable; + +public interface EntryListWidget extends OverlayListWidget { + void initBounds(Rectangle bounds); + + void initSearch(String searchTerm, boolean ignorePrevious); + + Widget asWidget(); + + void init(ScreenOverlay overlay); + + @Nullable + SearchFilter getSearchFilter(); +} diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListProvider.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListProvider.java new file mode 100644 index 000000000..66b43975b --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListProvider.java @@ -0,0 +1,38 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.entries; + +import me.shedaniel.rei.impl.client.ClientInternals; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +@ApiStatus.Internal +public interface FavoritesListProvider { + List PROVIDERS = ClientInternals.resolveServices(FavoritesListProvider.class); + + @Nullable + FavoritesListWidget getFavoritesList(); +} diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListWidget.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListWidget.java new file mode 100644 index 000000000..f81c751fa --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/entries/FavoritesListWidget.java @@ -0,0 +1,41 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.entries; + +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.overlay.OverlayListWidget; +import me.shedaniel.rei.api.common.display.Display; + +import javax.annotation.Nullable; + +public interface FavoritesListWidget extends OverlayListWidget { + void initBounds(); + + Widget asWidget(); + + Rectangle getFavoritesBounds(); + + void submitDisplayHistory(Display display, @Nullable Rectangle fromBounds); +} diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/hints/InputMethodWatcher.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/hints/InputMethodWatcher.java new file mode 100644 index 000000000..005d367ef --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/hints/InputMethodWatcher.java @@ -0,0 +1,172 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.hints; + +import me.shedaniel.math.Color; +import me.shedaniel.math.Point; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.search.method.InputMethod; +import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; +import me.shedaniel.rei.impl.client.gui.hints.HintProvider; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.SubMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.ToggleMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.provider.OverlayMenuEntryProvider; +import me.shedaniel.rei.impl.client.gui.screen.ConfigReloadingScreen; +import me.shedaniel.rei.impl.common.InternalLogger; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class InputMethodWatcher implements HintProvider, OverlayMenuEntryProvider { + public static final UUID MENU_UUID = UUID.fromString("b93cc166-d06f-4c5f-9bf0-334d18b4adaf"); + + @Override + public List provide() { + if (PluginManager.areAnyReloading() || ScreenOverlay.getInstance().orElseThrow().isHighlighting()) return Collections.emptyList(); + ResourceLocation id = ConfigObject.getInstance().getInputMethodId(); + if (id == null) { + String languageCode = Minecraft.getInstance().options.languageCode; + MutableComponent component = new TextComponent(""); + int match = 0; + for (Map.Entry> entry : InputMethodRegistry.getInstance().getAll().entrySet()) { + InputMethod method = entry.getValue(); + if (entry.getKey().equals(new ResourceLocation("rei:default"))) continue; + if (CollectionUtils.anyMatch(method.getMatchingLocales(), locale -> locale.code().equals(languageCode))) { + if (!component.getString().isEmpty()) { + component.append(", "); + } + + component.append(method.getName()); + match++; + } + } + if (match > 0) { + return List.of(new TranslatableComponent("text.rei.input.methods.hint"), + new TextComponent(" "), component); + } + } + + return Collections.emptyList(); + } + + @Override + @Nullable + public Tooltip provideTooltip(Point mouse) { + return null; + } + + @Override + public Color getColor() { + return Color.ofTransparent(0x50ffadca); + } + + @Override + public List getButtons(MenuAccess access) { + return List.of( + new HintButton(new TranslatableComponent("text.rei.input.methods.hint.configure"), bounds -> { + access.openOrClose(MENU_UUID, bounds.clone(), + () -> createInputMethodEntries(getApplicableInputMethods())); + }), + new HintButton(new TranslatableComponent("text.rei.input.methods.hint.ignore"), bounds -> { + ConfigManagerInternal.getInstance().set("functionality.inputMethod", new ResourceLocation("rei:default")); + }) + ); + } + + @Override + public List provide(Type type) { + if (type != Type.CRAFTABLE_FILTER) return List.of(); + + List>> applicableInputMethods = getApplicableInputMethods(); + if (applicableInputMethods.size() > 1) { + return List.of(new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.search_field.input_method"), createInputMethodEntries(applicableInputMethods))); + } + + return List.of(); + } + + public static List>> getApplicableInputMethods() { + String languageCode = Minecraft.getInstance().options.languageCode; + return InputMethodRegistry.getInstance().getAll().entrySet().stream() + .filter(entry -> CollectionUtils.anyMatch(entry.getValue().getMatchingLocales(), locale -> locale.code().equals(languageCode))) + .toList(); + } + + public static List createInputMethodEntries(List>> applicableInputMethods) { + ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); + ConfigObject config = ConfigObject.getInstance(); + return applicableInputMethods.stream() + .map(pair -> ToggleMenuEntry.of(pair.getValue().getName(), + () -> Objects.equals(config.getInputMethodId(), pair.getKey()), + bool -> { + ExecutorService service = Executors.newSingleThreadExecutor(); + InputMethod active = InputMethod.active(); + active.dispose(service).whenComplete((unused, throwable) -> { + if (throwable != null) { + InternalLogger.getInstance().error("Failed to dispose input method", throwable); + } + + manager.set("functionality.inputMethod", new ResourceLocation("rei:default")); + }).join(); + CompletableFuture future = pair.getValue().prepare(service).whenComplete((unused, throwable) -> { + if (throwable != null) { + InternalLogger.getInstance().error("Failed to prepare input method", throwable); + manager.set("functionality.inputMethod", new ResourceLocation("rei:default")); + } else { + manager.set("functionality.inputMethod", pair.getKey()); + } + }); + Screen screen = Minecraft.getInstance().screen; + Minecraft.getInstance().setScreen(new ConfigReloadingScreen(new TranslatableComponent("text.rei.input.methods.initializing"), + () -> !future.isDone(), () -> { + Minecraft.getInstance().setScreen(screen); + })); + future.whenComplete((unused, throwable) -> { + service.shutdown(); + }); + }) + .withActive(() -> !Objects.equals(config.getInputMethodId(), pair.getKey())) + .withTooltip(() -> Tooltip.create(TooltipContext.ofMouse(), pair.getValue().getDescription())) + ) + .toList(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/AbstractMenuEntry.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/AbstractMenuEntry.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/AbstractMenuEntry.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/AbstractMenuEntry.java index 47fc0b085..6cd269c3c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/AbstractMenuEntry.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/AbstractMenuEntry.java @@ -21,9 +21,11 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules; +package me.shedaniel.rei.impl.client.gui.overlay.menu; -public abstract class AbstractMenuEntry extends MenuEntry { +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; + +public abstract class AbstractMenuEntry extends FavoriteMenuEntry { private int x, y, width; private boolean selected, containsMouse, rendering; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/Menu.java similarity index 84% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/Menu.java index 05173e464..89675b0be 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/Menu.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/Menu.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules; +package me.shedaniel.rei.impl.client.gui.overlay.menu; import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; @@ -30,10 +30,10 @@ import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import me.shedaniel.rei.impl.client.gui.modules.entries.SubMenuEntry; -import me.shedaniel.rei.impl.client.gui.widget.LateRenderable; +import me.shedaniel.rei.impl.client.gui.overlay.menu.entries.SubMenuEntry; import net.minecraft.client.Minecraft; import org.jetbrains.annotations.ApiStatus; @@ -43,19 +43,19 @@ import java.util.UUID; @ApiStatus.Internal -public class Menu extends WidgetWithBounds implements LateRenderable { +public class Menu extends WidgetWithBounds { public static final UUID WEATHER = UUID.randomUUID(); public static final UUID GAME_TYPE = UUID.randomUUID(); public final Point menuStartPoint; public final boolean facingRight; public final boolean facingDownwards; - private final List entries = Lists.newArrayList(); + private final List entries = Lists.newArrayList(); public final ScrollingContainer scrolling = new ScrollingContainer() { @Override public int getMaxScrollHeight() { int i = 0; - for (MenuEntry entry : children()) { + for (FavoriteMenuEntry entry : children()) { i += entry.getEntryHeight(); } return i; @@ -72,7 +72,7 @@ public boolean hasScrollBar() { } }; - public Menu(Rectangle menuStart, Collection entries, boolean sort) { + public Menu(Rectangle menuStart, Collection entries, boolean sort) { buildEntries(entries, sort); int fullWidth = Minecraft.getInstance().screen.width; int fullHeight = Minecraft.getInstance().screen.height; @@ -92,15 +92,17 @@ public Menu(Rectangle menuStart, Collection entries, boolean sort) { } @SuppressWarnings("deprecation") - private void buildEntries(Collection entries, boolean sort) { + private void buildEntries(Collection entries, boolean sort) { this.entries.clear(); this.entries.addAll(entries); if (sort) { this.entries.sort(Comparator.comparing(entry -> entry instanceof SubMenuEntry ? 0 : 1) .thenComparing(entry -> entry instanceof SubMenuEntry menuEntry ? menuEntry.text.getString() : "")); } - for (MenuEntry entry : this.entries) { - entry.parent = this; + for (FavoriteMenuEntry entry : this.entries) { + if (entry instanceof SubMenuEntry) { + ((SubMenuEntry) entry).parentMenu = this; + } } } @@ -123,7 +125,7 @@ public int getInnerHeight(int y) { public int getMaxEntryWidth() { int i = 0; - for (MenuEntry entry : children()) { + for (FavoriteMenuEntry entry : children()) { if (entry.getEntryWidth() > i) i = entry.getEntryWidth(); } @@ -134,12 +136,12 @@ public int getMaxEntryWidth() { public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { Rectangle bounds = getBounds(); Rectangle innerBounds = getInnerBounds(); - fill(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), containsMouse(mouseX, mouseY) ? (REIRuntime.getInstance().isDarkThemeEnabled() ? -17587 : -1) : -6250336); + fill(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), containsMouse(mouseX, mouseY) ? (ConfigObject.getInstance().isUsingDarkTheme() ? -17587 : -1) : -6250336); fill(matrices, innerBounds.x, innerBounds.y, innerBounds.getMaxX(), innerBounds.getMaxY(), -16777216); boolean contains = innerBounds.contains(mouseX, mouseY); - MenuEntry focused = getFocused() instanceof MenuEntry menuEntry ? menuEntry : null; + FavoriteMenuEntry focused = getFocused() instanceof FavoriteMenuEntry menuEntry ? menuEntry : null; int currentY = innerBounds.y - scrolling.scrollAmountInt(); - for (MenuEntry child : children()) { + for (FavoriteMenuEntry child : children()) { boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight(); if (containsMouse) { focused = child; @@ -148,7 +150,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { } currentY = innerBounds.y - scrolling.scrollAmountInt(); ScissorsHandler.INSTANCE.scissor(scrolling.getScissorBounds()); - for (MenuEntry child : children()) { + for (FavoriteMenuEntry child : children()) { boolean rendering = currentY + child.getEntryHeight() >= innerBounds.y && currentY <= innerBounds.getMaxY(); boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight(); child.updateInformation(innerBounds.x, currentY, focused == child || containsMouse, containsMouse, rendering, getMaxEntryWidth()); @@ -159,7 +161,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { } ScissorsHandler.INSTANCE.removeLastScissor(); setFocused(focused); - scrolling.renderScrollBar(0, 1, REIRuntime.getInstance().isDarkThemeEnabled() ? 0.8f : 1f); + scrolling.renderScrollBar(0, 1, ConfigObject.getInstance().isUsingDarkTheme() ? 0.8f : 1f); scrolling.updatePosition(delta); } @@ -183,7 +185,7 @@ public boolean mouseScrolled(double mouseX, double mouseY, double amount) { scrolling.offset(ClothConfigInitializer.getScrollStep() * -amount, true); return true; } - for (MenuEntry child : children()) { + for (FavoriteMenuEntry child : children()) { if (child instanceof SubMenuEntry) { if (child.mouseScrolled(mouseX, mouseY, amount)) return true; @@ -195,7 +197,7 @@ public boolean mouseScrolled(double mouseX, double mouseY, double amount) { @Override public boolean containsMouse(double mouseX, double mouseY) { if (super.containsMouse(mouseX, mouseY)) return true; - for (MenuEntry child : children()) { + for (FavoriteMenuEntry child : children()) { if (child.containsMouse(mouseX, mouseY)) { return true; } @@ -204,7 +206,7 @@ public boolean containsMouse(double mouseX, double mouseY) { } @Override - public List children() { + public List children() { return entries; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuHolder.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/MenuAccessImpl.java similarity index 69% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuHolder.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/MenuAccessImpl.java index a112f0462..2a5a40fbe 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuHolder.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/MenuAccessImpl.java @@ -21,23 +21,29 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules; +package me.shedaniel.rei.impl.client.gui.overlay.menu; import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; import me.shedaniel.math.impl.PointHelper; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.Widgets; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; import org.jetbrains.annotations.Nullable; +import java.util.Collection; import java.util.List; import java.util.UUID; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.function.Supplier; -public class MenuHolder implements MenuAccess { +public class MenuAccessImpl implements MenuAccess { public final List afterRenders = Lists.newArrayList(); @Nullable private OverlayMenu menu = null; @@ -71,18 +77,34 @@ private void proceedOpenMenuOrElse(UUID uuid, Runnable runnable, Consumer false, point -> true); + public void open(UUID uuid, Rectangle selfBounds, Supplier> menuSupplier) { + open(uuid, selfBounds, menuSupplier, point -> false, point -> true); } @Override - public void open(UUID uuid, Menu menu, Predicate or, Predicate and) { + public void open(UUID uuid, Rectangle selfBounds, Supplier> menuSupplier, Predicate or, Predicate and) { + Menu menu = new Menu(selfBounds, menuSupplier.get(), false); this.menu = new OverlayMenu(uuid, menu, Widgets.withTranslate(menu, 0, 0, 400), or, and); } + @Override + public void openOrClose(UUID uuid, Rectangle selfBounds, Supplier> menuSupplier) { + boolean isOpened = isOpened(uuid); + if (isOpened || !isAnyOpened()) { + boolean inBounds = (isValidPoint(PointHelper.ofMouse()) && selfBounds.contains(PointHelper.ofMouse())) || isInBounds(uuid); + if (isOpened != inBounds) { + if (inBounds) { + open(uuid, selfBounds.clone(), menuSupplier, selfBounds::contains, point -> true); + } else { + close(); + } + } + } + } + @Override public boolean isValidPoint(Point point) { - return ScreenOverlayImpl.getInstance().isNotInExclusionZones(point.x, point.y); + return ScreenOverlay.getInstance().orElseThrow().isNotInExclusionZones(point.x, point.y); } @Override @@ -108,7 +130,7 @@ public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) close(); } else { if (menu.wrappedMenu.containsMouse(mouseX, mouseY)) { - ScreenOverlayImpl.getInstance().clearTooltips(); + REIRuntime.getInstance().clearTooltips(); } menu.wrappedMenu.render(matrices, mouseX, mouseY, delta); } @@ -120,14 +142,12 @@ public boolean mouseScrolled(double mouseX, double mouseY, double amount) { } private static class OverlayMenu { - private UUID uuid; - private Menu menu; - private Widget wrappedMenu; - private Predicate inBounds; + private final UUID uuid; + private final Widget wrappedMenu; + private final Predicate inBounds; public OverlayMenu(UUID uuid, Menu menu, Widget wrappedMenu, Predicate or, Predicate and) { this.uuid = uuid; - this.menu = menu; this.wrappedMenu = wrappedMenu; this.inBounds = or.or(menu::containsMouse).and(and); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EmptyMenuEntry.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/EmptyMenuEntry.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EmptyMenuEntry.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/EmptyMenuEntry.java index 4ccfa4414..092ef0e48 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/EmptyMenuEntry.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/EmptyMenuEntry.java @@ -21,10 +21,10 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules.entries; +package me.shedaniel.rei.impl.client.gui.overlay.menu.entries; import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.AbstractMenuEntry; import net.minecraft.client.gui.components.events.GuiEventListener; import java.util.Collections; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SeparatorMenuEntry.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/SeparatorMenuEntry.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SeparatorMenuEntry.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/SeparatorMenuEntry.java index 8af7d4c52..792039877 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SeparatorMenuEntry.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/SeparatorMenuEntry.java @@ -21,10 +21,10 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules.entries; +package me.shedaniel.rei.impl.client.gui.overlay.menu.entries; import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.AbstractMenuEntry; import net.minecraft.client.gui.components.events.GuiEventListener; import java.util.Collections; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubMenuEntry.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/SubMenuEntry.java similarity index 87% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubMenuEntry.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/SubMenuEntry.java index ada112783..8de4d621d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/SubMenuEntry.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/SubMenuEntry.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules.entries; +package me.shedaniel.rei.impl.client.gui.overlay.menu.entries; import com.google.common.base.MoreObjects; import com.google.common.collect.Lists; @@ -29,11 +29,11 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.api.ScissorsHandler; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.impl.client.gui.InternalTextures; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; -import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; -import me.shedaniel.rei.impl.client.gui.modules.Menu; -import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; +import me.shedaniel.rei.impl.client.gui.InternalTextures; +import me.shedaniel.rei.impl.client.gui.overlay.menu.AbstractMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.Menu; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.network.chat.Component; @@ -45,18 +45,19 @@ public class SubMenuEntry extends AbstractMenuEntry { public final Component text; private int textWidth = -69; - protected List entries; + protected List entries; + public Menu parentMenu; protected Menu childMenu; public SubMenuEntry(Component text) { this(text, Collections.emptyList()); } - public SubMenuEntry(Component text, Supplier> entries) { + public SubMenuEntry(Component text, Supplier> entries) { this(text, entries.get()); } - public SubMenuEntry(Component text, List entries) { + public SubMenuEntry(Component text, List entries) { this.text = MoreObjects.firstNonNull(text, ImmutableTextComponent.EMPTY); this.entries = entries; } @@ -70,7 +71,7 @@ private int getTextWidth() { public Menu getChildMenu() { if (childMenu == null) { - this.childMenu = new Menu(new Rectangle(getParent().getBounds().x + 1, getY() - 1, getParent().getBounds().width - 2, getEntryHeight() - 2), entries, false); + this.childMenu = new Menu(new Rectangle(parentMenu.getBounds().x + 1, getY() - 1, parentMenu.getBounds().width - 2, getEntryHeight() - 2), entries, false); } return childMenu; } @@ -92,11 +93,11 @@ public void render(PoseStack poses, int mouseX, int mouseY, float delta) { if (!entries.isEmpty()) { Menu menu = getChildMenu(); - Rectangle menuStart = new Rectangle(getParent().getBounds().x, getY(), getParent().getBounds().width, getEntryHeight()); + Rectangle menuStart = new Rectangle(parentMenu.getBounds().x, getY(), parentMenu.getBounds().width, getEntryHeight()); int fullWidth = Minecraft.getInstance().screen.width; int fullHeight = Minecraft.getInstance().screen.height; - boolean facingRight = getParent().facingRight; + boolean facingRight = parentMenu.facingRight; int menuWidth = menu.getMaxEntryWidth() + 2 + (menu.hasScrollBar() ? 6 : 0); if (facingRight && fullWidth - menuStart.getMaxX() < menuWidth + 10) { facingRight = false; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/TextMenuEntry.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/TextMenuEntry.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/TextMenuEntry.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/TextMenuEntry.java index 69740e383..7b30096ad 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/TextMenuEntry.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/TextMenuEntry.java @@ -21,10 +21,10 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules.entries; +package me.shedaniel.rei.impl.client.gui.overlay.menu.entries; import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.AbstractMenuEntry; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.network.chat.Component; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/ToggleMenuEntry.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/ToggleMenuEntry.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/ToggleMenuEntry.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/ToggleMenuEntry.java index bf250f086..e47ae5ef5 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/entries/ToggleMenuEntry.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/entries/ToggleMenuEntry.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules.entries; +package me.shedaniel.rei.impl.client.gui.overlay.menu.entries; import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; @@ -32,8 +32,7 @@ import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.modules.AbstractMenuEntry; +import me.shedaniel.rei.impl.client.gui.overlay.menu.AbstractMenuEntry; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.Component; @@ -118,7 +117,7 @@ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { ScissorsHandler.INSTANCE.clearScissors(); matrices.pushPose(); matrices.translate(0, 0, -400); - ScreenOverlayImpl.getInstance().renderTooltip(matrices, tooltip); + REIRuntime.getInstance().getOverlay().orElseThrow().renderTooltip(matrices, tooltip); matrices.popPose(); for (Rectangle area : areas) { ScissorsHandler.INSTANCE.scissor(area); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/util/Weather.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/provider/OverlayMenuEntryProvider.java similarity index 61% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/util/Weather.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/provider/OverlayMenuEntryProvider.java index 09fbd0024..ae21ca415 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/util/Weather.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/menu/provider/OverlayMenuEntryProvider.java @@ -21,41 +21,23 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.common.util; +package me.shedaniel.rei.impl.client.gui.overlay.menu.provider; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.impl.client.ClientInternals; import org.jetbrains.annotations.ApiStatus; +import java.util.List; + @ApiStatus.Internal -public enum Weather { - CLEAR(0, "text.rei.weather.clear"), - RAIN(1, "text.rei.weather.rain"), - THUNDER(2, "text.rei.weather.thunder"); - - private final int id; - private final String translateKey; +public interface OverlayMenuEntryProvider { + List PROVIDERS = ClientInternals.resolveServices(OverlayMenuEntryProvider.class); - Weather(int id, String translateKey) { - this.id = id; - this.translateKey = translateKey; - } - - public static Weather byId(int id) { - return byId(id, CLEAR); - } - - public static Weather byId(int id, Weather defaultWeather) { - for (Weather weather : values()) { - if (weather.id == id) - return weather; - } - return defaultWeather; - } - - public int getId() { - return id; - } + List provide(Type type); - public String getTranslateKey() { - return translateKey; + enum Type { + CRAFTABLE_FILTER, + CONFIG, + ; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayTooltipComponent.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/DisplayTooltipComponent.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayTooltipComponent.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/DisplayTooltipComponent.java index 7afa419ed..4c92004dd 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayTooltipComponent.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/DisplayTooltipComponent.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.overlay.widgets; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Rectangle; diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/DisplayedEntryWidget.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/DisplayedEntryWidget.java new file mode 100644 index 000000000..149fdd118 --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/DisplayedEntryWidget.java @@ -0,0 +1,248 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.widgets; + +import com.google.common.base.Suppliers; +import me.shedaniel.rei.api.client.ClientHelper; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.config.ItemCheatingMode; +import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; +import me.shedaniel.rei.api.client.gui.widgets.Slot; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; +import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; +import me.shedaniel.rei.api.client.view.Views; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.client.provider.AutoCraftingEvaluator; +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.ConcurrentModificationException; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +public abstract class DisplayedEntryWidget extends GuiComponent implements UnaryOperator, Slot.ActionPredicate { + public final Slot slot; + private long lastCheckTime = -1; + private long lastCheckedTime = -1; + private Display display; + private Supplier displayTooltipComponent; + + public int backupY; + + protected DisplayedEntryWidget(Slot slot) { + this.slot = slot; + slot.tooltipProcessor(this); + slot.noHighlightIfEmpty(); + slot.tooltipsEnabled(s -> !ClientHelper.getInstance().isCheating() || Minecraft.getInstance().screen instanceof DisplayScreen || Minecraft.getInstance().player.containerMenu.getCarried().isEmpty()); + slot.action(this); + this.backupY = slot.getBounds().y; + } + + @Override + public boolean doMouse(Slot slot, double mouseX, double mouseY, int button) { + if (ClientHelper.getInstance().isCheating() && !Screen.hasControlDown() && !(Minecraft.getInstance().screen instanceof DisplayScreen)) { + EntryStack entry = slot.getCurrentEntry().copy(); + if (!entry.isEmpty()) { + if (entry.getType() != VanillaEntryTypes.ITEM) { + EntryStack cheatsAs = entry.cheatsAs(); + entry = cheatsAs.isEmpty() ? entry : cheatsAs; + } + if (entry.getValueType() == ItemStack.class) { + boolean all; + if (ConfigObject.getInstance().getItemCheatingMode() == ItemCheatingMode.REI_LIKE) { + all = button == 1 || Screen.hasShiftDown(); + } else { + all = button != 1 || Screen.hasShiftDown(); + } + entry.castValue().setCount(!all ? 1 : entry.castValue().getMaxStackSize()); + } + return ClientHelper.getInstance().tryCheatingEntry(entry); + } + } + + if (!(Minecraft.getInstance().screen instanceof DisplayScreen) && Screen.hasControlDown()) { + try { + TransferHandler handler = getTransferHandler(true); + + if (handler != null) { + AbstractContainerScreen containerScreen = REIRuntime.getInstance().getPreviousContainerScreen(); + TransferHandler.Context context = TransferHandler.Context.create(true, Screen.hasShiftDown() || button == 1, containerScreen, display); + TransferHandler.Result transferResult = handler.handle(context); + + if (transferResult.isBlocking()) { + Widgets.produceClickSound(); + if (transferResult.isReturningToScreen() && Minecraft.getInstance().screen != containerScreen) { + Minecraft.getInstance().setScreen(containerScreen); + REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); + } + return true; + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + + return false; + } + + @Override + public boolean doKey(Slot slot, int keyCode, int scanCode, int modifiers) { + if (ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen)) { + EntryStack entry = slot.getCurrentEntry().copy(); + if (!entry.isEmpty()) { + if (entry.getType() != VanillaEntryTypes.ITEM) { + EntryStack cheatsAs = entry.cheatsAs(); + entry = cheatsAs.isEmpty() ? entry : cheatsAs; + } + if (entry.getValueType() == ItemStack.class) { + entry.castValue().setCount(entry.castValue().getMaxStackSize()); + + KeyMapping[] keyHotbarSlots = Minecraft.getInstance().options.keyHotbarSlots; + for (int i = 0; i < keyHotbarSlots.length; i++) { + if (keyHotbarSlots[i].matches(keyCode, scanCode)) { + return ClientHelper.getInstance().tryCheatingEntryTo(entry, i); + } + } + } + } + } + + return false; + } + + @Override + public Tooltip apply(Tooltip tooltip) { + if (!(Minecraft.getInstance().screen instanceof DisplayScreen)) { + boolean exists = getTransferHandler(false) != null; + + if (!exists) { + if (lastCheckedTime == -1 || Util.getMillis() - lastCheckedTime > 400) { + lastCheckedTime = Util.getMillis(); + } + + if (Util.getMillis() - lastCheckedTime > 200) { + lastCheckedTime = -1; + exists = getTransferHandler(true) != null; + } + } else { + lastCheckedTime = -1; + } + + if (exists) { + tooltip.add(new TranslatableComponent("text.auto_craft.move_items.tooltip").withStyle(ChatFormatting.YELLOW)); + tooltip.add((ClientTooltipComponent) displayTooltipComponent.get()); + } + } + + return tooltip; + } + + @Nullable + private TransferHandler _getTransferHandler() { + lastCheckTime = Util.getMillis(); + + if (PluginManager.areAnyReloading()) { + return null; + } + + try { + DisplayRegistry displayRegistry = DisplayRegistry.getInstance(); + CategoryRegistry categoryRegistry = CategoryRegistry.getInstance(); + Map, Boolean> filteringQuickCraftCategories = ConfigObject.getInstance().getFilteringQuickCraftCategories(); + for (Map.Entry, List> entry : displayRegistry.getAll().entrySet()) { + Optional> configuration; + if ((configuration = categoryRegistry.tryGet(entry.getKey())).isEmpty() + || categoryRegistry.isCategoryInvisible(configuration.get().getCategory())) continue; + if (!filteringQuickCraftCategories.getOrDefault(entry.getKey(), configuration.get().isQuickCraftingEnabledByDefault())) continue; + for (Display display : entry.getValue()) { + if ((!ConfigObject.getInstance().shouldFilterDisplays() || displayRegistry.isDisplayVisible(display)) + && Views.getInstance().isRecipesFor(slot.getEntries(), display)) { + AutoCraftingEvaluator.Result result = ClientInternals.getAutoCraftingEvaluator(display).get(); + + if (result.isSuccessful()) { + this.display = display; + this.displayTooltipComponent = Suppliers.memoize(() -> new DisplayTooltipComponent(display)); + return result.getSuccessfulHandler(); + } + } + } + } + } catch (ConcurrentModificationException ignored) { + display = null; + displayTooltipComponent = null; + lastCheckTime = -1; + } + + return null; + } + + private TransferHandler getTransferHandler(boolean query) { + if (PluginManager.areAnyReloading()) { + return null; + } + + if (display != null) { + if (Views.getInstance().isRecipesFor(slot.getEntries(), display)) { + AutoCraftingEvaluator.Result result = ClientInternals.getAutoCraftingEvaluator(display).get(); + + if (result.isSuccessful()) { + return result.getSuccessfulHandler(); + } + } + + display = null; + displayTooltipComponent = null; + lastCheckTime = -1; + } + + if (lastCheckTime != -1 && Util.getMillis() - lastCheckTime < 2000) { + return null; + } + + return query ? _getTransferHandler() : null; + } +} diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/OverlayWidgetProvider.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/OverlayWidgetProvider.java new file mode 100644 index 000000000..0c159ebb3 --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/OverlayWidgetProvider.java @@ -0,0 +1,47 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.widgets; + +import me.shedaniel.rei.api.client.gui.widgets.TextField; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; + +import java.util.List; +import java.util.function.BooleanSupplier; + +public interface OverlayWidgetProvider { + List PROVIDERS = ClientInternals.resolveServices(OverlayWidgetProvider.class); + + void provide(ScreenOverlay overlay, MenuAccess access, WidgetSink sink); + + interface WidgetSink { + void accept(Widget widget); + + void acceptLateRendered(Widget widget); + + void acceptTextField(TextField textField, BooleanSupplier isHighlighted); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionRenderingDebugger.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/RegionRenderingDebugger.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionRenderingDebugger.java rename to runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/RegionRenderingDebugger.java index b5e3a7e66..74f0694a5 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionRenderingDebugger.java +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/RegionRenderingDebugger.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget.region; +package me.shedaniel.rei.impl.client.gui.overlay.widgets; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; diff --git a/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ScaleIndicatorWidget.java b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ScaleIndicatorWidget.java new file mode 100644 index 000000000..5a5439fce --- /dev/null +++ b/runtime-frontend/overlay/src/main/java/me/shedaniel/rei/impl/client/gui/overlay/widgets/ScaleIndicatorWidget.java @@ -0,0 +1,72 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.overlay.widgets; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.clothconfig2.api.animator.NumberAnimator; +import me.shedaniel.clothconfig2.api.animator.ValueAnimator; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.util.Mth; + +import java.util.List; + +@SuppressWarnings("UnstableApiUsage") +public class ScaleIndicatorWidget extends Widget { + private final NumberAnimator scaleIndicator = ValueAnimator.ofDouble(0.0D) + .withConvention(() -> 0.0D, 8000); + private int x, y; + + public void setCenter(int x, int y) { + this.x = x; + this.y = y; + } + + public void set() { + this.scaleIndicator.setAs(10); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + scaleIndicator.update(delta); + if (scaleIndicator.value() > 0.04) { + matrices.pushPose(); + matrices.translate(0, 0, 500); + TextComponent component = new TextComponent(Math.round(ConfigObject.getInstance().getEntrySize() * 100) + "%"); + int width = font.width(component); + int backgroundColor = ((int) Math.round(0xa0 * Mth.clamp(scaleIndicator.value(), 0.0, 1.0))) << 24; + int textColor = ((int) Math.round(0xdd * Mth.clamp(scaleIndicator.value(), 0.0, 1.0))) << 24; + fillGradient(matrices, x - width / 2 - 2, y - 6, x + width / 2 + 2, y + 6, backgroundColor, backgroundColor); + font.draw(matrices, component, x - width / 2, y - 4, 0xFFFFFF | textColor); + matrices.popPose(); + } + } + + @Override + public List children() { + return List.of(); + } +} diff --git a/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.gui.widgets.TooltipQueue b/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.gui.widgets.TooltipQueue new file mode 100644 index 000000000..3c1bf18e1 --- /dev/null +++ b/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.gui.widgets.TooltipQueue @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.overlay.TooltipQueueImpl \ No newline at end of file diff --git a/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider b/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider new file mode 100644 index 000000000..cde887e18 --- /dev/null +++ b/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.overlay.hints.InputMethodWatcher \ No newline at end of file diff --git a/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.menu.provider.OverlayMenuEntryProvider b/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.menu.provider.OverlayMenuEntryProvider new file mode 100644 index 000000000..cde887e18 --- /dev/null +++ b/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.overlay.menu.provider.OverlayMenuEntryProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.overlay.hints.InputMethodWatcher \ No newline at end of file diff --git a/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.OverlayProvider b/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.OverlayProvider new file mode 100644 index 000000000..876eea91d --- /dev/null +++ b/runtime-frontend/overlay/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.OverlayProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.overlay.ScreenOverlayProviderImpl \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/MissingStacksTooltip.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/tooltip/MissingStacksTooltip.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/MissingStacksTooltip.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/tooltip/MissingStacksTooltip.java index 1a6868104..696384d03 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/MissingStacksTooltip.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/tooltip/MissingStacksTooltip.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.transfer; +package me.shedaniel.rei.impl.client.gui.tooltip; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; @@ -30,7 +30,6 @@ import me.shedaniel.rei.api.client.gui.SimpleDisplayRenderer; import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; @@ -54,7 +53,7 @@ public MissingStacksTooltip(List stacks) { @Override public int getHeight() { - int entrySize = EntryListWidget.entrySize(); + int entrySize = 18; int w = Math.max(1, MAX_WIDTH / entrySize); int height = Math.min(6, Mth.ceil(stacks.size() / (float) w)) * entrySize + 2; height += 12; @@ -63,7 +62,7 @@ public int getHeight() { @Override public int getWidth(Font font) { - int entrySize = EntryListWidget.entrySize(); + int entrySize = 18; int w = Math.max(1, MAX_WIDTH / entrySize); int size = stacks.size(); int width = Math.min(size, w) * entrySize; @@ -73,7 +72,7 @@ public int getWidth(Font font) { @Override public void renderImage(Font font, int x, int y, PoseStack poses, ItemRenderer renderer, int z) { - int entrySize = EntryListWidget.entrySize(); + int entrySize = 18; int w = Math.max(1, MAX_WIDTH / entrySize); int i = 0; poses.pushPose(); diff --git a/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/tooltip/MissingStacksTooltipProviderImpl.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/tooltip/MissingStacksTooltipProviderImpl.java new file mode 100644 index 000000000..66e027634 --- /dev/null +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/tooltip/MissingStacksTooltipProviderImpl.java @@ -0,0 +1,37 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.tooltip; + +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.impl.client.provider.MissingStacksTooltipProvider; +import net.minecraft.world.inventory.tooltip.TooltipComponent; + +import java.util.List; + +public class MissingStacksTooltipProviderImpl implements MissingStacksTooltipProvider { + @Override + public TooltipComponent provide(List stacks) { + return new MissingStacksTooltip(stacks); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ArrowWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ArrowWidget.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ArrowWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ArrowWidget.java index bbaaa6e9c..8afb30220 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ArrowWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ArrowWidget.java @@ -29,6 +29,7 @@ import me.shedaniel.clothconfig2.api.animator.ValueAnimator; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.Arrow; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.util.Mth; @@ -37,11 +38,11 @@ import java.util.List; import java.util.Objects; -public final class ArrowWidget extends Arrow { +final class ArrowWidget extends Arrow { private Rectangle bounds; private double animationDuration = -1; private final NumberAnimator darkBackgroundAlpha = ValueAnimator.ofFloat() - .withConvention(() -> REIRuntime.getInstance().isDarkThemeEnabled() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) + .withConvention(() -> ConfigObject.getInstance().isUsingDarkTheme() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) .asFloat(); public ArrowWidget(Rectangle bounds) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BatchedSlotsImpl.java similarity index 53% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BatchedSlotsImpl.java index 66f5c546c..dc1b2e4dc 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BatchedSlotsImpl.java @@ -21,96 +21,80 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Iterables; import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import me.shedaniel.math.Point; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.entry.renderer.BatchedEntryRenderer; import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; +import me.shedaniel.rei.api.client.gui.widgets.BatchedSlots; +import me.shedaniel.rei.api.client.gui.widgets.Slot; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.client.util.CrashReportUtils; import net.minecraft.CrashReport; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.renderer.MultiBufferSource; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableLong; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; -public class BatchedEntryRendererManager { - private boolean fastEntryRendering = ConfigObject.getInstance().doesFastEntryRendering(); - private Int2ObjectMap> grouping = new Int2ObjectOpenHashMap<>(); - private List toRender = new ArrayList<>(); +final class BatchedSlotsImpl extends BatchedSlots implements ForwardingList { + private final boolean fastEntryRendering = ConfigObject.getInstance().doesFastEntryRendering(); + private final Int2ObjectMap> grouping = new Int2ObjectOpenHashMap<>(); + private final List toRender = new ArrayList<>(); + private final List delegateList = new DelegatedSlotList(); + private int size; + public boolean debug; + public MutableInt debugSize = new MutableInt(); + public MutableLong debugTime = new MutableLong(); - public BatchedEntryRendererManager() { - } - - public BatchedEntryRendererManager(Collection widgets) { - addAll(widgets); - } - - public boolean isFastEntryRendering() { + @Override + public boolean isBatched() { return fastEntryRendering; } - public void addAll(Collection widgets) { - if (fastEntryRendering) { - for (EntryWidget widget : widgets) { - add(widget); - } - } else { - addAllSlow(widgets); - } + @Override + public List delegate() { + return delegateList; } - public void add(EntryWidget widget) { - if (fastEntryRendering) { - EntryStack currentEntry = widget.getCurrentEntry(); - try { - EntryRenderer renderer = currentEntry.getRenderer(); - if (renderer instanceof BatchedEntryRenderer) { - BatchedEntryRenderer batchedRenderer = (BatchedEntryRenderer) renderer; - EntryStack cast = currentEntry.cast(); - if (batchedRenderer.isBatched(cast)) { - Object extraData = batchedRenderer.getExtraData(cast); - int hash = batchedRenderer.getBatchIdentifier(cast, widget.getBounds(), extraData) - ^ widget.getCurrentEntry().getType().hashCode(); - List entries = grouping.get(hash); - if (entries == null) { - grouping.put(hash, entries = new ArrayList<>()); - } - entries.add(widget); - entries.add(extraData); - return; - } - } - } catch (Throwable throwable) { - CrashReport report = CrashReportUtils.essential(throwable, "Adding entry"); - CrashReportUtils.renderer(report, currentEntry); - CrashReportUtils.catchReport(report); - return; - } - } - - addSlow(widget); + @Override + public void addAllUnbatched(Collection slots) { + this.toRender.addAll(slots); + this.size += slots.size(); } - public void addAllSlow(Collection widgets) { - toRender.addAll(widgets); + @Override + public void addDebugger(MutableInt size, MutableLong time) { + this.debug = true; + this.debugSize = size; + this.debugTime = time; } - public void addSlow(EntryWidget widget) { - toRender.add(widget); + @Override + public void addUnbatched(Slot slot) { + this.toRender.add(slot); + this.size++; } + @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - render(false, null, null, matrices, mouseX, mouseY, delta); + if (this.debug) { + render(false, null, null, matrices, mouseX, mouseY, delta); + } else { + render(true, debugSize, debugTime, matrices, mouseX, mouseY, delta); + } } public void render(boolean debugTime, MutableInt size, MutableLong time, PoseStack matrices, int mouseX, int mouseY, float delta) { @@ -120,36 +104,70 @@ public void render(boolean debugTime, MutableInt size, MutableLong time, PoseSta for (int i = 0; i < extraData.length; i++) { extraData[i] = entries.get(i * 2 + 1); } - renderBatched(debugTime, size, time, matrices, mouseX, mouseY, delta, () -> new AbstractIterator<>() { + renderBatched(debugTime, size, time, matrices, mouseX, mouseY, delta, groupingAsList(entries), extraData); + } + } + if (!toRender.isEmpty()) { + renderSlow(debugTime, size, time, matrices, mouseX, mouseY, delta, toRender); + } + } + + public List groupingsAsList() { + return CollectionUtils.concatUnmodifiable((Iterable>) () -> new AbstractIterator<>() { + final Iterator> groups = grouping.values().iterator(); + + @Nullable + @Override + protected List computeNext() { + if (groups.hasNext()) { + return groupingAsList(groups.next()); + } + return endOfData(); + } + }); + } + + public List groupingAsList(List entries) { + return new AbstractList<>() { + @Override + public Slot get(int index) { + return (Slot) entries.get(index * 2); + } + + @Override + public Iterator iterator() { + return new AbstractIterator<>() { public int i = 0; @Override - protected EntryWidget computeNext() { + protected Slot computeNext() { if (i >= entries.size()) { return endOfData(); } - EntryWidget widget = (EntryWidget) entries.get(i); + Slot widget = (Slot) entries.get(i); i += 2; return widget; } - }, extraData); + }; } - } - if (!toRender.isEmpty()) { - renderSlow(debugTime, size, time, matrices, mouseX, mouseY, delta, toRender); - } + + @Override + public int size() { + return entries.size() / 2; + } + }; } - public static void renderEntries(boolean debugTime, MutableInt size, MutableLong time, boolean fastEntryRendering, PoseStack matrices, int mouseX, int mouseY, float delta, Collection entries) { + public static void renderEntries(boolean debugTime, MutableInt size, MutableLong time, boolean fastEntryRendering, PoseStack matrices, int mouseX, int mouseY, float delta, Collection entries) { if (fastEntryRendering) { - T firstWidget = Iterables.getFirst(entries, null); + Slot firstWidget = Iterables.getFirst(entries, null); if (firstWidget == null) return; EntryRenderer renderer = firstWidget.getCurrentEntry().getRenderer(); if (renderer instanceof BatchedEntryRenderer) { BatchedEntryRenderer firstRenderer = (BatchedEntryRenderer) renderer; Object[] extraData = new Object[entries.size()]; int i = 0; - for (T entry : entries) { + for (Slot entry : entries) { EntryStack currentEntry = entry.getCurrentEntry(); extraData[i++] = ((BatchedEntryRenderer) currentEntry.getRenderer()).getExtraData(currentEntry.cast()); } @@ -160,8 +178,8 @@ public static void renderEntries(boolean debugTime, Muta renderSlow(debugTime, size, time, matrices, mouseX, mouseY, delta, entries); } - private static void renderBatched(boolean debugTime, MutableInt size, MutableLong time, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable entries, Object[] extraData) { - T firstWidget = Iterables.getFirst(entries, null); + private static void renderBatched(boolean debugTime, MutableInt size, MutableLong time, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable entries, Object[] extraData) { + Slot firstWidget = Iterables.getFirst(entries, null); if (firstWidget == null) return; @SuppressWarnings("rawtypes") EntryStack first = firstWidget.getCurrentEntry(); @@ -171,7 +189,7 @@ private static void renderBatched(boolean debugTime, Mut long l = debugTime ? System.nanoTime() : 0; MultiBufferSource.BufferSource immediate = Minecraft.getInstance().renderBuffers().bufferSource(); int i = 0; - for (T entry : entries) { + for (Slot entry : entries) { try { entry.drawBackground(matrices, mouseX, mouseY, delta); } catch (Throwable throwable) { @@ -182,7 +200,7 @@ private static void renderBatched(boolean debugTime, Mut } } firstRenderer.startBatch(first, extraData[0], matrices, delta); - for (T entry : entries) { + for (Slot entry : entries) { try { @SuppressWarnings("rawtypes") EntryStack currentEntry = entry.getCurrentEntry(); @@ -199,7 +217,7 @@ private static void renderBatched(boolean debugTime, Mut immediate.endBatch(); firstRenderer.afterBase(first, extraData[0], matrices, delta); i = 0; - for (T entry : entries) { + for (Slot entry : entries) { try { @SuppressWarnings("rawtypes") EntryStack currentEntry = entry.getCurrentEntry(); @@ -212,15 +230,19 @@ private static void renderBatched(boolean debugTime, Mut } } immediate.endBatch(); - for (T entry : entries) { + for (Slot entry : entries) { try { if (entry.containsMouse(mouseX, mouseY)) { - entry.queueTooltip(matrices, mouseX, mouseY, delta); + Tooltip tooltip = entry.getCurrentTooltip(TooltipContext.of(new Point(mouseX, mouseY))); + if (tooltip != null) { + tooltip.queue(); + } - if (entry.hasHighlight()) { + if (entry.isHighlightEnabled()) { entry.drawHighlighted(matrices, mouseX, mouseY, delta); } } + entry.drawExtra(matrices, mouseX, mouseY, delta); } catch (Throwable throwable) { CrashReport report = CrashReportUtils.essential(throwable, "Rendering entry extra"); @@ -233,8 +255,8 @@ private static void renderBatched(boolean debugTime, Mut firstRenderer.endBatch(first, extraData[0], matrices, delta); } - public static void renderSlow(boolean debugTime, MutableInt size, MutableLong time, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable entries) { - for (T entry : entries) { + public static void renderSlow(boolean debugTime, MutableInt size, MutableLong time, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable entries) { + for (Slot entry : entries) { if (entry.getCurrentEntry().isEmpty()) continue; try { @@ -252,4 +274,77 @@ public static void renderSlow(boolean debugTime, Mutable } } } + + @Override + public List children() { + return null; + } + + private class DelegatedSlotList extends AbstractList { + private final List unmodifiable = CollectionUtils.concatUnmodifiable(toRender, + groupingsAsList()); + + @Override + public void add(int index, Slot element) { + add(element); + } + + @Override + public int size() { + return size; + } + + @Override + public boolean add(Slot widget) { + if (fastEntryRendering) { + EntryStack currentEntry = widget.getCurrentEntry(); + try { + EntryRenderer renderer = currentEntry.getRenderer(); + if (renderer instanceof BatchedEntryRenderer) { + BatchedEntryRenderer batchedRenderer = (BatchedEntryRenderer) renderer; + EntryStack cast = currentEntry.cast(); + if (batchedRenderer.isBatched(cast)) { + Object extraData = batchedRenderer.getExtraData(cast); + int hash = batchedRenderer.getBatchIdentifier(cast, widget.getBounds(), extraData) + ^ widget.getCurrentEntry().getType().hashCode(); + List entries = grouping.get(hash); + if (entries == null) { + grouping.put(hash, entries = new ArrayList<>()); + } + entries.add(widget); + entries.add(extraData); + size++; + return true; + } + } + } catch (Throwable throwable) { + CrashReport report = CrashReportUtils.essential(throwable, "Adding entry"); + CrashReportUtils.renderer(report, currentEntry); + CrashReportUtils.catchReport(report); + return false; + } + } + + addUnbatched(widget); + return true; + } + + @Override + public Slot get(int index) { + return unmodifiable.get(index); + } + + @Override + public boolean addAll(Collection widgets) { + if (fastEntryRendering) { + for (Slot widget : widgets) { + add(widget); + } + } else { + addAllUnbatched(widgets); + } + + return true; + } + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BurningFireWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BurningFireWidget.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BurningFireWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BurningFireWidget.java index 3f0a998d2..4140de261 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BurningFireWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/BurningFireWidget.java @@ -29,6 +29,7 @@ import me.shedaniel.clothconfig2.api.animator.ValueAnimator; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.BurningFire; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.util.Mth; @@ -37,11 +38,11 @@ import java.util.List; import java.util.Objects; -public final class BurningFireWidget extends BurningFire { +final class BurningFireWidget extends BurningFire { private Rectangle bounds; private double animationDuration = -1; private final NumberAnimator darkBackgroundAlpha = ValueAnimator.ofFloat() - .withConvention(() -> REIRuntime.getInstance().isDarkThemeEnabled() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) + .withConvention(() -> ConfigObject.getInstance().isUsingDarkTheme() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) .asFloat(); public BurningFireWidget(Rectangle bounds) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ButtonWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ButtonWidget.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ButtonWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ButtonWidget.java index a6b1689d2..ae46a15d4 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ButtonWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ButtonWidget.java @@ -32,6 +32,7 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.Button; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import net.minecraft.client.gui.GuiComponent; @@ -51,7 +52,7 @@ import java.util.function.Consumer; import java.util.function.Function; -public class ButtonWidget extends Button { +final class ButtonWidget extends Button { private static final ResourceLocation BUTTON_LOCATION = new ResourceLocation("roughlyenoughitems", "textures/gui/button.png"); private static final ResourceLocation BUTTON_LOCATION_DARK = new ResourceLocation("roughlyenoughitems", "textures/gui/button_dark.png"); private Rectangle bounds; @@ -78,7 +79,7 @@ public ButtonWidget(Rectangle rectangle, Component text) { this.bounds = Objects.requireNonNull(rectangle); this.text = Objects.requireNonNull(text); this.darkBackground = ValueAnimator.ofColor() - .withConvention(() -> Color.ofTransparent(REIRuntime.getInstance().isDarkThemeEnabled() ? 0xFFFFFFFF : 0x00FFFFFF), ValueAnimator.typicalTransitionTime()); + .withConvention(() -> Color.ofTransparent(ConfigObject.getInstance().isUsingDarkTheme() ? 0xFFFFFFFF : 0x00FFFFFF), ValueAnimator.typicalTransitionTime()); this.alpha = ValueProvider.constant(1.0); } @@ -303,7 +304,7 @@ public final int getTextureId(Point mouse) { } protected void renderBackground(PoseStack matrices, int x, int y, int width, int height, int textureOffset) { - renderBackground(matrices, x, y, width, height, textureOffset, REIRuntime.getInstance().isDarkThemeEnabled(), Color.ofTransparent(0xFFFFFFFF)); + renderBackground(matrices, x, y, width, height, textureOffset, ConfigObject.getInstance().isUsingDarkTheme(), Color.ofTransparent(0xFFFFFFFF)); } protected void renderBackground(PoseStack matrices, int x, int y, int width, int height, int textureOffset, boolean dark, Color color) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DelegateWidgetWithTranslate.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DelegateWidgetWithTranslate.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DelegateWidgetWithTranslate.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DelegateWidgetWithTranslate.java index e90c1cb19..5ccbf70da 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DelegateWidgetWithTranslate.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DelegateWidgetWithTranslate.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; @@ -34,10 +34,10 @@ import java.util.function.Supplier; -public class DelegateWidgetWithTranslate extends DelegateWidget { +class DelegateWidgetWithTranslate extends DelegateWidget { private final Supplier translate; - public DelegateWidgetWithTranslate(WidgetWithBounds widget, Supplier translate) { + DelegateWidgetWithTranslate(WidgetWithBounds widget, Supplier translate) { super(widget); this.translate = translate; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DrawableWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DrawableWidget.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DrawableWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DrawableWidget.java index 18afa3696..2fc13d483 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DrawableWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/DrawableWidget.java @@ -31,7 +31,7 @@ import java.util.Collections; import java.util.List; -public final class DrawableWidget extends Widget { +final class DrawableWidget extends Widget { private DrawableConsumer drawable; public DrawableWidget(DrawableConsumer drawable) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/EntryWidget.java similarity index 55% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/EntryWidget.java index bc626fb2c..e3e6052b1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/EntryWidget.java @@ -21,9 +21,8 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; -import com.google.common.base.Suppliers; import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; @@ -33,7 +32,6 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; @@ -44,72 +42,62 @@ import me.shedaniel.rei.api.client.gui.widgets.Slot; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; -import me.shedaniel.rei.api.client.overlay.ScreenOverlay; -import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; -import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; -import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; +import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.search.method.InputMethod; import me.shedaniel.rei.api.client.view.ViewSearchBuilder; -import me.shedaniel.rei.api.common.category.CategoryIdentifier; -import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.plugins.PluginManager; import me.shedaniel.rei.api.common.util.FormattingUtils; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; import me.shedaniel.rei.impl.client.gui.InternalTextures; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; -import me.shedaniel.rei.impl.client.view.ViewsImpl; import net.minecraft.ChatFormatting; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.resources.language.I18n; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.SoundEvents; import net.minecraft.util.Mth; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.Supplier; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; -public class EntryWidget extends Slot implements DraggableStackProviderWidget { - @ApiStatus.Internal - public static long stackDisplayOffset = 0; +@SuppressWarnings("UnstableApiUsage") +final class EntryWidget extends Slot implements DraggableStackProviderWidget { + private static long stackDisplayOffset = 0; + private final NumberAnimator darkHighlightedAlpha = ValueAnimator.ofFloat() + .withConvention(() -> ConfigObject.getInstance().isUsingDarkTheme() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()); + private final Rectangle bounds; @ApiStatus.Internal - private byte noticeMark = 0; - protected boolean highlight = true; - protected boolean tooltips = true; - protected boolean background = true; - protected boolean interactable = true; - protected boolean interactableFavorites = true; - protected boolean wasClicked = false; - private Rectangle bounds; + private byte noticeMark = Slot.UN_MARKED; + private long cyclingInterval = 1000L; + private Predicate highlight = slot -> true; + private Predicate tooltips = slot -> true; + private Predicate background = slot -> true; + private Predicate interactable = slot -> true; + private Predicate interactableFavorites = slot -> true; + private Function, @Nullable FavoriteEntry> favoriteEntryFunction = stack -> { + FavoriteEntry entry = FavoriteEntry.fromEntryStack(stack.normalize()); + return entry.isInvalid() ? null : entry; + }; + private BiPredicate containsPointFunction = (slot, point) -> { + Rectangle bounds = slot.getBounds(); + return point.x >= bounds.x + 1 && point.y >= bounds.y + 1 && point.x <= bounds.getMaxX() - 1 && point.y <= bounds.getMaxY() - 1; + }; + private boolean wasClicked = false; private List> entryStacks; @Nullable private Set> tooltipProcessors; - public ResourceLocation tagMatch; - public boolean removeTagMatch = true; - - private long lastCheckTime = -1; - private long lastCheckedTime = -1; - private Display display; - private Supplier displayTooltipComponent; + @Nullable + private Set actions; - public EntryWidget(Point point) { + EntryWidget(Point point) { this(new Rectangle(point.x - 1, point.y - 1, 18, 18)); } @@ -118,22 +106,6 @@ public EntryWidget(Rectangle bounds) { this.entryStacks = Collections.emptyList(); } - @Override - public EntryWidget unmarkInputOrOutput() { - noticeMark = 0; - return this; - } - - public EntryWidget markIsInput() { - noticeMark = 1; - return this; - } - - public EntryWidget markIsOutput() { - noticeMark = 2; - return this; - } - @Override public byte getNoticeMark() { return noticeMark; @@ -146,110 +118,87 @@ public void setNoticeMark(byte noticeMark) { @Override public void setInteractable(boolean interactable) { - interactable(interactable); + this.interactable = slot -> interactable; + this.interactableFavorites = this.interactableFavorites.and(slot -> interactable); } @Override public boolean isInteractable() { - return this.interactable; + return this.interactable.test(this); } @Override public void setInteractableFavorites(boolean interactableFavorites) { - interactableFavorites(interactableFavorites); + this.interactableFavorites = this.interactable.and(slot -> interactableFavorites); } @Override public boolean isInteractableFavorites() { - return interactableFavorites; - } - - public EntryWidget disableInteractions() { - return interactable(false); + return interactableFavorites.test(this); } @Override - public EntryWidget interactable(boolean b) { - interactable = b; - interactableFavorites = interactableFavorites && interactable; - return this; - } - - public EntryWidget disableFavoritesInteractions() { - return interactableFavorites(false); + public boolean isHighlightEnabled() { + return highlight.test(this); } @Override - public EntryWidget interactableFavorites(boolean b) { - interactableFavorites = b && interactable; - return this; + public void setHighlightEnabled(Predicate highlights) { + this.highlight = highlights; } - public EntryWidget noHighlight() { - return highlight(false); - } - - public EntryWidget highlight(boolean b) { - highlight = b; + @Override + public Slot highlightEnabled(Predicate highlight) { + this.highlight = this.highlight.and(highlight); return this; } @Override - public boolean isHighlightEnabled() { - return highlight; + public void setTooltipsEnabled(Predicate tooltipsEnabled) { + this.tooltips = tooltipsEnabled; } @Override - public void setHighlightEnabled(boolean highlights) { - highlight(highlights); - } - - public EntryWidget noTooltips() { - return tooltips(false); - } - - public EntryWidget tooltips(boolean b) { - tooltips = b; + public Slot tooltipsEnabled(Predicate tooltipsEnabled) { + this.tooltips = this.tooltips.and(tooltipsEnabled); return this; } - @Override - public void setTooltipsEnabled(boolean tooltipsEnabled) { - tooltips(tooltipsEnabled); - } - @Override public boolean isTooltipsEnabled() { - return tooltips; + return tooltips.test(this); } - public EntryWidget noBackground() { - return background(false); + @Override + public void setBackgroundEnabled(Predicate backgroundEnabled) { + this.background = backgroundEnabled; } - public EntryWidget background(boolean b) { - background = b; + @Override + public Slot backgroundEnabled(Predicate backgroundEnabled) { + this.background = this.background.and(backgroundEnabled); return this; } @Override - public void setBackgroundEnabled(boolean backgroundEnabled) { - background(backgroundEnabled); + public boolean isBackgroundEnabled() { + return background.test(this); } @Override - public boolean isBackgroundEnabled() { - return background; + public void setCyclingInterval(long cyclingInterval) { + this.cyclingInterval = cyclingInterval; } - public EntryWidget clearStacks() { - entryStacks = Collections.emptyList(); - return this; + @Override + public long getCyclingInterval() { + return cyclingInterval; } @Override public Slot clearEntries() { - return clearStacks(); + this.entryStacks = Collections.emptyList(); + return this; } @Override @@ -263,7 +212,6 @@ public EntryWidget entry(EntryStack stack) { } entryStacks.add(stack); } - if (removeTagMatch) tagMatch = null; return this; } @@ -274,7 +222,6 @@ public EntryWidget entries(Collection> stacks) { entryStacks = new ArrayList<>(entryStacks); } entryStacks.addAll(stacks); - if (removeTagMatch) tagMatch = null; } return this; } @@ -286,11 +233,7 @@ public EntryStack getCurrentEntry() { return EntryStack.empty(); if (size == 1) return entryStacks.get(0); - return entryStacks.get(Mth.floor(((System.currentTimeMillis() + stackDisplayOffset) / getCyclingInterval() % (double) size))); - } - - protected long getCyclingInterval() { - return 1000; + return entryStacks.get(Mth.floor(((System.currentTimeMillis() + stackDisplayOffset) / cyclingInterval % (double) size))); } @Override @@ -308,165 +251,79 @@ public Rectangle getInnerBounds() { return new Rectangle(bounds.x + 1, bounds.y + 1, bounds.width - 2, bounds.height - 2); } - @Nullable - private TransferHandler _getTransferHandler() { - lastCheckTime = Util.getMillis(); - - if (PluginManager.areAnyReloading()) { - return null; - } - - try { - DisplayRegistry displayRegistry = DisplayRegistry.getInstance(); - CategoryRegistry categoryRegistry = CategoryRegistry.getInstance(); - Map, Boolean> filteringQuickCraftCategories = ConfigObject.getInstance().getFilteringQuickCraftCategories(); - for (Map.Entry, List> entry : displayRegistry.getAll().entrySet()) { - Optional> configuration; - if ((configuration = categoryRegistry.tryGet(entry.getKey())).isEmpty() - || categoryRegistry.isCategoryInvisible(configuration.get().getCategory())) continue; - if (!filteringQuickCraftCategories.getOrDefault(entry.getKey(), configuration.get().isQuickCraftingEnabledByDefault())) continue; - for (Display display : entry.getValue()) { - if ((!ConfigObject.getInstance().shouldFilterDisplays() || displayRegistry.isDisplayVisible(display)) - && ViewsImpl.isRecipesFor(getEntries(), display)) { - AutoCraftingEvaluator.AutoCraftingResult result = AutoCraftingEvaluator.evaluateAutoCrafting(false, false, display, null); - if (result.successful) { - this.display = display; - this.displayTooltipComponent = Suppliers.memoize(() -> new DisplayTooltipComponent(display)); - return result.successfulHandler; - } - } - } - } - } catch (ConcurrentModificationException ignored) { - display = null; - displayTooltipComponent = null; - lastCheckTime = -1; - } - - return null; - } - - private TransferHandler getTransferHandler(boolean query) { - if (PluginManager.areAnyReloading()) { - return null; - } - - if (display != null) { - if (ViewsImpl.isRecipesFor(getEntries(), display)) { - AutoCraftingEvaluator.AutoCraftingResult result = AutoCraftingEvaluator.evaluateAutoCrafting(false, false, display, null); - if (result.successful) { - return result.successfulHandler; - } - } - - display = null; - displayTooltipComponent = null; - lastCheckTime = -1; - } - - if (lastCheckTime != -1 && Util.getMillis() - lastCheckTime < 2000) { - return null; - } - - return query ? _getTransferHandler() : null; - } - @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { drawBackground(matrices, mouseX, mouseY, delta); drawCurrentEntry(matrices, mouseX, mouseY, delta); - boolean highlighted = containsMouse(mouseX, mouseY); - if (hasTooltips() && highlighted) { + boolean hovered = containsMouse(mouseX, mouseY); + if (isTooltipsEnabled() && hovered) { queueTooltip(matrices, mouseX, mouseY, delta); } - if (hasHighlight() && highlighted) { + if (isHighlightEnabled() && hovered) { drawHighlighted(matrices, mouseX, mouseY, delta); } drawExtra(matrices, mouseX, mouseY, delta); } - public final boolean hasTooltips() { - return isTooltipsEnabled(); - } - - public final boolean hasHighlight() { - return isHighlightEnabled(); - } - private final NumberAnimator darkBackgroundAlpha = ValueAnimator.ofFloat() - .withConvention(() -> REIRuntime.getInstance().isDarkThemeEnabled() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) + .withConvention(() -> ConfigObject.getInstance().isUsingDarkTheme() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) .asFloat(); - protected void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (background) { - darkBackgroundAlpha.update(delta); - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(770, 771, 1, 0); - RenderSystem.blendFunc(770, 771); - RenderSystem.setShaderTexture(0, InternalTextures.CHEST_GUI_TEXTURE); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - blit(matrices, bounds.x, bounds.y, 0, 222, bounds.width, bounds.height); - if (darkBackgroundAlpha.value() > 0.0F) { - RenderSystem.setShaderTexture(0, InternalTextures.CHEST_GUI_TEXTURE_DARK); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, darkBackgroundAlpha.value()); - blit(matrices, bounds.x, bounds.y, 0, 222, bounds.width, bounds.height); + @Override + public void drawBackground(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (isBackgroundEnabled()) { + if (bounds.width == 16 && bounds.height == 16) { + darkBackgroundAlpha.update(delta); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(770, 771, 1, 0); + RenderSystem.blendFunc(770, 771); + RenderSystem.setShaderTexture(0, InternalTextures.CHEST_GUI_TEXTURE); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + blit(matrices, bounds.x, bounds.y, 0, 222, bounds.width, bounds.height); + if (darkBackgroundAlpha.value() > 0.0F) { + RenderSystem.setShaderTexture(0, InternalTextures.CHEST_GUI_TEXTURE_DARK); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, darkBackgroundAlpha.value()); + blit(matrices, bounds.x, bounds.y, 0, 222, bounds.width, bounds.height); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + } + } else { + Widgets.createSlotBase(bounds).render(matrices, mouseX, mouseY, delta); } } } - protected void drawCurrentEntry(PoseStack matrices, int mouseX, int mouseY, float delta) { + private void drawCurrentEntry(PoseStack matrices, int mouseX, int mouseY, float delta) { EntryStack entry = getCurrentEntry(); entry.setZ(100); entry.render(matrices, getInnerBounds(), mouseX, mouseY, delta); } - protected void queueTooltip(PoseStack matrices, int mouseX, int mouseY, float delta) { - Tooltip tooltip = getCurrentTooltip(TooltipContext.ofMouse().getPoint()); + private void queueTooltip(PoseStack matrices, int mouseX, int mouseY, float delta) { + Tooltip tooltip = getCurrentTooltip(TooltipContext.ofMouse()); if (tooltip != null) { tooltip.queue(); } } - protected void drawExtra(PoseStack matrices, int mouseX, int mouseY, float delta) {} + @Override + public void drawExtra(PoseStack matrices, int mouseX, int mouseY, float delta) {} @Override @Nullable - public Tooltip getCurrentTooltip(Point point) { - Tooltip tooltip = getCurrentEntry().getTooltip(TooltipContext.of(point)); - - if (tooltip != null && !(Minecraft.getInstance().screen instanceof DisplayScreen)) { - boolean exists = getTransferHandler(false) != null; - - if (!exists) { - if (lastCheckedTime == -1 || Util.getMillis() - lastCheckedTime > 400) { - lastCheckedTime = Util.getMillis(); - } - - if (Util.getMillis() - lastCheckedTime > 200) { - lastCheckedTime = -1; - exists = getTransferHandler(true) != null; - } - } else { - lastCheckedTime = -1; - } - - if (exists) { - tooltip.add(new TranslatableComponent("text.auto_craft.move_items.tooltip").withStyle(ChatFormatting.YELLOW)); - tooltip.add((ClientTooltipComponent) displayTooltipComponent.get()); - } - } + public Tooltip getCurrentTooltip(TooltipContext context) { + Tooltip tooltip = getCurrentEntry().getTooltip(context); if (tooltip != null) { - if (interactableFavorites && ConfigObject.getInstance().doDisplayFavoritesTooltip() && !ConfigObject.getInstance().getFavoriteKeyCode().isUnknown()) { + if (isInteractableFavorites() && ConfigObject.getInstance().doDisplayFavoritesTooltip() && !ConfigObject.getInstance().getFavoriteKeyCode().isUnknown()) { String name = ConfigObject.getInstance().getFavoriteKeyCode().getLocalizedName().getString(); - if (reverseFavoritesAction()) + if (isFavorites()) { tooltip.addAllTexts(Stream.of(I18n.get("text.rei.remove_favorites_tooltip", name).split("\n")) .map(TextComponent::new).collect(Collectors.toList())); - else + } else { tooltip.addAllTexts(Stream.of(I18n.get("text.rei.favorites_tooltip", name).split("\n")) .map(TextComponent::new).collect(Collectors.toList())); + } } if (tooltipProcessors != null) { @@ -492,11 +349,8 @@ public Tooltip getCurrentTooltip(Point point) { return tooltip; } - private final NumberAnimator darkHighlightedAlpha = ValueAnimator.ofFloat() - .withConvention(() -> REIRuntime.getInstance().isDarkThemeEnabled() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) - .asFloat(); - - protected void drawHighlighted(PoseStack matrices, int mouseX, int mouseY, float delta) { + @Override + public void drawHighlighted(PoseStack matrices, int mouseX, int mouseY, float delta) { darkHighlightedAlpha.update(delta); RenderSystem.disableDepthTest(); RenderSystem.colorMask(true, true, true, false); @@ -513,33 +367,58 @@ public List children() { return Collections.emptyList(); } - protected boolean wasClicked() { - boolean b = this.wasClicked; + private boolean wasClicked() { + boolean wasClicked = this.wasClicked; this.wasClicked = false; - return b; + return wasClicked; } + @Override public void tooltipProcessor(UnaryOperator operator) { if (tooltipProcessors == null) { tooltipProcessors = Collections.singleton(operator); - } else { + } else if (!tooltipProcessors.contains(operator)) { if (!(tooltipProcessors instanceof LinkedHashSet)) { tooltipProcessors = new LinkedHashSet<>(tooltipProcessors); } tooltipProcessors.add(operator); + } else if (tooltipProcessors.size() == 1) { + tooltipProcessors = Collections.singleton(operator); + } else { + tooltipProcessors.remove(operator); + tooltipProcessors.add(operator); + } + } + + @Override + public void action(ActionPredicate predicate) { + if (actions == null) { + actions = Collections.singleton(predicate); + } else if (!actions.contains(predicate)) { + if (!(actions instanceof LinkedHashSet)) { + actions = new LinkedHashSet<>(actions); + } + actions.add(predicate); + } else if (actions.size() == 1) { + actions = Collections.singleton(predicate); + } else { + actions.remove(predicate); + actions.add(predicate); } } @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (containsMouse(mouseX, mouseY)) + if (containsMouse(mouseX, mouseY)) { this.wasClicked = true; + } + return super.mouseClicked(mouseX, mouseY, button); } @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - if (REIRuntimeImpl.isWithinRecipeViewingScreen && entryStacks.size() > 1 && containsMouse(mouseX, mouseY)) { + if (minecraft.screen instanceof DisplayScreen && entryStacks.size() > 1 && containsMouse(mouseX, mouseY)) { if (amount < 0) { EntryWidget.stackDisplayOffset = ((System.currentTimeMillis() + stackDisplayOffset) / 1000 - 1) * 1000; return true; @@ -553,59 +432,38 @@ public boolean mouseScrolled(double mouseX, double mouseY, double amount) { @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { - if (!interactable) + if (!isInteractable()) return false; if (wasClicked() && containsMouse(mouseX, mouseY)) { - if (doAction(mouseX, mouseY, button)) { - return true; - } + return doAction(mouseX, mouseY, button); } return false; } - protected boolean doAction(double mouseX, double mouseY, int button) { - if (interactableFavorites && ConfigObject.getInstance().isFavoritesEnabled() && !getCurrentEntry().isEmpty()) { + private boolean doAction(double mouseX, double mouseY, int button) { + if (actions != null) { + for (ActionPredicate action : actions) { + if (action.doMouse(this, mouseX, mouseY, button)) { + return true; + } + } + } + + if (isInteractableFavorites() && ConfigObject.getInstance().isFavoritesEnabled() && !getCurrentEntry().isEmpty()) { ModifierKeyCode keyCode = ConfigObject.getInstance().getFavoriteKeyCode(); if (keyCode.matchesMouse(button)) { FavoriteEntry favoriteEntry = asFavoriteEntry(); if (favoriteEntry != null) { - if (reverseFavoritesAction()) { + if (isFavorites()) { ConfigObject.getInstance().getFavoriteEntries().remove(favoriteEntry); } else { ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry); } - ConfigManager.getInstance().saveConfig(); - FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); - if (favoritesListWidget != null) - favoritesListWidget.updateSearch(); return true; } } } - if (!(Minecraft.getInstance().screen instanceof DisplayScreen) && Screen.hasControlDown()) { - try { - TransferHandler handler = getTransferHandler(true); - - if (handler != null) { - AbstractContainerScreen containerScreen = REIRuntime.getInstance().getPreviousContainerScreen(); - TransferHandler.Context context = TransferHandler.Context.create(true, Screen.hasShiftDown() || button == 1, containerScreen, display); - TransferHandler.Result transferResult = handler.handle(context); - - if (transferResult.isBlocking()) { - minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - if (transferResult.isReturningToScreen() && Minecraft.getInstance().screen != containerScreen) { - Minecraft.getInstance().setScreen(containerScreen); - REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); - } - return true; - } - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - if ((ConfigObject.getInstance().getRecipeKeybind().getType() != InputConstants.Type.MOUSE && button == 0) || ConfigObject.getInstance().getRecipeKeybind().matchesMouse(button)) return ViewSearchBuilder.builder().addRecipesFor(getCurrentEntry()).open(); else if ((ConfigObject.getInstance().getUsageKeybind().getType() != InputConstants.Type.MOUSE && button == 1) || ConfigObject.getInstance().getUsageKeybind().matchesMouse(button)) @@ -614,25 +472,39 @@ else if ((ConfigObject.getInstance().getUsageKeybind().getType() != InputConstan return false; } - @ApiStatus.Internal - @Nullable - protected FavoriteEntry asFavoriteEntry() { - FavoriteEntry entry = FavoriteEntry.fromEntryStack(getCurrentEntry().normalize()); - return entry.isInvalid() ? null : entry; + @Override + public void setFavoriteEntryFunction(Function, FavoriteEntry> function) { + this.favoriteEntryFunction = function; + } + + @Override + public Function, FavoriteEntry> getFavoriteEntryFunction() { + return favoriteEntryFunction; + } + + @Override + public void setContainsPointFunction(BiPredicate containsPointFunction) { + this.containsPointFunction = containsPointFunction; + } + + @Override + public void appendContainsPointFunction(BiPredicate function) { + containsPointFunction = containsPointFunction.and(function); } @ApiStatus.Internal - public boolean cancelDeleteItems(EntryStack stack) { - return false; + @Nullable + private FavoriteEntry asFavoriteEntry() { + return favoriteEntryFunction.apply(getCurrentEntry()); } - protected boolean reverseFavoritesAction() { - return false; + private boolean isFavorites() { + return noticeMark == Slot.FAVORITE; } @Override public boolean containsMouse(double mouseX, double mouseY) { - return mouseX >= bounds.x + 1 && mouseY >= bounds.y + 1 && mouseX <= bounds.getMaxX() - 1 && mouseY <= bounds.getMaxY() - 1; + return containsPointFunction.test(this, new Point(mouseX, mouseY)); } @Override @@ -645,29 +517,35 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { } public boolean keyPressedIgnoreContains(int keyCode, int scanCode, int modifiers) { - if (!interactable) return false; + if (!isInteractable()) return false; + + if (actions != null) { + for (ActionPredicate action : actions) { + if (action.doKey(this, keyCode, scanCode, modifiers)) { + return true; + } + } + } - if (interactableFavorites && ConfigObject.getInstance().isFavoritesEnabled() && !getCurrentEntry().isEmpty()) { + if (isInteractableFavorites() && ConfigObject.getInstance().isFavoritesEnabled() && !getCurrentEntry().isEmpty()) { if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) { FavoriteEntry favoriteEntry = asFavoriteEntry(); if (favoriteEntry != null) { - if (reverseFavoritesAction()) { + if (isFavorites()) { ConfigObject.getInstance().getFavoriteEntries().remove(favoriteEntry); } else { ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry); } - ConfigManager.getInstance().saveConfig(); - FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); - if (favoritesListWidget != null) - favoritesListWidget.updateSearch(); return true; } } } + if (ConfigObject.getInstance().getRecipeKeybind().matchesKey(keyCode, scanCode)) return ViewSearchBuilder.builder().addRecipesFor(getCurrentEntry()).open(); else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(keyCode, scanCode)) return ViewSearchBuilder.builder().addUsagesFor(getCurrentEntry()).open(); + return false; } @@ -676,7 +554,7 @@ else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(keyCode, scanCo public DraggableStack getHoveredStack(DraggingContext context, double mouseX, double mouseY) { if (!getCurrentEntry().isEmpty() && containsMouse(mouseX, mouseY)) { return new DraggableStack() { - EntryStack stack = getCurrentEntry().copy() + final EntryStack stack = getCurrentEntry().copy() .removeSetting(EntryStack.Settings.RENDERER) .removeSetting(EntryStack.Settings.FLUID_RENDER_RATIO); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/FillRectangleDrawableConsumer.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/FillRectangleDrawableConsumer.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/FillRectangleDrawableConsumer.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/FillRectangleDrawableConsumer.java index 685d4619a..6957c14f3 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/FillRectangleDrawableConsumer.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/FillRectangleDrawableConsumer.java @@ -31,7 +31,7 @@ import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.renderer.GameRenderer; -public final class FillRectangleDrawableConsumer implements DrawableConsumer { +final class FillRectangleDrawableConsumer implements DrawableConsumer { private Rectangle rectangle; private int color; diff --git a/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ForwardingList.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ForwardingList.java new file mode 100644 index 000000000..2d8c2d3d3 --- /dev/null +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/ForwardingList.java @@ -0,0 +1,156 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget.basewidgets; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +interface ForwardingList extends List { + @Override + default int size() { + return delegate().size(); + } + + @Override + default boolean isEmpty() { + return delegate().isEmpty(); + } + + @Override + default boolean contains(Object o) { + return delegate().contains(o); + } + + @NotNull + @Override + default Iterator iterator() { + return delegate().iterator(); + } + + @NotNull + @Override + default Object[] toArray() { + return delegate().toArray(); + } + + @NotNull + @Override + default T[] toArray(@NotNull T[] a) { + return delegate().toArray(a); + } + + @Override + default boolean add(E e) { + return delegate().add(e); + } + + @Override + default boolean remove(Object o) { + return delegate().remove(o); + } + + @Override + default boolean containsAll(@NotNull Collection c) { + return delegate().containsAll(c); + } + + @Override + default boolean addAll(@NotNull Collection c) { + return delegate().addAll(c); + } + + @Override + default boolean addAll(int index, @NotNull Collection c) { + return delegate().addAll(index, c); + } + + @Override + default boolean removeAll(@NotNull Collection c) { + return delegate().removeAll(c); + } + + @Override + default boolean retainAll(@NotNull Collection c) { + return delegate().retainAll(c); + } + + @Override + default void clear() { + delegate().clear(); + } + + @Override + default E get(int index) { + return delegate().get(index); + } + + @Override + default E set(int index, E element) { + return delegate().set(index, element); + } + + @Override + default void add(int index, E element) { + delegate().add(index, element); + } + + @Override + default E remove(int index) { + return delegate().remove(index); + } + + @Override + default int indexOf(Object o) { + return delegate().indexOf(o); + } + + @Override + default int lastIndexOf(Object o) { + return delegate().lastIndexOf(o); + } + + @NotNull + @Override + default ListIterator listIterator() { + return delegate().listIterator(); + } + + @NotNull + @Override + default ListIterator listIterator(int index) { + return delegate().listIterator(index); + } + + @NotNull + @Override + default List subList(int fromIndex, int toIndex) { + return delegate().subList(fromIndex, toIndex); + } + + List delegate(); +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/LabelWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/LabelWidget.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/LabelWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/LabelWidget.java index f81f98165..dd2da618b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/LabelWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/LabelWidget.java @@ -31,10 +31,11 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.widgets.Label; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.Widgets; -import me.shedaniel.rei.impl.client.gui.text.TextTransformations; +import me.shedaniel.rei.impl.client.util.TextTransformations; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.locale.Language; import net.minecraft.network.chat.Component; @@ -49,7 +50,7 @@ import java.util.function.Consumer; import java.util.function.Function; -public final class LabelWidget extends Label { +final class LabelWidget extends Label { private boolean hovered = false; private boolean focused = false; private boolean clickable = false; @@ -57,9 +58,9 @@ public final class LabelWidget extends Label { private boolean hasShadow = true; private boolean focusable = true; private ValueProvider color = ValueAnimator.ofColor() - .withConvention(() -> Color.ofTransparent(REIRuntime.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : -1), 50); + .withConvention(() -> Color.ofTransparent(ConfigObject.getInstance().isUsingDarkTheme() ? 0xFFBBBBBB : -1), 50); private ValueProvider hoveredColor = ValueAnimator.ofColor() - .withConvention(() -> Color.ofTransparent(REIRuntime.getInstance().isDarkThemeEnabled() ? -1 : 0xFF66FFCC), 50); + .withConvention(() -> Color.ofTransparent(ConfigObject.getInstance().isUsingDarkTheme() ? -1 : 0xFF66FFCC), 50); private final ValueProvider finalColor = ValueAnimator.ofColor() .withConvention(() -> { if (!hovered) { @@ -169,7 +170,7 @@ public final void setColor(int color) { @Override public Label color(int lightModeColor, int darkModeColor) { this.color = ValueAnimator.ofColor() - .withConvention(() -> Color.ofTransparent(REIRuntime.getInstance().isDarkThemeEnabled() ? darkModeColor : lightModeColor), ValueAnimator.typicalTransitionTime()); + .withConvention(() -> Color.ofTransparent(ConfigObject.getInstance().isUsingDarkTheme() ? darkModeColor : lightModeColor), ValueAnimator.typicalTransitionTime()); this.color.completeImmediately(); this.finalColor.completeImmediately(); return this; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/MergedWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/MergedWidget.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/MergedWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/MergedWidget.java index 59e9607c7..dc037f954 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/MergedWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/MergedWidget.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; @@ -33,7 +33,7 @@ import java.util.List; import java.util.Objects; -public class MergedWidget extends Widget { +final class MergedWidget extends Widget { private final List widgets; public MergedWidget(Widget widget1, Widget widget2) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/NoOpWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/NoOpWidget.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/NoOpWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/NoOpWidget.java index b31c61532..804dfc738 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/NoOpWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/NoOpWidget.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Rectangle; @@ -31,7 +31,7 @@ import java.util.Collections; import java.util.List; -public class NoOpWidget extends WidgetWithBounds { +final class NoOpWidget extends WidgetWithBounds { public static final NoOpWidget INSTANCE = new NoOpWidget(); private NoOpWidget() { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/OverflowWidget.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/OverflowWidget.java index b47eac3df..e2102cc10 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/OverflowWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/OverflowWidget.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; @@ -30,19 +30,20 @@ import me.shedaniel.clothconfig2.api.scroll.ScrollingContainer; import me.shedaniel.math.FloatingPoint; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import me.shedaniel.rei.api.client.gui.widgets.CloseableScissors; +import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; +import me.shedaniel.rei.impl.client.gui.InternalCursorState; @SuppressWarnings("UnstableApiUsage") -public class OverflowWidget extends DelegateWidgetWithTranslate { +final class OverflowWidget extends DelegateWidgetWithTranslate { private final Rectangle bounds; private final NumberAnimator scale; private final ValueAnimator translate; private final ValueAnimator velocity; private boolean dragging; - public OverflowWidget(Rectangle bounds, WidgetWithBounds widget) { + OverflowWidget(Rectangle bounds, WidgetWithBounds widget) { super(widget, Matrix4f::new); this.bounds = bounds; this.scale = ValueAnimator.ofFloat() @@ -77,7 +78,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { widgetBounds.height - getBounds().height * scale.value(), delta, .0001) - (widgetBounds.height - getBounds().height / 2 * scale.value()) )); } - if (!RoughlyEnoughItemsCoreClient.isLeftMousePressed) { + if (!InternalCursorState.isLeftMousePressed) { this.translate.setAs(new FloatingPoint(this.translate.value().x + this.velocity.value().x, this.translate.value().y + this.velocity.value().y)); } this.velocity.update(delta); @@ -86,7 +87,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { ScrollingContainer.handleBounceBack(this.velocity.target().y, 0, delta, .0001) ), 20); - try (CloseableScissors scissors = scissor(poseStack, this.bounds)) { + try (CloseableScissors scissors = Widget.scissor(poseStack, this.bounds)) { boolean containsMouse = this.bounds.contains(mouseX, mouseY); if (containsMouse) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedCenterWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PaddedCenterWidget.java similarity index 92% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedCenterWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PaddedCenterWidget.java index 6dca02880..3a532edac 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedCenterWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PaddedCenterWidget.java @@ -21,16 +21,16 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.mojang.math.Matrix4f; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -public class PaddedCenterWidget extends DelegateWidgetWithTranslate { +final class PaddedCenterWidget extends DelegateWidgetWithTranslate { private final Rectangle bounds; - public PaddedCenterWidget(Rectangle bounds, WidgetWithBounds widget) { + PaddedCenterWidget(Rectangle bounds, WidgetWithBounds widget) { super(widget, Matrix4f::new); this.bounds = bounds; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PaddedWidget.java similarity index 90% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PaddedWidget.java index 42a10c70b..76fdd91b4 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/PaddedWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PaddedWidget.java @@ -21,16 +21,16 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.mojang.math.Matrix4f; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -public class PaddedWidget extends DelegateWidgetWithTranslate { +final class PaddedWidget extends DelegateWidgetWithTranslate { private final int padLeft, padRight, padTop, padBottom; - public PaddedWidget(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget) { + PaddedWidget(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget) { super(widget, Matrix4f::new); this.padLeft = padLeft; this.padRight = padRight; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PanelWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PanelWidget.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PanelWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PanelWidget.java index a67b3062a..cce955efd 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PanelWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/PanelWidget.java @@ -44,7 +44,7 @@ import java.util.Objects; import java.util.function.Predicate; -public final class PanelWidget extends Panel { +final class PanelWidget extends Panel { private static final PanelWidget TEMP = new PanelWidget(new Rectangle()); private Rectangle bounds; private int color = -1; @@ -52,7 +52,7 @@ public final class PanelWidget extends Panel { private int yTextureOffset = RecipeBorderType.DEFAULT.getYOffset(); private Predicate rendering = Predicates.alwaysTrue(); private final NumberAnimator darkBackgroundAlpha = ValueAnimator.ofFloat() - .withConvention(() -> REIRuntime.getInstance().isDarkThemeEnabled() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) + .withConvention(() -> ConfigObject.getInstance().isUsingDarkTheme() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) .asFloat(); public static boolean isRendering(Panel panel) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/RendererWrappedWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/RendererWrappedWidget.java similarity index 95% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/RendererWrappedWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/RendererWrappedWidget.java index 97d9f3e3d..fc7bcdece 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/RendererWrappedWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/RendererWrappedWidget.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Rectangle; @@ -34,7 +34,7 @@ import java.util.Objects; import java.util.function.Supplier; -public class RendererWrappedWidget extends WidgetWithBounds { +final class RendererWrappedWidget extends WidgetWithBounds { private final Renderer renderer; private final Supplier bounds; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TextFieldWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TextFieldWidget.java similarity index 74% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TextFieldWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TextFieldWidget.java index 69b393b18..059f907c9 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TextFieldWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TextFieldWidget.java @@ -23,10 +23,11 @@ package me.shedaniel.rei.impl.client.gui.widget.basewidgets; +import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; import com.mojang.math.Matrix4f; -import me.shedaniel.clothconfig2.api.TickableWidget; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.widgets.TextField; import me.shedaniel.rei.api.client.gui.widgets.Widget; @@ -35,8 +36,6 @@ import net.minecraft.Util; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.network.chat.Style; -import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Mth; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -48,31 +47,33 @@ import java.util.function.Predicate; @ApiStatus.Internal -public class TextFieldWidget extends WidgetWithBounds implements TickableWidget, TextField { - public Function stripInvalid = SharedConstants::filterText; - protected int frame; - protected boolean editable = true; - protected int firstCharacterIndex; - protected int cursorPos; - protected int highlightPos; - protected int editableColor = 0xe0e0e0; - protected int notEditableColor = 0x707070; - protected TextFormatter formatter = TextFormatter.DEFAULT; - private Rectangle bounds; +final class TextFieldWidget extends WidgetWithBounds implements TextField { + private final Rectangle bounds; + private Function textTransformer = SharedConstants::filterText; + private int frame; + private boolean editable = true; + private int firstCharacterIndex; + private int cursorPos; + private int highlightPos; + private int editableColor = 0xe0e0e0; + private int notEditableColor = 0x707070; + private TextFormatter formatter = TextFormatter.DEFAULT; + private SuggestionRenderer suggestionRenderer = (matrices, x, y, color) -> + this.font.drawShadow(matrices, this.font.plainSubstrByWidth(this.suggestion, this.getWidth()), x, y, color); + private BorderColorProvider borderColorProvider = BorderColorProvider.DEFAULT; private String text = ""; private int maxLength = 32; private boolean hasBorder = true; private boolean focusUnlocked = true; private boolean focused = false; - private boolean visible = true; private boolean selecting = false; @Nullable private String suggestion; - @Nullable - private Consumer responder; + private Consumer responder = str -> {}; + private BooleanConsumer focusedResponder = bool -> {}; private Predicate filter = s -> true; - public TextFieldWidget(Rectangle bounds) { + TextFieldWidget(Rectangle bounds) { this.bounds = bounds; } @@ -80,27 +81,61 @@ public TextFieldWidget(int x, int y, int width, int height) { this(new Rectangle(x, y, width, height)); } + @Override + public void setTextTransformer(Function textTransformer) { + this.textTransformer = textTransformer; + } + + @Override public String getSuggestion() { return suggestion; } + @Override public void setSuggestion(String suggestion) { this.suggestion = suggestion; } + @Override + public void setBorderColorProvider(BorderColorProvider borderColorProvider) { + this.borderColorProvider = borderColorProvider; + } + @Override public Rectangle getBounds() { return bounds; } + @Override public void setResponder(Consumer responder) { this.responder = responder; } + @Override + public void setFocusedResponder(BooleanConsumer responder) { + this.focusedResponder = responder; + } + + @Override public void setFormatter(TextFormatter formatter) { this.formatter = formatter; } + @Override + public TextFormatter getFormatter() { + return formatter; + } + + @Override + public void setSuggestionRenderer(SuggestionRenderer suggestionRenderer) { + this.suggestionRenderer = suggestionRenderer; + } + + @Override + public SuggestionRenderer getSuggestionRenderer() { + return suggestionRenderer; + } + @Override public void tick() { this.frame++; @@ -141,7 +176,7 @@ public void addText(String text) { int highlightStart = Math.min(this.cursorPos, this.highlightPos); int highlightEnd = Math.max(this.cursorPos, this.highlightPos); int k = this.maxLength - this.text.length() - (highlightStart - highlightEnd); - String textFiltered = stripInvalid.apply(text); + String textFiltered = textTransformer.apply(text); int l = textFiltered.length(); if (k < l) { textFiltered = textFiltered.substring(0, k); @@ -160,9 +195,7 @@ public void addText(String text) { } public void onChanged(String newText) { - if (this.responder != null) { - this.responder.accept(newText); - } + this.responder.accept(newText); } private void erase(int offset) { @@ -269,7 +302,7 @@ public void moveCursorToEnd() { @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (this.isVisible() && this.isFocused()) { + if (this.isFocused()) { this.selecting = Screen.hasShiftDown(); if (Screen.isSelectAll(keyCode)) { this.moveCursorToEnd(); @@ -347,7 +380,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { @Override public boolean charTyped(char character, int modifiers) { - if (this.isVisible() && this.isFocused()) { + if (this.isFocused()) { if (SharedConstants.isAllowedChatCharacter(character) && !( Screen.hasControlDown() && !Screen.hasShiftDown() && !Screen.hasAltDown() && ( character == 'a' || character == 'c' || character == 'v' @@ -373,32 +406,28 @@ public List children() { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!this.isVisible()) { - return false; - } else { - boolean hovered = mouseX >= (double) this.bounds.x && mouseX < (double) (this.bounds.x + this.bounds.width) && mouseY >= (double) this.bounds.y && mouseY < (double) (this.bounds.y + this.bounds.height); - if (this.focusUnlocked) { - this.setFocused(hovered); + boolean hovered = mouseX >= (double) this.bounds.x && mouseX < (double) (this.bounds.x + this.bounds.width) && mouseY >= (double) this.bounds.y && mouseY < (double) (this.bounds.y + this.bounds.height); + if (this.focusUnlocked) { + this.setFocused(hovered); + } + + if (this.focused && hovered && button == 0) { + int int_2 = Mth.floor(mouseX) - this.bounds.x; + if (this.hasBorder) { + int_2 -= 4; } - if (this.focused && hovered && button == 0) { - int int_2 = Mth.floor(mouseX) - this.bounds.x; - if (this.hasBorder) { - int_2 -= 4; - } - - String string_1 = this.font.plainSubstrByWidth(this.text.substring(this.firstCharacterIndex), this.getWidth()); - this.moveCursorTo(this.font.plainSubstrByWidth(string_1, int_2).length() + this.firstCharacterIndex); - return true; - } else { - return false; - } + String string_1 = this.font.plainSubstrByWidth(this.text.substring(this.firstCharacterIndex), this.getWidth()); + this.moveCursorTo(this.font.plainSubstrByWidth(string_1, int_2).length() + this.firstCharacterIndex); + return true; + } else { + return false; } } public void renderBorder(PoseStack matrices) { if (this.hasBorder()) { - int borderColor = containsMouse(mouse()) || focused ? 0xffffffff : 0xffa0a0a0; + int borderColor = this.borderColorProvider.getBorderColor(this); fill(matrices, this.bounds.x - 1, this.bounds.y - 1, this.bounds.x + this.bounds.width + 1, this.bounds.y + this.bounds.height + 1, 0xff000000); fill(matrices, this.bounds.x, this.bounds.y, this.bounds.x + this.bounds.width, this.bounds.y + this.bounds.height, borderColor); fill(matrices, this.bounds.x + 1, this.bounds.y + 1, this.bounds.x + this.bounds.width - 1, this.bounds.y + this.bounds.height - 1, 0xff000000); @@ -407,60 +436,58 @@ public void renderBorder(PoseStack matrices) { @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (this.isVisible()) { - this.renderBorder(matrices); - - int color = this.editable ? this.editableColor : this.notEditableColor; - int int_4 = this.cursorPos - this.firstCharacterIndex; - int int_5 = this.highlightPos - this.firstCharacterIndex; - String textClipped = this.font.plainSubstrByWidth(this.text.substring(this.firstCharacterIndex), this.getWidth()); - boolean boolean_1 = int_4 >= 0 && int_4 <= textClipped.length(); - boolean boolean_2 = this.focused && this.frame / 6 % 2 == 0 && boolean_1; - int x = this.hasBorder ? this.bounds.x + 4 : this.bounds.x; - int y = this.hasBorder ? this.bounds.y + (this.bounds.height - 8) / 2 : this.bounds.y; - int int_8 = x; - int_5 = Math.min(textClipped.length(), int_5); - - if (!textClipped.isEmpty()) { - String string_2 = boolean_1 ? textClipped.substring(0, int_4) : textClipped; - int_8 = this.font.drawShadow(matrices, this.formatter.format(this, string_2, this.firstCharacterIndex), (float) x, (float) y, color); - } - - boolean isCursorInsideText = this.cursorPos < this.text.length() || this.text.length() >= this.getMaxLength(); - int selectionLeft = int_8; - if (!boolean_1) { - selectionLeft = int_4 > 0 ? x + this.bounds.width : x; - } else if (isCursorInsideText) { - --int_8; - } - selectionLeft--; - - if (!textClipped.isEmpty() && boolean_1 && int_4 < textClipped.length()) { - this.font.drawShadow(matrices, this.formatter.format(this, textClipped.substring(int_4), this.cursorPos), (float) int_8, (float) y, color); - } - - if (!isCursorInsideText && text.isEmpty() && this.suggestion != null) { - renderSuggestion(matrices, x, y); - } - - if (boolean_2) { - fill(matrices, selectionLeft + 1, y, selectionLeft + 2, y + 9, ((0xFF) << 24) | ((((color >> 16 & 255) / 4) & 0xFF) << 16) | ((((color >> 8 & 255) / 4) & 0xFF) << 8) | ((((color & 255) / 4) & 0xFF))); - fill(matrices, selectionLeft, y - 1, selectionLeft + 1, y + 8, ((0xFF) << 24) | color); - } - - // Render selection overlay - if (int_5 != int_4) { - int selectionRight = x + this.font.width(textClipped.substring(0, int_5)); - this.renderSelection(matrices, selectionLeft, y - 1, selectionRight - 1, y + 9, color); - } + this.renderBorder(matrices); + + int color = this.editable ? this.editableColor : this.notEditableColor; + int int_4 = this.cursorPos - this.firstCharacterIndex; + int int_5 = this.highlightPos - this.firstCharacterIndex; + String textClipped = this.font.plainSubstrByWidth(this.text.substring(this.firstCharacterIndex), this.getWidth()); + boolean boolean_1 = int_4 >= 0 && int_4 <= textClipped.length(); + boolean boolean_2 = this.focused && this.frame / 6 % 2 == 0 && boolean_1; + int x = this.hasBorder ? this.bounds.x + 4 : this.bounds.x; + int y = this.hasBorder ? this.bounds.y + (this.bounds.height - 8) / 2 : this.bounds.y; + int int_8 = x; + int_5 = Math.min(textClipped.length(), int_5); + + if (!textClipped.isEmpty()) { + String string_2 = boolean_1 ? textClipped.substring(0, int_4) : textClipped; + int_8 = this.font.drawShadow(matrices, this.formatter.format(string_2, this.firstCharacterIndex), (float) x, (float) y, color); + } + + boolean isCursorInsideText = this.cursorPos < this.text.length() || this.text.length() >= this.getMaxLength(); + int selectionLeft = int_8; + if (!boolean_1) { + selectionLeft = int_4 > 0 ? x + this.bounds.width : x; + } else if (isCursorInsideText) { + --int_8; + } + selectionLeft--; + + if (!textClipped.isEmpty() && boolean_1 && int_4 < textClipped.length()) { + this.font.drawShadow(matrices, this.formatter.format(textClipped.substring(int_4), this.cursorPos), (float) int_8, (float) y, color); + } + + if (!isCursorInsideText && text.isEmpty() && this.suggestion != null) { + renderSuggestion(matrices, x, y); + } + + if (boolean_2) { + fill(matrices, selectionLeft + 1, y, selectionLeft + 2, y + 9, ((0xFF) << 24) | ((((color >> 16 & 255) / 4) & 0xFF) << 16) | ((((color >> 8 & 255) / 4) & 0xFF) << 8) | ((((color & 255) / 4) & 0xFF))); + fill(matrices, selectionLeft, y - 1, selectionLeft + 1, y + 8, ((0xFF) << 24) | color); + } + + // Render selection overlay + if (int_5 != int_4) { + int selectionRight = x + this.font.width(textClipped.substring(0, int_5)); + this.renderSelection(matrices, selectionLeft, y - 1, selectionRight - 1, y + 9, color); } } - protected void renderSuggestion(PoseStack matrices, int x, int y) { - this.font.drawShadow(matrices, this.font.plainSubstrByWidth(this.suggestion, this.getWidth()), x, y, -8355712); + private void renderSuggestion(PoseStack matrices, int x, int y) { + this.suggestionRenderer.renderSuggestion(matrices, x, y, -8355712); } - protected void renderSelection(PoseStack matrices, int x1, int y1, int x2, int y2, int color) { + private void renderSelection(PoseStack matrices, int x1, int y1, int x2, int y2, int color) { int tmp; if (x1 < x2) { tmp = x1; @@ -548,7 +575,7 @@ public void setNotEditableColor(int notEditableColor) { @Override public boolean changeFocus(boolean next) { - if (this.visible && this.editable) { + if (this.editable) { this.setFocused(!this.focused); return this.focused; } @@ -565,6 +592,17 @@ public void setFocused(boolean focused) { if (focused && !this.focused) this.frame = 0; this.focused = focused; + this.focusedResponder.accept(focused); + } + + @Override + public void setFocusedFromKey(boolean focused, InputConstants.Key key) { + setFocused(focused); + } + + @Override + public WidgetWithBounds asWidget() { + return this; } public void setIsEditable(boolean isEditable) { @@ -605,23 +643,7 @@ public void setFocusUnlocked(boolean focusUnlocked) { this.focusUnlocked = focusUnlocked; } - public boolean isVisible() { - return this.visible; - } - - public void setVisible(boolean visible) { - this.visible = visible; - } - public int getCharacterX(int index) { return index > this.text.length() ? this.bounds.x : this.bounds.x + this.font.width(this.text.substring(0, index)); } - - public interface TextFormatter { - TextFormatter DEFAULT = (widget, text, index) -> { - return FormattedCharSequence.forward(text, Style.EMPTY); - }; - - FormattedCharSequence format(TextFieldWidget widget, String text, int index); - } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TexturedDrawableConsumer.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TexturedDrawableConsumer.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TexturedDrawableConsumer.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TexturedDrawableConsumer.java index e3c178600..d519a4500 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TexturedDrawableConsumer.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/TexturedDrawableConsumer.java @@ -31,7 +31,7 @@ import net.minecraft.client.renderer.GameRenderer; import net.minecraft.resources.ResourceLocation; -public final class TexturedDrawableConsumer implements DrawableConsumer { +final class TexturedDrawableConsumer implements DrawableConsumer { private ResourceLocation identifier; private int x, y, width, height, uWidth, vHeight, textureWidth, textureHeight; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/VanillaWrappedWidget.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/VanillaWrappedWidget.java similarity index 96% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/VanillaWrappedWidget.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/VanillaWrappedWidget.java index 2aacd5e73..23b622e14 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/VanillaWrappedWidget.java +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/VanillaWrappedWidget.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.widget.basewidgets; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.rei.api.client.gui.widgets.Widget; @@ -34,7 +34,7 @@ import java.util.List; import java.util.Objects; -public class VanillaWrappedWidget extends Widget { +final class VanillaWrappedWidget extends Widget { private GuiEventListener element; public VanillaWrappedWidget(GuiEventListener element) { diff --git a/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/WidgetsProviderImpl.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/WidgetsProviderImpl.java new file mode 100644 index 000000000..cae2c165c --- /dev/null +++ b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/WidgetsProviderImpl.java @@ -0,0 +1,167 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget.basewidgets; + +import com.mojang.math.Matrix4f; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.DrawableConsumer; +import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.gui.widgets.*; +import me.shedaniel.rei.impl.client.provider.WidgetsProvider; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; + +import java.util.List; +import java.util.function.Supplier; + +public class WidgetsProviderImpl implements WidgetsProvider { + @Override + public boolean isRenderingPanel(Panel panel) { + return PanelWidget.isRendering(panel); + } + + @Override + public Widget wrapVanillaWidget(GuiEventListener element) { + if (element instanceof Widget) return (Widget) element; + return new VanillaWrappedWidget(element); + } + + @Override + public WidgetWithBounds wrapRenderer(Supplier bounds, Renderer renderer) { + return new RendererWrappedWidget(renderer, bounds); + } + + @Override + public WidgetWithBounds withTranslate(WidgetWithBounds widget, Supplier translate) { + return new DelegateWidgetWithTranslate(widget, translate); + } + + @Override + public Widget createDrawableWidget(DrawableConsumer drawable) { + return new DrawableWidget(drawable); + } + + @Override + public Slot createSlot(Point point) { + return new EntryWidget(point); + } + + @Override + public Slot createSlot(Rectangle bounds) { + return new EntryWidget(bounds); + } + + @Override + public Button createButton(Rectangle bounds, Component text) { + return new ButtonWidget(bounds, text); + } + + @Override + public Panel createPanelWidget(Rectangle bounds) { + return new PanelWidget(bounds); + } + + @Override + public Label createLabel(Point point, FormattedText text) { + return new LabelWidget(point, text); + } + + @Override + public Arrow createArrow(Rectangle rectangle) { + return new ArrowWidget(rectangle); + } + + @Override + public BurningFire createBurningFire(Rectangle rectangle) { + return new BurningFireWidget(rectangle); + } + + @Override + public DrawableConsumer createTexturedConsumer(ResourceLocation texture, int x, int y, int width, int height, float u, float v, int uWidth, int vHeight, int textureWidth, int textureHeight) { + return new TexturedDrawableConsumer(texture, x, y, width, height, u, v, uWidth, vHeight, textureWidth, textureHeight); + } + + @Override + public DrawableConsumer createFillRectangleConsumer(Rectangle rectangle, int color) { + return new FillRectangleDrawableConsumer(rectangle, color); + } + + @Override + public Widget createShapelessIcon(Point point) { + int magnification; + double scale = Minecraft.getInstance().getWindow().getGuiScale(); + if (scale >= 1 && scale <= 4 && scale == Math.floor(scale)) { + magnification = (int) scale; + } else if (scale > 4 && scale == Math.floor(scale)) { + magnification = 1; + for (int i = 4; i >= 1; i--) { + if (scale % i == 0) { + magnification = i; + break; + } + } + } else { + magnification = 4; + } + Rectangle bounds = new Rectangle(point.getX() - 9, point.getY() + 1, 8, 8); + Widget widget = Widgets.createTexturedWidget(new ResourceLocation("roughlyenoughitems:textures/gui/shapeless_icon_" + magnification + "x.png"), bounds.getX(), bounds.getY(), 0, 0, bounds.getWidth(), bounds.getHeight(), 1, 1, 1, 1); + return Widgets.withTooltip(Widgets.withBounds(widget, bounds), + new TranslatableComponent("text.rei.shapeless")); + } + + @Override + public Widget concatWidgets(List widgets) { + return new MergedWidget(widgets); + } + + @Override + public WidgetWithBounds noOp() { + return NoOpWidget.INSTANCE; + } + + @Override + public WidgetWithBounds wrapOverflow(Rectangle bounds, WidgetWithBounds widget) { + return new OverflowWidget(bounds, new PaddedCenterWidget(bounds, widget)); + } + + @Override + public WidgetWithBounds wrapPadded(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget) { + return new PaddedWidget(padLeft, padRight, padTop, padBottom, widget); + } + + @Override + public TextField createTextField(Rectangle bounds) { + return new TextFieldWidget(bounds); + } + + @Override + public BatchedSlots createBatchedSlots() { + return new BatchedSlotsImpl(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/package-info.java b/runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/package-info.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/package-info.java rename to runtime-frontend/widgets/src/main/java/me/shedaniel/rei/impl/client/gui/widget/basewidgets/package-info.java diff --git a/runtime-frontend/widgets/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.MissingStacksTooltipProvider b/runtime-frontend/widgets/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.MissingStacksTooltipProvider new file mode 100644 index 000000000..414aa0b7f --- /dev/null +++ b/runtime-frontend/widgets/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.MissingStacksTooltipProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.tooltip.MissingStacksTooltipProviderImpl \ No newline at end of file diff --git a/runtime-frontend/widgets/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.WidgetsProvider b/runtime-frontend/widgets/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.WidgetsProvider new file mode 100644 index 000000000..1b1510787 --- /dev/null +++ b/runtime-frontend/widgets/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.provider.WidgetsProvider @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.gui.widget.basewidgets.WidgetsProviderImpl \ No newline at end of file diff --git a/runtime/build.gradle b/runtime/build.gradle index ef54168cc..2cc114aac 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -1,19 +1,5 @@ -archivesBaseName = rootProject.name + "-" + project.name - -architectury { - common(forgeEnabled.toBoolean()) -} - -loom { - accessWidenerPath = gradle.rootProject.project("fabric").file("src/main/resources/roughlyenoughitems.accessWidener") -} - dependencies { - modCompileOnly("net.fabricmc:fabric-loader:${project.fabricloader_version}") - modApi("me.shedaniel.cloth:cloth-config:${cloth_config_version}") - modApi("dev.architectury:architectury:${architectury_version}") compileClasspath(annotationProcessor("org.projectlombok:lombok:1.18.22")) - compileClasspath(project(path: ":api", configuration: "namedElements")) testImplementation(project(path: ":api", configuration: "namedElements")) testImplementation("org.junit.jupiter:junit-jupiter:5.8.2") } @@ -21,34 +7,3 @@ dependencies { test { useJUnitPlatform() } - -remapJar { - classifier "raw" -} - -task fakeJar(type: Jar, dependsOn: remapJar) { - from remapJar.archiveFile.map { zipTree(it) } - from(rootProject.file("fake/fabric.mod.json")) { - into "" - } - classifier null -} - -artifacts { - apiElements(fakeJar) - runtimeElements(fakeJar) -} - -afterEvaluate { - configurations.apiElements.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.remapJar) } - configurations.runtimeElements.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.remapJar) } -} - -publishing { - publications { - mavenCommon(MavenPublication) { - artifactId = rootProject.name + "-" + project.name - from components.java - } - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index f7bc42f5f..4010edd6a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java @@ -23,131 +23,29 @@ package me.shedaniel.rei; -import com.google.common.collect.ImmutableList; import dev.architectury.platform.Platform; -import dev.architectury.registry.ReloadListenerRegistry; import dev.architectury.utils.Env; import dev.architectury.utils.EnvExecutor; -import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.annotation.Nullable; -import me.shedaniel.rei.api.common.entry.type.EntryType; -import me.shedaniel.rei.api.common.plugins.PluginManager; -import me.shedaniel.rei.api.common.plugins.PluginView; -import me.shedaniel.rei.api.common.plugins.REIPlugin; -import me.shedaniel.rei.api.common.plugins.REIServerPlugin; -import me.shedaniel.rei.api.common.registry.ReloadStage; -import me.shedaniel.rei.impl.Internals; -import me.shedaniel.rei.impl.common.InternalLogger; -import me.shedaniel.rei.impl.common.category.CategoryIdentifierImpl; -import me.shedaniel.rei.impl.common.display.DisplaySerializerRegistryImpl; -import me.shedaniel.rei.impl.common.entry.DeferringEntryTypeProviderImpl; -import me.shedaniel.rei.impl.common.entry.EntryIngredientImpl; -import me.shedaniel.rei.impl.common.entry.EntryStackProviderImpl; -import me.shedaniel.rei.impl.common.entry.comparison.FluidComparatorRegistryImpl; -import me.shedaniel.rei.impl.common.entry.comparison.ItemComparatorRegistryImpl; -import me.shedaniel.rei.impl.common.entry.comparison.NbtHasherProviderImpl; -import me.shedaniel.rei.impl.common.entry.settings.EntrySettingsAdapterRegistryImpl; -import me.shedaniel.rei.impl.common.entry.type.EntryTypeRegistryImpl; -import me.shedaniel.rei.impl.common.fluid.FluidSupportProviderImpl; -import me.shedaniel.rei.impl.common.logging.*; -import me.shedaniel.rei.impl.common.logging.performance.PerformanceLogger; -import me.shedaniel.rei.impl.common.logging.performance.PerformanceLoggerImpl; -import me.shedaniel.rei.impl.common.plugins.PluginManagerImpl; -import me.shedaniel.rei.impl.common.registry.RecipeManagerContextImpl; -import me.shedaniel.rei.impl.common.transfer.MenuInfoRegistryImpl; +import me.shedaniel.rei.impl.common.Internals; import me.shedaniel.rei.impl.init.PluginDetector; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.PackType; -import net.minecraft.util.Unit; -import org.apache.commons.lang3.mutable.MutableLong; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; import org.jetbrains.annotations.ApiStatus; -import java.util.ServiceLoader; -import java.util.function.Function; -import java.util.function.UnaryOperator; +import java.util.List; @ApiStatus.Internal public class RoughlyEnoughItemsCore { - @ApiStatus.Internal - public static final InternalLogger LOGGER = new TransformingLogger(new MultiLogger(ImmutableList.of( - new FileLogger(Platform.getGameFolder().resolve("logs/rei.log")), - new FilteringLogger(new FileLogger(Platform.getGameFolder().resolve("logs/rei-issues.log")), Level.WARN), - new Log4JLogger(LogManager.getFormatterLogger("REI")) - )), message -> "[REI] " + message); - public static final PerformanceLogger PERFORMANCE_LOGGER = new PerformanceLoggerImpl(); - private static final ServiceLoader PLUGIN_DETECTOR_LOADER = ServiceLoader.load(PluginDetector.class); + public static final List PLUGIN_DETECTORS = Internals.resolveServices(PluginDetector.class); static { - attachCommonInternals(); if (Platform.getEnvironment() == Env.CLIENT) { EnvExecutor.runInEnv(Env.CLIENT, () -> RoughlyEnoughItemsCoreClient::attachClientInternals); } } - public static void attachCommonInternals() { - Internals.attachInstanceSupplier(LOGGER, "logger"); - CategoryIdentifierImpl.attach(); - Internals.attachInstance((Function>) DeferringEntryTypeProviderImpl.INSTANCE, "entryTypeDeferred"); - Internals.attachInstance(EntryStackProviderImpl.INSTANCE, Internals.EntryStackProvider.class); - Internals.attachInstance(NbtHasherProviderImpl.INSTANCE, Internals.NbtHasherProvider.class); - Internals.attachInstance(EntryIngredientImpl.INSTANCE, Internals.EntryIngredientProvider.class); - Internals.attachInstanceSupplier(new PluginManagerImpl<>( - REIPlugin.class, - UnaryOperator.identity(), - new EntryTypeRegistryImpl(), - new EntrySettingsAdapterRegistryImpl(), - new RecipeManagerContextImpl<>(RecipeManagerContextImpl.supplier()), - new ItemComparatorRegistryImpl(), - new FluidComparatorRegistryImpl(), - new DisplaySerializerRegistryImpl(), - new FluidSupportProviderImpl()), "commonPluginManager"); - Internals.attachInstanceSupplier(new PluginManagerImpl<>( - REIServerPlugin.class, - view -> view.then(PluginView.getInstance()), - new MenuInfoRegistryImpl()), "serverPluginManager"); - } - - public static void _reloadPlugins(@Nullable ReloadStage stage) { - if (stage == null) { - for (ReloadStage reloadStage : ReloadStage.values()) { - _reloadPlugins(reloadStage); - } - return; - } - try { - for (PluginManager> instance : PluginManager.getActiveInstances()) { - instance.view().pre(stage); - } - for (PluginManager> instance : PluginManager.getActiveInstances()) { - instance.startReload(stage); - } - for (PluginManager> instance : PluginManager.getActiveInstances()) { - instance.view().post(stage); - } - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - public void onInitialize() { - PluginDetector detector = getPluginDetector(); - detector.detectCommonPlugins(); - detector.detectServerPlugins(); - RoughlyEnoughItemsNetwork.onInitialize(); - - if (Platform.getEnvironment() == Env.SERVER) { - MutableLong lastReload = new MutableLong(-1); - ReloadListenerRegistry.register(PackType.SERVER_DATA, (preparationBarrier, resourceManager, profilerFiller, profilerFiller2, executor, executor2) -> { - return preparationBarrier.wait(Unit.INSTANCE).thenRunAsync(() -> { - PERFORMANCE_LOGGER.clear(); - RoughlyEnoughItemsCore._reloadPlugins(null); - }, executor2); - }); + for (PluginDetector detector : PLUGIN_DETECTORS) { + detector.detectCommonPlugins(); + detector.detectServerPlugins(); } } - - public static PluginDetector getPluginDetector() { - return PLUGIN_DETECTOR_LOADER.findFirst().orElseThrow(); - } } diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index bcb3c0a45..140b28eb6 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -25,65 +25,35 @@ import com.google.common.collect.Lists; import com.mojang.serialization.DataResult; -import dev.architectury.event.Event; -import dev.architectury.event.EventFactory; import dev.architectury.event.EventResult; import dev.architectury.event.events.client.ClientGuiEvent; -import dev.architectury.event.events.client.ClientRecipeUpdateEvent; import dev.architectury.event.events.client.ClientScreenInputEvent; -import dev.architectury.networking.NetworkManager; +import dev.architectury.platform.Platform; import me.shedaniel.math.Point; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; -import me.shedaniel.rei.api.client.entry.filtering.FilteringRuleTypeRegistry; -import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; +import me.shedaniel.rei.api.client.gui.widgets.TextField; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; -import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.client.registry.screen.ClickArea; -import me.shedaniel.rei.api.client.registry.screen.OverlayDecider; import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; import me.shedaniel.rei.api.common.category.CategoryIdentifier; -import me.shedaniel.rei.api.common.plugins.PluginManager; -import me.shedaniel.rei.api.common.plugins.PluginView; -import me.shedaniel.rei.api.common.plugins.REIPlugin; -import me.shedaniel.rei.api.common.registry.ReloadStage; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.ClientInternals; import me.shedaniel.rei.impl.client.REIRuntimeImpl; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; -import me.shedaniel.rei.impl.client.config.addon.ConfigAddonRegistryImpl; -import me.shedaniel.rei.impl.client.entry.filtering.rules.FilteringRuleTypeRegistryImpl; -import me.shedaniel.rei.impl.client.entry.renderer.EntryRendererRegistryImpl; -import me.shedaniel.rei.impl.client.favorites.DelegatingFavoriteEntryProviderImpl; -import me.shedaniel.rei.impl.client.favorites.FavoriteEntryTypeRegistryImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.widget.InternalWidgets; -import me.shedaniel.rei.impl.client.gui.widget.QueuedTooltip; +import me.shedaniel.rei.impl.client.gui.InternalCursorState; +import me.shedaniel.rei.impl.client.gui.widget.CatchingExceptionUtils; import me.shedaniel.rei.impl.client.gui.widget.TooltipContextImpl; -import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; -import me.shedaniel.rei.impl.client.registry.category.CategoryRegistryImpl; -import me.shedaniel.rei.impl.client.registry.display.DisplayRegistryImpl; -import me.shedaniel.rei.impl.client.registry.screen.ScreenRegistryImpl; -import me.shedaniel.rei.impl.client.search.SearchProviderImpl; -import me.shedaniel.rei.impl.client.search.method.InputMethodRegistryImpl; -import me.shedaniel.rei.impl.client.subsets.SubsetsRegistryImpl; -import me.shedaniel.rei.impl.client.transfer.TransferHandlerRegistryImpl; -import me.shedaniel.rei.impl.client.view.ViewsImpl; -import me.shedaniel.rei.impl.common.InternalLogger; -import me.shedaniel.rei.impl.common.entry.type.EntryRegistryImpl; -import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsibleEntryRegistryImpl; -import me.shedaniel.rei.impl.common.entry.type.types.EmptyEntryDefinition; -import me.shedaniel.rei.impl.common.plugins.PluginManagerImpl; +import me.shedaniel.rei.impl.client.gui.widget.TooltipImpl; import me.shedaniel.rei.impl.common.util.IssuesDetector; -import me.shedaniel.rei.plugin.test.REITestPlugin; +import me.shedaniel.rei.impl.init.PluginDetector; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -91,31 +61,17 @@ import net.minecraft.client.gui.components.ImageButton; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.gui.screens.inventory.CraftingScreen; -import net.minecraft.client.gui.screens.recipebook.GhostRecipe; import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent; -import net.minecraft.client.resources.language.I18n; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.inventory.CraftingMenu; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.item.crafting.Ingredient; import org.apache.commons.lang3.function.TriFunction; -import org.apache.commons.lang3.mutable.MutableLong; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.Collection; -import java.util.ConcurrentModificationException; import java.util.List; -import java.util.concurrent.*; import java.util.function.BiFunction; import java.util.function.BooleanSupplier; import java.util.function.Function; @@ -124,23 +80,8 @@ @Environment(EnvType.CLIENT) public class RoughlyEnoughItemsCoreClient { - public static final Event PRE_UPDATE_RECIPES = EventFactory.createLoop(); - public static boolean isLeftMousePressed = false; - private static final ExecutorService RELOAD_PLUGINS = Executors.newSingleThreadScheduledExecutor(task -> { - Thread thread = new Thread(task, "REI-ReloadPlugins"); - thread.setDaemon(true); - thread.setUncaughtExceptionHandler(($, exception) -> { - InternalLogger.getInstance().throwException(exception); - }); - return thread; - }); - private static final List> RELOAD_TASKS = new CopyOnWriteArrayList<>(); - public static void attachClientInternals() { - InternalWidgets.attach(); - EmptyEntryDefinition.EmptyRenderer emptyEntryRenderer = new EmptyEntryDefinition.EmptyRenderer(); - ClientInternals.attachInstance((Supplier>) () -> emptyEntryRenderer, "emptyEntryRenderer"); - ClientInternals.attachInstance((BiFunction>, Supplier, FavoriteEntry>) DelegatingFavoriteEntryProviderImpl::new, "delegateFavoriteEntry"); + CatchingExceptionUtils.attach(); ClientInternals.attachInstance((Function>) (object) -> { String type = object.getString(FavoriteEntry.TYPE_KEY); ResourceLocation id = new ResourceLocation(type); @@ -148,16 +89,14 @@ public static void attachClientInternals() { if (entryType == null) return DataResult.error("Unknown favorite type: " + id + ", json: " + object); return entryType.read(object); }, "favoriteEntryFromJson"); - ClientInternals.attachInstance((BiFunction<@Nullable Point, Collection, Tooltip>) QueuedTooltip::impl, "tooltipProvider"); + ClientInternals.attachInstance((BiFunction<@Nullable Point, Collection, Tooltip>) TooltipImpl::impl, "tooltipProvider"); ClientInternals.attachInstance((TriFunction) TooltipContextImpl::new, "tooltipContextProvider"); - ClientInternals.attachInstance((Function) QueuedTooltip.TooltipEntryImpl::new, "tooltipEntryProvider"); - ClientInternals.attachInstance((Function<@Nullable Boolean, ClickArea.Result>) successful -> new ClickArea.Result() { - private List> categories = Lists.newArrayList(); - private BooleanSupplier execute = () -> { - return false; - }; + ClientInternals.attachInstance((Function) TooltipImpl.TooltipEntryImpl::new, "tooltipEntryProvider"); + ClientInternals.attachInstance((Function) successful -> new ClickArea.Result() { + private final List> categories = Lists.newArrayList(); + private BooleanSupplier execute = () -> false; private Supplier tooltip = () -> { - if (categories != null && !categories.isEmpty()) { + if (!categories.isEmpty()) { Component collect = CollectionUtils.mapAndJoinToComponent(categories, identifier -> CategoryRegistry.getInstance().tryGet(identifier) .map(config -> config.getCategory().getTitle()) @@ -206,137 +145,34 @@ public Stream> getCategories() { return categories.stream(); } }, "clickAreaHandlerResult"); - ClientInternals.attachInstanceSupplier(new FilteringRuleTypeRegistryImpl(), "filteringRuleTypeRegistry"); - ClientInternals.attachInstanceSupplier(new PluginManagerImpl<>( - REIClientPlugin.class, - view -> view.then(PluginView.getInstance()), - new EntryRendererRegistryImpl(), - new ViewsImpl(), - new InputMethodRegistryImpl(), - new SearchProviderImpl(), - new ConfigManagerImpl(), - new EntryRegistryImpl(), - new CollapsibleEntryRegistryImpl(), - FilteringRuleTypeRegistry.getInstance().basic(), - new CategoryRegistryImpl(), - new DisplayRegistryImpl(), - new ScreenRegistryImpl(), - new FavoriteEntryTypeRegistryImpl(), - new SubsetsRegistryImpl(), - new TransferHandlerRegistryImpl(), - new REIRuntimeImpl(), - new ConfigAddonRegistryImpl()), "clientPluginManager"); } public void onInitializeClient() { IssuesDetector.detect(); registerEvents(); - RoughlyEnoughItemsCore.getPluginDetector().detectClientPlugins().get().run(); - loadTestPlugins(); - - Minecraft client = Minecraft.getInstance(); - NetworkManager.registerReceiver(NetworkManager.s2c(), RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, (buf, context) -> { - ItemStack stack = buf.readItem(); - String player = buf.readUtf(32767); - if (client.player != null) { - client.player.displayClientMessage(new TextComponent(I18n.get("text.rei.cheat_items").replaceAll("\\{item_name}", EntryStacks.of(stack.copy()).asFormattedText().getString()).replaceAll("\\{item_count}", stack.copy().getCount() + "").replaceAll("\\{player_name}", player)), false); - } - }); - NetworkManager.registerReceiver(NetworkManager.s2c(), RoughlyEnoughItemsNetwork.NOT_ENOUGH_ITEMS_PACKET, (buf, context) -> { - Screen currentScreen = Minecraft.getInstance().screen; - if (currentScreen instanceof CraftingScreen craftingScreen) { - RecipeBookComponent recipeBookGui = craftingScreen.getRecipeBookComponent(); - GhostRecipe ghostSlots = recipeBookGui.ghostRecipe; - ghostSlots.clear(); - - List> input = Lists.newArrayList(); - int mapSize = buf.readInt(); - for (int i = 0; i < mapSize; i++) { - List list = Lists.newArrayList(); - int count = buf.readInt(); - for (int j = 0; j < count; j++) { - list.add(buf.readItem()); - } - input.add(list); - } - - ghostSlots.addIngredient(Ingredient.of(Items.STONE), 381203812, 12738291); - CraftingMenu container = craftingScreen.getMenu(); - for (int i = 0; i < input.size(); i++) { - List stacks = input.get(i); - if (!stacks.isEmpty()) { - Slot slot = container.getSlot(i + container.getResultSlotIndex() + 1); - ghostSlots.addIngredient(Ingredient.of(stacks.toArray(new ItemStack[0])), slot.x, slot.y); - } - } - } - }); - } - - private void loadTestPlugins() { - if (System.getProperty("rei.test", "false").equals("true")) { - PluginView.getClientInstance().registerPlugin(new REITestPlugin()); + for (PluginDetector detector : RoughlyEnoughItemsCore.PLUGIN_DETECTORS) { + detector.detectClientPlugins().get().run(); } + + Platform.getMod("roughlyenoughitems").registerConfigurationScreen(ConfigManager.getInstance()::getConfigScreen); } public static boolean shouldReturn(Screen screen) { - if (REIRuntime.getInstance().getOverlay().isEmpty()) return true; - if (screen == null) return true; - if (screen != Minecraft.getInstance().screen) return true; - return _shouldReturn(screen); + return !ScreenRegistry.getInstance().shouldDisplay(screen); } private static ScreenOverlay getOverlay() { - return REIRuntime.getInstance().getOverlay().orElseThrow(() -> new IllegalStateException("Overlay not initialized!")); - } - - private static boolean _shouldReturn(Screen screen) { - try { - for (OverlayDecider decider : ScreenRegistry.getInstance().getDeciders(screen)) { - InteractionResult result = decider.shouldScreenBeOverlaid(screen); - if (result != InteractionResult.PASS) { - return result == InteractionResult.FAIL || REIRuntime.getInstance().getPreviousScreen() == null; - } - } - } catch (ConcurrentModificationException ignored) { - } - return true; + return REIRuntime.getInstance().getOverlay().orElseThrow(); } private void registerEvents() { Minecraft client = Minecraft.getInstance(); final ResourceLocation recipeButtonTex = new ResourceLocation("textures/gui/recipe_button.png"); - MutableLong startReload = new MutableLong(-1); - MutableLong endReload = new MutableLong(-1); - PRE_UPDATE_RECIPES.register(recipeManager -> { - RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear(); - reloadPlugins(startReload, ReloadStage.START); - }); - ClientRecipeUpdateEvent.EVENT.register(recipeManager -> { - reloadPlugins(endReload, ReloadStage.END); - }); - ClientGuiEvent.INIT_PRE.register((screen, access) -> { - List stages = ((PluginManagerImpl>) PluginManager.getInstance()).getObservedStages(); - - if (Minecraft.getInstance().level != null && Minecraft.getInstance().player != null && stages.contains(ReloadStage.START) - && !stages.contains(ReloadStage.END) && !PluginManager.areAnyReloading() && screen instanceof AbstractContainerScreen) { - for (Future task : RELOAD_TASKS) { - if (!task.isDone()) { - return EventResult.pass(); - } - } - - InternalLogger.getInstance().error("Detected missing stage: END! This is possibly due to issues during client recipe reload! REI will force a reload of the recipes now!"); - reloadPlugins(endReload, ReloadStage.END); - } - - return EventResult.pass(); - }); ClientGuiEvent.INIT_POST.register((screen, access) -> { REIRuntime.getInstance().getOverlay(false, true); if (Minecraft.getInstance().screen == screen) { if (REIRuntime.getInstance().getPreviousScreen() != screen) { - OverlaySearchField searchField = REIRuntimeImpl.getSearchField(); + TextField searchField = REIRuntime.getInstance().getSearchTextField(); if (searchField != null) { searchField.setFocused(false); @@ -352,7 +188,8 @@ private void registerEvents() { } }); ClientScreenInputEvent.MOUSE_CLICKED_PRE.register((minecraftClient, screen, mouseX, mouseY, button) -> { - isLeftMousePressed = true; + if (button == 0) InternalCursorState.isLeftMousePressed = true; + if (button == 1) InternalCursorState.isRightMousePressed = true; if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); resetFocused(screen); @@ -366,7 +203,8 @@ private void registerEvents() { return EventResult.pass(); }); ClientScreenInputEvent.MOUSE_RELEASED_PRE.register((minecraftClient, screen, mouseX, mouseY, button) -> { - isLeftMousePressed = false; + if (button == 0) InternalCursorState.isLeftMousePressed = false; + if (button == 1) InternalCursorState.isRightMousePressed = false; if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); resetFocused(screen); @@ -389,7 +227,7 @@ && resetFocused(screen)) if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); if (screen.getFocused() != null && screen.getFocused() instanceof EditBox || (screen.getFocused() instanceof RecipeBookComponent && ((RecipeBookComponent) screen.getFocused()).searchBox != null && ((RecipeBookComponent) screen.getFocused()).searchBox.isFocused())) - if (!REIRuntimeImpl.getSearchField().isFocused()) + if (REIRuntime.getInstance().getSearchTextField() != null && !REIRuntime.getInstance().getSearchTextField().isFocused()) return EventResult.pass(); resetFocused(screen); if (getOverlay().charTyped(character, keyCode) @@ -404,7 +242,7 @@ && resetFocused(screen)) if (!(screen instanceof DisplayScreen)) { getOverlay().render(matrices, mouseX, mouseY, delta); } - ((ScreenOverlayImpl) getOverlay()).lateRender(matrices, mouseX, mouseY, delta); + getOverlay().lateRender(matrices, mouseX, mouseY, delta); resetFocused(screen); }); ClientScreenInputEvent.MOUSE_DRAGGED_PRE.register((minecraftClient, screen, mouseX1, mouseY1, button, mouseX2, mouseY2) -> { @@ -426,7 +264,7 @@ && resetFocused(screen)) } } if (screen.getFocused() != null && screen.getFocused() instanceof EditBox || (screen.getFocused() instanceof RecipeBookComponent && ((RecipeBookComponent) screen.getFocused()).searchBox != null && ((RecipeBookComponent) screen.getFocused()).searchBox.isFocused())) - if (!REIRuntimeImpl.getSearchField().isFocused()) + if (REIRuntime.getInstance().getSearchTextField() != null && !REIRuntime.getInstance().getSearchTextField().isFocused()) return EventResult.pass(); resetFocused(screen); if (getOverlay().keyPressed(i, i1, i2) @@ -438,7 +276,7 @@ && resetFocused(screen)) if (shouldReturn(screen) || screen instanceof DisplayScreen) return EventResult.pass(); if (screen.getFocused() != null && screen.getFocused() instanceof EditBox || (screen.getFocused() instanceof RecipeBookComponent && ((RecipeBookComponent) screen.getFocused()).searchBox != null && ((RecipeBookComponent) screen.getFocused()).searchBox.isFocused())) - if (!REIRuntimeImpl.getSearchField().isFocused()) + if (REIRuntime.getInstance().getSearchTextField() != null && !REIRuntime.getInstance().getSearchTextField().isFocused()) return EventResult.pass(); resetFocused(screen); if (getOverlay().keyReleased(i, i1, i2) @@ -454,31 +292,4 @@ private boolean resetFocused(Screen screen) { } return true; } - - @ApiStatus.Internal - public static void reloadPlugins(MutableLong lastReload, @Nullable ReloadStage start) { - if (Minecraft.getInstance().level == null) return; - if (lastReload != null) { - if (lastReload.getValue() > 0 && System.currentTimeMillis() - lastReload.getValue() <= 5000) { - InternalLogger.getInstance().warn("Suppressing Reload Plugins of stage " + start); - return; - } - lastReload.setValue(System.currentTimeMillis()); - } - if (ConfigObject.getInstance().doesRegisterRecipesInAnotherThread()) { - Future[] futures = new Future[1]; - CompletableFuture future = CompletableFuture.runAsync(() -> RoughlyEnoughItemsCore._reloadPlugins(start), RELOAD_PLUGINS) - .whenComplete((unused, throwable) -> { - // Remove the future from the list of futures - if (futures[0] != null) { - RELOAD_TASKS.remove(futures[0]); - futures[0] = null; - } - }); - futures[0] = future; - RELOAD_TASKS.add(future); - } else { - RoughlyEnoughItemsCore._reloadPlugins(start); - } - } } diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java deleted file mode 100644 index 80d868c28..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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; - -import dev.architectury.networking.NetworkManager; -import dev.architectury.networking.transformers.SplitPacketTransformer; -import io.netty.buffer.Unpooled; -import me.shedaniel.rei.api.common.category.CategoryIdentifier; -import me.shedaniel.rei.api.common.display.Display; -import me.shedaniel.rei.impl.common.transfer.InputSlotCrafter; -import net.minecraft.ChatFormatting; -import net.minecraft.Util; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.Mth; -import net.minecraft.world.Container; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.InventoryMenu; -import net.minecraft.world.inventory.RecipeBookMenu; -import net.minecraft.world.item.ItemStack; - -import java.util.Collections; - -public class RoughlyEnoughItemsNetwork { - public static final ResourceLocation DELETE_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "delete_item"); - public static final ResourceLocation CREATE_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "create_item"); - public static final ResourceLocation CREATE_ITEMS_HOTBAR_PACKET = new ResourceLocation("roughlyenoughitems", "create_item_hotbar"); - public static final ResourceLocation CREATE_ITEMS_GRAB_PACKET = new ResourceLocation("roughlyenoughitems", "create_item_grab"); - public static final ResourceLocation CREATE_ITEMS_MESSAGE_PACKET = new ResourceLocation("roughlyenoughitems", "ci_msg"); - public static final ResourceLocation MOVE_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "move_items"); - public static final ResourceLocation NOT_ENOUGH_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "og_not_enough"); - - public static void onInitialize() { - NetworkManager.registerReceiver(NetworkManager.c2s(), DELETE_ITEMS_PACKET, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { - ServerPlayer player = (ServerPlayer) context.getPlayer(); - if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { - player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); - return; - } - AbstractContainerMenu menu = player.containerMenu; - if (!menu.getCarried().isEmpty()) { - menu.setCarried(ItemStack.EMPTY); - menu.broadcastChanges(); - } - }); - NetworkManager.registerReceiver(NetworkManager.c2s(), CREATE_ITEMS_PACKET, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { - ServerPlayer player = (ServerPlayer) context.getPlayer(); - if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { - player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); - return; - } - ItemStack stack = buf.readItem(); - if (player.getInventory().add(stack.copy())) { - NetworkManager.sendToPlayer(player, RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(stack.copy()).writeUtf(player.getScoreboardName(), 32767)); - } else { - player.displayClientMessage(new TranslatableComponent("text.rei.failed_cheat_items"), false); - } - }); - NetworkManager.registerReceiver(NetworkManager.c2s(), CREATE_ITEMS_GRAB_PACKET, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { - ServerPlayer player = (ServerPlayer) context.getPlayer(); - if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { - player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); - return; - } - - AbstractContainerMenu menu = player.containerMenu; - ItemStack itemStack = buf.readItem(); - ItemStack stack = itemStack.copy(); - if (!menu.getCarried().isEmpty() && ItemStack.isSameIgnoreDurability(menu.getCarried(), stack) && ItemStack.tagMatches(menu.getCarried(), stack)) { - stack.setCount(Mth.clamp(stack.getCount() + menu.getCarried().getCount(), 1, stack.getMaxStackSize())); - } else if (!menu.getCarried().isEmpty()) { - return; - } - menu.setCarried(stack.copy()); - menu.broadcastChanges(); - NetworkManager.sendToPlayer(player, RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(itemStack.copy()).writeUtf(player.getScoreboardName(), 32767)); - }); - NetworkManager.registerReceiver(NetworkManager.c2s(), CREATE_ITEMS_HOTBAR_PACKET, Collections.singletonList(new SplitPacketTransformer()), (buf, context) -> { - ServerPlayer player = (ServerPlayer) context.getPlayer(); - if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { - player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); - return; - } - ItemStack stack = buf.readItem(); - int hotbarSlotId = buf.readVarInt(); - if (hotbarSlotId >= 0 && hotbarSlotId < 9) { - AbstractContainerMenu menu = player.containerMenu; - player.getInventory().items.set(hotbarSlotId, stack.copy()); - menu.broadcastChanges(); - NetworkManager.sendToPlayer(player, RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(stack.copy()).writeUtf(player.getScoreboardName(), 32767)); - } else { - player.displayClientMessage(new TranslatableComponent("text.rei.failed_cheat_items"), false); - } - }); - NetworkManager.registerReceiver(NetworkManager.c2s(), MOVE_ITEMS_PACKET, Collections.singletonList(new SplitPacketTransformer()), (packetByteBuf, context) -> { - ServerPlayer player = (ServerPlayer) context.getPlayer(); - CategoryIdentifier category = CategoryIdentifier.of(packetByteBuf.readResourceLocation()); - AbstractContainerMenu container = player.containerMenu; - InventoryMenu playerContainer = player.inventoryMenu; - try { - boolean shift = packetByteBuf.readBoolean(); - try { - InputSlotCrafter crafter = InputSlotCrafter.start(category, container, player, packetByteBuf.readAnySizeNbt(), shift); - } catch (InputSlotCrafter.NotEnoughMaterialsException e) { - if (!(container instanceof RecipeBookMenu)) { - return; - } - // TODO Implement Ghost Recipes - /*FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); - buf.writeInt(input.size()); - for (List stacks : input) { - buf.writeInt(stacks.size()); - for (ItemStack stack : stacks) { - buf.writeItem(stack); - } - } - NetworkManager.sendToPlayer(player, NOT_ENOUGH_ITEMS_PACKET, buf);*/ - } catch (IllegalStateException e) { - player.sendMessage(new TranslatableComponent(e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); - } catch (Exception e) { - player.sendMessage(new TranslatableComponent("error.rei.internal.error", e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); - e.printStackTrace(); - } - } catch (Exception e) { - e.printStackTrace(); - } - }); - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientHelperImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientHelperImpl.java index 7a90619fc..c132fa569 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientHelperImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientHelperImpl.java @@ -23,75 +23,32 @@ package me.shedaniel.rei.impl.client; -import com.google.common.base.Suppliers; -import dev.architectury.networking.NetworkManager; -import dev.architectury.platform.Platform; -import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.longs.Long2LongMap; -import it.unimi.dsi.fastutil.longs.Long2LongMaps; -import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; -import me.shedaniel.rei.RoughlyEnoughItemsNetwork; import me.shedaniel.rei.api.client.ClientHelper; import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.DisplayScreenType; import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; import me.shedaniel.rei.api.client.view.ViewSearchBuilder; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext; -import me.shedaniel.rei.api.common.entry.type.EntryDefinition; -import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; -import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.api.common.util.FormattingUtils; -import me.shedaniel.rei.impl.ClientInternals; +import me.shedaniel.rei.impl.client.gui.DisplayScreenStack; import me.shedaniel.rei.impl.client.gui.screen.CompositeDisplayViewingScreen; import me.shedaniel.rei.impl.client.gui.screen.DefaultDisplayViewingScreen; -import me.shedaniel.rei.impl.client.view.ViewsImpl; import me.shedaniel.rei.impl.display.DisplaySpec; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen; -import net.minecraft.core.NonNullList; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.LazyLoadedValue; -import net.minecraft.util.Mth; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.time.LocalDateTime; -import java.util.*; -import java.util.function.Supplier; -import java.util.stream.Stream; +import java.util.List; +import java.util.Map; @ApiStatus.Internal @Environment(EnvType.CLIENT) -public class ClientHelperImpl implements ClientHelper { - @ApiStatus.Internal - public final LazyLoadedValue isAprilFools = new LazyLoadedValue<>(() -> { - try { - LocalDateTime now = LocalDateTime.now(); - return now.getMonthValue() == 4 && now.getDayOfMonth() == 1; - } catch (Throwable ignored) { - } - return false; - }); - private final Map modNameCache = new HashMap() {{ - put("minecraft", "Minecraft"); - put("c", "Global"); - put("global", "Global"); - }}; - +public class ClientHelperImpl extends ClientNetworkHelperImpl implements ClientModNameHelperImpl { /** * @return the instance of {@link ClientHelperImpl} * @see ClientHelper#getInstance() @@ -101,498 +58,36 @@ public static ClientHelperImpl getInstance() { return (ClientHelperImpl) ClientHelper.getInstance(); } - public boolean hasPermissionToUsePackets() { - try { - Minecraft.getInstance().getConnection().getSuggestionsProvider().hasPermission(0); - return hasOperatorPermission() && canUsePackets(); - } catch (NullPointerException e) { - return true; - } - } - - public boolean hasOperatorPermission() { - try { - return Minecraft.getInstance().getConnection().getSuggestionsProvider().hasPermission(1); - } catch (NullPointerException e) { - return true; - } - } - - public boolean canUsePackets() { - return NetworkManager.canServerReceive(RoughlyEnoughItemsNetwork.CREATE_ITEMS_PACKET) && NetworkManager.canServerReceive(RoughlyEnoughItemsNetwork.CREATE_ITEMS_GRAB_PACKET) && NetworkManager.canServerReceive(RoughlyEnoughItemsNetwork.DELETE_ITEMS_PACKET); - } - - public boolean canUseHotbarPackets() { - return NetworkManager.canServerReceive(RoughlyEnoughItemsNetwork.CREATE_ITEMS_HOTBAR_PACKET); - } - - public boolean canDeleteItems() { - return hasPermissionToUsePackets() || Minecraft.getInstance().gameMode.hasInfiniteItems(); - } - - @Override - public void appendModIdToTooltips(Tooltip components, String modId) { - final String modName = ClientHelper.getInstance().getModFromModId(modId); - Iterator iterator = components.entries().iterator(); - while (iterator.hasNext()) { - Tooltip.Entry entry = iterator.next(); - if (entry.isText() && FormattingUtils.stripFormatting(entry.getAsText().getString()).equalsIgnoreCase(modName)) { - iterator.remove(); - } - } - components.add(ClientHelper.getInstance().getFormattedModFromModId(modId)); - } - - @Override - public String getModFromModId(String modId) { - if (modId == null) - return ""; - String any = modNameCache.getOrDefault(modId, null); - if (any != null) - return any; - if (Platform.isModLoaded(modId)) { - String modName = Platform.getMod(modId).getName(); - modNameCache.put(modId, modName); - return modName; - } - return modId; - } - - @Override - public boolean isCheating() { - return ConfigObject.getInstance().isCheating(); - } - - @Override - public void setCheating(boolean cheating) { - ConfigObject.getInstance().setCheating(cheating); - ConfigManager.getInstance().saveConfig(); - } - @Override - public void sendDeletePacket() { - if (Minecraft.getInstance().screen instanceof CreativeModeInventoryScreen inventoryScreen) { - Minecraft.getInstance().player.containerMenu.setCarried(ItemStack.EMPTY); - inventoryScreen.isQuickCrafting = false; - return; - } - NetworkManager.sendToServer(RoughlyEnoughItemsNetwork.DELETE_ITEMS_PACKET, new FriendlyByteBuf(Unpooled.buffer())); - if (Minecraft.getInstance().screen instanceof AbstractContainerScreen containerScreen) { - containerScreen.isQuickCrafting = false; - } - } - - @Override - public boolean tryCheatingEntry(EntryStack e) { - if (e.getType() != VanillaEntryTypes.ITEM) - return false; - EntryStack entry = (EntryStack) e; - if (Minecraft.getInstance().player == null) return false; - if (Minecraft.getInstance().player.getInventory() == null) return false; - ItemStack cheatedStack = entry.getValue().copy(); - if (ConfigObject.getInstance().isGrabbingItems() && Minecraft.getInstance().screen instanceof CreativeModeInventoryScreen) { - AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; - EntryStack stack = entry.copy(); - if (!menu.getCarried().isEmpty() && EntryStacks.equalsExact(EntryStacks.of(menu.getCarried()), stack)) { - stack.getValue().setCount(Mth.clamp(stack.getValue().getCount() + menu.getCarried().getCount(), 1, stack.getValue().getMaxStackSize())); - } else if (!menu.getCarried().isEmpty()) { - return false; - } - menu.setCarried(stack.getValue().copy()); - return true; - } else if (ClientHelperImpl.getInstance().canUsePackets()) { - AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; - EntryStack stack = entry.copy(); - if (!menu.getCarried().isEmpty() && !EntryStacks.equalsExact(EntryStacks.of(menu.getCarried()), stack)) { - return false; - } - try { - NetworkManager.sendToServer(ConfigObject.getInstance().isGrabbingItems() ? RoughlyEnoughItemsNetwork.CREATE_ITEMS_GRAB_PACKET : RoughlyEnoughItemsNetwork.CREATE_ITEMS_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(cheatedStack)); - return true; - } catch (Exception exception) { - return false; - } - } else { - ResourceLocation identifier = entry.getIdentifier(); - if (identifier == null) { - return false; - } - String tagMessage = cheatedStack.copy().getTag() != null && !cheatedStack.copy().getTag().isEmpty() ? cheatedStack.copy().getTag().getAsString() : ""; - String og = cheatedStack.getCount() == 1 ? ConfigObject.getInstance().getGiveCommand().replaceAll(" \\{count}", "") : ConfigObject.getInstance().getGiveCommand(); - String madeUpCommand = og.replaceAll("\\{player_name}", Minecraft.getInstance().player.getScoreboardName()).replaceAll("\\{item_name}", identifier.getPath()).replaceAll("\\{item_identifier}", identifier.toString()).replaceAll("\\{nbt}", tagMessage).replaceAll("\\{count}", String.valueOf(cheatedStack.getCount())); - if (madeUpCommand.length() > 256) { - madeUpCommand = og.replaceAll("\\{player_name}", Minecraft.getInstance().player.getScoreboardName()).replaceAll("\\{item_name}", identifier.getPath()).replaceAll("\\{item_identifier}", identifier.toString()).replaceAll("\\{nbt}", "").replaceAll("\\{count}", String.valueOf(cheatedStack.getCount())); - Minecraft.getInstance().player.displayClientMessage(new TranslatableComponent("text.rei.too_long_nbt"), false); - } - Minecraft.getInstance().player.chat(madeUpCommand); - return true; - } - } - - @Override - public boolean tryCheatingEntryTo(EntryStack e, int hotbarSlotId) { - if (e.getType() != VanillaEntryTypes.ITEM) - return false; - EntryStack entry = (EntryStack) e; - if (Minecraft.getInstance().player == null) return false; - if (Minecraft.getInstance().player.getInventory() == null) return false; - if (Minecraft.getInstance().gameMode != null && Minecraft.getInstance().screen instanceof CreativeModeInventoryScreen) { - AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; - EntryStack stack = entry.copy(); - if (menu.getCarried().isEmpty()) { - Minecraft.getInstance().player.getInventory().setItem(hotbarSlotId, stack.getValue().copy()); - Minecraft.getInstance().player.inventoryMenu.broadcastChanges(); - return true; - } - } - if (ClientHelperImpl.getInstance().canUseHotbarPackets()) { - AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; - EntryStack stack = entry.copy(); - if (!menu.getCarried().isEmpty()) { - return false; - } - try { - NetworkManager.sendToServer(RoughlyEnoughItemsNetwork.CREATE_ITEMS_HOTBAR_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(stack.getValue().copy()).writeVarInt(hotbarSlotId)); - return true; - } catch (Exception exception) { - return false; - } - } else return false; - } - - @ApiStatus.Internal - public Long2LongMap _getInventoryItemsTypes() { - EntryDefinition definition; - try { - definition = VanillaEntryTypes.ITEM.getDefinition(); - } catch (NullPointerException e) { - return Long2LongMaps.EMPTY_MAP; - } - Long2LongOpenHashMap map = new Long2LongOpenHashMap(); - for (NonNullList compartment : Minecraft.getInstance().player.getInventory().compartments) { - for (ItemStack stack : compartment) { - long hash = definition.hash(null, stack, ComparisonContext.FUZZY); - long newCount = map.getOrDefault(hash, 0) + Math.max(0, stack.getCount()); - map.put(hash, newCount); - } - } - return map; - } - - @ApiStatus.Internal - public Long2LongMap _getContainerItemsTypes() { - EntryDefinition definition; - try { - definition = VanillaEntryTypes.ITEM.getDefinition(); - } catch (NullPointerException e) { - return Long2LongMaps.EMPTY_MAP; - } - Long2LongOpenHashMap map = new Long2LongOpenHashMap(); - AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; - if (menu != null) { - for (Slot slot : menu.slots) { - ItemStack stack = slot.getItem(); - - if (!stack.isEmpty()) { - long hash = definition.hash(null, stack, ComparisonContext.FUZZY); - long newCount = map.getOrDefault(hash, 0) + Math.max(0, stack.getCount()); - map.put(hash, newCount); - } - } - } - return map; - } - - @ApiStatus.Internal - public void openDisplayViewingScreen(Map, List> map, @Nullable CategoryIdentifier category, List> ingredientNotice, List> resultNotice) { - LegacyWrapperViewSearchBuilder builder = new LegacyWrapperViewSearchBuilder(map); - for (EntryStack stack : ingredientNotice) { - builder.addInputNotice(stack); - } - for (EntryStack stack : resultNotice) { - builder.addOutputNotice(stack); - } - openView(builder.setPreferredOpenedCategory(category)); + public boolean openView(ViewSearchBuilder builder) { + return openView(builder.buildMapInternal(), builder.getPreferredOpenedCategory(), builder.getUsagesFor(), builder.getRecipesFor()); } - @Override - public boolean openView(ViewSearchBuilder builder) { - Map, List> map = builder.buildMapInternal(); + public boolean openView(Map, List> map, @Nullable CategoryIdentifier category, + List> usagesFor, List> recipesFor) { if (map.isEmpty()) return false; Screen screen; if (ConfigObject.getInstance().getRecipeScreenType() == DisplayScreenType.COMPOSITE) { - screen = new CompositeDisplayViewingScreen(map, builder.getPreferredOpenedCategory()); + screen = new CompositeDisplayViewingScreen(map, category); } else if (ConfigObject.getInstance().getRecipeScreenType() == DisplayScreenType.UNSET) { ConfigObject.getInstance().setRecipeScreenType(DisplayScreenType.ORIGINAL); ConfigManager.getInstance().saveConfig(); - return openView(builder); -// screen = new UncertainDisplayViewingScreen(REIRuntime.getInstance().getPreviousScreen(), DisplayScreenType.UNSET, true, original -> { -// ConfigObject.getInstance().setRecipeScreenType(original ? DisplayScreenType.ORIGINAL : DisplayScreenType.COMPOSITE); -// ConfigManager.getInstance().saveConfig(); -// openView(builder); -// }); + return openView(map, category, usagesFor, recipesFor); } else { - screen = new DefaultDisplayViewingScreen(map, builder.getPreferredOpenedCategory()); + screen = new DefaultDisplayViewingScreen(map, category); } if (screen instanceof DisplayScreen displayScreen) { - for (EntryStack stack : builder.getUsagesFor()) { + for (EntryStack stack : usagesFor) { displayScreen.addIngredientToNotice(stack); } - for (EntryStack stack : builder.getRecipesFor()) { + for (EntryStack stack : recipesFor) { displayScreen.addResultToNotice(stack); } } if (Minecraft.getInstance().screen instanceof DisplayScreen displayScreen) { - REIRuntimeImpl.getInstance().storeDisplayScreen(displayScreen); + DisplayScreenStack.storeDisplayScreen(displayScreen); } Minecraft.getInstance().setScreen(screen); return true; } - - @Override - public boolean canUseMovePackets() { - return NetworkManager.canServerReceive(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET); - } - - public void onInitializeClient() { - ClientInternals.attachInstance(this, ClientHelper.class); - ClientInternals.attachInstance((Supplier) ViewSearchBuilderImpl::new, "viewSearchBuilder"); - } - - private static abstract class AbstractViewSearchBuilder implements ViewSearchBuilder { - public ViewSearchBuilder fillPreferredOpenedCategory() { - if (getPreferredOpenedCategory() == null) { - Screen currentScreen = Minecraft.getInstance().screen; - if (currentScreen instanceof DisplayScreen displayScreen) { - setPreferredOpenedCategory(displayScreen.getCurrentCategoryId()); - } - } - return this; - } - - @Override - public Stream streamDisplays() { - return buildMapInternal().values().stream().flatMap(Collection::stream); - } - } - - public static final class ViewSearchBuilderImpl extends AbstractViewSearchBuilder { - private final Set> filteringCategories = new HashSet<>(); - private final Set> categories = new HashSet<>(); - private final List> recipesFor = new ArrayList<>(); - private final List> usagesFor = new ArrayList<>(); - @Nullable - private CategoryIdentifier preferredOpenedCategory = null; - private boolean mergeDisplays = true; - private boolean processVisibilityHandlers = true; - private final Supplier, List>> map = Suppliers.memoize(() -> ViewsImpl.buildMapFor(this)); - - @Override - public ViewSearchBuilder addCategory(CategoryIdentifier category) { - this.categories.add(category); - return this; - } - - @Override - public ViewSearchBuilder addCategories(Collection> categories) { - this.categories.addAll(categories); - return this; - } - - @Override - public Set> getCategories() { - return categories; - } - - @Override - public ViewSearchBuilder addRecipesFor(EntryStack stack) { - this.recipesFor.add(stack); - return this; - } - - @Override - public List> getRecipesFor() { - return recipesFor; - } - - @Override - public ViewSearchBuilder addUsagesFor(EntryStack stack) { - this.usagesFor.add(stack); - return this; - } - - @Override - public List> getUsagesFor() { - return usagesFor; - } - - @Override - public ViewSearchBuilder setPreferredOpenedCategory(@Nullable CategoryIdentifier category) { - this.preferredOpenedCategory = category; - return this; - } - - @Override - @Nullable - public CategoryIdentifier getPreferredOpenedCategory() { - return this.preferredOpenedCategory; - } - - @Override - public ViewSearchBuilder filterCategory(CategoryIdentifier category) { - this.filteringCategories.add(category); - return this; - } - - @Override - public ViewSearchBuilder filterCategories(Collection> categories) { - this.filteringCategories.addAll(categories); - return this; - } - - @Override - public Set> getFilteringCategories() { - return filteringCategories; - } - - @Override - public Map, List> buildMapInternal() { - fillPreferredOpenedCategory(); - return this.map.get(); - } - - @Override - public boolean isMergingDisplays() { - return mergeDisplays; - } - - @Override - public ViewSearchBuilder mergingDisplays(boolean mergingDisplays) { - this.mergeDisplays = mergingDisplays; - return this; - } - - @Override - public boolean isProcessingVisibilityHandlers() { - return processVisibilityHandlers; - } - - @Override - public ViewSearchBuilder processingVisibilityHandlers(boolean processingVisibilityHandlers) { - this.processVisibilityHandlers = processingVisibilityHandlers; - return this; - } - } - - public static final class LegacyWrapperViewSearchBuilder extends AbstractViewSearchBuilder { - private final Map, List> map; - @Nullable - private EntryStack inputNotice; - @Nullable - private EntryStack outputNotice; - @Nullable - private CategoryIdentifier preferredOpenedCategory = null; - - public LegacyWrapperViewSearchBuilder(Map, List> map) { - this.map = map; - } - - @Override - public ViewSearchBuilder addCategory(CategoryIdentifier category) { - return this; - } - - @Override - public ViewSearchBuilder addCategories(Collection> categories) { - return this; - } - - @Override - public Set> getCategories() { - return Collections.emptySet(); - } - - @Override - public ViewSearchBuilder filterCategory(CategoryIdentifier category) { - return this; - } - - @Override - public ViewSearchBuilder filterCategories(Collection> categories) { - return this; - } - - @Override - public Set> getFilteringCategories() { - return Collections.emptySet(); - } - - @Override - public ViewSearchBuilder addRecipesFor(EntryStack stack) { - return this; - } - - @Override - public List> getRecipesFor() { - return inputNotice == null ? Collections.emptyList() : Collections.singletonList(outputNotice); - } - - @Override - public ViewSearchBuilder addUsagesFor(EntryStack stack) { - return this; - } - - @Override - public List> getUsagesFor() { - return inputNotice == null ? Collections.emptyList() : Collections.singletonList(inputNotice); - } - - @Override - public ViewSearchBuilder setPreferredOpenedCategory(@Nullable CategoryIdentifier category) { - this.preferredOpenedCategory = category; - return this; - } - - @Override - @Nullable - public CategoryIdentifier getPreferredOpenedCategory() { - return this.preferredOpenedCategory; - } - - public LegacyWrapperViewSearchBuilder addInputNotice(@Nullable EntryStack stack) { - this.inputNotice = stack; - return this; - } - - public LegacyWrapperViewSearchBuilder addOutputNotice(@Nullable EntryStack stack) { - this.outputNotice = stack; - return this; - } - - @Override - public Map, List> buildMapInternal() { - fillPreferredOpenedCategory(); - return this.map; - } - - @Override - public boolean isMergingDisplays() { - return true; - } - - @Override - public ViewSearchBuilder mergingDisplays(boolean mergingDisplays) { - return this; - } - - @Override - public boolean isProcessingVisibilityHandlers() { - return false; - } - - @Override - public ViewSearchBuilder processingVisibilityHandlers(boolean processingVisibilityHandlers) { - return this; - } - } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientModNameHelperImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientModNameHelperImpl.java new file mode 100644 index 000000000..8fd9a9417 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientModNameHelperImpl.java @@ -0,0 +1,69 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client; + +import dev.architectury.platform.Platform; +import me.shedaniel.rei.api.client.ClientHelper; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.common.util.FormattingUtils; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public interface ClientModNameHelperImpl extends ClientHelper { + Map MOD_NAME_CACHE = new HashMap<>() {{ + put("minecraft", "Minecraft"); + put("c", "Common"); + put("global", "Global"); + }}; + + @Override + default void appendModIdToTooltips(Tooltip components, String modId) { + final String modName = ClientHelper.getInstance().getModFromModId(modId); + Iterator iterator = components.entries().iterator(); + while (iterator.hasNext()) { + Tooltip.Entry entry = iterator.next(); + if (entry.isText() && FormattingUtils.stripFormatting(entry.getAsText().getString()).equalsIgnoreCase(modName)) { + iterator.remove(); + } + } + components.add(ClientHelper.getInstance().getFormattedModFromModId(modId)); + } + + @Override + default String getModFromModId(String modId) { + if (modId == null) + return ""; + String any = MOD_NAME_CACHE.getOrDefault(modId, null); + if (any != null) + return any; + if (Platform.isModLoaded(modId)) { + String modName = Platform.getMod(modId).getName(); + MOD_NAME_CACHE.put(modId, modName); + return modName; + } + return modId; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientNetworkHelperImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientNetworkHelperImpl.java new file mode 100644 index 000000000..e2a9e0cf3 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/ClientNetworkHelperImpl.java @@ -0,0 +1,141 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client; + +import me.shedaniel.rei.api.client.ClientHelper; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; +import me.shedaniel.rei.api.common.networking.NetworkModule; +import me.shedaniel.rei.api.common.networking.NetworkModuleKey; +import me.shedaniel.rei.api.common.networking.NetworkingHelper; +import me.shedaniel.rei.api.common.util.EntryStacks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.util.Unit; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; + +import java.util.AbstractMap; + +public abstract class ClientNetworkHelperImpl implements ClientHelper { + @Override + public void sendDeletePacket() { + if (Minecraft.getInstance().screen instanceof CreativeModeInventoryScreen inventoryScreen) { + Minecraft.getInstance().player.containerMenu.setCarried(ItemStack.EMPTY); + inventoryScreen.isQuickCrafting = false; + return; + } + NetworkingHelper.getInstance().sendToServer(NetworkModule.DELETE_ITEM, Unit.INSTANCE); + if (Minecraft.getInstance().screen instanceof AbstractContainerScreen containerScreen) { + containerScreen.isQuickCrafting = false; + } + } + + @Override + public boolean tryCheatingEntry(EntryStack e) { + if (e.getType() != VanillaEntryTypes.ITEM) + return false; + EntryStack entry = (EntryStack) e; + if (Minecraft.getInstance().player == null) return false; + if (Minecraft.getInstance().player.getInventory() == null) return false; + ItemStack cheatedStack = entry.getValue().copy(); + if (ConfigObject.getInstance().isGrabbingItems() && Minecraft.getInstance().screen instanceof CreativeModeInventoryScreen) { + AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; + EntryStack stack = entry.copy(); + if (!menu.getCarried().isEmpty() && EntryStacks.equalsExact(EntryStacks.of(menu.getCarried()), stack)) { + stack.getValue().setCount(Mth.clamp(stack.getValue().getCount() + menu.getCarried().getCount(), 1, stack.getValue().getMaxStackSize())); + } else if (!menu.getCarried().isEmpty()) { + return false; + } + menu.setCarried(stack.getValue().copy()); + return true; + } else if (NetworkingHelper.getInstance().canUse(NetworkModule.CHEAT_GIVE) + || NetworkingHelper.getInstance().canUse(NetworkModule.CHEAT_GRAB)) { + AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; + EntryStack stack = entry.copy(); + if (!menu.getCarried().isEmpty() && !EntryStacks.equalsExact(EntryStacks.of(menu.getCarried()), stack)) { + return false; + } + try { + NetworkModuleKey key = ConfigObject.getInstance().isGrabbingItems() + && NetworkingHelper.getInstance().canUse(NetworkModule.CHEAT_GRAB) + ? NetworkModule.CHEAT_GRAB : NetworkModule.CHEAT_GIVE; + NetworkingHelper.getInstance().sendToServer(key, cheatedStack); + return true; + } catch (Exception exception) { + return false; + } + } else { + ResourceLocation identifier = entry.getIdentifier(); + if (identifier == null) { + return false; + } + String tagMessage = cheatedStack.copy().getTag() != null && !cheatedStack.copy().getTag().isEmpty() ? cheatedStack.copy().getTag().getAsString() : ""; + String og = cheatedStack.getCount() == 1 ? ConfigObject.getInstance().getGiveCommand().replaceAll(" \\{count}", "") : ConfigObject.getInstance().getGiveCommand(); + String madeUpCommand = og.replaceAll("\\{player_name}", Minecraft.getInstance().player.getScoreboardName()).replaceAll("\\{item_name}", identifier.getPath()).replaceAll("\\{item_identifier}", identifier.toString()).replaceAll("\\{nbt}", tagMessage).replaceAll("\\{count}", String.valueOf(cheatedStack.getCount())); + if (madeUpCommand.length() > 256) { + madeUpCommand = og.replaceAll("\\{player_name}", Minecraft.getInstance().player.getScoreboardName()).replaceAll("\\{item_name}", identifier.getPath()).replaceAll("\\{item_identifier}", identifier.toString()).replaceAll("\\{nbt}", "").replaceAll("\\{count}", String.valueOf(cheatedStack.getCount())); + Minecraft.getInstance().player.displayClientMessage(new TranslatableComponent("text.rei.too_long_nbt"), false); + } + Minecraft.getInstance().player.chat(madeUpCommand); + return true; + } + } + + @Override + public boolean tryCheatingEntryTo(EntryStack e, int hotbarSlotId) { + if (e.getType() != VanillaEntryTypes.ITEM) + return false; + EntryStack entry = (EntryStack) e; + if (Minecraft.getInstance().player == null) return false; + if (Minecraft.getInstance().player.getInventory() == null) return false; + if (Minecraft.getInstance().gameMode != null && Minecraft.getInstance().screen instanceof CreativeModeInventoryScreen) { + AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; + EntryStack stack = entry.copy(); + if (menu.getCarried().isEmpty()) { + Minecraft.getInstance().player.getInventory().setItem(hotbarSlotId, stack.getValue().copy()); + Minecraft.getInstance().player.inventoryMenu.broadcastChanges(); + return true; + } + } + if (NetworkingHelper.getInstance().canUse(NetworkModule.CHEAT_HOTBAR)) { + AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; + EntryStack stack = entry.copy(); + if (!menu.getCarried().isEmpty()) { + return false; + } + try { + NetworkingHelper.getInstance().sendToServer(NetworkModule.CHEAT_HOTBAR, new AbstractMap.SimpleEntry<>(stack.getValue().copy(), hotbarSlotId)); + return true; + } catch (Exception exception) { + return false; + } + } else return false; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/ErrorDisplayer.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/ErrorDisplayer.java index 29b7accfe..82424ac5c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/ErrorDisplayer.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/ErrorDisplayer.java @@ -24,7 +24,7 @@ package me.shedaniel.rei.impl.client; import me.shedaniel.rei.RoughlyEnoughItemsState; -import me.shedaniel.rei.impl.client.gui.screen.WarningAndErrorScreen; +import me.shedaniel.rei.impl.client.gui.screen.error.WarningAndErrorScreen; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java index bff0573e8..d577df670 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java @@ -23,31 +23,22 @@ package me.shedaniel.rei.impl.client; -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.systems.RenderSystem; import dev.architectury.event.EventResult; import dev.architectury.event.events.client.ClientGuiEvent; import dev.architectury.event.events.client.ClientTickEvent; -import dev.architectury.platform.Platform; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.DisplayPanelLocation; import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; -import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; -import me.shedaniel.rei.api.client.gui.widgets.TextField; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.common.registry.ReloadStage; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.hints.HintProvider; -import me.shedaniel.rei.impl.client.gui.widget.CachedEntryListRender; -import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; -import me.shedaniel.rei.impl.client.search.argument.Argument; +import me.shedaniel.rei.impl.client.gui.DisplayScreenStack; +import me.shedaniel.rei.impl.client.gui.InternalTextures; +import me.shedaniel.rei.impl.client.provider.OverlayTicker; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -58,23 +49,16 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.InvocationTargetException; -import java.util.*; +import java.util.Optional; -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; @ApiStatus.Internal @Environment(EnvType.CLIENT) public class REIRuntimeImpl implements REIRuntime { - private static final ResourceLocation DISPLAY_TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/display.png"); - private static final ResourceLocation DISPLAY_TEXTURE_DARK = new ResourceLocation("roughlyenoughitems", "textures/gui/display_dark.png"); - @ApiStatus.Internal - public static boolean isWithinRecipeViewingScreen = false; - private ScreenOverlayImpl overlay; - private OverlaySearchField searchField; + private ScreenOverlay overlay; private AbstractContainerScreen previousContainerScreen = null; private Screen previousScreen = null; - private LinkedHashSet lastDisplayScreen = Sets.newLinkedHashSetWithExpectedSize(10); - private List hintProviders = new ArrayList<>(); /** * @return the instance of screen helper @@ -85,84 +69,16 @@ public static REIRuntimeImpl getInstance() { return (REIRuntimeImpl) REIRuntime.getInstance(); } - public void addHintProvider(HintProvider provider) { - this.hintProviders.add(provider); - } - - public List getHintProviders() { - return Collections.unmodifiableList(hintProviders); - } - - @Override - public void queueTooltip(@Nullable Tooltip tooltip) { - if (overlay != null && tooltip != null) { - overlay.addTooltip(tooltip); - } - } - - @Override - public void clearTooltips() { - if (overlay != null) { - overlay.clearTooltips(); - } - } - - @Override - @Nullable - public TextField getSearchTextField() { - if (searchField == null) { - searchField = new OverlaySearchField(0, 0, 0, 0); - } - - return searchField; - } - - @Nullable - public static OverlaySearchField getSearchField() { - return (OverlaySearchField) getInstance().getSearchTextField(); - } - - public void storeDisplayScreen(DisplayScreen screen) { - while (lastDisplayScreen.size() >= 10) - lastDisplayScreen.remove(Iterables.get(lastDisplayScreen, 0)); - lastDisplayScreen.add(screen); - } - - public boolean hasLastDisplayScreen() { - return !lastDisplayScreen.isEmpty(); - } - - public Screen getLastDisplayScreen() { - DisplayScreen screen = Iterables.getLast(lastDisplayScreen); - lastDisplayScreen.remove(screen); - screen.recalculateCategoryPage(); - return (Screen) screen; - } - - @Override - public boolean isOverlayVisible() { - return ConfigObject.getInstance().isOverlayVisible(); - } - - @Override - public void toggleOverlayVisible() { - ConfigObject.getInstance().setOverlayVisible(!ConfigObject.getInstance().isOverlayVisible()); - ConfigManager.getInstance().saveConfig(); - } - @Override public Optional getOverlay(boolean reset, boolean init) { if ((overlay == null && init) || reset) { + overlay = ClientInternals.getNewOverlay(); try { - overlay = (ScreenOverlayImpl) Class.forName(Platform.isForge() ? "me.shedaniel.rei.impl.client.gui.forge.ScreenOverlayImplForge" - : "me.shedaniel.rei.impl.client.gui.fabric.ScreenOverlayImplFabric") - .getDeclaredConstructor() - .newInstance(); - } catch (InstantiationException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + overlay.getClass().getMethod("init").invoke(overlay); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new RuntimeException(e); } - overlay.init(); - getSearchField().setFocused(false); + overlay.getSearchField().setFocused(false); } return Optional.ofNullable(overlay); @@ -192,19 +108,9 @@ public void setPreviousScreen(Screen previousScreen) { } } - @Override - public boolean isDarkThemeEnabled() { - return ConfigObject.getInstance().isUsingDarkTheme(); - } - - @Override - public ResourceLocation getDefaultDisplayTexture() { - return getDefaultDisplayTexture(isDarkThemeEnabled()); - } - @Override public ResourceLocation getDefaultDisplayTexture(boolean darkTheme) { - return darkTheme ? DISPLAY_TEXTURE_DARK : DISPLAY_TEXTURE; + return darkTheme ? InternalTextures.DISPLAY_TEXTURE_DARK : InternalTextures.DISPLAY_TEXTURE; } @Override @@ -255,24 +161,19 @@ public Rectangle calculateFavoritesListArea() { @Override public void startReload() { - Argument.SEARCH_CACHE.clear(); - getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); - lastDisplayScreen.clear(); - if (!RenderSystem.isOnRenderThread()) { - RenderSystem.recordRenderCall(CachedEntryListRender::refresh); - } else { - CachedEntryListRender.refresh(); - } + startReload(null); } @Override public void startReload(ReloadStage stage) { - startReload(); + SearchProvider.getInstance().clearCache(); + getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); + DisplayScreenStack.clear(); } @Override public void endReload(ReloadStage stage) { - Argument.SEARCH_CACHE.clear(); + SearchProvider.getInstance().clearCache(); getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); } @@ -284,7 +185,10 @@ public void onInitializeClient() { }); ClientTickEvent.CLIENT_POST.register(minecraft -> { if (isOverlayVisible() && REIRuntime.getInstance().getOverlay().isPresent()) { - ScreenOverlayImpl.getInstance().tick(); + REIRuntime.getInstance().getSearchTextField().tick(); + for (OverlayTicker ticker : ClientInternals.getOverlayTickers()) { + ticker.tick(); + } } }); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java deleted file mode 100644 index 1a6b4430c..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.favorites; - -import com.mojang.serialization.DataResult; -import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; -import me.shedaniel.rei.api.client.gui.Renderer; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceLocation; - -import java.util.Collection; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; -import java.util.function.Supplier; - -public class DelegatingFavoriteEntryProviderImpl extends FavoriteEntry { - private final Supplier> supplier; - private final Supplier toJson; - private FavoriteEntry value = null; - - public DelegatingFavoriteEntryProviderImpl(Supplier> supplier, Supplier toJson) { - this.supplier = supplier; - this.toJson = toJson; - } - - @Override - public FavoriteEntry getUnwrapped() { - synchronized (this) { - if (this.value == null) { - DataResult result = supplier.get(); - this.value = result.getOrThrow(false, error -> {}); - } - } - return Objects.requireNonNull(value).getUnwrapped(); - } - - @Override - public UUID getUuid() { - return getUnwrapped().getUuid(); - } - - @Override - public boolean isInvalid() { - try { - return getUnwrapped().isInvalid(); - } catch (Exception e) { - return true; - } - } - - @Override - public Renderer getRenderer(boolean showcase) { - return getUnwrapped().getRenderer(showcase); - } - - @Override - public boolean doAction(int button) { - return getUnwrapped().doAction(button); - } - - @Override - public Optional>> getMenuEntries() { - return getUnwrapped().getMenuEntries(); - } - - @Override - public long hashIgnoreAmount() { - return getUnwrapped().hashIgnoreAmount(); - } - - @Override - public FavoriteEntry copy() { - return FavoriteEntry.delegateResult(supplier, toJson); - } - - @Override - public ResourceLocation getType() { - return getUnwrapped().getType(); - } - - @Override - public CompoundTag save(CompoundTag tag) { - if (toJson == null) { - return getUnwrapped().save(tag); - } - - return tag.merge(toJson.get()); - } - - @Override - public boolean isSame(FavoriteEntry other) { - return getUnwrapped().isSame(other.getUnwrapped()); - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/DisplayScreenStack.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/DisplayScreenStack.java new file mode 100644 index 000000000..9b590da56 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/DisplayScreenStack.java @@ -0,0 +1,56 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; +import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; +import net.minecraft.client.gui.screens.Screen; + +import java.util.LinkedHashSet; + +public class DisplayScreenStack { + private static final LinkedHashSet LAST_DISPLAY_SCREENS = Sets.newLinkedHashSetWithExpectedSize(10); + + public static void storeDisplayScreen(DisplayScreen screen) { + while (LAST_DISPLAY_SCREENS.size() >= 10) + LAST_DISPLAY_SCREENS.remove(Iterables.get(LAST_DISPLAY_SCREENS, 0)); + LAST_DISPLAY_SCREENS.add(screen); + } + + public static boolean hasLastDisplayScreen() { + return !LAST_DISPLAY_SCREENS.isEmpty(); + } + + public static Screen getLastDisplayScreen() { + DisplayScreen screen = Iterables.getLast(LAST_DISPLAY_SCREENS); + LAST_DISPLAY_SCREENS.remove(screen); + screen.recalculateCategoryPage(); + return (Screen) screen; + } + + public static void clear() { + LAST_DISPLAY_SCREENS.clear(); + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java deleted file mode 100644 index b4c1987d0..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/ScreenOverlayImpl.java +++ /dev/null @@ -1,564 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; -import me.shedaniel.math.impl.PointHelper; -import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.config.ConfigManager; -import me.shedaniel.rei.api.client.config.ConfigObject; -import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.gui.config.DisplayPanelLocation; -import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; -import me.shedaniel.rei.api.client.gui.drag.DraggingContext; -import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProvider; -import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitor; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.api.client.gui.widgets.Widget; -import me.shedaniel.rei.api.client.overlay.OverlayListWidget; -import me.shedaniel.rei.api.client.overlay.ScreenOverlay; -import me.shedaniel.rei.api.client.registry.screen.ClickArea; -import me.shedaniel.rei.api.client.registry.screen.OverlayDecider; -import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; -import me.shedaniel.rei.api.client.view.ViewSearchBuilder; -import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.plugins.PluginManager; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; -import me.shedaniel.rei.impl.client.gui.craftable.CraftableFilter; -import me.shedaniel.rei.impl.client.gui.dragging.CurrentDraggingStack; -import me.shedaniel.rei.impl.client.gui.modules.MenuAccess; -import me.shedaniel.rei.impl.client.gui.modules.MenuHolder; -import me.shedaniel.rei.impl.client.gui.widget.*; -import me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget; -import me.shedaniel.rei.impl.client.gui.widget.entrylist.PaginatedEntryListWidget; -import me.shedaniel.rei.impl.client.gui.widget.entrylist.ScrolledEntryListWidget; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; -import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.InteractionResult; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; - -@ApiStatus.Internal -public abstract class ScreenOverlayImpl extends ScreenOverlay { - private static final List TOOLTIPS = Lists.newArrayList(); - private static EntryListWidget entryListWidget = null; - private static FavoritesListWidget favoritesListWidget = null; - private final List widgets = Lists.newLinkedList(); - public boolean shouldReload = false; - public boolean shouldReloadSearch = false; - private Rectangle bounds; - private Window window; - private Widget configButton; - private CurrentDraggingStack draggingStack = new CurrentDraggingStack(); - @Nullable - public DefaultDisplayChoosePageWidget choosePageWidget; - private MenuHolder menuHolder = new MenuHolder(); - - public static EntryListWidget getEntryListWidget() { - boolean widgetScrolled = ConfigObject.getInstance().isEntryListWidgetScrolled(); - - if (entryListWidget != null) { - if (widgetScrolled && entryListWidget instanceof ScrolledEntryListWidget) { - return entryListWidget; - } else if (!widgetScrolled && entryListWidget instanceof PaginatedEntryListWidget) { - return entryListWidget; - } - } - - entryListWidget = widgetScrolled ? new ScrolledEntryListWidget() : new PaginatedEntryListWidget(); - - ScreenOverlayImpl overlay = ScreenOverlayImpl.getInstance(); - Rectangle overlayBounds = overlay.bounds; - entryListWidget.updateArea(Objects.requireNonNullElse(overlayBounds, new Rectangle()), REIRuntimeImpl.getSearchField() == null ? "" : REIRuntimeImpl.getSearchField().getText()); - entryListWidget.updateEntriesPosition(); - - return entryListWidget; - } - - @Nullable - public static FavoritesListWidget getFavoritesListWidget() { - return favoritesListWidget; - } - - public static ScreenOverlayImpl getInstance() { - return (ScreenOverlayImpl) REIRuntime.getInstance().getOverlay().get(); - } - - public void tick() { - if (REIRuntimeImpl.getSearchField() != null) { - REIRuntimeImpl.getSearchField().tick(); - if (Minecraft.getInstance().player != null && !PluginManager.areAnyReloading() && Minecraft.getInstance().player.tickCount % 5 == 0) { - CraftableFilter.INSTANCE.tick(); - } - } - } - - @Override - public void queueReloadOverlay() { - shouldReload = true; - } - - @Override - public void queueReloadSearch() { - shouldReloadSearch = true; - } - - @Override - public DraggingContext getDraggingContext() { - return draggingStack; - } - - protected boolean hasSpace() { - return !this.bounds.isEmpty(); - } - - public void init() { - this.draggingStack.set(DraggableComponentProvider.from(ScreenRegistry.getInstance()::getDraggableComponentProviders), - DraggableComponentVisitor.from(ScreenRegistry.getInstance()::getDraggableComponentVisitors)); - - this.shouldReload = false; - this.shouldReloadSearch = false; - this.children().clear(); - this.window = Minecraft.getInstance().getWindow(); - this.bounds = calculateOverlayBounds(); - - if (ConfigObject.getInstance().isFavoritesEnabled()) { - if (favoritesListWidget == null) { - favoritesListWidget = new FavoritesListWidget(); - } - favoritesListWidget.favoritePanel.resetRows(); - this.widgets.add(favoritesListWidget); - } - - OverlaySearchField searchField = REIRuntimeImpl.getSearchField(); - searchField.getBounds().setBounds(getSearchFieldArea()); - this.widgets.add(searchField); - - EntryListWidget entryListWidget = getEntryListWidget(); - entryListWidget.updateArea(this.bounds, searchField.getText()); - this.widgets.add(entryListWidget); - searchField.setResponder(s -> entryListWidget.updateSearch(s, false)); - entryListWidget.init(this); - - this.widgets.add(configButton = ConfigButtonWidget.create(this)); - if (ConfigObject.getInstance().isCraftableFilterEnabled()) { - this.widgets.add(CraftableFilterButtonWidget.create(this)); - } - - this.widgets.add(draggingStack); - } - - private Rectangle getSearchFieldArea() { - int widthRemoved = 1; - if (ConfigObject.getInstance().isCraftableFilterEnabled()) widthRemoved += 22; - if (ConfigObject.getInstance().isLowerConfigButton()) widthRemoved += 22; - SearchFieldLocation searchFieldLocation = REIRuntime.getInstance().getContextualSearchFieldLocation(); - return switch (searchFieldLocation) { - case TOP_SIDE -> getTopSideSearchFieldArea(widthRemoved); - case BOTTOM_SIDE -> getBottomSideSearchFieldArea(widthRemoved); - case CENTER -> getCenterSearchFieldArea(widthRemoved); - }; - } - - private Rectangle getTopSideSearchFieldArea(int widthRemoved) { - return new Rectangle(bounds.x + 2, 4, bounds.width - 6 - widthRemoved, 18); - } - - private Rectangle getBottomSideSearchFieldArea(int widthRemoved) { - return new Rectangle(bounds.x + 2, window.getGuiScaledHeight() - 22, bounds.width - 6 - widthRemoved, 18); - } - - private Rectangle getCenterSearchFieldArea(int widthRemoved) { - Rectangle screenBounds = ScreenRegistry.getInstance().getScreenBounds(minecraft.screen); - return new Rectangle(screenBounds.x, window.getGuiScaledHeight() - 22, screenBounds.width - widthRemoved, 18); - } - - @Override - public Rectangle getBounds() { - return bounds; - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (shouldReload || !calculateOverlayBounds().equals(bounds)) { - init(); - getEntryListWidget().updateSearch(REIRuntimeImpl.getSearchField().getText(), true); - } else { - for (OverlayDecider decider : ScreenRegistry.getInstance().getDeciders(minecraft.screen)) { - if (decider != null && decider.shouldRecalculateArea(ConfigObject.getInstance().getDisplayPanelLocation(), bounds)) { - init(); - break; - } - } - } - if (shouldReloadSearch || (ConfigManager.getInstance().isCraftableOnlyEnabled() && CraftableFilter.INSTANCE.wasDirty())) { - shouldReloadSearch = false; - getEntryListWidget().updateSearch(REIRuntimeImpl.getSearchField().getText(), true); - } - if (OverlaySearchField.isHighlighting) { - EntryHighlighter.render(matrices); - } - if (!hasSpace()) return; - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - this.renderWidgets(matrices, mouseX, mouseY, delta); - if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) { - Screen screen = Minecraft.getInstance().screen; - ClickArea.ClickAreaContext context = createClickAreaContext(mouseX, mouseY, screen); - List clickAreaTooltips = ScreenRegistry.getInstance().getClickAreaTooltips((Class) screen.getClass(), context); - if (clickAreaTooltips != null && !clickAreaTooltips.isEmpty()) { - Tooltip.create(clickAreaTooltips).queue(); - } - } - } - - private ClickArea.ClickAreaContext createClickAreaContext(double mouseX, double mouseY, Screen screen) { - return new ClickArea.ClickAreaContext<>() { - @Override - public Screen getScreen() { - return screen; - } - - @Override - public Point getMousePosition() { - return new Point(mouseX, mouseY); - } - }; - } - - private static Rectangle calculateOverlayBounds() { - Rectangle bounds = ScreenRegistry.getInstance().getOverlayBounds(ConfigObject.getInstance().getDisplayPanelLocation(), Minecraft.getInstance().screen); - - int widthReduction = (int) Math.round(bounds.width * (1 - ConfigObject.getInstance().getHorizontalEntriesBoundariesPercentage())); - if (ConfigObject.getInstance().getDisplayPanelLocation() == DisplayPanelLocation.RIGHT) - bounds.x += widthReduction; - bounds.width -= widthReduction; - int maxWidth = (int) Math.ceil(entrySize() * ConfigObject.getInstance().getHorizontalEntriesBoundariesColumns() + entrySize() * 0.75); - if (bounds.width > maxWidth) { - if (ConfigObject.getInstance().getDisplayPanelLocation() == DisplayPanelLocation.RIGHT) - bounds.x += bounds.width - maxWidth; - bounds.width = maxWidth; - } - - return bounds; - } - - public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (REIRuntime.getInstance().isOverlayVisible() && hasSpace()) { - REIRuntimeImpl.getSearchField().laterRender(matrices, mouseX, mouseY, delta); - for (Widget widget : widgets) { - if (widget instanceof LateRenderable && widget != menuHolder.widget()) - widget.render(matrices, mouseX, mouseY, delta); - } - matrices.pushPose(); - matrices.translate(0, 0, 500); - menuHolder.lateRender(matrices, mouseX, mouseY, delta); - matrices.popPose(); - if (choosePageWidget != null) { - setBlitOffset(500); - this.fillGradient(matrices, 0, 0, window.getGuiScaledWidth(), window.getGuiScaledHeight(), -1072689136, -804253680); - setBlitOffset(0); - choosePageWidget.render(matrices, mouseX, mouseY, delta); - } - } - if (choosePageWidget == null) { - TOOLTIPS.stream().filter(Objects::nonNull) - .reduce((tooltip, tooltip2) -> tooltip2) - .ifPresent(tooltip -> renderTooltip(matrices, tooltip)); - } - TOOLTIPS.clear(); - if (REIRuntime.getInstance().isOverlayVisible()) { - menuHolder.afterRender(); - } - } - - public void renderTooltip(PoseStack matrices, Tooltip tooltip) { - renderTooltipInner(minecraft.screen, matrices, tooltip, tooltip.getX(), tooltip.getY()); - } - - protected abstract void renderTooltipInner(Screen screen, PoseStack matrices, Tooltip tooltip, int mouseX, int mouseY); - - public void addTooltip(@Nullable Tooltip tooltip) { - if (tooltip != null) - TOOLTIPS.add(tooltip); - } - - public void clearTooltips() { - TOOLTIPS.clear(); - } - - public void renderWidgets(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (!REIRuntime.getInstance().isOverlayVisible()) - return; - for (Widget widget : widgets) { - if (!(widget instanceof LateRenderable)) - widget.render(matrices, mouseX, mouseY, delta); - } - } - - @Override - public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - if (!REIRuntime.getInstance().isOverlayVisible()) - return false; - if (menuHolder.mouseScrolled(mouseX, mouseY, amount)) - return true; - if (isInside(mouseX, mouseY) && getEntryListWidget().mouseScrolled(mouseX, mouseY, amount)) { - return true; - } - if (isNotInExclusionZones(PointHelper.getMouseX(), PointHelper.getMouseY())) { - if (favoritesListWidget != null && favoritesListWidget.mouseScrolled(mouseX, mouseY, amount)) - return true; - } - for (Widget widget : widgets) - if (widget != getEntryListWidget() && (favoritesListWidget == null || widget != favoritesListWidget) - && widget != menuHolder.widget() - && widget.mouseScrolled(mouseX, mouseY, amount)) - return true; - return false; - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (!hasSpace()) return false; - if (REIRuntime.getInstance().isOverlayVisible()) { - if (keyCode == 256 && choosePageWidget != null) { - choosePageWidget = null; - return true; - } - if (choosePageWidget != null) - return choosePageWidget.keyPressed(keyCode, scanCode, modifiers); - if (REIRuntimeImpl.getSearchField().keyPressed(keyCode, scanCode, modifiers)) - return true; - for (GuiEventListener listener : widgets) - if (listener != REIRuntimeImpl.getSearchField() && listener.keyPressed(keyCode, scanCode, modifiers)) - return true; - } - if (ConfigObject.getInstance().getHideKeybind().matchesKey(keyCode, scanCode)) { - REIRuntime.getInstance().toggleOverlayVisible(); - return true; - } - EntryStack stack = ScreenRegistry.getInstance().getFocusedStack(Minecraft.getInstance().screen, PointHelper.ofMouse()); - if (stack != null && !stack.isEmpty()) { - stack = stack.copy(); - if (ConfigObject.getInstance().getRecipeKeybind().matchesKey(keyCode, scanCode)) { - return ViewSearchBuilder.builder().addRecipesFor(stack).open(); - } else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(keyCode, scanCode)) { - return ViewSearchBuilder.builder().addUsagesFor(stack).open(); - } else if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) { - FavoriteEntry favoriteEntry = FavoriteEntry.fromEntryStack(stack); - ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry); - return true; - } - } - if (!REIRuntime.getInstance().isOverlayVisible()) - return false; - if (ConfigObject.getInstance().getFocusSearchFieldKeybind().matchesKey(keyCode, scanCode)) { - REIRuntimeImpl.getSearchField().setFocused(true); - setFocused(REIRuntimeImpl.getSearchField()); - REIRuntimeImpl.getSearchField().keybindFocusTime = System.currentTimeMillis(); - REIRuntimeImpl.getSearchField().keybindFocusKey = keyCode; - return true; - } - return false; - } - - @Override - public boolean keyReleased(int keyCode, int scanCode, int modifiers) { - if (!hasSpace()) return false; - if (REIRuntime.getInstance().isOverlayVisible()) { - if (choosePageWidget == null) { - if (REIRuntimeImpl.getSearchField().keyReleased(keyCode, scanCode, modifiers)) - return true; - for (GuiEventListener listener : widgets) - if (listener != REIRuntimeImpl.getSearchField() && listener == getFocused() && listener.keyPressed(keyCode, scanCode, modifiers)) - return true; - } - } - return false; - } - - @Override - public boolean charTyped(char character, int modifiers) { - if (!REIRuntime.getInstance().isOverlayVisible()) - return false; - if (!hasSpace()) return false; - if (choosePageWidget != null) { - return choosePageWidget.charTyped(character, modifiers); - } - if (REIRuntimeImpl.getSearchField().charTyped(character, modifiers)) - return true; - for (GuiEventListener listener : widgets) - if (listener != REIRuntimeImpl.getSearchField() && listener.charTyped(character, modifiers)) - return true; - return false; - } - - @Override - public List children() { - return widgets; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - boolean visible = REIRuntime.getInstance().isOverlayVisible(); - if (choosePageWidget != null) { - if (choosePageWidget.containsMouse(mouseX, mouseY)) { - return choosePageWidget.mouseClicked(mouseX, mouseY, button); - } else { - choosePageWidget = null; - init(); - return false; - } - } - if (!hasSpace()) return false; - if (visible && configButton.mouseClicked(mouseX, mouseY, button)) { - this.setFocused(configButton); - if (button == 0) - this.setDragging(true); - return true; - } - if (ConfigObject.getInstance().getHideKeybind().matchesMouse(button)) { - REIRuntime.getInstance().toggleOverlayVisible(); - return REIRuntime.getInstance().isOverlayVisible(); - } - EntryStack stack = ScreenRegistry.getInstance().getFocusedStack(Minecraft.getInstance().screen, PointHelper.ofMouse()); - if (stack != null && !stack.isEmpty()) { - stack = stack.copy(); - if (ConfigObject.getInstance().getRecipeKeybind().matchesMouse(button)) { - return ViewSearchBuilder.builder().addRecipesFor(stack).open(); - } else if (ConfigObject.getInstance().getUsageKeybind().matchesMouse(button)) { - return ViewSearchBuilder.builder().addUsagesFor(stack).open(); - } else if (visible && ConfigObject.getInstance().getFavoriteKeyCode().matchesMouse(button)) { - FavoriteEntry favoriteEntry = FavoriteEntry.fromEntryStack(stack); - ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry); - return true; - } - } - if (visible) { - Widget menuWidget = menuHolder.widget(); - if (menuWidget != null && menuWidget.mouseClicked(mouseX, mouseY, button)) { - this.setFocused(menuWidget); - if (button == 0) - this.setDragging(true); - REIRuntimeImpl.getSearchField().setFocused(false); - return true; - } - } - if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) { - Screen screen = Minecraft.getInstance().screen; - ClickArea.ClickAreaContext context = createClickAreaContext(mouseX, mouseY, screen); - if (ScreenRegistry.getInstance().executeClickArea((Class) screen.getClass(), context)) { - return true; - } - } - if (!visible) { - return false; - } - for (GuiEventListener element : widgets) { - if (element != configButton && element != menuHolder.widget() && element.mouseClicked(mouseX, mouseY, button)) { - this.setFocused(element); - if (button == 0) - this.setDragging(true); - if (!(element instanceof OverlaySearchField)) - REIRuntimeImpl.getSearchField().setFocused(false); - return true; - } - } - if (ConfigObject.getInstance().getFocusSearchFieldKeybind().matchesMouse(button)) { - REIRuntimeImpl.getSearchField().setFocused(true); - setFocused(REIRuntimeImpl.getSearchField()); - REIRuntimeImpl.getSearchField().keybindFocusTime = -1; - REIRuntimeImpl.getSearchField().keybindFocusKey = -1; - return true; - } - return false; - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - if (!REIRuntime.getInstance().isOverlayVisible()) - return false; - if (!hasSpace()) return false; - if (choosePageWidget != null) { - return choosePageWidget.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); - } - return (this.getFocused() != null && this.isDragging() && button == 0) && this.getFocused().mouseDragged(mouseX, mouseY, button, deltaX, deltaY); - } - - @Override - public GuiEventListener getFocused() { - if (choosePageWidget != null) - return choosePageWidget; - return super.getFocused(); - } - - public boolean isInside(double mouseX, double mouseY) { - return bounds.contains(mouseX, mouseY) && isNotInExclusionZones(mouseX, mouseY); - } - - @Override - public boolean isNotInExclusionZones(double mouseX, double mouseY) { - for (OverlayDecider decider : ScreenRegistry.getInstance().getDeciders(Minecraft.getInstance().screen)) { - InteractionResult in = decider.isInZone(mouseX, mouseY); - if (in != InteractionResult.PASS) - return in == InteractionResult.SUCCESS; - } - return true; - } - - public boolean isInside(Point point) { - return isInside(point.getX(), point.getY()); - } - - @Override - public OverlayListWidget getEntryList() { - return getEntryListWidget(); - } - - @Override - public Optional getFavoritesList() { - return Optional.ofNullable(getFavoritesListWidget()); - } - - public MenuAccess menuAccess() { - return menuHolder; - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/ChangelogLoader.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/ChangelogLoader.java index ae5a41def..b2bd91d0e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/ChangelogLoader.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/ChangelogLoader.java @@ -62,13 +62,14 @@ public static boolean hasVisited() { try (InputStreamReader reader = new FileReader(file)) { String version = IOUtils.toString(reader).trim(); - InputStream changesJsonStream = ChangelogLoader.class.getClassLoader().getResourceAsStream("roughlyenoughitems.changes.json"); - if (changesJsonStream != null) { - JsonObject object = JsonParser.parseReader(new InputStreamReader(changesJsonStream)) - .getAsJsonObject(); - String currentVersion = object.getAsJsonPrimitive("version").getAsString(); - if (currentVersion.equals(version)) { - visited = true; + try (InputStream changesJsonStream = ChangelogLoader.class.getClassLoader().getResourceAsStream("roughlyenoughitems.changes.json")) { + if (changesJsonStream != null) { + JsonObject object = JsonParser.parseReader(new InputStreamReader(changesJsonStream)) + .getAsJsonObject(); + String currentVersion = object.getAsJsonPrimitive("version").getAsString(); + if (currentVersion.equals(version)) { + visited = true; + } } } } catch (IOException e) { @@ -92,47 +93,49 @@ public void add(Function function) { visited = true; BuilderImpl builder = new BuilderImpl(); - InputStream changesJsonStream = ChangelogLoader.class.getClassLoader().getResourceAsStream("roughlyenoughitems.changes.json"); - if (changesJsonStream == null) { - builder.add(new TranslatableComponent("rei.changelog.error.missingChangelogFile")); - } else { - JsonObject object = JsonParser.parseReader(new InputStreamReader(changesJsonStream)) - .getAsJsonObject(); - String version = object.getAsJsonPrimitive("version").getAsString(); - Path file = Platform.getConfigFolder().resolve("roughlyenoughitems/changelog.txt"); - try { - Files.write(file, version.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - } catch (IOException e) { - e.printStackTrace(); - } - - InputStream changelogStream = ChangelogLoader.class.getClassLoader().getResourceAsStream("roughlyenoughitems/" + version + "/changelog.md"); - - if (changelogStream == null) { + try (InputStream changesJsonStream = ChangelogLoader.class.getClassLoader().getResourceAsStream("roughlyenoughitems.changes.json")) { + if (changesJsonStream == null) { builder.add(new TranslatableComponent("rei.changelog.error.missingChangelogFile")); } else { + JsonObject object = JsonParser.parseReader(new InputStreamReader(changesJsonStream)) + .getAsJsonObject(); + String version = object.getAsJsonPrimitive("version").getAsString(); + Path file = Platform.getConfigFolder().resolve("roughlyenoughitems/changelog.txt"); try { - JParseDown parseDown = new JParseDown(); - LinkedList blocks = parseDown.linesElements(IOUtils.readLines(changelogStream, StandardCharsets.UTF_8).toArray(new String[0])); - for (JParseDown.Block block : blocks) { - if (block.autoBreak) { - builder.add(width -> new ErrorsEntryListWidget.EmptyEntry(6)); - } - Builder blockBuilder = builder; - if (block instanceof JParseDown.BlockHeader) { - blockBuilder = function -> { - builder.add(width -> new ErrorsEntryListWidget.ScaledEntry(function.apply(Math.round(width / 1.5F)), 1.5F)); - }; - } - JParseDownToMinecraft.build(blockBuilder, block); - if (block.autoBreak) { - builder.add(width -> new ErrorsEntryListWidget.EmptyEntry(6)); + Files.writeString(file, version, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + } + + try (InputStream changelogStream = ChangelogLoader.class.getClassLoader().getResourceAsStream("roughlyenoughitems/" + version + "/changelog.md")) { + if (changelogStream == null) { + builder.add(new TranslatableComponent("rei.changelog.error.missingChangelogFile")); + } else { + try { + JParseDown parseDown = new JParseDown(); + LinkedList blocks = parseDown.linesElements(IOUtils.readLines(changelogStream, StandardCharsets.UTF_8).toArray(new String[0])); + for (JParseDown.Block block : blocks) { + if (block.autoBreak) { + builder.add(width -> new ErrorsEntryListWidget.EmptyEntry(6)); + } + Builder blockBuilder = builder; + if (block instanceof JParseDown.BlockHeader) { + blockBuilder = function -> { + builder.add(width -> new ErrorsEntryListWidget.ScaledEntry(function.apply(Math.round(width / 1.5F)), 1.5F)); + }; + } + JParseDownToMinecraft.build(blockBuilder, block); + if (block.autoBreak) { + builder.add(width -> new ErrorsEntryListWidget.EmptyEntry(6)); + } + } + } catch (IOException e) { + builder.add(new TranslatableComponent("rei.changelog.error.failedToReadChangelogFile")); } } - } catch (IOException e) { - builder.add(new TranslatableComponent("rei.changelog.error.failedToReadChangelogFile")); } } + } catch (IOException e) { } Minecraft.getInstance().setScreen(new ErrorsScreen(new TranslatableComponent("text.rei.changelog.title"), builder.components, Minecraft.getInstance().screen, true)); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/JParseDown.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/JParseDown.java index 6165f6a7a..01c306726 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/JParseDown.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/JParseDown.java @@ -64,10 +64,13 @@ public Line(String line) { } } - public abstract static class Component { + public static class Component { public String markup = null; public boolean hidden = false; public HashSet> nonNestables = new HashSet<>(); + + protected Component() { + } } public interface BlockType { @@ -366,11 +369,11 @@ public class BlockList extends Block { public String markerTypeRegex; public LinkedList lines = new LinkedList<>(); - + public BlockList() { autoBreak = true; } - + public static Block startBlock(JParseDown parseDown, Line line, Block block) { boolean ordered; String pattern; @@ -404,9 +407,9 @@ public static Block startBlock(JParseDown parseDown, Line line, Block block) { b.pattern = pattern; b.ordered = ordered; b.marker = marker; - b.markerType = !ordered ? - markerWithoutWhitespace : - markerWithoutWhitespace.substring(markerWithoutWhitespace.length() - 1, markerWithoutWhitespace.length()); + b.markerType = ordered ? + markerWithoutWhitespace.substring(markerWithoutWhitespace.length() - 1) : + markerWithoutWhitespace; b.markerTypeRegex = Pattern.quote(b.markerType); b.lines.add(body); @@ -476,9 +479,8 @@ public boolean isCompletable() { @Override public Block completeBlock() { - if (loose) { - if (!lines.getLast().isEmpty()) - lines.add(""); + if (loose && !lines.getLast().isEmpty()) { + lines.add(""); } return this; } @@ -573,7 +575,7 @@ public static class BlockHorizontalRule extends Block { public BlockHorizontalRule() { autoBreak = true; } - + @Override public Collection inline(JParseDown parseDown) { return Collections.singletonList(new InlineHorizontalRule()); @@ -613,7 +615,7 @@ public BlockReference(String id, ReferenceData data) { public static Block startBlock(JParseDown parseDown, Line line, Block block) { Matcher m; if (line.text.indexOf(']') >= 0 && (m = Pattern.compile("^\\[(.+?)\\]:[ ]*+?(?:[ ]+[\"\\'(](.+)[\"\\')])?[ ]*+$").matcher(line.text)).find()) { - String id = m.group(1).toLowerCase(); + String id = m.group(1).toLowerCase(Locale.ROOT); ReferenceData data = new ReferenceData(parseDown.convertUrl(m.group(2)), m.group(3)); parseDown.referenceDefinitions.put(id, data); return new BlockReference(id, data); @@ -634,11 +636,11 @@ public String toString() { } } - public abstract static class Inline extends Component { + public static class Inline extends Component { public int extent; public int position = -1; - public Inline() { + protected Inline() { } public Inline setExtent(String s) { @@ -834,7 +836,7 @@ public static Inline inline(JParseDown parseDown, String text, String context) { InlineLink link = (InlineLink) InlineLink.inline(parseDown, text, context); if (link == null) return null; - + return new InlineImage(link.url, link.text).setExtent(link.extent + 1); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/JParseDownToMinecraft.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/JParseDownToMinecraft.java index 9145a6298..0b0afaa00 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/JParseDownToMinecraft.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/changelog/JParseDownToMinecraft.java @@ -73,15 +73,17 @@ public static void build(ChangelogLoader.Builder builder, JParseDown.Block block } else if (inline instanceof JParseDown.InlineHorizontalRule) { builder.add(ErrorsEntryListWidget.HorizontalRuleEntry::new); } else if (inline instanceof JParseDown.InlineImage) { - InputStream stream = builder.getClass().getClassLoader().getResourceAsStream(((JParseDown.InlineImage) inline).src); - if (stream != null) { - try { - DynamicTexture texture = new DynamicTexture(NativeImage.read(stream)); - ResourceLocation id = Minecraft.getInstance().getTextureManager().register("rei_md_image_", texture); - builder.add(width -> new ErrorsEntryListWidget.ImageEntry(width, texture, id)); - } catch (IOException e) { - e.printStackTrace(); + try (InputStream stream = builder.getClass().getClassLoader().getResourceAsStream(((JParseDown.InlineImage) inline).src)) { + if (stream != null) { + try { + DynamicTexture texture = new DynamicTexture(NativeImage.read(stream)); + ResourceLocation id = Minecraft.getInstance().getTextureManager().register("rei_md_image_", texture); + builder.add(width -> new ErrorsEntryListWidget.ImageEntry(width, texture, id)); + } catch (IOException e) { + e.printStackTrace(); + } } + } catch (IOException e) { } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java deleted file mode 100644 index 1996dc5ef..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.craftable; - -import it.unimi.dsi.fastutil.longs.Long2LongMap; -import it.unimi.dsi.fastutil.longs.Long2LongMaps; -import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; -import me.shedaniel.rei.impl.client.ClientHelperImpl; - -public class CraftableFilter { - public static final CraftableFilter INSTANCE = new CraftableFilter(); - private boolean dirty = false; - private Long2LongMap invStacks = new Long2LongOpenHashMap(); - private Long2LongMap containerStacks = new Long2LongOpenHashMap(); - - public void markDirty() { - dirty = true; - } - - public boolean wasDirty() { - if (dirty) { - dirty = false; - return true; - } - - return false; - } - - public void tick() { - if (dirty) return; - Long2LongMap currentStacks; - try { - currentStacks = ClientHelperImpl.getInstance()._getInventoryItemsTypes(); - } catch (Throwable throwable) { - throwable.printStackTrace(); - currentStacks = Long2LongMaps.EMPTY_MAP; - } - if (!currentStacks.equals(this.invStacks)) { - invStacks = currentStacks; - markDirty(); - } - if (dirty) return; - - try { - currentStacks = ClientHelperImpl.getInstance()._getContainerItemsTypes(); - } catch (Throwable throwable) { - throwable.printStackTrace(); - currentStacks = Long2LongMaps.EMPTY_MAP; - } - if (!currentStacks.equals(this.containerStacks)) { - containerStacks = currentStacks; - markDirty(); - } - } - - public Long2LongMap getInvStacks() { - return invStacks; - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsScreen.java index ab0006ea0..ce6abd0eb 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsScreen.java @@ -27,7 +27,6 @@ import me.shedaniel.rei.impl.client.gui.error.ErrorsEntryListWidget.TextEntry; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.chat.NarratorChatListener; -import net.minecraft.client.gui.components.AbstractButton; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.GenericDirtMessageScreen; import net.minecraft.client.gui.screens.Screen; @@ -40,11 +39,10 @@ @ApiStatus.Internal public class ErrorsScreen extends Screen { - private List components; - private AbstractButton doneButton; + private final List components; + private final Screen parent; + private final boolean quitable; private ErrorsEntryListWidget listWidget; - private Screen parent; - private boolean quitable; public ErrorsScreen(Component title, List components, Screen parent, boolean quitable) { super(title); @@ -81,9 +79,9 @@ public void init() { } listWidget._addEntry(new TextEntry(NarratorChatListener.NO_TITLE, listWidget.getItemWidth())); if (quitable) { - addRenderableWidget(doneButton = new Button(width / 2 - 100, height - 26, 200, 20, new TranslatableComponent("gui.done"), button -> Minecraft.getInstance().setScreen(parent))); + addRenderableWidget(new Button(width / 2 - 100, height - 26, 200, 20, new TranslatableComponent("gui.done"), button -> Minecraft.getInstance().setScreen(parent))); } else { - addRenderableWidget(doneButton = new Button(width / 2 - 100, height - 26, 200, 20, new TranslatableComponent("menu.quit"), button -> exit())); + addRenderableWidget(new Button(width / 2 - 100, height - 26, 200, 20, new TranslatableComponent("menu.quit"), button -> exit())); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java index 88f339f3c..e01b50d8c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/AbstractDisplayViewingScreen.java @@ -48,9 +48,7 @@ import me.shedaniel.rei.api.common.entry.type.EntryType; import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; -import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; -import me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget; +import me.shedaniel.rei.impl.client.gui.DisplayScreenStack; import me.shedaniel.rei.impl.display.DisplaySpec; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; @@ -66,6 +64,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.util.Mth; import net.minecraft.world.inventory.tooltip.TooltipComponent; @@ -76,6 +75,8 @@ import java.util.function.UnaryOperator; import java.util.stream.Stream; +import static me.shedaniel.rei.impl.client.util.InternalEntryBounds.entrySize; + public abstract class AbstractDisplayViewingScreen extends Screen implements DisplayScreen { protected final Map, List> categoryMap; protected final List> categories; @@ -192,13 +193,13 @@ protected void transformResultNotice(List setupDisplay, List setupDisplay, List> noticeStacks) { if (noticeStacks.isEmpty()) return; - for (EntryWidget widget : Widgets.walk(setupDisplay, EntryWidget.class::isInstance)) { - if (widget.getNoticeMark() == marker && widget.getEntries().size() > 1) { + for (Slot slot : Widgets.walk(setupDisplay, Slot.class::isInstance)) { + if (slot.getNoticeMark() == marker && slot.getEntries().size() > 1) { for (EntryStack noticeStack : noticeStacks) { - EntryStack stack = CollectionUtils.findFirstOrNullEqualsExact(widget.getEntries(), noticeStack); + EntryStack stack = CollectionUtils.findFirstOrNullEqualsExact(slot.getEntries(), noticeStack); if (stack != null) { - widget.clearStacks(); - widget.entry(stack); + slot.clearEntries(); + slot.entry(stack); break; } } @@ -207,12 +208,12 @@ private static void transformNotice(int marker, List } protected void transformFiltering(List setupDisplay) { - for (EntryWidget widget : Widgets.walk(setupDisplay, EntryWidget.class::isInstance)) { - if (widget.getEntries().size() > 1) { - Collection> refiltered = EntryRegistry.getInstance().refilterNew(false, widget.getEntries()); + for (Slot slot : Widgets.walk(setupDisplay, Slot.class::isInstance)) { + if (slot.getEntries().size() > 1) { + Collection> refiltered = EntryRegistry.getInstance().refilterNew(false, slot.getEntries()); if (!refiltered.isEmpty()) { - widget.clearStacks(); - widget.entries(refiltered); + slot.clearEntries(); + slot.entries(refiltered); } } } @@ -220,11 +221,14 @@ protected void transformFiltering(List setupDisplay) protected void setupTags(List widgets) { outer: - for (EntryWidget widget : Widgets.walk(widgets, EntryWidget.class::isInstance)) { - if (widget.getNoticeMark() != EntryWidget.INPUT) continue; - addCyclingTooltip(widget); - widget.removeTagMatch = false; - if (widget.getEntries().size() <= 1) continue; + for (Slot widget : Widgets.walk(widgets, Slot.class::isInstance)) { + if (widget.getNoticeMark() != Slot.INPUT) continue; + + if (widget.getEntries().size() <= 1) { + addCyclingTooltip(widget, null); + continue; + } + EntryType type = null; for (EntryStack entry : widget.getEntries()) { if (type == null) { @@ -249,14 +253,16 @@ protected void setupTags(List widgets) { TagKey firstOrNull = CollectionUtils.findFirstOrNull(collection::iterator, key -> CollectionUtils.allMatch(objects, holder -> ((Holder) holder).is((TagKey) key))); if (firstOrNull != null) { - widget.tagMatch = firstOrNull.location(); + addCyclingTooltip(widget, firstOrNull.location()); + } else { + addCyclingTooltip(widget, null); } } } private static final int MAX_WIDTH = 200; - private void addCyclingTooltip(EntryWidget widget) { + private void addCyclingTooltip(Slot widget, @Nullable ResourceLocation tagMatch) { class TooltipProcessor implements UnaryOperator, TooltipComponent, ClientTooltipComponent { @Override public Tooltip apply(Tooltip tooltip) { @@ -284,28 +290,28 @@ public boolean equals(Object obj) { @Override public int getHeight() { - int entrySize = EntryListWidget.entrySize(); + int entrySize = entrySize(); int w = Math.max(1, MAX_WIDTH / entrySize); int height = Math.min(6, Mth.ceil(widget.getEntries().size() / (float) w)) * entrySize + 2; height += 12; - if (widget.tagMatch != null) height += 12; + if (tagMatch != null) height += 12; return height; } @Override public int getWidth(Font font) { - int entrySize = EntryListWidget.entrySize(); + int entrySize = entrySize(); int w = Math.max(1, MAX_WIDTH / entrySize); int size = widget.getEntries().size(); int width = Math.min(size, w) * entrySize; width = Math.max(width, font.width(new TranslatableComponent("text.rei.accepts"))); - if (widget.tagMatch != null) width = Math.max(width, font.width(new TranslatableComponent("text.rei.tag_accept", widget.tagMatch.toString()))); + if (tagMatch != null) width = Math.max(width, font.width(new TranslatableComponent("text.rei.tag_accept", tagMatch.toString()))); return width; } @Override public void renderImage(Font font, int x, int y, PoseStack poses, ItemRenderer renderer, int z) { - int entrySize = EntryListWidget.entrySize(); + int entrySize = entrySize(); int w = Math.max(1, MAX_WIDTH / entrySize); int i = 0; poses.pushPose(); @@ -332,10 +338,10 @@ public void renderText(Font font, int x, int y, Matrix4f pose, MultiBufferSource font.drawInBatch(new TranslatableComponent("text.rei.accepts").withStyle(ChatFormatting.GRAY), x, y + 2, -1, true, pose, buffers, false, 0, 15728880); - if (widget.tagMatch != null) { - int entrySize = EntryListWidget.entrySize(); + if (tagMatch != null) { + int entrySize = entrySize(); int w = Math.max(1, MAX_WIDTH / entrySize); - font.drawInBatch(new TranslatableComponent("text.rei.tag_accept", widget.tagMatch.toString()) + font.drawInBatch(new TranslatableComponent("text.rei.tag_accept", tagMatch.toString()) .withStyle(ChatFormatting.GRAY), x, y + 16 + Math.min(6, Mth.ceil(widget.getEntries().size() / (float) w)) * entrySize, -1, true, pose, buffers, false, 0, 15728880); @@ -347,7 +353,7 @@ public void renderText(Font font, int x, int y, Matrix4f pose, MultiBufferSource } protected static ScreenOverlay getOverlay() { - return REIRuntime.getInstance().getOverlay().orElseThrow(() -> new IllegalStateException("Overlay not initialized!")); + return REIRuntime.getInstance().getOverlay().orElseThrow(); } private boolean handleFocuses(int button) { @@ -391,8 +397,8 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (super.keyPressed(keyCode, scanCode, modifiers) || (getOverlay().keyPressed(keyCode, scanCode, modifiers) && handleFocuses())) return true; if (ConfigObject.getInstance().getPreviousScreenKeybind().matchesKey(keyCode, scanCode)) { - if (REIRuntimeImpl.getInstance().hasLastDisplayScreen()) { - minecraft.setScreen(REIRuntimeImpl.getInstance().getLastDisplayScreen()); + if (DisplayScreenStack.hasLastDisplayScreen()) { + minecraft.setScreen(DisplayScreenStack.getLastDisplayScreen()); } else { minecraft.setScreen(REIRuntime.getInstance().getPreviousScreen()); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java index 9da61f102..159940ee9 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java @@ -44,10 +44,9 @@ import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; +import me.shedaniel.rei.impl.client.gui.DisplayScreenStack; import me.shedaniel.rei.impl.client.gui.InternalTextures; -import me.shedaniel.rei.impl.client.gui.widget.EntryWidget; -import me.shedaniel.rei.impl.client.gui.widget.InternalWidgets; +import me.shedaniel.rei.impl.client.gui.widget.AutoCraftingButtonWidget; import me.shedaniel.rei.impl.client.gui.widget.TabWidget; import me.shedaniel.rei.impl.display.DisplaySpec; import net.minecraft.client.Minecraft; @@ -139,7 +138,9 @@ public void init() { widgets.add(Widgets.createSlotBase(new Rectangle(xx - 1, yy - 1, 2 + w * 16, 2 + h * 16))); int index = 0; for (EntryIngredient workingStation : workstations) { - widgets.add(new DefaultDisplayViewingScreen.WorkstationSlotWidget(xx, yy, workingStation)); + widgets.add(Widgets.createSlot(new Point(xx, yy)) + .entries(workingStation) + .noBackground()); index++; xx += 16; if (index >= ww) { @@ -169,13 +170,10 @@ public void init() { transformFiltering(setupDisplay); transformIngredientNotice(setupDisplay, ingredientStackToNotice); transformResultNotice(setupDisplay, resultStackToNotice); - for (EntryWidget widget : Widgets.walk(widgets, EntryWidget.class::isInstance)) { - widget.removeTagMatch = true; - } this.widgets.addAll(setupDisplay); Optional supplier = CategoryRegistry.getInstance().get(category.getCategoryIdentifier()).getPlusButtonArea(); if (supplier.isPresent() && supplier.get().get(recipeBounds) != null) - this.widgets.add(InternalWidgets.createAutoCraftingButtonWidget(recipeBounds, supplier.get().get(recipeBounds), new TextComponent(supplier.get().getButtonText()), display::provideInternalDisplay, display::provideInternalDisplayIds, setupDisplay, category)); + this.widgets.add(AutoCraftingButtonWidget.create(recipeBounds, supplier.get().get(recipeBounds), new TextComponent(supplier.get().getButtonText()), display::provideInternalDisplay, display::provideInternalDisplayIds, setupDisplay, category)); int index = 0; for (DisplaySpec recipeDisplay : categoryMap.get(category)) { @@ -275,8 +273,8 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { init(); return true; } else if (ConfigObject.getInstance().getPreviousScreenKeybind().matchesMouse(button)) { - if (REIRuntimeImpl.getInstance().hasLastDisplayScreen()) { - minecraft.setScreen(REIRuntimeImpl.getInstance().getLastDisplayScreen()); + if (DisplayScreenStack.hasLastDisplayScreen()) { + minecraft.setScreen(DisplayScreenStack.getLastDisplayScreen()); } else { minecraft.setScreen(REIRuntime.getInstance().getPreviousScreen()); } @@ -311,14 +309,11 @@ public boolean mouseScrolled(double mouseX, double mouseY, double amount) { scrollBarAlphaFutureTime = System.currentTimeMillis(); return true; } - REIRuntimeImpl.isWithinRecipeViewingScreen = true; for (GuiEventListener listener : children()) { if (listener.mouseScrolled(mouseX, mouseY, amount)) { - REIRuntimeImpl.isWithinRecipeViewingScreen = false; return true; } } - REIRuntimeImpl.isWithinRecipeViewingScreen = false; int tabSize = ConfigObject.getInstance().isUsingCompactTabs() ? 24 : 28; if (mouseX >= bounds.x && mouseX <= bounds.getMaxX() && mouseY >= bounds.y - tabSize && mouseY < bounds.y) { if (amount < 0) selectedCategoryIndex++; @@ -395,7 +390,7 @@ else if (scrollBarAlphaFuture == 1) Optional.ofNullable(displayRenderers.get(i).getTooltip(TooltipContext.of(new Point(mouseX, mouseY)))).ifPresent(Tooltip::queue); } } - scrolling.renderScrollBar(0, scrollBarAlpha, REIRuntime.getInstance().isDarkThemeEnabled() ? 0.8f : 1f); + scrolling.renderScrollBar(0, scrollBarAlpha, ConfigObject.getInstance().isUsingDarkTheme() ? 0.8f : 1f); ScissorsHandler.INSTANCE.removeLastScissor(); matrices.popPose(); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java index 64ec3f39b..f151f6e3f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java @@ -52,20 +52,18 @@ import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; +import me.shedaniel.rei.impl.client.gui.DisplayScreenStack; import me.shedaniel.rei.impl.client.gui.InternalTextures; import me.shedaniel.rei.impl.client.gui.RecipeDisplayExporter; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; import me.shedaniel.rei.impl.client.gui.toast.ExportRecipeIdentifierToast; -import me.shedaniel.rei.impl.client.gui.widget.*; -import me.shedaniel.rei.impl.client.gui.widget.basewidgets.PanelWidget; +import me.shedaniel.rei.impl.client.gui.widget.AutoCraftingButtonWidget; +import me.shedaniel.rei.impl.client.gui.widget.DisplayCompositeWidget; +import me.shedaniel.rei.impl.client.gui.widget.TabWidget; import me.shedaniel.rei.impl.display.DisplaySpec; -import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.chat.NarratorChatListener; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.ConfirmScreen; -import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.resources.language.I18n; import net.minecraft.client.resources.sounds.SimpleSoundInstance; @@ -224,19 +222,12 @@ public void init() { DefaultDisplayViewingScreen.this.init(); }).tooltipLine(new TranslatableComponent("text.rei.previous_page"))); this.widgets.add(Widgets.createClickableLabel(new Point(bounds.getCenterX(), bounds.getY() + 21), NarratorChatListener.NO_TITLE, label -> { - if (!Screen.hasShiftDown()) { - page = 0; - DefaultDisplayViewingScreen.this.init(); - } else { - ScreenOverlayImpl.getInstance().choosePageWidget = new DefaultDisplayChoosePageWidget(page -> { - DefaultDisplayViewingScreen.this.page = page; - DefaultDisplayViewingScreen.this.init(); - }, page, getCurrentTotalPages()); - } + page = 0; + DefaultDisplayViewingScreen.this.init(); }).onRender((matrices, label) -> { label.setMessage(new ImmutableTextComponent(String.format("%d/%d", page + 1, getCurrentTotalPages()))); label.setClickable(getCurrentTotalPages() > 1); - }).tooltipFunction(label -> label.isClickable() ? new Component[]{new TranslatableComponent("text.rei.go_back_first_page"), new TextComponent(" "), new TranslatableComponent("text.rei.shift_click_to", new TranslatableComponent("text.rei.choose_page")).withStyle(ChatFormatting.GRAY)} : null)); + }).tooltipFunction(label -> label.isClickable() ? new Component[]{new TranslatableComponent("text.rei.go_back_first_page")} : null)); this.widgets.add(recipeNext = Widgets.createButton(new Rectangle(bounds.getMaxX() - 17, bounds.getY() + 19, 12, 12), ImmutableTextComponent.EMPTY) .onClick(button -> { page++; @@ -262,7 +253,7 @@ public void init() { } initDisplays(); widgets = CollectionUtils.map(widgets, widget -> Widgets.withTranslate(widget, 0, 0, 10)); - widgets.add(Widgets.withTranslate(new PanelWidget(bounds), 0, 0, 5)); + widgets.add(Widgets.withTranslate(Widgets.createCategoryBase(bounds), 0, 0, 5)); widgets.add(Widgets.withTranslate(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { fill(matrices, bounds.x + 17, bounds.y + 5, bounds.x + bounds.width - 17, bounds.y + 17, darkStripesColor.value().getColor()); fill(matrices, bounds.x + 17, bounds.y + 19, bounds.x + bounds.width - 17, bounds.y + 31, darkStripesColor.value().getColor()); @@ -295,13 +286,10 @@ private void initDisplays() { transformFiltering(setupDisplay); transformIngredientNotice(setupDisplay, ingredientStackToNotice); transformResultNotice(setupDisplay, resultStackToNotice); - for (EntryWidget widget : Widgets.walk(widgets, EntryWidget.class::isInstance)) { - widget.removeTagMatch = true; - } this.recipeBounds.put(displayBounds, Pair.of(display, setupDisplay)); this.widgets.add(new DisplayCompositeWidget(display, setupDisplay, displayBounds)); if (plusButtonArea.isPresent()) { - this.widgets.add(InternalWidgets.createAutoCraftingButtonWidget(displayBounds, plusButtonArea.get().get(displayBounds), new TextComponent(plusButtonArea.get().getButtonText()), displaySupplier, display::provideInternalDisplayIds, setupDisplay, getCurrentCategory())); + this.widgets.add(AutoCraftingButtonWidget.create(displayBounds, plusButtonArea.get().get(displayBounds), new TextComponent(plusButtonArea.get().getButtonText()), displaySupplier, display::provideInternalDisplayIds, setupDisplay, getCurrentCategory())); } } } @@ -320,7 +308,9 @@ private void initWorkstations(List widgets) { int index = 0; xx += (innerWidth - 1) * 16; for (EntryIngredient workingStation : workstations) { - widgets.add(new WorkstationSlotWidget(xx, yy, workingStation)); + widgets.add(Widgets.createSlot(new Point(xx, yy)) + .entries(workingStation) + .noBackground()); index++; yy += 16; if (index >= hh) { @@ -369,7 +359,7 @@ private static int getRecipesPerPage(int totalHeight, DisplayCategory categor } private final ValueAnimator darkStripesColor = ValueAnimator.ofColor() - .withConvention(() -> Color.ofTransparent(REIRuntime.getInstance().isDarkThemeEnabled() ? 0xFF404040 : 0xFF9E9E9E), ValueAnimator.typicalTransitionTime()); + .withConvention(() -> Color.ofTransparent(ConfigObject.getInstance().isUsingDarkTheme() ? 0xFF404040 : 0xFF9E9E9E), ValueAnimator.typicalTransitionTime()); @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { @@ -486,9 +476,6 @@ private boolean checkExportDisplays() { transformFiltering(setupDisplay); transformIngredientNotice(setupDisplay, ingredientStackToNotice); transformResultNotice(setupDisplay, resultStackToNotice); - for (EntryWidget widget : Widgets.walk(widgets(), EntryWidget.class::isInstance)) { - widget.removeTagMatch = true; - } RecipeDisplayExporter.exportRecipeDisplay(displayBounds, spec, setupDisplay, false); } @@ -504,14 +491,11 @@ private boolean checkExportDisplays() { @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { - REIRuntimeImpl.isWithinRecipeViewingScreen = true; for (GuiEventListener listener : children()) { if (listener.mouseScrolled(mouseX, mouseY, amount)) { - REIRuntimeImpl.isWithinRecipeViewingScreen = false; return true; } } - REIRuntimeImpl.isWithinRecipeViewingScreen = false; if (getBounds().contains(PointHelper.ofMouse())) { if (amount > 0 && recipeBack.isEnabled()) recipeBack.onClick(); @@ -538,26 +522,14 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { recipeBack.onClick(); return recipeBack.isEnabled(); } else if (ConfigObject.getInstance().getPreviousScreenKeybind().matchesMouse(button)) { - if (REIRuntimeImpl.getInstance().hasLastDisplayScreen()) { - minecraft.setScreen(REIRuntimeImpl.getInstance().getLastDisplayScreen()); + if (DisplayScreenStack.hasLastDisplayScreen()) { + minecraft.setScreen(DisplayScreenStack.getLastDisplayScreen()); } else { minecraft.setScreen(REIRuntime.getInstance().getPreviousScreen()); } return true; } - return super.mouseClicked(mouseX, mouseY, button); - } - - public static class WorkstationSlotWidget extends EntryWidget { - public WorkstationSlotWidget(int x, int y, EntryIngredient widgets) { - super(new Point(x, y)); - entries(widgets); - noBackground(); - } - @Override - public boolean containsMouse(double mouseX, double mouseY) { - return getInnerBounds().contains(mouseX, mouseY); - } + return super.mouseClicked(mouseX, mouseY, button); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DynamicErrorFreeEntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/error/DynamicErrorFreeEntryListWidget.java similarity index 99% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DynamicErrorFreeEntryListWidget.java rename to runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/error/DynamicErrorFreeEntryListWidget.java index 528341ab7..fce32a8b8 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DynamicErrorFreeEntryListWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/error/DynamicErrorFreeEntryListWidget.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.widget; +package me.shedaniel.rei.impl.client.gui.screen.error; import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/WarningAndErrorScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/error/WarningAndErrorScreen.java similarity index 99% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/WarningAndErrorScreen.java rename to runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/error/WarningAndErrorScreen.java index 021ffa14e..737abec2a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/WarningAndErrorScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/error/WarningAndErrorScreen.java @@ -21,12 +21,11 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.screen; +package me.shedaniel.rei.impl.client.gui.screen.error; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.rei.RoughlyEnoughItemsState; -import me.shedaniel.rei.impl.client.gui.widget.DynamicErrorFreeEntryListWidget; import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.client.Minecraft; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/toast/CopyRecipeIdentifierToast.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/toast/CopyRecipeIdentifierToast.java index 1c4ab36cc..8a7ab2163 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/toast/CopyRecipeIdentifierToast.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/toast/CopyRecipeIdentifierToast.java @@ -25,17 +25,15 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.rei.impl.client.gui.InternalTextures; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.toasts.Toast; import net.minecraft.client.gui.components.toasts.ToastComponent; -import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @ApiStatus.Internal public class CopyRecipeIdentifierToast implements Toast { - - protected static final ResourceLocation TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/toasts.png"); private String title; private String subtitle; private long startTime; @@ -51,7 +49,7 @@ public static void addToast(String title, @Nullable String subtitleNullable) { @Override public Visibility render(PoseStack matrices, ToastComponent toastManager, long var2) { - RenderSystem.setShaderTexture(0, TEXTURE); + RenderSystem.setShaderTexture(0, InternalTextures.TOASTS); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); toastManager.blit(matrices, 0, 0, 0, 0, 160, 32); if (this.subtitle == null) { @@ -72,5 +70,4 @@ public Object getToken() { public enum Type { THIS_IS_SURE_A_TYPE } - } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/toast/ExportRecipeIdentifierToast.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/toast/ExportRecipeIdentifierToast.java index cd763c1f3..ac622e849 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/toast/ExportRecipeIdentifierToast.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/toast/ExportRecipeIdentifierToast.java @@ -25,19 +25,17 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.rei.impl.client.gui.InternalTextures; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.toasts.Toast; import net.minecraft.client.gui.components.toasts.ToastComponent; -import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @ApiStatus.Internal public class ExportRecipeIdentifierToast implements Toast { - - protected static final ResourceLocation TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/toasts.png"); - private String title; - private String subtitle; + private final String title; + private final String subtitle; private long startTime; public ExportRecipeIdentifierToast(String title, @Nullable String subtitleNullable) { @@ -51,7 +49,7 @@ public static void addToast(String title, @Nullable String subtitleNullable) { @Override public Visibility render(PoseStack matrices, ToastComponent toastManager, long var2) { - RenderSystem.setShaderTexture(0, TEXTURE); + RenderSystem.setShaderTexture(0, InternalTextures.TOASTS); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); toastManager.blit(matrices, 0, 0, 0, 0, 160, 32); if (this.subtitle == null) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingButtonWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingButtonWidget.java new file mode 100644 index 000000000..cad46cbef --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingButtonWidget.java @@ -0,0 +1,146 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget; + +import com.google.common.base.Suppliers; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.math.impl.PointHelper; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.widgets.*; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.registry.display.DisplayCategory; +import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.client.gui.toast.CopyRecipeIdentifierToast; +import me.shedaniel.rei.impl.client.provider.AutoCraftingEvaluator; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public class AutoCraftingButtonWidget { + public static Widget create(Rectangle displayBounds, Rectangle rectangle, Component text, + Supplier displaySupplier, Supplier> idsSupplier, List setupDisplay, DisplayCategory category) { + Button autoCraftingButton = Widgets.createButton(rectangle, text) + .focusable(false) + .onClick(button -> { + ClientInternals.getAutoCraftingEvaluator(displaySupplier.get()) + .actuallyCraft() + .stacked(Screen.hasShiftDown()) + .get(); + }); + return new DelegateWidget(autoCraftingButton) { + final Supplier[] result = Stream.of(true, false).map( + bool -> Suppliers.memoizeWithExpiration( + () -> ClientInternals.getAutoCraftingEvaluator(displaySupplier.get()) + .buildRenderer() + .buildTooltipRenderer(bool) + .ids(idsSupplier == null ? null : idsSupplier.get()) + .get(), + 1000, TimeUnit.MILLISECONDS + ) + ).toArray(Supplier[]::new); + + @Override + public void render(PoseStack poses, int mouseX, int mouseY, float delta) { + AutoCraftingEvaluator.Result result = this.result[(autoCraftingButton.isFocused() || containsMouse(mouseX, mouseY)) ? 1 : 0].get(); + + autoCraftingButton.setEnabled(result.isSuccessful()); + autoCraftingButton.setTint(result.getTint()); + + if (result.isApplicable()) { + autoCraftingButton.setText(text); + } else { + autoCraftingButton.setText(new TextComponent("!")); + } + + if (result.isApplicable() && (containsMouse(mouseX, mouseY) || autoCraftingButton.isFocused()) && result.getRenderer() != null) { + result.getRenderer().render(poses, mouseX, mouseY, delta, setupDisplay, displayBounds, displaySupplier.get()); + } + + this.widget.render(poses, mouseX, mouseY, delta); + + if (!autoCraftingButton.isFocused() && containsMouse(mouseX, mouseY)) { + tryTooltip(result, new Point(mouseX, mouseY)); + } else if (autoCraftingButton.isFocused()) { + Rectangle bounds = autoCraftingButton.getBounds(); + tryTooltip(result, new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2)); + } + } + + private void tryTooltip(AutoCraftingEvaluator.Result result, Point point) { + if (result.getTooltipRenderer() != null) { + result.getTooltipRenderer().accept(point, Tooltip::queue); + } + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (displaySupplier.get().getDisplayLocation().isPresent() && ConfigObject.getInstance().getCopyRecipeIdentifierKeybind().matchesKey(keyCode, scanCode) && containsMouse(PointHelper.ofMouse())) { + minecraft.keyboardHandler.setClipboard(displaySupplier.get().getDisplayLocation().get().toString()); + if (ConfigObject.getInstance().isToastDisplayedOnCopyIdentifier()) { + CopyRecipeIdentifierToast.addToast(I18n.get("msg.rei.copied_recipe_id"), I18n.get("msg.rei.recipe_id_details", displaySupplier.get().getDisplayLocation().get().toString())); + } + return true; + } else if (ConfigObject.getInstance().isFavoritesEnabled() && containsMouse(PointHelper.ofMouse())) { + if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) { + if (ScreenOverlay.getInstance().get().submitDisplayHistory(displaySupplier.get(), displayBounds.clone())) { + return true; + } + } + } + + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (displaySupplier.get().getDisplayLocation().isPresent() && ConfigObject.getInstance().getCopyRecipeIdentifierKeybind().matchesMouse(button) && containsMouse(PointHelper.ofMouse())) { + minecraft.keyboardHandler.setClipboard(displaySupplier.get().getDisplayLocation().get().toString()); + if (ConfigObject.getInstance().isToastDisplayedOnCopyIdentifier()) { + CopyRecipeIdentifierToast.addToast(I18n.get("msg.rei.copied_recipe_id"), I18n.get("msg.rei.recipe_id_details", displaySupplier.get().getDisplayLocation().get().toString())); + } + return true; + } else if (ConfigObject.getInstance().isFavoritesEnabled() && containsMouse(PointHelper.ofMouse())) { + if (ConfigObject.getInstance().getFavoriteKeyCode().matchesMouse(button)) { + if (ScreenOverlay.getInstance().get().submitDisplayHistory(displaySupplier.get(), displayBounds.clone())) { + return true; + } + } + } + + return super.mouseClicked(mouseX, mouseY, button); + } + }; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CatchingExceptionUtils.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CatchingExceptionUtils.java index b27b33e8e..eadf274ef 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CatchingExceptionUtils.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CatchingExceptionUtils.java @@ -24,10 +24,12 @@ package me.shedaniel.rei.impl.client.gui.widget; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; +import me.shedaniel.rei.impl.client.ClientInternals; import me.shedaniel.rei.impl.client.gui.error.ErrorsEntryListWidget; import me.shedaniel.rei.impl.client.gui.error.ErrorsScreen; import me.shedaniel.rei.impl.client.util.CrashReportUtils; import net.minecraft.CrashReport; +import net.minecraft.ReportedException; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.TextComponent; @@ -39,10 +41,15 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.function.BiConsumer; import java.util.function.Function; public class CatchingExceptionUtils { - public static void handleThrowable(Throwable throwable, String task) { + public static void attach() { + ClientInternals.attachInstance((BiConsumer) CatchingExceptionUtils::handleThrowable, "crashHandler"); + } + + private static void handleThrowable(Throwable throwable, String task) { CrashReport report = CrashReportUtils.essential(throwable, task); File reportsFolder = new File(Minecraft.getInstance().gameDirectory, "crash-reports"); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss"); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CraftableFilterButtonWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CraftableFilterButtonWidget.java deleted file mode 100644 index afd0654c1..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CraftableFilterButtonWidget.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget; - -import com.mojang.math.Vector4f; -import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.config.ConfigManager; -import me.shedaniel.rei.api.client.gui.config.SearchFieldLocation; -import me.shedaniel.rei.api.client.gui.widgets.Button; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.api.client.gui.widgets.Widget; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; -import me.shedaniel.rei.api.client.search.method.InputMethod; -import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; -import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; -import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.modules.MenuAccess; -import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; -import me.shedaniel.rei.impl.client.gui.modules.entries.SubMenuEntry; -import me.shedaniel.rei.impl.client.gui.modules.entries.ToggleMenuEntry; -import me.shedaniel.rei.impl.client.gui.screen.ConfigReloadingScreen; -import me.shedaniel.rei.impl.common.InternalLogger; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.chat.NarratorChatListener; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Blocks; - -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class CraftableFilterButtonWidget { - public static final UUID FILTER_MENU_UUID = UUID.fromString("2839e998-1679-4f9e-a257-37411d16f1e6"); - - public static Widget create(ScreenOverlayImpl overlay) { - Rectangle bounds = getCraftableFilterBounds(); - MenuAccess access = overlay.menuAccess(); - ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); - ItemStack icon = new ItemStack(Blocks.CRAFTING_TABLE); - Button filterButton = Widgets.createButton(bounds, NarratorChatListener.NO_TITLE) - .focusable(false) - .onClick(button -> { - ConfigManager.getInstance().toggleCraftableOnly(); - ScreenOverlayImpl.getEntryListWidget().updateSearch(REIRuntimeImpl.getSearchField().getText(), true); - }) - .onRender((matrices, button) -> { - button.setTint(ConfigManager.getInstance().isCraftableOnlyEnabled() ? 0x3800d907 : 0x38ff0000); - - access.openOrClose(FILTER_MENU_UUID, button.getBounds(), CraftableFilterButtonWidget::menuEntries); - }) - .containsMousePredicate((button, point) -> button.getBounds().contains(point) && overlay.isNotInExclusionZones(point.x, point.y)) - .tooltipLineSupplier(button -> new TranslatableComponent(ConfigManager.getInstance().isCraftableOnlyEnabled() ? "text.rei.showing_craftable" : "text.rei.showing_all")); - Widget overlayWidget = Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { - Vector4f vector = new Vector4f(bounds.x + 2, bounds.y + 2, helper.getBlitOffset() - 10, 1.0F); - vector.transform(matrices.last().pose()); - itemRenderer.blitOffset = vector.z(); - itemRenderer.renderGuiItem(icon, (int) vector.x(), (int) vector.y()); - itemRenderer.blitOffset = 0.0F; - }); - return InternalWidgets.wrapLateRenderable(Widgets.concat(filterButton, overlayWidget)); - } - - private static Collection menuEntries() { - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); - ArrayList entries = new ArrayList<>(List.of( - new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.search_field.position"), Arrays.stream(SearchFieldLocation.values()) - .map(location -> ToggleMenuEntry.of(new TextComponent(location.toString()), - () -> config.getSearchFieldLocation() == location, - bool -> config.setSearchFieldLocation(location)) - .withActive(() -> config.getSearchFieldLocation() != location) - ) - .toList()) - )); - - List>> applicableInputMethods = getApplicableInputMethods(); - if (applicableInputMethods.size() > 1) { - entries.add(new SubMenuEntry(new TranslatableComponent("text.rei.config.menu.search_field.input_method"), createInputMethodEntries(applicableInputMethods))); - } - - return entries; - } - - public static List>> getApplicableInputMethods() { - String languageCode = Minecraft.getInstance().options.languageCode; - return InputMethodRegistry.getInstance().getAll().entrySet().stream() - .filter(entry -> CollectionUtils.anyMatch(entry.getValue().getMatchingLocales(), locale -> locale.code().equals(languageCode))) - .toList(); - } - - public static List createInputMethodEntries(List>> applicableInputMethods) { - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); - return applicableInputMethods.stream() - .map(pair -> ToggleMenuEntry.of(pair.getValue().getName(), - () -> Objects.equals(config.getInputMethodId(), pair.getKey()), - bool -> { - ExecutorService service = Executors.newSingleThreadExecutor(); - InputMethod active = InputMethod.active(); - active.dispose(service).whenComplete((unused, throwable) -> { - if (throwable != null) { - InternalLogger.getInstance().error("Failed to dispose input method", throwable); - } - - ConfigManagerImpl.getInstance().getConfig().setInputMethodId(new ResourceLocation("rei:default")); - }).join(); - CompletableFuture future = pair.getValue().prepare(service).whenComplete((unused, throwable) -> { - if (throwable != null) { - InternalLogger.getInstance().error("Failed to prepare input method", throwable); - ConfigManagerImpl.getInstance().getConfig().setInputMethodId(new ResourceLocation("rei:default")); - } else { - ConfigManagerImpl.getInstance().getConfig().setInputMethodId(pair.getKey()); - } - }); - Screen screen = Minecraft.getInstance().screen; - Minecraft.getInstance().setScreen(new ConfigReloadingScreen(new TranslatableComponent("text.rei.input.methods.initializing"), - () -> !future.isDone(), () -> { - Minecraft.getInstance().setScreen(screen); - })); - future.whenComplete((unused, throwable) -> { - service.shutdown(); - }); - }) - .withActive(() -> !Objects.equals(config.getInputMethodId(), pair.getKey())) - .withTooltip(() -> Tooltip.create(Widget.mouse(), pair.getValue().getDescription())) - ) - .toList(); - } - - private static Rectangle getCraftableFilterBounds() { - Rectangle area = REIRuntimeImpl.getSearchField().getBounds().clone(); - area.setLocation(area.x + area.width + 4, area.y - 1); - area.setSize(20, 20); - return area; - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DefaultDisplayChoosePageWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DefaultDisplayChoosePageWidget.java deleted file mode 100644 index af0e2de06..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DefaultDisplayChoosePageWidget.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.gui.widgets.Button; -import me.shedaniel.rei.api.client.gui.widgets.Panel; -import me.shedaniel.rei.api.client.gui.widgets.Widget; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.widget.basewidgets.TextFieldWidget; -import net.minecraft.client.Minecraft; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.util.Mth; -import org.jetbrains.annotations.ApiStatus; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.function.IntConsumer; - -@ApiStatus.Internal -public class DefaultDisplayChoosePageWidget extends DraggableWidget { - - private int currentPage; - private int maxPage; - private Rectangle bounds, grabBounds, dragBounds; - private List widgets; - private IntConsumer callback; - private TextFieldWidget textFieldWidget; - private Panel base1, base2; - private Button btnDone; - - public DefaultDisplayChoosePageWidget(IntConsumer callback, int currentPage, int maxPage) { - super(getPointFromConfig()); - this.callback = callback; - this.currentPage = currentPage; - this.maxPage = maxPage; - initWidgets(getMidPoint()); - } - - private static Point getPointFromConfig() { - Window window = Minecraft.getInstance().getWindow(); - return new Point(window.getGuiScaledWidth() * .5, window.getGuiScaledHeight() * .5); - } - - @Override - public Rectangle getBounds() { - return bounds; - } - - @Override - public Rectangle getGrabBounds() { - return grabBounds; - } - - @Override - public Rectangle getDragBounds() { - return dragBounds; - } - - @Override - public boolean containsMouse(double mouseX, double mouseY) { - return getBounds().contains(mouseX, mouseY) || new Rectangle(bounds.x + bounds.width - 50, bounds.y + bounds.height - 3, 50, 36).contains(mouseX, mouseY); - } - - @Override - public void updateWidgets(Point midPoint) { - this.bounds = new Rectangle(midPoint.x - 50, midPoint.y - 20, 100, 40); - this.grabBounds = new Rectangle(midPoint.x - 50, midPoint.y - 20, 100, 16); - this.dragBounds = new Rectangle(midPoint.x - 50, midPoint.y - 20, 100, 70); - base1.getBounds().setLocation(bounds.x + bounds.width - 50, bounds.y + bounds.height - 6); - base2.getBounds().setBounds(bounds); - textFieldWidget.getBounds().setLocation(bounds.x + 7, bounds.y + 16); - btnDone.getBounds().setLocation(bounds.x + bounds.width - 45, bounds.y + bounds.height + 3); - } - - @Override - protected void initWidgets(Point midPoint) { - this.bounds = new Rectangle(midPoint.x - 50, midPoint.y - 20, 100, 40); - this.grabBounds = new Rectangle(midPoint.x - 50, midPoint.y - 20, 100, 16); - this.dragBounds = new Rectangle(midPoint.x - 50, midPoint.y - 20, 100, 70); - this.widgets = Lists.newArrayList(); - this.widgets.add(base1 = Widgets.createCategoryBase(new Rectangle(bounds.x + bounds.width - 50, bounds.y + bounds.height - 6, 50, 36))); - this.widgets.add(base2 = Widgets.createCategoryBase(bounds)); - this.widgets.add(new Widget() { - - private TranslatableComponent text = new TranslatableComponent("text.rei.choose_page"); - - @Override - public List children() { - return Collections.emptyList(); - } - - @Override - public void render(PoseStack matrices, int i, int i1, float v) { - font.draw(matrices, text.getVisualOrderText(), bounds.x + 5, bounds.y + 5, REIRuntime.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : 0xFF404040); - String endString = String.format(" /%d", maxPage); - int width = font.width(endString); - font.draw(matrices, endString, bounds.x + bounds.width - 5 - width, bounds.y + 22, REIRuntime.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : 0xFF404040); - } - }); - String endString = String.format(" /%d", maxPage); - int width = font.width(endString); - this.widgets.add(textFieldWidget = new TextFieldWidget(bounds.x + 7, bounds.y + 16, bounds.width - width - 12, 18)); - textFieldWidget.setMaxLength(10000); - textFieldWidget.stripInvalid = s -> { - StringBuilder stringBuilder_1 = new StringBuilder(); - char[] var2 = s.toCharArray(); - int var3 = var2.length; - - for (char char_1 : var2) { - if (Character.isDigit(char_1)) - stringBuilder_1.append(char_1); - } - - return stringBuilder_1.toString(); - }; - textFieldWidget.setText(String.valueOf(currentPage + 1)); - widgets.add(btnDone = Widgets.createButton(new Rectangle(bounds.x + bounds.width - 45, bounds.y + bounds.height + 3, 40, 20), new TranslatableComponent("gui.done")) - .onClick(button -> { - callback.accept(Mth.clamp(getIntFromString(textFieldWidget.getText()).orElse(0) - 1, 0, maxPage - 1)); - ScreenOverlayImpl.getInstance().choosePageWidget = null; - })); - textFieldWidget.setFocused(true); - } - - @Override - public Point processMidPoint(Point midPoint, Point mouse, Point startPoint, Window window, int relateX, int relateY) { - return new Point(Mth.clamp(mouse.x - relateX, getDragBounds().width / 2, window.getGuiScaledWidth() - getDragBounds().width / 2), Mth.clamp(mouse.y - relateY, 20, window.getGuiScaledHeight() - 50)); - } - - @Override - public List children() { - return widgets; - } - - @Override - public void render(PoseStack matrices, int i, int i1, float v) { - matrices.pushPose(); - matrices.translate(0, 0, 800); - for (Widget widget : widgets) { - widget.render(matrices, i, i1, v); - } - matrices.popPose(); - } - - @Override - public boolean charTyped(char char_1, int int_1) { - for (Widget widget : widgets) - if (widget.charTyped(char_1, int_1)) - return true; - return false; - } - - @Override - public boolean keyPressed(int int_1, int int_2, int int_3) { - if (int_1 == 335 || int_1 == 257) { - callback.accept(Mth.clamp(getIntFromString(textFieldWidget.getText()).orElse(0) - 1, 0, maxPage - 1)); - ScreenOverlayImpl.getInstance().choosePageWidget = null; - return true; - } - for (Widget widget : widgets) - if (widget.keyPressed(int_1, int_2, int_3)) - return true; - return false; - } - - public Optional getIntFromString(String s) { - try { - return Optional.of(Integer.valueOf(s)); - } catch (Exception ignored) { - } - return Optional.empty(); - } - - @Override - public void onMouseReleaseMidPoint(Point midPoint) { - } - -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayCompositeWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayCompositeWidget.java index d35ae8d32..829217f6e 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayCompositeWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayCompositeWidget.java @@ -34,9 +34,8 @@ import me.shedaniel.rei.api.client.gui.widgets.DelegateWidgetWithBounds; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.common.display.Display; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; import me.shedaniel.rei.impl.display.DisplaySpec; import net.minecraft.client.gui.screens.Screen; import org.jetbrains.annotations.Nullable; @@ -77,10 +76,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (ConfigObject.getInstance().isFavoritesEnabled() && containsMouse(mouse())) { if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) { - FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); - - if (favoritesListWidget != null) { - favoritesListWidget.displayHistory.addDisplay(getBounds().clone(), display.provideInternalDisplay()); + if (ScreenOverlay.getInstance().get().submitDisplayHistory(display.provideInternalDisplay(), getBounds().clone())) { return true; } } @@ -97,10 +93,7 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { if (ConfigObject.getInstance().isFavoritesEnabled() && containsMouse(mouseX, mouseY)) { if (ConfigObject.getInstance().getFavoriteKeyCode().matchesMouse(button)) { - FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); - - if (favoritesListWidget != null) { - favoritesListWidget.displayHistory.addDisplay(getBounds().clone(), display.provideInternalDisplay()); + if (ScreenOverlay.getInstance().get().submitDisplayHistory(display.provideInternalDisplay(), getBounds().clone())) { return true; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayedEntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayedEntryWidget.java deleted file mode 100644 index cf7f2f5b7..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayedEntryWidget.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget; - -import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.math.Point; -import me.shedaniel.rei.api.client.ClientHelper; -import me.shedaniel.rei.api.client.config.ConfigObject; -import me.shedaniel.rei.api.client.gui.config.ItemCheatingMode; -import me.shedaniel.rei.api.client.gui.screen.DisplayScreen; -import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; -import me.shedaniel.rei.api.common.util.EntryStacks; -import net.minecraft.client.KeyMapping; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.world.item.ItemStack; - -public abstract class DisplayedEntryWidget extends EntryWidget { - public int backupY; - - protected DisplayedEntryWidget(Point point, int entrySize) { - super(point); - this.backupY = point.y; - getBounds().width = getBounds().height = entrySize; - } - - @Override - protected void drawHighlighted(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (!getCurrentEntry().isEmpty()) - super.drawHighlighted(matrices, mouseX, mouseY, delta); - } - - @Override - public void queueTooltip(PoseStack matrices, int mouseX, int mouseY, float delta) { - if (ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen) && !minecraft.player.containerMenu.getCarried().isEmpty()) { - return; - } - super.queueTooltip(matrices, mouseX, mouseY, delta); - } - - @Override - protected boolean doAction(double mouseX, double mouseY, int button) { - if (ClientHelper.getInstance().isCheating() && !Screen.hasControlDown() && !(Minecraft.getInstance().screen instanceof DisplayScreen)) { - EntryStack entry = getCurrentEntry().copy(); - if (!entry.isEmpty()) { - if (entry.getType() != VanillaEntryTypes.ITEM) { - EntryStack cheatsAs = entry.cheatsAs(); - entry = cheatsAs.isEmpty() ? entry : cheatsAs; - } - if (entry.getValueType() == ItemStack.class) { - boolean all; - if (ConfigObject.getInstance().getItemCheatingMode() == ItemCheatingMode.REI_LIKE) { - all = button == 1 || Screen.hasShiftDown(); - } else { - all = button != 1 || Screen.hasShiftDown(); - } - entry.castValue().setCount(!all ? 1 : entry.castValue().getMaxStackSize()); - } - return ClientHelper.getInstance().tryCheatingEntry(entry); - } - } - - return super.doAction(mouseX, mouseY, button); - } - - @Override - public boolean cancelDeleteItems(EntryStack stack) { - if (!interactable || !ConfigObject.getInstance().isGrabbingItems()) - return super.cancelDeleteItems(stack); - if (ClientHelper.getInstance().isCheating() && !Screen.hasControlDown() && !(Minecraft.getInstance().screen instanceof DisplayScreen)) { - EntryStack entry = getCurrentEntry().copy(); - if (!entry.isEmpty()) { - if (entry.getType() != VanillaEntryTypes.ITEM) { - EntryStack cheatsAs = entry.cheatsAs(); - entry = cheatsAs.isEmpty() ? entry : cheatsAs; - } - return EntryStacks.equalsExact(entry, stack); - } - } - return super.cancelDeleteItems(stack); - } - - @Override - public boolean keyPressedIgnoreContains(int keyCode, int scanCode, int modifiers) { - if (ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen)) { - EntryStack entry = getCurrentEntry().copy(); - if (!entry.isEmpty()) { - if (entry.getType() != VanillaEntryTypes.ITEM) { - EntryStack cheatsAs = entry.cheatsAs(); - entry = cheatsAs.isEmpty() ? entry : cheatsAs; - } - if (entry.getValueType() == ItemStack.class) { - entry.castValue().setCount(entry.castValue().getMaxStackSize()); - - KeyMapping[] keyHotbarSlots = Minecraft.getInstance().options.keyHotbarSlots; - for (int i = 0; i < keyHotbarSlots.length; i++) { - if (keyHotbarSlots[i].matches(keyCode, scanCode)) { - return ClientHelper.getInstance().tryCheatingEntryTo(entry, i); - } - } - } - } - } - - return super.keyPressedIgnoreContains(keyCode, scanCode, modifiers); - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DraggableWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DraggableWidget.java deleted file mode 100644 index 4d41efd35..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DraggableWidget.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget; - -import com.mojang.blaze3d.platform.Window; -import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; -import me.shedaniel.math.impl.PointHelper; -import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.events.GuiEventListener; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public abstract class DraggableWidget extends WidgetWithBounds { - - public boolean dragged = false; - private Point midPoint, startPoint; - private int relateX, relateY; - - public DraggableWidget(Point startingPoint) { - initWidgets(midPoint = startingPoint); - } - - public DraggableWidget() { - this(new Point(Minecraft.getInstance().getWindow().getGuiScaledWidth() / 2, Minecraft.getInstance().getWindow().getGuiScaledHeight() / 2)); - } - - protected abstract void initWidgets(Point midPoint); - - public abstract void updateWidgets(Point midPoint); - - public abstract Rectangle getGrabBounds(); - - public abstract Rectangle getDragBounds(); - - public final Point getMidPoint() { - return midPoint; - } - - @Override - public boolean mouseDragged(double double_1, double double_2, int int_1, double double_3, double double_4) { - Point mouse = PointHelper.ofMouse(); - if (int_1 == 0) { - if (!dragged) { - if (getGrabBounds().contains(mouse)) { - startPoint = new Point(midPoint.x, midPoint.y); - relateX = mouse.x - midPoint.x; - relateY = mouse.y - midPoint.y; - dragged = true; - } - } else { - Window window = minecraft.getWindow(); - midPoint = processMidPoint(midPoint, mouse, startPoint, window, relateX, relateY); - updateWidgets(midPoint); - } - return true; - } - for (GuiEventListener listener : children()) - if (listener.mouseDragged(double_1, double_2, int_1, double_3, double_4)) - return true; - return false; - } - - public abstract Point processMidPoint(Point midPoint, Point mouse, Point startPoint, Window window, int relateX, int relateY); - - @Override - public boolean mouseReleased(double double_1, double double_2, int int_1) { - if (int_1 == 0) - if (dragged) { - dragged = false; - onMouseReleaseMidPoint(getMidPoint()); - return true; - } - for (GuiEventListener listener : children()) - if (listener.mouseReleased(double_1, double_2, int_1)) - return true; - return false; - } - - public void onMouseReleaseMidPoint(Point midPoint) { - } - -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryHighlighter.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryHighlighter.java deleted file mode 100644 index 850fa333d..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryHighlighter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget; - -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListSearchManager; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiComponent; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.world.inventory.Slot; - -public class EntryHighlighter extends GuiComponent { - public static void render(PoseStack matrices) { - RenderSystem.disableDepthTest(); - RenderSystem.colorMask(true, true, true, false); - if (Minecraft.getInstance().screen instanceof AbstractContainerScreen containerScreen) { - int x = containerScreen.leftPos, y = containerScreen.topPos; - for (Slot slot : containerScreen.getMenu().slots) { - if (!slot.hasItem() || !EntryListSearchManager.INSTANCE.matches(EntryStacks.of(slot.getItem()))) { - matrices.pushPose(); - matrices.translate(0, 0, 500f); - fillGradient(matrices, x + slot.x, y + slot.y, x + slot.x + 16, y + slot.y + 16, 0xdc202020, 0xdc202020, 0); - matrices.popPose(); - } else { - matrices.pushPose(); - matrices.translate(0, 0, 200f); - fillGradient(matrices, x + slot.x, y + slot.y, x + slot.x + 16, y + slot.y + 16, 0x345fff3b, 0x345fff3b, 0); - - fillGradient(matrices, x + slot.x - 1, y + slot.y - 1, x + slot.x, y + slot.y + 16 + 1, 0xff5fff3b, 0xff5fff3b, 0); - fillGradient(matrices, x + slot.x + 16, y + slot.y - 1, x + slot.x + 16 + 1, y + slot.y + 16 + 1, 0xff5fff3b, 0xff5fff3b, 0); - fillGradient(matrices, x + slot.x - 1, y + slot.y - 1, x + slot.x + 16, y + slot.y, 0xff5fff3b, 0xff5fff3b, 0); - fillGradient(matrices, x + slot.x - 1, y + slot.y + 16, x + slot.x + 16, y + slot.y + 16 + 1, 0xff5fff3b, 0xff5fff3b, 0); - - matrices.popPose(); - } - } - } - RenderSystem.colorMask(true, true, true, true); - RenderSystem.enableDepthTest(); - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java deleted file mode 100644 index 67296e755..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget; - -import com.google.common.base.Suppliers; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Matrix4f; -import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; -import me.shedaniel.math.impl.PointHelper; -import me.shedaniel.rei.api.client.config.ConfigObject; -import me.shedaniel.rei.api.client.gui.DrawableConsumer; -import me.shedaniel.rei.api.client.gui.Renderer; -import me.shedaniel.rei.api.client.gui.widgets.*; -import me.shedaniel.rei.api.client.registry.display.DisplayCategory; -import me.shedaniel.rei.api.common.display.Display; -import me.shedaniel.rei.impl.ClientInternals; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.toast.CopyRecipeIdentifierToast; -import me.shedaniel.rei.impl.client.gui.widget.basewidgets.*; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.resources.language.I18n; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.FormattedText; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.ApiStatus; - -import java.util.Collection; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -@ApiStatus.Internal -@Environment(EnvType.CLIENT) -public final class InternalWidgets { - private InternalWidgets() {} - - public static Widget createAutoCraftingButtonWidget(Rectangle displayBounds, Rectangle rectangle, Component text, Supplier displaySupplier, Supplier> idsSupplier, List setupDisplay, DisplayCategory category) { - Button autoCraftingButton = Widgets.createButton(rectangle, text) - .focusable(false) - .onClick(button -> { - AutoCraftingEvaluator.evaluateAutoCrafting(true, Screen.hasShiftDown(), displaySupplier.get(), idsSupplier); - }); - return new DelegateWidget(autoCraftingButton) { - final Supplier result = Suppliers.memoizeWithExpiration( - () -> AutoCraftingEvaluator.evaluateAutoCrafting(false, false, displaySupplier.get(), idsSupplier), - 1000, TimeUnit.MILLISECONDS - ); - - @Override - public void render(PoseStack poses, int mouseX, int mouseY, float delta) { - AutoCraftingEvaluator.AutoCraftingResult result = this.result.get(); - - autoCraftingButton.setEnabled(result.successful); - autoCraftingButton.setTint(result.tint); - - if (result.hasApplicable) { - autoCraftingButton.setText(text); - } else { - autoCraftingButton.setText(new TextComponent("!")); - } - - if (result.hasApplicable && (containsMouse(mouseX, mouseY) || autoCraftingButton.isFocused()) && result.renderer != null) { - result.renderer.render(poses, mouseX, mouseY, delta, setupDisplay, displayBounds, displaySupplier.get()); - } - - this.widget.render(poses, mouseX, mouseY, delta); - - if (!autoCraftingButton.isFocused() && containsMouse(mouseX, mouseY)) { - tryTooltip(result, new Point(mouseX, mouseY)); - } else if (autoCraftingButton.isFocused()) { - Rectangle bounds = autoCraftingButton.getBounds(); - tryTooltip(result, new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2)); - } - } - - private void tryTooltip(AutoCraftingEvaluator.AutoCraftingResult result, Point point) { - if (result.tooltipRenderer != null) { - result.tooltipRenderer.accept(point, Tooltip::queue); - } - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (displaySupplier.get().getDisplayLocation().isPresent() && ConfigObject.getInstance().getCopyRecipeIdentifierKeybind().matchesKey(keyCode, scanCode) && containsMouse(PointHelper.ofMouse())) { - minecraft.keyboardHandler.setClipboard(displaySupplier.get().getDisplayLocation().get().toString()); - if (ConfigObject.getInstance().isToastDisplayedOnCopyIdentifier()) { - CopyRecipeIdentifierToast.addToast(I18n.get("msg.rei.copied_recipe_id"), I18n.get("msg.rei.recipe_id_details", displaySupplier.get().getDisplayLocation().get().toString())); - } - return true; - } else if (ConfigObject.getInstance().isFavoritesEnabled() && containsMouse(PointHelper.ofMouse())) { - if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) { - FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); - - if (favoritesListWidget != null) { - favoritesListWidget.displayHistory.addDisplay(displayBounds.clone(), displaySupplier.get()); - return true; - } - } - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (displaySupplier.get().getDisplayLocation().isPresent() && ConfigObject.getInstance().getCopyRecipeIdentifierKeybind().matchesMouse(button) && containsMouse(PointHelper.ofMouse())) { - minecraft.keyboardHandler.setClipboard(displaySupplier.get().getDisplayLocation().get().toString()); - if (ConfigObject.getInstance().isToastDisplayedOnCopyIdentifier()) { - CopyRecipeIdentifierToast.addToast(I18n.get("msg.rei.copied_recipe_id"), I18n.get("msg.rei.recipe_id_details", displaySupplier.get().getDisplayLocation().get().toString())); - } - return true; - } else if (ConfigObject.getInstance().isFavoritesEnabled() && containsMouse(PointHelper.ofMouse())) { - if (ConfigObject.getInstance().getFavoriteKeyCode().matchesMouse(button)) { - FavoritesListWidget favoritesListWidget = ScreenOverlayImpl.getFavoritesListWidget(); - - if (favoritesListWidget != null) { - favoritesListWidget.displayHistory.addDisplay(displayBounds.clone(), displaySupplier.get()); - return true; - } - } - } - - return super.mouseClicked(mouseX, mouseY, button); - } - }; - } - - public static WidgetWithBounds wrapLateRenderable(Widget widget) { - return new LateRenderableWidget(widget); - } - - public static Widget concatWidgets(List widgets) { - return new MergedWidget(widgets); - } - - private static class LateRenderableWidget extends DelegateWidget implements LateRenderable { - private LateRenderableWidget(Widget widget) { - super(widget); - } - } - - public static void attach() { - ClientInternals.attachInstance(new WidgetsProvider(), ClientInternals.WidgetsProvider.class); - } - - private static class WidgetsProvider implements ClientInternals.WidgetsProvider { - @Override - public boolean isRenderingPanel(Panel panel) { - return PanelWidget.isRendering(panel); - } - - @Override - public Widget wrapVanillaWidget(GuiEventListener element) { - if (element instanceof Widget) return (Widget) element; - return new VanillaWrappedWidget(element); - } - - @Override - public WidgetWithBounds wrapRenderer(Supplier bounds, Renderer renderer) { - return new RendererWrappedWidget(renderer, bounds); - } - - @Override - public WidgetWithBounds withTranslate(WidgetWithBounds widget, Supplier translate) { - return new DelegateWidgetWithTranslate(widget, translate); - } - - @Override - public Widget createDrawableWidget(DrawableConsumer drawable) { - return new DrawableWidget(drawable); - } - - @Override - public Slot createSlot(Point point) { - return new EntryWidget(point); - } - - @Override - public Slot createSlot(Rectangle bounds) { - return new EntryWidget(bounds); - } - - @Override - public Button createButton(Rectangle bounds, Component text) { - return new ButtonWidget(bounds, text); - } - - @Override - public Panel createPanelWidget(Rectangle bounds) { - return new PanelWidget(bounds); - } - - @Override - public Label createLabel(Point point, FormattedText text) { - return new LabelWidget(point, text); - } - - @Override - public Arrow createArrow(Rectangle rectangle) { - return new ArrowWidget(rectangle); - } - - @Override - public BurningFire createBurningFire(Rectangle rectangle) { - return new BurningFireWidget(rectangle); - } - - @Override - public DrawableConsumer createTexturedConsumer(ResourceLocation texture, int x, int y, int width, int height, float u, float v, int uWidth, int vHeight, int textureWidth, int textureHeight) { - return new TexturedDrawableConsumer(texture, x, y, width, height, u, v, uWidth, vHeight, textureWidth, textureHeight); - } - - @Override - public DrawableConsumer createFillRectangleConsumer(Rectangle rectangle, int color) { - return new FillRectangleDrawableConsumer(rectangle, color); - } - - @Override - public Widget createShapelessIcon(Point point) { - int magnification; - double scale = Minecraft.getInstance().getWindow().getGuiScale(); - if (scale >= 1 && scale <= 4 && scale == Math.floor(scale)) { - magnification = (int) scale; - } else if (scale > 4 && scale == Math.floor(scale)) { - magnification = 1; - for (int i = 4; i >= 1; i--) { - if (scale % i == 0) { - magnification = i; - break; - } - } - } else { - magnification = 4; - } - Rectangle bounds = new Rectangle(point.getX() - 9, point.getY() + 1, 8, 8); - Widget widget = Widgets.createTexturedWidget(new ResourceLocation("roughlyenoughitems:textures/gui/shapeless_icon_" + magnification + "x.png"), bounds.getX(), bounds.getY(), 0, 0, bounds.getWidth(), bounds.getHeight(), 1, 1, 1, 1); - return Widgets.withTooltip(Widgets.withBounds(widget, bounds), - new TranslatableComponent("text.rei.shapeless")); - } - - @Override - public Widget concatWidgets(List widgets) { - return InternalWidgets.concatWidgets(widgets); - } - - @Override - public WidgetWithBounds noOp() { - return NoOpWidget.INSTANCE; - } - - @Override - public WidgetWithBounds wrapOverflow(Rectangle bounds, WidgetWithBounds widget) { - return new OverflowWidget(bounds, new PaddedCenterWidget(bounds, widget)); - } - - @Override - public WidgetWithBounds wrapPadded(int padLeft, int padRight, int padTop, int padBottom, WidgetWithBounds widget) { - return new PaddedWidget(padLeft, padRight, padTop, padBottom, widget); - } - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabWidget.java index 671f854ad..ab41eb765 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TabWidget.java @@ -31,6 +31,7 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.ClientHelper; import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggableStackProviderWidget; @@ -65,7 +66,7 @@ public class TabWidget extends WidgetWithBounds implements DraggableStackProvide @Nullable private Predicate onClick; private final NumberAnimator darkBackgroundAlpha = ValueAnimator.ofFloat() - .withConvention(() -> REIRuntime.getInstance().isDarkThemeEnabled() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) + .withConvention(() -> ConfigObject.getInstance().isUsingDarkTheme() ? 1.0F : 0.0F, ValueAnimator.typicalTransitionTime()) .asFloat(); private TabWidget(int id, Rectangle bounds, int u, int v, @Nullable Predicate onClick) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/QueuedTooltip.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TooltipImpl.java similarity index 93% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/QueuedTooltip.java rename to runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TooltipImpl.java index 59fe6f55a..0cf49f746 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/QueuedTooltip.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/TooltipImpl.java @@ -45,12 +45,12 @@ */ @ApiStatus.Internal @Environment(EnvType.CLIENT) -public class QueuedTooltip implements Tooltip { +public class TooltipImpl implements Tooltip { private Point location; private List entries; private EntryStack stack = EntryStack.empty(); - private QueuedTooltip(Point location, Collection entries) { + private TooltipImpl(Point location, Collection entries) { this.location = location; if (this.location == null) { this.location = PointHelper.ofMouse(); @@ -58,8 +58,8 @@ private QueuedTooltip(Point location, Collection entrie this.entries = (List) Lists.newArrayList(entries); } - public static QueuedTooltip impl(Point location, Collection text) { - return new QueuedTooltip(location, text); + public static TooltipImpl impl(Point location, Collection text) { + return new TooltipImpl(location, text); } @Override @@ -107,7 +107,7 @@ public void queue() { @Override public Tooltip copy() { - QueuedTooltip tooltip = new QueuedTooltip(location.clone(), entries); + TooltipImpl tooltip = new TooltipImpl(location.clone(), entries); tooltip.withContextStack(getContextStack()); return tooltip; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesEntriesManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesEntriesManager.java deleted file mode 100644 index 38416b7cf..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesEntriesManager.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget.favorites; - -import me.shedaniel.rei.api.client.config.ConfigManager; -import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; -import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; -import me.shedaniel.rei.impl.client.config.ConfigObjectImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; - -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -public class FavoritesEntriesManager { - public static final FavoritesEntriesManager INSTANCE = new FavoritesEntriesManager(); - - private Stream getDefaultFavorites() { - return StreamSupport.stream(FavoriteEntryType.registry().sections().spliterator(), false) - .flatMap(section -> section.getDefaultEntries().stream()); - } - - public List getFavorites() { - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); - List defaultFavorites = getDefaultFavorites().collect(Collectors.toList()); - defaultFavorites.removeAll(config.getHiddenFavoriteEntries()); - - List favorites = new ArrayList<>(config.getConfigFavoriteEntries()); - defaultFavorites.removeAll(favorites); - favorites.addAll(0, defaultFavorites); - favorites.removeIf(FavoriteEntry::isInvalid); - return favorites; - } - - public void remove(FavoriteEntry entry) { - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); - - config.getConfigFavoriteEntries().remove(entry); - if (getDefaultFavorites().anyMatch(e -> e.equals(entry)) && !config.getHiddenFavoriteEntries().contains(entry)) { - config.getHiddenFavoriteEntries().add(entry); - } - - ConfigManager.getInstance().saveConfig(); - FavoritesListWidget widget = ScreenOverlayImpl.getFavoritesListWidget(); - if (widget != null) { - widget.updateSearch(); - } - } - - public void add(FavoriteEntry entry) { - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); - List defaultFavorites = getDefaultFavorites().toList(); - - config.getConfigFavoriteEntries().remove(entry); - if (CollectionUtils.anyMatch(defaultFavorites, e -> e.equals(entry)) && !config.getHiddenFavoriteEntries().contains(entry)) { - config.getHiddenFavoriteEntries().add(entry); - } - - for (int i = defaultFavorites.size() - 1; i >= 0; i--) { - FavoriteEntry e = defaultFavorites.get(i); - if (!config.getConfigFavoriteEntries().contains(e) && !config.getHiddenFavoriteEntries().contains(e)) { - config.getConfigFavoriteEntries().add(0, e); - } - } - - config.getHiddenFavoriteEntries().remove(entry); - if (!CollectionUtils.anyMatch(defaultFavorites, e -> e.equals(entry))) { - config.getConfigFavoriteEntries().add(entry); - } - - ConfigManager.getInstance().saveConfig(); - FavoritesListWidget widget = ScreenOverlayImpl.getFavoritesListWidget(); - if (widget != null) { - widget.updateSearch(); - } - } - - public void setEntries(List entries) { - List defaultFavorites = getDefaultFavorites().collect(Collectors.toList()); - List hiddenDefaultFavorites = new ArrayList<>(defaultFavorites); - hiddenDefaultFavorites.removeAll(entries); - ConfigObjectImpl config = ConfigManagerImpl.getInstance().getConfig(); - config.getHiddenFavoriteEntries().clear(); - config.getHiddenFavoriteEntries().addAll(hiddenDefaultFavorites); - config.getConfigFavoriteEntries().clear(); - config.getConfigFavoriteEntries().addAll(entries); - - ConfigManager.getInstance().saveConfig(); - FavoritesListWidget widget = ScreenOverlayImpl.getFavoritesListWidget(); - if (widget != null) { - widget.updateSearch(); - } - } - - public List asListView() { - return new AbstractList<>() { - @Override - public FavoriteEntry get(int index) { - return getFavorites().get(index); - } - - @Override - public int size() { - return getFavorites().size(); - } - - @Override - public void add(int index, FavoriteEntry entry) { - FavoritesEntriesManager.this.add(entry); - } - - @Override - public boolean remove(Object o) { - if (o instanceof FavoriteEntry) { - FavoritesEntriesManager.this.remove((FavoriteEntry) o); - return true; - } else { - return false; - } - } - }; - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionEntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionEntryWidget.java deleted file mode 100644 index c4a50ffd1..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionEntryWidget.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui.widget.region; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector4f; -import me.shedaniel.math.FloatingPoint; -import me.shedaniel.math.Point; -import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.entry.region.RegionEntry; -import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; -import me.shedaniel.rei.api.client.overlay.ScreenOverlay; -import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.modules.MenuAccess; -import me.shedaniel.rei.impl.client.gui.modules.MenuEntry; -import me.shedaniel.rei.impl.client.gui.widget.DisplayedEntryWidget; -import net.minecraft.client.gui.components.events.GuiEventListener; - -import java.util.*; -import java.util.function.Supplier; - -public class RegionEntryWidget> extends DisplayedEntryWidget { - private final RealRegionEntry entry; - - RegionEntryWidget(RealRegionEntry entry, int x, int y, int entrySize) { - super(new Point(x, y), entrySize); - this.entry = entry; - this.clearEntries().entry(entry.getEntry().toStack()); - } - - @Override - protected FavoriteEntry asFavoriteEntry() { - return entry.region.listener.asFavorite(entry); - } - - @Override - public boolean containsMouse(double mouseX, double mouseY) { - return super.containsMouse(mouseX, mouseY) && entry.region.containsMouse(mouseX, mouseY); - } - - @Override - protected boolean reverseFavoritesAction() { - return true; - } - - @Override - public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - Optional overlayOptional = REIRuntime.getInstance().getOverlay(); - Optional>> menuEntries = entry.getEntry().getMenuEntries(); - FloatingPoint value = entry.pos.value(); - FloatingPoint target = entry.pos.target(); - if (Math.abs(value.x - target.x) < 1 && Math.abs(value.y - target.y) < 1 && overlayOptional.isPresent() && menuEntries.isPresent()) { - ScreenOverlayImpl overlay = (ScreenOverlayImpl) overlayOptional.get(); - MenuAccess access = overlay.menuAccess(); - UUID uuid = entry.getEntry().getUuid(); - - access.openOrClose(uuid, getBounds(), () -> - CollectionUtils.map(menuEntries.get().get(), entry -> convertMenu(overlay, entry))); - } - Vector4f vector4f = new Vector4f(mouseX, mouseY, 0, 1.0F); - vector4f.transform(matrices.last().pose()); - super.render(matrices, (int) vector4f.x(), (int) vector4f.y(), delta); - } - - private MenuEntry convertMenu(ScreenOverlayImpl overlay, FavoriteMenuEntry entry) { - return new MenuEntry() { - @Override - public List children() { - return Collections.singletonList(entry); - } - - @Override - public void render(PoseStack poseStack, int i, int j, float f) { - entry.render(poseStack, i, j, f); - } - - @Override - public int getEntryWidth() { - return entry.getEntryWidth(); - } - - @Override - public int getEntryHeight() { - return entry.getEntryHeight(); - } - - @Override - public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) { - entry.closeMenu = overlay.menuAccess()::close; - entry.updateInformation(xPos, yPos, selected, containsMouse, rendering, width); - } - - @Override - public int getZ() { - return entry.getZ(); - } - - @Override - public void setZ(int z) { - entry.setZ(z); - } - }; - } - - @Override - protected boolean doAction(double mouseX, double mouseY, int button) { - return entry.getEntry().doAction(button) || super.doAction(mouseX, mouseY, button); - } - - public RealRegionEntry getEntry() { - return entry; - } -} \ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/init/RoughlyEnoughItemsInitializer.java b/runtime/src/main/java/me/shedaniel/rei/impl/init/RoughlyEnoughItemsInitializer.java index 31436a70a..74872de4d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/init/RoughlyEnoughItemsInitializer.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/init/RoughlyEnoughItemsInitializer.java @@ -45,15 +45,16 @@ public static void onInitialize() { adapter.checkMods(); if (RoughlyEnoughItemsState.getErrors().isEmpty()) { + initializeEntryPoint(false, "me.shedaniel.rei.impl.common.logging.LoggerInitializer"); + initializeEntryPoint(false, "me.shedaniel.rei.impl.common.init.CoreInitialization"); initializeEntryPoint(false, "me.shedaniel.rei.RoughlyEnoughItemsCore"); } } public static void onInitializeClient() { if (RoughlyEnoughItemsState.getErrors().isEmpty()) { + initializeEntryPoint(true, "me.shedaniel.rei.impl.client.init.CoreClientInitialization"); initializeEntryPoint(true, "me.shedaniel.rei.RoughlyEnoughItemsCoreClient"); - initializeEntryPoint(true, "me.shedaniel.rei.REIModMenuEntryPoint"); - initializeEntryPoint(true, "me.shedaniel.rei.impl.client.ClientHelperImpl"); initializeEntryPoint(true, "me.shedaniel.rei.impl.client.REIRuntimeImpl"); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/init/ServiceBasedPluginDetector.java b/runtime/src/main/java/me/shedaniel/rei/impl/init/ServiceBasedPluginDetector.java new file mode 100644 index 000000000..787287377 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/init/ServiceBasedPluginDetector.java @@ -0,0 +1,61 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.init; + +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import me.shedaniel.rei.api.common.plugins.REIServerPlugin; +import me.shedaniel.rei.impl.common.Internals; + +import java.util.List; +import java.util.function.Supplier; + +public class ServiceBasedPluginDetector implements PluginDetector { + @Override + public void detectServerPlugins() { + List plugins = Internals.resolveServices(REIServerPlugin.class); + for (REIServerPlugin plugin : plugins) { + PluginManager.getServerInstance().view().registerPlugin(plugin); + } + } + + @Override + public void detectCommonPlugins() { + List> plugins = Internals.resolveServices((Class>) (Class) REIPlugin.class); + for (REIPlugin plugin : plugins) { + PluginManager.getInstance().view().registerPlugin(plugin); + } + } + + @Override + public Supplier detectClientPlugins() { + return () -> () -> { + List plugins = Internals.resolveServices(REIClientPlugin.class); + for (REIClientPlugin plugin : plugins) { + PluginManager.getClientInstance().view().registerPlugin(plugin); + } + }; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java index 781380276..3a38adf77 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java +++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java @@ -23,115 +23,20 @@ package me.shedaniel.rei.plugin.client.runtime; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.Lifecycle; -import dev.architectury.platform.Platform; -import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; -import me.shedaniel.rei.api.client.ClientHelper; -import me.shedaniel.rei.api.client.REIRuntime; -import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; -import me.shedaniel.rei.api.client.gui.AbstractRenderer; -import me.shedaniel.rei.api.client.gui.Renderer; -import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProviderWidget; -import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitorWidget; import me.shedaniel.rei.api.client.gui.widgets.Panel; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; -import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; -import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.registry.screen.ExclusionZones; import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; -import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; -import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; -import me.shedaniel.rei.api.client.util.ClientEntryStacks; -import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.plugins.PluginManager; -import me.shedaniel.rei.api.common.plugins.REIPlugin; -import me.shedaniel.rei.api.common.registry.Reloadable; -import me.shedaniel.rei.api.common.util.EntryStacks; -import me.shedaniel.rei.impl.client.ClientHelperImpl; -import me.shedaniel.rei.impl.client.REIRuntimeImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; import me.shedaniel.rei.impl.client.gui.screen.DefaultDisplayViewingScreen; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; -import me.shedaniel.rei.impl.client.search.method.DefaultInputMethod; -import me.shedaniel.rei.impl.client.search.method.unihan.BomopofoInputMethod; -import me.shedaniel.rei.impl.client.search.method.unihan.JyutpingInputMethod; -import me.shedaniel.rei.impl.client.search.method.unihan.PinyinInputMethod; -import me.shedaniel.rei.impl.client.search.method.unihan.UniHanManager; -import me.shedaniel.rei.impl.common.entry.type.EntryRegistryImpl; -import me.shedaniel.rei.impl.common.entry.type.EntryRegistryListener; -import me.shedaniel.rei.plugin.autocrafting.DefaultCategoryHandler; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; import java.util.Collections; -import java.util.List; -import java.util.function.Function; @Environment(EnvType.CLIENT) @ApiStatus.Internal public class DefaultClientRuntimePlugin implements REIClientPlugin { - private final FilteredStacksVisibilityHandler filteredStacksVisibilityHandler = new FilteredStacksVisibilityHandler(); - - @SuppressWarnings("rawtypes") - public DefaultClientRuntimePlugin() { - PluginStageExecutionWatcher watcher = new PluginStageExecutionWatcher(); - for (PluginManager> instance : PluginManager.getActiveInstances()) { - instance.registerReloadable((Reloadable) watcher.reloadable(instance)); - } - REIRuntimeImpl.getInstance().addHintProvider(watcher); - REIRuntimeImpl.getInstance().addHintProvider(new SearchBarHighlightWatcher()); - REIRuntimeImpl.getInstance().addHintProvider(new SearchFilterPrepareWatcher()); - REIRuntimeImpl.getInstance().addHintProvider(new InputMethodWatcher()); - } - - @Override - public void registerEntries(EntryRegistry registry) { - if (ClientHelperImpl.getInstance().isAprilFools.get()) { - registry.addEntry(ClientEntryStacks.of(new AbstractRenderer() { - private ResourceLocation id = new ResourceLocation("roughlyenoughitems", "textures/gui/kirb.png"); - - @Override - public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { - RenderSystem.setShaderTexture(0, id); - innerBlit(matrices.last().pose(), bounds.x, bounds.getMaxX(), bounds.y, bounds.getMaxY(), getBlitOffset(), 0, 1, 0, 1); - } - - @Override - @Nullable - public Tooltip getTooltip(Point point) { - return Tooltip.create(new TextComponent("Kirby"), ClientHelper.getInstance().getFormattedModFromModId("Dream Land")); - } - })); - } - - ((EntryRegistryImpl) registry).listeners.add(new EntryRegistryListener() { - @Override - public void onReFilter(List> stacks) { - filteredStacksVisibilityHandler.reset(); - } - }); - } - - @Override - public void registerDisplays(DisplayRegistry registry) { - filteredStacksVisibilityHandler.reset(); - registry.registerVisibilityPredicate(filteredStacksVisibilityHandler); - } - @Override public void registerScreens(ScreenRegistry registry) { ExclusionZones zones = registry.exclusionZones(); @@ -141,126 +46,5 @@ public void registerScreens(ScreenRegistry registry) { return Collections.emptyList(); return Collections.singletonList(widget.getBounds().clone()); }); - zones.register(Screen.class, screen -> { - FavoritesListWidget widget = ScreenOverlayImpl.getFavoritesListWidget(); - if (widget != null) { - if (widget.togglePanelButton.isVisible()) { - return Collections.singletonList(widget.togglePanelButton.bounds); - } - } - return Collections.emptyList(); - }); - registry.registerDraggableComponentProvider(DraggableComponentProviderWidget.from(context -> { - if (RoughlyEnoughItemsCoreClient.shouldReturn(context.getScreen()) || !REIRuntime.getInstance().isOverlayVisible()) return Collections.emptyList(); - return Widgets.walk(REIRuntime.getInstance().getOverlay().get().children(), DraggableComponentProviderWidget.class::isInstance); - })); - registry.registerDraggableComponentVisitor(DraggableComponentVisitorWidget.from(context -> { - if (RoughlyEnoughItemsCoreClient.shouldReturn(context.getScreen()) || !REIRuntime.getInstance().isOverlayVisible()) return Collections.emptyList(); - return Widgets.walk(REIRuntime.getInstance().getOverlay().get().children(), DraggableComponentVisitorWidget.class::isInstance); - })); - } - - @Override - public void registerFavorites(FavoriteEntryType.Registry registry) { - registry.register(EntryStackFavoriteType.INSTANCE.id, EntryStackFavoriteType.INSTANCE); - } - - @Override - public void registerTransferHandlers(TransferHandlerRegistry registry) { - registry.register(new DefaultCategoryHandler()); - } - - @Override - public void registerInputMethods(InputMethodRegistry registry) { - registry.add(DefaultInputMethod.ID, DefaultInputMethod.INSTANCE); - UniHanManager manager = new UniHanManager(Platform.getConfigFolder().resolve("roughlyenoughitems/unihan.zip")); - registry.add(new ResourceLocation("rei:pinyin"), new PinyinInputMethod(manager)); - registry.add(new ResourceLocation("rei:jyutping"), new JyutpingInputMethod(manager)); - registry.add(new ResourceLocation("rei:bomopofo"), new BomopofoInputMethod(manager)); - } - - private enum EntryStackFavoriteType implements FavoriteEntryType { - INSTANCE(FavoriteEntryType.ENTRY_STACK); - - private final String key = "data"; - private ResourceLocation id; - - EntryStackFavoriteType(ResourceLocation id) { - this.id = id; - } - - @Override - public DataResult read(CompoundTag object) { - EntryStack stack; - try { - stack = EntryStack.read(object.getCompound(key)); - } catch (Throwable throwable) { - return DataResult.error(throwable.getMessage()); - } - return DataResult.success(new EntryStackFavoriteEntry(stack), Lifecycle.stable()); - } - - @Override - public DataResult fromArgs(Object... args) { - if (args.length == 0) return DataResult.error("Cannot create EntryStackFavoriteEntry from empty args!"); - if (!(args[0] instanceof EntryStack stack)) - return DataResult.error("Creation of EntryStackFavoriteEntry from args expected EntryStack as the first argument!"); - if (!stack.supportSaving()) - return DataResult.error("Creation of EntryStackFavoriteEntry from an unserializable stack!"); - return DataResult.success(new EntryStackFavoriteEntry(stack), Lifecycle.stable()); - } - - @Override - public CompoundTag save(EntryStackFavoriteEntry entry, CompoundTag tag) { - tag.put(key, entry.stack.saveStack()); - return tag; - } - } - - private static class EntryStackFavoriteEntry extends FavoriteEntry { - private static final Function, String> CANCEL_FLUID_AMOUNT = s -> null; - private final EntryStack stack; - private final long hash; - - public EntryStackFavoriteEntry(EntryStack stack) { - this.stack = stack.normalize(); - this.hash = EntryStacks.hashExact(this.stack); - } - - @Override - public boolean isInvalid() { - return this.stack.isEmpty(); - } - - @Override - public Renderer getRenderer(boolean showcase) { - return this.stack; - } - - @Override - public boolean doAction(int button) { - return false; - } - - @Override - public long hashIgnoreAmount() { - return hash; - } - - @Override - public FavoriteEntry copy() { - return new EntryStackFavoriteEntry(stack.normalize()); - } - - @Override - public ResourceLocation getType() { - return EntryStackFavoriteType.INSTANCE.id; - } - - @Override - public boolean isSame(FavoriteEntry other) { - if (!(other instanceof EntryStackFavoriteEntry that)) return false; - return EntryStacks.equalsExact(stack, that.stack); - } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/InputMethodWatcher.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/InputMethodWatcher.java deleted file mode 100644 index 81fff836f..000000000 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/InputMethodWatcher.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.plugin.client.runtime; - -import me.shedaniel.math.Color; -import me.shedaniel.math.Point; -import me.shedaniel.rei.api.client.config.ConfigManager; -import me.shedaniel.rei.api.client.config.ConfigObject; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.api.client.search.method.InputMethod; -import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; -import me.shedaniel.rei.api.common.plugins.PluginManager; -import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.config.ConfigManagerImpl; -import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; -import me.shedaniel.rei.impl.client.gui.hints.HintProvider; -import me.shedaniel.rei.impl.client.gui.modules.MenuAccess; -import me.shedaniel.rei.impl.client.gui.widget.CraftableFilterButtonWidget; -import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; -import me.shedaniel.rei.impl.client.search.method.DefaultInputMethod; -import net.minecraft.client.Minecraft; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -public class InputMethodWatcher implements HintProvider { - @Override - public List provide() { - if (PluginManager.areAnyReloading() || OverlaySearchField.isHighlighting) return Collections.emptyList(); - ResourceLocation id = ConfigObject.getInstance().getInputMethodId(); - if (id == null) { - String languageCode = Minecraft.getInstance().options.languageCode; - MutableComponent component = new TextComponent(""); - int match = 0; - for (InputMethod method : InputMethodRegistry.getInstance().getAll().values()) { - if (method instanceof DefaultInputMethod) continue; - if (CollectionUtils.anyMatch(method.getMatchingLocales(), locale -> locale.code().equals(languageCode))) { - if (!component.getString().isEmpty()) { - component.append(", "); - } - - component.append(method.getName()); - match++; - } - } - if (match > 0) { - return List.of(new TranslatableComponent("text.rei.input.methods.hint"), - new TextComponent(" "), component); - } - } - - return Collections.emptyList(); - } - - @Override - @Nullable - public Tooltip provideTooltip(Point mouse) { - return null; - } - - @Override - public Color getColor() { - return Color.ofTransparent(0x50ffadca); - } - - @Override - public List getButtons() { - return List.of( - new HintButton(new TranslatableComponent("text.rei.input.methods.hint.configure"), bounds -> { - MenuAccess access = ScreenOverlayImpl.getInstance().menuAccess(); - access.openOrClose(CraftableFilterButtonWidget.FILTER_MENU_UUID, bounds.clone(), - () -> CraftableFilterButtonWidget.createInputMethodEntries(CraftableFilterButtonWidget.getApplicableInputMethods())); - }), - new HintButton(new TranslatableComponent("text.rei.input.methods.hint.ignore"), bounds -> { - ConfigManagerImpl.getInstance().getConfig().setInputMethodId(new ResourceLocation("rei:default")); - ConfigManager.getInstance().saveConfig(); - }) - ); - } -} diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/PluginStageExecutionWatcher.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/PluginStageExecutionWatcher.java index 57f30d2bc..4380b71bd 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/PluginStageExecutionWatcher.java +++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/PluginStageExecutionWatcher.java @@ -36,6 +36,7 @@ import me.shedaniel.rei.api.common.registry.Reloadable; import me.shedaniel.rei.api.common.util.ImmutableTextComponent; import me.shedaniel.rei.impl.client.gui.hints.HintProvider; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import org.apache.commons.lang3.StringUtils; @@ -48,6 +49,12 @@ public class PluginStageExecutionWatcher implements HintProvider { private final Map, PluginManagerData> allStages = new HashMap<>(); + public PluginStageExecutionWatcher() { + for (PluginManager> instance : PluginManager.getActiveInstances()) { + instance.registerReloadable((Reloadable) reloadable(instance)); + } + } + private static class PluginManagerData { private final PluginManager manager; private final Map>> beganStages = new HashMap<>(); @@ -64,49 +71,7 @@ private void clear() { } public > Reloadable reloadable(PluginManager manager) { - return new Reloadable<>() { - private PluginManagerData data() { - return allStages.computeIfAbsent(manager, PluginManagerData::new); - } - - @Override - public void startReload() { - for (ReloadStage stage : ReloadStage.values()) { - startReload(stage); - } - } - - @Override - public void startReload(ReloadStage stage) { - synchronized (allStages) { - if (manager == PluginManager.getInstance() && stage.ordinal() == 0) { - allStages.clear(); - } - data().beganStages.put(stage, new ArrayList<>()); - } - } - - @Override - public void endReload() { - for (ReloadStage stage : ReloadStage.values()) { - endReload(stage); - } - } - - @Override - public void endReload(ReloadStage stage) { - synchronized (allStages) { - data().finishedStages.add(stage); - } - } - - @Override - public void beforeReloadable(ReloadStage stage, Reloadable other) { - synchronized (allStages) { - data().beganStages.get(stage).add(other); - } - } - }; + return new Observatory<>(manager); } public Set notVisited() { @@ -226,7 +191,55 @@ public Color getColor() { } @Override - public List getButtons() { + public List getButtons(MenuAccess access) { return Collections.emptyList(); } + + private class Observatory> implements Reloadable { + private final PluginManager manager; + + public Observatory(PluginManager manager) {this.manager = manager;} + + private PluginManagerData data() { + return allStages.computeIfAbsent(manager, PluginManagerData::new); + } + + @Override + public void startReload() { + for (ReloadStage stage : ReloadStage.values()) { + startReload(stage); + } + } + + @Override + public void startReload(ReloadStage stage) { + synchronized (allStages) { + if (manager == PluginManager.getInstance() && stage.ordinal() == 0) { + allStages.clear(); + } + data().beganStages.put(stage, new ArrayList<>()); + } + } + + @Override + public void endReload() { + for (ReloadStage stage : ReloadStage.values()) { + endReload(stage); + } + } + + @Override + public void endReload(ReloadStage stage) { + synchronized (allStages) { + data().finishedStages.add(stage); + } + } + + @Override + public void beforeReloadable(ReloadStage stage, Reloadable other) { + synchronized (allStages) { + data().beganStages.get(stage).add(other); + } + } + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchBarHighlightWatcher.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchBarHighlightWatcher.java index efaaa35d1..0d711ee4c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchBarHighlightWatcher.java +++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/SearchBarHighlightWatcher.java @@ -26,8 +26,9 @@ import me.shedaniel.math.Color; import me.shedaniel.math.Point; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.impl.client.gui.hints.HintProvider; -import me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import org.jetbrains.annotations.Nullable; @@ -38,7 +39,7 @@ public class SearchBarHighlightWatcher implements HintProvider { @Override public List provide() { - return OverlaySearchField.isHighlighting ? Collections.singletonList(new TranslatableComponent("text.rei.inventory.highlighting.enabled")) : + return ScreenOverlay.getInstance().get().isHighlighting() ? Collections.singletonList(new TranslatableComponent("text.rei.inventory.highlighting.enabled")) : Collections.emptyList(); } @@ -54,7 +55,7 @@ public Color getColor() { } @Override - public List getButtons() { + public List getButtons(MenuAccess access) { return Collections.emptyList(); } } diff --git a/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.ClientHelper b/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.ClientHelper new file mode 100644 index 000000000..f140cca3c --- /dev/null +++ b/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.ClientHelper @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.ClientHelperImpl \ No newline at end of file diff --git a/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.REIRuntime b/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.REIRuntime new file mode 100644 index 000000000..89e5aaac2 --- /dev/null +++ b/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.REIRuntime @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.REIRuntimeImpl \ No newline at end of file diff --git a/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider b/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider new file mode 100644 index 000000000..a63183fb2 --- /dev/null +++ b/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.gui.hints.HintProvider @@ -0,0 +1,2 @@ +me.shedaniel.rei.plugin.client.runtime.PluginStageExecutionWatcher +me.shedaniel.rei.plugin.client.runtime.SearchBarHighlightWatcher \ No newline at end of file diff --git a/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.impl.init.PluginDetector b/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.impl.init.PluginDetector new file mode 100644 index 000000000..971b542a3 --- /dev/null +++ b/runtime/src/main/resources/META-INF/services/me.shedaniel.rei.impl.init.PluginDetector @@ -0,0 +1 @@ +me.shedaniel.rei.impl.init.ServiceBasedPluginDetector \ No newline at end of file diff --git a/runtime/src/test/java/InputMethodTest.java b/runtime/src/test/java/InputMethodTest.java deleted file mode 100644 index 0b0ba1cb3..000000000 --- a/runtime/src/test/java/InputMethodTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 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. - */ - -import it.unimi.dsi.fastutil.ints.IntList; -import me.shedaniel.rei.impl.Internals; -import me.shedaniel.rei.impl.client.search.argument.InputMethodMatcher; -import me.shedaniel.rei.impl.client.search.method.unihan.PinyinInputMethod; -import me.shedaniel.rei.impl.client.search.method.unihan.UniHanManager; -import me.shedaniel.rei.impl.common.InternalLogger; -import org.apache.logging.log4j.Level; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import java.nio.file.Path; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class InputMethodTest { - public static final InternalLogger LOGGER = new InternalLogger() { - @Override - public void throwException(Throwable throwable) { - throwable.printStackTrace(); - } - - @Override - public void log(Level level, String message) { - System.out.println("[" + level.name() + "] " + message); - } - - @Override - public void log(Level level, String message, Throwable throwable) { - System.out.println("[" + level.name() + "] " + message); - throwable.printStackTrace(); - } - }; - - @TempDir - static Path tempDir; - - static PinyinInputMethod pinyinInputMethod; - - @BeforeAll - static void setup() { - Internals.attachInstanceSupplier(LOGGER, "logger"); - - UniHanManager manager = new UniHanManager(tempDir.resolve("unihan.zip")); - pinyinInputMethod = new PinyinInputMethod(manager); - ExecutorService service = Executors.newSingleThreadExecutor(); - pinyinInputMethod.prepare(service).join(); - service.shutdown(); - } - - void testPinyin() { - assertTrue(pinyinContains("漢", "han")); - assertTrue(pinyinContains("漢語", "hanyu")); - assertTrue(pinyinContains("漢", "ha")); - assertTrue(pinyinContains("漢語", "hayu")); - assertTrue(pinyinContains("测试文本", "ceshiwenben")); - assertTrue(pinyinContains("测试文本", "ceshiwenbe")); - assertTrue(pinyinContains("测试文本", "ceshiwben")); - assertTrue(pinyinContains("测试文本", "ceshwbe")); - assertTrue(pinyinContains("测试文本", "ce4shi4wb")); - assertFalse(pinyinContains("测试文本", "ce2shi4wb")); - assertTrue(pinyinContains("合金炉", "hejinlu")); - assertTrue(pinyinContains("洗矿场", "xikuangchang")); - assertTrue(pinyinContains("洗矿场", "xikuachang")); - assertTrue(pinyinContains("流体", "liuti")); - assertTrue(pinyinContains("轰20", "hong2")); - assertTrue(pinyinContains("hong2", "hong2")); - } - - boolean pinyinContains(String input, String substr) { - return InputMethodMatcher.contains(pinyinInputMethod, IntList.of(input.codePoints().toArray()), IntList.of(substr.codePoints().toArray())); - } -} diff --git a/settings.gradle b/settings.gradle index 937a949bf..ddcbff822 100755 --- a/settings.gradle +++ b/settings.gradle @@ -11,6 +11,34 @@ rootProject.name = "RoughlyEnoughItems" include "api" include "default-plugin" +include "shared-internals" +include "runtime-engine" +include "runtime-engine:logging" +include "runtime-engine:entry-types" +include "runtime-engine:entry-stacks" +include "runtime-engine:categories" +include "runtime-engine:configs" +include "runtime-engine:displays" +include "runtime-engine:filtering-entries" +include "runtime-engine:entries" +include "runtime-engine:screens" +include "runtime-engine:favorites" +include "runtime-engine:search" +include "runtime-engine:subsets" +include "runtime-engine:transfer-handlers" +include "runtime-engine:menu-info" +include "runtime-engine:plugins" +include "runtime-engine:views" +include "runtime-engine:default-runtime-plugin" +include "runtime-engine:initialization" +include "runtime-engine:networking" +include "runtime-frontend" +include "runtime-frontend:widgets" +include "runtime-frontend:filtering" +include "runtime-frontend:display" +include "runtime-frontend:overlay" +include "runtime-frontend:overlay-entries" +include "runtime-frontend:favorites-entries" include "runtime" include "fabric" include "forge" diff --git a/shared-internals/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerInternal.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerInternal.java new file mode 100644 index 000000000..7a60c7692 --- /dev/null +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerInternal.java @@ -0,0 +1,57 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.config; + +import me.shedaniel.autoconfig.gui.registry.GuiRegistry; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Jankson; +import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; +import me.shedaniel.rei.api.client.config.ConfigManager; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Collection; +import java.util.Collections; + +@ApiStatus.Internal +public interface ConfigManagerInternal extends ConfigManager { + /** + * @return the instance of {@link ConfigManagerInternal} + */ + static ConfigManagerInternal getInstance() { + return (ConfigManagerInternal) ConfigManager.getInstance(); + } + + Object get(String fieldKey); + + boolean set(String fieldKey, Object value); + + interface SystemSetup { + default void setup(Jankson.Builder builder) {} + + default void setup(GuiRegistry registry) {} + + default Collection> collectAdvanced() { + return Collections.emptyList(); + } + } +} diff --git a/shared-internals/src/main/java/me/shedaniel/rei/impl/client/favorites/MutableFavoritesList.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/favorites/MutableFavoritesList.java new file mode 100644 index 000000000..27ac4c940 --- /dev/null +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/favorites/MutableFavoritesList.java @@ -0,0 +1,32 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.favorites; + +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; + +import java.util.List; + +public interface MutableFavoritesList extends List { + void setAll(List entries); +} diff --git a/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/InternalCursorState.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/InternalCursorState.java new file mode 100644 index 000000000..5319924f7 --- /dev/null +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/InternalCursorState.java @@ -0,0 +1,32 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.impl.client.gui; + +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public class InternalCursorState { + public static boolean isLeftMousePressed; + public static boolean isRightMousePressed; +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/InternalTextures.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/InternalTextures.java similarity index 84% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/InternalTextures.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/InternalTextures.java index 4823008b6..4ab5c6961 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/InternalTextures.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/InternalTextures.java @@ -32,4 +32,7 @@ public class InternalTextures { public static final ResourceLocation ARROW_RIGHT_SMALL_TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/arrow_right_small.png"); public static final ResourceLocation CHEST_GUI_TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/recipecontainer.png"); public static final ResourceLocation CHEST_GUI_TEXTURE_DARK = new ResourceLocation("roughlyenoughitems", "textures/gui/recipecontainer_dark.png"); + public static final ResourceLocation DISPLAY_TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/display.png"); + public static final ResourceLocation DISPLAY_TEXTURE_DARK = new ResourceLocation("roughlyenoughitems", "textures/gui/display_dark.png"); + public static final ResourceLocation TOASTS = new ResourceLocation("roughlyenoughitems", "textures/gui/toasts.png"); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/hints/HintProvider.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/hints/HintProvider.java similarity index 89% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/hints/HintProvider.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/hints/HintProvider.java index c7697c533..475e48f44 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/hints/HintProvider.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/hints/HintProvider.java @@ -27,6 +27,8 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.impl.client.gui.menu.MenuAccess; +import me.shedaniel.rei.impl.common.Internals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.chat.Component; @@ -37,6 +39,8 @@ @Environment(EnvType.CLIENT) public interface HintProvider { + List PROVIDERS = Internals.resolveServices(HintProvider.class); + List provide(); @Nullable @@ -49,7 +53,7 @@ default Double getProgress() { Color getColor(); - List getButtons(); + List getButtons(MenuAccess access); record HintButton(Component name, Consumer action) {} } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuAccess.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/menu/MenuAccess.java similarity index 64% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuAccess.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/menu/MenuAccess.java index 3d8d6896f..79daeb3f0 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/modules/MenuAccess.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/menu/MenuAccess.java @@ -21,11 +21,11 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.modules; +package me.shedaniel.rei.impl.client.gui.menu; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; -import me.shedaniel.math.impl.PointHelper; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; import java.util.Collection; import java.util.UUID; @@ -39,24 +39,11 @@ public interface MenuAccess { boolean isInBounds(UUID uuid); - void open(UUID uuid, Menu menu); + void open(UUID uuid, Rectangle selfBounds, Supplier> menuSupplier); - void open(UUID uuid, Menu menu, Predicate or, Predicate and); + void open(UUID uuid, Rectangle selfBounds, Supplier> menuSupplier, Predicate or, Predicate and); - default void openOrClose(UUID uuid, Rectangle selfBounds, Supplier> menuSupplier) { - boolean isOpened = isOpened(uuid); - if (isOpened || !isAnyOpened()) { - boolean inBounds = (isValidPoint(PointHelper.ofMouse()) && selfBounds.contains(PointHelper.ofMouse())) || isInBounds(uuid); - if (isOpened != inBounds) { - if (inBounds) { - Menu menu = new Menu(selfBounds.clone(), menuSupplier.get(), false); - open(uuid, menu, selfBounds::contains, point -> true); - } else { - close(); - } - } - } - } + void openOrClose(UUID uuid, Rectangle selfBounds, Supplier> menuSupplier); boolean isValidPoint(Point point); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ConfigReloadingScreen.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ConfigReloadingScreen.java similarity index 96% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ConfigReloadingScreen.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ConfigReloadingScreen.java index 3d3895880..7d64bc935 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ConfigReloadingScreen.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/gui/screen/ConfigReloadingScreen.java @@ -33,10 +33,10 @@ import java.util.function.BooleanSupplier; @ApiStatus.Internal -public class ConfigReloadingScreen extends Screen { +public final class ConfigReloadingScreen extends Screen { private final Component title; private final BooleanSupplier predicate; - private Runnable parent; + private final Runnable parent; public ConfigReloadingScreen(Component title, BooleanSupplier predicate, Runnable parent) { super(NarratorChatListener.NO_TITLE); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java similarity index 97% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java index da63bc0c9..442fda91c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java @@ -43,7 +43,7 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; -public class AsyncSearchManager { +public class AsyncSearchManager implements SearchManager { private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-AsyncSearchManager").asService(); private final Supplier>> stacksProvider; private final Supplier>> additionalPredicateSupplier; @@ -58,20 +58,17 @@ public AsyncSearchManager(Supplier>> stacksProvider, Supplier this.transformer = transformer; } + @Override public void markDirty() { synchronized (AsyncSearchManager.this) { this.last = null; } } - @Nullable - public SearchFilter filter() { - return this.filter; - } - private record ExecutorTuple(SearchFilter filter, CompletableFuture>, SearchFilter>> future) { } + @Override public void updateFilter(String filter) { if (this.filter == null || !this.filter.getFilter().equals(filter)) { if (this.executor != null) { @@ -82,12 +79,14 @@ public void updateFilter(String filter) { } } + @Override public boolean isDirty() { synchronized (AsyncSearchManager.this) { return this.last == null || this.last.getValue() != this.filter; } } + @Override public Future getAsync(BiConsumer>, SearchFilter> consumer) { if (this.executor == null || this.executor.filter() != filter) { if (this.executor != null) { @@ -105,6 +104,11 @@ public Future getAsync(BiConsumer>, SearchFilter> consumer }, EXECUTOR_SERVICE))).future(); } + @Override + public List> get() { + return getNow(); + } + public List> getNow() { try { return get(Runnable::run).get().getKey(); @@ -209,7 +213,14 @@ public static CompletableFuture>, SearchFilter>> ge return CompletableFuture.completedFuture(new AbstractMap.SimpleImmutableEntry<>(Lists.newArrayList(), filter)); } + @Override public boolean matches(EntryStack stack) { return filter.test(stack); } + + @Override + @Nullable + public SearchFilter getSearchFilter() { + return filter; + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/IntRange.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/SearchManager.java similarity index 63% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/search/IntRange.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/SearchManager.java index e4d29f9c9..e57d36f4c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/IntRange.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/search/SearchManager.java @@ -23,39 +23,27 @@ package me.shedaniel.rei.impl.client.search; -import java.util.Objects; +import me.shedaniel.rei.api.client.search.SearchFilter; +import me.shedaniel.rei.api.common.entry.EntryStack; +import org.jetbrains.annotations.Nullable; -public class IntRange { - private final int min; - private final int max; - - private IntRange(int min, int max) { - this.min = min; - this.max = max; - } +import java.util.List; +import java.util.concurrent.Future; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public interface SearchManager extends Supplier>> { + void markDirty(); - public static IntRange of(int min, int max) { - return new IntRange(min, max); - } + void updateFilter(String filter); - public int min() { - return min; - } + boolean isDirty(); - public int max() { - return max; - } + Future getAsync(BiConsumer>, SearchFilter> consumer); - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - IntRange intRange = (IntRange) o; - return min == intRange.min && max == intRange.max; - } + boolean matches(EntryStack stack); - @Override - public int hashCode() { - return Objects.hash(min, max); - } + @Nullable + SearchFilter getSearchFilter(); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java similarity index 94% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java index bea5a7669..96c4fd177 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java @@ -24,7 +24,7 @@ package me.shedaniel.rei.impl.client.util; import me.shedaniel.rei.api.client.gui.Renderer; -import me.shedaniel.rei.impl.client.gui.widget.CatchingExceptionUtils; +import me.shedaniel.rei.impl.client.ClientInternals; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; @@ -69,6 +69,6 @@ public static ReportedException throwReport(CrashReport report) { } public static void catchReport(CrashReport report) { - CatchingExceptionUtils.handleThrowable(new ReportedException(report), report.getTitle()); + ClientInternals.crash(new ReportedException(report), report.getTitle()); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/REIModMenuEntryPoint.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/InternalEntryBounds.java similarity index 79% rename from runtime/src/main/java/me/shedaniel/rei/REIModMenuEntryPoint.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/InternalEntryBounds.java index cba2abecc..ca5d88e28 100644 --- a/runtime/src/main/java/me/shedaniel/rei/REIModMenuEntryPoint.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/InternalEntryBounds.java @@ -21,13 +21,15 @@ * SOFTWARE. */ -package me.shedaniel.rei; +package me.shedaniel.rei.impl.client.util; -import dev.architectury.platform.Platform; -import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.config.ConfigObject; +import net.minecraft.util.Mth; -public class REIModMenuEntryPoint { - public void onInitializeClient() { - Platform.getMod("roughlyenoughitems").registerConfigurationScreen(ConfigManager.getInstance()::getConfigScreen); +public class InternalEntryBounds { + private static final int SIZE = 18; + + public static int entrySize() { + return Mth.ceil(SIZE * ConfigObject.getInstance().getEntrySize()); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/text/TextTransformations.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/TextTransformations.java similarity index 98% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/gui/text/TextTransformations.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/TextTransformations.java index 245356770..44f621722 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/text/TextTransformations.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/TextTransformations.java @@ -21,7 +21,7 @@ * SOFTWARE. */ -package me.shedaniel.rei.impl.client.gui.text; +package me.shedaniel.rei.impl.client.util; import me.shedaniel.math.Color; import net.minecraft.Util; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/client/util/ThreadCreator.java diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/util/HashedEntryStackWrapper.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/common/util/HashedEntryStackWrapper.java similarity index 96% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/util/HashedEntryStackWrapper.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/common/util/HashedEntryStackWrapper.java index 401f9a174..9803c1797 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/common/util/HashedEntryStackWrapper.java +++ b/shared-internals/src/main/java/me/shedaniel/rei/impl/common/util/HashedEntryStackWrapper.java @@ -25,14 +25,11 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.EntryStacks; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; import org.jetbrains.annotations.ApiStatus; import java.util.Objects; @ApiStatus.Internal -@Environment(EnvType.CLIENT) public class HashedEntryStackWrapper { private final EntryStack stack; private long hash; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/util/RectangleUtils.java b/shared-internals/src/main/java/me/shedaniel/rei/impl/common/util/RectangleUtils.java similarity index 100% rename from runtime/src/main/java/me/shedaniel/rei/impl/common/util/RectangleUtils.java rename to shared-internals/src/main/java/me/shedaniel/rei/impl/common/util/RectangleUtils.java