网络包all

This commit is contained in:
GaLicn 2025-09-06 14:33:26 +08:00
parent a18614ca7b
commit 6d4f806fcd
6 changed files with 110 additions and 192 deletions

View File

@ -5,7 +5,7 @@ import appeng.api.implementations.menuobjects.ItemMenuHost;
import appeng.helpers.WirelessTerminalMenuHost; import appeng.helpers.WirelessTerminalMenuHost;
import appeng.items.tools.powered.WirelessTerminalItem; import appeng.items.tools.powered.WirelessTerminalItem;
import appeng.menu.MenuOpener; import appeng.menu.MenuOpener;
import appeng.menu.locator.MenuLocator; import appeng.menu.locator.MenuHostLocator;
import appeng.menu.me.common.MEStorageMenu; import appeng.menu.me.common.MEStorageMenu;
import com.extendedae_plus.menu.host.CuriosWTMenuHost; import com.extendedae_plus.menu.host.CuriosWTMenuHost;
import com.extendedae_plus.menu.host.CuriosWirelessTerminalMenuHost; import com.extendedae_plus.menu.host.CuriosWirelessTerminalMenuHost;
@ -23,7 +23,7 @@ import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
* 适配 Curios 槽位的自定义 MenuLocator * 适配 Curios 槽位的自定义 MenuLocator
* 通过 slotId + index 在两端查找 Curios 实际物品引用确保 NBT 变化如耗电能持久化 * 通过 slotId + index 在两端查找 Curios 实际物品引用确保 NBT 变化如耗电能持久化
*/ */
public record CuriosItemLocator(String slotId, int index) implements MenuLocator { public record CuriosItemLocator(String slotId, int index) implements MenuHostLocator {
@Override @Override
@Nullable @Nullable
public <T> T locate(Player player, Class<T> hostInterface) { public <T> T locate(Player player, Class<T> hostInterface) {

View File

@ -20,5 +20,9 @@ public class ModNetwork {
registrar.playToServer(CraftingMonitorOpenProviderC2SPacket.TYPE, CraftingMonitorOpenProviderC2SPacket.STREAM_CODEC, CraftingMonitorOpenProviderC2SPacket::handle); registrar.playToServer(CraftingMonitorOpenProviderC2SPacket.TYPE, CraftingMonitorOpenProviderC2SPacket.STREAM_CODEC, CraftingMonitorOpenProviderC2SPacket::handle);
registrar.playToServer(OpenProviderUiC2SPacket.TYPE, OpenProviderUiC2SPacket.STREAM_CODEC, OpenProviderUiC2SPacket::handle); registrar.playToServer(OpenProviderUiC2SPacket.TYPE, OpenProviderUiC2SPacket.STREAM_CODEC, OpenProviderUiC2SPacket::handle);
registrar.playToServer(UploadEncodedPatternToProviderC2SPacket.TYPE, UploadEncodedPatternToProviderC2SPacket.STREAM_CODEC, UploadEncodedPatternToProviderC2SPacket::handle); registrar.playToServer(UploadEncodedPatternToProviderC2SPacket.TYPE, UploadEncodedPatternToProviderC2SPacket.STREAM_CODEC, UploadEncodedPatternToProviderC2SPacket::handle);
// 新增JEI 中键打开合成界面 & 无线终端拾取方块物品
registrar.playToServer(OpenCraftFromJeiC2SPacket.TYPE, OpenCraftFromJeiC2SPacket.STREAM_CODEC, OpenCraftFromJeiC2SPacket::handle);
registrar.playToServer(PickFromWirelessC2SPacket.TYPE, PickFromWirelessC2SPacket.STREAM_CODEC, PickFromWirelessC2SPacket::handle);
registrar.playToServer(PullFromJeiOrCraftC2SPacket.TYPE, PullFromJeiOrCraftC2SPacket.STREAM_CODEC, PullFromJeiOrCraftC2SPacket::handle);
} }
} }

View File

@ -8,36 +8,39 @@ import appeng.menu.locator.MenuLocators;
import appeng.menu.me.crafting.CraftAmountMenu; import appeng.menu.me.crafting.CraftAmountMenu;
import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.menu.locator.CuriosItemLocator;
import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.WirelessTerminalLocator;
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.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent; import net.neoforged.neoforge.network.handling.IPayloadContext;
import java.util.function.Supplier;
/** /**
* C2S JEI 中键点击请求打开 AE 的下单界面 * C2S JEI 中键点击请求打开 AE 的下单界面
* 负载为一个 GenericStack物品或流体 * 负载为一个 GenericStack物品或流体
*/ */
public class OpenCraftFromJeiC2SPacket { public class OpenCraftFromJeiC2SPacket implements CustomPacketPayload {
public static final Type<OpenCraftFromJeiC2SPacket> TYPE = new Type<>(
ResourceLocation.fromNamespaceAndPath(com.extendedae_plus.ExtendedAEPlus.MODID, "open_craft_from_jei"));
public static final StreamCodec<RegistryFriendlyByteBuf, OpenCraftFromJeiC2SPacket> STREAM_CODEC = StreamCodec.of(
(buf, pkt) -> GenericStack.writeBuffer(pkt.stack, buf),
buf -> new OpenCraftFromJeiC2SPacket(GenericStack.readBuffer(buf))
);
private final GenericStack stack; private final GenericStack stack;
public OpenCraftFromJeiC2SPacket(GenericStack stack) { public OpenCraftFromJeiC2SPacket(GenericStack stack) {
this.stack = stack; this.stack = stack;
} }
public static void encode(OpenCraftFromJeiC2SPacket msg, FriendlyByteBuf buf) { @Override
GenericStack.writeBuffer(msg.stack, buf); public Type<? extends CustomPacketPayload> type() {
return TYPE;
} }
public static OpenCraftFromJeiC2SPacket decode(FriendlyByteBuf buf) { public static void handle(final OpenCraftFromJeiC2SPacket msg, final IPayloadContext ctx) {
var gs = GenericStack.readBuffer(buf); ctx.enqueueWork(() -> {
return new OpenCraftFromJeiC2SPacket(gs); if (!(ctx.player() instanceof ServerPlayer player)) return;
}
public static void handle(OpenCraftFromJeiC2SPacket msg, Supplier<NetworkEvent.Context> ctx) {
var context = ctx.get();
context.enqueueWork(() -> {
ServerPlayer player = context.getSender();
if (player == null || msg.stack == null) return; if (player == null || msg.stack == null) return;
// 仅支持 AEKey 为可合成的种类 // 仅支持 AEKey 为可合成的种类
@ -61,7 +64,7 @@ public class OpenCraftFromJeiC2SPacket {
if (!(located.stack.getItem() instanceof WirelessTerminalItem wt)) return; if (!(located.stack.getItem() instanceof WirelessTerminalItem wt)) return;
// 基本前置校验联网电量 // 基本前置校验联网电量
IGrid grid = wt.getLinkedGrid(located.stack, player.level(), player); IGrid grid = wt.getLinkedGrid(located.stack, player.level(), null);
if (grid == null) return; if (grid == null) return;
if (!wt.hasPower(player, 0.5, located.stack)) return; if (!wt.hasPower(player, 0.5, located.stack)) return;
@ -82,6 +85,5 @@ public class OpenCraftFromJeiC2SPacket {
// 未知宿主回退忽略 // 未知宿主回退忽略
} }
}); });
context.setPacketHandled(true);
} }
} }

View File

@ -10,23 +10,39 @@ import appeng.items.tools.powered.WirelessTerminalItem;
import appeng.me.helpers.PlayerSource; import appeng.me.helpers.PlayerSource;
import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.WirelessTerminalLocator;
import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal; import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal;
import de.mari_023.ae2wtlib.terminal.WTMenuHost;
import de.mari_023.ae2wtlib.wut.WTDefinition;
import de.mari_023.ae2wtlib.wut.WUTHandler;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; 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.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.NetworkEvent; import net.neoforged.neoforge.network.handling.IPayloadContext;
import java.util.function.Supplier; public class PickFromWirelessC2SPacket implements CustomPacketPayload {
public static final Type<PickFromWirelessC2SPacket> TYPE = new Type<>(
ResourceLocation.fromNamespaceAndPath(com.extendedae_plus.ExtendedAEPlus.MODID, "pick_from_wireless"));
public static final StreamCodec<RegistryFriendlyByteBuf, PickFromWirelessC2SPacket> STREAM_CODEC = StreamCodec.of(
(buf, pkt) -> {
buf.writeBlockPos(pkt.pos);
buf.writeEnum(pkt.face);
buf.writeDouble(pkt.hitLoc.x);
buf.writeDouble(pkt.hitLoc.y);
buf.writeDouble(pkt.hitLoc.z);
},
buf -> new PickFromWirelessC2SPacket(
buf.readBlockPos(),
buf.readEnum(Direction.class),
new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble())
)
);
public class PickFromWirelessC2SPacket {
private final BlockPos pos; private final BlockPos pos;
private final Direction face; private final Direction face;
private final Vec3 hitLoc; private final Vec3 hitLoc;
@ -37,101 +53,41 @@ public class PickFromWirelessC2SPacket {
this.hitLoc = hitLoc; this.hitLoc = hitLoc;
} }
public static void encode(PickFromWirelessC2SPacket msg, FriendlyByteBuf buf) { @Override
buf.writeBlockPos(msg.pos); public Type<? extends CustomPacketPayload> type() {
buf.writeEnum(msg.face); return TYPE;
buf.writeDouble(msg.hitLoc.x);
buf.writeDouble(msg.hitLoc.y);
buf.writeDouble(msg.hitLoc.z);
} }
public static PickFromWirelessC2SPacket decode(FriendlyByteBuf buf) { public static void handle(final PickFromWirelessC2SPacket msg, final IPayloadContext ctx) {
BlockPos pos = buf.readBlockPos(); ctx.enqueueWork(() -> {
Direction face = buf.readEnum(Direction.class); if (!(ctx.player() instanceof ServerPlayer player)) return;
double x = buf.readDouble(); if (player.isCreative()) return;
double y = buf.readDouble();
double z = buf.readDouble();
return new PickFromWirelessC2SPacket(pos, face, new Vec3(x, y, z));
}
public static void handle(PickFromWirelessC2SPacket msg, Supplier<NetworkEvent.Context> ctx) {
NetworkEvent.Context context = ctx.get();
context.enqueueWork(() -> {
ServerPlayer player = context.getSender();
if (player == null || player.isCreative()) {
return;
}
ServerLevel level = player.serverLevel(); ServerLevel level = player.serverLevel();
BlockState state = level.getBlockState(msg.pos); BlockState state = level.getBlockState(msg.pos);
if (state == null || state.isAir()) { if (state == null || state.isAir()) return;
return;
}
// 服务端权威定位玩家任意槽位的无线终端 Curios // 服务端权威定位玩家任意槽位的无线终端 Curios
LocatedTerminal located = WirelessTerminalLocator.find(player); LocatedTerminal located = WirelessTerminalLocator.find(player);
ItemStack terminal = located.stack; ItemStack terminal = located.stack;
if (terminal.isEmpty()) { if (terminal.isEmpty()) return;
return;
}
IGrid grid; IGrid grid;
boolean usedWtHost = false; // 统一走 AE2 原生路径处理包含 Curios 情况
// 若来自 Curios优先通过 ae2wtlib WTMenuHost 获取量子桥网络绕过距离限制 WirelessCraftingTerminalItem wct = terminal.getItem() instanceof WirelessCraftingTerminalItem c ? c : null;
String curiosSlotId = located.getCuriosSlotId(); WirelessTerminalItem wt = wct != null ? wct : (terminal.getItem() instanceof WirelessTerminalItem t ? t : null);
int curiosIndex = located.getCuriosIndex(); if (wt == null) return;
WTMenuHost wtHost = null; grid = wt.getLinkedGrid(terminal, level, null);
if (curiosSlotId != null && curiosIndex >= 0) { if (grid == null) return;
String current = WUTHandler.getCurrentTerminal(terminal); if (!wt.hasPower(player, 0.5, terminal)) return;
WTDefinition def = WUTHandler.wirelessTerminals.get(current);
if (def != null) {
wtHost = def.wTMenuHostFactory().create(player, null, terminal, (p, sub) -> {});
if (wtHost != null) {
var node = wtHost.getActionableNode();
if (node != null) {
grid = node.getGrid();
if (grid == null) {
return;
}
// 通过 WTMenuHost 的电力处理以兼容量子卡补能
if (!wtHost.drainPower()) {
return;
}
usedWtHost = true;
} else {
return;
}
} else {
return;
}
} else {
return;
}
} else {
// Curios AE2 原生路径处理
WirelessCraftingTerminalItem wct = terminal.getItem() instanceof WirelessCraftingTerminalItem c ? c : null;
WirelessTerminalItem wt = wct != null ? wct : (terminal.getItem() instanceof WirelessTerminalItem t ? t : null);
if (wt == null) {
return;
}
grid = wt.getLinkedGrid(terminal, level, player);
if (grid == null) {
return;
}
if (!wt.hasPower(player, 0.5, terminal)) {
return;
}
}
// 计算 pick 对应的物品使用客户端实际命中位置保证多部件方块AE2 CableBus/部件能返回正确克隆物品 // 计算 pick 对应的物品使用客户端实际命中位置保证多部件方块能返回正确克隆物品
BlockHitResult bhr = new BlockHitResult(msg.hitLoc, msg.face, msg.pos, true); BlockHitResult bhr = new BlockHitResult(msg.hitLoc, msg.face, msg.pos, true);
ItemStack picked = state.getBlock().getCloneItemStack(state, bhr, level, msg.pos, player); ItemStack picked = state.getBlock().getCloneItemStack(state, bhr, level, msg.pos, player);
if (picked.isEmpty()) { if (picked.isEmpty()) {
// 兜底用方块本身
picked = state.getBlock().asItem().getDefaultInstance(); picked = state.getBlock().asItem().getDefaultInstance();
} }
if (picked.isEmpty()) { if (picked.isEmpty()) return;
return;
}
int targetMax = picked.getMaxStackSize(); int targetMax = picked.getMaxStackSize();
AEItemKey targetKey = AEItemKey.of(picked); AEItemKey targetKey = AEItemKey.of(picked);
@ -142,10 +98,6 @@ public class PickFromWirelessC2SPacket {
ItemStack inHand = player.getMainHandItem(); ItemStack inHand = player.getMainHandItem();
var inv = player.getInventory(); var inv = player.getInventory();
// 决定放置目标
// 1) 若主手为空 -> 放主手空间为整组
// 2) 若主手为同一物品且未满 -> 合并到主手空间为主手剩余空间
// 3) 其他情况主手不为空且不是同物品-> 放入背包空槽空间为整组
boolean handIsSameItem = !inHand.isEmpty() && AEItemKey.of(inHand).equals(targetKey); boolean handIsSameItem = !inHand.isEmpty() && AEItemKey.of(inHand).equals(targetKey);
boolean placeToMainHand = inHand.isEmpty() || (handIsSameItem && inHand.getCount() < inHand.getMaxStackSize()); boolean placeToMainHand = inHand.isEmpty() || (handIsSameItem && inHand.getCount() < inHand.getMaxStackSize());
@ -154,56 +106,41 @@ public class PickFromWirelessC2SPacket {
space = inHand.isEmpty() ? targetMax : Math.min(targetMax, inHand.getMaxStackSize() - inHand.getCount()); space = inHand.isEmpty() ? targetMax : Math.min(targetMax, inHand.getMaxStackSize() - inHand.getCount());
} else { } else {
int free = inv.getFreeSlot(); int free = inv.getFreeSlot();
if (free == -1) { if (free == -1) return;
return; // 背包已满不进行拉取
}
space = targetMax; space = targetMax;
} }
if (space <= 0) { if (space <= 0) return;
return;
}
long extracted = StorageHelper.poweredExtraction(energy, storage, targetKey, space, new PlayerSource(player)); long extracted = StorageHelper.poweredExtraction(energy, storage, targetKey, space, new PlayerSource(player));
if (extracted <= 0) { if (extracted <= 0) return;
return;
}
if (placeToMainHand) { if (placeToMainHand) {
if (inHand.isEmpty()) { if (inHand.isEmpty()) {
inv.setItem(inv.selected, targetKey.toStack((int) extracted)); inv.setItem(inv.selected, targetKey.toStack((int) extracted));
} else { } else {
// 合并到主手
int add = (int) Math.min(extracted, inHand.getMaxStackSize() - inHand.getCount()); int add = (int) Math.min(extracted, inHand.getMaxStackSize() - inHand.getCount());
if (add > 0) { if (add > 0) {
inHand.grow(add); inHand.grow(add);
inv.setItem(inv.selected, inHand); // 写回以确保同步 inv.setItem(inv.selected, inHand);
} }
} }
} else { } else {
int free = inv.getFreeSlot(); int free = inv.getFreeSlot();
if (free == -1) { if (free == -1) {
// 理论上不会发生上面已判断为安全起见将提取物退回网络
StorageHelper.poweredInsert(energy, storage, targetKey, extracted, new PlayerSource(player)); StorageHelper.poweredInsert(energy, storage, targetKey, extracted, new PlayerSource(player));
return; return;
} }
inv.setItem(free, targetKey.toStack((int) extracted)); inv.setItem(free, targetKey.toStack((int) extracted));
} }
if (usedWtHost) { WirelessCraftingTerminalItem wct2 = terminal.getItem() instanceof WirelessCraftingTerminalItem c2 ? c2 : null;
// WTMenuHost 已在 drainPower 中处理能量消耗/回充此处不重复扣除 WirelessTerminalItem wt2 = wct2 != null ? wct2 : (terminal.getItem() instanceof WirelessTerminalItem t2 ? t2 : null);
} else { if (wt2 != null) {
// 原生 AE2 扣能 wt2.usePower(player, Math.max(0.5, extracted * 0.05), terminal);
WirelessCraftingTerminalItem wct2 = terminal.getItem() instanceof WirelessCraftingTerminalItem c2 ? c2 : null;
WirelessTerminalItem wt2 = wct2 != null ? wct2 : (terminal.getItem() instanceof WirelessTerminalItem t2 ? t2 : null);
if (wt2 != null) {
wt2.usePower(player, Math.max(0.5, extracted * 0.05), terminal);
}
} }
// 确保写回若位于 Curios 等需要显式写回的容器
located.commit(); located.commit();
player.containerMenu.broadcastChanges(); player.containerMenu.broadcastChanges();
}); });
context.setPacketHandled(true);
} }
} }

