diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 18cc1033c..f2631ddea 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -14,6 +14,7 @@ import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; +import io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -129,6 +130,7 @@ import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.BiFunction; import java.util.function.Predicate; @@ -1767,6 +1769,15 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public static class FinishConfigurationListener implements NMSPacketListener { + private void returnToWorld(NetWorkUser user, Queue configurationTasks, Object packetListener) { + configurationTasks.add(CoreReflections.instance$JoinWorldTask); + try { + CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$startNextTask.invokeExact(packetListener); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Cannot return to world for " + user.name(), e); + } + } + @SuppressWarnings("unchecked") @Override public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { @@ -1817,15 +1828,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes // 请求资源包 ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost(); host.requestResourcePackDownloadLink(user.uuid()).whenComplete((dataList, t) -> { - if (t != null) { - CraftEngine.instance().logger().warn("Failed to get pack data for player " + user.name(), t); - FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); - return; - } - if (dataList.isEmpty()) { - FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); - return; - } Queue configurationTasks; try { configurationTasks = (Queue) CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter.invokeExact(packetListener); @@ -1834,13 +1836,22 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); return; } + if (t != null) { + CraftEngine.instance().logger().warn("Failed to get pack data for player " + user.name(), t); + returnToWorld(user, configurationTasks, packetListener); + return; + } + if (dataList.isEmpty()) { + returnToWorld(user, configurationTasks, packetListener); + return; + } // 向配置阶段连接的任务重加入资源包的任务 for (ResourcePackDownloadData data : dataList) { configurationTasks.add(FastNMS.INSTANCE.constructor$ServerResourcePackConfigurationTask(ResourcePackUtils.createServerResourcePackInfo(data.uuid(), data.url(), data.sha1()))); user.addResourcePackUUID(data.uuid()); } // 最后再加入一个 JoinWorldTask 并开始资源包任务 - FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + returnToWorld(user, configurationTasks, packetListener); }); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 146162837..5d4d7286b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3958,6 +3958,27 @@ public final class CoreReflections { } } + // 1.20.2+ + public static final Method method$ServerConfigurationPacketListenerImpl$startNextTask = Optional.ofNullable(clazz$ServerConfigurationPacketListenerImpl) + .map(it -> ReflectionUtils.getDeclaredMethod(it, void.class, VersionHelper.isOrAbove1_20_5() ? new String[]{"startNextTask", "o"} : new String[]{"startNextTask", "p"})) + .orElse(null); + + public static final MethodHandle methodHandle$ServerConfigurationPacketListenerImpl$startNextTask; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + methodHandle$ServerConfigurationPacketListenerImpl$startNextTask = + ReflectionUtils.unreflectMethod(method$ServerConfigurationPacketListenerImpl$startNextTask) + .asType(MethodType.methodType(void.class, Object.class)); + } else { + methodHandle$ServerConfigurationPacketListenerImpl$startNextTask = null; + } + } catch (IllegalAccessException e) { + throw new ReflectionInitException("Failed to initialize reflection", e); + } + } + public static final Class clazz$JoinWorldTask = MiscUtils.requireNonNullIf( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("server.network.config.JoinWorldTask") diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 5089cdfb1..bb9da733c 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -220,7 +220,7 @@ warning.config.template.argument.self_increase_int.invalid_range: "Issue warning.config.template.argument.to_upper_case.invalid_locale: "Issue found in file - The template '' is using an invalid locale '' in 'to_upper_case' argument." warning.config.template.argument.to_upper_case.missing_value: "Issue found in file - The template '' is missing the required 'value' argument for 'to_upper_case' argument." warning.config.template.argument.to_lower_case.invalid_locale: "Issue found in file - The template '' is using an invalid locale '' in 'to_lower_case' argument." -warning.config.template.argument.to_lower_case.missing_value: "Issue found in file - The template '' is missing the required 'value' argument for 'to_upper_case' argument." +warning.config.template.argument.to_lower_case.missing_value: "Issue found in file - The template '' is missing the required 'value' argument for 'to_lower_case' argument." warning.config.template.argument.list.invalid_type: "Issue found in file - The template '' is using a 'list' argument which expects a 'List' as argument while the input argument is a(n) ''." warning.config.template.argument.missing_value: "Issue found in file - The config '' is missing the template argument for ''. Please use the arguments option to configure or set a default value for this parameter." warning.config.vanilla_loot.missing_type: "Issue found in file - The vanilla loot '' is missing the required 'type' argument." @@ -544,6 +544,7 @@ warning.config.function.transform_block.missing_block: "Issue found in f warning.config.function.cycle_block_property.missing_property: "Issue found in file - The config '' is missing the required 'property' argument for 'cycle_block_property' function." warning.config.function.set_exp.missing_count: "Issue found in file - The config '' is missing the required 'count' argument for 'set_exp' function." warning.config.function.set_level.missing_count: "Issue found in file - The config '' is missing the required 'count' argument for 'set_level' function." +warning.config.function.play_totem_animation.missing_item: "Issue found in file - The config '' is missing the required 'item' argument for 'play_totem_animation' function." warning.config.function.clear_item.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'clear_item' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index bf82355f0..f31e79875 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -88,6 +88,8 @@ command.send_resource_pack.success.multiple: "发送资源包给 command.locale.set.failure: "区域设置格式无效: " command.locale.set.success: "已为 更新选定区域设置为 " command.locale.unset.success: "已清除 的选定区域设置" +command.entity_view_distance_scale.set.success: "已为 的实体可见距离百分比设置为 " +command.entity_culling.toggle.success: "已为 的实体剔除状态设置为 " warning.network.resource_pack.unverified_uuid: "玩家 使用未经服务器验证的 UUID () 尝试请求获取资源包" warning.config.pack.duplicated_files: "发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决" warning.config.yaml.duplicated_key: "在文件 发现问题 - 在第行发现重复的键 '', 这可能会导致一些意料之外的问题" @@ -101,6 +103,7 @@ warning.config.type.quaternionf: "在文件 发现问题 - 无 warning.config.type.vector3f: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为三维向量类型 (选项 '')" warning.config.type.vec3d: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为双精度浮点数三维向量类型 (选项 '')" warning.config.type.map: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为映射类型 (选项 '')" +warning.config.type.aabb: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为轴对齐包围盒类型 (选项 '')" warning.config.type.snbt.invalid_syntax: "在文件 发现问题 - 无法加载 '': 无效的 SNBT 语法 ''" warning.config.type.snbt.invalid_syntax.parse_error: ",位于第个字符:" warning.config.type.snbt.invalid_syntax.here: "<--[此处]" @@ -214,6 +217,10 @@ warning.config.translation.unknown_locale: "在文件 发现问 warning.config.template.duplicate: "在文件 发现问题 - 重复的模板 '' 请检查其他文件中是否存在相同配置" warning.config.template.invalid: "在文件 发现问题 - 配置项 '' 使用了无效的模板 ''" warning.config.template.argument.self_increase_int.invalid_range: "在文件 发现问题 - 模板 '' 在 'self_increase_int' 参数中使用了一个起始值 '' 大于终止值 ''" +warning.config.template.argument.to_upper_case.invalid_locale: "在文件 发现问题 - 模板 '' 在 'to_upper_case' 参数中使用了无效的区域设置 ''" +warning.config.template.argument.to_upper_case.missing_value: "在文件 发现问题 - 模板 '' 缺少 'to_upper_case' 参数所需的 'value' 参数" +warning.config.template.argument.to_lower_case.invalid_locale: "在文件 发现问题 - 模板 '' 在 'to_lower_case' 参数中使用了无效的区域设置 ''" +warning.config.template.argument.to_lower_case.missing_value: "在文件 发现问题 - 模板 '' 缺少 'to_lower_case' 参数所需的 'value' 参数" warning.config.template.argument.list.invalid_type: "在文件 发现问题 - 模板 '' 的 'list' 参数需要列表类型 但输入参数类型为 ''" warning.config.template.argument.missing_value: "在文件 发现问题 - 配置项 '' 缺少了 '' 必要的模板参数值. 请使用 arguments 选项进行配置或为此参数设定默认值" warning.config.vanilla_loot.missing_type: "在文件 发现问题 - 原版战利品 '' 缺少必需的 'type' 参数" @@ -226,6 +233,7 @@ warning.config.jukebox_song.duplicate: "在文件 发现问题 - warning.config.jukebox_song.missing_sound: "在文件 发现问题 - 唱片机歌曲 '' 缺少必需的 'sound' 参数" warning.config.furniture.duplicate: "在文件 发现问题 - 重复的家具 '' 请检查其他文件中是否存在相同配置" warning.config.furniture.missing_variants: "在文件 发现问题 - 家具 '' 缺少必需的 'variants' 参数" +warning.config.furniture.element.invalid_type: "在文件 发现问题 - 家具 '' 使用了无效的元素类型 ''" warning.config.furniture.element.item_display.missing_item: "在文件 发现问题 - 家具 '' 的 'item_display' 元素缺少必需的 'item' 参数" warning.config.furniture.settings.unknown: "在文件 发现问题 - 家具 '' 使用了未知的设置类型 ''" warning.config.furniture.hitbox.invalid_type: "在文件 发现问题 - 家具 '' 使用了无效的碰撞箱类型 ''" @@ -536,6 +544,7 @@ warning.config.function.transform_block.missing_block: "在文件 在文件 发现问题 - 配置项 '' 缺少 'cycle_block_property' 函数所需的 'property' 参数" warning.config.function.set_exp.missing_count: "在文件 发现问题 - 配置项 '' 缺少 'set_exp' 函数所需的 'count' 参数" warning.config.function.set_level.missing_count: "在文件 发现问题 - 配置项 '' 缺少 'set_level' 函数所需的 'count' 参数" +warning.config.function.play_totem_animation.missing_item: "在文件 发现问题 - 配置项 '' 缺少 'play_totem_animation' 函数所需的 'item' 参数" warning.config.function.clear_item.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'clear_item' 函数所需的 'id' 参数" warning.config.selector.missing_type: "在文件 发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 发现问题 - 配置项 '' 使用了无效的选择器类型 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/Category.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/Category.java index c4c18bb80..639ccbbfc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/Category.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/Category.java @@ -1,7 +1,10 @@ package net.momirealms.craftengine.core.plugin.gui.category; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -14,8 +17,9 @@ public class Category implements Comparable { private final List members; private final int priority; private final boolean hidden; + private final Condition condition; - public Category(Key id, String displayName, List displayLore, Key icon, List members, int priority, boolean hidden) { + public Category(Key id, String displayName, List displayLore, Key icon, List members, int priority, boolean hidden, Condition condition) { this.id = id; this.displayName = displayName; this.members = new ArrayList<>(members); @@ -23,6 +27,7 @@ public class Category implements Comparable { this.priority = priority; this.displayLore = new ArrayList<>(displayLore); this.hidden = hidden; + this.condition = condition; } public void addMember(String member) { @@ -45,6 +50,11 @@ public class Category implements Comparable { return hidden; } + @Nullable + public Condition condition() { + return condition; + } + public List displayLore() { return displayLore; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 27baae5e7..c4b664d83 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -13,8 +13,12 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.condition.AllOfCondition; +import net.momirealms.craftengine.core.plugin.context.event.EventConditions; import net.momirealms.craftengine.core.plugin.gui.*; import net.momirealms.craftengine.core.plugin.gui.Ingredient; import net.momirealms.craftengine.core.util.*; @@ -120,8 +124,11 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { List members = MiscUtils.getAsStringList(section.getOrDefault("list", List.of())); Key icon = Key.of(section.getOrDefault("icon", ItemKeys.STONE).toString()); int priority = ResourceConfigUtils.getAsInt(section.getOrDefault("priority", 0), "priority"); - Category category = new Category(id, name, MiscUtils.getAsStringList(section.getOrDefault("lore", List.of())), icon, new ArrayList<>(members), priority, - ResourceConfigUtils.getAsBoolean(section.getOrDefault("hidden", false), "hidden")); + List lore = MiscUtils.getAsStringList(section.getOrDefault("lore", List.of())); + boolean hidden = ResourceConfigUtils.getAsBoolean(section.getOrDefault("hidden", false), "hidden"); + List> conditionList = ResourceConfigUtils.parseConfigAsList(ResourceConfigUtils.get(section, "conditions", "condition"), EventConditions::fromMap); + Condition conditions = conditionList.isEmpty() ? null : conditionList.size() == 1 ? conditionList.getFirst() : new AllOfCondition<>(conditionList); + Category category = new Category(id, name, lore, icon, new ArrayList<>(members), priority, hidden, conditions); if (ItemBrowserManagerImpl.this.byId.containsKey(id)) { ItemBrowserManagerImpl.this.byId.get(id).merge(category); } else { @@ -162,6 +169,10 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { ); List iconList = this.categoryOnMainPage.stream().map(it -> { + Condition condition = it.condition(); + if (condition != null && !condition.test(PlayerOptionalContext.of(player))) { + return null; + } Item item = this.plugin.itemManager().createWrappedItem(it.icon(), player); if (ItemUtils.isEmpty(item)) { this.plugin.logger().warn("Can't not find item " + it.icon() + " for category icon"); @@ -251,6 +262,10 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { item = Objects.requireNonNull(this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player)); item.customNameJson(AdventureHelper.componentToJson(Component.text(subCategoryId).color(NamedTextColor.RED).decoration(TextDecoration.ITALIC, false))); } else { + Condition condition = subCategory.condition(); + if (condition != null && !condition.test(PlayerOptionalContext.of(player))) { + return null; + } item = this.plugin.itemManager().createWrappedItem(subCategory.icon(), player); if (ItemUtils.isEmpty(item)) { if (!subCategory.icon().equals(ItemKeys.AIR)) { @@ -322,7 +337,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }); } - }).toList(); + }).filter(Objects::nonNull).toList(); PagedGui.builder() .addIngredients(itemList)