From 02b644a9bc1a34c0a70ba9ccd2426251fea5e68d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 10 Dec 2025 21:22:11 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8D1.21.11=20atlas=E5=8F=98?= =?UTF-8?q?=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../furniture/FurnitureEventListener.java | 23 +- .../protocol/ClientCustomBlockPacket.java | 1 - common-files/src/main/resources/config.yml | 4 +- .../resources/internal/atlases/blocks.json | 37 -- .../resources/internal/atlases/items.json | 37 ++ .../core/pack/AbstractPackManager.java | 376 +++++++++++++----- .../core/plugin/config/Config.java | 14 +- gradle.properties | 4 +- 8 files changed, 331 insertions(+), 165 deletions(-) create mode 100644 common-files/src/main/resources/internal/atlases/items.json diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java index 74d3784b1..a73595f1b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java @@ -143,17 +143,18 @@ public class FurnitureEventListener implements Listener { if (index >= variants.size()) { index = 0; } - furniture.setVariant(variants.get(index)); - try { - Object systemChatPacket = NetworkReflections.constructor$ClientboundSystemChatPacket.newInstance( - ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.update") - .arguments( - Component.text("variant"), - Component.text(variants.get(index)) - )), true); - player.sendPacket(systemChatPacket, false); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Could not create system chat packet", e); + if (furniture.setVariant(variants.get(index))) { + try { + Object systemChatPacket = NetworkReflections.constructor$ClientboundSystemChatPacket.newInstance( + ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.update") + .arguments( + Component.text("variant"), + Component.text(variants.get(index)) + )), true); + player.sendPacket(systemChatPacket, false); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Could not create system chat packet", e); + } } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientCustomBlockPacket.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientCustomBlockPacket.java index f9dea382d..698ce1fc9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientCustomBlockPacket.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientCustomBlockPacket.java @@ -88,5 +88,4 @@ public record ClientCustomBlockPacket(int vanillaSize, int currentSize) implemen } } } - } diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 6132f428e..14f683dca 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -149,15 +149,15 @@ resource-pack: length: 2 # Determines the depth of the obfuscated path. path: - source: obf depth: 4 length: 2 # Prevent straightforward unzip anti-unzip: false + # Assemble multiple textures into one giant texture atlas to make it more difficult for thieves to directly extract the individual textures. # A larger atlas will result in slower generation speed, but it will also lead to a smaller resource pack size. atlas: prefix: atlas # The prefix of the folder where the generated atlas will be located - images-per-canvas: 256 + images-per-canvas: 256 # -1 = disable # Sometimes, some vanilla files that have been overwritten might be mistakenly obfuscated # Please add the ignored textures/models/sounds here if that happens bypass-textures: diff --git a/common-files/src/main/resources/internal/atlases/blocks.json b/common-files/src/main/resources/internal/atlases/blocks.json index d9881608f..541ce56ad 100644 --- a/common-files/src/main/resources/internal/atlases/blocks.json +++ b/common-files/src/main/resources/internal/atlases/blocks.json @@ -5,11 +5,6 @@ "prefix": "block/", "source": "block" }, - { - "type": "minecraft:directory", - "prefix": "item/", - "source": "item" - }, { "type": "minecraft:directory", "prefix": "entity/conduit/", @@ -19,41 +14,9 @@ "type": "minecraft:single", "resource": "minecraft:entity/bell/bell_body" }, - { - "type": "minecraft:single", - "resource": "minecraft:entity/decorated_pot/decorated_pot_side" - }, { "type": "minecraft:single", "resource": "minecraft:entity/enchanting_table_book" - }, - { - "type": "minecraft:paletted_permutations", - "palette_key": "minecraft:trims/color_palettes/trim_palette", - "permutations": { - "amethyst": "minecraft:trims/color_palettes/amethyst", - "copper": "minecraft:trims/color_palettes/copper", - "copper_darker": "minecraft:trims/color_palettes/copper_darker", - "diamond": "minecraft:trims/color_palettes/diamond", - "diamond_darker": "minecraft:trims/color_palettes/diamond_darker", - "emerald": "minecraft:trims/color_palettes/emerald", - "gold": "minecraft:trims/color_palettes/gold", - "gold_darker": "minecraft:trims/color_palettes/gold_darker", - "iron": "minecraft:trims/color_palettes/iron", - "iron_darker": "minecraft:trims/color_palettes/iron_darker", - "lapis": "minecraft:trims/color_palettes/lapis", - "netherite": "minecraft:trims/color_palettes/netherite", - "netherite_darker": "minecraft:trims/color_palettes/netherite_darker", - "quartz": "minecraft:trims/color_palettes/quartz", - "redstone": "minecraft:trims/color_palettes/redstone", - "resin": "minecraft:trims/color_palettes/resin" - }, - "textures": [ - "minecraft:trims/items/helmet_trim", - "minecraft:trims/items/chestplate_trim", - "minecraft:trims/items/leggings_trim", - "minecraft:trims/items/boots_trim" - ] } ] } \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/items.json b/common-files/src/main/resources/internal/atlases/items.json new file mode 100644 index 000000000..811935d8d --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/items.json @@ -0,0 +1,37 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "item/", + "source": "item" + }, + { + "type": "minecraft:paletted_permutations", + "palette_key": "minecraft:trims/color_palettes/trim_palette", + "permutations": { + "amethyst": "minecraft:trims/color_palettes/amethyst", + "copper": "minecraft:trims/color_palettes/copper", + "copper_darker": "minecraft:trims/color_palettes/copper_darker", + "diamond": "minecraft:trims/color_palettes/diamond", + "diamond_darker": "minecraft:trims/color_palettes/diamond_darker", + "emerald": "minecraft:trims/color_palettes/emerald", + "gold": "minecraft:trims/color_palettes/gold", + "gold_darker": "minecraft:trims/color_palettes/gold_darker", + "iron": "minecraft:trims/color_palettes/iron", + "iron_darker": "minecraft:trims/color_palettes/iron_darker", + "lapis": "minecraft:trims/color_palettes/lapis", + "netherite": "minecraft:trims/color_palettes/netherite", + "netherite_darker": "minecraft:trims/color_palettes/netherite_darker", + "quartz": "minecraft:trims/color_palettes/quartz", + "redstone": "minecraft:trims/color_palettes/redstone", + "resin": "minecraft:trims/color_palettes/resin" + }, + "textures": [ + "minecraft:trims/items/helmet_trim", + "minecraft:trims/items/chestplate_trim", + "minecraft:trims/items/leggings_trim", + "minecraft:trims/items/boots_trim" + ] + } + ] +} \ No newline at end of file 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 6af44c281..6fec67260 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 @@ -82,6 +82,7 @@ public abstract class AbstractPackManager implements PackManager { // 原版资产id public static final Set VANILLA_TEXTURES = new HashSet<>(); public static final Set VANILLA_MODELS = new HashSet<>(); + public static final Set VANILLA_BLOCK_MODELS = new HashSet<>(); public static final Set VANILLA_SOUNDS = new HashSet<>(); // 简化的model读取器 @@ -116,7 +117,8 @@ public abstract class AbstractPackManager implements PackManager { private final Map loadedPacks = new HashMap<>(); private final Map sectionParsers = new HashMap<>(); private final TreeSet sortedParsers = new TreeSet<>(); - private final JsonObject vanillaAtlas; + private final JsonObject vanillaBlockAtlas; + private final JsonObject vanillaItemAtlas; private Map cachedConfigFiles = Collections.emptyMap(); private Map cachedAssetFiles = Collections.emptyMap(); protected BiConsumer zipGenerator; @@ -167,10 +169,15 @@ public abstract class AbstractPackManager implements PackManager { } this.initInternalData(); try (InputStream inputStream = plugin.resourceStream("internal/atlases/blocks.json")) { - this.vanillaAtlas = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject(); + this.vanillaBlockAtlas = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject(); } catch (IOException e) { throw new RuntimeException("Failed to read internal/atlases/blocks.json", e); } + try (InputStream inputStream = plugin.resourceStream("internal/atlases/items.json")) { + this.vanillaItemAtlas = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject(); + } catch (IOException e) { + throw new RuntimeException("Failed to read internal/atlases/items.json", e); + } } private void initInternalData() { @@ -184,7 +191,9 @@ public abstract class AbstractPackManager implements PackManager { })); loadInternalData("internal/models/block/_all.json", ((key, jsonObject) -> { PRESET_MODELS_BLOCK.put(key, jsonObject); - VANILLA_MODELS.add(Key.of(key.namespace(), "block/" + key.value())); + Key modelKey = Key.of(key.namespace(), "block/" + key.value()); + VANILLA_MODELS.add(modelKey); + VANILLA_BLOCK_MODELS.add(modelKey); })); loadModernItemModel("internal/items/_all.json", (PRESET_ITEMS::put)); VANILLA_MODELS.add(Key.of("minecraft", "builtin/entity")); @@ -1224,37 +1233,106 @@ public abstract class AbstractPackManager implements PackManager { return; } - Multimap imageToFonts = ArrayListMultimap.create(); // 图片到字体的映射 - Multimap modelToItems = ArrayListMultimap.create(); // 模型到物品的映射 - Multimap modelToBlocks = ArrayListMultimap.create(); // 模型到方块的映射 - Multimap imageToModels = ArrayListMultimap.create(); // 纹理到模型的映射 - Multimap imageToEquipments = ArrayListMultimap.create(); // 纹理到盔甲的映射 + Multimap glyphToFonts = ArrayListMultimap.create(); // 图片到字体的映射 + Multimap modelToItemDefinitions = ArrayListMultimap.create(); // 模型到物品的映射 + Multimap modelToBlockStates = ArrayListMultimap.create(); // 模型到方块的映射 + Multimap textureToModels = ArrayListMultimap.create(); // 纹理到模型的映射 + Multimap textureToEquipments = ArrayListMultimap.create(); // 纹理到盔甲的映射 Multimap oggToSoundEvents = ArrayListMultimap.create(); // 音频到声音的映射 Set collectedModels = new HashSet<>(); - Set texturesInAtlas = new HashSet<>(); - Set existingTextures = new HashSet<>(VANILLA_TEXTURES); - Map directoryMapper = new HashMap<>(); - processAtlas(this.vanillaAtlas, directoryMapper::put, existingTextures::add, texturesInAtlas::add); - Map allAtlas = new HashMap<>(); + Set existingBlockTextures = new HashSet<>(VANILLA_TEXTURES); + Set existingItemTextures = new HashSet<>(VANILLA_TEXTURES); + Set blockTexturesInAtlas = new HashSet<>(); + Set itemTexturesInAtlas = new HashSet<>(); + Map blockDirectoryMapper = new HashMap<>(); + Map itemDirectoryMapper = new HashMap<>(); + + // block atlas可以被item和block同时使用 + processAtlas( + this.vanillaBlockAtlas, + (prefix, source) -> { + itemDirectoryMapper.put(prefix, source); + blockDirectoryMapper.put(source, prefix); + }, + k -> { + existingBlockTextures.add(k); + existingItemTextures.add(k); + }, + k -> { + blockTexturesInAtlas.add(k); + itemTexturesInAtlas.add(k); + } + ); + // item atlas侧重于物品 + processAtlas( + this.vanillaItemAtlas, + itemDirectoryMapper::put, + existingItemTextures::add, + itemTexturesInAtlas::add + ); + + Map blockAtlas = new HashMap<>(); + Map itemAtlas = new HashMap<>(); // 如果需要验证资源包,则需要先读取所有atlas if (Config.validateResourcePack()) { for (Path rootPath : rootPaths) { - Path atlasesFile = rootPath + Path blockAtlasFile = rootPath .resolve("assets") .resolve("minecraft") .resolve("atlases") .resolve("blocks.json"); - if (Files.exists(atlasesFile)) { + if (Files.exists(blockAtlasFile)) { try { - JsonObject atlasJsonObject = GsonHelper.readJsonFile(atlasesFile).getAsJsonObject(); - processAtlas(atlasJsonObject, directoryMapper::put, existingTextures::add, texturesInAtlas::add); - allAtlas.put(atlasesFile, atlasJsonObject); + JsonObject atlasJsonObject = GsonHelper.readJsonFile(blockAtlasFile).getAsJsonObject(); + processAtlas( + atlasJsonObject, + (prefix, source) -> { + itemDirectoryMapper.put(prefix, source); + blockDirectoryMapper.put(source, prefix); + }, + k -> { + existingBlockTextures.add(k); + existingItemTextures.add(k); + }, + k -> { + blockTexturesInAtlas.add(k); + itemTexturesInAtlas.add(k); + } + ); + blockAtlas.put(blockAtlasFile, atlasJsonObject); } catch (IOException | JsonParseException e) { - TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", atlasesFile.toAbsolutePath().toString()); + TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", blockAtlasFile.toAbsolutePath().toString()); } } + Path itemAtlasFile = rootPath + .resolve("assets") + .resolve("minecraft") + .resolve("atlases") + .resolve("items.json"); + if (Files.exists(itemAtlasFile)) { + try { + JsonObject atlasJsonObject = GsonHelper.readJsonFile(itemAtlasFile).getAsJsonObject(); + processAtlas( + atlasJsonObject, + itemDirectoryMapper::put, + existingItemTextures::add, + itemTexturesInAtlas::add + ); + itemAtlas.put(itemAtlasFile, atlasJsonObject); + } catch (IOException | JsonParseException e) { + TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", itemAtlasFile.toAbsolutePath().toString()); + } + } + } + Path defaultBlockAtlas = path.resolve("assets").resolve("minecraft").resolve("atlases").resolve("blocks.json"); + if (!blockAtlas.containsKey(defaultBlockAtlas)) { + blockAtlas.put(defaultBlockAtlas, new JsonObject()); + } + Path defaultItemAtlas = path.resolve("assets").resolve("minecraft").resolve("atlases").resolve("items.json"); + if (!itemAtlas.containsKey(defaultItemAtlas)) { + itemAtlas.put(defaultItemAtlas, new JsonObject()); } } @@ -1298,7 +1376,7 @@ public abstract class AbstractPackManager implements PackManager { if (type.equals("bitmap") && providerJO.has("file")) { String pngFile = providerJO.get("file").getAsString(); Key resourceLocation = Key.of(FileUtils.pathWithoutExtension(pngFile)); - imageToFonts.put(resourceLocation, fontName); + glyphToFonts.put(resourceLocation, fontName); } } } @@ -1327,7 +1405,7 @@ public abstract class AbstractPackManager implements PackManager { return FileVisitResult.CONTINUE; } Key item = Key.of(namespace, FileUtils.pathWithoutExtension(file.getFileName().toString())); - collectItemModelsDeeply(itemJson, (resourceLocation) -> modelToItems.put(resourceLocation, item)); + collectItemModelsDeeply(itemJson, (resourceLocation) -> modelToItemDefinitions.put(resourceLocation, item)); return FileVisitResult.CONTINUE; } }); @@ -1353,9 +1431,9 @@ public abstract class AbstractPackManager implements PackManager { } String blockId = FileUtils.pathWithoutExtension(file.getFileName().toString()); if (blockStateJson.has("multipart")) { - collectMultipart(blockStateJson.getAsJsonArray("multipart"), (location) -> modelToBlocks.put(location, blockId)); + collectMultipart(blockStateJson.getAsJsonArray("multipart"), (location) -> modelToBlockStates.put(location, blockId)); } else if (blockStateJson.has("variants")) { - collectVariants(blockId, blockStateJson.getAsJsonObject("variants"), modelToBlocks::put); + collectVariants(blockId, blockStateJson.getAsJsonObject("variants"), modelToBlockStates::put); } return FileVisitResult.CONTINUE; } @@ -1389,7 +1467,7 @@ public abstract class AbstractPackManager implements PackManager { if (lay instanceof JsonObject layObj) { Key rawTexture = Key.of(layObj.get("texture").getAsString()); Key fullPath = Key.of(rawTexture.namespace(), "entity/equipment/" + type + "/" + rawTexture.value()); - imageToEquipments.put(fullPath, Key.of(namespace, equipmentId)); + textureToEquipments.put(fullPath, Key.of(namespace, equipmentId)); } } } @@ -1438,7 +1516,7 @@ public abstract class AbstractPackManager implements PackManager { } // 验证font的贴图是否存在 - label: for (Map.Entry> entry : imageToFonts.asMap().entrySet()) { + label: for (Map.Entry> entry : glyphToFonts.asMap().entrySet()) { Key key = entry.getKey(); if (VANILLA_TEXTURES.contains(key)) continue; String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; @@ -1451,7 +1529,7 @@ public abstract class AbstractPackManager implements PackManager { } // 验证equipment的贴图是否存在 - label: for (Map.Entry> entry : imageToEquipments.asMap().entrySet()) { + label: for (Map.Entry> entry : textureToEquipments.asMap().entrySet()) { Key key = entry.getKey(); if (VANILLA_TEXTURES.contains(key)) continue; String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; @@ -1476,8 +1554,34 @@ public abstract class AbstractPackManager implements PackManager { TranslationManager.instance().log("warning.config.resource_pack.generation.missing_sound", entry.getValue().stream().distinct().toList().toString(), oggPath); } + // 验证方块模型是否存在,验证的同时去收集贴图 + label: for (Map.Entry> entry : modelToBlockStates.asMap().entrySet()) { + Key modelResourceLocation = entry.getKey(); + boolean alreadyChecked = !collectedModels.add(modelResourceLocation); + if (alreadyChecked) continue; + String modelPath = "assets/" + modelResourceLocation.namespace() + "/models/" + modelResourceLocation.value() + ".json"; + for (Path rootPath : rootPaths) { + Path modelJsonPath = rootPath.resolve(modelPath); + if (Files.exists(modelJsonPath)) { + JsonObject jsonObject; + try { + jsonObject = GsonHelper.readJsonFile(modelJsonPath).getAsJsonObject(); + } catch (IOException | JsonParseException e) { + TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", modelJsonPath.toAbsolutePath().toString()); + continue; + } + verifyParentModelAndCollectTextures(modelResourceLocation, jsonObject, rootPaths, textureToModels, collectedModels); + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_block_model", entry.getValue().stream().distinct().toList().toString(), modelPath); + } + + // 所有方块纹理,必须进入blocks.json,而不是items.json,因此当前收集到的textures都为方块纹理 + Set blockTextures = new HashSet<>(textureToModels.keys()); + // 验证物品模型是否存在,验证的同时去收集贴图 - label: for (Map.Entry> entry : modelToItems.asMap().entrySet()) { + label: for (Map.Entry> entry : modelToItemDefinitions.asMap().entrySet()) { Key modelResourceLocation = entry.getKey(); boolean alreadyChecked = !collectedModels.add(modelResourceLocation); if (alreadyChecked || VANILLA_MODELS.contains(modelResourceLocation)) continue; @@ -1492,116 +1596,172 @@ public abstract class AbstractPackManager implements PackManager { TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", modelJsonPath.toAbsolutePath().toString()); continue; } - verifyParentModelAndCollectTextures(modelResourceLocation, modelJson, rootPaths, imageToModels, collectedModels); + verifyParentModelAndCollectTextures(modelResourceLocation, modelJson, rootPaths, textureToModels, collectedModels); continue label; } } TranslationManager.instance().log("warning.config.resource_pack.generation.missing_item_model", entry.getValue().stream().distinct().toList().toString(), modelPath); } - // 验证方块模型是否存在,验证的同时去收集贴图 - label: for (Map.Entry> entry : modelToBlocks.asMap().entrySet()) { - Key modelResourceLocation = entry.getKey(); - boolean alreadyChecked = !collectedModels.add(modelResourceLocation); - if (alreadyChecked || VANILLA_MODELS.contains(modelResourceLocation)) continue; - String modelPath = "assets/" + modelResourceLocation.namespace() + "/models/" + modelResourceLocation.value() + ".json"; - for (Path rootPath : rootPaths) { - Path modelJsonPath = rootPath.resolve(modelPath); - if (Files.exists(modelJsonPath)) { - JsonObject jsonObject; - try { - jsonObject = GsonHelper.readJsonFile(modelJsonPath).getAsJsonObject(); - } catch (IOException | JsonParseException e) { - TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", modelJsonPath.toAbsolutePath().toString()); - continue; - } - verifyParentModelAndCollectTextures(modelResourceLocation, jsonObject, rootPaths, imageToModels, collectedModels); - continue label; - } - } - TranslationManager.instance().log("warning.config.resource_pack.generation.missing_block_model", entry.getValue().stream().distinct().toList().toString(), modelPath); - } - - Set texturesToFix = new HashSet<>(); + Set blockTexturesToFix = new HashSet<>(); + Set itemTexturesToFix = new HashSet<>(); // 验证贴图是否存在 boolean enableObf = Config.enableObfuscation(); - label: for (Map.Entry> entry : imageToModels.asMap().entrySet()) { + label: for (Map.Entry> entry : textureToModels.asMap().entrySet()) { Key key = entry.getKey(); - // 已经存在的贴图,直接过滤 - if (existingTextures.contains(key)) continue; - // 直接在single中被指定的贴图,只检测是否存在 - if (enableObf || texturesInAtlas.contains(key)) { - String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; - for (Path rootPath : rootPaths) { - if (Files.exists(rootPath.resolve(imagePath))) { - continue label; - } - } - TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); - } else { - for (Map.Entry directorySource : directoryMapper.entrySet()) { - String prefix = directorySource.getKey(); - if (key.value().startsWith(prefix)) { - String imagePath = "assets/" + key.namespace() + "/textures/" + directorySource.getValue() + key.value().substring(prefix.length()) + ".png"; - for (Path rootPath : rootPaths) { - if (Files.exists(rootPath.resolve(imagePath))) { - continue label; - } - } - TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); - continue label; - } - } - if (Config.fixTextureAtlas()) { + + // 是方块的贴图 + if (blockTextures.contains(key)) { + // 已经存在的贴图,直接过滤 + if (existingBlockTextures.contains(key)) continue; + + // 直接在single中被指定的贴图,只检测是否存在 + if (enableObf || blockTexturesInAtlas.contains(key)) { String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; for (Path rootPath : rootPaths) { if (Files.exists(rootPath.resolve(imagePath))) { - texturesToFix.add(key); continue label; } } TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); } else { - TranslationManager.instance().log("warning.config.resource_pack.generation.texture_not_in_atlas", key.toString()); + for (Map.Entry directorySource : blockDirectoryMapper.entrySet()) { + String prefix = directorySource.getKey(); + if (key.value().startsWith(prefix)) { + String imagePath = "assets/" + key.namespace() + "/textures/" + directorySource.getValue() + key.value().substring(prefix.length()) + ".png"; + for (Path rootPath : rootPaths) { + if (Files.exists(rootPath.resolve(imagePath))) { + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); + continue label; + } + } + if (Config.fixTextureAtlas()) { + String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; + for (Path rootPath : rootPaths) { + if (Files.exists(rootPath.resolve(imagePath))) { + blockTexturesToFix.add(key); + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); + } else { + TranslationManager.instance().log("warning.config.resource_pack.generation.texture_not_in_atlas", key.toString()); + } + } + } + // 是物品的贴图 + else { + // 已经存在的贴图,直接过滤 + if (existingItemTextures.contains(key)) continue; + // 直接在single中被指定的贴图,只检测是否存在 + if (enableObf || itemTexturesInAtlas.contains(key)) { + String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; + for (Path rootPath : rootPaths) { + if (Files.exists(rootPath.resolve(imagePath))) { + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); + } else { + for (Map.Entry directorySource : itemDirectoryMapper.entrySet()) { + String prefix = directorySource.getKey(); + if (key.value().startsWith(prefix)) { + String imagePath = "assets/" + key.namespace() + "/textures/" + directorySource.getValue() + key.value().substring(prefix.length()) + ".png"; + for (Path rootPath : rootPaths) { + if (Files.exists(rootPath.resolve(imagePath))) { + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); + continue label; + } + } + if (Config.fixTextureAtlas()) { + String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; + for (Path rootPath : rootPaths) { + if (Files.exists(rootPath.resolve(imagePath))) { + itemTexturesToFix.add(key); + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); + } else { + TranslationManager.instance().log("warning.config.resource_pack.generation.texture_not_in_atlas", key.toString()); + } } } } // 修复 atlas - if (Config.fixTextureAtlas() && !texturesToFix.isEmpty()) { - List sourcesToAdd = new ArrayList<>(); - for (Key toFix : texturesToFix) { - JsonObject source = new JsonObject(); - source.addProperty("type", "single"); - source.addProperty("resource", toFix.asString()); - sourcesToAdd.add(source); + if (Config.fixTextureAtlas()) { + + boolean is1_21_11 = Config.packMinVersion().isAtOrAbove(MinecraftVersions.V1_21_11); + if (!is1_21_11) { + blockTexturesToFix.addAll(itemTexturesToFix); + itemTexturesToFix.clear(); } - Path defaultAtlas = path.resolve("assets").resolve("minecraft").resolve("atlases").resolve("blocks.json"); - if (!allAtlas.containsKey(defaultAtlas)) { - allAtlas.put(defaultAtlas, new JsonObject()); - try { - Files.createDirectories(defaultAtlas.getParent()); - } catch (IOException e) { - this.plugin.logger().warn("could not create default atlas directory", e); + // 修复方块贴图 + + if (!blockTexturesToFix.isEmpty()) { + List sourcesToAdd = new ArrayList<>(); + for (Key toFix : blockTexturesToFix) { + JsonObject source = new JsonObject(); + source.addProperty("type", "single"); + source.addProperty("resource", toFix.asString()); + sourcesToAdd.add(source); + } + + for (Map.Entry atlas : blockAtlas.entrySet()) { + JsonObject right = atlas.getValue(); + JsonArray sources = right.getAsJsonArray("sources"); + if (sources == null) { + sources = new JsonArray(); + right.add("sources", sources); + } + for (JsonObject source : sourcesToAdd) { + sources.add(source); + } + try { + Files.createDirectories(atlas.getKey().getParent()); + GsonHelper.writeJsonFile(right, atlas.getKey()); + } catch (IOException e) { + this.plugin.logger().warn("Failed to write atlas to json file", e); + } } } - for (Map.Entry atlas : allAtlas.entrySet()) { - JsonObject right = atlas.getValue(); - JsonArray sources = right.getAsJsonArray("sources"); - if (sources == null) { - sources = new JsonArray(); - right.add("sources", sources); + // 修复物品贴图 + + if (!itemTexturesToFix.isEmpty()) { + List sourcesToAdd = new ArrayList<>(); + for (Key toFix : itemTexturesToFix) { + JsonObject source = new JsonObject(); + source.addProperty("type", "single"); + source.addProperty("resource", toFix.asString()); + sourcesToAdd.add(source); } - for (JsonObject source : sourcesToAdd) { - sources.add(source); - } - try { - GsonHelper.writeJsonFile(right, atlas.getKey()); - } catch (IOException e) { - this.plugin.logger().warn("Failed to write atlas to json file", e); + + for (Map.Entry atlas : itemAtlas.entrySet()) { + JsonObject right = atlas.getValue(); + JsonArray sources = right.getAsJsonArray("sources"); + if (sources == null) { + sources = new JsonArray(); + right.add("sources", sources); + } + for (JsonObject source : sourcesToAdd) { + sources.add(source); + } + try { + Files.createDirectories(atlas.getKey().getParent()); + GsonHelper.writeJsonFile(right, atlas.getKey()); + } catch (IOException e) { + this.plugin.logger().warn("Failed to write atlas to json file", e); + } } } } 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 f343ce3f3..13b130d1b 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 @@ -90,7 +90,8 @@ public class Config { protected boolean resource_pack$protection$fake_file_size; protected NumberProvider resource_pack$protection$obfuscation$namespace$length; protected int resource_pack$protection$obfuscation$namespace$amount; - protected String resource_pack$protection$obfuscation$path$source; + protected String resource_pack$protection$obfuscation$path$block_source; + protected String resource_pack$protection$obfuscation$path$item_source; protected NumberProvider resource_pack$protection$obfuscation$path$depth; protected NumberProvider resource_pack$protection$obfuscation$path$length; protected int resource_pack$protection$obfuscation$atlas$images_per_canvas; @@ -364,7 +365,8 @@ public class Config { resource_pack$protection$obfuscation$namespace$length = NumberProviders.fromObject(config.get("resource-pack.protection.obfuscation.namespace.length", 2)); resource_pack$protection$obfuscation$path$depth = NumberProviders.fromObject(config.get("resource-pack.protection.obfuscation.path.depth", 4)); resource_pack$protection$obfuscation$path$length = NumberProviders.fromObject(config.get("resource-pack.protection.obfuscation.path.length", 2)); - resource_pack$protection$obfuscation$path$source = config.getString("resource-pack.protection.obfuscation.path.source", "obf"); + resource_pack$protection$obfuscation$path$block_source = config.getString("resource-pack.protection.obfuscation.path.block-source", "obf_block"); + resource_pack$protection$obfuscation$path$item_source = config.getString("resource-pack.protection.obfuscation.path.block-source", "obf_item"); resource_pack$protection$obfuscation$path$anti_unzip = config.getBoolean("resource-pack.protection.obfuscation.path.anti-unzip", false); resource_pack$protection$obfuscation$atlas$images_per_canvas = config.getInt("resource-pack.protection.obfuscation.atlas.images-per-canvas", 256); resource_pack$protection$obfuscation$atlas$prefix = config.getString("resource-pack.protection.obfuscation.atlas.prefix", "atlas"); @@ -864,8 +866,12 @@ public class Config { return instance.resource_pack$protection$obfuscation$namespace$amount; } - public static String atlasSource() { - return instance.resource_pack$protection$obfuscation$path$source; + public static String blockAtlasSource() { + return instance.resource_pack$protection$obfuscation$path$block_source; + } + + public static String itemAtlasSource() { + return instance.resource_pack$protection$obfuscation$path$item_source; } public static NumberProvider pathDepth() { diff --git a/gradle.properties b/gradle.properties index ebb6ef0e4..4eccbf354 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx4G # Project settings project_version=0.0.66.3 -config_version=60 +config_version=61 lang_version=43 project_group=net.momirealms latest_supported_version=1.21.11 @@ -38,7 +38,7 @@ zstd_version=1.5.7-6 commons_io_version=2.21.0 commons_lang3_version=3.20.0 sparrow_nbt_version=0.10.9 -sparrow_util_version=0.69 +sparrow_util_version=0.72 fastutil_version=8.5.18 netty_version=4.1.128.Final joml_version=1.10.8