From 9954713e457a5a5d80025432961b56ab0003bbb0 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Thu, 28 Jul 2022 01:39:41 +0800 Subject: More work on config module --- .../rei/impl/client/config/ConfigManagerImpl.java | 59 +--- .../rei/impl/client/config/ConfigObjectImpl.java | 10 +- .../config/entries/RecipeScreenTypeEntry.java | 1 - .../client/config/entries/ReloadPluginsEntry.java | 118 ++++++++ .../entries/UncertainDisplayViewingScreen.java | 304 +++++++++++++++++++++ .../client/gui/credits/CreditsEntryListWidget.java | 216 +++++++++++++++ .../rei/impl/client/gui/credits/CreditsScreen.java | 165 +++++++++++ .../favorites/FavoriteEntryTypeRegistryImpl.java | 4 +- .../widget/favorites/FavoritesEntriesManager.java | 29 +- ...pl.ClientInternals$FavoritesEntriesListProvider | 1 + .../config/entries/FilteringAddRuleScreen.java | 26 +- .../config/entries/FilteringConfigEntries.java | 79 ++++++ .../impl/client/config/entries/FilteringEntry.java | 8 +- .../config/entries/FilteringRuleOptionsScreen.java | 23 +- .../config/entries/FilteringRulesScreen.java | 24 +- .../entry/filtering/AbstractFilteringRule.java | 8 +- .../client/entry/filtering/FilteringCache.java | 5 +- .../client/entry/filtering/FilteringCacheImpl.java | 7 +- .../client/entry/filtering/FilteringContext.java | 1 - .../entry/filtering/FilteringContextType.java | 3 + .../client/entry/filtering/FilteringResult.java | 1 - .../impl/client/entry/filtering/FilteringRule.java | 86 ------ .../entry/filtering/FilteringRuleInternal.java | 18 ++ .../client/entry/filtering/FilteringRuleType.java | 54 ++++ .../entry/filtering/rules/ManualFilteringRule.java | 61 +---- .../filtering/rules/ManualFilteringRuleType.java | 58 ++++ .../entry/filtering/rules/SearchFilteringRule.java | 181 +----------- .../filtering/rules/SearchFilteringRuleType.java | 179 ++++++++++++ .../entry/type/PreFilteredEntryListImpl.java | 5 +- .../runtime/FilteredStacksVisibilityHandler.java | 3 + ...client.config.ConfigManagerInternal$SystemSetup | 1 + 31 files changed, 1313 insertions(+), 425 deletions(-) create mode 100644 runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java create mode 100644 runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/UncertainDisplayViewingScreen.java create mode 100644 runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java create mode 100644 runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java create mode 100644 runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.ClientInternals$FavoritesEntriesListProvider create mode 100644 runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/config/entries/FilteringConfigEntries.java delete mode 100644 runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringRule.java create mode 100644 runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringRuleInternal.java create mode 100644 runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/FilteringRuleType.java create mode 100644 runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/ManualFilteringRuleType.java create mode 100644 runtime-engine/filtering-entries/src/main/java/me/shedaniel/rei/impl/client/entry/filtering/rules/SearchFilteringRuleType.java create mode 100644 runtime-engine/filtering-entries/src/main/resources/META-INF/services/me.shedaniel.rei.impl.client.config.ConfigManagerInternal$SystemSetup (limited to 'runtime-engine') diff --git a/runtime-engine/configs/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 index 2970c5b62..df956d185 100644 --- a/runtime-engine/configs/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,7 +23,6 @@ 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; @@ -51,6 +50,7 @@ import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigManager; import me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry; import me.shedaniel.rei.api.client.config.entry.EntryStackProvider; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRule; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.config.CheatingMode; import me.shedaniel.rei.api.client.gui.config.DisplayScreenType; @@ -58,14 +58,11 @@ import me.shedaniel.rei.api.client.gui.config.SyntaxHighlightingMode; import me.shedaniel.rei.api.client.overlay.ScreenOverlay; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; 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.Internals; import me.shedaniel.rei.impl.client.config.addon.ConfigAddonRegistryImpl; import me.shedaniel.rei.impl.client.config.entries.*; -import me.shedaniel.rei.impl.client.entry.filtering.FilteringRule; import me.shedaniel.rei.impl.client.entry.filtering.rules.ManualFilteringRule; -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; @@ -88,7 +85,6 @@ 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; @@ -123,18 +119,9 @@ public class ConfigManagerImpl implements ConfigManagerInternal { 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); + for (SystemSetup setup : Internals.resolveServices(SystemSetup.class)) { + setup.setup(guiRegistry); + } InternalLogger.getInstance().info("Config loaded"); saveConfig(); } @@ -234,32 +221,6 @@ public class ConfigManagerImpl implements ConfigManagerInternal { } }); - // FilteringRule - builder.registerSerializer(FilteringRule.class, (value, marshaller) -> { - try { - return marshaller.serialize(FilteringRule.save(value, new CompoundTag())); - } catch (Exception e) { - e.printStackTrace(); - return JsonNull.INSTANCE; - } - }); - builder.registerDeserializer(Tag.class, FilteringRule.class, (value, marshaller) -> { - try { - return FilteringRule.read((CompoundTag) value); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - }); - builder.registerDeserializer(String.class, FilteringRule.class, (value, marshaller) -> { - try { - return FilteringRule.read(TagParser.parseTag(value)); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - }); - // FavoriteEntry builder.registerSerializer(FavoriteEntry.class, (value, marshaller) -> { try { @@ -282,6 +243,10 @@ public class ConfigManagerImpl implements ConfigManagerInternal { } }); + for (SystemSetup setup : Internals.resolveServices(SystemSetup.class)) { + setup.setup(builder); + } + return builder.build(); } @@ -295,7 +260,7 @@ public class ConfigManagerImpl implements ConfigManagerInternal { @Override public void saveConfig() { - if (getConfig().getFilteringRules().stream().noneMatch(filteringRule -> filteringRule instanceof ManualFilteringRule)) { + if (getConfig().getFilteringRules().stream().noneMatch(FilteringRule::isManual)) { getConfig().getFilteringRules().add(new ManualFilteringRule()); } AutoConfig.getConfigHolder(ConfigObjectImpl.class).registerLoadListener((configHolder, configObject) -> { @@ -427,8 +392,8 @@ public class ConfigManagerImpl implements ConfigManagerInternal { 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(); }); diff --git a/runtime-engine/configs/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 index d0b63a1ff..ae2008f0a 100644 --- a/runtime-engine/configs/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 @@ -33,10 +33,10 @@ import me.shedaniel.clothconfig2.api.Modifier; import me.shedaniel.clothconfig2.api.ModifierKeyCode; 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.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.config.*; -import me.shedaniel.rei.impl.client.entry.filtering.FilteringRule; -import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesEntriesManager; +import me.shedaniel.rei.impl.ClientInternals; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; @@ -341,7 +341,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { @Override public List getFavoriteEntries() { - return FavoritesEntriesManager.INSTANCE.asListView(); + return ClientInternals.getFavoritesEntriesList(); } public List getConfigFavoriteEntries() { @@ -368,7 +368,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { } @ApiStatus.Internal - public List> getFilteringRules() { + public List getFilteringRules() { return advanced.filtering.filteringRules; } @@ -652,7 +652,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData { 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<>(); } } } diff --git a/runtime-engine/configs/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 index bc37f2a35..514f8bd3f 100644 --- a/runtime-engine/configs/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.platform.Window; 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-engine/configs/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 new file mode 100644 index 000000000..45ab4ef4e --- /dev/null +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/ReloadPluginsEntry.java @@ -0,0 +1,118 @@ +/* + * 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.ImmutableList; +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 net.minecraft.client.Minecraft; +import net.minecraft.client.gui.chat.NarratorChatListener; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.util.Unit; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; +import java.util.Optional; + +@ApiStatus.Internal +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); + }) { + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + if (PluginManager.areAnyReloading()) { + Screen screen = Minecraft.getInstance().screen; + Minecraft.getInstance().setScreen(new ConfigReloadingScreen(new TranslatableComponent("text.rei.config.is.reloading"), PluginManager::areAnyReloading, () -> Minecraft.getInstance().setScreen(screen))); + } else { + super.render(matrices, mouseX, mouseY, delta); + } + } + }; + private AbstractWidget reloadSearchButton = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> { + SearchProvider.getInstance().clearCache(); + }); + private List children = ImmutableList.of(reloadPluginsButton, reloadSearchButton); + + public ReloadPluginsEntry(int width) { + super(NarratorChatListener.NO_TITLE, false); + this.width = width; + reloadPluginsButton.setMessage(new TranslatableComponent("text.rei.reload_config")); + reloadSearchButton.setMessage(new TranslatableComponent("text.rei.reload_search")); + } + + @Override + public Unit getValue() { + return Unit.INSTANCE; + } + + @Override + public Optional getDefaultValue() { + return Optional.of(Unit.INSTANCE); + } + + @Override + public void save() { + + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { + super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta); + Window window = Minecraft.getInstance().getWindow(); + this.reloadPluginsButton.active = this.isEditable(); + this.reloadPluginsButton.y = y; + 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() && SearchProvider.getInstance().hasCache(); + this.reloadSearchButton.y = y; + this.reloadSearchButton.setWidth(width / 2 - 2); + this.reloadSearchButton.x = x + entryWidth / 2 + 2; + this.reloadSearchButton.render(matrices, mouseX, mouseY, delta); + } + + @Override + public List children() { + return children; + } + + @Override + public List narratables() { + return children; + } +} diff --git a/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/UncertainDisplayViewingScreen.java b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/UncertainDisplayViewingScreen.java new file mode 100644 index 000000000..96c3542c6 --- /dev/null +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/config/entries/UncertainDisplayViewingScreen.java @@ -0,0 +1,304 @@ +/* + * 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 com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import dev.architectury.platform.Platform; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import me.shedaniel.clothconfig2.api.ScissorsHandler; +import me.shedaniel.clothconfig2.api.animator.NumberAnimator; +import me.shedaniel.clothconfig2.api.animator.ValueAnimator; +import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget; +import me.shedaniel.clothconfig2.impl.EasingMethod; +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.ConfigObject; +import me.shedaniel.rei.api.client.gui.config.DisplayScreenType; +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.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.ConfigManagerInternal; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.chat.NarratorChatListener; +import net.minecraft.client.gui.components.AbstractSliderButton; +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.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@ApiStatus.Internal +public class UncertainDisplayViewingScreen extends Screen { + private static final ResourceLocation DEFAULT = new ResourceLocation("roughlyenoughitems", "textures/gui/screenshot_default.png"); + private static final ResourceLocation COMPOSITE = new ResourceLocation("roughlyenoughitems", "textures/gui/screenshot_composite.png"); + private final List widgets; + protected long start; + protected long duration; + private boolean isSet; + private boolean original; + private double frame = 0; + private double target = 0; + private BooleanConsumer callback; + private Button button; + private Screen parent; + private Widget slider; + private boolean showTips; + public NumberAnimator scroll = ValueAnimator.ofDouble(); + private List allModsUsingJEI = null; + private boolean jeiEnabled = false; + + public UncertainDisplayViewingScreen(Screen parent, DisplayScreenType type, boolean showTips, BooleanConsumer callback) { + super(ImmutableTextComponent.EMPTY); + this.widgets = Lists.newArrayList(); + if (type == DisplayScreenType.UNSET) { + this.isSet = false; + this.original = true; + } else { + this.isSet = true; + this.original = type == DisplayScreenType.ORIGINAL; + moveFrameTo(original ? 0 : 1, false, 0); + } + this.scroll.setAs(0); + this.callback = callback; + this.parent = parent; + this.showTips = showTips; + if (showTips && false && Platform.isForge()) { + this.jeiEnabled = ConfigObject.getInstance().isJEICompatibilityLayerEnabled(); + allModsUsingJEI = ClientInternals.getJeiCompatMods().stream() + .distinct() + .map(ClientHelper.getInstance()::getModFromModId) + .collect(Collectors.toList()); + } + } + + public final double clamp(double v) { + return clamp(v, 30); + } + + public final double clamp(double v, double clampExtension) { + return Mth.clamp(v, -clampExtension, 1 + clampExtension); + } + + private void moveFrameTo(double value, boolean animated, long duration) { + target = clamp(value); + + if (animated) { + start = System.currentTimeMillis(); + this.duration = duration; + } else { + frame = target; + } + } + + @Override + public void init() { + this.children().clear(); + this.widgets.clear(); + this._children().add(button = Widgets.createButton(new Rectangle(width / 2 - 100, height - 40, 200, 20), NarratorChatListener.NO_TITLE) + .onRender((matrices, button) -> { + button.setEnabled(isSet); + if (scroll.target() != 0 && allModsUsingJEI != null) { + button.setText(new TranslatableComponent("gui.done")); + } else { + button.setText(isSet ? new TranslatableComponent("text.rei.select") : new TranslatableComponent("config.roughlyenoughitems.recipeScreenType.unset")); + } + }) + .onClick(button -> { + if (scroll.target() == 0 && allModsUsingJEI != null) { + scroll.setTo(200, 450); + } else if (allModsUsingJEI != null && jeiEnabled) { + ConfigManagerInternal.getInstance().set("advanced.enableJeiCompatibilityLayer", jeiEnabled); + Minecraft.getInstance().setScreen(REIRuntime.getInstance().getPreviousScreen()); + } else { + callback.accept(original); + } + })); + this.widgets.add(transformScroll(new ScreenTypeSelection(width / 2 - 200 - 5, height / 2 - 112 / 2 - 10, DisplayScreenType.ORIGINAL))); + this.widgets.add(transformScroll(Widgets.createLabel(new Point(width / 2 - 200 - 5 + 104, height / 2 - 112 / 2 + 115), new TranslatableComponent("config.roughlyenoughitems.recipeScreenType.original")).noShadow().color(-1124073473))); + this.widgets.add(transformScroll(new ScreenTypeSelection(width / 2 + 5, height / 2 - 112 / 2 - 10, DisplayScreenType.COMPOSITE))); + this.widgets.add(transformScroll(Widgets.createLabel(new Point(width / 2 + 5 + 104, height / 2 - 112 / 2 + 115), new TranslatableComponent("config.roughlyenoughitems.recipeScreenType.composite")).noShadow().color(-1124073473))); + this.widgets.add(slider = transformScroll(Widgets.wrapVanillaWidget(new AbstractSliderButton(width / 2 - 100, height * 2 - 64, 200, 20, new TranslatableComponent("text.rei.jei_compat.false"), 0) { + @Override + protected void updateMessage() { + setMessage(new TranslatableComponent("text.rei.jei_compat." + (jeiEnabled = value == 1f))); + } + + @Override + protected void applyValue() { + + } + + @Override + public void renderButton(PoseStack poseStack, int i, int j, float f) { + y = UncertainDisplayViewingScreen.this.height * 2 - 64; + super.renderButton(poseStack, i, j, f); + y = UncertainDisplayViewingScreen.this.height * 2 - 64 - (int) (scroll.floatValue() / 200f * height); + } + }))); + this._children().addAll(widgets); + } + + public List _children() { + return (List) children(); + } + + private Widget transformScroll(Widget widget) { + return Widgets.withTranslate(widget, () -> Matrix4f.createTranslateMatrix(0, -(scroll.floatValue() / 200f * height), 0)); + } + + @Override + public void render(PoseStack matrices, int int_1, int int_2, float float_1) { + scroll.update(float_1); + if (this.minecraft.level != null) { + renderBackground(matrices); + } else { + this.fillGradient(matrices, 0, 0, this.width, this.height, -16777216, -16777216); + } + if (scroll.target() == 0) { + drawCenteredString(matrices, this.font, new TranslatableComponent("text.rei.recipe_screen_type.selection"), this.width / 2, 20, 16777215); + } else { + drawCenteredString(matrices, this.font, new TranslatableComponent("text.rei.jei_compat"), this.width / 2, 20, 16777215); + } + ScissorsHandler.INSTANCE.scissor(new Rectangle(0, 20 + font.lineHeight + 2, width, height - 42)); + if (showTips) { + float i = 32 - (scroll.floatValue() / 200f * height); + for (FormattedCharSequence s : this.font.split(new TranslatableComponent("text.rei.recipe_screen_type.selection.sub").withStyle(ChatFormatting.GRAY), width - 30)) { + font.drawShadow(matrices, s, width / 2 - font.width(s) / 2, i, -1); + i += 10; + } + if (allModsUsingJEI != null) { + i = 32 + height - (scroll.floatValue() / 200f * height); + for (FormattedCharSequence s : this.font.split(new TranslatableComponent("text.rei.jei_compat.sub", new TranslatableComponent("text.rei.jei_compat.sub.stability"), + new TextComponent(String.join(", ", allModsUsingJEI))).withStyle(ChatFormatting.GRAY), width - 30)) { + font.drawShadow(matrices, s, width / 2 - font.width(s) / 2, i, -1); + i += 10; + } + } + } + super.render(matrices, int_1, int_2, float_1); + for (Widget widget : widgets) { + widget.render(matrices, int_1, int_2, float_1); + } + if (isSet) { + matrices.pushPose(); + matrices.translate(0, -(scroll.floatValue() / 200f * height), 0); + updateFramePosition(float_1); + int x = (int) (width / 2 - 205 + (210 * frame)); + int y = height / 2 - 112 / 2 - 10; + fillGradient(matrices, x - 2, y - 4, x - 6 + 208, y - 4 + 2, -1778384897, -1778384897); + fillGradient(matrices, x - 2, y - 4 + 126 - 2, x - 6 + 208, y - 4 + 126, -1778384897, -1778384897); + fillGradient(matrices, x - 4, y - 4, x - 4 + 2, y - 4 + 126, -1778384897, -1778384897); + fillGradient(matrices, x - 4 + 208 - 2, y - 4, x - 4 + 208, y - 4 + 126, -1778384897, -1778384897); + matrices.popPose(); + } + ScissorsHandler.INSTANCE.removeLastScissor(); + button.render(matrices, int_1, int_2, float_1); + } + + private void updateFramePosition(float delta) { + target = clamp(target); + if (!DynamicNewSmoothScrollingEntryListWidget.Precision.almostEquals(frame, target, DynamicNewSmoothScrollingEntryListWidget.Precision.FLOAT_EPSILON)) + frame = ease(frame, target, Math.min((System.currentTimeMillis() - start) / (double) duration * delta * 3.0D, 1)); + else + frame = target; + } + + private double ease(double start, double end, double amount) { + return start + (end - start) * EasingMethod.EasingMethodImpl.LINEAR.apply(amount); + } + + @Override + public boolean keyPressed(int int_1, int int_2, int int_3) { + if (int_1 == 256 || this.minecraft.options.keyInventory.matches(int_1, int_2)) { + Minecraft.getInstance().setScreen(parent); + if (parent instanceof AbstractContainerScreen) { + REIRuntime.getInstance().getOverlay().get().queueReloadOverlay(); + } + return true; + } + return super.keyPressed(int_1, int_2, int_3); + } + + @Override + public boolean mouseDragged(double d, double e, int i, double f, double g) { + return slider.mouseDragged(d, e, i, f, g) || super.mouseDragged(d, e, i, f, g); + } + + public class ScreenTypeSelection extends WidgetWithBounds { + private final DisplayScreenType type; + private Rectangle bounds; + + public ScreenTypeSelection(int x, int y, DisplayScreenType type) { + this.type = type; + this.bounds = new Rectangle(x - 4 + 16, y - 4, 176 + 8, 120 + 8); + } + + @Override + public Rectangle getBounds() { + return bounds; + } + + @Override + public void render(PoseStack matrices, int i, int i1, float delta) { + RenderSystem.setShaderTexture(0, type == DisplayScreenType.ORIGINAL ? DEFAULT : COMPOSITE); + blit(matrices, bounds.x + (type == DisplayScreenType.ORIGINAL ? 8 : 4), bounds.y + 4, bounds.width - 8, bounds.height - 8, 113, type == DisplayScreenType.ORIGINAL ? 16 : 27, 854 - 113 * 2, 480 - 27 * 2, 854, 480); + } + + @Override + public boolean mouseClicked(double double_1, double double_2, int int_1) { + if (containsMouse(double_1, double_2)) { + original = (type == DisplayScreenType.ORIGINAL); + if (!isSet) { + moveFrameTo(original ? 0 : 1, false, 0); + } + isSet = true; + moveFrameTo(original ? 0 : 1, true, 500); + return true; + } + return false; + } + + @Override + public List children() { + return Collections.emptyList(); + } + } +} diff --git a/runtime-engine/configs/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 new file mode 100644 index 000000000..9a576014c --- /dev/null +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java @@ -0,0 +1,216 @@ +/* + * 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.credits; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.clothconfig2.gui.widget.DynamicSmoothScrollingEntryListWidget; +import me.shedaniel.rei.impl.client.gui.text.TextTransformations; +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.FormattedCharSequence; +import org.jetbrains.annotations.ApiStatus; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.List; + +@ApiStatus.Internal +public class CreditsEntryListWidget extends DynamicSmoothScrollingEntryListWidget { + private boolean inFocus; + + public CreditsEntryListWidget(Minecraft client, int width, int height, int startY, int endY) { + super(client, width, height, startY, endY, GuiComponent.BACKGROUND_LOCATION); + } + + @Override + public boolean changeFocus(boolean boolean_1) { + if (!this.inFocus && this.getItemCount() == 0) { + return false; + } else { + this.inFocus = !this.inFocus; + if (this.inFocus && this.getFocused() == null && this.getItemCount() > 0) { + this.moveSelection(1); + } else if (this.inFocus && this.getFocused() != null) { + this.moveSelection(0); + } + + return this.inFocus; + } + } + + public void creditsClearEntries() { + clearItems(); + } + + private CreditsItem rei_getEntry(int index) { + return this.children().get(index); + } + + public void creditsAddEntry(CreditsItem entry) { + addItem(entry); + } + + @Override + public int getItemWidth() { + return width - 80; + } + + @Override + protected int getScrollbarPosition() { + return width - 40; + } + + public static abstract class CreditsItem extends DynamicSmoothScrollingEntryListWidget.Entry { + @Override + public List narratables() { + return Collections.emptyList(); + } + } + + public static class TextCreditsItem extends CreditsItem { + private Component text; + + public TextCreditsItem(Component text) { + this.text = text; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { + Minecraft.getInstance().font.drawShadow(matrices, text.getVisualOrderText(), x + 5, y + 5, -1); + } + + @Override + public int getItemHeight() { + return 12; + } + + @Override + public boolean changeFocus(boolean boolean_1) { + return false; + } + } + + public static class TranslationCreditsItem extends CreditsItem { + private Component language; + private List translators; + private int maxWidth; + + public TranslationCreditsItem(Component language, Component translators, int width, int maxWidth) { + this.language = language; + this.translators = Minecraft.getInstance().font.split(translators, width); + this.maxWidth = maxWidth; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { + Minecraft.getInstance().font.drawShadow(matrices, language.getVisualOrderText(), x + 5, y + 5, -1); + int yy = y + 5; + for (FormattedCharSequence translator : translators) { + Minecraft.getInstance().font.drawShadow(matrices, translator, x + 5 + maxWidth, yy, -1); + yy += 12; + } + } + + @Override + public int getItemHeight() { + return 12 * translators.size(); + } + + @Override + public boolean changeFocus(boolean boolean_1) { + return false; + } + } + + public static class LinkItem extends CreditsItem { + private Component text; + private List textSplit; + private String link; + private boolean contains; + private boolean rainbow; + + public LinkItem(Component text, String link, int width, boolean rainbow) { + this.text = text; + this.textSplit = Minecraft.getInstance().font.split(text, width); + this.link = link; + this.rainbow = rainbow; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { + contains = mouseX >= x && mouseX <= x + entryWidth && mouseY >= y && mouseY <= y + entryHeight; + if (contains) { + Minecraft.getInstance().screen.renderTooltip(matrices, new TextComponent("Click to open link."), mouseX, mouseY); + int yy = y; + for (FormattedCharSequence textSp : textSplit) { + FormattedCharSequence underlined = characterVisitor -> { + return textSp.accept((charIndex, style, codePoint) -> characterVisitor.accept(charIndex, style.applyFormat(ChatFormatting.UNDERLINE), codePoint)); + }; + if (rainbow) underlined = TextTransformations.applyRainbow(underlined, x + 5, yy); + Minecraft.getInstance().font.drawShadow(matrices, underlined, x + 5, yy, 0xff1fc3ff); + yy += 12; + } + } else { + int yy = y; + for (FormattedCharSequence textSp : textSplit) { + if (rainbow) textSp = TextTransformations.applyRainbow(textSp, x + 5, yy); + Minecraft.getInstance().font.drawShadow(matrices, textSp, x + 5, yy, 0xff1fc3ff); + yy += 12; + } + } + } + + @Override + public int getItemHeight() { + return 12 * textSplit.size(); + } + + @Override + public boolean changeFocus(boolean boolean_1) { + return false; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (contains && button == 0) { + Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + try { + Util.getPlatform().openUri(new URI(link)); + return true; + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + return false; + } + } +} diff --git a/runtime-engine/configs/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 new file mode 100644 index 000000000..8ca4fe7ef --- /dev/null +++ b/runtime-engine/configs/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.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.client.gui.credits; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import dev.architectury.platform.Platform; +import me.shedaniel.rei.api.common.util.ImmutableTextComponent; +import me.shedaniel.rei.impl.client.gui.credits.CreditsEntryListWidget.TextCreditsItem; +import me.shedaniel.rei.impl.client.gui.credits.CreditsEntryListWidget.TranslationCreditsItem; +import net.minecraft.ChatFormatting; +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.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; +import net.minecraft.util.Tuple; +import org.jetbrains.annotations.ApiStatus; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +@ApiStatus.Internal +public class CreditsScreen extends Screen { + private Screen parent; + private AbstractButton buttonDone; + private CreditsEntryListWidget entryListWidget; + + public CreditsScreen(Screen parent) { + super(new TextComponent("")); + this.parent = parent; + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (keyCode == 256 && this.shouldCloseOnEsc()) { + openPrevious(); + return true; + } + return super.keyPressed(keyCode, scanCode, modifiers); + } + + public static class TranslatorEntry { + private final String name; + private final boolean proofreader; + + public TranslatorEntry(String name) { + this(name, false); + } + + public TranslatorEntry(String name, boolean proofreader) { + this.name = name; + this.proofreader = proofreader; + } + + public String getName() { + return name; + } + } + + @Override + public void init() { + addWidget(entryListWidget = new CreditsEntryListWidget(minecraft, width, height, 32, height - 32)); + entryListWidget.creditsClearEntries(); + List>> translators = Lists.newArrayList(); + Exception[] exception = {null}; + fillTranslators(exception, translators); + List>> translatorsMapped = translators.stream().map(pair -> { + return new Tuple<>( + " " + (I18n.exists("language.roughlyenoughitems." + pair.getA().toLowerCase(Locale.ROOT).replace(' ', '_')) ? I18n.get("language.roughlyenoughitems." + pair.getA().toLowerCase(Locale.ROOT).replace(' ', '_')) : pair.getA()), + pair.getB() + ); + }).collect(Collectors.toList()); + int i = width - 80 - 6; + for (String line : String.format("§lRoughly Enough Items (v%s)\n§7Originally a fork for Almost Enough Items.\n\n§lLanguage Translation\n%s\n\n§lLicense\n§7Roughly Enough Items is licensed under MIT.", Platform.getMod("roughlyenoughitems").getVersion(), "%translators%").split("\n")) + if (line.equalsIgnoreCase("%translators%")) { + if (exception[0] != null) { + entryListWidget.creditsAddEntry(new TextCreditsItem(new ImmutableTextComponent("Failed to get translators: " + exception[0].toString()))); + for (StackTraceElement traceElement : exception[0].getStackTrace()) + entryListWidget.creditsAddEntry(new TextCreditsItem(new ImmutableTextComponent(" at " + traceElement))); + } else { + int maxWidth = translatorsMapped.stream().mapToInt(pair -> font.width(pair.getA())).max().orElse(0) + 5; + for (Tuple> pair : translatorsMapped) { + MutableComponent text = new TextComponent(""); + boolean isFirst = true; + for (TranslatorEntry entry : pair.getB()) { + if (!isFirst) { + text = text.append(new TextComponent(", ")); + } + isFirst = false; + MutableComponent component = new TextComponent(entry.getName()); + if (entry.proofreader) + component = component.withStyle(ChatFormatting.GOLD); + text = text.append(component); + } + entryListWidget.creditsAddEntry(new TranslationCreditsItem(new TranslatableComponent(pair.getA()), text, i - maxWidth - 10, maxWidth)); + } + } + } else entryListWidget.creditsAddEntry(new TextCreditsItem(new ImmutableTextComponent(line))); + entryListWidget.creditsAddEntry(new TextCreditsItem(NarratorChatListener.NO_TITLE)); + entryListWidget.creditsAddEntry(new CreditsEntryListWidget.LinkItem(new ImmutableTextComponent("Visit the project at GitHub."), "https://www.github.com/shedaniel/RoughlyEnoughItems", entryListWidget.getItemWidth(), false)); + entryListWidget.creditsAddEntry(new CreditsEntryListWidget.LinkItem(new ImmutableTextComponent("Visit the project page at CurseForge."), "https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items", entryListWidget.getItemWidth(), false)); + entryListWidget.creditsAddEntry(new CreditsEntryListWidget.LinkItem(new ImmutableTextComponent("Support the project via Patreon!"), "https://patreon.com/shedaniel", entryListWidget.getItemWidth(), true)); + entryListWidget.creditsAddEntry(new TextCreditsItem(NarratorChatListener.NO_TITLE)); + addRenderableWidget(buttonDone = new Button(width / 2 - 100, height - 26, 200, 20, new TranslatableComponent("gui.done"), button -> openPrevious())); + } + + 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")) + .getDeclaredMethod("fillTranslators", Exception[].class, List.class) + .invoke(null, exception, translators); + } catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private void openPrevious() { + Minecraft.getInstance().setScreen(parent); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + if (entryListWidget.mouseScrolled(mouseX, mouseY, amount)) + return true; + return super.mouseScrolled(mouseX, mouseY, amount); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + this.renderDirtBackground(0); + this.entryListWidget.render(matrices, mouseX, mouseY, delta); + drawCenteredString(matrices, this.font, I18n.get("text.rei.credits"), this.width / 2, 16, 16777215); + super.render(matrices, mouseX, mouseY, delta); + } + +} diff --git a/runtime-engine/favorites/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 index 39de487d9..6cd8ffb24 100644 --- a/runtime-engine/favorites/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 @@ -107,8 +107,8 @@ public class FavoriteEntryTypeRegistryImpl implements FavoriteEntryType.Registry @Override public void endReload() { if (ConfigObject.getInstance().isFavoritesEnabled()) { - FavoritesEntriesManager.INSTANCE.getConfigFavoriteEntries().removeIf(FavoriteEntry::isInvalid); - FavoritesEntriesManager.INSTANCE.getConfigHiddenFavoriteEntries().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 index 2f92bc197..40f1de3a7 100644 --- 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 @@ -30,6 +30,7 @@ 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.ClientInternals; import me.shedaniel.rei.impl.client.config.ConfigManagerInternal; import me.shedaniel.rei.impl.client.favorites.MutableFavoritesList; @@ -40,25 +41,24 @@ 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(); +public class FavoritesEntriesManager implements ClientInternals.FavoritesEntriesListProvider { - public List getConfigFavoriteEntries() { + public static List getConfigFavoriteEntries() { ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); return (List) manager.get("basics.favorites"); } - public List getConfigHiddenFavoriteEntries() { + public static List getConfigHiddenFavoriteEntries() { ConfigManagerInternal manager = ConfigManagerInternal.getInstance(); return (List) manager.get("basics.hiddenFavorites"); } - private Stream getDefaultFavorites() { + private static Stream getDefaultFavorites() { return StreamSupport.stream(FavoriteEntryType.registry().sections().spliterator(), false) .flatMap(section -> section.getDefaultEntries().stream()); } - public List getFavorites() { + public static List getFavorites() { List defaultFavorites = getDefaultFavorites().collect(Collectors.toList()); defaultFavorites.removeAll(getConfigHiddenFavoriteEntries()); @@ -69,7 +69,7 @@ public class FavoritesEntriesManager { return favorites; } - public void remove(FavoriteEntry entry) { + public static void remove(FavoriteEntry entry) { getConfigFavoriteEntries().remove(entry); if (getDefaultFavorites().anyMatch(e -> e.equals(entry)) && !getConfigHiddenFavoriteEntries().contains(entry)) { getConfigHiddenFavoriteEntries().add(entry); @@ -79,7 +79,7 @@ public class FavoritesEntriesManager { REIRuntime.getInstance().getOverlay().flatMap(ScreenOverlay::getFavoritesList).ifPresent(OverlayListWidget::queueReloadSearch); } - public void add(FavoriteEntry entry) { + public static void add(FavoriteEntry entry) { List defaultFavorites = getDefaultFavorites().toList(); getConfigFavoriteEntries().remove(entry); @@ -103,7 +103,7 @@ public class FavoritesEntriesManager { REIRuntime.getInstance().getOverlay().flatMap(ScreenOverlay::getFavoritesList).ifPresent(OverlayListWidget::queueReloadSearch); } - public void setEntries(List entries) { + public static void setEntries(List entries) { List defaultFavorites = getDefaultFavorites().toList(); List hiddenDefaultFavorites = new ArrayList<>(defaultFavorites); hiddenDefaultFavorites.removeAll(entries); @@ -116,11 +116,12 @@ public class FavoritesEntriesManager { REIRuntime.getInstance().getOverlay().flatMap(ScreenOverlay::getFavoritesList).ifPresent(OverlayListWidget::queueReloadSearch); } - public List asListView() { + @Override + public List get() { return new ListView(); } - private class ListView extends AbstractList implements MutableFavoritesList { + private static class ListView extends AbstractList implements MutableFavoritesList { @Override public FavoriteEntry get(int index) { return getFavorites().get(index); @@ -133,13 +134,13 @@ public class FavoritesEntriesManager { @Override public void add(int index, FavoriteEntry entry) { - FavoritesEntriesManager.this.add(entry); + FavoritesEntriesManager.add(entry); } @Override public boolean remove(Object o) { if (o instanceof FavoriteEntry) { - FavoritesEntriesManager.this.remove((FavoriteEntry) o); + FavoritesEntriesManager.remove((FavoriteEntry) o); return true; } else { return false; @@ -148,7 +149,7 @@ public class FavoritesEntriesManager { @Override public void setAll(List entries) { - FavoritesEntriesManager.this.setEntries(entries); + FavoritesEntriesManager.setEntries(entries); } } } diff --git a/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.ClientInternals$FavoritesEntriesListProvider b/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.ClientInternals$FavoritesEntriesListProvider new file mode 100644 index 000000000..6b97f7540 --- /dev/null +++ b/runtime-engine/favorites/src/main/resources/META-INF/services/me.shedaniel.rei.impl.ClientInternals$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/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 index 61f16508f..abb5653ae 100644 --- a/runtime-engine/filtering-entries/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 @@ -25,8 +25,10 @@ package me.shedaniel.rei.impl.client.config.entries; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; -import me.shedaniel.rei.impl.client.entry.filtering.FilteringRule; -import me.shedaniel.rei.impl.client.entry.filtering.rules.ManualFilteringRule; +import me.shedaniel.rei.api.client.entry.filtering.FilteringRule; +import me.shedaniel.rei.impl.client.entry.filtering.FilteringRuleInternal; +import me.shedaniel.rei.impl.client.entry.filtering.FilteringRuleType; +import me.shedaniel.rei.impl.client.entry.filtering.rules.ManualFilteringRuleType; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -65,9 +67,9 @@ public class FilteringAddRuleScreen extends Screen { })); } rulesList = addWidget(new RulesList(minecraft, width, height, 30, height, BACKGROUND_LOCATION)); - for (FilteringRule rule : FilteringRule.REGISTRY.values()) { - if (!(rule instanceof ManualFilteringRule)) - rulesList.addItem(new DefaultRuleEntry(parent, entry, rule.createNew(), null)); + for (FilteringRuleType type : FilteringRuleType.REGISTRY.values()) { + if (!(type instanceof ManualFilteringRuleType)) + rulesList.addItem(new DefaultRuleEntry(parent, entry, type.createNew(), null)); } rulesList.selectItem(rulesList.children().get(0)); } @@ -124,13 +126,13 @@ public class FilteringAddRuleScreen extends Screen { } public static abstract class RuleEntry extends DynamicElementListWidget.ElementEntry { - private final FilteringRule rule; + private final FilteringRuleInternal rule; - public RuleEntry(FilteringRule rule) { + public RuleEntry(FilteringRuleInternal rule) { this.rule = rule; } - public FilteringRule getRule() { + public FilteringRuleInternal getRule() { return rule; } @@ -149,9 +151,9 @@ public class FilteringAddRuleScreen extends Screen { private final Button addButton; private final BiFunction screenFunction; - public DefaultRuleEntry(Screen parent, FilteringEntry entry, FilteringRule rule, BiFunction screenFunction) { + public DefaultRuleEntry(Screen parent, FilteringEntry entry, FilteringRuleInternal rule, BiFunction screenFunction) { super(rule); - this.screenFunction = (screenFunction == null ? rule.createEntryScreen().orElse(null) : screenFunction); + this.screenFunction = (s