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;