新增虚拟合成卡

This commit is contained in:
GaLi 2025-11-24 15:49:00 +08:00
parent 8e87508b62
commit d10c26d3e3
14 changed files with 258 additions and 42 deletions

View File

@ -0,0 +1,13 @@
package com.extendedae_plus.ae.items;
import appeng.items.materials.UpgradeCardItem;
/**
* 虚拟合成卡用于自动完成样板供应器的合成任务
* 逻辑由 PatternProviderLogic mixin 处理此处仅作为升级卡物品本体
*/
public class VirtualCraftingCardItem extends UpgradeCardItem {
public VirtualCraftingCardItem(Properties properties) {
super(properties);
}
}

View File

@ -4,9 +4,12 @@ import com.extendedae_plus.ExtendedAEPlus;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
import java.util.List;
public final class ModCreativeTabs {
public static final DeferredRegister<CreativeModeTab> TABS =
DeferredRegister.create(Registries.CREATIVE_MODE_TAB, ExtendedAEPlus.MODID);
@ -15,24 +18,26 @@ public final class ModCreativeTabs {
.title(Component.translatable("itemGroup." + ExtendedAEPlus.MODID + ".main"))
.icon(() -> ModItems.WIRELESS_TRANSCEIVER.get().getDefaultInstance())
.displayItems((params, output) -> {
// 将本模组物品加入创造物品栏
output.accept(ModItems.WIRELESS_TRANSCEIVER.get());
output.accept(ModItems.NETWORK_PATTERN_CONTROLLER.get());
output.accept(ModItems.ACCELERATOR_4x.get());
output.accept(ModItems.ACCELERATOR_16x.get());
output.accept(ModItems.ACCELERATOR_64x.get());
output.accept(ModItems.ACCELERATOR_256x.get());
output.accept(ModItems.ACCELERATOR_1024x.get());
output.accept(ModItems.ASSEMBLER_MATRIX_UPLOAD_CORE.get());
output.accept(ModItems.CHANNEL_CARD.get());
output.accept(ModItems.ENTITY_TICKER_PART_ITEM.get());
// 放入四个预设的 stacksx2,x4,x8,x16使用 ModItems 工厂创建
output.accept(ModItems.createEntitySpeedCardStack((byte) 2));
output.accept(ModItems.createEntitySpeedCardStack((byte) 4));
output.accept(ModItems.createEntitySpeedCardStack((byte) 8));
output.accept(ModItems.createEntitySpeedCardStack((byte) 16));
List.of(
ModItems.WIRELESS_TRANSCEIVER.get().getDefaultInstance(),
ModItems.NETWORK_PATTERN_CONTROLLER.get().getDefaultInstance(),
ModItems.ACCELERATOR_4x.get().getDefaultInstance(),
ModItems.ACCELERATOR_16x.get().getDefaultInstance(),
ModItems.ACCELERATOR_64x.get().getDefaultInstance(),
ModItems.ACCELERATOR_256x.get().getDefaultInstance(),
ModItems.ACCELERATOR_1024x.get().getDefaultInstance(),
ModItems.ASSEMBLER_MATRIX_UPLOAD_CORE.get().getDefaultInstance(),
ModItems.CHANNEL_CARD.get().getDefaultInstance(),
ModItems.VIRTUAL_CRAFTING_CARD.get().getDefaultInstance(),
ModItems.ENTITY_TICKER_PART_ITEM.get().getDefaultInstance(),
ModItems.INFINITY_BIGINTEGER_CELL_ITEM.get().getDefaultInstance()
).forEach(output::accept);
output.accept(ModItems.INFINITY_BIGINTEGER_CELL_ITEM.get());
// 放入四个预设的 stacksx2,x4,x8,x16使用 ModItems 工厂创建
for (byte multiplier : new byte[] {2, 4, 8, 16}) {
ItemStack stack = ModItems.createEntitySpeedCardStack(multiplier);
output.accept(stack);
}
})
.build());

View File

@ -5,6 +5,7 @@ import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem;
import com.extendedae_plus.ae.items.EntitySpeedTickerPartItem;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem;
import com.extendedae_plus.ae.items.VirtualCraftingCardItem;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -70,6 +71,11 @@ public final class ModItems {
() -> new ChannelCardItem(new Item.Properties())
);
public static final DeferredItem<VirtualCraftingCardItem> VIRTUAL_CRAFTING_CARD = ITEMS.register(
"virtual_crafting_card",
() -> new VirtualCraftingCardItem(new Item.Properties())
);
public static final DeferredItem<Item> INFINITY_BIGINTEGER_CELL_ITEM = ITEMS.register(
"infinity_biginteger_cell", InfinityBigIntegerCellItem::new
);

View File

@ -16,37 +16,41 @@ public class UpgradeCards {
// 使用单一的 UpgradeCard Item 作为注册键总共允许安装 4 不同等级由 ItemStack NBT 区分
Upgrades.add(ModItems.ENTITY_SPEED_CARD.get(), ModItems.ENTITY_TICKER_PART_ITEM.get(), 4, "group.entity_ticker.name");
// 频道卡对齐旧版注册 AE2 接口方块与部件
//
String interfaceGroup = GuiText.Interface.getTranslationKey();
Upgrades.add(ModItems.CHANNEL_CARD.get(), AEBlocks.INTERFACE, 1, interfaceGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), AEParts.INTERFACE, 1, interfaceGroup);
// 频道卡AE2 样板供应器方块与部件
//
String patternProviderGroup = "group.pattern_provider.name";
Upgrades.add(ModItems.CHANNEL_CARD.get(), AEBlocks.PATTERN_PROVIDER, 1, patternProviderGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), AEParts.PATTERN_PROVIDER, 1, patternProviderGroup);
Upgrades.add(ModItems.VIRTUAL_CRAFTING_CARD.get(), AEBlocks.PATTERN_PROVIDER, 1, patternProviderGroup);
Upgrades.add(ModItems.VIRTUAL_CRAFTING_CARD.get(), AEParts.PATTERN_PROVIDER, 1, patternProviderGroup);
// 频道卡AE2 I/O 总线与存储总线部件
//
String ioBusGroup = GuiText.IOBuses.getTranslationKey();
String storageGroup = "group.storage.name";
Upgrades.add(ModItems.CHANNEL_CARD.get(), AEParts.IMPORT_BUS, 1, ioBusGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), AEParts.EXPORT_BUS, 1, ioBusGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), AEParts.STORAGE_BUS, 1, storageGroup);
// 频道卡ExtendedAE 扩展组件支持强依赖直接引用
// 扩展接口
//
//
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.EX_INTERFACE, 1, interfaceGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.EX_INTERFACE_PART, 1, interfaceGroup);
// 扩展样板供应器
//
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.EX_PATTERN_PROVIDER, 1, patternProviderGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.EX_PATTERN_PROVIDER_PART, 1, patternProviderGroup);
Upgrades.add(ModItems.VIRTUAL_CRAFTING_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.EX_PATTERN_PROVIDER, 1, patternProviderGroup);
Upgrades.add(ModItems.VIRTUAL_CRAFTING_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.EX_PATTERN_PROVIDER_PART, 1, patternProviderGroup);
// 扩展 I/O 总线
//
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.EX_IMPORT_BUS, 1, ioBusGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.EX_EXPORT_BUS, 1, ioBusGroup);
// 其他扩展总线标签精确阈值等
//
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.TAG_STORAGE_BUS, 1, storageGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.TAG_EXPORT_BUS, 1, ioBusGroup);
Upgrades.add(ModItems.CHANNEL_CARD.get(), com.glodblock.github.extendedae.common.EAESingletons.MOD_STORAGE_BUS, 1, storageGroup);

