Add ability to disable/enable all plugins

Add ability to fully disable and enable each plugin. Fully disabling
plugin means removing it from scheduler and eventBus and fully stopping
it. That improves performance, because it basically removes overhead of
any plugin that is disabled.

Fixes: #280

Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
This commit is contained in:
Tomas Slusny
2018-01-10 19:11:17 +01:00
parent 635ec89c91
commit c3fae86356
10 changed files with 182 additions and 89 deletions

View File

@@ -151,7 +151,7 @@ public class RuneLite
// Initialize Discord service
discordService.init();
// Load default configuration
// Load user configuration
configManager.load();
// Register event listeners
@@ -159,6 +159,7 @@ public class RuneLite
eventBus.register(menuManager);
eventBus.register(chatMessageManager);
eventBus.register(gui);
eventBus.register(pluginManager);
// Setup the notifier
notifier = new Notifier(properties.getTitle(), gui.getTrayIcon());
@@ -172,7 +173,7 @@ public class RuneLite
// Plugins have provided their config, so set default config
// to main settings
configManager.loadDefault();
pluginManager.loadDefaultPluginConfiguration();
// Start plugins
pluginManager.startCorePlugins();

View File

@@ -41,10 +41,10 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite;
import net.runelite.client.config.ConfigManager;
import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.client.RuneLite;
import net.runelite.client.config.ConfigManager;
import net.runelite.http.api.account.AccountClient;
import net.runelite.http.api.account.OAuthResponse;
import net.runelite.http.api.ws.messages.LoginResponse;
@@ -261,4 +261,4 @@ public class SessionManager
closeSession();
deleteSession();
}
}
}

View File

@@ -26,5 +26,4 @@ package net.runelite.client.config;
public interface Config
{
}

View File

@@ -25,8 +25,6 @@
package net.runelite.client.config;
import com.google.common.eventbus.EventBus;
import com.google.inject.Injector;
import com.google.inject.Key;
import java.awt.Color;
import java.awt.Dimension;
import java.io.File;
@@ -37,8 +35,8 @@ import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ScheduledExecutorService;
@@ -46,10 +44,9 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.ConfigChanged;
import net.runelite.client.RuneLite;
import net.runelite.client.account.AccountSession;
import net.runelite.api.events.ConfigChanged;
import net.runelite.client.plugins.PluginManager;
import net.runelite.http.api.config.ConfigClient;
import net.runelite.http.api.config.ConfigEntry;
import net.runelite.http.api.config.Configuration;
@@ -66,9 +63,6 @@ public class ConfigManager
@Inject
ScheduledExecutorService executor;
@Inject
PluginManager pluginManager;
private AccountSession session;
private ConfigClient client;
private File propertiesFile;
@@ -81,42 +75,6 @@ public class ConfigManager
this.propertiesFile = getPropertiesFile();
}
public ConfigManager(EventBus eventBus, AccountSession session)
{
this.eventBus = eventBus;
switchSession(session);
}
public List<Config> getConfigProxies()
{
List<Injector> injectors = new ArrayList<>();
injectors.add(RuneLite.getInjector());
pluginManager.getPlugins().forEach(pl -> injectors.add(pl.getInjector()));
List<Config> list = new ArrayList<>();
for (Injector injector : injectors)
{
for (Key<?> key : injector.getAllBindings().keySet())
{
Class<?> type = key.getTypeLiteral().getRawType();
if (Config.class.isAssignableFrom(type))
{
Config config = (Config) injector.getInstance(key);
list.add(config);
}
}
}
return list;
}
public void loadDefault()
{
for (Object config : getConfigProxies())
{
setDefaultConfiguration(config, false);
}
}
public final void switchSession(AccountSession session)
{
if (session == null)
@@ -133,7 +91,6 @@ public class ConfigManager
this.propertiesFile = getPropertiesFile();
load(); // load profile specific config
loadDefault(); // set defaults over anything not set
}
private File getPropertiesFile()
@@ -183,8 +140,18 @@ public class ConfigManager
for (ConfigEntry entry : configuration.getConfig())
{
log.debug("Loading configuration value from client {}: {}", entry.getKey(), entry.getValue());
final String[] split = entry.getKey().split("\\.");
final String groupName = split[0];
final String key = split[1];
final String value = entry.getValue();
final String oldValue = (String) properties.setProperty(entry.getKey(), value);
properties.setProperty(entry.getKey(), entry.getValue());
ConfigChanged configChanged = new ConfigChanged();
configChanged.setGroup(groupName);
configChanged.setKey(key);
configChanged.setOldValue(oldValue);
configChanged.setNewValue(value);
eventBus.post(configChanged);
}
try
@@ -343,16 +310,11 @@ public class ConfigManager
List<ConfigItemDescriptor> items = Arrays.stream(inter.getMethods())
.filter(m -> m.getParameterCount() == 0)
.sorted((m1, m2)
-> Integer.compare(
m1.getDeclaredAnnotation(ConfigItem.class).position(),
m2.getDeclaredAnnotation(ConfigItem.class).position()
)
)
.sorted(Comparator.comparingInt(m -> m.getDeclaredAnnotation(ConfigItem.class).position()))
.map(m -> new ConfigItemDescriptor(
m.getDeclaredAnnotation(ConfigItem.class),
m.getReturnType()
))
m.getDeclaredAnnotation(ConfigItem.class),
m.getReturnType()
))
.collect(Collectors.toList());
return new ConfigDescriptor(group, items);
}

