增加鼠标中间拉取ae网络中物品功能,并且适配curios饰品槽
This commit is contained in:
parent
687652daf8
commit
b5cb61a160
|
|
@ -85,6 +85,9 @@ dependencies {
|
|||
|
||||
annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor"
|
||||
|
||||
//curios
|
||||
modRuntimeOnly "curse.maven:curios-309927:${curios_version}"
|
||||
modCompileOnly "curse.maven:curios-309927:${curios_version}"
|
||||
|
||||
// Runtime test
|
||||
modRuntimeOnly "curse.maven:architectury-api-419699:${architectury_version}"
|
||||
|
|
@ -95,7 +98,6 @@ dependencies {
|
|||
modRuntimeOnly "curse.maven:projecte-226410:${projecte_version}"
|
||||
modRuntimeOnly "curse.maven:appliede-1009940:${appliede_version}"
|
||||
modRuntimeOnly "curse.maven:cloth-config-348521:5729105"
|
||||
modRuntimeOnly "curse.maven:curios-309927:${curios_version}"
|
||||
//extendedAE
|
||||
modImplementation files('libs/ExtendedAE-1.20-1.4.2-forge.jar')
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.extendedae_plus.init.ModBlocks;
|
|||
import com.extendedae_plus.init.ModBlockEntities;
|
||||
import com.extendedae_plus.init.ModItems;
|
||||
import com.extendedae_plus.init.ModCreativeTabs;
|
||||
import com.extendedae_plus.network.ModNetwork;
|
||||
|
||||
/**
|
||||
* ExtendedAE Plus 主mod类
|
||||
|
|
@ -43,6 +44,7 @@ public class ExtendedAEPlus {
|
|||
* 通用初始化设置
|
||||
*/
|
||||
private void commonSetup(final FMLCommonSetupEvent event) {
|
||||
// 现已改用 ExtendedAE 的 EPPNetworkHandler + CGenericPacket,无需自定义网络初始化
|
||||
// 注册本模组网络通道与数据包
|
||||
event.enqueueWork(ModNetwork::register);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package com.extendedae_plus.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
|
||||
import com.extendedae_plus.network.ModNetwork;
|
||||
import com.extendedae_plus.network.PickFromWirelessC2SPacket;
|
||||
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
public class PickFromWirelessMixin {
|
||||
@Shadow public LocalPlayer player;
|
||||
@Shadow public HitResult hitResult;
|
||||
|
||||
@Inject(method = "pickBlock", at = @At("HEAD"), cancellable = true)
|
||||
private void extendedae_plus$pickFromAeWireless(CallbackInfo ci) {
|
||||
if (this.player == null || this.hitResult == null || this.hitResult.getType() != HitResult.Type.BLOCK) {
|
||||
return;
|
||||
}
|
||||
// 仅生存模式
|
||||
GameType type = Minecraft.getInstance().gameMode != null ? Minecraft.getInstance().gameMode.getPlayerMode() : null;
|
||||
if (type == null || type.isCreative()) {
|
||||
return;
|
||||
}
|
||||
// 发送到服务端处理
|
||||
BlockHitResult bhr = (BlockHitResult) this.hitResult;
|
||||
ModNetwork.CHANNEL.sendToServer(new PickFromWirelessC2SPacket(bhr.getBlockPos(), bhr.getDirection()));
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
30
src/main/java/com/extendedae_plus/network/ModNetwork.java
Normal file
30
src/main/java/com/extendedae_plus/network/ModNetwork.java
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package com.extendedae_plus.network;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
|
||||
public class ModNetwork {
|
||||
private static final String PROTOCOL_VERSION = "1";
|
||||
public static final SimpleChannel CHANNEL = NetworkRegistry.ChannelBuilder
|
||||
.named(new ResourceLocation(ExtendedAEPlus.MODID, "main"))
|
||||
.networkProtocolVersion(() -> PROTOCOL_VERSION)
|
||||
.clientAcceptedVersions(PROTOCOL_VERSION::equals)
|
||||
.serverAcceptedVersions(PROTOCOL_VERSION::equals)
|
||||
.simpleChannel();
|
||||
|
||||
private static int id = 0;
|
||||
|
||||
public static void register() {
|
||||
CHANNEL.messageBuilder(PickFromWirelessC2SPacket.class, nextId(), NetworkDirection.PLAY_TO_SERVER)
|
||||
.encoder(PickFromWirelessC2SPacket::encode)
|
||||
.decoder(PickFromWirelessC2SPacket::decode)
|
||||
.consumerNetworkThread(PickFromWirelessC2SPacket::handle)
|
||||
.add();
|
||||
}
|
||||
|
||||
private static int nextId() { return id++; }
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
package com.extendedae_plus.network;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.storage.MEStorage;
|
||||
import appeng.api.storage.StorageHelper;
|
||||
import appeng.api.stacks.AEItemKey;
|
||||
import appeng.api.networking.energy.IEnergyService;
|
||||
import appeng.me.helpers.PlayerSource;
|
||||
import appeng.items.tools.powered.WirelessTerminalItem;
|
||||
import com.extendedae_plus.util.WirelessTerminalLocator;
|
||||
import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal;
|
||||
|
||||
public class PickFromWirelessC2SPacket {
|
||||
private final BlockPos pos;
|
||||
private final Direction face;
|
||||
|
||||
public PickFromWirelessC2SPacket(BlockPos pos, Direction face) {
|
||||
this.pos = pos;
|
||||
this.face = face;
|
||||
}
|
||||
|
||||
public static void encode(PickFromWirelessC2SPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeBlockPos(msg.pos);
|
||||
buf.writeEnum(msg.face);
|
||||
}
|
||||
|
||||
public static PickFromWirelessC2SPacket decode(FriendlyByteBuf buf) {
|
||||
BlockPos pos = buf.readBlockPos();
|
||||
Direction face = buf.readEnum(Direction.class);
|
||||
return new PickFromWirelessC2SPacket(pos, face);
|
||||
}
|
||||
|
||||
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();
|
||||
BlockState state = level.getBlockState(msg.pos);
|
||||
if (state == null || state.isAir()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 服务端权威:定位玩家任意槽位的无线终端(含 Curios)
|
||||
LocatedTerminal located = WirelessTerminalLocator.find(player);
|
||||
ItemStack terminal = located.stack;
|
||||
WirelessTerminalItem wt = terminal.getItem() instanceof WirelessTerminalItem w ? w : null;
|
||||
if (wt == null || terminal.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 校验网络与电量
|
||||
IGrid grid = wt.getLinkedGrid(terminal, level, player);
|
||||
if (grid == null) {
|
||||
return;
|
||||
}
|
||||
if (!wt.hasPower(player, 0.5, terminal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算 pick 对应的物品
|
||||
BlockHitResult bhr = new BlockHitResult(player.position(), msg.face, msg.pos, true);
|
||||
ItemStack picked = state.getBlock().getCloneItemStack(state, bhr, level, msg.pos, player);
|
||||
if (picked.isEmpty()) {
|
||||
// 兜底用方块本身
|
||||
picked = state.getBlock().asItem().getDefaultInstance();
|
||||
}
|
||||
if (picked.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int targetMax = picked.getMaxStackSize();
|
||||
AEItemKey targetKey = AEItemKey.of(picked);
|
||||
|
||||
IEnergyService energy = grid.getEnergyService();
|
||||
MEStorage storage = grid.getStorageService().getInventory();
|
||||
|
||||
ItemStack inHand = player.getMainHandItem();
|
||||
|
||||
// 若主手有物品:尝试将其移动到玩家背包的空槽位;若没有空位则中止
|
||||
if (!inHand.isEmpty()) {
|
||||
var inv = player.getInventory();
|
||||
int free = inv.getFreeSlot();
|
||||
if (free == -1) {
|
||||
return; // 背包已满,不进行拉取
|
||||
}
|
||||
// 将主手整组移动到空槽位
|
||||
inv.setItem(free, inHand.copy());
|
||||
inv.setItem(inv.selected, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
// 现在主手应为空:拉取目标物品,尽量填满一组
|
||||
int space = targetMax; // 主手为空,目标为一整组
|
||||
long extracted = StorageHelper.poweredExtraction(energy, storage, targetKey, space, new PlayerSource(player));
|
||||
if (extracted <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.getInventory().setItem(player.getInventory().selected, targetKey.toStack((int) extracted));
|
||||
wt.usePower(player, Math.max(0.5, extracted * 0.05), terminal);
|
||||
// 确保写回(若位于 Curios 等需要显式写回的容器)
|
||||
located.commit();
|
||||
player.containerMenu.broadcastChanges();
|
||||
});
|
||||
context.setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
package com.extendedae_plus.util;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
|
||||
import appeng.items.tools.powered.WirelessTerminalItem;
|
||||
|
||||
// Curios API (软依赖)
|
||||
import top.theillusivec4.curios.api.CuriosApi;
|
||||
import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
|
||||
import top.theillusivec4.curios.api.type.inventory.IDynamicStackHandler;
|
||||
import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler;
|
||||
|
||||
/**
|
||||
* 定位玩家身上的无线终端:
|
||||
* - 原版槽位:主手、副手、盔甲、背包
|
||||
* - 若加载了 Curios:遍历所有饰品槽
|
||||
* 返回一个可写回的结果,以便能量消耗等 NBT 变更能持久化。
|
||||
*/
|
||||
public final class WirelessTerminalLocator {
|
||||
private WirelessTerminalLocator() {}
|
||||
|
||||
public static final class LocatedTerminal {
|
||||
public final ItemStack stack;
|
||||
private final Consumer<ItemStack> setter;
|
||||
|
||||
public LocatedTerminal(ItemStack stack, Consumer<ItemStack> setter) {
|
||||
this.stack = stack;
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
public void set(ItemStack newStack) { this.setter.accept(newStack); }
|
||||
public void commit() { this.setter.accept(this.stack); }
|
||||
public boolean isEmpty() { return this.stack == null || this.stack.isEmpty(); }
|
||||
}
|
||||
|
||||
public static LocatedTerminal find(Player player) {
|
||||
if (player == null) return new LocatedTerminal(ItemStack.EMPTY, s -> {});
|
||||
|
||||
// 1) 原版槽位
|
||||
var inv = player.getInventory();
|
||||
int size = inv.getContainerSize();
|
||||
for (int i = 0; i < size; i++) {
|
||||
ItemStack st = inv.getItem(i);
|
||||
if (!st.isEmpty() && st.getItem() instanceof WirelessTerminalItem) {
|
||||
final int slot = i;
|
||||
return new LocatedTerminal(st, (ns) -> inv.setItem(slot, ns));
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Curios 饰品槽(若已加载)
|
||||
if (ModList.get().isLoaded("curios")) {
|
||||
try {
|
||||
// Curios 1.20.x: 通过 CuriosApi.getCuriosInventory 获取 LazyOptional
|
||||
var resolved = CuriosApi.getCuriosInventory(player).resolve();
|
||||
if (resolved.isPresent()) {
|
||||
ICuriosItemHandler handler = resolved.get();
|
||||
for (ICurioStacksHandler stacksHandler : handler.getCurios().values()) {
|
||||
IDynamicStackHandler stacks = stacksHandler.getStacks();
|
||||
int slots = stacks.getSlots();
|
||||
for (int i = 0; i < slots; i++) {
|
||||
ItemStack st = stacks.getStackInSlot(i);
|
||||
if (!st.isEmpty() && st.getItem() instanceof WirelessTerminalItem) {
|
||||
final int slot = i;
|
||||
return new LocatedTerminal(st, (ns) -> stacks.setStackInSlot(slot, ns));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
// 若 Curios API 在运行时不可用或发生异常,则忽略并返回空
|
||||
}
|
||||
}
|
||||
|
||||
return new LocatedTerminal(ItemStack.EMPTY, s -> {});
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,8 @@
|
|||
"GuiExPatternProviderMixin",
|
||||
"SlotGridLayoutMixin",
|
||||
"GuiExPatternTerminalMixin",
|
||||
"HighlightButtonMixin"
|
||||
"HighlightButtonMixin",
|
||||
"PickFromWirelessMixin"
|
||||
],
|
||||
"mixins": [
|
||||
"ContainerExPatternProviderMixin",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user