diff --git a/README.md b/README.md index ed59fba..1616213 100644 --- a/README.md +++ b/README.md @@ -26,44 +26,44 @@ mod包名为com.le.teleportmirror 。 ## 回城魔镜 ### 初级回城魔镜 -金锭 指南针 金锭 -铁锭 蓝色染色玻璃板 铁锭 +金锭 指南针 金锭 +铁锭 蓝色染色玻璃板 铁锭 铜锭 铁锭 铜锭 ### 中级回城魔镜 -钻石 末影珍珠 钻石 -青金石 初级回城魔镜 青金石 +钻石 末影珍珠 钻石 +青金石 初级回城魔镜 青金石 红石 紫水晶碎片 红石 ### 高级回城魔镜 -钻石 末影之眼 钻石 -绿宝石 中级回城魔镜 绿宝石 +钻石 末影之眼 钻石 +绿宝石 中级回城魔镜 绿宝石 钻石 烈焰棒 钻石 ### 永久回城魔镜 -潜影壳 紫颂果 潜影壳 -末影珍珠 高级回城魔镜 末影珍珠 +潜影壳 紫颂果 潜影壳 +末影珍珠 高级回城魔镜 末影珍珠 潜影壳 回响碎片 潜影壳 ## 传送魔镜 ### 初级传送魔镜 -金锭 拴绳 金锭 -铁锭 橙色染色玻璃板 铁锭 +金锭 拴绳 金锭 +铁锭 橙色染色玻璃板 铁锭 铜锭 铁锭 铜锭 ### 中级传送魔镜 -钻石 末影珍珠 钻石 -青金石 初级传送魔镜 青金石 +钻石 末影珍珠 钻石 +青金石 初级传送魔镜 青金石 红石 紫水晶碎片 红石 ### 高级传送魔镜 -钻石 末影之眼 钻石 -绿宝石 中级传送魔镜 绿宝石 +钻石 末影之眼 钻石 +绿宝石 中级传送魔镜 绿宝石 钻石 烈焰棒 钻石 ### 永久传送魔镜 -潜影壳 紫颂果 潜影壳 -末影珍珠 高级传送魔镜 末影珍珠 +潜影壳 紫颂果 潜影壳 +末影珍珠 高级传送魔镜 末影珍珠 潜影壳 回响碎片 潜影壳 # 五、特殊机制 diff --git a/gradle.properties b/gradle.properties index eb0f6db..bd325cf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -32,7 +32,7 @@ mod_name=Teleport Mirror # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=1.0.2 +mod_version=1.0.3 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/com/le/teleportmirror/Config.java b/src/main/java/com/le/teleportmirror/Config.java index 01ac891..a627248 100644 --- a/src/main/java/com/le/teleportmirror/Config.java +++ b/src/main/java/com/le/teleportmirror/Config.java @@ -2,6 +2,22 @@ package com.le.teleportmirror; import net.neoforged.neoforge.common.ModConfigSpec; +/** + * Mod 配置项 + *

+ * 使用 NeoForge 的 {@link ModConfigSpec} 定义所有可配置项。 + * 所有配置项按功能分为以下几个部分: + *