View File

@@ -37,6 +37,8 @@ public @interface PluginDescriptor
{
String name();
boolean enabledByDefault() default true;
boolean developerPlugin() default false;
boolean loadWhenOutdated() default false;

View File

@@ -26,12 +26,14 @@ package net.runelite.client.plugins;
import com.google.common.collect.ImmutableSet;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
import com.google.inject.Binder;
import com.google.inject.CreationException;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@@ -40,11 +42,18 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Singleton;
import javax.swing.SwingUtilities;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.client.RuneLite;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.events.PluginChanged;
import net.runelite.client.task.Schedule;
import net.runelite.client.task.ScheduledMethod;
@@ -65,10 +74,94 @@ public class PluginManager
@Inject
Scheduler scheduler;
@Inject
ConfigManager configManager;
@Inject
ScheduledExecutorService executor;
@Setter
boolean isOutdated;
private final List<Plugin> plugins = new CopyOnWriteArrayList<>();
private final List<Plugin> activePlugins = new CopyOnWriteArrayList<>();
private final String runeliteGroupName = RuneLiteConfig.class
.getAnnotation(ConfigGroup.class).keyName();
@Subscribe
public void onSessionOpen(SessionOpen event)
{
refreshPlugins();
}
@Subscribe
public void onSessionClose(SessionClose event)
{
refreshPlugins();
}
private void refreshPlugins()
{
loadDefaultPluginConfiguration();
getPlugins()
.forEach(plugin -> executor.submit(() ->
{
try
{
if (!startPlugin(plugin))
{
stopPlugin(plugin);
}
}
catch (PluginInstantiationException e)
{
log.warn("Error during starting/stopping plugin {}. {}", plugin.getClass().getSimpleName(), e);
}
}));
}
public List<Config> getPluginConfigProxies()
{
List<Injector> injectors = new ArrayList<>();
injectors.add(RuneLite.getInjector());
getPlugins().forEach(pl -> injectors.add(pl.getInjector()));
List<Config> list = new ArrayList<>();
for (Injector injector : injectors)
{
for (Key<?> key : injector.getAllBindings().keySet())
{
Class<?> type = key.getTypeLiteral().getRawType();
if (Config.class.isAssignableFrom(type))
{
Config config = (Config) injector.getInstance(key);
list.add(config);
}
}
}
return list;
}
public void loadDefaultPluginConfiguration()
{
for (Object config : getPluginConfigProxies())
{
configManager.setDefaultConfiguration(config, false);
}
for (Plugin plugin : getPlugins())
{
final String keyName = plugin.getClass().getSimpleName().toLowerCase();
final String value = configManager.getConfiguration(runeliteGroupName, keyName);
if (value == null)
{
final PluginDescriptor pluginDescriptor = plugin.getClass().getAnnotation(PluginDescriptor.class);
final boolean enabled = pluginDescriptor == null || pluginDescriptor.enabledByDefault();
configManager.setConfiguration(runeliteGroupName, keyName, String.valueOf(enabled));
}
}
}
public void loadCorePlugins() throws IOException
{
@@ -86,7 +179,7 @@ public class PluginManager
}
catch (PluginInstantiationException ex)
{
log.warn("Unable to start plugin {}", plugin.getClass().getSimpleName(), ex);
log.warn("Unable to start plugin {}. {}", plugin.getClass().getSimpleName(), ex);
plugins.remove(plugin);
}
}
@@ -136,11 +229,11 @@ public class PluginManager
Plugin plugin;
try
{
plugin = instantiate(pluginDescriptor, (Class<Plugin>) clazz);
plugin = instantiate((Class<Plugin>) clazz);
}
catch (PluginInstantiationException ex)
{
log.warn("error instantiating plugin!", ex);
log.warn("Error instantiating plugin!", ex);
continue;
}
@@ -150,8 +243,15 @@ public class PluginManager
return scannedPlugins;
}
void startPlugin(Plugin plugin) throws PluginInstantiationException
public synchronized boolean startPlugin(Plugin plugin) throws PluginInstantiationException
{
if (activePlugins.contains(plugin) || !isPluginEnabled(plugin))
{
return false;
}
activePlugins.add(plugin);
try
{
// plugins always start in the event thread
@@ -169,22 +269,30 @@ public class PluginManager
log.debug("Plugin {} is now running", plugin.getClass().getSimpleName());
eventBus.register(plugin);
eventBus.post(new PluginChanged(plugin, true));
schedule(plugin);
eventBus.post(new PluginChanged(plugin, true));
}
catch (InterruptedException | InvocationTargetException ex)
{
throw new PluginInstantiationException(ex);
}
return true;
}
void stopPlugin(Plugin plugin) throws PluginInstantiationException
public synchronized boolean stopPlugin(Plugin plugin) throws PluginInstantiationException
{
if (!activePlugins.contains(plugin) || isPluginEnabled(plugin))
{
return false;
}
activePlugins.remove(plugin);
try
{
unschedule(plugin);
eventBus.unregister(plugin);
eventBus.post(new PluginChanged(plugin, false));
// plugins always stop in the event thread
SwingUtilities.invokeAndWait(() ->
@@ -199,19 +307,37 @@ public class PluginManager
}
});
log.debug("Plugin {} is now stopped", plugin.getClass().getSimpleName());
eventBus.post(new PluginChanged(plugin, false));
}
catch (InterruptedException | InvocationTargetException ex)
{
throw new PluginInstantiationException(ex);
}
return true;
}
Plugin instantiate(PluginDescriptor pluginDescriptor, Class<Plugin> clazz) throws PluginInstantiationException
public void setPluginEnabled(Plugin plugin, boolean enabled)
{
final String keyName = plugin.getClass().getSimpleName().toLowerCase();
configManager.setConfiguration(runeliteGroupName, keyName, String.valueOf(enabled));
}
public boolean isPluginEnabled(Plugin plugin)
{
final String keyName = plugin.getClass().getSimpleName().toLowerCase();
final String value = configManager.getConfiguration(runeliteGroupName, keyName);
return Boolean.valueOf(value);
}
private Plugin instantiate(Class<Plugin> clazz) throws PluginInstantiationException
{
Plugin plugin;
try
{
plugin = (Plugin) clazz.newInstance();
plugin = clazz.newInstance();
}
catch (InstantiationException | IllegalAccessException ex)
{
@@ -222,7 +348,7 @@ public class PluginManager
{
Module pluginModule = (Binder binder) ->
{
binder.bind((Class<Plugin>) clazz).toInstance(plugin);
binder.bind(clazz).toInstance(plugin);
binder.install(plugin);
};
Injector pluginInjector = RuneLite.getInjector().createChildInjector(pluginModule);
@@ -234,7 +360,7 @@ public class PluginManager
throw new PluginInstantiationException(ex);
}
log.debug("Loaded plugin {}", pluginDescriptor.name());
log.debug("Loaded plugin {}", clazz.getSimpleName());
return plugin;
}

View File

@@ -66,6 +66,7 @@ import net.runelite.client.config.ConfigDescriptor;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigItemDescriptor;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.plugins.PluginManager;
import net.runelite.client.ui.PluginPanel;
@Slf4j
@@ -74,14 +75,16 @@ public class ConfigPanel extends PluginPanel
private static final int TEXT_FIELD_WIDTH = 7;
private static final int SPINNER_FIELD_WIDTH = 6;
private final PluginManager pluginManager;
private final ConfigManager configManager;
private final JTextField searchBar = new JTextField();
private Map<String, JPanel> children = new TreeMap<>();
private int scrollBarPosition = 0;
public ConfigPanel(ConfigManager configManager)
public ConfigPanel(PluginManager pluginManager, ConfigManager configManager)
{
super();
this.pluginManager = pluginManager;
this.configManager = configManager;
searchBar.getDocument().addDocumentListener(new DocumentListener()
@@ -112,7 +115,7 @@ public class ConfigPanel extends PluginPanel
final void rebuildPluginList()
{
Map<String, JPanel> newChildren = new TreeMap<>();
configManager.getConfigProxies()
pluginManager.getPluginConfigProxies()
.stream()
// Convert config proxies to pair of config descriptors and config proxies
.map(c -> new AbstractMap.SimpleEntry<>(configManager.getConfigDescriptor(c), c))

View File

@@ -32,6 +32,7 @@ import net.runelite.client.config.ConfigManager;
import net.runelite.client.events.PluginChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginManager;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton;
@@ -47,13 +48,16 @@ public class ConfigPlugin extends Plugin
@Inject
private ConfigManager configManager;
@Inject
PluginManager pluginManager;
private ConfigPanel configPanel;
private NavigationButton navButton;
@Override
protected void startUp() throws Exception
{
configPanel = new ConfigPanel(configManager);
configPanel = new ConfigPanel(pluginManager, configManager);
navButton = new NavigationButton(
"Configuration",

View File

@@ -59,6 +59,7 @@ public class PluginToolbar extends JToolBar
buttons.add(button);
add(button);
revalidate();
repaint();
}
public void removeNavigation(NavigationButton button)
@@ -66,6 +67,7 @@ public class PluginToolbar extends JToolBar
buttons.remove(button);
remove(button);
revalidate();
repaint();
}
private void onClick(NavigationButton button)

View File

@@ -32,9 +32,10 @@ import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -44,11 +45,11 @@ import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ResizeableChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.events.PluginChanged;
import net.runelite.api.events.ResizeableChanged;
import net.runelite.client.plugins.PluginManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxOverlay;
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
@@ -75,7 +76,7 @@ public class OverlayRenderer
@Inject
TooltipOverlay tooltipOverlay;
private final List<Overlay> overlays = new ArrayList<>();
private final List<Overlay> overlays = new CopyOnWriteArrayList<>();
private BufferedImage surface;
private Graphics2D surfaceGraphics;
@@ -107,16 +108,7 @@ public class OverlayRenderer
@Subscribe
public void onPluginChanged(PluginChanged event)
{
if (event.isLoaded())
{
overlays.addAll(event.getPlugin().getOverlays());
}
else
{
overlays.removeAll(event.getPlugin().getOverlays());
}
sortOverlays(overlays);
refreshPlugins();
}
private void refreshPlugins()
@@ -126,8 +118,10 @@ public class OverlayRenderer
.concat(
pluginManager.getPlugins()
.stream()
.filter(plugin -> pluginManager.isPluginEnabled(plugin))
.flatMap(plugin -> plugin.getOverlays().stream()),
Stream.of(infoBoxOverlay, tooltipOverlay))
.filter(Objects::nonNull)
.collect(Collectors.toList()));
sortOverlays(overlays);
}