优化修改映射的体验

This commit is contained in:
GaLi 2025-08-20 14:15:48 +08:00
parent 552c53400c
commit 61e73aa81a
3 changed files with 122 additions and 6 deletions

View File

@ -149,6 +149,12 @@ public class ProviderSelectScreen extends Screen {
.build();
this.addRenderableWidget(addMap);
// 删除映射按中文值精确匹配删除按钮
Button delByCn = Button.builder(Component.literal("删除映射"), b -> deleteMappingByCnFromUI())
.bounds(centerX + 240, navY + 30, 60, 20)
.build();
this.addRenderableWidget(delByCn);
// 关闭按钮
Button close = Button.builder(Component.translatable("gui.cancel"), b -> onClose())
.bounds(centerX - 40, navY + 30, 80, 20)
@ -353,4 +359,22 @@ public class ProviderSelectScreen extends Screen {
if (player != null) player.sendSystemMessage(Component.literal("写入映射失败"));
}
}
// 使用中文值精确匹配删除映射
private void deleteMappingByCnFromUI() {
String val = cnInput == null ? "" : cnInput.getValue().trim();
var player = Minecraft.getInstance().player;
if (val.isEmpty()) {
if (player != null) player.sendSystemMessage(Component.literal("请输入中文名称后再删除映射"));
return;
}
int removed = com.extendedae_plus.util.ExtendedAEPatternUploadUtil.removeMappingsByCnValue(val);
if (removed > 0) {
if (player != null) player.sendSystemMessage(Component.literal("已删除 " + removed + " 条映射,中文= " + val));
applyFilter();
needsRefresh = true;
} else {
if (player != null) player.sendSystemMessage(Component.literal("未找到中文为 '" + val + "' 的映射"));
}
}
}

View File

@ -33,17 +33,17 @@ public abstract class EncodePatternTransferHandlerMixin {
// 仅记录处理配方 3x3 合成
if (EncodingHelper.isSupportedCraftingRecipe(recipe)) return;
name = ExtendedAEPatternUploadUtil.mapRecipeTypeToSearchKey(recipe);
} else if (recipeBase instanceof com.gregtechceu.gtceu.api.recipe.GTRecipe gtRecipe) {
// GTCEu 专用 GTRecipeType 提取注册ID并映射为中文或path
name = ExtendedAEPatternUploadUtil.mapGTCEuRecipeToSearchKey(gtRecipe);
} else if (recipeBase != null &&
"com.gregtechceu.gtceu.api.recipe.GTRecipe".equals(recipeBase.getClass().getName())) {
// 反射路径GTCEu 专用 GTRecipeType 提取注册ID并映射为中文或path
name = ExtendedAEPatternUploadUtil.mapGTCEuRecipeToSearchKey(recipeBase);
} else if ("com.gregtechceu.gtceu.integration.jei.recipe.GTRecipeWrapper".equals(recipeBase.getClass().getName())) {
// 通过反射处理 GTCEu JEI 包装类避免硬依赖
try {
var field = recipeBase.getClass().getField("recipe"); // public final GTRecipe recipe;
Object inner = field.get(recipeBase);
if (inner instanceof com.gregtechceu.gtceu.api.recipe.GTRecipe gtRecipeInner) {
name = ExtendedAEPatternUploadUtil.mapGTCEuRecipeToSearchKey(gtRecipeInner);
}
// 反射路径将内部 GTRecipe Object 传入
name = ExtendedAEPatternUploadUtil.mapGTCEuRecipeToSearchKey(inner);
} catch (Throwable ignored) {
// 反射失败则继续走通用回退
}

View File

@ -179,6 +179,69 @@ public class ExtendedAEPatternUploadUtil {
}
}
/**
* 按中文值精确匹配删除映射支持别名与完整ID
* 返回删除的条目数量
*/
public static synchronized int removeMappingsByCnValue(String cnValue) {
if (cnValue == null) return 0;
String target = cnValue.trim();
if (target.isEmpty()) return 0;
try {
Path cfgDir = FMLPaths.CONFIGDIR.get();
Path cfgPath = cfgDir.resolve(CONFIG_RELATIVE);
if (!Files.exists(cfgPath)) {
return 0;
}
String json = Files.readString(cfgPath);
JsonObject obj = GSON.fromJson(json, JsonObject.class);
if (obj == null) return 0;
java.util.List<String> toRemove = new java.util.ArrayList<>();
for (java.util.Map.Entry<String, JsonElement> e : obj.entrySet()) {
JsonElement v = e.getValue();
if (v != null && v.isJsonPrimitive()) {
String name = v.getAsString();
if (target.equals(name)) {
toRemove.add(e.getKey());
}
}
}
if (toRemove.isEmpty()) return 0;
// JSON 中移除
for (String k : toRemove) {
obj.remove(k);
}
Files.createDirectories(cfgPath.getParent());
Files.writeString(cfgPath, GSON.toJson(obj));
// 同步移除内存映射
for (String k : toRemove) {
if (k.contains(":")) {
try {
ResourceLocation rl = new ResourceLocation(k);
// 仅当值匹配才移除双重保险
String cur = CUSTOM_NAMES.get(rl);
if (target.equals(cur)) {
CUSTOM_NAMES.remove(rl);
}
} catch (Exception ignored) {}
} else {
// 别名按小写存放
String lower = k.toLowerCase();
String cur = CUSTOM_ALIASES.get(lower);
if (target.equals(cur)) {
CUSTOM_ALIASES.remove(lower);
}
}
}
return toRemove.size();
} catch (IOException e) {
return 0;
}
}
public static String mapRecipeTypeToCn(Recipe<?> recipe) {
if (recipe == null) return null;
RecipeType<?> type = recipe.getType();
@ -255,6 +318,35 @@ public class ExtendedAEPatternUploadUtil {
}
}
/**
* 仅使用反射的 GTCEu GTRecipe -> 搜索关键字避免在运行时直接引用 GTCEu
* 逻辑与 {@link #mapGTCEuRecipeToSearchKey(com.gregtechceu.gtceu.api.recipe.GTRecipe)} 等价
*/
public static String mapGTCEuRecipeToSearchKey(Object gtRecipeObj) {
if (gtRecipeObj == null) return null;
try {
// 通过反射调用 getType() toString() 应返回 registryName namespace:path
java.lang.reflect.Method mGetType = gtRecipeObj.getClass().getMethod("getType");
Object typeObj = mGetType.invoke(gtRecipeObj);
String idStr = String.valueOf(typeObj);
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;
}
}
/**
* JEI 传入的 recipeBase 不是原版 Recipe<?> 根据类的包名/类名推导一个尽量可用的搜索关键字
* 例如"moe.gregtech.recipe.SomeAssemblerRecipe" -> "gtceu assembler"