Validate mod files
This commit is contained in:
parent
fe32ccd2bd
commit
ae88c07bf4
|
@ -2,14 +2,23 @@
|
|||
format_version = "1.0.0"
|
||||
|
||||
[frog.mod]
|
||||
id = "example_mod_test"
|
||||
name = "Example Mod Test Mod"
|
||||
version = "0.0.1"
|
||||
license = "CC0-1.0"
|
||||
credits = [
|
||||
{ name = "You", roles = ["author", "other_role"] }
|
||||
]
|
||||
|
||||
[frog.dependencies]
|
||||
depends = [
|
||||
{ id = "awesome-mod", versions = "0.0.0", name = "Awesome Mod" },
|
||||
{ id = "other-awesome-mod", versions = "0.0.0", name = "Other Awesome Mod", link = "https://google.com" },
|
||||
{ id = "other-awesome-mod2", versions = "0.0.0", name = "Other Awesome Mod" },
|
||||
{ id = "other-awesome-mod3", versions = "0.0.0", name = "Other Awesome Mod" },
|
||||
{ id = "other-awesome-mod4", versions = "0.0.0", name = "Other Awesome Mod" },
|
||||
{ id = "other-awesome-mod5", versions = "0.0.0", name = "Other Awesome Mod" },
|
||||
{ id = "other-awesome-mod6", versions = "0.0.0", name = "Other Awesome Mod" },
|
||||
{ id = "other-awesome-mod7", versions = "0.0.0", name = "Other Awesome Mod" }
|
||||
]
|
||||
|
||||
[frog.extensions]
|
||||
prelaunch="dev.frogmc.example.ExampleTestMod"
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.nio.file.FileSystem;
|
|||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||
|
@ -16,7 +17,10 @@ import com.electronwill.nightconfig.toml.TomlParser;
|
|||
import dev.frogmc.frogloader.api.mod.ModDependencies;
|
||||
import dev.frogmc.frogloader.api.mod.ModExtensions;
|
||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||
import dev.frogmc.frogloader.api.mod.SemVer;
|
||||
import dev.frogmc.frogloader.impl.SemVerParseException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -32,7 +36,7 @@ public class ModPropertiesReader {
|
|||
CommentedConfig props = PARSER.parse(fs.getPath(PROPERTIES_FILE_NAME), FileNotFoundAction.THROW_ERROR);
|
||||
|
||||
return Optional.of(readProperties(props, Collections.singleton(mod)));
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | InvalidModPropertiesException e) {
|
||||
LOGGER.warn("Failed to read mod properties: ", e);
|
||||
}
|
||||
|
||||
|
@ -60,7 +64,7 @@ public class ModPropertiesReader {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static ModProperties readProperties(UnmodifiableConfig config, Collection<Path> sources) {
|
||||
private static ModProperties readProperties(UnmodifiableConfig config, Collection<Path> sources) throws InvalidModPropertiesException {
|
||||
String manifestVer = config.get("frog.format_version");
|
||||
|
||||
try {
|
||||
|
@ -73,53 +77,91 @@ public class ModPropertiesReader {
|
|||
@AllArgsConstructor
|
||||
private enum FormatVersion {
|
||||
V1_0_0("1.0.0", (config, sources) -> {
|
||||
List<String> badProperties = new ArrayList<>();
|
||||
|
||||
String id = config.get("frog.mod.id");
|
||||
String name = config.get("frog.mod.name");
|
||||
String icon = config.get("frog.mod.icon");
|
||||
String version = config.get("frog.mod.version");
|
||||
String license = config.get("frog.mod.license");
|
||||
String license = Objects.requireNonNullElse(config.get("frog.mod.license"), "");
|
||||
|
||||
if (license == null) {
|
||||
license = "";
|
||||
if (id == null || id.isEmpty())
|
||||
badProperties.add("frog.mod.id");
|
||||
|
||||
if (name == null || name.isEmpty())
|
||||
badProperties.add("frog.mod.name");
|
||||
|
||||
SemVer semVer = null;
|
||||
|
||||
if (version == null || version.isEmpty())
|
||||
badProperties.add("frog.mod.version");
|
||||
else {
|
||||
try {
|
||||
semVer = SemVerImpl.parse(version);
|
||||
} catch (SemVerParseException e) {
|
||||
badProperties.add("frog.mod.version");
|
||||
}
|
||||
}
|
||||
|
||||
List<UnmodifiableConfig> creditsList = config.get("frog.mod.credits");
|
||||
Map<String, Collection<String>> credits = new HashMap<>();
|
||||
if (creditsList != null) {
|
||||
creditsList.forEach(c -> credits.put(c.get("name"), c.get("roles")));
|
||||
int i = 0;
|
||||
|
||||
for (UnmodifiableConfig entry : creditsList) {
|
||||
String entryName = entry.get("name");
|
||||
Collection<String> entryRoles = entry.get("roles");
|
||||
|
||||
if (entryName == null || entryName.isEmpty())
|
||||
badProperties.add("frog.mod.credits." + i + ".name");
|
||||
|
||||
if (entryRoles == null || entryRoles.isEmpty())
|
||||
badProperties.add("frog.mod.credits." + i + ".name");
|
||||
|
||||
credits.put(entryName, entryRoles);
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
Collection<ModDependencies.Entry> depends = new HashSet<>();
|
||||
List<UnmodifiableConfig> dependsConfig = config.get("frog.dependencies.depends");
|
||||
if (dependsConfig != null) {
|
||||
dependsConfig.forEach(entry -> depends.add(new ModDependencies.Entry(entry.get("id"), entry.get("versions"), entry.get("link"), entry.get("name"))));
|
||||
Function<String, Collection<ModDependencies.Entry>> parseDependencies = key -> {
|
||||
Collection<ModDependencies.Entry> result = new HashSet<>();
|
||||
|
||||
List<UnmodifiableConfig> dependenciesConfig = config.get("frog.dependencies." + key);
|
||||
if (dependenciesConfig != null) {
|
||||
int i = 0;
|
||||
|
||||
for (UnmodifiableConfig entry : dependenciesConfig) {
|
||||
String entryId = entry.get("id");
|
||||
String entryVersions = entry.get("versions");
|
||||
|
||||
if (entryId == null || entryId.isEmpty())
|
||||
badProperties.add("frog.dependencies." + key + '.' + i + ".id");
|
||||
|
||||
result.add(new ModDependencies.Entry(entryId, entryVersions, entry.get("link"), entry.get("name")));
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
Collection<ModDependencies.Entry> breaks = new HashSet<>();
|
||||
List<UnmodifiableConfig> breaksConfig = config.get("frog.dependencies.breaks");
|
||||
if (breaksConfig != null) {
|
||||
breaksConfig.forEach(entry -> breaks.add(new ModDependencies.Entry(entry.get("id"), entry.get("versions"), entry.get("link"), entry.get("name"))));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Collection<ModDependencies.Entry> suggests = new HashSet<>();
|
||||
List<UnmodifiableConfig> suggestsConfig = config.get("frog.dependencies.suggests");
|
||||
if (suggestsConfig != null) {
|
||||
suggestsConfig.forEach(entry -> suggests.add(new ModDependencies.Entry(entry.get("id"), entry.get("versions"), entry.get("link"), entry.get("name"))));
|
||||
}
|
||||
|
||||
Collection<ModDependencies.Entry> provides = new HashSet<>();
|
||||
List<UnmodifiableConfig> providesConfig = config.get("frog.dependencies.provides");
|
||||
if (providesConfig != null) {
|
||||
providesConfig.forEach(entry -> provides.add(new ModDependencies.Entry(entry.get("id"), entry.get("version"), entry.get("link"), entry.get("name"))));
|
||||
}
|
||||
var depends = parseDependencies.apply("depends");
|
||||
var breaks = parseDependencies.apply("breaks");
|
||||
var suggests = parseDependencies.apply("suggests");
|
||||
var provides = parseDependencies.apply("provides");
|
||||
|
||||
if (!badProperties.isEmpty())
|
||||
throw new InvalidModPropertiesException(id, sources, badProperties);
|
||||
|
||||
UnmodifiableConfig extensionsConfig = config.get("frog.extensions");
|
||||
Map<String, Object> extensions = new HashMap<>();
|
||||
if (extensionsConfig != null) {
|
||||
if (extensionsConfig != null)
|
||||
extensionsConfig.entrySet().forEach(entry -> extensions.put(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
|
||||
return new ModPropertiesImpl(id, name, icon, SemVerImpl.parse(version), license, Collections.unmodifiableMap(credits),
|
||||
return new ModPropertiesImpl(id, name, icon, semVer, license, Collections.unmodifiableMap(credits),
|
||||
new ModDependencies(depends, breaks, suggests, provides), ModExtensions.of(extensions), sources);
|
||||
});
|
||||
|
||||
|
@ -133,8 +175,26 @@ public class ModPropertiesReader {
|
|||
|
||||
@FunctionalInterface
|
||||
public interface Parser {
|
||||
ModProperties parse(UnmodifiableConfig config, Collection<Path> sources) throws IOException;
|
||||
ModProperties parse(UnmodifiableConfig config, Collection<Path> sources) throws IOException, InvalidModPropertiesException;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class InvalidModPropertiesException extends Exception {
|
||||
|
||||
private final Collection<String> invalid;
|
||||
|
||||
public InvalidModPropertiesException(String id, Collection<Path> sources, Collection<String> invalid) {
|
||||
super(
|
||||
"Invalid properties for %s (%s) - invalid or missing values for: %s".formatted(
|
||||
Objects.requireNonNullElse(id, "<unknown>"),
|
||||
sources.stream().map(Path::toString).collect(Collectors.joining(", ")),
|
||||
String.join(", ", invalid)
|
||||
)
|
||||
);
|
||||
this.invalid = invalid;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue