From db07951974cb6be7538b42c1ea45649e6deaf98e Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Tue, 30 Sep 2025 18:27:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=B2=E7=9F=A5=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/DebugCleanCacheCommand.java | 210 ++++++++++-------- .../feature/DebugTargetBlockCommand.java | 9 +- .../core/item/AbstractItemManager.java | 25 ++- .../core/plugin/config/Config.java | 6 + gradle.properties | 2 +- 5 files changed, 141 insertions(+), 111 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java index 3c3ad6ed7..bf41e6f10 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java @@ -41,10 +41,10 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature @Override public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder - .required("type", StringParser.stringComponent().suggestionProvider(new SuggestionProvider<>() { + .optional("type", StringParser.stringComponent().suggestionProvider(new SuggestionProvider<>() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(List.of(Suggestion.suggestion("custom-model-data"), Suggestion.suggestion("custom-block-states"), Suggestion.suggestion("visual-block-states"), Suggestion.suggestion("font"))); + return CompletableFuture.completedFuture(List.of(Suggestion.suggestion("custom-model-data"), Suggestion.suggestion("custom-block-states"), Suggestion.suggestion("visual-block-states"), Suggestion.suggestion("font"), Suggestion.suggestion("all"))); } })) .handler(context -> { @@ -52,103 +52,17 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature context.sender().sendMessage("The plugin is reloading. Please wait until the process is complete."); return; } - String type = context.get("type"); + String type = context.getOrDefault("type", "all"); switch (type) { - case "custom-model-data" -> { - BukkitItemManager instance = BukkitItemManager.instance(); - Map> idsMap = new HashMap<>(); - for (CustomItem item : instance.loadedItems().values()) { - Set ids = idsMap.computeIfAbsent(item.clientBoundMaterial(), k -> new HashSet<>()); - ids.add(item.id().asString()); - } - int total = 0; - for (Map.Entry entry : getAllCachedCustomModelData().entrySet()) { - Set ids = idsMap.getOrDefault(entry.getKey(), Collections.emptySet()); - List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); - total += removed.size(); - try { - entry.getValue().saveToCache(); - } catch (IOException e) { - this.plugin().logger().warn("Error while saving custom model data allocation for material " + entry.getKey().asString(), e); - return; - } - for (String id : removed) { - this.plugin().logger().info("Cleaned unsued item: " + id); - } - } - context.sender().sendMessage("Cleaned " + total + " unused custom model data"); - } - case "font", "images" -> { - BukkitFontManager instance = this.plugin().fontManager(); - Map> idsMap = new HashMap<>(); - for (BitmapImage image : instance.loadedImages().values()) { - Set ids = idsMap.computeIfAbsent(image.font(), k -> new HashSet<>()); - String id = image.id().toString(); - ids.add(id); - for (int i = 0; i < image.rows(); i++) { - for (int j = 0; j < image.columns(); j++) { - String imageArgs = id + ":" + i + ":" + j; - ids.add(imageArgs); - } - } - } - int total = 0; - for (Map.Entry entry : getAllCachedFont().entrySet()) { - Key font = entry.getKey(); - Set ids = idsMap.getOrDefault(font, Collections.emptySet()); - List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); - try { - entry.getValue().saveToCache(); - } catch (IOException e) { - this.plugin().logger().warn("Error while saving codepoint allocation for font " + font.asString(), e); - return; - } - for (String id : removed) { - this.plugin().logger().info("Cleaned unsued image: " + id); - } - total += removed.size(); - } - context.sender().sendMessage("Cleaned " + total + " unused codepoints"); - } - case "custom-block-states" -> { - BukkitBlockManager instance = BukkitBlockManager.instance(); - Set ids = new HashSet<>(); - for (CustomBlock customBlock : instance.loadedBlocks().values()) { - for (ImmutableBlockState state : customBlock.variantProvider().states()) { - ids.add(state.toString()); - } - } - IdAllocator idAllocator = instance.blockParser().internalIdAllocator(); - List removed = idAllocator.cleanupUnusedIds(i -> !ids.contains(i)); - try { - idAllocator.saveToCache(); - } catch (IOException e) { - this.plugin().logger().warn("Error while saving custom block states allocation", e); - } - for (String id : removed) { - this.plugin().logger().info("Cleaned unsued block state: " + id); - } - context.sender().sendMessage("Cleaned " + removed.size() + " unused custom block states"); - } - case "visual-block-states" -> { - BukkitBlockManager instance = BukkitBlockManager.instance(); - Set ids = new HashSet<>(); - for (CustomBlock customBlock : instance.loadedBlocks().values()) { - for (ImmutableBlockState state : customBlock.variantProvider().states()) { - ids.add(state.vanillaBlockState()); - } - } - VisualBlockStateAllocator visualBlockStateAllocator = instance.blockParser().visualBlockStateAllocator(); - List removed = visualBlockStateAllocator.cleanupUnusedIds(i -> !ids.contains(i)); - try { - visualBlockStateAllocator.saveToCache(); - } catch (IOException e) { - this.plugin().logger().warn("Error while saving visual block states allocation", e); - } - for (String id : removed) { - this.plugin().logger().info("Cleaned unsued block appearance: " + id); - } - context.sender().sendMessage("Cleaned " + removed.size() + " unused block state appearances"); + case "custom-model-data" -> handleCustomModelData(context); + case "font", "images" -> handleFont(context); + case "custom-block-states" -> handleCustomBlockState(context); + case "visual-block-states" -> handleVisualBlockState(context); + case "all" -> { + handleCustomModelData(context); + handleFont(context); + handleCustomBlockState(context); + handleVisualBlockState(context); } } }); @@ -159,6 +73,106 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature return "debug_clean_cache"; } + private void handleVisualBlockState(CommandContext context) { + BukkitBlockManager instance = BukkitBlockManager.instance(); + Set ids = new HashSet<>(); + for (CustomBlock customBlock : instance.loadedBlocks().values()) { + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + ids.add(state.vanillaBlockState()); + } + } + VisualBlockStateAllocator visualBlockStateAllocator = instance.blockParser().visualBlockStateAllocator(); + List removed = visualBlockStateAllocator.cleanupUnusedIds(i -> !ids.contains(i)); + try { + visualBlockStateAllocator.saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving visual block states allocation", e); + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued block appearance: " + id); + } + context.sender().sendMessage("Cleaned " + removed.size() + " unused block state appearances"); + } + + private void handleCustomBlockState(CommandContext context) { + BukkitBlockManager instance = BukkitBlockManager.instance(); + Set ids = new HashSet<>(); + for (CustomBlock customBlock : instance.loadedBlocks().values()) { + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + ids.add(state.toString()); + } + } + IdAllocator idAllocator = instance.blockParser().internalIdAllocator(); + List removed = idAllocator.cleanupUnusedIds(i -> !ids.contains(i)); + try { + idAllocator.saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving custom block states allocation", e); + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued block state: " + id); + } + context.sender().sendMessage("Cleaned " + removed.size() + " unused custom block states"); + } + + private void handleFont(CommandContext context) { + BukkitFontManager instance = this.plugin().fontManager(); + Map> idsMap = new HashMap<>(); + for (BitmapImage image : instance.loadedImages().values()) { + Set ids = idsMap.computeIfAbsent(image.font(), k -> new HashSet<>()); + String id = image.id().toString(); + ids.add(id); + for (int i = 0; i < image.rows(); i++) { + for (int j = 0; j < image.columns(); j++) { + String imageArgs = id + ":" + i + ":" + j; + ids.add(imageArgs); + } + } + } + int total = 0; + for (Map.Entry entry : getAllCachedFont().entrySet()) { + Key font = entry.getKey(); + Set ids = idsMap.getOrDefault(font, Collections.emptySet()); + List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); + try { + entry.getValue().saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving codepoint allocation for font " + font.asString(), e); + return; + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued image: " + id); + } + total += removed.size(); + } + context.sender().sendMessage("Cleaned " + total + " unused codepoints"); + } + + private void handleCustomModelData(CommandContext context) { + BukkitItemManager instance = BukkitItemManager.instance(); + Map> idsMap = new HashMap<>(); + for (CustomItem item : instance.loadedItems().values()) { + Set ids = idsMap.computeIfAbsent(item.clientBoundMaterial(), k -> new HashSet<>()); + ids.add(item.id().asString()); + } + int total = 0; + for (Map.Entry entry : getAllCachedCustomModelData().entrySet()) { + Set ids = idsMap.getOrDefault(entry.getKey(), Collections.emptySet()); + List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); + total += removed.size(); + try { + entry.getValue().saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving custom model data allocation for material " + entry.getKey().asString(), e); + return; + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued item: " + id); + } + } + context.sender().sendMessage("Cleaned " + total + " unused custom model data"); + } + public Map getAllCachedCustomModelData() { Path cacheDir = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("custom-model-data"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java index 4ed380551..c684296a8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -10,6 +11,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.sender.Sender; +import net.momirealms.craftengine.core.plugin.config.Config; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; @@ -44,15 +46,14 @@ public class DebugTargetBlockCommand extends BukkitCommandFeature Sender sender = plugin().senderFactory().wrap(context.sender()); sender.sendMessage(Component.text(bData)); int id = BlockStateUtils.blockStateToId(blockState); - - Object holder = BukkitBlockManager.instance().getMinecraftBlockHolder(id); - if (holder != null) { + if (!BlockStateUtils.isVanillaBlock(id)) { + Object holder = BukkitBlockManager.instance().getMinecraftBlockHolder(id); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(id); if (immutableBlockState != null) { sender.sendMessage(Component.text(immutableBlockState.toString())); } ImmutableBlockState dataInCache = plugin().worldManager().getWorld(block.getWorld().getUID()).getBlockStateAtIfLoaded(LocationUtils.toBlockPos(block.getLocation())); - sender.sendMessage(Component.text("cache-state: " + !dataInCache.isEmpty())); + sender.sendMessage(Component.text("cache-state: " + (dataInCache != null && !dataInCache.isEmpty()))); try { @SuppressWarnings("unchecked") Set tags = (Set) CoreReflections.field$Holder$Reference$tags.get(holder); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 9d3c7b909..7928753e7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -338,7 +338,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } private boolean needsItemModelCompatibility() { - return Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2); + return Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && VersionHelper.isOrAbove1_21_2(); //todo 能否通过客户端包解决问题 } public Map idAllocators() { @@ -403,6 +403,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // custom model data CompletableFuture customModelDataFuture; + boolean forceCustomModelData; if (!isVanillaItem) { // 如果用户指定了,说明要手动分配,不管他是什么版本,都强制设置模型值 @@ -415,9 +416,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); } customModelDataFuture = getOrCreateIdAllocator(clientBoundMaterial).assignFixedId(id.asString(), customModelData); + forceCustomModelData = true; } // 用户没指定custom-model-data,则看当前资源包版本兼容需求 else { + forceCustomModelData = false; // 如果最低版本要1.21.1以下支持 if (needsCustomModelDataCompatibility()) { customModelDataFuture = getOrCreateIdAllocator(clientBoundMaterial).requestAutoId(id.asString()); @@ -428,6 +431,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } } else { + forceCustomModelData = false; // 原版物品不应该有这个 customModelDataFuture = CompletableFuture.completedFuture(0); } @@ -458,15 +462,17 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // item model Key itemModel = null; + boolean forceItemModel = false; // 如果这个版本可以使用 item model if (!isVanillaItem && needsItemModelCompatibility()) { // 如果用户主动设定了item model,那么肯定要设置 if (section.containsKey("item-model")) { itemModel = Key.from(section.get("item-model").toString()); + forceItemModel = true; } // 用户没设置item model也没设置custom model data,那么为他生成一个基于物品id的item model - else if (customModelData == 0) { + else if (customModelData == 0 || Config.alwaysUseItemModel()) { itemModel = id; } // 用户没设置item model但是有custom model data,那么就使用custom model data @@ -476,11 +482,17 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl boolean clientBoundModel = VersionHelper.PREMIUM && (section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-model"), "client-bound-model") : Config.globalClientboundModel()); CustomItem.Builder itemBuilder = createPlatformItemBuilder(uniqueId, material, clientBoundMaterial); - if (customModelData > 0) { + + // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model + Map modelSection = MiscUtils.castToMap(section.get("model"), true); + Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); + boolean hasModelSection = modelSection != null || legacyModelSection != null; + + if (customModelData > 0 && (hasModelSection || forceCustomModelData)) { if (clientBoundModel) itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData)); else itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); } - if (itemModel != null) { + if (itemModel != null && (hasModelSection || forceItemModel)) { if (clientBoundModel) itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModel)); else itemBuilder.dataModifier(new ItemModelModifier<>(itemModel)); } @@ -586,10 +598,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return; } - // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model - Map modelSection = MiscUtils.castToMap(section.get("model"), true); - Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); - if (modelSection == null && legacyModelSection == null) { + if (!hasModelSection) { collector.throwIfPresent(); return; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 357414f9a..788862341 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -164,6 +164,7 @@ public class Config { protected boolean item$update_triggers$pick_up; protected int item$custom_model_data_starting_value$default; protected Map item$custom_model_data_starting_value$overrides; + protected boolean item$always_use_item_model; protected String equipment$sacrificed_vanilla_armor$type; protected Key equipment$sacrificed_vanilla_armor$asset_id; @@ -407,6 +408,7 @@ public class Config { item$update_triggers$drop = config.getBoolean("item.update-triggers.drop", false); item$update_triggers$pick_up = config.getBoolean("item.update-triggers.pick-up", false); item$custom_model_data_starting_value$default = config.getInt("item.custom-model-data-starting-value.default", 10000); + item$always_use_item_model = config.getBoolean("item.always-use-item-model", true) && VersionHelper.isOrAbove1_21_2(); Section customModelDataOverridesSection = config.getSection("item.custom-model-data-starting-value.overrides"); if (customModelDataOverridesSection != null) { @@ -549,6 +551,10 @@ public class Config { return instance.block$serverside_blocks; } + public static boolean alwaysUseItemModel() { + return instance.item$always_use_item_model; + } + public static boolean filterConfigurationPhaseDisconnect() { return instance.filterConfigurationPhaseDisconnect; } diff --git a/gradle.properties b/gradle.properties index 1de766a2f..f633a3e61 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.8 +project_version=0.0.63.9 config_version=47 lang_version=32 project_group=net.momirealms