diff --git a/src/main/java/com/extendedae_plus/client/screen/ProviderSelectScreen.java b/src/main/java/com/extendedae_plus/client/screen/ProviderSelectScreen.java index 4b4b141..682a398 100644 --- a/src/main/java/com/extendedae_plus/client/screen/ProviderSelectScreen.java +++ b/src/main/java/com/extendedae_plus/client/screen/ProviderSelectScreen.java @@ -13,6 +13,8 @@ import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.extendedae_plus.util.GlobalSendMessage.sendPlayerMessage; + /** * 简单的供应器选择弹窗。 * 展示若干个可点击的供应器条目,点击后发送带 providerId 的上传请求。 @@ -211,16 +213,10 @@ public class ProviderSelectScreen extends Screen { private void reloadMapping() { try { ExtendedAEPatternUploadUtil.loadRecipeTypeNames(); - var player = Minecraft.getInstance().player; - if (player != null) { - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.reload_mapping_success")); - } + sendPlayerMessage(Component.translatable("extendedae_plus.screen.reload_mapping_success")); // 重载后不强制刷新筛选,但如需立即应用到名称匹配,可手动编辑搜索框或翻页 } catch (Throwable t) { - var player = Minecraft.getInstance().player; - if (player != null) { - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.reload_mapping_fail", t.getClass().getSimpleName())); - } + sendPlayerMessage(Component.translatable("extendedae_plus.screen.reload_mapping_fail", t.getClass().getSimpleName())); } } @@ -467,22 +463,19 @@ public class ProviderSelectScreen extends Screen { private void addMappingFromUI() { String key = query == null ? "" : query.trim(); String val = cnInput == null ? "" : cnInput.getValue().trim(); - var player = Minecraft.getInstance().player; + if (key.isEmpty()) { - if (player != null) - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.enter_search_key")); + sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.enter_search_key")); return; } if (val.isEmpty()) { - if (player != null) - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.enter_cn_name")); + sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.enter_cn_name")); return; } + boolean ok = ExtendedAEPatternUploadUtil.addOrUpdateAliasMapping(key, val); if (ok) { - if (player != null) - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.mapping_added", - key, val)); + sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.mapping_added", key, val)); // 将刚添加的中文名写入搜索框,作为当前查询 this.query = val; if (this.searchBox != null) { @@ -493,30 +486,25 @@ public class ProviderSelectScreen extends Screen { page = 0; refreshButtons(); } else { - if (player != null) - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.mapping_failed")); + sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.mapping_failed")); } } // 使用中文值精确匹配删除映射 private void deleteMappingByCnFromUI() { String val = cnInput == null ? "" : cnInput.getValue().trim(); - var player = Minecraft.getInstance().player; if (val.isEmpty()) { - if (player != null) - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.enter_cn_name_delete")); + sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.enter_cn_name_delete")); return; } int removed = ExtendedAEPatternUploadUtil.removeMappingsByCnValue(val); if (removed > 0) { - if (player != null) - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.mapping_deleted", removed, val)); + sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.mapping_deleted", removed, val)); applyFilter(); page = 0; refreshButtons(); } else { - if (player != null) - player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.mapping_not_found", val)); + sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.mapping_not_found", val)); } } diff --git a/src/main/java/com/extendedae_plus/util/ExtendedAEPatternUploadUtil.java b/src/main/java/com/extendedae_plus/util/ExtendedAEPatternUploadUtil.java index 6715411..af71ee9 100644 --- a/src/main/java/com/extendedae_plus/util/ExtendedAEPatternUploadUtil.java +++ b/src/main/java/com/extendedae_plus/util/ExtendedAEPatternUploadUtil.java @@ -16,10 +16,7 @@ import appeng.util.inv.FilteredInternalInventory; import appeng.util.inv.filter.IAEItemFilter; import com.extendedae_plus.mixin.ae2.accessor.PatternEncodingTermMenuAccessor; import com.glodblock.github.extendedae.common.tileentities.matrix.TileAssemblerMatrixBase; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.google.gson.*; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; @@ -38,6 +35,8 @@ import java.nio.file.Path; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import static com.extendedae_plus.util.GlobalSendMessage.sendPlayerMessage; + /** * ExtendedAE扩展样板管理终端专用的样板上传工具类 * 兼容ExtendedAE的ContainerExPatternTerminal和原版AE2的PatternAccessTermMenu @@ -170,9 +169,12 @@ public class ExtendedAEPatternUploadUtil { CUSTOM_ALIASES.put(key.toLowerCase(), cnValue); } return true; + } catch (JsonSyntaxException e) { + sendPlayerMessage(Component.literal("ExtendedAE_Plus: 配置文件解析失败, " + e.getMessage())); } catch (IOException e) { return false; } + return false; } /** @@ -233,37 +235,12 @@ public class ExtendedAEPatternUploadUtil { } } return toRemove.size(); + } catch (JsonSyntaxException e) { + sendPlayerMessage(Component.literal("ExtendedAE_Plus: 配置文件解析失败, " + e.getMessage())); } catch (IOException e) { return 0; } - } - - public static String mapRecipeTypeToCn(Recipe recipe) { - if (recipe == null) return null; - RecipeType type = recipe.getType(); - ResourceLocation key = BuiltInRegistries.RECIPE_TYPE.getKey(type); - if (key == null) return null; - // 1) 自定义配置优先 - String custom = CUSTOM_NAMES.get(key); - if (custom != null && !custom.isBlank()) { - return custom; - } - String id = key.toString(); - String path = key.getPath(); - // 常见原版类型映射 - switch (path) { - case "smelting": - return "熔炉"; // 熔炉 - case "blasting": - return "高炉"; - case "smoking": - return "烟熏"; - case "campfire_cooking": - return "营火"; - default: - // 其他模组类型,若未配置中文则返回原始ID(namespace:path)作为英文回退 - return id; - } + return 0; } /** @@ -287,36 +264,8 @@ public class ExtendedAEPatternUploadUtil { return key.getPath(); } - /** - * GTCEu 的 GTRecipe -> 搜索关键字 - * 优先自定义中文映射;其次使用注册ID的 path;最后回退到完整ID字符串。 - */ - public static String mapGTCEuRecipeToSearchKey(com.gregtechceu.gtceu.api.recipe.GTRecipe gtRecipe) { - if (gtRecipe == null) return null; - try { - // GTRecipeType.toString() 返回 registryName.toString() 即 namespace:path - String idStr = String.valueOf(gtRecipe.getType()); - if (idStr == null || idStr.isBlank()) return null; - ResourceLocation rl = new ResourceLocation(idStr); - // 1) 先查别名(使用 path 作为最终搜索关键字) - String path = rl.getPath(); - if (path != null) { - String alias = CUSTOM_ALIASES.get(path.toLowerCase()); - if (alias != null && !alias.isBlank()) return alias; - } - // 2) 再查完整ID映射 - String custom = CUSTOM_NAMES.get(rl); - if (custom != null && !custom.isBlank()) return custom; - // 3) 默认返回 path 作为搜索关键字 - return (path != null && !path.isBlank()) ? path : idStr; - } catch (Throwable t) { - return null; - } - } - /** * 仅使用反射的 GTCEu GTRecipe -> 搜索关键字(避免在运行时直接引用 GTCEu 类)。 - * 逻辑与 {@link #mapGTCEuRecipeToSearchKey(com.gregtechceu.gtceu.api.recipe.GTRecipe)} 等价。 */ public static String mapGTCEuRecipeToSearchKey(Object gtRecipeObj) { if (gtRecipeObj == null) return null; @@ -738,60 +687,6 @@ public class ExtendedAEPatternUploadUtil { } } - /** - * 批量上传样板到指定供应器(支持ExtendedAE和原版AE2) - * - * @param player 玩家 - * @param playerSlotIndices 玩家背包槽位索引数组 - * @param providerId 目标样板供应器ID - * @return 成功上传的样板数量 - */ - public static int uploadMultiplePatterns(ServerPlayer player, int[] playerSlotIndices, long providerId) { - int successCount = 0; - - for (int slotIndex : playerSlotIndices) { - if (uploadPatternToProvider(player, slotIndex, providerId)) { - successCount++; - } - } - - String terminalType = isExtendedAETerminal(player) ? "扩展样板管理终端" : "样板访问终端"; - sendMessage(player, "ExtendedAE Plus: 通过" + terminalType + "批量上传完成,成功上传 " + successCount + " 个样板"); - return successCount; - } - - /** - * 检查样板供应器是否有足够的空槽位 - * - * @param providerId 供应器ID - * @param menu 样板访问终端菜单(支持ExtendedAE) - * @param requiredSlots 需要的槽位数 - * @return 是否有足够的空槽位 - */ - public static boolean hasEnoughSlots(long providerId, PatternAccessTermMenu menu, int requiredSlots) { - PatternContainer container = getPatternContainerById(menu, providerId); - if (container == null) { - return false; - } - - InternalInventory inventory = container.getTerminalPatternInventory(); - if (inventory == null) { - return false; - } - - int availableSlots = 0; - for (int i = 0; i < inventory.size(); i++) { - if (inventory.getStackInSlot(i).isEmpty()) { - availableSlots++; - if (availableSlots >= requiredSlots) { - return true; - } - } - } - - return false; - } - /** * 获取样板供应器中的空槽位数量 * @@ -974,101 +869,6 @@ public class ExtendedAEPatternUploadUtil { return container.getGrid() != null; } - /** - * 获取当前终端类型的描述 - * - * @param player 玩家 - * @return 终端类型描述 - */ - public static String getTerminalTypeDescription(ServerPlayer player) { - if (isExtendedAETerminal(player)) { - return "ExtendedAE扩展样板管理终端"; - } else if (getPatternAccessMenu(player) != null) { - return "AE2样板访问终端"; - } else { - return "未知终端类型"; - } - } - - /** - * 从 AE2 的图样编码终端菜单上传当前“已编码图样”至当前网络中任意可用的样板供应器。 - * 策略: - * 1) 仅当 encoded 槽位存在有效编码样板时执行; - * 2) 通过 menu.getNetworkNode() 获取 IGrid,遍历在线的 PatternContainer; - * 3) 仅选择在终端中可见(isVisibleInTerminal)且库存存在空位的供应器; - * 4) 使用 AE2 的标准 FilteredInternalInventory + Pattern 过滤器尝试插入; - * 5) 成功后清空 encoded 槽位,返回 true;否则返回 false。 - */ - public static boolean uploadFromEncodingMenuToAnyProvider(ServerPlayer player, PatternEncodingTermMenu menu) { - if (player == null || menu == null) { - return false; - } - // 读取已编码槽位的物品(通过 accessor) - var encodedSlot = ((PatternEncodingTermMenuAccessor) (Object) menu) - .eap$getEncodedPatternSlot(); - ItemStack stack = encodedSlot.getItem(); - if (stack.isEmpty() || !PatternDetailsHelper.isEncodedPattern(stack)) { - return false; - } - - // 获取 AE 网络 - IGridNode node = menu.getNetworkNode(); - if (node == null) { - return false; - } - IGrid grid = node.getGrid(); - if (grid == null) { - return false; - } - - // 遍历在线的 PatternContainer,寻找第一个可见且有空位的供应器 - try { - for (var machineClass : grid.getMachineClasses()) { - if (PatternContainer.class.isAssignableFrom(machineClass)) { - @SuppressWarnings("unchecked") - Class containerClass = (Class) machineClass; - for (var container : grid.getActiveMachines(containerClass)) { - if (container == null || !container.isVisibleInTerminal()) { - continue; - } - InternalInventory inv = container.getTerminalPatternInventory(); - if (inv == null || inv.size() <= 0) { - continue; - } - boolean hasEmpty = false; - for (int i = 0; i < inv.size(); i++) { - if (inv.getStackInSlot(i).isEmpty()) { - hasEmpty = true; - break; - } - } - if (!hasEmpty) { - continue; - } - - // 按 AE2 样板过滤规则尝试插入 - var filtered = new FilteredInternalInventory(inv, new ExtendedAEPatternFilter()); - ItemStack toInsert = stack.copy(); - ItemStack remain = filtered.addItems(toInsert); - if (remain.getCount() < toInsert.getCount()) { - int inserted = toInsert.getCount() - remain.getCount(); - stack.shrink(inserted); - if (stack.isEmpty()) { - encodedSlot.set(ItemStack.EMPTY); - } else { - encodedSlot.set(stack); - } - return true; - } - } - } - } - } catch (Throwable t) { - // 忽略异常以避免噪声 - } - return false; - } - /** * 将图样编码终端的“已编码图样”上传到指定的样板供应器(通过 providerId 定位)。 */ diff --git a/src/main/java/com/extendedae_plus/util/GlobalSendMessage.java b/src/main/java/com/extendedae_plus/util/GlobalSendMessage.java new file mode 100644 index 0000000..5bf08f1 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/GlobalSendMessage.java @@ -0,0 +1,16 @@ +package com.extendedae_plus.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; + +public class GlobalSendMessage { + /** + * 简化发送玩家消息的辅助方法 + */ + public static void sendPlayerMessage(Component msg) { + var player = Minecraft.getInstance().player; + if (player != null) { + player.sendSystemMessage(msg); + } + } +}