View File

@ -0,0 +1,12 @@
package com.extendedae_plus.mixin.ae2.accessor;
import appeng.crafting.execution.CraftingCpuLogic;
import appeng.crafting.execution.ExecutingCraftingJob;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(value = CraftingCpuLogic.class, remap = false)
public interface CraftingCpuLogicAccessor {
@Accessor("job")
ExecutingCraftingJob eap$getJob();
}

View File

@ -0,0 +1,14 @@
package com.extendedae_plus.mixin.ae2.accessor;
import appeng.api.crafting.IPatternDetails;
import appeng.crafting.execution.ExecutingCraftingJob;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(value = ExecutingCraftingJob.class, remap = false)
public interface ExecutingCraftingJobAccessor {
@Accessor("tasks")
Map<IPatternDetails, ExecutingCraftingJobTaskProgressAccessor> eap$getTasks();
}

View File

@ -0,0 +1,10 @@
package com.extendedae_plus.mixin.ae2.accessor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(targets = "appeng.crafting.execution.ExecutingCraftingJob$TaskProgress", remap = false)
public interface ExecutingCraftingJobTaskProgressAccessor {
@Accessor("value")
long eap$getValue();
}

View File

@ -1,22 +1,30 @@
package com.extendedae_plus.mixin.ae2.compat;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.IGridConnection;
import appeng.api.networking.IManagedGridNode;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.security.IActionSource;
import appeng.api.stacks.KeyCounter;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.api.upgrades.UpgradeInventories;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.bridge.CompatUpgradeProvider;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.mixin.ae2.accessor.CraftingCpuLogicAccessor;
import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobAccessor;
import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobTaskProgressAccessor;
import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@ -25,6 +33,7 @@ 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.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@ -52,6 +61,9 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Unique
private boolean eap$compatHasInitialized = false;
@Unique
private boolean eap$compatVirtualCraftingEnabled = false;
@Final
@Shadow
private PatternProviderLogicHost host;
@ -72,7 +84,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 未安装AppliedFlux我们需要提供升级槽
this.eap$compatUpgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(), 1, this::eap$compatOnUpgradesChanged);
host.getTerminalIcon().getItem(), 2, this::eap$compatOnUpgradesChanged);
} else {
// 安装了AppliedFlux我们不提供升级槽但保留空的兼容槽用于备用
this.eap$compatUpgrades = UpgradeInventories.empty();
@ -92,6 +104,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
eap$compatLastChannel = -1;
eap$compatHasInitialized = false;
eap$compatInitializeChannelLink();
eap$compatSyncVirtualCraftingState();
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 兼容升级变更处理失败", t);
}
@ -136,6 +149,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
eap$compatLastChannel = -1;
eap$compatHasInitialized = false;
eap$compatInitializeChannelLink();
eap$compatSyncVirtualCraftingState();
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 读取兼容升级失败", t);
}
@ -260,6 +274,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
}
if (!found) {
eap$compatSyncVirtualCraftingState();
if (eap$compatLink != null) {
eap$compatLink.setFrequency(0L);
eap$compatLink.updateStatus();
@ -309,6 +324,8 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
});
}
eap$compatSyncVirtualCraftingState();
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 初始化频道链接失败", t);
}
@ -356,6 +373,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
eap$compatLastChannel = -1; // 强制重新初始化
eap$compatHasInitialized = false;
eap$compatInitializeChannelLink();
eap$compatSyncVirtualCraftingState();
}
break;
}
@ -365,6 +383,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
eap$compatLastChannel = -1;
eap$compatHasInitialized = false;
eap$compatInitializeChannelLink();
eap$compatSyncVirtualCraftingState();
}
} catch (Throwable t) {
}
@ -416,15 +435,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
// CompatUpgradeProvider 实现仅在未安装 appflux 时由我们提供升级槽
@Unique
private boolean eap$hasChannelCard(IUpgradeInventory inventory) {
if (inventory == null) {
return false;
}
for (ItemStack stack : inventory) {
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
return true;
}
}
return false;
return eap$compatInventoryContains(inventory, ModItems.CHANNEL_CARD.get());
}
/**
@ -455,4 +466,117 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
public IUpgradeInventory eap$getCompatUpgrades() {
return this.eap$compatUpgrades != null ? this.eap$compatUpgrades : UpgradeInventories.empty();
}
@Inject(method = "pushPattern", at = @At("RETURN"), cancellable = true)
private void eap$compatAfterPushPattern(IPatternDetails patternDetails, KeyCounter[] inputHolder, CallbackInfoReturnable<Boolean> cir) {
if (cir.getReturnValueZ()) {
eap$compatTryVirtualCompletion(patternDetails);
}
}
@Unique
private void eap$compatTryVirtualCompletion(IPatternDetails patternDetails) {
if (!eap$compatVirtualCraftingEnabled) {
return;
}
var node = this.mainNode.getNode();
if (node == null) {
return;
}
var grid = node.getGrid();
if (grid == null) {
return;
}
var craftingService = grid.getCraftingService();
if (craftingService == null) {
return;
}
for (ICraftingCPU cpu : craftingService.getCpus()) {
if (!cpu.isBusy()) {
continue;
}
if (cpu instanceof CraftingCPUCluster cluster) {
if (cluster.craftingLogic instanceof CraftingCpuLogicAccessor logicAccessor) {
var job = logicAccessor.eap$getJob();
if (job instanceof ExecutingCraftingJobAccessor accessor) {
var tasks = accessor.eap$getTasks();
var progress = tasks.get(patternDetails);
if (progress == null && patternDetails != null) {
var patternDefinition = patternDetails.getDefinition();
for (var entry : tasks.entrySet()) {
var taskPattern = entry.getKey();
if (taskPattern == patternDetails) {
progress = entry.getValue();
break;
}
if (taskPattern != null && patternDefinition != null) {
var taskDefinition = taskPattern.getDefinition();
if (taskDefinition != null && taskDefinition.equals(patternDefinition)) {
progress = entry.getValue();
break;
}
}
}
}
if (progress != null && progress.eap$getValue() <= 1) {
cluster.cancelJob();
break;
}
}
}
}
}
}
@Unique
private void eap$compatSyncVirtualCraftingState() {
try {
IUpgradeInventory upgrades = eap$compatGetEffectiveUpgrades();
this.eap$compatVirtualCraftingEnabled = eap$compatInventoryContains(upgrades, ModItems.VIRTUAL_CRAFTING_CARD.get());
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 同步虚拟合成卡状态失败", t);
}
}
@Unique
private IUpgradeInventory eap$compatGetEffectiveUpgrades() {
IUpgradeInventory upgrades;
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
upgrades = this.eap$compatUpgrades;
} else {
upgrades = eap$getAppliedFluxUpgrades();
}
if (upgrades == null || upgrades == UpgradeInventories.empty()) {
if (upgrades != this.eap$compatUpgrades && this.eap$compatUpgrades != null) {
upgrades = this.eap$compatUpgrades;
} else {
var fallback = eap$getAppliedFluxUpgrades();
if (fallback != null) {
upgrades = fallback;
}
}
}
return upgrades;
}
@Unique
private boolean eap$compatInventoryContains(IUpgradeInventory inventory, Item item) {
if (inventory == null) {
return false;
}
for (ItemStack stack : inventory) {
if (!stack.isEmpty() && stack.getItem() == item) {
return true;
}
}
return false;
}
}

View File

@ -19,6 +19,7 @@
"item.extendedae_plus.network_pattern_controller": "Pattern Provider Status Controller",
"item.extendedae_plus.assembler_matrix_upload_core": "Assembly Matrix Upload Core",
"item.extendedae_plus.channel_card": "Channel Card",
"item.extendedae_plus.virtual_crafting_card": "Virtual Crafting Card",
"item.extendedae_plus.channel_card.channel": "Channel: %d",
"item.extendedae_plus.channel_card.channel.unset": "Channel: Unset",
"item.extendedae_plus.channel_card.set": "Channel set to: %d",
@ -116,9 +117,9 @@
"extendedae_plus.tooltip.owner.public": "Owner: Public",
"extendedae_plus.tooltip.channels": "Channels: %d",
"extendedae_plus.tooltip.channels_of": "Channels: %d / %d",
"extendedae_plus.tooltip.frequency": "Frequency: %d",
"extendedae_plus.tooltip.master_mode": "Mode: %s",
"extendedae_plus.tooltip.locked": "Status: %s",
"extendedae_plus.tooltip.frequency_secondary": "Frequency: %d",
"extendedae_plus.tooltip.master_mode_secondary": "Mode: %s",
"extendedae_plus.tooltip.locked_secondary": "Status: %s",
"gui.extendedae_plus.frequency_input.title": "Set Frequency",
"gui.extendedae_plus.frequency_input.field": "Frequency",

View File

@ -19,6 +19,7 @@
"item.extendedae_plus.network_pattern_controller": "样板供应器状态控制器",
"item.extendedae_plus.assembler_matrix_upload_core": "装配矩阵上传核心",
"item.extendedae_plus.channel_card": "频道卡",
"item.extendedae_plus.virtual_crafting_card": "虚拟合成卡",
"item.extendedae_plus.channel_card.channel": "频道: %d",
"item.extendedae_plus.channel_card.channel.unset": "频道: 未设置",
"item.extendedae_plus.channel_card.set": "频道已设置为: %d",
@ -78,9 +79,6 @@
"config.jade.plugin_extendedae_plus.wt_network_usable": "显示网络在线状态",
"config.jade.plugin_extendedae_plus.wt_channels": "显示频道使用情况",
"config.jade.plugin_extendedae_plus.wt_owner": "显示所有者信息",
"extendedae_plus.tooltip.frequency": "频率: %d",
"extendedae_plus.tooltip.master_mode": "模式: %s",
"extendedae_plus.tooltip.locked": "锁定状态: %s",
"screen.extendedae_plus.title": "ExtendedAE Plus 配置",
"config.extendedae_plus": "ExtendedAE Plus",
@ -118,7 +116,8 @@
"extendedae_plus.tooltip.channels_of": "频道: %d / %d",
"extendedae_plus.tooltip.frequency": "频率: %d",
"extendedae_plus.tooltip.master_mode": "模式: %s",
"extendedae_plus.tooltip.locked": "状态: %s",
"extendedae_plus.tooltip.locked": "锁定状态: %s",
"extendedae_plus.tooltip.locked_state": "状态: %s",
"gui.extendedae_plus.frequency_input.title": "设置频率",
"gui.extendedae_plus.frequency_input.field": "频率",

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "extendedae_plus:item/virtual_crafting_card"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

View File

@ -0,0 +1,19 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "ae2:advanced_card"
},
{
"item": "minecraft:crafting_table"
},
{
"item": "minecraft:lever"
}
],
"result": {
"id": "extendedae_plus:virtual_crafting_card",
"count": 1
}
}

View File

@ -17,6 +17,9 @@
"ae2.accessor.MEStorageMenuAccessor",
"ae2.accessor.PatternEncodingTermMenuAccessor",
"ae2.accessor.PatternProviderLogicAccessor",
"ae2.accessor.CraftingCpuLogicAccessor",
"ae2.accessor.ExecutingCraftingJobAccessor",
"ae2.accessor.ExecutingCraftingJobTaskProgressAccessor",
"ae2.accessor.PatternProviderLogicPatternInputsAccessor",
"ae2.accessor.PatternProviderLogicPatternsAccessor",
"ae2.accessor.PatternProviderMenuAdvancedAccessor",