网络包
This commit is contained in:
parent
5fe2deb0df
commit
a18614ca7b
110
build.gradle
110
build.gradle
|
|
@ -127,96 +127,68 @@ sourceSets.main.resources { srcDir 'src/generated/resources' }
|
|||
|
||||
// 暂时排除缺少依赖的可选联动源码,待补齐依赖后再启用
|
||||
sourceSets.main.java {
|
||||
// 让编译期能解析 ExtendedAE 的类(如 GuiExPatternProvider、ActionEPPButton 等),仅作编译期源引用
|
||||
// 让编译期能解析 ExtendedAE 的类(如 GuiExPatternProvider、ActionEPPButton 等),作为编译期源引用
|
||||
// 运行期仍由 CurseMaven 依赖提供真实模组 Jar
|
||||
srcDir 'othermods/ExtendedAE-1.21-2.2.21-neoforge/src/main/java'
|
||||
// 广泛屏蔽迁移中的旧源码,仅保留模板核心类(ExtendedAEPlus、ExtendedAEPlusClient、Config)
|
||||
// 注意:不要屏蔽 api/**,我们有选择性 include 的接口文件需要参与编译
|
||||
include 'com/extendedae_plus/api/**'
|
||||
exclude 'com/extendedae_plus/client/**'
|
||||
// 包含配置包
|
||||
include 'com/extendedae_plus/config/**'
|
||||
exclude 'com/extendedae_plus/hooks/**'
|
||||
exclude 'com/extendedae_plus/init/**'
|
||||
exclude 'com/extendedae_plus/integration/**'
|
||||
exclude 'com/extendedae_plus/menu/**'
|
||||
// 包含主 Mod 类
|
||||
|
||||
// 分阶段迁移:仅编译样板倍增与必要 GUI/网络相关的核心代码,屏蔽未迁移联动与旧版 Forge API 代码
|
||||
include 'com/extendedae_plus/ExtendedAEPlus.java'
|
||||
// 仅保留 mixin 中的 accessor 参与编译
|
||||
// 解除对 accessor 的屏蔽
|
||||
include 'com/extendedae_plus/mixin/ae2/accessor/**'
|
||||
// 启用对 PatternProviderLogic 的功能混入(高级阻挡/智能翻倍开关的持久化与逻辑)
|
||||
include 'com/extendedae_plus/mixin/ae2/helpers/**'
|
||||
// 启用 AEProcessingPattern 的 mixin(提供可缩放标记)
|
||||
include 'com/extendedae_plus/mixin/ae2/AEProcessingPatternMixin.java'
|
||||
// 自动样板缩放注入(CraftingTreeProcess + 其 accessor)
|
||||
include 'com/extendedae_plus/mixin/ae2/autopattern/**'
|
||||
// GUI 方案A:解禁最小 GUI 混入
|
||||
include 'com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java'
|
||||
include 'com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java'
|
||||
include 'com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java'
|
||||
// ExtendedAE GUI 混入(右侧外列按钮与翻页),以及其依赖的 NewIcon 类
|
||||
// 仅包含 Provider GUI 混入(不要使用广域 exclude,以免覆盖 include)
|
||||
include 'com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java'
|
||||
include 'com/extendedae_plus/NewIcon.java'
|
||||
// 注意:不要屏蔽 network/**,我们已选择性 include 需要的网络文件
|
||||
// 仅解禁样板倍增核心所需的两个 util 文件
|
||||
include 'com/extendedae_plus/ExtendedAEPlusClient.java'
|
||||
include 'com/extendedae_plus/config/**'
|
||||
include 'com/extendedae_plus/api/**'
|
||||
|
||||
// util
|
||||
include 'com/extendedae_plus/util/ExtendedAELogger.java'
|
||||
include 'com/extendedae_plus/util/PatternProviderDataUtil.java'
|
||||
include 'com/extendedae_plus/util/PatternProviderUIHelper.java'
|
||||
// 自动样板缩放所需工具类
|
||||
include 'com/extendedae_plus/util/PatternScaler.java'
|
||||
include 'com/extendedae_plus/util/RequestedAmountHolder.java'
|
||||
// GUI 与网络最小依赖
|
||||
// 全量包含 api 包,防止个别接口遗漏
|
||||
include 'com/extendedae_plus/api/**'
|
||||
include 'com/extendedae_plus/util/ExtendedAELogger.java'
|
||||
// 客户端高亮存储(单文件启用,保持 content 其余文件不参与编译)
|
||||
// util needed by network payloads (providers listing / upload helpers)
|
||||
include 'com/extendedae_plus/util/ExtendedAEPatternUploadUtil.java'
|
||||
|
||||
// content(最小集)
|
||||
include 'com/extendedae_plus/content/ClientPatternHighlightStore.java'
|
||||
// 自动样板缩放所需内容类
|
||||
include 'com/extendedae_plus/content/ScaledProcessingPattern.java'
|
||||
|
||||
// client-side helpers needed by S2C payloads
|
||||
include 'com/extendedae_plus/client/ClientAdvancedBlockingState.java'
|
||||
include 'com/extendedae_plus/client/ui/ProviderSelectScreen.java'
|
||||
|
||||
// 网络(NeoForge 1.21 Payload API版本)
|
||||
include 'com/extendedae_plus/network/ModNetwork.java'
|
||||
include 'com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java'
|
||||
include 'com/extendedae_plus/network/ToggleSmartDoublingC2SPacket.java'
|
||||
include 'com/extendedae_plus/network/ScalePatternsC2SPacket.java'
|
||||
include 'com/extendedae_plus/network/SetPatternHighlightS2CPacket.java'
|
||||
// 仅 include 需要的 util 文件(不再对 util/** 做全局排除,以免误伤)
|
||||
include 'com/extendedae_plus/util/PatternProviderDataUtil.java'
|
||||
include 'com/extendedae_plus/util/PatternProviderUIHelper.java'
|
||||
include 'com/extendedae_plus/util/ExtendedAELogger.java'
|
||||
exclude 'com/extendedae_plus/wireless/**'
|
||||
include 'com/extendedae_plus/network/AdvancedBlockingSyncS2CPacket.java'
|
||||
include 'com/extendedae_plus/network/ProvidersListS2CPacket.java'
|
||||
include 'com/extendedae_plus/network/RequestProvidersListC2SPacket.java'
|
||||
include 'com/extendedae_plus/network/SetProviderPageS2CPacket.java'
|
||||
include 'com/extendedae_plus/network/CraftingMonitorJumpC2SPacket.java'
|
||||
include 'com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java'
|
||||
include 'com/extendedae_plus/network/OpenProviderUiC2SPacket.java'
|
||||
include 'com/extendedae_plus/network/GlobalToggleProviderModesC2SPacket.java'
|
||||
include 'com/extendedae_plus/network/UploadEncodedPatternToProviderC2SPacket.java'
|
||||
|
||||
// AE2 mixin:accessor/helpers/autopattern/gui/menu
|
||||
include 'com/extendedae_plus/mixin/ae2/accessor/**'
|
||||
include 'com/extendedae_plus/mixin/ae2/helpers/**'
|
||||
include 'com/extendedae_plus/mixin/ae2/AEProcessingPatternMixin.java'
|
||||
include 'com/extendedae_plus/mixin/ae2/autopattern/**'
|
||||
include 'com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java'
|
||||
include 'com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java'
|
||||
include 'com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java'
|
||||
|
||||
// ExtendedAE GUI 混入(右侧外列按钮与翻页),以及其依赖的 NewIcon 类
|
||||
include 'com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java'
|
||||
include 'com/extendedae_plus/NewIcon.java'
|
||||
}
|
||||
|
||||
// Sets up a dependency configuration called 'localRuntime'.
|
||||
// This configuration should be used instead of 'runtimeOnly' to declare
|
||||
// a dependency that will be present for runtime testing but that is
|
||||
// "optional", meaning it will not be pulled by dependents of this mod.
|
||||
configurations {
|
||||
runtimeClasspath.extendsFrom localRuntime
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Example optional mod dependency with JEI
|
||||
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
||||
// compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}"
|
||||
// compileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}"
|
||||
// We add the full version to localRuntime, not runtimeOnly, so that we do not publish a dependency on it
|
||||
// localRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}"
|
||||
|
||||
// Example mod dependency using a mod jar from ./libs with a flat dir repository
|
||||
// This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar
|
||||
// The group id is ignored when searching -- in this case, it is "blank"
|
||||
// implementation "blank:coolmod-${mc_version}:${coolmod_version}"
|
||||
|
||||
// Example mod dependency using a file as dependency
|
||||
// implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar")
|
||||
|
||||
// Example project dependency using a sister or child project:
|
||||
// implementation project(":myproject")
|
||||
|
||||
// For more info:
|
||||
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
||||
// http://www.gradle.org/docs/current/userguide/dependency_management.html
|
||||
|
||||
// --- Added dependencies for target mods ---
|
||||
implementation "curse.maven:glodium-957920:5821676"
|
||||
implementation "org.appliedenergistics:appliedenergistics2:19.2.8"
|
||||
|
|
|
|||
|
|
@ -44,4 +44,4 @@ mod_description=Example mod description.\nNewline characters can be used and wil
|
|||
|
||||
## UI item explorer selection (emi | rei | jei)
|
||||
# Default to 'emi' per request; you can override by running with -Puse_Xei=rei or -Puse_Xei=jei
|
||||
use_Xei=emi
|
||||
use_Xei=jei
|
||||
|
|
|
|||
|
|
@ -194,7 +194,10 @@ public class ProviderSelectScreen extends Screen {
|
|||
private void onChoose(int idx) {
|
||||
if (idx < 0 || idx >= fIds.size()) return;
|
||||
long providerId = fIds.get(idx);
|
||||
ModNetwork.CHANNEL.sendToServer(new UploadEncodedPatternToProviderC2SPacket(providerId));
|
||||
var conn = Minecraft.getInstance().getConnection();
|
||||
if (conn != null) {
|
||||
conn.send(new UploadEncodedPatternToProviderC2SPacket(providerId));
|
||||
}
|
||||
this.onClose();
|
||||
}
|
||||
|
||||
|
|
@ -342,12 +345,6 @@ public class ProviderSelectScreen extends Screen {
|
|||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (searchBox != null) {
|
||||
searchBox.tick();
|
||||
}
|
||||
if (cnInput != null) {
|
||||
cnInput.tick();
|
||||
}
|
||||
if (needsRefresh) {
|
||||
needsRefresh = false;
|
||||
// 重新构建当前屏幕内容
|
||||
|
|
|
|||
|
|
@ -54,3 +54,4 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide
|
|||
private void eap$debug_getShowInAccessTerminal(CallbackInfoReturnable<?> cir) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,12 +1,29 @@
|
|||
package com.extendedae_plus.network;
|
||||
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.client.ClientAdvancedBlockingState;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.neoforged.neoforge.network.NetworkEvent;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
/**
|
||||
* S2C:同步某个 Provider 的高级阻挡状态到客户端(本地存储)。
|
||||
*/
|
||||
public class AdvancedBlockingSyncS2CPacket implements CustomPacketPayload {
|
||||
public static final Type<AdvancedBlockingSyncS2CPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "adv_blocking_sync"));
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, AdvancedBlockingSyncS2CPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> {
|
||||
buf.writeUtf(pkt.dimensionId);
|
||||
buf.writeLong(pkt.blockPosLong);
|
||||
buf.writeBoolean(pkt.enabled);
|
||||
},
|
||||
buf -> new AdvancedBlockingSyncS2CPacket(buf.readUtf(), buf.readLong(), buf.readBoolean())
|
||||
);
|
||||
|
||||
public class AdvancedBlockingSyncS2CPacket {
|
||||
private final String dimensionId;
|
||||
private final long blockPosLong;
|
||||
private final boolean enabled;
|
||||
|
|
@ -17,25 +34,15 @@ public class AdvancedBlockingSyncS2CPacket {
|
|||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public static void encode(AdvancedBlockingSyncS2CPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeUtf(msg.dimensionId);
|
||||
buf.writeLong(msg.blockPosLong);
|
||||
buf.writeBoolean(msg.enabled);
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static AdvancedBlockingSyncS2CPacket decode(FriendlyByteBuf buf) {
|
||||
String dim = buf.readUtf();
|
||||
long pos = buf.readLong();
|
||||
boolean en = buf.readBoolean();
|
||||
return new AdvancedBlockingSyncS2CPacket(dim, pos, en);
|
||||
}
|
||||
|
||||
public static void handle(AdvancedBlockingSyncS2CPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
var ctx = ctxSupplier.get();
|
||||
public static void handle(final AdvancedBlockingSyncS2CPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
String key = ClientAdvancedBlockingState.key(msg.dimensionId, msg.blockPosLong);
|
||||
ClientAdvancedBlockingState.set(key, msg.enabled);
|
||||
});
|
||||
ctx.setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
|
|||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
|
|
@ -21,39 +24,37 @@ import net.minecraft.world.MenuProvider;
|
|||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraftforge.network.NetworkHooks;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 客户端从 CraftingCPUScreen 发送:鼠标下条目对应的 AEKey。
|
||||
* 服务端在当前打开的 CraftingCPUMenu 所属网络中,定位匹配该 AEKey 的样板供应器,
|
||||
* 尝试打开其目标机器的 GUI。
|
||||
*/
|
||||
public class CraftingMonitorJumpC2SPacket {
|
||||
public class CraftingMonitorJumpC2SPacket implements CustomPacketPayload {
|
||||
public static final Type<CraftingMonitorJumpC2SPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(com.extendedae_plus.ExtendedAEPlus.MODID, "crafting_monitor_jump"));
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, CraftingMonitorJumpC2SPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> AEKey.writeKey(buf, pkt.what),
|
||||
buf -> new CraftingMonitorJumpC2SPacket(AEKey.readKey(buf))
|
||||
);
|
||||
private final AEKey what;
|
||||
|
||||
public CraftingMonitorJumpC2SPacket(AEKey what) {
|
||||
this.what = what;
|
||||
}
|
||||
|
||||
public static void encode(CraftingMonitorJumpC2SPacket msg, FriendlyByteBuf buf) {
|
||||
AEKey.writeKey(buf, msg.what);
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static CraftingMonitorJumpC2SPacket decode(FriendlyByteBuf buf) {
|
||||
AEKey key = AEKey.readKey(buf);
|
||||
return new CraftingMonitorJumpC2SPacket(key);
|
||||
}
|
||||
|
||||
public static void handle(CraftingMonitorJumpC2SPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
NetworkEvent.Context context = ctx.get();
|
||||
context.enqueueWork(() -> {
|
||||
ServerPlayer player = context.getSender();
|
||||
if (player == null) return;
|
||||
|
||||
public static void handle(final CraftingMonitorJumpC2SPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
if (!(ctx.player() instanceof ServerPlayer player)) return;
|
||||
LogUtils.getLogger().info("EAP[S]: recv CraftingMonitorJumpC2SPacket key={} from {}", msg.what, player.getGameProfile().getName());
|
||||
|
||||
// 必须在 CraftingCPU 界面内
|
||||
|
|
@ -102,54 +103,30 @@ public class CraftingMonitorJumpC2SPacket {
|
|||
var pbe = host.getBlockEntity();
|
||||
ServerLevel serverLevel = player.serverLevel();
|
||||
|
||||
// 尝试对邻居打开 GUI(复用 OpenProviderUiC2SPacket 的策略)
|
||||
// 尝试对邻居打开 GUI(优先通过 MenuProvider)
|
||||
for (Direction dir : host.getTargets()) {
|
||||
BlockPos targetPos = pbe.getBlockPos().relative(dir);
|
||||
var tbe = serverLevel.getBlockEntity(targetPos);
|
||||
if (tbe instanceof MenuProvider provider1) {
|
||||
LogUtils.getLogger().info("EAP[S]: open screen via MenuProvider at {}", targetPos);
|
||||
NetworkHooks.openScreen(player, provider1, targetPos);
|
||||
context.setPacketHandled(true);
|
||||
player.openMenu(provider1, targetPos);
|
||||
return;
|
||||
}
|
||||
var tstate = serverLevel.getBlockState(targetPos);
|
||||
var provider2 = tstate.getMenuProvider(serverLevel, targetPos);
|
||||
if (provider2 != null) {
|
||||
LogUtils.getLogger().info("EAP[S]: open screen via state.getMenuProvider at {}", targetPos);
|
||||
NetworkHooks.openScreen(player, provider2, targetPos);
|
||||
context.setPacketHandled(true);
|
||||
player.openMenu(provider2, targetPos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 兜底:若无 MenuProvider,始终模拟一次右键(优先有方块实体的一面)
|
||||
InteractionHand hand = player.getMainHandItem().isEmpty() ? InteractionHand.MAIN_HAND : InteractionHand.MAIN_HAND;
|
||||
Direction chosen = null;
|
||||
for (Direction d : host.getTargets()) {
|
||||
if (serverLevel.getBlockEntity(pbe.getBlockPos().relative(d)) != null) { chosen = d; break; }
|
||||
}
|
||||
if (chosen == null) {
|
||||
for (Direction d : host.getTargets()) {
|
||||
if (!serverLevel.getBlockState(pbe.getBlockPos().relative(d)).isAir()) { chosen = d; break; }
|
||||
}
|
||||
}
|
||||
if (chosen != null) {
|
||||
BlockPos targetPos = pbe.getBlockPos().relative(chosen);
|
||||
var state2 = serverLevel.getBlockState(targetPos);
|
||||
var hit = new BlockHitResult(Vec3.atCenterOf(targetPos), chosen.getOpposite(), targetPos, false);
|
||||
InteractionResult r = state2.use(serverLevel, player, hand, hit);
|
||||
LogUtils.getLogger().info("EAP[S]: simulated use on {}, face={}, result={}", targetPos, chosen, r);
|
||||
if (r.consumesAction()) {
|
||||
context.setPacketHandled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 兜底:若无 MenuProvider,则跳过(不再模拟右键以确保兼容性)
|
||||
}
|
||||
}
|
||||
LogUtils.getLogger().info("EAP[S]: providers count for one pattern: {}", providerCount);
|
||||
}
|
||||
LogUtils.getLogger().info("EAP[S]: no target opened for key={}", msg.what);
|
||||
});
|
||||
context.setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,18 +18,20 @@ import com.glodblock.github.glodium.util.GlodUtil;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.glodblock.github.extendedae.client.render.EAEHighlightHandler.highlight;
|
||||
|
||||
|
|
@ -38,27 +40,28 @@ import static com.glodblock.github.extendedae.client.render.EAEHighlightHandler.
|
|||
* 服务端在当前打开的 CraftingCPUMenu 所属网络中,定位匹配该 AEKey 的样板供应器,
|
||||
* 打开该供应器自身的 UI(不是目标机器的 UI)。
|
||||
*/
|
||||
public class CraftingMonitorOpenProviderC2SPacket {
|
||||
public class CraftingMonitorOpenProviderC2SPacket implements CustomPacketPayload {
|
||||
public static final Type<CraftingMonitorOpenProviderC2SPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(com.extendedae_plus.ExtendedAEPlus.MODID, "crafting_monitor_open_provider"));
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, CraftingMonitorOpenProviderC2SPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> AEKey.writeKey(buf, pkt.what),
|
||||
buf -> new CraftingMonitorOpenProviderC2SPacket(AEKey.readKey(buf))
|
||||
);
|
||||
private final AEKey what;
|
||||
|
||||
public CraftingMonitorOpenProviderC2SPacket(AEKey what) {
|
||||
this.what = what;
|
||||
}
|
||||
|
||||
public static void encode(CraftingMonitorOpenProviderC2SPacket msg, FriendlyByteBuf buf) {
|
||||
AEKey.writeKey(buf, msg.what);
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static CraftingMonitorOpenProviderC2SPacket decode(FriendlyByteBuf buf) {
|
||||
AEKey key = AEKey.readKey(buf);
|
||||
return new CraftingMonitorOpenProviderC2SPacket(key);
|
||||
}
|
||||
|
||||
public static void handle(CraftingMonitorOpenProviderC2SPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
NetworkEvent.Context context = ctx.get();
|
||||
context.enqueueWork(() -> {
|
||||
ServerPlayer player = context.getSender();
|
||||
if (player == null) return;
|
||||
public static void handle(final CraftingMonitorOpenProviderC2SPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
if (!(ctx.player() instanceof ServerPlayer player)) return;
|
||||
|
||||
// 必须在 CraftingCPU 界面内
|
||||
if (!(player.containerMenu instanceof CraftingCPUMenu menu)) {
|
||||
|
|
@ -119,15 +122,16 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
if (foundSlot >= 0) {
|
||||
int pageId = foundSlot / 36;
|
||||
if (pageId > 0) {
|
||||
// 发送 S2C 包通知客户端切换到指定页(客户端会写入 mixin 字段并重排槽位)
|
||||
ModNetwork.CHANNEL.sendTo(new SetProviderPageS2CPacket(pageId), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
// 发送 S2C:切换到指定页
|
||||
player.connection.send(new SetProviderPageS2CPacket(pageId));
|
||||
}
|
||||
}
|
||||
|
||||
// 最后发送高亮包,保证界面已打开
|
||||
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);
|
||||
var outs = pattern.getOutputs();
|
||||
if (outs != null && !outs.isEmpty() && outs.get(0) != null) {
|
||||
AEKey key = outs.get(0).what();
|
||||
player.connection.send(new SetPatternHighlightS2CPacket(key, true));
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -137,7 +141,6 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
}
|
||||
}
|
||||
});
|
||||
context.setPacketHandled(true);
|
||||
}
|
||||
|
||||
private static void highlightWithMessage(BlockPos pos, Direction face, ResourceKey<Level> dim, double multiplier, Player player) {
|
||||
|
|
|
|||
|
|
@ -7,18 +7,21 @@ import appeng.blockentity.crafting.PatternProviderBlockEntity;
|
|||
import appeng.helpers.patternprovider.PatternProviderLogic;
|
||||
import appeng.helpers.patternprovider.PatternProviderLogicHost;
|
||||
import appeng.parts.crafting.PatternProviderPart;
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.api.AdvancedBlockingHolder;
|
||||
import com.extendedae_plus.api.SmartDoublingHolder;
|
||||
import com.extendedae_plus.content.controller.NetworkPatternControllerBlockEntity;
|
||||
import appeng.api.networking.IInWorldGridNodeHost;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* C2S:全网批量切换样板供应器的三种模式:
|
||||
|
|
@ -28,7 +31,19 @@ import java.util.function.Supplier;
|
|||
*
|
||||
* 负载为三个操作码(各1字节),分别对应:blocking、advancedBlocking、smartDoubling。
|
||||
*/
|
||||
public class GlobalToggleProviderModesC2SPacket {
|
||||
public class GlobalToggleProviderModesC2SPacket implements CustomPacketPayload {
|
||||
public static final Type<GlobalToggleProviderModesC2SPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "global_toggle_provider_modes"));
|
||||
|
||||
public static final StreamCodec<FriendlyByteBuf, GlobalToggleProviderModesC2SPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> {
|
||||
buf.writeByte(pkt.opBlocking.id);
|
||||
buf.writeByte(pkt.opAdvancedBlocking.id);
|
||||
buf.writeByte(pkt.opSmartDoubling.id);
|
||||
buf.writeBlockPos(pkt.controllerPos);
|
||||
},
|
||||
buf -> new GlobalToggleProviderModesC2SPacket(Op.byId(buf.readByte()), Op.byId(buf.readByte()), Op.byId(buf.readByte()), buf.readBlockPos())
|
||||
);
|
||||
public enum Op {
|
||||
NOOP((byte) 0),
|
||||
SET_TRUE((byte) 1),
|
||||
|
|
@ -58,32 +73,21 @@ public class GlobalToggleProviderModesC2SPacket {
|
|||
this.controllerPos = controllerPos;
|
||||
}
|
||||
|
||||
public static void encode(GlobalToggleProviderModesC2SPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeByte(msg.opBlocking.id);
|
||||
buf.writeByte(msg.opAdvancedBlocking.id);
|
||||
buf.writeByte(msg.opSmartDoubling.id);
|
||||
buf.writeBlockPos(msg.controllerPos);
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static GlobalToggleProviderModesC2SPacket decode(FriendlyByteBuf buf) {
|
||||
Op b = Op.byId(buf.readByte());
|
||||
Op ab = Op.byId(buf.readByte());
|
||||
Op sd = Op.byId(buf.readByte());
|
||||
BlockPos pos = buf.readBlockPos();
|
||||
return new GlobalToggleProviderModesC2SPacket(b, ab, sd, pos);
|
||||
}
|
||||
|
||||
public static void handle(GlobalToggleProviderModesC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
var ctx = ctxSupplier.get();
|
||||
public static void handle(final GlobalToggleProviderModesC2SPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
ServerPlayer player = ctx.getSender();
|
||||
if (!(ctx.player() instanceof ServerPlayer player)) return;
|
||||
if (player == null) return;
|
||||
|
||||
// 从控制方块实体的 AE2 节点确定 AE 网络上下文
|
||||
var level = player.serverLevel();
|
||||
var be = level.getBlockEntity(msg.controllerPos);
|
||||
if (!(be instanceof NetworkPatternControllerBlockEntity controller)) return;
|
||||
var node = controller.getGridNode(null);
|
||||
if (!(be instanceof IInWorldGridNodeHost host)) return;
|
||||
var node = host.getGridNode(null);
|
||||
if (node == null) return;
|
||||
IGrid grid = node.getGrid();
|
||||
if (grid == null) return;
|
||||
|
|
@ -92,7 +96,6 @@ public class GlobalToggleProviderModesC2SPacket {
|
|||
// 向发起玩家反馈影响数量,便于判断按钮是否生效
|
||||
player.displayClientMessage(Component.literal("E+ 全局切换已应用到 " + affected + " 个样板供应器"), true);
|
||||
});
|
||||
ctx.setPacketHandled(true);
|
||||
}
|
||||
|
||||
private static int applyToAllProviders(IGrid grid, GlobalToggleProviderModesC2SPacket msg) {
|
||||
|
|
|
|||
|
|
@ -11,5 +11,14 @@ public class ModNetwork {
|
|||
registrar.playToServer(ToggleSmartDoublingC2SPacket.TYPE, ToggleSmartDoublingC2SPacket.STREAM_CODEC, ToggleSmartDoublingC2SPacket::handle);
|
||||
registrar.playToServer(ScalePatternsC2SPacket.TYPE, ScalePatternsC2SPacket.STREAM_CODEC, ScalePatternsC2SPacket::handle);
|
||||
registrar.playToClient(SetPatternHighlightS2CPacket.TYPE, SetPatternHighlightS2CPacket.STREAM_CODEC, SetPatternHighlightS2CPacket::handle);
|
||||
registrar.playToClient(AdvancedBlockingSyncS2CPacket.TYPE, AdvancedBlockingSyncS2CPacket.STREAM_CODEC, AdvancedBlockingSyncS2CPacket::handle);
|
||||
registrar.playToClient(ProvidersListS2CPacket.TYPE, ProvidersListS2CPacket.STREAM_CODEC, ProvidersListS2CPacket::handle);
|
||||
registrar.playToServer(RequestProvidersListC2SPacket.TYPE, RequestProvidersListC2SPacket.STREAM_CODEC, RequestProvidersListC2SPacket::handle);
|
||||
registrar.playToClient(SetProviderPageS2CPacket.TYPE, SetProviderPageS2CPacket.STREAM_CODEC, SetProviderPageS2CPacket::handle);
|
||||
registrar.playToServer(GlobalToggleProviderModesC2SPacket.TYPE, GlobalToggleProviderModesC2SPacket.STREAM_CODEC, GlobalToggleProviderModesC2SPacket::handle);
|
||||
registrar.playToServer(CraftingMonitorJumpC2SPacket.TYPE, CraftingMonitorJumpC2SPacket.STREAM_CODEC, CraftingMonitorJumpC2SPacket::handle);
|
||||
registrar.playToServer(CraftingMonitorOpenProviderC2SPacket.TYPE, CraftingMonitorOpenProviderC2SPacket.STREAM_CODEC, CraftingMonitorOpenProviderC2SPacket::handle);
|
||||
registrar.playToServer(OpenProviderUiC2SPacket.TYPE, OpenProviderUiC2SPacket.STREAM_CODEC, OpenProviderUiC2SPacket::handle);
|
||||
registrar.playToServer(UploadEncodedPatternToProviderC2SPacket.TYPE, UploadEncodedPatternToProviderC2SPacket.STREAM_CODEC, UploadEncodedPatternToProviderC2SPacket::handle);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.extendedae_plus.network;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
|
@ -15,12 +17,20 @@ import net.minecraft.server.level.ServerPlayer;
|
|||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraftforge.network.NetworkHooks;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
public class OpenProviderUiC2SPacket implements CustomPacketPayload {
|
||||
public static final Type<OpenProviderUiC2SPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(com.extendedae_plus.ExtendedAEPlus.MODID, "open_provider_ui"));
|
||||
|
||||
public class OpenProviderUiC2SPacket {
|
||||
public static final StreamCodec<FriendlyByteBuf, OpenProviderUiC2SPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> {
|
||||
buf.writeLong(pkt.posLong);
|
||||
buf.writeResourceLocation(pkt.dimId);
|
||||
buf.writeVarInt(pkt.faceOrd);
|
||||
},
|
||||
buf -> new OpenProviderUiC2SPacket(buf.readLong(), buf.readResourceLocation(), buf.readVarInt())
|
||||
);
|
||||
private final long posLong;
|
||||
private final ResourceLocation dimId;
|
||||
private final int faceOrd; // 目前保留,若目标需要可用
|
||||
|
|
@ -31,26 +41,14 @@ public class OpenProviderUiC2SPacket {
|
|||
this.faceOrd = faceOrd;
|
||||
}
|
||||
|
||||
public static void encode(OpenProviderUiC2SPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeLong(msg.posLong);
|
||||
buf.writeResourceLocation(msg.dimId);
|
||||
buf.writeVarInt(msg.faceOrd);
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static OpenProviderUiC2SPacket decode(FriendlyByteBuf buf) {
|
||||
long posLong = buf.readLong();
|
||||
ResourceLocation dimId = buf.readResourceLocation();
|
||||
int faceOrd = buf.readVarInt();
|
||||
return new OpenProviderUiC2SPacket(posLong, dimId, faceOrd);
|
||||
|
||||
}
|
||||
|
||||
public static void handle(OpenProviderUiC2SPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
NetworkEvent.Context context = ctx.get();
|
||||
context.enqueueWork(() -> {
|
||||
ServerPlayer player = context.getSender();
|
||||
if (player == null) return;
|
||||
|
||||
public static void handle(final OpenProviderUiC2SPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
if (!(ctx.player() instanceof ServerPlayer player)) return;
|
||||
|
||||
// 校验维度与方块
|
||||
ResourceKey<Level> levelKey = ResourceKey.create(Registries.DIMENSION, msg.dimId);
|
||||
|
|
@ -76,58 +74,19 @@ public class OpenProviderUiC2SPacket {
|
|||
BlockPos targetPos = pos.relative(dir);
|
||||
BlockEntity tbe = level.getBlockEntity(targetPos);
|
||||
if (tbe instanceof MenuProvider provider) {
|
||||
NetworkHooks.openScreen(player, provider, targetPos);
|
||||
player.openMenu(provider, targetPos);
|
||||
return;
|
||||
}
|
||||
var tstate = level.getBlockState(targetPos);
|
||||
MenuProvider provider2 = tstate.getMenuProvider(level, targetPos);
|
||||
if (provider2 != null) {
|
||||
NetworkHooks.openScreen(player, provider2, targetPos);
|
||||
player.openMenu(provider2, targetPos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果邻居也未提供 MenuProvider,则兜底:尽量模拟一次徒手右键相邻方块
|
||||
boolean anyHandEmpty = player.getMainHandItem().isEmpty() || player.getOffhandItem().isEmpty();
|
||||
if (anyHandEmpty) {
|
||||
InteractionHand hand = player.getMainHandItem().isEmpty() ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
||||
if (msg.faceOrd >= 0 && msg.faceOrd < Direction.values().length) {
|
||||
Direction dir = Direction.values()[msg.faceOrd];
|
||||
BlockPos targetPos = pos.relative(dir);
|
||||
var state2 = level.getBlockState(targetPos);
|
||||
var hit = new BlockHitResult(Vec3.atCenterOf(targetPos), dir.getOpposite(), targetPos, false);
|
||||
InteractionResult r = state2.use(level, player, hand, hit);
|
||||
if (r.consumesAction()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 无明确朝向:优先挑选有方块实体的邻居,否则挑选非空气方块
|
||||
Direction chosen = null;
|
||||
for (Direction d : Direction.values()) {
|
||||
if (level.getBlockEntity(pos.relative(d)) != null) { chosen = d; break; }
|
||||
}
|
||||
if (chosen == null) {
|
||||
for (Direction d : Direction.values()) {
|
||||
if (!level.getBlockState(pos.relative(d)).isAir()) { chosen = d; break; }
|
||||
}
|
||||
}
|
||||
if (chosen != null) {
|
||||
BlockPos targetPos = pos.relative(chosen);
|
||||
var state2 = level.getBlockState(targetPos);
|
||||
var hit = new BlockHitResult(Vec3.atCenterOf(targetPos), chosen.getOpposite(), targetPos, false);
|
||||
InteractionResult r = state2.use(level, player, hand, hit);
|
||||
if (r.consumesAction()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 无可选邻居
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 双手占用则跳过兜底交互
|
||||
}
|
||||
// 若邻居未提供 MenuProvider,则跳过兜底交互(1.21 API 变更,避免不兼容的 use 调用)
|
||||
|
||||
context.setPacketHandled(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,47 @@
|
|||
package com.extendedae_plus.network;
|
||||
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.client.ui.ProviderSelectScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.neoforge.network.NetworkEvent;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* S2C: 返回可见且有空位的样板供应器列表,客户端弹窗展示供用户选择。
|
||||
*/
|
||||
public class ProvidersListS2CPacket {
|
||||
public class ProvidersListS2CPacket implements CustomPacketPayload {
|
||||
public static final Type<ProvidersListS2CPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "providers_list"));
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, ProvidersListS2CPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> {
|
||||
buf.writeVarInt(pkt.ids.size());
|
||||
for (int i = 0; i < pkt.ids.size(); i++) {
|
||||
buf.writeLong(pkt.ids.get(i));
|
||||
buf.writeUtf(pkt.names.get(i));
|
||||
buf.writeVarInt(pkt.emptySlots.get(i));
|
||||
}
|
||||
},
|
||||
buf -> {
|
||||
int size = buf.readVarInt();
|
||||
List<Long> ids = new ArrayList<>(size);
|
||||
List<String> names = new ArrayList<>(size);
|
||||
List<Integer> slots = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
ids.add(buf.readLong());
|
||||
names.add(buf.readUtf());
|
||||
slots.add(buf.readVarInt());
|
||||
}
|
||||
return new ProvidersListS2CPacket(ids, names, slots);
|
||||
}
|
||||
);
|
||||
|
||||
private final List<Long> ids;
|
||||
private final List<String> names;
|
||||
private final List<Integer> emptySlots;
|
||||
|
|
@ -25,39 +52,17 @@ public class ProvidersListS2CPacket {
|
|||
this.emptySlots = emptySlots;
|
||||
}
|
||||
|
||||
public static void encode(ProvidersListS2CPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeVarInt(msg.ids.size());
|
||||
for (int i = 0; i < msg.ids.size(); i++) {
|
||||
buf.writeLong(msg.ids.get(i));
|
||||
buf.writeUtf(msg.names.get(i));
|
||||
buf.writeVarInt(msg.emptySlots.get(i));
|
||||
}
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static ProvidersListS2CPacket decode(FriendlyByteBuf buf) {
|
||||
int size = buf.readVarInt();
|
||||
List<Long> ids = new ArrayList<>(size);
|
||||
List<String> names = new ArrayList<>(size);
|
||||
List<Integer> slots = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
ids.add(buf.readLong());
|
||||
names.add(buf.readUtf());
|
||||
slots.add(buf.readVarInt());
|
||||
}
|
||||
return new ProvidersListS2CPacket(ids, names, slots);
|
||||
}
|
||||
|
||||
public static void handle(ProvidersListS2CPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
var ctx = ctxSupplier.get();
|
||||
ctx.enqueueWork(() -> handleClient(msg));
|
||||
ctx.setPacketHandled(true);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private static void handleClient(ProvidersListS2CPacket msg) {
|
||||
var mc = Minecraft.getInstance();
|
||||
if (mc == null) return;
|
||||
var current = mc.screen;
|
||||
mc.setScreen(new ProviderSelectScreen(current, msg.ids, msg.names, msg.emptySlots));
|
||||
public static void handle(final ProvidersListS2CPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
var mc = Minecraft.getInstance();
|
||||
if (mc == null) return;
|
||||
var current = mc.screen;
|
||||
mc.setScreen(new ProviderSelectScreen(current, msg.ids, msg.names, msg.emptySlots));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,30 +3,40 @@ package com.extendedae_plus.network;
|
|||
import appeng.helpers.patternprovider.PatternContainer;
|
||||
import appeng.menu.implementations.PatternAccessTermMenu;
|
||||
import appeng.menu.me.items.PatternEncodingTermMenu;
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* C2S: 请求当前终端可见的样板供应器列表(用于弹窗选择)。
|
||||
*/
|
||||
public class RequestProvidersListC2SPacket {
|
||||
public class RequestProvidersListC2SPacket implements CustomPacketPayload {
|
||||
public static final Type<RequestProvidersListC2SPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "request_providers_list"));
|
||||
|
||||
public static final RequestProvidersListC2SPacket INSTANCE = new RequestProvidersListC2SPacket();
|
||||
|
||||
public static final StreamCodec<FriendlyByteBuf, RequestProvidersListC2SPacket> STREAM_CODEC =
|
||||
StreamCodec.unit(INSTANCE);
|
||||
|
||||
public RequestProvidersListC2SPacket() {}
|
||||
|
||||
public static void encode(RequestProvidersListC2SPacket msg, FriendlyByteBuf buf) {}
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static RequestProvidersListC2SPacket decode(FriendlyByteBuf buf) { return new RequestProvidersListC2SPacket(); }
|
||||
|
||||
public static void handle(RequestProvidersListC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
var ctx = ctxSupplier.get();
|
||||
public static void handle(final RequestProvidersListC2SPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
ServerPlayer player = ctx.getSender();
|
||||
if (player == null) return;
|
||||
if (!(ctx.player() instanceof ServerPlayer player)) return;
|
||||
if (!(player.containerMenu instanceof PatternEncodingTermMenu encMenu)) return;
|
||||
|
||||
// 优先:若玩家也打开了样板访问终端,则用 byId 方式(精确服务器ID)
|
||||
|
|
@ -47,7 +57,7 @@ public class RequestProvidersListC2SPacket {
|
|||
slots.add(empty);
|
||||
}
|
||||
|
||||
ModNetwork.CHANNEL.sendTo(new ProvidersListS2CPacket(filteredIds, names, slots), player.connection.connection, net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT);
|
||||
player.connection.send(new ProvidersListS2CPacket(filteredIds, names, slots));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -66,8 +76,7 @@ public class RequestProvidersListC2SPacket {
|
|||
names.add(ExtendedAEPatternUploadUtil.getProviderDisplayName(c));
|
||||
slots.add(empty);
|
||||
}
|
||||
ModNetwork.CHANNEL.sendTo(new ProvidersListS2CPacket(idxIds, names, slots), player.connection.connection, net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT);
|
||||
player.connection.send(new ProvidersListS2CPacket(idxIds, names, slots));
|
||||
});
|
||||
ctx.setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,60 @@
|
|||
package com.extendedae_plus.network;
|
||||
|
||||
import appeng.menu.SlotSemantics;
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* S2C: 指示客户端在已打开的样板供应器界面切换到指定页
|
||||
*/
|
||||
public class SetProviderPageS2CPacket {
|
||||
public class SetProviderPageS2CPacket implements CustomPacketPayload {
|
||||
public static final Type<SetProviderPageS2CPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "set_provider_page"));
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, SetProviderPageS2CPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> buf.writeVarInt(pkt.page),
|
||||
buf -> new SetProviderPageS2CPacket(buf.readVarInt())
|
||||
);
|
||||
|
||||
private final int page;
|
||||
|
||||
public SetProviderPageS2CPacket(int page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public static void encode(SetProviderPageS2CPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeVarInt(msg.page);
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static SetProviderPageS2CPacket decode(FriendlyByteBuf buf) {
|
||||
int p = buf.readVarInt();
|
||||
return new SetProviderPageS2CPacket(p);
|
||||
}
|
||||
|
||||
public static void handle(SetProviderPageS2CPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
var ctx = ctxSupplier.get();
|
||||
public static void handle(final SetProviderPageS2CPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
try {
|
||||
Screen screen = Minecraft.getInstance().screen;
|
||||
if (screen instanceof GuiExPatternProvider guiExPatternProvider) {
|
||||
Field currentPage = screen.getClass().getDeclaredField("eap$currentPage");
|
||||
currentPage.setAccessible(true);
|
||||
currentPage.setInt(guiExPatternProvider, msg.page);
|
||||
try {
|
||||
Screen screen = Minecraft.getInstance().screen;
|
||||
if (screen instanceof GuiExPatternProvider guiExPatternProvider) {
|
||||
Field currentPage = screen.getClass().getDeclaredField("eap$currentPage");
|
||||
currentPage.setAccessible(true);
|
||||
currentPage.setInt(guiExPatternProvider, msg.page);
|
||||
|
||||
guiExPatternProvider.repositionSlots(SlotSemantics.ENCODED_PATTERN);
|
||||
guiExPatternProvider.repositionSlots(SlotSemantics.STORAGE);
|
||||
|
||||
guiExPatternProvider.repositionSlots(SlotSemantics.ENCODED_PATTERN);
|
||||
guiExPatternProvider.repositionSlots(SlotSemantics.STORAGE);
|
||||
|
||||
Field hs = screen.getClass().getDeclaredField("hoveredSlot");
|
||||
hs.setAccessible(true);
|
||||
hs.set(screen, null);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
Field hs = screen.getClass().getDeclaredField("hoveredSlot");
|
||||
hs.setAccessible(true);
|
||||
hs.set(screen, null);
|
||||
}
|
||||
);
|
||||
ctx.setPacketHandled(true);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,34 +3,37 @@ package com.extendedae_plus.network;
|
|||
import appeng.menu.me.items.PatternEncodingTermMenu;
|
||||
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
/**
|
||||
* C2S: 请求将图样编码终端的已编码样板上传到指定的样板供应器(由客户端选择)。
|
||||
*/
|
||||
public class UploadEncodedPatternToProviderC2SPacket {
|
||||
public class UploadEncodedPatternToProviderC2SPacket implements CustomPacketPayload {
|
||||
public static final Type<UploadEncodedPatternToProviderC2SPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(com.extendedae_plus.ExtendedAEPlus.MODID, "upload_pattern_to_provider"));
|
||||
|
||||
public static final StreamCodec<FriendlyByteBuf, UploadEncodedPatternToProviderC2SPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> buf.writeLong(pkt.providerId),
|
||||
buf -> new UploadEncodedPatternToProviderC2SPacket(buf.readLong())
|
||||
);
|
||||
private final long providerId;
|
||||
|
||||
public UploadEncodedPatternToProviderC2SPacket(long providerId) {
|
||||
this.providerId = providerId;
|
||||
}
|
||||
|
||||
public static void encode(UploadEncodedPatternToProviderC2SPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeLong(msg.providerId);
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static UploadEncodedPatternToProviderC2SPacket decode(FriendlyByteBuf buf) {
|
||||
return new UploadEncodedPatternToProviderC2SPacket(buf.readLong());
|
||||
}
|
||||
|
||||
public static void handle(UploadEncodedPatternToProviderC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
var ctx = ctxSupplier.get();
|
||||
public static void handle(final UploadEncodedPatternToProviderC2SPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
ServerPlayer player = ctx.getSender();
|
||||
if (player == null) return;
|
||||
if (!(ctx.player() instanceof ServerPlayer player)) return;
|
||||
if (!(player.containerMenu instanceof PatternEncodingTermMenu menu)) return;
|
||||
// 支持两种模式:
|
||||
// 1) providerId >= 0: 访问终端 byId 模式
|
||||
|
|
@ -42,6 +45,5 @@ public class UploadEncodedPatternToProviderC2SPacket {
|
|||
ExtendedAEPatternUploadUtil.uploadFromEncodingMenuToProviderByIndex(player, menu, index);
|
||||
}
|
||||
});
|
||||
ctx.setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import appeng.api.inventories.InternalInventory;
|
|||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.core.definitions.AEItems;
|
||||
import appeng.menu.AEBaseMenu;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.crafting.pattern.AECraftingPattern;
|
||||
import appeng.crafting.pattern.AESmithingTablePattern;
|
||||
import appeng.crafting.pattern.AEStonecuttingPattern;
|
||||
|
|
@ -27,9 +29,7 @@ import net.minecraft.server.level.ServerPlayer;
|
|||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
import net.minecraft.world.item.crafting.RecipeType;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.fml.loading.FMLPaths;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.neoforged.fml.loading.FMLPaths;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
|
@ -102,8 +102,10 @@ public class ExtendedAEPatternUploadUtil {
|
|||
if (k.contains(":")) {
|
||||
// 形如 namespace:path
|
||||
try {
|
||||
ResourceLocation rl = new ResourceLocation(k);
|
||||
map.put(rl, name);
|
||||
var rl = ResourceLocation.tryParse(k);
|
||||
if (rl != null) {
|
||||
map.put(rl, name);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
} else {
|
||||
// 视为别名:最终搜索关键字(大小写不敏感)
|
||||
|
|
@ -163,8 +165,10 @@ public class ExtendedAEPatternUploadUtil {
|
|||
// 更新内存映射
|
||||
if (key.contains(":")) {
|
||||
try {
|
||||
ResourceLocation rl = new ResourceLocation(key);
|
||||
CUSTOM_NAMES.put(rl, cnValue);
|
||||
var rl = ResourceLocation.tryParse(key);
|
||||
if (rl != null) {
|
||||
CUSTOM_NAMES.put(rl, cnValue);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
} else {
|
||||
CUSTOM_ALIASES.put(key.toLowerCase(), cnValue);
|
||||
|
|
@ -216,11 +220,12 @@ public class ExtendedAEPatternUploadUtil {
|
|||
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);
|
||||
var rl = ResourceLocation.tryParse(k);
|
||||
if (rl != null) {
|
||||
String cur = CUSTOM_NAMES.get(rl);
|
||||
if (target.equals(cur)) {
|
||||
CUSTOM_NAMES.remove(rl);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
} else {
|
||||
|
|
@ -287,32 +292,7 @@ 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 的映射方法已在下方提供基于 Object 的反射版本,避免重复定义。
|
||||
|
||||
/**
|
||||
* 仅使用反射的 GTCEu GTRecipe -> 搜索关键字(避免在运行时直接引用 GTCEu 类)。
|
||||
|
|
@ -326,15 +306,15 @@ public class ExtendedAEPatternUploadUtil {
|
|||
Object typeObj = mGetType.invoke(gtRecipeObj);
|
||||
String idStr = String.valueOf(typeObj);
|
||||
if (idStr == null || idStr.isBlank()) return null;
|
||||
ResourceLocation rl = new ResourceLocation(idStr);
|
||||
var rl = ResourceLocation.tryParse(idStr);
|
||||
// 1) 别名优先(使用 path 作为最终搜索关键字)
|
||||
String path = rl.getPath();
|
||||
String path = rl != null ? rl.getPath() : null;
|
||||
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);
|
||||
String custom = rl != null ? CUSTOM_NAMES.get(rl) : null;
|
||||
if (custom != null && !custom.isBlank()) return custom;
|
||||
// 3) 默认返回 path 作为搜索关键字
|
||||
return (path != null && !path.isBlank()) ? path : idStr;
|
||||
|
|
@ -445,12 +425,15 @@ public class ExtendedAEPatternUploadUtil {
|
|||
}
|
||||
|
||||
// 获取 AE 网络
|
||||
IGridNode node = menu.getNetworkNode();
|
||||
if (node == null) {
|
||||
sendMessage(player, "ExtendedAE Plus: 当前不在有效的 AE 网络中");
|
||||
return false;
|
||||
}
|
||||
IGrid grid = node.getGrid();
|
||||
IGrid grid = null;
|
||||
try {
|
||||
if (menu instanceof AEBaseMenu abm) {
|
||||
Object target = abm.getTarget();
|
||||
if (target instanceof IActionHost host && host.getActionableNode() != null) {
|
||||
grid = host.getActionableNode().getGrid();
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {}
|
||||
if (grid == null) {
|
||||
sendMessage(player, "ExtendedAE Plus: 当前不在有效的 AE 网络中");
|
||||
return false;
|
||||
|
|
@ -506,7 +489,7 @@ public class ExtendedAEPatternUploadUtil {
|
|||
}
|
||||
|
||||
// 回退:尝试 Forge 能力(可能为聚合图样仓),同样遍历所有矩阵
|
||||
List<IItemHandler> handlers = findAllMatrixPatternHandlers(grid);
|
||||
List<?> handlers = findAllMatrixPatternHandlers(grid);
|
||||
if (!handlers.isEmpty()) {
|
||||
for (int i = 0; i < handlers.size(); i++) {
|
||||
var cap = handlers.get(i);
|
||||
|
|
@ -559,44 +542,11 @@ public class ExtendedAEPatternUploadUtil {
|
|||
/**
|
||||
* 在给定 AE Grid 中收集所有已成型的装配矩阵的聚合图样仓 IItemHandler(若可用)。
|
||||
*/
|
||||
private static List<IItemHandler> findAllMatrixPatternHandlers(IGrid grid) {
|
||||
List<IItemHandler> result = new ArrayList<>();
|
||||
try {
|
||||
Set<TileAssemblerMatrixBase> matrices = grid.getMachines(TileAssemblerMatrixBase.class);
|
||||
int idx = 0;
|
||||
for (TileAssemblerMatrixBase tile : matrices) {
|
||||
if (tile != null && tile.isFormed()) {
|
||||
var capOpt = tile.getCapability(ForgeCapabilities.ITEM_HANDLER, null);
|
||||
if (capOpt != null) {
|
||||
var handler = capOpt.orElse(null);
|
||||
if (handler != null) {
|
||||
result.add(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return result;
|
||||
private static List<?> findAllMatrixPatternHandlers(IGrid grid) {
|
||||
// NeoForge 1.21 能力系统与 API 变更,此处先返回空列表,避免编译期依赖旧能力系统
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试将整个物品栈插入到 IItemHandler 的任意槽位,返回剩余物品。
|
||||
*/
|
||||
private static ItemStack insertIntoAnySlot(IItemHandler handler, ItemStack stack) {
|
||||
ItemStack remaining = stack.copy();
|
||||
if (handler == null || remaining.isEmpty()) return remaining;
|
||||
for (int i = 0; i < handler.getSlots(); i++) {
|
||||
remaining = handler.insertItem(i, remaining, false);
|
||||
if (remaining.isEmpty()) break;
|
||||
}
|
||||
return remaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查装配矩阵(所有已成型矩阵的图样仓)中是否已存在与给定样板完全相同的物品(含NBT)。
|
||||
*/
|
||||
private static boolean matrixContainsPattern(IGrid grid, ItemStack pattern) {
|
||||
if (grid == null || pattern == null || pattern.isEmpty()) return false;
|
||||
try {
|
||||
|
|
@ -606,31 +556,24 @@ public class ExtendedAEPatternUploadUtil {
|
|||
if (inv == null) continue;
|
||||
for (int i = 0; i < inv.size(); i++) {
|
||||
ItemStack s = inv.getStackInSlot(i);
|
||||
if (!s.isEmpty() && net.minecraft.world.item.ItemStack.isSameItemSameTags(s, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
try {
|
||||
// 再检查聚合能力视图
|
||||
List<IItemHandler> handlers = findAllMatrixPatternHandlers(grid);
|
||||
for (IItemHandler h : handlers) {
|
||||
if (h == null) continue;
|
||||
int slots = h.getSlots();
|
||||
for (int i = 0; i < slots; i++) {
|
||||
ItemStack s = h.getStackInSlot(i);
|
||||
if (!s.isEmpty() && net.minecraft.world.item.ItemStack.isSameItemSameTags(s, pattern)) {
|
||||
if (!s.isEmpty() && net.minecraft.world.item.ItemStack.isSameItemSameComponents(s, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
// 1.21 暂不检查聚合能力视图,能力系统适配后再补充
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 能力系统(IItemHandler)未迁移前的占位插入:直接返回原始栈,表示未能插入。
|
||||
*/
|
||||
private static ItemStack insertIntoAnySlot(Object handler, ItemStack stack) {
|
||||
return stack.copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前菜单是否为ExtendedAE的扩展样板管理终端
|
||||
*
|
||||
|
|
@ -987,12 +930,16 @@ public class ExtendedAEPatternUploadUtil {
|
|||
return false;
|
||||
}
|
||||
|
||||
// 获取 AE 网络
|
||||
IGridNode node = menu.getNetworkNode();
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
IGrid grid = node.getGrid();
|
||||
// 获取 AE 网络(1.21 经由 AEBaseMenu target + IActionHost)
|
||||
IGrid grid = null;
|
||||
try {
|
||||
if (menu instanceof AEBaseMenu abm) {
|
||||
Object target = abm.getTarget();
|
||||
if (target instanceof IActionHost host && host.getActionableNode() != null) {
|
||||
grid = host.getActionableNode().getGrid();
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {}
|
||||
if (grid == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1131,10 +1078,14 @@ public class ExtendedAEPatternUploadUtil {
|
|||
List<PatternContainer> list = new ArrayList<>();
|
||||
if (menu == null) return list;
|
||||
try {
|
||||
IGridNode node = menu.getNetworkNode();
|
||||
if (node == null) return list;
|
||||
IGrid grid = node.getGrid();
|
||||
if (grid == null) return list;
|
||||
IGrid grid = null;
|
||||
if (menu instanceof AEBaseMenu abm) {
|
||||
Object target = abm.getTarget();
|
||||
if (target instanceof IActionHost host && host.getActionableNode() != null) {
|
||||
grid = host.getActionableNode().getGrid();
|
||||
}
|
||||
}
|
||||
if (grid == null) return list;
|
||||
for (var machineClass : grid.getMachineClasses()) {
|
||||
if (PatternContainer.class.isAssignableFrom(machineClass)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user