适配JEI新版的历史记录
This commit is contained in:
parent
8d6dc8ef9c
commit
7d621af169
|
|
@ -99,7 +99,7 @@ dependencies {
|
||||||
modRuntimeOnly "curse.maven:advancedae-1084104:6939473"
|
modRuntimeOnly "curse.maven:advancedae-1084104:6939473"
|
||||||
|
|
||||||
modCompileOnly "mezz.jei:jei-${minecraft_version}-forge:${jei_version}"
|
modCompileOnly "mezz.jei:jei-${minecraft_version}-forge:${jei_version}"
|
||||||
modRuntimeOnly "mezz.jei:jei-${minecraft_version}-forge:15.20.0.112"
|
modRuntimeOnly "mezz.jei:jei-${minecraft_version}-forge:15.20.0.129"
|
||||||
modImplementation "mezz.jei:jei-${minecraft_version}-forge:${jei_version}"
|
modImplementation "mezz.jei:jei-${minecraft_version}-forge:${jei_version}"
|
||||||
modImplementation "curse.maven:jade-324717:${jade_version}"
|
modImplementation "curse.maven:jade-324717:${jade_version}"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ glodium_version=5006780
|
||||||
ae2_version=15.4.5
|
ae2_version=15.4.5
|
||||||
guideme_version=20.1.7
|
guideme_version=20.1.7
|
||||||
wireless_terminals_version=5162352
|
wireless_terminals_version=5162352
|
||||||
jei_version=15.19.5.99
|
jei_version=15.20.0.129
|
||||||
applied_flux_version=5329825
|
applied_flux_version=5329825
|
||||||
mega_cells_version=5320730
|
mega_cells_version=5320730
|
||||||
jade_version=4768593
|
jade_version=4768593
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import org.spongepowered.asm.mixin.Pseudo;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -56,6 +57,49 @@ public final class JeiBookmarkBridge {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<ITypedIngredient<?>> getIngredientUnderMouse() {
|
||||||
|
return getIngredientUnderMouse(MouseUtil.getX(), MouseUtil.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<ITypedIngredient<?>> getIngredientUnderMouse(double mouseX, double mouseY) {
|
||||||
|
IJeiRuntime rt = getRuntime();
|
||||||
|
if (rt == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ITypedIngredient<?>> ingredient = getTypedIngredientFromClickableSource(rt.getIngredientListOverlay(), mouseX, mouseY);
|
||||||
|
if (ingredient.isPresent()) {
|
||||||
|
return ingredient;
|
||||||
|
}
|
||||||
|
|
||||||
|
IBookmarkOverlay bookmarkOverlay = rt.getBookmarkOverlay();
|
||||||
|
ingredient = getTypedIngredientFromClickableSource(bookmarkOverlay, mouseX, mouseY);
|
||||||
|
if (ingredient.isPresent()) {
|
||||||
|
return ingredient;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rt.getIngredientListOverlay() != null) {
|
||||||
|
var hovered = rt.getIngredientListOverlay().getIngredientUnderMouse();
|
||||||
|
if (hovered.isPresent()) {
|
||||||
|
return hovered.map(i -> (ITypedIngredient<?>) i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bookmarkOverlay != null) {
|
||||||
|
var hovered = bookmarkOverlay.getIngredientUnderMouse();
|
||||||
|
if (hovered.isPresent()) {
|
||||||
|
return hovered.map(i -> (ITypedIngredient<?>) i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Object> bookmark = getBookmarkUnderMouse(bookmarkOverlay, mouseX, mouseY);
|
||||||
|
if (bookmark.isPresent()) {
|
||||||
|
return getTypedIngredientFromBookmark(bookmark.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
public static void addBookmark(ItemStack stack) {
|
public static void addBookmark(ItemStack stack) {
|
||||||
IJeiRuntime rt = getRuntime();
|
IJeiRuntime rt = getRuntime();
|
||||||
if (rt == null) return;
|
if (rt == null) return;
|
||||||
|
|
@ -167,64 +211,21 @@ public final class JeiBookmarkBridge {
|
||||||
* @return 配方书签对象(RecipeBookmark<?, ?>),如果不是配方书签则返回空
|
* @return 配方书签对象(RecipeBookmark<?, ?>),如果不是配方书签则返回空
|
||||||
*/
|
*/
|
||||||
public static Optional<?> getRecipeBookmarkUnderMouse() {
|
public static Optional<?> getRecipeBookmarkUnderMouse() {
|
||||||
IJeiRuntime rt = getRuntime();
|
Optional<?> bookmark = getBookmarkUnderMouse();
|
||||||
if (rt == null) return Optional.empty();
|
if (bookmark.isPresent() && isRecipeBookmark(bookmark.get())) {
|
||||||
|
return bookmark;
|
||||||
IBookmarkOverlay bookmarkOverlay = rt.getBookmarkOverlay();
|
|
||||||
if (!(bookmarkOverlay instanceof BookmarkOverlayAccessor accessor)) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 优先路径:直接从鼠标下 clickable 元素提取 bookmark(避免 typedIngredient equals 误判)
|
|
||||||
try {
|
|
||||||
var overlayObj = (Object) bookmarkOverlay;
|
|
||||||
var streamObj = overlayObj.getClass()
|
|
||||||
.getMethod("getIngredientUnderMouse", double.class, double.class)
|
|
||||||
.invoke(overlayObj, MouseUtil.getX(), MouseUtil.getY());
|
|
||||||
if (streamObj instanceof java.util.stream.Stream<?> stream) {
|
|
||||||
Object clickable = stream.findFirst().orElse(null);
|
|
||||||
if (clickable != null) {
|
|
||||||
Object element = clickable.getClass().getMethod("getElement").invoke(clickable);
|
|
||||||
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) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取鼠标下的元素
|
|
||||||
Optional<ITypedIngredient<?>> ingredientOpt = bookmarkOverlay.getIngredientUnderMouse();
|
|
||||||
if (ingredientOpt.isEmpty()) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历书签列表,查找匹配的配方书签
|
|
||||||
BookmarkList bookmarkList = accessor.eap$getBookmarkList();
|
|
||||||
for (IElement<?> element : bookmarkList.getElements()) {
|
|
||||||
// 检查元素的 TypedIngredient 是否匹配
|
|
||||||
if (element.getTypedIngredient().equals(ingredientOpt.get())) {
|
|
||||||
// 检查是否有关联的书签
|
|
||||||
Optional<?> bookmarkOpt = element.getBookmark();
|
|
||||||
if (bookmarkOpt.isPresent()) {
|
|
||||||
Object bookmark = bookmarkOpt.get();
|
|
||||||
// 判断是否为 RecipeBookmark(而非 IngredientBookmark)
|
|
||||||
if (bookmark.getClass().getSimpleName().equals("RecipeBookmark")) {
|
|
||||||
return Optional.of(bookmark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<?> getBookmarkUnderMouse() {
|
||||||
|
IJeiRuntime rt = getRuntime();
|
||||||
|
if (rt == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return getBookmarkUnderMouse(rt.getBookmarkOverlay(), MouseUtil.getX(), MouseUtil.getY());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从 JEI 书签移除物品
|
* 从 JEI 书签移除物品
|
||||||
*/
|
*/
|
||||||
|
|
@ -243,4 +244,190 @@ public final class JeiBookmarkBridge {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Optional<Object> getClickableIngredientUnderMouse(Object owner, double mouseX, double mouseY) {
|
||||||
|
if (owner == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object streamObj = owner.getClass()
|
||||||
|
.getMethod("getIngredientUnderMouse", double.class, double.class)
|
||||||
|
.invoke(owner, mouseX, mouseY);
|
||||||
|
if (streamObj instanceof java.util.stream.Stream<?> stream) {
|
||||||
|
return Optional.ofNullable(stream.findFirst().orElse(null));
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<ITypedIngredient<?>> getTypedIngredientFromClickableSource(Object owner, double mouseX, double mouseY) {
|
||||||
|
return getClickableIngredientUnderMouse(owner, mouseX, mouseY)
|
||||||
|
.flatMap(JeiBookmarkBridge::getElementFromClickable)
|
||||||
|
.flatMap(JeiBookmarkBridge::getTypedIngredientFromElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<Object> getBookmarkUnderMouse(IBookmarkOverlay overlay, double mouseX, double mouseY) {
|
||||||
|
if (overlay == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Object> bookmark = getClickableIngredientUnderMouse(overlay, mouseX, mouseY)
|
||||||
|
.flatMap(JeiBookmarkBridge::getElementFromClickable)
|
||||||
|
.flatMap(JeiBookmarkBridge::getBookmarkFromElement);
|
||||||
|
if (bookmark.isPresent()) {
|
||||||
|
return bookmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ITypedIngredient<?>> hoveredIngredient = getTypedIngredientFromClickableSource(overlay, mouseX, mouseY);
|
||||||
|
if (hoveredIngredient.isEmpty()) {
|
||||||
|
hoveredIngredient = overlay.getIngredientUnderMouse();
|
||||||
|
}
|
||||||
|
if (hoveredIngredient.isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return findBookmarkByTypedIngredient(overlay, hoveredIngredient.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<Object> getElementFromClickable(Object clickable) {
|
||||||
|
if (clickable == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(clickable.getClass().getMethod("getElement").invoke(clickable));
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<Object> getBookmarkFromElement(Object element) {
|
||||||
|
if (element == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object bookmarkOpt = element.getClass().getMethod("getBookmark").invoke(element);
|
||||||
|
if (bookmarkOpt instanceof Optional<?> optional && optional.isPresent()) {
|
||||||
|
return Optional.ofNullable(optional.get());
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<ITypedIngredient<?>> getTypedIngredientFromElement(Object element) {
|
||||||
|
if (element == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object typed = element.getClass().getMethod("getTypedIngredient").invoke(element);
|
||||||
|
if (typed instanceof ITypedIngredient<?> typedIngredient) {
|
||||||
|
return Optional.of(typedIngredient);
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<ITypedIngredient<?>> getTypedIngredientFromBookmark(Object bookmark) {
|
||||||
|
if (bookmark == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object typed = bookmark.getClass().getMethod("getDisplayIngredient").invoke(bookmark);
|
||||||
|
if (typed instanceof ITypedIngredient<?> typedIngredient) {
|
||||||
|
return Optional.of(typedIngredient);
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object typed = bookmark.getClass().getMethod("getIngredient").invoke(bookmark);
|
||||||
|
if (typed instanceof ITypedIngredient<?> typedIngredient) {
|
||||||
|
return Optional.of(typedIngredient);
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object element = bookmark.getClass().getMethod("getElement").invoke(bookmark);
|
||||||
|
return getTypedIngredientFromElement(element);
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<Object> findBookmarkByTypedIngredient(IBookmarkOverlay overlay, ITypedIngredient<?> hoveredIngredient) {
|
||||||
|
if (overlay == null || hoveredIngredient == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
Object firstMatch = null;
|
||||||
|
for (Object bookmark : getBookmarksFromOverlay(overlay)) {
|
||||||
|
Optional<ITypedIngredient<?>> typedIngredient = getTypedIngredientFromBookmark(bookmark);
|
||||||
|
if (typedIngredient.isPresent() && hoveredIngredient.equals(typedIngredient.get())) {
|
||||||
|
if (isRecipeBookmark(bookmark)) {
|
||||||
|
return Optional.of(bookmark);
|
||||||
|
}
|
||||||
|
if (firstMatch == null) {
|
||||||
|
firstMatch = bookmark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(firstMatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Object> getBookmarksFromOverlay(IBookmarkOverlay overlay) {
|
||||||
|
if (overlay == null) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Object> bookmarks = new ArrayList<>();
|
||||||
|
Object bookmarkList = readFieldValue(overlay, "bookmarkList");
|
||||||
|
Object bookmarkValues = readFieldValue(bookmarkList, "bookmarksList");
|
||||||
|
addBookmarks(bookmarks, bookmarkValues);
|
||||||
|
|
||||||
|
Object lookupHistoryOverlay = readFieldValue(overlay, "lookupHistoryOverlay");
|
||||||
|
Object lookupHistory = readFieldValue(lookupHistoryOverlay, "lookupHistory");
|
||||||
|
Object historyValues = readFieldValue(lookupHistory, "elements");
|
||||||
|
addBookmarks(bookmarks, historyValues);
|
||||||
|
return bookmarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addBookmarks(List<Object> target, Object source) {
|
||||||
|
if (!(source instanceof List<?> list)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Object value : list) {
|
||||||
|
if (value != null) {
|
||||||
|
target.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object readFieldValue(Object owner, String fieldName) {
|
||||||
|
if (owner == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Field field = owner.getClass().getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
return field.get(owner);
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isRecipeBookmark(Object bookmark) {
|
||||||
|
if (bookmark == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ("RecipeBookmark".equals(bookmark.getClass().getSimpleName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
bookmark.getClass().getMethod("getRecipeCategory");
|
||||||
|
bookmark.getClass().getMethod("getRecipe");
|
||||||
|
return true;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,14 @@ public final class JeiRuntimeProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<ITypedIngredient<?>> getIngredientUnderMouse() {
|
public static Optional<ITypedIngredient<?>> getIngredientUnderMouse() {
|
||||||
|
try {
|
||||||
|
Class<?> mouseUtil = Class.forName("mezz.jei.gui.input.MouseUtil");
|
||||||
|
double mouseX = ((Number) mouseUtil.getMethod("getX").invoke(null)).doubleValue();
|
||||||
|
double mouseY = ((Number) mouseUtil.getMethod("getY").invoke(null)).doubleValue();
|
||||||
|
return getIngredientUnderMouse(mouseX, mouseY);
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
IJeiRuntime rt = RUNTIME;
|
IJeiRuntime rt = RUNTIME;
|
||||||
if (rt == null) return Optional.empty();
|
if (rt == null) return Optional.empty();
|
||||||
|
|
||||||
|
|
@ -55,6 +63,17 @@ public final class JeiRuntimeProxy {
|
||||||
* 在 JEI 配方界面区域内,基于屏幕坐标查询鼠标下的配料(优先物品,其次流体)。
|
* 在 JEI 配方界面区域内,基于屏幕坐标查询鼠标下的配料(优先物品,其次流体)。
|
||||||
*/
|
*/
|
||||||
public static Optional<ITypedIngredient<?>> getIngredientUnderMouse(double mouseX, double mouseY) {
|
public static Optional<ITypedIngredient<?>> getIngredientUnderMouse(double mouseX, double mouseY) {
|
||||||
|
try {
|
||||||
|
Class<?> bridge = Class.forName("com.extendedae_plus.integration.jei.JeiBookmarkBridge");
|
||||||
|
var method = bridge.getMethod("getIngredientUnderMouse", double.class, double.class);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Optional<ITypedIngredient<?>> result = (Optional<ITypedIngredient<?>>) method.invoke(null, mouseX, mouseY);
|
||||||
|
if (result != null && result.isPresent()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
IJeiRuntime rt = RUNTIME;
|
IJeiRuntime rt = RUNTIME;
|
||||||
if (rt == null || rt.getRecipesGui() == null) return Optional.empty();
|
if (rt == null || rt.getRecipesGui() == null) return Optional.empty();
|
||||||
|
|
||||||
|
|
@ -184,6 +203,18 @@ public final class JeiRuntimeProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<?> getBookmarkUnderMouse() {
|
||||||
|
try {
|
||||||
|
Class<?> bridge = Class.forName("com.extendedae_plus.integration.jei.JeiBookmarkBridge");
|
||||||
|
var m = bridge.getMethod("getBookmarkUnderMouse");
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Optional<?> result = (Optional<?>) m.invoke(null);
|
||||||
|
return result == null ? Optional.empty() : result;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Note: helper methods moved to bridge to avoid referencing JEI GUI at class load time.
|
// Note: helper methods moved to bridge to avoid referencing JEI GUI at class load time.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user