为样板供应器添加升级槽

This commit is contained in:
GaLicn 2025-09-22 18:24:29 +08:00
parent 45121b8647
commit 8a4950f244
8 changed files with 326 additions and 0 deletions

View File

@ -0,0 +1,12 @@
package com.extendedae_plus.bridge;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.menu.ToolboxMenu;
public interface IUpgradableMenu {
ToolboxMenu getToolbox();
IUpgradeInventory getUpgrades();
default boolean hasUpgrade(net.minecraft.world.level.ItemLike upgradeCard) {
return getUpgrades().isInstalled(upgradeCard);
}
}

View File

@ -0,0 +1,48 @@
package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.api.upgrades.Upgrades;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.ToolboxPanel;
import appeng.client.gui.widgets.UpgradesPanel;
import appeng.core.localization.GuiText;
import appeng.menu.SlotSemantics;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.bridge.IUpgradableMenu;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
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.CallbackInfo;
import java.util.ArrayList;
import java.util.List;
@Mixin(value = PatternProviderScreen.class, remap = false)
public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> {
@Inject(method = "<init>", at = @At("TAIL"))
private void extendedae_plus$initUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
this.widgets.add("upgrades", new UpgradesPanel(
menu.getSlots(SlotSemantics.UPGRADE),
this::extendedae_plus$getCompatibleUpgrades));
if (((IUpgradableMenu) menu).getToolbox().isPresent()) {
this.widgets.add("toolbox", new ToolboxPanel(style, ((IUpgradableMenu) menu).getToolbox().getName()));
}
}
@Unique
private List<Component> extendedae_plus$getCompatibleUpgrades() {
var list = new ArrayList<Component>();
list.add(GuiText.CompatibleUpgrades.text());
list.addAll(Upgrades.getTooltipLinesForMachine(((IUpgradableMenu) menu).getUpgrades().getUpgradableItem()));
return list;
}
public PatternProviderScreenUpgradesMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
}

View File

@ -0,0 +1,21 @@
package com.extendedae_plus.mixin.ae2.helpers.patternprovider;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
/**
* PatternProviderLogicHost 作为 IUpgradeableObject 的代理菜单可从 host 获取升级槽
*/
@Mixin(value = PatternProviderLogicHost.class, remap = false)
public interface PatternProviderLogicHostUpgradesMixin extends IUpgradeableObject {
@Shadow PatternProviderLogic getLogic();
@Override
default IUpgradeInventory getUpgrades() {
return ((IUpgradeableObject) this.getLogic()).getUpgrades();
}
}

View File

@ -0,0 +1,30 @@
package com.extendedae_plus.mixin.ae2.helpers.patternprovider;
import appeng.helpers.patternprovider.PatternProviderLogic;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
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;
/**
* 注入到 PatternProviderLogic.Ticker 的每tick回调驱动无线链接状态更新
*/
@Mixin(targets = "appeng.helpers.patternprovider.PatternProviderLogic$Ticker", remap = false)
public abstract class PatternProviderLogicTickerMixin {
// Mixin 访问内部类的外部引用字段javac 生成名 this$0
@Shadow(remap = false)
@Final
private PatternProviderLogic this$0;
@Inject(method = "tickingRequest", at = @At("TAIL"))
private void extendedae_plus$tickTail(appeng.api.networking.IGridNode node, int ticksSinceLastCall,
CallbackInfoReturnable<appeng.api.networking.ticking.TickRateModulation> cir) {
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) {
bridge.extendedae_plus$updateWirelessLink();
}
}
}

View File

@ -0,0 +1,112 @@
package com.extendedae_plus.mixin.ae2.helpers.patternprovider;
import appeng.api.networking.IManagedGridNode;
import appeng.api.networking.security.IActionSource;
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 com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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 net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import java.util.List;
/**
* PatternProviderLogic 注入升级槽实现 IUpgradeableObject
* 仅负责升级槽的持久化/掉落/清空与初始化不改变原有逻辑
*/
@Mixin(value = PatternProviderLogic.class, remap = false)
public abstract class PatternProviderLogicUpgradesMixin implements IUpgradeableObject, InterfaceWirelessLinkBridge {
@Unique
private IUpgradeInventory extendedae_plus$upgrades = UpgradeInventories.empty();
@Unique
private WirelessSlaveLink extendedae_plus$link;
@Final
@Shadow
private PatternProviderLogicHost host;
@Final
@Shadow
private IManagedGridNode mainNode;
@Final
@Shadow
private IActionSource actionSource;
@Unique
private void extendedae_plus$onUpgradesChanged() {
this.host.saveChanges();
// 读取频道卡更新无线链接频率
long channel = 0L;
for (var stack : this.extendedae_plus$upgrades) {
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
channel = ChannelCardItem.getChannel(stack);
break;
}
}
if (extendedae_plus$link == null) {
var endpoint = new GenericNodeEndpointImpl(() -> host.getBlockEntity(), () -> this.mainNode.getNode());
extendedae_plus$link = new WirelessSlaveLink(endpoint);
}
extendedae_plus$link.setFrequency(channel);
extendedae_plus$link.updateStatus();
}
@Override
public IUpgradeInventory getUpgrades() {
return this.extendedae_plus$upgrades;
}
@Inject(method = "<init>(Lappeng/api/networking/IManagedGridNode;Lappeng/helpers/patternprovider/PatternProviderLogicHost;I)V",
at = @At("TAIL"))
private void extendedae_plus$initUpgrades(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
this.extendedae_plus$upgrades = UpgradeInventories.forMachine(host.getTerminalIcon().getItem(), 1, this::extendedae_plus$onUpgradesChanged);
}
@Inject(method = "writeToNBT", at = @At("TAIL"))
private void extendedae_plus$saveUpgrades(CompoundTag tag, CallbackInfo ci) {
this.extendedae_plus$upgrades.writeToNBT(tag, "upgrades");
}
@Inject(method = "readFromNBT", at = @At("TAIL"))
private void extendedae_plus$loadUpgrades(CompoundTag tag, CallbackInfo ci) {
this.extendedae_plus$upgrades.readFromNBT(tag, "upgrades");
}
@Inject(method = "addDrops", at = @At("TAIL"))
private void extendedae_plus$dropUpgrades(List<ItemStack> drops, CallbackInfo ci) {
for (var stack : this.extendedae_plus$upgrades) {
if (!stack.isEmpty()) {
drops.add(stack);
}
}
}
@Inject(method = "clearContent", at = @At("TAIL"))
private void extendedae_plus$clearUpgrades(CallbackInfo ci) {
this.extendedae_plus$upgrades.clear();
}
@Override
public void extendedae_plus$updateWirelessLink() {
if (extendedae_plus$link != null) {
extendedae_plus$link.updateStatus();
}
}
}

