mirror of
https://github.com/FalsePattern/FalsePatternLib.git
synced 2026-11-12 00:17:49 +00:00
feat: Support deploading non-coremods without restarting the game
This commit is contained in:
5 files changed
+100
-9
No files matched your search
+1
-1
@@ -5,7 +5,7 @@ plugins {
|
||||
group = "com.falsepattern"
|
||||
|
||||
//bump this after ANY change to the deploader!
|
||||
val deploaderVersion = 2
|
||||
val deploaderVersion = 3
|
||||
|
||||
minecraft_fp {
|
||||
java {
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.falsepattern.deploader.version.RawVersion;
|
||||
import com.falsepattern.deploader.version.SemanticVersion;
|
||||
import com.falsepattern.deploader.version.Version;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.netty.util.internal.ConcurrentSet;
|
||||
import lombok.NonNull;
|
||||
@@ -41,6 +42,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import cpw.mods.fml.common.MetadataCollection;
|
||||
import cpw.mods.fml.common.ModMetadata;
|
||||
import cpw.mods.fml.fpdeploader.SystemExitBypassHelper;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
@@ -81,6 +83,7 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -123,7 +126,7 @@ public class DependencyLoaderImpl {
|
||||
metadataCollectionModListAccessor.setAccessible(true);
|
||||
}
|
||||
|
||||
private static AtomicBoolean modDownloaded = new AtomicBoolean(false);
|
||||
private static AtomicBoolean needReboot = new AtomicBoolean(false);
|
||||
|
||||
private static void ensureExists(Path directory) {
|
||||
if (!Files.exists(directory)) {
|
||||
@@ -464,17 +467,17 @@ public class DependencyLoaderImpl {
|
||||
baseTasks.addAll(tasks);
|
||||
tasks = executeArtifactLoading(baseTasks, false);
|
||||
}
|
||||
if (modDownloaded.get()) {
|
||||
if (needReboot.get()) {
|
||||
val msg = "One or more minecraft mods which have been loaded by the FP DepLoader require a game restart to fully install.";
|
||||
if (!SystemUtils.IS_OS_MAC) {
|
||||
try {
|
||||
JOptionPane.showMessageDialog(null, "A minecraft mod has been downloaded by the FalsePatternLib dependency downloader.\nYou must restart the game to apply these changes.", "Mod Dependency Download notice", JOptionPane.WARNING_MESSAGE);
|
||||
JOptionPane.showMessageDialog(null, msg + "\nThe game will exit when you close this prompt.", "Mod Dependency Download notice", JOptionPane.WARNING_MESSAGE);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
val msg = "A minecraft mod has been downloaded by the FalsePatternLib dependency downloader, and requires a game restart to get installed properly.";
|
||||
for (int i = 0; i < 16; i++) {
|
||||
LOG.warn(msg);
|
||||
}
|
||||
System.exit(0);
|
||||
SystemExitBypassHelper.exit();
|
||||
throw new ModDependencyDownloaded(msg);
|
||||
}
|
||||
}
|
||||
@@ -1113,7 +1116,7 @@ public class DependencyLoaderImpl {
|
||||
Files.delete(tmpFile);
|
||||
} else {
|
||||
if (isMod) {
|
||||
modDownloaded.set(true);
|
||||
detectModReloadRequirement(tmpFile);
|
||||
}
|
||||
try {
|
||||
Files.move(tmpFile, file, StandardCopyOption.ATOMIC_MOVE);
|
||||
@@ -1154,6 +1157,60 @@ public class DependencyLoaderImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private void detectModReloadRequirement(Path file) {
|
||||
if (needReboot.get())
|
||||
return;
|
||||
try (val jar = new JarFile(file.toFile())) {
|
||||
if (LowLevelCallMultiplexer.rfbDetected) {
|
||||
//Detect RFB plugins
|
||||
val entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
val entry = entries.nextElement();
|
||||
if (entry.getName().contains("META-INF/rfb-plugin")) {
|
||||
needReboot.set(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
//Detect coremods
|
||||
val manifest = jar.getManifest().getMainAttributes();
|
||||
val isCoreMod = manifest.getValue("TweakClass") != null || manifest.getValue("FMLCorePlugin") != null;
|
||||
if (isCoreMod) {
|
||||
needReboot.set(true);
|
||||
return;
|
||||
}
|
||||
//Detect mixins
|
||||
val entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
val entry = entries.nextElement();
|
||||
val name = entry.getName();
|
||||
if (name.contains("META-INF/rfb-plugin")) {
|
||||
needReboot.set(true);
|
||||
return;
|
||||
}
|
||||
if (!name.endsWith(".json")) {
|
||||
continue;
|
||||
}
|
||||
val data = jar.getInputStream(entry);
|
||||
val gson = new GsonBuilder().create();
|
||||
val element = gson.fromJson(new InputStreamReader(data), JsonElement.class);
|
||||
if (!element.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
val obj = element.getAsJsonObject();
|
||||
if (obj.has("refmap") || obj.has("compatibilityLevel") || obj.has("target")) {
|
||||
//Most likely contains mixins, better safe than sorry
|
||||
needReboot.set(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//bail out safely
|
||||
needReboot.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
private ChecksumStatus validateChecksum(String url) throws IOException {
|
||||
for (val checksumType : CHECKSUM_TYPES) {
|
||||
val checksumURL = url + "." + checksumType;
|
||||
|
||||
@@ -37,7 +37,7 @@ import java.util.List;
|
||||
|
||||
@UtilityClass
|
||||
public class LowLevelCallMultiplexer {
|
||||
private static boolean rfbDetected = false;
|
||||
public static boolean rfbDetected = false;
|
||||
public static void rfbDetected() {
|
||||
rfbDetected = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of FalsePatternLib.
|
||||
*
|
||||
* Copyright (C) 2022-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* FalsePatternLib is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* FalsePatternLib 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with FalsePatternLib. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package cpw.mods.fml.fpdeploader;
|
||||
|
||||
public class SystemExitBypassHelper {
|
||||
public static void exit() {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,8 @@ public final class DeploaderStub {
|
||||
if (rfb) {
|
||||
rfbDetected = true;
|
||||
RFBUtil.preinit();
|
||||
} else {
|
||||
LaunchWrapperUtil.preinit();
|
||||
}
|
||||
Object deploader = Launch.blackboard.get(BLACKBOARD_MARKER);
|
||||
if (deploader != null) {
|
||||
@@ -203,7 +205,7 @@ public final class DeploaderStub {
|
||||
try {
|
||||
Method exc = loader.getClass()
|
||||
.getDeclaredMethod("addClassLoaderExclusion", String.class);
|
||||
exc.invoke(loader, "com_falsepattern_deploader_".replace("_", "."));
|
||||
exc.invoke(loader, "com_falsepattern_deploader_".replace('_', '.'));
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
@@ -221,6 +223,9 @@ public final class DeploaderStub {
|
||||
}
|
||||
|
||||
private static class LaunchWrapperUtil {
|
||||
static void preinit() {
|
||||
Launch.classLoader.addTransformerExclusion("com_falsepattern_deploader_".replace('_', '.'));
|
||||
}
|
||||
static Path gameDir() {
|
||||
return Launch.minecraftHome == null ? Paths.get(".") : Launch.minecraftHome.toPath();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user