From b35297ee18cee5afd84107cc6ede97b9851d08aa Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Tue, 19 Aug 2025 18:12:14 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9gtceu=E5=A4=9A?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E6=9C=BA=E5=99=A8=E5=A4=8D=E5=88=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 34 ++-- gradle.properties | 2 +- .../ae2/QuartzCuttingKnifeItemMixin.java | 188 +++++++++++------- 3 files changed, 128 insertions(+), 96 deletions(-) diff --git a/build.gradle b/build.gradle index f5d2652..ca8821b 100644 --- a/build.gradle +++ b/build.gradle @@ -56,50 +56,40 @@ dependencies { mappings loom.officialMojangMappings() forge "net.minecraftforge:forge:${forge_version}" + //exendedae前置 modImplementation "curse.maven:glodium-957920:${glodium_version}" + //extendedAE + modImplementation files('libs/ExtendedAE-1.20-1.4.2-forge.jar') + + //ae2 modImplementation "appeng:appliedenergistics2-forge:${ae2_version}" modImplementation "org.appliedenergistics:guideme:${guideme_version}" - modCompileOnly "curse.maven:applied-energistics-2-wireless-terminals-459929:${wireless_terminals_version}" + modCompileOnly "mezz.jei:jei-${minecraft_version}-forge:${jei_version}" + + annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" + modCompileOnly "curse.maven:applied-flux-965012:${applied_flux_version}" modCompileOnly "curse.maven:mega-cells-622112:${mega_cells_version}" modCompileOnly "curse.maven:jade-324717:${jade_version}" - // REI - modCompileOnly "me.shedaniel.cloth:basic-math:${basic_math_version}" - modCompileOnly "curse.maven:architectury-api-419699:${architectury_version}" - modCompileOnly "me.shedaniel:RoughlyEnoughItems-forge:${rei_version}" - modCompileOnly "me.shedaniel.cloth:cloth-config-forge:${cloth_config_version}" - - // ProjectE - modCompileOnly "curse.maven:projecte-226410:${projecte_version}" - modCompileOnly "curse.maven:appliede-1009940:${appliede_version}" - // GregTech modCompileOnly "curse.maven:gregtechceu-modern-890405:${gregtech_version}" modCompileOnly "curse.maven:ldlib-626676:${ldlib_version}" - // Immersive Engineering - modCompileOnly "curse.maven:immersive-engineering-231951:${ie_version}" - - 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:curios-309927:${curios_version}" + modRuntimeOnly "curse.maven:jade-324717:${jade_version}" modRuntimeOnly "curse.maven:architectury-api-419699:${architectury_version}" modRuntimeOnly "curse.maven:applied-energistics-2-wireless-terminals-459929:${wireless_terminals_version}" modRuntimeOnly "mezz.jei:jei-${minecraft_version}-forge:${jei_version}" - modRuntimeOnly "curse.maven:jade-324717:${jade_version}" - modRuntimeOnly "curse.maven:mega-cells-622112:${mega_cells_version}" - modRuntimeOnly "curse.maven:projecte-226410:${projecte_version}" - modRuntimeOnly "curse.maven:appliede-1009940:${appliede_version}" modRuntimeOnly "curse.maven:cloth-config-348521:5729105" - //extendedAE - modImplementation files('libs/ExtendedAE-1.20-1.4.2-forge.jar') + //jec modCompileOnly "curse.maven:just-enough-characters-250702:6680042" modRuntimeOnly "curse.maven:just-enough-characters-250702:6680042" diff --git a/gradle.properties b/gradle.properties index 9e2dd99..dce7331 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G loom.platform = forge # Mod properties -mod_version = 1.3.1 +mod_version = 1.3.1-fix1 maven_group = com.extendedae_plus archives_name = extendedae_plus diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/QuartzCuttingKnifeItemMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/QuartzCuttingKnifeItemMixin.java index 20c187b..8d76785 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/QuartzCuttingKnifeItemMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/QuartzCuttingKnifeItemMixin.java @@ -1,35 +1,45 @@ package com.extendedae_plus.mixin.ae2; +import appeng.api.parts.IPartHost; +import appeng.api.parts.SelectedPart; import appeng.items.tools.quartz.QuartzCuttingKnifeItem; -import net.minecraft.client.Minecraft; -import net.minecraft.network.chat.Component; +import com.gregtechceu.gtceu.api.blockentity.MetaMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.mojang.blaze3d.platform.Window; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.Nameable; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.Nameable; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; -import appeng.api.parts.IPartHost; -import appeng.api.parts.SelectedPart; +import net.minecraft.world.phys.Vec3; import org.lwjgl.glfw.GLFW; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import java.awt.*; -import java.awt.datatransfer.StringSelection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; + /** * 为 AE2 石英切割刀添加:潜行 + 右键 指向世界中的方块/部件(如线缆)时,复制其名称到剪贴板。 - * + *
* 设计要点(参考原类 QuartzCuttingKnifeItem 的写法): * - 原本右键会打开 QuartzKnifeMenu。我们在客户端、潜行且命中方块时,优先拦截并复制名称。 * - 名称优先取方块实体的自定义名(若实现 Nameable),否则使用方块显示名。 @@ -37,6 +47,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; */ @Mixin(value = QuartzCuttingKnifeItem.class) public abstract class QuartzCuttingKnifeItemMixin { + private static final Logger LOGGER = LoggerFactory.getLogger("ExtendedAEPlus"); @Inject(method = "use", at = @At("HEAD"), cancellable = true) private void eap$copyNameOnShiftRightClick(Level level, Player player, InteractionHand hand, @@ -55,37 +66,17 @@ public abstract class QuartzCuttingKnifeItemMixin { } var pos = bhr.getBlockPos(); var state = level.getBlockState(pos); - if (state == null || state.isAir()) { - return; - } - String name = null; - BlockEntity be = level.getBlockEntity(pos); - // 优先:若为 AE2 线缆总线,选择命中的具体 Part 名称 - if (be instanceof IPartHost partHost) { - SelectedPart sel = partHost.selectPartWorld(bhr.getLocation()); - if (sel.part != null) { - var stack = new net.minecraft.world.item.ItemStack(sel.part.getPartItem()); - name = stack.getHoverName().getString(); - } else if (sel.facade != null) { - var stack = sel.facade.getItemStack(); - if (!stack.isEmpty()) { - name = stack.getHoverName().getString(); - } - } - } - if (be instanceof Nameable nm) { - var custom = nm.getCustomName(); - if (custom != null) { - name = custom.getString(); - } - } - if (name == null || name.isBlank()) { - name = state.getBlock().getName().getString(); - } - boolean ok = tryCopyToClipboard(mc, name); - player.displayClientMessage(Component.literal(ok - ? ("已复制方块名: " + name) + if (state == null || state.isAir()) return; + + // 获取方块名称 + String name = eap$getBlockName(level, pos, hr.getLocation()); + + // 复制到剪贴板并反馈 + boolean success = eap$tryCopyToClipboard(Minecraft.getInstance(), name); + player.displayClientMessage(Component.literal(success + ? ("已复制方块/部件名: " + name) : "复制失败:整合包可能限制剪贴板或未聚焦窗口"), true); + // 拦截默认行为,不再打开刀具界面 ItemStack held = player.getItemInHand(hand); cir.setReturnValue(new InteractionResultHolder<>(InteractionResult.SUCCESS, held)); @@ -101,40 +92,85 @@ public abstract class QuartzCuttingKnifeItemMixin { } var pos = context.getClickedPos(); var state = level.getBlockState(pos); - if (state == null || state.isAir()) { - return; + if (state.isAir()) return; + + // 获取方块名称 + String name = eap$getBlockName(level, pos, context.getClickLocation()); + + // 复制到剪贴板并反馈 + boolean success = eap$tryCopyToClipboard(Minecraft.getInstance(), name); + player.displayClientMessage(Component.literal(success + ? ("已复制方块/部件名: " + name) + : "复制失败:整合包可能限制剪贴板或未聚焦窗口"), true); + + // 拦截默认行为 + cir.setReturnValue(InteractionResult.SUCCESS); + } + + /** + * 获取方块或部件的名称,优先级:自定义名称 > AE2 部件 > GregTech 配方翻译 > 方块名称 + */ + @Unique + private String eap$getBlockName(Level level, BlockPos pos, Vec3 clickLocation) { + BlockEntity blockEntity = level.getBlockEntity(pos); + BlockState state = level.getBlockState(pos); + + // 1. 自定义名称 + if (blockEntity instanceof Nameable nameable && nameable.getCustomName() != null) { + return nameable.getCustomName().getString(); } - String name = null; - BlockEntity be = level.getBlockEntity(pos); - // 优先:若为 AE2 线缆总线,选择命中的具体 Part 名称(使用点击位置的世界坐标) - if (be instanceof IPartHost partHost) { - // 与 RenderBlockOutlineHook 相同,基于世界坐标选取部件 - SelectedPart sel = partHost.selectPartWorld(context.getClickLocation()); + + // 2. AE2 部件 + String ae2Name = eap$handleAE2Block(blockEntity, clickLocation); + if (ae2Name != null && !ae2Name.isBlank()) { + return ae2Name; + } + + // 3. GregTech CEu 配方翻译 + String gtceuName = eap$handleGTCEuBlock(blockEntity); + if (gtceuName != null && !gtceuName.isBlank()) { + return gtceuName; + } + + // 4. 方块名称 + return state.getBlock().getName().getString(); + } + + /** + * 处理 GregTech CEu 方块,获取配方翻译名 + */ + @Unique + private String eap$handleGTCEuBlock(BlockEntity blockEntity) { + if (blockEntity instanceof MetaMachineBlockEntity meta) { + if (meta.metaMachine instanceof WorkableElectricMultiblockMachine workable) { + String recipeName = workable.getRecipeType().toString(); + // e.g., gtceu.cracker + String translationKey = "gtceu." + recipeName.replace("gtceu:",""); + // 客户端直接使用 I18n + return I18n.get(translationKey, recipeName); // e.g., 裂化机 + } + } + return null; + } + + /** + * 处理 AE2 方块,获取部件或外观名称 + */ + @Unique + private String eap$handleAE2Block(BlockEntity blockEntity, Vec3 clickLocation) { + if (blockEntity instanceof IPartHost partHost) { + SelectedPart sel = partHost.selectPartWorld(clickLocation); if (sel.part != null) { - var stack = new net.minecraft.world.item.ItemStack(sel.part.getPartItem()); - name = stack.getHoverName().getString(); + ItemStack stack = new ItemStack(sel.part.getPartItem()); + return stack.getHoverName().getString(); } else if (sel.facade != null) { - var stack = sel.facade.getItemStack(); + ItemStack stack = sel.facade.getItemStack(); if (!stack.isEmpty()) { - name = stack.getHoverName().getString(); + return stack.getHoverName().getString(); } } } - if (be instanceof Nameable nm) { - var custom = nm.getCustomName(); - if (custom != null) { - name = custom.getString(); - } - } - if (name == null || name.isBlank()) { - name = state.getBlock().getName().getString(); - } - boolean ok = tryCopyToClipboard(Minecraft.getInstance(), name); - player.displayClientMessage(Component.literal(ok - ? ("已复制方块/部件名: " + name) - : "复制失败:整合包可能限制剪贴板或未聚焦窗口"), true); - // 拦截默认行为 - cir.setReturnValue(InteractionResult.SUCCESS); + return null; } /** @@ -143,27 +179,33 @@ public abstract class QuartzCuttingKnifeItemMixin { * 2) GLFW.glfwSetClipboardString(Window handle) * 3) AWT 系统剪贴板(可能在某些整合包/无头环境不可用) */ - private static boolean tryCopyToClipboard(Minecraft mc, String text) { - if (text == null) return false; + @Unique + private static boolean eap$tryCopyToClipboard(Minecraft mc, String text) { + if (text == null || text.isBlank()) return false; // 确保在游戏主线程执行 if (!mc.isSameThread()) { AtomicBoolean result = new AtomicBoolean(false); CountDownLatch latch = new CountDownLatch(1); mc.execute(() -> { try { - result.set(doCopy(mc, text)); + result.set(eap$doCopy(mc, text)); } finally { latch.countDown(); } }); - try { latch.await(); } catch (InterruptedException ignored) {} + try { + latch.await(); + } catch (InterruptedException e) { + LOGGER.error("剪贴板复制线程中断: {}", e.getMessage()); + } return result.get(); } else { - return doCopy(mc, text); + return eap$doCopy(mc, text); } } - private static boolean doCopy(Minecraft mc, String text) { + @Unique + private static boolean eap$doCopy(Minecraft mc, String text) { try { mc.keyboardHandler.setClipboard(text); return true; From 0df716570a77365f363e372491f342d329749d15 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Wed, 20 Aug 2025 01:02:59 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9gtceu=E5=A4=9A?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E6=9C=BA=E5=99=A8=E5=A4=8D=E5=88=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae2/QuartzCuttingKnifeItemMixin.java | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/QuartzCuttingKnifeItemMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/QuartzCuttingKnifeItemMixin.java index 8d76785..5e1aadc 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/QuartzCuttingKnifeItemMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/QuartzCuttingKnifeItemMixin.java @@ -3,8 +3,6 @@ package com.extendedae_plus.mixin.ae2; import appeng.api.parts.IPartHost; import appeng.api.parts.SelectedPart; import appeng.items.tools.quartz.QuartzCuttingKnifeItem; -import com.gregtechceu.gtceu.api.blockentity.MetaMachineBlockEntity; -import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.mojang.blaze3d.platform.Window; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.language.I18n; @@ -23,6 +21,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; +import net.minecraftforge.fml.ModList; import org.lwjgl.glfw.GLFW; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,6 +33,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.awt.*; import java.awt.datatransfer.StringSelection; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; @@ -127,9 +128,11 @@ public abstract class QuartzCuttingKnifeItemMixin { } // 3. GregTech CEu 配方翻译 - String gtceuName = eap$handleGTCEuBlock(blockEntity); - if (gtceuName != null && !gtceuName.isBlank()) { - return gtceuName; + if (ModList.get().isLoaded("gtceu")) { + String gtceuName = eap$handleGTCEuBlock(blockEntity); + if (gtceuName != null && !gtceuName.isBlank()) { + return gtceuName; + } } // 4. 方块名称 @@ -141,16 +144,40 @@ public abstract class QuartzCuttingKnifeItemMixin { */ @Unique private String eap$handleGTCEuBlock(BlockEntity blockEntity) { - if (blockEntity instanceof MetaMachineBlockEntity meta) { - if (meta.metaMachine instanceof WorkableElectricMultiblockMachine workable) { - String recipeName = workable.getRecipeType().toString(); - // e.g., gtceu.cracker - String translationKey = "gtceu." + recipeName.replace("gtceu:",""); - // 客户端直接使用 I18n - return I18n.get(translationKey, recipeName); // e.g., 裂化机 + try { + // 动态加载 GTCEu 类 + Class> metaMachineBlockEntityClass = Class.forName("com.gregtechceu.gtceu.api.blockentity.MetaMachineBlockEntity"); + Class> workableElectricMultiblockMachineClass = Class.forName("com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine"); + + if (metaMachineBlockEntityClass.isInstance(blockEntity)) { + // 获取 metaMachine 字段 + Field metaMachineField = metaMachineBlockEntityClass.getDeclaredField("metaMachine"); + metaMachineField.setAccessible(true); + Object metaMachine = metaMachineField.get(blockEntity); + + if (workableElectricMultiblockMachineClass.isInstance(metaMachine)) { + // 调用 getRecipeType 方法 + Method getRecipeTypeMethod = workableElectricMultiblockMachineClass.getMethod("getRecipeType"); + getRecipeTypeMethod.setAccessible(true); + Object recipeType = getRecipeTypeMethod.invoke(metaMachine); + + if (recipeType != null) { + // 调用 toString 方法获取配方名 + String recipeName = recipeType.toString().replace("gtceu:", ""); + String translationKey = "gtceu." + recipeName; // e.g., gtceu.cracker + // 客户端使用 I18n + return I18n.get(translationKey, recipeName); // e.g., 裂化机 + } + } } + } catch (ClassNotFoundException e) { + LOGGER.info("GregTech CEu 类未找到,跳过配方翻译处理"); + return null; // GTCEu 不可用 + } catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e) { + LOGGER.error("处理 GTCEu 配方翻译失败: {}", e.getMessage()); + return null; // 反射失败 } - return null; + return null; // 非 GTCEu 方块实体 } /**