aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2022-06-20 00:33:48 +0800
committershedaniel <daniel@shedaniel.me>2022-06-20 17:19:36 +0800
commit025fc7576e962e428b77989f04f0913d17764fd2 (patch)
tree05ac986db00b612cdc34985870426d677a07b1db
parent1379931584442106b71e15f56862b7f6ec5786d8 (diff)
downloadRoughlyEnoughItems-025fc7576e962e428b77989f04f0913d17764fd2.tar.gz
RoughlyEnoughItems-025fc7576e962e428b77989f04f0913d17764fd2.tar.bz2
RoughlyEnoughItems-025fc7576e962e428b77989f04f0913d17764fd2.zip
Implement Config Addons, Close #908
-rw-r--r--api/src/main/java/me/shedaniel/rei/api/client/config/addon/ConfigAddon.java59
-rw-r--r--api/src/main/java/me/shedaniel/rei/api/client/config/addon/ConfigAddonRegistry.java56
-rw-r--r--api/src/main/java/me/shedaniel/rei/api/client/plugins/REIClientPlugin.java12
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java9
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonRegistryImpl.java54
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonsScreen.java193
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java96
-rwxr-xr-xruntime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json1
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_cn.json1
-rw-r--r--runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_tw.json1
11 files changed, 485 insertions, 1 deletions
diff --git a/api/src/main/java/me/shedaniel/rei/api/client/config/addon/ConfigAddon.java b/api/src/main/java/me/shedaniel/rei/api/client/config/addon/ConfigAddon.java
new file mode 100644
index 000000000..ef1855128
--- /dev/null
+++ b/api/src/main/java/me/shedaniel/rei/api/client/config/addon/ConfigAddon.java
@@ -0,0 +1,59 @@
+/*
+ * 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.config.addon;
+
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.Component;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * A config addon, which will be shown in the REI config screen.
+ *
+ * @since 8.3
+ */
+@ApiStatus.Experimental
+public interface ConfigAddon {
+ /**
+ * Returns the name of the addon, this will be shown in the addons list.
+ *
+ * @return the name of the addon
+ */
+ Component getName();
+
+ /**
+ * Returns the description of the addon, this will be shown in the addons list.
+ *
+ * @return the description of the addon
+ */
+ Component getDescription();
+
+ /**
+ * Opens the config screen for this addon, given the parent screen.
+ * Do not call {@link net.minecraft.client.Minecraft#setScreen(Screen)} directly,
+ * and make sure to set the screen as the parent screen to exit the config screen.
+ *
+ * @param parent the parent screen
+ */
+ Screen createScreen(Screen parent);
+}
diff --git a/api/src/main/java/me/shedaniel/rei/api/client/config/addon/ConfigAddonRegistry.java b/api/src/main/java/me/shedaniel/rei/api/client/config/addon/ConfigAddonRegistry.java
new file mode 100644
index 000000000..0156e1347
--- /dev/null
+++ b/api/src/main/java/me/shedaniel/rei/api/client/config/addon/ConfigAddonRegistry.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.api.client.config.addon;
+
+import me.shedaniel.rei.api.client.plugins.REIClientPlugin;
+import me.shedaniel.rei.api.common.plugins.PluginManager;
+import me.shedaniel.rei.api.common.registry.Reloadable;
+import org.jetbrains.annotations.ApiStatus;
+
+/**
+ * Registry for {@link ConfigAddon}s.
+ * Registered config addons will show up at the top of the config screen,
+ * and allow users to search and configure them easily.
+ * <p>
+ * REI does not provide serialization for config addons,
+ * that is up to the developer to implement.
+ *
+ * @since 8.3
+ */
+@ApiStatus.Experimental
+public interface ConfigAddonRegistry extends Reloadable<REIClientPlugin> {
+ /**
+ * @return the {@link PluginManager} instance
+ */
+ static ConfigAddonRegistry getInstance() {
+ return PluginManager.getClientInstance().get(ConfigAddonRegistry.class);
+ }
+
+ /**
+ * Registers a config addon. The addons displayed will be sorted by their name alphabetically.
+ *
+ * @param addon the addon to register
+ */
+ void register(ConfigAddon addon);
+}
diff --git a/api/src/main/java/me/shedaniel/rei/api/client/plugins/REIClientPlugin.java b/api/src/main/java/me/shedaniel/rei/api/client/plugins/REIClientPlugin.java
index 8eca42c42..9cf6cdbb1 100644
--- a/api/src/main/java/me/shedaniel/rei/api/client/plugins/REIClientPlugin.java
+++ b/api/src/main/java/me/shedaniel/rei/api/client/plugins/REIClientPlugin.java
@@ -23,6 +23,7 @@
package me.shedaniel.rei.api.client.plugins;
+import me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry;
import me.shedaniel.rei.api.client.entry.renderer.EntryRendererRegistry;
import me.shedaniel.rei.api.client.favorites.FavoriteEntryType;
import me.shedaniel.rei.api.client.registry.category.CategoryRegistry;
@@ -121,6 +122,17 @@ public interface REIClientPlugin extends REIPlugin<REIClientPlugin> {
default void registerTransferHandlers(TransferHandlerRegistry registry) {
}
+ /**
+ * Registers new config addons.
+ *
+ * @param registry the registry
+ * @since 8.3
+ */
+ @ApiStatus.OverrideOnly
+ @ApiStatus.Experimental
+ default void registerConfigAddons(ConfigAddonRegistry registry) {
+ }
+
@Override
default Class<REIClientPlugin> getPluginProviderClass() {
return REIClientPlugin.class;
diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
index 5d4203689..fbb07360a 100644
--- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
+++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java
@@ -60,6 +60,7 @@ import me.shedaniel.rei.api.common.util.ImmutableTextComponent;
import me.shedaniel.rei.impl.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.renderer.EntryRendererRegistryImpl;
import me.shedaniel.rei.impl.client.favorites.DelegatingFavoriteEntryProviderImpl;
import me.shedaniel.rei.impl.client.favorites.FavoriteEntryTypeRegistryImpl;
@@ -234,7 +235,8 @@ public class RoughlyEnoughItemsCoreClient {
new FavoriteEntryTypeRegistryImpl(),
new SubsetsRegistryImpl(),
new TransferHandlerRegistryImpl(),
- new REIRuntimeImpl()), "clientPluginManager");
+ new REIRuntimeImpl(),
+ new ConfigAddonRegistryImpl()), "clientPluginManager");
}
public void onInitializeClient() {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java
index 1685e67ae..01b96a7ed 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/ConfigManagerImpl.java
@@ -49,6 +49,7 @@ import me.shedaniel.clothconfig2.gui.entries.TextListEntry;
import me.shedaniel.rei.RoughlyEnoughItemsCore;
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.favorites.FavoriteEntry;
import me.shedaniel.rei.api.client.gui.config.CheatingMode;
@@ -60,6 +61,7 @@ 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.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;
@@ -376,6 +378,13 @@ public class ConfigManagerImpl implements ConfigManager {
builder.getOrCreateCategory(new TranslatableComponent("config.roughlyenoughitems.advanced")).getEntries().add(0, new PerformanceEntry(220));
}
return builder.setAfterInitConsumer(screen -> {
+ ConfigAddonRegistryImpl addonRegistry = (ConfigAddonRegistryImpl) ConfigAddonRegistry.getInstance();
+ if (!addonRegistry.getAddons().isEmpty()) {
+ ((GlobalizedClothConfigScreen) screen).listWidget.children().add(0, (AbstractConfigEntry) new EmptyEntry(4));
+ ConfigAddonsEntry configAddonsEntry = new ConfigAddonsEntry(220);
+ configAddonsEntry.setScreen((AbstractConfigScreen) screen);
+ ((GlobalizedClothConfigScreen) screen).listWidget.children().add(0, (AbstractConfigEntry) configAddonsEntry);
+ }
((GlobalizedClothConfigScreen) screen).listWidget.children().add(0, (AbstractConfigEntry) new EmptyEntry(4));
TextListEntry supportText = ConfigEntryBuilder.create().startTextDescription(
new TranslatableComponent("text.rei.support.me.desc",
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonRegistryImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonRegistryImpl.java
new file mode 100644
index 000000000..859c6a867
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonRegistryImpl.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.impl.client.config.addon;
+
+import me.shedaniel.rei.api.client.config.addon.ConfigAddon;
+import me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry;
+import me.shedaniel.rei.api.client.plugins.REIClientPlugin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConfigAddonRegistryImpl implements ConfigAddonRegistry {
+ private final List<ConfigAddon> addons = new ArrayList<>();
+
+ @Override
+ public void startReload() {
+ this.addons.clear();
+ }
+
+ @Override
+ public void register(ConfigAddon addon) {
+ this.addons.add(addon);
+ }
+
+ @Override
+ public void acceptPlugin(REIClientPlugin plugin) {
+ plugin.registerConfigAddons(this);
+ }
+
+ public List<ConfigAddon> getAddons() {
+ return this.addons;
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonsScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonsScreen.java
new file mode 100644
index 000000000..0773483e9
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/addon/ConfigAddonsScreen.java
@@ -0,0 +1,193 @@
+/*
+ * 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.addon;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget;
+import me.shedaniel.rei.api.client.config.addon.ConfigAddon;
+import me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry;
+import net.minecraft.client.Minecraft;
+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.locale.Language;
+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 java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import static me.shedaniel.rei.impl.client.gui.screen.DefaultDisplayViewingScreen.CHEST_GUI_TEXTURE;
+
+public class ConfigAddonsScreen extends Screen {
+ private AddonsList rulesList;
+ private final Screen parent;
+
+ public ConfigAddonsScreen(Screen parent) {
+ super(new TranslatableComponent("text.rei.addons"));
+ this.parent = parent;
+ }
+
+ @Override
+ public void init() {
+ super.init();
+ {
+ Component backText = new TextComponent("↩ ").append(new TranslatableComponent("gui.back"));
+ addRenderableWidget(new Button(4, 4, Minecraft.getInstance().font.width(backText) + 10, 20, backText, button -> {
+ minecraft.setScreen(parent);
+ }));
+ }
+ rulesList = addWidget(new AddonsList(minecraft, width, height, 30, height, BACKGROUND_LOCATION));
+ ConfigAddonRegistryImpl addonRegistry = (ConfigAddonRegistryImpl) ConfigAddonRegistry.getInstance();
+ for (ConfigAddon addon : addonRegistry.getAddons()) {
+ rulesList.addItem(new DefaultAddonEntry(parent, addon));
+ }
+ }
+
+ @Override
+ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
+ this.rulesList.render(matrices, mouseX, mouseY, delta);
+ super.render(matrices, mouseX, mouseY, delta);
+ this.font.drawShadow(matrices, this.title.getVisualOrderText(), this.width / 2.0F - this.font.width(this.title) / 2.0F, 12.0F, -1);
+ }
+
+ public static class AddonsList extends DynamicElementListWidget<AddonEntry> {
+ private boolean inFocus;
+
+ public AddonsList(Minecraft client, int width, int height, int top, int bottom, ResourceLocation backgroundLocation) {
+ super(client, width, height, top, bottom, backgroundLocation);
+ }
+
+ @Override
+ public boolean changeFocus(boolean lookForwards) {
+ if (!this.inFocus && this.getItemCount() == 0) {
+ return false;
+ } else {
+ this.inFocus = !this.inFocus;
+ if (this.inFocus && this.getSelectedItem() == null && this.getItemCount() > 0) {
+ this.moveSelection(1);
+ } else if (this.inFocus && this.getSelectedItem() != null) {
+ this.getSelectedItem();
+ }
+
+ return this.inFocus;
+ }
+ }
+
+ @Override
+ protected boolean isSelected(int index) {
+ return false;
+ }
+
+ @Override
+ protected int addItem(AddonEntry item) {
+ return super.addItem(item);
+ }
+
+ @Override
+ public int getItemWidth() {
+ return width - 40;
+ }
+
+ @Override
+ protected int getScrollbarPosition() {
+ return width - 14;
+ }
+ }
+
+ public static abstract class AddonEntry extends DynamicElementListWidget.ElementEntry<AddonEntry> {
+ @Override
+ public int getItemHeight() {
+ return 26;
+ }
+
+ @Override
+ public boolean changeFocus(boolean lookForwards) {
+ return false;
+ }
+ }
+
+ public static class DefaultAddonEntry extends AddonEntry {
+ private final Button configureButton;
+ private final ConfigAddon addon;
+
+ public DefaultAddonEntry(Screen parent, ConfigAddon addon) {
+ this.addon = addon;
+ this.configureButton = new Button(0, 0, 20, 20, Component.nullToEmpty(null), button -> {
+ Minecraft.getInstance().setScreen(this.addon.createScreen(Minecraft.getInstance().screen));
+ }) {
+ @Override
+ protected void renderBg(PoseStack matrices, Minecraft client, int mouseX, int mouseY) {
+ super.renderBg(matrices, client, mouseX, mouseY);
+ RenderSystem.setShaderTexture(0, CHEST_GUI_TEXTURE);
+ blit(matrices, x + 3, y + 3, 0, 0, 14, 14);
+ }
+ };
+ }
+
+ @Override
+ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) {
+ Minecraft client = Minecraft.getInstance();
+ {
+ Component title = addon.getName();
+ int i = client.font.width(title);
+ if (i > entryWidth - 28) {
+ FormattedText titleTrimmed = FormattedText.composite(client.font.substrByWidth(title, entryWidth - 28 - client.font.width("...")), FormattedText.of("..."));
+ client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(titleTrimmed), x + 2, y + 1, 16777215);
+ } else {
+ client.font.drawShadow(matrices, title.getVisualOrderText(), x + 2, y + 1, 16777215);
+ }
+ }
+ {
+ Component subtitle = addon.getDescription();
+ int i = client.font.width(subtitle);
+ if (i > entryWidth - 28) {
+ FormattedText subtitleTrimmed = FormattedText.composite(client.font.substrByWidth(subtitle, entryWidth - 28 - client.font.width("...")), FormattedText.of("..."));
+ client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(subtitleTrimmed), x + 2, y + 12, 8421504);
+ } else {
+ client.font.drawShadow(matrices, subtitle.getVisualOrderText(), x + 2, y + 12, 8421504);
+ }
+ }
+ configureButton.x = x + entryWidth - 25;
+ configureButton.y = y + 1;
+ configureButton.render(matrices, mouseX, mouseY, delta);
+ }
+
+ @Override
+ public List<? extends GuiEventListener> children() {
+ return Collections.singletonList(configureButton);
+ }
+
+ @Override
+ public List<? extends NarratableEntry> narratables() {
+ return Collections.singletonList(configureButton);
+ }
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java
new file mode 100644
index 000000000..017201a14
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/entries/ConfigAddonsEntry.java
@@ -0,0 +1,96 @@
+/*
+ * 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.api.client.REIRuntime;
+import me.shedaniel.rei.impl.client.config.addon.ConfigAddonsScreen;
+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.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 ConfigAddonsEntry extends AbstractConfigListEntry<Unit> {
+ private int width;
+ private AbstractWidget buttonWidget = new Button(0, 0, 0, 20, NarratorChatListener.NO_TITLE, button -> {
+ Minecraft.getInstance().setScreen(new ConfigAddonsScreen(Minecraft.getInstance().screen));
+ });
+ private List<AbstractWidget> children = ImmutableList.of(buttonWidget);
+
+ public ConfigAddonsEntry(int width) {
+ super(NarratorChatListener.NO_TITLE, false);
+ this.width = width;
+ this.buttonWidget.setMessage(REIRuntime.getInstance().getPreviousContainerScreen() != null && Minecraft.getInstance().getConnection() != null
+ && Minecraft.getInstance().getConnection().getRecipeManager() != null ? new TranslatableComponent("text.rei.addons")
+ : new TranslatableComponent("config.roughlyenoughitems.filteredEntries.loadWorldFirst"));
+ }
+
+ @Override
+ public Unit getValue() {
+ return Unit.INSTANCE;
+ }
+
+ @Override
+ public Optional<Unit> 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.buttonWidget.active = REIRuntime.getInstance().getPreviousContainerScreen() != null && Minecraft.getInstance().getConnection() != null
+ && Minecraft.getInstance().getConnection().getRecipeManager() != null && this.isEditable();
+ this.buttonWidget.y = y;
+ this.buttonWidget.x = x + entryWidth / 2 - width / 2;
+ this.buttonWidget.setWidth(width);
+ this.buttonWidget.render(matrices, mouseX, mouseY, delta);
+ }
+
+ @Override
+ public List<? extends GuiEventListener> children() {
+ return children;
+ }
+
+ @Override
+ public List<? extends NarratableEntry> narratables() {
+ return children;
+ }
+}
diff --git a/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json b/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json
index db5690e60..a8e443ca2 100755
--- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json
+++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json
@@ -71,6 +71,7 @@
"text.rei.accepts": "Accepts following:",
"text.rei.tag_accept": "Tag: #%s",
"text.rei.performance": "Performance Analysis",
+ "text.rei.addons": "REI Addons",
"text.rei.shapeless": "Shapeless",
"ordering.rei.ascending": "Ascending",
"ordering.rei.descending": "Descending",
diff --git a/runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_cn.json b/runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_cn.json
index 968b4d01c..8bc5bdbeb 100644
--- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_cn.json
+++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_cn.json
@@ -70,6 +70,7 @@
"text.rei.too_long_nbt": "§c物品 NBT 太长,不能应用于多人游戏.",
"text.rei.tag_accept": "标签:#%s",
"text.rei.performance": "性能分析",
+ "text.rei.addons": "REI 插件",
"text.rei.shapeless": "无序合成",
"ordering.rei.ascending": "顺序",
"ordering.rei.descending": "倒序",
diff --git a/runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_tw.json b/runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_tw.json
index 0c7937016..8f2bc1312 100644
--- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_tw.json
+++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/zh_tw.json
@@ -71,6 +71,7 @@
"text.rei.accepts": "接受以下物品:",
"text.rei.tag_accept": "標籤: #%s",
"text.rei.performance": "效能分析",
+ "text.rei.addons": "REI 附加功能",
"text.rei.shapeless": "無序合成",
"ordering.rei.ascending": "從 A 到 Z",
"ordering.rei.descending": "從 Z 到 A",