From 16f07b7e3b3a66bb053c261d53e787eb7930fd11 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sat, 26 Sep 2020 23:21:36 +0200 Subject: [PATCH] wip modding (3) --- pom.xml | 5 ++ .../java/de/bixilon/minosoft/Minosoft.java | 4 + .../objectLoader/recipes/Ingredient.java | 3 + .../modding/{loading => }/MinosoftMod.java | 4 +- .../bixilon/minosoft/modding/ModLoader.java | 36 -------- .../minosoft/modding/loading/ModInfo.java | 35 ++++++-- .../minosoft/modding/loading/ModLoader.java | 87 +++++++++++++++++++ 7 files changed, 132 insertions(+), 42 deletions(-) rename src/main/java/de/bixilon/minosoft/modding/{loading => }/MinosoftMod.java (90%) delete mode 100644 src/main/java/de/bixilon/minosoft/modding/ModLoader.java create mode 100644 src/main/java/de/bixilon/minosoft/modding/loading/ModLoader.java 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; + } +}