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

View File

@@ -38,13 +38,7 @@ import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
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.Method;
import java.util.ArrayList;
import java.util.Collection;
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.SessionClose;
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.ui.SplashScreen;
import net.runelite.client.util.GameEventManager;
import net.runelite.client.util.ReflectUtil;
@Singleton
@Slf4j
@@ -636,59 +627,14 @@ public class PluginManager
private void schedule(Plugin plugin)
{
for (Method method : plugin.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 = 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);
}
// note to devs: this method will almost certainly merge conflict in the future, just apply the changes in the scheduler instead
scheduler.registerObject(plugin);
}
private void unschedule(Plugin plugin)
{
List<ScheduledMethod> methods = new ArrayList<>(scheduler.getScheduledMethods());
for (ScheduledMethod method : methods)
{
if (method.getObject() != plugin)
{
continue;
}
log.debug("Removing scheduled task {}", method);
scheduler.removeScheduledMethod(method);
}
// note to devs: this method will almost certainly merge conflict in the future, just apply the changes in the scheduler instead
scheduler.unregisterObject(plugin);
}
/**

View File

@@ -24,10 +24,16 @@
*/
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.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.CopyOnWriteArrayList;
@@ -60,6 +66,63 @@ public class Scheduler
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()
{
Instant now = Instant.now();