9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

适配1.21.11 atlas变动

This commit is contained in:
XiaoMoMi
2025-12-10 21:22:11 +08:00
parent 0d8d41ced0
commit 02b644a9bc
8 changed files with 331 additions and 165 deletions

View File

@@ -143,7 +143,7 @@ public class FurnitureEventListener implements Listener {
if (index >= variants.size()) { if (index >= variants.size()) {
index = 0; index = 0;
} }
furniture.setVariant(variants.get(index)); if (furniture.setVariant(variants.get(index))) {
try { try {
Object systemChatPacket = NetworkReflections.constructor$ClientboundSystemChatPacket.newInstance( Object systemChatPacket = NetworkReflections.constructor$ClientboundSystemChatPacket.newInstance(
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.update") ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.update")
@@ -157,4 +157,5 @@ public class FurnitureEventListener implements Listener {
} }
} }
} }
}
} }

View File

@@ -88,5 +88,4 @@ public record ClientCustomBlockPacket(int vanillaSize, int currentSize) implemen
} }
} }
} }
} }

View File

@@ -149,15 +149,15 @@ resource-pack:
length: 2 length: 2
# Determines the depth of the obfuscated path. # Determines the depth of the obfuscated path.
path: path:
source: obf
depth: 4 depth: 4
length: 2 length: 2
# Prevent straightforward unzip # Prevent straightforward unzip
anti-unzip: false 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. # A larger atlas will result in slower generation speed, but it will also lead to a smaller resource pack size.
atlas: atlas:
prefix: atlas # The prefix of the folder where the generated atlas will be located 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 # Sometimes, some vanilla files that have been overwritten might be mistakenly obfuscated
# Please add the ignored textures/models/sounds here if that happens # Please add the ignored textures/models/sounds here if that happens
bypass-textures: bypass-textures:

View File

@@ -5,11 +5,6 @@
"prefix": "block/", "prefix": "block/",
"source": "block" "source": "block"
}, },
{
"type": "minecraft:directory",
"prefix": "item/",
"source": "item"
},
{ {
"type": "minecraft:directory", "type": "minecraft:directory",
"prefix": "entity/conduit/", "prefix": "entity/conduit/",
@@ -19,41 +14,9 @@
"type": "minecraft:single", "type": "minecraft:single",
"resource": "minecraft:entity/bell/bell_body" "resource": "minecraft:entity/bell/bell_body"
}, },
{
"type": "minecraft:single",
"resource": "minecraft:entity/decorated_pot/decorated_pot_side"
},
{ {
"type": "minecraft:single", "type": "minecraft:single",
"resource": "minecraft:entity/enchanting_table_book" "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"
]
} }
] ]
} }

View File

@@ -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"
]
}
]
}

View File

