配方书签功能移植

This commit is contained in:
GaLi 2026-03-01 16:20:06 +08:00
parent 88370db511
commit b5ac0b6fbe
2 changed files with 122 additions and 1 deletions

View File

@ -123,6 +123,10 @@ public final class CtrlQPatternKeyHandler {
try { try {
ResourceLocation recipeId = getRecipeId(recipeBookmark); ResourceLocation recipeId = getRecipeId(recipeBookmark);
if (recipeId == null) { if (recipeId == null) {
Minecraft mc = Minecraft.getInstance();
if (mc.player != null) {
mc.player.displayClientMessage(Component.translatable("message.extendedae_plus.recipe_not_found"), true);
}
return; return;
} }
@ -164,6 +168,10 @@ public final class CtrlQPatternKeyHandler {
try { try {
ResourceLocation recipeId = getRecipeId(recipeBookmark); ResourceLocation recipeId = getRecipeId(recipeBookmark);
if (recipeId == null) { if (recipeId == null) {
Minecraft mc = Minecraft.getInstance();
if (mc.player != null) {
mc.player.displayClientMessage(Component.translatable("message.extendedae_plus.recipe_not_found"), true);
}
return; return;
} }
@ -220,6 +228,18 @@ public final class CtrlQPatternKeyHandler {
} }
} }
try {
var getDisplayIngredientMethod = recipeBookmark.getClass().getMethod("getDisplayIngredient");
Object displayIngredient = getDisplayIngredientMethod.invoke(recipeBookmark);
if (displayIngredient instanceof ITypedIngredient<?> typed) {
List<RecipeInfo> infos = RecipeFinderUtil.findRecipesByIngredient(typed);
if (!infos.isEmpty()) {
return infos;
}
}
} catch (Throwable ignored) {
}
try { try {
var getRecipeOutputMethod = recipeBookmark.getClass().getMethod("getRecipeOutput"); var getRecipeOutputMethod = recipeBookmark.getClass().getMethod("getRecipeOutput");
Object recipeOutput = getRecipeOutputMethod.invoke(recipeBookmark); Object recipeOutput = getRecipeOutputMethod.invoke(recipeBookmark);
@ -241,6 +261,11 @@ public final class CtrlQPatternKeyHandler {
} }
private static ResourceLocation getRecipeId(Object recipeBookmark) { private static ResourceLocation getRecipeId(Object recipeBookmark) {
if (recipeBookmark == null) {
return null;
}
// JEI 1.20 兼容分支
try { try {
var getRecipeUidMethod = recipeBookmark.getClass().getMethod("getRecipeUid"); var getRecipeUidMethod = recipeBookmark.getClass().getMethod("getRecipeUid");
Object recipeId = getRecipeUidMethod.invoke(recipeBookmark); Object recipeId = getRecipeUidMethod.invoke(recipeBookmark);
@ -249,6 +274,43 @@ public final class CtrlQPatternKeyHandler {
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
// JEI 1.21+ recipeCategory.getRegistryName(recipe) 获取
try {
Object recipe = recipeBookmark.getClass().getMethod("getRecipe").invoke(recipeBookmark);
Object recipeCategory = recipeBookmark.getClass().getMethod("getRecipeCategory").invoke(recipeBookmark);
if (recipe != null && recipeCategory != null) {
try {
Object recipeId = recipeCategory.getClass().getMethod("getRegistryName", Object.class).invoke(recipeCategory, recipe);
if (recipeId instanceof ResourceLocation rl) {
return rl;
}
} catch (Throwable ignored) {
for (var m : recipeCategory.getClass().getMethods()) {
if (!"getRegistryName".equals(m.getName()) || m.getParameterCount() != 1) {
continue;
}
Object recipeId = m.invoke(recipeCategory, recipe);
if (recipeId instanceof ResourceLocation rl) {
return rl;
}
}
}
}
} catch (Throwable ignored) {
}
// 反射字段兜底JEI 内部 RecipeBookmark 存在 recipeUid 字段
try {
var f = recipeBookmark.getClass().getDeclaredField("recipeUid");
f.setAccessible(true);
Object recipeId = f.get(recipeBookmark);
if (recipeId instanceof ResourceLocation rl) {
return rl;
}
} catch (Throwable ignored) {
}
return null; return null;
} }
@ -316,4 +378,3 @@ public final class CtrlQPatternKeyHandler {
.toList(); .toList();
} }
} }

View File

@ -151,6 +151,32 @@ public final class JeiRuntimeProxy {
Object overlay = rt.getClass().getMethod("getBookmarkOverlay").invoke(rt); Object overlay = rt.getClass().getMethod("getBookmarkOverlay").invoke(rt);
if (overlay == null) return Optional.empty(); if (overlay == null) return Optional.empty();
// JEI 1.21 优先路径直接拿鼠标下 clickable element bookmark
try {
double mouseX = getGuiMouseX();
double mouseY = getGuiMouseY();
Object clickableStream = overlay.getClass()
.getMethod("getIngredientUnderMouse", double.class, double.class)
.invoke(overlay, mouseX, mouseY);
if (clickableStream instanceof java.util.stream.Stream<?> stream) {
Object firstClickable = stream.findFirst().orElse(null);
if (firstClickable != null) {
Object element = firstClickable.getClass().getMethod("getElement").invoke(firstClickable);
if (element != null) {
Object bookmarkOpt = element.getClass().getMethod("getBookmark").invoke(element);
if (bookmarkOpt instanceof Optional<?> b && b.isPresent()) {
Object bookmark = b.get();
if (bookmark != null && "RecipeBookmark".equals(bookmark.getClass().getSimpleName())) {
return Optional.of(bookmark);
}
}
}
}
}
} catch (Throwable ignored) {
}
// 兼容回退基于 typed ingredient 匹配 bookmarkList 元素
Object ingredientOpt = overlay.getClass().getMethod("getIngredientUnderMouse").invoke(overlay); Object ingredientOpt = overlay.getClass().getMethod("getIngredientUnderMouse").invoke(overlay);
if (!(ingredientOpt instanceof Optional<?> opt) || opt.isEmpty()) return Optional.empty(); if (!(ingredientOpt instanceof Optional<?> opt) || opt.isEmpty()) return Optional.empty();
Object hoveredIngredient = opt.get(); Object hoveredIngredient = opt.get();
@ -189,6 +215,40 @@ public final class JeiRuntimeProxy {
return Optional.empty(); return Optional.empty();
} }
private static double getGuiMouseX() {
try {
Class<?> mcCls = Class.forName("net.minecraft.client.Minecraft");
Object mc = mcCls.getMethod("getInstance").invoke(null);
Object mouseHandler = mcCls.getField("mouseHandler").get(mc);
Object window = mcCls.getMethod("getWindow").invoke(mc);
double xpos = (double) mouseHandler.getClass().getMethod("xpos").invoke(mouseHandler);
int guiW = (int) window.getClass().getMethod("getGuiScaledWidth").invoke(window);
int screenW = (int) window.getClass().getMethod("getScreenWidth").invoke(window);
if (screenW <= 0) return xpos;
return xpos * ((double) guiW / (double) screenW);
} catch (Throwable ignored) {
return 0.0D;
}
}
private static double getGuiMouseY() {
try {
Class<?> mcCls = Class.forName("net.minecraft.client.Minecraft");
Object mc = mcCls.getMethod("getInstance").invoke(null);
Object mouseHandler = mcCls.getField("mouseHandler").get(mc);
Object window = mcCls.getMethod("getWindow").invoke(mc);
double ypos = (double) mouseHandler.getClass().getMethod("ypos").invoke(mouseHandler);
int guiH = (int) window.getClass().getMethod("getGuiScaledHeight").invoke(window);
int screenH = (int) window.getClass().getMethod("getScreenHeight").invoke(window);
if (screenH <= 0) return ypos;
return ypos * ((double) guiH / (double) screenH);
} catch (Throwable ignored) {
return 0.0D;
}
}
public static void addBookmark(ItemStack stack) { public static void addBookmark(ItemStack stack) {
Object rt = RUNTIME; Object rt = RUNTIME;
if (rt == null || stack == null || stack.isEmpty()) return; if (rt == null || stack == null || stack.isEmpty()) return;