优化频道卡连接逻辑

This commit is contained in:
GaLi 2026-03-26 18:12:44 +08:00
parent 38b06eb484
commit 53cb588675
10 changed files with 313 additions and 104 deletions

View File

@ -47,4 +47,11 @@ public interface IInterfaceWirelessLinkBridge {
default void eap$handleDelayedInit() {
// 默认实现为空
}
/**
* 指示宿主是否需要保持慢速 tick 以维持无线连接
*/
default boolean eap$shouldKeepTicking() {
return false;
}
}

View File

@ -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) {
}
}
}

View File

@ -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;
}
}

View File

@ -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<appeng.api.networking.ticking.TickRateModulation> 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);
}
}
}
}

View File

@ -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<appeng.api.networking.ticking.TickRateModulation> 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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -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<TickRateModulation> 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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -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<TickRateModulation> 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);
}
}
}
}

View File

@ -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<UUID> 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();
}
}