快捷从EMI配方树界面编写/上传样板
This commit is contained in:
parent
be3bc1dcf8
commit
7fe6d63c03
|
|
@ -15,7 +15,7 @@ loader_version_range=[1,)
|
|||
mod_id=extendedae_plus
|
||||
mod_name=ExtendedAE-Plus
|
||||
mod_license=LGPL-3.0-or-later
|
||||
mod_version=1.0.0fix
|
||||
mod_version=1.0.1
|
||||
mod_group_id=com.extendedae_plus
|
||||
mod_authors=GaLicn, XianYuFish001
|
||||
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.config.ModConfig;
|
||||
import com.extendedae_plus.init.*;
|
||||
import com.extendedae_plus.network.ModNetwork;
|
||||
import com.extendedae_plus.util.storage.InfinityStorageManager;
|
||||
import com.mojang.logging.LogUtils;
|
||||
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.network.*;
|
||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||
|
||||
public class ModNetwork {
|
||||
|
|
@ -39,5 +40,8 @@ public class ModNetwork {
|
|||
registrar.playToServer(C2SPacketTargetKeyTriggered.TYPE,
|
||||
C2SPacketTargetKeyTriggered.STREAM_CODEC,
|
||||
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.SlotGridLayoutMixin",
|
||||
"ae2.menu.CraftConfirmMenuGoBackMixin",
|
||||
"emi.MixinBoMScreen",
|
||||
"emi.MixinEncodingHelper",
|
||||
"extendedae.accessor.GuiExPatternTerminalAccessor",
|
||||
"extendedae.accessor.GuiExPatternTerminalSlotsRowAccessor",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user