From 90a20aae83a71536d6749850fa1222fcaa539547 Mon Sep 17 00:00:00 2001
From: Owain van Brakel <owain.vanbrakel@gmail.com>
Date: Tue, 11 Feb 2020 03:29:04 +0100
Subject: [PATCH 1/3] external: Silence pf4j

---
 runelite-client/src/main/resources/logback.xml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/runelite-client/src/main/resources/logback.xml b/runelite-client/src/main/resources/logback.xml
index 3942b92ca50..f283650cac7 100644
--- a/runelite-client/src/main/resources/logback.xml
+++ b/runelite-client/src/main/resources/logback.xml
@@ -55,4 +55,6 @@
 		<appender-ref ref="STDOUT"/>
 		<appender-ref ref="FILE"/>
 	</root>
+
+	<logger name="org.pf4j.AbstractPluginManager" level="OFF"/>
 </configuration>
\ No newline at end of file

From 3ac70f5fe60fb17eb0cc4c57cc275e5a88514982 Mon Sep 17 00:00:00 2001
From: Owain van Brakel <owain.vanbrakel@gmail.com>
Date: Tue, 11 Feb 2020 03:29:32 +0100
Subject: [PATCH 2/3] external: Install missing dependencies on startup instead
 of crashing

---
 .../java/net/runelite/client/RuneLite.java    |  2 +-
 .../client/plugins/ExternalPluginManager.java | 77 ++++++++++++++++++-
 2 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java
index fe2a9f41c2a..70d0df5a9ff 100644
--- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java
+++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java
@@ -372,6 +372,7 @@ private void start() throws Exception
 		pluginManager.loadCorePlugins();
 
 		// Load external plugins
+		externalPluginManager.startExternalUpdateManager();
 		externalPluginManager.startExternalPluginManager();
 
 		RuneLiteSplashScreen.stage(.75, "Finalizing configuration");
@@ -380,7 +381,6 @@ private void start() throws Exception
 		// to main settings
 		pluginManager.loadDefaultPluginConfiguration();
 
-		externalPluginManager.startExternalUpdateManager();
 
 		RuneLiteSplashScreen.stage(.77, "Updating external plugins");
 		externalPluginManager.update();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/ExternalPluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/ExternalPluginManager.java
index a9217678cb2..b59f1819594 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/ExternalPluginManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/ExternalPluginManager.java
@@ -9,6 +9,7 @@
 import java.lang.reflect.InvocationTargetException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -41,10 +42,12 @@
 import org.pf4j.JarPluginLoader;
 import org.pf4j.JarPluginRepository;
 import org.pf4j.ManifestPluginDescriptorFinder;
+import org.pf4j.PluginAlreadyLoadedException;
 import org.pf4j.PluginDependency;
 import org.pf4j.PluginDescriptorFinder;
 import org.pf4j.PluginLoader;
 import org.pf4j.PluginRepository;
+import org.pf4j.PluginRuntimeException;
 import org.pf4j.PluginWrapper;
 import org.pf4j.RuntimeMode;
 import org.pf4j.update.DefaultUpdateRepository;
@@ -112,6 +115,55 @@ public RuntimeMode getRuntimeMode()
 			{
 				return debug ? RuntimeMode.DEVELOPMENT : RuntimeMode.DEPLOYMENT;
 			}
+
+			@Override
+			public void loadPlugins()
+			{
+				if (Files.notExists(pluginsRoot) || !Files.isDirectory(pluginsRoot))
+				{
+					log.warn("No '{}' root", pluginsRoot);
+					return;
+				}
+
+				List<Path> pluginPaths = pluginRepository.getPluginPaths();
+
+				if (pluginPaths.isEmpty())
+				{
+					log.info("No plugins");
+					return;
+				}
+
+				log.debug("Found {} possible plugins: {}", pluginPaths.size(), pluginPaths);
+
+				for (Path pluginPath : pluginPaths)
+				{
+					try
+					{
+						loadPluginFromPath(pluginPath);
+					}
+					catch (PluginRuntimeException e)
+					{
+						if (!(e instanceof PluginAlreadyLoadedException))
+						{
+							log.error(e.getMessage(), e);
+						}
+					}
+				}
+
+				try
+				{
+					resolvePlugins();
+				}
+				catch (PluginRuntimeException e)
+				{
+					if (e instanceof DependencyResolver.DependenciesNotFoundException)
+					{
+						throw e;
+					}
+
+					log.error(e.getMessage(), e);
+				}
+			}
 		};
 		this.externalPluginManager.setSystemVersion(SYSTEM_VERSION);
 	}
@@ -145,7 +197,30 @@ public static <T> Predicate<T> not(Predicate<T> t)
 
 	public void startExternalPluginManager()
 	{
-		this.externalPluginManager.loadPlugins();
+		try
+		{
+			this.externalPluginManager.loadPlugins();
+		}
+		catch (Exception ex)
+		{
+			if (ex instanceof DependencyResolver.DependenciesNotFoundException)
+			{
+				List<String> deps = ((DependencyResolver.DependenciesNotFoundException) ex).getDependencies();
+
+				log.error("The following dependencies are missing: {}", deps);
+
+				for (String dep : ((DependencyResolver.DependenciesNotFoundException) ex).getDependencies())
+				{
+					install(dep);
+				}
+
+				startExternalPluginManager();
+			}
+
+			log.error("{}", ex.getMessage());
+		}
+
+		log.info(String.valueOf(externalPluginManager.getResolvedPlugins()));
 	}
 
 	public void startExternalUpdateManager()

From 7742e61360fe41fff5ceaa58aacdf398468ab7fd Mon Sep 17 00:00:00 2001
From: Owain van Brakel <owain.vanbrakel@gmail.com>
Date: Tue, 11 Feb 2020 03:30:09 +0100
Subject: [PATCH 3/3] external: Don't crash when another client has a lock on a
 jar

---
 .../client/plugins/ExternalPluginManager.java     | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/ExternalPluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/ExternalPluginManager.java
index b59f1819594..e6a40bcb514 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/ExternalPluginManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/ExternalPluginManager.java
@@ -209,7 +209,7 @@ public void startExternalPluginManager()
 
 				log.error("The following dependencies are missing: {}", deps);
 
-				for (String dep : ((DependencyResolver.DependenciesNotFoundException) ex).getDependencies())
+				for (String dep : deps)
 				{
 					install(dep);
 				}
@@ -557,11 +557,18 @@ public void update()
 			{
 				PluginInfo.PluginRelease lastRelease = updateManager.getLastPluginRelease(plugin.id);
 				String lastVersion = lastRelease.version;
-				boolean updated = updateManager.updatePlugin(plugin.id, lastVersion);
+				try
+				{
+					boolean updated = updateManager.updatePlugin(plugin.id, lastVersion);
 
-				if (!updated)
+					if (!updated)
+					{
+						log.warn("Cannot update plugin '{}'", plugin.id);
+					}
+				}
+				catch (PluginRuntimeException ex)
 				{
-					log.warn("Cannot update plugin '{}'", plugin.id);
+					log.warn("Cannot update plugin '{}', the user probably has another client open", plugin.id);
 				}
 			}
 		}