From 6bd2ed2ef217d1bcebcc1040eeeae8a43a2f1983 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 27 Sep 2025 19:51:52 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A8=A1=E5=9E=8B=E5=80=BC?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 1 + .../core/item/AbstractItemManager.java | 119 +++++++++--------- .../core/pack/cache/IdAllocator.java | 34 ++++- 3 files changed, 90 insertions(+), 64 deletions(-) diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 8bfe8c7ad..eaf5c8740 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -193,6 +193,7 @@ warning.config.item.invalid_custom_model_data: "Issue found in file Issue found in file - The item '' is using a custom model data '' that is too large. It's recommended to use a value lower than 16,777,216." warning.config.item.item_model.conflict: "Issue found in file - The item '' is using an invalid 'item-model' option because this item model has been occupied by a vanilla item." warning.config.item.custom_model_data_conflict: "Issue found in file - The item '' is using a custom model data '' that has been occupied by item ''." +warning.config.item.custom_model_data_exhausted: "Issue found in file - Cannot allocate custom model data for item '' as the custom model data has already been exhausted." warning.config.item.invalid_component: "Issue found in file - The item '' is using a non-existing component type ''." warning.config.item.missing_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." warning.config.item.missing_model: "Issue found in file - The item '' is missing the required 'model' section for 1.21.4+ resource pack support." 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 b31c26ff3..0dee19193 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 @@ -52,7 +52,6 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected final Map> customItemsById = new HashMap<>(); protected final Map> customItemsByPath = new HashMap<>(); protected final Map> customItemTags = new HashMap<>(); - protected final Map> cmdConflictChecker = new HashMap<>(); protected final Map modernItemModels1_21_4 = new HashMap<>(); protected final Map> modernItemModels1_21_2 = new HashMap<>(); protected final Map> legacyOverrides = new HashMap<>(); @@ -128,7 +127,6 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl this.modernOverrides.clear(); this.customItemTags.clear(); this.equipments.clear(); - this.cmdConflictChecker.clear(); this.modernItemModels1_21_4.clear(); this.modernItemModels1_21_2.clear(); } @@ -331,7 +329,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } private boolean needsItemModelCompatibility() { - return Config.packMaxVersion().isAbove(MinecraftVersions.V1_21_2); + return Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2); } public Map idAllocators() { @@ -425,11 +423,19 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl customModelDataFuture = CompletableFuture.completedFuture(0); } - // 是否使用客户端侧模型 - boolean clientBoundModel = VersionHelper.PREMIUM && (section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-model"), "client-bound-model") : Config.globalClientboundModel()); - // 当模型值完成分配的时候 - customModelDataFuture.thenAccept(customModelData -> ResourceConfigUtils.runCatching(path, node, () -> { + customModelDataFuture.whenComplete((customModelData, throwable) -> ResourceConfigUtils.runCatching(path, node, () -> { + + if (throwable != null) { + // 检测custom model data 冲突 + if (throwable instanceof IdAllocator.IdConflictException exception) { + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(exception.id()), exception.previousOwner()); + } + // custom model data 已被用尽,不太可能 + else if (throwable instanceof IdAllocator.IdExhaustedException) { + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_exhausted"); + } + } // item model Key itemModel = null; @@ -447,6 +453,9 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 用户没设置item model但是有custom model data,那么就使用custom model data } + // 是否使用客户端侧模型 + 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) { if (clientBoundModel) itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData)); @@ -553,6 +562,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl * ======================== */ + // 原版物品还改模型?自己替换json去 + if (isVanillaItem) { + return; + } + // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model Map modelSection = MiscUtils.castToMap(section.get("model"), true); Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); @@ -561,9 +575,8 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return; } - boolean needsModelSection = isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null); // 只对自定义物品有这个限制,既没有模型值也没有item-model - if (!isVanillaItem && customModelData == 0 && itemModel == null) { + if (customModelData == 0 && itemModel == null) { collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model_id")); } @@ -572,7 +585,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 旧版格式 TreeSet legacyOverridesModels = null; // 如果需要支持新版item model 或者用户需要旧版本兼容,但是没配置legacy-model - if (needsModelSection) { + if (isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null)) { // 1.21.4+必须要配置model区域,如果不需要高版本兼容,则可以只写legacy-model if (modelSection == null) { collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model")); @@ -603,66 +616,52 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl legacyOverridesModels = new TreeSet<>(); processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, clientBoundMaterial, customModelData); if (legacyOverridesModels.isEmpty()) { - collector.add(new LocalizedResourceConfigException("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString())); + collector.add(new LocalizedResourceConfigException("warning.config.item.legacy_model.cannot_convert")); } } } - // 自定义物品的model处理 - if (!isVanillaItem) { - // 这个item-model是否存在,且是原版item-model - boolean isVanillaItemModel = itemModel != null && AbstractPackManager.PRESET_ITEMS.containsKey(itemModel); - // 使用了自定义模型值 - if (customModelData != 0) { - // 如果用户主动设置了item-model且为原版物品,则使用item-model为基础模型,否则使用其视觉材质对应的item-model - Key finalBaseModel = isVanillaItemModel ? itemModel : clientBoundMaterial; - // 检查cmd冲突 - Map conflict = AbstractItemManager.this.cmdConflictChecker.computeIfAbsent(finalBaseModel, k -> new HashMap<>()); - if (conflict.containsKey(customModelData)) { - collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString())); - } - conflict.put(customModelData, id); - // 添加新版item model - if (isModernFormatRequired() && modernModel != null) { - TreeMap map = AbstractItemManager.this.modernOverrides.computeIfAbsent(finalBaseModel, k -> new TreeMap<>()); - map.put(customModelData, new ModernItemModel( - modernModel, - ResourceConfigUtils.getAsBoolean(section.getOrDefault("oversized-in-gui", true), "oversized-in-gui"), - ResourceConfigUtils.getAsBoolean(section.getOrDefault("hand-animation-on-swap", true), "hand-animation-on-swap") - )); - } - // 添加旧版 overrides - if (needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { - TreeSet lom = AbstractItemManager.this.legacyOverrides.computeIfAbsent(finalBaseModel, k -> new TreeSet<>()); - lom.addAll(legacyOverridesModels); - } - } else if (isVanillaItemModel) { - collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModel.asString())); - } + boolean hasLegacyModel = legacyOverridesModels != null && !legacyOverridesModels.isEmpty(); + boolean hasModernModel = modernModel != null; - // 使用了item-model组件,且不是原版物品的 - if (itemModel != null && !isVanillaItemModel) { - if (isModernFormatRequired() && modernModel != null) { - AbstractItemManager.this.modernItemModels1_21_4.put(itemModel, new ModernItemModel( - modernModel, - ResourceConfigUtils.getAsBoolean(section.getOrDefault("oversized-in-gui", true), "oversized-in-gui"), - ResourceConfigUtils.getAsBoolean(section.getOrDefault("hand-animation-on-swap", true), "hand-animation-on-swap") - )); - } - if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { - TreeSet lom = AbstractItemManager.this.modernItemModels1_21_2.computeIfAbsent(itemModel, k -> new TreeSet<>()); - lom.addAll(legacyOverridesModels); - } - } - } else { - // 原版物品的item model覆写 - if (isModernFormatRequired()) { - AbstractItemManager.this.modernItemModels1_21_4.put(id, new ModernItemModel( + // 自定义物品的model处理 + // 这个item-model是否存在,且是原版item-model + boolean isVanillaItemModel = itemModel != null && AbstractPackManager.PRESET_ITEMS.containsKey(itemModel); + // 使用了自定义模型值 + if (customModelData != 0) { + // 如果用户主动设置了item-model且为原版物品,则使用item-model为基础模型,否则使用其视觉材质对应的item-model + Key finalBaseModel = isVanillaItemModel ? itemModel : clientBoundMaterial; + // 添加新版item model + if (isModernFormatRequired() && hasModernModel) { + TreeMap map = AbstractItemManager.this.modernOverrides.computeIfAbsent(finalBaseModel, k -> new TreeMap<>()); + map.put(customModelData, new ModernItemModel( modernModel, ResourceConfigUtils.getAsBoolean(section.getOrDefault("oversized-in-gui", true), "oversized-in-gui"), ResourceConfigUtils.getAsBoolean(section.getOrDefault("hand-animation-on-swap", true), "hand-animation-on-swap") )); } + // 添加旧版 overrides + if (needsLegacyCompatibility() && hasLegacyModel) { + TreeSet lom = AbstractItemManager.this.legacyOverrides.computeIfAbsent(finalBaseModel, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } + } else if (isVanillaItemModel) { + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModel.asString())); + } + + // 使用了item-model组件,且不是原版物品的 + if (itemModel != null && !isVanillaItemModel) { + if (isModernFormatRequired() && hasModernModel) { + AbstractItemManager.this.modernItemModels1_21_4.put(itemModel, new ModernItemModel( + modernModel, + ResourceConfigUtils.getAsBoolean(section.getOrDefault("oversized-in-gui", true), "oversized-in-gui"), + ResourceConfigUtils.getAsBoolean(section.getOrDefault("hand-animation-on-swap", true), "hand-animation-on-swap") + )); + } + if (needsItemModelCompatibility() && needsLegacyCompatibility() && hasLegacyModel) { + TreeSet lom = AbstractItemManager.this.modernItemModels1_21_2.computeIfAbsent(itemModel, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } } // 抛出异常 diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java index 63913d3e5..a4fe866f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java @@ -223,20 +223,46 @@ public class IdAllocator { } public static class IdConflictException extends RuntimeException { + private final String previousOwner; + private final int id; + public IdConflictException(String previousOwner, int id) { super("ID " + id + " is already occupied by: " + previousOwner); + this.previousOwner = previousOwner; + this.id = id; } - } - public static class IdOutOfRangeException extends RuntimeException { - public IdOutOfRangeException(String name, int id, int min, int max) { - super("ID " + id + " for '" + name + "' is out of range. Valid range: " + min + "-" + max); + public String previousOwner() { + return previousOwner; + } + + public int id() { + return id; } } public static class IdExhaustedException extends RuntimeException { + private final String name; + private final int min; + private final int max; + public IdExhaustedException(String name, int min, int max) { super("No available auto ID for '" + name + "'. All IDs in range " + min + "-" + max + " are occupied."); + this.name = name; + this.min = min; + this.max = max; + } + + public String name() { + return name; + } + + public int min() { + return min; + } + + public int max() { + return max; } } } \ No newline at end of file