This commit is contained in:
C-H716 2025-10-27 12:05:21 +08:00
parent 07ef2e6461
commit ac308242e2
2 changed files with 113 additions and 176 deletions

View File

@ -6,6 +6,7 @@ import appeng.api.networking.security.IActionHost;
import appeng.api.stacks.AEKey;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.me.service.CraftingService;
import appeng.menu.AEBaseMenu;
import appeng.menu.locator.MenuLocators;
import appeng.menu.me.crafting.CraftingCPUMenu;
import appeng.parts.AEBasePart;
@ -85,7 +86,7 @@ public class CraftingMonitorOpenProviderC2SPacket {
/**
* GridHelper: 从菜单中获取网格实例
*/
public static final class GridHelper {
private static final class GridHelper {
private GridHelper() {}
/**
@ -93,7 +94,7 @@ public class CraftingMonitorOpenProviderC2SPacket {
* @param menu 当前 AEBaseMenu
* @return Grid null
*/
public static IGrid getGridFromMenu(appeng.menu.AEBaseMenu menu) {
private static IGrid getGridFromMenu(AEBaseMenu menu) {
Object target = menu.getTarget();
if (target instanceof IActionHost host && host.getActionableNode() != null) {
return host.getActionableNode().getGrid();
@ -105,7 +106,7 @@ public class CraftingMonitorOpenProviderC2SPacket {
/**
* PatternLocator: 根据样板定位可用的 Provider
*/
public static final class PatternLocator {
private static final class PatternLocator {
private PatternLocator() {}
/**
@ -115,7 +116,7 @@ public class CraftingMonitorOpenProviderC2SPacket {
* @param grid 当前 Grid
* @return 第一个可用的 PatternProviderLogic null
*/
public static PatternProviderLogic findValidProvider(CraftingService cs, IPatternDetails pattern, IGrid grid) {
private static PatternProviderLogic findValidProvider(CraftingService cs, IPatternDetails pattern, IGrid grid) {
var providers = cs.getProviders(pattern);
for (var provider : providers) {
if (provider instanceof PatternProviderLogic ppl) {
@ -132,7 +133,7 @@ public class CraftingMonitorOpenProviderC2SPacket {
/**
* ProviderUIHelper: 打开 Provider UI 并发送客户端反馈
*/
public static final class ProviderUIHelper {
private static final class ProviderUIHelper {
private ProviderUIHelper() {}
/**
@ -146,7 +147,7 @@ public class CraftingMonitorOpenProviderC2SPacket {
* @param pattern 样板
* @param player 玩家
*/
public static void openProviderUI(PatternProviderLogic provider, IPatternDetails pattern, ServerPlayer player) {
private static void openProviderUI(PatternProviderLogic provider, IPatternDetails pattern, ServerPlayer player) {
var host = ((PatternProviderLogicAccessor) provider).eap$host();
var pbe = host.getBlockEntity();
if (pbe == null) return;

View File

@ -4,6 +4,7 @@ import appeng.api.crafting.IPatternDetails;
import appeng.api.crafting.PatternDetailsHelper;
import appeng.api.inventories.InternalInventory;
import appeng.api.networking.IGrid;
import appeng.api.networking.IManagedGridNode;
import appeng.helpers.patternprovider.PatternContainer;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.menu.implementations.PatternAccessTermMenu;
@ -12,210 +13,111 @@ import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
/**
* 样板供应器数据工具类
* 用于获取样板供应器中的所有样板数据包括输入输出物品的数量信息
*/
public class PatternProviderDataUtil {
private static final int INVALID_SLOT = -1;
private static final String UNKNOWN_PROVIDER = "未知供应器";
/**
* 判断 provider 是否可用并属于指定网格在线且有频道/处于活跃状态
*/
public static boolean isProviderAvailable(PatternProviderLogic provider, IGrid expectedGrid) {
if (provider == null || expectedGrid == null) return false;
public static boolean isProviderAvailable(@NotNull PatternProviderLogic provider, @NotNull IGrid expectedGrid) {
try {
var grid = provider.getGrid();
IGrid grid = provider.getGrid();
if (grid == null || !grid.equals(expectedGrid)) return false;
// 使用 accessor 获取 mainNode再调用 isActive
if (provider instanceof PatternProviderLogicAccessor accessor) {
var mainNode = accessor.eap$mainNode();
if (mainNode == null) return false;
try {
var isActiveMethod = mainNode.getClass().getMethod("isActive");
Object active = isActiveMethod.invoke(mainNode);
if (active instanceof Boolean && !((Boolean) active)) return false;
} catch (NoSuchMethodException nsme) {
// 没有 isActive 方法时退回到检查 channels
try {
var getChannels = mainNode.getClass().getMethod("getChannels");
Object channels = getChannels.invoke(mainNode);
if (channels instanceof java.util.Collection) {
if (((java.util.Collection<?>) channels).isEmpty()) return false;
}
} catch (Exception ignored) {
// 无法判断 channels 认为不可用
return false;
}
}
} else {
// 没有 accessor 的情况尽量通过反射判断 mainNode.channels
try {
var mainNodeField = provider.getClass().getDeclaredField("mainNode");
mainNodeField.setAccessible(true);
var mainNode = mainNodeField.get(provider);
if (mainNode == null) return false;
var getChannelsMethod = mainNode.getClass().getMethod("getChannels");
Object channels = getChannelsMethod.invoke(mainNode);
if (channels instanceof java.util.Collection) {
return !((java.util.Collection<?>) channels).isEmpty();
}
} catch (Exception e) {
return false;
}
}
return true;
} catch (Exception e) {
return false;
}
}
/**
* 查找 provider 中匹配给定定义的样板槽位轻量按需解码并早退出
* @param patternProvider 要搜索的 provider
* @param targetDefinition pattern.getDefinition() 返回的对象用于 equals 比较
* @return 找到的槽位索引未找到返回 -1
*/
public static int findSlotForPattern(PatternProviderLogic patternProvider, Object targetDefinition) {
if (patternProvider == null || targetDefinition == null) return -1;
InternalInventory inv = patternProvider.getPatternInv();
if (inv == null) return -1;
Level level = getPatternProviderLevel(patternProvider);
if (level == null) return -1;
for (int i = 0; i < inv.size(); i++) {
ItemStack s = inv.getStackInSlot(i);
if (s.isEmpty()) continue;
try {
IPatternDetails d = PatternDetailsHelper.decodePattern(s, level);
if (d != null && d.getDefinition().equals(targetDefinition)) {
return i;
}
} catch (Exception ignored) {}
}
return -1;
}
/**
* ExtendedAE风格安全获取样板供应器的Level对象
*/
private static Level getPatternProviderLevel(PatternProviderLogic patternProvider) {
if (patternProvider == null) return null;
try {
if (patternProvider instanceof PatternProviderLogicAccessor accessor) {
var host = accessor.eap$host();
if (host != null) {
BlockEntity be = host.getBlockEntity();
if (be != null) {
return be.getLevel();
}
}
IManagedGridNode mainNode = accessor.eap$mainNode();
return mainNode != null && mainNode.isActive();
}
} catch (Exception ignored) {
}
return null;
}
/**
* 获取样板供应器中的空槽位数量
*
* @param providerId 供应器ID
* @param menu 样板访问终端菜单支持ExtendedAE
* @return 空槽位数量如果无法访问则返回-1
*/
public static int getAvailableSlots(long providerId, PatternAccessTermMenu menu) {
PatternContainer container = PatternTerminalUtil.getPatternContainerById(menu, providerId);
if (container == null) {
return -1;
}
InternalInventory inventory = container.getTerminalPatternInventory();
if (inventory == null) {
return -1;
}
int availableSlots = 0;
for (int i = 0; i < inventory.size(); i++) {
if (inventory.getStackInSlot(i).isEmpty()) {
availableSlots++;
}
}
return availableSlots;
}
/**
* 获取样板供应器的显示名称
*
* @param providerId 供应器ID
* @param menu 样板访问终端菜单
* @return 显示名称如果无法获取则返回"未知供应器"
*/
public static String getProviderDisplayName(long providerId, PatternAccessTermMenu menu) {
PatternContainer container = PatternTerminalUtil.getPatternContainerById(menu, providerId);
if (container == null) {
return "未知供应器";
}
try {
// 尝试获取供应器的组信息来构建显示名称
var group = container.getTerminalGroup();
if (group != null) {
// 使用 Component 序列化来保持翻译键而不是直接 getString()
// 这样客户端可以根据自己的语言设置进行翻译
return Component.Serializer.toJson(group.name());
}
} catch (Exception e) {
// 忽略异常使用默认名称
}
return "样板供应器 #" + providerId;
return false;
}
/**
* 验证样板供应器是否可用
*
* @param providerId 供应器ID
* @param menu 样板访问终端菜单
* @param menu 样板访问终端菜单
* @return 是否可用
*/
public static boolean isProviderAvailable(long providerId, PatternAccessTermMenu menu) {
PatternContainer container = PatternTerminalUtil.getPatternContainerById(menu, providerId);
if (container == null) {
return false;
}
// 检查是否在终端中可见
if (!container.isVisibleInTerminal()) {
return false;
}
// 检查是否连接到网络
if (container == null) return false;
if (!container.isVisibleInTerminal()) return false;
return container.getGrid() != null;
}
/** 获取供应器显示名(优先组名) */
public static String getProviderDisplayName(PatternContainer container) {
if (container == null) return "未知供应器";
try {
var group = container.getTerminalGroup();
if (group != null) {
// 使用 Component 序列化来保持翻译键而不是直接 getString()
// 这样客户端可以根据自己的语言设置进行翻译
return Component.Serializer.toJson(group.name());
/**
* 查找 provider 中匹配给定定义的样板槽位轻量按需解码并早退出
*
* @param provider 要搜索的 provider
* @param targetDefinition pattern.getDefinition() 返回的对象用于 equals 比较
* @return 找到的槽位索引未找到返回 -1
*/
public static int findSlotForPattern(@Nullable PatternProviderLogic provider, @Nullable Object targetDefinition) {
if (provider == null || targetDefinition == null) return INVALID_SLOT;
InternalInventory inv = provider.getPatternInv();
if (inv == null || inv.isEmpty()) return INVALID_SLOT;
Level level = getPatternProviderLevel(provider);
if (level == null) return INVALID_SLOT;
for (int i = 0; i < inv.size(); i++) {
ItemStack stack = inv.getStackInSlot(i);
if (stack.isEmpty() || !stack.hasTag()) continue; // 快速跳过无Nbt样板
try {
IPatternDetails details = PatternDetailsHelper.decodePattern(stack, level);
if (details != null && targetDefinition.equals(details.getDefinition())) {
return i;
}
} catch (Exception ignored) {
}
} catch (Throwable ignored) {
}
return "样板供应器";
return INVALID_SLOT;
}
/** 计算供应器空槽位数量 */
public static int getAvailableSlots(PatternContainer container) {
if (container == null) return -1;
/**
* 获取样板供应器的 Level 对象
*/
@Nullable
private static Level getPatternProviderLevel(@Nullable PatternProviderLogic provider) {
if (!(provider instanceof PatternProviderLogicAccessor accessor)) return null;
var host = accessor.eap$host();
if (host == null) return null;
BlockEntity be = host.getBlockEntity();
return be != null ? be.getLevel() : null;
}
/**
* 获取样板供应器中的空槽位数量
*
* @param providerId 供应器ID
* @param menu 样板访问终端菜单支持ExtendedAE
* @return 空槽位数量如果无法访问则返回-1
*/
public static int getAvailableSlots(long providerId, PatternAccessTermMenu menu) {
PatternContainer container = PatternTerminalUtil.getPatternContainerById(menu, providerId);
return getAvailableSlots(container);
}
/**
* 计算供应器空槽位数量
*/
public static int getAvailableSlots(@Nullable PatternContainer container) {
if (container == null) return INVALID_SLOT;
InternalInventory inv = container.getTerminalPatternInventory();
if (inv == null) return -1;
if (inv == null) return INVALID_SLOT;
int available = 0;
for (int i = 0; i < inv.size(); i++) {
if (inv.getStackInSlot(i).isEmpty()) available++;
@ -223,5 +125,39 @@ public class PatternProviderDataUtil {
return available;
}
/**
* 获取样板供应器的显示名称
*
* @param providerId 供应器ID
* @param menu 样板访问终端菜单
* @return 显示名称如果无法获取则返回"未知供应器"
*/
public static String getProviderDisplayName(long providerId, PatternAccessTermMenu menu) {
PatternContainer container = PatternTerminalUtil.getPatternContainerById(menu, providerId);
return getProviderDisplayName(container, providerId);
}
/**
* 获取供应器显示名优先组名
*/
public static String getProviderDisplayName(@Nullable PatternContainer container) {
return getProviderDisplayName(container, -1);
}
/**
* 实际显示名获取逻辑
*/
private static String getProviderDisplayName(@Nullable PatternContainer container, long providerId) {
if (container == null) return UNKNOWN_PROVIDER;
try {
var group = container.getTerminalGroup();
if (group != null) {
// 使用 Component 序列化来保持翻译键而不是直接 getString()
// 这样客户端可以根据自己的语言设置进行翻译
return Component.Serializer.toJson(group.name());
}
} catch (Exception ignored) {
}
return providerId > 0 ? "样板供应器 #" + providerId : "样板供应器";
}
}