Merge branch 'master' of https://github.com/open-osrs/runelite into fix-test-branch
This commit is contained in:
@@ -29,6 +29,7 @@ import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
@@ -41,6 +42,7 @@ public class ClientThread implements Executor
|
||||
private final ConcurrentLinkedQueue<BooleanSupplier> invokes = new ConcurrentLinkedQueue<>();
|
||||
|
||||
@Inject
|
||||
@Nullable
|
||||
private Client client;
|
||||
|
||||
public void invoke(Runnable r)
|
||||
|
||||
@@ -26,12 +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.Constructor;
|
||||
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,12 +168,8 @@ class ConfigInvocationHandler implements InvocationHandler
|
||||
|
||||
static Object callDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable
|
||||
{
|
||||
// Call the default method implementation - https://rmannibucau.wordpress.com/2014/03/27/java-8-default-interface-methods-and-jdk-dynamic-proxies/
|
||||
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
|
||||
constructor.setAccessible(true);
|
||||
|
||||
Class<?> declaringClass = method.getDeclaringClass();
|
||||
return constructor.newInstance(declaringClass, MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE)
|
||||
return ReflectUtil.privateLookupIn(declaringClass)
|
||||
.unreflectSpecial(method, declaringClass)
|
||||
.bindTo(proxy)
|
||||
.invokeWithArguments(args);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||
* 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.events;
|
||||
|
||||
import lombok.Value;
|
||||
import net.runelite.api.events.Event;
|
||||
import net.runelite.http.api.worlds.WorldResult;
|
||||
|
||||
/**
|
||||
* Fired when the @{link net.runelite.client.game.WorldService} refreshes the world list
|
||||
*/
|
||||
@Value
|
||||
public class WorldsFetch implements Event
|
||||
{
|
||||
private final WorldResult worldResult;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public class Flexo extends Robot
|
||||
public static final int fixedWidth = Constants.GAME_FIXED_WIDTH;
|
||||
public static final int fixedHeight = Constants.GAME_FIXED_HEIGHT;
|
||||
public static boolean isStretched;
|
||||
public static final int minDelay = 45;
|
||||
public static int minDelay = 45;
|
||||
public static MouseMotionFactory currentMouseMotionFactory;
|
||||
public boolean pausedIndefinitely = false;
|
||||
private Robot peer;
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||
* 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.game;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.events.WorldsFetch;
|
||||
import net.runelite.client.util.RunnableExceptionLogger;
|
||||
import net.runelite.http.api.worlds.World;
|
||||
import net.runelite.http.api.worlds.WorldClient;
|
||||
import net.runelite.http.api.worlds.WorldResult;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class WorldService
|
||||
{
|
||||
private static final int WORLD_FETCH_TIMER = 10; // minutes
|
||||
|
||||
private final Client client;
|
||||
private final ScheduledExecutorService scheduledExecutorService;
|
||||
private final WorldClient worldClient;
|
||||
private final EventBus eventBus;
|
||||
private final CompletableFuture<WorldResult> firstRunFuture = new CompletableFuture<>();
|
||||
|
||||
private WorldResult worlds;
|
||||
|
||||
@Inject
|
||||
private WorldService(Client client, ScheduledExecutorService scheduledExecutorService, WorldClient worldClient,
|
||||
EventBus eventBus)
|
||||
{
|
||||
this.client = client;
|
||||
this.scheduledExecutorService = scheduledExecutorService;
|
||||
this.worldClient = worldClient;
|
||||
this.eventBus = eventBus;
|
||||
|
||||
scheduledExecutorService.scheduleWithFixedDelay(RunnableExceptionLogger.wrap(this::tick), 0, WORLD_FETCH_TIMER, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private void tick()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (worlds == null || client.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
fetch();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
firstRunFuture.complete(worlds);
|
||||
}
|
||||
}
|
||||
|
||||
private void fetch()
|
||||
{
|
||||
log.debug("Fetching worlds");
|
||||
|
||||
try
|
||||
{
|
||||
WorldResult worldResult = worldClient.lookupWorlds();
|
||||
worldResult.getWorlds().sort(Comparator.comparingInt(World::getId));
|
||||
worlds = worldResult;
|
||||
eventBus.post(WorldsFetch.class, new WorldsFetch(worldResult));
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("Error looking up worlds", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh()
|
||||
{
|
||||
scheduledExecutorService.execute(this::fetch);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WorldResult getWorlds()
|
||||
{
|
||||
if (!firstRunFuture.isDone())
|
||||
{
|
||||
try
|
||||
{
|
||||
return firstRunFuture.get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException | ExecutionException | TimeoutException e)
|
||||
{
|
||||
log.warn("Failed to retrieve worlds on first run", e);
|
||||
}
|
||||
}
|
||||
|
||||
return worlds;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@ import net.runelite.client.input.KeyListener;
|
||||
import net.runelite.client.input.KeyManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Chat History",
|
||||
@@ -61,7 +62,7 @@ import net.runelite.client.plugins.PluginDescriptor;
|
||||
@Singleton
|
||||
public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
{
|
||||
private static final String WELCOME_MESSAGE = "Welcome to Old School RuneScape.";
|
||||
private static final String WELCOME_MESSAGE = "Welcome to Old School RuneScape";
|
||||
private static final String CLEAR_HISTORY = "Clear history";
|
||||
private static final String CLEAR_PRIVATE = "<col=ffff00>Private:";
|
||||
private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB;
|
||||
@@ -137,7 +138,8 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
{
|
||||
// Start sending old messages right after the welcome message, as that is most reliable source
|
||||
// of information that chat history was reset
|
||||
if (chatMessage.getMessage().equals(WELCOME_MESSAGE))
|
||||
ChatMessageType chatMessageType = chatMessage.getType();
|
||||
if (chatMessageType == ChatMessageType.WELCOME && StringUtils.startsWithIgnoreCase(chatMessage.getMessage(), WELCOME_MESSAGE))
|
||||
{
|
||||
if (!this.retainChatHistory)
|
||||
{
|
||||
@@ -154,7 +156,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
return;
|
||||
}
|
||||
|
||||
switch (chatMessage.getType())
|
||||
switch (chatMessageType)
|
||||
{
|
||||
case PRIVATECHATOUT:
|
||||
case PRIVATECHAT:
|
||||
@@ -174,7 +176,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
case FRIENDSCHAT:
|
||||
case CONSOLE:
|
||||
final QueuedMessage queuedMessage = QueuedMessage.builder()
|
||||
.type(chatMessage.getType())
|
||||
.type(chatMessageType)
|
||||
.name(chatMessage.getName())
|
||||
.sender(chatMessage.getSender())
|
||||
.value(tweakSpaces(chatMessage.getMessage()))
|
||||
|
||||
@@ -25,22 +25,21 @@
|
||||
package net.runelite.client.plugins.defaultworld;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.events.SessionOpen;
|
||||
import net.runelite.client.game.WorldService;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.util.WorldUtil;
|
||||
import net.runelite.http.api.worlds.World;
|
||||
import net.runelite.http.api.worlds.WorldClient;
|
||||
import net.runelite.http.api.worlds.WorldResult;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Default World",
|
||||
@@ -58,10 +57,7 @@ public class DefaultWorldPlugin extends Plugin
|
||||
private DefaultWorldConfig config;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private WorldClient worldClient;
|
||||
private WorldService worldService;
|
||||
|
||||
private int worldCache;
|
||||
private boolean worldChangeRequired;
|
||||
@@ -122,39 +118,33 @@ public class DefaultWorldPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
worldClient.lookupWorlds()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.from(clientThread))
|
||||
.subscribe(
|
||||
(worldResult) ->
|
||||
{
|
||||
if (worldResult == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
final WorldResult worldResult = worldService.getWorlds();
|
||||
|
||||
final World world = worldResult.findWorld(correctedWorld);
|
||||
if (worldResult == null)
|
||||
{
|
||||
log.warn("Failed to lookup worlds.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (world != null)
|
||||
{
|
||||
final net.runelite.api.World rsWorld = client.createWorld();
|
||||
rsWorld.setActivity(world.getActivity());
|
||||
rsWorld.setAddress(world.getAddress());
|
||||
rsWorld.setId(world.getId());
|
||||
rsWorld.setPlayerCount(world.getPlayers());
|
||||
rsWorld.setLocation(world.getLocation());
|
||||
rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes()));
|
||||
final World world = worldResult.findWorld(correctedWorld);
|
||||
|
||||
client.changeWorld(rsWorld);
|
||||
log.debug("Applied new world {}", correctedWorld);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.warn("World {} not found.", correctedWorld);
|
||||
}
|
||||
},
|
||||
(e) -> log.warn("Error looking up world {}. Error: {}", correctedWorld, e)
|
||||
);
|
||||
if (world != null)
|
||||
{
|
||||
final net.runelite.api.World rsWorld = client.createWorld();
|
||||
rsWorld.setActivity(world.getActivity());
|
||||
rsWorld.setAddress(world.getAddress());
|
||||
rsWorld.setId(world.getId());
|
||||
rsWorld.setPlayerCount(world.getPlayers());
|
||||
rsWorld.setLocation(world.getLocation());
|
||||
rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes()));
|
||||
|
||||
client.changeWorld(rsWorld);
|
||||
log.debug("Applied new world {}", correctedWorld);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.warn("World {} not found.", correctedWorld);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyWorld()
|
||||
|
||||
@@ -175,6 +175,10 @@ class WidgetInfoTableModel extends AbstractTableModel
|
||||
out.add(new WidgetField<>("RelativeY", Widget::getRelativeY, Widget::setRelativeY, Integer.class));
|
||||
out.add(new WidgetField<>("Width", Widget::getWidth, Widget::setWidth, Integer.class));
|
||||
out.add(new WidgetField<>("Height", Widget::getHeight, Widget::setHeight, Integer.class));
|
||||
out.add(new WidgetField<>("RotationX", Widget::getRotationX, Widget::setRotationX, Integer.class));
|
||||
out.add(new WidgetField<>("RotationY", Widget::getRotationY, Widget::setRotationY, Integer.class));
|
||||
out.add(new WidgetField<>("RotationZ", Widget::getRotationZ, Widget::setRotationZ, Integer.class));
|
||||
out.add(new WidgetField<>("ModelZoom", Widget::getModelZoom, Widget::setModelZoom, Integer.class));
|
||||
out.add(new WidgetField<>("CanvasLocation", Widget::getCanvasLocation));
|
||||
out.add(new WidgetField<>("Bounds", Widget::getBounds));
|
||||
out.add(new WidgetField<>("ScrollX", Widget::getScrollX, Widget::setScrollX, Integer.class));
|
||||
|
||||
@@ -84,7 +84,9 @@ enum Emoji
|
||||
ALIEN("(@.@)"),
|
||||
EGGPLANT("8=D"),
|
||||
WAVE("(^_^)/"),
|
||||
HEART_EYES("(*.*)");
|
||||
HEART_EYES("(*.*)"),
|
||||
FACEPALM("M-)"),
|
||||
;
|
||||
|
||||
private static final Map<String, Emoji> emojiMap;
|
||||
|
||||
|
||||
@@ -33,14 +33,15 @@ import net.runelite.client.config.Range;
|
||||
public interface FpsConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
keyName = "limitMode",
|
||||
name = "Limit Mode",
|
||||
description = "Stay at or under the target frames per second even when in this mode",
|
||||
keyName = "limitFps",
|
||||
name = "Limit Global FPS",
|
||||
description = "Global FPS limit in effect regardless of<br>" +
|
||||
"whether window is in focus or not",
|
||||
position = 1
|
||||
)
|
||||
default FpsLimitMode limitMode()
|
||||
default boolean limitFps()
|
||||
{
|
||||
return FpsLimitMode.NEVER;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Range(
|
||||
@@ -49,8 +50,8 @@ public interface FpsConfig extends Config
|
||||
)
|
||||
@ConfigItem(
|
||||
keyName = "maxFps",
|
||||
name = "FPS target",
|
||||
description = "Desired max frames per second",
|
||||
name = "Global FPS target",
|
||||
description = "Desired max global frames per second",
|
||||
position = 2
|
||||
)
|
||||
default int maxFps()
|
||||
@@ -58,11 +59,33 @@ public interface FpsConfig extends Config
|
||||
return 50;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "limitFpsUnfocused",
|
||||
name = "Limit FPS unfocused",
|
||||
description = "FPS limit while window is out of focus",
|
||||
position = 3
|
||||
)
|
||||
default boolean limitFpsUnfocused()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "maxFpsUnfocused",
|
||||
name = "Unfocused FPS target",
|
||||
description = "Desired max frames per second for unfocused",
|
||||
position = 4
|
||||
)
|
||||
default int maxFpsUnfocused()
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "drawFps",
|
||||
name = "Draw FPS indicator",
|
||||
description = "Show a number in the corner for the current FPS",
|
||||
position = 3
|
||||
position = 5
|
||||
)
|
||||
default boolean drawFps()
|
||||
{
|
||||
|
||||
@@ -69,7 +69,13 @@ public class FpsDrawListener implements Runnable
|
||||
void reloadConfig()
|
||||
{
|
||||
lastMillis = System.currentTimeMillis();
|
||||
targetDelay = 1000 / Math.max(1, config.maxFps());
|
||||
|
||||
int fps = config.limitFpsUnfocused() && !isFocused
|
||||
? config.maxFpsUnfocused()
|
||||
: config.maxFps();
|
||||
|
||||
targetDelay = 1000 / Math.max(1, fps);
|
||||
|
||||
sleepDelay = targetDelay;
|
||||
|
||||
for (int i = 0; i < SAMPLE_SIZE; i++)
|
||||
@@ -81,18 +87,18 @@ public class FpsDrawListener implements Runnable
|
||||
void onFocusChanged(FocusChanged event)
|
||||
{
|
||||
this.isFocused = event.isFocused();
|
||||
reloadConfig(); // load new delay
|
||||
}
|
||||
|
||||
private boolean isEnforced()
|
||||
{
|
||||
return FpsLimitMode.ALWAYS == plugin.getLimitMode()
|
||||
|| (FpsLimitMode.UNFOCUSED == plugin.getLimitMode() && !isFocused);
|
||||
return config.limitFps()
|
||||
|| (config.limitFpsUnfocused() && !isFocused);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
|
||||
if (!isEnforced())
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -57,16 +57,16 @@ public class FpsOverlay extends Overlay
|
||||
|
||||
// Local dependencies
|
||||
private final Client client;
|
||||
private final FpsPlugin plugin;
|
||||
private final FpsConfig config;
|
||||
|
||||
// Often changing values
|
||||
private boolean isFocused = true;
|
||||
|
||||
@Inject
|
||||
private FpsOverlay(final FpsPlugin plugin, final Client client)
|
||||
private FpsOverlay(final FpsConfig config, final Client client)
|
||||
{
|
||||
this.client = client;
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
setLayer(OverlayLayer.ABOVE_WIDGETS);
|
||||
setPriority(OverlayPriority.HIGH);
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
@@ -79,8 +79,8 @@ public class FpsOverlay extends Overlay
|
||||
|
||||
private boolean isEnforced()
|
||||
{
|
||||
return FpsLimitMode.ALWAYS == plugin.getLimitMode()
|
||||
|| (FpsLimitMode.UNFOCUSED == plugin.getLimitMode() && !isFocused);
|
||||
return config.limitFps()
|
||||
|| (config.limitFpsUnfocused() && !isFocused);
|
||||
}
|
||||
|
||||
private Color getFpsValueColor()
|
||||
@@ -91,7 +91,7 @@ public class FpsOverlay extends Overlay
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
if (!plugin.isDrawFps())
|
||||
if (!config.drawFps())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ package net.runelite.client.plugins.fps;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Singleton;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.events.FocusChanged;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
@@ -71,15 +69,6 @@ public class FpsPlugin extends Plugin
|
||||
@Inject
|
||||
private DrawManager drawManager;
|
||||
|
||||
@Inject
|
||||
private FpsConfig fpsConfig;
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private FpsLimitMode limitMode;
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private boolean drawFps;
|
||||
|
||||
@Provides
|
||||
FpsConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
@@ -92,9 +81,6 @@ public class FpsPlugin extends Plugin
|
||||
if (event.getGroup().equals(CONFIG_GROUP_KEY))
|
||||
{
|
||||
drawListener.reloadConfig();
|
||||
|
||||
limitMode = fpsConfig.limitMode();
|
||||
drawFps = fpsConfig.drawFps();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,9 +94,6 @@ public class FpsPlugin extends Plugin
|
||||
@Override
|
||||
protected void startUp()
|
||||
{
|
||||
|
||||
limitMode = fpsConfig.limitMode();
|
||||
drawFps = fpsConfig.drawFps();
|
||||
overlayManager.add(overlay);
|
||||
drawManager.registerEveryFrameListener(drawListener);
|
||||
drawListener.reloadConfig();
|
||||
|
||||
@@ -84,7 +84,6 @@ class InventoryGridOverlay extends Overlay
|
||||
final Point mousePoint = new Point(mouse.getX(), mouse.getY());
|
||||
final int if1DraggedItemIndex = client.getIf1DraggedItemIndex();
|
||||
final WidgetItem draggedItem = inventoryWidget.getWidgetItem(if1DraggedItemIndex);
|
||||
final int itemId = draggedItem.getId();
|
||||
final Rectangle initialBounds = draggedItem.getCanvasBounds();
|
||||
|
||||
if (initialMousePoint == null)
|
||||
@@ -92,7 +91,7 @@ class InventoryGridOverlay extends Overlay
|
||||
initialMousePoint = mousePoint;
|
||||
}
|
||||
|
||||
if (itemId == -1 || !hoverActive && initialMousePoint.distance(mousePoint) < DISTANCE_TO_ACTIVATE_HOVER)
|
||||
if (draggedItem.getId() == -1 || !hoverActive && initialMousePoint.distance(mousePoint) < DISTANCE_TO_ACTIVATE_HOVER)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -101,16 +100,15 @@ class InventoryGridOverlay extends Overlay
|
||||
|
||||
for (int i = 0; i < INVENTORY_SIZE; ++i)
|
||||
{
|
||||
WidgetItem widgetItem = inventoryWidget.getWidgetItem(i);
|
||||
final int targetItemId = widgetItem.getId();
|
||||
WidgetItem targetWidgetItem = inventoryWidget.getWidgetItem(i);
|
||||
|
||||
final Rectangle bounds = widgetItem.getCanvasBounds();
|
||||
final Rectangle bounds = targetWidgetItem.getCanvasBounds();
|
||||
boolean inBounds = bounds.contains(mousePoint);
|
||||
|
||||
if (plugin.isShowItem() && inBounds)
|
||||
{
|
||||
drawItem(graphics, bounds, itemId);
|
||||
drawItem(graphics, initialBounds, targetItemId);
|
||||
drawItem(graphics, bounds, draggedItem);
|
||||
drawItem(graphics, initialBounds, targetWidgetItem);
|
||||
}
|
||||
|
||||
if (plugin.isShowHighlight() && inBounds)
|
||||
@@ -128,14 +126,14 @@ class InventoryGridOverlay extends Overlay
|
||||
return null;
|
||||
}
|
||||
|
||||
private void drawItem(Graphics2D graphics, Rectangle bounds, int itemId)
|
||||
private void drawItem(Graphics2D graphics, Rectangle bounds, WidgetItem item)
|
||||
{
|
||||
if (itemId == -1)
|
||||
if (item.getId() == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final BufferedImage draggedItemImage = itemManager.getImage(itemId);
|
||||
final BufferedImage draggedItemImage = itemManager.getImage(item.getId(), item.getQuantity(), false);
|
||||
final int x = (int) bounds.getX();
|
||||
final int y = (int) bounds.getY();
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.IconID;
|
||||
import net.runelite.api.VarClientInt;
|
||||
import net.runelite.api.VarClientStr;
|
||||
import net.runelite.api.Varbits;
|
||||
@@ -212,7 +211,7 @@ public class KeyRemappingPlugin extends Plugin
|
||||
Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT);
|
||||
if (chatboxInput != null && chatboxInput.getText().endsWith(PRESS_ENTER_TO_CHAT))
|
||||
{
|
||||
chatboxInput.setText(getWaitingText());
|
||||
setChatboxWidgetInput(chatboxInput, PRESS_ENTER_TO_CHAT);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -227,7 +226,7 @@ public class KeyRemappingPlugin extends Plugin
|
||||
Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT);
|
||||
if (chatboxInput != null && chatboxFocused() && !typing)
|
||||
{
|
||||
chatboxInput.setText(getWaitingText());
|
||||
setChatboxWidgetInput(chatboxInput, PRESS_ENTER_TO_CHAT);
|
||||
}
|
||||
break;
|
||||
case SCRIPT_EVENT_BLOCK_CHAT_INPUT:
|
||||
@@ -246,7 +245,7 @@ public class KeyRemappingPlugin extends Plugin
|
||||
Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT);
|
||||
if (chatboxInput != null)
|
||||
{
|
||||
chatboxInput.setText(getWaitingText());
|
||||
setChatboxWidgetInput(chatboxInput, PRESS_ENTER_TO_CHAT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,39 +256,24 @@ public class KeyRemappingPlugin extends Plugin
|
||||
{
|
||||
final boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1;
|
||||
final Color textColor = isChatboxTransparent ? JagexColors.CHAT_TYPED_TEXT_TRANSPARENT_BACKGROUND : JagexColors.CHAT_TYPED_TEXT_OPAQUE_BACKGROUND;
|
||||
chatboxInput.setText(getPlayerNameWithIcon() + ": " + ColorUtil.wrapWithColorTag(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT) + "*", textColor));
|
||||
setChatboxWidgetInput(chatboxInput, ColorUtil.wrapWithColorTag(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT) + "*", textColor));
|
||||
}
|
||||
}
|
||||
|
||||
private String getPlayerNameWithIcon()
|
||||
{
|
||||
IconID icon;
|
||||
switch (client.getAccountType())
|
||||
{
|
||||
case IRONMAN:
|
||||
icon = IconID.IRONMAN;
|
||||
break;
|
||||
case ULTIMATE_IRONMAN:
|
||||
icon = IconID.ULTIMATE_IRONMAN;
|
||||
break;
|
||||
case HARDCORE_IRONMAN:
|
||||
icon = IconID.HARDCORE_IRONMAN;
|
||||
break;
|
||||
default:
|
||||
return client.getLocalPlayer().getName();
|
||||
}
|
||||
return icon + client.getLocalPlayer().getName();
|
||||
}
|
||||
|
||||
private String getWaitingText()
|
||||
private void setChatboxWidgetInput(Widget widget, String input)
|
||||
{
|
||||
if (this.hideDisplayName)
|
||||
{
|
||||
return PRESS_ENTER_TO_CHAT;
|
||||
widget.setText(input);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
String text = widget.getText();
|
||||
int idx = text.indexOf(':');
|
||||
if (idx != -1)
|
||||
{
|
||||
return getPlayerNameWithIcon() + ": " + PRESS_ENTER_TO_CHAT;
|
||||
String newText = text.substring(0, idx) + ": " + input;
|
||||
widget.setText(newText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (c) 2019, hsamoht <https://github.com/hsamoht>
|
||||
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||
* 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.leaguechaticons;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatPlayer;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.IconID;
|
||||
import net.runelite.api.IndexedSprite;
|
||||
import net.runelite.api.MessageNode;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.ScriptCallbackEvent;
|
||||
import net.runelite.api.util.Text;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.WorldService;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.http.api.worlds.World;
|
||||
import net.runelite.http.api.worlds.WorldResult;
|
||||
import net.runelite.http.api.worlds.WorldType;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Chat League Icons",
|
||||
description = "Changes the chat icon for players on league worlds",
|
||||
enabledByDefault = false
|
||||
)
|
||||
@Slf4j
|
||||
public class LeagueChatIconsPlugin extends Plugin
|
||||
{
|
||||
private static final String SCRIPT_EVENT_SET_CHATBOX_INPUT = "setChatboxInput";
|
||||
private static final String IRONMAN_PREFIX = "<img=" + IconID.IRONMAN.getIndex() + ">";
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ChatMessageManager chatMessageManager;
|
||||
|
||||
@Inject
|
||||
private WorldService worldService;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
private int leagueIconOffset = -1; // offset for league icon
|
||||
private boolean onLeagueWorld;
|
||||
|
||||
@Override
|
||||
protected void startUp()
|
||||
{
|
||||
onLeagueWorld = false;
|
||||
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
if (client.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
loadLeagueIcon();
|
||||
onLeagueWorld = isLeagueWorld(client.getWorld());
|
||||
if (onLeagueWorld)
|
||||
{
|
||||
setChatboxName(getNameChatbox());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown()
|
||||
{
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
if (client.getGameState() == GameState.LOGGED_IN && onLeagueWorld)
|
||||
{
|
||||
setChatboxName(getNameDefault());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||
{
|
||||
if (gameStateChanged.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
loadLeagueIcon();
|
||||
onLeagueWorld = isLeagueWorld(client.getWorld());
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent)
|
||||
{
|
||||
if (scriptCallbackEvent.getEventName().equals(SCRIPT_EVENT_SET_CHATBOX_INPUT) && onLeagueWorld)
|
||||
{
|
||||
setChatboxName(getNameChatbox());
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onChatMessage(ChatMessage chatMessage)
|
||||
{
|
||||
if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (chatMessage.getType())
|
||||
{
|
||||
case PRIVATECHAT:
|
||||
case MODPRIVATECHAT:
|
||||
// Note this is unable to change icon on PMs if they are not a friend or in clan chat
|
||||
case FRIENDSCHAT:
|
||||
String name = Text.removeTags(chatMessage.getName());
|
||||
if (isChatPlayerOnLeague(name))
|
||||
{
|
||||
addLeagueIconToMessage(chatMessage);
|
||||
}
|
||||
break;
|
||||
case PUBLICCHAT:
|
||||
case MODCHAT:
|
||||
if (onLeagueWorld)
|
||||
{
|
||||
addLeagueIconToMessage(chatMessage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the League Icon in front of player names chatting from a league world.
|
||||
*
|
||||
* @param chatMessage chat message to edit sender name on
|
||||
*/
|
||||
private void addLeagueIconToMessage(ChatMessage chatMessage)
|
||||
{
|
||||
String name = chatMessage.getName();
|
||||
if (!name.startsWith(IRONMAN_PREFIX))
|
||||
{
|
||||
// don't replace non-ironman icons, like mods
|
||||
return;
|
||||
}
|
||||
|
||||
name = Text.removeTags(name);
|
||||
|
||||
final MessageNode messageNode = chatMessage.getMessageNode();
|
||||
messageNode.setName(getNameWithIcon(leagueIconOffset, name));
|
||||
|
||||
chatMessageManager.update(messageNode);
|
||||
client.refreshChat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the player name in the chatbox input
|
||||
*/
|
||||
private void setChatboxName(String name)
|
||||
{
|
||||
Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT);
|
||||
if (chatboxInput != null)
|
||||
{
|
||||
String text = chatboxInput.getText();
|
||||
int idx = text.indexOf(':');
|
||||
if (idx != -1)
|
||||
{
|
||||
String newText = name + text.substring(idx);
|
||||
chatboxInput.setText(newText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the league name, including possible icon, of the local player.
|
||||
*
|
||||
* @return String of icon + name
|
||||
*/
|
||||
private String getNameChatbox()
|
||||
{
|
||||
Player player = client.getLocalPlayer();
|
||||
if (player != null)
|
||||
{
|
||||
return getNameWithIcon(leagueIconOffset, player.getName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default name, including possible icon, of the local player.
|
||||
*
|
||||
* @return String of icon + name
|
||||
*/
|
||||
private String getNameDefault()
|
||||
{
|
||||
Player player = client.getLocalPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int iconIndex;
|
||||
switch (client.getAccountType())
|
||||
{
|
||||
case IRONMAN:
|
||||
iconIndex = IconID.IRONMAN.getIndex();
|
||||
break;
|
||||
case HARDCORE_IRONMAN:
|
||||
iconIndex = IconID.HARDCORE_IRONMAN.getIndex();
|
||||
break;
|
||||
case ULTIMATE_IRONMAN:
|
||||
iconIndex = IconID.ULTIMATE_IRONMAN.getIndex();
|
||||
break;
|
||||
default:
|
||||
return player.getName();
|
||||
}
|
||||
|
||||
return getNameWithIcon(iconIndex, player.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a name formatted with icon
|
||||
*
|
||||
* @param iconIndex index of the icon
|
||||
* @param name name of the player
|
||||
* @return String of icon + name
|
||||
*/
|
||||
private static String getNameWithIcon(int iconIndex, String name)
|
||||
{
|
||||
String icon = "<img=" + iconIndex + ">";
|
||||
return icon + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a player name is a friend or clan member on a league world.
|
||||
*
|
||||
* @param name name of player to check.
|
||||
* @return boolean true/false.
|
||||
*/
|
||||
private boolean isChatPlayerOnLeague(String name)
|
||||
{
|
||||
ChatPlayer player = getChatPlayerFromName(name);
|
||||
|
||||
if (player == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int world = player.getWorld();
|
||||
return isLeagueWorld(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the world is a League world.
|
||||
*
|
||||
* @param worldNumber number of the world to check.
|
||||
* @return boolean true/false if it is a league world or not.
|
||||
*/
|
||||
private boolean isLeagueWorld(int worldNumber)
|
||||
{
|
||||
WorldResult worlds = worldService.getWorlds();
|
||||
if (worlds == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
World world = worlds.findWorld(worldNumber);
|
||||
return world != null && world.getTypes().contains(WorldType.LEAGUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the league icon into the client.
|
||||
*/
|
||||
private void loadLeagueIcon()
|
||||
{
|
||||
final IndexedSprite[] modIcons = client.getModIcons();
|
||||
|
||||
if (leagueIconOffset != -1 || modIcons == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage image = ImageUtil.getResourceStreamFromClass(getClass(), "league_icon.png");
|
||||
IndexedSprite indexedSprite = ImageUtil.getImageIndexedSprite(image, client);
|
||||
|
||||
leagueIconOffset = modIcons.length;
|
||||
|
||||
final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + 1);
|
||||
newModIcons[newModIcons.length - 1] = indexedSprite;
|
||||
|
||||
client.setModIcons(newModIcons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a ChatPlayer object from a clean name by searching clan and friends list.
|
||||
*
|
||||
* @param name name of player to find.
|
||||
* @return ChatPlayer if found, else null.
|
||||
*/
|
||||
private ChatPlayer getChatPlayerFromName(String name)
|
||||
{
|
||||
if (client.isClanMember(name))
|
||||
{
|
||||
return Arrays.stream(client.getClanMembers())
|
||||
.filter(clanMember -> Text.removeTags(clanMember.getUsername()).equals(name))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (client.isFriended(name, true))
|
||||
{
|
||||
return Arrays.stream(client.getFriends())
|
||||
.filter(friend -> Text.removeTags(friend.getName()).equals(name))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -122,10 +122,9 @@ public class LearnToClickPlugin extends Plugin
|
||||
MenuEntry[] menuEntries = client.getMenuEntries();
|
||||
for (MenuEntry entry : menuEntries)
|
||||
{
|
||||
if ((entry.getOption().equals("Floating") && this.shouldRightClickMap) ||
|
||||
(entry.getOption().equals("Hide") && this.shouldRightClickXp) || (entry.getOption().equals("Show")
|
||||
&& this.shouldRightClickXp) || (entry.getOption().equals("Auto retaliate")
|
||||
&& this.shouldRightClickRetaliate))
|
||||
if ((entry.getOption().equals("Floating <col=ff9040>World Map</col>") && this.shouldRightClickMap) ||
|
||||
(entry.getTarget().equals("<col=ff9040>XP drops</col>") && this.shouldRightClickXp) ||
|
||||
(entry.getOption().equals("Auto retaliate") && this.shouldRightClickRetaliate))
|
||||
{
|
||||
event.setForceRightClick(true);
|
||||
return;
|
||||
@@ -136,8 +135,8 @@ public class LearnToClickPlugin extends Plugin
|
||||
@Subscribe
|
||||
private void onMenuEntryAdded(MenuEntryAdded event)
|
||||
{
|
||||
if ((event.getOption().equals("Floating") && this.shouldRightClickMap) || (event.getOption().equals("Hide")
|
||||
&& this.shouldRightClickXp) || (event.getOption().equals("Show") && this.shouldRightClickXp) ||
|
||||
if ((event.getOption().equals("Floating <col=ff9040>World Map</col>") && this.shouldRightClickMap) ||
|
||||
(event.getTarget().equals("<col=ff9040>XP drops</col>") && this.shouldRightClickXp) ||
|
||||
(event.getOption().equals("Auto retaliate") && this.shouldRightClickRetaliate))
|
||||
{
|
||||
forceRightClickFlag = true;
|
||||
|
||||
@@ -105,7 +105,7 @@ public interface LootTrackerConfig extends Config
|
||||
@ConfigItem(
|
||||
keyName = "syncPanel",
|
||||
name = "Synchronize panel contents",
|
||||
description = "Synchronize you local loot tracker with your online (requires being logged in). This means" +
|
||||
description = "Synchronize your local loot tracker with your online (requires being logged in). This means" +
|
||||
" that panel is filled with portion of your remote data on startup and deleting data in panel deletes them" +
|
||||
" also on server."
|
||||
)
|
||||
|
||||
@@ -25,10 +25,12 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.music;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Provides;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -76,6 +78,10 @@ import net.runelite.client.plugins.PluginDescriptor;
|
||||
)
|
||||
public class MusicPlugin extends Plugin
|
||||
{
|
||||
private static final Set<Integer> SOURCELESS_PLAYER_SOUNDS = ImmutableSet.of(
|
||||
SoundEffectID.TELEPORT_VWOOP
|
||||
);
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@@ -559,13 +565,14 @@ public class MusicPlugin extends Plugin
|
||||
private void onAreaSoundEffectPlayed(AreaSoundEffectPlayed areaSoundEffectPlayed)
|
||||
{
|
||||
Actor source = areaSoundEffectPlayed.getSource();
|
||||
int soundId = areaSoundEffectPlayed.getSoundId();
|
||||
if (source == client.getLocalPlayer()
|
||||
&& musicConfig.muteOwnAreaSounds())
|
||||
{
|
||||
areaSoundEffectPlayed.consume();
|
||||
}
|
||||
else if (source != client.getLocalPlayer()
|
||||
&& source instanceof Player
|
||||
&& (source instanceof Player || (source == null && SOURCELESS_PLAYER_SOUNDS.contains(soundId)))
|
||||
&& musicConfig.muteOtherAreaSounds())
|
||||
{
|
||||
areaSoundEffectPlayed.consume();
|
||||
@@ -576,9 +583,10 @@ public class MusicPlugin extends Plugin
|
||||
areaSoundEffectPlayed.consume();
|
||||
}
|
||||
else if (source == null
|
||||
&& !SOURCELESS_PLAYER_SOUNDS.contains(soundId)
|
||||
&& musicConfig.muteEnvironmentAreaSounds())
|
||||
{
|
||||
areaSoundEffectPlayed.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import static net.runelite.api.Constants.REGION_SIZE;
|
||||
import net.runelite.api.DecorativeObject;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.GameState;
|
||||
@@ -350,8 +349,8 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
|
||||
|
||||
for (ObjectPoint objectPoint : objectPoints)
|
||||
{
|
||||
if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX()
|
||||
&& (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY())
|
||||
if (worldPoint.getRegionX() == objectPoint.getRegionX()
|
||||
&& worldPoint.getRegionY() == objectPoint.getRegionY())
|
||||
{
|
||||
// Transform object to get the name which matches against what we've stored
|
||||
if (objectPoint.getName().equals(getObjectDefinition(object.getId()).getName()))
|
||||
@@ -446,18 +445,27 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
|
||||
}
|
||||
final int regionId = worldPoint.getRegionID();
|
||||
final ObjectPoint point = new ObjectPoint(
|
||||
object.getId(),
|
||||
name,
|
||||
regionId,
|
||||
worldPoint.getX() & (REGION_SIZE - 1),
|
||||
worldPoint.getY() & (REGION_SIZE - 1),
|
||||
worldPoint.getRegionX(),
|
||||
worldPoint.getRegionY(),
|
||||
client.getPlane());
|
||||
|
||||
Set<ObjectPoint> objectPoints = points.computeIfAbsent(regionId, k -> new HashSet<>());
|
||||
|
||||
if (objectPoints.contains(point))
|
||||
if (objects.remove(object))
|
||||
{
|
||||
objectPoints.remove(point);
|
||||
objects.remove(object);
|
||||
// Use object id instead of name to match the object point with this object due to the object name being
|
||||
// able to change because of multilocs.
|
||||
if (!objectPoints.removeIf(op -> (op.getId() == -1 || op.getId() == object.getId())
|
||||
&& op.getRegionX() == worldPoint.getRegionX()
|
||||
&& op.getRegionY() == worldPoint.getRegionY()
|
||||
&& op.getZ() == worldPoint.getPlane()))
|
||||
{
|
||||
log.warn("unable to find object point for unmarked object {}", object.getId());
|
||||
}
|
||||
|
||||
log.debug("Unmarking object: {}", point);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -25,11 +25,16 @@
|
||||
|
||||
package net.runelite.client.plugins.objectindicators;
|
||||
|
||||
import lombok.Value;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Value
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ObjectPoint
|
||||
{
|
||||
private int id = -1;
|
||||
private String name;
|
||||
private int regionId;
|
||||
private int regionX;
|
||||
|
||||
@@ -33,7 +33,7 @@ import lombok.Getter;
|
||||
import net.runelite.client.plugins.raids.solver.Layout;
|
||||
import net.runelite.client.plugins.raids.solver.Room;
|
||||
|
||||
public class Raid
|
||||
class Raid
|
||||
{
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final RaidRoom[] rooms = new RaidRoom[16];
|
||||
|
||||
@@ -76,6 +76,7 @@ import net.runelite.api.util.Text;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import static net.runelite.api.widgets.WidgetID.BARROWS_REWARD_GROUP_ID;
|
||||
import static net.runelite.api.widgets.WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID;
|
||||
import static net.runelite.api.widgets.WidgetID.CHATBOX_GROUP_ID;
|
||||
import static net.runelite.api.widgets.WidgetID.CLUE_SCROLL_REWARD_GROUP_ID;
|
||||
import static net.runelite.api.widgets.WidgetID.DIALOG_SPRITE_GROUP_ID;
|
||||
import static net.runelite.api.widgets.WidgetID.KINGDOM_GROUP_ID;
|
||||
@@ -303,11 +304,11 @@ public class ScreenshotPlugin extends Plugin
|
||||
String fileName = null;
|
||||
if (client.getWidget(WidgetInfo.LEVEL_UP_LEVEL) != null)
|
||||
{
|
||||
fileName = parseLevelUpWidget(WidgetInfo.LEVEL_UP_LEVEL);
|
||||
fileName = parseLevelUpWidget(client.getWidget(WidgetInfo.LEVEL_UP_LEVEL));
|
||||
}
|
||||
else if (client.getWidget(WidgetInfo.DIALOG_SPRITE_TEXT) != null)
|
||||
{
|
||||
fileName = parseLevelUpWidget(WidgetInfo.DIALOG_SPRITE_TEXT);
|
||||
fileName = parseLevelUpWidget(client.getWidget(WidgetInfo.DIALOG_SPRITE_TEXT));
|
||||
}
|
||||
else if (client.getWidget(WidgetInfo.QUEST_COMPLETED_NAME_TEXT) != null)
|
||||
{
|
||||
@@ -315,6 +316,10 @@ public class ScreenshotPlugin extends Plugin
|
||||
String text = client.getWidget(WidgetInfo.QUEST_COMPLETED_NAME_TEXT).getText();
|
||||
fileName = "Quest(" + text.substring(19, text.length() - 1) + ")";
|
||||
}
|
||||
else if (client.getWidget(WidgetInfo.CHATBOX_CONTAINER).getChild(1) != null)
|
||||
{
|
||||
fileName = parseLevelUpWidget(client.getWidget(WidgetInfo.CHATBOX_CONTAINER).getChild(1));
|
||||
}
|
||||
|
||||
if (fileName != null)
|
||||
{
|
||||
@@ -485,6 +490,7 @@ public class ScreenshotPlugin extends Plugin
|
||||
break;
|
||||
case LEVEL_UP_GROUP_ID:
|
||||
case DIALOG_SPRITE_GROUP_ID:
|
||||
case CHATBOX_GROUP_ID:
|
||||
if (!this.screenshotLevels)
|
||||
{
|
||||
return;
|
||||
@@ -549,6 +555,7 @@ public class ScreenshotPlugin extends Plugin
|
||||
case LEVEL_UP_GROUP_ID:
|
||||
case DIALOG_SPRITE_GROUP_ID:
|
||||
case QUEST_COMPLETED_GROUP_ID:
|
||||
case CHATBOX_GROUP_ID:
|
||||
{
|
||||
// level up widget gets loaded prior to the text being set, so wait until the next tick
|
||||
shouldTakeScreenshot = true;
|
||||
@@ -574,22 +581,21 @@ public class ScreenshotPlugin extends Plugin
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a WidgetInfo pointing to the middle widget of the level-up dialog,
|
||||
* Receives a Widget containing the level-up dialog,
|
||||
* and parses it into a shortened string for filename usage.
|
||||
*
|
||||
* @param levelUpLevel WidgetInfo pointing to the required text widget,
|
||||
* with the format "Your Skill (level is/are) now 99."
|
||||
* @param levelUpWidget Widget containing the level-up text,
|
||||
* with the format "Your Skill (level is/are) now 99."
|
||||
* @return Shortened string in the format "Skill(99)"
|
||||
*/
|
||||
String parseLevelUpWidget(WidgetInfo levelUpLevel)
|
||||
String parseLevelUpWidget(Widget levelUpWidget)
|
||||
{
|
||||
Widget levelChild = client.getWidget(levelUpLevel);
|
||||
if (levelChild == null)
|
||||
if (levelUpWidget == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Matcher m = LEVEL_UP_PATTERN.matcher(levelChild.getText());
|
||||
Matcher m = LEVEL_UP_PATTERN.matcher(levelUpWidget.getText());
|
||||
if (!m.matches())
|
||||
{
|
||||
return null;
|
||||
|
||||
@@ -38,7 +38,8 @@ enum TeleportWidget
|
||||
WidgetInfo.SPELL_LUMBRIDGE_HOME_TELEPORT.getId(),
|
||||
WidgetInfo.SPELL_EDGEVILLE_HOME_TELEPORT.getId(),
|
||||
WidgetInfo.SPELL_LUNAR_HOME_TELEPORT.getId(),
|
||||
WidgetInfo.SPELL_ARCEUUS_HOME_TELEPORT.getId()
|
||||
WidgetInfo.SPELL_ARCEUUS_HOME_TELEPORT.getId(),
|
||||
WidgetInfo.SPELL_KOUREND_HOME_TELEPORT.getId()
|
||||
);
|
||||
private static final Collection MINIGAME_TELEPORT_IDS = ImmutableList.of(
|
||||
WidgetInfo.MINIGAME_TELEPORT_BUTTON.getId()
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Magic fTail
|
||||
* 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.virtuallevels;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.ModelID;
|
||||
import net.runelite.api.Skill;
|
||||
|
||||
@Getter
|
||||
public enum SkillModel
|
||||
{
|
||||
CONSTRUCTION1(Skill.CONSTRUCTION, ModelID.HAMMER, 10, 14, 669, 15, 0, 329),
|
||||
CONSTRUCTION2(Skill.CONSTRUCTION, ModelID.SAW, 11, 14, 615, 111, 0, 451),
|
||||
COOKING(Skill.COOKING, ModelID.COOKING_SKILL_MODEL, 31, 59, 169, 1593, 0, 963),
|
||||
CRAFTING1(Skill.CRAFTING, ModelID.HAMMER, 30, 24, 418, 14, 0, 496),
|
||||
CRAFTING2(Skill.CRAFTING, ModelID.CHISEL, 39, 45, 353, 18, 0, 400),
|
||||
DEFENCE(Skill.DEFENCE, ModelID.STEEL_KITESHIELD, 34, 37, 337, 1074, 0, 598),
|
||||
FARMING(Skill.FARMING, ModelID.WATERING_CAN, 31, 52, 118, 1278, 0, 451),
|
||||
FIREMAKING(Skill.FIREMAKING, ModelID.FIREMAKING_SKILL_MODEL, 29, 55, 115, 1689, 0, 771),
|
||||
FISHING(Skill.FISHING, ModelID.RAW_TUNA, 33, 30, 351, 1865, 0, 517),
|
||||
FLETCHING1(Skill.FLETCHING, ModelID.STEEL_ARROW, 43, 19, 254, 1257, 0, 408),
|
||||
FLETCHING2(Skill.FLETCHING, ModelID.STEEL_ARROW, 46, 44, 223, 177, 0, 444),
|
||||
HERBLORE(Skill.HERBLORE, ModelID.CLEAN_HERB, 20, 35, 550, 2024, 0, 344),
|
||||
HITPOINTS(Skill.HITPOINTS, ModelID.HEARTH, 35, 58, 538, 0, 0, 250),
|
||||
MAGIC(Skill.MAGIC, ModelID.BLUE_WIZARD_HAT, 29, 50, 131, 1913, 0, 344),
|
||||
MINING(Skill.MINING, ModelID.STEEL_PICKAXE, 38, 33, 292, 1166, 0, 413),
|
||||
PRAYER(Skill.PRAYER, ModelID.PRAYER_SKILL_MODEL, 29, 27, 582, 504, 0, 505),
|
||||
RANGED1(Skill.RANGED, ModelID.STEEL_ARROW, 28, 34, 206, 195, 0, 405),
|
||||
RANGED2(Skill.RANGED, ModelID.SHORTBOW, 42, 17, 422, 1618, 0, 397),
|
||||
RUNECRAFT(Skill.RUNECRAFT, ModelID.PURE_ESSENCE, 35, 38, 242, 1979, 0, 328),
|
||||
SLAYER(Skill.SLAYER, ModelID.SLAYER_SKILL_MODEL, 34, 60, 221, 1944, 0, 649),
|
||||
SMITHING(Skill.SMITHING, ModelID.ANVIL, 34, 53, 97, 1868, 0, 716),
|
||||
STRENGTH(Skill.STRENGTH, ModelID.STRENGTH_SKILL_MODEL, 35, 23, 512, 14, 0, 631),
|
||||
AGILITY(Skill.AGILITY, ModelID.AGILITY_SKILL_MODEL, 29, 29, 533, 2040, 0, 685),
|
||||
THIEVING(Skill.THIEVING, ModelID.HIGHWAYMAN_MASK, 42, 31, 366, 55, 0, 155),
|
||||
WOODCUTTING(Skill.WOODCUTTING, ModelID.WILLOW_TREE, 20, 69, 116, 1978, 0, 1800),
|
||||
ATTACK1(Skill.ATTACK, ModelID.STEEL_SWORD, 65, 38, 234, 148, 0, 444),
|
||||
ATTACK2(Skill.ATTACK, ModelID.STEEL_LONGSWORD, 27, 29, 198, 1419, 0, 330),
|
||||
HUNTER(Skill.HUNTER, ModelID.FOOTPRINT, 45, 48, 512, 0, 0, 1000);
|
||||
|
||||
private static final ListMultimap<Skill, SkillModel> skillModels = ArrayListMultimap.create();
|
||||
|
||||
private final Skill skill;
|
||||
private final int modelID;
|
||||
private final int originalX;
|
||||
private final int originalY;
|
||||
private final int rotationX;
|
||||
private final int rotationY;
|
||||
private final int rotationZ;
|
||||
private final int modelZoom;
|
||||
|
||||
SkillModel(Skill skill, int modelID, int originalX, int originalY, int rotationX, int rotationY, int rotationZ, int modelZoom)
|
||||
{
|
||||
this.skill = skill;
|
||||
this.modelID = modelID;
|
||||
this.originalX = originalX;
|
||||
this.originalY = originalY;
|
||||
this.rotationX = rotationX;
|
||||
this.rotationY = rotationY;
|
||||
this.rotationZ = rotationZ;
|
||||
this.modelZoom = modelZoom;
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
for (SkillModel skillModel : values())
|
||||
{
|
||||
skillModels.put(skillModel.skill, skillModel);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SkillModel> getSkillModels(Skill skill)
|
||||
{
|
||||
return skillModels.get(skill);
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,22 @@ import net.runelite.client.config.ConfigItem;
|
||||
@ConfigGroup("virtuallevels")
|
||||
public interface VirtualLevelsConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
keyName = "virtualMessage",
|
||||
name = "Enable level up message for virtual levels",
|
||||
description = "Configures whether or not to show level up messages for virtual levels",
|
||||
position = 0
|
||||
)
|
||||
default boolean virtualMessage()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "virtualTotalLevel",
|
||||
name = "Virtual Total Level",
|
||||
description = "Count virtual levels towards total level",
|
||||
position = 0
|
||||
position = 1
|
||||
)
|
||||
default boolean virtualTotalLevel()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Joshua Filby <joshua@filby.me>
|
||||
* Copyright (c) 2018, Jordan Atwood <jordan.atwood423@gmail.com>
|
||||
* Copyright (c) 2018, Magic fTail
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,17 +27,40 @@
|
||||
package net.runelite.client.plugins.virtuallevels;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Experience;
|
||||
import net.runelite.api.FontID;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.ScriptID;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.ScriptCallbackEvent;
|
||||
import net.runelite.api.events.StatChanged;
|
||||
import net.runelite.api.events.WidgetLoaded;
|
||||
import net.runelite.api.widgets.JavaScriptCallback;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetID;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetPositionMode;
|
||||
import net.runelite.api.widgets.WidgetSizeMode;
|
||||
import net.runelite.api.widgets.WidgetTextAlignment;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.client.events.PluginChanged;
|
||||
import net.runelite.client.input.KeyListener;
|
||||
import net.runelite.client.input.KeyManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
|
||||
@@ -47,9 +71,14 @@ import net.runelite.client.plugins.PluginDescriptor;
|
||||
enabledByDefault = false
|
||||
)
|
||||
@Singleton
|
||||
public class VirtualLevelsPlugin extends Plugin
|
||||
public class VirtualLevelsPlugin extends Plugin implements KeyListener
|
||||
{
|
||||
private static final String TOTAL_LEVEL_TEXT_PREFIX = "Total level:<br>";
|
||||
private static final int X_OFFSET = 13;
|
||||
private static final int Y_OFFSET = 16;
|
||||
|
||||
private final Map<Skill, Integer> previousXpMap = new EnumMap<>(Skill.class);
|
||||
private final List<Skill> skillsLeveledUp = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
private VirtualLevelsConfig config;
|
||||
@@ -60,6 +89,16 @@ public class VirtualLevelsPlugin extends Plugin
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private EventBus eventBus;
|
||||
|
||||
@Inject
|
||||
private KeyManager keyManager;
|
||||
|
||||
private boolean loginTick = false;
|
||||
private boolean closeMessage;
|
||||
private boolean messageOpen;
|
||||
|
||||
@Provides
|
||||
VirtualLevelsConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
@@ -71,6 +110,7 @@ public class VirtualLevelsPlugin extends Plugin
|
||||
protected void shutDown()
|
||||
{
|
||||
clientThread.invoke(this::simulateSkillChange);
|
||||
keyManager.unregisterKeyListener(this);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -79,6 +119,7 @@ public class VirtualLevelsPlugin extends Plugin
|
||||
// this is guaranteed to be called after the plugin has been registered by the eventbus. startUp is not.
|
||||
if (pluginChanged.getPlugin() == this)
|
||||
{
|
||||
keyManager.registerKeyListener(this);
|
||||
clientThread.invoke(this::simulateSkillChange);
|
||||
}
|
||||
}
|
||||
@@ -151,4 +192,226 @@ public class VirtualLevelsPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildVirtualLevelUp(Skill skill)
|
||||
{
|
||||
Widget chatboxContainer = client.getWidget(WidgetInfo.CHATBOX_CONTAINER);
|
||||
|
||||
if (chatboxContainer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
String skillName = skill.getName();
|
||||
int skillLevel = Experience.getLevelForXp(client.getSkillExperience(skill));
|
||||
List<SkillModel> skillModels = SkillModel.getSkillModels(skill);
|
||||
String prefix = (skill == Skill.AGILITY || skill == Skill.ATTACK) ? "an " : "a ";
|
||||
|
||||
Widget levelUpLevel = chatboxContainer.createChild(-1, WidgetType.TEXT);
|
||||
Widget levelUpText = chatboxContainer.createChild(-1, WidgetType.TEXT);
|
||||
Widget levelUpContinue = chatboxContainer.createChild(-1, WidgetType.TEXT);
|
||||
|
||||
levelUpLevel.setText("Congratulations, you just advanced " + prefix + skillName + " level.");
|
||||
levelUpLevel.setTextColor(0x000080);
|
||||
levelUpLevel.setFontId(FontID.QUILL_8);
|
||||
levelUpLevel.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
levelUpLevel.setOriginalX(73 + X_OFFSET);
|
||||
levelUpLevel.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
levelUpLevel.setOriginalY(15 + Y_OFFSET);
|
||||
levelUpLevel.setOriginalWidth(390);
|
||||
levelUpLevel.setOriginalHeight(30);
|
||||
levelUpLevel.setXTextAlignment(WidgetTextAlignment.CENTER);
|
||||
levelUpLevel.setYTextAlignment(WidgetTextAlignment.LEFT);
|
||||
levelUpLevel.setWidthMode(WidgetSizeMode.ABSOLUTE);
|
||||
levelUpLevel.revalidate();
|
||||
|
||||
levelUpText.setText((skill == Skill.HITPOINTS ? "Your Hitpoints are now " + skillLevel :
|
||||
"Your " + skillName + " level is now " + skillLevel) + ".");
|
||||
levelUpText.setFontId(FontID.QUILL_8);
|
||||
levelUpText.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
levelUpText.setOriginalX(73 + X_OFFSET);
|
||||
levelUpText.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
levelUpText.setOriginalY(44 + Y_OFFSET);
|
||||
levelUpText.setOriginalWidth(390);
|
||||
levelUpText.setOriginalHeight(30);
|
||||
levelUpText.setXTextAlignment(WidgetTextAlignment.CENTER);
|
||||
levelUpText.setYTextAlignment(WidgetTextAlignment.LEFT);
|
||||
levelUpText.setWidthMode(WidgetSizeMode.ABSOLUTE);
|
||||
levelUpText.revalidate();
|
||||
|
||||
levelUpContinue.setText("Click here to continue");
|
||||
levelUpContinue.setTextColor(0x0000ff);
|
||||
levelUpContinue.setFontId(FontID.QUILL_8);
|
||||
levelUpContinue.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
levelUpContinue.setOriginalX(73 + X_OFFSET);
|
||||
levelUpContinue.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
levelUpContinue.setOriginalY(74 + Y_OFFSET);
|
||||
levelUpContinue.setOriginalWidth(390);
|
||||
levelUpContinue.setOriginalHeight(17);
|
||||
levelUpContinue.setXTextAlignment(WidgetTextAlignment.CENTER);
|
||||
levelUpContinue.setYTextAlignment(WidgetTextAlignment.LEFT);
|
||||
levelUpContinue.setWidthMode(WidgetSizeMode.ABSOLUTE);
|
||||
levelUpContinue.setAction(0, "Continue");
|
||||
levelUpContinue.setOnOpListener((JavaScriptCallback) ev -> closeNextTick());
|
||||
levelUpContinue.setOnMouseOverListener((JavaScriptCallback) ev -> levelUpContinue.setTextColor(0xFFFFFF));
|
||||
levelUpContinue.setOnMouseLeaveListener((JavaScriptCallback) ev -> levelUpContinue.setTextColor(0x0000ff));
|
||||
levelUpContinue.setHasListener(true);
|
||||
levelUpContinue.revalidate();
|
||||
|
||||
for (SkillModel skillModel : skillModels)
|
||||
{
|
||||
buildWidgetModel(chatboxContainer, skillModel);
|
||||
}
|
||||
|
||||
messageOpen = true;
|
||||
}
|
||||
|
||||
private void buildWidgetModel(Widget chatboxContainer, SkillModel model)
|
||||
{
|
||||
int iconWidth = 32;
|
||||
int iconHeight = 32;
|
||||
|
||||
if (model.getSkill() == Skill.CONSTRUCTION)
|
||||
{
|
||||
iconWidth = 49;
|
||||
iconHeight = 61;
|
||||
}
|
||||
|
||||
Widget levelUpModel = chatboxContainer.createChild(-1, WidgetType.MODEL);
|
||||
|
||||
levelUpModel.setModelId(model.getModelID());
|
||||
levelUpModel.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
levelUpModel.setOriginalX(model.getOriginalX() + X_OFFSET);
|
||||
levelUpModel.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
|
||||
levelUpModel.setOriginalY(model.getOriginalY() + Y_OFFSET);
|
||||
levelUpModel.setOriginalWidth(iconWidth);
|
||||
levelUpModel.setOriginalHeight(iconHeight);
|
||||
levelUpModel.setRotationX(model.getRotationX());
|
||||
levelUpModel.setRotationY(model.getRotationY());
|
||||
levelUpModel.setRotationZ(model.getRotationZ());
|
||||
levelUpModel.setModelZoom(model.getModelZoom());
|
||||
levelUpModel.revalidate();
|
||||
}
|
||||
|
||||
private void closeNextTick()
|
||||
{
|
||||
if (!messageOpen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Widget levelUpContinue = client.getWidget(WidgetInfo.CHATBOX_CONTAINER).getChild(2);
|
||||
|
||||
levelUpContinue.setText("Please wait...");
|
||||
|
||||
messageOpen = false;
|
||||
closeMessage = true;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged event)
|
||||
{
|
||||
if (event.getGameState() == GameState.LOGIN_SCREEN)
|
||||
{
|
||||
loginTick = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (Skill skill : Skill.values())
|
||||
{
|
||||
previousXpMap.put(skill, client.getSkillExperience(skill));
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatChanged(StatChanged event)
|
||||
{
|
||||
Skill skill = event.getSkill();
|
||||
|
||||
int xpAfter = client.getSkillExperience(skill);
|
||||
int levelAfter = Experience.getLevelForXp(xpAfter);
|
||||
|
||||
int xpBefore = previousXpMap.get(skill);
|
||||
int levelBefore = Experience.getLevelForXp(xpBefore);
|
||||
|
||||
previousXpMap.put(skill, xpAfter);
|
||||
|
||||
if (!config.virtualMessage() || levelAfter < 100 || levelBefore >= levelAfter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!loginTick)
|
||||
{
|
||||
skillsLeveledUp.add(skill);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameTick(GameTick event)
|
||||
{
|
||||
loginTick = false;
|
||||
|
||||
if (closeMessage)
|
||||
{
|
||||
clientThread.invoke(() -> client.runScript(
|
||||
ScriptID.MESSAGE_LAYER_CLOSE,
|
||||
1,
|
||||
1
|
||||
));
|
||||
|
||||
closeMessage = false;
|
||||
}
|
||||
|
||||
if (skillsLeveledUp.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Widget chatboxContainer = client.getWidget(WidgetInfo.CHATBOX_CONTAINER);
|
||||
|
||||
if (chatboxContainer != null && !chatboxContainer.isHidden())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Skill skill = skillsLeveledUp.get(0);
|
||||
|
||||
skillsLeveledUp.remove(skill);
|
||||
|
||||
clientThread.invoke(() -> client.runScript(ScriptID.MESSAGE_LAYER_OPEN));
|
||||
clientThread.invoke(() -> buildVirtualLevelUp(skill));
|
||||
WidgetLoaded widgetLoaded = new WidgetLoaded();
|
||||
widgetLoaded.setGroupId(WidgetID.CHATBOX_GROUP_ID);
|
||||
eventBus.post(WidgetLoaded.class, widgetLoaded);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e)
|
||||
{
|
||||
if (e.getKeyChar() != ' ')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (messageOpen)
|
||||
{
|
||||
closeNextTick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,23 +25,27 @@
|
||||
package net.runelite.client.plugins.woodcutting;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import lombok.AccessLevel;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.Getter;
|
||||
import static net.runelite.api.ObjectID.REDWOOD;
|
||||
import static net.runelite.api.ObjectID.REDWOOD_29670;
|
||||
import static net.runelite.api.NullObjectID.NULL_10823;
|
||||
import static net.runelite.api.NullObjectID.NULL_10835;
|
||||
import net.runelite.api.ObjectID;
|
||||
import static net.runelite.api.ObjectID.*;
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
@Getter
|
||||
enum Tree
|
||||
{
|
||||
REDWOOD_TREE_SPAWN(REDWOOD, REDWOOD_29670);
|
||||
|
||||
private final int[] treeIds;
|
||||
|
||||
Tree(final int... treeIds)
|
||||
{
|
||||
this.treeIds = treeIds;
|
||||
}
|
||||
REGULAR_TREE(null, TREE, TREE_1277, TREE_1278, TREE_1279, TREE_1280),
|
||||
OAK_TREE(Duration.ofMillis(8500), ObjectID.OAK_TREE, OAK_TREE_4540, OAK_10820),
|
||||
WILLOW_TREE(Duration.ofMillis(8500), WILLOW, WILLOW_10833, WILLOW_10831),
|
||||
MAPLE_TREE(Duration.ofSeconds(35), ObjectID.MAPLE_TREE, MAPLE_TREE_10832, MAPLE_TREE_36681),
|
||||
TEAK_TREE(Duration.ofMillis(8500), TEAK, TEAK_36686),
|
||||
MAHOGANY_TREE(Duration.ofMillis(8500), MAHOGANY, MAHOGANY_36688),
|
||||
YEW_TREE(Duration.ofMinutes(1), YEW, NULL_10823, YEW_36683),
|
||||
MAGIC_TREE(Duration.ofMinutes(2), MAGIC_TREE_10834, NULL_10835),
|
||||
REDWOOD(Duration.ofMinutes(2), ObjectID.REDWOOD, REDWOOD_29670);
|
||||
|
||||
private static final Map<Integer, Tree> TREES;
|
||||
|
||||
@@ -60,6 +64,16 @@ enum Tree
|
||||
TREES = builder.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private final Duration respawnTime;
|
||||
private final int[] treeIds;
|
||||
|
||||
Tree(@org.jetbrains.annotations.Nullable Duration respawnTime, int... treeIds)
|
||||
{
|
||||
this.respawnTime = respawnTime;
|
||||
this.treeIds = treeIds;
|
||||
}
|
||||
|
||||
static Tree findTree(int objectId)
|
||||
{
|
||||
return TREES.get(objectId);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2019, David <Dava96@github.com>
|
||||
* 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.woodcutting;
|
||||
|
||||
import java.time.Instant;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
class TreeRespawn
|
||||
{
|
||||
private final Tree tree;
|
||||
private final LocalPoint location;
|
||||
private final Instant startTime;
|
||||
private final int respawnTime;
|
||||
|
||||
boolean isExpired()
|
||||
{
|
||||
return Instant.now().isAfter(startTime.plusMillis(respawnTime));
|
||||
}
|
||||
}
|
||||
@@ -85,4 +85,15 @@ public interface WoodcuttingConfig extends Config
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 6,
|
||||
keyName = "showRespawnTimers",
|
||||
name = "Show respawn timers",
|
||||
description = "Configures whether to display the respawn timer overlay"
|
||||
)
|
||||
default boolean showRespawnTimers()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,6 @@ import net.runelite.client.ui.overlay.components.TitleComponent;
|
||||
import net.runelite.client.ui.overlay.components.table.TableAlignment;
|
||||
import net.runelite.client.ui.overlay.components.table.TableComponent;
|
||||
|
||||
|
||||
@Singleton
|
||||
class WoodcuttingOverlay extends Overlay
|
||||
{
|
||||
@@ -51,17 +50,18 @@ class WoodcuttingOverlay extends Overlay
|
||||
|
||||
private final Client client;
|
||||
private final WoodcuttingPlugin plugin;
|
||||
private final WoodcuttingConfig config;
|
||||
private final XpTrackerService xpTrackerService;
|
||||
private final PanelComponent panelComponent = new PanelComponent();
|
||||
|
||||
|
||||
@Inject
|
||||
private WoodcuttingOverlay(final Client client, final WoodcuttingPlugin plugin, final XpTrackerService xpTrackerService)
|
||||
private WoodcuttingOverlay(Client client, WoodcuttingPlugin plugin, WoodcuttingConfig config, XpTrackerService xpTrackerService)
|
||||
{
|
||||
super(plugin);
|
||||
setPosition(OverlayPosition.TOP_LEFT);
|
||||
this.client = client;
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.xpTrackerService = xpTrackerService;
|
||||
getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Woodcutting overlay"));
|
||||
getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY, WOODCUTTING_RESET, "Woodcutting overlay"));
|
||||
@@ -70,7 +70,7 @@ class WoodcuttingOverlay extends Overlay
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
if (!plugin.isShowWoodcuttingStats())
|
||||
if (!config.showWoodcuttingStats())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -107,7 +107,7 @@ class WoodcuttingOverlay extends Overlay
|
||||
{
|
||||
tableComponent.addRow("Logs cut:", Integer.toString(actions));
|
||||
|
||||
if (plugin.isShowGPEarned())
|
||||
if (config.showGPEarned())
|
||||
{
|
||||
tableComponent.addRow("GP earned:", Integer.toString((plugin.getGpEarned())));
|
||||
}
|
||||
@@ -123,5 +123,4 @@ class WoodcuttingOverlay extends Overlay
|
||||
return panelComponent.render(graphics);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -27,17 +27,18 @@ package net.runelite.client.plugins.woodcutting;
|
||||
import com.google.inject.Provides;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.MenuOpcode;
|
||||
import net.runelite.api.Player;
|
||||
@@ -51,7 +52,6 @@ import net.runelite.api.events.GameTick;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.client.events.OverlayMenuClicked;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
@@ -64,14 +64,21 @@ import net.runelite.client.ui.overlay.OverlayMenuEntry;
|
||||
@PluginDescriptor(
|
||||
name = "Woodcutting",
|
||||
description = "Show woodcutting statistics and/or bird nest notifications",
|
||||
tags = {"birds", "nest", "notifications", "overlay", "skilling", "wc"}
|
||||
tags = {"birds", "nest", "notifications", "overlay", "skilling", "wc"},
|
||||
enabledByDefault = false
|
||||
)
|
||||
@Singleton
|
||||
@PluginDependency(XpTrackerPlugin.class)
|
||||
@Slf4j
|
||||
public class WoodcuttingPlugin extends Plugin
|
||||
{
|
||||
private static final Pattern WOOD_CUT_PATTERN = Pattern.compile("You get (?:some|an)[\\w ]+(?:logs?|mushrooms)\\.");
|
||||
|
||||
@Getter
|
||||
private final Set<GameObject> treeObjects = new HashSet<>();
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final List<TreeRespawn> respawns = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
private Notifier notifier;
|
||||
|
||||
@@ -93,24 +100,13 @@ public class WoodcuttingPlugin extends Plugin
|
||||
@Inject
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
@Getter
|
||||
private WoodcuttingSession session;
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
@Getter
|
||||
private Axe axe;
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final Set<GameObject> treeObjects = new HashSet<>();
|
||||
|
||||
private int statTimeout;
|
||||
boolean showNestNotification;
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private boolean showWoodcuttingStats;
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private boolean showRedwoodTrees;
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private boolean showGPEarned;
|
||||
|
||||
private boolean recentlyLoggedIn;
|
||||
private int treeTypeID;
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private int gpEarned;
|
||||
@@ -122,19 +118,18 @@ public class WoodcuttingPlugin extends Plugin
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp()
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
updateConfig();
|
||||
|
||||
overlayManager.add(overlay);
|
||||
overlayManager.add(treesOverlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown()
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
overlayManager.remove(overlay);
|
||||
overlayManager.remove(treesOverlay);
|
||||
respawns.clear();
|
||||
treeObjects.clear();
|
||||
session = null;
|
||||
axe = null;
|
||||
@@ -155,12 +150,16 @@ public class WoodcuttingPlugin extends Plugin
|
||||
@Subscribe
|
||||
private void onGameTick(GameTick gameTick)
|
||||
{
|
||||
recentlyLoggedIn = false;
|
||||
|
||||
respawns.removeIf(TreeRespawn::isExpired);
|
||||
|
||||
if (session == null || session.getLastLogCut() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Duration statTimeout = Duration.ofMinutes(this.statTimeout);
|
||||
Duration statTimeout = Duration.ofMinutes(config.statTimeout());
|
||||
Duration sinceCut = Duration.between(session.getLastLogCut(), Instant.now());
|
||||
|
||||
if (sinceCut.compareTo(statTimeout) >= 0)
|
||||
@@ -189,13 +188,90 @@ public class WoodcuttingPlugin extends Plugin
|
||||
gpEarned += itemManager.getItemPrice(treeTypeID);
|
||||
}
|
||||
|
||||
if (event.getMessage().contains("A bird's nest falls out of the tree") && this.showNestNotification)
|
||||
if (event.getMessage().contains("A bird's nest falls out of the tree") && config.showNestNotification())
|
||||
{
|
||||
notifier.notify("A bird nest has spawned!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameObjectSpawned(final GameObjectSpawned event)
|
||||
{
|
||||
GameObject gameObject = event.getGameObject();
|
||||
Tree tree = Tree.findTree(gameObject.getId());
|
||||
|
||||
if (tree == Tree.REDWOOD)
|
||||
{
|
||||
treeObjects.add(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameObjectDespawned(final GameObjectDespawned event)
|
||||
{
|
||||
final GameObject object = event.getGameObject();
|
||||
|
||||
Tree tree = Tree.findTree(object.getId());
|
||||
if (tree != null)
|
||||
{
|
||||
if (tree.getRespawnTime() != null && !recentlyLoggedIn)
|
||||
{
|
||||
log.debug("Adding respawn timer for {} tree at {}", tree, object.getLocalLocation());
|
||||
TreeRespawn treeRespawn = new TreeRespawn(tree, object.getLocalLocation(), Instant.now(), (int) tree.getRespawnTime().toMillis());
|
||||
respawns.add(treeRespawn);
|
||||
}
|
||||
|
||||
if (tree == Tree.REDWOOD)
|
||||
{
|
||||
treeObjects.remove(event.getGameObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameObjectChanged(final GameObjectChanged event)
|
||||
{
|
||||
treeObjects.remove(event.getGameObject());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameStateChanged(final GameStateChanged event)
|
||||
{
|
||||
switch (event.getGameState())
|
||||
{
|
||||
case LOADING:
|
||||
case HOPPING:
|
||||
respawns.clear();
|
||||
treeObjects.clear();
|
||||
break;
|
||||
case LOGGED_IN:
|
||||
// After login trees that are depleted will be changed,
|
||||
// wait for the next game tick before watching for
|
||||
// trees to despawn
|
||||
recentlyLoggedIn = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onAnimationChanged(final AnimationChanged event)
|
||||
{
|
||||
Player local = client.getLocalPlayer();
|
||||
|
||||
if (event.getActor() != local)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int animId = local.getAnimation();
|
||||
Axe axe = Axe.findAxeByAnimId(animId);
|
||||
if (axe != null)
|
||||
{
|
||||
this.axe = axe;
|
||||
}
|
||||
}
|
||||
|
||||
private void typeOfLogCut(String message)
|
||||
{
|
||||
if (message.contains("mushrooms."))
|
||||
@@ -239,75 +315,4 @@ public class WoodcuttingPlugin extends Plugin
|
||||
treeTypeID = ItemID.LOGS;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameObjectSpawned(final GameObjectSpawned event)
|
||||
{
|
||||
GameObject gameObject = event.getGameObject();
|
||||
Tree tree = Tree.findTree(gameObject.getId());
|
||||
|
||||
if (tree != null)
|
||||
{
|
||||
treeObjects.add(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameObjectDespawned(final GameObjectDespawned event)
|
||||
{
|
||||
treeObjects.remove(event.getGameObject());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameObjectChanged(final GameObjectChanged event)
|
||||
{
|
||||
treeObjects.remove(event.getGameObject());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onGameStateChanged(final GameStateChanged event)
|
||||
{
|
||||
if (event.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
treeObjects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onAnimationChanged(final AnimationChanged event)
|
||||
{
|
||||
Player local = client.getLocalPlayer();
|
||||
|
||||
if (event.getActor() != local)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int animId = local.getAnimation();
|
||||
Axe axe = Axe.findAxeByAnimId(animId);
|
||||
if (axe != null)
|
||||
{
|
||||
this.axe = axe;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onConfigChanged(ConfigChanged event)
|
||||
{
|
||||
if (!event.getGroup().equals("woodcutting"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
private void updateConfig()
|
||||
{
|
||||
this.statTimeout = config.statTimeout();
|
||||
this.showNestNotification = config.showNestNotification();
|
||||
this.showWoodcuttingStats = config.showWoodcuttingStats();
|
||||
this.showRedwoodTrees = config.showRedwoodTrees();
|
||||
this.showGPEarned = config.showGPEarned();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2019, David <Dava96@github.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -25,29 +26,36 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.woodcutting;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.Perspective;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
import net.runelite.client.ui.overlay.OverlayUtil;
|
||||
import net.runelite.client.ui.overlay.components.ProgressPieComponent;
|
||||
|
||||
@Singleton
|
||||
class WoodcuttingTreesOverlay extends Overlay
|
||||
{
|
||||
private final Client client;
|
||||
private final WoodcuttingConfig config;
|
||||
private final ItemManager itemManager;
|
||||
private final WoodcuttingPlugin plugin;
|
||||
|
||||
@Inject
|
||||
private WoodcuttingTreesOverlay(final Client client, final ItemManager itemManager, final WoodcuttingPlugin plugin)
|
||||
private WoodcuttingTreesOverlay(final Client client, final WoodcuttingConfig config, final ItemManager itemManager, final WoodcuttingPlugin plugin)
|
||||
{
|
||||
this.client = client;
|
||||
this.config = config;
|
||||
this.itemManager = itemManager;
|
||||
this.plugin = plugin;
|
||||
setLayer(OverlayLayer.ABOVE_SCENE);
|
||||
@@ -57,15 +65,22 @@ class WoodcuttingTreesOverlay extends Overlay
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
if (plugin.getSession() == null || !plugin.isShowRedwoodTrees())
|
||||
renderAxes(graphics);
|
||||
renderTimers(graphics);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void renderAxes(Graphics2D graphics)
|
||||
{
|
||||
if (plugin.getSession() == null || !config.showRedwoodTrees())
|
||||
{
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
Axe axe = plugin.getAxe();
|
||||
if (axe == null)
|
||||
{
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
for (GameObject treeObject : plugin.getTreeObjects())
|
||||
@@ -75,7 +90,34 @@ class WoodcuttingTreesOverlay extends Overlay
|
||||
OverlayUtil.renderImageLocation(client, graphics, treeObject.getLocalLocation(), itemManager.getImage(axe.getItemId()), 120);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void renderTimers(Graphics2D graphics)
|
||||
{
|
||||
List<TreeRespawn> respawns = plugin.getRespawns();
|
||||
if (respawns.isEmpty() || !config.showRespawnTimers())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Instant now = Instant.now();
|
||||
for (TreeRespawn treeRespawn : respawns)
|
||||
{
|
||||
LocalPoint loc = treeRespawn.getLocation();
|
||||
|
||||
float percent = (now.toEpochMilli() - treeRespawn.getStartTime().toEpochMilli()) / (float) treeRespawn.getRespawnTime();
|
||||
Point point = Perspective.localToCanvas(client, loc, client.getPlane());
|
||||
if (point == null || percent > 1.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ProgressPieComponent ppc = new ProgressPieComponent();
|
||||
ppc.setBorderColor(Color.ORANGE);
|
||||
ppc.setFill(Color.YELLOW);
|
||||
ppc.setPosition(point);
|
||||
ppc.setProgress(percent);
|
||||
ppc.render(graphics);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,11 +30,9 @@ import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ObjectArrays;
|
||||
import com.google.inject.Provides;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -75,6 +73,8 @@ import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.config.Keybind;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.client.events.WorldsFetch;
|
||||
import net.runelite.client.game.WorldService;
|
||||
import net.runelite.client.input.KeyManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
@@ -87,7 +87,6 @@ import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.client.util.WorldUtil;
|
||||
import net.runelite.client.util.ping.Ping;
|
||||
import net.runelite.http.api.worlds.World;
|
||||
import net.runelite.http.api.worlds.WorldClient;
|
||||
import net.runelite.http.api.worlds.WorldResult;
|
||||
import net.runelite.http.api.worlds.WorldType;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
@@ -126,9 +125,6 @@ public class WorldHopperPlugin extends Plugin
|
||||
@Inject
|
||||
private ChatMessageManager chatMessageManager;
|
||||
|
||||
@Inject
|
||||
private ScheduledExecutorService executorService;
|
||||
|
||||
@Inject
|
||||
private WorldHopperConfig config;
|
||||
|
||||
@@ -139,7 +135,7 @@ public class WorldHopperPlugin extends Plugin
|
||||
private WorldHopperPingOverlay worldHopperOverlay;
|
||||
|
||||
@Inject
|
||||
private WorldClient worldClient;
|
||||
private WorldService worldService;
|
||||
|
||||
private ScheduledExecutorService hopperExecutorService;
|
||||
|
||||
@@ -154,11 +150,9 @@ public class WorldHopperPlugin extends Plugin
|
||||
|
||||
private int favoriteWorld1, favoriteWorld2;
|
||||
|
||||
private ScheduledFuture<?> worldResultFuture, pingFuture, currPingFuture;
|
||||
private WorldResult worldResult;
|
||||
private ScheduledFuture<?> pingFuture, currPingFuture;
|
||||
private int currentWorld;
|
||||
private Instant lastFetch;
|
||||
private boolean firstRun;
|
||||
|
||||
private Keybind previousKey;
|
||||
private Keybind nextKey;
|
||||
@@ -203,7 +197,6 @@ public class WorldHopperPlugin extends Plugin
|
||||
{
|
||||
updateConfig();
|
||||
|
||||
firstRun = true;
|
||||
currentPing = -1;
|
||||
|
||||
keyManager.registerKeyListener(previousKeyListener);
|
||||
@@ -231,12 +224,15 @@ public class WorldHopperPlugin extends Plugin
|
||||
|
||||
// The plugin has its own executor for pings, as it blocks for a long time
|
||||
hopperExecutorService = new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor());
|
||||
// On first run this schedules an initial ping on hopperExecutorService
|
||||
worldResultFuture = executorService.scheduleAtFixedRate(this::tick, 0, WORLD_FETCH_TIMER, TimeUnit.MINUTES);
|
||||
// Run the first-run ping
|
||||
hopperExecutorService.execute(this::pingInitialWorlds);
|
||||
|
||||
// Give some initial delay - this won't run until after pingInitialWorlds finishes from tick() anyway
|
||||
pingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingNextWorld, 15, 3, TimeUnit.SECONDS);
|
||||
currPingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingCurrentWorld, 15, 1, TimeUnit.SECONDS);
|
||||
|
||||
// populate initial world list
|
||||
updateList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -253,11 +249,6 @@ public class WorldHopperPlugin extends Plugin
|
||||
keyManager.unregisterKeyListener(previousKeyListener);
|
||||
keyManager.unregisterKeyListener(nextKeyListener);
|
||||
|
||||
worldResultFuture.cancel(true);
|
||||
worldResultFuture = null;
|
||||
worldResult = null;
|
||||
lastFetch = null;
|
||||
|
||||
clientToolbar.removeNavigation(navButton);
|
||||
|
||||
hopperExecutorService.shutdown();
|
||||
@@ -393,6 +384,7 @@ public class WorldHopperPlugin extends Plugin
|
||||
|
||||
// Don't add entry if user is offline
|
||||
ChatPlayer player = getChatPlayerFromName(event.getTarget());
|
||||
WorldResult worldResult = worldService.getWorlds();
|
||||
|
||||
if (player == null || player.getWorld() == 0 || player.getWorld() == client.getWorld()
|
||||
|| worldResult == null)
|
||||
@@ -484,26 +476,6 @@ public class WorldHopperPlugin extends Plugin
|
||||
this.lastFetch = Instant.now(); // This counts as a fetch as it updates populations
|
||||
}
|
||||
|
||||
private void tick()
|
||||
{
|
||||
Instant now = Instant.now();
|
||||
if (lastFetch != null && now.toEpochMilli() - lastFetch.toEpochMilli() < TICK_THROTTLE)
|
||||
{
|
||||
log.debug("Throttling world refresh tick");
|
||||
return;
|
||||
}
|
||||
|
||||
fetchWorlds();
|
||||
|
||||
// Ping worlds once at startup
|
||||
if (firstRun)
|
||||
{
|
||||
firstRun = false;
|
||||
// On first run we ping all of the worlds at once to initialize the ping values
|
||||
hopperExecutorService.execute(this::pingInitialWorlds);
|
||||
}
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
Instant now = Instant.now();
|
||||
@@ -513,29 +485,14 @@ public class WorldHopperPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
fetchWorlds();
|
||||
lastFetch = now;
|
||||
worldService.refresh();
|
||||
}
|
||||
|
||||
private void fetchWorlds()
|
||||
@Subscribe
|
||||
public void onWorldsFetch(WorldsFetch worldsFetch)
|
||||
{
|
||||
log.debug("Fetching worlds");
|
||||
|
||||
worldClient.lookupWorlds()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.take(1)
|
||||
.subscribe(
|
||||
(worldResult) ->
|
||||
{
|
||||
if (worldResult != null)
|
||||
{
|
||||
worldResult.getWorlds().sort(Comparator.comparingInt(World::getId));
|
||||
this.worldResult = worldResult;
|
||||
this.lastFetch = Instant.now();
|
||||
updateList();
|
||||
}
|
||||
},
|
||||
(ex) -> log.warn("Error looking up worlds", ex)
|
||||
);
|
||||
updateList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -543,11 +500,16 @@ public class WorldHopperPlugin extends Plugin
|
||||
*/
|
||||
private void updateList()
|
||||
{
|
||||
SwingUtilities.invokeLater(() -> panel.populate(worldResult.getWorlds()));
|
||||
WorldResult worldResult = worldService.getWorlds();
|
||||
if (worldResult != null)
|
||||
{
|
||||
SwingUtilities.invokeLater(() -> panel.populate(worldResult.getWorlds()));
|
||||
}
|
||||
}
|
||||
|
||||
private void hop(boolean previous)
|
||||
{
|
||||
WorldResult worldResult = worldService.getWorlds();
|
||||
if (worldResult == null || client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
return;
|
||||
@@ -658,6 +620,7 @@ public class WorldHopperPlugin extends Plugin
|
||||
|
||||
private void hop(int worldId)
|
||||
{
|
||||
WorldResult worldResult = worldService.getWorlds();
|
||||
// Don't try to hop if the world doesn't exist
|
||||
World world = worldResult.findWorld(worldId);
|
||||
if (world == null)
|
||||
@@ -801,6 +764,7 @@ public class WorldHopperPlugin extends Plugin
|
||||
*/
|
||||
private void pingInitialWorlds()
|
||||
{
|
||||
WorldResult worldResult = worldService.getWorlds();
|
||||
if (worldResult == null || !this.showSidebar || !this.ping)
|
||||
{
|
||||
return;
|
||||
@@ -838,6 +802,7 @@ public class WorldHopperPlugin extends Plugin
|
||||
*/
|
||||
private void pingNextWorld()
|
||||
{
|
||||
WorldResult worldResult = worldService.getWorlds();
|
||||
if (worldResult == null || !this.showSidebar || !this.ping)
|
||||
{
|
||||
return;
|
||||
@@ -874,6 +839,7 @@ public class WorldHopperPlugin extends Plugin
|
||||
*/
|
||||
private void pingCurrentWorld()
|
||||
{
|
||||
WorldResult worldResult = worldService.getWorlds();
|
||||
// There is no reason to ping the current world if not logged in, as the overlay doesn't draw
|
||||
if (worldResult == null || !this.displayPing || client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
|
||||
@@ -70,7 +70,8 @@ class ClientConfigLoader
|
||||
supplier = new HostSupplier();
|
||||
}
|
||||
|
||||
url = supplier.get();
|
||||
String host = supplier.get();
|
||||
url = url.newBuilder().host(host).build();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Abex
|
||||
* Copyright (c) 2019, Lucas <https://github.com/lucwousin>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -25,8 +24,10 @@
|
||||
*/
|
||||
package net.runelite.client.rs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
@@ -36,41 +37,46 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import net.runelite.http.api.worlds.World;
|
||||
import net.runelite.http.api.worlds.WorldClient;
|
||||
import net.runelite.http.api.worlds.WorldResult;
|
||||
import okhttp3.HttpUrl;
|
||||
import net.runelite.http.api.worlds.WorldType;
|
||||
|
||||
@Slf4j
|
||||
class HostSupplier implements Supplier<HttpUrl>
|
||||
class HostSupplier implements Supplier<String>
|
||||
{
|
||||
private final Random random = new Random();
|
||||
private final Queue<HttpUrl> hosts = new ArrayDeque<>();
|
||||
private final Random random = new Random(System.nanoTime());
|
||||
private Queue<String> hosts = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public HttpUrl get()
|
||||
public String get()
|
||||
{
|
||||
if (!hosts.isEmpty())
|
||||
{
|
||||
return hosts.poll();
|
||||
}
|
||||
|
||||
List<HttpUrl> newHosts = new WorldClient(RuneLiteAPI.CLIENT)
|
||||
.lookupWorlds()
|
||||
.map(WorldResult::getWorlds)
|
||||
.blockingSingle()
|
||||
.stream()
|
||||
.map(World::getAddress)
|
||||
.map(HttpUrl::parse)
|
||||
.collect(Collectors.toList());
|
||||
try
|
||||
{
|
||||
List<String> newHosts = new WorldClient(RuneLiteAPI.CLIENT)
|
||||
.lookupWorlds()
|
||||
.getWorlds()
|
||||
.stream()
|
||||
.filter(w -> w.getTypes().isEmpty() || EnumSet.of(WorldType.MEMBERS).equals(w.getTypes()))
|
||||
.map(World::getAddress)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Collections.shuffle(newHosts, random);
|
||||
Collections.shuffle(newHosts, random);
|
||||
|
||||
hosts.addAll(newHosts.subList(0, 16));
|
||||
hosts.addAll(newHosts.subList(0, 16));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn("Unable to retrieve world list", e);
|
||||
}
|
||||
|
||||
while (hosts.size() < 2)
|
||||
{
|
||||
hosts.add(HttpUrl.parse("oldschool" + (random.nextInt(50) + 1) + ".runescape.COM"));
|
||||
hosts.add("oldschool" + (random.nextInt(50) + 1) + ".runescape.COM");
|
||||
}
|
||||
|
||||
return hosts.poll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1024,9 +1024,9 @@ public class ClientUI
|
||||
setOpacityMethod.invoke(peerField.get(frame), opacity);
|
||||
|
||||
}
|
||||
catch (NoSuchFieldException | NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException e)
|
||||
catch (NoSuchFieldException | NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException | NullPointerException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user