+ */ public class Config { private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder(); diff --git a/src/main/java/com/le/teleportmirror/MirrorItem.java b/src/main/java/com/le/teleportmirror/MirrorItem.java index aaa2c85..f090018 100644 --- a/src/main/java/com/le/teleportmirror/MirrorItem.java +++ b/src/main/java/com/le/teleportmirror/MirrorItem.java @@ -20,34 +20,60 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.UseAnim; import net.minecraft.world.level.Level; +/** + * 魔镜物品类 + *

+ * 魔镜是一个可蓄力使用的物品,长按右键蓄力完成后触发传送效果。 + * 支持两种功能类型(回城/传送)和四个等级(初级/中级/高级/永久)。 + *

+ * 使用流程: + *

    + *
  1. 玩家右键开始蓄力(显示弓的动画)
  2. + *
  3. 达到蓄力时间后触发效果
  4. + *
  5. 回城魔镜直接传送;传送魔镜打开玩家选择界面
  6. + *
  7. 消耗耐久、附加副作用、设置冷却
  8. + *
+ */ public class MirrorItem extends Item { + /** 魔镜等级 */ private final MirrorTier tier; + /** 魔镜功能类型 */ private final MirrorType type; + /** + * @param tier 魔镜等级 + * @param type 魔镜类型(回城或传送) + * @param properties 物品属性(耐久度、堆叠数等) + */ public MirrorItem(MirrorTier tier, MirrorType type, Properties properties) { super(properties); this.tier = tier; this.type = type; } + /** 获取魔镜等级 */ public MirrorTier getTier() { return tier; } + /** 获取魔镜功能类型 */ public MirrorType getMirrorType() { return type; } + /** 使用弓的拉动动画来表现蓄力过程 */ @Override public UseAnim getUseAnimation(ItemStack stack) { return UseAnim.BOW; } + /** 允许无限蓄力(实际在 onUseTick 中检测是否达到蓄力阈值) */ @Override public int getUseDuration(ItemStack stack, LivingEntity entity) { return 72000; } + /** 右键开始使用魔镜,若在冷却中则无法使用 */ @Override public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { ItemStack stack = player.getItemInHand(hand); @@ -58,6 +84,10 @@ public class MirrorItem extends Item { return InteractionResultHolder.consume(stack); } + /** + * 每 tick 调用,检测蓄力是否达到设定阈值。 + * 到达阈值后停止蓄力,并根据魔镜类型执行回城传送或打开玩家选择界面。 + */ @Override public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, int remainingUseDuration) { if (level.isClientSide) { @@ -86,6 +116,9 @@ public class MirrorItem extends Item { public void releaseUsing(ItemStack stack, Level level, LivingEntity entity, int timeCharged) { } + /** + * 检查当前等级的魔镜是否允许跨维度传送 + */ private boolean canCrossDimension() { return switch (tier) { case BASIC -> Config.ALLOW_CROSS_DIMENSION_BASIC.get(); @@ -95,6 +128,12 @@ public class MirrorItem extends Item { }; } + /** + * 执行回城传送:将玩家传送到其重生点或世界出生点 + * + * @param player 使用魔镜的玩家 + * @param stack 魔镜物品堆 + */ private void performReturnTeleport(ServerPlayer player, ItemStack stack) { ServerLevel serverLevel = player.serverLevel(); BlockPos targetPos; @@ -102,6 +141,7 @@ public class MirrorItem extends Item { ResourceKey respawnDimension = player.getRespawnDimension(); BlockPos respawnPos = player.getRespawnPosition(); + // 优先使用玩家的重生点(床/重生锚) if (respawnPos != null) { targetLevel = player.server.getLevel(respawnDimension); if (targetLevel == null) { @@ -109,6 +149,7 @@ public class MirrorItem extends Item { } targetPos = respawnPos; } else { + // 否则使用主世界的全局出生点 targetLevel = player.server.getLevel(Level.OVERWORLD); if (targetLevel == null) { targetLevel = serverLevel; @@ -128,6 +169,13 @@ public class MirrorItem extends Item { targetLevel.playSound(null, targetPos, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1.0f, 1.0f); } + /** + * 执行传送到目标玩家身边 + * + * @param player 使用魔镜的玩家 + * @param target 目标玩家 + * @param stack 魔镜物品堆 + */ public void performTeleportToPlayer(ServerPlayer player, ServerPlayer target, ItemStack stack) { ServerLevel targetLevel = target.serverLevel(); BlockPos targetPos = target.blockPosition(); @@ -144,6 +192,10 @@ public class MirrorItem extends Item { targetLevel.playSound(null, targetPos, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1.0f, 1.0f); } + /** + * 获取配置中的最大耐久度 + * 永久等级返回 {@link Integer#MAX_VALUE} + */ private int getConfigMaxDamage() { return switch (tier) { case BASIC -> Config.BASIC_DURABILITY.get(); @@ -153,6 +205,9 @@ public class MirrorItem extends Item { }; } + /** + * 消耗一次魔镜使用:附加副作用、设置冷却、扣除耐久 + */ private void consumeMirrorUse(ServerPlayer player, ItemStack stack) { applySideEffects(player); applyCooldown(player); @@ -160,6 +215,7 @@ public class MirrorItem extends Item { if (!tier.isPermanent()) { int maxDamage = getConfigMaxDamage(); if (stack.getDamageValue() + 1 >= maxDamage) { + // 耐久耗尽,物品销毁 stack.shrink(1); player.level().playSound(null, player.blockPosition(), SoundEvents.ITEM_BREAK, SoundSource.PLAYERS, 1.0f, 1.0f); @@ -169,11 +225,13 @@ public class MirrorItem extends Item { } } + /** 设置冷却时间(以 tick 为单位,1秒=20tick) */ private void applyCooldown(Player player) { int cooldownTicks = Config.COOLDOWN_SECONDS.get() * 20; player.getCooldowns().addCooldown(this, cooldownTicks); } + /** 根据魔镜类型和等级获取副作用配置字符串 */ private String getEffectsConfig() { return switch (type) { case RETURN -> switch (tier) { @@ -191,6 +249,7 @@ public class MirrorItem extends Item { }; } + /** 根据魔镜等级获取饱食度消耗配置字符串 */ private String getFoodLevelConfig() { return switch (tier) { case BASIC -> Config.FOOD_LEVEL_BASIC.get(); @@ -200,6 +259,7 @@ public class MirrorItem extends Item { }; } + /** 根据魔镜等级获取饱和度消耗配置字符串 */ private String getSaturationConfig() { return switch (tier) { case BASIC -> Config.SATURATION_COST_BASIC.get(); @@ -209,6 +269,10 @@ public class MirrorItem extends Item { }; } + /** + * 给玩家附加副作用效果和饱食度消耗 + * 副作用配置格式:"effect_id,dur_seconds,amplifier;..." + */ private void applySideEffects(Player player) { String effectsConfig = getEffectsConfig(); if (effectsConfig == null || effectsConfig.isBlank()) { @@ -245,12 +309,21 @@ public class MirrorItem extends Item { applyFoodCost(player); } + /** 扣减饱食度和饱和度 */ private void applyFoodCost(Player player) { FoodData foodData = player.getFoodData(); applyCostValue(getFoodLevelConfig(), (float) foodData.getFoodLevel(), newVal -> foodData.setFoodLevel(newVal.intValue())); applyCostValue(getSaturationConfig(), foodData.getSaturationLevel(), newVal -> foodData.setSaturation(newVal)); } + /** + * 通用数值扣减方法 + * 支持百分比模式(以%结尾)和固定值模式 + * + * @param config 配置字符串,如 "50%" 或 "4.0" + * @param currentValue 当前数值 + * @param setter 数值设置回调 + */ private void applyCostValue(String config, float currentValue, java.util.function.Consumer setter) { if (config == null || config.isBlank()) { return; @@ -272,11 +345,13 @@ public class MirrorItem extends Item { } } + /** 魔镜不可附魔 */ @Override public boolean isEnchantable(ItemStack stack) { return false; } + /** 永久魔镜显示附魔光效 */ @Override public boolean isFoil(ItemStack stack) { return tier == MirrorTier.PERMANENT; diff --git a/src/main/java/com/le/teleportmirror/MirrorNetwork.java b/src/main/java/com/le/teleportmirror/MirrorNetwork.java index 042417f..6b44ae8 100644 --- a/src/main/java/com/le/teleportmirror/MirrorNetwork.java +++ b/src/main/java/com/le/teleportmirror/MirrorNetwork.java @@ -15,8 +15,22 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +/** + * 魔镜的网络通信层 + *

+ * 负责定义和注册自定义网络负载(CustomPacketPayload), + * 处理客户端与服务端之间的魔镜相关通信: + *

    + *
  • OpenPlayerSelectionPayload - 服务端→客户端,打开玩家选择界面
  • + *
  • RequestTeleportPayload - 客户端→服务端,请求传送到目标玩家
  • + *
+ */ public class MirrorNetwork { + /** + * 注册所有的网络负载处理器 + * 在 RegisterPayloadHandlersEvent 事件中调用 + */ public static void registerPayloads(final RegisterPayloadHandlersEvent event) { final PayloadRegistrar registrar = event.registrar(TeleportMirrorMod.MODID).versioned("1.0.0"); @@ -33,15 +47,23 @@ public class MirrorNetwork { ); } + /** + * 向指定客户端发送打开玩家选择界面的请求 + * + * @param player 目标玩家 + * @param tier 魔镜等级 + */ public static void sendOpenSelectionToClient(ServerPlayer player, MirrorTier tier) { List names = new ArrayList<>(); List uuids = new ArrayList<>(); boolean teamOnly = Config.TELEPORT_TEAM_ONLY.get(); for (ServerPlayer onlinePlayer : player.server.getPlayerList().getPlayers()) { + // 排除使用者自身 if (onlinePlayer.getUUID().equals(player.getUUID())) { continue; } + // 如果开启了同队伍限制,仅保留同队伍玩家 if (teamOnly) { var playerTeam = player.getTeam(); var targetTeam = onlinePlayer.getTeam(); @@ -59,6 +81,10 @@ public class MirrorNetwork { PacketDistributor.sendToPlayer(player, new OpenPlayerSelectionPayload(names, uuids, tier.getName())); } + /** + * 处理服务端发来的打开选择界面负载 + * 通过反射调用客户端专用类以避免在服务端加载客户端代码 + */ private static void handleOpenSelection(OpenPlayerSelectionPayload payload, IPayloadContext context) { context.enqueueWork(() -> { try { @@ -71,6 +97,10 @@ public class MirrorNetwork { }); } + /** + * 处理客户端发来的传送请求 + * 验证玩家手中的魔镜类型和等级后执行传送 + */ private static void handleRequestTeleport(RequestTeleportPayload payload, IPayloadContext context) { context.enqueueWork(() -> { ServerPlayer sender = (ServerPlayer) context.player(); @@ -84,6 +114,7 @@ public class MirrorNetwork { ItemStack mainHand = sender.getMainHandItem(); ItemStack offHand = sender.getOffhandItem(); + // 检查主手和副手中是否有正确的传送魔镜 ItemStack mirrorStack = null; if (mainHand.getItem() instanceof MirrorItem mirrorItem && mirrorItem.getMirrorType() == MirrorType.TELEPORT) { mirrorStack = mainHand; @@ -104,6 +135,9 @@ public class MirrorNetwork { }); } + /** + * 打开玩家选择界面的网络负载(服务端 → 客户端) + */ public record OpenPlayerSelectionPayload(List playerNames, List playerUuids, String tierName) implements CustomPacketPayload { public static final Type TYPE = new Type<>( @@ -140,6 +174,9 @@ public class MirrorNetwork { } } + /** + * 请求传送到目标玩家的网络负载(客户端 → 服务端) + */ public record RequestTeleportPayload(UUID targetUuid, String tierName) implements CustomPacketPayload { public static final Type TYPE = new Type<>( ResourceLocation.fromNamespaceAndPath(TeleportMirrorMod.MODID, "request_teleport")); diff --git a/src/main/java/com/le/teleportmirror/MirrorNetworkClient.java b/src/main/java/com/le/teleportmirror/MirrorNetworkClient.java index c52a089..9c3382d 100644 --- a/src/main/java/com/le/teleportmirror/MirrorNetworkClient.java +++ b/src/main/java/com/le/teleportmirror/MirrorNetworkClient.java @@ -5,9 +5,21 @@ import net.minecraft.client.Minecraft; import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.OnlyIn; +/** + * 客户端网络处理器 + *

+ * 仅编译到客户端(通过 @OnlyIn(Dist.CLIENT) 注解), + * 负责接收服务端发来的网络负载并打开对应的客户端界面。 + * 在专用服务端环境中此类不会被加载。 + */ @OnlyIn(Dist.CLIENT) public class MirrorNetworkClient { + /** + * 接收服务端发送的玩家选择请求,在客户端打开玩家选择界面 + * + * @param payload 包含可选玩家列表、UUID 和魔镜等级的网络负载 + */ public static void openPlayerSelection(MirrorNetwork.OpenPlayerSelectionPayload payload) { Minecraft client = Minecraft.getInstance(); MirrorTier tier = MirrorTier.valueOf(payload.tierName().toUpperCase()); diff --git a/src/main/java/com/le/teleportmirror/MirrorTier.java b/src/main/java/com/le/teleportmirror/MirrorTier.java index 9e7458f..00d4dba 100644 --- a/src/main/java/com/le/teleportmirror/MirrorTier.java +++ b/src/main/java/com/le/teleportmirror/MirrorTier.java @@ -1,12 +1,25 @@ package com.le.teleportmirror; +/** + * 魔镜的等级 + *

+ * 不同等级影响耐久度、冷却时间、副作用强度等属性 + *

    + *
  • BASIC (初级) - 默认耐久10
  • + *
  • INTERMEDIATE (中级) - 默认耐久50
  • + *
  • ADVANCED (高级) - 默认耐久100
  • + *
  • PERMANENT (永久) - 无限耐久,无副作用
  • + *
+ */ public enum MirrorTier { BASIC(10, "basic"), INTERMEDIATE(50, "intermediate"), ADVANCED(100, "advanced"), PERMANENT(-1, "permanent"); + /** 默认耐久度 */ private final int defaultDurability; + /** 等级名称,用于注册和序列化 */ private final String name; MirrorTier(int defaultDurability, String name) { @@ -14,14 +27,17 @@ public enum MirrorTier { this.name = name; } + /** 获取该等级的默认耐久度 */ public int getDefaultDurability() { return defaultDurability; } + /** 获取等级名称 */ public String getName() { return name; } + /** 是否为永久等级(无限耐久) */ public boolean isPermanent() { return this == PERMANENT; } diff --git a/src/main/java/com/le/teleportmirror/MirrorType.java b/src/main/java/com/le/teleportmirror/MirrorType.java index 24b6068..bd518f6 100644 --- a/src/main/java/com/le/teleportmirror/MirrorType.java +++ b/src/main/java/com/le/teleportmirror/MirrorType.java @@ -1,15 +1,23 @@ package com.le.teleportmirror; +/** + * 魔镜的功能类型 + *

+ * RETURN - 回城魔镜:将使用者传送回出生点 + * TELEPORT - 传送魔镜:将使用者传送到另一个玩家身边 + */ public enum MirrorType { RETURN("return"), TELEPORT("teleport"); + /** 类型名称,用于注册和序列化 */ private final String name; MirrorType(String name) { this.name = name; } + /** 获取类型名称 */ public String getName() { return name; } diff --git a/src/main/java/com/le/teleportmirror/TeleportMirrorMod.java b/src/main/java/com/le/teleportmirror/TeleportMirrorMod.java index 069b295..480b8b6 100644 --- a/src/main/java/com/le/teleportmirror/TeleportMirrorMod.java +++ b/src/main/java/com/le/teleportmirror/TeleportMirrorMod.java @@ -30,46 +30,74 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +/** + * Teleport Mirror Mod 主类 + *

+ * NeoForge Mod 的入口点(通过 {@link Mod} 注解)。 + * 负责: + *

    + *
  • 注册所有魔镜物品(8种:回城/传送 × 4个等级)
  • + *
  • 创建创造模式标签页
  • + *
  • 注册配置文件
  • + *
  • 注册网络负载处理器
  • + *
  • 在服务端启动时注入配置覆盖的配方
  • + *
+ */ @Mod(TeleportMirrorMod.MODID) public class TeleportMirrorMod { public static final String MODID = "teleportmirror"; + /** 物品注册器 */ public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID); + /** 创造模式标签页注册器 */ public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID); + // ==================== 回城魔镜 ==================== + + /** 初级回城魔镜 */ public static final DeferredItem BASIC_RETURN_MIRROR = ITEMS.register("basic_return_mirror", () -> new MirrorItem(MirrorTier.BASIC, MirrorType.RETURN, new Item.Properties().stacksTo(1).durability(MirrorTier.BASIC.getDefaultDurability()))); + /** 中级回城魔镜 */ public static final DeferredItem INTERMEDIATE_RETURN_MIRROR = ITEMS.register("intermediate_return_mirror", () -> new MirrorItem(MirrorTier.INTERMEDIATE, MirrorType.RETURN, new Item.Properties().stacksTo(1).durability(MirrorTier.INTERMEDIATE.getDefaultDurability()))); + /** 高级回城魔镜 */ public static final DeferredItem ADVANCED_RETURN_MIRROR = ITEMS.register("advanced_return_mirror", () -> new MirrorItem(MirrorTier.ADVANCED, MirrorType.RETURN, new Item.Properties().stacksTo(1).durability(MirrorTier.ADVANCED.getDefaultDurability()))); + /** 永久回城魔镜 */ public static final DeferredItem PERMANENT_RETURN_MIRROR = ITEMS.register("permanent_return_mirror", () -> new MirrorItem(MirrorTier.PERMANENT, MirrorType.RETURN, new Item.Properties().stacksTo(1))); + // ==================== 传送魔镜 ==================== + + /** 初级传送魔镜 */ public static final DeferredItem BASIC_TELEPORT_MIRROR = ITEMS.register("basic_teleport_mirror", () -> new MirrorItem(MirrorTier.BASIC, MirrorType.TELEPORT, new Item.Properties().stacksTo(1).durability(MirrorTier.BASIC.getDefaultDurability()))); + /** 中级传送魔镜 */ public static final DeferredItem INTERMEDIATE_TELEPORT_MIRROR = ITEMS.register("intermediate_teleport_mirror", () -> new MirrorItem(MirrorTier.INTERMEDIATE, MirrorType.TELEPORT, new Item.Properties().stacksTo(1).durability(MirrorTier.INTERMEDIATE.getDefaultDurability()))); + /** 高级传送魔镜 */ public static final DeferredItem ADVANCED_TELEPORT_MIRROR = ITEMS.register("advanced_teleport_mirror", () -> new MirrorItem(MirrorTier.ADVANCED, MirrorType.TELEPORT, new Item.Properties().stacksTo(1).durability(MirrorTier.ADVANCED.getDefaultDurability()))); + /** 永久传送魔镜 */ public static final DeferredItem PERMANENT_TELEPORT_MIRROR = ITEMS.register("permanent_teleport_mirror", () -> new MirrorItem(MirrorTier.PERMANENT, MirrorType.TELEPORT, new Item.Properties().stacksTo(1))); + /** 创造模式 "魔镜" 标签页,包含所有8种魔镜 */ public static final DeferredHolder MIRROR_TAB = CREATIVE_MODE_TABS.register("mirror_tab", () -> CreativeModeTab.builder() .title(Component.translatable("itemGroup.teleportmirror")) @@ -86,6 +114,11 @@ public class TeleportMirrorMod { output.accept(PERMANENT_TELEPORT_MIRROR.get()); }).build()); + /** + * Mod 构造器 + * 注册物品、创造标签页、配置文件、网络负载处理器, + * 并在服务端启动时注入配置覆盖的配方 + */ public TeleportMirrorMod(IEventBus modEventBus, ModContainer modContainer) { ITEMS.register(modEventBus); CREATIVE_MODE_TABS.register(modEventBus); @@ -96,14 +129,19 @@ public class TeleportMirrorMod { NeoForge.EVENT_BUS.addListener(this::onServerStarted); } + /** 注册网络负载处理器 */ private void onRegisterPayloads(final RegisterPayloadHandlersEvent event) { MirrorNetwork.registerPayloads(event); } + /** 服务端启动后,注入配置覆盖的配方 */ private void onServerStarted(final ServerStartedEvent event) { registerConfigRecipes(event.getServer().getRecipeManager()); } + /** + * 检查所有8种魔镜的配方配置,将配置覆盖的配方注入到配方管理器 + */ private void registerConfigRecipes(net.minecraft.world.item.crafting.RecipeManager manager) { tryRegisterRecipe(manager, Config.ENABLE_BASIC_RECIPE.get(), Config.RECIPE_OVERRIDE_RETURN_BASIC.get(), BASIC_RETURN_MIRROR.get(), "basic_return_mirror"); @@ -123,6 +161,19 @@ public class TeleportMirrorMod { Config.RECIPE_OVERRIDE_TELEPORT_PERMANENT.get(), PERMANENT_TELEPORT_MIRROR.get(), "permanent_teleport_mirror"); } + /** + * 尝试将配置覆盖的配方注入到配方管理器 + *

+ * 如果 override 为空则跳过(使用默认 JSON 配方)。 + * 如果 enabled 为 false 也跳过(配方被禁用)。 + * 通过反射访问配方管理器的内部 Map 来注入动态配方。 + * + * @param manager 配方管理器 + * @param enabled 配方是否启用 + * @param override 配方覆盖字符串 + * @param result 配方输出物品 + * @param name 配方名称 + */ @SuppressWarnings("unchecked") private void tryRegisterRecipe(net.minecraft.world.item.crafting.RecipeManager manager, boolean enabled, String override, Item result, String name) { @@ -150,6 +201,17 @@ public class TeleportMirrorMod { } } + /** + * 将配方覆盖字符串解析为 RecipeHolder + *

+ * 格式:"row1;row2;row3|key=item_id;..." + * 示例:" C ;CGC; C |C=minecraft:copper_ingot;G=minecraft:glass_pane" + * + * @param override 配方覆盖字符串 + * @param result 配方输出物品 + * @param name 配方名称 + * @return 解析后的 RecipeHolder,解析失败返回 null + */ private RecipeHolder parseRecipeOverride(String override, Item result, String name) { String[] parts = override.split("\\|"); if (parts.length < 2) return null; diff --git a/src/main/java/com/le/teleportmirror/screen/PlayerSelectionScreen.java b/src/main/java/com/le/teleportmirror/screen/PlayerSelectionScreen.java index e64fbb2..3fadf11 100644 --- a/src/main/java/com/le/teleportmirror/screen/PlayerSelectionScreen.java +++ b/src/main/java/com/le/teleportmirror/screen/PlayerSelectionScreen.java @@ -11,13 +11,35 @@ import net.neoforged.neoforge.network.PacketDistributor; import java.util.List; import java.util.UUID; +/** + * 玩家选择界面 + *

+ * 当玩家使用传送魔镜长按右键蓄力完成后,客户端会打开此界面。 + * 界面列出当前在线的可选玩家,玩家点击按钮选择目标后, + * 通过网络包向服务端发送传送请求,服务端执行实际传送逻辑。 + *

+ * 支持分页:每页最多显示 {@value #BUTTONS_PER_PAGE} 名玩家, + * 通过滚动按钮切换页码。 + *

+ * 该界面不暂停游戏(isPauseScreen 返回 false)。 + */ public class PlayerSelectionScreen extends Screen { + /** 可选玩家名称列表 */ private final List playerNames; + /** 可选玩家 UUID 列表(与 playerNames 一一对应) */ private final List playerUuids; + /** 当前使用的魔镜等级 */ private final MirrorTier tier; + /** 当前滚动偏移量 */ private int scrollOffset = 0; + /** 每页最多显示的玩家按钮数量 */ private static final int BUTTONS_PER_PAGE = 8; + /** + * @param playerNames 可选玩家的显示名称 + * @param playerUuids 可选玩家的 UUID + * @param tier 魔镜等级 + */ public PlayerSelectionScreen(List playerNames, List playerUuids, MirrorTier tier) { super(Component.translatable("screen.teleportmirror.select_player")); this.playerNames = playerNames; @@ -31,6 +53,10 @@ public class PlayerSelectionScreen extends Screen { rebuildButtons(); } + /** + * 重建按钮布局 + * 根据 scrollOffset 显示当前页的玩家按钮,以及滚动按钮和取消按钮 + */ private void rebuildButtons() { this.clearWidgets(); @@ -55,15 +81,16 @@ public class PlayerSelectionScreen extends Screen { .build()); } + // 如果玩家数量超过单页容量,显示滚动按钮 if (playerNames.size() > BUTTONS_PER_PAGE) { this.addRenderableWidget(Button.builder( - Component.literal("\u25B2"), + Component.literal("\u25B2"), // 上箭头 ▲ btn -> { scrollOffset = Math.max(0, scrollOffset - 1); rebuildButtons(); }) .pos(centerX + buttonWidth / 2 + 5, startY) .size(20, 20) .build()); this.addRenderableWidget(Button.builder( - Component.literal("\u25BC"), + Component.literal("\u25BC"), // 下箭头 ▼ btn -> { scrollOffset = Math.min(maxOffset, scrollOffset + 1); rebuildButtons(); }) .pos(centerX + buttonWidth / 2 + 5, startY + BUTTONS_PER_PAGE * (buttonHeight + spacing) - spacing) .size(20, 20) @@ -78,6 +105,11 @@ public class PlayerSelectionScreen extends Screen { .build()); } + /** + * 玩家点击某个目标后,向服务端发送传送请求并关闭界面 + * + * @param index 所选玩家在列表中的索引 + */ private void selectPlayer(int index) { if (index >= 0 && index < playerUuids.size()) { UUID targetUuid = playerUuids.get(index);