update scheduler implementation

This commit is contained in:
ThatGamerBlue
2021-02-19 00:31:53 +00:00
parent ad3c060327
commit 492dac91e9
3 changed files with 81 additions and 58 deletions

View File

@@ -30,6 +30,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.openosrs.client.graphics.ModelOutlineRenderer;
import java.io.File; import java.io.File;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean; import java.lang.management.RuntimeMXBean;
@@ -73,6 +74,7 @@ import net.runelite.client.menus.MenuManager;
import net.runelite.client.plugins.OPRSExternalPluginManager; import net.runelite.client.plugins.OPRSExternalPluginManager;
import net.runelite.client.rs.ClientLoader; import net.runelite.client.rs.ClientLoader;
import net.runelite.client.rs.ClientUpdateCheckMode; import net.runelite.client.rs.ClientUpdateCheckMode;
import net.runelite.client.task.Scheduler;
import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.DrawManager; import net.runelite.client.ui.DrawManager;
import net.runelite.client.ui.FatalErrorDialog; import net.runelite.client.ui.FatalErrorDialog;
@@ -171,6 +173,9 @@ public class RuneLite
@Inject @Inject
private Provider<WorldMapOverlay> worldMapOverlay; private Provider<WorldMapOverlay> worldMapOverlay;
@Inject
private Provider<ModelOutlineRenderer> modelOutlineRenderer;
@Inject @Inject
private Provider<LootManager> lootManager; private Provider<LootManager> lootManager;
@@ -184,6 +189,9 @@ public class RuneLite
@Nullable @Nullable
private Client client; private Client client;
@Inject
private Scheduler scheduler;
public static void main(String[] args) throws Exception public static void main(String[] args) throws Exception
{ {
Locale.setDefault(Locale.ENGLISH); Locale.setDefault(Locale.ENGLISH);
@@ -397,6 +405,12 @@ public class RuneLite
// Start plugins // Start plugins
pluginManager.startPlugins(); pluginManager.startPlugins();
// Register additional schedulers
if (this.client != null)
{
scheduler.registerObject(modelOutlineRenderer.get());
}
SplashScreen.stop(); SplashScreen.stop();
clientUI.show(); clientUI.show();

View File

@@ -38,13 +38,7 @@ import com.google.inject.Injector;
import com.google.inject.Key; import com.google.inject.Key;
import com.google.inject.Module; import com.google.inject.Module;
import java.io.IOException; import java.io.IOException;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@@ -72,12 +66,9 @@ import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.PluginChanged; import net.runelite.client.events.PluginChanged;
import net.runelite.client.events.SessionClose; import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen; import net.runelite.client.events.SessionOpen;
import net.runelite.client.task.Schedule;
import net.runelite.client.task.ScheduledMethod;
import net.runelite.client.task.Scheduler; import net.runelite.client.task.Scheduler;
import net.runelite.client.ui.SplashScreen; import net.runelite.client.ui.SplashScreen;
import net.runelite.client.util.GameEventManager; import net.runelite.client.util.GameEventManager;
import net.runelite.client.util.ReflectUtil;
@Singleton @Singleton
@Slf4j @Slf4j
@@ -636,59 +627,14 @@ public class PluginManager
private void schedule(Plugin plugin) private void schedule(Plugin plugin)
{ {
for (Method method : plugin.getClass().getMethods()) // note to devs: this method will almost certainly merge conflict in the future, just apply the changes in the scheduler instead
{ scheduler.registerObject(plugin);
Schedule schedule = method.getAnnotation(Schedule.class);
if (schedule == null)
{
continue;
}
Runnable runnable = null;
try
{
final Class<?> clazz = method.getDeclaringClass();
final MethodHandles.Lookup caller = ReflectUtil.privateLookupIn(clazz);
final MethodType subscription = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
final MethodHandle target = caller.findVirtual(clazz, method.getName(), subscription);
final CallSite site = LambdaMetafactory.metafactory(
caller,
"run",
MethodType.methodType(Runnable.class, clazz),
subscription,
target,
subscription);
final MethodHandle factory = site.getTarget();
runnable = (Runnable) factory.bindTo(plugin).invokeExact();
}
catch (Throwable e)
{
log.warn("Unable to create lambda for method {}", method, e);
}
ScheduledMethod scheduledMethod = new ScheduledMethod(schedule, method, plugin, runnable);
log.debug("Scheduled task {}", scheduledMethod);
scheduler.addScheduledMethod(scheduledMethod);
}
} }
private void unschedule(Plugin plugin) private void unschedule(Plugin plugin)
{ {
List<ScheduledMethod> methods = new ArrayList<>(scheduler.getScheduledMethods()); // note to devs: this method will almost certainly merge conflict in the future, just apply the changes in the scheduler instead
scheduler.unregisterObject(plugin);
for (ScheduledMethod method : methods)
{
if (method.getObject() != plugin)
{
continue;
}
log.debug("Removing scheduled task {}", method);
scheduler.removeScheduledMethod(method);
}
} }
/** /**

View File

@@ -24,10 +24,16 @@
*/ */
package net.runelite.client.task; package net.runelite.client.task;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
@@ -60,6 +66,63 @@ public class Scheduler
return Collections.unmodifiableList(scheduledMethods); return Collections.unmodifiableList(scheduledMethods);
} }
public void registerObject(Object obj)
{
for (Method method : obj.getClass().getMethods())
{
Schedule schedule = method.getAnnotation(Schedule.class);
if (schedule == null)
{
continue;
}
Runnable runnable = null;
try
{
final Class<?> clazz = method.getDeclaringClass();
final MethodHandles.Lookup caller = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
final MethodType subscription = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
final MethodHandle target = caller.findVirtual(clazz, method.getName(), subscription);
final CallSite site = LambdaMetafactory.metafactory(
caller,
"run",
MethodType.methodType(Runnable.class, clazz),
subscription,
target,
subscription);
final MethodHandle factory = site.getTarget();
runnable = (Runnable) factory.bindTo(obj).invokeExact();
}
catch (Throwable e)
{
log.warn("Unable to create lambda for method {}", method, e);
}
ScheduledMethod scheduledMethod = new ScheduledMethod(schedule, method, obj, runnable);
log.debug("Scheduled task {}", scheduledMethod);
addScheduledMethod(scheduledMethod);
}
}
public void unregisterObject(Object obj)
{
List<ScheduledMethod> methods = new ArrayList<>(getScheduledMethods());
for (ScheduledMethod method : methods)
{
if (method.getObject() != obj)
{
continue;
}
log.debug("Removing scheduled task {}", method);
removeScheduledMethod(method);
}
}
public void tick() public void tick()
{ {
Instant now = Instant.now(); Instant now = Instant.now();