View File

@ -0,0 +1,49 @@
package com.extendedae_plus.mixin.ae2.menu;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.AEBaseMenu;
import appeng.menu.ToolboxMenu;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.bridge.IUpgradableMenu;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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;
@Mixin(value = PatternProviderMenu.class, remap = false)
public abstract class PatternProviderMenuUpgradesMixin extends AEBaseMenu implements IUpgradableMenu {
@Final
@Shadow protected PatternProviderLogic logic;
@Unique
private ToolboxMenu extendedae_plus$toolbox;
@Inject(method = "<init>(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V",
at = @At("TAIL"))
private void extendedae_plus$initUpgrades(MenuType<?> menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
this.extendedae_plus$toolbox = new ToolboxMenu(this);
this.setupUpgrades(((IUpgradeableObject) host).getUpgrades());
}
@Override
public ToolboxMenu getToolbox() {
return this.extendedae_plus$toolbox;
}
@Override
public IUpgradeInventory getUpgrades() {
return ((IUpgradeableObject) this.logic).getUpgrades();
}
public PatternProviderMenuUpgradesMixin(MenuType<?> menuType, int id, Inventory playerInventory, Object host) {
super(menuType, id, playerInventory, host);
}
}

View File

@ -0,0 +1,49 @@
package com.extendedae_plus.wireless.endpoint;
import appeng.api.networking.IGridNode;
import com.extendedae_plus.wireless.IWirelessEndpoint;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.Objects;
import java.util.function.Supplier;
/**
* 通用 IWirelessEndpoint通过提供方块实体与节点的 Supplier 实现
*/
public class GenericNodeEndpointImpl implements IWirelessEndpoint {
private final Supplier<BlockEntity> blockEntitySupplier;
private final Supplier<IGridNode> nodeSupplier;
public GenericNodeEndpointImpl(Supplier<BlockEntity> blockEntitySupplier, Supplier<IGridNode> nodeSupplier) {
this.blockEntitySupplier = Objects.requireNonNull(blockEntitySupplier);
this.nodeSupplier = Objects.requireNonNull(nodeSupplier);
}
@Override
public ServerLevel getServerLevel() {
var be = blockEntitySupplier.get();
if (be == null) return null;
Level lvl = be.getLevel();
return (lvl instanceof ServerLevel) ? (ServerLevel) lvl : null;
}
@Override
public BlockPos getBlockPos() {
var be = blockEntitySupplier.get();
return be != null ? be.getBlockPos() : BlockPos.ZERO;
}
@Override
public IGridNode getGridNode() {
return nodeSupplier.get();
}
@Override
public boolean isEndpointRemoved() {
var be = blockEntitySupplier.get();
return be == null || be.isRemoved();
}
}

View File

@ -20,6 +20,7 @@
"ae2.client.gui.PatternEncodingTermScreenMixin",
"ae2.client.gui.PatternProviderCloseMixin",
"ae2.client.gui.PatternProviderScreenMixin",
"ae2.client.gui.PatternProviderScreenUpgradesMixin",
"ae2.client.gui.SlotGridLayoutMixin",
"ae2.menu.CraftConfirmMenuGoBackMixin",
"extendedae.accessor.GuiExPatternTerminalAccessor",
@ -62,6 +63,10 @@
"ae2.menu.PatternEncodingTermMenuMixin",
"ae2.menu.PatternProviderMenuAdvancedMixin",
"ae2.menu.PatternProviderMenuDoublingMixin",
"ae2.helpers.patternprovider.PatternProviderLogicUpgradesMixin",
"ae2.helpers.patternprovider.PatternProviderLogicHostUpgradesMixin",
"ae2.menu.PatternProviderMenuUpgradesMixin",
"ae2.helpers.patternprovider.PatternProviderLogicTickerMixin",
"ae2WTlib.ContainerUWirelessExPatternTerminalMixin",
"extendedae.common.PartExPatternProviderMixin",
"extendedae.common.TileExPatternProviderMixin",