频道卡
This commit is contained in:
parent
47aa90a438
commit
0571efe2f9
|
|
@ -0,0 +1,66 @@
|
|||
package com.extendedae_plus.ae.items;
|
||||
|
||||
import appeng.items.materials.UpgradeCardItem;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 频道卡(MVP):仅存储一个 long 类型的频道号到 NBT:"channel"。
|
||||
* 继承 AE2 的 UpgradeCardItem 以复用升级卡判定与提示框架。
|
||||
*/
|
||||
public class ChannelCardItem extends UpgradeCardItem {
|
||||
public static final String TAG_CHANNEL = "channel";
|
||||
|
||||
public ChannelCardItem(Item.Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
public static void setChannel(ItemStack stack, long channel) {
|
||||
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
||||
tag.putLong(TAG_CHANNEL, channel);
|
||||
stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
|
||||
}
|
||||
|
||||
public static long getChannel(ItemStack stack) {
|
||||
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
||||
return tag.contains(TAG_CHANNEL) ? tag.getLong(TAG_CHANNEL) : 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> lines, TooltipFlag flag) {
|
||||
super.appendHoverText(stack, context, lines, flag);
|
||||
long ch = getChannel(stack);
|
||||
if (ch == 0L) {
|
||||
lines.add(Component.translatable("item.extendedae_plus.channel_card.channel.unset"));
|
||||
} else {
|
||||
lines.add(Component.translatable("item.extendedae_plus.channel_card.channel", ch));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
if (!level.isClientSide) {
|
||||
long ch = getChannel(stack);
|
||||
boolean dec = player.isShiftKeyDown();
|
||||
long next = dec ? Math.max(0L, ch - 1L) : ch + 1L;
|
||||
if (next != ch) {
|
||||
setChannel(stack, next);
|
||||
player.displayClientMessage(Component.translatable("item.extendedae_plus.channel_card.set", next), true);
|
||||
}
|
||||
}
|
||||
return InteractionResultHolder.sidedSuccess(stack, level.isClientSide);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.extendedae_plus.bridge;
|
||||
|
||||
/**
|
||||
* 非 mixin 包下的桥接接口,供 mixin 进行 instanceof 检测和回调。
|
||||
*/
|
||||
public interface InterfaceWirelessLinkBridge {
|
||||
void eap$updateWirelessLink();
|
||||
|
||||
/**
|
||||
* 获取无线连接状态(服务端返回真实状态,客户端返回同步状态)
|
||||
*/
|
||||
default boolean eap$isWirelessConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置客户端的无线连接状态(仅在客户端使用)
|
||||
*/
|
||||
default void eap$setClientWirelessState(boolean connected) {
|
||||
// 默认实现为空
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已经进行过tick初始化
|
||||
*/
|
||||
default boolean eap$hasTickInitialized() {
|
||||
return true; // 默认认为已初始化
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置tick初始化状态
|
||||
*/
|
||||
default void eap$setTickInitialized(boolean initialized) {
|
||||
// 默认实现为空
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行频道链接初始化
|
||||
*/
|
||||
default void eap$initializeChannelLink() {
|
||||
// 默认实现为空
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并处理延迟初始化
|
||||
*/
|
||||
default void eap$handleDelayedInit() {
|
||||
// 默认实现为空
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ public final class ModCreativeTabs {
|
|||
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());
|
||||
// 放入四个预设的 stacks(x2,x4,x8,x16),使用 ModItems 工厂创建
|
||||
output.accept(ModItems.createEntitySpeedCardStack((byte) 2));
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.extendedae_plus.init;
|
|||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem;
|
||||
import com.extendedae_plus.ae.items.EntitySpeedTickerPartItem;
|
||||
import com.extendedae_plus.ae.items.ChannelCardItem;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
|
@ -62,6 +63,12 @@ public final class ModItems {
|
|||
() -> new EntitySpeedCardItem(new Item.Properties())
|
||||
);
|
||||
|
||||
// 频道卡:用于AE机器的无线频道连接
|
||||
public static final DeferredItem<ChannelCardItem> CHANNEL_CARD = ITEMS.register(
|
||||
"channel_card",
|
||||
() -> new ChannelCardItem(new Item.Properties())
|
||||
);
|
||||
|
||||
/**
|
||||
* 工厂:创建带 multiplier 的实体加速卡 ItemStack(2/4/8/16)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,225 @@
|
|||
package com.extendedae_plus.mixin.ae2.helpers;
|
||||
|
||||
import appeng.api.upgrades.IUpgradeInventory;
|
||||
import appeng.helpers.InterfaceLogic;
|
||||
import appeng.helpers.InterfaceLogicHost;
|
||||
import com.extendedae_plus.ae.items.ChannelCardItem;
|
||||
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
|
||||
import com.extendedae_plus.init.ModItems;
|
||||
import com.extendedae_plus.wireless.WirelessSlaveLink;
|
||||
import com.extendedae_plus.wireless.endpoint.InterfaceNodeEndpointImpl;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
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(InterfaceLogic.class)
|
||||
public abstract class InterfaceLogicChannelCardMixin implements InterfaceWirelessLinkBridge {
|
||||
|
||||
@Shadow(remap = false) public abstract IUpgradeInventory getUpgrades();
|
||||
|
||||
@Shadow(remap = false) public abstract appeng.api.networking.IGridNode getActionableNode();
|
||||
|
||||
@Shadow(remap = false) protected InterfaceLogicHost host;
|
||||
|
||||
@Shadow(remap = false) protected appeng.api.networking.IManagedGridNode mainNode;
|
||||
|
||||
@Unique
|
||||
private WirelessSlaveLink eap$link;
|
||||
|
||||
@Unique
|
||||
private long eap$lastChannel = -1;
|
||||
|
||||
@Unique
|
||||
private boolean eap$clientConnected = false;
|
||||
|
||||
@Unique
|
||||
private boolean eap$hasInitialized = false;
|
||||
|
||||
@Unique
|
||||
private int eap$delayedInitTicks = 0;
|
||||
|
||||
static {
|
||||
// InterfaceLogicChannelCardMixin 已加载
|
||||
}
|
||||
|
||||
@Inject(method = "onUpgradesChanged", at = @At("TAIL"), remap = false)
|
||||
private void eap$onUpgradesChangedTail(CallbackInfo ci) {
|
||||
// 升级变更时重置标志并尝试初始化
|
||||
eap$lastChannel = -1;
|
||||
eap$hasInitialized = false;
|
||||
eap$initializeChannelLink();
|
||||
}
|
||||
|
||||
@Inject(method = "gridChanged", at = @At("TAIL"), remap = false)
|
||||
private void eap$afterGridChanged(CallbackInfo ci) {
|
||||
// 网格状态变化时重置标志并设置延迟初始化
|
||||
eap$lastChannel = -1;
|
||||
eap$hasInitialized = false;
|
||||
eap$delayedInitTicks = 10; // 适当增加延迟tick,等待网格完成引导
|
||||
// 尝试唤醒设备,确保后续还能继续tick
|
||||
if (mainNode != null) {
|
||||
mainNode.ifPresent((grid, node) -> {
|
||||
try {
|
||||
grid.getTickManager().wakeDevice(node);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "readFromNBT", at = @At("TAIL"), remap = false)
|
||||
private void eap$afterReadNBT(net.minecraft.nbt.CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) {
|
||||
// 从 NBT加载时重置标志
|
||||
eap$lastChannel = -1;
|
||||
eap$hasInitialized = false;
|
||||
// 直接尝试初始化
|
||||
eap$initializeChannelLink();
|
||||
}
|
||||
|
||||
@Inject(method = "clearContent", at = @At("HEAD"), remap = false)
|
||||
private void eap$onClearContent(CallbackInfo ci) {
|
||||
if (eap$link != null) {
|
||||
eap$link.onUnloadOrRemove();
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
public void eap$initializeChannelLink() {
|
||||
// 仅在服务端执行,避免在渲染线程/客户端触发任何初始化路径
|
||||
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 避免重复初始化
|
||||
if (eap$hasInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查网格节点是否在线(1.21.1版本使用isActive替代hasGridBooted)
|
||||
if (mainNode == null || !mainNode.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
long channel = 0L;
|
||||
boolean found = false;
|
||||
for (ItemStack stack : getUpgrades()) {
|
||||
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
|
||||
channel = ChannelCardItem.getChannel(stack);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// 无频道卡:断开并视为初始化完成
|
||||
if (eap$link != null) {
|
||||
eap$link.setFrequency(0L);
|
||||
eap$link.updateStatus();
|
||||
}
|
||||
eap$hasInitialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (eap$link == null) {
|
||||
var endpoint = new InterfaceNodeEndpointImpl(host, () -> this.mainNode.getNode());
|
||||
eap$link = new WirelessSlaveLink(endpoint);
|
||||
}
|
||||
|
||||
eap$link.setFrequency(channel);
|
||||
eap$link.updateStatus();
|
||||
|
||||
if (eap$link.isConnected()) {
|
||||
eap$hasInitialized = true; // 设置初始化完成标志
|
||||
} else {
|
||||
// 不标记为完成,允许后续tick重试
|
||||
eap$hasInitialized = false;
|
||||
// 设置一个短延迟窗口,避免每tick刷屏
|
||||
eap$delayedInitTicks = Math.max(eap$delayedInitTicks, 5);
|
||||
try {
|
||||
mainNode.ifPresent((grid, node) -> {
|
||||
try {
|
||||
grid.getTickManager().wakeDevice(node);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
});
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eap$updateWirelessLink() {
|
||||
if (eap$link != null) {
|
||||
eap$link.updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eap$isWirelessConnected() {
|
||||
// InterfaceLogic没有isClientSide方法,需要通过host判断
|
||||
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) {
|
||||
return eap$clientConnected;
|
||||
} else {
|
||||
return eap$link != null && eap$link.isConnected();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eap$setClientWirelessState(boolean connected) {
|
||||
eap$clientConnected = connected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eap$hasTickInitialized() {
|
||||
return eap$hasInitialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eap$setTickInitialized(boolean initialized) {
|
||||
eap$hasInitialized = initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eap$handleDelayedInit() {
|
||||
// 仅在服务端执行延迟初始化,避免在渲染线程/客户端触发任何初始化路径
|
||||
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 若尚未初始化,则持续尝试,直到网格完成引导
|
||||
if (!eap$hasInitialized) {
|
||||
if (mainNode == null || !mainNode.isActive()) {
|
||||
// 仍在引导,消耗计时器
|
||||
if (eap$delayedInitTicks > 0) {
|
||||
eap$delayedInitTicks--;
|
||||
}
|
||||
if (eap$delayedInitTicks == 0) {
|
||||
// 重新设定一个短延迟窗口,并唤醒设备,以保证后续还能继续 tick
|
||||
eap$delayedInitTicks = 5;
|
||||
try {
|
||||
mainNode.ifPresent((grid, node) -> {
|
||||
try {
|
||||
grid.getTickManager().wakeDevice(node);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
});
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 网格已引导完成,执行初始化
|
||||
eap$initializeChannelLink();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eap$initializeChannelLink方法已在上面实现
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
package com.extendedae_plus.mixin.ae2.parts.automation;
|
||||
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.upgrades.IUpgradeInventory;
|
||||
import appeng.api.upgrades.IUpgradeableObject;
|
||||
import appeng.helpers.InterfaceLogicHost;
|
||||
import appeng.parts.automation.IOBusPart;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import com.extendedae_plus.util.ExtendedAELogger;
|
||||
import com.extendedae_plus.ae.items.ChannelCardItem;
|
||||
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
|
||||
import com.extendedae_plus.init.ModItems;
|
||||
import com.extendedae_plus.wireless.WirelessSlaveLink;
|
||||
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 给 AE2 的 I/O 总线注入频道卡联动:在升级变更时读取频道并更新无线链接。
|
||||
*/
|
||||
@Mixin(value = IOBusPart.class, remap = false)
|
||||
public abstract class IOBusPartChannelCardMixin implements InterfaceWirelessLinkBridge, IUpgradeableObject {
|
||||
|
||||
@Unique
|
||||
private WirelessSlaveLink eap$link;
|
||||
|
||||
@Unique
|
||||
private long eap$lastChannel = -1;
|
||||
|
||||
@Unique
|
||||
private boolean eap$clientConnected = false;
|
||||
|
||||
@Unique
|
||||
private boolean eap$hasTickInitialized = false;
|
||||
|
||||
@Inject(method = "upgradesChanged", at = @At("TAIL"))
|
||||
private void eap$onUpgradesChanged(CallbackInfo ci) {
|
||||
// 只在服务端初始化频道链接
|
||||
if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
eap$initializeChannelLink();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tickingRequest", at = @At("HEAD"))
|
||||
private void eap$beforeTick(appeng.api.networking.IGridNode node, int ticksSinceLastCall, org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable<appeng.api.networking.ticking.TickRateModulation> cir) {
|
||||
// 在第一次tick时初始化频道链接(此时网格节点已经在线)
|
||||
if (!eap$hasTickInitialized && !((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
eap$hasTickInitialized = true;
|
||||
eap$initializeChannelLink();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "readFromNBT", at = @At("TAIL"))
|
||||
private void eap$afterReadFromNBT(CompoundTag extra, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) {
|
||||
// 从NBT加载时重置频道缓存和tick初始化标志
|
||||
if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
eap$lastChannel = -1;
|
||||
eap$hasTickInitialized = false; // 重置标志,允许再次初始化
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
public void eap$initializeChannelLink() {
|
||||
// 防止重复调用
|
||||
if (((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
IUpgradeInventory inv = this.getUpgrades();
|
||||
long channel = 0L;
|
||||
boolean found = false;
|
||||
for (var stack : inv) {
|
||||
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
|
||||
channel = ChannelCardItem.getChannel(stack);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 频道没有变化则跳过
|
||||
if (eap$lastChannel == channel) {
|
||||
return;
|
||||
}
|
||||
eap$lastChannel = channel;
|
||||
|
||||
ExtendedAELogger.LOGGER.debug("[服务端] IOBus 初始化频道链接: found={}, channel={}", found, channel);
|
||||
|
||||
if (!found) {
|
||||
// 无频道卡则断开
|
||||
if (eap$link != null) {
|
||||
eap$link.setFrequency(0L);
|
||||
eap$link.updateStatus();
|
||||
ExtendedAELogger.LOGGER.debug("[服务端] IOBus 断开频道链接");
|
||||
// 立即通知客户端状态变化(断开连接无需延迟)
|
||||
((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (eap$link == null) {
|
||||
var endpoint = new GenericNodeEndpointImpl(
|
||||
() -> ((appeng.parts.AEBasePart)(Object)this).getHost().getBlockEntity(),
|
||||
() -> ((IActionHost)(Object)this).getActionableNode()
|
||||
);
|
||||
eap$link = new WirelessSlaveLink(endpoint);
|
||||
ExtendedAELogger.LOGGER.debug("[服务端] IOBus 创建新的无线链接");
|
||||
}
|
||||
|
||||
eap$link.setFrequency(channel);
|
||||
eap$link.updateStatus();
|
||||
ExtendedAELogger.LOGGER.debug("[服务端] IOBus 设置频道: {}, 连接状态: {}", channel, eap$link.isConnected());
|
||||
|
||||
// 通知客户端状态变化
|
||||
((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate();
|
||||
} catch (Exception e) {
|
||||
ExtendedAELogger.LOGGER.error("[服务端] IOBus 初始化频道链接失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eap$updateWirelessLink() {
|
||||
if (eap$link != null) {
|
||||
eap$link.updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eap$isWirelessConnected() {
|
||||
if (((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
return eap$clientConnected;
|
||||
} else {
|
||||
return eap$link != null && eap$link.isConnected();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eap$setClientWirelessState(boolean connected) {
|
||||
eap$clientConnected = connected;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
package com.extendedae_plus.mixin.ae2.parts.storagebus;
|
||||
|
||||
import appeng.api.networking.IGridNodeListener;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.upgrades.IUpgradeInventory;
|
||||
import appeng.api.upgrades.IUpgradeableObject;
|
||||
import appeng.parts.storagebus.StorageBusPart;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import com.extendedae_plus.util.ExtendedAELogger;
|
||||
import com.extendedae_plus.ae.items.ChannelCardItem;
|
||||
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
|
||||
import com.extendedae_plus.init.ModItems;
|
||||
import com.extendedae_plus.wireless.WirelessSlaveLink;
|
||||
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 给 AE2 的存储总线注入频道卡联动:在升级变更时读取频道并更新无线链接。
|
||||
*/
|
||||
@Mixin(value = StorageBusPart.class, remap = false)
|
||||
public abstract class StorageBusPartChannelCardMixin implements InterfaceWirelessLinkBridge, IUpgradeableObject {
|
||||
|
||||
@Unique
|
||||
private WirelessSlaveLink eap$link;
|
||||
|
||||
@Unique
|
||||
private long eap$lastChannel = -1;
|
||||
|
||||
@Unique
|
||||
private boolean eap$clientConnected = false;
|
||||
|
||||
@Inject(method = "upgradesChanged", at = @At("TAIL"))
|
||||
private void eap$onUpgradesChanged(CallbackInfo ci) {
|
||||
// 只在服务端初始化频道链接
|
||||
if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
eap$initializeChannelLink();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "onMainNodeStateChanged", at = @At("TAIL"))
|
||||
private void eap$onMainNodeStateChanged(IGridNodeListener.State reason, CallbackInfo ci) {
|
||||
// 在节点状态变化时(包括加载后的GRID_BOOT)重新初始化频道链接
|
||||
if (reason == IGridNodeListener.State.GRID_BOOT && !((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
eap$initializeChannelLink();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "readFromNBT", at = @At("TAIL"))
|
||||
private void eap$afterReadFromNBT(CompoundTag extra, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) {
|
||||
// 从NBT加载后也重新初始化频道链接(只在服务端)
|
||||
if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
// 从NBT加载时重置频道缓存,强制重新初始化
|
||||
eap$lastChannel = -1;
|
||||
eap$initializeChannelLink();
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
public void eap$initializeChannelLink() {
|
||||
// 防止重复调用
|
||||
if (((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
IUpgradeInventory inv = this.getUpgrades();
|
||||
long channel = 0L;
|
||||
boolean found = false;
|
||||
for (var stack : inv) {
|
||||
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
|
||||
channel = ChannelCardItem.getChannel(stack);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 频道没有变化则跳过
|
||||
if (eap$lastChannel == channel) {
|
||||
return;
|
||||
}
|
||||
eap$lastChannel = channel;
|
||||
|
||||
ExtendedAELogger.LOGGER.debug("[服务端] StorageBus 初始化频道链接: found={}, channel={}", found, channel);
|
||||
|
||||
if (!found) {
|
||||
if (eap$link != null) {
|
||||
eap$link.setFrequency(0L);
|
||||
eap$link.updateStatus();
|
||||
ExtendedAELogger.LOGGER.debug("[服务端] StorageBus 断开频道链接");
|
||||
// 通知客户端状态变化
|
||||
((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (eap$link == null) {
|
||||
var endpoint = new GenericNodeEndpointImpl(
|
||||
() -> ((appeng.parts.AEBasePart)(Object)this).getHost().getBlockEntity(),
|
||||
() -> ((IActionHost)(Object)this).getActionableNode()
|
||||
);
|
||||
eap$link = new WirelessSlaveLink(endpoint);
|
||||
ExtendedAELogger.LOGGER.debug("[服务端] StorageBus 创建新的无线链接");
|
||||
}
|
||||
|
||||
eap$link.setFrequency(channel);
|
||||
eap$link.updateStatus();
|
||||
ExtendedAELogger.LOGGER.debug("[服务端] StorageBus 设置频道: {}, 连接状态: {}", channel, eap$link.isConnected());
|
||||
|
||||
// 通知客户端状态变化
|
||||
((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate();
|
||||
} catch (Exception e) {
|
||||
ExtendedAELogger.LOGGER.error("[服务端] StorageBus 初始化频道链接失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eap$updateWirelessLink() {
|
||||
if (eap$link != null) {
|
||||
eap$link.updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eap$isWirelessConnected() {
|
||||
if (((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
|
||||
return eap$clientConnected;
|
||||
} else {
|
||||
return eap$link != null && eap$link.isConnected();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eap$setClientWirelessState(boolean connected) {
|
||||
eap$clientConnected = connected;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.extendedae_plus.wireless.endpoint;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.helpers.InterfaceLogicHost;
|
||||
import com.extendedae_plus.wireless.IWirelessEndpoint;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* IWirelessEndpoint 实现:基于 InterfaceLogicHost 与节点提供者。
|
||||
*/
|
||||
public class InterfaceNodeEndpointImpl implements IWirelessEndpoint {
|
||||
private final InterfaceLogicHost host;
|
||||
private final Supplier<IGridNode> nodeSupplier;
|
||||
|
||||
public InterfaceNodeEndpointImpl(InterfaceLogicHost host, Supplier<IGridNode> nodeSupplier) {
|
||||
this.host = Objects.requireNonNull(host);
|
||||
this.nodeSupplier = Objects.requireNonNull(nodeSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLevel getServerLevel() {
|
||||
var be = host.getBlockEntity();
|
||||
if (be == null) return null;
|
||||
Level lvl = be.getLevel();
|
||||
return (lvl instanceof ServerLevel) ? (ServerLevel) lvl : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getBlockPos() {
|
||||
var be = host.getBlockEntity();
|
||||
return be != null ? be.getBlockPos() : BlockPos.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getGridNode() {
|
||||
return nodeSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEndpointRemoved() {
|
||||
var be = host.getBlockEntity();
|
||||
return be == null || be.isRemoved();
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,10 @@
|
|||
"item.extendedae_plus.1024x_crafting_accelerator": "1024x Crafting Accelerator",
|
||||
"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.channel_card.channel": "Channel: %d",
|
||||
"item.extendedae_plus.channel_card.channel.unset": "Channel: Unset",
|
||||
"item.extendedae_plus.channel_card.set": "Channel set to: %d",
|
||||
"item.extendedae_plus.entity_speed_card": "Entity Speed Card",
|
||||
"item.extendedae_plus.entity_speed_card.x2": "Entity Speed Card (x2)",
|
||||
"item.extendedae_plus.entity_speed_card.x4": "Entity Speed Card (x4)",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@
|
|||
"item.extendedae_plus.1024x_crafting_accelerator": "1024x并行处理单元",
|
||||
"item.extendedae_plus.network_pattern_controller": "样板供应器状态控制器",
|
||||
"item.extendedae_plus.assembler_matrix_upload_core": "装配矩阵上传核心",
|
||||
"item.extendedae_plus.channel_card": "频道卡",
|
||||
"item.extendedae_plus.channel_card.channel": "频道: %d",
|
||||
"item.extendedae_plus.channel_card.channel.unset": "频道: 未设置",
|
||||
"item.extendedae_plus.channel_card.set": "频道已设置为: %d",
|
||||
"item.extendedae_plus.entity_speed_card": "实体加速卡",
|
||||
"item.extendedae_plus.entity_speed_card.x2": "实体加速卡 (x2)",
|
||||
"item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "extendedae_plus:item/channel_card"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"ingredients": [
|
||||
{ "item": "ae2:advanced_card" },
|
||||
{ "item": "extendedae_plus:wireless_transceiver" }
|
||||
],
|
||||
"result": { "item": "extendedae_plus:channel_card", "count": 1 }
|
||||
}
|
||||
|
|
@ -25,8 +25,11 @@
|
|||
"ae2.autopattern.CraftingTreeNodeMixin",
|
||||
"ae2.autopattern.CraftingTreeProcessMixin",
|
||||
"ae2.autopattern.PatternProviderLogicContainsRedirectMixin",
|
||||
"ae2.helpers.InterfaceLogicChannelCardMixin",
|
||||
"ae2.helpers.PatternProviderLogicAdvancedMixin",
|
||||
"ae2.helpers.PatternProviderLogicDoublingMixin",
|
||||
"ae2.parts.automation.IOBusPartChannelCardMixin",
|
||||
"ae2.parts.storagebus.StorageBusPartChannelCardMixin",
|
||||
"ae2.menu.ContainerPatternEncodingTermMenuMixin",
|
||||
"ae2.menu.MEStorageMenuMixin",
|
||||
"ae2.menu.PatternEncodingTermMenuMixin",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user