适配JEI新版的历史记录
This commit is contained in:
parent
8d6dc8ef9c
commit
7d621af169
|
|
@ -99,7 +99,7 @@ dependencies {
|
|||
modRuntimeOnly "curse.maven:advancedae-1084104:6939473"
|
||||
|
||||
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 "curse.maven:jade-324717:${jade_version}"
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ glodium_version=5006780
|
|||
ae2_version=15.4.5
|
||||
guideme_version=20.1.7
|
||||
wireless_terminals_version=5162352
|
||||
jei_version=15.19.5.99
|
||||
jei_version=15.20.0.129
|
||||
applied_flux_version=5329825
|
||||
mega_cells_version=5320730
|
||||
jade_version=4768593
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import org.spongepowered.asm.mixin.Pseudo;
|
|||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
|
@ -56,6 +57,49 @@ public final class JeiBookmarkBridge {
|
|||
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) {
|
||||
IJeiRuntime rt = getRuntime();
|
||||
if (rt == null) return;
|
||||
|
|
@ -167,64 +211,21 @@ public final class JeiBookmarkBridge {
|
|||
* @return 配方书签对象(RecipeBookmark<?, ?>),如果不是配方书签则返回空
|
||||
*/
|
||||
public static Optional<?> getRecipeBookmarkUnderMouse() {
|
||||
IJeiRuntime rt = getRuntime();
|
||||
if (rt == null) return Optional.empty();
|
||||
|
||||
IBookmarkOverlay bookmarkOverlay = rt.getBookmarkOverlay();
|
||||
if (!(bookmarkOverlay instanceof BookmarkOverlayAccessor accessor)) {
|
||||
return Optional.empty();
|
||||
Optional<?> bookmark = getBookmarkUnderMouse();
|
||||
if (bookmark.isPresent() && isRecipeBookmark(bookmark.get())) {
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
// 优先路径:直接从鼠标下 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();
|
||||
}
|
||||
|
||||
public static Optional<?> getBookmarkUnderMouse() {
|
||||
IJeiRuntime rt = getRuntime();
|
||||
if (rt == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return getBookmarkUnderMouse(rt.getBookmarkOverlay(), MouseUtil.getX(), MouseUtil.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 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() {
|
||||
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;
|
||||
if (rt == null) return Optional.empty();
|
||||
|
||||
|
|
@ -55,6 +63,17 @@ public final class JeiRuntimeProxy {
|
|||
* 在 JEI 配方界面区域内,基于屏幕坐标查询鼠标下的配料(优先物品,其次流体)。
|
||||
*/
|
||||
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;
|
||||
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.
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user