Merge pull request #1 from C-H716/feature/gtceu-recipe-type-copy
添加对gtceu多模式机器复制支持
This commit is contained in:
commit
552c53400c
34
build.gradle
34
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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,46 @@
|
|||
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.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 net.minecraftforge.fml.ModList;
|
||||
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.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* 为 AE2 石英切割刀添加:潜行 + 右键 指向世界中的方块/部件(如线缆)时,复制其名称到剪贴板。
|
||||
*
|
||||
* <p>
|
||||
* 设计要点(参考原类 QuartzCuttingKnifeItem 的写法):
|
||||
* - 原本右键会打开 QuartzKnifeMenu。我们在客户端、潜行且命中方块时,优先拦截并复制名称。
|
||||
* - 名称优先取方块实体的自定义名(若实现 Nameable),否则使用方块显示名。
|
||||
|
|
@ -37,6 +48,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 +67,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 +93,111 @@ 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 配方翻译
|
||||
if (ModList.get().isLoaded("gtceu")) {
|
||||
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) {
|
||||
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; // 非 GTCEu 方块实体
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 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 +206,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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user