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