Merge branch 'refs/heads/master' into develop/fix
# Conflicts: # src/main/java/com/extendedae_plus/compat/CompatibilityTest.java # src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java # src/main/java/com/extendedae_plus/mixin/ae2/items/QuartzCuttingKnifeItemMixin.java # src/main/java/com/extendedae_plus/mixin/appflux/AppfluxPatternProviderLogicMixin.java # src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java
This commit is contained in:
commit
e232fc4e4f
19
CHANGELOG.md
19
CHANGELOG.md
|
|
@ -2,6 +2,25 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [1.4.3]
|
||||||
|
### ⚠️ 重要提醒 / Important Notice
|
||||||
|
- **更新会导致旧版的无限盘失效,如有需要请先导盘再更新**
|
||||||
|
- **Updating will invalidate old infinite disks. Please export data before updating if needed.**
|
||||||
|
|
||||||
|
### Added / 新增
|
||||||
|
- 装配矩阵上传核心 - 现在必须在装配矩阵中添加该核心才能正常使用自动上传合成样板功能
|
||||||
|
- Assembly Matrix Upload Core - now required in Assembly Matrix to use automatic pattern upload functionality.
|
||||||
|
- 频道卡 - 手持频道卡右键可调整频率,将频道卡放入AE设备将自动连接上同频率的本模组的无线收发器
|
||||||
|
- Channel Card - right-click while holding to adjust frequency, placing in AE devices automatically connects to same-frequency wireless transceivers.
|
||||||
|
|
||||||
|
### Fixed / 修复
|
||||||
|
- 修复合成计划中添加缺失物品时,流体、MEK化学品出现错误书签
|
||||||
|
- Fixed incorrect bookmarks for fluids and Mekanism chemicals when adding missing items in crafting plan.
|
||||||
|
- 修复吞噬万籁的寂静的重大bug
|
||||||
|
- Fixed critical bug in Devourer of Cosmic Silence.
|
||||||
|
- 修复JEI模组不存在时导致的崩溃问题
|
||||||
|
- Fixed crash when JEI mod is not present.
|
||||||
|
|
||||||
## [1.4.2]
|
## [1.4.2]
|
||||||
### Added / 新增
|
### Added / 新增
|
||||||
- 添加实体加速器,最高可加速 1024 倍(配置文件可配置能耗、黑名单、额外消耗倍率名单)
|
- 添加实体加速器,最高可加速 1024 倍(配置文件可配置能耗、黑名单、额外消耗倍率名单)
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ dependencies {
|
||||||
|
|
||||||
|
|
||||||
//mae2
|
//mae2
|
||||||
modRuntimeOnly "curse.maven:modern-ae2-additions-1028068:6827727"
|
// modRuntimeOnly "curse.maven:modern-ae2-additions-1028068:6827727"
|
||||||
modCompileOnly "curse.maven:modern-ae2-additions-1028068:6827727"
|
modCompileOnly "curse.maven:modern-ae2-additions-1028068:6827727"
|
||||||
|
|
||||||
//aea
|
//aea
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
|
||||||
loom.platform = forge
|
loom.platform = forge
|
||||||
|
|
||||||
# Mod properties
|
# Mod properties
|
||||||
mod_version = 1.4.3-beta
|
mod_version = 1.4.3
|
||||||
maven_group = com.extendedae_plus
|
maven_group = com.extendedae_plus
|
||||||
archives_name = extendedae_plus
|
archives_name = extendedae_plus
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,7 @@ public final class InputEvents {
|
||||||
if (!ModList.get().isLoaded("jei")) {
|
if (!ModList.get().isLoaded("jei")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 若 JEI 运行时尚未就绪,跳过
|
// 注意:不要在 try/catch 之外直接访问 JEI 运行时,避免类加载崩溃
|
||||||
if (JeiRuntimeProxy.get() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 优先处理:Shift + 左键(拉取或下单)
|
// 优先处理:Shift + 左键(拉取或下单)
|
||||||
if (event.getButton() == GLFW.GLFW_MOUSE_BUTTON_LEFT && Screen.hasShiftDown()) {
|
if (event.getButton() == GLFW.GLFW_MOUSE_BUTTON_LEFT && Screen.hasShiftDown()) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -103,9 +100,7 @@ public final class InputEvents {
|
||||||
if (!ModList.get().isLoaded("jei")) {
|
if (!ModList.get().isLoaded("jei")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (JeiRuntimeProxy.get() == null) {
|
// 注意:不要在 try/catch 之外直接访问 JEI 运行时,避免类加载崩溃
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (event.getKeyCode() != GLFW.GLFW_KEY_F) return;
|
if (event.getKeyCode() != GLFW.GLFW_KEY_F) return;
|
||||||
|
|
||||||
// 仅当鼠标确实悬停在 JEI 配料上时触发
|
// 仅当鼠标确实悬停在 JEI 配料上时触发
|
||||||
|
|
|
||||||
|
|
@ -183,10 +183,29 @@ public class ProviderSelectScreen extends Screen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将服务器发送的名称(可能是 Component JSON)反序列化为本地化文本
|
||||||
|
*/
|
||||||
|
private String deserializeComponentName(String name) {
|
||||||
|
try {
|
||||||
|
// 如果名称是 JSON 格式的 Component,反序列化后获取本地化文本
|
||||||
|
if (name.startsWith("{") || name.startsWith("\"")) {
|
||||||
|
Component component = Component.Serializer.fromJson(name);
|
||||||
|
if (component != null) {
|
||||||
|
return component.getString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果不是 JSON 或解析失败,使用原始字符串
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
private String buildLabel(int idx) {
|
private String buildLabel(int idx) {
|
||||||
String name = fNames.get(idx);
|
String name = fNames.get(idx);
|
||||||
int totalSlots = fTotalSlots.get(idx);
|
int totalSlots = fTotalSlots.get(idx);
|
||||||
int count = fCount.get(idx);
|
int count = fCount.get(idx);
|
||||||
|
|
||||||
// 不显示具体 id,显示合并统计:名称(总空位)x数量
|
// 不显示具体 id,显示合并统计:名称(总空位)x数量
|
||||||
return name + " (" + totalSlots + ") x" + count;
|
return name + " (" + totalSlots + ") x" + count;
|
||||||
}
|
}
|
||||||
|
|
@ -215,7 +234,11 @@ public class ProviderSelectScreen extends Screen {
|
||||||
String name = names.get(i);
|
String name = names.get(i);
|
||||||
long id = ids.get(i);
|
long id = ids.get(i);
|
||||||
int slots = emptySlots.get(i);
|
int slots = emptySlots.get(i);
|
||||||
Group g = map.computeIfAbsent(name, k -> new Group());
|
|
||||||
|
// 将 Component JSON 转换为本地化文本用于分组键
|
||||||
|
String groupKey = deserializeComponentName(name);
|
||||||
|
|
||||||
|
Group g = map.computeIfAbsent(groupKey, k -> new Group());
|
||||||
g.count++;
|
g.count++;
|
||||||
g.totalSlots += Math.max(0, slots);
|
g.totalSlots += Math.max(0, slots);
|
||||||
// 挑选空位最多的作为代表 id;若并列,保留先到者
|
// 挑选空位最多的作为代表 id;若并列,保留先到者
|
||||||
|
|
|
||||||
|
|
@ -13,28 +13,21 @@ public class CompatibilityTest {
|
||||||
* 测试模组兼容性检测
|
* 测试模组兼容性检测
|
||||||
*/
|
*/
|
||||||
public static void testCompatibility() {
|
public static void testCompatibility() {
|
||||||
Logger.EAP$LOGGER.info("=== ExtendedAE_Plus 兼容性测试开始 ===");
|
|
||||||
|
|
||||||
// 测试appflux模组检测
|
// 测试appflux模组检测
|
||||||
boolean appfluxExists = ModList.get().isLoaded("appflux");
|
boolean appfluxExists = ModList.get().isLoaded("appflux");
|
||||||
Logger.EAP$LOGGER.info("ExtendedAE-appflux模组检测结果: {}", appfluxExists ? "存在" : "不存在");
|
|
||||||
|
|
||||||
// 测试升级卡槽功能启用状态
|
// 测试升级卡槽功能启用状态
|
||||||
boolean shouldEnableUpgrades = UpgradeSlotCompat.shouldEnableUpgradeSlots();
|
boolean shouldEnableUpgrades = UpgradeSlotCompat.shouldEnableUpgradeSlots();
|
||||||
Logger.EAP$LOGGER.info("升级卡槽功能启用状态: {}", shouldEnableUpgrades ? "启用" : "禁用");
|
|
||||||
|
|
||||||
// 测试Screen升级面板添加状态
|
// 测试Screen升级面板添加状态
|
||||||
boolean shouldAddPanel = UpgradeSlotCompat.shouldAddUpgradePanelToScreen();
|
boolean shouldAddPanel = UpgradeSlotCompat.shouldAddUpgradePanelToScreen();
|
||||||
Logger.EAP$LOGGER.info("Screen升级面板添加状态: {}", shouldAddPanel ? "启用" : "禁用");
|
|
||||||
|
|
||||||
// 输出兼容性策略
|
// 输出兼容性策略
|
||||||
if (appfluxExists) {
|
if (appfluxExists) {
|
||||||
Logger.EAP$LOGGER.info("兼容性策略: 检测到ExtendedAE-appflux模组,将使用其升级卡槽功能");
|
|
||||||
} else {
|
} else {
|
||||||
Logger.EAP$LOGGER.info("兼容性策略: 未检测到ExtendedAE-appflux模组,将使用我们自己的升级卡槽功能");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.EAP$LOGGER.info("=== ExtendedAE_Plus 兼容性测试完成 ===");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
package com.extendedae_plus.integration.jei;
|
||||||
|
|
||||||
|
import com.extendedae_plus.mixin.jei.accessor.BookmarkOverlayAccessor;
|
||||||
|
import mezz.jei.api.constants.VanillaTypes;
|
||||||
|
import mezz.jei.api.forge.ForgeTypes;
|
||||||
|
import mezz.jei.api.ingredients.IIngredientType;
|
||||||
|
import mezz.jei.api.ingredients.ITypedIngredient;
|
||||||
|
import mezz.jei.api.runtime.IBookmarkOverlay;
|
||||||
|
import mezz.jei.api.runtime.IJeiRuntime;
|
||||||
|
import mezz.jei.gui.bookmarks.BookmarkList;
|
||||||
|
import mezz.jei.gui.bookmarks.IngredientBookmark;
|
||||||
|
import mezz.jei.gui.overlay.elements.IElement;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fml.ModList;
|
||||||
|
import org.spongepowered.asm.mixin.Pseudo;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将所有会引用 JEI GUI 内部类(如 BookmarkList、IngredientBookmark、IElement 等)的逻辑
|
||||||
|
* 隔离在此桥接类中,避免在未安装 JEI 或 JEI 组件不完整时过早类加载导致的 NoClassDefFoundError。
|
||||||
|
*
|
||||||
|
* 该类仅会被 {@link JeiRuntimeProxy} 通过反射调用。
|
||||||
|
*/
|
||||||
|
@Pseudo
|
||||||
|
public final class JeiBookmarkBridge {
|
||||||
|
private JeiBookmarkBridge() {}
|
||||||
|
|
||||||
|
// 通过 JeiRuntimeProxy 的包内可见方法安全地获取 Runtime
|
||||||
|
private static @Nullable IJeiRuntime getRuntime() {
|
||||||
|
try {
|
||||||
|
Class<?> proxy = Class.forName("com.extendedae_plus.integration.jei.JeiRuntimeProxy");
|
||||||
|
var m = proxy.getDeclaredMethod("get");
|
||||||
|
Object rt = m.invoke(null);
|
||||||
|
return (IJeiRuntime) rt;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<? extends ITypedIngredient<?>> getBookmarkList() {
|
||||||
|
IJeiRuntime rt = getRuntime();
|
||||||
|
if (rt == null) return Collections.emptyList();
|
||||||
|
IBookmarkOverlay bookmarkOverlay = rt.getBookmarkOverlay();
|
||||||
|
if (bookmarkOverlay instanceof BookmarkOverlayAccessor accessor) {
|
||||||
|
BookmarkList bookmarkList = accessor.eap$getBookmarkList();
|
||||||
|
return bookmarkList.getElements().stream().map(IElement::getTypedIngredient).toList();
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addBookmark(ItemStack stack) {
|
||||||
|
IJeiRuntime rt = getRuntime();
|
||||||
|
if (rt == null) return;
|
||||||
|
|
||||||
|
IBookmarkOverlay overlay = rt.getBookmarkOverlay();
|
||||||
|
if (overlay instanceof BookmarkOverlayAccessor accessor) {
|
||||||
|
BookmarkList list = accessor.eap$getBookmarkList();
|
||||||
|
Optional<ITypedIngredient<ItemStack>> typedOpt = rt.getIngredientManager()
|
||||||
|
.createTypedIngredient(VanillaTypes.ITEM_STACK, stack);
|
||||||
|
typedOpt.ifPresent(typed -> {
|
||||||
|
IngredientBookmark<ItemStack> bookmark = IngredientBookmark.create(typed, rt.getIngredientManager());
|
||||||
|
list.add(bookmark); // add 内部会自动保存到配置
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addBookmark(FluidStack fluidStack) {
|
||||||
|
IJeiRuntime rt = getRuntime();
|
||||||
|
if (rt == null) return;
|
||||||
|
|
||||||
|
IBookmarkOverlay overlay = rt.getBookmarkOverlay();
|
||||||
|
if (overlay instanceof BookmarkOverlayAccessor accessor) {
|
||||||
|
BookmarkList list = accessor.eap$getBookmarkList();
|
||||||
|
Optional<ITypedIngredient<FluidStack>> typedOpt = rt.getIngredientManager()
|
||||||
|
.createTypedIngredient(ForgeTypes.FLUID_STACK, fluidStack);
|
||||||
|
typedOpt.ifPresent(typed -> {
|
||||||
|
IngredientBookmark<FluidStack> bookmark = IngredientBookmark.create(typed, rt.getIngredientManager());
|
||||||
|
list.add(bookmark); // add 内部会自动保存到配置
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果存在 Mekanism/appmek,则将 Mekanism 化学堆栈添加到 JEI 书签。
|
||||||
|
*/
|
||||||
|
public static void addBookmark(Object chemicalStack) {
|
||||||
|
if (!ModList.get().isLoaded("mekanism") && !ModList.get().isLoaded("appmek")) return;
|
||||||
|
|
||||||
|
IJeiRuntime rt = getRuntime();
|
||||||
|
if (rt == null) return;
|
||||||
|
|
||||||
|
IBookmarkOverlay overlay = rt.getBookmarkOverlay();
|
||||||
|
if (overlay instanceof BookmarkOverlayAccessor accessor) {
|
||||||
|
BookmarkList list = accessor.eap$getBookmarkList();
|
||||||
|
try {
|
||||||
|
if (chemicalStack == null) return;
|
||||||
|
|
||||||
|
// Determine Mekanism JEI ingredient type constant by runtime class name
|
||||||
|
String clsName = chemicalStack.getClass().getName();
|
||||||
|
String mekanismJeiClass = "mekanism.client.jei.MekanismJEI";
|
||||||
|
Class<?> jeiCls = Class.forName(mekanismJeiClass);
|
||||||
|
Field typeField = getField(clsName, jeiCls);
|
||||||
|
|
||||||
|
if (typeField == null) return;
|
||||||
|
Object typeConst = typeField.get(null);
|
||||||
|
|
||||||
|
// Use ingredient manager reflectively to create a typed ingredient
|
||||||
|
Object ingredientManager = rt.getIngredientManager();
|
||||||
|
Method createTypedIngredient = ingredientManager.getClass().getMethod("createTypedIngredient", IIngredientType.class, Object.class);
|
||||||
|
Object opt = createTypedIngredient.invoke(ingredientManager, typeConst, chemicalStack);
|
||||||
|
if (!(opt instanceof Optional<?> typedOpt)) return;
|
||||||
|
if (typedOpt.isPresent()) {
|
||||||
|
Object typed = typedOpt.get();
|
||||||
|
// Find a compatible static create(...) method on IngredientBookmark where
|
||||||
|
// the second parameter is assignable from the actual ingredientManager instance.
|
||||||
|
Method createMethod = null;
|
||||||
|
for (Method m : IngredientBookmark.class.getMethods()) {
|
||||||
|
if (!m.getName().equals("create")) continue;
|
||||||
|
Class<?>[] params = m.getParameterTypes();
|
||||||
|
if (params.length != 2) continue;
|
||||||
|
// first param should accept the typed ingredient
|
||||||
|
boolean firstOk = params[0].isAssignableFrom(typed.getClass()) || params[0].isAssignableFrom(ITypedIngredient.class);
|
||||||
|
boolean secondOk = params[1].isAssignableFrom(ingredientManager.getClass());
|
||||||
|
if (firstOk && secondOk) {
|
||||||
|
createMethod = m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (createMethod != null) {
|
||||||
|
Object bookmark = createMethod.invoke(null, typed, ingredientManager);
|
||||||
|
if (bookmark != null) {
|
||||||
|
list.add((IngredientBookmark) bookmark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @Nullable Field getField(String clsName, Class<?> jeiCls) throws NoSuchFieldException {
|
||||||
|
Field typeField = null;
|
||||||
|
if ("mekanism.api.chemical.gas.GasStack".equals(clsName)) {
|
||||||
|
typeField = jeiCls.getField("TYPE_GAS");
|
||||||
|
} else if ("mekanism.api.chemical.infuse.InfusionStack".equals(clsName)) {
|
||||||
|
typeField = jeiCls.getField("TYPE_INFUSION");
|
||||||
|
} else if ("mekanism.api.chemical.pigment.PigmentStack".equals(clsName)) {
|
||||||
|
typeField = jeiCls.getField("TYPE_PIGMENT");
|
||||||
|
} else if ("mekanism.api.chemical.slurry.SlurryStack".equals(clsName)) {
|
||||||
|
typeField = jeiCls.getField("TYPE_SLURRY");
|
||||||
|
}
|
||||||
|
return typeField;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 JEI 书签移除物品
|
||||||
|
*/
|
||||||
|
public static void removeBookmark(ItemStack stack) {
|
||||||
|
IJeiRuntime rt = getRuntime();
|
||||||
|
if (rt == null) return;
|
||||||
|
|
||||||
|
IBookmarkOverlay overlay = rt.getBookmarkOverlay();
|
||||||
|
if (overlay instanceof BookmarkOverlayAccessor accessor) {
|
||||||
|
BookmarkList list = accessor.eap$getBookmarkList();
|
||||||
|
Optional<ITypedIngredient<ItemStack>> typedOpt = rt.getIngredientManager()
|
||||||
|
.createTypedIngredient(VanillaTypes.ITEM_STACK, stack);
|
||||||
|
typedOpt.ifPresent(typed -> {
|
||||||
|
IngredientBookmark<ItemStack> bookmark = IngredientBookmark.create(typed, rt.getIngredientManager());
|
||||||
|
list.remove(bookmark);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,24 +1,16 @@
|
||||||
package com.extendedae_plus.integration.jei;
|
package com.extendedae_plus.integration.jei;
|
||||||
|
|
||||||
import com.extendedae_plus.mixin.jei.accessor.BookmarkOverlayAccessor;
|
|
||||||
import mezz.jei.api.constants.VanillaTypes;
|
import mezz.jei.api.constants.VanillaTypes;
|
||||||
import mezz.jei.api.forge.ForgeTypes;
|
|
||||||
import mezz.jei.api.ingredients.IIngredientType;
|
|
||||||
import mezz.jei.api.ingredients.ITypedIngredient;
|
import mezz.jei.api.ingredients.ITypedIngredient;
|
||||||
import mezz.jei.api.runtime.IBookmarkOverlay;
|
import mezz.jei.api.runtime.IBookmarkOverlay;
|
||||||
import mezz.jei.api.runtime.IIngredientListOverlay;
|
import mezz.jei.api.runtime.IIngredientListOverlay;
|
||||||
import mezz.jei.api.runtime.IJeiRuntime;
|
import mezz.jei.api.runtime.IJeiRuntime;
|
||||||
import mezz.jei.gui.bookmarks.BookmarkList;
|
|
||||||
import mezz.jei.gui.bookmarks.IngredientBookmark;
|
|
||||||
import mezz.jei.gui.overlay.elements.IElement;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
import net.minecraftforge.fml.ModList;
|
import net.minecraftforge.fml.ModList;
|
||||||
import org.spongepowered.asm.mixin.Pseudo;
|
import org.spongepowered.asm.mixin.Pseudo;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -131,48 +123,35 @@ public final class JeiRuntimeProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取JEI书签列表
|
* 获取 JEI 书签列表。为避免在未安装 JEI GUI 时崩溃,使用反射委托到桥接类。
|
||||||
*/
|
*/
|
||||||
public static List<? extends ITypedIngredient<?>> getBookmarkList() {
|
public static List<? extends ITypedIngredient<?>> getBookmarkList() {
|
||||||
IJeiRuntime rt = RUNTIME;
|
try {
|
||||||
if (rt == null) return Collections.emptyList();
|
Class<?> bridge = Class.forName("com.extendedae_plus.integration.jei.JeiBookmarkBridge");
|
||||||
IBookmarkOverlay bookmarkOverlay = rt.getBookmarkOverlay();
|
var m = bridge.getMethod("getBookmarkList");
|
||||||
if (bookmarkOverlay instanceof BookmarkOverlayAccessor accessor) {
|
@SuppressWarnings("unchecked")
|
||||||
BookmarkList bookmarkList = accessor.eap$getBookmarkList();
|
List<? extends ITypedIngredient<?>> list = (List<? extends ITypedIngredient<?>>) m.invoke(null);
|
||||||
return bookmarkList.getElements().stream().map(IElement::getTypedIngredient).toList();
|
return list == null ? Collections.emptyList() : list;
|
||||||
}
|
} catch (Throwable ignored) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void addBookmark(ItemStack stack) {
|
public static void addBookmark(ItemStack stack) {
|
||||||
IJeiRuntime rt = RUNTIME;
|
try {
|
||||||
if (rt == null) return;
|
Class<?> bridge = Class.forName("com.extendedae_plus.integration.jei.JeiBookmarkBridge");
|
||||||
|
var m = bridge.getMethod("addBookmark", ItemStack.class);
|
||||||
IBookmarkOverlay overlay = rt.getBookmarkOverlay();
|
m.invoke(null, stack);
|
||||||
if (overlay instanceof BookmarkOverlayAccessor accessor) {
|
} catch (Throwable ignored) {
|
||||||
BookmarkList list = accessor.eap$getBookmarkList();
|
|
||||||
Optional<ITypedIngredient<ItemStack>> typedOpt = rt.getIngredientManager()
|
|
||||||
.createTypedIngredient(VanillaTypes.ITEM_STACK, stack);
|
|
||||||
typedOpt.ifPresent(typed -> {
|
|
||||||
IngredientBookmark<ItemStack> bookmark = IngredientBookmark.create(typed, rt.getIngredientManager());
|
|
||||||
list.add(bookmark); // add 内部会自动保存到配置
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addBookmark(FluidStack fluidStack) {
|
public static void addBookmark(FluidStack fluidStack) {
|
||||||
IJeiRuntime rt = RUNTIME;
|
try {
|
||||||
if (rt == null) return;
|
Class<?> bridge = Class.forName("com.extendedae_plus.integration.jei.JeiBookmarkBridge");
|
||||||
|
var m = bridge.getMethod("addBookmark", FluidStack.class);
|
||||||
IBookmarkOverlay overlay = rt.getBookmarkOverlay();
|
m.invoke(null, fluidStack);
|
||||||
if (overlay instanceof BookmarkOverlayAccessor accessor) {
|
} catch (Throwable ignored) {
|
||||||
BookmarkList list = accessor.eap$getBookmarkList();
|
|
||||||
Optional<ITypedIngredient<FluidStack>> typedOpt = rt.getIngredientManager()
|
|
||||||
.createTypedIngredient(ForgeTypes.FLUID_STACK, fluidStack);
|
|
||||||
typedOpt.ifPresent(typed -> {
|
|
||||||
IngredientBookmark<FluidStack> bookmark = IngredientBookmark.create(typed, rt.getIngredientManager());
|
|
||||||
list.add(bookmark); // add 内部会自动保存到配置
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,91 +159,25 @@ public final class JeiRuntimeProxy {
|
||||||
* 如果存在 Mekanism/appmek,则将 Mekanism 化学堆栈添加到 JEI 书签。
|
* 如果存在 Mekanism/appmek,则将 Mekanism 化学堆栈添加到 JEI 书签。
|
||||||
*/
|
*/
|
||||||
public static void addBookmark(Object chemicalStack) {
|
public static void addBookmark(Object chemicalStack) {
|
||||||
if (!ModList.get().isLoaded("mekanism") && !ModList.get().isLoaded("appmek")) return;
|
|
||||||
|
|
||||||
IJeiRuntime rt = RUNTIME;
|
|
||||||
if (rt == null) return;
|
|
||||||
|
|
||||||
IBookmarkOverlay overlay = rt.getBookmarkOverlay();
|
|
||||||
if (overlay instanceof BookmarkOverlayAccessor accessor) {
|
|
||||||
BookmarkList list = accessor.eap$getBookmarkList();
|
|
||||||
try {
|
try {
|
||||||
if (chemicalStack == null) return;
|
Class<?> bridge = Class.forName("com.extendedae_plus.integration.jei.JeiBookmarkBridge");
|
||||||
|
var m = bridge.getMethod("addBookmark", Object.class);
|
||||||
// Determine Mekanism JEI ingredient type constant by runtime class name
|
m.invoke(null, chemicalStack);
|
||||||
String clsName = chemicalStack.getClass().getName();
|
} catch (Throwable ignored) {
|
||||||
String mekanismJeiClass = "mekanism.client.jei.MekanismJEI";
|
|
||||||
Class<?> jeiCls = Class.forName(mekanismJeiClass);
|
|
||||||
Field typeField = getField(clsName, jeiCls);
|
|
||||||
|
|
||||||
if (typeField == null) return;
|
|
||||||
Object typeConst = typeField.get(null);
|
|
||||||
|
|
||||||
// Use ingredient manager reflectively to create a typed ingredient
|
|
||||||
Object ingredientManager = rt.getIngredientManager();
|
|
||||||
Method createTypedIngredient = ingredientManager.getClass().getMethod("createTypedIngredient", IIngredientType.class, Object.class);
|
|
||||||
Object opt = createTypedIngredient.invoke(ingredientManager, typeConst, chemicalStack);
|
|
||||||
if (!(opt instanceof Optional<?> typedOpt)) return;
|
|
||||||
if (typedOpt.isPresent()) {
|
|
||||||
Object typed = typedOpt.get();
|
|
||||||
// Find a compatible static create(...) method on IngredientBookmark where
|
|
||||||
// the second parameter is assignable from the actual ingredientManager instance.
|
|
||||||
Method createMethod = null;
|
|
||||||
for (Method m : IngredientBookmark.class.getMethods()) {
|
|
||||||
if (!m.getName().equals("create")) continue;
|
|
||||||
Class<?>[] params = m.getParameterTypes();
|
|
||||||
if (params.length != 2) continue;
|
|
||||||
// first param should accept the typed ingredient
|
|
||||||
boolean firstOk = params[0].isAssignableFrom(typed.getClass()) || params[0].isAssignableFrom(ITypedIngredient.class);
|
|
||||||
boolean secondOk = params[1].isAssignableFrom(ingredientManager.getClass());
|
|
||||||
if (firstOk && secondOk) {
|
|
||||||
createMethod = m;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (createMethod != null) {
|
|
||||||
Object bookmark = createMethod.invoke(null, typed, ingredientManager);
|
|
||||||
if (bookmark != null) {
|
|
||||||
list.add((IngredientBookmark) bookmark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable Field getField(String clsName, Class<?> jeiCls) throws NoSuchFieldException {
|
// Note: helper methods moved to bridge to avoid referencing JEI GUI at class load time.
|
||||||
Field typeField = null;
|
|
||||||
if ("mekanism.api.chemical.gas.GasStack".equals(clsName)) {
|
|
||||||
typeField = jeiCls.getField("TYPE_GAS");
|
|
||||||
} else if ("mekanism.api.chemical.infuse.InfusionStack".equals(clsName)) {
|
|
||||||
typeField = jeiCls.getField("TYPE_INFUSION");
|
|
||||||
} else if ("mekanism.api.chemical.pigment.PigmentStack".equals(clsName)) {
|
|
||||||
typeField = jeiCls.getField("TYPE_PIGMENT");
|
|
||||||
} else if ("mekanism.api.chemical.slurry.SlurryStack".equals(clsName)) {
|
|
||||||
typeField = jeiCls.getField("TYPE_SLURRY");
|
|
||||||
}
|
|
||||||
return typeField;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从 JEI 书签移除物品
|
* 从 JEI 书签移除物品(反射委托)
|
||||||
*/
|
*/
|
||||||
public static void removeBookmark(ItemStack stack) {
|
public static void removeBookmark(ItemStack stack) {
|
||||||
IJeiRuntime rt = RUNTIME;
|
try {
|
||||||
if (rt == null) return;
|
Class<?> bridge = Class.forName("com.extendedae_plus.integration.jei.JeiBookmarkBridge");
|
||||||
|
var m = bridge.getMethod("removeBookmark", ItemStack.class);
|
||||||
IBookmarkOverlay overlay = rt.getBookmarkOverlay();
|
m.invoke(null, stack);
|
||||||
if (overlay instanceof BookmarkOverlayAccessor accessor) {
|
} catch (Throwable ignored) {
|
||||||
BookmarkList list = accessor.eap$getBookmarkList();
|
|
||||||
Optional<ITypedIngredient<ItemStack>> typedOpt = rt.getIngredientManager()
|
|
||||||
.createTypedIngredient(VanillaTypes.ITEM_STACK, stack);
|
|
||||||
typedOpt.ifPresent(typed -> {
|
|
||||||
IngredientBookmark<ItemStack> bookmark = IngredientBookmark.create(typed, rt.getIngredientManager());
|
|
||||||
list.remove(bookmark);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ public abstract class InterfaceScreenMixin<T extends AEBaseMenu> {
|
||||||
int imageWidth = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getImageWidth();
|
int imageWidth = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getImageWidth();
|
||||||
// 按照样板供应器界面一致的布局:界面右缘外侧竖排
|
// 按照样板供应器界面一致的布局:界面右缘外侧竖排
|
||||||
int bx = leftPos + imageWidth + 1;
|
int bx = leftPos + imageWidth + 1;
|
||||||
int by = topPos + 20;
|
int by = topPos + 70; // 向下偏移25px (从20改为45)
|
||||||
int spacing = 22;
|
int spacing = 22;
|
||||||
if (eap$divideBy2Button != null) { eap$divideBy2Button.setX(bx); eap$divideBy2Button.setY(by); }
|
if (eap$divideBy2Button != null) { eap$divideBy2Button.setX(bx); eap$divideBy2Button.setY(by); }
|
||||||
if (eap$x2Button != null) { eap$x2Button.setX(bx); eap$x2Button.setY(by + spacing); }
|
if (eap$x2Button != null) { eap$x2Button.setX(bx); eap$x2Button.setY(by + spacing); }
|
||||||
|
|
|
||||||
|
|
@ -99,9 +99,11 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj
|
||||||
at = @At("TAIL"))
|
at = @At("TAIL"))
|
||||||
private void eap$compatInitUpgrades(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
|
private void eap$compatInitUpgrades(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
boolean upgradeSlots = UpgradeSlotCompat.shouldEnableUpgradeSlots();
|
boolean upgradeSlots = UpgradeSlotCompat.shouldEnableUpgradeSlots();
|
||||||
boolean channelCard = UpgradeSlotCompat.shouldEnableChannelCard();
|
boolean channelCard = UpgradeSlotCompat.shouldEnableChannelCard();
|
||||||
|
|
||||||
|
|
||||||
if (upgradeSlots) {
|
if (upgradeSlots) {
|
||||||
// 只有在升级槽功能启用时才创建升级槽
|
// 只有在升级槽功能启用时才创建升级槽
|
||||||
this.eap$compatUpgrades = UpgradeInventories.forMachine(
|
this.eap$compatUpgrades = UpgradeInventories.forMachine(
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,6 @@ public abstract class QuartzCuttingKnifeItemMixin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
EAP$LOGGER.info("GregTech CEu 类未找到,跳过配方翻译处理");
|
|
||||||
return null; // GTCEu 不可用
|
return null; // GTCEu 不可用
|
||||||
} catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e) {
|
} catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e) {
|
||||||
EAP$LOGGER.error("处理 GTCEu 配方翻译失败: {}", e.getMessage());
|
EAP$LOGGER.error("处理 GTCEu 配方翻译失败: {}", e.getMessage());
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,10 @@ public class AppfluxPatternProviderLogicMixin {
|
||||||
at = @At("TAIL"))
|
at = @At("TAIL"))
|
||||||
private void eap$modifyAppfluxUpgradeSlots(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
|
private void eap$modifyAppfluxUpgradeSlots(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// 只有当appflux存在且不启用我们的升级槽时才修改数量
|
// 只有当appflux存在且不启用我们的升级槽时才修改数量
|
||||||
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots() && UpgradeSlotCompat.shouldEnableChannelCard()) {
|
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots() && UpgradeSlotCompat.shouldEnableChannelCard()) {
|
||||||
|
|
||||||
// 使用反射找到appflux的升级槽字段并替换
|
// 使用反射找到appflux的升级槽字段并替换
|
||||||
try {
|
try {
|
||||||
Field upgradesField = this.getClass().getDeclaredField("af_$upgrades");
|
Field upgradesField = this.getClass().getDeclaredField("af_$upgrades");
|
||||||
|
|
@ -37,6 +39,7 @@ public class AppfluxPatternProviderLogicMixin {
|
||||||
IUpgradeInventory currentUpgrades = (IUpgradeInventory) upgradesField.get(this);
|
IUpgradeInventory currentUpgrades = (IUpgradeInventory) upgradesField.get(this);
|
||||||
|
|
||||||
if (currentUpgrades != null) {
|
if (currentUpgrades != null) {
|
||||||
|
|
||||||
// 创建新的2槽升级槽
|
// 创建新的2槽升级槽
|
||||||
IUpgradeInventory newUpgrades = UpgradeInventories.forMachine(
|
IUpgradeInventory newUpgrades = UpgradeInventories.forMachine(
|
||||||
host.getTerminalIcon().getItem(),
|
host.getTerminalIcon().getItem(),
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,6 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
|
||||||
try { cfgPages = Math.max(1, ModConfig.INSTANCE.pageMultiplier); } catch (Throwable ignored) {}
|
try { cfgPages = Math.max(1, ModConfig.INSTANCE.pageMultiplier); } catch (Throwable ignored) {}
|
||||||
int calcPages = Math.max(1, (int) Math.ceil(totalSlots / (double) SLOTS_PER_PAGE));
|
int calcPages = Math.max(1, (int) Math.ceil(totalSlots / (double) SLOTS_PER_PAGE));
|
||||||
int desiredMaxPage = Math.max(cfgPages, calcPages);
|
int desiredMaxPage = Math.max(cfgPages, calcPages);
|
||||||
EAP$LOGGER.info("[EAP] GuiExPatternProvider init: totalSlots={}, cfgPages={}, calcPages={}, desiredMaxPage={}", totalSlots, cfgPages, calcPages, desiredMaxPage);
|
|
||||||
// 更新本地最大页
|
// 更新本地最大页
|
||||||
this.eap$maxPageLocal = Math.max(1, desiredMaxPage);
|
this.eap$maxPageLocal = Math.max(1, desiredMaxPage);
|
||||||
this.eap$currentPage = 0;
|
this.eap$currentPage = 0;
|
||||||
|
|
@ -158,8 +157,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
// 同步到本地 GUI 页码
|
// 同步到本地 GUI 页码
|
||||||
this.eap$currentPage = newPage;
|
this.eap$currentPage = newPage;
|
||||||
// 日志与强制重排(放在更新本地页码之后,确保布局读取到新页)
|
// 强制重排(放在更新本地页码之后,确保布局读取到新页)
|
||||||
EAP$LOGGER.info("[EAP] PrevPage clicked: {} -> {} (max={})", currentPage, newPage, maxPage);
|
|
||||||
this.repositionSlots(SlotSemantics.ENCODED_PATTERN);
|
this.repositionSlots(SlotSemantics.ENCODED_PATTERN);
|
||||||
this.repositionSlots(SlotSemantics.STORAGE);
|
this.repositionSlots(SlotSemantics.STORAGE);
|
||||||
this.hoveredSlot = null;
|
this.hoveredSlot = null;
|
||||||
|
|
@ -185,8 +183,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
// 同步到本地 GUI 页码
|
// 同步到本地 GUI 页码
|
||||||
this.eap$currentPage = newPage;
|
this.eap$currentPage = newPage;
|
||||||
// 日志与强制重排(放在更新本地页码之后,确保布局读取到新页)
|
// 强制重排(放在更新本地页码之后,确保布局读取到新页)
|
||||||
EAP$LOGGER.info("[EAP] NextPage clicked: {} -> {} (max={})", currentPage, newPage, maxPage);
|
|
||||||
this.repositionSlots(SlotSemantics.ENCODED_PATTERN);
|
this.repositionSlots(SlotSemantics.ENCODED_PATTERN);
|
||||||
this.repositionSlots(SlotSemantics.STORAGE);
|
this.repositionSlots(SlotSemantics.STORAGE);
|
||||||
this.hoveredSlot = null;
|
this.hoveredSlot = null;
|
||||||
|
|
@ -329,7 +326,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
|
||||||
|
|
||||||
// 定位到 GUI 右缘外侧一点(使用绝对屏幕坐标)
|
// 定位到 GUI 右缘外侧一点(使用绝对屏幕坐标)
|
||||||
int bx = this.leftPos + this.imageWidth + 1; // 向右平移 1px 到面板外侧
|
int bx = this.leftPos + this.imageWidth + 1; // 向右平移 1px 到面板外侧
|
||||||
int by = this.topPos + 20;
|
int by = this.topPos + 50; // 向下偏移25px (从20改为45)
|
||||||
int spacing = 22;
|
int spacing = 22;
|
||||||
// 翻页按钮交由左侧工具栏布局,无需手动定位
|
// 翻页按钮交由左侧工具栏布局,无需手动定位
|
||||||
if (this.divideBy2Button != null) {
|
if (this.divideBy2Button != null) {
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,9 @@ public class CraftingMonitorJumpC2SPacket {
|
||||||
ServerPlayer player = context.getSender();
|
ServerPlayer player = context.getSender();
|
||||||
if (player == null) return;
|
if (player == null) return;
|
||||||
|
|
||||||
LogUtils.getLogger().info("EAP[S]: recv CraftingMonitorJumpC2SPacket key={} from {}", msg.what, player.getGameProfile().getName());
|
|
||||||
|
|
||||||
// 必须在 CraftingCPU 界面内
|
// 必须在 CraftingCPU 界面内
|
||||||
if (!(player.containerMenu instanceof appeng.menu.me.crafting.CraftingCPUMenu menu)) {
|
if (!(player.containerMenu instanceof appeng.menu.me.crafting.CraftingCPUMenu menu)) {
|
||||||
LogUtils.getLogger().info("EAP[S]: not in CraftingCPUMenu, abort");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,19 +65,16 @@ public class CraftingMonitorJumpC2SPacket {
|
||||||
grid = host.getActionableNode().getGrid();
|
grid = host.getActionableNode().getGrid();
|
||||||
}
|
}
|
||||||
if (grid == null) {
|
if (grid == null) {
|
||||||
LogUtils.getLogger().info("EAP[S]: grid is null, abort");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cs = grid.getCraftingService();
|
var cs = grid.getCraftingService();
|
||||||
if (!(cs instanceof CraftingService craftingService)) {
|
if (!(cs instanceof CraftingService craftingService)) {
|
||||||
LogUtils.getLogger().info("EAP[S]: craftingService is null/unsupported, abort");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1) 根据 AEKey 找到可能的样板(pattern)
|
// 1) 根据 AEKey 找到可能的样板(pattern)
|
||||||
Collection<IPatternDetails> patterns = craftingService.getCraftingFor(msg.what);
|
Collection<IPatternDetails> patterns = craftingService.getCraftingFor(msg.what);
|
||||||
LogUtils.getLogger().info("EAP[S]: patterns found={} for key={}", patterns.size(), msg.what);
|
|
||||||
if (patterns.isEmpty()) {
|
if (patterns.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -90,9 +85,6 @@ public class CraftingMonitorJumpC2SPacket {
|
||||||
int providerCount = 0;
|
int providerCount = 0;
|
||||||
for (var provider : providers) {
|
for (var provider : providers) {
|
||||||
providerCount++;
|
providerCount++;
|
||||||
try {
|
|
||||||
LogUtils.getLogger().info("EAP[S]: provider class={}", provider.getClass().getName());
|
|
||||||
} catch (Throwable ignored) {}
|
|
||||||
if (provider instanceof PatternProviderLogic ppl) {
|
if (provider instanceof PatternProviderLogic ppl) {
|
||||||
// 使用 accessor 获取 host(受保护字段通过 accessor 访问)
|
// 使用 accessor 获取 host(受保护字段通过 accessor 访问)
|
||||||
PatternProviderLogicHost host = ((PatternProviderLogicAccessor) ppl).eap$host();
|
PatternProviderLogicHost host = ((PatternProviderLogicAccessor) ppl).eap$host();
|
||||||
|
|
@ -105,7 +97,6 @@ public class CraftingMonitorJumpC2SPacket {
|
||||||
BlockPos targetPos = pbe.getBlockPos().relative(dir);
|
BlockPos targetPos = pbe.getBlockPos().relative(dir);
|
||||||
var tbe = serverLevel.getBlockEntity(targetPos);
|
var tbe = serverLevel.getBlockEntity(targetPos);
|
||||||
if (tbe instanceof MenuProvider provider1) {
|
if (tbe instanceof MenuProvider provider1) {
|
||||||
LogUtils.getLogger().info("EAP[S]: open screen via MenuProvider at {}", targetPos);
|
|
||||||
NetworkHooks.openScreen(player, provider1, targetPos);
|
NetworkHooks.openScreen(player, provider1, targetPos);
|
||||||
context.setPacketHandled(true);
|
context.setPacketHandled(true);
|
||||||
return;
|
return;
|
||||||
|
|
@ -113,7 +104,6 @@ public class CraftingMonitorJumpC2SPacket {
|
||||||
var tstate = serverLevel.getBlockState(targetPos);
|
var tstate = serverLevel.getBlockState(targetPos);
|
||||||
var provider2 = tstate.getMenuProvider(serverLevel, targetPos);
|
var provider2 = tstate.getMenuProvider(serverLevel, targetPos);
|
||||||
if (provider2 != null) {
|
if (provider2 != null) {
|
||||||
LogUtils.getLogger().info("EAP[S]: open screen via state.getMenuProvider at {}", targetPos);
|
|
||||||
NetworkHooks.openScreen(player, provider2, targetPos);
|
NetworkHooks.openScreen(player, provider2, targetPos);
|
||||||
context.setPacketHandled(true);
|
context.setPacketHandled(true);
|
||||||
return;
|
return;
|
||||||
|
|
@ -136,7 +126,6 @@ public class CraftingMonitorJumpC2SPacket {
|
||||||
var state2 = serverLevel.getBlockState(targetPos);
|
var state2 = serverLevel.getBlockState(targetPos);
|
||||||
var hit = new BlockHitResult(Vec3.atCenterOf(targetPos), chosen.getOpposite(), targetPos, false);
|
var hit = new BlockHitResult(Vec3.atCenterOf(targetPos), chosen.getOpposite(), targetPos, false);
|
||||||
InteractionResult r = state2.use(serverLevel, player, hand, hit);
|
InteractionResult r = state2.use(serverLevel, player, hand, hit);
|
||||||
LogUtils.getLogger().info("EAP[S]: simulated use on {}, face={}, result={}", targetPos, chosen, r);
|
|
||||||
if (r.consumesAction()) {
|
if (r.consumesAction()) {
|
||||||
context.setPacketHandled(true);
|
context.setPacketHandled(true);
|
||||||
return;
|
return;
|
||||||
|
|
@ -144,9 +133,7 @@ public class CraftingMonitorJumpC2SPacket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogUtils.getLogger().info("EAP[S]: providers count for one pattern: {}", providerCount);
|
|
||||||
}
|
}
|
||||||
LogUtils.getLogger().info("EAP[S]: no target opened for key={}", msg.what);
|
|
||||||
});
|
});
|
||||||
context.setPacketHandled(true);
|
context.setPacketHandled(true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -941,7 +941,9 @@ public class ExtendedAEPatternUploadUtil {
|
||||||
// 尝试获取供应器的组信息来构建显示名称
|
// 尝试获取供应器的组信息来构建显示名称
|
||||||
var group = container.getTerminalGroup();
|
var group = container.getTerminalGroup();
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
return group.name().getString();
|
// 使用 Component 序列化来保持翻译键,而不是直接 getString()
|
||||||
|
// 这样客户端可以根据自己的语言设置进行翻译
|
||||||
|
return Component.Serializer.toJson(group.name());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 忽略异常,使用默认名称
|
// 忽略异常,使用默认名称
|
||||||
|
|
@ -1183,7 +1185,11 @@ public class ExtendedAEPatternUploadUtil {
|
||||||
if (container == null) return "未知供应器";
|
if (container == null) return "未知供应器";
|
||||||
try {
|
try {
|
||||||
var group = container.getTerminalGroup();
|
var group = container.getTerminalGroup();
|
||||||
if (group != null) return group.name().getString();
|
if (group != null) {
|
||||||
|
// 使用 Component 序列化来保持翻译键,而不是直接 getString()
|
||||||
|
// 这样客户端可以根据自己的语言设置进行翻译
|
||||||
|
return Component.Serializer.toJson(group.name());
|
||||||
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
return "样板供应器";
|
return "样板供应器";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user