aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2024-04-25 22:02:16 +0900
committershedaniel <daniel@shedaniel.me>2024-04-25 22:02:16 +0900
commit1a86c46219b873313085ba384903b1077c832c4e (patch)
tree5d7cc481217a5fc2c09875633383e275415dc416
parenta377a5bf80f3f93ef788b9fcd4ceb5c529219cb7 (diff)
parentc8aac81ec745aca534b301185af61c7b35d35025 (diff)
downloadRoughlyEnoughItems-1a86c46219b873313085ba384903b1077c832c4e.tar.gz
RoughlyEnoughItems-1a86c46219b873313085ba384903b1077c832c4e.tar.bz2
RoughlyEnoughItems-1a86c46219b873313085ba384903b1077c832c4e.zip
Merge remote-tracking branch 'origin/14.x-1.20.4' into 15.x-1.20.5
# Conflicts: # runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntryWidget.java
-rw-r--r--default-plugin/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientPlugin.java63
-rw-r--r--default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/DefaultCompostingCategory.java5
-rw-r--r--default-plugin/src/main/java/me/shedaniel/rei/plugin/client/categories/anvil/DefaultAnvilCategory.java15
-rw-r--r--default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/AnvilRecipe.java11
-rw-r--r--default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/DefaultAnvilDisplay.java55
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/configure/PanelBoundariesConfiguration.java14
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/CompositeDisplayViewingScreen.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/DefaultDisplayViewingScreen.java3
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java8
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayValidator.java54
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java4
-rwxr-xr-xruntime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json1
12 files changed, 218 insertions, 19 deletions
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 013b7deb0..e43ee532e 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
@@ -97,6 +97,7 @@ import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.item.crafting.*;
+import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.ComposterBlock;
@@ -105,12 +106,14 @@ import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
+import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.ApiStatus;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
+import java.util.stream.IntStream;
import java.util.stream.Stream;
@Environment(EnvType.CLIENT)
@@ -394,6 +397,66 @@ public class DefaultClientPlugin implements REIClientPlugin, BuiltinClientPlugin
registerForgePotions(registry, this);
}
+ for (Item item : BuiltInRegistries.ITEM) {
+ ItemStack stack = item.getDefaultInstance();
+ if (!stack.isDamageableItem()) continue;
+ EntryIngredient repairMaterialBase = null;
+ if (item instanceof TieredItem tieredItem) {
+ Tier tier = tieredItem.getTier();
+ repairMaterialBase = EntryIngredients.ofIngredient(tier.getRepairIngredient());
+ } else if (item instanceof ArmorItem armorItem) {
+ ArmorMaterial material = armorItem.getMaterial();
+ repairMaterialBase = EntryIngredients.ofIngredient(material.getRepairIngredient());
+ } else if (item instanceof ShieldItem shieldItem) {
+ repairMaterialBase = EntryIngredients.ofItemTag(ItemTags.PLANKS);
+ repairMaterialBase.filter(s -> shieldItem.isValidRepairItem(stack, s.castValue()));
+ } else if (item instanceof ElytraItem elytraItem) {
+ repairMaterialBase = EntryIngredients.of(Items.PHANTOM_MEMBRANE);
+ repairMaterialBase.filter(s -> elytraItem.isValidRepairItem(stack, s.castValue()));
+ }
+ if (repairMaterialBase == null || repairMaterialBase.isEmpty()) continue;
+ for (int[] i = {1}; i[0] <= 4; i[0]++) {
+ ItemStack baseStack = item.getDefaultInstance();
+ int toRepair = i[0] == 4 ? item.getMaxDamage() : baseStack.getMaxDamage() / 4 * i[0];
+ baseStack.setDamageValue(toRepair);
+ EntryIngredient repairMaterial = repairMaterialBase.map(s -> {
+ EntryStack<?> newStack = s.copy();
+ newStack.<ItemStack>castValue().setCount(i[0]);
+ return newStack;
+ });
+ Optional<Pair<ItemStack, Integer>> output = DefaultAnvilDisplay.calculateOutput(baseStack, repairMaterial.get(0).castValue());
+ if (output.isEmpty()) continue;
+ registry.add(new DefaultAnvilDisplay(List.of(EntryIngredients.of(baseStack), repairMaterial),
+ Collections.singletonList(EntryIngredients.of(output.get().getLeft())), Optional.empty(), OptionalInt.of(output.get().getRight())));
+ }
+ }
+ List<Pair<EnchantmentInstance, ItemStack>> enchantmentBooks = BuiltInRegistries.ENCHANTMENT.stream()
+ .flatMap(enchantment -> {
+ if (enchantment.getMaxLevel() - enchantment.getMinLevel() >= 10) {
+ return IntStream.of(enchantment.getMinLevel(), enchantment.getMaxLevel())
+ .mapToObj(lvl -> new EnchantmentInstance(enchantment, lvl));
+ } else {
+ return IntStream.rangeClosed(enchantment.getMinLevel(), enchantment.getMaxLevel())
+ .mapToObj(lvl -> new EnchantmentInstance(enchantment, lvl));
+ }
+ })
+ .map(instance -> {
+ return Pair.of(instance, EnchantedBookItem.createForEnchantment(instance));
+ })
+ .toList();
+ EntryRegistry.getInstance().getEntryStacks().forEach(stack -> {
+ if (stack.getType() != VanillaEntryTypes.ITEM) return;
+ ItemStack itemStack = stack.castValue();
+ if (!itemStack.isEnchantable()) return;
+ for (Pair<EnchantmentInstance, ItemStack> pair : enchantmentBooks) {
+ if (!pair.getKey().enchantment.canEnchant(itemStack)) continue;
+ Optional<Pair<ItemStack, Integer>> output = DefaultAnvilDisplay.calculateOutput(itemStack, pair.getValue());
+ if (output.isEmpty()) continue;
+ registry.add(new DefaultAnvilDisplay(List.of(EntryIngredients.of(itemStack), EntryIngredients.of(pair.getValue())),
+ Collections.singletonList(EntryIngredients.of(output.get().getLeft())), Optional.empty(), OptionalInt.of(output.get().getRight())));
+ }
+ });
+
for (Registry<?> reg : BuiltInRegistries.REGISTRY) {
reg.getTags().forEach(tagPair -> registry.add(tagPair.getFirst()));
}
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 27005fee2..01b9edfaa 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
@@ -34,6 +34,7 @@ import me.shedaniel.rei.api.client.gui.widgets.Widgets;
import me.shedaniel.rei.api.client.registry.display.DisplayCategory;
import me.shedaniel.rei.api.common.category.CategoryIdentifier;
import me.shedaniel.rei.api.common.entry.EntryIngredient;
+import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
import me.shedaniel.rei.api.common.util.EntryStacks;
import me.shedaniel.rei.plugin.common.BuiltinPlugin;
import me.shedaniel.rei.plugin.common.displays.DefaultCompostingDisplay;
@@ -95,8 +96,8 @@ public class DefaultCompostingCategory implements DisplayCategory<DefaultCompost
for (int y = 0; y < 5; y++)
for (int x = 0; x < 7; x++) {
EntryIngredient entryIngredient = stacks.size() > i ? stacks.get(i) : EntryIngredient.empty();
- if (!entryIngredient.isEmpty()) {
- ItemStack firstStack = (ItemStack) entryIngredient.get(0).getValue();
+ if (!entryIngredient.isEmpty() && entryIngredient.get(0).getType() == VanillaEntryTypes.ITEM) {
+ ItemStack firstStack = entryIngredient.get(0).castValue();
float chance = ComposterBlock.COMPOSTABLES.getFloat(firstStack.getItem());
if (chance > 0.0f) {
entryIngredient = entryIngredient.map(stack -> stack.copy().tooltip(Component.translatable("text.rei.composting.chance", Mth.clamp(Mth.floor(chance * 100), 0, 100)).withStyle(ChatFormatting.YELLOW)));
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 f8c16278e..c1f292e96 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
@@ -34,6 +34,8 @@ import me.shedaniel.rei.api.common.category.CategoryIdentifier;
import me.shedaniel.rei.api.common.util.EntryStacks;
import me.shedaniel.rei.plugin.common.BuiltinPlugin;
import me.shedaniel.rei.plugin.common.displays.anvil.DefaultAnvilDisplay;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Font;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.Blocks;
@@ -57,7 +59,7 @@ public class DefaultAnvilCategory implements DisplayCategory<DefaultAnvilDisplay
@Override
public List<Widget> setupDisplay(DefaultAnvilDisplay display, Rectangle bounds) {
- Point startPoint = new Point(bounds.getCenterX() - 31, bounds.getCenterY() - 13);
+ Point startPoint = new Point(bounds.getCenterX() - 31, bounds.getCenterY() - (display.getCost().isPresent() ? 20 : 13));
List<Widget> widgets = Lists.newArrayList();
widgets.add(Widgets.createRecipeBase(bounds));
widgets.add(Widgets.createArrow(new Point(startPoint.x + 27, startPoint.y + 4)));
@@ -65,11 +67,20 @@ public class DefaultAnvilCategory implements DisplayCategory<DefaultAnvilDisplay
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());
+ if (display.getCost().isPresent()) {
+ widgets.add(Widgets.createDrawableWidget((graphics, mouseX, mouseY, delta) -> {
+ Font font = Minecraft.getInstance().font;
+ Component component = Component.translatable("container.repair.cost", display.getCost().getAsInt());
+ int x = startPoint.x + 102 - font.width(component) - 2;
+ graphics.fill(x - 2, startPoint.y + 28, startPoint.x + 102, startPoint.y + 28 + 12, 0x4f000000);
+ graphics.drawString(font, component, x, startPoint.y + 28 + 2, 0x80ff20);
+ }));
+ }
return widgets;
}
@Override
public int getDisplayHeight() {
- return 36;
+ return 48;
}
}
diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/AnvilRecipe.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/AnvilRecipe.java
index ba4f70458..694868145 100644
--- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/AnvilRecipe.java
+++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/AnvilRecipe.java
@@ -28,6 +28,7 @@ import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.List;
+import java.util.OptionalInt;
public class AnvilRecipe {
@Nullable
@@ -35,12 +36,18 @@ public class AnvilRecipe {
private final List<ItemStack> leftInput;
private final List<ItemStack> rightInputs;
private final List<ItemStack> outputs;
+ private final OptionalInt cost;
public AnvilRecipe(@Nullable ResourceLocation id, List<ItemStack> leftInput, List<ItemStack> rightInputs, List<ItemStack> outputs) {
+ this(id, leftInput, rightInputs, outputs, OptionalInt.empty());
+ }
+
+ public AnvilRecipe(@Nullable ResourceLocation id, List<ItemStack> leftInput, List<ItemStack> rightInputs, List<ItemStack> outputs, OptionalInt cost) {
this.id = id;
this.leftInput = leftInput;
this.rightInputs = rightInputs;
this.outputs = outputs;
+ this.cost = cost;
}
public ResourceLocation getId() {
@@ -58,4 +65,8 @@ public class AnvilRecipe {
public List<ItemStack> getOutputs() {
return outputs;
}
+
+ public OptionalInt getCost() {
+ return cost;
+ }
}
diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/DefaultAnvilDisplay.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/DefaultAnvilDisplay.java
index 0c2b5e655..befc8d143 100644
--- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/DefaultAnvilDisplay.java
+++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/displays/anvil/DefaultAnvilDisplay.java
@@ -28,14 +28,20 @@ import me.shedaniel.rei.api.common.display.basic.BasicDisplay;
import me.shedaniel.rei.api.common.entry.EntryIngredient;
import me.shedaniel.rei.api.common.util.EntryIngredients;
import me.shedaniel.rei.plugin.common.BuiltinPlugin;
+import net.minecraft.client.Minecraft;
+import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.entity.player.Inventory;
+import net.minecraft.world.inventory.AnvilMenu;
+import net.minecraft.world.item.ItemStack;
+import org.apache.commons.lang3.tuple.Pair;
+import org.jetbrains.annotations.ApiStatus;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
public class DefaultAnvilDisplay extends BasicDisplay {
+ private final OptionalInt cost;
+
public DefaultAnvilDisplay(AnvilRecipe recipe) {
this(
Arrays.asList(
@@ -43,12 +49,22 @@ public class DefaultAnvilDisplay extends BasicDisplay {
EntryIngredients.ofItemStacks(recipe.getRightInputs())
),
Collections.singletonList(EntryIngredients.ofItemStacks(recipe.getOutputs())),
- Optional.ofNullable(recipe.getId())
+ Optional.ofNullable(recipe.getId()),
+ recipe.getCost()
);
}
public DefaultAnvilDisplay(List<EntryIngredient> inputs, List<EntryIngredient> outputs, Optional<ResourceLocation> location) {
+ this(inputs, outputs, location, OptionalInt.empty());
+ }
+
+ public DefaultAnvilDisplay(List<EntryIngredient> inputs, List<EntryIngredient> outputs, Optional<ResourceLocation> location, CompoundTag tag) {
+ this(inputs, outputs, location, tag.contains("Cost") ? OptionalInt.of(tag.getInt("Cost")) : OptionalInt.empty());
+ }
+
+ public DefaultAnvilDisplay(List<EntryIngredient> inputs, List<EntryIngredient> outputs, Optional<ResourceLocation> location, OptionalInt cost) {
super(inputs, outputs, location);
+ this.cost = cost;
}
@Override
@@ -56,7 +72,34 @@ public class DefaultAnvilDisplay extends BasicDisplay {
return BuiltinPlugin.ANVIL;
}
+ public OptionalInt getCost() {
+ return cost;
+ }
+
public static BasicDisplay.Serializer<DefaultAnvilDisplay> serializer() {
- return BasicDisplay.Serializer.ofSimple(DefaultAnvilDisplay::new);
+ return BasicDisplay.Serializer.of(DefaultAnvilDisplay::new, (display, tag) -> {
+ if (display.getCost().isPresent()) {
+ tag.putInt("Cost", display.getCost().getAsInt());
+ }
+ });
+ }
+
+ @ApiStatus.Experimental
+ @ApiStatus.Internal
+ public static Optional<Pair<ItemStack, Integer>> calculateOutput(ItemStack left, ItemStack right) {
+ try {
+ if (Minecraft.getInstance().player == null) return Optional.empty();
+ AnvilMenu menu = new AnvilMenu(0, new Inventory(Minecraft.getInstance().player));
+ menu.setItem(0, menu.incrementStateId(), left);
+ menu.setItem(1, menu.incrementStateId(), right);
+ ItemStack output = menu.getSlot(2).getItem().copy();
+ if (!output.isEmpty()) {
+ return Optional.of(Pair.of(output, menu.getCost()));
+ } else {
+ return Optional.empty();
+ }
+ } catch (Throwable ignored) {
+ return Optional.empty();
+ }
}
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/configure/PanelBoundariesConfiguration.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/configure/PanelBoundariesConfiguration.java
index 8e00929e0..38c259e8c 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/configure/PanelBoundariesConfiguration.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/config/options/configure/PanelBoundariesConfiguration.java
@@ -79,7 +79,7 @@ public enum PanelBoundariesConfiguration implements OptionValueEntry.Configurato
public void init() {
super.init();
PanelBoundary boundary = access.get(option);
- addRenderableWidget(horizontalLimit = Checkbox.builder(literal("config.rei.options.layout.boundaries.desc.limit_by_percentage"), font).pos(0, 0).selected(this.horizontalUsePercentage).onValueChange((checkbox, opt) -> {
+ addRenderableWidget(horizontalLimit = Checkbox.builder(Component.empty(), font).pos(0, 0).selected(this.horizontalUsePercentage).onValueChange((checkbox, opt) -> {
horizontalUsePercentage = opt;
PanelBoundary newBoundary = access.get(option);
access.set(option, new PanelBoundary(1.0, newBoundary.verticalPercentage(), 50, newBoundary.verticalLimit(), 1.0, newBoundary.verticalAlign()));
@@ -141,8 +141,8 @@ public enum PanelBoundariesConfiguration implements OptionValueEntry.Configurato
if (!isReducedMotion()) innerAlphaAnimator.setTo(-1.0F, 200);
}
});
- addRenderableWidget(verticalLimit = Checkbox.builder(literal("config.rei.options.layout.boundaries.desc.limit_by_percentage"), font).pos(0, 0).selected(this.verticalUsePercentage).onValueChange((checkbox, opt) -> {
- verticalUsePercentage = !opt;
+ addRenderableWidget(verticalLimit = Checkbox.builder(Component.empty(), font).pos(0, 0).selected(this.verticalUsePercentage).onValueChange((checkbox, opt) -> {
+ verticalUsePercentage = opt;
PanelBoundary newBoundary = access.get(option);
access.set(option, new PanelBoundary(newBoundary.horizontalPercentage(), 1.0, newBoundary.horizontalLimit(), 1000, newBoundary.horizontalAlign(), 0.5));
if (!isReducedMotion()) innerAlphaAnimator.setTo(-1.0F, 200);
@@ -262,12 +262,18 @@ public enum PanelBoundariesConfiguration implements OptionValueEntry.Configurato
}
@Override
+ public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
+ super.renderBackground(graphics, mouseX, mouseY, delta);
+ Rectangle panelBounds = new Rectangle(this.width * 3 / 10, this.height * 4 / 40, this.width * 4 / 10, this.height * 32 / 40);
+ Widgets.createCategoryBase(panelBounds).render(graphics, mouseX, mouseY, delta);
+ }
+
+ @Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
this.innerAlphaAnimator.setTarget(this.innerAlphaAnimator.target() + (1.0F - this.innerAlphaAnimator.target()) * 0.06F);
this.innerAlphaAnimator.update(delta);
super.render(graphics, mouseX, mouseY, delta);
Rectangle panelBounds = new Rectangle(this.width * 3 / 10, this.height * 4 / 40, this.width * 4 / 10, this.height * 32 / 40);
- Widgets.createCategoryBase(panelBounds).render(graphics, mouseX, mouseY, delta);
int y = panelBounds.y + 6;
graphics.drawString(this.font, translatable("config.rei.options.layout.boundaries.desc.configure").withStyle(ChatFormatting.UNDERLINE), panelBounds.x + 6, y, 0xff404040, false);
y += 14;
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 6d7d255f5..7fe45a4c8 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
@@ -38,6 +38,7 @@ import me.shedaniel.rei.api.client.gui.widgets.*;
import me.shedaniel.rei.api.client.registry.category.ButtonArea;
import me.shedaniel.rei.api.client.registry.category.CategoryRegistry;
import me.shedaniel.rei.api.client.registry.display.DisplayCategory;
+import me.shedaniel.rei.api.client.registry.display.DisplayRegistry;
import me.shedaniel.rei.api.client.view.ViewSearchBuilder;
import me.shedaniel.rei.api.common.category.CategoryIdentifier;
import me.shedaniel.rei.api.common.display.Display;
@@ -46,6 +47,7 @@ import me.shedaniel.rei.impl.client.REIRuntimeImpl;
import me.shedaniel.rei.impl.client.gui.widget.EntryWidget;
import me.shedaniel.rei.impl.client.gui.widget.InternalWidgets;
import me.shedaniel.rei.impl.display.DisplaySpec;
+import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.events.GuiEventListener;
@@ -180,7 +182,7 @@ public class CompositeDisplayViewingScreen extends AbstractDisplayViewingScreen
this.widgets.add(Widgets.createClickableLabel(new Point(bounds.x + 4 + scrollListBounds.width / 2, bounds.y + 6), categories.get(selectedCategoryIndex).getTitle(), label -> {
ViewSearchBuilder.builder().addAllCategories().open();
- }).tooltip(Component.translatable("text.rei.view_all_categories")).noShadow().color(0xFF404040, 0xFFBBBBBB).hoveredColor(0xFF0041FF, 0xFFFFBD4D));
+ }).tooltip(Component.translatable("text.rei.view_all_categories"), Component.translatable("text.rei.view_all_categories.tooltip", CategoryRegistry.getInstance().stream().filter(config -> !DisplayRegistry.getInstance().get(config.getCategoryIdentifier()).isEmpty()).count()).withStyle(ChatFormatting.DARK_GRAY)).noShadow().color(0xFF404040, 0xFFBBBBBB).hoveredColor(0xFF0041FF, 0xFFFFBD4D));
this.widgets.add(new ButtonListWidget(buttonList));
this.children().addAll(widgets);
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 c90fffa69..278ecd2e1 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
@@ -45,6 +45,7 @@ import me.shedaniel.rei.api.client.gui.widgets.Widgets;
import me.shedaniel.rei.api.client.registry.category.ButtonArea;
import me.shedaniel.rei.api.client.registry.category.CategoryRegistry;
import me.shedaniel.rei.api.client.registry.display.DisplayCategory;
+import me.shedaniel.rei.api.client.registry.display.DisplayRegistry;
import me.shedaniel.rei.api.client.view.ViewSearchBuilder;
import me.shedaniel.rei.api.common.category.CategoryIdentifier;
import me.shedaniel.rei.api.common.display.Display;
@@ -164,7 +165,7 @@ public class DefaultDisplayViewingScreen extends AbstractDisplayViewingScreen {
.onClick(button -> previousCategory()).tooltipLine(Component.translatable("text.rei.previous_category")));
this.widgets.add(Widgets.createClickableLabel(new Point(bounds.getCenterX(), bounds.getY() + 7), getCurrentCategory().getTitle(), clickableLabelWidget -> {
ViewSearchBuilder.builder().addAllCategories().open();
- }).tooltip(Component.translatable("text.rei.view_all_categories")));
+ }).tooltip(Component.translatable("text.rei.view_all_categories"), Component.translatable("text.rei.view_all_categories.tooltip", CategoryRegistry.getInstance().stream().filter(config -> !DisplayRegistry.getInstance().get(config.getCategoryIdentifier()).isEmpty()).count()).withStyle(ChatFormatting.DARK_GRAY)));
this.widgets.add(categoryNext = Widgets.createButton(new Rectangle(bounds.getCenterX() + guiWidth / 2 - 17, bounds.getY() + 5, 12, 12), Component.literal(""))
.onClick(button -> nextCategory()).tooltipLine(Component.translatable("text.rei.next_category")));
this.categoryBack.setEnabled(categories.size() > 1);
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java
index b1e154b3e..6bc909aad 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayRegistryImpl.java
@@ -80,7 +80,9 @@ public class DisplayRegistryImpl extends RecipeManagerContextImpl<REIClientPlugi
lastAddWarning = System.currentTimeMillis();
}
- this.displaysHolder.add(display, origin);
+ if (DisplayValidator.validate(display)) {
+ this.displaysHolder.add(display, origin);
+ }
}
@Override
@@ -200,6 +202,10 @@ public class DisplayRegistryImpl extends RecipeManagerContextImpl<REIClientPlugi
}
}
+ for (List<Display> displays : getAll().values()) {
+ displays.removeIf(display -> !DisplayValidator.validate(display));
+ }
+
this.displaysHolder.endReload();
InternalLogger.getInstance().debug("Registered %d displays", displaySize());
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayValidator.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayValidator.java
new file mode 100644
index 000000000..6ebd4dbf0
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/registry/display/DisplayValidator.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, 2023 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.registry.display;
+
+import me.shedaniel.rei.api.client.registry.category.CategoryRegistry;
+import me.shedaniel.rei.api.client.registry.display.DisplayCategory;
+import me.shedaniel.rei.api.common.category.CategoryIdentifier;
+import me.shedaniel.rei.api.common.display.Display;
+import me.shedaniel.rei.impl.common.InternalLogger;
+
+public class DisplayValidator {
+ public static boolean validate(Display display) {
+ CategoryIdentifier<?> identifier = display.getCategoryIdentifier();
+
+ try {
+ CategoryRegistry.CategoryConfiguration<?> configuration = CategoryRegistry.getInstance().get(identifier);
+
+ try {
+ DisplayCategory<Display> category = (DisplayCategory<Display>) configuration.getCategory();
+ category.getDisplayWidth(display);
+ return true;
+ } catch (ClassCastException exception) {
+ InternalLogger.getInstance().error("Display [%s] %s failed validation check for category [%s] %s", display.getDisplayLocation().orElse(null), display, identifier, configuration.getCategory());
+ return false;
+ }
+ } catch (NullPointerException exception) {
+ return true;
+ } catch (Throwable throwable) {
+ InternalLogger.getInstance().error("Display [%s] %s failed validation check for category [%s]".formatted(display.getDisplayLocation().orElse(null), display, identifier), throwable);
+ return false;
+ }
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java
index aebdbb6c1..34bff7be2 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java
@@ -31,7 +31,7 @@ import it.unimi.dsi.fastutil.longs.Long2LongMaps;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
-import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
+import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
import me.shedaniel.rei.api.client.REIRuntime;
import me.shedaniel.rei.api.client.config.ConfigObject;
import me.shedaniel.rei.api.client.registry.category.CategoryRegistry;
@@ -281,7 +281,7 @@ public class ViewsImpl implements Views {
if (b != null) {
return b;
}
- map.put(key, new ReferenceOpenHashSet<>());
+ map.put(key, new ReferenceLinkedOpenHashSet<>());
return map.get(key);
}
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 73bcb103a..fa6f3dbd4 100755
--- a/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json
+++ b/runtime/src/main/resources/assets/roughlyenoughitems/lang/en_us.json
@@ -137,6 +137,7 @@
"text.rei.left_arrow": "<",
"text.rei.right_arrow": ">",
"text.rei.view_all_categories": "View All Categories",
+ "text.rei.view_all_categories.tooltip": "%d categories",
"text.rei.go_back_first_page": "Back to Page 1",
"text.rei.choose_page": "Choose Page",
"text.rei.shift_click_to": "Shift-Click to %s",