runelite-client: use guava service manager for plugins

Seems more robust and the whole client doesn't break if one plugin fails
This commit is contained in:
Adam
2017-04-21 22:37:02 -04:00
parent 345d197171
commit 23dabe982c
11 changed files with 147 additions and 67 deletions

View File

@@ -25,9 +25,13 @@
package net.runelite.client.plugins; package net.runelite.client.plugins;
import com.google.common.util.concurrent.AbstractIdleService;
import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.Overlay;
public abstract class Plugin public abstract class Plugin extends AbstractIdleService
{ {
public abstract Overlay getOverlay(); public Overlay getOverlay()
{
return null;
}
} }

View File

@@ -24,9 +24,13 @@
*/ */
package net.runelite.client.plugins; package net.runelite.client.plugins;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Service;
import com.google.common.util.concurrent.ServiceManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import net.runelite.client.RuneLite; import net.runelite.client.RuneLite;
import net.runelite.client.plugins.boosts.Boosts; import net.runelite.client.plugins.boosts.Boosts;
import net.runelite.client.plugins.bosstimer.BossTimers; import net.runelite.client.plugins.bosstimer.BossTimers;
@@ -45,7 +49,7 @@ public class PluginManager
private static final Logger logger = LoggerFactory.getLogger(PluginManager.class); private static final Logger logger = LoggerFactory.getLogger(PluginManager.class);
private final RuneLite runelite; private final RuneLite runelite;
private final List<Plugin> plugins = new ArrayList<>(); private ServiceManager manager;
public PluginManager(RuneLite runelite) public PluginManager(RuneLite runelite)
{ {
@@ -54,30 +58,67 @@ public class PluginManager
public void loadAll() public void loadAll()
{ {
load(new Boosts()); List<Plugin> plugins = new ArrayList<>();
load(new OpponentInfo()); plugins.add(new Boosts());
load(new FPS()); plugins.add(new OpponentInfo());
load(new Hiscore()); plugins.add(new FPS());
load(new BossTimers()); plugins.add(new Hiscore());
load(new Xtea()); plugins.add(new BossTimers());
load(new IdleNotifier()); plugins.add(new Xtea());
load(new Runecraft()); plugins.add(new IdleNotifier());
plugins.add(new Runecraft());
if (RuneLite.getOptions().has("developer-mode")) if (RuneLite.getOptions().has("developer-mode"))
{ {
logger.info("Loading developer plugins"); logger.info("Loading developer plugins");
load(new DevTools()); plugins.add(new DevTools());
} }
}
private void load(Plugin plugin) // Add plugin listeners
{ for (Plugin plugin : plugins)
plugins.add(plugin); {
runelite.getEventBus().register(plugin); Service.Listener listener = new Service.Listener()
{
@Override
public void running()
{
logger.debug("Plugin {} is now running", plugin);
runelite.getEventBus().register(plugin);
}
@Override
public void stopping(Service.State from)
{
logger.debug("Plugin {} is stopping", plugin);
runelite.getEventBus().unregister(logger);
}
@Override
public void failed(Service.State from, Throwable failure)
{
logger.warn("Plugin {} has failed", plugin, failure);
if (from == Service.State.RUNNING)
{
runelite.getEventBus().unregister(logger);
}
}
};
plugin.addListener(listener, MoreExecutors.directExecutor());
}
manager = new ServiceManager(plugins);
logger.debug("Starting plugins...");
manager.startAsync();
} }
public Collection<Plugin> getPlugins() public Collection<Plugin> getPlugins()
{ {
return plugins; return manager.servicesByState().get(Service.State.RUNNING)
.stream()
.map(s -> (Plugin) s)
.collect(Collectors.toList());
} }
} }

View File

@@ -37,4 +37,14 @@ public class Boosts extends Plugin
{ {
return overlay; return overlay;
} }
@Override
protected void startUp() throws Exception
{
}
@Override
protected void shutDown() throws Exception
{
}
} }

View File

@@ -46,6 +46,16 @@ public class BossTimers extends Plugin
private final List<Boss> bosses = loadBossData(); private final List<Boss> bosses = loadBossData();
@Override
protected void startUp() throws Exception
{
}
@Override
protected void shutDown() throws Exception
{
}
@Override @Override
public Overlay getOverlay() public Overlay getOverlay()
{ {

View File

@@ -25,10 +25,8 @@
package net.runelite.client.plugins.devtools; package net.runelite.client.plugins.devtools;
import java.awt.Font; import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment; import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.io.IOException;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import net.runelite.client.RuneLite; import net.runelite.client.RuneLite;
@@ -60,34 +58,26 @@ public class DevTools extends Plugin
private Font font; private Font font;
public DevTools() @Override
protected void startUp() throws Exception
{ {
navButton.getButton().addActionListener(this::setPluginPanel); navButton.getButton().addActionListener(this::setPluginPanel);
try ImageIcon icon = new ImageIcon(ImageIO.read(getClass().getResourceAsStream("devtools_icon.png")));
{ navButton.getButton().setIcon(icon);
ImageIcon icon = new ImageIcon(ImageIO.read(getClass().getResourceAsStream("devtools_icon.png")));
navButton.getButton().setIcon(icon);
}
catch (IOException ex)
{
logger.warn("Unable to load devtools icon", ex);
}
ui.getNavigationPanel().addNavigation(navButton); ui.getNavigationPanel().addNavigation(navButton);
try font = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream("runescape.ttf"));
{
font = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream("runescape.ttf"));
font = font.deriveFont(Font.PLAIN, 16); font = font.deriveFont(Font.PLAIN, 16);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(font); ge.registerFont(font);
} }
catch (FontFormatException | IOException ex)
{ @Override
logger.warn("Unable to load font", ex); protected void shutDown() throws Exception
} {
} }
@Override @Override

