client: LambdaMetaFactory for subscribe annotation, java target… (#2128)
client: LambdaMetaFactory for subscribe annotation, java target level 11
This commit is contained in:
@@ -44,7 +44,6 @@ plugins {
|
||||
id(Plugins.latestVersion.first) version Plugins.latestVersion.second
|
||||
id(Plugins.grgit.first) version Plugins.grgit.second
|
||||
|
||||
checkstyle
|
||||
application
|
||||
}
|
||||
|
||||
@@ -83,9 +82,9 @@ subprojects {
|
||||
project.extra["rootPath"] = rootDir.toString().replace("\\", "/")
|
||||
|
||||
if (this.name != "runescape-client") {
|
||||
apply(plugin = "checkstyle")
|
||||
apply<CheckstylePlugin>()
|
||||
|
||||
checkstyle {
|
||||
configure<CheckstyleExtension> {
|
||||
maxWarnings = 0
|
||||
toolVersion = "8.25"
|
||||
isShowViolations = true
|
||||
@@ -114,8 +113,8 @@ subprojects {
|
||||
|
||||
tasks {
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
withType<JavaCompile> {
|
||||
|
||||
@@ -59,7 +59,7 @@ tasks {
|
||||
"rs.client" to deobjars.find { it.name.startsWith("runescape-client") }.toString().replace("\\", "/")
|
||||
)
|
||||
|
||||
processResources {
|
||||
processResources {
|
||||
finalizedBy("filterResources")
|
||||
}
|
||||
|
||||
@@ -112,3 +112,14 @@ tasks {
|
||||
main = "net.runelite.deob.updater.UpdateMappings"
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
publications {
|
||||
register("asd", MavenPublication::class) {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
|
||||
* 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 HOLDER 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.api.config;
|
||||
|
||||
import java.awt.Dimension;
|
||||
|
||||
/**
|
||||
* A utility class containing constant values.
|
||||
*/
|
||||
public class Constants
|
||||
{
|
||||
/**
|
||||
* The original width of the game when running in fixed mode.
|
||||
*/
|
||||
public static final int GAME_FIXED_WIDTH = 765;
|
||||
|
||||
/**
|
||||
* The original height of the game when running in fixed mode.
|
||||
*/
|
||||
public static final int GAME_FIXED_HEIGHT = 503;
|
||||
|
||||
/**
|
||||
* Dimension representation of the width and height of the game in fixed mode.
|
||||
*/
|
||||
public static final Dimension GAME_FIXED_SIZE = new Dimension(GAME_FIXED_WIDTH, GAME_FIXED_HEIGHT);
|
||||
|
||||
/**
|
||||
* The aspect ratio of the game when running in fixed mode.
|
||||
*/
|
||||
public static final double GAME_FIXED_ASPECT_RATIO = (double) GAME_FIXED_WIDTH / (double) GAME_FIXED_HEIGHT;
|
||||
|
||||
/**
|
||||
* The default camera zoom value.
|
||||
*/
|
||||
public static final int CLIENT_DEFAULT_ZOOM = 512;
|
||||
|
||||
/**
|
||||
* The width and length of a chunk (8x8 tiles).
|
||||
*/
|
||||
public static final int CHUNK_SIZE = 8;
|
||||
|
||||
/**
|
||||
* The width and length of a map region (64x64 tiles).
|
||||
*/
|
||||
public static final int REGION_SIZE = 64;
|
||||
|
||||
/**
|
||||
* The width and length of the scene (13 chunks x 8 tiles).
|
||||
*/
|
||||
public static final int SCENE_SIZE = 104;
|
||||
|
||||
/**
|
||||
* The max allowed plane by the game.
|
||||
* <p>
|
||||
* This value is exclusive. The plane is set by 2 bits which restricts
|
||||
* the plane value to 0-3.
|
||||
*/
|
||||
public static final int MAX_Z = 4;
|
||||
|
||||
public static final int TILE_FLAG_BRIDGE = 2;
|
||||
|
||||
/**
|
||||
* The number of milliseconds in a client tick.
|
||||
* <p>
|
||||
* This is the length of a single frame when the client is running at
|
||||
* the maximum framerate of 50 fps.
|
||||
*/
|
||||
public static final int CLIENT_TICK_LENGTH = 20;
|
||||
|
||||
/**
|
||||
* The number of milliseconds in a server game tick.
|
||||
* <p>
|
||||
* This is the length of a single game cycle under ideal conditions.
|
||||
* All game-play actions operate within multiples of this duration.
|
||||
*/
|
||||
public static final int GAME_TICK_LENGTH = 600;
|
||||
|
||||
/**
|
||||
* Used when getting High Alchemy value - multiplied by general store price.
|
||||
*/
|
||||
public static final float HIGH_ALCHEMY_CONSTANT = 0.6f;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public class ClientSessionManager
|
||||
{
|
||||
sessionClient.openSession()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.from(clientThread))
|
||||
.observeOn(Schedulers.single())
|
||||
.subscribe(this::setUuid, this::error);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public class ClientSessionManager
|
||||
|
||||
sessionClient.pingSession(sessionId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.from(clientThread))
|
||||
.observeOn(Schedulers.single())
|
||||
.doOnError(this::error)
|
||||
.subscribe();
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class ClientSessionManager
|
||||
{
|
||||
sessionClient.delete(sessionId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.from(clientThread))
|
||||
.observeOn(Schedulers.single())
|
||||
.doOnError(this::error)
|
||||
.subscribe();
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ public class RuneLite
|
||||
|
||||
final ClientLoader clientLoader = new ClientLoader(options.valueOf(updateMode));
|
||||
Completable.fromAction(clientLoader::get)
|
||||
.subscribeOn(Schedulers.single())
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.subscribe();
|
||||
|
||||
Completable.fromAction(ClassPreloader::preload)
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
package net.runelite.client.callback;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.reactivex.plugins.RxJavaPlugins;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -45,6 +47,12 @@ public class ClientThread implements Executor
|
||||
@Nullable
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ClientThread()
|
||||
{
|
||||
RxJavaPlugins.setSingleSchedulerHandler(old -> Schedulers.from(this));
|
||||
}
|
||||
|
||||
public void invoke(Runnable r)
|
||||
{
|
||||
invoke(() ->
|
||||
|
||||
@@ -26,11 +26,11 @@ package net.runelite.client.config;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.util.ReflectUtil;
|
||||
|
||||
@Slf4j
|
||||
class ConfigInvocationHandler implements InvocationHandler
|
||||
@@ -169,7 +169,7 @@ class ConfigInvocationHandler implements InvocationHandler
|
||||
static Object callDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable
|
||||
{
|
||||
Class<?> declaringClass = method.getDeclaringClass();
|
||||
return ReflectUtil.privateLookupIn(declaringClass)
|
||||
return MethodHandles.privateLookupIn(declaringClass, MethodHandles.lookup())
|
||||
.unreflectSpecial(method, declaringClass)
|
||||
.bindTo(proxy)
|
||||
.invokeWithArguments(args);
|
||||
|
||||
@@ -449,6 +449,10 @@ public class ConfigManager
|
||||
{
|
||||
return Integer.parseInt(str);
|
||||
}
|
||||
if (type == long.class)
|
||||
{
|
||||
return Long.parseLong(str);
|
||||
}
|
||||
if (type == Color.class)
|
||||
{
|
||||
return ColorUtil.fromString(str);
|
||||
@@ -615,6 +619,10 @@ public class ConfigManager
|
||||
{
|
||||
return ((EnumSet) object).toArray()[0].getClass().getCanonicalName() + "{" + object.toString() + "}";
|
||||
}
|
||||
if (object instanceof Number)
|
||||
{
|
||||
return String.valueOf(object);
|
||||
}
|
||||
return object.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package net.runelite.client.eventbus;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.LambdaMetafactory;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.events.Event;
|
||||
|
||||
@Slf4j
|
||||
public class AccessorGenerator
|
||||
{
|
||||
public static Set<Subscription> scanSubscribes(Lookup caller, Object ref)
|
||||
{
|
||||
ImmutableSet.Builder<Subscription> builder = ImmutableSet.builder();
|
||||
|
||||
final Class<?> refClass = ref.getClass();
|
||||
caller = getPrivateAccess(refClass, caller).in(refClass);
|
||||
|
||||
for (Method method : refClass.getDeclaredMethods())
|
||||
{
|
||||
Subscribe sub = method.getAnnotation(Subscribe.class);
|
||||
if (sub != null)
|
||||
{
|
||||
final Consumer accessor;
|
||||
final Class paramType = method.getParameterTypes()[0];
|
||||
|
||||
try
|
||||
{
|
||||
accessor = getConsumerFor(caller, ref, method);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
log.warn("Creating consumer lambda for {} failed!", method, t);
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.add(new Subscription(paramType, accessor, sub.takeUntil(), sub.subscribe(), sub.observe()));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <EVENT extends Event> Consumer<EVENT> getConsumerFor(Lookup caller, Object ref, Method method) throws Throwable
|
||||
{
|
||||
final MethodHandle methodHandle = caller.unreflect(method);
|
||||
|
||||
final MethodType actualConsumer = methodHandle.type().dropParameterTypes(0, 1);
|
||||
final MethodType eventsConsumer = actualConsumer.erase();
|
||||
final MethodType factoryType = methodType(Consumer.class, ref.getClass());
|
||||
|
||||
final CallSite callsite = LambdaMetafactory.metafactory(
|
||||
caller, // To get past security checks
|
||||
"accept", // The name of the method to implement inside the lambda type
|
||||
factoryType, // Signature of the factory method
|
||||
eventsConsumer, // Signature of function implementation
|
||||
methodHandle, // Target method
|
||||
actualConsumer // Target method signature
|
||||
);
|
||||
|
||||
final MethodHandle factory = callsite.getTarget();
|
||||
return (Consumer<EVENT>) factory.invoke(ref);
|
||||
}
|
||||
|
||||
private static Lookup getPrivateAccess(Class<?> into, Lookup from)
|
||||
{
|
||||
try
|
||||
{
|
||||
return MethodHandles.privateLookupIn(into, from);
|
||||
}
|
||||
catch (IllegalAccessException a)
|
||||
{
|
||||
log.warn("Failed to get private access in {} from {}", into, from, a);
|
||||
return from;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import io.reactivex.annotations.Nullable;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.sentry.Sentry;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -19,7 +18,6 @@ import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.events.Event;
|
||||
import net.runelite.client.RuneLiteProperties;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.OpenOSRSConfig;
|
||||
|
||||
@Slf4j
|
||||
@@ -33,9 +31,6 @@ public class EventBus implements EventBusInterface
|
||||
@Inject
|
||||
private OpenOSRSConfig openOSRSConfig;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@NonNull
|
||||
private <T extends Event> Relay<Object> getSubject(Class<T> eventClass)
|
||||
{
|
||||
@@ -60,41 +55,9 @@ public class EventBus implements EventBusInterface
|
||||
return observable -> until > 0 ? observable.take(until) : observable;
|
||||
}
|
||||
|
||||
private Scheduler getScheduler(EventScheduler scheduler)
|
||||
{
|
||||
Scheduler subscribeScheduler;
|
||||
switch (scheduler)
|
||||
{
|
||||
case COMPUTATION:
|
||||
subscribeScheduler = Schedulers.computation();
|
||||
break;
|
||||
case IO:
|
||||
subscribeScheduler = Schedulers.io();
|
||||
break;
|
||||
case NEWTHREAD:
|
||||
subscribeScheduler = Schedulers.newThread();
|
||||
break;
|
||||
case SINGLE:
|
||||
subscribeScheduler = Schedulers.single();
|
||||
break;
|
||||
case TRAMPOLINE:
|
||||
subscribeScheduler = Schedulers.trampoline();
|
||||
break;
|
||||
case CLIENT:
|
||||
subscribeScheduler = Schedulers.from(clientThread);
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
subscribeScheduler = null;
|
||||
break;
|
||||
}
|
||||
|
||||
return subscribeScheduler;
|
||||
}
|
||||
|
||||
private <T> ObservableTransformer<T, T> applyScheduler(EventScheduler eventScheduler, boolean subscribe)
|
||||
{
|
||||
Scheduler scheduler = getScheduler(eventScheduler);
|
||||
Scheduler scheduler = eventScheduler.get();
|
||||
|
||||
return observable -> scheduler == null ? observable : subscribe ? observable.subscribeOn(scheduler) : observable.observeOn(scheduler);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
package net.runelite.client.eventbus;
|
||||
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.annotations.Nullable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.function.Supplier;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum EventScheduler
|
||||
{
|
||||
DEFAULT(null),
|
||||
COMPUTATION("computation"),
|
||||
IO("io"),
|
||||
NEWTHREAD("newThread"),
|
||||
SINGLE("single"),
|
||||
TRAMPOLINE("trampoline"),
|
||||
CLIENT("client");
|
||||
DEFAULT(() -> null),
|
||||
COMPUTATION(Schedulers::computation),
|
||||
IO(Schedulers::io),
|
||||
NEWTHREAD(Schedulers::newThread),
|
||||
SINGLE(Schedulers::single),
|
||||
TRAMPOLINE(Schedulers::trampoline),
|
||||
CLIENT(Schedulers::single);
|
||||
|
||||
public final String scheduler;
|
||||
private Supplier<Scheduler> scheduler;
|
||||
|
||||
EventScheduler(@Nullable String scheduler)
|
||||
@Nullable
|
||||
public Scheduler get()
|
||||
{
|
||||
this.scheduler = scheduler;
|
||||
return scheduler.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.runelite.client.eventbus;
|
||||
|
||||
import io.reactivex.functions.Consumer;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class Subscription
|
||||
{
|
||||
private final Class type;
|
||||
private final Consumer method;
|
||||
private final int takeUntil;
|
||||
private final EventScheduler subscribe;
|
||||
private final EventScheduler observe;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void subscribe(EventBus eventBus, Object lifecycle)
|
||||
{
|
||||
eventBus.subscribe(type, lifecycle, method, takeUntil, subscribe, observe);
|
||||
}
|
||||
}
|
||||
@@ -24,25 +24,23 @@
|
||||
*/
|
||||
package net.runelite.client.plugins;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import java.lang.reflect.Method;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Value;
|
||||
import net.runelite.api.events.Event;
|
||||
import net.runelite.client.eventbus.AccessorGenerator;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.EventScheduler;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.eventbus.Subscription;
|
||||
|
||||
public abstract class Plugin implements Module
|
||||
{
|
||||
private final Set<Subscription> annotatedSubscriptions = findSubscriptions();
|
||||
private final Object annotatedSubsLock = new Object();
|
||||
private Set<Subscription> annotatedSubscriptions = null;
|
||||
|
||||
@Getter(AccessLevel.PROTECTED)
|
||||
protected Injector injector;
|
||||
@@ -60,53 +58,33 @@ public abstract class Plugin implements Module
|
||||
{
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final void addAnnotatedSubscriptions(EventBus eventBus)
|
||||
{
|
||||
annotatedSubscriptions.forEach(sub -> eventBus.subscribe(sub.type, annotatedSubsLock, sub.method, sub.takeUntil, sub.subscribe, sub.observe));
|
||||
if (annotatedSubscriptions == null)
|
||||
{
|
||||
Observable.fromCallable(this::findSubscriptions)
|
||||
.subscribeOn(Schedulers.computation())
|
||||
.observeOn(Schedulers.single())
|
||||
.subscribe(subs -> addSubs(eventBus, (annotatedSubscriptions = subs)));
|
||||
}
|
||||
else
|
||||
{
|
||||
addSubs(eventBus, annotatedSubscriptions);
|
||||
}
|
||||
}
|
||||
|
||||
final void removeAnnotatedSubscriptions(EventBus eventBus)
|
||||
{
|
||||
eventBus.unregister(annotatedSubsLock);
|
||||
eventBus.unregister(this);
|
||||
}
|
||||
|
||||
private Set<Subscription> findSubscriptions()
|
||||
{
|
||||
ImmutableSet.Builder<Subscription> builder = ImmutableSet.builder();
|
||||
|
||||
for (Method method : this.getClass().getDeclaredMethods())
|
||||
{
|
||||
Subscribe annotation = method.getAnnotation(Subscribe.class);
|
||||
if (annotation == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
assert method.getParameterCount() == 1 : "Methods annotated with @Subscribe should have only one parameter";
|
||||
|
||||
Class<?> type = method.getParameterTypes()[0];
|
||||
|
||||
assert Event.class.isAssignableFrom(type) : "Parameters of methods annotated with @Subscribe should implement net.runelite.api.events.Event";
|
||||
assert method.getReturnType() == void.class : "Methods annotated with @Subscribe should have a void return type";
|
||||
|
||||
method.setAccessible(true);
|
||||
|
||||
Subscription sub = new Subscription(type.asSubclass(Event.class), event -> method.invoke(this, event), annotation.takeUntil(), annotation.subscribe(), annotation.observe());
|
||||
|
||||
builder.add(sub);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
return AccessorGenerator.scanSubscribes(MethodHandles.lookup(), this);
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class Subscription
|
||||
private void addSubs(EventBus eventBus, Collection<Subscription> subs)
|
||||
{
|
||||
private final Class type;
|
||||
private final Consumer method;
|
||||
private final int takeUntil;
|
||||
private final EventScheduler subscribe;
|
||||
private final EventScheduler observe;
|
||||
subs.forEach(s -> s.subscribe(eventBus, this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
package net.runelite.client.plugins;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.graph.Graph;
|
||||
@@ -218,13 +219,17 @@ public class PluginManager
|
||||
public void startCorePlugins()
|
||||
{
|
||||
List<Plugin> scannedPlugins = new ArrayList<>(plugins);
|
||||
int loaded = 0;
|
||||
int loaded = 0, started = 0;
|
||||
|
||||
final Stopwatch timer = Stopwatch.createStarted();
|
||||
for (Plugin plugin : scannedPlugins)
|
||||
{
|
||||
try
|
||||
{
|
||||
startPlugin(plugin);
|
||||
if (startPlugin(plugin))
|
||||
{
|
||||
++started;
|
||||
}
|
||||
}
|
||||
catch (PluginInstantiationException ex)
|
||||
{
|
||||
@@ -236,6 +241,8 @@ public class PluginManager
|
||||
|
||||
RuneLiteSplashScreen.stage(.80, 1, "Starting plugins", loaded, scannedPlugins.size());
|
||||
}
|
||||
|
||||
log.debug("Started {}/{} plugins in {}", started, loaded, timer);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -185,9 +185,8 @@ public class BlackjackPlugin extends Plugin
|
||||
@Override
|
||||
public boolean matches(MenuEntry entry)
|
||||
{
|
||||
return
|
||||
Text.removeTags(entry.getTarget(), true).equalsIgnoreCase(this.getTarget()) &&
|
||||
entry.getOption().equalsIgnoreCase(this.getOption());
|
||||
return entry.getOption().equalsIgnoreCase(this.getOption()) &&
|
||||
Text.removeTags(entry.getTarget(), true).equalsIgnoreCase(this.getTarget());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,7 +1025,7 @@ public class ChatCommandsPlugin extends Plugin
|
||||
ItemPrice item = retrieveFromList(results, search);
|
||||
CLIENT.lookupItem(item.getId())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.from(clientThread))
|
||||
.observeOn(Schedulers.single())
|
||||
.subscribe(
|
||||
(osbresult) ->
|
||||
{
|
||||
|
||||
@@ -362,7 +362,7 @@ public class ExaminePlugin extends Plugin
|
||||
int finalQuantity = quantity;
|
||||
CLIENT.lookupItem(id)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.from(clientThread))
|
||||
.observeOn(Schedulers.single())
|
||||
.subscribe(
|
||||
(osbresult) ->
|
||||
{
|
||||
|
||||
@@ -605,7 +605,7 @@ public class GrandExchangePlugin extends Plugin
|
||||
{
|
||||
CLIENT.lookupItem(itemId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.from(clientThread))
|
||||
.observeOn(Schedulers.single())
|
||||
.subscribe(
|
||||
(osbresult) ->
|
||||
{
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||
* Copyright (c) 2018, Abex
|
||||
* 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.util;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ReflectUtil
|
||||
{
|
||||
private ReflectUtil()
|
||||
{
|
||||
}
|
||||
|
||||
public static MethodHandles.Lookup privateLookupIn(Class clazz)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Java 9+ has privateLookupIn method on MethodHandles, but since we are shipping and using Java 8
|
||||
// we need to access it via reflection. This is preferred way because it's Java 9+ public api and is
|
||||
// likely to not change
|
||||
final Method privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
|
||||
return (MethodHandles.Lookup) privateLookupIn.invoke(null, clazz, MethodHandles.lookup());
|
||||
}
|
||||
catch (InvocationTargetException | IllegalAccessException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// In Java 8 we first do standard lookupIn class
|
||||
final MethodHandles.Lookup lookupIn = MethodHandles.lookup().in(clazz);
|
||||
|
||||
// and then we mark it as trusted for private lookup via reflection on private field
|
||||
final Field modes = MethodHandles.Lookup.class.getDeclaredField("allowedModes");
|
||||
modes.setAccessible(true);
|
||||
modes.setInt(lookupIn, -1); // -1 == TRUSTED
|
||||
return lookupIn;
|
||||
}
|
||||
catch (ReflectiveOperationException ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import java.applet.Applet;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -51,6 +52,7 @@ import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.RuneLiteModule;
|
||||
import net.runelite.client.config.Config;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
import net.runelite.client.eventbus.AccessorGenerator;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -218,7 +220,8 @@ public class PluginManagerTest
|
||||
}
|
||||
|
||||
TestPlugin plugin = new TestPlugin();
|
||||
pluginManager.startPlugin(plugin);
|
||||
AccessorGenerator.scanSubscribes(MethodHandles.lookup(), plugin)
|
||||
.forEach(s -> s.subscribe(eventbus, plugin));
|
||||
eventbus.post(TestEvent.class, new TestEvent());
|
||||
assert plugin.thisShouldBeTrue;
|
||||
}
|
||||
|
||||
@@ -29,12 +29,16 @@ dependencies {
|
||||
compileOnly(Libraries.guava)
|
||||
compileOnly(Libraries.javaxInject)
|
||||
compileOnly(Libraries.slf4jApi)
|
||||
|
||||
implementation(project(":runescape-api"))
|
||||
compileOnly(project(":runescape-api"))
|
||||
}
|
||||
|
||||
tasks {
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_7
|
||||
targetCompatibility = JavaVersion.VERSION_1_7
|
||||
disableAutoTargetJvm()
|
||||
}
|
||||
withType<JavaCompile> {
|
||||
options.compilerArgs.addAll(arrayOf("-source", "7", "-Xlint:-unchecked"))
|
||||
options.compilerArgs.addAll(arrayOf("-Xlint:-unchecked"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
*/
|
||||
package net.runelite.mixins;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import net.runelite.api.HashTable;
|
||||
import net.runelite.api.Node;
|
||||
import net.runelite.api.Point;
|
||||
@@ -31,20 +36,15 @@ import net.runelite.api.WidgetNode;
|
||||
import net.runelite.api.events.WidgetHiddenChanged;
|
||||
import net.runelite.api.events.WidgetPositioned;
|
||||
import net.runelite.api.mixins.Copy;
|
||||
import net.runelite.api.mixins.FieldHook;
|
||||
import net.runelite.api.mixins.Inject;
|
||||
import net.runelite.api.mixins.Mixin;
|
||||
import net.runelite.api.mixins.Replace;
|
||||
import net.runelite.api.mixins.Shadow;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||
import net.runelite.api.widgets.WidgetItem;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import net.runelite.api.mixins.FieldHook;
|
||||
import net.runelite.api.mixins.Inject;
|
||||
import net.runelite.api.mixins.Mixin;
|
||||
import net.runelite.api.mixins.Shadow;
|
||||
import net.runelite.rs.api.RSClient;
|
||||
import net.runelite.rs.api.RSModel;
|
||||
import net.runelite.rs.api.RSNode;
|
||||
@@ -215,22 +215,10 @@ public abstract class RSWidgetMixin implements RSWidget
|
||||
|
||||
Widget parent = getParent();
|
||||
|
||||
if (parent == null)
|
||||
{
|
||||
if (TO_GROUP(getId()) != client.getWidgetRoot())
|
||||
{
|
||||
// Widget has no parent and is not the root widget (which is always visible),
|
||||
// so it's not visible.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (parent.isHidden())
|
||||
{
|
||||
// If the parent is hidden, this widget is also hidden.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// If the parent is hidden, this widget is also hidden.
|
||||
// Widget has no parent and is not the root widget (which is always visible),
|
||||
// so it's not visible.
|
||||
return parent == null ? TO_GROUP(getId()) != client.getWidgetRoot() : parent.isHidden();
|
||||
}
|
||||
|
||||
@Inject
|
||||
|
||||
Reference in New Issue
Block a user