diff options
| author | Alex <8379108+Alex33856@users.noreply.github.com> | 2025-07-24 16:04:24 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-24 16:04:24 -0400 |
| commit | ab85baafd92ea6f46a879005adb5a40629bbd64d (patch) | |
| tree | 92403035f1f2771b683f22d656ef5dd049a3310a /src/main/java | |
| parent | 4126dccbb67f4afd2eae791e61fde6526a9ca7c5 (diff) | |
| download | Skyblocker-ab85baafd92ea6f46a879005adb5a40629bbd64d.tar.gz Skyblocker-ab85baafd92ea6f46a879005adb5a40629bbd64d.tar.bz2 Skyblocker-ab85baafd92ea6f46a879005adb5a40629bbd64d.zip | |
REI /viewrecipe Crafting, Skyblock Info Display (#1496)
* Skyblock Info Display + /viewrecipe Crafting
* Don't register global display generator if already there
* Check if /viewrecipe failed, use similar system for item price lookup failure
* Exclude Forge recipes
* Update comment
* Update Item Price Lookup keybind translation
Diffstat (limited to 'src/main/java')
8 files changed, 286 insertions, 5 deletions
diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockTransferHandler.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockTransferHandler.java new file mode 100644 index 00000000..8272a474 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockTransferHandler.java @@ -0,0 +1,81 @@ +package de.hysky.skyblocker.compatibility.rei; + +import de.hysky.skyblocker.compatibility.rei.info.SkyblockInfoCategory; +import de.hysky.skyblocker.skyblock.itemlist.recipes.SkyblockCraftingRecipe; +import de.hysky.skyblocker.utils.NEURepoManager; +import de.hysky.skyblocker.utils.scheduler.MessageScheduler; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import io.github.moulberry.repo.data.NEUCraftingRecipe; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.api.common.entry.EntryStack; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; +import net.minecraft.item.ItemStack; +import net.minecraft.text.Text; + +public class SkyblockTransferHandler implements TransferHandler { + private static final int MAX_FAIL_COUNT = 5; + + private String FAILED_ITEM; + private int FAIL_COUNT; + + @Override + public ApplicabilityResult checkApplicable(Context context) { + // Only work on our displays + CategoryIdentifier<?> identifier = context.getDisplay().getCategoryIdentifier(); + if (identifier != CategoryIdentifier.of(SkyblockCraftingRecipe.IDENTIFIER) && identifier != CategoryIdentifier.of(SkyblockInfoCategory.IDENTIFIER)) + return ApplicabilityResult.createNotApplicable(); + + EntryIngredient ingredient = context.getDisplay().getOutputEntries().getFirst(); + EntryStack<?> entryStack = ingredient.getFirst(); + if (!(entryStack.getValue() instanceof ItemStack itemStack)) + return ApplicabilityResult.createNotApplicable(); + + // Not applicable if it has 0 recipes, or no crafting recipe + String neuId = itemStack.getNeuName(); + if (!NEURepoManager.getRecipes().containsKey(neuId) || NEURepoManager.getRecipes().get(neuId).stream().noneMatch(recipe -> recipe instanceof NEUCraftingRecipe)) + return ApplicabilityResult.createApplicableWithError(Text.translatable("skyblocker.rei.transfer.noRecipe")); + + return ApplicabilityResult.createApplicable(); + + } + + private boolean hasFailed(String skyblockId) { + if (skyblockId.equals(FAILED_ITEM)) { + if (FAIL_COUNT < MAX_FAIL_COUNT) { + FAIL_COUNT += 1; + return true; + } + + FAILED_ITEM = ""; + FAIL_COUNT = 0; + } + return false; + } + + private void checkScreen(String skyblockId) { + Screen currentScreen = MinecraftClient.getInstance().currentScreen; + if (!(currentScreen instanceof GenericContainerScreen)) { + FAIL_COUNT = 0; + FAILED_ITEM = skyblockId; + } + } + + @Override + public Result handle(Context context) { + EntryIngredient ingredient = context.getDisplay().getOutputEntries().getFirst(); + EntryStack<?> entryStack = ingredient.getFirst(); + if (!(entryStack.getValue() instanceof ItemStack itemStack)) return Result.createNotApplicable(); + + String skyblockId = itemStack.getSkyblockId(); + if (hasFailed(skyblockId)) return Result.createFailed(Text.translatable("skyblocker.rei.transfer.failed")); + if (!context.isActuallyCrafting()) return Result.createSuccessful(); + + MessageScheduler.INSTANCE.sendMessageAfterCooldown("/viewrecipe " + skyblockId, false); + Scheduler.INSTANCE.schedule(() -> checkScreen(skyblockId), 5); + return Result.createSuccessful(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockerREIClientPlugin.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockerREIClientPlugin.java index 59a694f6..febcf032 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockerREIClientPlugin.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockerREIClientPlugin.java @@ -1,5 +1,9 @@ package de.hysky.skyblocker.compatibility.rei; +import de.hysky.skyblocker.compatibility.rei.info.SkyblockInfoCategory; +import de.hysky.skyblocker.compatibility.rei.info.SkyblockInfoDisplayGenerator; +import de.hysky.skyblocker.compatibility.rei.recipe.SkyblockRecipeCategory; +import de.hysky.skyblocker.compatibility.rei.recipe.SkyblockRecipeDisplayGenerator; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor; import de.hysky.skyblocker.skyblock.garden.visitor.VisitorHelper; @@ -15,6 +19,7 @@ import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.registry.screen.ExclusionZones; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.util.EntryStacks; import net.minecraft.client.gui.screen.Screen; @@ -29,19 +34,24 @@ import java.util.List; */ public class SkyblockerREIClientPlugin implements REIClientPlugin { - @Override + @Override public void registerCategories(CategoryRegistry categoryRegistry) { if (!SkyblockerConfigManager.get().general.itemList.enableItemList) return; categoryRegistry.addWorkstations(CategoryIdentifier.of(SkyblockCraftingRecipe.IDENTIFIER), EntryStacks.of(Items.CRAFTING_TABLE)); categoryRegistry.addWorkstations(CategoryIdentifier.of(SkyblockForgeRecipe.IDENTIFIER), EntryStacks.of(Items.ANVIL)); categoryRegistry.add(new SkyblockRecipeCategory(SkyblockCraftingRecipe.IDENTIFIER, Text.translatable("emi.category.skyblocker.skyblock_crafting"), ItemUtils.getSkyblockerStack(), 73)); categoryRegistry.add(new SkyblockRecipeCategory(SkyblockForgeRecipe.IDENTIFIER, Text.translatable("emi.category.skyblocker.skyblock_forge"), ItemUtils.getSkyblockerForgeStack(), 84)); + + categoryRegistry.add(new SkyblockInfoCategory()); } @Override public void registerDisplays(DisplayRegistry displayRegistry) { if (!SkyblockerConfigManager.get().general.itemList.enableItemList) return; - displayRegistry.registerGlobalDisplayGenerator(new SkyblockRecipeDisplayGenerator()); + if (displayRegistry.getGlobalDisplayGenerators().stream().noneMatch(generator -> generator instanceof SkyblockRecipeDisplayGenerator)) + displayRegistry.registerGlobalDisplayGenerator(new SkyblockRecipeDisplayGenerator()); + if (displayRegistry.getGlobalDisplayGenerators().stream().noneMatch(generator -> generator instanceof SkyblockInfoDisplayGenerator)) + displayRegistry.registerGlobalDisplayGenerator(new SkyblockInfoDisplayGenerator()); } @Override @@ -66,6 +76,12 @@ public class SkyblockerREIClientPlugin implements REIClientPlugin { } @Override + public void registerTransferHandlers(TransferHandlerRegistry registry) { + if (!SkyblockerConfigManager.get().general.itemList.enableItemList) return; + registry.register(new SkyblockTransferHandler()); + } + + @Override public double getPriority() { return -50; } diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoCategory.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoCategory.java new file mode 100644 index 00000000..d1e48458 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoCategory.java @@ -0,0 +1,114 @@ +package de.hysky.skyblocker.compatibility.rei.info; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.skyblock.item.ItemPrice; +import de.hysky.skyblocker.skyblock.item.WikiLookup; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; +import de.hysky.skyblocker.utils.render.gui.AbstractCustomHypixelGUI; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.gui.widgets.Slot; +import me.shedaniel.rei.api.client.gui.widgets.Widget; +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.EntryStack; +import me.shedaniel.rei.api.common.util.EntryStacks; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.DirectionalLayoutWidget; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.util.ArrayList; +import java.util.List; + +public class SkyblockInfoCategory implements DisplayCategory<SkyblockInfoDisplay> { + private static final int REI_SLOT_HEIGHT = 18; + private static final int OFFSET = 10; + private static final int RED_ERROR_COLOR = 0xFFFF5555; + private static final EntryStack<ItemStack> ICON = EntryStacks.of(new ItemStack(Items.CHEST)); + + public static final Identifier IDENTIFIER = Identifier.of(SkyblockerMod.NAMESPACE, "skyblock_info"); + + @Override + public CategoryIdentifier<? extends SkyblockInfoDisplay> getCategoryIdentifier() { + return CategoryIdentifier.of(IDENTIFIER); + } + + @Override + public Text getTitle() { + return Text.translatable("emi.category.skyblocker.skyblock_info"); + } + + @Override + public Renderer getIcon() { + return ICON; + } + + private ButtonWidget getWikiLookupButton(Text text, boolean isOfficial, ItemStack itemStack, ClientPlayerEntity player) { + ButtonWidget btn = ButtonWidget.builder(text, (button) -> WikiLookup.openWiki(itemStack, player, isOfficial)).build(); + + if (ItemRepository.getWikiLink(itemStack.getNeuName(), isOfficial) == null) { + btn.setMessage(btn.getMessage().copy().withColor(RED_ERROR_COLOR)); + btn.active = false; + } + + return btn; + } + + private boolean checkScreen() { + Screen currentScreen = MinecraftClient.getInstance().currentScreen; + return currentScreen instanceof GenericContainerScreen || currentScreen instanceof AbstractCustomHypixelGUI<?>; + } + + @Override + public List<Widget> setupDisplay(SkyblockInfoDisplay display, Rectangle bounds) { + List<Widget> widgets = new ArrayList<>(); + EntryStack<?> entryStack = display.getInputEntries().getFirst().getFirst(); + if (!(entryStack.getValue() instanceof ItemStack itemStack)) return widgets; + + widgets.add(Widgets.createRecipeBase(bounds)); + Slot slot = Widgets.createSlot(new Point(bounds.getCenterX() - 9 + 1, bounds.y + 1 + OFFSET / 2)).entry(entryStack); + widgets.add(slot); + + ClientPlayerEntity player = MinecraftClient.getInstance().player; + DirectionalLayoutWidget layoutWidget = DirectionalLayoutWidget.vertical(); + layoutWidget.setPosition(bounds.x + OFFSET, bounds.y + OFFSET + REI_SLOT_HEIGHT); + + layoutWidget.add(ButtonWidget.builder(Text.translatable("key.itemPriceLookup"), (button) -> { + ItemPrice.itemPriceLookup(player, itemStack); + + Scheduler.INSTANCE.schedule(() -> { + if (checkScreen()) return; + button.setMessage(Text.translatable("skyblocker.rei.skyblockInfo.failedToFind").withColor(RED_ERROR_COLOR)); + button.active = false; + }, 10); + }).build()); + + layoutWidget.add(getWikiLookupButton(Text.translatable("key.wikiLookup.official"), true, itemStack, player)); + layoutWidget.add(getWikiLookupButton(Text.translatable("key.wikiLookup.fandom"), false, itemStack, player)); + + layoutWidget.forEachChild(child -> widgets.add(Widgets.wrapVanillaWidget(child))); + layoutWidget.refreshPositions(); + + return widgets; + } + + @Override + public int getDisplayHeight() { + return 3 * ButtonWidget.DEFAULT_HEIGHT + REI_SLOT_HEIGHT + 2 * OFFSET; + } + + @Override + public int getDisplayWidth(SkyblockInfoDisplay display) { + return 150 + 20; + } +} diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoDisplay.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoDisplay.java new file mode 100644 index 00000000..22714941 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoDisplay.java @@ -0,0 +1,47 @@ +package de.hysky.skyblocker.compatibility.rei.info; + +import de.hysky.skyblocker.SkyblockerMod; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.display.DisplaySerializer; +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.api.common.util.EntryStacks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Optional; + +public class SkyblockInfoDisplay implements Display { + private final ItemStack displayItem; + + public SkyblockInfoDisplay(ItemStack item) { + this.displayItem = item; + } + + @Override + public List<EntryIngredient> getInputEntries() { + return List.of(EntryIngredient.of(EntryStacks.of(displayItem))); + } + + @Override + public List<EntryIngredient> getOutputEntries() { + return List.of(EntryIngredient.of(EntryStacks.of(displayItem))); + } + + @Override + public CategoryIdentifier<?> getCategoryIdentifier() { + return CategoryIdentifier.of(Identifier.of(SkyblockerMod.NAMESPACE, "skyblock_info")); + } + + @Override + public Optional<Identifier> getDisplayLocation() { + return Optional.empty(); + } + + @Override + public @Nullable DisplaySerializer<? extends Display> getSerializer() { + return null; + } +} diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoDisplayGenerator.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoDisplayGenerator.java new file mode 100644 index 00000000..2b440220 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/info/SkyblockInfoDisplayGenerator.java @@ -0,0 +1,23 @@ +package de.hysky.skyblocker.compatibility.rei.info; + +import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator; +import me.shedaniel.rei.api.common.entry.EntryStack; +import net.minecraft.item.ItemStack; + +import java.util.List; +import java.util.Optional; + +public class SkyblockInfoDisplayGenerator implements DynamicDisplayGenerator<SkyblockInfoDisplay> { + @Override + public Optional<List<SkyblockInfoDisplay>> getRecipeFor(EntryStack<?> entry) { + if (!(entry.getValue() instanceof ItemStack entryStack)) return Optional.empty(); + if (entryStack.getSkyblockId().isEmpty()) return Optional.empty(); + entryStack.setCount(1); + return Optional.of(List.of(new SkyblockInfoDisplay(entryStack))); + } + + @Override + public Optional<List<SkyblockInfoDisplay>> getUsageFor(EntryStack<?> entry) { + return getRecipeFor(entry); + } +} diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockRecipeCategory.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/recipe/SkyblockRecipeCategory.java index 0460a1cf..167bafcf 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockRecipeCategory.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/recipe/SkyblockRecipeCategory.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.compatibility.rei; +package de.hysky.skyblocker.compatibility.rei.recipe; import de.hysky.skyblocker.skyblock.itemlist.recipes.SkyblockRecipe; import me.shedaniel.math.Point; diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockRecipeDisplay.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/recipe/SkyblockRecipeDisplay.java index 44d44011..640497c0 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockRecipeDisplay.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/recipe/SkyblockRecipeDisplay.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.compatibility.rei; +package de.hysky.skyblocker.compatibility.rei.recipe; import de.hysky.skyblocker.skyblock.itemlist.recipes.SkyblockRecipe; import me.shedaniel.rei.api.common.category.CategoryIdentifier; diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockRecipeDisplayGenerator.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/recipe/SkyblockRecipeDisplayGenerator.java index 2b9775c6..6ac36288 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockRecipeDisplayGenerator.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/recipe/SkyblockRecipeDisplayGenerator.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.compatibility.rei; +package de.hysky.skyblocker.compatibility.rei.recipe; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator; |
