From 53cb5886750c53e61ad54db061b73021611545a9 Mon Sep 17 00:00:00 2001 From: GaLi <3096147684@qq.com> Date: Thu, 26 Mar 2026 18:12:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=A2=91=E9=81=93=E5=8D=A1?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bridge/IInterfaceWirelessLinkBridge.java | 7 ++ .../PatternProviderLogicCompatMixin.java | 115 +++++++++++++----- .../InterfaceLogicChannelCardMixin.java | 56 +++++---- .../helpers/InterfaceLogicTickerMixin.java | 9 +- .../PatternProviderLogicTickerMixin.java | 9 +- .../automation/IOBusPartChannelCardMixin.java | 60 +++++---- .../IOBusPartTickerChannelCardMixin.java | 8 +- .../StorageBusPartChannelCardMixin.java | 60 +++++---- .../StorageBusPartTickerChannelCardMixin.java | 8 +- .../util/wireless/ChannelCardLinkHelper.java | 85 +++++++++++++ 10 files changed, 313 insertions(+), 104 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/util/wireless/ChannelCardLinkHelper.java diff --git a/src/main/java/com/extendedae_plus/api/bridge/IInterfaceWirelessLinkBridge.java b/src/main/java/com/extendedae_plus/api/bridge/IInterfaceWirelessLinkBridge.java index f83aea5..d71c9e0 100644 --- a/src/main/java/com/extendedae_plus/api/bridge/IInterfaceWirelessLinkBridge.java +++ b/src/main/java/com/extendedae_plus/api/bridge/IInterfaceWirelessLinkBridge.java @@ -47,4 +47,11 @@ public interface IInterfaceWirelessLinkBridge { default void eap$handleDelayedInit() { // 默认实现为空 } + + /** + * 指示宿主是否需要保持慢速 tick 以维持无线连接。 + */ + default boolean eap$shouldKeepTicking() { + return false; + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java index d91d133..fbfbd38 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java @@ -9,6 +9,7 @@ import appeng.api.stacks.KeyCounter; import appeng.api.upgrades.IUpgradeInventory; import appeng.api.upgrades.IUpgradeableObject; import appeng.api.upgrades.UpgradeInventories; +import appeng.blockentity.AEBaseBlockEntity; import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogicHost; import appeng.me.cluster.implementations.CraftingCPUCluster; @@ -18,10 +19,10 @@ import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge; import com.extendedae_plus.compat.PatternProviderLogicVirtualCompatBridge; import com.extendedae_plus.compat.UpgradeSlotCompat; import com.extendedae_plus.init.ModItems; -import com.extendedae_plus.items.materials.ChannelCardItem; import com.extendedae_plus.mixin.ae2.accessor.CraftingCpuLogicAccessor; import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobAccessor; import com.extendedae_plus.util.Logger; +import com.extendedae_plus.util.wireless.ChannelCardLinkHelper; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Final; @@ -34,6 +35,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.List; +import java.util.UUID; /** * PatternProviderLogic的兼容性Mixin @@ -52,6 +54,9 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Unique private long eap$compatLastChannel = -1; + @Unique + private UUID eap$compatLastOwner; + @Unique private boolean eap$compatClientConnected = false; @@ -82,10 +87,11 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Unique private void eap$compatOnUpgradesChanged() { try { - this.host.saveChanges(); + this.eap$compatNotifyHostChanged(); eap$compatSyncVirtualCraftingState(); if (UpgradeSlotCompat.shouldEnableChannelCard()) { eap$compatLastChannel = -1; + eap$compatLastOwner = null; eap$compatHasInitialized = false; eap$compatInitializeChannelLink(); } @@ -161,6 +167,7 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj eap$compatSyncVirtualCraftingState(); if (UpgradeSlotCompat.shouldEnableChannelCard()) { eap$compatLastChannel = -1; + eap$compatLastOwner = null; eap$compatHasInitialized = false; eap$compatInitializeChannelLink(); } @@ -169,7 +176,7 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj } } - // 监听 appflux 1.21.1 当前源码中的升级变化回调 + // 兼容较新的 appflux 升级变化回调命名 @Inject(method = "af_onUpgradesChanged", at = @At("TAIL"), remap = false, require = 0) private void eap$onAppfluxUpgradesChanged(CallbackInfo ci) { eap$compatOnExternalUpgradesChanged(); @@ -223,6 +230,7 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj if (UpgradeSlotCompat.shouldEnableChannelCard()) { eap$compatLastChannel = -1; + eap$compatLastOwner = null; eap$compatHasInitialized = false; eap$compatInitializeChannelLink(); } @@ -298,7 +306,11 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj try { if (eap$compatLink != null) { + boolean wasConnected = eap$compatLink.isConnected(); eap$compatLink.updateStatus(); + if (wasConnected != eap$compatLink.isConnected()) { + this.eap$compatNotifyHostChanged(); + } } } catch (Exception e) { Logger.EAP$LOGGER.error("兼容性无线链接更新失败", e); @@ -335,32 +347,33 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj long channel = 0L; boolean found = false; + UUID ownerUUID = null; // 获取升级槽 - 如果装了appflux则从appflux获取,否则从我们自己的获取 IUpgradeInventory upgrades = eap$compatGetEffectiveUpgradeInventory(); - - if (upgrades != null) { - for (ItemStack stack : upgrades) { - if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) { - channel = ChannelCardItem.getChannel(stack); - java.util.UUID ownerUUID = ChannelCardItem.getOwnerUUID(stack); - if (ownerUUID != null) { - // 保存ownerUUID到局部变量,后面设置到link - channel |= ((long) ownerUUID.hashCode() << 32); // 临时存储 - } - found = true; - break; - } - } + + var boundChannel = ChannelCardLinkHelper.findBoundChannel(upgrades, this::eap$getFallbackOwner); + if (boundChannel != null) { + channel = boundChannel.channel(); + ownerUUID = boundChannel.owner(); + found = true; } if (!found) { // 无频道卡:断开并视为初始化完成 - if (eap$compatLink != null) { - eap$compatLink.setFrequency(0L); - eap$compatLink.updateStatus(); - } + ChannelCardLinkHelper.disconnect(eap$compatLink); eap$compatHasInitialized = true; + eap$compatLastChannel = 0L; + eap$compatLastOwner = null; + this.eap$compatNotifyHostChanged(); + return; + } + + if (eap$compatLink != null + && ChannelCardLinkHelper.sameTarget(eap$compatLastChannel, eap$compatLastOwner, boundChannel)) { + if (eap$compatLink.isConnected()) { + eap$compatHasInitialized = true; + } return; } @@ -369,20 +382,12 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj eap$compatLink = new WirelessSlaveLink(endpoint); } - // 从频道卡重新读取ownerUUID并设置 - java.util.UUID cardOwner = null; - if (upgrades != null) { - for (ItemStack stack : upgrades) { - if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) { - cardOwner = ChannelCardItem.getOwnerUUID(stack); - channel = ChannelCardItem.getChannel(stack); // 重新读取正确的频率 - break; - } - } - } - eap$compatLink.setPlacerId(cardOwner); + eap$compatLink.setPlacerId(ownerUUID); eap$compatLink.setFrequency(channel); eap$compatLink.updateStatus(); + eap$compatLastChannel = channel; + eap$compatLastOwner = ownerUUID; + this.eap$compatNotifyHostChanged(); if (eap$compatLink.isConnected()) { eap$compatHasInitialized = true; @@ -418,6 +423,26 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj return UpgradeInventories.empty(); } + @Override + public boolean eap$shouldKeepTicking() { + if (!UpgradeSlotCompat.shouldEnableChannelCard()) { + return false; + } + + try { + if (host.getBlockEntity() == null || host.getBlockEntity().getLevel() == null + || host.getBlockEntity().getLevel().isClientSide) { + return false; + } + return ChannelCardLinkHelper.shouldKeepTicking( + eap$compatGetEffectiveUpgradeInventory(), + eap$compatLink, + eap$compatHasInitialized); + } catch (Throwable ignored) { + } + return false; + } + @Override public void eap$setClientWirelessState(boolean connected) { if (UpgradeSlotCompat.shouldEnableChannelCard()) { @@ -500,6 +525,7 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj try { eap$compatLastChannel = -1; + eap$compatLastOwner = null; eap$compatHasInitialized = false; eap$compatDelayedInitTicks = 10; try { @@ -511,4 +537,27 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj Logger.EAP$LOGGER.error("兼容性主节点状态变更处理失败", e); } } + + @Unique + private UUID eap$getFallbackOwner() { + if (this.mainNode != null && this.mainNode.getNode() != null) { + return this.mainNode.getNode().getOwningPlayerProfileId(); + } + return null; + } + + @Unique + private void eap$compatNotifyHostChanged() { + try { + this.host.saveChanges(); + } catch (Throwable ignored) { + } + + try { + if (this.host.getBlockEntity() instanceof AEBaseBlockEntity blockEntity) { + blockEntity.markForUpdate(); + } + } catch (Throwable ignored) { + } + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/InterfaceLogicChannelCardMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/InterfaceLogicChannelCardMixin.java index a960dd2..693e261 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/InterfaceLogicChannelCardMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/InterfaceLogicChannelCardMixin.java @@ -6,9 +6,8 @@ import appeng.helpers.InterfaceLogicHost; import com.extendedae_plus.ae.wireless.WirelessSlaveLink; import com.extendedae_plus.ae.wireless.endpoint.InterfaceNodeEndpointImpl; import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge; -import com.extendedae_plus.init.ModItems; -import com.extendedae_plus.items.materials.ChannelCardItem; -import net.minecraft.world.item.ItemStack; +import com.extendedae_plus.util.wireless.ChannelCardLinkHelper; +import java.util.UUID; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -32,6 +31,9 @@ public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirele @Unique private long eap$lastChannel = -1; + + @Unique + private UUID eap$lastOwner; @Unique private boolean eap$clientConnected = false; @@ -46,6 +48,7 @@ public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirele private void eap$onUpgradesChangedTail(CallbackInfo ci) { // 升级变更时重置标志并尝试初始化 eap$lastChannel = -1; + eap$lastOwner = null; eap$hasInitialized = false; eap$initializeChannelLink(); } @@ -54,6 +57,7 @@ public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirele private void eap$afterGridChanged(CallbackInfo ci) { // 网格状态变化时重置标志并设置延迟初始化 eap$lastChannel = -1; + eap$lastOwner = null; eap$hasInitialized = false; eap$delayedInitTicks = 10; // 适当增加延迟tick,等待网格完成引导 // 尝试唤醒设备,确保后续还能继续tick @@ -71,6 +75,7 @@ public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirele private void eap$afterReadNBT(net.minecraft.nbt.CompoundTag tag, CallbackInfo ci) { // 从 NBT加载时重置标志 eap$lastChannel = -1; + eap$lastOwner = null; eap$hasInitialized = false; // 直接尝试初始化 eap$initializeChannelLink(); @@ -101,25 +106,22 @@ public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirele } try { - long channel = 0L; - java.util.UUID ownerUUID = null; - boolean found = false; - for (ItemStack stack : getUpgrades()) { - if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) { - channel = ChannelCardItem.getChannel(stack); - ownerUUID = ChannelCardItem.getOwnerUUID(stack); - found = true; - break; - } - } + var boundChannel = ChannelCardLinkHelper.findBoundChannel(getUpgrades(), this::eap$getFallbackOwner); + long channel = boundChannel != null ? boundChannel.channel() : 0L; + boolean found = boundChannel != null; + UUID ownerUUID = boundChannel != null ? boundChannel.owner() : null; if (!found) { // 无频道卡:断开并视为初始化完成 - if (eap$link != null) { - eap$link.setFrequency(0L); - eap$link.updateStatus(); - } + ChannelCardLinkHelper.disconnect(eap$link); eap$hasInitialized = true; + eap$lastChannel = 0L; + eap$lastOwner = null; + return; + } + + if (eap$link != null && ChannelCardLinkHelper.sameTarget(eap$lastChannel, eap$lastOwner, boundChannel)) { + eap$hasInitialized = eap$link.isConnected(); return; } @@ -128,10 +130,11 @@ public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirele eap$link = new WirelessSlaveLink(endpoint); } - // 设置频道卡的所有者UUID(如果有的话) eap$link.setPlacerId(ownerUUID); eap$link.setFrequency(channel); eap$link.updateStatus(); + eap$lastChannel = channel; + eap$lastOwner = ownerUUID; if (eap$link.isConnected()) { eap$hasInitialized = true; // 设置初始化完成标志 @@ -175,6 +178,11 @@ public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirele public void eap$setClientWirelessState(boolean connected) { eap$clientConnected = connected; } + + @Override + public boolean eap$shouldKeepTicking() { + return ChannelCardLinkHelper.shouldKeepTicking(this.getUpgrades(), eap$link, eap$hasInitialized); + } @Override public boolean eap$hasTickInitialized() { @@ -219,6 +227,12 @@ public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirele } } } - - // eap$initializeChannelLink方法已在上面实现 + + @Unique + private UUID eap$getFallbackOwner() { + if (mainNode != null && mainNode.getNode() != null) { + return mainNode.getNode().getOwningPlayerProfileId(); + } + return null; + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/InterfaceLogicTickerMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/InterfaceLogicTickerMixin.java index dd1a038..0f0d999 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/InterfaceLogicTickerMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/InterfaceLogicTickerMixin.java @@ -1,5 +1,6 @@ package com.extendedae_plus.mixin.ae2.helpers; +import appeng.api.networking.ticking.TickRateModulation; import appeng.helpers.InterfaceLogic; import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge; import org.spongepowered.asm.mixin.Mixin; @@ -46,11 +47,17 @@ public abstract class InterfaceLogicTickerMixin { } } - @Inject(method = "tickingRequest", at = @At("TAIL"), remap = false) + @Inject(method = "tickingRequest", at = @At("TAIL"), remap = false, cancellable = true) private void eap$tickTail(appeng.api.networking.IGridNode node, int ticksSinceLastCall, CallbackInfoReturnable cir) { + if (node != null && node.getLevel() != null && node.getLevel().isClientSide) { + return; + } if (this.extendedae_plus$getOuterLogic() instanceof IInterfaceWirelessLinkBridge bridge) { bridge.eap$updateWirelessLink(); + if (bridge.eap$shouldKeepTicking() && cir.getReturnValue() == TickRateModulation.SLEEP) { + cir.setReturnValue(TickRateModulation.SLOWER); + } } } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/patternprovider/PatternProviderLogicTickerMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/patternprovider/PatternProviderLogicTickerMixin.java index 30f7ef3..267d664 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/patternprovider/PatternProviderLogicTickerMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/patternprovider/PatternProviderLogicTickerMixin.java @@ -1,5 +1,6 @@ package com.extendedae_plus.mixin.ae2.helpers.patternprovider; +import appeng.api.networking.ticking.TickRateModulation; import appeng.helpers.patternprovider.PatternProviderLogic; import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge; import org.spongepowered.asm.mixin.Mixin; @@ -44,11 +45,17 @@ public abstract class PatternProviderLogicTickerMixin { } } - @Inject(method = "tickingRequest", at = @At("TAIL")) + @Inject(method = "tickingRequest", at = @At("TAIL"), cancellable = true) private void eap$tickTail(appeng.api.networking.IGridNode node, int ticksSinceLastCall, CallbackInfoReturnable cir) { + if (node != null && node.getLevel() != null && node.getLevel().isClientSide) { + return; + } if (this.extendedae_plus$getOuterLogic() instanceof IInterfaceWirelessLinkBridge bridge) { bridge.eap$updateWirelessLink(); + if (bridge.eap$shouldKeepTicking() && cir.getReturnValue() == TickRateModulation.SLEEP) { + cir.setReturnValue(TickRateModulation.SLOWER); + } } } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/parts/automation/IOBusPartChannelCardMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/parts/automation/IOBusPartChannelCardMixin.java index 657ca0c..718e330 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/parts/automation/IOBusPartChannelCardMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/parts/automation/IOBusPartChannelCardMixin.java @@ -7,10 +7,10 @@ import appeng.parts.automation.IOBusPart; import com.extendedae_plus.ae.wireless.WirelessSlaveLink; import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl; import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge; -import com.extendedae_plus.init.ModItems; -import com.extendedae_plus.items.materials.ChannelCardItem; import com.extendedae_plus.util.Logger; +import com.extendedae_plus.util.wireless.ChannelCardLinkHelper; import net.minecraft.nbt.CompoundTag; +import java.util.UUID; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -28,6 +28,9 @@ public abstract class IOBusPartChannelCardMixin implements IInterfaceWirelessLin @Unique private long eap$lastChannel = -1; + + @Unique + private UUID eap$lastOwner; @Unique private boolean eap$clientConnected = false; @@ -57,6 +60,7 @@ public abstract class IOBusPartChannelCardMixin implements IInterfaceWirelessLin // 从NBT加载时重置频道缓存和tick初始化标志 if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) { eap$lastChannel = -1; + eap$lastOwner = null; eap$hasTickInitialized = false; // 重置标志,允许再次初始化 } } @@ -70,38 +74,32 @@ public abstract class IOBusPartChannelCardMixin implements IInterfaceWirelessLin try { IUpgradeInventory inv = this.getUpgrades(); - long channel = 0L; - java.util.UUID ownerUUID = null; - boolean found = false; - for (var stack : inv) { - if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) { - channel = ChannelCardItem.getChannel(stack); - ownerUUID = ChannelCardItem.getOwnerUUID(stack); - found = true; - break; - } - } - - // 频道没有变化则跳过 - if (eap$lastChannel == channel) { + var boundChannel = ChannelCardLinkHelper.findBoundChannel(inv, this::eap$getFallbackOwner); + long channel = boundChannel != null ? boundChannel.channel() : 0L; + boolean found = boundChannel != null; + UUID ownerUUID = boundChannel != null ? boundChannel.owner() : null; + + if (eap$link != null && ChannelCardLinkHelper.sameTarget(eap$lastChannel, eap$lastOwner, boundChannel)) { return; } eap$lastChannel = channel; - + eap$lastOwner = ownerUUID; + Logger.EAP$LOGGER.debug("[服务端] IOBus 初始化频道链接: found={}, channel={}", found, channel); - + if (!found) { // 无频道卡则断开 if (eap$link != null) { - eap$link.setFrequency(0L); - eap$link.updateStatus(); + ChannelCardLinkHelper.disconnect(eap$link); Logger.EAP$LOGGER.debug("[服务端] IOBus 断开频道链接"); // 立即通知客户端状态变化(断开连接无需延迟) ((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate(); } + eap$lastChannel = 0L; + eap$lastOwner = null; return; } - + if (eap$link == null) { var endpoint = new GenericNodeEndpointImpl( () -> ((appeng.parts.AEBasePart)(Object)this).getHost().getBlockEntity(), @@ -110,8 +108,7 @@ public abstract class IOBusPartChannelCardMixin implements IInterfaceWirelessLin eap$link = new WirelessSlaveLink(endpoint); Logger.EAP$LOGGER.debug("[服务端] IOBus 创建新的无线链接"); } - - // 设置频道卡的所有者UUID(如果有的话) + eap$link.setPlacerId(ownerUUID); eap$link.setFrequency(channel); eap$link.updateStatus(); @@ -130,6 +127,11 @@ public abstract class IOBusPartChannelCardMixin implements IInterfaceWirelessLin eap$link.updateStatus(); } } + + @Override + public boolean eap$shouldKeepTicking() { + return ChannelCardLinkHelper.shouldKeepTicking(this.getUpgrades(), eap$link, eap$hasTickInitialized); + } @Override public boolean eap$isWirelessConnected() { @@ -144,4 +146,16 @@ public abstract class IOBusPartChannelCardMixin implements IInterfaceWirelessLin public void eap$setClientWirelessState(boolean connected) { eap$clientConnected = connected; } + + @Unique + private UUID eap$getFallbackOwner() { + try { + var node = ((IActionHost) (Object) this).getActionableNode(); + if (node != null) { + return node.getOwningPlayerProfileId(); + } + } catch (Throwable ignored) { + } + return null; + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/parts/automation/IOBusPartTickerChannelCardMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/parts/automation/IOBusPartTickerChannelCardMixin.java index a964e14..06b415f 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/parts/automation/IOBusPartTickerChannelCardMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/parts/automation/IOBusPartTickerChannelCardMixin.java @@ -15,10 +15,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(value = IOBusPart.class, remap = false) public abstract class IOBusPartTickerChannelCardMixin { - @Inject(method = "tickingRequest", at = @At("TAIL")) + @Inject(method = "tickingRequest", at = @At("TAIL"), cancellable = true) private void eap$tickTail(IGridNode node, int ticksSinceLastCall, CallbackInfoReturnable cir) { + if (((IOBusPart) (Object) this).isClientSide()) { + return; + } if (this instanceof IInterfaceWirelessLinkBridge bridge) { bridge.eap$updateWirelessLink(); + if (bridge.eap$shouldKeepTicking() && cir.getReturnValue() == TickRateModulation.SLEEP) { + cir.setReturnValue(TickRateModulation.SLOWER); + } } } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/parts/storagebus/StorageBusPartChannelCardMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/parts/storagebus/StorageBusPartChannelCardMixin.java index ee6d970..7391c39 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/parts/storagebus/StorageBusPartChannelCardMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/parts/storagebus/StorageBusPartChannelCardMixin.java @@ -8,10 +8,10 @@ import appeng.parts.storagebus.StorageBusPart; import com.extendedae_plus.ae.wireless.WirelessSlaveLink; import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl; import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge; -import com.extendedae_plus.init.ModItems; -import com.extendedae_plus.items.materials.ChannelCardItem; import com.extendedae_plus.util.Logger; +import com.extendedae_plus.util.wireless.ChannelCardLinkHelper; import net.minecraft.nbt.CompoundTag; +import java.util.UUID; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -29,6 +29,9 @@ public abstract class StorageBusPartChannelCardMixin implements IInterfaceWirele @Unique private long eap$lastChannel = -1; + + @Unique + private UUID eap$lastOwner; @Unique private boolean eap$clientConnected = false; @@ -55,6 +58,7 @@ public abstract class StorageBusPartChannelCardMixin implements IInterfaceWirele if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) { // 从NBT加载时重置频道缓存,强制重新初始化 eap$lastChannel = -1; + eap$lastOwner = null; eap$initializeChannelLink(); } } @@ -68,37 +72,31 @@ public abstract class StorageBusPartChannelCardMixin implements IInterfaceWirele try { IUpgradeInventory inv = this.getUpgrades(); - long channel = 0L; - java.util.UUID ownerUUID = null; - boolean found = false; - for (var stack : inv) { - if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) { - channel = ChannelCardItem.getChannel(stack); - ownerUUID = ChannelCardItem.getOwnerUUID(stack); - found = true; - break; - } - } - - // 频道没有变化则跳过 - if (eap$lastChannel == channel) { + var boundChannel = ChannelCardLinkHelper.findBoundChannel(inv, this::eap$getFallbackOwner); + long channel = boundChannel != null ? boundChannel.channel() : 0L; + boolean found = boundChannel != null; + UUID ownerUUID = boundChannel != null ? boundChannel.owner() : null; + + if (eap$link != null && ChannelCardLinkHelper.sameTarget(eap$lastChannel, eap$lastOwner, boundChannel)) { return; } eap$lastChannel = channel; - + eap$lastOwner = ownerUUID; + Logger.EAP$LOGGER.debug("[服务端] StorageBus 初始化频道链接: found={}, channel={}", found, channel); - + if (!found) { if (eap$link != null) { - eap$link.setFrequency(0L); - eap$link.updateStatus(); + ChannelCardLinkHelper.disconnect(eap$link); Logger.EAP$LOGGER.debug("[服务端] StorageBus 断开频道链接"); // 通知客户端状态变化 ((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate(); } + eap$lastChannel = 0L; + eap$lastOwner = null; return; } - + if (eap$link == null) { var endpoint = new GenericNodeEndpointImpl( () -> ((appeng.parts.AEBasePart)(Object)this).getHost().getBlockEntity(), @@ -107,8 +105,7 @@ public abstract class StorageBusPartChannelCardMixin implements IInterfaceWirele eap$link = new WirelessSlaveLink(endpoint); Logger.EAP$LOGGER.debug("[服务端] StorageBus 创建新的无线链接"); } - - // 设置频道卡的所有者UUID(如果有的话) + eap$link.setPlacerId(ownerUUID); eap$link.setFrequency(channel); eap$link.updateStatus(); @@ -127,6 +124,11 @@ public abstract class StorageBusPartChannelCardMixin implements IInterfaceWirele eap$link.updateStatus(); } } + + @Override + public boolean eap$shouldKeepTicking() { + return ChannelCardLinkHelper.shouldKeepTicking(this.getUpgrades(), eap$link, true); + } @Override public boolean eap$isWirelessConnected() { @@ -141,4 +143,16 @@ public abstract class StorageBusPartChannelCardMixin implements IInterfaceWirele public void eap$setClientWirelessState(boolean connected) { eap$clientConnected = connected; } + + @Unique + private UUID eap$getFallbackOwner() { + try { + var node = ((IActionHost) (Object) this).getActionableNode(); + if (node != null) { + return node.getOwningPlayerProfileId(); + } + } catch (Throwable ignored) { + } + return null; + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/parts/storagebus/StorageBusPartTickerChannelCardMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/parts/storagebus/StorageBusPartTickerChannelCardMixin.java index 2227e45..c8e2428 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/parts/storagebus/StorageBusPartTickerChannelCardMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/parts/storagebus/StorageBusPartTickerChannelCardMixin.java @@ -15,10 +15,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(value = StorageBusPart.class, remap = false) public abstract class StorageBusPartTickerChannelCardMixin { - @Inject(method = "tickingRequest", at = @At("TAIL")) + @Inject(method = "tickingRequest", at = @At("TAIL"), cancellable = true) private void eap$tickTail(IGridNode node, int ticksSinceLastCall, CallbackInfoReturnable cir) { + if (((StorageBusPart) (Object) this).isClientSide()) { + return; + } if (this instanceof IInterfaceWirelessLinkBridge bridge) { bridge.eap$updateWirelessLink(); + if (bridge.eap$shouldKeepTicking() && cir.getReturnValue() == TickRateModulation.SLEEP) { + cir.setReturnValue(TickRateModulation.SLOWER); + } } } } diff --git a/src/main/java/com/extendedae_plus/util/wireless/ChannelCardLinkHelper.java b/src/main/java/com/extendedae_plus/util/wireless/ChannelCardLinkHelper.java new file mode 100644 index 0000000..86c447f --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/wireless/ChannelCardLinkHelper.java @@ -0,0 +1,85 @@ +package com.extendedae_plus.util.wireless; + +import appeng.api.upgrades.IUpgradeInventory; +import com.extendedae_plus.ae.wireless.WirelessSlaveLink; +import com.extendedae_plus.init.ModItems; +import com.extendedae_plus.items.materials.ChannelCardItem; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Supplier; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +/** + * 统一处理频道卡扫描、目标比较、断链与保活判定。 + */ +public final class ChannelCardLinkHelper { + + private ChannelCardLinkHelper() { + } + + public record BoundChannel(long channel, @Nullable UUID owner) { + } + + @Nullable + public static BoundChannel findBoundChannel(@Nullable IUpgradeInventory upgrades, Supplier fallbackOwner) { + if (upgrades == null) { + return null; + } + + for (ItemStack stack : upgrades) { + if (stack.isEmpty() || stack.getItem() != ModItems.CHANNEL_CARD.get()) { + continue; + } + + UUID owner = ChannelCardItem.getOwnerUUID(stack); + if (owner == null) { + owner = fallbackOwner.get(); + } + + return new BoundChannel(ChannelCardItem.getChannel(stack), owner); + } + + return null; + } + + public static boolean hasChannelCard(@Nullable IUpgradeInventory upgrades) { + if (upgrades == null) { + return false; + } + + for (ItemStack stack : upgrades) { + if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) { + return true; + } + } + + return false; + } + + public static boolean sameTarget(long lastChannel, @Nullable UUID lastOwner, @Nullable BoundChannel boundChannel) { + return boundChannel != null + && lastChannel == boundChannel.channel() + && Objects.equals(lastOwner, boundChannel.owner()); + } + + public static boolean hasActiveLink(@Nullable WirelessSlaveLink link) { + return link != null && (link.getFrequency() != 0L || link.isConnected()); + } + + public static boolean shouldKeepTicking(@Nullable IUpgradeInventory upgrades, + @Nullable WirelessSlaveLink link, + boolean initialized) { + return !initialized || hasChannelCard(upgrades) || hasActiveLink(link); + } + + public static void disconnect(@Nullable WirelessSlaveLink link) { + if (link == null) { + return; + } + + link.setPlacerId(null); + link.setFrequency(0L); + link.updateStatus(); + } +}