diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java index 6d08819b9..fecb9a35e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java @@ -8,8 +8,8 @@ import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext; -import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.FriendlyByteBuf; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java index eed379c5f..42e38e4f0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java @@ -11,8 +11,8 @@ import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext; -import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.FriendlyByteBuf; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java index ee05e0ae2..0e1a180e8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java @@ -8,8 +8,8 @@ import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.util.FriendlyByteBuf; import org.bukkit.inventory.ItemStack; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java index fdb6d772a..24a05eaf1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java @@ -11,8 +11,8 @@ import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext; -import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.FriendlyByteBuf; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java index 669aaa9f0..c3b4174da 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java @@ -11,10 +11,10 @@ import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; -import net.momirealms.craftengine.core.plugin.network.event.NMSPacketEvent; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.plugin.network.event.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.event.NMSPacketEvent; import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 133632a86..32deff53e 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -94,12 +94,13 @@ resource-pack: resolution: type: merge_font # Validate if there is any error in the resource pack, such as missing textures or models. - # Validation may not always be accurate due to the presence of overlays, and it is time-consuming for plugins to simulate multiple client versions for testing. + # Validation may not always be accurate due to the presence of resource pack overlays. # If your resource pack is compliant with the standard, you can disable validation to improve the resource pack generation speed. validation: enable: true - # Fix images that are not within the texture atlas. It is unreasonable to always rely on plugins to fix your mistakes. + # Fix textures that are not within the atlas. It is unreasonable to always rely on plugins to fix your mistakes. # You should strive to make your resource pack more standardized after gaining some experience with resource packs. + # When a model file mixes textures from both the blocks atlas and the items atlas, you must manually fix the issue. fix-atlas: true # Optimize your resource pack by reducing its size without any quality loss. optimization: diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 3288d670c..934b2c29d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -1,8 +1,6 @@ package net.momirealms.craftengine.core.pack; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.HashMultimap; -import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; @@ -1186,12 +1184,12 @@ public abstract class AbstractPackManager implements PackManager { return; } - Multimap glyphToFonts = ArrayListMultimap.create(); // 图片到字体的映射 - Multimap modelToItemDefinitions = ArrayListMultimap.create(); // 模型到物品的映射 - Multimap modelToBlockStates = ArrayListMultimap.create(); // 模型到方块的映射 - Multimap textureToModels = ArrayListMultimap.create(); // 纹理到模型的映射 - Multimap textureToEquipments = ArrayListMultimap.create(); // 纹理到盔甲的映射 - Multimap oggToSoundEvents = ArrayListMultimap.create(); // 音频到声音的映射 + Multimap glyphToFonts = HashMultimap.create(128, 32); // 图片到字体的映射 + Multimap modelToItemDefinitions = HashMultimap.create(128, 4); // 模型到物品的映射 + Multimap modelToBlockStates = HashMultimap.create(128, 32); // 模型到方块的映射 + Multimap textureToModels = HashMultimap.create(128, 8); // 纹理到模型的映射 + Multimap textureToEquipments = HashMultimap.create(128, 8); // 纹理到盔甲的映射 + Multimap oggToSoundEvents = HashMultimap.create(128, 4); // 音频到声音的映射 Map blockAtlasJsons = new LinkedHashMap<>(); Map itemAtlasJsons = new LinkedHashMap<>(); @@ -1239,16 +1237,17 @@ public abstract class AbstractPackManager implements PackManager { /* - 构建Atlas文件 + 构建Atlas文件, + 验证只使用默认的atlas,否则整个过程将会变成非常复杂 */ - Atlas blockAtlas = new Atlas(MiscUtils.make(new ArrayList<>(), k -> { + Atlas blockAtlas = new Atlas(MiscUtils.make(new ArrayList<>(4), k -> { k.add(blockAtlasJsons.get(defaultBlockAtlas)); k.add(this.vanillaBlockAtlas); return k; })); - Atlas itemAtlas = new Atlas(MiscUtils.make(new ArrayList<>(), k -> { + Atlas itemAtlas = new Atlas(MiscUtils.make(new ArrayList<>(4), k -> { k.add(itemAtlasJsons.get(defaultItemAtlas)); k.add(this.vanillaItemAtlas); return k; @@ -1289,14 +1288,16 @@ public abstract class AbstractPackManager implements PackManager { if (providers != null) { Key fontName = Key.of(namespace, FileUtils.pathWithoutExtension(file.getFileName().toString())); for (JsonElement provider : providers) { - if (provider instanceof JsonObject providerJO && providerJO.has("type")) { - String type = providerJO.get("type").getAsString(); - if (type.equals("bitmap") && providerJO.has("file")) { - String pngFile = providerJO.get("file").getAsString(); - Key resourceLocation = Key.of(FileUtils.pathWithoutExtension(pngFile)); - glyphToFonts.put(resourceLocation, fontName); - } - } + if (!(provider instanceof JsonObject providerJO)) continue; + JsonPrimitive typePrimitive = providerJO.getAsJsonPrimitive("type"); + if (typePrimitive == null) continue; + String type = typePrimitive.getAsString(); + if (!type.equals("bitmap")) continue; + JsonPrimitive filePrimitive = providerJO.getAsJsonPrimitive("file"); + if (filePrimitive == null) continue; + String pngFile = filePrimitive.getAsString(); + Key resourceLocation = Key.of(FileUtils.pathWithoutExtension(pngFile)); + glyphToFonts.put(resourceLocation, fontName); } } return FileVisitResult.CONTINUE; @@ -1383,9 +1384,11 @@ public abstract class AbstractPackManager implements PackManager { if (layer.getValue() instanceof JsonArray equipmentLayer) { for (JsonElement lay : equipmentLayer) { if (lay instanceof JsonObject layObj) { - Key rawTexture = Key.of(layObj.get("texture").getAsString()); - Key fullPath = Key.of(rawTexture.namespace(), "entity/equipment/" + type + "/" + rawTexture.value()); - textureToEquipments.put(fullPath, Key.of(namespace, equipmentId)); + if (layObj.get("texture") instanceof JsonPrimitive layerTexture) { + Key rawTexture = Key.of(layerTexture.getAsString()); + Key fullPath = Key.of(rawTexture.namespace(), "entity/equipment/" + type + "/" + rawTexture.value()); + textureToEquipments.put(fullPath, Key.of(namespace, equipmentId)); + } } } } @@ -1411,9 +1414,7 @@ public abstract class AbstractPackManager implements PackManager { if (soundArray != null) { for (JsonElement sound : soundArray) { if (sound instanceof JsonPrimitive primitive) { - if (primitive.isString()) { - oggToSoundEvents.put(Key.of(primitive.getAsString()), soundKey); - } + oggToSoundEvents.put(Key.of(primitive.getAsString()), soundKey); } else if (sound instanceof JsonObject soundObj && soundObj.has("name")) { if (soundObj.has("type")) { String type = soundObj.get("type").getAsString(); @@ -1481,12 +1482,12 @@ public abstract class AbstractPackManager implements PackManager { */ // 获取所有带贴图的模型以及自定义父模型 - Map blockModels = new LinkedHashMap<>(); - Map itemModels = new LinkedHashMap<>(); + Map blockModels = new HashMap<>(256); + Map itemModels = new HashMap<>(256); // 此map仅用于缓存遇到过的路径上的模型 - Map blockModelsCache = new LinkedHashMap<>(); - Map itemModelsCache = new LinkedHashMap<>(); - Set checkedModels = new HashSet<>(); + Map blockModelsCache = new HashMap<>(256); + Map itemModelsCache = new HashMap<>(256); + Set checkedModels = new HashSet<>(256); // 收集全部方块状态的模型贴图 label: for (Map.Entry> entry : modelToBlockStates.asMap().entrySet()) { @@ -1510,7 +1511,7 @@ public abstract class AbstractPackManager implements PackManager { } // 提示方块状态缺少模型 if (!VANILLA_MODELS.contains(modelPath)) { - TranslationManager.instance().log("warning.config.resource_pack.generation.missing_block_model", entry.getValue().stream().distinct().toList().toString(), modelStringPath); + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_block_model", entry.getValue().toString(), modelStringPath); } } @@ -1535,7 +1536,7 @@ public abstract class AbstractPackManager implements PackManager { } } if (!VANILLA_MODELS.contains(modelPath)) { - TranslationManager.instance().log("warning.config.resource_pack.generation.missing_item_model", entry.getValue().stream().distinct().toList().toString(), modelStringPath); + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_item_model", entry.getValue().toString(), modelStringPath); } } @@ -1547,9 +1548,9 @@ public abstract class AbstractPackManager implements PackManager { */ - Multimap blockAtlasesToFix = LinkedHashMultimap.create(); - Multimap itemAtlasesToFix = LinkedHashMultimap.create(); - Multimap anyAtlasesToFix = LinkedHashMultimap.create(); + Multimap blockAtlasesToFix = HashMultimap.create(64, 4); + Multimap itemAtlasesToFix = HashMultimap.create(64, 4); + Multimap anyAtlasesToFix = HashMultimap.create(64, 4); // 验证方块贴图是否在图集里 Iterator> iterator1 = blockModels.entrySet().iterator(); @@ -1560,19 +1561,9 @@ public abstract class AbstractPackManager implements PackManager { boolean shouldRemove = false; for (Map.Entry texture : textures.entrySet()) { Key spritePath = texture.getValue(); - boolean definedInBlockAtlas = blockAtlas.isDefined(spritePath); - boolean definedInItemAtlas = itemAtlas.isDefined(spritePath); - - // 双重定义 - if (definedInItemAtlas && definedInBlockAtlas) { - TranslationManager.instance().log("warning.config.resource_pack.generation.duplicated_sprite", - entry.getKey().asString(), spritePath.asString(), - "minecraft:textures/atlas/blocks.png", "minecraft:textures/atlas/items.png"); - shouldRemove = true; - break; - } // 方块纹理不应该在item图集内,这样必然出问题 + boolean definedInItemAtlas = itemAtlas.isDefined(spritePath); if (definedInItemAtlas) { TranslationManager.instance().log("warning.config.resource_pack.generation.multiple_atlases", entry.getKey().asString(), "minecraft:textures/atlas/blocks.png", @@ -1582,7 +1573,7 @@ public abstract class AbstractPackManager implements PackManager { } // 未在方块图集内定义 - if (!definedInBlockAtlas) { + if (!blockAtlas.isDefined(spritePath)) { // 如果尝试修复 if (Config.fixTextureAtlas()) { // 只能在方块图集 @@ -1649,14 +1640,13 @@ public abstract class AbstractPackManager implements PackManager { textureToModels.put(spritePath, entry.getKey()); } } - } - - // 那么就至少有一个定义 - if (definedInBlockAtlas) { - blockAtlasInUse = true; - } - if (definedInItemAtlas) { - itemAtlasInUse = true; + } else { + // 那么就至少有一个定义 + if (definedInBlockAtlas) { + blockAtlasInUse = true; + } else /* if (definedInItemAtlas) */ { + itemAtlasInUse = true; + } } } @@ -1745,7 +1735,7 @@ public abstract class AbstractPackManager implements PackManager { } if (!itemAtlasesToFix.isEmpty()) { - List sourcesToAdd = new ArrayList<>(); + List sourcesToAdd = new ArrayList<>(itemAtlasesToFix.size()); for (Key itemTexture : itemAtlasesToFix.keySet()) { itemAtlas.addSingle(itemTexture); JsonObject source = new JsonObject(); @@ -1773,7 +1763,7 @@ public abstract class AbstractPackManager implements PackManager { } if (!blockAtlasesToFix.isEmpty()) { - List sourcesToAdd = new ArrayList<>(); + List sourcesToAdd = new ArrayList<>(blockAtlasesToFix.size()); for (Key blockTexture : blockAtlasesToFix.keySet()) { blockAtlas.addSingle(blockTexture); JsonObject source = new JsonObject(); @@ -1845,11 +1835,16 @@ public abstract class AbstractPackManager implements PackManager { } } } + + // todo 验证 unstitch 和 paletted permutations } // 经过这一步拿到的模型为包含全部父贴图的模型 + @SuppressWarnings("all") public TexturedModel getTexturedModel(Key path, JsonObject modelJson, Path[] rootPaths, Map models) { TexturedModel texturedModel = new TexturedModel(modelJson); + // 放这里防止parent互相引用造成死循环 + models.put(path, texturedModel); if (modelJson.has("parent")) { Key parentModelPath = Key.from(modelJson.get("parent").getAsString()); TexturedModel parent = models.get(parentModelPath); @@ -1863,17 +1858,25 @@ public abstract class AbstractPackManager implements PackManager { } else { // 否则只从缓存里拿一份用于归并 if (VANILLA_MODELS.contains(parentModelPath)) { + // 可能为空,因为存在built-in模型 parent = PRESET_MODELS.get(parentModelPath); + if (parent == null) { + parent = TexturedModel.BUILTIN; + } + models.put(parentModelPath, parent); } else { - TranslationManager.instance().log("warning.config.resource_pack.generation.missing_parent_model", path.asString(), parentModelStringPath); + parent = TexturedModel.EMPTY; + models.put(parentModelPath, parent); } } } - if (parent != null) { + if (parent == TexturedModel.EMPTY) { + String parentModelStringPath = "assets/" + parentModelPath.namespace() + "/models/" + parentModelPath.value() + ".json"; + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_parent_model", path.asString(), parentModelStringPath); + } else { texturedModel.addParent(parent); } } - models.put(path, texturedModel); return texturedModel; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/atlas/Atlas.java b/core/src/main/java/net/momirealms/craftengine/core/pack/atlas/Atlas.java index 434064a51..7717bb219 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/atlas/Atlas.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/atlas/Atlas.java @@ -15,6 +15,7 @@ import java.util.stream.Collectors; public final class Atlas { private final Map directory; + private final String[] prefixes; // 已经被包含在图集内的贴图 private final Set defined; // 单独添加的 @@ -109,6 +110,7 @@ public final class Atlas { } } this.filtered = MiscUtils.anyOf(filtered); + this.prefixes = this.directory.keySet().toArray(new String[0]); } public Atlas(List atlasJsons) { @@ -135,10 +137,8 @@ public final class Atlas { if (this.filtered.test(texture)) return false; if (this.defined.contains(texture)) return true; String path = texture.value(); - for (Map.Entry entry : this.directory.entrySet()) { - if (path.startsWith(entry.getKey())) { - return true; - } + for (String prefix : this.prefixes) { + if (path.startsWith(prefix)) return true; } return false; } @@ -156,8 +156,9 @@ public final class Atlas { String path = texture.value(); // 路径匹配 for (Map.Entry entry : this.directory.entrySet()) { - if (path.startsWith(entry.getKey())) { - return Key.of(texture.namespace(), entry.getValue() + path.substring(entry.getKey().length())); + String prefix = entry.getKey(); + if (path.startsWith(prefix)) { + return Key.of(texture.namespace(), entry.getValue() + path.substring(prefix.length())); } } return null; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/atlas/TexturedModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/atlas/TexturedModel.java index e192079ba..98ff36ae4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/atlas/TexturedModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/atlas/TexturedModel.java @@ -9,6 +9,7 @@ import java.util.Map; public class TexturedModel { public static final TexturedModel EMPTY = new TexturedModel(Map.of()); + public static final TexturedModel BUILTIN = new TexturedModel(Map.of()); public final Map textures; private TexturedModel(Map textures) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java index 3b5a584f1..0f6cbdc2b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java @@ -1,7 +1,10 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; import com.google.common.collect.ImmutableSet; -import com.google.gson.*; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.AdventureHelper;