From a855c0284c3b285dd8a71b57ec35702995ae5b30 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 11 Jan 2020 00:34:07 +0800 Subject: 3.3.7 --- gradle.properties | 2 +- .../java/me/shedaniel/rei/api/RecipeCategory.java | 1 - .../java/me/shedaniel/rei/api/RecipeHelper.java | 6 +- .../me/shedaniel/rei/gui/entries/RecipeEntry.java | 104 +------- .../me/shedaniel/rei/impl/RecipeHelperImpl.java | 138 ++++++----- .../java/me/shedaniel/rei/impl/RenderingEntry.java | 112 +++++++++ .../me/shedaniel/rei/plugin/DefaultPlugin.java | 29 ++- .../composting/DefaultCompostingCategory.java | 1 - .../information/DefaultInformationCategory.java | 275 +++++++++++++++++++++ .../information/DefaultInformationDisplay.java | 75 ++++++ .../me/shedaniel/rei/utils/CollectionUtils.java | 8 + .../assets/roughlyenoughitems/lang/en_us.json | 1 + .../roughlyenoughitems/textures/gui/display.png | Bin 10151 -> 11200 bytes .../textures/gui/display_dark.png | Bin 8722 -> 9896 bytes src/main/resources/fabric.mod.json | 24 +- 15 files changed, 597 insertions(+), 179 deletions(-) create mode 100644 src/main/java/me/shedaniel/rei/impl/RenderingEntry.java create mode 100644 src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationCategory.java create mode 100644 src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationDisplay.java diff --git a/gradle.properties b/gradle.properties index 10120432e..85db4cfa8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -mod_version=3.3.6 +mod_version=3.3.7 minecraft_version=1.15.1 yarn_version=1.15.1+build.1 fabricloader_version=0.7.2+build.174 diff --git a/src/main/java/me/shedaniel/rei/api/RecipeCategory.java b/src/main/java/me/shedaniel/rei/api/RecipeCategory.java index fb3ec0866..fea0cf166 100644 --- a/src/main/java/me/shedaniel/rei/api/RecipeCategory.java +++ b/src/main/java/me/shedaniel/rei/api/RecipeCategory.java @@ -121,7 +121,6 @@ public interface RecipeCategory { * * @return the amount of recipes, returns -1 if not fixed */ - @Deprecated default int getFixedRecipesPerPage() { return -1; } diff --git a/src/main/java/me/shedaniel/rei/api/RecipeHelper.java b/src/main/java/me/shedaniel/rei/api/RecipeHelper.java index 448f00d9e..9c50febba 100644 --- a/src/main/java/me/shedaniel/rei/api/RecipeHelper.java +++ b/src/main/java/me/shedaniel/rei/api/RecipeHelper.java @@ -178,7 +178,11 @@ public interface RecipeHelper { * @deprecated {@link RecipeHelper#isDisplayVisible(RecipeDisplay)} )} */ @Deprecated - boolean isDisplayVisible(RecipeDisplay display, boolean respectConfig); + default boolean isDisplayVisible(RecipeDisplay display, boolean respectConfig) { + return isDisplayVisible(display); + } + + boolean isDisplayNotVisible(RecipeDisplay display); /** * Checks if the display is visible by asking recipe visibility handlers diff --git a/src/main/java/me/shedaniel/rei/gui/entries/RecipeEntry.java b/src/main/java/me/shedaniel/rei/gui/entries/RecipeEntry.java index 0361c2ba5..42e93f467 100644 --- a/src/main/java/me/shedaniel/rei/gui/entries/RecipeEntry.java +++ b/src/main/java/me/shedaniel/rei/gui/entries/RecipeEntry.java @@ -5,107 +5,11 @@ package me.shedaniel.rei.gui.entries; -import me.shedaniel.rei.api.EntryStack; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.util.Identifier; +import me.shedaniel.rei.gui.widget.QueuedTooltip; +import me.shedaniel.rei.impl.RenderingEntry; -import java.util.Optional; - -public abstract class RecipeEntry extends DrawableHelper implements EntryStack { - @Override - public Optional getIdentifier() { - return Optional.empty(); - } - - @Override - public Type getType() { - return Type.RENDER; - } - - @Override - public int getAmount() { - return 0; - } - - @Override - public void setAmount(int amount) { - - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public EntryStack copy() { - return this; - } - - @Override - public Object getObject() { - return null; - } - - @Override - public boolean equals(EntryStack stack, boolean ignoreTags, boolean ignoreAmount) { - return stack == this; - } - - @Override - public boolean equalsIgnoreTagsAndAmount(EntryStack stack) { - return stack == this; - } - - @Override - public boolean equalsIgnoreTags(EntryStack stack) { - return stack == this; - } - - @Override - public boolean equalsIgnoreAmount(EntryStack stack) { - return stack == this; - } - - @Override - public boolean equalsAll(EntryStack stack) { - return stack == this; - } - - @Override - public int getZ() { - return getBlitOffset(); - } - - @Override - public void setZ(int z) { - setBlitOffset(z); - } - - @Override - public EntryStack setting(Settings settings, T value) { - return this; - } - - @Override - public EntryStack removeSetting(Settings settings) { - return this; - } - - @Override - public EntryStack clearSettings() { - return this; - } - - @Override - public EntryStack addSetting(Settings settings, T value) { - return this; - } - - @Override - public T get(Settings settings) { - return settings.getDefaultValue(); - } +public abstract class RecipeEntry extends RenderingEntry { + public abstract QueuedTooltip getTooltip(int mouseX, int mouseY); public abstract int getHeight(); diff --git a/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java b/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java index af2d66637..898d82fbc 100644 --- a/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java +++ b/src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java @@ -46,7 +46,8 @@ public class RecipeHelperImpl implements RecipeHelper { private final List screenClickAreas = Lists.newLinkedList(); private final int[] recipeCount = {0}; private final Map> recipeCategoryListMap = Maps.newLinkedHashMap(); - private final List> categories = Lists.newLinkedList(); + private final Map, Identifier> categories = Maps.newLinkedHashMap(); + private final Map> reversedCategories = Maps.newHashMap(); private final Map autoCraftAreaSupplierMap = Maps.newLinkedHashMap(); private final Map>> categoryWorkingStations = Maps.newLinkedHashMap(); private final List displayVisibilityHandlers = Lists.newLinkedList(); @@ -88,9 +89,10 @@ public class RecipeHelperImpl implements RecipeHelper { @Override public void registerCategory(RecipeCategory category) { - categories.add(category); - recipeCategoryListMap.put(category.getIdentifier(), Lists.newLinkedList()); - categoryWorkingStations.put(category.getIdentifier(), Lists.newLinkedList()); + categories.put(category, category.getIdentifier()); + reversedCategories.put(category.getIdentifier(), category); + recipeCategoryListMap.put(category.getIdentifier(), Lists.newArrayList()); + categoryWorkingStations.put(category.getIdentifier(), Lists.newArrayList()); } @SafeVarargs @@ -126,32 +128,40 @@ public class RecipeHelperImpl implements RecipeHelper { @Override public Map, List> getRecipesFor(EntryStack stack) { - Map> categoriesMap = new HashMap<>(); - categories.forEach(f -> categoriesMap.put(f.getIdentifier(), Lists.newArrayList())); - for (Map.Entry> entry : recipeCategoryListMap.entrySet()) { - RecipeCategory category = getCategory(entry.getKey()); - for (RecipeDisplay recipeDisplay : entry.getValue()) - for (EntryStack outputStack : recipeDisplay.getOutputEntries()) - if (stack.equals(outputStack)) - categoriesMap.get(recipeDisplay.getRecipeCategory()).add(recipeDisplay); + Map, List> result = Maps.newLinkedHashMap(); + for (Map.Entry, Identifier> entry : categories.entrySet()) { + RecipeCategory category = entry.getKey(); + Identifier categoryId = entry.getValue(); + Set set = Sets.newLinkedHashSet(); + for (RecipeDisplay display : recipeCategoryListMap.get(categoryId)) { + for (EntryStack outputStack : display.getOutputEntries()) + if (stack.equals(outputStack) && isDisplayVisible(display)) { + set.add(display); + break; + } + } + if (!set.isEmpty()) + CollectionUtils.getOrPutEmptyList(result, category).addAll(set); } for (LiveRecipeGenerator liveRecipeGenerator : liveRecipeGenerators) { - liveRecipeGenerator.getRecipeFor(stack).ifPresent(o -> categoriesMap.get(liveRecipeGenerator.getCategoryIdentifier()).addAll(o)); + RecipeCategory category = getCategory(liveRecipeGenerator.getCategoryIdentifier()); + Optional> recipeFor = liveRecipeGenerator.getRecipeFor(stack); + if (recipeFor.isPresent()) { + Set set = Sets.newLinkedHashSet(); + for (RecipeDisplay display : recipeFor.get()) { + if (isDisplayVisible(display)) + set.add(display); + } + if (!set.isEmpty()) + CollectionUtils.getOrPutEmptyList(result, category).addAll(set); + } } - Map, List> recipeCategoryListMap = Maps.newLinkedHashMap(); - categories.forEach(category -> { - if (categoriesMap.containsKey(category.getIdentifier()) && !categoriesMap.get(category.getIdentifier()).isEmpty()) - recipeCategoryListMap.put(category, categoriesMap.get(category.getIdentifier()).stream().filter(this::isDisplayVisible).collect(Collectors.toList())); - }); - for (RecipeCategory category : Lists.newArrayList(recipeCategoryListMap.keySet())) - if (recipeCategoryListMap.get(category).isEmpty()) - recipeCategoryListMap.remove(category); - return recipeCategoryListMap; + return result; } @Override public RecipeCategory getCategory(Identifier identifier) { - return CollectionUtils.findFirstOrNull(categories, category -> category.getIdentifier().equals(identifier)); + return reversedCategories.get(identifier); } @Override @@ -171,44 +181,48 @@ public class RecipeHelperImpl implements RecipeHelper { @Override public Map, List> getUsagesFor(EntryStack stack) { - Map> categoriesMap = new HashMap<>(); - categories.forEach(f -> categoriesMap.put(f.getIdentifier(), Sets.newLinkedHashSet())); - for (Map.Entry> entry : recipeCategoryListMap.entrySet()) { - boolean isWorkstationCategory = isStackWorkStationOfCategory(entry.getKey(), stack); - for (RecipeDisplay recipeDisplay : entry.getValue()) { + Map, List> result = Maps.newLinkedHashMap(); + for (Map.Entry, Identifier> entry : categories.entrySet()) { + Set set = Sets.newLinkedHashSet(); + RecipeCategory category = entry.getKey(); + Identifier categoryId = entry.getValue(); + for (RecipeDisplay display : recipeCategoryListMap.get(categoryId)) { back: - for (List input : recipeDisplay.getInputEntries()) { + for (List input : display.getInputEntries()) { for (EntryStack otherEntry : input) { if (otherEntry.equals(stack)) { - categoriesMap.get(recipeDisplay.getRecipeCategory()).add(recipeDisplay); + if (isDisplayVisible(display)) + set.add(display); break back; } } } } - if (isWorkstationCategory) { - for (RecipeDisplay recipeDisplay : entry.getValue()) { - categoriesMap.get(recipeDisplay.getRecipeCategory()).add(recipeDisplay); - } + if (isStackWorkStationOfCategory(categoryId, stack)) { + set.addAll(recipeCategoryListMap.get(categoryId)); } + if (!set.isEmpty()) + CollectionUtils.getOrPutEmptyList(result, category).addAll(set); } for (LiveRecipeGenerator liveRecipeGenerator : liveRecipeGenerators) { - liveRecipeGenerator.getUsageFor(stack).ifPresent(o -> categoriesMap.get(liveRecipeGenerator.getCategoryIdentifier()).addAll(o)); - } - Map, List> recipeCategoryListMap = Maps.newLinkedHashMap(); - for (RecipeCategory category : categories) { - if (categoriesMap.containsKey(category.getIdentifier()) && !categoriesMap.get(category.getIdentifier()).isEmpty()) - recipeCategoryListMap.put(category, CollectionUtils.filterSetToList(categoriesMap.get(category.getIdentifier()), this::isDisplayVisible)); + RecipeCategory category = getCategory(liveRecipeGenerator.getCategoryIdentifier()); + Optional> recipeFor = liveRecipeGenerator.getUsageFor(stack); + if (recipeFor.isPresent()) { + Set set = Sets.newLinkedHashSet(); + for (RecipeDisplay display : recipeFor.get()) { + if (isDisplayVisible(display)) + set.add(display); + } + if (!set.isEmpty()) + CollectionUtils.getOrPutEmptyList(result, category).addAll(set); + } } - for (RecipeCategory category : Lists.newArrayList(recipeCategoryListMap.keySet())) - if (recipeCategoryListMap.get(category).isEmpty()) - recipeCategoryListMap.remove(category); - return recipeCategoryListMap; + return result; } @Override public List> getAllCategories() { - return Collections.unmodifiableList(categories); + return Lists.newArrayList(categories.keySet()); } @Override @@ -234,6 +248,7 @@ public class RecipeHelperImpl implements RecipeHelper { this.recipeManager = recipeManager; this.recipeCategoryListMap.clear(); this.categories.clear(); + this.reversedCategories.clear(); this.autoCraftAreaSupplierMap.clear(); this.screenClickAreas.clear(); this.categoryWorkingStations.clear(); @@ -331,8 +346,9 @@ public class RecipeHelperImpl implements RecipeHelper { ((DisplayHelperImpl) DisplayHelper.getInstance()).resetCache(); ScreenHelper.getOptionalOverlay().ifPresent(overlay -> overlay.shouldReInit = true); + displayVisibilityHandlers.sort(VISIBILITY_HANDLER_COMPARATOR); long usedTime = System.currentTimeMillis() - startTime; - RoughlyEnoughItemsCore.LOGGER.info("[REI] Registered %d stack entries, %d recipes displays, %d exclusion zones suppliers, %d bounds handler, %d visibility handlers and %d categories (%s) in %d ms.", EntryRegistry.getInstance().getStacksList().size(), recipeCount[0], DisplayHelper.getInstance().getBaseBoundsHandler().supplierSize(), DisplayHelper.getInstance().getAllBoundsHandlers().size(), getDisplayVisibilityHandlers().size(), categories.size(), categories.stream().map(RecipeCategory::getCategoryName).collect(Collectors.joining(", ")), usedTime); + RoughlyEnoughItemsCore.LOGGER.info("[REI] Registered %d stack entries, %d recipes displays, %d exclusion zones suppliers, %d bounds handler, %d visibility handlers and %d categories (%s) in %d ms.", EntryRegistry.getInstance().getStacksList().size(), recipeCount[0], DisplayHelper.getInstance().getBaseBoundsHandler().supplierSize(), DisplayHelper.getInstance().getAllBoundsHandlers().size(), getDisplayVisibilityHandlers().size(), categories.size(), categories.keySet().stream().map(RecipeCategory::getCategoryName).collect(Collectors.joining(", ")), usedTime); } @Override @@ -359,15 +375,18 @@ public class RecipeHelperImpl implements RecipeHelper { @Override public Map, List> getAllRecipes() { - Map, List> map = Maps.newLinkedHashMap(); - for (RecipeCategory recipeCategory : categories) { - if (recipeCategoryListMap.containsKey(recipeCategory.getIdentifier())) { - List list = CollectionUtils.filter(recipeCategoryListMap.get(recipeCategory.getIdentifier()), this::isDisplayVisible); - if (!list.isEmpty()) - map.put(recipeCategory, list); + Map, List> result = Maps.newLinkedHashMap(); + for (Map.Entry, Identifier> entry : categories.entrySet()) { + RecipeCategory category = entry.getKey(); + Identifier categoryId = entry.getValue(); + List displays = recipeCategoryListMap.get(categoryId); + if (displays != null) { + displays.removeIf(this::isDisplayNotVisible); + if (!displays.isEmpty()) + result.put(category, Lists.newArrayList(displays)); } } - return map; + return result; } @Override @@ -391,22 +410,21 @@ public class RecipeHelperImpl implements RecipeHelper { } @Override - public boolean isDisplayVisible(RecipeDisplay display, boolean respectConfig) { - return isDisplayVisible(display); + public boolean isDisplayNotVisible(RecipeDisplay display) { + return !isDisplayVisible(display); } @Override public boolean isDisplayVisible(RecipeDisplay display) { RecipeCategory category = getCategory(display.getRecipeCategory()); - List list = getDisplayVisibilityHandlers().stream().sorted(VISIBILITY_HANDLER_COMPARATOR).collect(Collectors.toList()); - for (DisplayVisibilityHandler displayVisibilityHandler : list) { - try { + try { + for (DisplayVisibilityHandler displayVisibilityHandler : displayVisibilityHandlers) { ActionResult visibility = displayVisibilityHandler.handleDisplay(category, display); if (visibility != ActionResult.PASS) return visibility == ActionResult.SUCCESS; - } catch (Throwable throwable) { - RoughlyEnoughItemsCore.LOGGER.error("[REI] Failed to check if the recipe is visible!", throwable); } + } catch (Throwable throwable) { + RoughlyEnoughItemsCore.LOGGER.error("[REI] Failed to check if the recipe is visible!", throwable); } return true; } diff --git a/src/main/java/me/shedaniel/rei/impl/RenderingEntry.java b/src/main/java/me/shedaniel/rei/impl/RenderingEntry.java new file mode 100644 index 000000000..766b9f193 --- /dev/null +++ b/src/main/java/me/shedaniel/rei/impl/RenderingEntry.java @@ -0,0 +1,112 @@ +package me.shedaniel.rei.impl; + +import me.shedaniel.rei.api.EntryStack; +import me.shedaniel.rei.gui.widget.QueuedTooltip; +import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.util.Identifier; + +import javax.annotation.Nullable; +import java.util.Optional; + +public abstract class RenderingEntry extends DrawableHelper implements EntryStack { + @Override + public Optional getIdentifier() { + return Optional.empty(); + } + + @Override + public Type getType() { + return Type.RENDER; + } + + @Override + public int getAmount() { + return 0; + } + + @Override + public void setAmount(int amount) { + + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public EntryStack copy() { + return this; + } + + @Override + public Object getObject() { + return null; + } + + @Override + public boolean equals(EntryStack stack, boolean ignoreTags, boolean ignoreAmount) { + return stack == this; + } + + @Override + public boolean equalsIgnoreTagsAndAmount(EntryStack stack) { + return stack == this; + } + + @Override + public boolean equalsIgnoreTags(EntryStack stack) { + return stack == this; + } + + @Override + public boolean equalsIgnoreAmount(EntryStack stack) { + return stack == this; + } + + @Override + public boolean equalsAll(EntryStack stack) { + return stack == this; + } + + @Override + public int getZ() { + return getBlitOffset(); + } + + @Override + public void setZ(int z) { + setBlitOffset(z); + } + + @Override + public EntryStack setting(Settings settings, T value) { + return this; + } + + @Override + public EntryStack removeSetting(Settings settings) { + return this; + } + + @Override + public EntryStack clearSettings() { + return this; + } + + @Override + public EntryStack addSetting(Settings settings, T value) { + return this; + } + + @Override + public T get(Settings settings) { + return settings.getDefaultValue(); + } + + @Nullable + @Override + public QueuedTooltip getTooltip(int mouseX, int mouseY) { + return null; + } +} diff --git a/src/main/java/me/shedaniel/rei/plugin/DefaultPlugin.java b/src/main/java/me/shedaniel/rei/plugin/DefaultPlugin.java index 5513b2fe8..0f04e72d0 100644 --- a/src/main/java/me/shedaniel/rei/plugin/DefaultPlugin.java +++ b/src/main/java/me/shedaniel/rei/plugin/DefaultPlugin.java @@ -30,6 +30,8 @@ import me.shedaniel.rei.plugin.crafting.DefaultShapedDisplay; import me.shedaniel.rei.plugin.crafting.DefaultShapelessDisplay; import me.shedaniel.rei.plugin.fuel.DefaultFuelCategory; import me.shedaniel.rei.plugin.fuel.DefaultFuelDisplay; +import me.shedaniel.rei.plugin.information.DefaultInformationCategory; +import me.shedaniel.rei.plugin.information.DefaultInformationDisplay; import me.shedaniel.rei.plugin.smelting.DefaultSmeltingDisplay; import me.shedaniel.rei.plugin.smoking.DefaultSmokingDisplay; import me.shedaniel.rei.plugin.stonecutting.DefaultStoneCuttingCategory; @@ -69,9 +71,11 @@ public class DefaultPlugin implements REIPluginV0 { public static final Identifier PLUGIN = new Identifier("roughlyenoughitems", "default_plugin"); public static final Identifier COMPOSTING = new Identifier("minecraft", "plugins/composting"); public static final Identifier FUEL = new Identifier("minecraft", "plugins/fuel"); + public static final Identifier INFO = new Identifier("roughlyenoughitems", "plugins/information"); private static final Identifier DISPLAY_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/display.png"); private static final Identifier DISPLAY_TEXTURE_DARK = new Identifier("roughlyenoughitems", "textures/gui/display_dark.png"); private static final List BREWING_DISPLAYS = Lists.newArrayList(); + private static final List INFO_DISPLAYS = Lists.newArrayList(); public static Identifier getDisplayTexture() { return ScreenHelper.isDarkModeEnabled() ? DISPLAY_TEXTURE_DARK : DISPLAY_TEXTURE; @@ -81,6 +85,10 @@ public class DefaultPlugin implements REIPluginV0 { BREWING_DISPLAYS.add(display); } + public static void registerInfoDisplay(DefaultInformationDisplay display) { + INFO_DISPLAYS.add(display); + } + @Override public Identifier getPluginIdentifier() { return PLUGIN; @@ -91,6 +99,11 @@ public class DefaultPlugin implements REIPluginV0 { return SemanticVersion.parse("3.2.33"); } + @Override + public void preRegister() { + INFO_DISPLAYS.clear(); + } + @Override public void registerEntries(EntryRegistry entryRegistry) { if (!ConfigObject.getInstance().isLoadingDefaultPlugin()) { @@ -149,6 +162,13 @@ public class DefaultPlugin implements REIPluginV0 { if (!ConfigObject.getInstance().isLoadingDefaultPlugin()) { return; } + // DefaultPlugin.registerInfoDisplay(DefaultInformationDisplay.createFromEntry(EntryStack.create(Items.FURNACE), new LiteralText("Furnace Info")) + // .lines(new LiteralText("Furnace is a nice block, crafted using 8 cobblestone."), + // new LiteralText("An amazing tool to burn lil taters."), + // new LiteralText("Now available in a store next to you."), + // new LiteralText("Now with 60% off for an limited time!"), + // new LiteralText("Get it with coupon code: ").append(new LiteralText("TATERS").formatted(Formatting.BOLD)) + // )); recipeHelper.registerRecipes(CRAFTING, ShapelessRecipe.class, DefaultShapelessDisplay::new); recipeHelper.registerRecipes(CRAFTING, ShapedRecipe.class, DefaultShapedDisplay::new); recipeHelper.registerRecipes(SMELTING, SmeltingRecipe.class, DefaultSmeltingDisplay::new); @@ -186,9 +206,7 @@ public class DefaultPlugin implements REIPluginV0 { map.put(entry.getKey(), entry.getFloatValue()); } List stacks = new LinkedList<>(map.keySet()); - stacks.sort((first, second) -> { - return (int) ((map.get(first) - map.get(second)) * 100); - }); + stacks.sort((first, second) -> (int) ((map.get(first) - map.get(second)) * 100)); for (int i = 0; i < stacks.size(); i += MathHelper.clamp(48, 1, stacks.size() - i)) { List thisStacks = Lists.newArrayList(); for (int j = i; j < i + 48; j++) @@ -203,6 +221,10 @@ public class DefaultPlugin implements REIPluginV0 { @Override public void postRegister() { + RecipeHelper.getInstance().registerCategory(new DefaultInformationCategory()); + for (DefaultInformationDisplay display : INFO_DISPLAYS) { + RecipeHelper.getInstance().registerDisplay(INFO, display); + } // Sit tight! This will be a fast journey! long time = System.currentTimeMillis(); for (EntryStack stack : EntryRegistry.getInstance().getStacksList()) @@ -321,6 +343,7 @@ public class DefaultPlugin implements REIPluginV0 { recipeHelper.registerWorkingStations(COMPOSTING, EntryStack.create(Items.COMPOSTER)); recipeHelper.removeAutoCraftButton(FUEL); recipeHelper.removeAutoCraftButton(COMPOSTING); + recipeHelper.removeAutoCraftButton(INFO); recipeHelper.registerScreenClickArea(new Rectangle(88, 32, 28, 23), CraftingTableScreen.class, CRAFTING); recipeHelper.registerScreenClickArea(new Rectangle(137, 29, 10, 13), InventoryScreen.class, CRAFTING); recipeHelper.registerScreenClickArea(new Rectangle(97, 16, 14, 30), BrewingStandScreen.class, BREWING); diff --git a/src/main/java/me/shedaniel/rei/plugin/composting/DefaultCompostingCategory.java b/src/main/java/me/shedaniel/rei/plugin/composting/DefaultCompostingCategory.java index 96d3e2027..d427dc1a2 100644 --- a/src/main/java/me/shedaniel/rei/plugin/composting/DefaultCompostingCategory.java +++ b/src/main/java/me/shedaniel/rei/plugin/composting/DefaultCompostingCategory.java @@ -104,7 +104,6 @@ public class DefaultCompostingCategory implements RecipeCategory { + @Override + public Identifier getIdentifier() { + return DefaultPlugin.INFO; + } + + @Override + public String getCategoryName() { + return I18n.translate("category.rei.information"); + } + + @Override + public RecipeEntry getSimpleRenderer(DefaultInformationDisplay recipe) { + Text name = recipe.getName(); + return new RecipeEntry() { + @Override + public int getHeight() { + return 10 + MinecraftClient.getInstance().textRenderer.fontHeight; + } + + @Nullable + @Override + public QueuedTooltip getTooltip(int mouseX, int mouseY) { + return null; + } + + @Override + public void render(Rectangle rectangle, int mouseX, int mouseY, float delta) { + MinecraftClient.getInstance().textRenderer.draw(name.asFormattedString(), rectangle.x + 5, rectangle.y + 6, -1); + } + }; + } + + @Override + public EntryStack getLogo() { + return new RenderingEntry() { + @Override + public void render(Rectangle bounds, int mouseX, int mouseY, float delta) { + MinecraftClient.getInstance().getTextureManager().bindTexture(DefaultPlugin.getDisplayTexture()); + Matrix4f matrix4f = Matrix4f.method_24021(-1.2f, -1, 0); + DefaultInformationCategory.innerBlit(matrix4f, bounds.getCenterX() - 8, bounds.getCenterX() + 8, bounds.getCenterY() - 8, bounds.getCenterY() + 8, 0, 116f / 256f, (116f + 16f) / 256f, 0f, 16f / 256f); + } + }; + } + + protected static void innerBlit(Matrix4f matrix4f, int xStart, int xEnd, int yStart, int yEnd, int z, float uStart, float uEnd, float vStart, float vEnd) { + BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); + bufferBuilder.begin(7, VertexFormats.POSITION_TEXTURE); + bufferBuilder.vertex(matrix4f, xStart, yEnd, z).texture(uStart, vEnd).next(); + bufferBuilder.vertex(matrix4f, xEnd, yEnd, z).texture(uEnd, vEnd).next(); + bufferBuilder.vertex(matrix4f, xEnd, yStart, z).texture(uEnd, vStart).next(); + bufferBuilder.vertex(matrix4f, xStart, yStart, z).texture(uStart, vStart).next(); + bufferBuilder.end(); + RenderSystem.enableAlphaTest(); + BufferRenderer.draw(bufferBuilder); + } + + @Override + public List setupDisplay(Supplier recipeDisplaySupplier, Rectangle bounds) { + DefaultInformationDisplay display = recipeDisplaySupplier.get(); + List widgets = Lists.newArrayList(); + widgets.add(new LabelWidget(new Point(bounds.getCenterX(), bounds.y + 3), display.getName().asFormattedString()).noShadow().color(ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : 0xFF404040)); + widgets.add(EntryWidget.create(bounds.getCenterX() - 8, bounds.y + 15).entries(display.getEntryStacks())); + Rectangle rectangle = new Rectangle(bounds.getCenterX() - (bounds.width / 2), bounds.y + 35, bounds.width, bounds.height - 40); + widgets.add(new SlotBaseWidget(rectangle)); + widgets.add(new ScrollableTextWidget(rectangle, display.getTexts())); + return widgets; + } + + @Override + public int getDisplayHeight() { + return 140; + } + + @Override + public int getFixedRecipesPerPage() { + return 1; + } + + private static class ScrollableTextWidget extends WidgetWithBounds { + private Rectangle bounds; + private List texts; + private double target; + private double scroll; + private long start; + private long duration; + + public ScrollableTextWidget(Rectangle bounds, List texts) { + this.bounds = bounds; + this.texts = Lists.newArrayList(); + for (Text text : texts) { + if (!this.texts.isEmpty()) + this.texts.add(null); + this.texts.addAll(Texts.wrapLines(text, bounds.width - 11, MinecraftClient.getInstance().textRenderer, true, false)); + } + } + + @Override + public boolean mouseScrolled(double double_1, double double_2, double double_3) { + if (containsMouse(double_1, double_2)) { + offset(ClothConfigInitializer.getScrollStep() * -double_3, true); + return true; + } + return false; + } + + public void offset(double value, boolean animated) { + scrollTo(target + value, animated); + } + + public void scrollTo(double value, boolean animated) { + scrollTo(value, animated, ClothConfigInitializer.getScrollDuration()); + } + + public void scrollTo(double value, boolean animated, long duration) { + target = clamp(value); + + if (animated) { + start = System.currentTimeMillis(); + this.duration = duration; + } else + scroll = target; + } + + public final double clamp(double v) { + return clamp(v, DynamicEntryListWidget.SmoothScrollingSettings.CLAMP_EXTENSION); + } + + public final double clamp(double v, double clampExtension) { + return MathHelper.clamp(v, -clampExtension, getMaxScroll() + clampExtension); + } + + protected int getMaxScroll() { + return Math.max(0, this.getMaxScrollPosition() - this.getBounds().height + 4); + } + + protected int getMaxScrollPosition() { + int i = 0; + for (Text entry : texts) { + i += entry == null ? 4 : font.fontHeight; + } + return i; + } + + @Override + public Rectangle getBounds() { + return bounds; + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + updatePosition(delta); + Rectangle innerBounds = new Rectangle(bounds.x + 1, bounds.y + 1, bounds.width - 7, bounds.height - 2); + ScissorsHandler.INSTANCE.scissor(innerBounds); + int currentY = (int) -scroll + innerBounds.y; + for (Text text : texts) { + if (text != null && currentY + font.fontHeight >= innerBounds.y && currentY <= innerBounds.getMaxY()) { + font.draw(text.asFormattedString(), innerBounds.x + 2, currentY + 2, ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : 0xFF090909); + } + currentY += text == null ? 4 : font.fontHeight; + } + ScissorsHandler.INSTANCE.removeLastScissor(); + ScissorsHandler.INSTANCE.scissor(bounds); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(770, 771, 0, 1); + RenderSystem.disableAlphaTest(); + RenderSystem.shadeModel(7425); + RenderSystem.disableTexture(); + renderScrollBar(); + RenderSystem.enableTexture(); + RenderSystem.shadeModel(7424); + RenderSystem.enableAlphaTest(); + RenderSystem.disableBlend(); + ScissorsHandler.INSTANCE.removeLastScissor(); + } + + @SuppressWarnings("deprecation") + private void renderScrollBar() { + int maxScroll = getMaxScroll(); + int scrollbarPositionMinX = getBounds().getMaxX() - 7; + int scrollbarPositionMaxX = scrollbarPositionMinX + 6; + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + if (maxScroll > 0) { + int height = (int) (((this.getBounds().height - 2f) * (this.getBounds().height - 2f)) / this.getMaxScrollPosition()); + height = MathHelper.clamp(height, 32, this.getBounds().height - 2); + height -= Math.min((scroll < 0 ? (int) -scroll : scroll > maxScroll ? (int) scroll - maxScroll : 0), height * .95); + height = Math.max(10, height); + int minY = Math.min(Math.max((int) scroll * (this.getBounds().height - 2 - height) / maxScroll + getBounds().y + 1, getBounds().y + 1), getBounds().getMaxY() -1 - height); + + boolean hovered = new Rectangle(scrollbarPositionMinX, minY, scrollbarPositionMaxX - scrollbarPositionMinX, height).contains(PointHelper.fromMouse()); + int bottomC = hovered ? 168 : 128; + int topC = hovered ? 222 : 172; + + // Black Bar + buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR); + buffer.vertex(scrollbarPositionMinX, this.getBounds().y + 1, 0.0D).texture(0, 1).color(0, 0, 0, 255).next(); + buffer.vertex(scrollbarPositionMaxX, this.getBounds().y + 1, 0.0D).texture(1, 1).color(0, 0, 0, 255).next(); + buffer.vertex(scrollbarPositionMaxX, getBounds().getMaxY() - 1, 0.0D).texture(1, 0).color(0, 0, 0, 255).next(); + buffer.vertex(scrollbarPositionMinX, getBounds().getMaxY() - 1, 0.0D).texture(0, 0).color(0, 0, 0, 255).next(); + tessellator.draw(); + + // Bottom + buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR); + buffer.vertex(scrollbarPositionMinX, minY + height, 0.0D).texture(0, 1).color(bottomC, bottomC, bottomC, 255).next(); + buffer.vertex(scrollbarPositionMaxX, minY + height, 0.0D).texture(1, 1).color(bottomC, bottomC, bottomC, 255).next(); + buffer.vertex(scrollbarPositionMaxX, minY, 0.0D).texture(1, 0).color(bottomC, bottomC, bottomC, 255).next(); + buffer.vertex(scrollbarPositionMinX, minY, 0.0D).texture(0, 0).color(bottomC, bottomC, bottomC, 255).next(); + tessellator.draw(); + + // Top + buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR); + buffer.vertex(scrollbarPositionMinX, (minY + height - 1), 0.0D).texture(0, 1).color(topC, topC, topC, 255).next(); + buffer.vertex((scrollbarPositionMaxX - 1), (minY + height - 1), 0.0D).texture(1, 1).color(topC, topC, topC, 255).next(); + buffer.vertex((scrollbarPositionMaxX - 1), minY, 0.0D).texture(1, 0).color(topC, topC, topC, 255).next(); + buffer.vertex(scrollbarPositionMinX, minY, 0.0D).texture(0, 0).color(topC, topC, topC, 255).next(); + tessellator.draw(); + } + } + + private void updatePosition(float delta) { + target = clamp(target); + if (target < 0) { + target -= target * (1 - ClothConfigInitializer.getBounceBackMultiplier()) * delta / 3; + } else if (target > getMaxScroll()) { + target = (target - getMaxScroll()) * (1 - (1 - ClothConfigInitializer.getBounceBackMultiplier()) * delta / 3) + getMaxScroll(); + } + if (!DynamicNewSmoothScrollingEntryListWidget.Precision.almostEquals(scroll, target, DynamicNewSmoothScrollingEntryListWidget.Precision.FLOAT_EPSILON)) + scroll = (float) DynamicNewSmoothScrollingEntryListWidget.Interpolation.expoEase(scroll, target, Math.min((System.currentTimeMillis() - start) / ((double) duration), 1)); + else + scroll = target; + } + + @Override + public List children() { + return Collections.emptyList(); + } + } +} diff --git a/src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationDisplay.java b/src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationDisplay.java new file mode 100644 index 000000000..84f8c2bbd --- /dev/null +++ b/src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationDisplay.java @@ -0,0 +1,75 @@ +package me.shedaniel.rei.plugin.information; + +import com.google.common.collect.Lists; +import me.shedaniel.rei.api.EntryStack; +import me.shedaniel.rei.api.RecipeDisplay; +import me.shedaniel.rei.plugin.DefaultPlugin; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class DefaultInformationDisplay implements RecipeDisplay { + private List entryStacks; + private List texts; + private Text name; + + protected DefaultInformationDisplay(List entryStacks, Text name) { + this.entryStacks = entryStacks; + this.name = name; + this.texts = Lists.newArrayList(); + } + + public static DefaultInformationDisplay createFromEntries(List entryStacks, Text name) { + return new DefaultInformationDisplay(entryStacks, name); + } + + public static DefaultInformationDisplay createFromEntry(EntryStack entryStack, Text name) { + return createFromEntries(Collections.singletonList(entryStack), name); + } + + @Override + public List> getInputEntries() { + return Collections.singletonList(entryStacks); + } + + @Override + public List getOutputEntries() { + return Collections.emptyList(); + } + + public DefaultInformationDisplay line(Text line) { + texts.add(line); + return this; + } + + public DefaultInformationDisplay lines(Text... lines) { + texts.addAll(Arrays.asList(lines)); + return this; + } + + public DefaultInformationDisplay lines(Collection lines) { + texts.addAll(lines); + return this; + } + + List getEntryStacks() { + return entryStacks; + } + + Text getName() { + return name; + } + + List getTexts() { + return texts; + } + + @Override + public Identifier getRecipeCategory() { + return DefaultPlugin.INFO; + } +} diff --git a/src/main/java/me/shedaniel/rei/utils/CollectionUtils.java b/src/main/java/me/shedaniel/rei/utils/CollectionUtils.java index 296c9c747..44d6f5f6d 100644 --- a/src/main/java/me/shedaniel/rei/utils/CollectionUtils.java +++ b/src/main/java/me/shedaniel/rei/utils/CollectionUtils.java @@ -16,6 +16,14 @@ import java.util.function.Predicate; @Internal public class CollectionUtils { + public static List getOrPutEmptyList(Map> map, A key) { + List b = map.get(key); + if (b != null) + return b; + map.put(key, Lists.newArrayList()); + return map.get(key); + } + public static T findFirstOrNullEquals(List list, T obj) { for (T t : list) { if (t.equals(obj)) diff --git a/src/main/resources/assets/roughlyenoughitems/lang/en_us.json b/src/main/resources/assets/roughlyenoughitems/lang/en_us.json index 096539b17..f0391eeef 100755 --- a/src/main/resources/assets/roughlyenoughitems/lang/en_us.json +++ b/src/main/resources/assets/roughlyenoughitems/lang/en_us.json @@ -25,6 +25,7 @@ "category.rei.brewing.result": "Resulted Potion", "category.rei.composting": "Composting", "category.rei.stripping": "Stripping", + "category.rei.information": "Information", "text.rei.composting.chance": "§e%d%% Chance", "text.rei.composting.page": "Page %d", "text.rei.config": "Config", diff --git a/src/main/resources/assets/roughlyenoughitems/textures/gui/display.png b/src/main/resources/assets/roughlyenoughitems/textures/gui/display.png index 98a2392d3..b730c61e7 100644 Binary files a/src/main/resources/assets/roughlyenoughitems/textures/gui/display.png and b/src/main/resources/assets/roughlyenoughitems/textures/gui/display.png differ diff --git a/src/main/resources/assets/roughlyenoughitems/textures/gui/display_dark.png b/src/main/resources/assets/roughlyenoughitems/textures/gui/display_dark.png index d5bd24b90..950fb6afb 100644 Binary files a/src/main/resources/assets/roughlyenoughitems/textures/gui/display_dark.png and b/src/main/resources/assets/roughlyenoughitems/textures/gui/display_dark.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 632df23b3..a3189648c 100755 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -5,7 +5,7 @@ "description": "To allow players to view items and recipes.", "version": "${version}", "authors": [ - "Danielshe" + "shedaniel" ], "contact": { "homepage": "https://minecraft.curseforge.com/projects/roughly-enough-items", @@ -45,19 +45,19 @@ ], "custom": { "rei:translators": { - "English": "Danielshe", + "English": "shedaniel", "Japanese": ["swordglowsblue", "hinataaki"], - "Simplified Chinese": ["XuyuEre", "Danielshe"], - "Traditional Chinese": ["hugoalh", "gxy17886", "Danielshe"], - "French": "Yanis48", - "German": "MelanX", - "Estonian": "Madis0", - "Portuguese": "thiagokenis", - "LOLCAT": "Danielshe", - "Upside Down English": "Danielshe", + "Simplified Chinese": ["XuyuEre", "shedaniel", "SciUniv_Moring", "Takakura-Anri"], + "Traditional Chinese": ["hugoalh", "gxy17886", "shedaniel"], + "French": ["Yanis48", "Koockies"], + "German": ["MelanX", "guntram7"], + "Estonian": ["Madis0"], + "Portuguese": ["thiagokenis"], + "LOLCAT": ["shedaniel", "RaxedMC"], + "Upside Down English": ["shedaniel"], "Brazilian Portuguese": ["thiagokenis", "joaoh1"], - "Bulgarian": "geniiii", - "Russian": "MrYonter" + "Bulgarian": ["geniiii"], + "Russian": ["MrYonter", "kwmika1girl", "LimyChitou", "Great_Manalal", "s3rbug", "TheByKotik", "ebogish"] } } } -- cgit