JEI写样板支持shift控制启用物品替换,alt启用流体替换

This commit is contained in:
GaLi 2026-03-03 10:53:05 +08:00
parent a389b7ba5e
commit 45fdf749b1
3 changed files with 56 additions and 28 deletions

View File

@ -4,6 +4,7 @@ import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.client.ModKeybindings; import com.extendedae_plus.client.ModKeybindings;
import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.integration.jei.JeiRuntimeProxy; import com.extendedae_plus.integration.jei.JeiRuntimeProxy;
import com.extendedae_plus.network.pattern.CreateAndUploadPatternC2SPacket;
import com.extendedae_plus.network.pattern.CreateCtrlQPatternC2SPacket; import com.extendedae_plus.network.pattern.CreateCtrlQPatternC2SPacket;
import com.extendedae_plus.network.provider.RequestProvidersListC2SPacket; import com.extendedae_plus.network.provider.RequestProvidersListC2SPacket;
import com.extendedae_plus.util.RecipeFinderUtil; import com.extendedae_plus.util.RecipeFinderUtil;
@ -22,7 +23,9 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ScreenEvent; import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import org.lwjgl.glfw.GLFW;
import java.sql.SQLOutput;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -42,8 +45,10 @@ public class CtrlQPatternKeyHandler {
Screen screen = event.getScreen(); Screen screen = event.getScreen();
int keyCode = event.getKeyCode(); int keyCode = event.getKeyCode();
int scanCode = event.getScanCode(); int scanCode = event.getScanCode();
boolean isAllowSubstitutes = Screen.hasShiftDown();
boolean isFluidSubstitutes = Screen.hasAltDown();
// 使用 KeyMapping 检测按键包含修饰键 // 使用 KeyMapping
if (!ModKeybindings.CREATE_PATTERN_KEY.matches(keyCode, scanCode)) { if (!ModKeybindings.CREATE_PATTERN_KEY.matches(keyCode, scanCode)) {
return; return;
} }
@ -58,7 +63,7 @@ public class CtrlQPatternKeyHandler {
if (recipeBookmark.isPresent()) { if (recipeBookmark.isPresent()) {
// 配方书签分支处理带有配方类型的书签 // 配方书签分支处理带有配方类型的书签
handleRecipeBookmark(recipeBookmark.get()); handleRecipeBookmark(recipeBookmark.get(),isAllowSubstitutes,isFluidSubstitutes);
event.setCanceled(true); event.setCanceled(true);
return; return;
} }
@ -106,12 +111,17 @@ public class CtrlQPatternKeyHandler {
// 获取输出材料转换为 ItemStack流体会被包装 // 获取输出材料转换为 ItemStack流体会被包装
List<ItemStack> selectedOutputs = convertOutputsToItemStacks(selectedRecipeInfo); List<ItemStack> selectedOutputs = convertOutputsToItemStacks(selectedRecipeInfo);
System.out.println("sendPackage");
// 发送网络包到服务器 // 发送网络包到服务器
ModNetwork.CHANNEL.sendToServer(new CreateCtrlQPatternC2SPacket( ModNetwork.CHANNEL.sendToServer(new CreateCtrlQPatternC2SPacket(
selectedRecipeInfo.getRecipe().getId(), selectedRecipeInfo.getRecipe().getId(),
selectedRecipeInfo.isCraftingRecipe(), selectedRecipeInfo.isCraftingRecipe(),
selectedIngredients, selectedIngredients,
selectedOutputs selectedOutputs,
false,
isAllowSubstitutes,
isFluidSubstitutes
)); ));
// 消耗事件防止传播 // 消耗事件防止传播
@ -123,14 +133,14 @@ public class CtrlQPatternKeyHandler {
* *
* @param recipeBookmark 配方书签对象RecipeBookmark<?, ?> * @param recipeBookmark 配方书签对象RecipeBookmark<?, ?>
*/ */
private static void handleRecipeBookmark(Object recipeBookmark) { private static void handleRecipeBookmark(Object recipeBookmark,boolean isAllowSubstitutes,boolean isFluidSubstitutes) {
// 判断配方类型 // 判断配方类型
if (isCraftingRecipe(recipeBookmark)) { if (isCraftingRecipe(recipeBookmark)) {
// 合成配方分支 // 合成配方分支
handleCraftingRecipeBookmark(recipeBookmark); handleCraftingRecipeBookmark(recipeBookmark,isAllowSubstitutes,isFluidSubstitutes);
} else { } else {
// 其他配方分支加工配方等 // 其他配方分支加工配方等
handleProcessingRecipeBookmark(recipeBookmark); handleProcessingRecipeBookmark(recipeBookmark,isAllowSubstitutes,isFluidSubstitutes);
} }
} }
@ -163,7 +173,7 @@ public class CtrlQPatternKeyHandler {
* *
* @param recipeBookmark 配方书签对象 * @param recipeBookmark 配方书签对象
*/ */
private static void handleCraftingRecipeBookmark(Object recipeBookmark) { private static void handleCraftingRecipeBookmark(Object recipeBookmark,boolean isAllowSubstitutes,boolean isFluidSubstitutes) {
try { try {
// 1. 获取配方ID // 1. 获取配方ID
net.minecraft.resources.ResourceLocation recipeId = getRecipeIdCompat(recipeBookmark); net.minecraft.resources.ResourceLocation recipeId = getRecipeIdCompat(recipeBookmark);
@ -274,11 +284,13 @@ public class CtrlQPatternKeyHandler {
List<ItemStack> selectedOutputs = convertOutputsToItemStacks(matchingRecipeInfo); List<ItemStack> selectedOutputs = convertOutputsToItemStacks(matchingRecipeInfo);
// 11. 发送网络包创建样板并上传到装配矩阵 // 11. 发送网络包创建样板并上传到装配矩阵
ModNetwork.CHANNEL.sendToServer(new com.extendedae_plus.network.pattern.CreateAndUploadPatternC2SPacket( ModNetwork.CHANNEL.sendToServer(new CreateAndUploadPatternC2SPacket(
recipeId, recipeId,
matchingRecipeInfo.isCraftingRecipe(), matchingRecipeInfo.isCraftingRecipe(),
selectedIngredients, selectedIngredients,
selectedOutputs selectedOutputs,
isAllowSubstitutes,
isFluidSubstitutes
)); ));
} catch (Exception e) { } catch (Exception e) {
@ -291,7 +303,7 @@ public class CtrlQPatternKeyHandler {
* *
* @param recipeBookmark 配方书签对象 * @param recipeBookmark 配方书签对象
*/ */
private static void handleProcessingRecipeBookmark(Object recipeBookmark) { private static void handleProcessingRecipeBookmark(Object recipeBookmark,boolean isAllowSubstitutes,boolean isFluidSubstitutes) {
try { try {
net.minecraft.resources.ResourceLocation recipeId = getRecipeIdCompat(recipeBookmark); net.minecraft.resources.ResourceLocation recipeId = getRecipeIdCompat(recipeBookmark);
if (recipeId == null) { if (recipeId == null) {
@ -382,7 +394,9 @@ public class CtrlQPatternKeyHandler {
matchingRecipeInfo.isCraftingRecipe(), matchingRecipeInfo.isCraftingRecipe(),
selectedIngredients, selectedIngredients,
selectedOutputs, selectedOutputs,
true true,
isAllowSubstitutes,
isFluidSubstitutes
)); ));
ModNetwork.CHANNEL.sendToServer(new RequestProvidersListC2SPacket()); ModNetwork.CHANNEL.sendToServer(new RequestProvidersListC2SPacket());
@ -396,7 +410,6 @@ public class CtrlQPatternKeyHandler {
return null; return null;
} }
// JEI 1.20 分支
try { try {
var getRecipeUidMethod = recipeBookmark.getClass().getMethod("getRecipeUid"); var getRecipeUidMethod = recipeBookmark.getClass().getMethod("getRecipeUid");
Object recipeId = getRecipeUidMethod.invoke(recipeBookmark); Object recipeId = getRecipeUidMethod.invoke(recipeBookmark);
@ -406,7 +419,6 @@ public class CtrlQPatternKeyHandler {
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
// JEI 1.21+ 分支
try { try {
Object recipe = recipeBookmark.getClass().getMethod("getRecipe").invoke(recipeBookmark); Object recipe = recipeBookmark.getClass().getMethod("getRecipe").invoke(recipeBookmark);
Object recipeCategory = recipeBookmark.getClass().getMethod("getRecipeCategory").invoke(recipeBookmark); Object recipeCategory = recipeBookmark.getClass().getMethod("getRecipeCategory").invoke(recipeBookmark);

View File

@ -42,12 +42,16 @@ public class CreateAndUploadPatternC2SPacket {
private final boolean isCraftingPattern; private final boolean isCraftingPattern;
private final List<ItemStack> selectedIngredients; private final List<ItemStack> selectedIngredients;
private final List<ItemStack> outputs; private final List<ItemStack> outputs;
private final boolean isAllowSubstitutes;
private final boolean isFluidSubstitutes;
public CreateAndUploadPatternC2SPacket(ResourceLocation recipeId, boolean isCraftingPattern, List<ItemStack> selectedIngredients, List<ItemStack> outputs) { public CreateAndUploadPatternC2SPacket(ResourceLocation recipeId, boolean isCraftingPattern, List<ItemStack> selectedIngredients, List<ItemStack> outputs, boolean isAllowSubstitutes, boolean isFluidSubstitutes) {
this.recipeId = recipeId; this.recipeId = recipeId;
this.isCraftingPattern = isCraftingPattern; this.isCraftingPattern = isCraftingPattern;
this.selectedIngredients = selectedIngredients; this.selectedIngredients = selectedIngredients;
this.outputs = outputs; this.outputs = outputs;
this.isAllowSubstitutes = isAllowSubstitutes;
this.isFluidSubstitutes = isFluidSubstitutes;
} }
public static void encode(CreateAndUploadPatternC2SPacket msg, FriendlyByteBuf buf) { public static void encode(CreateAndUploadPatternC2SPacket msg, FriendlyByteBuf buf) {
@ -61,6 +65,8 @@ public class CreateAndUploadPatternC2SPacket {
for (ItemStack stack : msg.outputs) { for (ItemStack stack : msg.outputs) {
buf.writeItem(stack); buf.writeItem(stack);
} }
buf.writeBoolean(msg.isAllowSubstitutes);
buf.writeBoolean(msg.isFluidSubstitutes);
} }
public static CreateAndUploadPatternC2SPacket decode(FriendlyByteBuf buf) { public static CreateAndUploadPatternC2SPacket decode(FriendlyByteBuf buf) {
@ -76,7 +82,9 @@ public class CreateAndUploadPatternC2SPacket {
for (int i = 0; i < outputCount; i++) { for (int i = 0; i < outputCount; i++) {
outputs.add(buf.readItem()); outputs.add(buf.readItem());
} }
return new CreateAndUploadPatternC2SPacket(recipeId, isCraftingPattern, ingredients, outputs); boolean isAllowSubstitutes = buf.readBoolean();
boolean isFluidSubstitutes = buf.readBoolean();
return new CreateAndUploadPatternC2SPacket(recipeId, isCraftingPattern, ingredients, outputs,isAllowSubstitutes,isFluidSubstitutes);
} }
public static void handle(CreateAndUploadPatternC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) { public static void handle(CreateAndUploadPatternC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
@ -121,7 +129,7 @@ public class CreateAndUploadPatternC2SPacket {
} }
// 4. 创建样板 // 4. 创建样板
ItemStack pattern = createPattern(recipe, msg.isCraftingPattern, msg.selectedIngredients, msg.outputs, player); ItemStack pattern = createPattern(recipe, msg.isCraftingPattern, msg.selectedIngredients, msg.outputs,msg.isAllowSubstitutes,msg.isFluidSubstitutes, player);
if (pattern.isEmpty()) { if (pattern.isEmpty()) {
// 创建失败退还空白样板到网络 // 创建失败退还空白样板到网络
@ -222,7 +230,7 @@ public class CreateAndUploadPatternC2SPacket {
/** /**
* 从配方创建样板 * 从配方创建样板
*/ */
private static ItemStack createPattern(Recipe<?> recipe, boolean isCrafting, List<ItemStack> selectedIngredients, List<ItemStack> selectedOutputs, ServerPlayer player) { private static ItemStack createPattern(Recipe<?> recipe, boolean isCrafting, List<ItemStack> selectedIngredients, List<ItemStack> selectedOutputs, boolean isAllowSubstitutes, boolean isFluidSubstitutes, ServerPlayer player) {
try { try {
if (isCrafting && recipe instanceof CraftingRecipe craftingRecipe) { if (isCrafting && recipe instanceof CraftingRecipe craftingRecipe) {
// 合成样板 // 合成样板
@ -241,8 +249,8 @@ public class CreateAndUploadPatternC2SPacket {
craftingRecipe, craftingRecipe,
inputs, inputs,
output, output,
true, isAllowSubstitutes,
false isFluidSubstitutes
); );
encodedPattern.getOrCreateTag().putString("encodePlayer", player.getName().getString()); encodedPattern.getOrCreateTag().putString("encodePlayer", player.getName().getString());

View File

@ -41,17 +41,21 @@ public class CreateCtrlQPatternC2SPacket {
private final List<ItemStack> selectedIngredients; private final List<ItemStack> selectedIngredients;
private final List<ItemStack> outputs; private final List<ItemStack> outputs;
private final boolean openProviderSelector; private final boolean openProviderSelector;
private final boolean isAllowSubstitutes;
private final boolean isFluidSubstitutes;
public CreateCtrlQPatternC2SPacket(ResourceLocation recipeId, boolean isCraftingPattern, List<ItemStack> selectedIngredients, List<ItemStack> outputs) { public CreateCtrlQPatternC2SPacket(ResourceLocation recipeId, boolean isCraftingPattern, List<ItemStack> selectedIngredients, List<ItemStack> outputs,boolean isAllowSubstitutes,boolean isFluidSubstitutes) {
this(recipeId, isCraftingPattern, selectedIngredients, outputs, false); this(recipeId, isCraftingPattern, selectedIngredients, outputs, false, isAllowSubstitutes, isFluidSubstitutes);
} }
public CreateCtrlQPatternC2SPacket(ResourceLocation recipeId, boolean isCraftingPattern, List<ItemStack> selectedIngredients, List<ItemStack> outputs, boolean openProviderSelector) { public CreateCtrlQPatternC2SPacket(ResourceLocation recipeId, boolean isCraftingPattern, List<ItemStack> selectedIngredients, List<ItemStack> outputs, boolean openProviderSelector,boolean isAllowSubstitutes,boolean isFluidSubstitutes) {
this.recipeId = recipeId; this.recipeId = recipeId;
this.isCraftingPattern = isCraftingPattern; this.isCraftingPattern = isCraftingPattern;
this.selectedIngredients = selectedIngredients; this.selectedIngredients = selectedIngredients;
this.outputs = outputs; this.outputs = outputs;
this.openProviderSelector = openProviderSelector; this.openProviderSelector = openProviderSelector;
this.isAllowSubstitutes = isAllowSubstitutes;
this.isFluidSubstitutes = isFluidSubstitutes;
} }
public static void encode(CreateCtrlQPatternC2SPacket msg, FriendlyByteBuf buf) { public static void encode(CreateCtrlQPatternC2SPacket msg, FriendlyByteBuf buf) {
@ -65,6 +69,8 @@ public class CreateCtrlQPatternC2SPacket {
for (ItemStack stack : msg.outputs) { for (ItemStack stack : msg.outputs) {
buf.writeItem(stack); buf.writeItem(stack);
} }
buf.writeBoolean(msg.isAllowSubstitutes);
buf.writeBoolean(msg.isFluidSubstitutes);
buf.writeBoolean(msg.openProviderSelector); buf.writeBoolean(msg.openProviderSelector);
} }
@ -84,8 +90,10 @@ public class CreateCtrlQPatternC2SPacket {
outputs.add(buf.readItem()); outputs.add(buf.readItem());
} }
boolean isAllowSubstitutes = buf.readBoolean();
boolean isFluidSubstitutes = buf.readBoolean();
boolean openProviderSelector = buf.readableBytes() > 0 && buf.readBoolean(); boolean openProviderSelector = buf.readableBytes() > 0 && buf.readBoolean();
return new CreateCtrlQPatternC2SPacket(recipeId, isCraftingPattern, ingredients, outputs, openProviderSelector); return new CreateCtrlQPatternC2SPacket(recipeId, isCraftingPattern, ingredients, outputs, openProviderSelector,isAllowSubstitutes,isFluidSubstitutes);
} }
public static void handle(CreateCtrlQPatternC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) { public static void handle(CreateCtrlQPatternC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
@ -110,7 +118,7 @@ public class CreateCtrlQPatternC2SPacket {
return; return;
} }
ItemStack pattern = createPattern(recipe, msg.isCraftingPattern, msg.selectedIngredients, msg.outputs, player); ItemStack pattern = createPattern(recipe, msg.isCraftingPattern, msg.selectedIngredients, msg.outputs,msg.isAllowSubstitutes,msg.isFluidSubstitutes, player);
if (pattern.isEmpty()) { if (pattern.isEmpty()) {
player.getInventory().add(AEItems.BLANK_PATTERN.stack()); player.getInventory().add(AEItems.BLANK_PATTERN.stack());
player.displayClientMessage(Component.translatable("message.extendedae_plus.pattern_creation_failed"), false); player.displayClientMessage(Component.translatable("message.extendedae_plus.pattern_creation_failed"), false);
@ -235,7 +243,7 @@ public class CreateCtrlQPatternC2SPacket {
return false; return false;
} }
private static ItemStack createPattern(Recipe<?> recipe, boolean isCrafting, List<ItemStack> selectedIngredients, List<ItemStack> selectedOutputs, ServerPlayer player) { private static ItemStack createPattern(Recipe<?> recipe, boolean isCrafting, List<ItemStack> selectedIngredients, List<ItemStack> selectedOutputs, boolean isAllowSubstitutes,boolean isFluidSubstitutes, ServerPlayer player) {
try { try {
if (isCrafting && recipe instanceof CraftingRecipe craftingRecipe) { if (isCrafting && recipe instanceof CraftingRecipe craftingRecipe) {
ItemStack[] inputs = new ItemStack[9]; ItemStack[] inputs = new ItemStack[9];
@ -252,8 +260,8 @@ public class CreateCtrlQPatternC2SPacket {
craftingRecipe, craftingRecipe,
inputs, inputs,
output, output,
true, isAllowSubstitutes,
false isFluidSubstitutes
); );
encodedPattern.getOrCreateTag().putString("encodePlayer", player.getName().getString()); encodedPattern.getOrCreateTag().putString("encodePlayer", player.getName().getString());
@ -302,4 +310,4 @@ public class CreateCtrlQPatternC2SPacket {
return ItemStack.EMPTY; return ItemStack.EMPTY;
} }
} }
} }