mirror of
https://github.com/AlmostReliable/almostunified.git
synced 2024-11-14 19:25:13 -05:00
implement JEI decorators for indicator
This commit is contained in:
parent
a784c3055e
commit
dc957b7ab8
11 changed files with 92 additions and 106 deletions
|
@ -48,6 +48,6 @@ public interface AlmostUnifiedPlatform {
|
||||||
|
|
||||||
enum Platform {
|
enum Platform {
|
||||||
FORGE,
|
FORGE,
|
||||||
FABRIC;
|
FABRIC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,22 @@ import com.almostreliable.unified.AlmostUnifiedFallbackRuntime;
|
||||||
import com.almostreliable.unified.api.ModConstants;
|
import com.almostreliable.unified.api.ModConstants;
|
||||||
import com.almostreliable.unified.config.UnifyConfig;
|
import com.almostreliable.unified.config.UnifyConfig;
|
||||||
import com.almostreliable.unified.recipe.CRTLookup;
|
import com.almostreliable.unified.recipe.CRTLookup;
|
||||||
|
import com.almostreliable.unified.recipe.ClientRecipeTracker.ClientRecipeLink;
|
||||||
import com.almostreliable.unified.utils.Utils;
|
import com.almostreliable.unified.utils.Utils;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import me.shedaniel.rei.plugincompatibilities.api.REIPluginCompatIgnore;
|
import me.shedaniel.rei.plugincompatibilities.api.REIPluginCompatIgnore;
|
||||||
import mezz.jei.api.IModPlugin;
|
import mezz.jei.api.IModPlugin;
|
||||||
import mezz.jei.api.JeiPlugin;
|
import mezz.jei.api.JeiPlugin;
|
||||||
import mezz.jei.api.constants.VanillaTypes;
|
import mezz.jei.api.constants.VanillaTypes;
|
||||||
|
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
|
||||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||||
|
import mezz.jei.api.recipe.category.extensions.IRecipeCategoryDecorator;
|
||||||
|
import mezz.jei.api.registration.IAdvancedRegistration;
|
||||||
import mezz.jei.api.runtime.IJeiRuntime;
|
import mezz.jei.api.runtime.IJeiRuntime;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.renderer.Rect2i;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@REIPluginCompatIgnore
|
@REIPluginCompatIgnore
|
||||||
|
@ -45,19 +48,37 @@ public class AlmostJEI implements IModPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <R> void handleIndicator(GuiGraphics guiGraphics, PoseStack stack, int mX, int mY, int posX, int posY, IRecipeCategory<R> recipeCategory, R recipe) {
|
@Override
|
||||||
var recipeId = recipeCategory.getRegistryName(recipe);
|
public void registerAdvanced(IAdvancedRegistration registration) {
|
||||||
if (recipeId == null) return;
|
var recipeTypes = registration.getJeiHelpers().getAllRecipeTypes();
|
||||||
|
recipeTypes.forEach(rt -> registration.addRecipeCategoryDecorator(rt, new Decorator<>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Decorator<T> implements IRecipeCategoryDecorator<T> {
|
||||||
|
|
||||||
var link = CRTLookup.getLink(recipeId);
|
private static final int RECIPE_BORDER_PADDING = 4;
|
||||||
if (link == null) return;
|
|
||||||
|
|
||||||
var area = new Rect2i(posX, posY, RecipeIndicator.RENDER_SIZE, RecipeIndicator.RENDER_SIZE);
|
@Override
|
||||||
RecipeIndicator.renderIndicator(guiGraphics, stack, area);
|
public void draw(T recipe, IRecipeCategory<T> recipeCategory, IRecipeSlotsView recipeSlotsView, GuiGraphics guiGraphics, double mouseX, double mouseY) {
|
||||||
if (mX >= area.getX() && mX <= area.getX() + area.getWidth() &&
|
var recipeLink = resolveLink(recipeCategory, recipe);
|
||||||
mY >= area.getY() && mY <= area.getY() + area.getHeight()) {
|
if (recipeLink == null) return;
|
||||||
Utils.renderTooltip(guiGraphics, mX, mY, RecipeIndicator.constructTooltip(link));
|
|
||||||
|
var pX = recipeCategory.getWidth() + (2 * RECIPE_BORDER_PADDING) - RecipeIndicator.RENDER_SIZE;
|
||||||
|
var pY = recipeCategory.getHeight() + (2 * RECIPE_BORDER_PADDING) - RecipeIndicator.RENDER_SIZE;
|
||||||
|
RecipeIndicator.renderIndicator(guiGraphics, pX, pY, RecipeIndicator.RENDER_SIZE);
|
||||||
|
|
||||||
|
if (mouseX >= pX && mouseX <= pX + RecipeIndicator.RENDER_SIZE &&
|
||||||
|
mouseY >= pY && mouseY <= pY + RecipeIndicator.RENDER_SIZE) {
|
||||||
|
RecipeIndicator.renderTooltip(guiGraphics, recipeLink, mouseX, mouseY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static <R> ClientRecipeLink resolveLink(IRecipeCategory<R> recipeCategory, R recipe) {
|
||||||
|
var recipeId = recipeCategory.getRegistryName(recipe);
|
||||||
|
if (recipeId == null) return null;
|
||||||
|
|
||||||
|
return CRTLookup.getLink(recipeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import me.shedaniel.rei.api.common.display.Display;
|
||||||
import me.shedaniel.rei.api.common.plugins.PluginManager;
|
import me.shedaniel.rei.api.common.plugins.PluginManager;
|
||||||
import me.shedaniel.rei.api.common.registry.ReloadStage;
|
import me.shedaniel.rei.api.common.registry.ReloadStage;
|
||||||
import me.shedaniel.rei.api.common.util.EntryIngredients;
|
import me.shedaniel.rei.api.common.util.EntryIngredients;
|
||||||
import net.minecraft.client.renderer.Rect2i;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -99,21 +98,30 @@ public class AlmostREI implements REIClientPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Widget> setupDisplay(Display display, Rectangle bounds) {
|
public List<Widget> setupDisplay(Display display, Rectangle bounds) {
|
||||||
var widgets = lastView.setupDisplay(display, bounds);
|
int pX;
|
||||||
var area = calculateArea(bounds);
|
int pY;
|
||||||
widgets.add(Widgets.createDrawableWidget((guiGraphics, mX, mY, delta) ->
|
int size;
|
||||||
RecipeIndicator.renderIndicator(guiGraphics, guiGraphics.pose(), area)));
|
|
||||||
var tooltipArea = new Rectangle(area.getX(), area.getY(), area.getWidth(), area.getHeight());
|
|
||||||
widgets.add(Widgets.createTooltip(tooltipArea, RecipeIndicator.constructTooltip(link)));
|
|
||||||
return widgets;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rect2i calculateArea(Rectangle bounds) {
|
|
||||||
if (plusButtonArea != null) {
|
if (plusButtonArea != null) {
|
||||||
var area = plusButtonArea.get(bounds);
|
var area = plusButtonArea.get(bounds);
|
||||||
return new Rect2i(area.x, area.y - area.height - 2, area.width, area.height);
|
pX = area.x;
|
||||||
|
pY = area.y - area.height - 2;
|
||||||
|
size = area.width;
|
||||||
|
} else {
|
||||||
|
pX = bounds.x - RecipeIndicator.RENDER_SIZE / 2;
|
||||||
|
pY = bounds.y - RecipeIndicator.RENDER_SIZE / 2;
|
||||||
|
size = RecipeIndicator.RENDER_SIZE;
|
||||||
}
|
}
|
||||||
return new Rect2i(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
||||||
|
var widgets = lastView.setupDisplay(display, bounds);
|
||||||
|
widgets.add(Widgets.createDrawableWidget(
|
||||||
|
(guiGraphics, mX, mY, delta) -> RecipeIndicator.renderIndicator(guiGraphics, pX, pY, size)
|
||||||
|
));
|
||||||
|
|
||||||
|
var tooltipArea = new Rectangle(pX, pY, size, size);
|
||||||
|
widgets.add(Widgets.createTooltip(tooltipArea, RecipeIndicator.constructTooltip(link)));
|
||||||
|
|
||||||
|
return widgets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,34 @@ package com.almostreliable.unified.compat;
|
||||||
|
|
||||||
import com.almostreliable.unified.recipe.ClientRecipeTracker.ClientRecipeLink;
|
import com.almostreliable.unified.recipe.ClientRecipeTracker.ClientRecipeLink;
|
||||||
import com.almostreliable.unified.utils.Utils;
|
import com.almostreliable.unified.utils.Utils;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.renderer.Rect2i;
|
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public final class RecipeIndicator {
|
final class RecipeIndicator {
|
||||||
|
|
||||||
public static final int RENDER_SIZE = 10;
|
static final int RENDER_SIZE = 10;
|
||||||
private static final int TEXTURE_SIZE = 16;
|
private static final int TEXTURE_SIZE = 16;
|
||||||
private static final ResourceLocation TEXTURE = Utils.getRL("textures/ingot.png");
|
private static final ResourceLocation TEXTURE = Utils.getRL("textures/ingot.png");
|
||||||
|
|
||||||
private RecipeIndicator() {}
|
private RecipeIndicator() {}
|
||||||
|
|
||||||
|
static void renderIndicator(GuiGraphics guiGraphics, int pX, int pY, int size) {
|
||||||
|
var poseStack = guiGraphics.pose();
|
||||||
|
poseStack.pushPose();
|
||||||
|
|
||||||
|
poseStack.translate(pX, pY, 0);
|
||||||
|
var scale = size / (float) TEXTURE_SIZE;
|
||||||
|
poseStack.scale(scale, scale, scale);
|
||||||
|
guiGraphics.blit(TEXTURE, 0, 0, 0, 0, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE);
|
||||||
|
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
static List<Component> constructTooltip(ClientRecipeLink link) {
|
static List<Component> constructTooltip(ClientRecipeLink link) {
|
||||||
var unified = Component.translatable(Utils.prefix("unified")).append(": ")
|
var unified = Component.translatable(Utils.prefix("unified")).append(": ")
|
||||||
.withStyle(c -> c.withColor(ChatFormatting.AQUA));
|
.withStyle(c -> c.withColor(ChatFormatting.AQUA));
|
||||||
|
@ -32,22 +43,30 @@ public final class RecipeIndicator {
|
||||||
|
|
||||||
return List.of(
|
return List.of(
|
||||||
Component.translatable(Utils.prefix("description")).withStyle(c -> c.withColor(ChatFormatting.GOLD)),
|
Component.translatable(Utils.prefix("description")).withStyle(c -> c.withColor(ChatFormatting.GOLD)),
|
||||||
Component.literal(""),
|
Component.literal(" "),
|
||||||
unified,
|
unified,
|
||||||
duplicate,
|
duplicate,
|
||||||
Component.literal(""),
|
Component.literal(" "),
|
||||||
Component.translatable(Utils.prefix("warning")).withStyle(c -> c.withColor(ChatFormatting.RED))
|
Component.translatable(Utils.prefix("warning")).withStyle(c -> c.withColor(ChatFormatting.RED))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void renderIndicator(GuiGraphics guiGraphics, PoseStack poseStack, Rect2i area) {
|
static void renderTooltip(GuiGraphics guiGraphics, ClientRecipeLink link, double mouseX, double mouseY) {
|
||||||
poseStack.pushPose();
|
var mc = Minecraft.getInstance();
|
||||||
poseStack.translate(area.getX(), area.getY(), 0);
|
var font = mc.font;
|
||||||
var scale = area.getWidth() / (float) TEXTURE_SIZE;
|
var screen = mc.screen;
|
||||||
poseStack.scale(scale, scale, scale);
|
if (screen == null) return;
|
||||||
guiGraphics.blit(TEXTURE, 0, 0, 0, 0, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE);
|
|
||||||
poseStack.popPose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public record RenderEntry(int pX, int pY) {}
|
var tooltip = constructTooltip(link).stream()
|
||||||
|
.map(c -> font.split(c, screen.width - (int) mouseX - 200))
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
guiGraphics.renderTooltip(
|
||||||
|
font,
|
||||||
|
tooltip,
|
||||||
|
(int) mouseX,
|
||||||
|
(int) mouseY
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
package com.almostreliable.unified.mixin.compat;
|
|
||||||
|
|
||||||
import com.almostreliable.unified.compat.AlmostJEI;
|
|
||||||
import com.almostreliable.unified.compat.RecipeIndicator;
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import mezz.jei.api.gui.drawable.IDrawable;
|
|
||||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
|
||||||
import mezz.jei.library.gui.recipes.RecipeLayout;
|
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
|
||||||
|
|
||||||
@Mixin(RecipeLayout.class)
|
|
||||||
public abstract class JeiRecipeLayoutMixin<R> {
|
|
||||||
|
|
||||||
@Shadow(remap = false) @Final
|
|
||||||
private IRecipeCategory<R> recipeCategory;
|
|
||||||
@Shadow(remap = false) @Final
|
|
||||||
private R recipe;
|
|
||||||
|
|
||||||
@Inject(method = "drawRecipe", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V", ordinal = 1), locals = LocalCapture.CAPTURE_FAILHARD)
|
|
||||||
private void unified$catchLayoutInfo(GuiGraphics guiGraphics, int mouseX, int mouseY, CallbackInfo ci, IDrawable background, int mX, int mY, PoseStack poseStack, int x, int y) {
|
|
||||||
var posX = x - RecipeIndicator.RENDER_SIZE;
|
|
||||||
var posY = y - RecipeIndicator.RENDER_SIZE;
|
|
||||||
AlmostJEI.handleIndicator(guiGraphics, poseStack, mX, mY, posX, posY, recipeCategory, recipe);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
|
||||||
package com.almostreliable.unified.mixin.compat;
|
|
||||||
|
|
||||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
|
@ -1,17 +1,10 @@
|
||||||
package com.almostreliable.unified.utils;
|
package com.almostreliable.unified.utils;
|
||||||
|
|
||||||
import com.almostreliable.unified.BuildConfig;
|
import com.almostreliable.unified.BuildConfig;
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.ComponentRenderUtils;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.util.FormattedCharSequence;
|
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
public static final ResourceLocation UNUSED_ID = new ResourceLocation(BuildConfig.MOD_ID, "unused_id");
|
public static final ResourceLocation UNUSED_ID = new ResourceLocation(BuildConfig.MOD_ID, "unused_id");
|
||||||
|
@ -44,16 +37,4 @@ public final class Utils {
|
||||||
public static String prefix(String path) {
|
public static String prefix(String path) {
|
||||||
return BuildConfig.MOD_ID + "." + path;
|
return BuildConfig.MOD_ID + "." + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void renderTooltip(GuiGraphics guiGraphics, int mX, int mY, List<Component> tooltip) {
|
|
||||||
var mc = Minecraft.getInstance();
|
|
||||||
var screen = mc.screen;
|
|
||||||
if (screen == null) return;
|
|
||||||
|
|
||||||
List<FormattedCharSequence> formattedTooltip = new ArrayList<>(tooltip.size());
|
|
||||||
for (Component line : tooltip) {
|
|
||||||
formattedTooltip.addAll(ComponentRenderUtils.wrapComponents(line, 300, mc.font));
|
|
||||||
}
|
|
||||||
guiGraphics.renderTooltip(mc.font, formattedTooltip, mX, mY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
"unifier.TieredItemMixin"
|
"unifier.TieredItemMixin"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"compat.JeiRecipeLayoutMixin",
|
|
||||||
"runtime.ClientPacketListenerMixin"
|
"runtime.ClientPacketListenerMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
|
|
|
@ -34,10 +34,8 @@ dependencies {
|
||||||
shadowCommon(project(":Common", "transformProductionFabric")) { isTransitive = false }
|
shadowCommon(project(":Common", "transformProductionFabric")) { isTransitive = false }
|
||||||
|
|
||||||
// compile time mods
|
// compile time mods
|
||||||
|
modCompileOnly("mezz.jei:jei-$minecraftVersion-fabric-api:$jeiVersion") // required for common jei plugin
|
||||||
modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:$reiVersion") // required for common rei plugin
|
modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:$reiVersion") // required for common rei plugin
|
||||||
compileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // required to disable rei compat layer on jei plugin
|
|
||||||
testCompileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // don't question this, it's required for compiling
|
|
||||||
modCompileOnly("mezz.jei:jei-$minecraftVersion-fabric-api:$jeiVersion") // required for common jei plugin and mixin
|
|
||||||
|
|
||||||
// runtime dependencies
|
// runtime dependencies
|
||||||
modLocalRuntime(
|
modLocalRuntime(
|
||||||
|
|
|
@ -52,12 +52,10 @@ dependencies {
|
||||||
shadowCommon(project(":Common", "transformProductionForge")) { isTransitive = false }
|
shadowCommon(project(":Common", "transformProductionForge")) { isTransitive = false }
|
||||||
|
|
||||||
// compile time mods
|
// compile time mods
|
||||||
modCompileOnly("me.shedaniel:RoughlyEnoughItems-forge:$reiVersion") // required for common rei plugin | api does not work here
|
modCompileOnly("mezz.jei:jei-$minecraftVersion-forge-api:$jeiVersion") { // required for common jei plugin
|
||||||
compileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // required to disable rei compat layer on jei plugin
|
|
||||||
testCompileOnly("me.shedaniel:REIPluginCompatibilities-forge-annotations:9.+") // don't question this, it's required for compiling
|
|
||||||
modCompileOnly("mezz.jei:jei-$minecraftVersion-forge-api:$jeiVersion") { // required for common jei plugin and mixin
|
|
||||||
isTransitive = false // prevents breaking the forge runtime
|
isTransitive = false // prevents breaking the forge runtime
|
||||||
}
|
}
|
||||||
|
modCompileOnly("me.shedaniel:RoughlyEnoughItems-forge:$reiVersion") // required for common rei plugin
|
||||||
|
|
||||||
// runtime mods
|
// runtime mods
|
||||||
when (forgeRecipeViewer) {
|
when (forgeRecipeViewer) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ junitVersion = 5.9.0
|
||||||
parchmentVersion = 2023.07.23
|
parchmentVersion = 2023.07.23
|
||||||
|
|
||||||
# Mod Dependencies
|
# Mod Dependencies
|
||||||
jeiVersion = 15.0.0.12
|
jeiVersion = 15.1.0.18
|
||||||
reiVersion = 12.0.625
|
reiVersion = 12.0.625
|
||||||
|
|
||||||
# Fabric Dependencies
|
# Fabric Dependencies
|
||||||
|
|
Loading…
Reference in a new issue