@@ -82,6 +82,7 @@ public abstract class AbstractPackManager implements PackManager {
// 原版资产id // 原版资产id
public static final Set<Key> VANILLA_TEXTURES = new HashSet<>(); public static final Set<Key> VANILLA_TEXTURES = new HashSet<>();
public static final Set<Key> VANILLA_MODELS = new HashSet<>(); public static final Set<Key> VANILLA_MODELS = new HashSet<>();
public static final Set<Key> VANILLA_BLOCK_MODELS = new HashSet<>();
public static final Set<Key> VANILLA_SOUNDS = new HashSet<>(); public static final Set<Key> VANILLA_SOUNDS = new HashSet<>();
// 简化的model读取器 // 简化的model读取器
@@ -116,7 +117,8 @@ public abstract class AbstractPackManager implements PackManager {
private final Map<String, Pack> loadedPacks = new HashMap<>(); private final Map<String, Pack> loadedPacks = new HashMap<>();
private final Map<String, ConfigParser> sectionParsers = new HashMap<>(); private final Map<String, ConfigParser> sectionParsers = new HashMap<>();
private final TreeSet<ConfigParser> sortedParsers = new TreeSet<>(); private final TreeSet<ConfigParser> sortedParsers = new TreeSet<>();
private final JsonObject vanillaAtlas; private final JsonObject vanillaBlockAtlas;
private final JsonObject vanillaItemAtlas;
private Map<Path, CachedConfigFile> cachedConfigFiles = Collections.emptyMap(); private Map<Path, CachedConfigFile> cachedConfigFiles = Collections.emptyMap();
private Map<Path, CachedAssetFile> cachedAssetFiles = Collections.emptyMap(); private Map<Path, CachedAssetFile> cachedAssetFiles = Collections.emptyMap();
protected BiConsumer<Path, Path> zipGenerator; protected BiConsumer<Path, Path> zipGenerator;
@@ -167,10 +169,15 @@ public abstract class AbstractPackManager implements PackManager {
} }
this.initInternalData(); this.initInternalData();
try (InputStream inputStream = plugin.resourceStream("internal/atlases/blocks.json")) { 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) { } catch (IOException e) {
throw new RuntimeException("Failed to read internal/atlases/blocks.json", 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() { private void initInternalData() {
@@ -184,7 +191,9 @@ public abstract class AbstractPackManager implements PackManager {
})); }));
loadInternalData("internal/models/block/_all.json", ((key, jsonObject) -> { loadInternalData("internal/models/block/_all.json", ((key, jsonObject) -> {
PRESET_MODELS_BLOCK.put(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)); loadModernItemModel("internal/items/_all.json", (PRESET_ITEMS::put));
VANILLA_MODELS.add(Key.of("minecraft", "builtin/entity")); VANILLA_MODELS.add(Key.of("minecraft", "builtin/entity"));
@@ -1224,37 +1233,106 @@ public abstract class AbstractPackManager implements PackManager {
return; return;
} }
Multimap<Key, Key> imageToFonts = ArrayListMultimap.create(); // 图片到字体的映射 Multimap<Key, Key> glyphToFonts = ArrayListMultimap.create(); // 图片到字体的映射
Multimap<Key, Key> modelToItems = ArrayListMultimap.create(); // 模型到物品的映射 Multimap<Key, Key> modelToItemDefinitions = ArrayListMultimap.create(); // 模型到物品的映射
Multimap<Key, String> modelToBlocks = ArrayListMultimap.create(); // 模型到方块的映射 Multimap<Key, String> modelToBlockStates = ArrayListMultimap.create(); // 模型到方块的映射
Multimap<Key, Key> imageToModels = ArrayListMultimap.create(); // 纹理到模型的映射 Multimap<Key, Key> textureToModels = ArrayListMultimap.create(); // 纹理到模型的映射
Multimap<Key, Key> imageToEquipments = ArrayListMultimap.create(); // 纹理到盔甲的映射 Multimap<Key, Key> textureToEquipments = ArrayListMultimap.create(); // 纹理到盔甲的映射
Multimap<Key, Key> oggToSoundEvents = ArrayListMultimap.create(); // 音频到声音的映射 Multimap<Key, Key> oggToSoundEvents = ArrayListMultimap.create(); // 音频到声音的映射
Set<Key> collectedModels = new HashSet<>(); Set<Key> collectedModels = new HashSet<>();
Set<Key> texturesInAtlas = new HashSet<>(); Set<Key> existingBlockTextures = new HashSet<>(VANILLA_TEXTURES);
Set<Key> existingTextures = new HashSet<>(VANILLA_TEXTURES); Set<Key> existingItemTextures = new HashSet<>(VANILLA_TEXTURES);
Map<String, String> directoryMapper = new HashMap<>(); Set<Key> blockTexturesInAtlas = new HashSet<>();
processAtlas(this.vanillaAtlas, directoryMapper::put, existingTextures::add, texturesInAtlas::add); Set<Key> itemTexturesInAtlas = new HashSet<>();
Map<Path, JsonObject> allAtlas = new HashMap<>(); Map<String, String> blockDirectoryMapper = new HashMap<>();
Map<String, String> 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<Path, JsonObject> blockAtlas = new HashMap<>();
Map<Path, JsonObject> itemAtlas = new HashMap<>();
// 如果需要验证资源包则需要先读取所有atlas // 如果需要验证资源包则需要先读取所有atlas
if (Config.validateResourcePack()) { if (Config.validateResourcePack()) {
for (Path rootPath : rootPaths) { for (Path rootPath : rootPaths) {
Path atlasesFile = rootPath Path blockAtlasFile = rootPath
.resolve("assets") .resolve("assets")
.resolve("minecraft") .resolve("minecraft")
.resolve("atlases") .resolve("atlases")
.resolve("blocks.json"); .resolve("blocks.json");
if (Files.exists(atlasesFile)) { if (Files.exists(blockAtlasFile)) {
try { try {
JsonObject atlasJsonObject = GsonHelper.readJsonFile(atlasesFile).getAsJsonObject(); JsonObject atlasJsonObject = GsonHelper.readJsonFile(blockAtlasFile).getAsJsonObject();
processAtlas(atlasJsonObject, directoryMapper::put, existingTextures::add, texturesInAtlas::add); processAtlas(
allAtlas.put(atlasesFile, atlasJsonObject); 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) { } 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")) { if (type.equals("bitmap") && providerJO.has("file")) {
String pngFile = providerJO.get("file").getAsString(); String pngFile = providerJO.get("file").getAsString();
Key resourceLocation = Key.of(FileUtils.pathWithoutExtension(pngFile)); 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; return FileVisitResult.CONTINUE;
} }
Key item = Key.of(namespace, FileUtils.pathWithoutExtension(file.getFileName().toString())); 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; return FileVisitResult.CONTINUE;
} }
}); });
@@ -1353,9 +1431,9 @@ public abstract class AbstractPackManager implements PackManager {
} }
String blockId = FileUtils.pathWithoutExtension(file.getFileName().toString()); String blockId = FileUtils.pathWithoutExtension(file.getFileName().toString());
if (blockStateJson.has("multipart")) { 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")) { } else if (blockStateJson.has("variants")) {
collectVariants(blockId, blockStateJson.getAsJsonObject("variants"), modelToBlocks::put); collectVariants(blockId, blockStateJson.getAsJsonObject("variants"), modelToBlockStates::put);
} }
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} }
@@ -1389,7 +1467,7 @@ public abstract class AbstractPackManager implements PackManager {
if (lay instanceof JsonObject layObj) { if (lay instanceof JsonObject layObj) {
Key rawTexture = Key.of(layObj.get("texture").getAsString()); Key rawTexture = Key.of(layObj.get("texture").getAsString());
Key fullPath = Key.of(rawTexture.namespace(), "entity/equipment/" + type + "/" + rawTexture.value()); 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的贴图是否存在 // 验证font的贴图是否存在
label: for (Map.Entry<Key, Collection<Key>> entry : imageToFonts.asMap().entrySet()) { label: for (Map.Entry<Key, Collection<Key>> entry : glyphToFonts.asMap().entrySet()) {
Key key = entry.getKey(); Key key = entry.getKey();
if (VANILLA_TEXTURES.contains(key)) continue; if (VANILLA_TEXTURES.contains(key)) continue;
String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png";
@@ -1451,7 +1529,7 @@ public abstract class AbstractPackManager implements PackManager {
} }
// 验证equipment的贴图是否存在 // 验证equipment的贴图是否存在
label: for (Map.Entry<Key, Collection<Key>> entry : imageToEquipments.asMap().entrySet()) { label: for (Map.Entry<Key, Collection<Key>> entry : textureToEquipments.asMap().entrySet()) {
Key key = entry.getKey(); Key key = entry.getKey();
if (VANILLA_TEXTURES.contains(key)) continue; if (VANILLA_TEXTURES.contains(key)) continue;
String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; 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); TranslationManager.instance().log("warning.config.resource_pack.generation.missing_sound", entry.getValue().stream().distinct().toList().toString(), oggPath);
} }
// 验证方块模型是否存在,验证的同时去收集贴图
label: for (Map.Entry<Key, Collection<String>> 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<Key> blockTextures = new HashSet<>(textureToModels.keys());
// 验证物品模型是否存在,验证的同时去收集贴图 // 验证物品模型是否存在,验证的同时去收集贴图
label: for (Map.Entry<Key, Collection<Key>> entry : modelToItems.asMap().entrySet()) { label: for (Map.Entry<Key, Collection<Key>> entry : modelToItemDefinitions.asMap().entrySet()) {
Key modelResourceLocation = entry.getKey(); Key modelResourceLocation = entry.getKey();
boolean alreadyChecked = !collectedModels.add(modelResourceLocation); boolean alreadyChecked = !collectedModels.add(modelResourceLocation);
if (alreadyChecked || VANILLA_MODELS.contains(modelResourceLocation)) continue; if (alreadyChecked || VANILLA_MODELS.contains(modelResourceLocation)) continue;
@@ -1492,46 +1596,28 @@ public abstract class AbstractPackManager implements PackManager {
TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", modelJsonPath.toAbsolutePath().toString()); TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", modelJsonPath.toAbsolutePath().toString());
continue; continue;
} }
verifyParentModelAndCollectTextures(modelResourceLocation, modelJson, rootPaths, imageToModels, collectedModels); verifyParentModelAndCollectTextures(modelResourceLocation, modelJson, rootPaths, textureToModels, collectedModels);
continue label; continue label;
} }
} }
TranslationManager.instance().log("warning.config.resource_pack.generation.missing_item_model", entry.getValue().stream().distinct().toList().toString(), modelPath); TranslationManager.instance().log("warning.config.resource_pack.generation.missing_item_model", entry.getValue().stream().distinct().toList().toString(), modelPath);
} }
// 验证方块模型是否存在,验证的同时去收集贴图 Set<Key> blockTexturesToFix = new HashSet<>();
label: for (Map.Entry<Key, Collection<String>> entry : modelToBlocks.asMap().entrySet()) { Set<Key> itemTexturesToFix = new HashSet<>();
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<Key> texturesToFix = new HashSet<>();
// 验证贴图是否存在 // 验证贴图是否存在
boolean enableObf = Config.enableObfuscation(); boolean enableObf = Config.enableObfuscation();
label: for (Map.Entry<Key, Collection<Key>> entry : imageToModels.asMap().entrySet()) { label: for (Map.Entry<Key, Collection<Key>> entry : textureToModels.asMap().entrySet()) {
Key key = entry.getKey(); Key key = entry.getKey();
// 是方块的贴图
if (blockTextures.contains(key)) {
// 已经存在的贴图,直接过滤 // 已经存在的贴图,直接过滤
if (existingTextures.contains(key)) continue; if (existingBlockTextures.contains(key)) continue;
// 直接在single中被指定的贴图只检测是否存在 // 直接在single中被指定的贴图只检测是否存在
if (enableObf || texturesInAtlas.contains(key)) { if (enableObf || blockTexturesInAtlas.contains(key)) {
String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png";
for (Path rootPath : rootPaths) { for (Path rootPath : rootPaths) {
if (Files.exists(rootPath.resolve(imagePath))) { if (Files.exists(rootPath.resolve(imagePath))) {
@@ -1540,7 +1626,7 @@ public abstract class AbstractPackManager implements PackManager {
} }
TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath);
} else { } else {
for (Map.Entry<String, String> directorySource : directoryMapper.entrySet()) { for (Map.Entry<String, String> directorySource : blockDirectoryMapper.entrySet()) {
String prefix = directorySource.getKey(); String prefix = directorySource.getKey();
if (key.value().startsWith(prefix)) { if (key.value().startsWith(prefix)) {
String imagePath = "assets/" + key.namespace() + "/textures/" + directorySource.getValue() + key.value().substring(prefix.length()) + ".png"; String imagePath = "assets/" + key.namespace() + "/textures/" + directorySource.getValue() + key.value().substring(prefix.length()) + ".png";
@@ -1557,7 +1643,7 @@ public abstract class AbstractPackManager implements PackManager {
String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png";
for (Path rootPath : rootPaths) { for (Path rootPath : rootPaths) {
if (Files.exists(rootPath.resolve(imagePath))) { if (Files.exists(rootPath.resolve(imagePath))) {
texturesToFix.add(key); blockTexturesToFix.add(key);
continue label; continue label;
} }
} }
@@ -1567,28 +1653,70 @@ public abstract class AbstractPackManager implements PackManager {
} }
} }
} }
// 是物品的贴图
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<String, String> 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 // 修复 atlas
if (Config.fixTextureAtlas() && !texturesToFix.isEmpty()) { if (Config.fixTextureAtlas()) {
boolean is1_21_11 = Config.packMinVersion().isAtOrAbove(MinecraftVersions.V1_21_11);
if (!is1_21_11) {
blockTexturesToFix.addAll(itemTexturesToFix);
itemTexturesToFix.clear();
}
// 修复方块贴图
if (!blockTexturesToFix.isEmpty()) {
List<JsonObject> sourcesToAdd = new ArrayList<>(); List<JsonObject> sourcesToAdd = new ArrayList<>();
for (Key toFix : texturesToFix) { for (Key toFix : blockTexturesToFix) {
JsonObject source = new JsonObject(); JsonObject source = new JsonObject();
source.addProperty("type", "single"); source.addProperty("type", "single");
source.addProperty("resource", toFix.asString()); source.addProperty("resource", toFix.asString());
sourcesToAdd.add(source); sourcesToAdd.add(source);
} }
Path defaultAtlas = path.resolve("assets").resolve("minecraft").resolve("atlases").resolve("blocks.json"); for (Map.Entry<Path, JsonObject> atlas : blockAtlas.entrySet()) {
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);
}
}
for (Map.Entry<Path, JsonObject> atlas : allAtlas.entrySet()) {
JsonObject right = atlas.getValue(); JsonObject right = atlas.getValue();
JsonArray sources = right.getAsJsonArray("sources"); JsonArray sources = right.getAsJsonArray("sources");
if (sources == null) { if (sources == null) {
@@ -1599,12 +1727,44 @@ public abstract class AbstractPackManager implements PackManager {
sources.add(source); sources.add(source);
} }
try { try {
Files.createDirectories(atlas.getKey().getParent());
GsonHelper.writeJsonFile(right, atlas.getKey()); GsonHelper.writeJsonFile(right, atlas.getKey());
} catch (IOException e) { } catch (IOException e) {
this.plugin.logger().warn("Failed to write atlas to json file", e); this.plugin.logger().warn("Failed to write atlas to json file", e);
} }
} }
} }
// 修复物品贴图
if (!itemTexturesToFix.isEmpty()) {
List<JsonObject> sourcesToAdd = new ArrayList<>();
for (Key toFix : itemTexturesToFix) {
JsonObject source = new JsonObject();
source.addProperty("type", "single");
source.addProperty("resource", toFix.asString());
sourcesToAdd.add(source);
}
for (Map.Entry<Path, JsonObject> 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);
}
}
}
}
} }
private void verifyParentModelAndCollectTextures(Key sourceModelLocation, JsonObject sourceModelJson, Path[] rootPaths, Multimap<Key, Key> imageToModels, Set<Key> collected) { private void verifyParentModelAndCollectTextures(Key sourceModelLocation, JsonObject sourceModelJson, Path[] rootPaths, Multimap<Key, Key> imageToModels, Set<Key> collected) {

View File

@@ -90,7 +90,8 @@ public class Config {
protected boolean resource_pack$protection$fake_file_size; protected boolean resource_pack$protection$fake_file_size;
protected NumberProvider resource_pack$protection$obfuscation$namespace$length; protected NumberProvider resource_pack$protection$obfuscation$namespace$length;
protected int resource_pack$protection$obfuscation$namespace$amount; 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$depth;
protected NumberProvider resource_pack$protection$obfuscation$path$length; protected NumberProvider resource_pack$protection$obfuscation$path$length;
protected int resource_pack$protection$obfuscation$atlas$images_per_canvas; 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$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$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$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$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$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"); 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; return instance.resource_pack$protection$obfuscation$namespace$amount;
} }
public static String atlasSource() { public static String blockAtlasSource() {
return instance.resource_pack$protection$obfuscation$path$source; 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() { public static NumberProvider pathDepth() {

View File

@@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx4G
# Project settings # Project settings
project_version=0.0.66.3 project_version=0.0.66.3
config_version=60 config_version=61
lang_version=43 lang_version=43
project_group=net.momirealms project_group=net.momirealms
latest_supported_version=1.21.11 latest_supported_version=1.21.11
@@ -38,7 +38,7 @@ zstd_version=1.5.7-6
commons_io_version=2.21.0 commons_io_version=2.21.0
commons_lang3_version=3.20.0 commons_lang3_version=3.20.0
sparrow_nbt_version=0.10.9 sparrow_nbt_version=0.10.9
sparrow_util_version=0.69 sparrow_util_version=0.72
fastutil_version=8.5.18 fastutil_version=8.5.18
netty_version=4.1.128.Final netty_version=4.1.128.Final
joml_version=1.10.8 joml_version=1.10.8