9
0
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:
XiaoMoMi
2025-12-17 19:26:42 +08:00
parent bc16e248e7
commit f2042dc9c8
13 changed files with 383 additions and 177 deletions

View File

@@ -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:

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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