提交
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package thaumicenergistics.mixins.ae2;
|
||||
|
||||
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.CallbackInfo;
|
||||
import appeng.api.util.KeyTypeSelection;
|
||||
import appeng.api.util.KeyTypeSelectionHost;
|
||||
import appeng.parts.reporting.AbstractTerminalPart;
|
||||
import thaumicenergistics.common.integration.appeng.AEssentiaKeyType;
|
||||
import thaumicenergistics.common.parts.EssentiaTerminalPart;
|
||||
|
||||
/**
|
||||
* 在普通 ME 终端的 KeyTypeSelection 中始终禁用 AEssentiaKeyType。
|
||||
* ⚠ KeyTypeSelection.readFromNBT (line 101) 会先全部 setValue(false) 再读 NBT 恢复,
|
||||
* 所以仅仅在构造器 TAIL 注入是不够的——readFromNBT 会把构造器的修改完全清掉。
|
||||
* 需要同时在 readFromNBT TAIL 再注入一次,确保 essentia 始终被禁用。
|
||||
* EssentiaTerminalPart 覆盖了 getKeyTypeSelection() 返回自己的实例,不受影响。
|
||||
*/
|
||||
@Mixin(AbstractTerminalPart.class)
|
||||
public abstract class MixinAbstractTerminalPart implements KeyTypeSelectionHost {
|
||||
|
||||
/**
|
||||
* 构造器 TAIL:新放置的终端,在 keyTypeSelection 初始化后禁用 essentia。
|
||||
*/
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void removeEssentiaFromRegularTerminal(CallbackInfo ci) {
|
||||
if ((Object) this instanceof EssentiaTerminalPart) return;
|
||||
doDisableEssentia();
|
||||
}
|
||||
|
||||
/**
|
||||
* readFromNBT TAIL:从存档加载后,readFromNBT 会重置 keyTypeSelection,
|
||||
* 需要再次禁用 essentia 以确保不会被 NBT 恢复重新打开。
|
||||
*/
|
||||
@Inject(method = "readFromNBT", at = @At("TAIL"))
|
||||
private void onReadFromNBT(CallbackInfo ci) {
|
||||
if ((Object) this instanceof EssentiaTerminalPart) return;
|
||||
doDisableEssentia();
|
||||
}
|
||||
|
||||
private void doDisableEssentia() {
|
||||
try {
|
||||
KeyTypeSelection sel = this.getKeyTypeSelection();
|
||||
// 先检查是否包含 AEssentiaKeyType(可能 keyTypeSelection 还没完全初始化)
|
||||
try {
|
||||
if (sel.isEnabled(AEssentiaKeyType.INSTANCE)) {
|
||||
sel.setEnabled(AEssentiaKeyType.INSTANCE, false);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// keyTypeSelection 中不包含 AEssentiaKeyType → 无需操作
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 构造阶段 host 为空,saveChanges() → getHost().markForSave() 会 NPE
|
||||
// setEnabled 内部的 map 修改已完成,catch 忽略
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package thaumicenergistics.mixins.ae2;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import thaumcraft.api.aspects.Aspect;
|
||||
import thaumcraft.api.aspects.AspectList;
|
||||
import thaumcraft.api.aspects.IEssentiaContainerItem;
|
||||
import appeng.api.stacks.GenericStack;
|
||||
import appeng.helpers.externalstorage.GenericStackInv;
|
||||
import appeng.util.ConfigMenuInventory;
|
||||
import thaumicenergistics.common.integration.appeng.AEssentiaKey;
|
||||
import thaumicenergistics.common.integration.appeng.AEssentiaKeyType;
|
||||
import thaumicenergistics.common.integration.tc.TCReflection;
|
||||
|
||||
/**
|
||||
* Mixin ConfigMenuInventory:在 AE2 原有的 ItemStack→AEKey 转换失败后,
|
||||
* 追加 Thaumcraft 源质容器物品的检测。
|
||||
*
|
||||
* 当玩家把装有源质的罐子({@code thaumcraft:jar_of_essentia})或药水
|
||||
* 拖入 AE 设备的筛选槽时,AE2 原生逻辑不认识这类物品,返回 null。
|
||||
* 此 Mixin 在原方法返回 null 后拦截,检测物品是否为
|
||||
* {@link IEssentiaContainerItem},若则提取其中的源质转为 {@link AEssentiaKey}。
|
||||
*
|
||||
* 这使得在没有 JEI 的情况下,玩家也能通过拖拽源质罐子到筛选槽来设置源质筛选。
|
||||
*/
|
||||
@Mixin(ConfigMenuInventory.class)
|
||||
public abstract class MixinConfigMenuInventory {
|
||||
|
||||
@Shadow(remap = false)
|
||||
@Final
|
||||
private GenericStackInv inv;
|
||||
|
||||
/**
|
||||
* 在 convertToSuitableStack 返回 null 时拦截,
|
||||
* 检测物品是否为 Thaumcraft 源质容器并转换。
|
||||
*/
|
||||
@Inject(
|
||||
method = "convertToSuitableStack",
|
||||
at = @At("RETURN"),
|
||||
cancellable = true
|
||||
)
|
||||
private void convertEssentiaContainer(ItemStack stack,
|
||||
CallbackInfoReturnable<@Nullable GenericStack> cir) {
|
||||
// 如果 AE2 原生逻辑已经成功转换,不做任何事
|
||||
if (cir.getReturnValue() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 空栈无需处理
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查底层 ConfigInventory 是否支持源质类型
|
||||
if (!this.inv.isSupportedType(AEssentiaKeyType.INSTANCE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检测是否为 Thaumcraft 源质容器物品
|
||||
if (stack.getItem() instanceof IEssentiaContainerItem containerItem) {
|
||||
AspectList aspects = containerItem.getAspects(stack);
|
||||
if (aspects == null || aspects.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 取第一个源质(罐子通常只装一种)
|
||||
Aspect firstAspect = aspects.getAspects()[0];
|
||||
if (firstAspect == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var aspectId = TCReflection.getAspectId(firstAspect);
|
||||
if (aspectId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AEssentiaKey key = AEssentiaKey.of(aspectId);
|
||||
long amount = aspects.getAmount(firstAspect);
|
||||
cir.setReturnValue(new GenericStack(key, amount));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package thaumicenergistics.mixins.ae2;
|
||||
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.CallbackInfo;
|
||||
@Mixin(targets = "appeng.crafting.CraftingTreeProcess", remap = false)
|
||||
public abstract class MixinCraftingTreeProcess {
|
||||
@Inject(method = "<init>", at = @At("RETURN"), remap = false)
|
||||
private void onConstructed(CallbackInfo ci) {}
|
||||
}
|
||||
Reference in New Issue
Block a user