快捷从EMI配方树界面编写/上传样板
This commit is contained in:
parent
be3bc1dcf8
commit
7fe6d63c03
|
|
@ -15,7 +15,7 @@ loader_version_range=[1,)
|
||||||
mod_id=extendedae_plus
|
mod_id=extendedae_plus
|
||||||
mod_name=ExtendedAE-Plus
|
mod_name=ExtendedAE-Plus
|
||||||
mod_license=LGPL-3.0-or-later
|
mod_license=LGPL-3.0-or-later
|
||||||
mod_version=1.0.0fix
|
mod_version=1.0.1
|
||||||
mod_group_id=com.extendedae_plus
|
mod_group_id=com.extendedae_plus
|
||||||
mod_authors=GaLicn, XianYuFish001
|
mod_authors=GaLicn, XianYuFish001
|
||||||
mod_description=
|
mod_description=
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellHandler;
|
||||||
import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellInventory;
|
import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellInventory;
|
||||||
import com.extendedae_plus.config.ModConfig;
|
import com.extendedae_plus.config.ModConfig;
|
||||||
import com.extendedae_plus.init.*;
|
import com.extendedae_plus.init.*;
|
||||||
import com.extendedae_plus.network.ModNetwork;
|
|
||||||
import com.extendedae_plus.util.storage.InfinityStorageManager;
|
import com.extendedae_plus.util.storage.InfinityStorageManager;
|
||||||
import com.mojang.logging.LogUtils;
|
import com.mojang.logging.LogUtils;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.extendedae_plus.network;
|
package com.extendedae_plus.init;
|
||||||
|
|
||||||
import com.extendedae_plus.ExtendedAEPlus;
|
import com.extendedae_plus.ExtendedAEPlus;
|
||||||
|
import com.extendedae_plus.network.*;
|
||||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
|
|
||||||
public class ModNetwork {
|
public class ModNetwork {
|
||||||
|
|
@ -39,5 +40,8 @@ public class ModNetwork {
|
||||||
registrar.playToServer(C2SPacketTargetKeyTriggered.TYPE,
|
registrar.playToServer(C2SPacketTargetKeyTriggered.TYPE,
|
||||||
C2SPacketTargetKeyTriggered.STREAM_CODEC,
|
C2SPacketTargetKeyTriggered.STREAM_CODEC,
|
||||||
C2SPacketTargetKeyTriggered::handle);
|
C2SPacketTargetKeyTriggered::handle);
|
||||||
|
registrar.playToServer(C2SPacketStoneCuttingID.TYPE,
|
||||||
|
C2SPacketStoneCuttingID.STREAM_CODEC,
|
||||||
|
C2SPacketStoneCuttingID::handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.extendedae_plus.integration.emi;
|
||||||
|
|
||||||
|
import appeng.api.stacks.GenericStack;
|
||||||
|
import appeng.integration.modules.emi.EmiStackHelper;
|
||||||
|
import dev.emi.emi.api.recipe.EmiRecipe;
|
||||||
|
import dev.emi.emi.api.stack.EmiStack;
|
||||||
|
import dev.emi.emi.bom.FoldState;
|
||||||
|
import dev.emi.emi.bom.MaterialNode;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.crafting.RecipeType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class HandlerBoMRecipes {
|
||||||
|
public static HashMap<ResourceLocation, GenericStack> collectInputs(MaterialNode parentNode) {
|
||||||
|
var recipe = parentNode.recipe;
|
||||||
|
if (parentNode.state != FoldState.EXPANDED) return new HashMap<>();
|
||||||
|
if (parentNode.children == null) return new HashMap<>();
|
||||||
|
|
||||||
|
HashMap<ResourceLocation, GenericStack> results = new HashMap<>();
|
||||||
|
var type = recipe.getBackingRecipe().value().getType();
|
||||||
|
|
||||||
|
parentNode.children.forEach(child -> {
|
||||||
|
EmiStack stack;
|
||||||
|
|
||||||
|
if (child.recipe != null && type != RecipeType.STONECUTTING)
|
||||||
|
stack = child.recipe.getOutputs().getFirst().getEmiStacks().getFirst();
|
||||||
|
else stack = child.ingredient.getEmiStacks().getFirst();
|
||||||
|
|
||||||
|
recipe.getInputs().forEach(input -> {
|
||||||
|
if (input.getEmiStacks().contains(stack)) {
|
||||||
|
stack.setAmount(input.getEmiStacks().getFirst().getAmount());
|
||||||
|
GenericStack genericStack = EmiStackHelper.toGenericStack(stack);
|
||||||
|
if (genericStack == null) return;
|
||||||
|
|
||||||
|
results.put(input.getEmiStacks().getFirst().getId(), genericStack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static void handle(C2SPacketStoneCuttingID packet, ServerPlayer player) {
|
||||||
|
// if (!(player.containerMenu instanceof PatternEncodingTermMenu menu)) return;
|
||||||
|
//// RecipeHolder<?> recipeHolder = player.level().getRecipeManager()
|
||||||
|
//// .byKey(packet.recipeID()).orElse(null);
|
||||||
|
// EmiRecipe recipe = EmiApi.getRecipeManager()
|
||||||
|
// .getRecipe(packet.recipeID());
|
||||||
|
//
|
||||||
|
// if (recipe == null) return;
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// menu.clear();
|
||||||
|
// List<List<GenericStack>> modifiedInputs = updateRecipe(recipe, packet.batches(), packet.selectedStacks());
|
||||||
|
//
|
||||||
|
// // 遍历原配方的每个输入
|
||||||
|
// for (EmiIngredient originalInput : recipe.getInputs()) {
|
||||||
|
// if (!originalInput.getEmiStacks().isEmpty()) {
|
||||||
|
// EmiStack firstStack = originalInput.getEmiStacks().getFirst();
|
||||||
|
// ResourceLocation stackId = firstStack.getId();
|
||||||
|
//
|
||||||
|
// if (packet.selectedStacks().containsKey(stackId))
|
||||||
|
// modifiedInputs.add(List.of(
|
||||||
|
// packet.selectedStacks().getOrDefault(stackId, EmiStackHelper.toGenericStack(firstStack))));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 获取输出(保持不变)
|
||||||
|
// List<GenericStack> outputs = EmiStackHelper.ofOutputs(recipe);
|
||||||
|
//
|
||||||
|
// // 编码修改后的配方
|
||||||
|
//// EncodingHelper.encodeProcessingRecipe(menu, modifiedInputs, outputs);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// ExtendedAEPlus.LOGGER.debug("encode failed:", e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static List<List<GenericStack>> updateRecipe(EmiRecipe original, long batches,
|
||||||
|
HashMap<ResourceLocation, GenericStack> selectedInputs) {
|
||||||
|
List<List<GenericStack>> modifiedInputs = new ArrayList<>();
|
||||||
|
|
||||||
|
EmiStackHelper.ofInputs(original).forEach(stacks -> {
|
||||||
|
if (!stacks.isEmpty()) {
|
||||||
|
GenericStack originStack = stacks.getFirst();
|
||||||
|
ResourceLocation stackId = originStack.what().getId();
|
||||||
|
|
||||||
|
if (selectedInputs.containsKey(stackId))
|
||||||
|
modifiedInputs.add(List.of(
|
||||||
|
selectedInputs.getOrDefault(stackId, originStack)));
|
||||||
|
} else modifiedInputs.add(List.of());
|
||||||
|
});
|
||||||
|
return modifiedInputs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
package com.extendedae_plus.integration.emi;
|
||||||
|
|
||||||
|
import appeng.api.stacks.AEItemKey;
|
||||||
|
import appeng.api.stacks.GenericStack;
|
||||||
|
import appeng.core.network.ServerboundPacket;
|
||||||
|
import appeng.core.network.serverbound.InventoryActionPacket;
|
||||||
|
import appeng.helpers.InventoryAction;
|
||||||
|
import appeng.menu.me.items.PatternEncodingTermMenu;
|
||||||
|
import appeng.parts.encoding.EncodingMode;
|
||||||
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||||
|
import net.minecraft.world.item.crafting.RecipeType;
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class PatternFillingHelper {
|
||||||
|
public static void encodeCraftingRecipe(PatternEncodingTermMenu menu,
|
||||||
|
@Nullable RecipeHolder<?> recipe,
|
||||||
|
List<List<GenericStack>> genericIngredients,
|
||||||
|
Predicate<ItemStack> visiblePredicate) {
|
||||||
|
if (recipe != null && recipe.value().getType().equals(RecipeType.STONECUTTING)) {
|
||||||
|
menu.setMode(EncodingMode.STONECUTTING);
|
||||||
|
menu.setStonecuttingRecipeId(recipe.id());
|
||||||
|
} else if (recipe != null && recipe.value().getType().equals(RecipeType.SMITHING))
|
||||||
|
menu.setMode(EncodingMode.SMITHING_TABLE);
|
||||||
|
else menu.setMode(EncodingMode.CRAFTING);
|
||||||
|
|
||||||
|
var encodedInputs = NonNullList.withSize(menu.getCraftingGridSlots().length, ItemStack.EMPTY);
|
||||||
|
|
||||||
|
for (int slot = 0; slot < genericIngredients.size(); slot++) {
|
||||||
|
var genericIngredient = genericIngredients.get(slot);
|
||||||
|
if (genericIngredient.isEmpty()) continue;
|
||||||
|
|
||||||
|
GenericStack selectedStack = null;
|
||||||
|
for (var stack : genericIngredient) {
|
||||||
|
if (stack.what() instanceof AEItemKey itemKey) {
|
||||||
|
ItemStack itemStack = itemKey.toStack();
|
||||||
|
if (visiblePredicate.test(itemStack)) {
|
||||||
|
selectedStack = stack;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedStack == null) selectedStack = genericIngredient.getFirst();
|
||||||
|
|
||||||
|
if (selectedStack.what() instanceof AEItemKey itemKey)
|
||||||
|
encodedInputs.set(slot, itemKey.toStack());
|
||||||
|
else encodedInputs.set(slot, GenericStack.wrapInItemStack(selectedStack.what(), 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < encodedInputs.size(); i++) {
|
||||||
|
ItemStack encodedInput = encodedInputs.get(i);
|
||||||
|
ServerboundPacket message = new InventoryActionPacket(
|
||||||
|
InventoryAction.SET_FILTER, menu.getCraftingGridSlots()[i].index, encodedInput);
|
||||||
|
PacketDistributor.sendToServer(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var outputSlot : menu.getProcessingOutputSlots()) {
|
||||||
|
ServerboundPacket message = new InventoryActionPacket(
|
||||||
|
InventoryAction.SET_FILTER, outputSlot.index, ItemStack.EMPTY);
|
||||||
|
PacketDistributor.sendToServer(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void encodeProcessingRecipe(PatternEncodingTermMenu menu, List<List<GenericStack>> genericIngredients,
|
||||||
|
List<GenericStack> genericResults) {
|
||||||
|
menu.setMode(EncodingMode.PROCESSING);
|
||||||
|
|
||||||
|
for (int i = 0; i < menu.getProcessingInputSlots().length; i++) {
|
||||||
|
ItemStack stackToSet = ItemStack.EMPTY;
|
||||||
|
|
||||||
|
if (i < genericIngredients.size() && !genericIngredients.get(i).isEmpty()) {
|
||||||
|
GenericStack selectedStack = genericIngredients.get(i).getFirst();
|
||||||
|
stackToSet = GenericStack.wrapInItemStack(selectedStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerboundPacket message = new InventoryActionPacket(
|
||||||
|
InventoryAction.SET_FILTER, menu.getProcessingInputSlots()[i].index, stackToSet);
|
||||||
|
PacketDistributor.sendToServer(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < menu.getProcessingOutputSlots().length; i++) {
|
||||||
|
ItemStack stackToSet = ItemStack.EMPTY;
|
||||||
|
|
||||||
|
if (i < genericResults.size()) {
|
||||||
|
GenericStack resultStack = genericResults.get(i);
|
||||||
|
stackToSet = GenericStack.wrapInItemStack(resultStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerboundPacket message = new InventoryActionPacket(
|
||||||
|
InventoryAction.SET_FILTER, menu.getProcessingOutputSlots()[i].index, stackToSet);
|
||||||
|
PacketDistributor.sendToServer(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
package com.extendedae_plus.mixin.emi;
|
||||||
|
|
||||||
|
import appeng.api.stacks.GenericStack;
|
||||||
|
import appeng.integration.modules.emi.EmiStackHelper;
|
||||||
|
import appeng.menu.me.items.PatternEncodingTermMenu;
|
||||||
|
import com.extendedae_plus.integration.emi.HandlerBoMRecipes;
|
||||||
|
import com.extendedae_plus.integration.emi.PatternFillingHelper;
|
||||||
|
import com.extendedae_plus.network.RequestProvidersListC2SPacket;
|
||||||
|
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil;
|
||||||
|
import dev.emi.emi.api.stack.EmiStack;
|
||||||
|
import dev.emi.emi.bom.BoM;
|
||||||
|
import dev.emi.emi.bom.MaterialNode;
|
||||||
|
import dev.emi.emi.screen.BoMScreen;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.crafting.RecipeType;
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(BoMScreen.class)
|
||||||
|
public abstract class MixinBoMScreen {
|
||||||
|
@Inject(method = "mouseClicked", at = @At("HEAD"))
|
||||||
|
private void onMouseClick(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (!(button == GLFW.GLFW_MOUSE_BUTTON_MIDDLE && Screen.hasControlDown())) return;
|
||||||
|
try {
|
||||||
|
var self = (BoMScreen)(Object) this;
|
||||||
|
Object hover = self.getHoveredStack((int) mouseX, (int) mouseY);
|
||||||
|
HashMap<ResourceLocation, GenericStack> selectedInputs;
|
||||||
|
|
||||||
|
// 救救孩子😭😭😭为什么private内部类套内部类aaa
|
||||||
|
// Mixins你们好啊, 我是reflection大王, 我要来破坏代码兼容性了😈😈😈
|
||||||
|
// 你知道吗: 其实以前这里套了两层reflection😋😋😋
|
||||||
|
if (hover != null) {
|
||||||
|
Field nodeField = hover.getClass().getDeclaredField("node");
|
||||||
|
nodeField.setAccessible(true);
|
||||||
|
Object nodeObject = nodeField.get(hover);
|
||||||
|
MaterialNode node = (MaterialNode) nodeObject;
|
||||||
|
|
||||||
|
if (node.recipe != null) {
|
||||||
|
if (Minecraft.getInstance().player.containerMenu instanceof PatternEncodingTermMenu menu) {
|
||||||
|
boolean isCraftingRecipe = false;
|
||||||
|
if (node.recipe.getBackingRecipe() != null) {
|
||||||
|
var type = node.recipe.getBackingRecipe().value().getType();
|
||||||
|
if (type == RecipeType.CRAFTING || type == RecipeType.STONECUTTING || type == RecipeType.SMITHING)
|
||||||
|
isCraftingRecipe = true;
|
||||||
|
}
|
||||||
|
menu.clear();
|
||||||
|
|
||||||
|
if (isCraftingRecipe) {
|
||||||
|
PatternFillingHelper.encodeCraftingRecipe(menu,
|
||||||
|
node.recipe.getBackingRecipe(),
|
||||||
|
HandlerBoMRecipes.updateRecipe(node.recipe, BoM.tree.batches,
|
||||||
|
HandlerBoMRecipes.collectInputs(node)),
|
||||||
|
stack -> true);
|
||||||
|
|
||||||
|
menu.encode();
|
||||||
|
} else {
|
||||||
|
EmiStack nodeStack = node.ingredient.getEmiStacks().getFirst();
|
||||||
|
List<EmiStack> outputs = new ArrayList<>(node.recipe.getOutputs());
|
||||||
|
outputs.remove(nodeStack);
|
||||||
|
outputs.addFirst(nodeStack);
|
||||||
|
PatternFillingHelper.encodeProcessingRecipe(menu,
|
||||||
|
HandlerBoMRecipes.updateRecipe(node.recipe, BoM.tree.batches,
|
||||||
|
HandlerBoMRecipes.collectInputs(node)),
|
||||||
|
outputs.stream().map(EmiStackHelper::toGenericStack).toList());
|
||||||
|
|
||||||
|
menu.encode();
|
||||||
|
|
||||||
|
String name = ExtendedAEPatternUploadUtil.mapRecipeTypeToSearchKey(node.recipe.getBackingRecipe().value());
|
||||||
|
if (!(name == null || name.isBlank()))
|
||||||
|
ExtendedAEPatternUploadUtil.setLastProcessingName(name);
|
||||||
|
|
||||||
|
PacketDistributor.sendToServer(RequestProvidersListC2SPacket.INSTANCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.extendedae_plus.network;
|
||||||
|
|
||||||
|
import appeng.menu.me.items.PatternEncodingTermMenu;
|
||||||
|
import com.extendedae_plus.ExtendedAEPlus;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public record C2SPacketStoneCuttingID(ResourceLocation recipeID) implements CustomPacketPayload {
|
||||||
|
public static final Type<C2SPacketStoneCuttingID> TYPE = new Type<>(
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "bom_pattern_encoding"));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<? extends CustomPacketPayload> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final StreamCodec<RegistryFriendlyByteBuf, C2SPacketStoneCuttingID> STREAM_CODEC = StreamCodec.composite(
|
||||||
|
ResourceLocation.STREAM_CODEC, C2SPacketStoneCuttingID::recipeID,
|
||||||
|
C2SPacketStoneCuttingID::new);
|
||||||
|
|
||||||
|
public static void handle(C2SPacketStoneCuttingID packet, IPayloadContext context) {
|
||||||
|
if (context.player().level().isClientSide) return;
|
||||||
|
context.enqueueWork(() -> {
|
||||||
|
if (!(context.player().containerMenu instanceof PatternEncodingTermMenu menu)) return;
|
||||||
|
menu.setStonecuttingRecipeId(packet.recipeID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
"ae2.client.gui.PatternProviderScreenMixin",
|
"ae2.client.gui.PatternProviderScreenMixin",
|
||||||
"ae2.client.gui.SlotGridLayoutMixin",
|
"ae2.client.gui.SlotGridLayoutMixin",
|
||||||
"ae2.menu.CraftConfirmMenuGoBackMixin",
|
"ae2.menu.CraftConfirmMenuGoBackMixin",
|
||||||
|
"emi.MixinBoMScreen",
|
||||||
"emi.MixinEncodingHelper",
|
"emi.MixinEncodingHelper",
|
||||||
"extendedae.accessor.GuiExPatternTerminalAccessor",
|
"extendedae.accessor.GuiExPatternTerminalAccessor",
|
||||||
"extendedae.accessor.GuiExPatternTerminalSlotsRowAccessor",
|
"extendedae.accessor.GuiExPatternTerminalSlotsRowAccessor",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user