runelite-client: add synchronous job scheduler
Convert existing plugins to use it, so that the code all runs on the same main game thread. Fixes various thread related issues caused from accessing game state from executor threads.
This commit is contained in:
@@ -49,6 +49,7 @@ import net.runelite.client.events.SessionClose;
|
||||
import net.runelite.client.events.SessionOpen;
|
||||
import net.runelite.client.menus.MenuManager;
|
||||
import net.runelite.client.plugins.PluginManager;
|
||||
import net.runelite.client.task.Scheduler;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.overlay.OverlayRenderer;
|
||||
import net.runelite.http.api.account.AccountClient;
|
||||
@@ -75,7 +76,8 @@ public class RuneLite
|
||||
private final MenuManager menuManager = new MenuManager(this);
|
||||
private OverlayRenderer renderer;
|
||||
private final EventBus eventBus = new EventBus(this::eventExceptionHandler);
|
||||
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
|
||||
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
|
||||
private final Scheduler scheduler = new Scheduler(this);
|
||||
private WSClient wsclient;
|
||||
|
||||
private AccountSession accountSession;
|
||||
@@ -327,6 +329,11 @@ public class RuneLite
|
||||
return executor;
|
||||
}
|
||||
|
||||
public Scheduler getScheduler()
|
||||
{
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
public static TrayIcon getTrayIcon()
|
||||
{
|
||||
return trayIcon;
|
||||
|
||||
@@ -32,6 +32,7 @@ import net.runelite.api.Skill;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.events.*;
|
||||
import net.runelite.client.game.DeathChecker;
|
||||
import net.runelite.client.task.Scheduler;
|
||||
import net.runelite.client.ui.overlay.OverlayRenderer;
|
||||
import net.runelite.rs.api.MainBufferProvider;
|
||||
import org.slf4j.Logger;
|
||||
@@ -41,16 +42,23 @@ public class Hooks
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(Hooks.class);
|
||||
|
||||
private static final long CHECK = 600; // ms - how often to run checks
|
||||
|
||||
private static final RuneLite runelite = RuneLite.getRunelite();
|
||||
private static final DeathChecker death = new DeathChecker(runelite);
|
||||
|
||||
public static void draw(Object provider, Graphics graphics, int x, int y)
|
||||
{
|
||||
// XXX fix injector to use interface in signature
|
||||
MainBufferProvider mpb = (MainBufferProvider) provider;
|
||||
BufferedImage image = (BufferedImage) mpb.getImage();
|
||||
private static long lastCheck;
|
||||
|
||||
OverlayRenderer renderer = runelite.getRenderer();
|
||||
public static void clientMainLoop(Object client, boolean arg1)
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (now - lastCheck < CHECK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lastCheck = now;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -61,6 +69,18 @@ public class Hooks
|
||||
logger.warn("error during death check", ex);
|
||||
}
|
||||
|
||||
Scheduler scheduler = runelite.getScheduler();
|
||||
scheduler.tick();
|
||||
}
|
||||
|
||||
public static void draw(Object provider, Graphics graphics, int x, int y)
|
||||
{
|
||||
// XXX fix injector to use interface in signature
|
||||
MainBufferProvider mpb = (MainBufferProvider) provider;
|
||||
BufferedImage image = (BufferedImage) mpb.getImage();
|
||||
|
||||
OverlayRenderer renderer = runelite.getRenderer();
|
||||
|
||||
try
|
||||
{
|
||||
renderer.render(image);
|
||||
|
||||
@@ -24,9 +24,11 @@
|
||||
*/
|
||||
package net.runelite.client.plugins;
|
||||
|
||||
import net.runelite.client.task.ScheduledMethod;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.google.common.util.concurrent.Service;
|
||||
import com.google.common.util.concurrent.ServiceManager;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -56,6 +58,7 @@ import net.runelite.client.plugins.xpglobes.XpGlobes;
|
||||
import net.runelite.client.plugins.xptracker.XPTracker;
|
||||
import net.runelite.client.plugins.xtea.Xtea;
|
||||
import net.runelite.client.plugins.zulrah.Zulrah;
|
||||
import net.runelite.client.task.Schedule;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -117,6 +120,8 @@ public class PluginManager
|
||||
{
|
||||
logger.debug("Plugin {} is now running", plugin);
|
||||
runelite.getEventBus().register(plugin);
|
||||
|
||||
schedule(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,6 +129,7 @@ public class PluginManager
|
||||
{
|
||||
logger.debug("Plugin {} is stopping", plugin);
|
||||
runelite.getEventBus().unregister(plugin);
|
||||
unschedule(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,6 +140,7 @@ public class PluginManager
|
||||
if (from == Service.State.RUNNING)
|
||||
{
|
||||
runelite.getEventBus().unregister(plugin);
|
||||
unschedule(plugin);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -154,4 +161,38 @@ public class PluginManager
|
||||
.map(s -> (Plugin) s)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void schedule(Plugin plugin)
|
||||
{
|
||||
for (Method method : plugin.getClass().getMethods())
|
||||
{
|
||||
Schedule schedule = method.getAnnotation(Schedule.class);
|
||||
|
||||
if (schedule == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ScheduledMethod scheduledMethod = new ScheduledMethod(schedule, method, plugin);
|
||||
logger.debug("Scheduled task {}", scheduledMethod);
|
||||
|
||||
runelite.getScheduler().addScheduledMethod(scheduledMethod);
|
||||
}
|
||||
}
|
||||
|
||||
private void unschedule(Plugin plugin)
|
||||
{
|
||||
List<ScheduledMethod> methods = new ArrayList<>(runelite.getScheduler().getScheduledMethods());
|
||||
|
||||
for (ScheduledMethod method : methods)
|
||||
{
|
||||
if (method.getObject() != plugin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.debug("Removing scheduled task {}", method);
|
||||
runelite.getScheduler().removeScheduledMethod(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,35 +24,31 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.clanchat;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.task.Schedule;
|
||||
|
||||
public class ClanChat extends Plugin
|
||||
{
|
||||
|
||||
private final long INTERVAL = 600;
|
||||
private ScheduledFuture<?> future;
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor();
|
||||
future = executor.scheduleAtFixedRate(this::updateClanChatTitle, INTERVAL, INTERVAL, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
future.cancel(true);
|
||||
}
|
||||
|
||||
private void updateClanChatTitle()
|
||||
@Schedule(
|
||||
period = 600,
|
||||
unit = ChronoUnit.MILLIS
|
||||
)
|
||||
public void updateClanChatTitle()
|
||||
{
|
||||
if (RuneLite.getClient().getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
|
||||
@@ -24,49 +24,41 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.combatnotifier;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import net.runelite.api.Actor;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
|
||||
import java.awt.*;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.runelite.client.task.Schedule;
|
||||
|
||||
public class CombatNotifier extends Plugin
|
||||
{
|
||||
private static final int CHECK_INTERVAL = 1;
|
||||
|
||||
private final Client client = RuneLite.getClient();
|
||||
private final RuneLite runelite = RuneLite.getRunelite();
|
||||
private final CombatNotifierConfig config = runelite.getConfigManager()
|
||||
.getConfig(CombatNotifierConfig.class);
|
||||
|
||||
private ScheduledFuture<?> future;
|
||||
private Instant lastInteracting;
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor();
|
||||
future = executor.scheduleAtFixedRate(this::checkIdle, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
future.cancel(true);
|
||||
}
|
||||
|
||||
private void checkIdle()
|
||||
@Schedule(
|
||||
period = 1,
|
||||
unit = ChronoUnit.SECONDS
|
||||
)
|
||||
public void checkIdle()
|
||||
{
|
||||
if (client.getGameState() != GameState.LOGGED_IN || !config.isEnabled())
|
||||
{
|
||||
@@ -88,4 +80,4 @@ public class CombatNotifier extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,32 +25,27 @@
|
||||
package net.runelite.client.plugins.fishing;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.events.ChatMessage;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.task.Schedule;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FishingPlugin extends Plugin
|
||||
{
|
||||
private static final int CHECK_INTERVAL = 1;
|
||||
|
||||
private final RuneLite runelite = RuneLite.getRunelite();
|
||||
private final FishingConfig config = runelite.getConfigManager().getConfig(FishingConfig.class);
|
||||
private final FishingOverlay overlay = new FishingOverlay(this);
|
||||
private final FishingSpotOverlay spotOverlay = new FishingSpotOverlay(this);
|
||||
|
||||
private FishingSession session = new FishingSession();
|
||||
private ScheduledFuture<?> future;
|
||||
|
||||
@Override
|
||||
public Collection<Overlay> getOverlays()
|
||||
@@ -61,9 +56,6 @@ public class FishingPlugin extends Plugin
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
ScheduledExecutorService executor = runelite.getExecutor();
|
||||
future = executor.scheduleAtFixedRate(this::checkFishing, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS);
|
||||
|
||||
// Initialize overlay config
|
||||
spotOverlay.updateConfig();
|
||||
}
|
||||
@@ -71,7 +63,6 @@ public class FishingPlugin extends Plugin
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
future.cancel(true);
|
||||
}
|
||||
|
||||
public FishingConfig getConfig()
|
||||
@@ -104,7 +95,11 @@ public class FishingPlugin extends Plugin
|
||||
spotOverlay.updateConfig();
|
||||
}
|
||||
|
||||
private void checkFishing()
|
||||
@Schedule(
|
||||
period = 1,
|
||||
unit = ChronoUnit.SECONDS
|
||||
)
|
||||
public void checkFishing()
|
||||
{
|
||||
Instant lastFishCaught = session.getLastFishCaught();
|
||||
if (lastFishCaught == null)
|
||||
|
||||
@@ -25,13 +25,9 @@
|
||||
package net.runelite.client.plugins.idlenotifier;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.TrayIcon;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import static net.runelite.api.AnimationID.*;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
@@ -39,32 +35,26 @@ import net.runelite.api.Player;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.events.AnimationChanged;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.task.Schedule;
|
||||
|
||||
public class IdleNotifier extends Plugin
|
||||
{
|
||||
private static final String OPERATING_SYSTEM = System.getProperty("os.name");
|
||||
private static final int CHECK_INTERVAL = 2;
|
||||
private static final Duration WAIT_DURATION = Duration.ofMillis(2500L);
|
||||
|
||||
private final Client client = RuneLite.getClient();
|
||||
private final RuneLite runelite = RuneLite.getRunelite();
|
||||
private final TrayIcon trayIcon = RuneLite.getTrayIcon();
|
||||
|
||||
private ScheduledFuture<?> future;
|
||||
private Instant lastAnimating;
|
||||
private boolean notifyIdle = false;
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
ScheduledExecutorService executor = runelite.getExecutor();
|
||||
future = executor.scheduleAtFixedRate(this::checkIdle, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
future.cancel(true);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -74,6 +64,7 @@ public class IdleNotifier extends Plugin
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int animation = client.getLocalPlayer().getAnimation();
|
||||
switch (animation)
|
||||
{
|
||||
@@ -148,7 +139,11 @@ public class IdleNotifier extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIdle()
|
||||
@Schedule(
|
||||
period = 2,
|
||||
unit = ChronoUnit.SECONDS
|
||||
)
|
||||
public void checkIdle()
|
||||
{
|
||||
Player local = client.getLocalPlayer();
|
||||
if (notifyIdle && local.getAnimation() == IDLE
|
||||
|
||||
@@ -27,25 +27,21 @@ package net.runelite.client.plugins.woodcutting;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.events.ChatMessage;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.task.Schedule;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
|
||||
public class WoodcuttingPlugin extends Plugin
|
||||
{
|
||||
private static final int CHECK_INTERVAL = 1;
|
||||
|
||||
private final RuneLite runelite = RuneLite.getRunelite();
|
||||
private final WoodcuttingConfig config = runelite.getConfigManager().getConfig(WoodcuttingConfig.class);
|
||||
private final WoodcuttingOverlay overlay = new WoodcuttingOverlay(this);
|
||||
|
||||
private WoodcuttingSession session = new WoodcuttingSession();
|
||||
private ScheduledFuture<?> future;
|
||||
|
||||
@Override
|
||||
public Overlay getOverlay()
|
||||
@@ -56,14 +52,11 @@ public class WoodcuttingPlugin extends Plugin
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
ScheduledExecutorService executor = runelite.getExecutor();
|
||||
future = executor.scheduleAtFixedRate(this::checkCutting, CHECK_INTERVAL, CHECK_INTERVAL, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
future.cancel(true);
|
||||
}
|
||||
|
||||
public WoodcuttingConfig getConfig()
|
||||
@@ -90,7 +83,11 @@ public class WoodcuttingPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCutting()
|
||||
@Schedule(
|
||||
period = 1,
|
||||
unit = ChronoUnit.SECONDS
|
||||
)
|
||||
public void checkCutting()
|
||||
{
|
||||
Instant lastLogCut = session.getLastLogCut();
|
||||
if (lastLogCut == null)
|
||||
|
||||
@@ -27,7 +27,6 @@ package net.runelite.client.plugins.xptracker;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.events.ExperienceChanged;
|
||||
@@ -35,13 +34,11 @@ import net.runelite.client.events.GameStateChanged;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
import net.runelite.client.util.RunnableExceptionLogger;
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import net.runelite.client.task.Schedule;
|
||||
|
||||
public class XPTracker extends Plugin
|
||||
{
|
||||
@@ -50,25 +47,25 @@ public class XPTracker extends Plugin
|
||||
private final RuneLite runeLite = RuneLite.getRunelite();
|
||||
private final ClientUI ui = runeLite.getGui();
|
||||
private final Client client = RuneLite.getClient();
|
||||
private ScheduledFuture<?> future;
|
||||
|
||||
private final NavigationButton navButton = new NavigationButton("XP Tracker");
|
||||
private final XPPanel xpPanel = new XPPanel(runeLite, this);
|
||||
private SkillXPInfo[] xpInfos = new SkillXPInfo[NUMBER_OF_SKILLS];
|
||||
private final SkillXPInfo[] xpInfos = new SkillXPInfo[NUMBER_OF_SKILLS];
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged event)
|
||||
{
|
||||
//reset upon login
|
||||
if (event.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
xpPanel.resetAllSkillXpHr();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onXpChanged(ExperienceChanged event)
|
||||
{
|
||||
Skill skill = event.getSkill();
|
||||
String currentUser = client.getLocalPlayer().getName();
|
||||
int skillIdx = skill.ordinal();
|
||||
|
||||
//To catch login ExperienceChanged event.
|
||||
@@ -79,7 +76,7 @@ public class XPTracker extends Plugin
|
||||
else
|
||||
{
|
||||
xpInfos[skillIdx] = new SkillXPInfo(client.getSkillExperience(skill),
|
||||
skill);
|
||||
skill);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,10 +93,6 @@ public class XPTracker extends Plugin
|
||||
navButton.getButton().setText("XP");
|
||||
ui.getNavigationPanel().addNavigation(navButton);
|
||||
|
||||
ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor();
|
||||
future = executor.scheduleAtFixedRate(RunnableExceptionLogger.wrap(
|
||||
xpPanel::updateAllSkillXpHr), 0, 600, TimeUnit.MILLISECONDS);
|
||||
|
||||
Font font = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream("/runescape.ttf"));
|
||||
font = font.deriveFont(Font.BOLD, 16);
|
||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
@@ -109,7 +102,15 @@ public class XPTracker extends Plugin
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
future.cancel(true);
|
||||
}
|
||||
|
||||
@Schedule(
|
||||
period = 600,
|
||||
unit = ChronoUnit.MILLIS
|
||||
)
|
||||
public void updateXp()
|
||||
{
|
||||
xpPanel.updateAllSkillXpHr();
|
||||
}
|
||||
|
||||
public SkillXPInfo[] getXpInfos()
|
||||
|
||||
@@ -55,32 +55,27 @@ class StatusOverlay extends Overlay
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
ZulrahInstance current, next;
|
||||
Fight fight = plugin.getFight();
|
||||
|
||||
synchronized (plugin)
|
||||
if (client.getGameState() != GameState.LOGGED_IN || fight == null)
|
||||
{
|
||||
Fight fight = plugin.getFight();
|
||||
|
||||
if (client.getGameState() != GameState.LOGGED_IN || fight == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//TODO: Add prayer checking and health warning
|
||||
graphics.setColor(Color.WHITE);
|
||||
|
||||
ZulrahPattern pattern = fight.getPattern();
|
||||
if (pattern == null)
|
||||
{
|
||||
// can draw at least the starting place here?
|
||||
return null;
|
||||
}
|
||||
|
||||
// Show current type, next type, and jad
|
||||
current = fight.getZulrah();
|
||||
next = pattern.get(fight.getStage() + 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
//TODO: Add prayer checking and health warning
|
||||
graphics.setColor(Color.WHITE);
|
||||
|
||||
ZulrahPattern pattern = fight.getPattern();
|
||||
if (pattern == null)
|
||||
{
|
||||
// can draw at least the starting place here?
|
||||
return null;
|
||||
}
|
||||
|
||||
// Show current type, next type, and jad
|
||||
ZulrahInstance current = fight.getZulrah();
|
||||
ZulrahInstance next = pattern.get(fight.getStage() + 1);
|
||||
|
||||
String currentStr = "Current: " + current.getType();
|
||||
String nextStr = "Next: " + (next != null ? next.getType() : "Restart");
|
||||
String jadStr;
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.zulrah;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
@@ -54,29 +53,22 @@ public class TileOverlay extends Overlay
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
ZulrahPattern pattern;
|
||||
Point startLocationWorld;
|
||||
int stage;
|
||||
Fight fight = plugin.getFight();
|
||||
|
||||
synchronized (plugin)
|
||||
if (client.getGameState() != GameState.LOGGED_IN || fight == null)
|
||||
{
|
||||
Fight fight = plugin.getFight();
|
||||
|
||||
if (client.getGameState() != GameState.LOGGED_IN || fight == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
pattern = fight.getPattern();
|
||||
if (pattern == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
startLocationWorld = fight.getStartLocationWorld();
|
||||
stage = fight.getStage();
|
||||
return null;
|
||||
}
|
||||
|
||||
ZulrahPattern pattern = fight.getPattern();
|
||||
if (pattern == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Point startLocationWorld = fight.getStartLocationWorld();
|
||||
int stage = fight.getStage();
|
||||
|
||||
ZulrahInstance current = pattern.get(stage);
|
||||
if (current == null)
|
||||
{
|
||||
@@ -123,7 +115,7 @@ public class TileOverlay extends Overlay
|
||||
|
||||
//to make the centre of the tile on the point, rather than the tile the point resides in
|
||||
localTile = new Point(localTile.getX() + Perspective.LOCAL_TILE_SIZE / 2, localTile.getY() + Perspective.LOCAL_TILE_SIZE / 2);
|
||||
|
||||
|
||||
Polygon poly = Perspective.getCanvasTilePoly(client, localTile);
|
||||
if (poly != null)
|
||||
{
|
||||
|
||||
@@ -25,11 +25,9 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.zulrah;
|
||||
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.NPC;
|
||||
@@ -44,8 +42,8 @@ import net.runelite.client.plugins.zulrah.patterns.ZulrahPatternA;
|
||||
import net.runelite.client.plugins.zulrah.patterns.ZulrahPatternB;
|
||||
import net.runelite.client.plugins.zulrah.patterns.ZulrahPatternC;
|
||||
import net.runelite.client.plugins.zulrah.patterns.ZulrahPatternD;
|
||||
import net.runelite.client.task.Schedule;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.util.RunnableExceptionLogger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -68,8 +66,6 @@ public class Zulrah extends Plugin
|
||||
|
||||
private Fight fight;
|
||||
|
||||
private ScheduledFuture<?> future;
|
||||
|
||||
@Override
|
||||
public Collection<Overlay> getOverlays()
|
||||
{
|
||||
@@ -79,17 +75,18 @@ public class Zulrah extends Plugin
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
ScheduledExecutorService executor = RuneLite.getRunelite().getExecutor();
|
||||
future = executor.scheduleAtFixedRate(RunnableExceptionLogger.wrap(this::update), 100, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
future.cancel(true);
|
||||
}
|
||||
|
||||
private synchronized void update()
|
||||
@Schedule(
|
||||
period = 600,
|
||||
unit = ChronoUnit.MILLIS
|
||||
)
|
||||
public void update()
|
||||
{
|
||||
if (client == null || client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.task;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Schedule
|
||||
{
|
||||
long period();
|
||||
|
||||
ChronoUnit unit();
|
||||
|
||||
boolean asynchronous() default false;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.task;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Instant;
|
||||
|
||||
public class ScheduledMethod
|
||||
{
|
||||
private final Schedule schedule;
|
||||
private final Method method;
|
||||
private final Object object;
|
||||
private Instant last = Instant.now();
|
||||
|
||||
public ScheduledMethod(Schedule schedule, Method method, Object object)
|
||||
{
|
||||
this.schedule = schedule;
|
||||
this.method = method;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "ScheduledMethod{" + "schedule=" + schedule + ", method=" + method + ", object=" + object + '}';
|
||||
}
|
||||
|
||||
public Schedule getSchedule()
|
||||
{
|
||||
return schedule;
|
||||
}
|
||||
|
||||
public Method getMethod()
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
public Object getObject()
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
public Instant getLast()
|
||||
{
|
||||
return last;
|
||||
}
|
||||
|
||||
public void setLast(Instant last)
|
||||
{
|
||||
this.last = last;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.task;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import net.runelite.client.RuneLite;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Scheduler
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(Scheduler.class);
|
||||
|
||||
private final RuneLite runelite;
|
||||
private final List<ScheduledMethod> scheduledMethods = new ArrayList<>();
|
||||
|
||||
public Scheduler(RuneLite runelite)
|
||||
{
|
||||
this.runelite = runelite;
|
||||
}
|
||||
|
||||
public void addScheduledMethod(ScheduledMethod method)
|
||||
{
|
||||
scheduledMethods.add(method);
|
||||
}
|
||||
|
||||
public void removeScheduledMethod(ScheduledMethod method)
|
||||
{
|
||||
scheduledMethods.remove(method);
|
||||
}
|
||||
|
||||
public List<ScheduledMethod> getScheduledMethods()
|
||||
{
|
||||
return Collections.unmodifiableList(scheduledMethods);
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
Instant now = Instant.now();
|
||||
|
||||
for (ScheduledMethod scheduledMethod : scheduledMethods)
|
||||
{
|
||||
Instant last = scheduledMethod.getLast();
|
||||
|
||||
Duration difference = Duration.between(last, now);
|
||||
|
||||
Schedule schedule = scheduledMethod.getSchedule();
|
||||
Duration timeSinceRun = Duration.of(schedule.period(), schedule.unit());
|
||||
|
||||
if (difference.compareTo(timeSinceRun) > 0)
|
||||
{
|
||||
logger.trace("Scheduled task triggered: {}", scheduledMethod);
|
||||
|
||||
scheduledMethod.setLast(now);
|
||||
|
||||
if (schedule.asynchronous())
|
||||
{
|
||||
ScheduledExecutorService executor = runelite.getExecutor();
|
||||
executor.submit(() -> run(scheduledMethod));
|
||||
}
|
||||
else
|
||||
{
|
||||
run(scheduledMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void run(ScheduledMethod scheduledMethod)
|
||||
{
|
||||
Method method = scheduledMethod.getMethod();
|
||||
|
||||
try
|
||||
{
|
||||
method.invoke(scheduledMethod.getObject());
|
||||
}
|
||||
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex)
|
||||
{
|
||||
logger.warn("error invoking scheduled task", ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.warn("error during scheduled task", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user