rl-client: implement our pf4j plugins, extract pf4j out of net.runelite package. (#2883)

This commit is contained in:
Tyler Bochard
2020-12-26 19:28:30 -05:00
committed by GitHub
parent 7c021d2dcc
commit 53fe72452a
35 changed files with 4046 additions and 41 deletions

View File

@@ -0,0 +1,58 @@
package com.openosrs.client.util;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class DeferredDocumentChangedListener implements DocumentListener
{
private final Timer timer;
private final List<ChangeListener> listeners;
public DeferredDocumentChangedListener()
{
listeners = new ArrayList<>(25);
timer = new Timer(200, e -> fireStateChanged());
timer.setRepeats(false);
}
public void addChangeListener(ChangeListener listener)
{
listeners.add(listener);
}
private void fireStateChanged()
{
if (!listeners.isEmpty())
{
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : listeners)
{
listener.stateChanged(evt);
}
}
}
@Override
public void insertUpdate(DocumentEvent e)
{
timer.restart();
}
@Override
public void removeUpdate(DocumentEvent e)
{
timer.restart();
}
@Override
public void changedUpdate(DocumentEvent e)
{
timer.restart();
}
}

View File

@@ -0,0 +1,178 @@
package com.openosrs.client.util;
import com.openosrs.client.OpenOSRS;
import io.reactivex.rxjava3.subjects.PublishSubject;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite;
import com.openosrs.client.config.OpenOSRSConfig;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ClientShutdown;
import net.runelite.client.events.ConfigChanged;
import com.openosrs.client.ui.OpenOSRSSplashScreen;
import org.jgroups.Address;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.ObjectMessage;
import org.jgroups.Receiver;
import org.jgroups.View;
import org.jgroups.util.Util;
@Slf4j
@Singleton
public class Groups implements Receiver
{
private final OpenOSRSConfig openOSRSConfig;
private final JChannel channel;
@Getter(AccessLevel.PUBLIC)
private int instanceCount;
@Getter(AccessLevel.PUBLIC)
private List<Address> members;
@Getter(AccessLevel.PUBLIC)
private final Map<String, List<Address>> messageMap = new HashMap<>();
@Getter(AccessLevel.PUBLIC)
private final PublishSubject<Message> messageStringSubject = PublishSubject.create();
@Getter(AccessLevel.PUBLIC)
private final PublishSubject<Message> messageObjectSubject = PublishSubject.create();
@Inject
public Groups(OpenOSRSConfig openOSRSConfig, EventBus eventBus) throws Exception
{
this.openOSRSConfig = openOSRSConfig;
try (final InputStream is = RuneLite.class.getResourceAsStream("/udp-openosrs.xml"))
{
this.channel = new JChannel(is)
.setName(OpenOSRS.uuid)
.setReceiver(this)
.setDiscardOwnMessages(true)
.connect("openosrs");
}
eventBus.register(this);
}
@Subscribe
public void onClientShutdown(ClientShutdown event)
{
Future<Void> f = close();
event.waitFor(f);
}
public void broadcastSring(String command)
{
send(null, command);
}
public void sendConfig(Address destination, ConfigChanged configChanged)
{
if (!openOSRSConfig.localSync() || OpenOSRSSplashScreen.showing() || instanceCount < 2)
{
return;
}
try
{
byte[] buffer = Util.objectToByteBuffer(configChanged);
Message message = new ObjectMessage()
.setDest(destination)
.setObject(buffer);
channel.send(message);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void sendString(String command)
{
String[] messageObject = command.split(";");
String pluginId = messageObject[1];
messageMap.put(pluginId, new ArrayList<>());
for (Address member : channel.getView().getMembers())
{
if (member.toString().equals(OpenOSRS.uuid))
{
continue;
}
messageMap.get(pluginId).add(member);
send(member, command);
}
}
public void send(Address destination, String command)
{
if (!openOSRSConfig.localSync() || OpenOSRSSplashScreen.showing() || instanceCount < 2)
{
return;
}
try
{
channel.send(new ObjectMessage(destination, command));
}
catch (Exception e)
{
e.printStackTrace();
}
}
@Override
public void viewAccepted(View view)
{
members = view.getMembers();
instanceCount = members.size();
}
@Override
public void receive(Message message)
{
if (OpenOSRSSplashScreen.showing())
{
return;
}
if (message.getObject() instanceof String)
{
messageStringSubject.onNext(message);
}
else
{
messageObjectSubject.onNext(message);
}
}
private CompletableFuture<Void> close()
{
CompletableFuture<Void> future = new CompletableFuture<>();
try
{
channel.close();
future.complete(null);
}
catch (Exception ex)
{
future.completeExceptionally(ex);
}
return future;
}
}

View File

@@ -0,0 +1,59 @@
package com.openosrs.client.util;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.function.Predicate;
public class ImageUtil extends net.runelite.client.util.ImageUtil
{
/**
* Recolors pixels of the given image with the given color based on a given recolor condition
* predicate.
*
* @param image The image which should have its non-transparent pixels recolored.
* @param color The color with which to recolor pixels.
* @param recolorCondition The condition on which to recolor pixels with the given color.
* @return The given image with all pixels fulfilling the recolor condition predicate
* set to the given color.
*/
public static BufferedImage recolorImage(final BufferedImage image, final Color color, final Predicate<Color> recolorCondition)
{
final BufferedImage recoloredImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < recoloredImage.getWidth(); x++)
{
for (int y = 0; y < recoloredImage.getHeight(); y++)
{
final Color pixelColor = new Color(image.getRGB(x, y), true);
if (!recolorCondition.test(pixelColor))
{
recoloredImage.setRGB(x, y, image.getRGB(x, y));
continue;
}
recoloredImage.setRGB(x, y, color.getRGB());
}
}
return recoloredImage;
}
public static BufferedImage recolorImage(BufferedImage image, final Color color)
{
int width = image.getWidth();
int height = image.getHeight();
WritableRaster raster = image.getRaster();
for (int xx = 0; xx < width; xx++)
{
for (int yy = 0; yy < height; yy++)
{
int[] pixels = raster.getPixel(xx, yy, (int[]) null);
pixels[0] = color.getRed();
pixels[1] = color.getGreen();
pixels[2] = color.getBlue();
raster.setPixel(xx, yy, pixels);
}
}
return image;
}
}

View File

@@ -0,0 +1,202 @@
package com.openosrs.client.util;
import java.awt.Polygon;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.runelite.api.Client;
import net.runelite.api.Player;
import net.runelite.api.WorldType;
import net.runelite.api.coords.WorldPoint;
public class MiscUtils
{
private static final int[] abovePointsX = {2944, 3392, 3392, 2944};
private static final int[] abovePointsY = {3523, 3523, 3971, 3971};
private static final int[] belowPointsX = {2944, 2944, 3264, 3264};
private static final int[] belowPointsY = {9918, 10360, 10360, 9918};
private static final Polygon abovePoly = new Polygon(abovePointsX, abovePointsY, abovePointsX.length);
private static final Polygon belowPoly = new Polygon(belowPointsX, belowPointsY, belowPointsX.length);
private static final ChronoUnit[] ORDERED_CHRONOS = new ChronoUnit[]
{
ChronoUnit.YEARS,
ChronoUnit.MONTHS,
ChronoUnit.WEEKS,
ChronoUnit.DAYS,
ChronoUnit.HOURS,
ChronoUnit.MINUTES,
ChronoUnit.SECONDS
};
//test replacement so private for now
private static boolean inWildy(WorldPoint point)
{
if (point == null)
{
return false;
}
return abovePoly.contains(point.getX(), point.getY()) || belowPoly.contains(point.getX(), point.getY());
}
public static int getWildernessLevelFrom(Client client, WorldPoint point)
{
if (client == null)
{
return 0;
}
if (point == null)
{
return 0;
}
int x = point.getX();
if (point.getPlane() == 0 && (x < 2940 || x > 3391))
{
return 0;
}
int y = point.getY();
//v underground //v above ground
int wildernessLevel = clamp(y > 6400 ? ((y - 9920) / 8) + 1 : ((y - 3520) / 8) + 1, 0, 56);
if (point.getPlane() > 0 && y < 9920)
{
wildernessLevel = 0;
}
if (client.getWorldType().stream().anyMatch(worldType -> worldType == WorldType.PVP || worldType == WorldType.HIGH_RISK))
{
wildernessLevel += 15;
}
return Math.max(0, wildernessLevel);
}
public static int clamp(int val, int min, int max)
{
return Math.max(min, Math.min(max, val));
}
public static float clamp(float val, float min, float max)
{
return Math.max(min, Math.min(max, val));
}
public static boolean inWilderness(Client client)
{
Player localPlayer = client.getLocalPlayer();
if (localPlayer == null)
{
return false;
}
return inWildy(localPlayer.getWorldLocation());
//return getWildernessLevelFrom(client, localPlayer.getWorldLocation()) > 0;
}
public static String formatTimeAgo(Duration dur)
{
long dA = 0, dB = 0, rm;
ChronoUnit cA = null, cB = null;
for (int i = 0; i < ORDERED_CHRONOS.length; i++)
{
cA = ORDERED_CHRONOS[i];
dA = dur.getSeconds() / cA.getDuration().getSeconds();
rm = dur.getSeconds() % cA.getDuration().getSeconds();
if (dA <= 0)
{
cA = null;
continue;
}
if (i + 1 < ORDERED_CHRONOS.length)
{
cB = ORDERED_CHRONOS[i + 1];
dB = rm / cB.getDuration().getSeconds();
if (dB <= 0)
{
cB = null;
}
}
break;
}
if (cA == null)
{
return "just now.";
}
String str = formatUnit(cA, dA);
if (cB != null)
{
str += " and " + formatUnit(cB, dB);
}
return str + " ago.";
}
private static String formatUnit(ChronoUnit chrono, long val)
{
boolean multiple = val != 1;
String str;
if (multiple)
{
str = val + " ";
}
else
{
str = "a" + (chrono == ChronoUnit.HOURS ? "n " : " ");
}
str += chrono.name().toLowerCase();
if (!multiple)
{
if (str.charAt(str.length() - 1) == 's')
{
str = str.substring(0, str.length() - 1);
}
}
else if (str.charAt(str.length() - 1) != 's')
{
str += "s";
}
return str;
}
/**
* Mostly stolen from {@link java.net.URLStreamHandler#toExternalForm(URL)}
*
* @param url URL to encode
* @return URL, with path, query and ref encoded
*/
public static String urlToStringEncoded(URL url)
{
String s;
String path = url.getPath() != null ? Stream.of(url.getPath().split("/"))
.map(s2 -> URLEncoder.encode(s2, StandardCharsets.UTF_8)).collect(Collectors.joining("/")) : "";
return url.getProtocol()
+ ':'
+ (((s = url.getAuthority()) != null && s.length() > 0) ? "//" + s : "")
+ (path)
+ (((s = url.getQuery()) != null) ? '?' + urlEncode(s) : "")
+ (((s = url.getRef()) != null) ? '#' + urlEncode(s) : "");
}
private static String urlEncode(String s)
{
return URLEncoder.encode(s, StandardCharsets.UTF_8);
}
}

View File

@@ -0,0 +1,110 @@
package com.openosrs.client.util;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import net.runelite.client.util.CallableExceptionLogger;
import static net.runelite.client.util.RunnableExceptionLogger.wrap;
import org.jetbrains.annotations.NotNull;
// Awkward name because plugins already referenced the ExecutorServiceExceptionLogger
// (which only handles ScheduledExecutorServices) before this class was introduced
public class NonScheduledExecutorServiceExceptionLogger implements ExecutorService
{
private final ExecutorService service;
public NonScheduledExecutorServiceExceptionLogger(ExecutorService service)
{
this.service = service;
}
@Override
public void shutdown()
{
service.shutdown();
}
@NotNull
@Override
public List<Runnable> shutdownNow()
{
return service.shutdownNow();
}
@Override
public boolean isShutdown()
{
return service.isShutdown();
}
@Override
public boolean isTerminated()
{
return service.isTerminated();
}
@Override
public boolean awaitTermination(long timeout, @NotNull TimeUnit unit) throws InterruptedException
{
return service.awaitTermination(timeout, unit);
}
@Override
public void execute(@NotNull Runnable command)
{
service.execute(wrap(command));
}
@NotNull
@Override
public <T> Future<T> submit(@NotNull Callable<T> task)
{
return service.submit(CallableExceptionLogger.wrap(task));
}
@NotNull
@Override
public <T> Future<T> submit(@NotNull Runnable task, T result)
{
return service.submit(wrap(task), result);
}
@NotNull
@Override
public Future<?> submit(@NotNull Runnable task)
{
return service.submit(wrap(task));
}
@NotNull
@Override
public <T> List<Future<T>> invokeAll(@NotNull Collection<? extends Callable<T>> tasks) throws InterruptedException
{
return service.invokeAll(tasks);
}
@NotNull
@Override
public <T> List<Future<T>> invokeAll(@NotNull Collection<? extends Callable<T>> tasks, long timeout, @NotNull TimeUnit unit) throws InterruptedException
{
return service.invokeAll(tasks, timeout, unit);
}
@NotNull
@Override
public <T> T invokeAny(@NotNull Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException
{
return service.invokeAny(tasks);
}
@Override
public <T> T invokeAny(@NotNull Collection<? extends Callable<T>> tasks, long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
return service.invokeAny(tasks, timeout, unit);
}
}

View File

@@ -0,0 +1,19 @@
package com.openosrs.client.util;
import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
public class SwingUtil extends net.runelite.client.util.SwingUtil
{
public static void syncExec(final Runnable r) throws InvocationTargetException, InterruptedException
{
if (EventQueue.isDispatchThread())
{
r.run();
}
else
{
EventQueue.invokeAndWait(r);
}
}
}