fix:修复制作界面跳转样板可能打开未活跃供应器问题
This commit is contained in:
parent
1ca8c8c48e
commit
8fec6fff87
|
|
@ -13,7 +13,6 @@ import appeng.menu.me.crafting.CraftingCPUMenu;
|
|||
import appeng.parts.AEBasePart;
|
||||
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
|
||||
import com.extendedae_plus.util.PatternProviderDataUtil;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
|
|
@ -49,11 +48,8 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
ServerPlayer player = context.getSender();
|
||||
if (player == null) return;
|
||||
|
||||
LogUtils.getLogger().info("EAP[S]: recv CraftingMonitorOpenProviderC2SPacket key={} from {}", msg.what, player.getGameProfile().getName());
|
||||
|
||||
// 必须在 CraftingCPU 界面内
|
||||
if (!(player.containerMenu instanceof CraftingCPUMenu menu)) {
|
||||
LogUtils.getLogger().info("EAP[S]: not in CraftingCPUMenu, abort");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -64,19 +60,16 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
grid = host.getActionableNode().getGrid();
|
||||
}
|
||||
if (grid == null) {
|
||||
LogUtils.getLogger().info("EAP[S]: grid is null, abort");
|
||||
return;
|
||||
}
|
||||
|
||||
var cs = grid.getCraftingService();
|
||||
if (!(cs instanceof CraftingService craftingService)) {
|
||||
LogUtils.getLogger().info("EAP[S]: craftingService is null/unsupported, abort");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1) 根据 AEKey 找到可能的样板(pattern)
|
||||
Collection<IPatternDetails> patterns = craftingService.getCraftingFor(msg.what);
|
||||
LogUtils.getLogger().info("EAP[S]: patterns found={} for key={}", patterns.size(), msg.what);
|
||||
if (patterns.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -91,14 +84,35 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
if (host == null) continue;
|
||||
var pbe = host.getBlockEntity();
|
||||
if (pbe == null) continue;
|
||||
// 在服务端上下文中执行,pbe 仅用于构造菜单定位器
|
||||
|
||||
// 跳过未连接到网格或不活跃的 provider(例如缺少频道/通道)
|
||||
try {
|
||||
var providerGrid = ppl.getGrid();
|
||||
if (providerGrid == null || !providerGrid.equals(grid)) {
|
||||
continue;
|
||||
}
|
||||
// 如果 provider 自身对外提供的通道/频道信息不可用或不活跃,跳过
|
||||
try {
|
||||
// 尝试通过 provider 的主节点判断是否有 channel
|
||||
var mainNodeField = ppl.getClass().getDeclaredField("mainNode");
|
||||
mainNodeField.setAccessible(true);
|
||||
var mainNode = mainNodeField.get(ppl);
|
||||
if (mainNode == null) continue;
|
||||
var getChannelsMethod = mainNode.getClass().getMethod("getChannels");
|
||||
Object channels = null;
|
||||
channels = getChannelsMethod.invoke(mainNode);
|
||||
if (channels instanceof java.util.Collection) {
|
||||
if (((java.util.Collection<?>) channels).isEmpty()) continue;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
// 无法判断 channel 时继续:不因反射失败而阻止正常 provider
|
||||
}
|
||||
} catch (Exception e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 直接打开供应器自身的 UI(调用 Host 默认方法)
|
||||
try {
|
||||
// 告知目标玩家客户端高亮该 AEKey(避免全局服务端状态污染)
|
||||
AEKey key = pattern.getOutputs()[0].what();
|
||||
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
|
||||
// 部件与方块实体分别选择定位器并打开界面
|
||||
if (host instanceof AEBasePart part) {
|
||||
host.openMenu(player, MenuLocators.forPart(part));
|
||||
|
|
@ -106,18 +120,8 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
host.openMenu(player, MenuLocators.forBlockEntity(pbe));
|
||||
}
|
||||
|
||||
// 先在该 provider 中定位 pattern 的槽位索引,以便计算页码
|
||||
int foundSlot = -1;
|
||||
var list = PatternProviderDataUtil.getAllPatternData(ppl);
|
||||
for (var pd : list) {
|
||||
|
||||
if (pd != null && pd.getPatternDetails() != null
|
||||
&& pd.getPatternDetails().getDefinition().equals(pattern.getDefinition())) {
|
||||
foundSlot = pd.getSlotIndex();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
// 先在该 provider 中定位 pattern 的槽位索引,以便计算页码(尽量早退出,按槽位逐个解码)
|
||||
int foundSlot = findSlotIndexInProvider(ppl, pattern);
|
||||
if (foundSlot >= 0) {
|
||||
int pageId = foundSlot / 36;
|
||||
if (pageId > 0) {
|
||||
|
|
@ -125,19 +129,36 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
ModNetwork.CHANNEL.sendTo(new SetProviderPageS2CPacket(pageId), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
}
|
||||
context.setPacketHandled(true);
|
||||
|
||||
// 最后发送高亮包,保证界面已打开
|
||||
if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) {
|
||||
AEKey key = pattern.getOutputs()[0].what();
|
||||
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (Throwable t) {
|
||||
LogUtils.getLogger().error("EAP[S]: open provider UI failed at {}", pbe.getBlockPos(), t);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogUtils.getLogger().info("EAP[S]: no provider UI opened for key={}", msg.what);
|
||||
});
|
||||
context.setPacketHandled(true);
|
||||
}
|
||||
|
||||
private static int findSlotIndexInProvider(PatternProviderLogic ppl, IPatternDetails pattern) {
|
||||
try {
|
||||
// 通过逐槽位解码并在找到匹配定义时立即返回索引,避免分配大量对象
|
||||
var list = PatternProviderDataUtil.getAllPatternData(ppl);
|
||||
for (var pd : list) {
|
||||
if (pd != null && pd.getPatternDetails() != null && pd.getPatternDetails().getDefinition().equals(pattern.getDefinition())) {
|
||||
return pd.getSlotIndex();
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,11 @@ import appeng.api.inventories.InternalInventory;
|
|||
import appeng.api.stacks.AEKey;
|
||||
import appeng.api.stacks.GenericStack;
|
||||
import appeng.helpers.patternprovider.PatternProviderLogic;
|
||||
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import appeng.helpers.patternprovider.PatternProviderLogicHost;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -230,26 +233,8 @@ public class PatternProviderDataUtil {
|
|||
if (patternInventory == null) {
|
||||
return patternDataList;
|
||||
}
|
||||
|
||||
// 通过反射安全地访问host字段获取Level
|
||||
Level level = null;
|
||||
try {
|
||||
var hostField = patternProvider.getClass().getDeclaredField("host");
|
||||
hostField.setAccessible(true);
|
||||
var host = hostField.get(patternProvider);
|
||||
if (host != null) {
|
||||
var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity");
|
||||
var blockEntity = getBlockEntityMethod.invoke(host);
|
||||
if (blockEntity != null) {
|
||||
var getLevelMethod = blockEntity.getClass().getMethod("getLevel");
|
||||
level = (Level) getLevelMethod.invoke(blockEntity);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果反射失败,返回空列表
|
||||
return patternDataList;
|
||||
}
|
||||
|
||||
// 获取 Level(使用 mixin accessor 替代反射)
|
||||
Level level = getPatternProviderLevel(patternProvider);
|
||||
if (level == null) {
|
||||
return patternDataList;
|
||||
}
|
||||
|
|
@ -353,24 +338,7 @@ public class PatternProviderDataUtil {
|
|||
return null;
|
||||
}
|
||||
|
||||
// 通过反射安全地访问host字段获取Level
|
||||
Level level = null;
|
||||
try {
|
||||
var hostField = patternProvider.getClass().getDeclaredField("host");
|
||||
hostField.setAccessible(true);
|
||||
var host = hostField.get(patternProvider);
|
||||
if (host != null) {
|
||||
var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity");
|
||||
var blockEntity = getBlockEntityMethod.invoke(host);
|
||||
if (blockEntity != null) {
|
||||
var getLevelMethod = blockEntity.getClass().getMethod("getLevel");
|
||||
level = (Level) getLevelMethod.invoke(blockEntity);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Level level = getPatternProviderLevel(patternProvider);
|
||||
if (level == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -862,50 +830,30 @@ public class PatternProviderDataUtil {
|
|||
// 1. 设置物品到库存
|
||||
patternInventory.setItemDirect(slot, newPattern);
|
||||
|
||||
// 2. 标记数据为脏数据,确保保存到磁盘
|
||||
// 2. 标记数据为脏数据,确保保存到磁盘(尝试使用 mixin accessor 替代反射)
|
||||
try {
|
||||
// 通过反射获取host并标记为脏数据
|
||||
var hostField = patternProvider.getClass().getDeclaredField("host");
|
||||
hostField.setAccessible(true);
|
||||
var host = hostField.get(patternProvider);
|
||||
|
||||
if (host != null) {
|
||||
// 获取BlockEntity并标记为脏数据
|
||||
var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity");
|
||||
var blockEntity = getBlockEntityMethod.invoke(host);
|
||||
|
||||
if (blockEntity != null) {
|
||||
// 调用setChanged()方法标记为脏数据
|
||||
var setChangedMethod = blockEntity.getClass().getMethod("setChanged");
|
||||
setChangedMethod.invoke(blockEntity);
|
||||
|
||||
// 尝试触发网络同步
|
||||
try {
|
||||
var levelField = blockEntity.getClass().getSuperclass().getDeclaredField("level");
|
||||
levelField.setAccessible(true);
|
||||
Level level = (Level) levelField.get(blockEntity);
|
||||
|
||||
if (level != null && !level.isClientSide()) {
|
||||
// 服务器端:强制同步到客户端
|
||||
var getBlockPosMethod = blockEntity.getClass().getMethod("getBlockPos");
|
||||
var blockPos = getBlockPosMethod.invoke(blockEntity);
|
||||
|
||||
if (blockPos != null) {
|
||||
// 通知客户端方块状态变更
|
||||
var getBlockStateMethod = blockEntity.getClass().getMethod("getBlockState");
|
||||
var blockState = getBlockStateMethod.invoke(blockEntity);
|
||||
level.sendBlockUpdated((net.minecraft.core.BlockPos) blockPos,
|
||||
(net.minecraft.world.level.block.state.BlockState) blockState,
|
||||
(net.minecraft.world.level.block.state.BlockState) blockState, 3);
|
||||
}
|
||||
if (patternProvider instanceof PatternProviderLogicAccessor accessor) {
|
||||
var host = accessor.eap$host();
|
||||
if (host != null) {
|
||||
BlockEntity be = host.getBlockEntity();
|
||||
if (be != null) {
|
||||
try {
|
||||
be.setChanged();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
Level level = be.getLevel();
|
||||
if (level != null && !level.isClientSide()) {
|
||||
var pos = be.getBlockPos();
|
||||
var state = be.getBlockState();
|
||||
level.sendBlockUpdated(pos, state, state, 3);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
} catch (Exception syncException) {
|
||||
// 网络同步失败不影响主要功能
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果反射失败,使用备用方案
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
// 3. 强制更新样板缓存
|
||||
|
|
@ -920,20 +868,18 @@ public class PatternProviderDataUtil {
|
|||
* ExtendedAE风格:安全获取样板供应器的Level对象
|
||||
*/
|
||||
private static Level getPatternProviderLevel(PatternProviderLogic patternProvider) {
|
||||
if (patternProvider == null) return null;
|
||||
try {
|
||||
var hostField = patternProvider.getClass().getDeclaredField("host");
|
||||
hostField.setAccessible(true);
|
||||
var host = hostField.get(patternProvider);
|
||||
if (host != null) {
|
||||
var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity");
|
||||
var blockEntity = getBlockEntityMethod.invoke(host);
|
||||
if (blockEntity != null) {
|
||||
var getLevelMethod = blockEntity.getClass().getMethod("getLevel");
|
||||
return (Level) getLevelMethod.invoke(blockEntity);
|
||||
if (patternProvider instanceof PatternProviderLogicAccessor accessor) {
|
||||
var host = accessor.eap$host();
|
||||
if (host != null) {
|
||||
BlockEntity be = host.getBlockEntity();
|
||||
if (be != null) {
|
||||
return be.getLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 静默处理异常,返回null让调用者处理
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user