View File

@ -15,81 +15,60 @@ import appeng.menu.me.crafting.CraftAmountMenu;
import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.menu.locator.CuriosItemLocator;
import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.WirelessTerminalLocator;
import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal; import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal;
import de.mari_023.ae2wtlib.terminal.WTMenuHost; import net.minecraft.network.RegistryFriendlyByteBuf;
import de.mari_023.ae2wtlib.wut.WTDefinition; import net.minecraft.network.codec.StreamCodec;
import de.mari_023.ae2wtlib.wut.WUTHandler; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent; import net.neoforged.neoforge.network.handling.IPayloadContext;
import java.util.function.Supplier; public class PullFromJeiOrCraftC2SPacket implements CustomPacketPayload {
public static final Type<PullFromJeiOrCraftC2SPacket> TYPE = new Type<>(
ResourceLocation.fromNamespaceAndPath(com.extendedae_plus.ExtendedAEPlus.MODID, "pull_from_jei_or_craft"));
public static final StreamCodec<RegistryFriendlyByteBuf, PullFromJeiOrCraftC2SPacket> STREAM_CODEC = StreamCodec.of(
(buf, pkt) -> GenericStack.writeBuffer(pkt.stack, buf),
buf -> new PullFromJeiOrCraftC2SPacket(GenericStack.readBuffer(buf))
);
public class PullFromJeiOrCraftC2SPacket {
private final GenericStack stack; private final GenericStack stack;
public PullFromJeiOrCraftC2SPacket(GenericStack stack) { public PullFromJeiOrCraftC2SPacket(GenericStack stack) {
this.stack = stack; this.stack = stack;
} }
public static void encode(PullFromJeiOrCraftC2SPacket msg, FriendlyByteBuf buf) { @Override
GenericStack.writeBuffer(msg.stack, buf); public Type<? extends CustomPacketPayload> type() {
return TYPE;
} }
public static PullFromJeiOrCraftC2SPacket decode(FriendlyByteBuf buf) { public static void handle(final PullFromJeiOrCraftC2SPacket msg, final IPayloadContext ctx) {
var gs = GenericStack.readBuffer(buf); ctx.enqueueWork(() -> {
return new PullFromJeiOrCraftC2SPacket(gs); if (!(ctx.player() instanceof ServerPlayer player)) return;
} if (msg.stack == null) return;
public static void handle(PullFromJeiOrCraftC2SPacket msg, Supplier<NetworkEvent.Context> ctx) {
NetworkEvent.Context context = ctx.get();
context.enqueueWork(() -> {
ServerPlayer player = context.getSender();
if (player == null || msg.stack == null) return;
// 仅处理物品
AEKey what = msg.stack.what(); AEKey what = msg.stack.what();
if (!(what instanceof AEItemKey itemKey)) return; if (!(what instanceof AEItemKey itemKey)) return;
// 定位玩家持有/Curios 的无线终端
LocatedTerminal located = WirelessTerminalLocator.find(player); LocatedTerminal located = WirelessTerminalLocator.find(player);
ItemStack terminal = located.stack; ItemStack terminal = located.stack;
if (terminal.isEmpty()) return; if (terminal.isEmpty()) return;
IGrid grid; IGrid grid;
boolean usedWtHost = false; // 统一 AE2 原生路径
// Curios 情况优先通过 WTMenuHost 获取网络并由其处理能量 ServerLevel level = player.serverLevel();
String curiosSlotId = located.getCuriosSlotId(); WirelessCraftingTerminalItem wct = terminal.getItem() instanceof WirelessCraftingTerminalItem c ? c : null;
int curiosIndex = located.getCuriosIndex(); WirelessTerminalItem wt = wct != null ? wct : (terminal.getItem() instanceof WirelessTerminalItem t ? t : null);
WTMenuHost wtHost = null; if (wt == null) return;
if (curiosSlotId != null && curiosIndex >= 0) { grid = wt.getLinkedGrid(terminal, level, null);
String current = WUTHandler.getCurrentTerminal(terminal); if (grid == null) return;
WTDefinition def = WUTHandler.wirelessTerminals.get(current); if (!wt.hasPower(player, 0.5, terminal)) return;
if (def == null) return;
wtHost = def.wTMenuHostFactory().create(player, null, terminal, (p, sub) -> {});
if (wtHost == null) return;
var node = wtHost.getActionableNode();
if (node == null) return;
grid = node.getGrid();
if (grid == null) return;
if (!wtHost.drainPower()) return;
usedWtHost = true;
} else {
// 原生路径
ServerLevel level = player.serverLevel();
WirelessCraftingTerminalItem wct = terminal.getItem() instanceof WirelessCraftingTerminalItem c ? c : null;
WirelessTerminalItem wt = wct != null ? wct : (terminal.getItem() instanceof WirelessTerminalItem t ? t : null);
if (wt == null) return;
grid = wt.getLinkedGrid(terminal, level, player);
if (grid == null) return;
if (!wt.hasPower(player, 0.5, terminal)) return;
}
// 仅放入背包空槽位
var inv = player.getInventory(); var inv = player.getInventory();
int free = inv.getFreeSlot(); int free = inv.getFreeSlot();
if (free == -1) return; // 背包已满 if (free == -1) return;
int targetMax = itemKey.toStack(1).getMaxStackSize(); int targetMax = itemKey.toStack(1).getMaxStackSize();
IEnergyService energy = grid.getEnergyService(); IEnergyService energy = grid.getEnergyService();
@ -98,23 +77,21 @@ public class PullFromJeiOrCraftC2SPacket {
long extracted = StorageHelper.poweredExtraction(energy, storage, itemKey, targetMax, new PlayerSource(player)); long extracted = StorageHelper.poweredExtraction(energy, storage, itemKey, targetMax, new PlayerSource(player));
if (extracted > 0) { if (extracted > 0) {
inv.setItem(free, itemKey.toStack((int) extracted)); inv.setItem(free, itemKey.toStack((int) extracted));
if (!usedWtHost) { WirelessCraftingTerminalItem wct2 = terminal.getItem() instanceof WirelessCraftingTerminalItem c2 ? c2 : null;
// 扣能 PickFromWirelessC2SPacket 保持一致 WirelessTerminalItem wt2 = wct2 != null ? wct2 : (terminal.getItem() instanceof WirelessTerminalItem t2 ? t2 : null);
WirelessCraftingTerminalItem wct2 = terminal.getItem() instanceof WirelessCraftingTerminalItem c2 ? c2 : null; if (wt2 != null) {
WirelessTerminalItem wt2 = wct2 != null ? wct2 : (terminal.getItem() instanceof WirelessTerminalItem t2 ? t2 : null); wt2.usePower(player, Math.max(0.5, extracted * 0.05), terminal);
if (wt2 != null) {
wt2.usePower(player, Math.max(0.5, extracted * 0.05), terminal);
}
} }
located.commit(); located.commit();
player.containerMenu.broadcastChanges(); player.containerMenu.broadcastChanges();
return; return;
} }
// 无库存时若可合成则打开下单界面
var craftingService = grid.getCraftingService(); var craftingService = grid.getCraftingService();
if (!craftingService.isCraftable(what)) return; if (!craftingService.isCraftable(what)) return;
String curiosSlotId = located.getCuriosSlotId();
int curiosIndex = located.getCuriosIndex();
if (curiosSlotId != null && curiosIndex >= 0) { if (curiosSlotId != null && curiosIndex >= 0) {
CraftAmountMenu.open(player, new CuriosItemLocator(curiosSlotId, curiosIndex), what, 1); CraftAmountMenu.open(player, new CuriosItemLocator(curiosSlotId, curiosIndex), what, 1);
} else { } else {
@ -127,6 +104,5 @@ public class PullFromJeiOrCraftC2SPacket {
} }
} }
}); });
context.setPacketHandled(true);
} }
} }

View File

@ -296,7 +296,6 @@ public class ExtendedAEPatternUploadUtil {
/** /**
* 仅使用反射的 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;