为编码样板添加 EMI 配方 ID 记录
在通过 EMI 填充配方并编码为样板时,记录下对应的 EMI 配方 ID。 - 当使用 EMI 的配方填充功能时,会发送一个包含配方 ID 的数据包到服务端。 - 在编码样板时,将此配方 ID 存储在样板物品的 NBT 数据中。 - 在样板的悬浮提示中显示其关联的配方名称,以便追溯。
This commit is contained in:
parent
7636fff3b4
commit
4dab5b82ef
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.extendedae_plus.api.upload;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public interface IPatternEncodingIdSync {
|
||||||
|
/**
|
||||||
|
* 由客户端发送的编码指令附带的 recipe id。
|
||||||
|
*/
|
||||||
|
void eap$clientRecipeIdUpload(ResourceLocation id);
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.extendedae_plus.init;
|
||||||
import com.extendedae_plus.ExtendedAEPlus;
|
import com.extendedae_plus.ExtendedAEPlus;
|
||||||
import com.extendedae_plus.network.*;
|
import com.extendedae_plus.network.*;
|
||||||
import com.extendedae_plus.network.packet.EAPConfigButtonPacket;
|
import com.extendedae_plus.network.packet.EAPConfigButtonPacket;
|
||||||
|
import com.extendedae_plus.network.upload.EncodeWithRecipeIdC2SPacket;
|
||||||
import com.extendedae_plus.network.upload.EncodeWithShiftFlagC2SPacket;
|
import com.extendedae_plus.network.upload.EncodeWithShiftFlagC2SPacket;
|
||||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
|
|
||||||
|
|
@ -26,6 +27,7 @@ public class ModNetwork {
|
||||||
registrar.playToServer(CreateAndUploadPatternC2SPacket.TYPE, CreateAndUploadPatternC2SPacket.STREAM_CODEC, CreateAndUploadPatternC2SPacket::handle);
|
registrar.playToServer(CreateAndUploadPatternC2SPacket.TYPE, CreateAndUploadPatternC2SPacket.STREAM_CODEC, CreateAndUploadPatternC2SPacket::handle);
|
||||||
registrar.playToServer(CancelPendingPatternC2SPacket.TYPE,CancelPendingPatternC2SPacket.STREAM_CODEC,CancelPendingPatternC2SPacket::handle);
|
registrar.playToServer(CancelPendingPatternC2SPacket.TYPE,CancelPendingPatternC2SPacket.STREAM_CODEC,CancelPendingPatternC2SPacket::handle);
|
||||||
registrar.playToServer(EncodeWithShiftFlagC2SPacket.TYPE, EncodeWithShiftFlagC2SPacket.STREAM_CODEC, EncodeWithShiftFlagC2SPacket::handle);
|
registrar.playToServer(EncodeWithShiftFlagC2SPacket.TYPE, EncodeWithShiftFlagC2SPacket.STREAM_CODEC, EncodeWithShiftFlagC2SPacket::handle);
|
||||||
|
registrar.playToServer(EncodeWithRecipeIdC2SPacket.TYPE, EncodeWithRecipeIdC2SPacket.STREAM_CODEC, EncodeWithRecipeIdC2SPacket::handle);
|
||||||
// 新增:JEI 中键打开合成界面 & 无线终端拾取方块物品
|
// 新增:JEI 中键打开合成界面 & 无线终端拾取方块物品
|
||||||
registrar.playToServer(com.extendedae_plus.network.OpenCraftFromJeiC2SPacket.TYPE,
|
registrar.playToServer(com.extendedae_plus.network.OpenCraftFromJeiC2SPacket.TYPE,
|
||||||
com.extendedae_plus.network.OpenCraftFromJeiC2SPacket.STREAM_CODEC,
|
com.extendedae_plus.network.OpenCraftFromJeiC2SPacket.STREAM_CODEC,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.extendedae_plus.config.ModConfigs;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
|
@ -28,6 +29,12 @@ public class EncodedPatternItemMixin {
|
||||||
String name = tag.getString("encodePlayer");
|
String name = tag.getString("encodePlayer");
|
||||||
lines.add(Component.translatable("extendedae_plus.pattern.hovertext.player", name).withStyle(ChatFormatting.GRAY));
|
lines.add(Component.translatable("extendedae_plus.pattern.hovertext.player", name).withStyle(ChatFormatting.GRAY));
|
||||||
}
|
}
|
||||||
|
if (tag.contains("recipeId")) {
|
||||||
|
String id = tag.getString("recipeId");
|
||||||
|
ResourceLocation location = ResourceLocation.tryParse(id);
|
||||||
|
if (location == null) return;
|
||||||
|
lines.add(Component.translatable("extendedae_plus.pattern.hovertext.player", Component.translatable("recipe." + location.getNamespace() + "." + location.getPath())).withStyle(ChatFormatting.GRAY));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,20 @@
|
||||||
package com.extendedae_plus.mixin.ae2.menu;
|
package com.extendedae_plus.mixin.ae2.menu;
|
||||||
|
|
||||||
import appeng.api.crafting.PatternDetailsHelper;
|
import appeng.api.crafting.PatternDetailsHelper;
|
||||||
|
import appeng.api.stacks.GenericStack;
|
||||||
import appeng.menu.me.items.PatternEncodingTermMenu;
|
import appeng.menu.me.items.PatternEncodingTermMenu;
|
||||||
import appeng.menu.slot.RestrictedInputSlot;
|
import appeng.menu.slot.RestrictedInputSlot;
|
||||||
import appeng.parts.encoding.EncodingMode;
|
import appeng.parts.encoding.EncodingMode;
|
||||||
|
import com.extendedae_plus.api.upload.IPatternEncodingIdSync;
|
||||||
import com.extendedae_plus.api.upload.IPatternEncodingShiftUploadSync;
|
import com.extendedae_plus.api.upload.IPatternEncodingShiftUploadSync;
|
||||||
|
import com.extendedae_plus.util.RecipeFinderUtilEMI;
|
||||||
import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
|
import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
|
||||||
import com.glodblock.github.glodium.network.packet.sync.ActionMap;
|
import com.glodblock.github.glodium.network.packet.sync.ActionMap;
|
||||||
import com.glodblock.github.glodium.network.packet.sync.IActionHolder;
|
import com.glodblock.github.glodium.network.packet.sync.IActionHolder;
|
||||||
|
import dev.emi.emi.api.recipe.EmiRecipe;
|
||||||
|
import dev.emi.emi.api.stack.EmiStack;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
@ -22,13 +28,14 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 给 AE2 的 PatternEncodingTermMenu 增加一个通用动作持有者,实现接收 EPP 的 CGenericPacket 动作。
|
* 给 AE2 的 PatternEncodingTermMenu 增加一个通用动作持有者,实现接收 EPP 的 CGenericPacket 动作。
|
||||||
* 注册动作 "upload_to_matrix":仅上传“合成图样”到 ExtendedAE 装配矩阵。
|
* 注册动作 "upload_to_matrix":仅上传“合成图样”到 ExtendedAE 装配矩阵。
|
||||||
*/
|
*/
|
||||||
@Mixin(PatternEncodingTermMenu.class)
|
@Mixin(PatternEncodingTermMenu.class)
|
||||||
public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHolder, IPatternEncodingShiftUploadSync {
|
public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHolder, IPatternEncodingShiftUploadSync, IPatternEncodingIdSync {
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final ActionMap eap$actions = ActionMap.create();
|
private final ActionMap eap$actions = ActionMap.create();
|
||||||
|
|
||||||
|
|
@ -38,6 +45,9 @@ public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHo
|
||||||
@Unique
|
@Unique
|
||||||
private boolean eap$pendingShiftUpload;
|
private boolean eap$pendingShiftUpload;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private ResourceLocation eap$pendingRecipeIdUpload;
|
||||||
|
|
||||||
@Shadow(remap = false)
|
@Shadow(remap = false)
|
||||||
private RestrictedInputSlot encodedPatternSlot;
|
private RestrictedInputSlot encodedPatternSlot;
|
||||||
|
|
||||||
|
|
@ -55,6 +65,11 @@ public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHo
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
@Override
|
||||||
|
public void eap$clientRecipeIdUpload(ResourceLocation id) {
|
||||||
|
this.eap$pendingRecipeIdUpload = id;
|
||||||
|
}
|
||||||
@Unique
|
@Unique
|
||||||
private void eap$scheduleUploadWithRetry(ServerPlayer sp, PatternEncodingTermMenu menu, int attemptsLeft) {
|
private void eap$scheduleUploadWithRetry(ServerPlayer sp, PatternEncodingTermMenu menu, int attemptsLeft) {
|
||||||
sp.server.execute(() -> {
|
sp.server.execute(() -> {
|
||||||
|
|
@ -140,7 +155,24 @@ public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHo
|
||||||
if (itemStack != null && !itemStack.isEmpty()) {
|
if (itemStack != null && !itemStack.isEmpty()) {
|
||||||
CustomData.update(DataComponents.CUSTOM_DATA, itemStack, tag -> {
|
CustomData.update(DataComponents.CUSTOM_DATA, itemStack, tag -> {
|
||||||
tag.putString("encodePlayer", this.epp$player.getGameProfile().getName());
|
tag.putString("encodePlayer", this.epp$player.getGameProfile().getName());
|
||||||
|
if (this.eap$pendingRecipeIdUpload !=null) {
|
||||||
|
EmiRecipe recipe = RecipeFinderUtilEMI.findRecipeById(this.eap$pendingRecipeIdUpload);
|
||||||
|
// 检查样板与配方是否对应
|
||||||
|
List<GenericStack> stacks = PatternDetailsHelper.decodePattern(itemStack, this.epp$player.level()).getOutputs();
|
||||||
|
if (stacks != null && recipe != null) {
|
||||||
|
List<EmiStack> stacks2 = recipe.getOutputs();
|
||||||
|
|
||||||
|
List<ResourceLocation> ids1 = stacks.stream().map(s -> s.what().getId()).sorted().toList();
|
||||||
|
List<ResourceLocation> ids2 = stacks2.stream().map(EmiStack::getId).sorted().toList();
|
||||||
|
|
||||||
|
if (ids1.equals(ids2)) {
|
||||||
|
tag.putString("recipeId", this.eap$pendingRecipeIdUpload.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.eap$pendingRecipeIdUpload =null;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cir.setReturnValue(itemStack);
|
cir.setReturnValue(itemStack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.extendedae_plus.mixin.emi;
|
||||||
|
|
||||||
|
import com.extendedae_plus.network.upload.EncodeWithRecipeIdC2SPacket;
|
||||||
|
import dev.emi.emi.api.recipe.EmiRecipe;
|
||||||
|
import dev.emi.emi.api.recipe.handler.EmiCraftContext;
|
||||||
|
import dev.emi.emi.registry.EmiRecipeFiller;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(EmiRecipeFiller.class)
|
||||||
|
public class EmiRecipeFillerMixin {
|
||||||
|
@Inject(method = "performFill", at = @At("RETURN"), remap = false)
|
||||||
|
private static <T extends AbstractContainerMenu> void onPerformFill(EmiRecipe recipe, AbstractContainerScreen<T> screen, EmiCraftContext.Type type, EmiCraftContext.Destination destination, int amount, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
PacketDistributor.sendToServer(new EncodeWithRecipeIdC2SPacket(recipe.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.extendedae_plus.network.upload;
|
||||||
|
|
||||||
|
import appeng.menu.me.items.PatternEncodingTermMenu;
|
||||||
|
import com.extendedae_plus.ExtendedAEPlus;
|
||||||
|
import com.extendedae_plus.api.upload.IPatternEncodingIdSync;
|
||||||
|
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.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C2S:图样编码终端点击「编码」按钮时上传客户端的配方ID。
|
||||||
|
*/
|
||||||
|
public class EncodeWithRecipeIdC2SPacket implements CustomPacketPayload {
|
||||||
|
|
||||||
|
public static final Type<EncodeWithRecipeIdC2SPacket> TYPE = new Type<>(
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "encode_with_recipe"));
|
||||||
|
|
||||||
|
public static final StreamCodec<FriendlyByteBuf, EncodeWithRecipeIdC2SPacket> STREAM_CODEC = StreamCodec.of(
|
||||||
|
(buf, pkt) -> buf.writeResourceLocation(pkt.id),
|
||||||
|
buf -> new EncodeWithRecipeIdC2SPacket(buf.readResourceLocation())
|
||||||
|
);
|
||||||
|
|
||||||
|
private final ResourceLocation id;
|
||||||
|
|
||||||
|
public EncodeWithRecipeIdC2SPacket(ResourceLocation id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handle(final EncodeWithRecipeIdC2SPacket msg, final IPayloadContext ctx) {
|
||||||
|
ctx.enqueueWork(() -> {
|
||||||
|
if (!(ctx.player() instanceof ServerPlayer player)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (player.containerMenu instanceof PatternEncodingTermMenu menu
|
||||||
|
&& menu instanceof IPatternEncodingIdSync sync) {
|
||||||
|
sync.eap$clientRecipeIdUpload(msg.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<? extends CustomPacketPayload> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.extendedae_plus.util;
|
||||||
|
|
||||||
|
import appeng.api.stacks.AEFluidKey;
|
||||||
|
import appeng.api.stacks.AEItemKey;
|
||||||
|
import appeng.api.stacks.GenericStack;
|
||||||
|
import com.extendedae_plus.integration.jei.JeiRuntimeProxy;
|
||||||
|
import dev.emi.emi.api.EmiApi;
|
||||||
|
import dev.emi.emi.api.recipe.EmiRecipe;
|
||||||
|
import dev.emi.emi.api.recipe.EmiRecipeManager;
|
||||||
|
import mezz.jei.api.constants.RecipeTypes;
|
||||||
|
import mezz.jei.api.constants.VanillaTypes;
|
||||||
|
import mezz.jei.api.gui.IRecipeLayoutDrawable;
|
||||||
|
import mezz.jei.api.gui.ingredient.IRecipeSlotView;
|
||||||
|
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
|
||||||
|
import mezz.jei.api.helpers.IJeiHelpers;
|
||||||
|
import mezz.jei.api.ingredients.ITypedIngredient;
|
||||||
|
import mezz.jei.api.neoforge.NeoForgeTypes;
|
||||||
|
import mezz.jei.api.recipe.*;
|
||||||
|
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||||
|
import mezz.jei.api.runtime.IJeiRuntime;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.crafting.CraftingRecipe;
|
||||||
|
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||||
|
import net.neoforged.neoforge.fluids.FluidStack;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于 EMI 查找配方,提取输入输出槽位与数量信息。
|
||||||
|
*/
|
||||||
|
public final class RecipeFinderUtilEMI {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger("ExtendedAE Plus - RecipeFinder");
|
||||||
|
static EmiRecipeManager manager = EmiApi.getRecipeManager();
|
||||||
|
private RecipeFinderUtilEMI() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static EmiRecipe findRecipeById(ResourceLocation location) {
|
||||||
|
return manager.getRecipe(location);
|
||||||
|
}
|
||||||
|
@Nullable
|
||||||
|
public static EmiRecipe findRecipeById(String id) {
|
||||||
|
return findRecipeById(ResourceLocation.parse(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -53,10 +53,10 @@
|
||||||
"ae2.parts.automation.IOBusPartChannelCardMixin",
|
"ae2.parts.automation.IOBusPartChannelCardMixin",
|
||||||
"ae2.parts.storagebus.StorageBusPartChannelCardMixin",
|
"ae2.parts.storagebus.StorageBusPartChannelCardMixin",
|
||||||
"ae2WTlib.ContainerUWirelessExPatternTerminalMixin",
|
"ae2WTlib.ContainerUWirelessExPatternTerminalMixin",
|
||||||
|
"emi.EmiRecipeFillerMixin",
|
||||||
"extendedae.common.PartExPatternProviderMixin",
|
"extendedae.common.PartExPatternProviderMixin",
|
||||||
"extendedae.common.TileExPatternProviderMixin",
|
"extendedae.common.TileExPatternProviderMixin",
|
||||||
"extendedae.common.matrix.ClusterAssemblerMatrixMixin",
|
"extendedae.common.matrix.ClusterAssemblerMatrixMixin",
|
||||||
"extendedae.common.matrix.ClusterAssemblerMatrixMixin",
|
|
||||||
"extendedae.container.ContainerAssemblerMatrixPatternSlotTrackerMixin",
|
"extendedae.container.ContainerAssemblerMatrixPatternSlotTrackerMixin",
|
||||||
"extendedae.container.ContainerExPatternProviderMixin",
|
"extendedae.container.ContainerExPatternProviderMixin",
|
||||||
"extendedae.container.ContainerExPatternTerminalMixin",
|
"extendedae.container.ContainerExPatternTerminalMixin",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user