mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
改进验证逻辑1
This commit is contained in:
@@ -98,9 +98,17 @@ resource-pack:
|
||||
# If your resource pack is compliant with the standard, you can disable validation to improve the resource pack generation speed.
|
||||
validation:
|
||||
enable: true
|
||||
# Determines on which versions the resource pack validation will be performed.
|
||||
# Allowed values:
|
||||
# - 1.20.1, 1.21, 1.21.8, etc.
|
||||
# - latest: the latest client version
|
||||
# - server: the current server version
|
||||
test-versions:
|
||||
- server
|
||||
# Fix textures that are not within the atlas. It is unreasonable to always rely on plugins to fix your mistakes.
|
||||
# CraftEngine will only fix the atlas of resource pack under the first version specified in the test-versions.
|
||||
# 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.
|
||||
# The fix-atlas feature is not all-powerful since 1.21.11. In some cases, CraftEngine cannot fix it for you, and you will need to fix your model yourself.
|
||||
fix-atlas: true
|
||||
# Optimize your resource pack by reducing its size without any quality loss.
|
||||
optimization:
|
||||
|
||||
@@ -18,6 +18,8 @@ import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionCondit
|
||||
import net.momirealms.craftengine.core.pack.host.ResourcePackHost;
|
||||
import net.momirealms.craftengine.core.pack.host.ResourcePackHosts;
|
||||
import net.momirealms.craftengine.core.pack.host.impl.NoneHost;
|
||||
import net.momirealms.craftengine.core.pack.mcmeta.Overlay;
|
||||
import net.momirealms.craftengine.core.pack.mcmeta.PackMcMeta;
|
||||
import net.momirealms.craftengine.core.pack.model.ItemModel;
|
||||
import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel;
|
||||
import net.momirealms.craftengine.core.pack.model.ModernItemModel;
|
||||
@@ -791,7 +793,9 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
long time2 = System.currentTimeMillis();
|
||||
this.plugin.logger().info(TranslationManager.instance().translateLog("info.resource_pack.generate", String.valueOf(time2 - time1)));
|
||||
if (Config.validateResourcePack()) {
|
||||
this.validateResourcePack(generatedPackPath);
|
||||
for (MinecraftVersion version : Config.validationTestVersions()) {
|
||||
this.validateResourcePack(generatedPackPath, version);
|
||||
}
|
||||
}
|
||||
long time3 = System.currentTimeMillis();
|
||||
this.plugin.logger().info(TranslationManager.instance().translateLog("info.resource_pack.validate", String.valueOf(time3 - time2)));
|
||||
@@ -825,10 +829,10 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
if (!rawMeta.has("pack")) {
|
||||
JsonObject pack = new JsonObject();
|
||||
rawMeta.add("pack", pack);
|
||||
pack.addProperty("pack_format", Config.packMinVersion().packFormat());
|
||||
pack.addProperty("pack_format", Config.packMinVersion().packFormat().major());
|
||||
JsonObject supportedFormats = new JsonObject();
|
||||
supportedFormats.addProperty("min_inclusive", Config.packMinVersion().packFormat());
|
||||
supportedFormats.addProperty("max_inclusive", Config.packMaxVersion().packFormat());
|
||||
supportedFormats.addProperty("min_inclusive", Config.packMinVersion().packFormat().major());
|
||||
supportedFormats.addProperty("max_inclusive", Config.packMaxVersion().packFormat().major());
|
||||
pack.add("supported_formats", supportedFormats);
|
||||
changed = true;
|
||||
}
|
||||
@@ -869,7 +873,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
private void removeAllShaders(Path path) {
|
||||
List<Path> rootPaths;
|
||||
try {
|
||||
rootPaths = FileUtils.collectOverlays(path);
|
||||
rootPaths = MiscUtils.init(FileUtils.collectOverlays(path), a -> a.addFirst(path));
|
||||
} catch (IOException e) {
|
||||
plugin.logger().warn("Failed to collect overlays for " + path.toAbsolutePath(), e);
|
||||
return;
|
||||
@@ -889,7 +893,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
// 收集全部overlay
|
||||
Path[] rootPaths;
|
||||
try {
|
||||
rootPaths = FileUtils.collectOverlays(path).toArray(new Path[0]);
|
||||
rootPaths = MiscUtils.init(FileUtils.collectOverlays(path), a -> a.addFirst(path)).toArray(new Path[0]);
|
||||
} catch (IOException e) {
|
||||
this.plugin.logger().warn("Failed to collect overlays for " + path.toAbsolutePath(), e);
|
||||
return;
|
||||
@@ -1174,16 +1178,37 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private void validateResourcePack(Path path) {
|
||||
// 收集全部overlay
|
||||
Path[] rootPaths;
|
||||
private void validateResourcePack(Path path, MinecraftVersion version) {
|
||||
Path packMcMetaPath = path.resolve("pack.mcmeta");
|
||||
PackMcMeta packMeta;
|
||||
try {
|
||||
rootPaths = FileUtils.collectOverlays(path).toArray(new Path[0]);
|
||||
packMeta = new PackMcMeta(GsonHelper.readJsonFile(packMcMetaPath).getAsJsonObject());
|
||||
} catch (IOException e) {
|
||||
this.plugin.logger().warn("Failed to collect overlays for " + path.toAbsolutePath(), e);
|
||||
this.plugin.logger().warn("Failed to read pack.mcmeta " + packMcMetaPath.toAbsolutePath(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前版本生效的overlays
|
||||
List<String> overlayDirectories = new ArrayList<>();
|
||||
for (Overlay overlay : packMeta.overlays()) {
|
||||
if (overlay.test(version)) {
|
||||
overlayDirectories.add(overlay.directory());
|
||||
}
|
||||
}
|
||||
overlayDirectories = overlayDirectories.stream().distinct().toList();
|
||||
|
||||
List<Path> rootPathList = new ArrayList<>();
|
||||
rootPathList.add(path);
|
||||
for (String directory : overlayDirectories) {
|
||||
Path resolve = path.resolve(directory);
|
||||
if (Files.isDirectory(resolve)) {
|
||||
rootPathList.add(resolve);
|
||||
}
|
||||
}
|
||||
|
||||
// 收集全部overlay,按照正确的顺序加载
|
||||
Path[] rootPaths = rootPathList.toArray(new Path[0]);
|
||||
|
||||
Multimap<Key, Key> glyphToFonts = HashMultimap.create(128, 32); // 图片到字体的映射
|
||||
Multimap<Key, Key> modelToItemDefinitions = HashMultimap.create(128, 4); // 模型到物品的映射
|
||||
Multimap<Key, String> modelToBlockStates = HashMultimap.create(128, 32); // 模型到方块的映射
|
||||
@@ -1191,8 +1216,11 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
Multimap<Key, Key> textureToEquipments = HashMultimap.create(128, 8); // 纹理到盔甲的映射
|
||||
Multimap<Key, Key> oggToSoundEvents = HashMultimap.create(128, 4); // 音频到声音的映射
|
||||
|
||||
Map<Path, JsonObject> blockAtlasJsons = new LinkedHashMap<>();
|
||||
Map<Path, JsonObject> itemAtlasJsons = new LinkedHashMap<>();
|
||||
Map<Path, JsonObject> blockAtlasJsons = new HashMap<>();
|
||||
Map<Path, JsonObject> itemAtlasJsons = new HashMap<>();
|
||||
|
||||
JsonObject lastBlocksAtlas = null;
|
||||
JsonObject lastItemAtlas = null;
|
||||
|
||||
// 如果需要验证资源包,则需要先读取所有atlas
|
||||
for (Path rootPath : rootPaths) {
|
||||
@@ -1205,6 +1233,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
try {
|
||||
JsonObject atlasJsonObject = GsonHelper.readJsonFile(blockAtlasFile).getAsJsonObject();
|
||||
blockAtlasJsons.put(blockAtlasFile, atlasJsonObject);
|
||||
lastBlocksAtlas = atlasJsonObject;
|
||||
} catch (IOException | JsonParseException e) {
|
||||
TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", blockAtlasFile.toAbsolutePath().toString());
|
||||
}
|
||||
@@ -1218,6 +1247,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
try {
|
||||
JsonObject atlasJsonObject = GsonHelper.readJsonFile(itemAtlasFile).getAsJsonObject();
|
||||
itemAtlasJsons.put(itemAtlasFile, atlasJsonObject);
|
||||
lastItemAtlas = atlasJsonObject;
|
||||
} catch (IOException | JsonParseException e) {
|
||||
TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", itemAtlasFile.toAbsolutePath().toString());
|
||||
}
|
||||
@@ -1242,16 +1272,15 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
|
||||
|
||||
*/
|
||||
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<>(4), k -> {
|
||||
k.add(itemAtlasJsons.get(defaultItemAtlas));
|
||||
k.add(this.vanillaItemAtlas);
|
||||
return k;
|
||||
}));
|
||||
Atlas blockAtlas;
|
||||
Atlas itemAtlas;
|
||||
if (version.isAtOrAbove(MinecraftVersions.V1_21_11)) {
|
||||
blockAtlas = new Atlas(ListUtils.newNonNullList(lastBlocksAtlas, this.vanillaBlockAtlas));
|
||||
itemAtlas = new Atlas(ListUtils.newNonNullList(lastItemAtlas, this.vanillaItemAtlas));
|
||||
} else {
|
||||
blockAtlas = new Atlas(ListUtils.newNonNullList(lastBlocksAtlas, this.vanillaBlockAtlas, this.vanillaItemAtlas));
|
||||
itemAtlas = null;
|
||||
}
|
||||
|
||||
for (Path rootPath : rootPaths) {
|
||||
Path assetsPath = rootPath.resolve("assets");
|
||||
@@ -1564,7 +1593,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
Key spritePath = texture.getValue();
|
||||
|
||||
// 方块纹理不应该在item图集内,这样必然出问题
|
||||
boolean definedInItemAtlas = itemAtlas.isDefined(spritePath);
|
||||
boolean definedInItemAtlas = itemAtlas != null && itemAtlas.isDefined(spritePath);
|
||||
if (definedInItemAtlas) {
|
||||
TranslationManager.instance().log("warning.config.resource_pack.generation.multiple_atlases",
|
||||
entry.getKey().asString(), "minecraft:textures/atlas/blocks.png",
|
||||
@@ -1614,7 +1643,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
for (Map.Entry<String, Key> texture : textures.entrySet()) {
|
||||
Key spritePath = texture.getValue();
|
||||
boolean definedInBlockAtlas = blockAtlas.isDefined(spritePath);
|
||||
boolean definedInItemAtlas = itemAtlas.isDefined(spritePath);
|
||||
boolean definedInItemAtlas = itemAtlas != null && itemAtlas.isDefined(spritePath);
|
||||
|
||||
// 双倍定义
|
||||
if (definedInItemAtlas && definedInBlockAtlas) {
|
||||
@@ -1735,7 +1764,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
itemAtlasesToFix.clear();
|
||||
}
|
||||
|
||||
if (!itemAtlasesToFix.isEmpty()) {
|
||||
if (!itemAtlasesToFix.isEmpty() && itemAtlas != null) {
|
||||
List<JsonObject> sourcesToAdd = new ArrayList<>(itemAtlasesToFix.size());
|
||||
for (Key itemTexture : itemAtlasesToFix.keySet()) {
|
||||
itemAtlas.addSingle(itemTexture);
|
||||
@@ -1809,7 +1838,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
Map<String, Key> textures = entry.getValue().textures;
|
||||
for (Map.Entry<String, Key> texture : textures.entrySet()) {
|
||||
Key spritePath = texture.getValue();
|
||||
Key sourceTexturePath = itemAtlas.getSourceTexturePath(spritePath);
|
||||
Key sourceTexturePath = itemAtlas == null ? null : itemAtlas.getSourceTexturePath(spritePath);
|
||||
if (sourceTexturePath != null) {
|
||||
textureToModels.put(sourceTexturePath, entry.getKey());
|
||||
} else {
|
||||
|
||||
@@ -6,23 +6,25 @@ 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.pack.mcmeta.PackVersion;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.craftengine.core.util.GsonHelper;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static net.momirealms.craftengine.core.pack.mcmeta.PackVersion.MAX_PACK_VERSION;
|
||||
import static net.momirealms.craftengine.core.pack.mcmeta.PackVersion.MIN_PACK_VERSION;
|
||||
|
||||
public class ResolutionMergePackMcMeta implements Resolution {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
public static final Set<String> STANDARD_PACK_KEYS = ImmutableSet.of("pack", "features", "filter", "overlays", "language");
|
||||
public static final PackVersion MIN_PACK_VERSION = new PackVersion(15, 0); // 1.20
|
||||
public static final PackVersion MAX_PACK_VERSION = new PackVersion(1000, 0); // future
|
||||
|
||||
private final String description;
|
||||
|
||||
public ResolutionMergePackMcMeta(String description) {
|
||||
@@ -164,87 +166,23 @@ public class ResolutionMergePackMcMeta implements Resolution {
|
||||
PackVersion max = supportedVersions.right();
|
||||
// 旧版格式支持
|
||||
JsonObject supportedFormats = new JsonObject();
|
||||
supportedFormats.addProperty("min_inclusive", min.major);
|
||||
supportedFormats.addProperty("max_inclusive", max.major);
|
||||
supportedFormats.addProperty("min_inclusive", min.major());
|
||||
supportedFormats.addProperty("max_inclusive", max.major());
|
||||
entryJson.add("formats", supportedFormats);
|
||||
// 新版格式支持
|
||||
JsonArray minFormat = new JsonArray();
|
||||
minFormat.add(min.major);
|
||||
minFormat.add(min.minor);
|
||||
minFormat.add(min.major());
|
||||
minFormat.add(min.minor());
|
||||
entryJson.add("min_format", minFormat);
|
||||
JsonArray maxFormat = new JsonArray();
|
||||
maxFormat.add(max.major);
|
||||
maxFormat.add(max.minor);
|
||||
maxFormat.add(max.major());
|
||||
maxFormat.add(max.minor());
|
||||
entryJson.add("max_format", maxFormat);
|
||||
overlayCollector.accept(entryJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record PackVersion(int major, int minor) implements Comparable<PackVersion> {
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull ResolutionMergePackMcMeta.PackVersion o) {
|
||||
// 首先比较 major 版本
|
||||
int majorCompare = Integer.compare(this.major, o.major);
|
||||
if (majorCompare != 0) {
|
||||
return majorCompare;
|
||||
}
|
||||
// 如果 major 相同,则比较 minor 版本
|
||||
return Integer.compare(this.minor, o.minor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回两个版本中较小的那个(版本较低的)
|
||||
*/
|
||||
public static PackVersion getLower(PackVersion v1, PackVersion v2) {
|
||||
if (v1 == null) return v2;
|
||||
if (v2 == null) return v1;
|
||||
return v1.compareTo(v2) <= 0 ? v1 : v2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回两个版本中较大的那个(版本较高的)
|
||||
*/
|
||||
public static PackVersion getHigher(PackVersion v1, PackVersion v2) {
|
||||
if (v1 == null) return v2;
|
||||
if (v2 == null) return v1;
|
||||
return v1.compareTo(v2) >= 0 ? v1 : v2;
|
||||
}
|
||||
|
||||
public static PackVersion getLowest(List<PackVersion> versions) {
|
||||
if (versions == null || versions.isEmpty()) {
|
||||
return MIN_PACK_VERSION;
|
||||
}
|
||||
|
||||
PackVersion lowest = versions.getFirst();
|
||||
for (int i = 1; i < versions.size(); i++) {
|
||||
lowest = getLower(lowest, versions.get(i));
|
||||
}
|
||||
return lowest;
|
||||
}
|
||||
|
||||
public static PackVersion getHighest(List<PackVersion> versions) {
|
||||
if (versions == null || versions.isEmpty()) {
|
||||
return MAX_PACK_VERSION;
|
||||
}
|
||||
|
||||
PackVersion highest = versions.getFirst();
|
||||
for (int i = 1; i < versions.size(); i++) {
|
||||
highest = getHigher(highest, versions.get(i));
|
||||
}
|
||||
return highest;
|
||||
}
|
||||
|
||||
public static PackVersion parse(float num) {
|
||||
String str = String.valueOf(num);
|
||||
String[] parts = str.split("\\.");
|
||||
int integerPart = Integer.parseInt(parts[0]);
|
||||
int decimalPart = parts.length > 1 ? Integer.parseInt(parts[1]) : 0;
|
||||
return new PackVersion(integerPart, decimalPart);
|
||||
}
|
||||
}
|
||||
|
||||
public static void mergePack(JsonObject merged, JsonObject pack1, JsonObject pack2) {
|
||||
Pair<PackVersion, PackVersion> pack1Version = getSupportedVersions(pack1);
|
||||
Pair<PackVersion, PackVersion> pack2Version = getSupportedVersions(pack2);
|
||||
@@ -252,18 +190,18 @@ public class ResolutionMergePackMcMeta implements Resolution {
|
||||
PackVersion max = PackVersion.getHigher(pack1Version.right(), pack2Version.right());
|
||||
// 旧版格式支持
|
||||
JsonObject supportedFormats = new JsonObject();
|
||||
supportedFormats.addProperty("min_inclusive", min.major);
|
||||
supportedFormats.addProperty("max_inclusive", max.major);
|
||||
supportedFormats.addProperty("min_inclusive", min.major());
|
||||
supportedFormats.addProperty("max_inclusive", max.major());
|
||||
merged.add("supported_formats", supportedFormats);
|
||||
merged.addProperty("pack_format", min.major);
|
||||
merged.addProperty("pack_format", min.major());
|
||||
// 新版格式支持
|
||||
JsonArray minFormat = new JsonArray();
|
||||
minFormat.add(min.major);
|
||||
minFormat.add(min.minor);
|
||||
minFormat.add(min.major());
|
||||
minFormat.add(min.minor());
|
||||
merged.add("min_format", minFormat);
|
||||
JsonArray maxFormat = new JsonArray();
|
||||
maxFormat.add(max.major);
|
||||
maxFormat.add(max.minor);
|
||||
maxFormat.add(max.major());
|
||||
maxFormat.add(max.minor());
|
||||
merged.add("max_format", maxFormat);
|
||||
}
|
||||
|
||||
@@ -307,15 +245,15 @@ public class ResolutionMergePackMcMeta implements Resolution {
|
||||
case JsonArray array -> {
|
||||
if (array.isEmpty()) return Pair.of(MIN_PACK_VERSION, MAX_PACK_VERSION);
|
||||
if (array.size() == 1) {
|
||||
return new Pair<>(new PackVersion(GsonHelper.getAsInt(array.get(0), MIN_PACK_VERSION.major), 0), MAX_PACK_VERSION);
|
||||
return new Pair<>(new PackVersion(GsonHelper.getAsInt(array.get(0), MIN_PACK_VERSION.major()), 0), MAX_PACK_VERSION);
|
||||
}
|
||||
if (array.size() == 2) {
|
||||
return new Pair<>(new PackVersion(GsonHelper.getAsInt(array.get(0), MIN_PACK_VERSION.major), 0), new PackVersion(GsonHelper.getAsInt(array.get(1), MAX_PACK_VERSION.major), 0));
|
||||
return new Pair<>(new PackVersion(GsonHelper.getAsInt(array.get(0), MIN_PACK_VERSION.major()), 0), new PackVersion(GsonHelper.getAsInt(array.get(1), MAX_PACK_VERSION.major()), 0));
|
||||
}
|
||||
}
|
||||
case JsonObject object -> {
|
||||
int min = GsonHelper.getAsInt(object.get("min_inclusive"), MIN_PACK_VERSION.major);
|
||||
int max = GsonHelper.getAsInt(object.get("max_inclusive"), MAX_PACK_VERSION.major);
|
||||
int min = GsonHelper.getAsInt(object.get("min_inclusive"), MIN_PACK_VERSION.major());
|
||||
int max = GsonHelper.getAsInt(object.get("max_inclusive"), MAX_PACK_VERSION.major());
|
||||
return new Pair<>(new PackVersion(min, 0), new PackVersion(max, 0));
|
||||
}
|
||||
default -> {
|
||||
@@ -328,10 +266,10 @@ public class ResolutionMergePackMcMeta implements Resolution {
|
||||
if (format instanceof JsonArray array) {
|
||||
if (array.isEmpty()) return defaultVersion;
|
||||
if (array.size() == 1) {
|
||||
return new PackVersion(GsonHelper.getAsInt(array.get(0), defaultVersion.major), 0);
|
||||
return new PackVersion(GsonHelper.getAsInt(array.get(0), defaultVersion.major()), 0);
|
||||
}
|
||||
if (array.size() == 2) {
|
||||
return new PackVersion(GsonHelper.getAsInt(array.get(0), defaultVersion.major), GsonHelper.getAsInt(array.get(1), defaultVersion.minor));
|
||||
return new PackVersion(GsonHelper.getAsInt(array.get(0), defaultVersion.major()), GsonHelper.getAsInt(array.get(1), defaultVersion.minor()));
|
||||
}
|
||||
} else if (format instanceof JsonPrimitive jsonPrimitive) {
|
||||
float version = jsonPrimitive.getAsFloat();
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package net.momirealms.craftengine.core.pack.mcmeta;
|
||||
|
||||
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.util.GsonHelper;
|
||||
import net.momirealms.craftengine.core.util.MinecraftVersion;
|
||||
import net.momirealms.craftengine.core.util.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Overlay {
|
||||
private final PackVersion minVersion;
|
||||
private final PackVersion maxVersion;
|
||||
private final String directory;
|
||||
|
||||
public Overlay(PackVersion minVersion,
|
||||
PackVersion maxVersion,
|
||||
String directory
|
||||
) {
|
||||
this.minVersion = minVersion;
|
||||
this.maxVersion = maxVersion;
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
public Overlay(JsonObject overlay) {
|
||||
this.directory = overlay.get("directory").getAsString();
|
||||
Pair<PackVersion, PackVersion> supportedVersions = getSupportedVersions(overlay);
|
||||
this.minVersion = supportedVersions.left();
|
||||
this.maxVersion = supportedVersions.right();
|
||||
}
|
||||
|
||||
public PackVersion minVersion() {
|
||||
return minVersion;
|
||||
}
|
||||
|
||||
public PackVersion maxVersion() {
|
||||
return maxVersion;
|
||||
}
|
||||
|
||||
public String directory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
public boolean test(MinecraftVersion version) {
|
||||
return version.packFormat().isAtOrAbove(this.minVersion) && version.packFormat().isAtOrBelow(this.maxVersion);
|
||||
}
|
||||
|
||||
private static Pair<PackVersion, PackVersion> getSupportedVersions(JsonObject pack) {
|
||||
List<PackVersion> minVersions = new ArrayList<>();
|
||||
List<PackVersion> maxVersions = new ArrayList<>();
|
||||
if (pack.has("min_format")) {
|
||||
minVersions.add(getFormatVersion(pack.get("min_format")));
|
||||
}
|
||||
if (pack.has("max_format")) {
|
||||
maxVersions.add(getFormatVersion(pack.get("max_format")));
|
||||
}
|
||||
if (pack.has("formats")) {
|
||||
Pair<PackVersion, PackVersion> supportedFormats = parseSupportedFormats(pack.get("formats"));
|
||||
minVersions.add(supportedFormats.left());
|
||||
maxVersions.add(supportedFormats.right());
|
||||
}
|
||||
return Pair.of(
|
||||
PackVersion.getLowest(minVersions),
|
||||
PackVersion.getHighest(maxVersions)
|
||||
);
|
||||
}
|
||||
|
||||
private static PackVersion getFormatVersion(JsonElement format) {
|
||||
if (format instanceof JsonArray array) {
|
||||
if (array.size() == 1) {
|
||||
return new PackVersion(GsonHelper.getAsInt(array.get(0), 15), 0);
|
||||
}
|
||||
if (array.size() == 2) {
|
||||
return new PackVersion(GsonHelper.getAsInt(array.get(0), 15), GsonHelper.getAsInt(array.get(1), 1000));
|
||||
}
|
||||
} else if (format instanceof JsonPrimitive jsonPrimitive) {
|
||||
float version = jsonPrimitive.getAsFloat();
|
||||
return PackVersion.parse(version);
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown overlay version format: " + format);
|
||||
}
|
||||
|
||||
private static Pair<PackVersion, PackVersion> parseSupportedFormats(JsonElement formats) {
|
||||
switch (formats) {
|
||||
case JsonPrimitive jsonPrimitive -> {
|
||||
return new Pair<>(new PackVersion(jsonPrimitive.getAsInt(), 0), new PackVersion(jsonPrimitive.getAsInt(), 0));
|
||||
}
|
||||
case JsonArray array -> {
|
||||
if (array.size() == 2) {
|
||||
return new Pair<>(new PackVersion(GsonHelper.getAsInt(array.get(0), 15), 0), new PackVersion(GsonHelper.getAsInt(array.get(1), 1000), 0));
|
||||
}
|
||||
}
|
||||
case JsonObject object -> {
|
||||
int min = GsonHelper.getAsInt(object.get("min_inclusive"), 15);
|
||||
int max = GsonHelper.getAsInt(object.get("max_inclusive"), 1000);
|
||||
return new Pair<>(new PackVersion(min, 0), new PackVersion(max, 0));
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported overlay version format: " + formats);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package net.momirealms.craftengine.core.pack.mcmeta;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PackMcMeta {
|
||||
private final List<Overlay> overlays;
|
||||
|
||||
public PackMcMeta(JsonObject mcmeta) {
|
||||
this.overlays = getOverlays(mcmeta);
|
||||
}
|
||||
|
||||
private List<Overlay> getOverlays(JsonObject mcmeta) {
|
||||
List<Overlay> overlays = new ArrayList<>();
|
||||
JsonObject overlaysJson = mcmeta.getAsJsonObject("overlays");
|
||||
if (overlaysJson != null) {
|
||||
JsonArray entries = overlaysJson.getAsJsonArray("entries");
|
||||
if (entries != null) {
|
||||
for (JsonElement overlayJson : entries) {
|
||||
if (overlayJson instanceof JsonObject overlayJsonObj) {
|
||||
overlays.add(new Overlay(overlayJsonObj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return overlays;
|
||||
}
|
||||
|
||||
public List<Overlay> overlays() {
|
||||
return this.overlays;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package net.momirealms.craftengine.core.pack.mcmeta;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record PackVersion(int major, int minor) implements Comparable<PackVersion> {
|
||||
public static final PackVersion MIN_PACK_VERSION = new PackVersion(15, 0); // 1.20
|
||||
public static final PackVersion MAX_PACK_VERSION = new PackVersion(1000, 0); // future
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull PackVersion o) {
|
||||
// 首先比较 major 版本
|
||||
int majorCompare = Integer.compare(this.major, o.major);
|
||||
if (majorCompare != 0) {
|
||||
return majorCompare;
|
||||
}
|
||||
// 如果 major 相同,则比较 minor 版本
|
||||
return Integer.compare(this.minor, o.minor);
|
||||
}
|
||||
|
||||
public boolean isAtOrAbove(PackVersion other) {
|
||||
return this.compareTo(other) >= 0;
|
||||
}
|
||||
|
||||
public boolean isAbove(PackVersion other) {
|
||||
return this.compareTo(other) > 0;
|
||||
}
|
||||
|
||||
public boolean isAtOrBelow(PackVersion other) {
|
||||
return this.compareTo(other) <= 0;
|
||||
}
|
||||
|
||||
public boolean isBelow(PackVersion other) {
|
||||
return this.compareTo(other) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回两个版本中较小的那个(版本较低的)
|
||||
*/
|
||||
public static PackVersion getLower(PackVersion v1, PackVersion v2) {
|
||||
if (v1 == null) return v2;
|
||||
if (v2 == null) return v1;
|
||||
return v1.compareTo(v2) <= 0 ? v1 : v2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回两个版本中较大的那个(版本较高的)
|
||||
*/
|
||||
public static PackVersion getHigher(PackVersion v1, PackVersion v2) {
|
||||
if (v1 == null) return v2;
|
||||
if (v2 == null) return v1;
|
||||
return v1.compareTo(v2) >= 0 ? v1 : v2;
|
||||
}
|
||||
|
||||
public static PackVersion getLowest(List<PackVersion> versions) {
|
||||
if (versions == null || versions.isEmpty()) {
|
||||
return MIN_PACK_VERSION;
|
||||
}
|
||||
|
||||
PackVersion lowest = versions.getFirst();
|
||||
for (int i = 1; i < versions.size(); i++) {
|
||||
lowest = getLower(lowest, versions.get(i));
|
||||
}
|
||||
return lowest;
|
||||
}
|
||||
|
||||
public static PackVersion getHighest(List<PackVersion> versions) {
|
||||
if (versions == null || versions.isEmpty()) {
|
||||
return MAX_PACK_VERSION;
|
||||
}
|
||||
|
||||
PackVersion highest = versions.getFirst();
|
||||
for (int i = 1; i < versions.size(); i++) {
|
||||
highest = getHigher(highest, versions.get(i));
|
||||
}
|
||||
return highest;
|
||||
}
|
||||
|
||||
public static PackVersion parse(float num) {
|
||||
String str = String.valueOf(num);
|
||||
String[] parts = str.split("\\.");
|
||||
int integerPart = Integer.parseInt(parts[0]);
|
||||
int decimalPart = parts.length > 1 ? Integer.parseInt(parts[1]) : 0;
|
||||
return new PackVersion(integerPart, decimalPart);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package net.momirealms.craftengine.core.pack.overlay;
|
||||
|
||||
import net.momirealms.craftengine.core.util.MinecraftVersion;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class ResourcePackOverlay {
|
||||
private final MinecraftVersion minVersion;
|
||||
private final MinecraftVersion maxVersion;
|
||||
private final Path folder;
|
||||
|
||||
public ResourcePackOverlay(MinecraftVersion minVersion,
|
||||
MinecraftVersion maxVersion,
|
||||
Path folder
|
||||
) {
|
||||
this.minVersion = minVersion;
|
||||
this.maxVersion = maxVersion;
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
public MinecraftVersion minVersion() {
|
||||
return minVersion;
|
||||
}
|
||||
|
||||
public MinecraftVersion maxVersion() {
|
||||
return maxVersion;
|
||||
}
|
||||
|
||||
public Path folder() {
|
||||
return folder;
|
||||
}
|
||||
}
|
||||
@@ -60,12 +60,14 @@ public interface Revision {
|
||||
|
||||
@Override
|
||||
public int maxPackVersion() {
|
||||
return MinecraftVersions.FUTURE.packFormat();
|
||||
// todo 重构revision系统
|
||||
return MinecraftVersions.FUTURE.packFormat().major();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int minPackVersion() {
|
||||
return this.minVersion.packFormat();
|
||||
// todo 重构revision系统
|
||||
return this.minVersion.packFormat().major();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,12 +114,12 @@ public interface Revision {
|
||||
|
||||
@Override
|
||||
public int minPackVersion() {
|
||||
return this.minVersion.packFormat();
|
||||
return this.minVersion.packFormat().major();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxPackVersion() {
|
||||
return this.maxVersion.packFormat();
|
||||
return this.maxVersion.packFormat().major();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -79,6 +79,7 @@ public class Config {
|
||||
|
||||
protected boolean resource_pack$validation$enable;
|
||||
protected boolean resource_pack$validation$fix_atlas;
|
||||
protected List<MinecraftVersion> resource_pack$validation$test_versions;
|
||||
protected boolean resource_pack$exclude_core_shaders;
|
||||
|
||||
protected boolean resource_pack$protection$obfuscation$enable;
|
||||
@@ -391,6 +392,7 @@ public class Config {
|
||||
}).collect(Collectors.toSet());
|
||||
resource_pack$validation$enable = config.getBoolean("resource-pack.validation.enable", true);
|
||||
resource_pack$validation$fix_atlas = config.getBoolean("resource-pack.validation.fix-atlas", true);
|
||||
resource_pack$validation$test_versions = config.getStringList("resource-pack.validation.test-versions", List.of("server")).stream().map(Config::getVersion).distinct().toList();
|
||||
resource_pack$exclude_core_shaders = config.getBoolean("resource-pack.exclude-core-shaders", false);
|
||||
resource_pack$overlay_format = config.getString("resource-pack.overlay-format", "overlay_{version}");
|
||||
if (!resource_pack$overlay_format.contains("{version}")) {
|
||||
@@ -1110,6 +1112,10 @@ public class Config {
|
||||
return instance.resource_pack$validation$fix_atlas;
|
||||
}
|
||||
|
||||
public static List<MinecraftVersion> validationTestVersions() {
|
||||
return instance.resource_pack$validation$test_versions;
|
||||
}
|
||||
|
||||
public static boolean excludeShaders() {
|
||||
return instance.resource_pack$exclude_core_shaders;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FileUtils {
|
||||
@@ -67,9 +68,21 @@ public class FileUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Path> collectOverlays(Path resourcePackFolder, Predicate<String> directoryPredicate) throws IOException {
|
||||
List<Path> folders = new ObjectArrayList<>();
|
||||
try (Stream<Path> paths = Files.list(resourcePackFolder)) {
|
||||
folders.addAll(paths
|
||||
.filter(Files::isDirectory)
|
||||
.filter(path -> directoryPredicate.test(path.getFileName().toString()))
|
||||
.filter(path -> !path.getFileName().toString().equals("assets"))
|
||||
.filter(path -> Files.exists(path.resolve("assets")))
|
||||
.toList());
|
||||
}
|
||||
return folders;
|
||||
}
|
||||
|
||||
public static List<Path> collectOverlays(Path resourcePackFolder) throws IOException {
|
||||
List<Path> folders = new ObjectArrayList<>();
|
||||
folders.add(resourcePackFolder);
|
||||
try (Stream<Path> paths = Files.list(resourcePackFolder)) {
|
||||
folders.addAll(paths
|
||||
.filter(Files::isDirectory)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.momirealms.craftengine.core.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -13,4 +15,13 @@ public final class ListUtils {
|
||||
if (list.size() == 2) return List.of(list.get(0), list.get(1));
|
||||
return list;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> List<T> newNonNullList(T... elements) {
|
||||
List<T> list = new ArrayList<>(elements.length);
|
||||
for (T element : elements) {
|
||||
if (element != null) list.add(element);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,38 @@
|
||||
package net.momirealms.craftengine.core.util;
|
||||
|
||||
import net.momirealms.craftengine.core.pack.mcmeta.PackVersion;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class MinecraftVersion implements Comparable<MinecraftVersion> {
|
||||
public static final Map<Integer, Integer> PACK_FORMATS = new HashMap<>();
|
||||
public static final Map<Integer, PackVersion> PACK_FORMATS = new HashMap<>();
|
||||
static {
|
||||
PACK_FORMATS.put(1_20_00, 15);
|
||||
PACK_FORMATS.put(1_20_01, 15);
|
||||
PACK_FORMATS.put(1_20_02, 18);
|
||||
PACK_FORMATS.put(1_20_03, 22);
|
||||
PACK_FORMATS.put(1_20_04, 22);
|
||||
PACK_FORMATS.put(1_20_05, 32);
|
||||
PACK_FORMATS.put(1_20_06, 32);
|
||||
PACK_FORMATS.put(1_21_00, 34);
|
||||
PACK_FORMATS.put(1_21_01, 34);
|
||||
PACK_FORMATS.put(1_21_02, 42);
|
||||
PACK_FORMATS.put(1_21_03, 42);
|
||||
PACK_FORMATS.put(1_21_04, 46);
|
||||
PACK_FORMATS.put(1_21_05, 55);
|
||||
PACK_FORMATS.put(1_21_06, 63);
|
||||
PACK_FORMATS.put(1_21_07, 64);
|
||||
PACK_FORMATS.put(1_21_08, 64);
|
||||
PACK_FORMATS.put(1_21_09, 69);
|
||||
PACK_FORMATS.put(1_21_10, 69);
|
||||
PACK_FORMATS.put(1_21_11, 75);
|
||||
PACK_FORMATS.put(1_99_99, 1000);
|
||||
PACK_FORMATS.put(1_20_00, new PackVersion(15, 0));
|
||||
PACK_FORMATS.put(1_20_01, new PackVersion(15, 0));
|
||||
PACK_FORMATS.put(1_20_02, new PackVersion(18, 0));
|
||||
PACK_FORMATS.put(1_20_03, new PackVersion(22, 0));
|
||||
PACK_FORMATS.put(1_20_04, new PackVersion(22, 0));
|
||||
PACK_FORMATS.put(1_20_05, new PackVersion(32, 0));
|
||||
PACK_FORMATS.put(1_20_06, new PackVersion(32, 0));
|
||||
PACK_FORMATS.put(1_21_00, new PackVersion(34, 0));
|
||||
PACK_FORMATS.put(1_21_01, new PackVersion(34, 0));
|
||||
PACK_FORMATS.put(1_21_02, new PackVersion(42, 0));
|
||||
PACK_FORMATS.put(1_21_03, new PackVersion(42, 0));
|
||||
PACK_FORMATS.put(1_21_04, new PackVersion(46, 0));
|
||||
PACK_FORMATS.put(1_21_05, new PackVersion(55, 0));
|
||||
PACK_FORMATS.put(1_21_06, new PackVersion(63, 0));
|
||||
PACK_FORMATS.put(1_21_07, new PackVersion(64, 0));
|
||||
PACK_FORMATS.put(1_21_08, new PackVersion(64, 0));
|
||||
PACK_FORMATS.put(1_21_09, new PackVersion(69, 0));
|
||||
PACK_FORMATS.put(1_21_10, new PackVersion(69, 0));
|
||||
PACK_FORMATS.put(1_21_11, new PackVersion(75, 0));
|
||||
PACK_FORMATS.put(99_99_99, new PackVersion(1000, 0));
|
||||
}
|
||||
|
||||
private final int version;
|
||||
private final String versionString;
|
||||
private final int packFormat;
|
||||
private final PackVersion packFormat;
|
||||
|
||||
public static MinecraftVersion parse(final String version) {
|
||||
return new MinecraftVersion(version);
|
||||
@@ -40,7 +42,7 @@ public final class MinecraftVersion implements Comparable<MinecraftVersion> {
|
||||
return versionString;
|
||||
}
|
||||
|
||||
public int packFormat() {
|
||||
public PackVersion packFormat() {
|
||||
return packFormat;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
|
||||
# Project settings
|
||||
project_version=0.0.66.4
|
||||
config_version=62
|
||||
project_version=0.0.66.5
|
||||
config_version=63
|
||||
lang_version=45
|
||||
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.74
|
||||
sparrow_util_version=0.75
|
||||
fastutil_version=8.5.18
|
||||
netty_version=4.1.128.Final
|
||||
joml_version=1.10.8
|
||||
|
||||
Reference in New Issue
Block a user