无线收发器绑定ftbteams
This commit is contained in:
parent
1449df8f8b
commit
2732a9aee1
|
|
@ -171,6 +171,11 @@ dependencies {
|
|||
//geckolib
|
||||
runtimeOnly "curse.maven:geckolib-388172:7009924"
|
||||
|
||||
//ftbteams
|
||||
runtimeOnly "curse.maven:ftb-teams-forge-404468:6930910"
|
||||
runtimeOnly "curse.maven:ftb-library-forge-404465:7029003"
|
||||
runtimeOnly "curse.maven:architectury-api-419699:5786327"
|
||||
|
||||
|
||||
runtimeOnly fileTree(dir: 'libs', includes: ['*.jar'])
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.extendedae_plus.ae.items;
|
||||
|
||||
import appeng.items.materials.UpgradeCardItem;
|
||||
import com.extendedae_plus.util.WirelessTeamUtil;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
|
@ -15,13 +17,20 @@ import net.minecraft.world.level.Level;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 频道卡(MVP):仅存储一个 long 类型的频道号到 NBT:"channel"。
|
||||
* 频道卡:存储频道号、所有者UUID和团队信息
|
||||
* - 右键空气:增加频道号
|
||||
* - 潜行右键空气:减少频道号
|
||||
* - 潜行左键空气:写入/清除玩家UUID和团队信息(通过网络包处理)
|
||||
* - 潜行左键收发器:将频道卡的所有者信息写入收发器
|
||||
* 继承 AE2 的 UpgradeCardItem 以复用升级卡判定与提示框架。
|
||||
*/
|
||||
public class ChannelCardItem extends UpgradeCardItem {
|
||||
public static final String TAG_CHANNEL = "channel";
|
||||
public static final String TAG_OWNER_UUID = "ownerUUID";
|
||||
public static final String TAG_TEAM_NAME = "teamName"; // 用于显示
|
||||
|
||||
public ChannelCardItem(Item.Properties properties) {
|
||||
super(properties);
|
||||
|
|
@ -38,29 +47,110 @@ public class ChannelCardItem extends UpgradeCardItem {
|
|||
return tag.contains(TAG_CHANNEL) ? tag.getLong(TAG_CHANNEL) : 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置频道卡的所有者UUID
|
||||
*/
|
||||
public static void setOwnerUUID(ItemStack stack, UUID ownerUUID) {
|
||||
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
||||
tag.putUUID(TAG_OWNER_UUID, ownerUUID);
|
||||
stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取频道卡的所有者UUID
|
||||
*/
|
||||
@Nullable
|
||||
public static UUID getOwnerUUID(ItemStack stack) {
|
||||
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
||||
return tag.hasUUID(TAG_OWNER_UUID) ? tag.getUUID(TAG_OWNER_UUID) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置团队名称(用于显示)
|
||||
*/
|
||||
public static void setTeamName(ItemStack stack, String teamName) {
|
||||
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
||||
tag.putString(TAG_TEAM_NAME, teamName);
|
||||
stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取团队名称
|
||||
*/
|
||||
@Nullable
|
||||
public static String getTeamName(ItemStack stack) {
|
||||
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
||||
return tag.contains(TAG_TEAM_NAME) ? tag.getString(TAG_TEAM_NAME) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有者信息
|
||||
*/
|
||||
public static void clearOwner(ItemStack stack) {
|
||||
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
|
||||
tag.remove(TAG_OWNER_UUID);
|
||||
tag.remove(TAG_TEAM_NAME);
|
||||
stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
// 显示所有者信息
|
||||
UUID ownerUUID = getOwnerUUID(stack);
|
||||
String teamName = getTeamName(stack);
|
||||
|
||||
if (ownerUUID != null) {
|
||||
if (teamName != null && !teamName.isEmpty()) {
|
||||
lines.add(Component.translatable("item.extendedae_plus.channel_card.owner.team", teamName));
|
||||
} else {
|
||||
lines.add(Component.translatable("item.extendedae_plus.channel_card.owner.player", ownerUUID.toString().substring(0, 8)));
|
||||
}
|
||||
} else {
|
||||
lines.add(Component.translatable("item.extendedae_plus.channel_card.owner.unset"));
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
long next;
|
||||
|
||||
if (player.isShiftKeyDown()) {
|
||||
// 潜行右键:减少频率
|
||||
next = Math.max(0L, ch - 1L);
|
||||
} else {
|
||||
// 普通右键:增加频率
|
||||
next = 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLeftClickEntity(ItemStack stack, Player player, net.minecraft.world.entity.Entity entity) {
|
||||
// 左键实体时不做任何事,避免伤害实体
|
||||
if (player.isShiftKeyDown()) {
|
||||
return true; // 取消默认行为
|
||||
}
|
||||
return super.onLeftClickEntity(stack, player, entity);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
package com.extendedae_plus.client;
|
||||
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.init.ModItems;
|
||||
import com.extendedae_plus.network.ChannelCardBindPacket;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.client.event.InputEvent;
|
||||
import net.neoforged.neoforge.network.PacketDistributor;
|
||||
|
||||
/**
|
||||
* 频道卡客户端事件处理器
|
||||
* 处理左键空气事件并发送网络包到服务端
|
||||
*/
|
||||
@EventBusSubscriber(modid = ExtendedAEPlus.MODID, value = Dist.CLIENT)
|
||||
public class ChannelCardClientHandler {
|
||||
|
||||
/**
|
||||
* 左键空气事件(仅客户端)
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onLeftClickEmpty(InputEvent.InteractionKeyMappingTriggered event) {
|
||||
// 只处理左键空气(attack模式)
|
||||
if (!event.isAttack()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取客户端玩家
|
||||
Player player = Minecraft.getInstance().player;
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 只处理潜行
|
||||
if (!player.isShiftKeyDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否手持频道卡
|
||||
InteractionHand hand = event.getHand();
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
if (stack.getItem() != ModItems.CHANNEL_CARD.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送网络包到服务端
|
||||
PacketDistributor.sendToServer(new ChannelCardBindPacket(hand));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,12 +1,16 @@
|
|||
package com.extendedae_plus.content.wireless;
|
||||
|
||||
import com.extendedae_plus.ae.items.ChannelCardItem;
|
||||
import com.extendedae_plus.init.ModBlockEntities;
|
||||
import com.extendedae_plus.init.ModItems;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.ItemInteractionResult;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
|
@ -16,6 +20,9 @@ import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
|||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class WirelessTransceiverBlock extends Block implements EntityBlock {
|
||||
public WirelessTransceiverBlock(Properties props) {
|
||||
|
|
@ -28,28 +35,71 @@ public class WirelessTransceiverBlock extends Block implements EntityBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void attack(BlockState state, Level level, BlockPos pos, Player player) {
|
||||
// 潜行左键:减频(-1 或 -10)
|
||||
if (!level.isClientSide && player.isShiftKeyDown()) {
|
||||
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
|
||||
super.setPlacedBy(level, pos, state, placer, stack);
|
||||
if (!level.isClientSide && placer instanceof Player player) {
|
||||
BlockEntity be = level.getBlockEntity(pos);
|
||||
if (be instanceof WirelessTransceiverBlockEntity te) {
|
||||
if (te.isLocked()) {
|
||||
player.displayClientMessage(Component.literal("收发器已锁定,无法修改频道"), true);
|
||||
te.setPlacerId(player.getUUID(), player.getName().getString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attack(BlockState state, Level level, BlockPos pos, Player player) {
|
||||
if (!level.isClientSide) {
|
||||
BlockEntity be = level.getBlockEntity(pos);
|
||||
if (be instanceof WirelessTransceiverBlockEntity te) {
|
||||
ItemStack mainHand = player.getMainHandItem();
|
||||
|
||||
// 潜行左键频道卡:写入频道卡信息到收发器
|
||||
if (player.isShiftKeyDown() && mainHand.getItem() == ModItems.CHANNEL_CARD.get()) {
|
||||
handleChannelCardBinding(te, mainHand, player);
|
||||
super.attack(state, level, pos, player);
|
||||
return;
|
||||
}
|
||||
int step = 1;
|
||||
if (player.getMainHandItem().is(Items.REDSTONE_TORCH)) step = 10;
|
||||
if (player.getMainHandItem().is(Items.STICK)) step = 10;
|
||||
long f = te.getFrequency();
|
||||
f -= step;
|
||||
if (f < 0) f = 0;
|
||||
te.setFrequency(f);
|
||||
player.displayClientMessage(Component.literal("频道:" + te.getFrequency()), true);
|
||||
|
||||
// 潜行左键(其他物品):减频(-1 或 -10)
|
||||
if (player.isShiftKeyDown()) {
|
||||
if (te.isLocked()) {
|
||||
player.displayClientMessage(Component.literal("收发器已锁定,无法修改频道"), true);
|
||||
super.attack(state, level, pos, player);
|
||||
return;
|
||||
}
|
||||
int step = 1;
|
||||
if (mainHand.is(Items.REDSTONE_TORCH)) step = 10;
|
||||
if (mainHand.is(Items.STICK)) step = 10;
|
||||
long f = te.getFrequency();
|
||||
f -= step;
|
||||
if (f < 0) f = 0;
|
||||
te.setFrequency(f);
|
||||
player.displayClientMessage(Component.literal("频道:" + te.getFrequency()), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.attack(state, level, pos, player);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理频道卡绑定到收发器
|
||||
*/
|
||||
private void handleChannelCardBinding(WirelessTransceiverBlockEntity te, ItemStack channelCard, Player player) {
|
||||
UUID cardOwner = ChannelCardItem.getOwnerUUID(channelCard);
|
||||
|
||||
if (cardOwner != null) {
|
||||
// 写入频道卡的所有者到收发器
|
||||
String teamName = ChannelCardItem.getTeamName(channelCard);
|
||||
te.setPlacerId(cardOwner, teamName);
|
||||
player.displayClientMessage(
|
||||
Component.literal("已将收发器绑定至:" + (teamName != null ? teamName : cardOwner.toString().substring(0, 8))),
|
||||
true
|
||||
);
|
||||
} else {
|
||||
// 频道卡未绑定所有者,使用当前玩家
|
||||
te.setPlacerId(player.getUUID(), player.getName().getString());
|
||||
player.displayClientMessage(Component.literal("频道卡未绑定,已使用当前玩家"), true);
|
||||
}
|
||||
}
|
||||
|
||||
// 1.21+: 拆分为 useItemOn 与 useWithoutItem
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 无线收发器方块实体(骨架):
|
||||
|
|
@ -34,6 +35,11 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
|
|||
private long frequency = 1L;
|
||||
private boolean masterMode = false;
|
||||
private boolean locked = false;
|
||||
|
||||
@Nullable
|
||||
private UUID placerId; // 放置者UUID,用于队伍隔离
|
||||
@Nullable
|
||||
private String placerName; // 放置者名称,用于显示
|
||||
|
||||
private WirelessMasterLink masterLink;
|
||||
private WirelessSlaveLink slaveLink;
|
||||
|
|
@ -97,6 +103,43 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
|
|||
}
|
||||
|
||||
/* ===================== 公共方法(交互调用) ===================== */
|
||||
|
||||
/**
|
||||
* 设置放置者UUID和名称(在方块放置时调用)
|
||||
*/
|
||||
public void setPlacerId(@Nullable UUID placerId, @Nullable String placerName) {
|
||||
if (this.placerId != null && !this.placerId.equals(placerId)) {
|
||||
// 如果所有者改变,需要重新注册
|
||||
if (this.masterMode) {
|
||||
masterLink.onUnloadOrRemove();
|
||||
} else {
|
||||
slaveLink.onUnloadOrRemove();
|
||||
}
|
||||
}
|
||||
this.placerId = placerId;
|
||||
this.placerName = placerName;
|
||||
this.masterLink.setPlacerId(placerId);
|
||||
this.slaveLink.setPlacerId(placerId);
|
||||
setChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅设置UUID(兼容旧代码)
|
||||
*/
|
||||
public void setPlacerId(@Nullable UUID placerId) {
|
||||
setPlacerId(placerId, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UUID getPlacerId() {
|
||||
return placerId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPlacerName() {
|
||||
return placerName;
|
||||
}
|
||||
|
||||
public long getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
|
@ -193,6 +236,12 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
|
|||
tag.putLong("frequency", frequency);
|
||||
tag.putBoolean("master", masterMode);
|
||||
tag.putBoolean("locked", locked);
|
||||
if (placerId != null) {
|
||||
tag.putUUID("placerId", placerId);
|
||||
}
|
||||
if (placerName != null) {
|
||||
tag.putString("placerName", placerName);
|
||||
}
|
||||
if (managedNode != null) {
|
||||
managedNode.saveToNBT(tag);
|
||||
}
|
||||
|
|
@ -204,6 +253,17 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
|
|||
this.frequency = tag.getLong("frequency");
|
||||
this.masterMode = tag.getBoolean("master");
|
||||
this.locked = tag.getBoolean("locked");
|
||||
|
||||
if (tag.hasUUID("placerId")) {
|
||||
this.placerId = tag.getUUID("placerId");
|
||||
this.masterLink.setPlacerId(this.placerId);
|
||||
this.slaveLink.setPlacerId(this.placerId);
|
||||
}
|
||||
|
||||
if (tag.contains("placerName")) {
|
||||
this.placerName = tag.getString("placerName");
|
||||
}
|
||||
|
||||
if (managedNode != null) {
|
||||
managedNode.loadFromNBT(tag);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,5 +34,9 @@ public class ModNetwork {
|
|||
registrar.playToServer(com.extendedae_plus.network.PullFromJeiOrCraftC2SPacket.TYPE,
|
||||
com.extendedae_plus.network.PullFromJeiOrCraftC2SPacket.STREAM_CODEC,
|
||||
com.extendedae_plus.network.PullFromJeiOrCraftC2SPacket::handle);
|
||||
// 频道卡绑定
|
||||
registrar.playToServer(com.extendedae_plus.network.ChannelCardBindPacket.TYPE,
|
||||
com.extendedae_plus.network.ChannelCardBindPacket.STREAM_CODEC,
|
||||
com.extendedae_plus.network.ChannelCardBindPacket::handle);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,39 @@ public enum WirelessTransceiverJadePluginComponents implements IBlockComponentPr
|
|||
tooltip.add(Component.literal((usable ? "设备在线" : "设备离线")));
|
||||
}
|
||||
}
|
||||
},
|
||||
OWNER("wt_owner") {
|
||||
@Override
|
||||
protected void add(BlockAccessor accessor, ITooltip tooltip, IPluginConfig config, CompoundTag data) {
|
||||
if (data.contains("ownerName")) {
|
||||
String ownerName = data.getString("ownerName");
|
||||
tooltip.add(Component.translatable("extendedae_plus.tooltip.owner", ownerName));
|
||||
} else if (data.hasUUID("placerId")) {
|
||||
// 有placerId但没有名称,显示UUID
|
||||
java.util.UUID placerId = data.getUUID("placerId");
|
||||
tooltip.add(Component.translatable("extendedae_plus.tooltip.owner", placerId.toString().substring(0, 8) + "..."));
|
||||
} else {
|
||||
// 没有所有者信息(公共收发器)
|
||||
tooltip.add(Component.translatable("extendedae_plus.tooltip.owner.public"));
|
||||
}
|
||||
}
|
||||
},
|
||||
CHANNELS("wt_channels") {
|
||||
@Override
|
||||
protected void add(BlockAccessor accessor, ITooltip tooltip, IPluginConfig config, CompoundTag data) {
|
||||
if (data.contains("usedChannels") && data.contains("maxChannels")) {
|
||||
int usedChannels = data.getInt("usedChannels");
|
||||
int maxChannels = data.getInt("maxChannels");
|
||||
// 参考AE2的显示方式
|
||||
if (maxChannels <= 0) {
|
||||
// 无限频道或未设置
|
||||
tooltip.add(Component.translatable("extendedae_plus.tooltip.channels", usedChannels));
|
||||
} else {
|
||||
// 显示 "已使用/最大"
|
||||
tooltip.add(Component.translatable("extendedae_plus.tooltip.channels_of", usedChannels, maxChannels));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final ResourceLocation uid;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.extendedae_plus.wireless.IWirelessEndpoint;
|
|||
import com.extendedae_plus.wireless.WirelessMasterRegistry;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import snownee.jade.api.BlockAccessor;
|
||||
import snownee.jade.api.IServerDataProvider;
|
||||
|
|
@ -28,6 +29,19 @@ public enum WirelessTransceiverProvider implements IServerDataProvider<BlockAcce
|
|||
data.putLong("frequency", blockEntity.getFrequency());
|
||||
data.putBoolean("masterMode", blockEntity.isMasterMode());
|
||||
data.putBoolean("locked", blockEntity.isLocked());
|
||||
|
||||
// 添加所有者信息(有FTBTeams时显示团队,否则显示玩家)
|
||||
var placerId = blockEntity.getPlacerId();
|
||||
if (placerId != null) {
|
||||
data.putUUID("placerId", placerId);
|
||||
var level = blockEntity.getServerLevel();
|
||||
if (level != null) {
|
||||
// 使用WirelessTeamUtil自动判断显示团队或玩家名称
|
||||
Component ownerName = com.extendedae_plus.util.WirelessTeamUtil.getNetworkOwnerName(level, placerId);
|
||||
data.putString("ownerName", ownerName.getString());
|
||||
}
|
||||
}
|
||||
|
||||
// 判断 AE 网络是否可用:节点存在、加入网路且网络通电
|
||||
IGridNode node = blockEntity.getGridNode();
|
||||
IGrid grid = node == null ? null : node.getGrid();
|
||||
|
|
@ -40,11 +54,34 @@ public enum WirelessTransceiverProvider implements IServerDataProvider<BlockAcce
|
|||
}
|
||||
}
|
||||
data.putBoolean("networkUsable", networkUsable);
|
||||
|
||||
// 添加频道使用信息(参考AE2的 IUsedChannelProvider 实现)
|
||||
int usedChannels = 0;
|
||||
int maxChannels = 0;
|
||||
if (node != null && node.isActive()) {
|
||||
// 遍历该节点的所有连接,取使用频道数的最大值
|
||||
for (var connection : node.getConnections()) {
|
||||
usedChannels = Math.max(connection.getUsedChannels(), usedChannels);
|
||||
}
|
||||
// 获取节点的最大频道容量(致密线缆为32)
|
||||
if (node instanceof appeng.me.GridNode gridNode) {
|
||||
var channelMode = gridNode.getGrid().getPathingService().getChannelMode();
|
||||
if (channelMode == appeng.api.networking.pathing.ChannelMode.INFINITE) {
|
||||
maxChannels = -1; // 无限频道
|
||||
} else {
|
||||
maxChannels = gridNode.getMaxChannels();
|
||||
}
|
||||
}
|
||||
}
|
||||
data.putInt("usedChannels", usedChannels);
|
||||
data.putInt("maxChannels", maxChannels);
|
||||
|
||||
// 如果是从模式,查询主节点位置与维度
|
||||
if (!blockEntity.isMasterMode()) {
|
||||
var level = blockEntity.getServerLevel();
|
||||
long freq = blockEntity.getFrequency();
|
||||
IWirelessEndpoint master = WirelessMasterRegistry.get(level, freq);
|
||||
// 使用placerId查找主节点(支持队伍隔离)
|
||||
IWirelessEndpoint master = WirelessMasterRegistry.get(level, freq, blockEntity.getPlacerId());
|
||||
if (master != null && !master.isEndpointRemoved()) {
|
||||
if (master instanceof WirelessTransceiverBlockEntity masterBlockEntity && masterBlockEntity.getCustomName() != null) {
|
||||
data.putString("customName", masterBlockEntity.getCustomName().getString());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
package com.extendedae_plus.network;
|
||||
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.ae.items.ChannelCardItem;
|
||||
import com.extendedae_plus.init.ModItems;
|
||||
import com.extendedae_plus.util.WirelessTeamUtil;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 频道卡绑定网络包
|
||||
* 客户端发送到服务端,用于处理左键空气的绑定/解绑操作
|
||||
*/
|
||||
public class ChannelCardBindPacket implements CustomPacketPayload {
|
||||
|
||||
public static final Type<ChannelCardBindPacket> TYPE = new Type<>(
|
||||
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "channel_card_bind"));
|
||||
|
||||
public static final StreamCodec<FriendlyByteBuf, ChannelCardBindPacket> STREAM_CODEC = StreamCodec.of(
|
||||
(buf, pkt) -> buf.writeEnum(pkt.hand),
|
||||
buf -> new ChannelCardBindPacket(buf.readEnum(InteractionHand.class))
|
||||
);
|
||||
|
||||
private final InteractionHand hand;
|
||||
|
||||
public ChannelCardBindPacket(InteractionHand hand) {
|
||||
this.hand = hand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public static void handle(final ChannelCardBindPacket msg, final IPayloadContext ctx) {
|
||||
ctx.enqueueWork(() -> {
|
||||
if (!(ctx.player() instanceof ServerPlayer player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack stack = player.getItemInHand(msg.hand);
|
||||
if (stack.getItem() != ModItems.CHANNEL_CARD.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerLevel level = player.serverLevel();
|
||||
UUID currentOwner = ChannelCardItem.getOwnerUUID(stack);
|
||||
|
||||
if (currentOwner != null) {
|
||||
// 已有所有者,清除
|
||||
ChannelCardItem.clearOwner(stack);
|
||||
player.displayClientMessage(
|
||||
Component.translatable("item.extendedae_plus.channel_card.owner.cleared"),
|
||||
true
|
||||
);
|
||||
} else {
|
||||
// 写入当前玩家的UUID和团队信息
|
||||
UUID playerUUID = player.getUUID();
|
||||
ChannelCardItem.setOwnerUUID(stack, playerUUID);
|
||||
|
||||
// 获取团队名称用于显示
|
||||
Component teamName = WirelessTeamUtil.getNetworkOwnerName(level, playerUUID);
|
||||
ChannelCardItem.setTeamName(stack, teamName.getString());
|
||||
|
||||
player.displayClientMessage(
|
||||
Component.translatable("item.extendedae_plus.channel_card.owner.bound", teamName),
|
||||
true
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
221
src/main/java/com/extendedae_plus/util/WirelessTeamUtil.java
Normal file
221
src/main/java/com/extendedae_plus/util/WirelessTeamUtil.java
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
package com.extendedae_plus.util;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.neoforged.fml.ModList;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 无线收发器队伍工具类
|
||||
* 实现FTBTeams软依赖:有FTBTeams时使用队伍UUID,没有时使用玩家UUID
|
||||
*/
|
||||
public class WirelessTeamUtil {
|
||||
|
||||
private static final boolean FTB_TEAMS_LOADED = ModList.get().isLoaded("ftbteams");
|
||||
|
||||
/**
|
||||
* 获取用于无线网络隔离的UUID
|
||||
* - 如果安装了FTBTeams且玩家在队伍中,返回队伍UUID(同队玩家共享)
|
||||
* - 否则返回玩家自己的UUID(独立网络)
|
||||
*
|
||||
* @param level 服务端世界
|
||||
* @param playerUUID 玩家UUID
|
||||
* @return 网络所有者UUID
|
||||
*/
|
||||
public static UUID getNetworkOwnerUUID(@Nullable ServerLevel level, UUID playerUUID) {
|
||||
if (playerUUID == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!FTB_TEAMS_LOADED) {
|
||||
return playerUUID;
|
||||
}
|
||||
|
||||
if (level == null) {
|
||||
return playerUUID;
|
||||
}
|
||||
|
||||
try {
|
||||
return getTeamUUID(level, playerUUID);
|
||||
} catch (Exception e) {
|
||||
// 如果FTBTeams API调用失败,回退到玩家UUID
|
||||
return playerUUID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网络所有者的显示名称(用于UI显示)
|
||||
*
|
||||
* @param level 服务端世界
|
||||
* @param playerUUID 玩家UUID
|
||||
* @return 显示名称
|
||||
*/
|
||||
public static Component getNetworkOwnerName(@Nullable ServerLevel level, UUID playerUUID) {
|
||||
if (FTB_TEAMS_LOADED && level != null) {
|
||||
try {
|
||||
return getTeamName(level, playerUUID);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试获取玩家名称
|
||||
if (level != null) {
|
||||
ServerPlayer player = level.getServer().getPlayerList().getPlayer(playerUUID);
|
||||
if (player != null) {
|
||||
return player.getName();
|
||||
}
|
||||
}
|
||||
|
||||
return Component.literal(playerUUID.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查网络所有者是否有效(玩家在线或队伍存在)
|
||||
*
|
||||
* @param level 服务端世界
|
||||
* @param playerUUID 玩家UUID
|
||||
* @return 是否有效
|
||||
*/
|
||||
public static boolean hasNetworkOwner(@Nullable ServerLevel level, UUID playerUUID) {
|
||||
if (FTB_TEAMS_LOADED && level != null) {
|
||||
try {
|
||||
return hasTeamOwner(level, playerUUID);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
// 检查玩家是否在线
|
||||
if (level != null) {
|
||||
return level.getServer().getPlayerList().getPlayer(playerUUID) != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ==================== FTBTeams 集成(通过反射调用避免硬依赖)====================
|
||||
|
||||
private static UUID getTeamUUID(ServerLevel level, UUID playerUUID) {
|
||||
try {
|
||||
// 使用FTBTeams API
|
||||
var apiClass = Class.forName("dev.ftb.mods.ftbteams.api.FTBTeamsAPI");
|
||||
var api = apiClass.getMethod("api").invoke(null); // 静态方法,返回API实例
|
||||
|
||||
// 检查Manager是否已加载(在api实例上调用)
|
||||
Boolean isLoaded = (Boolean) api.getClass().getMethod("isManagerLoaded").invoke(api);
|
||||
|
||||
if (!isLoaded) {
|
||||
return playerUUID;
|
||||
}
|
||||
|
||||
var getManager = api.getClass().getMethod("getManager").invoke(api);
|
||||
|
||||
if (getManager == null) {
|
||||
return playerUUID;
|
||||
}
|
||||
|
||||
var managerClass = getManager.getClass();
|
||||
var getTeamForPlayer = managerClass.getMethod("getTeamForPlayerID", UUID.class);
|
||||
var teamOptional = getTeamForPlayer.invoke(getManager, playerUUID);
|
||||
|
||||
if (teamOptional != null) {
|
||||
var optionalClass = teamOptional.getClass();
|
||||
var isPresent = (boolean) optionalClass.getMethod("isPresent").invoke(teamOptional);
|
||||
|
||||
if (isPresent) {
|
||||
var team = optionalClass.getMethod("get").invoke(teamOptional);
|
||||
var teamClass = team.getClass();
|
||||
return (UUID) teamClass.getMethod("getTeamId").invoke(team);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 反射调用失败,回退
|
||||
}
|
||||
|
||||
return playerUUID;
|
||||
}
|
||||
|
||||
private static Component getTeamName(ServerLevel level, UUID playerUUID) {
|
||||
try {
|
||||
var apiClass = Class.forName("dev.ftb.mods.ftbteams.api.FTBTeamsAPI");
|
||||
var api = apiClass.getMethod("api").invoke(null);
|
||||
|
||||
// 检查Manager是否已加载
|
||||
Boolean isLoaded = (Boolean) api.getClass().getMethod("isManagerLoaded").invoke(api);
|
||||
if (!isLoaded) {
|
||||
// Manager未加载,回退到玩家名称
|
||||
ServerPlayer player = level.getServer().getPlayerList().getPlayer(playerUUID);
|
||||
if (player != null) {
|
||||
return player.getName();
|
||||
}
|
||||
return Component.literal(playerUUID.toString());
|
||||
}
|
||||
|
||||
var getManager = api.getClass().getMethod("getManager").invoke(api);
|
||||
|
||||
if (getManager == null) {
|
||||
return Component.literal(playerUUID.toString());
|
||||
}
|
||||
|
||||
var managerClass = getManager.getClass();
|
||||
var getTeamForPlayer = managerClass.getMethod("getTeamForPlayerID", UUID.class);
|
||||
var teamOptional = getTeamForPlayer.invoke(getManager, playerUUID);
|
||||
|
||||
if (teamOptional != null) {
|
||||
var optionalClass = teamOptional.getClass();
|
||||
var isPresent = (boolean) optionalClass.getMethod("isPresent").invoke(teamOptional);
|
||||
|
||||
if (isPresent) {
|
||||
var team = optionalClass.getMethod("get").invoke(teamOptional);
|
||||
var teamClass = team.getClass();
|
||||
return (Component) teamClass.getMethod("getName").invoke(team);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 反射调用失败,回退
|
||||
}
|
||||
|
||||
// 回退到玩家名称
|
||||
ServerPlayer player = level.getServer().getPlayerList().getPlayer(playerUUID);
|
||||
if (player != null) {
|
||||
return player.getName();
|
||||
}
|
||||
|
||||
return Component.literal(playerUUID.toString());
|
||||
}
|
||||
|
||||
private static boolean hasTeamOwner(ServerLevel level, UUID playerUUID) {
|
||||
try {
|
||||
var apiClass = Class.forName("dev.ftb.mods.ftbteams.api.FTBTeamsAPI");
|
||||
var api = apiClass.getMethod("api").invoke(null);
|
||||
|
||||
// 检查Manager是否已加载
|
||||
Boolean isLoaded = (Boolean) api.getClass().getMethod("isManagerLoaded").invoke(api);
|
||||
if (!isLoaded) {
|
||||
return level.getServer().getPlayerList().getPlayer(playerUUID) != null;
|
||||
}
|
||||
|
||||
var getManager = api.getClass().getMethod("getManager").invoke(api);
|
||||
|
||||
if (getManager == null) {
|
||||
return level.getServer().getPlayerList().getPlayer(playerUUID) != null;
|
||||
}
|
||||
|
||||
var managerClass = getManager.getClass();
|
||||
var getTeamForPlayer = managerClass.getMethod("getTeamForPlayerID", UUID.class);
|
||||
var teamOptional = getTeamForPlayer.invoke(getManager, playerUUID);
|
||||
|
||||
if (teamOptional != null) {
|
||||
var optionalClass = teamOptional.getClass();
|
||||
return (boolean) optionalClass.getMethod("isPresent").invoke(teamOptional);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 反射调用失败,回退
|
||||
}
|
||||
|
||||
return level.getServer().getPlayerList().getPlayer(playerUUID) != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
package com.extendedae_plus.wireless;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 主收发器端逻辑:负责在频率变化/加载时向注册中心登记唯一主端,卸载时反注册。
|
||||
|
|
@ -10,10 +13,16 @@ public class WirelessMasterLink {
|
|||
private final IWirelessEndpoint host;
|
||||
private long frequency; // 0 为未设置
|
||||
private boolean registered;
|
||||
@Nullable
|
||||
private UUID placerId; // 放置者UUID
|
||||
|
||||
public WirelessMasterLink(IWirelessEndpoint host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public void setPlacerId(@Nullable UUID placerId) {
|
||||
this.placerId = placerId;
|
||||
}
|
||||
|
||||
public long getFrequency() { return frequency; }
|
||||
|
||||
|
|
@ -27,7 +36,7 @@ public class WirelessMasterLink {
|
|||
}
|
||||
|
||||
// 频率未变的情况下也要校正注册状态:
|
||||
// - 当从“从端”切回“主端”时,registered 可能为 false,需要重新注册;
|
||||
// - 当从"从端"切回"主端"时,registered 可能为 false,需要重新注册;
|
||||
// - 当频率为 0 或端点被移除时,确保处于未注册。
|
||||
if (frequency != 0L && !host.isEndpointRemoved()) {
|
||||
if (!registered) {
|
||||
|
|
@ -43,7 +52,8 @@ public class WirelessMasterLink {
|
|||
public boolean register() {
|
||||
ServerLevel level = host.getServerLevel();
|
||||
if (level == null || frequency == 0L) return false;
|
||||
boolean ok = WirelessMasterRegistry.register(level, frequency, host);
|
||||
// placerId可以为null(公共收发器模式)
|
||||
boolean ok = WirelessMasterRegistry.register(level, frequency, placerId, host);
|
||||
this.registered = ok;
|
||||
return ok;
|
||||
}
|
||||
|
|
@ -51,7 +61,8 @@ public class WirelessMasterLink {
|
|||
public void unregister() {
|
||||
ServerLevel level = host.getServerLevel();
|
||||
if (!registered || level == null || frequency == 0L) return;
|
||||
WirelessMasterRegistry.unregister(level, frequency, host);
|
||||
// placerId可以为null(公共收发器模式)
|
||||
WirelessMasterRegistry.unregister(level, frequency, placerId, host);
|
||||
registered = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,43 +1,68 @@
|
|||
package com.extendedae_plus.wireless;
|
||||
|
||||
import com.extendedae_plus.config.ModConfigs;
|
||||
import com.extendedae_plus.util.WirelessTeamUtil;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 无线主端注册中心:按 维度 + 频率 唯一注册一个主收发器端点。
|
||||
* 无线主端注册中心:按 维度 + 频率 + 所有者 唯一注册一个主收发器端点。
|
||||
* 从端通过本注册中心按频率查找主端,实现一对多连接。
|
||||
* 所有者隔离:有FTBTeams时同队共享,没有时每个玩家独立。
|
||||
* 公共模式:placerId为null时使用公共UUID,所有人都能访问(向下兼容旧版本)。
|
||||
*/
|
||||
public final class WirelessMasterRegistry {
|
||||
private WirelessMasterRegistry() {}
|
||||
|
||||
private static final Map<Key, WeakReference<IWirelessEndpoint>> MASTERS = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 公共收发器UUID(用于没有设置所有者的收发器)
|
||||
* 所有placerId为null的收发器都使用这个UUID,实现公共访问
|
||||
*/
|
||||
public static final UUID PUBLIC_NETWORK_UUID = new UUID(0, 0);
|
||||
|
||||
public static synchronized boolean register(ServerLevel level, long frequency, IWirelessEndpoint endpoint) {
|
||||
public static synchronized boolean register(ServerLevel level, long frequency, @Nullable UUID placerId, IWirelessEndpoint endpoint) {
|
||||
Objects.requireNonNull(level, "level");
|
||||
Objects.requireNonNull(endpoint, "endpoint");
|
||||
if (frequency == 0L) return false;
|
||||
final Key key = new Key(useGlobal() ? null : level.dimension(), frequency);
|
||||
|
||||
// 获取网络所有者UUID
|
||||
// placerId为null时使用公共UUID(向下兼容旧版本收发器)
|
||||
UUID ownerUUID = placerId != null
|
||||
? WirelessTeamUtil.getNetworkOwnerUUID(level, placerId)
|
||||
: PUBLIC_NETWORK_UUID;
|
||||
|
||||
final Key key = new Key(useGlobal() ? null : level.dimension(), frequency, ownerUUID);
|
||||
|
||||
cleanupIfCleared(key);
|
||||
var existing = MASTERS.get(key);
|
||||
var existingVal = existing == null ? null : existing.get();
|
||||
if (existingVal != null && !existingVal.isEndpointRemoved()) {
|
||||
// 同维度同频率已经有主端
|
||||
// 同维度同频率同所有者已经有主端
|
||||
return false;
|
||||
}
|
||||
MASTERS.put(key, new WeakReference<>(endpoint));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static synchronized void unregister(ServerLevel level, long frequency, IWirelessEndpoint endpoint) {
|
||||
public static synchronized void unregister(ServerLevel level, long frequency, @Nullable UUID placerId, IWirelessEndpoint endpoint) {
|
||||
if (frequency == 0L || level == null) return;
|
||||
final Key key = new Key(useGlobal() ? null : level.dimension(), frequency);
|
||||
|
||||
UUID ownerUUID = placerId != null
|
||||
? WirelessTeamUtil.getNetworkOwnerUUID(level, placerId)
|
||||
: PUBLIC_NETWORK_UUID;
|
||||
|
||||
final Key key = new Key(useGlobal() ? null : level.dimension(), frequency, ownerUUID);
|
||||
|
||||
var ref = MASTERS.get(key);
|
||||
if (ref != null) {
|
||||
var cur = ref.get();
|
||||
|
|
@ -47,9 +72,15 @@ public final class WirelessMasterRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
public static synchronized IWirelessEndpoint get(ServerLevel level, long frequency) {
|
||||
public static synchronized IWirelessEndpoint get(ServerLevel level, long frequency, @Nullable UUID placerId) {
|
||||
if (frequency == 0L || level == null) return null;
|
||||
final Key key = new Key(useGlobal() ? null : level.dimension(), frequency);
|
||||
|
||||
UUID ownerUUID = placerId != null
|
||||
? WirelessTeamUtil.getNetworkOwnerUUID(level, placerId)
|
||||
: PUBLIC_NETWORK_UUID;
|
||||
|
||||
final Key key = new Key(useGlobal() ? null : level.dimension(), frequency, ownerUUID);
|
||||
|
||||
cleanupIfCleared(key);
|
||||
var ref = MASTERS.get(key);
|
||||
return ref == null ? null : ref.get();
|
||||
|
|
@ -66,9 +97,12 @@ public final class WirelessMasterRegistry {
|
|||
return ModConfigs.WIRELESS_CROSS_DIM_ENABLE.get();
|
||||
}
|
||||
|
||||
private record Key(ResourceKey<Level> dim, long freq) {
|
||||
@Override public String toString() {
|
||||
return (dim == null ? "*" : dim.location().toString()) + "#" + freq;
|
||||
private record Key(@Nullable ResourceKey<Level> dim, long freq, UUID owner) {
|
||||
@Override
|
||||
public String toString() {
|
||||
return (dim == null ? "*" : dim.location().toString())
|
||||
+ "#" + freq
|
||||
+ "@" + owner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,18 +7,22 @@ import appeng.me.service.helpers.ConnectionWrapper;
|
|||
import com.extendedae_plus.config.ModConfigs;
|
||||
import com.extendedae_plus.util.ExtendedAELogger;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 从收发器连接器:
|
||||
* - 通过频率查找同维度主收发器;
|
||||
* - 校验距离(<= ModConfigs.WIRELESS_MAX_RANGE);
|
||||
* - 动态创建/销毁 AE2 连接(GridConnection),实现“一主多从”。
|
||||
* - 动态创建/销毁 AE2 连接(GridConnection),实现"一主多从"。
|
||||
*/
|
||||
public class WirelessSlaveLink {
|
||||
private final IWirelessEndpoint host;
|
||||
private long frequency; // 0 未设置
|
||||
@Nullable
|
||||
private UUID placerId; // 放置者UUID
|
||||
|
||||
private ConnectionWrapper connection = new ConnectionWrapper(null);
|
||||
private boolean shutdown = true;
|
||||
|
|
@ -27,6 +31,10 @@ public class WirelessSlaveLink {
|
|||
public WirelessSlaveLink(IWirelessEndpoint host) {
|
||||
this.host = Objects.requireNonNull(host);
|
||||
}
|
||||
|
||||
public void setPlacerId(@Nullable UUID placerId) {
|
||||
this.placerId = placerId;
|
||||
}
|
||||
|
||||
public void setFrequency(long frequency) {
|
||||
if (this.frequency != frequency) {
|
||||
|
|
@ -62,7 +70,8 @@ public class WirelessSlaveLink {
|
|||
return;
|
||||
}
|
||||
|
||||
IWirelessEndpoint master = WirelessMasterRegistry.get(level, frequency);
|
||||
// placerId可以为null(公共收发器模式)
|
||||
IWirelessEndpoint master = WirelessMasterRegistry.get(level, frequency, placerId);
|
||||
shutdown = false;
|
||||
distance = 0.0D;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@
|
|||
"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.channel_card.owner.unset": "Owner: Unbound",
|
||||
"item.extendedae_plus.channel_card.owner.team": "Owner: %s",
|
||||
"item.extendedae_plus.channel_card.owner.player": "Owner: %s",
|
||||
"item.extendedae_plus.channel_card.owner.bound": "Bound to: %s",
|
||||
"item.extendedae_plus.channel_card.owner.cleared": "Binding cleared",
|
||||
"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)",
|
||||
|
|
@ -103,5 +108,17 @@
|
|||
"extendedae_plus.configuration.prioritizeDiskEnergy": "Prioritize FE energy from disk (requires Applied Flux)",
|
||||
|
||||
"extendedae_plus.configuration.state_on": "On",
|
||||
"extendedae_plus.configuration.state_off": "Off"
|
||||
"extendedae_plus.configuration.state_off": "Off",
|
||||
|
||||
"extendedae_plus.tooltip.owner": "Owner: %s",
|
||||
"extendedae_plus.tooltip.owner.public": "Owner: Public",
|
||||
"extendedae_plus.tooltip.channels": "Channels: %d",
|
||||
"extendedae_plus.tooltip.channels_of": "Channels: %d / %d",
|
||||
"extendedae_plus.tooltip.frequency": "Frequency: %d",
|
||||
"extendedae_plus.tooltip.master_mode": "Mode: %s",
|
||||
"extendedae_plus.tooltip.locked": "Status: %s",
|
||||
|
||||
"group.pattern_provider.name": "Pattern Provider",
|
||||
"group.storage.name": "Storage Bus",
|
||||
"group.entity_ticker.name": "Entity Ticker"
|
||||
}
|
||||
|
|
@ -22,6 +22,11 @@
|
|||
"item.extendedae_plus.channel_card.channel": "频道: %d",
|
||||
"item.extendedae_plus.channel_card.channel.unset": "频道: 未设置",
|
||||
"item.extendedae_plus.channel_card.set": "频道已设置为: %d",
|
||||
"item.extendedae_plus.channel_card.owner.unset": "所有者: 未绑定",
|
||||
"item.extendedae_plus.channel_card.owner.team": "所有者: %s",
|
||||
"item.extendedae_plus.channel_card.owner.player": "所有者: %s",
|
||||
"item.extendedae_plus.channel_card.owner.bound": "已绑定到: %s",
|
||||
"item.extendedae_plus.channel_card.owner.cleared": "已清除绑定",
|
||||
"item.extendedae_plus.entity_speed_card": "实体加速卡",
|
||||
"item.extendedae_plus.entity_speed_card.x2": "实体加速卡 (x2)",
|
||||
"item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)",
|
||||
|
|
@ -103,5 +108,17 @@
|
|||
"extendedae_plus.configuration.prioritizeDiskEnergy": "优先从磁盘提取FE能量(仅当Applied Flux模组存在时生效)",
|
||||
|
||||
"extendedae_plus.configuration.state_on": "开",
|
||||
"extendedae_plus.configuration.state_off": "关"
|
||||
"extendedae_plus.configuration.state_off": "关",
|
||||
|
||||
"extendedae_plus.tooltip.owner": "所有者: %s",
|
||||
"extendedae_plus.tooltip.owner.public": "所有者: 公共",
|
||||
"extendedae_plus.tooltip.channels": "频道: %d",
|
||||
"extendedae_plus.tooltip.channels_of": "频道: %d / %d",
|
||||
"extendedae_plus.tooltip.frequency": "频率: %d",
|
||||
"extendedae_plus.tooltip.master_mode": "模式: %s",
|
||||
"extendedae_plus.tooltip.locked": "状态: %s",
|
||||
|
||||
"group.pattern_provider.name": "样板供应器",
|
||||
"group.storage.name": "存储总线",
|
||||
"group.entity_ticker.name": "实体加速器"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user