View File

@@ -37,4 +37,14 @@ public class FPS extends Plugin
{ {
return overlay; return overlay;
} }
@Override
protected void startUp() throws Exception
{
}
@Override
protected void shutDown() throws Exception
{
}
} }

View File

@@ -26,7 +26,6 @@ package net.runelite.client.plugins.hiscore;
import com.google.common.eventbus.Subscribe; import com.google.common.eventbus.Subscribe;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
@@ -35,7 +34,6 @@ import net.runelite.client.events.PlayerMenuOptionClicked;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.NavigationButton;
import net.runelite.client.ui.overlay.Overlay;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -51,19 +49,13 @@ public class Hiscore extends Plugin
private final RuneLite runeLite = RuneLite.getRunelite(); private final RuneLite runeLite = RuneLite.getRunelite();
private final ClientUI ui = runeLite.getGui(); private final ClientUI ui = runeLite.getGui();
public Hiscore() @Override
protected void startUp() throws Exception
{ {
navButton.getButton().addActionListener(this::setPluginPanel); navButton.getButton().addActionListener(this::setPluginPanel);
try ImageIcon icon = new ImageIcon(ImageIO.read(getClass().getResourceAsStream("hiscore.gif")));
{ navButton.getButton().setIcon(icon);
ImageIcon icon = new ImageIcon(ImageIO.read(getClass().getResourceAsStream("hiscore.gif")));
navButton.getButton().setIcon(icon);
}
catch (IOException ex)
{
logger.warn(null, ex);
}
ui.getNavigationPanel().addNavigation(navButton); ui.getNavigationPanel().addNavigation(navButton);
@@ -71,9 +63,8 @@ public class Hiscore extends Plugin
} }
@Override @Override
public Overlay getOverlay() protected void shutDown() throws Exception
{ {
return null;
} }
private void setPluginPanel(ActionEvent e) private void setPluginPanel(ActionEvent e)

View File

@@ -30,6 +30,7 @@ import java.awt.TrayIcon;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static net.runelite.api.AnimationID.*; import static net.runelite.api.AnimationID.*;
import net.runelite.api.Client; import net.runelite.api.Client;
@@ -37,7 +38,6 @@ import net.runelite.api.GameState;
import net.runelite.client.RuneLite; import net.runelite.client.RuneLite;
import net.runelite.client.events.AnimationChanged; import net.runelite.client.events.AnimationChanged;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.overlay.Overlay;
public class IdleNotifier extends Plugin public class IdleNotifier extends Plugin
{ {
@@ -48,19 +48,21 @@ public class IdleNotifier extends Plugin
private final Client client = RuneLite.getClient(); private final Client client = RuneLite.getClient();
private final TrayIcon trayIcon = RuneLite.getTrayIcon(); private final TrayIcon trayIcon = RuneLite.getTrayIcon();
private ScheduledFuture<?> future;
private Instant lastAnimating; private Instant lastAnimating;
private boolean notifyIdle = false; private boolean notifyIdle = false;
@Override @Override
public Overlay getOverlay() protected void startUp() throws Exception
{
return null;
}
public IdleNotifier()
{ {
ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor(); ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor();
executor.scheduleAtFixedRate(this::checkIdle, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS); future = executor.scheduleAtFixedRate(this::checkIdle, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS);
}
@Override
protected void shutDown() throws Exception
{
future.cancel(true);
} }
@Subscribe @Subscribe
@@ -124,7 +126,7 @@ public class IdleNotifier extends Plugin
private void checkIdle() private void checkIdle()
{ {
if (notifyIdle && client.getLocalPlayer().getAnimation() == IDLE if (notifyIdle && client.getLocalPlayer().getAnimation() == IDLE
&& Instant.now().compareTo(lastAnimating.plus(WAIT_DURATION)) >= 0) && Instant.now().compareTo(lastAnimating.plus(WAIT_DURATION)) >= 0)
{ {
trayIcon.displayMessage("RuneLite", "You are now idle.", TrayIcon.MessageType.NONE); trayIcon.displayMessage("RuneLite", "You are now idle.", TrayIcon.MessageType.NONE);

View File

@@ -22,7 +22,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.opponentinfo; package net.runelite.client.plugins.opponentinfo;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
@@ -44,6 +43,16 @@ public class OpponentInfo extends Plugin
return overlay; return overlay;
} }
@Override
protected void startUp() throws Exception
{
}
@Override
protected void shutDown() throws Exception
{
}
public static Map<String, Integer> loadNpcHealth() public static Map<String, Integer> loadNpcHealth()
{ {
Gson gson = new Gson(); Gson gson = new Gson();

View File

@@ -37,4 +37,13 @@ public class Runecraft extends Plugin
return overlay; return overlay;
} }
@Override
protected void startUp() throws Exception
{
}
@Override
protected void shutDown() throws Exception
{
}
} }

View File

@@ -51,9 +51,13 @@ public class Xtea extends Plugin
private final Set<Integer> sentRegions = new HashSet<>(); private final Set<Integer> sentRegions = new HashSet<>();
@Override @Override
public Overlay getOverlay() protected void startUp() throws Exception
{
}
@Override
protected void shutDown() throws Exception
{ {
return null;
} }
@Subscribe @Subscribe