捕获json解析异常避免造成游戏崩溃
This commit is contained in:
parent
7c67b839bb
commit
c42f429b0a
|
|
@ -13,6 +13,8 @@ import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static com.extendedae_plus.util.GlobalSendMessage.sendPlayerMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 简单的供应器选择弹窗。
|
* 简单的供应器选择弹窗。
|
||||||
* 展示若干个可点击的供应器条目,点击后发送带 providerId 的上传请求。
|
* 展示若干个可点击的供应器条目,点击后发送带 providerId 的上传请求。
|
||||||
|
|
@ -211,16 +213,10 @@ public class ProviderSelectScreen extends Screen {
|
||||||
private void reloadMapping() {
|
private void reloadMapping() {
|
||||||
try {
|
try {
|
||||||
ExtendedAEPatternUploadUtil.loadRecipeTypeNames();
|
ExtendedAEPatternUploadUtil.loadRecipeTypeNames();
|
||||||
var player = Minecraft.getInstance().player;
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.reload_mapping_success"));
|
||||||
if (player != null) {
|
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.reload_mapping_success"));
|
|
||||||
}
|
|
||||||
// 重载后不强制刷新筛选,但如需立即应用到名称匹配,可手动编辑搜索框或翻页
|
// 重载后不强制刷新筛选,但如需立即应用到名称匹配,可手动编辑搜索框或翻页
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
var player = Minecraft.getInstance().player;
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.reload_mapping_fail", t.getClass().getSimpleName()));
|
||||||
if (player != null) {
|
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.reload_mapping_fail", t.getClass().getSimpleName()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -467,22 +463,19 @@ public class ProviderSelectScreen extends Screen {
|
||||||
private void addMappingFromUI() {
|
private void addMappingFromUI() {
|
||||||
String key = query == null ? "" : query.trim();
|
String key = query == null ? "" : query.trim();
|
||||||
String val = cnInput == null ? "" : cnInput.getValue().trim();
|
String val = cnInput == null ? "" : cnInput.getValue().trim();
|
||||||
var player = Minecraft.getInstance().player;
|
|
||||||
if (key.isEmpty()) {
|
if (key.isEmpty()) {
|
||||||
if (player != null)
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.enter_search_key"));
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.enter_search_key"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (val.isEmpty()) {
|
if (val.isEmpty()) {
|
||||||
if (player != null)
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.enter_cn_name"));
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.enter_cn_name"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean ok = ExtendedAEPatternUploadUtil.addOrUpdateAliasMapping(key, val);
|
boolean ok = ExtendedAEPatternUploadUtil.addOrUpdateAliasMapping(key, val);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
if (player != null)
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.mapping_added", key, val));
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.mapping_added",
|
|
||||||
key, val));
|
|
||||||
// 将刚添加的中文名写入搜索框,作为当前查询
|
// 将刚添加的中文名写入搜索框,作为当前查询
|
||||||
this.query = val;
|
this.query = val;
|
||||||
if (this.searchBox != null) {
|
if (this.searchBox != null) {
|
||||||
|
|
@ -493,30 +486,25 @@ public class ProviderSelectScreen extends Screen {
|
||||||
page = 0;
|
page = 0;
|
||||||
refreshButtons();
|
refreshButtons();
|
||||||
} else {
|
} else {
|
||||||
if (player != null)
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.mapping_failed"));
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.mapping_failed"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用中文值精确匹配删除映射
|
// 使用中文值精确匹配删除映射
|
||||||
private void deleteMappingByCnFromUI() {
|
private void deleteMappingByCnFromUI() {
|
||||||
String val = cnInput == null ? "" : cnInput.getValue().trim();
|
String val = cnInput == null ? "" : cnInput.getValue().trim();
|
||||||
var player = Minecraft.getInstance().player;
|
|
||||||
if (val.isEmpty()) {
|
if (val.isEmpty()) {
|
||||||
if (player != null)
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.enter_cn_name_delete"));
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.enter_cn_name_delete"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int removed = ExtendedAEPatternUploadUtil.removeMappingsByCnValue(val);
|
int removed = ExtendedAEPatternUploadUtil.removeMappingsByCnValue(val);
|
||||||
if (removed > 0) {
|
if (removed > 0) {
|
||||||
if (player != null)
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.mapping_deleted", removed, val));
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.mapping_deleted", removed, val));
|
|
||||||
applyFilter();
|
applyFilter();
|
||||||
page = 0;
|
page = 0;
|
||||||
refreshButtons();
|
refreshButtons();
|
||||||
} else {
|
} else {
|
||||||
if (player != null)
|
sendPlayerMessage(Component.translatable("extendedae_plus.screen.upload.mapping_not_found", val));
|
||||||
player.sendSystemMessage(Component.translatable("extendedae_plus.screen.upload.mapping_not_found", val));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,7 @@ import appeng.util.inv.FilteredInternalInventory;
|
||||||
import appeng.util.inv.filter.IAEItemFilter;
|
import appeng.util.inv.filter.IAEItemFilter;
|
||||||
import com.extendedae_plus.mixin.ae2.accessor.PatternEncodingTermMenuAccessor;
|
import com.extendedae_plus.mixin.ae2.accessor.PatternEncodingTermMenuAccessor;
|
||||||
import com.glodblock.github.extendedae.common.tileentities.matrix.TileAssemblerMatrixBase;
|
import com.glodblock.github.extendedae.common.tileentities.matrix.TileAssemblerMatrixBase;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.*;
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
@ -38,6 +35,8 @@ import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import static com.extendedae_plus.util.GlobalSendMessage.sendPlayerMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExtendedAE扩展样板管理终端专用的样板上传工具类
|
* ExtendedAE扩展样板管理终端专用的样板上传工具类
|
||||||
* 兼容ExtendedAE的ContainerExPatternTerminal和原版AE2的PatternAccessTermMenu
|
* 兼容ExtendedAE的ContainerExPatternTerminal和原版AE2的PatternAccessTermMenu
|
||||||
|
|
@ -170,9 +169,12 @@ public class ExtendedAEPatternUploadUtil {
|
||||||
CUSTOM_ALIASES.put(key.toLowerCase(), cnValue);
|
CUSTOM_ALIASES.put(key.toLowerCase(), cnValue);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
sendPlayerMessage(Component.literal("ExtendedAE_Plus: 配置文件解析失败, " + e.getMessage()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -233,37 +235,12 @@ public class ExtendedAEPatternUploadUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return toRemove.size();
|
return toRemove.size();
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
sendPlayerMessage(Component.literal("ExtendedAE_Plus: 配置文件解析失败, " + e.getMessage()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -287,36 +264,8 @@ public class ExtendedAEPatternUploadUtil {
|
||||||
return key.getPath();
|
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 类)。
|
* 仅使用反射的 GTCEu GTRecipe -> 搜索关键字(避免在运行时直接引用 GTCEu 类)。
|
||||||
* 逻辑与 {@link #mapGTCEuRecipeToSearchKey(com.gregtechceu.gtceu.api.recipe.GTRecipe)} 等价。
|
|
||||||
*/
|
*/
|
||||||
public static String mapGTCEuRecipeToSearchKey(Object gtRecipeObj) {
|
public static String mapGTCEuRecipeToSearchKey(Object gtRecipeObj) {
|
||||||
if (gtRecipeObj == null) return null;
|
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;
|
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<? extends PatternContainer> containerClass = (Class<? extends PatternContainer>) 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 定位)。
|
* 将图样编码终端的“已编码图样”上传到指定的样板供应器(通过 providerId 定位)。
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user