From 77edd130542927cd1c2114a374f7825a2b086bc9 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Mon, 27 Oct 2025 01:27:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A3=85=E9=85=8D=E7=9F=A9=E9=98=B5=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/GlobalSendMessage.java | 7 + .../util/uploadPattern/MatrixUploadUtil.java | 289 ++++++------------ .../assets/extendedae_plus/lang/zh_cn.json | 3 + 3 files changed, 111 insertions(+), 188 deletions(-) diff --git a/src/main/java/com/extendedae_plus/util/GlobalSendMessage.java b/src/main/java/com/extendedae_plus/util/GlobalSendMessage.java index 5bf08f1..d067182 100644 --- a/src/main/java/com/extendedae_plus/util/GlobalSendMessage.java +++ b/src/main/java/com/extendedae_plus/util/GlobalSendMessage.java @@ -2,6 +2,7 @@ package com.extendedae_plus.util; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; public class GlobalSendMessage { /** @@ -13,4 +14,10 @@ public class GlobalSendMessage { player.sendSystemMessage(msg); } } + + public static void sendPlayerMessage(Player player, Component msg) { + if (player != null) { + player.sendSystemMessage(msg); + } + } } diff --git a/src/main/java/com/extendedae_plus/util/uploadPattern/MatrixUploadUtil.java b/src/main/java/com/extendedae_plus/util/uploadPattern/MatrixUploadUtil.java index f41cd86..98132db 100644 --- a/src/main/java/com/extendedae_plus/util/uploadPattern/MatrixUploadUtil.java +++ b/src/main/java/com/extendedae_plus/util/uploadPattern/MatrixUploadUtil.java @@ -13,267 +13,180 @@ import appeng.menu.me.items.PatternEncodingTermMenu; import appeng.menu.slot.RestrictedInputSlot; import com.extendedae_plus.content.matrix.UploadCoreBlockEntity; import com.extendedae_plus.mixin.ae2.accessor.PatternEncodingTermMenuAccessor; -import com.glodblock.github.extendedae.common.tileentities.matrix.TileAssemblerMatrixBase; +import com.glodblock.github.extendedae.common.me.matrix.ClusterAssemblerMatrix; import com.glodblock.github.extendedae.common.tileentities.matrix.TileAssemblerMatrixPattern; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.items.IItemHandler; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; +import static com.extendedae_plus.util.GlobalSendMessage.sendPlayerMessage; + /** - * 与装配矩阵 (assembler matrix) 上传 / 检查 相关的工具方法。 - * 保留原有逻辑与容错行为。 + * ExtendedAE 装配矩阵样板上传 + * 用于从 AE2 的样板编码终端上传至装配矩阵(仅合成样板)。 */ public final class MatrixUploadUtil { private MatrixUploadUtil() {} - /** - * 发送消息给玩家 - * - * @param player 玩家 - * @param message 消息内容 - */ - private static void sendMessage(ServerPlayer player, String message) { - // 静默:不再向玩家左下角发送任何提示信息 - // 如需恢复,取消下面注释即可: - // if (player != null) { - // player.sendSystemMessage(Component.literal(message)); - // } - // 如果玩家为null,静默忽略(用于测试环境) - } /** - * 从 AE2 的图样编码终端菜单上传当前“已编码图样”至 ExtendedAE 装配矩阵(仅合成图样)。 - * 不会处理“处理图样”。 + * 从 AE2 的样板编码终端菜单上传当前“已编码合成样板”至 ExtendedAE 装配矩阵(仅合成样板) * * @param player 服务器玩家 * @param menu PatternEncodingTermMenu - * @return 是否成功插入矩阵 */ - public static boolean uploadFromEncodingMenuToMatrix(ServerPlayer player, PatternEncodingTermMenu menu) { - if (player == null || menu == null) { - return false; - } - + public static void uploadFromEncodingMenuToMatrix(ServerPlayer player, PatternEncodingTermMenu menu) { + if (player == null || menu == null) return; // 读取已编码槽位的物品 - RestrictedInputSlot encodedSlot = ((PatternEncodingTermMenuAccessor)menu).eap$getEncodedPatternSlot(); + RestrictedInputSlot encodedSlot = ((PatternEncodingTermMenuAccessor) menu).eap$getEncodedPatternSlot(); ItemStack stack = encodedSlot.getItem(); - if (stack.isEmpty() || !PatternDetailsHelper.isEncodedPattern(stack)) { - return false; - } + if (stack.isEmpty() || !PatternDetailsHelper.isEncodedPattern(stack)) return; - // 仅允许“合成/锻造台/切石机图样” + // 仅允许“合成/锻造台/切石机样板” IPatternDetails details = PatternDetailsHelper.decodePattern(stack, player.level()); if (!(details instanceof AECraftingPattern || details instanceof AESmithingTablePattern || details instanceof AEStonecuttingPattern)) { - return false; + return; } // 获取 AE 网络 IGridNode node = menu.getNetworkNode(); - if (node == null) { - return false; - } - IGrid grid = node.getGrid(); - if (grid == null) { - return false; - } + if (node == null) return; - // 在尝试上传之前,检查装配矩阵是否已经存在相同样板(物品与NBT完全一致) - if (matrixContainsPattern(grid, stack)) { - // 直接提醒并跳过上传,并将同等数量的空白样板放回空白样板槽,否则退回玩家背包 - if (player != null) { - player.sendSystemMessage(Component.literal("ExtendedAE Plus: 装配矩阵已存在相同样板,已跳过上传并返还空白样板")); - } - try { - var accessor = (PatternEncodingTermMenuAccessor) (Object) menu; - var blankSlot = accessor.eap$getBlankPatternSlot(); - ItemStack blanks = AEItems.BLANK_PATTERN.stack(stack.getCount()); - if (blankSlot != null && blankSlot.mayPlace(blanks)) { - ItemStack remain = blankSlot.safeInsert(blanks); - if (!remain.isEmpty() && player != null) { - player.getInventory().placeItemBackInInventory(remain, false); - } - } else if (player != null) { - player.getInventory().placeItemBackInInventory(blanks, false); - } - } catch (Throwable t) { - if (player != null) { - // 兜底:直接还给玩家背包 - player.getInventory().placeItemBackInInventory(AEItems.BLANK_PATTERN.stack(stack.getCount()), false); - } - } - // 清空编码样板槽,防止再次输出 - encodedSlot.set(ItemStack.EMPTY); - return false; - } + IGrid grid = node.getGrid(); + if (grid == null) return; + + int stackCount = stack.getCount(); + ItemStack toInsert = stack.copy(); // 收集所有可用的装配矩阵(图样模块)内部库存并逐一尝试(遵循其过滤规则) List inventories = findAllMatrixPatternInventories(grid); - if (!inventories.isEmpty()) { - for (int i = 0; i < inventories.size(); i++) { - var inv = inventories.get(i); - ItemStack toInsert = stack.copy(); - ItemStack remain = inv.addItems(toInsert); - if (remain.getCount() < stack.getCount()) { - int inserted = stack.getCount() - remain.getCount(); - stack.shrink(inserted); - if (stack.isEmpty()) { - encodedSlot.set(ItemStack.EMPTY); - } - sendMessage(player, "extendedae_plus.upload_to_matrix.success"); - return true; - } - } - // 所有内部库存都无法接收 -> 尝试 capability 回退 - } - // 回退:尝试 Forge 能力(可能为聚合图样仓),同样遍历所有矩阵 - List handlers = findAllMatrixPatternHandlers(grid); - if (!handlers.isEmpty()) { - for (int i = 0; i < handlers.size(); i++) { - var cap = handlers.get(i); - ItemStack toInsert = stack.copy(); - ItemStack remain = insertIntoAnySlot(cap, toInsert); - if (remain.getCount() < stack.getCount()) { - int inserted = stack.getCount() - remain.getCount(); - stack.shrink(inserted); - if (stack.isEmpty()) { - encodedSlot.set(ItemStack.EMPTY); - } - sendMessage(player, "extendedae_plus.upload_to_matrix.success"); - return true; - } + // 在尝试上传之前,检查装配矩阵是否已经存在相同样板(物品与NBT完全一致) + if (matrixContainsPattern(inventories, stack)) { + // 直接提醒并跳过上传,并将同等数量的空白样板放回空白样板槽,否则退回玩家背包 + sendPlayerMessage(player, Component.translatable("extendedae_plus.upload_to_matrix.repetition")); + refundBlankPattern(player, menu, stackCount); + encodedSlot.set(ItemStack.EMPTY); + return; + } + // 尝试插入 + for (InternalInventory inv : inventories) { + if (inv == null) continue; + ItemStack remain = inv.addItems(toInsert); + if (remain.getCount() < stackCount) { + completeUploadSuccess(player, encodedSlot, stack, remain); + return; } } // 未找到可用矩阵或全部拒收 - if (inventories.isEmpty() && handlers.isEmpty()) { - sendMessage(player, "extendedae_plus.upload_to_matrix.fail_no_matrix"); - } else { - sendMessage(player, "extendedae_plus.upload_to_matrix.fail_full"); - } - return false; + sendPlayerMessage(player, + inventories.isEmpty() + ? Component.translatable("extendedae_plus.upload_to_matrix.fail_no_matrix") + : Component.translatable("extendedae_plus.upload_to_matrix.fail_full")); } /** - * 在给定 AE Grid 中收集所有已成型且在线的装配矩阵“图样模块”的用于外部插入的内部库存。 - * 优先使用 TileAssemblerMatrixPattern#getExposedInventory(仅允许插入,且已带AE过滤规则)。 + * 在给定 AE Grid 中收集所有已成型且在线的装配矩阵“样板核心”的用于外部插入的内部库存 */ private static List findAllMatrixPatternInventories(IGrid grid) { List result = new ArrayList<>(); + if (grid == null) return result; + try { - var tiles = grid.getMachines(TileAssemblerMatrixPattern.class); - for (TileAssemblerMatrixPattern tile : tiles) { - if (tile != null && tile.isFormed() && tile.getMainNode().isActive() && clusterHasSingleUploadCore(tile)) { - var inv = tile.getExposedInventory(); + // 获取网络中所有 Pattern Tile + Set allTiles = grid.getMachines(TileAssemblerMatrixPattern.class); + // 用 Set 记录已经扫描过的集群,避免重复调用 clusterHasSingleUploadCore + Set scannedClusters = new HashSet<>(); + + for (TileAssemblerMatrixPattern tile : allTiles) { + if (tile == null || !tile.isFormed() || !tile.getMainNode().isActive()) continue; + + ClusterAssemblerMatrix cluster = tile.getCluster(); + if (cluster == null) continue; + + // 如果该集群已经扫描过,或者该集群含 UploadCore,则处理 tile + if (scannedClusters.contains(cluster) || clusterHasSingleUploadCore(cluster)) { + scannedClusters.add(cluster); // 标记为已扫描 + + InternalInventory inv = tile.getExposedInventory(); if (inv != null) { result.add(inv); } } } - } catch (Throwable t) { - } + } catch (Throwable ignored) {} return result; } /** - * 在给定 AE Grid 中收集所有已成型的装配矩阵的聚合图样仓 IItemHandler(若可用)。 + * 检查装配矩阵(所有已成型矩阵的样板核心)中是否已存在与给定样板完全相同的物品(含NBT) */ - private static List findAllMatrixPatternHandlers(IGrid grid) { - List result = new ArrayList<>(); - try { - Set matrices = grid.getMachines(TileAssemblerMatrixBase.class); - for (TileAssemblerMatrixBase tile : matrices) { - if (tile != null && tile.isFormed() && clusterHasSingleUploadCore(tile)) { - var capOpt = tile.getCapability(ForgeCapabilities.ITEM_HANDLER, null); - if (capOpt != null) { - var handler = capOpt.orElse(null); - if (handler != null) { - result.add(handler); - } - } + private static boolean matrixContainsPattern(@NotNull List inventories, @NotNull ItemStack pattern) { + for (InternalInventory inv : inventories) { + if (inv == null) continue; + for (int i = 0; i < inv.size(); i++) { + ItemStack s = inv.getStackInSlot(i); + if (!s.isEmpty() && ItemStack.isSameItemSameTags(s, pattern)) { + return true; } } - } catch (Throwable ignored) { - } - return result; - } - - /** - * 检查装配矩阵(所有已成型矩阵的图样仓)中是否已存在与给定样板完全相同的物品(含NBT)。 - */ - private static boolean matrixContainsPattern(IGrid grid, ItemStack pattern) { - if (grid == null || pattern == null || pattern.isEmpty()) return false; - try { - // 先检查提供外部插入视图的内部库存 - List inventories = findAllMatrixPatternInventories(grid); - for (InternalInventory inv : inventories) { - if (inv == null) continue; - for (int i = 0; i < inv.size(); i++) { - ItemStack s = inv.getStackInSlot(i); - if (!s.isEmpty() && ItemStack.isSameItemSameTags(s, pattern)) { - return true; - } - } - } - } catch (Throwable t) { - } - try { - // 再检查聚合能力视图 - List handlers = findAllMatrixPatternHandlers(grid); - for (IItemHandler h : handlers) { - if (h == null) continue; - int slots = h.getSlots(); - for (int i = 0; i < slots; i++) { - ItemStack s = h.getStackInSlot(i); - if (!s.isEmpty() && ItemStack.isSameItemSameTags(s, pattern)) { - return true; - } - } - } - } catch (Throwable t) { } return false; } /** * 判断给定矩阵集群中是否存在“装配矩阵上传核心”。 - * 要求:至少存在 1 个即可,不限制数量。 - * 传入任意属于该集群的 Tile(如 Pattern/Crafter/Frame 等)。 */ - private static boolean clusterHasSingleUploadCore(TileAssemblerMatrixBase any) { + private static boolean clusterHasSingleUploadCore(@NotNull ClusterAssemblerMatrix cluster) { try { - if (any == null || any.getCluster() == null) return false; - int cores = 0; - var it = any.getCluster().getBlockEntities(); + var it = cluster.getBlockEntities(); while (it.hasNext()) { - var te = it.next(); - if (te instanceof UploadCoreBlockEntity) { - cores++; - } + if (it.next() instanceof UploadCoreBlockEntity) return true; } - return cores >= 1; // 至少一个即可 - } catch (Throwable t) { - return false; + } catch (Throwable ignored) {} + return false; + } + + /** + * 上传成功后处理:清空编码槽,发送提示。 + */ + private static void completeUploadSuccess(ServerPlayer player, RestrictedInputSlot encodedSlot, ItemStack stack, ItemStack remain) { + int inserted = stack.getCount() - remain.getCount(); + if (inserted > 0) { + stack.shrink(inserted); + if (stack.isEmpty()) encodedSlot.set(ItemStack.EMPTY); + sendPlayerMessage(player, Component.translatable("extendedae_plus.upload_to_matrix.success")); } } /** - * 尝试将整个物品栈插入到 IItemHandler 的任意槽位,返回剩余物品。 + * 当发现重复样板时返还空白样板。 */ - private static ItemStack insertIntoAnySlot(IItemHandler handler, ItemStack stack) { - ItemStack remaining = stack.copy(); - if (handler == null || remaining.isEmpty()) return remaining; - for (int i = 0; i < handler.getSlots(); i++) { - remaining = handler.insertItem(i, remaining, false); - if (remaining.isEmpty()) break; + private static void refundBlankPattern(ServerPlayer player, PatternEncodingTermMenu menu, int count) { + try { + var accessor = (PatternEncodingTermMenuAccessor) menu; + var blankSlot = accessor.eap$getBlankPatternSlot(); + ItemStack blanks = AEItems.BLANK_PATTERN.stack(count); + if (blankSlot != null && blankSlot.mayPlace(blanks)) { + ItemStack remain = blankSlot.safeInsert(blanks); + if (!remain.isEmpty() && player != null) { + player.getInventory().placeItemBackInInventory(remain, false); + } + } else if (player != null) { + player.getInventory().placeItemBackInInventory(blanks, false); + } + } catch (Throwable t) { + if (player != null) { + player.getInventory().placeItemBackInInventory(AEItems.BLANK_PATTERN.stack(count), false); + } } - return remaining; } } diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 005f39c..66a1135 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -49,6 +49,9 @@ "extendedae_plus.upload_to_matrix.fail_not_crafting": "仅支持上传合成样板,处理样板将被忽略", "extendedae_plus.upload_to_matrix.fail_no_matrix": "未在当前网络中找到已成型的装配矩阵", "extendedae_plus.upload_to_matrix.fail_full": "装配矩阵的样板仓已满或无法插入", + "extendedae_plus.upload_to_matrix.repetition": "装配矩阵已存在相同样板,已跳过上传并返还空白样板", + + "extendedae_plus.screen.reload_mapping": "重载映射", "extendedae_plus.screen.reload_mapping_success": "重载映射成功", "extendedae_plus.screen.reload_mapping_fail": "重载映射失败: %s",