diff --git a/pom.xml b/pom.xml
index 3bfdf24c8..34672b6f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -114,5 +114,10 @@
+
+ org.xeustechnologies
+ jcl-core
+ 2.8
+
\ No newline at end of file
diff --git a/src/main/java/de/bixilon/minosoft/Minosoft.java b/src/main/java/de/bixilon/minosoft/Minosoft.java
index 508f1a773..d2ed0ad19 100644
--- a/src/main/java/de/bixilon/minosoft/Minosoft.java
+++ b/src/main/java/de/bixilon/minosoft/Minosoft.java
@@ -21,6 +21,7 @@ import de.bixilon.minosoft.gui.main.AccountListCell;
import de.bixilon.minosoft.gui.main.Server;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.logging.LogLevels;
+import de.bixilon.minosoft.modding.loading.ModLoader;
import de.bixilon.minosoft.util.OSUtil;
import de.bixilon.minosoft.util.Util;
import de.bixilon.minosoft.util.mojang.api.MojangAccount;
@@ -70,6 +71,9 @@ public class Minosoft {
selectAccount(accountList.get(config.getString(GameConfiguration.ACCOUNT_SELECTED)));
serverList = config.getServers();
+ Thread modThread = new Thread(ModLoader::loadMods);
+ modThread.setName("ModLoader");
+ modThread.start();
Launcher.start();
}
diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/recipes/Ingredient.java b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/recipes/Ingredient.java
index 076e691e7..356d123b5 100644
--- a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/recipes/Ingredient.java
+++ b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/recipes/Ingredient.java
@@ -52,6 +52,9 @@ public class Ingredient {
if (super.equals(obj)) {
return true;
}
+ if (this.hashCode() != obj.hashCode()) {
+ return false;
+ }
Ingredient their = (Ingredient) obj;
return slotEquals(getSlot(), their.getSlot());
}
diff --git a/src/main/java/de/bixilon/minosoft/modding/loading/MinosoftMod.java b/src/main/java/de/bixilon/minosoft/modding/MinosoftMod.java
similarity index 90%
rename from src/main/java/de/bixilon/minosoft/modding/loading/MinosoftMod.java
rename to src/main/java/de/bixilon/minosoft/modding/MinosoftMod.java
index 8ff20a37c..5ba2bb1d7 100644
--- a/src/main/java/de/bixilon/minosoft/modding/loading/MinosoftMod.java
+++ b/src/main/java/de/bixilon/minosoft/modding/MinosoftMod.java
@@ -11,7 +11,9 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
-package de.bixilon.minosoft.modding.loading;
+package de.bixilon.minosoft.modding;
+
+import de.bixilon.minosoft.modding.loading.ModPhases;
interface MinosoftModInterface {
boolean start(ModPhases phase);
diff --git a/src/main/java/de/bixilon/minosoft/modding/ModLoader.java b/src/main/java/de/bixilon/minosoft/modding/ModLoader.java
deleted file mode 100644
index 057e20130..000000000
--- a/src/main/java/de/bixilon/minosoft/modding/ModLoader.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Codename Minosoft
- * Copyright (C) 2020 Moritz Zwerger
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program. If not, see .
- *
- * This software is not affiliated with Mojang AB, the original developer of Minecraft.
- */
-
-package de.bixilon.minosoft.modding;
-
-import de.bixilon.minosoft.Config;
-
-import java.io.File;
-
-public class ModLoader {
- ModPhases currentPhase;
-
- public static void loadMods() {
- // load all jars, parse the mod.json
- // sort the list and prioritize
- // load all lists and dependencies async
- File[] files = new File(Config.homeDir + "mods").listFiles();
- if (files == null) {
- // no mods to load
- return;
- }
- for (File modFile : files) {
-
- }
- }
-}
diff --git a/src/main/java/de/bixilon/minosoft/modding/loading/ModInfo.java b/src/main/java/de/bixilon/minosoft/modding/loading/ModInfo.java
index c7f68176c..fa9b766d7 100644
--- a/src/main/java/de/bixilon/minosoft/modding/loading/ModInfo.java
+++ b/src/main/java/de/bixilon/minosoft/modding/loading/ModInfo.java
@@ -28,7 +28,7 @@ public class ModInfo {
final String[] authors;
final String identifier;
final String mainClass;
- LoadingInfo info;
+ LoadingInfo loadingInfo;
public ModInfo(JsonObject json) {
this.uuid = Util.uuidFromString(json.get("uuid").getAsString());
@@ -46,9 +46,9 @@ public class ModInfo {
this.mainClass = json.get("mainClass").getAsString();
if (json.has("loading")) {
JsonObject loading = json.getAsJsonObject("loading");
- this.info = new LoadingInfo();
+ this.loadingInfo = new LoadingInfo();
if (loading.has("priority")) {
- this.info.setLoadingPriority(LoadingPriorities.valueOf(loading.get("priority").getAsString()));
+ this.loadingInfo.setLoadingPriority(LoadingPriorities.valueOf(loading.get("priority").getAsString()));
}
}
}
@@ -81,7 +81,32 @@ public class ModInfo {
return mainClass;
}
- public LoadingInfo getInfo() {
- return info;
+ public LoadingInfo getLoadingInfo() {
+ return loadingInfo;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("name=\"%s\", uuid=%s, versionName=\"%s\", versionId=%d", getName(), getUUID(), getVersionName(), getVersionId());
+ }
+
+ @Override
+ public int hashCode() {
+ return uuid.hashCode() * versionId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this.hashCode() != obj.hashCode()) {
+ return false;
+ }
+ if (super.equals(obj)) {
+ return true;
+ }
+ ModInfo their = (ModInfo) obj;
+ return getUUID().equals(their.getUUID()) && getVersionId() == their.getVersionId();
}
}
diff --git a/src/main/java/de/bixilon/minosoft/modding/loading/ModLoader.java b/src/main/java/de/bixilon/minosoft/modding/loading/ModLoader.java
new file mode 100644
index 000000000..505c7a491
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/modding/loading/ModLoader.java
@@ -0,0 +1,87 @@
+/*
+ * Codename Minosoft
+ * Copyright (C) 2020 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.modding.loading;
+
+import de.bixilon.minosoft.Config;
+import de.bixilon.minosoft.logging.Log;
+import de.bixilon.minosoft.modding.MinosoftMod;
+import de.bixilon.minosoft.util.Util;
+import org.xeustechnologies.jcl.JarClassLoader;
+import org.xeustechnologies.jcl.JclObjectFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.TreeMap;
+import java.util.zip.ZipFile;
+
+public class ModLoader {
+ static TreeMap modMap;
+
+ ModPhases currentPhase;
+
+ public static void loadMods() {
+ modMap = new TreeMap<>((a, b) -> {
+ LoadingPriorities priorityA = getLoadingPriorityOrDefault(a);
+ LoadingPriorities priorityB = getLoadingPriorityOrDefault(b);
+ return -(priorityA.ordinal() - priorityB.ordinal());
+ });
+ // load all jars, parse the mod.json
+ // sort the list and prioritize
+ // load all lists and dependencies async
+ File[] files = new File(Config.homeDir + "mods").listFiles();
+ if (files == null) {
+ // no mods to load
+ return;
+ }
+ for (File modFile : files) {
+ if (modFile.isDirectory()) {
+ continue;
+ }
+ try {
+ Log.verbose(String.format("[MOD] Loading file %s", modFile.getAbsolutePath()));
+ ZipFile zipFile = new ZipFile(modFile);
+ ModInfo modInfo = new ModInfo(Util.readJsonFromZip("mod.json", zipFile));
+ if (modMap.containsKey(modInfo)) {
+ Log.warn(String.format("Mod %s:%d (uuid=%s) is loaded multiple times! Skipping", modInfo.getName(), modInfo.getVersionId(), modInfo.getUUID()));
+ continue;
+ }
+ JarClassLoader jcl = new JarClassLoader();
+ jcl.add(modFile.getAbsolutePath());
+ JclObjectFactory factory = JclObjectFactory.getInstance();
+
+ MinosoftMod instance = (MinosoftMod) factory.create(jcl, modInfo.getMainClass());
+ Log.verbose(String.format("[MOD] Mod file loaded (%s)", modInfo));
+ modMap.put(modInfo, instance);
+ zipFile.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.warn(String.format("Could not load mod: %s", modFile.getAbsolutePath()));
+ }
+ }
+
+ for (ModPhases phase : ModPhases.values()) {
+ Log.verbose(String.format("Map loading phase changed: %s", phase));
+ modMap.forEach((modInfo, instance) -> {
+ instance.start(phase);
+ });
+ }
+ }
+
+ private static LoadingPriorities getLoadingPriorityOrDefault(ModInfo info) {
+ if (info.getLoadingInfo() != null && info.getLoadingInfo().getLoadingPriority() != null) {
+ return info.getLoadingInfo().getLoadingPriority();
+ }
+ return LoadingPriorities.NORMAL;
+ }
+}