diff options
| author | shedaniel <daniel@shedaniel.me> | 2024-04-25 22:02:16 +0900 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2024-04-25 22:02:16 +0900 |
| commit | 1a86c46219b873313085ba384903b1077c832c4e (patch) | |
| tree | 5d7cc481217a5fc2c09875633383e275415dc416 | |
| parent | a377a5bf80f3f93ef788b9fcd4ceb5c529219cb7 (diff) | |
| parent | c8aac81ec745aca534b301185af61c7b35d35025 (diff) | |
| download | RoughlyEnoughItems-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
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", |
