From 64fb68df17ea472701f12d9229a91017117adbe3 Mon Sep 17 00:00:00 2001 From: GaLi <3096147684@qq.com> Date: Sun, 10 Aug 2025 17:31:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=A0=B7=E6=9D=BF=E5=80=8D?= =?UTF-8?q?=E5=A2=9E=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/ExtendedAEPlus.java | 4 +- .../java/com/extendedae_plus/NewIcon.java | 29 + .../client/gui/PatternBetterIcons.java | 28 + .../mixin/GuiExPatternProviderMixin.java | 83 +- .../util/PatternProviderDataUtil.java | 903 ++++++++++++++++++ .../util/PatternProviderUIHelper.java | 111 +++ .../extendedae_plus/textures/gui/nicons.png | Bin 0 -> 381 bytes 7 files changed, 1144 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/NewIcon.java create mode 100644 src/main/java/com/extendedae_plus/client/gui/PatternBetterIcons.java create mode 100644 src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java create mode 100644 src/main/java/com/extendedae_plus/util/PatternProviderUIHelper.java create mode 100644 src/main/resources/assets/extendedae_plus/textures/gui/nicons.png diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index a9c4d90..04bec4e 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -12,7 +12,9 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; */ @Mod("extendedae_plus") public class ExtendedAEPlus { - + + public static final String MODID = "extendedae_plus"; + public ExtendedAEPlus() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); diff --git a/src/main/java/com/extendedae_plus/NewIcon.java b/src/main/java/com/extendedae_plus/NewIcon.java new file mode 100644 index 0000000..34825bb --- /dev/null +++ b/src/main/java/com/extendedae_plus/NewIcon.java @@ -0,0 +1,29 @@ +package com.extendedae_plus; + +import appeng.client.gui.style.Blitter; +import com.glodblock.github.extendedae.ExtendedAE; +import net.minecraft.resources.ResourceLocation; + +public class NewIcon { + @SuppressWarnings("all") + private static final ResourceLocation TEXTURE = new ResourceLocation(ExtendedAEPlus.MODID,"textures/gui/nicons.png"); + + + + public static final Blitter MULTIPLY2; + public static final Blitter DIVIDE2; + public static final Blitter MULTIPLY5; + public static final Blitter DIVIDE5; + public static final Blitter MULTIPLY10; + public static final Blitter DIVIDE10; + + static { + MULTIPLY2 = Blitter.texture(TEXTURE, 64, 64).src(32, 0, 16, 16); + DIVIDE2 = Blitter.texture(TEXTURE, 64, 64).src(48, 0, 16, 16); + MULTIPLY5 = Blitter.texture(TEXTURE, 64, 64).src(0, 0, 16, 16); + DIVIDE5 = Blitter.texture(TEXTURE, 64, 64).src(16, 0, 16, 16); + MULTIPLY10 = Blitter.texture(TEXTURE, 64, 64).src(0, 16, 16, 16); + DIVIDE10 = Blitter.texture(TEXTURE, 64, 64).src(16, 16, 16, 16); + + } +} diff --git a/src/main/java/com/extendedae_plus/client/gui/PatternBetterIcons.java b/src/main/java/com/extendedae_plus/client/gui/PatternBetterIcons.java new file mode 100644 index 0000000..5af0c8f --- /dev/null +++ b/src/main/java/com/extendedae_plus/client/gui/PatternBetterIcons.java @@ -0,0 +1,28 @@ +package com.extendedae_plus.client.gui; + +import appeng.client.gui.style.Blitter; +import net.minecraft.resources.ResourceLocation; + +/** + * PatternBetter功能的图标定义 + * 复刻自PatternBetter模组的NewIcon类 + */ +public class PatternBetterIcons { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath("extendedae_plus", "textures/gui/pattern_better_icons.png"); + + public static final Blitter MULTIPLY2; + public static final Blitter DIVIDE2; + public static final Blitter MULTIPLY5; + public static final Blitter DIVIDE5; + public static final Blitter MULTIPLY10; + public static final Blitter DIVIDE10; + + static { + MULTIPLY2 = Blitter.texture(TEXTURE, 64, 64).src(32, 0, 16, 16); + DIVIDE2 = Blitter.texture(TEXTURE, 64, 64).src(48, 0, 16, 16); + MULTIPLY5 = Blitter.texture(TEXTURE, 64, 64).src(0, 0, 16, 16); + DIVIDE5 = Blitter.texture(TEXTURE, 64, 64).src(16, 0, 16, 16); + MULTIPLY10 = Blitter.texture(TEXTURE, 64, 64).src(0, 16, 16, 16); + DIVIDE10 = Blitter.texture(TEXTURE, 64, 64).src(16, 16, 16, 16); + } +} diff --git a/src/main/java/com/extendedae_plus/mixin/GuiExPatternProviderMixin.java b/src/main/java/com/extendedae_plus/mixin/GuiExPatternProviderMixin.java index c1cff42..c00e5d0 100644 --- a/src/main/java/com/extendedae_plus/mixin/GuiExPatternProviderMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/GuiExPatternProviderMixin.java @@ -6,6 +6,8 @@ import appeng.client.gui.style.PaletteColor; import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.widgets.VerticalButtonBar; import appeng.menu.SlotSemantics; +import com.extendedae_plus.NewIcon; +import com.extendedae_plus.util.PatternProviderUIHelper; import com.glodblock.github.extendedae.client.button.ActionEPPButton; import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; import com.glodblock.github.extendedae.container.ContainerExPatternProvider; @@ -86,6 +88,12 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen { - int currentPage = getCurrentPage(); - int maxPage = getMaxPage(); - // 循环翻页:最后一页向后翻到第一页 - int newPage = (currentPage + 1) % maxPage; - try { - ContainerExPatternProvider menu1 = this.getMenu(); - java.lang.reflect.Method setPageMethod = menu1.getClass().getMethod("setPage", int.class); - setPageMethod.invoke(menu1, newPage); - } catch (Exception e) { - // 忽略反射错误 - } - }, Icon.ARROW_RIGHT); + int currentPage = getCurrentPage(); + int maxPage = getMaxPage(); + // 循环翻页:最后一页向后翻到第一页 + int newPage = (currentPage + 1) % maxPage; + try { + ContainerExPatternProvider menu1 = this.getMenu(); + java.lang.reflect.Method setPageMethod = menu1.getClass().getMethod("setPage", int.class); + setPageMethod.invoke(menu1, newPage); + } catch (Exception e) { + // 忽略反射错误 + } + }, Icon.ARROW_RIGHT); this.addToLeftToolbar(this.nextPage); this.addToLeftToolbar(this.prevPage); } + + // x2 按钮 - 一直显示,将所有处理样板的输入输出乘以2 + this.x2Button = new ActionEPPButton((b) -> { + try { + var result = PatternProviderUIHelper.multiplyCurrentPatternAmounts(2.0); + if (result != null) { + if (result.isSuccessful()) { + System.out.println("成功将 " + result.getScaledPatterns() + " 个处理样板的数量乘以2!"); + if (result.getFailedPatterns() > 0) { + System.out.println("跳过了 " + result.getFailedPatterns() + " 个合成样板(合成样板不支持数量缩放)"); + } + } else { + System.out.println("样板数量缩放失败:" + String.join(", ", result.getErrors())); + } + } else { + System.out.println("无法获取当前样板供应器,请确保界面已正确打开"); + } + } catch (Exception e) { + System.out.println("执行样板数量乘2时发生错误:" + e.getMessage()); + e.printStackTrace(); + } + }, NewIcon.MULTIPLY2); + + // /2 按钮 - 一直显示,将所有处理样板的输入输出除以2 + this.divideBy2Button = new ActionEPPButton((b) -> { + try { + var result = PatternProviderUIHelper.divideCurrentPatternAmounts(2.0); + if (result != null) { + if (result.isSuccessful()) { + System.out.println("成功将 " + result.getScaledPatterns() + " 个处理样板的数量除以2!"); + if (result.getFailedPatterns() > 0) { + System.out.println("跳过了 " + result.getFailedPatterns() + " 个合成样板(合成样板不支持数量缩放)"); + } + } else { + System.out.println("样板数量缩放失败:" + String.join(", ", result.getErrors())); + } + } else { + System.out.println("无法获取当前样板供应器,请确保界面已正确打开"); + } + } catch (Exception e) { + System.out.println("执行样板数量除以2时发生错误:" + e.getMessage()); + e.printStackTrace(); + } + }, NewIcon.DIVIDE2); + + this.addToLeftToolbar(this.x2Button); + this.addToLeftToolbar(this.divideBy2Button); } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java b/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java new file mode 100644 index 0000000..0828e10 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java @@ -0,0 +1,903 @@ +package com.extendedae_plus.util; + +import appeng.api.crafting.IPatternDetails; +import appeng.api.crafting.PatternDetailsHelper; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.GenericStack; +import appeng.helpers.patternprovider.PatternProviderLogic; +import appeng.api.inventories.InternalInventory; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +import java.util.ArrayList; +import java.util.List; +import java.util.Arrays; + +/** + * 样板供应器数据工具类 + * 用于获取样板供应器中的所有样板数据,包括输入输出物品的数量信息 + */ +public class PatternProviderDataUtil { + + /** + * 样板数据类,包含样板的输入输出信息 + */ + public static class PatternData { + private final IPatternDetails patternDetails; + private final ItemStack patternStack; + private final int slotIndex; + private final List inputs; + private final List outputs; + + public PatternData(IPatternDetails patternDetails, ItemStack patternStack, int slotIndex) { + this.patternDetails = patternDetails; + this.patternStack = patternStack; + this.slotIndex = slotIndex; + this.inputs = new ArrayList<>(); + this.outputs = new ArrayList<>(); + + // 解析输入数据 + parseInputs(); + // 解析输出数据 + parseOutputs(); + } + + private void parseInputs() { + IPatternDetails.IInput[] patternInputs = patternDetails.getInputs(); + for (int i = 0; i < patternInputs.length; i++) { + IPatternDetails.IInput input = patternInputs[i]; + GenericStack[] possibleInputs = input.getPossibleInputs(); + long multiplier = input.getMultiplier(); + + for (GenericStack possibleInput : possibleInputs) { + if (possibleInput != null && possibleInput.what() != null) { + inputs.add(new InputData(possibleInput.what(), possibleInput.amount() * multiplier, i)); + } + } + } + } + + private void parseOutputs() { + GenericStack[] patternOutputs = patternDetails.getOutputs(); + for (int i = 0; i < patternOutputs.length; i++) { + GenericStack output = patternOutputs[i]; + if (output != null && output.what() != null) { + outputs.add(new OutputData(output.what(), output.amount(), i)); + } + } + } + + public IPatternDetails getPatternDetails() { + return patternDetails; + } + + public ItemStack getPatternStack() { + return patternStack; + } + + public int getSlotIndex() { + return slotIndex; + } + + public List getInputs() { + return inputs; + } + + public List getOutputs() { + return outputs; + } + + /** + * 获取样板的定义键 + */ + public String getPatternDefinition() { + return patternDetails.getDefinition().toString(); + } + + /** + * 检查是否为制作样板 + * 通过检查实现类型来判断 + */ + public boolean isCraftingPattern() { + // 根据AE2源码,制作样板使用AECraftingPattern类 + return patternDetails.getClass().getSimpleName().equals("AECraftingPattern"); + } + + /** + * 检查是否为处理样板 + * 通过检查实现类型来判断 + */ + public boolean isProcessingPattern() { + // 处理样板使用AEProcessingPattern类 + return patternDetails.getClass().getSimpleName().equals("AEProcessingPattern"); + } + + /** + * 检查是否为石切样板 + * 通过检查定义类型来判断 + */ + public boolean isStonecuttingPattern() { + return patternDetails.getDefinition().toString().contains("stonecutting"); + } + + /** + * 检查是否为锻造样板 + * 通过检查定义类型来判断 + */ + public boolean isSmithingPattern() { + return patternDetails.getDefinition().toString().contains("smithing"); + } + + /** + * 获取样板的输出数量(主要输出) + */ + public long getPrimaryOutputAmount() { + if (outputs.isEmpty()) { + return 0; + } + return outputs.get(0).getAmount(); + } + + /** + * 检查样板是否有副产品 + */ + public boolean hasSecondaryOutputs() { + return outputs.size() > 1; + } + } + + /** + * 输入数据类 + */ + public static class InputData { + private final AEKey key; + private final long amount; + private final int inputIndex; + + public InputData(AEKey key, long amount, int inputIndex) { + this.key = key; + this.amount = amount; + this.inputIndex = inputIndex; + } + + public AEKey getKey() { + return key; + } + + public long getAmount() { + return amount; + } + + public int getInputIndex() { + return inputIndex; + } + + public String getDisplayName() { + return key.getDisplayName().getString(); + } + } + + /** + * 输出数据类 + */ + public static class OutputData { + private final AEKey key; + private final long amount; + private final int outputIndex; + + public OutputData(AEKey key, long amount, int outputIndex) { + this.key = key; + this.amount = amount; + this.outputIndex = outputIndex; + } + + public AEKey getKey() { + return key; + } + + public long getAmount() { + return amount; + } + + public int getOutputIndex() { + return outputIndex; + } + + public String getDisplayName() { + return key.getDisplayName().getString(); + } + } + + /** + * 获取样板供应器中的所有样板数据 + * + * @param patternProvider 样板供应器逻辑 + * @return 所有样板的详细信息列表 + */ + public static List getAllPatternData(PatternProviderLogic patternProvider) { + List patternDataList = new ArrayList<>(); + + if (patternProvider == null) { + return patternDataList; + } + + // 获取样板库存 + InternalInventory patternInventory = patternProvider.getPatternInv(); + if (patternInventory == null) { + return patternDataList; + } + + // 通过反射安全地访问host字段获取Level + Level level = null; + try { + var hostField = patternProvider.getClass().getDeclaredField("host"); + hostField.setAccessible(true); + var host = hostField.get(patternProvider); + if (host != null) { + var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity"); + var blockEntity = getBlockEntityMethod.invoke(host); + if (blockEntity != null) { + var getLevelMethod = blockEntity.getClass().getMethod("getLevel"); + level = (Level) getLevelMethod.invoke(blockEntity); + } + } + } catch (Exception e) { + // 如果反射失败,返回空列表 + return patternDataList; + } + + if (level == null) { + return patternDataList; + } + + // 遍历所有样板槽位 + for (int i = 0; i < patternInventory.size(); i++) { + ItemStack patternStack = patternInventory.getStackInSlot(i); + if (!patternStack.isEmpty()) { + // 解码样板 + IPatternDetails patternDetails = PatternDetailsHelper.decodePattern(patternStack, level); + if (patternDetails != null) { + patternDataList.add(new PatternData(patternDetails, patternStack, i)); + } + } + } + + return patternDataList; + } + + /** + * 获取样板供应器中的样板数量 + * + * @param patternProvider 样板供应器逻辑 + * @return 样板数量 + */ + public static int getPatternCount(PatternProviderLogic patternProvider) { + if (patternProvider == null) { + return 0; + } + + InternalInventory patternInventory = patternProvider.getPatternInv(); + if (patternInventory == null) { + return 0; + } + + int count = 0; + for (int i = 0; i < patternInventory.size(); i++) { + if (!patternInventory.getStackInSlot(i).isEmpty()) { + count++; + } + } + + return count; + } + + /** + * 获取样板供应器的总槽位数 + * + * @param patternProvider 样板供应器逻辑 + * @return 总槽位数 + */ + public static int getTotalSlots(PatternProviderLogic patternProvider) { + if (patternProvider == null) { + return 0; + } + + InternalInventory patternInventory = patternProvider.getPatternInv(); + return patternInventory != null ? patternInventory.size() : 0; + } + + /** + * 获取样板供应器的可用槽位数 + * + * @param patternProvider 样板供应器逻辑 + * @return 可用槽位数 + */ + public static int getAvailableSlots(PatternProviderLogic patternProvider) { + return getTotalSlots(patternProvider) - getPatternCount(patternProvider); + } + + /** + * 检查样板供应器是否有足够的槽位 + * + * @param patternProvider 样板供应器逻辑 + * @param requiredSlots 需要的槽位数 + * @return 是否有足够的槽位 + */ + public static boolean hasEnoughSlots(PatternProviderLogic patternProvider, int requiredSlots) { + return getAvailableSlots(patternProvider) >= requiredSlots; + } + + /** + * 获取指定槽位的样板数据 + * + * @param patternProvider 样板供应器逻辑 + * @param slotIndex 槽位索引 + * @return 样板数据,如果槽位为空或无效则返回null + */ + public static PatternData getPatternDataAtSlot(PatternProviderLogic patternProvider, int slotIndex) { + if (patternProvider == null) { + return null; + } + + InternalInventory patternInventory = patternProvider.getPatternInv(); + if (patternInventory == null || slotIndex < 0 || slotIndex >= patternInventory.size()) { + return null; + } + + ItemStack patternStack = patternInventory.getStackInSlot(slotIndex); + if (patternStack.isEmpty()) { + return null; + } + + // 通过反射安全地访问host字段获取Level + Level level = null; + try { + var hostField = patternProvider.getClass().getDeclaredField("host"); + hostField.setAccessible(true); + var host = hostField.get(patternProvider); + if (host != null) { + var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity"); + var blockEntity = getBlockEntityMethod.invoke(host); + if (blockEntity != null) { + var getLevelMethod = blockEntity.getClass().getMethod("getLevel"); + level = (Level) getLevelMethod.invoke(blockEntity); + } + } + } catch (Exception e) { + return null; + } + + if (level == null) { + return null; + } + + IPatternDetails patternDetails = PatternDetailsHelper.decodePattern(patternStack, level); + if (patternDetails == null) { + return null; + } + + return new PatternData(patternDetails, patternStack, slotIndex); + } + + /** + * 检查样板供应器是否为空 + * + * @param patternProvider 样板供应器逻辑 + * @return 是否为空 + */ + public static boolean isEmpty(PatternProviderLogic patternProvider) { + return getPatternCount(patternProvider) == 0; + } + + /** + * 检查样板供应器是否已满 + * + * @param patternProvider 样板供应器逻辑 + * @return 是否已满 + */ + public static boolean isFull(PatternProviderLogic patternProvider) { + return getAvailableSlots(patternProvider) == 0; + } + + /** + * 获取样板供应器的优先级 + * + * @param patternProvider 样板供应器逻辑 + * @return 优先级值 + */ + public static int getPatternPriority(PatternProviderLogic patternProvider) { + if (patternProvider == null) { + return 0; + } + return patternProvider.getPatternPriority(); + } + + /** + * 检查样板供应器是否连接到ME网络 + * + * @param patternProvider 样板供应器逻辑 + * @return 是否连接到网络 + */ + public static boolean isConnectedToNetwork(PatternProviderLogic patternProvider) { + if (patternProvider == null) { + return false; + } + return patternProvider.getGrid() != null; + } + + /** + * 检查样板供应器是否处于活跃状态 + * + * @param patternProvider 样板供应器逻辑 + * @return 是否活跃 + */ + public static boolean isActive(PatternProviderLogic patternProvider) { + if (patternProvider == null) { + return false; + } + var grid = patternProvider.getGrid(); + if (grid == null) { + return false; + } + // 检查网格节点是否活跃 + try { + // 使用反射安全地访问mainNode字段 + var mainNodeField = patternProvider.getClass().getDeclaredField("mainNode"); + mainNodeField.setAccessible(true); + var mainNode = mainNodeField.get(patternProvider); + if (mainNode != null) { + var isActiveMethod = mainNode.getClass().getMethod("isActive"); + return (Boolean) isActiveMethod.invoke(mainNode); + } + } catch (Exception e) { + // 如果反射失败,假设是活跃的 + } + return true; + } + + /** + * 获取样板供应器的显示名称 + * + * @param patternProvider 样板供应器逻辑 + * @return 显示名称 + */ + public static String getDisplayName(PatternProviderLogic patternProvider) { + if (patternProvider == null) { + return "未知样板供应器"; + } + + try { + var group = patternProvider.getTerminalGroup(); + if (group != null && group.name() != null) { + return group.name().getString(); + } + } catch (Exception e) { + // 忽略异常,使用默认名称 + } + + return "样板供应器"; + } + + /** + * 样板缩放操作结果 + */ + public static class PatternScalingResult { + private final int totalPatterns; + private final int scaledPatterns; + private final int failedPatterns; + private final List errors; + + public PatternScalingResult(int totalPatterns, int scaledPatterns, int failedPatterns, List errors) { + this.totalPatterns = totalPatterns; + this.scaledPatterns = scaledPatterns; + this.failedPatterns = failedPatterns; + this.errors = new ArrayList<>(errors); + } + + public int getTotalPatterns() { return totalPatterns; } + public int getScaledPatterns() { return scaledPatterns; } + public int getFailedPatterns() { return failedPatterns; } + public List getErrors() { return new ArrayList<>(errors); } + + public boolean isSuccessful() { return failedPatterns == 0; } + public boolean hasPartialSuccess() { return scaledPatterns > 0 && failedPatterns > 0; } + } + + /** + * 对样板供应器中的所有样板进行输入输出数量倍增 + * + * @param patternProvider 样板供应器逻辑 + * @param multiplier 倍数(必须大于0) + * @return 缩放操作结果 + */ + public static PatternScalingResult multiplyPatternAmounts(PatternProviderLogic patternProvider, double multiplier) { + if (multiplier <= 0) { + throw new IllegalArgumentException("倍数必须大于0"); + } + return scalePatternAmounts(patternProvider, multiplier, true); + } + + /** + * 对样板供应器中的所有样板进行输入输出数量倍除 + * + * @param patternProvider 样板供应器逻辑 + * @param divisor 除数(必须大于0) + * @return 缩放操作结果 + */ + public static PatternScalingResult dividePatternAmounts(PatternProviderLogic patternProvider, double divisor) { + if (divisor <= 0) { + throw new IllegalArgumentException("除数必须大于0"); + } + return scalePatternAmounts(patternProvider, 1.0 / divisor, false); + } + + /** + * 内部方法:执行样板数量缩放 + */ + private static PatternScalingResult scalePatternAmounts(PatternProviderLogic patternProvider, double scaleFactor, boolean isMultiply) { + List errors = new ArrayList<>(); + int totalPatterns = 0; + int scaledPatterns = 0; + int failedPatterns = 0; + + if (patternProvider == null) { + errors.add("样板供应器为null"); + return new PatternScalingResult(0, 0, 0, errors); + } + + InternalInventory patternInventory = patternProvider.getPatternInv(); + if (patternInventory == null) { + errors.add("无法访问样板库存"); + return new PatternScalingResult(0, 0, 0, errors); + } + + // 获取Level对象 + Level level = null; + try { + var hostField = patternProvider.getClass().getDeclaredField("host"); + hostField.setAccessible(true); + var host = hostField.get(patternProvider); + if (host != null) { + var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity"); + var blockEntity = getBlockEntityMethod.invoke(host); + if (blockEntity != null) { + var getLevelMethod = blockEntity.getClass().getMethod("getLevel"); + level = (Level) getLevelMethod.invoke(blockEntity); + } + } + } catch (Exception e) { + errors.add("无法获取Level对象: " + e.getMessage()); + return new PatternScalingResult(0, 0, 0, errors); + } + + if (level == null) { + errors.add("Level对象为null"); + return new PatternScalingResult(0, 0, 0, errors); + } + + // 遍历所有样板槽位 + for (int i = 0; i < patternInventory.size(); i++) { + ItemStack patternStack = patternInventory.getStackInSlot(i); + if (patternStack.isEmpty()) { + continue; + } + + totalPatterns++; + + try { + // 解码原始样板 + IPatternDetails originalPattern = PatternDetailsHelper.decodePattern(patternStack, level); + if (originalPattern == null) { + errors.add("槽位 " + i + ": 无法解码样板"); + failedPatterns++; + continue; + } + + // 检查是否为合成样板 + boolean isCraftingPattern = originalPattern.getClass().getSimpleName().equals("AECraftingPattern"); + + if (isCraftingPattern) { + // 合成样板跳过缩放,不计入失败数 + continue; + } + + // 如果是除法操作,检查是否可以被除 + if (scaleFactor < 1.0) { + double divisor = 1.0 / scaleFactor; + if (!canDivideProcessingPattern(originalPattern, divisor)) { + // 不能被除的样板跳过,不计入失败数,但记录信息 + errors.add("槽位 " + i + ": 样板数量为1或不能被整除,跳过除法操作"); + failedPatterns++; + continue; + } + } + + // 缩放样板(只处理处理样板) + ItemStack scaledPatternStack = scalePattern(originalPattern, scaleFactor, level); + if (scaledPatternStack == null || scaledPatternStack.isEmpty()) { + errors.add("槽位 " + i + ": 样板缩放失败"); + failedPatterns++; + continue; + } + + // 替换原样板 + patternInventory.setItemDirect(i, scaledPatternStack); + scaledPatterns++; + + } catch (Exception e) { + errors.add("槽位 " + i + ": 处理样板时发生异常 - " + e.getMessage()); + failedPatterns++; + } + } + + // 触发样板更新 + try { + patternProvider.updatePatterns(); + } catch (Exception e) { + errors.add("更新样板列表时发生异常: " + e.getMessage()); + } + + return new PatternScalingResult(totalPatterns, scaledPatterns, failedPatterns, errors); + } + + /** + * 缩放单个样板的输入输出数量 + * 注意:只有处理样板会被缩放,合成样板会被跳过 + */ + private static ItemStack scalePattern(IPatternDetails originalPattern, double scaleFactor, Level level) { + try { + // 检查样板类型 + boolean isCraftingPattern = originalPattern.getClass().getSimpleName().equals("AECraftingPattern"); + boolean isProcessingPattern = originalPattern.getClass().getSimpleName().equals("AEProcessingPattern"); + + if (isCraftingPattern) { + // 合成样板不参与缩放,直接返回null表示跳过 + return null; + } else if (isProcessingPattern) { + // 如果是除法操作(scaleFactor < 1),需要检查是否可以除 + if (scaleFactor < 1.0) { + double divisor = 1.0 / scaleFactor; + if (!canDivideProcessingPattern(originalPattern, divisor)) { + // 不能被除,返回null表示跳过 + return null; + } + } + // 只有处理样板才进行缩放 + return scaleProcessingPattern(originalPattern, scaleFactor); + } else { + // 对于未知类型的样板,也尝试作为处理样板处理 + if (scaleFactor < 1.0) { + double divisor = 1.0 / scaleFactor; + if (!canDivideProcessingPattern(originalPattern, divisor)) { + return null; + } + } + return scaleProcessingPattern(originalPattern, scaleFactor); + } + } catch (Exception e) { + return null; + } + } + + /** + * 检查处理样板是否可以被除法操作 + * 如果输出为1且不能被整除,则不能再除 + */ + private static boolean canDivideProcessingPattern(IPatternDetails originalPattern, double divisor) { + try { + // 获取原始输入输出 + IPatternDetails.IInput[] originalInputs = originalPattern.getInputs(); + GenericStack[] originalOutputs = originalPattern.getOutputs(); + + // 检查输入是否可以被除 + for (IPatternDetails.IInput input : originalInputs) { + GenericStack[] possibleInputs = input.getPossibleInputs(); + long multiplier = input.getMultiplier(); + + if (possibleInputs.length > 0 && possibleInputs[0] != null) { + GenericStack primaryInput = possibleInputs[0]; + long currentAmount = primaryInput.amount() * multiplier; + + // 如果当前数量为1且不能被整除,则不能除 + if (currentAmount == 1 || (currentAmount % divisor != 0 && currentAmount < divisor)) { + return false; + } + } + } + + // 检查输出是否可以被除 + for (GenericStack output : originalOutputs) { + if (output != null && output.what() != null) { + long currentAmount = output.amount(); + + // 如果当前数量为1且不能被整除,则不能除 + if (currentAmount == 1 || (currentAmount % divisor != 0 && currentAmount < divisor)) { + return false; + } + } + } + + return true; + } catch (Exception e) { + return false; + } + } + + /** + * 缩放处理样板 + */ + private static ItemStack scaleProcessingPattern(IPatternDetails originalPattern, double scaleFactor) { + try { + // 获取原始输入输出 + IPatternDetails.IInput[] originalInputs = originalPattern.getInputs(); + GenericStack[] originalOutputs = originalPattern.getOutputs(); + + // 缩放输入 + List scaledInputs = new ArrayList<>(); + for (IPatternDetails.IInput input : originalInputs) { + GenericStack[] possibleInputs = input.getPossibleInputs(); + long multiplier = input.getMultiplier(); + + if (possibleInputs.length > 0 && possibleInputs[0] != null) { + GenericStack primaryInput = possibleInputs[0]; + long newAmount = Math.max(1, Math.round(primaryInput.amount() * multiplier * scaleFactor)); + scaledInputs.add(new GenericStack(primaryInput.what(), newAmount)); + } + } + + // 缩放输出 + List scaledOutputs = new ArrayList<>(); + for (GenericStack output : originalOutputs) { + if (output != null && output.what() != null) { + long newAmount = Math.max(1, Math.round(output.amount() * scaleFactor)); + scaledOutputs.add(new GenericStack(output.what(), newAmount)); + } + } + + // 创建新的处理样板 + return PatternDetailsHelper.encodeProcessingPattern( + scaledInputs.toArray(new GenericStack[0]), + scaledOutputs.toArray(new GenericStack[0]) + ); + + } catch (Exception e) { + return null; + } + } + + // 注意:根据用户要求,合成样板不参与任何缩放操作 + // 因此移除了 scaleCraftingPattern 方法 + + /** + * 预览样板缩放结果(不实际修改样板) + * + * @param patternProvider 样板供应器逻辑 + * @param scaleFactor 缩放因子 + * @return 预览结果列表 + */ + public static List previewPatternScaling(PatternProviderLogic patternProvider, double scaleFactor) { + List previews = new ArrayList<>(); + + if (patternProvider == null || scaleFactor <= 0) { + return previews; + } + + List patterns = getAllPatternData(patternProvider); + for (PatternData pattern : patterns) { + // 只预览处理样板的缩放效果 + boolean isCraftingPattern = pattern.getPatternDetails().getClass().getSimpleName().equals("AECraftingPattern"); + + if (!isCraftingPattern) { + PatternScalingPreview preview = new PatternScalingPreview( + pattern.getSlotIndex(), + pattern.getPatternDetails(), + scaleFactor + ); + previews.add(preview); + } + } + + return previews; + } + + /** + * 样板缩放预览类 + */ + public static class PatternScalingPreview { + private final int slotIndex; + private final IPatternDetails originalPattern; + private final double scaleFactor; + private final List inputPreviews; + private final List outputPreviews; + + public PatternScalingPreview(int slotIndex, IPatternDetails originalPattern, double scaleFactor) { + this.slotIndex = slotIndex; + this.originalPattern = originalPattern; + this.scaleFactor = scaleFactor; + this.inputPreviews = new ArrayList<>(); + this.outputPreviews = new ArrayList<>(); + + calculatePreviews(); + } + + private void calculatePreviews() { + // 预览输入变化 + for (IPatternDetails.IInput input : originalPattern.getInputs()) { + GenericStack[] possibleInputs = input.getPossibleInputs(); + long multiplier = input.getMultiplier(); + + if (possibleInputs.length > 0 && possibleInputs[0] != null) { + GenericStack primaryInput = possibleInputs[0]; + long originalAmount = primaryInput.amount() * multiplier; + long newAmount = Math.max(1, Math.round(originalAmount * scaleFactor)); + + inputPreviews.add(new InputPreview( + primaryInput.what(), + originalAmount, + newAmount + )); + } + } + + // 预览输出变化 + for (GenericStack output : originalPattern.getOutputs()) { + if (output != null && output.what() != null) { + long originalAmount = output.amount(); + long newAmount = Math.max(1, Math.round(originalAmount * scaleFactor)); + + outputPreviews.add(new OutputPreview( + output.what(), + originalAmount, + newAmount + )); + } + } + } + + // Getters + public int getSlotIndex() { return slotIndex; } + public double getScaleFactor() { return scaleFactor; } + public List getInputPreviews() { return new ArrayList<>(inputPreviews); } + public List getOutputPreviews() { return new ArrayList<>(outputPreviews); } + } + + /** + * 输入预览类 + */ + public static class InputPreview { + private final AEKey key; + private final long originalAmount; + private final long newAmount; + + public InputPreview(AEKey key, long originalAmount, long newAmount) { + this.key = key; + this.originalAmount = originalAmount; + this.newAmount = newAmount; + } + + public AEKey getKey() { return key; } + public long getOriginalAmount() { return originalAmount; } + public long getNewAmount() { return newAmount; } + public String getDisplayName() { return key.getDisplayName().getString(); } + } + + /** + * 输出预览类 + */ + public static class OutputPreview { + private final AEKey key; + private final long originalAmount; + private final long newAmount; + + public OutputPreview(AEKey key, long originalAmount, long newAmount) { + this.key = key; + this.originalAmount = originalAmount; + this.newAmount = newAmount; + } + + public AEKey getKey() { return key; } + public long getOriginalAmount() { return originalAmount; } + public long getNewAmount() { return newAmount; } + public String getDisplayName() { return key.getDisplayName().getString(); } + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/util/PatternProviderUIHelper.java b/src/main/java/com/extendedae_plus/util/PatternProviderUIHelper.java new file mode 100644 index 0000000..53d4a0f --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/PatternProviderUIHelper.java @@ -0,0 +1,111 @@ +package com.extendedae_plus.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import appeng.client.gui.implementations.PatternProviderScreen; +import appeng.helpers.patternprovider.PatternProviderLogic; +import appeng.menu.implementations.PatternProviderMenu; + +/** + * 样板供应器UI辅助工具类 + * 用于在样板供应器界面中获取PatternProviderLogic对象 + */ +public class PatternProviderUIHelper { + + /** + * 获取当前打开的样板供应器的PatternProviderLogic + * + * @return PatternProviderLogic对象,如果当前没有打开样板供应器界面则返回null + */ + public static PatternProviderLogic getCurrentPatternProvider() { + Minecraft mc = Minecraft.getInstance(); + Screen currentScreen = mc.screen; + + if (currentScreen instanceof PatternProviderScreen patternScreen) { + PatternProviderMenu menu = (PatternProviderMenu) patternScreen.getMenu(); + + // 通过反射安全地访问protected字段 + try { + var logicField = PatternProviderMenu.class.getDeclaredField("logic"); + logicField.setAccessible(true); + return (PatternProviderLogic) logicField.get(menu); + } catch (Exception e) { + // 如果反射失败,返回null + return null; + } + } + + return null; + } + + /** + * 检查当前是否打开了样板供应器界面 + * + * @return 如果当前打开的是样板供应器界面则返回true + */ + public static boolean isPatternProviderScreenOpen() { + Minecraft mc = Minecraft.getInstance(); + return mc.screen instanceof PatternProviderScreen; + } + + /** + * 获取当前样板供应器界面的Screen对象 + * + * @return PatternProviderScreen对象,如果当前没有打开样板供应器界面则返回null + */ + public static PatternProviderScreen getCurrentPatternProviderScreen() { + Minecraft mc = Minecraft.getInstance(); + Screen currentScreen = mc.screen; + + if (currentScreen instanceof PatternProviderScreen patternScreen) { + return patternScreen; + } + + return null; + } + + /** + * 在当前样板供应器中执行样板数量倍增 + * + * @param multiplier 倍数(必须大于0) + * @return 缩放操作结果,如果当前没有打开样板供应器界面则返回null + */ + public static PatternProviderDataUtil.PatternScalingResult multiplyCurrentPatternAmounts(double multiplier) { + PatternProviderLogic patternProvider = getCurrentPatternProvider(); + if (patternProvider == null) { + return null; + } + + return PatternProviderDataUtil.multiplyPatternAmounts(patternProvider, multiplier); + } + + /** + * 在当前样板供应器中执行样板数量倍除 + * + * @param divisor 除数(必须大于0) + * @return 缩放操作结果,如果当前没有打开样板供应器界面则返回null + */ + public static PatternProviderDataUtil.PatternScalingResult divideCurrentPatternAmounts(double divisor) { + PatternProviderLogic patternProvider = getCurrentPatternProvider(); + if (patternProvider == null) { + return null; + } + + return PatternProviderDataUtil.dividePatternAmounts(patternProvider, divisor); + } + + /** + * 预览当前样板供应器的缩放效果 + * + * @param scaleFactor 缩放因子 + * @return 预览结果列表,如果当前没有打开样板供应器界面则返回空列表 + */ + public static java.util.List previewCurrentPatternScaling(double scaleFactor) { + PatternProviderLogic patternProvider = getCurrentPatternProvider(); + if (patternProvider == null) { + return new java.util.ArrayList<>(); + } + + return PatternProviderDataUtil.previewPatternScaling(patternProvider, scaleFactor); + } +} diff --git a/src/main/resources/assets/extendedae_plus/textures/gui/nicons.png b/src/main/resources/assets/extendedae_plus/textures/gui/nicons.png new file mode 100644 index 0000000000000000000000000000000000000000..6773deea7fc8990823e2aedafb4e1365e801fe78 GIT binary patch literal 381 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z%{^TlLn`LH zz44m!kby{BqG)~kW}gQPa}OlWIed1L!=F;GA19uwh-m+?3s`g3GE+}=LW~~6hvVxO zH%tlI_FJGydtcA&v+uVin(hxj9^3515&rhbYEbOS9tmsL+!Qdjj`H4*RtJW$T}YNb1P%{)x=h- zq?)?5MwaxOF?({g|V|e=AG0qi#=`vfp$U_nfo#vAMzvzpv%na*k=w z&-9!AEpM(IseZMn?$_sU7uK#gw<2BewQkk^T^#S?8*&BThNoXKKAd{S%MKWB2=E|5 XKL7A%!@PfYqCtY5u6{1-oD!M