diff --git a/build.gradle b/build.gradle index 89a7b24..7fb722b 100644 --- a/build.gradle +++ b/build.gradle @@ -40,6 +40,7 @@ dependencies { implementation('net.minecraft:launchwrapper:1.12') { transitive = false } implementation 'org.ow2.asm:asm:6.2' implementation 'org.ow2.asm:asm-commons:6.2' + compile 'com.vdurmont:semver4j:2.2.0' } minecraft { diff --git a/src/main/java/org/dimdev/riftloader/Dependency.java b/src/main/java/org/dimdev/riftloader/Dependency.java new file mode 100644 index 0000000..43349f5 --- /dev/null +++ b/src/main/java/org/dimdev/riftloader/Dependency.java @@ -0,0 +1,11 @@ +package org.dimdev.riftloader; + +public class Dependency { + + public String id; + public String type; + public String load; + public String mavenId; + public String minVersion; + public String maxVersion; +} diff --git a/src/main/java/org/dimdev/riftloader/MissingDependencyException.java b/src/main/java/org/dimdev/riftloader/MissingDependencyException.java new file mode 100644 index 0000000..1fdafe5 --- /dev/null +++ b/src/main/java/org/dimdev/riftloader/MissingDependencyException.java @@ -0,0 +1,7 @@ +package org.dimdev.riftloader; + +public class MissingDependencyException extends RuntimeException { + public MissingDependencyException(String s) { + super(s); + } +} diff --git a/src/main/java/org/dimdev/riftloader/ModInfo.java b/src/main/java/org/dimdev/riftloader/ModInfo.java index 07e341f..d64c845 100644 --- a/src/main/java/org/dimdev/riftloader/ModInfo.java +++ b/src/main/java/org/dimdev/riftloader/ModInfo.java @@ -9,6 +9,8 @@ public class ModInfo { public String id; public String name; + public String version; + public List dependencies = new ArrayList<>(); public List authors = new ArrayList<>(); public List listeners = new ArrayList<>(); } diff --git a/src/main/java/org/dimdev/riftloader/RiftLoader.java b/src/main/java/org/dimdev/riftloader/RiftLoader.java index 07e3929..19dcd7b 100644 --- a/src/main/java/org/dimdev/riftloader/RiftLoader.java +++ b/src/main/java/org/dimdev/riftloader/RiftLoader.java @@ -2,6 +2,8 @@ import com.google.gson.Gson; import com.google.gson.JsonParseException; +import com.vdurmont.semver4j.Semver; +import com.vdurmont.semver4j.SemverException; import net.minecraft.launchwrapper.Launch; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -76,6 +78,7 @@ public void findMods(File modsDir) { mod.source = file; mod.id = "optifine"; mod.name = "Optifine"; + mod.version = "1.13-alpha8"; mod.authors.add("sp614x"); mod.listeners.add("org.dimdev.riftloader.OptifineLoader"); modInfoMap.put("optifine", mod); @@ -136,6 +139,18 @@ private void loadModFromJson(InputStream in, File source) { throw new ModConflictException("Duplicate mod '" + modInfo.id + "': " + modInfoMap.get(modInfo.id).source + ", " + modInfo.source); } + // Make sure the version is proper SemVer + if (modInfo.version == null) { + log.warn("Mod file " + modInfo.source + "'s riftmod.json is missing a 'version' field. This may affect dependencies!"); + } else { + try { + Semver version = new Semver(modInfo.version, Semver.SemverType.LOOSE); + } catch (SemverException t) { + log.warn("Mod file " + modInfo.source + "'s riftmod.json has a malformed 'version' field. This may affect dependencies!"); + log.warn("SemVer error: " + t.getMessage()); + } + } + // Add the mod to the 'id -> mod info' map modInfoMap.put(modInfo.id, modInfo); log.info("Loaded mod '" + modInfo.id + "'"); @@ -150,6 +165,44 @@ public void sortMods() { public void initMods() { log.info("Initializing mods"); + + // Check dependencies + for (ModInfo modInfo : modInfoMap.values()) { + if (!modInfo.dependencies.isEmpty()) { + log.info("Found dependency list for " + modInfo.id); + for (Dependency dependency : modInfo.dependencies) { + log.info(dependency.id); + log.info(dependency.minVersion); + log.info(dependency.load); + if (!modInfoMap.containsKey(dependency.id)) { + if (dependency.type.equals("hard")) throw new MissingDependencyException("Mod " + modInfo.source + " is missing hard dependency " + dependency.id + ":" + dependency.minVersion); + else log.error("Mod " + modInfo.source + " is missing soft dependency " + dependency.id + ":" + dependency.minVersion + ". This may impact gameplay!"); + } + ModInfo depInfo = modInfoMap.get(dependency.id); + Semver trueVersion = new Semver(depInfo.version, Semver.SemverType.LOOSE); + try { + Semver lowestVersion = new Semver(dependency.minVersion, Semver.SemverType.LOOSE); + if (trueVersion.isLowerThan(lowestVersion)) { + if (dependency.type.equals("hard")) throw new MissingDependencyException("Mod " + modInfo.source + " has outdated hard dependency: " + dependency.id + " must be at least " + lowestVersion); + else log.error("Mod " + modInfo.source + " has outdated soft dependency: " + dependency.id + " must be at least " + lowestVersion); + } + + if (dependency.maxVersion != null) { + Semver highestVersion = new Semver(dependency.maxVersion, Semver.SemverType.LOOSE); + if (trueVersion.isGreaterThan(highestVersion)) { + if (dependency.type.equals("hard")) throw new MissingDependencyException("Mod " + modInfo.source + " has outdated hard dependency: " + dependency.id + " must be at most " + highestVersion); + else log.error("Mod " + modInfo.source + " has outdated soft dependency: " + dependency.id + " must be at most " + highestVersion); } + } + } catch (SemverException t) { + if (dependency.type.equals("hard")) throw new MissingDependencyException("Mod " + modInfo.source + " has malformed hard dependency in " + dependency.id + ": SemVer error " + t.getMessage()); + else log.error("Mod " + modInfo.source + " has malformed soft dependency in " + dependency.id + ": SemVer error " + t.getMessage()); + } + } + } else { + log.info("Found no dependencies for " + modInfo.id); + } + } + // Load all the mod jars for (ModInfo modInfo : modInfoMap.values()) { try { diff --git a/src/main/resources/riftmod.json b/src/main/resources/riftmod.json index 192688c..7e689fe 100644 --- a/src/main/resources/riftmod.json +++ b/src/main/resources/riftmod.json @@ -1,6 +1,7 @@ { "id": "rift", "name": "Rift", + "version": "1.0.3-SNAPSHOT", "authors": [ "Runemoro" ],