devtools: add shell window
This commit is contained in:
@@ -51,26 +51,20 @@ import net.runelite.client.util.ReflectUtil;
|
||||
@ThreadSafe
|
||||
public class EventBus
|
||||
{
|
||||
@FunctionalInterface
|
||||
public interface SubscriberMethod
|
||||
{
|
||||
void invoke(Object event);
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class Subscriber
|
||||
public static class Subscriber
|
||||
{
|
||||
private final Object object;
|
||||
private final Method method;
|
||||
private final float priority;
|
||||
@EqualsAndHashCode.Exclude
|
||||
private final SubscriberMethod lamda;
|
||||
private final Consumer<Object> lambda;
|
||||
|
||||
void invoke(final Object arg) throws Exception
|
||||
{
|
||||
if (lamda != null)
|
||||
if (lambda != null)
|
||||
{
|
||||
lamda.invoke(arg);
|
||||
lambda.accept(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -80,7 +74,9 @@ public class EventBus
|
||||
}
|
||||
|
||||
private final Consumer<Throwable> exceptionHandler;
|
||||
private ImmutableMultimap<Class, Subscriber> subscribers = ImmutableMultimap.of();
|
||||
|
||||
@Nonnull
|
||||
private ImmutableMultimap<Class<?>, Subscriber> subscribers = ImmutableMultimap.of();
|
||||
|
||||
/**
|
||||
* Instantiates EventBus with default exception handler
|
||||
@@ -99,13 +95,8 @@ public class EventBus
|
||||
*/
|
||||
public synchronized void register(@Nonnull final Object object)
|
||||
{
|
||||
final ImmutableMultimap.Builder<Class, Subscriber> builder = ImmutableMultimap.builder();
|
||||
|
||||
if (subscribers != null)
|
||||
{
|
||||
builder.putAll(subscribers);
|
||||
}
|
||||
|
||||
final ImmutableMultimap.Builder<Class<?>, Subscriber> builder = ImmutableMultimap.builder();
|
||||
builder.putAll(subscribers);
|
||||
builder.orderValuesBy(Comparator.comparing(Subscriber::getPriority).reversed()
|
||||
.thenComparing(s -> s.object.getClass().getName()));
|
||||
|
||||
@@ -141,7 +132,7 @@ public class EventBus
|
||||
Preconditions.checkArgument(method.getName().equals(preferredName), "Subscribed method " + method + " should be named " + preferredName);
|
||||
|
||||
method.setAccessible(true);
|
||||
SubscriberMethod lambda = null;
|
||||
Consumer<Object> lambda = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -150,14 +141,14 @@ public class EventBus
|
||||
final MethodHandle target = caller.findVirtual(clazz, method.getName(), subscription);
|
||||
final CallSite site = LambdaMetafactory.metafactory(
|
||||
caller,
|
||||
"invoke",
|
||||
MethodType.methodType(SubscriberMethod.class, clazz),
|
||||
"accept",
|
||||
MethodType.methodType(Consumer.class, clazz),
|
||||
subscription.changeParameterType(0, Object.class),
|
||||
target,
|
||||
subscription);
|
||||
|
||||
final MethodHandle factory = site.getTarget();
|
||||
lambda = (SubscriberMethod) factory.bindTo(object).invokeExact();
|
||||
lambda = (Consumer<Object>) factory.bindTo(object).invokeExact();
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
@@ -173,6 +164,21 @@ public class EventBus
|
||||
subscribers = builder.build();
|
||||
}
|
||||
|
||||
public synchronized <T> Subscriber register(Class<T> clazz, Consumer<T> subFn, float priority)
|
||||
{
|
||||
final ImmutableMultimap.Builder<Class<?>, Subscriber> builder = ImmutableMultimap.builder();
|
||||
builder.putAll(subscribers);
|
||||
builder.orderValuesBy(Comparator.comparing(Subscriber::getPriority).reversed()
|
||||
.thenComparing(s -> s.object.getClass().getName()));
|
||||
|
||||
Subscriber sub = new Subscriber(subFn, null, priority, (Consumer<Object>) subFn);
|
||||
builder.put(clazz, sub);
|
||||
|
||||
subscribers = builder.build();
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all subscribed methods from provided subscriber object.
|
||||
*
|
||||
@@ -180,12 +186,7 @@ public class EventBus
|
||||
*/
|
||||
public synchronized void unregister(@Nonnull final Object object)
|
||||
{
|
||||
if (subscribers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Multimap<Class, Subscriber> map = HashMultimap.create();
|
||||
final Multimap<Class<?>, Subscriber> map = HashMultimap.create();
|
||||
map.putAll(subscribers);
|
||||
|
||||
for (Class<?> clazz = object.getClass(); clazz != null; clazz = clazz.getSuperclass())
|
||||
@@ -207,6 +208,21 @@ public class EventBus
|
||||
subscribers = ImmutableMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
public synchronized void unregister(Subscriber sub)
|
||||
{
|
||||
if (sub == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Multimap<Class<?>, Subscriber> map = HashMultimap.create();
|
||||
map.putAll(subscribers);
|
||||
|
||||
map.values().remove(sub);
|
||||
|
||||
subscribers = ImmutableMultimap.copyOf(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts provided event to all registered subscribers. Subscriber calls are invoked immediately,
|
||||
* ordered by priority then their declaring class' name.
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.devtools;
|
||||
|
||||
import com.google.inject.ProvisionException;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.TrayIcon;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@@ -32,6 +33,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.MenuAction;
|
||||
@@ -44,6 +46,7 @@ import net.runelite.client.ui.overlay.infobox.Counter;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
@Slf4j
|
||||
class DevToolsPanel extends PluginPanel
|
||||
{
|
||||
private final Client client;
|
||||
@@ -174,6 +177,21 @@ class DevToolsPanel extends PluginPanel
|
||||
disconnectBtn.addActionListener(e -> clientThread.invoke(() -> client.setGameState(GameState.CONNECTION_LOST)));
|
||||
container.add(disconnectBtn);
|
||||
|
||||
try
|
||||
{
|
||||
ShellFrame sf = plugin.getInjector().getInstance(ShellFrame.class);
|
||||
container.add(plugin.getShell());
|
||||
plugin.getShell().addFrame(sf);
|
||||
}
|
||||
catch (LinkageError | ProvisionException e)
|
||||
{
|
||||
log.debug("Shell is not supported", e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.info("Shell couldn't be loaded", e);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ public class DevToolsPlugin extends Plugin
|
||||
private DevToolsButton soundEffects;
|
||||
private DevToolsButton scriptInspector;
|
||||
private DevToolsButton inventoryInspector;
|
||||
private DevToolsButton shell;
|
||||
private NavigationButton navButton;
|
||||
|
||||
@Provides
|
||||
@@ -187,6 +188,7 @@ public class DevToolsPlugin extends Plugin
|
||||
soundEffects = new DevToolsButton("Sound Effects");
|
||||
scriptInspector = new DevToolsButton("Script Inspector");
|
||||
inventoryInspector = new DevToolsButton("Inventory Inspector");
|
||||
shell = new DevToolsButton("Shell");
|
||||
|
||||
overlayManager.add(overlay);
|
||||
overlayManager.add(locationOverlay);
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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.plugins.devtools;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.jshell.ShellPanel;
|
||||
|
||||
@Singleton
|
||||
class ShellFrame extends DevToolsFrame
|
||||
{
|
||||
private final ShellPanel shellPanel;
|
||||
|
||||
@Inject
|
||||
ShellFrame(ClientThread clientThread, ScheduledExecutorService executor)
|
||||
{
|
||||
this.shellPanel = new ShellPanel(executor)
|
||||
{
|
||||
@Override
|
||||
protected void invokeOnClientThread(Runnable r)
|
||||
{
|
||||
clientThread.invoke(r);
|
||||
}
|
||||
};
|
||||
setContentPane(shellPanel);
|
||||
|
||||
setTitle("RuneLite Shell");
|
||||
|
||||
pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open()
|
||||
{
|
||||
shellPanel.switchContext(RuneLite.getInjector());
|
||||
super.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
super.close();
|
||||
shellPanel.freeContext();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user