This commit is contained in:
TheRealNull
2020-12-19 17:52:08 -05:00
parent b6f47eb581
commit 473fe2fa43
93 changed files with 1600 additions and 1296 deletions

View File

@@ -28,7 +28,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.annotation.Nullable;
import net.runelite.http.api.RuneLiteAPI;
import okhttp3.HttpUrl;
public class RuneLiteProperties
@@ -145,7 +144,7 @@ public class RuneLiteProperties
public static HttpUrl getPluginHubBase()
{
String version = System.getProperty(PLUGINHUB_VERSION, properties.getProperty(PLUGINHUB_VERSION));
return HttpUrl.parse(properties.get(PLUGINHUB_BASE) + "/" + RuneLiteAPI.getVersion());
return HttpUrl.parse(properties.get(PLUGINHUB_BASE) + "/" + version);
}
public static String getImgurClientId()

View File

@@ -37,15 +37,15 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.BufferProvider;
import net.runelite.api.Client;
import net.runelite.api.Renderable;
import net.runelite.api.MainBufferProvider;
import net.runelite.api.NullItemID;
import net.runelite.api.RenderOverview;
import net.runelite.api.Renderable;
import net.runelite.api.Skill;
import net.runelite.api.WorldMapManager;
import net.runelite.api.events.BeforeMenuRender;
@@ -331,7 +331,7 @@ public class Hooks implements Callbacks
try
{
renderer.render(graphics2d, OverlayLayer.ALWAYS_ON_TOP);
renderer.renderOverlayLayer(graphics2d, OverlayLayer.ALWAYS_ON_TOP);
}
catch (Exception ex)
{
@@ -426,7 +426,7 @@ public class Hooks implements Callbacks
try
{
renderer.render(graphics2d, OverlayLayer.ABOVE_SCENE);
renderer.renderOverlayLayer(graphics2d, OverlayLayer.ABOVE_SCENE);
}
catch (Exception ex)
{
@@ -442,7 +442,7 @@ public class Hooks implements Callbacks
try
{
renderer.render(graphics2d, OverlayLayer.UNDER_WIDGETS);
renderer.renderOverlayLayer(graphics2d, OverlayLayer.UNDER_WIDGETS);
}
catch (Exception ex)
{
@@ -450,27 +450,6 @@ public class Hooks implements Callbacks
}
}
@Override
public void drawAfterWidgets()
{
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
Graphics2D graphics2d = getGraphics(bufferProvider);
try
{
renderer.render(graphics2d, OverlayLayer.ABOVE_MAP);
renderer.render(graphics2d, OverlayLayer.ABOVE_WIDGETS);
}
catch (Exception ex)
{
log.warn("Error during overlay rendering", ex);
}
// WidgetItemOverlays render at ABOVE_WIDGETS, reset widget item
// list for next frame.
overlayManager.getItemWidgets().clear();
}
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
@@ -508,12 +487,34 @@ public class Hooks implements Callbacks
}
@Override
public void drawItem(int itemId, WidgetItem widgetItem)
public void drawInterface(int interfaceId, List<WidgetItem> widgetItems)
{
// Empty bank item
if (widgetItem.getId() != NullItemID.NULL_6512)
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
Graphics2D graphics2d = getGraphics(bufferProvider);
try
{
overlayManager.getItemWidgets().add(widgetItem);
renderer.renderAfterInterface(graphics2d, interfaceId, widgetItems);
}
catch (Exception ex)
{
log.warn("Error during overlay rendering", ex);
}
}
@Override
public void drawLayer(Widget layer, List<WidgetItem> widgetItems)
{
MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider();
Graphics2D graphics2d = getGraphics(bufferProvider);
try
{
renderer.renderAfterLayer(graphics2d, layer, widgetItems);
}
catch (Exception ex)
{
log.warn("Error during overlay rendering", ex);
}
}
@@ -539,6 +540,7 @@ public class Hooks implements Callbacks
eventBus.post(fakeXpDrop);
}
public static void clearColorBuffer(int x, int y, int width, int height, int color)
{
BufferProvider bp = client.getBufferProvider();

View File

@@ -1041,7 +1041,7 @@ public class ConfigManager
{
updateRSProfile();
}
@Subscribe
private void onPlayerChanged(PlayerChanged ev)
{

View File

@@ -27,6 +27,7 @@ package net.runelite.client.config;
import lombok.RequiredArgsConstructor;
import lombok.Getter;
import net.runelite.client.ui.FontManager;
import java.awt.Font;
@Getter

View File

@@ -67,13 +67,12 @@ public class ExternalPluginClient
{
HttpUrl manifest = RuneLiteProperties.getPluginHubBase()
.newBuilder()
.addPathSegment("manifest.js")
.addPathSegments("manifest.js")
.build();
try (Response res = okHttpClient.newCall(new Request.Builder().url(manifest).build()).execute())
{
if (res.code() != 200)
{
System.out.println(manifest.url().toString());
throw new IOException("Non-OK response code: " + res.code());
}

View File

@@ -118,10 +118,10 @@ public enum AgilityShortcut
GNOME_STRONGHOLD_ROCKS(37, "Rocks", new WorldPoint(2485, 3515, 0), ROCKS_16534, ROCKS_16535),
AL_KHARID_MINING_PITCLIFF_SCRAMBLE(38, "Rocks", new WorldPoint(3305, 3315, 0), ROCKS_16549, ROCKS_16550),
YANILLE_WALL_GRAPPLE(39, "Grapple Wall", new WorldPoint(2552, 3072, 0), WALL_17047),
NEITIZNOT_BRIDGE_REPAIR(40, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307),
NEITIZNOT_BRIDGE_SOUTHEAST(40, "Rope Bridge", null, ROPE_BRIDGE_21308, ROPE_BRIDGE_21309),
NEITIZNOT_BRIDGE_NORTHWEST(40, "Rope Bridge", null, ROPE_BRIDGE_21310, ROPE_BRIDGE_21311),
NEITIZNOT_BRIDGE_NORTH(40, "Rope Bridge", null, ROPE_BRIDGE_21312, ROPE_BRIDGE_21313),
NEITIZNOT_BRIDGE_REPAIR(0, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307),
NEITIZNOT_BRIDGE_SOUTHEAST(0, "Rope Bridge", null, ROPE_BRIDGE_21308, ROPE_BRIDGE_21309),
NEITIZNOT_BRIDGE_NORTHWEST(0, "Rope Bridge", null, ROPE_BRIDGE_21310, ROPE_BRIDGE_21311),
NEITIZNOT_BRIDGE_NORTH(0, "Rope Bridge", null, ROPE_BRIDGE_21312, ROPE_BRIDGE_21313),
NEITIZNOT_BRIDGE_NORTHEAST(40, "Broken Rope bridge", null, ROPE_BRIDGE_21314, ROPE_BRIDGE_21315),
KOUREND_LAKE_JUMP_EAST(40, "Stepping Stones", new WorldPoint(1612, 3570, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
KOUREND_LAKE_JUMP_WEST(40, "Stepping Stones", new WorldPoint(1604, 3572, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),

View File

@@ -24,11 +24,7 @@
*/
package net.runelite.client.game;
import com.google.common.collect.ImmutableMap;
import com.google.gson.stream.JsonReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
@@ -46,14 +42,12 @@ public class NPCManager
{
private final OkHttpClient okHttpClient;
private Map<Integer, NpcInfo> npcMap = Collections.emptyMap();
private ImmutableMap<Integer, NPCStats> statsMap;
@Inject
private NPCManager(OkHttpClient okHttpClient, ScheduledExecutorService scheduledExecutorService)
{
this.okHttpClient = okHttpClient;
scheduledExecutorService.execute(this::loadNpcs);
loadStats();
}
@Nullable
@@ -80,45 +74,4 @@ public class NPCManager
log.warn("error loading npc stats", e);
}
}
private void loadStats()
{
try (JsonReader reader = new JsonReader(new InputStreamReader(NPCManager.class.getResourceAsStream("/npc_stats.json"), StandardCharsets.UTF_8)))
{
ImmutableMap.Builder<Integer, NPCStats> builder = ImmutableMap.builderWithExpectedSize(2821);
reader.beginObject();
while (reader.hasNext())
{
builder.put(
Integer.parseInt(reader.nextName()),
NPCStats.NPC_STATS_TYPE_ADAPTER.read(reader)
);
}
reader.endObject();
statsMap = builder.build();
}
catch (IOException e)
{
e.printStackTrace();
}
}
/**
* Returns the attack speed for target NPC ID.
*
* @param npcId NPC id
* @return attack speed in game ticks for NPC ID.
*/
public int getAttackSpeed(final int npcId)
{
final NPCStats s = statsMap.get(npcId);
if (s == null || s.getAttackSpeed() == -1)
{
return -1;
}
return s.getAttackSpeed();
}
}

View File

@@ -1,203 +0,0 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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 com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import lombok.Builder;
import lombok.Value;
@Value
@Builder(builderClassName = "Builder")
public class NPCStats
{
private final String name;
private final int hitpoints;
private final int combatLevel;
private final int slayerLevel;
private final int attackSpeed;
private final int attackLevel;
private final int strengthLevel;
private final int defenceLevel;
private final int rangeLevel;
private final int magicLevel;
private final int stab;
private final int slash;
private final int crush;
private final int range;
private final int magic;
private final int stabDef;
private final int slashDef;
private final int crushDef;
private final int rangeDef;
private final int magicDef;
private final int bonusAttack;
private final int bonusStrength;
private final int bonusRangeStrength;
private final int bonusMagicDamage;
private final boolean poisonImmune;
private final boolean venomImmune;
private final boolean dragon;
private final boolean demon;
private final boolean undead;
/**
* Based off the formula found here: http://services.runescape.com/m=forum/c=PLuJ4cy6gtA/forums.ws?317,318,712,65587452,209,337584542#209
*
* @return bonus XP modifier
*/
public double calculateXpModifier()
{
final double averageLevel = Math.floor((attackLevel + strengthLevel + defenceLevel + hitpoints) / 4);
final double averageDefBonus = Math.floor((stabDef + slashDef + crushDef) / 3);
return (1 + Math.floor(averageLevel * (averageDefBonus + bonusStrength + bonusAttack) / 5120) / 40);
}
// Because this class is here we can't add the TypeAdapter to gson (easily)
// doesn't mean we can't use one to do it a bit quicker
public static final TypeAdapter<NPCStats> NPC_STATS_TYPE_ADAPTER = new TypeAdapter<>()
{
@Override
public void write(JsonWriter out, NPCStats value)
{
throw new UnsupportedOperationException("Not supported");
}
@Override
public NPCStats read(JsonReader in) throws IOException
{
in.beginObject();
NPCStats.Builder builder = NPCStats.builder();
// Name is the only one that's guaranteed
in.skipValue();
builder.name(in.nextString());
while (in.hasNext())
{
switch (in.nextName())
{
case "hitpoints":
builder.hitpoints(in.nextInt());
break;
case "combatLevel":
builder.combatLevel(in.nextInt());
break;
case "slayerLevel":
builder.slayerLevel(in.nextInt());
break;
case "attackSpeed":
builder.attackSpeed(in.nextInt());
break;
case "attackLevel":
builder.attackLevel(in.nextInt());
break;
case "strengthLevel":
builder.strengthLevel(in.nextInt());
break;
case "defenceLevel":
builder.defenceLevel(in.nextInt());
break;
case "rangeLevel":
builder.rangeLevel(in.nextInt());
break;
case "magicLevel":
builder.magicLevel(in.nextInt());
break;
case "stab":
builder.stab(in.nextInt());
break;
case "slash":
builder.slash(in.nextInt());
break;
case "crush":
builder.crush(in.nextInt());
break;
case "range":
builder.range(in.nextInt());
break;
case "magic":
builder.magic(in.nextInt());
break;
case "stabDef":
builder.stabDef(in.nextInt());
break;
case "slashDef":
builder.slashDef(in.nextInt());
break;
case "crushDef":
builder.crushDef(in.nextInt());
break;
case "rangeDef":
builder.rangeDef(in.nextInt());
break;
case "magicDef":
builder.magicDef(in.nextInt());
break;
case "bonusAttack":
builder.bonusAttack(in.nextInt());
break;
case "bonusStrength":
builder.bonusStrength(in.nextInt());
break;
case "bonusRangeStrength":
builder.bonusRangeStrength(in.nextInt());
break;
case "bonusMagicDamage":
builder.bonusMagicDamage(in.nextInt());
break;
case "poisonImmune":
builder.poisonImmune(in.nextBoolean());
break;
case "venomImmune":
builder.venomImmune(in.nextBoolean());
break;
case "dragon":
builder.dragon(in.nextBoolean());
break;
case "demon":
builder.demon(in.nextBoolean());
break;
case "undead":
builder.undead(in.nextBoolean());
break;
}
}
in.endObject();
return builder.build();
}
};
}

View File

@@ -140,7 +140,7 @@ public class MenuManager
MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
menuEntry.setOption(currentMenu.getMenuOption());
menuEntry.setActionParam1(widgetId);
menuEntry.setParam1(widgetId);
menuEntry.setTarget(currentMenu.getMenuTarget());
menuEntry.setType(MenuAction.RUNELITE.getId());
@@ -241,17 +241,17 @@ public class MenuManager
return; // not a managed widget option or custom player option
}
int widgetId = event.getActionParam1();
int widgetId = event.getWidgetId();
Collection<WidgetMenuOption> options = managedMenuOptions.get(widgetId);
for (WidgetMenuOption curMenuOption : options)
{
if (curMenuOption.getMenuTarget().equals(event.getTarget())
&& curMenuOption.getMenuOption().equals(event.getOption()))
if (curMenuOption.getMenuTarget().equals(event.getMenuTarget())
&& curMenuOption.getMenuOption().equals(event.getMenuOption()))
{
WidgetMenuOptionClicked customMenu = new WidgetMenuOptionClicked();
customMenu.setMenuOption(event.getOption());
customMenu.setMenuTarget(event.getTarget());
customMenu.setMenuOption(event.getMenuOption());
customMenu.setMenuTarget(event.getMenuTarget());
customMenu.setWidget(curMenuOption.getWidget());
eventBus.post(customMenu);
return; // don't continue because it's not a player option
@@ -260,14 +260,14 @@ public class MenuManager
// removes bounty hunter emblem tag and tier from player name, e.g:
// "username<img=20>5<col=40ff00> (level-42)" -> "username<col=40ff00> (level-42)"
String target = BOUNTY_EMBLEM_TAG_AND_TIER_REGEXP.matcher(event.getTarget()).replaceAll("");
String target = BOUNTY_EMBLEM_TAG_AND_TIER_REGEXP.matcher(event.getMenuTarget()).replaceAll("");
// removes tags and level from player names for example:
// <col=ffffff>username<col=40ff00> (level-42) or <col=ffffff><img=2>username</col>
String username = Text.removeTags(target).split("[(]")[0].trim();
PlayerMenuOptionClicked playerMenuOptionClicked = new PlayerMenuOptionClicked();
playerMenuOptionClicked.setMenuOption(event.getOption());
playerMenuOptionClicked.setMenuOption(event.getMenuOption());
playerMenuOptionClicked.setMenuTarget(username);
eventBus.post(playerMenuOptionClicked);

View File

@@ -25,6 +25,7 @@
package net.runelite.client.menus;
import net.runelite.api.widgets.WidgetInfo;
import java.awt.Color;
import net.runelite.client.ui.JagexColors;
import net.runelite.client.util.ColorUtil;

View File

@@ -27,6 +27,7 @@ package net.runelite.client.plugins.blastmine;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import java.awt.Color;
@ConfigGroup("blastmine")

View File

@@ -42,7 +42,6 @@ import net.runelite.api.Point;
import net.runelite.api.Tile;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.widgets.Widget;
import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
@@ -91,12 +90,10 @@ public class BlastMineRockOverlay extends Overlay
}
final Tile[][][] tiles = client.getScene().getTiles();
final Widget viewport = client.getViewportWidget();
for (final BlastMineRock rock : rocks.values())
{
if (viewport == null ||
rock.getGameObject().getCanvasLocation() == null ||
if (rock.getGameObject().getCanvasLocation() == null ||
rock.getGameObject().getWorldLocation().distanceTo(client.getLocalPlayer().getWorldLocation()) > MAX_DISTANCE)
{
continue;

View File

@@ -136,10 +136,6 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener
Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT);
if (settingsInit != null)
{
throw new UnsupportedOperationException("Implement");
//client.createScriptEvent(settingsInit.getOnLoadListener())
//.setSource(settingsInit)
//.run();
}
});
}
@@ -165,10 +161,6 @@ public class CameraPlugin extends Plugin implements KeyListener, MouseListener
Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT);
if (settingsInit != null)
{
throw new UnsupportedOperationException("Implement");
//client.createScriptEvent(settingsInit.getOnLoadListener())
//.setSource(settingsInit)
//.run();
}
});
}

View File

@@ -53,7 +53,7 @@ import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.vars.InputType;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatMessageManager;
@@ -204,7 +204,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener
}
final int groupId = TO_GROUP(entry.getParam1());
final int childId = getChildFromID(entry.getParam1());
final int childId = TO_CHILD(entry.getParam1());
if (groupId != WidgetInfo.CHATBOX.getGroupId())
{

View File

@@ -280,6 +280,8 @@ class PluginHubPanel extends PluginPanel
return;
}
}
addrm.setText("Installing");
addrm.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
externalPluginManager.install(manifest.getInternalName());
});
}
@@ -287,14 +289,24 @@ class PluginHubPanel extends PluginPanel
{
addrm.setText("Remove");
addrm.setBackground(new Color(0xBE2828));
addrm.addActionListener(l -> externalPluginManager.remove(manifest.getInternalName()));
addrm.addActionListener(l ->
{
addrm.setText("Removing");
addrm.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
externalPluginManager.remove(manifest.getInternalName());
});
}
else
{
assert update;
addrm.setText("Update");
addrm.setBackground(new Color(0x1F621F));
addrm.addActionListener(l -> externalPluginManager.update());
addrm.addActionListener(l ->
{
addrm.setText("Updating");
addrm.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
externalPluginManager.update();
});
}
addrm.setBorder(new LineBorder(addrm.getBackground().darker()));
addrm.setFocusPainted(false);
@@ -313,7 +325,7 @@ class PluginHubPanel extends PluginPanel
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.PREFERRED_SIZE, 100)
.addComponent(help, 0, 24, 24)
.addComponent(configure, 0, 24, 24)
.addComponent(addrm, 0, 50, GroupLayout.PREFERRED_SIZE)
.addComponent(addrm, 0, 57, GroupLayout.PREFERRED_SIZE)
.addGap(5))));
int lineHeight = description.getFontMetrics(description.getFont()).getHeight();

View File

@@ -76,7 +76,6 @@ class PluginListPanel extends PluginPanel
private static final String RUNELITE_GROUP_NAME = RuneLiteConfig.class.getAnnotation(ConfigGroup.class).value();
private static final String PINNED_PLUGINS_CONFIG_KEY = "pinnedPlugins";
private static final ImmutableList<String> CATEGORY_TAGS = ImmutableList.of(
"OpenOSRS",
"Combat",
"Chat",
"Item",
@@ -165,16 +164,10 @@ class PluginListPanel extends PluginPanel
setLayout(new BorderLayout());
setBackground(ColorScheme.DARK_GRAY_COLOR);
JButton externalPluginOPRSButton = new JButton("OpenOSRS Hub");
externalPluginOPRSButton.setBorder(new EmptyBorder(5, 5, 5, 5));
externalPluginOPRSButton.setLayout(new BorderLayout(0, BORDER_OFFSET));
externalPluginOPRSButton.addActionListener(l -> muxer.pushState(pluginHubPanelProvider.get()));
JPanel topPanel = new JPanel();
topPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
topPanel.setLayout(new BorderLayout(0, BORDER_OFFSET));
topPanel.add(searchBar, BorderLayout.CENTER);
topPanel.add(externalPluginOPRSButton, BorderLayout.SOUTH);
add(topPanel, BorderLayout.NORTH);
mainPanel = new FixedWidthPanel();

View File

@@ -27,6 +27,7 @@ package net.runelite.client.plugins.devtools;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.CollisionDataFlag;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

View File

@@ -63,7 +63,7 @@ import net.runelite.api.events.ScriptPostFired;
import net.runelite.api.events.ScriptPreFired;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
@@ -120,7 +120,7 @@ public class ScriptInspector extends JFrame
if (source != null)
{
int id = source.getId();
output += " - " + TO_GROUP(id) + "." + getChildFromID(id);
output += " - " + TO_GROUP(id) + "." + TO_CHILD(id);
if (source.getIndex() != -1)
{

View File

@@ -59,7 +59,7 @@ import net.runelite.api.Client;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.SpriteID;
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
import net.runelite.client.events.ConfigChanged;
import net.runelite.api.events.MenuEntryAdded;
@@ -464,7 +464,7 @@ class WidgetInspector extends JFrame
picker = parent.createChild(-1, WidgetType.GRAPHIC);
log.info("Picker is {}.{} [{}]", WidgetInfo.TO_GROUP(picker.getId()), WidgetInfo.getChildFromID(picker.getId()), picker.getIndex());
log.info("Picker is {}.{} [{}]", WidgetInfo.TO_GROUP(picker.getId()), WidgetInfo.TO_CHILD(picker.getId()), picker.getIndex());
picker.setSpriteId(SpriteID.MOBILE_FINGER_ON_INTERFACE);
picker.setOriginalWidth(15);
@@ -538,7 +538,7 @@ class WidgetInspector extends JFrame
{
continue;
}
String name = WidgetInfo.TO_GROUP(entry.getParam1()) + "." + WidgetInfo.getChildFromID(entry.getParam1());
String name = WidgetInfo.TO_GROUP(entry.getParam1()) + "." + WidgetInfo.TO_CHILD(entry.getParam1());
if (entry.getParam0() != -1)
{
@@ -584,7 +584,7 @@ class WidgetInspector extends JFrame
public static String getWidgetIdentifier(Widget widget)
{
int id = widget.getId();
String str = TO_GROUP(id) + "." + getChildFromID(id);
String str = TO_GROUP(id) + "." + TO_CHILD(id);
if (widget.getIndex() != -1)
{

View File

@@ -37,6 +37,7 @@ import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.MenuEntry;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
@@ -61,6 +62,7 @@ public class WidgetInspectorOverlay extends Overlay
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
setPriority(OverlayPriority.HIGHEST);
drawAfterInterface(WidgetID.FULLSCREEN_MAP_GROUP_ID);
}
@Override

View File

@@ -35,6 +35,7 @@ import net.runelite.api.Point;
import net.runelite.api.RenderOverview;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
@@ -56,7 +57,8 @@ public class WorldMapLocationOverlay extends Overlay
this.plugin = plugin;
setPosition(OverlayPosition.DYNAMIC);
setPriority(OverlayPriority.HIGHEST);
setLayer(OverlayLayer.ABOVE_MAP);
setLayer(OverlayLayer.MANUAL);
drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID);
}
@Override

View File

@@ -35,6 +35,7 @@ import net.runelite.api.Client;
import net.runelite.api.Point;
import net.runelite.api.RenderOverview;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
@@ -56,7 +57,8 @@ class WorldMapRegionOverlay extends Overlay
{
setPosition(OverlayPosition.DYNAMIC);
setPriority(OverlayPriority.HIGH);
setLayer(OverlayLayer.ABOVE_MAP);
setLayer(OverlayLayer.MANUAL);
drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID);
this.client = client;
this.plugin = plugin;
}

View File

@@ -45,7 +45,7 @@ import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import static net.runelite.api.widgets.WidgetInfo.SEED_VAULT_ITEM_CONTAINER;
import static net.runelite.api.widgets.WidgetInfo.getChildFromID;
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.chat.ChatColorType;
@@ -124,7 +124,7 @@ public class ExaminePlugin extends Plugin
int widgetId = event.getWidgetId();
int widgetGroup = TO_GROUP(widgetId);
int widgetChild = getChildFromID(widgetId);
int widgetChild = TO_CHILD(widgetId);
Widget widget = client.getWidget(widgetGroup, widgetChild);
WidgetItem widgetItem = widget.getWidgetItem(event.getActionParam());
quantity = widgetItem != null && widgetItem.getId() >= 0 ? widgetItem.getQuantity() : 1;
@@ -267,7 +267,7 @@ public class ExaminePlugin extends Plugin
private int[] findItemFromWidget(int widgetId, int actionParam)
{
int widgetGroup = TO_GROUP(widgetId);
int widgetChild = getChildFromID(widgetId);
int widgetChild = TO_CHILD(widgetId);
Widget widget = client.getWidget(widgetGroup, widgetChild);
if (widget == null)

View File

@@ -563,7 +563,7 @@ public class GrandExchangePlugin extends Plugin
{
case WidgetID.BANK_GROUP_ID:
// Don't show for view tabs and such
if (WidgetInfo.getChildFromID(widgetId) != WidgetInfo.BANK_ITEM_CONTAINER.getChildId())
if (WidgetInfo.TO_CHILD(widgetId) != WidgetInfo.BANK_ITEM_CONTAINER.getChildId())
{
break;
}

View File

@@ -111,7 +111,7 @@ public class GroundItemsOverlay extends Overlay
final FontMetrics fm = graphics.getFontMetrics();
final Player player = client.getLocalPlayer();
if (player == null || client.getViewportWidget() == null)
if (player == null)
{
return null;
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2017, Devin French <https://github.com/devinfrench>
* 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.idlenotifier;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Units;
@ConfigGroup("idlenotifier")
public interface IdleNotifierConfig extends Config
{
@ConfigItem(
keyName = "animationidle",
name = "Idle Animation Notifications",
description = "Configures if idle animation notifications are enabled",
position = 1
)
default boolean animationIdle()
{
return true;
}
@ConfigItem(
keyName = "interactionidle",
name = "Idle Interaction Notifications",
description = "Configures if idle interaction notifications are enabled e.g. combat, fishing",
position = 2
)
default boolean interactionIdle()
{
return true;
}
@ConfigItem(
keyName = "movementidle",
name = "Idle Movement Notifications",
description = "Configures if idle movement notifications are enabled e.g. running, walking",
position = 3
)
default boolean movementIdle()
{
return false;
}
@ConfigItem(
keyName = "logoutidle",
name = "Idle Logout Notifications",
description = "Configures if the idle logout notifications are enabled",
position = 4
)
default boolean logoutIdle()
{
return true;
}
@ConfigItem(
keyName = "timeout",
name = "Idle Notification Delay",
description = "The notification delay after the player is idle",
position = 5
)
@Units(Units.MILLISECONDS)
default int getIdleNotificationDelay()
{
return 5000;
}
@ConfigItem(
keyName = "hitpoints",
name = "Hitpoints Notification Threshold",
description = "The amount of hitpoints to send a notification at. A value of 0 will disable notification.",
position = 6
)
default int getHitpointsThreshold()
{
return 0;
}
@ConfigItem(
keyName = "prayer",
name = "Prayer Notification Threshold",
description = "The amount of prayer points to send a notification at. A value of 0 will disable notification.",
position = 7
)
default int getPrayerThreshold()
{
return 0;
}
@ConfigItem(
keyName = "oxygen",
name = "Oxygen Notification Threshold",
position = 8,
description = "The amount of remaining oxygen to send a notification at. A value of 0 will disable notification."
)
@Units(Units.PERCENT)
default int getOxygenThreshold()
{
return 0;
}
@ConfigItem(
keyName = "spec",
name = "Special Attack Energy Notification Threshold",
position = 9,
description = "The amount of spec energy reached to send a notification at. A value of 0 will disable notification."
)
@Units(Units.PERCENT)
default int getSpecEnergyThreshold()
{
return 0;
}
}

View File

@@ -0,0 +1,746 @@
/*
* Copyright (c) 2016-2017, Abel Briggs
* Copyright (c) 2017, Kronos <https://github.com/KronosDesign>
* 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.idlenotifier;
import com.google.inject.Provides;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import net.runelite.api.Actor;
import static net.runelite.api.AnimationID.*;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.GameState;
import net.runelite.api.GraphicID;
import net.runelite.api.Hitsplat;
import net.runelite.api.NPC;
import net.runelite.api.NPCComposition;
import net.runelite.api.Player;
import net.runelite.api.Skill;
import net.runelite.api.VarPlayer;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.GraphicChanged;
import net.runelite.api.events.HitsplatApplied;
import net.runelite.api.events.InteractingChanged;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@PluginDescriptor(
name = "Idle Notifier",
description = "Send a notification when going idle, or when HP/Prayer reaches a threshold",
tags = {"health", "hitpoints", "notifications", "prayer"}
)
public class IdleNotifierPlugin extends Plugin
{
// This must be more than 500 client ticks (10 seconds) before you get AFK kicked
private static final int LOGOUT_WARNING_MILLIS = (4 * 60 + 40) * 1000; // 4 minutes and 40 seconds
private static final int COMBAT_WARNING_MILLIS = 19 * 60 * 1000; // 19 minutes
private static final int LOGOUT_WARNING_CLIENT_TICKS = LOGOUT_WARNING_MILLIS / Constants.CLIENT_TICK_LENGTH;
private static final int COMBAT_WARNING_CLIENT_TICKS = COMBAT_WARNING_MILLIS / Constants.CLIENT_TICK_LENGTH;
private static final int HIGHEST_MONSTER_ATTACK_SPEED = 8; // Except Scarab Mage, but they are with other monsters
private static final Duration SIX_HOUR_LOGOUT_WARNING_AFTER_DURATION = Duration.ofMinutes(340);
private static final String FISHING_SPOT = "Fishing spot";
@Inject
private Notifier notifier;
@Inject
private Client client;
@Inject
private IdleNotifierConfig config;
private Instant lastAnimating;
private int lastAnimation = IDLE;
private Instant lastInteracting;
private Actor lastInteract;
private Instant lastMoving;
private WorldPoint lastPosition;
private boolean notifyPosition = false;
private boolean notifyHitpoints = true;
private boolean notifyPrayer = true;
private boolean notifyOxygen = true;
private boolean notifyIdleLogout = true;
private boolean notify6HourLogout = true;
private int lastSpecEnergy = 1000;
private int lastCombatCountdown = 0;
private Instant sixHourWarningTime;
private boolean ready;
private boolean lastInteractWasCombat;
@Provides
IdleNotifierConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(IdleNotifierConfig.class);
}
@Subscribe
public void onAnimationChanged(AnimationChanged event)
{
if (client.getGameState() != GameState.LOGGED_IN)
{
return;
}
Player localPlayer = client.getLocalPlayer();
if (localPlayer != event.getActor())
{
return;
}
int graphic = localPlayer.getGraphic();
int animation = localPlayer.getAnimation();
switch (animation)
{
/* Woodcutting */
case WOODCUTTING_BRONZE:
case WOODCUTTING_IRON:
case WOODCUTTING_STEEL:
case WOODCUTTING_BLACK:
case WOODCUTTING_MITHRIL:
case WOODCUTTING_ADAMANT:
case WOODCUTTING_RUNE:
case WOODCUTTING_GILDED:
case WOODCUTTING_DRAGON:
case WOODCUTTING_INFERNAL:
case WOODCUTTING_3A_AXE:
case WOODCUTTING_CRYSTAL:
case WOODCUTTING_TRAILBLAZER:
/* Cooking(Fire, Range) */
case COOKING_FIRE:
case COOKING_RANGE:
case COOKING_WINE:
/* Crafting(Gem Cutting, Glassblowing, Spinning, Battlestaves, Pottery) */
case GEM_CUTTING_OPAL:
case GEM_CUTTING_JADE:
case GEM_CUTTING_REDTOPAZ:
case GEM_CUTTING_SAPPHIRE:
case GEM_CUTTING_EMERALD:
case GEM_CUTTING_RUBY:
case GEM_CUTTING_DIAMOND:
case GEM_CUTTING_AMETHYST:
case CRAFTING_GLASSBLOWING:
case CRAFTING_SPINNING:
case CRAFTING_BATTLESTAVES:
case CRAFTING_LEATHER:
case CRAFTING_POTTERS_WHEEL:
case CRAFTING_POTTERY_OVEN:
/* Fletching(Cutting, Stringing, Adding feathers and heads) */
case FLETCHING_BOW_CUTTING:
case FLETCHING_STRING_NORMAL_SHORTBOW:
case FLETCHING_STRING_OAK_SHORTBOW:
case FLETCHING_STRING_WILLOW_SHORTBOW:
case FLETCHING_STRING_MAPLE_SHORTBOW:
case FLETCHING_STRING_YEW_SHORTBOW:
case FLETCHING_STRING_MAGIC_SHORTBOW:
case FLETCHING_STRING_NORMAL_LONGBOW:
case FLETCHING_STRING_OAK_LONGBOW:
case FLETCHING_STRING_WILLOW_LONGBOW:
case FLETCHING_STRING_MAPLE_LONGBOW:
case FLETCHING_STRING_YEW_LONGBOW:
case FLETCHING_STRING_MAGIC_LONGBOW:
case FLETCHING_ATTACH_FEATHERS_TO_ARROWSHAFT:
case FLETCHING_ATTACH_HEADS:
case FLETCHING_ATTACH_BOLT_TIPS_TO_BRONZE_BOLT:
case FLETCHING_ATTACH_BOLT_TIPS_TO_IRON_BROAD_BOLT:
case FLETCHING_ATTACH_BOLT_TIPS_TO_BLURITE_BOLT:
case FLETCHING_ATTACH_BOLT_TIPS_TO_STEEL_BOLT:
case FLETCHING_ATTACH_BOLT_TIPS_TO_MITHRIL_BOLT:
case FLETCHING_ATTACH_BOLT_TIPS_TO_ADAMANT_BOLT:
case FLETCHING_ATTACH_BOLT_TIPS_TO_RUNE_BOLT:
case FLETCHING_ATTACH_BOLT_TIPS_TO_DRAGON_BOLT:
/* Smithing(Anvil, Furnace, Cannonballs */
case SMITHING_ANVIL:
case SMITHING_SMELTING:
case SMITHING_CANNONBALL:
/* Fishing */
case FISHING_CRUSHING_INFERNAL_EELS:
case FISHING_CUTTING_SACRED_EELS:
case FISHING_BIG_NET:
case FISHING_NET:
case FISHING_POLE_CAST:
case FISHING_CAGE:
case FISHING_HARPOON:
case FISHING_BARBTAIL_HARPOON:
case FISHING_DRAGON_HARPOON:
case FISHING_INFERNAL_HARPOON:
case FISHING_CRYSTAL_HARPOON:
case FISHING_TRAILBLAZER_HARPOON:
case FISHING_TRAILBLAZER_HARPOON_2:
case FISHING_OILY_ROD:
case FISHING_KARAMBWAN:
case FISHING_BAREHAND:
case FISHING_PEARL_ROD:
case FISHING_PEARL_FLY_ROD:
case FISHING_PEARL_BARBARIAN_ROD:
case FISHING_PEARL_ROD_2:
case FISHING_PEARL_FLY_ROD_2:
case FISHING_PEARL_BARBARIAN_ROD_2:
case FISHING_PEARL_OILY_ROD:
/* Mining(Normal) */
case MINING_BRONZE_PICKAXE:
case MINING_IRON_PICKAXE:
case MINING_STEEL_PICKAXE:
case MINING_BLACK_PICKAXE:
case MINING_MITHRIL_PICKAXE:
case MINING_ADAMANT_PICKAXE:
case MINING_RUNE_PICKAXE:
case MINING_GILDED_PICKAXE:
case MINING_DRAGON_PICKAXE:
case MINING_DRAGON_PICKAXE_UPGRADED:
case MINING_DRAGON_PICKAXE_OR:
case MINING_INFERNAL_PICKAXE:
case MINING_3A_PICKAXE:
case MINING_CRYSTAL_PICKAXE:
case MINING_TRAILBLAZER_PICKAXE:
case MINING_TRAILBLAZER_PICKAXE_2:
case MINING_TRAILBLAZER_PICKAXE_3:
case DENSE_ESSENCE_CHIPPING:
case DENSE_ESSENCE_CHISELING:
/* Mining(Motherlode) */
case MINING_MOTHERLODE_BRONZE:
case MINING_MOTHERLODE_IRON:
case MINING_MOTHERLODE_STEEL:
case MINING_MOTHERLODE_BLACK:
case MINING_MOTHERLODE_MITHRIL:
case MINING_MOTHERLODE_ADAMANT:
case MINING_MOTHERLODE_RUNE:
case MINING_MOTHERLODE_GILDED:
case MINING_MOTHERLODE_DRAGON:
case MINING_MOTHERLODE_DRAGON_UPGRADED:
case MINING_MOTHERLODE_DRAGON_OR:
case MINING_MOTHERLODE_INFERNAL:
case MINING_MOTHERLODE_3A:
case MINING_MOTHERLODE_CRYSTAL:
case MINING_MOTHERLODE_TRAILBLAZER:
/* Herblore */
case HERBLORE_PESTLE_AND_MORTAR:
case HERBLORE_POTIONMAKING:
case HERBLORE_MAKE_TAR:
/* Magic */
case MAGIC_CHARGING_ORBS:
case MAGIC_LUNAR_PLANK_MAKE:
case MAGIC_LUNAR_STRING_JEWELRY:
case MAGIC_MAKE_TABLET:
case MAGIC_ENCHANTING_JEWELRY:
case MAGIC_ENCHANTING_AMULET_1:
case MAGIC_ENCHANTING_AMULET_2:
case MAGIC_ENCHANTING_AMULET_3:
case MAGIC_ENCHANTING_BOLTS:
/* Prayer */
case USING_GILDED_ALTAR:
/* Farming */
case FARMING_MIX_ULTRACOMPOST:
case FARMING_HARVEST_BUSH:
case FARMING_HARVEST_HERB:
case FARMING_HARVEST_FRUIT_TREE:
case FARMING_HARVEST_FLOWER:
case FARMING_HARVEST_ALLOTMENT:
/* Misc */
case PISCARILIUS_CRANE_REPAIR:
case HOME_MAKE_TABLET:
case SAND_COLLECTION:
resetTimers();
lastAnimation = animation;
lastAnimating = Instant.now();
break;
case MAGIC_LUNAR_SHARED:
if (graphic == GraphicID.BAKE_PIE)
{
resetTimers();
lastAnimation = animation;
lastAnimating = Instant.now();
break;
}
case IDLE:
lastAnimating = Instant.now();
break;
default:
// On unknown animation simply assume the animation is invalid and dont throw notification
lastAnimation = IDLE;
lastAnimating = null;
}
}
@Subscribe
public void onInteractingChanged(InteractingChanged event)
{
final Actor source = event.getSource();
if (source != client.getLocalPlayer())
{
return;
}
final Actor target = event.getTarget();
// Reset last interact
if (target != null)
{
lastInteract = null;
}
else
{
lastInteracting = Instant.now();
}
final boolean isNpc = target instanceof NPC;
// If this is not NPC, do not process as we are not interested in other entities
if (!isNpc)
{
return;
}
final NPC npc = (NPC) target;
final NPCComposition npcComposition = npc.getComposition();
final List<String> npcMenuActions = Arrays.asList(npcComposition.getActions());
if (npcMenuActions.contains("Attack"))
{
// Player is most likely in combat with attack-able NPC
resetTimers();
lastInteract = target;
lastInteracting = Instant.now();
lastInteractWasCombat = true;
}
else if (target.getName() != null && target.getName().contains(FISHING_SPOT))
{
// Player is fishing
resetTimers();
lastInteract = target;
lastInteracting = Instant.now();
lastInteractWasCombat = false;
}
}
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
lastInteracting = null;
GameState state = gameStateChanged.getGameState();
switch (state)
{
case LOGIN_SCREEN:
resetTimers();
break;
case LOGGING_IN:
case HOPPING:
case CONNECTION_LOST:
ready = true;
break;
case LOGGED_IN:
if (ready)
{
sixHourWarningTime = Instant.now().plus(SIX_HOUR_LOGOUT_WARNING_AFTER_DURATION);
ready = false;
resetTimers();
}
break;
}
}
@Subscribe
public void onHitsplatApplied(HitsplatApplied event)
{
if (event.getActor() != client.getLocalPlayer())
{
return;
}
final Hitsplat hitsplat = event.getHitsplat();
if (hitsplat.getHitsplatType() == Hitsplat.HitsplatType.DAMAGE_ME
|| hitsplat.getHitsplatType() == Hitsplat.HitsplatType.BLOCK_ME)
{
lastCombatCountdown = HIGHEST_MONSTER_ATTACK_SPEED;
}
}
@Subscribe
public void onGraphicChanged(GraphicChanged event)
{
Actor actor = event.getActor();
if (actor != client.getLocalPlayer())
{
return;
}
if (actor.getGraphic() == GraphicID.SPLASH)
{
lastCombatCountdown = HIGHEST_MONSTER_ATTACK_SPEED;
}
}
@Subscribe
public void onGameTick(GameTick event)
{
final Player local = client.getLocalPlayer();
final Duration waitDuration = Duration.ofMillis(config.getIdleNotificationDelay());
lastCombatCountdown = Math.max(lastCombatCountdown - 1, 0);
if (client.getGameState() != GameState.LOGGED_IN
|| local == null
// If user has clicked in the last second then they're not idle so don't send idle notification
|| System.currentTimeMillis() - client.getMouseLastPressedMillis() < 1000
|| client.getKeyboardIdleTicks() < 10)
{
resetTimers();
return;
}
if (config.logoutIdle() && checkIdleLogout())
{
notifier.notify("[" + local.getName() + "] is about to log out from idling too long!");
}
if (check6hrLogout())
{
notifier.notify("[" + local.getName() + "] is about to log out from being online for 6 hours!");
}
if (config.animationIdle() && checkAnimationIdle(waitDuration, local))
{
notifier.notify("[" + local.getName() + "] is now idle!");
}
if (config.movementIdle() && checkMovementIdle(waitDuration, local))
{
notifier.notify("[" + local.getName() + "] has stopped moving!");
}
if (config.interactionIdle() && checkInteractionIdle(waitDuration, local))
{
if (lastInteractWasCombat)
{
notifier.notify("[" + local.getName() + "] is now out of combat!");
}
else
{
notifier.notify("[" + local.getName() + "] is now idle!");
}
}
if (checkLowHitpoints())
{
notifier.notify("[" + local.getName() + "] has low hitpoints!");
}
if (checkLowPrayer())
{
notifier.notify("[" + local.getName() + "] has low prayer!");
}
if (checkLowOxygen())
{
notifier.notify("[" + local.getName() + "] has low oxygen!");
}
if (checkFullSpecEnergy())
{
notifier.notify("[" + local.getName() + "] has restored spec energy!");
}
}
private boolean checkFullSpecEnergy()
{
int currentSpecEnergy = client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT);
int threshold = config.getSpecEnergyThreshold() * 10;
if (threshold == 0)
{
lastSpecEnergy = currentSpecEnergy;
return false;
}
// Check if we have regenerated over the threshold, and that the
// regen was small enough.
boolean notify = lastSpecEnergy < threshold && currentSpecEnergy >= threshold
&& currentSpecEnergy - lastSpecEnergy <= 100;
lastSpecEnergy = currentSpecEnergy;
return notify;
}
private boolean checkLowOxygen()
{
if (config.getOxygenThreshold() == 0)
{
return false;
}
if (config.getOxygenThreshold() >= client.getVar(Varbits.OXYGEN_LEVEL) * 0.1)
{
if (!notifyOxygen)
{
notifyOxygen = true;
return true;
}
}
else
{
notifyOxygen = false;
}
return false;
}
private boolean checkLowHitpoints()
{
if (config.getHitpointsThreshold() == 0)
{
return false;
}
if (client.getRealSkillLevel(Skill.HITPOINTS) > config.getHitpointsThreshold())
{
if (client.getBoostedSkillLevel(Skill.HITPOINTS) + client.getVar(Varbits.NMZ_ABSORPTION) <= config.getHitpointsThreshold())
{
if (!notifyHitpoints)
{
notifyHitpoints = true;
return true;
}
}
else
{
notifyHitpoints = false;
}
}
return false;
}
private boolean checkLowPrayer()
{
if (config.getPrayerThreshold() == 0)
{
return false;
}
if (client.getRealSkillLevel(Skill.PRAYER) > config.getPrayerThreshold())
{
if (client.getBoostedSkillLevel(Skill.PRAYER) <= config.getPrayerThreshold())
{
if (!notifyPrayer)
{
notifyPrayer = true;
return true;
}
}
else
{
notifyPrayer = false;
}
}
return false;
}
private boolean checkInteractionIdle(Duration waitDuration, Player local)
{
if (lastInteract == null)
{
return false;
}
final Actor interact = local.getInteracting();
if (interact == null)
{
if (lastInteracting != null
&& Instant.now().compareTo(lastInteracting.plus(waitDuration)) >= 0
&& lastCombatCountdown == 0)
{
lastInteract = null;
lastInteracting = null;
// prevent animation notifications from firing too
lastAnimation = IDLE;
lastAnimating = null;
return true;
}
}
else
{
lastInteracting = Instant.now();
}
return false;
}
private boolean checkIdleLogout()
{
// Check clientside AFK first, because this is required for the server to disconnect you for being first
int idleClientTicks = client.getKeyboardIdleTicks();
if (client.getMouseIdleTicks() < idleClientTicks)
{
idleClientTicks = client.getMouseIdleTicks();
}
if (idleClientTicks < LOGOUT_WARNING_CLIENT_TICKS)
{
notifyIdleLogout = true;
return false;
}
// If we are not receiving hitsplats then we can be afk kicked
if (lastCombatCountdown <= 0)
{
boolean warn = notifyIdleLogout;
notifyIdleLogout = false;
return warn;
}
// We are in combat, so now we have to check for the timer that knocks you out of combat
// I think there are other conditions that I don't know about, because during testing I just didn't
// get removed from combat sometimes.
final long lastInteractionAgo = System.currentTimeMillis() - client.getMouseLastPressedMillis();
if (lastInteractionAgo < COMBAT_WARNING_MILLIS || client.getKeyboardIdleTicks() < COMBAT_WARNING_CLIENT_TICKS)
{
notifyIdleLogout = true;
return false;
}
boolean warn = notifyIdleLogout;
notifyIdleLogout = false;
return warn;
}
private boolean check6hrLogout()
{
if (sixHourWarningTime == null)
{
return false;
}
if (Instant.now().compareTo(sixHourWarningTime) >= 0)
{
if (notify6HourLogout)
{
notify6HourLogout = false;
return true;
}
}
else
{
notify6HourLogout = true;
}
return false;
}
private boolean checkAnimationIdle(Duration waitDuration, Player local)
{
if (lastAnimation == IDLE)
{
return false;
}
final int animation = local.getAnimation();
if (animation == IDLE)
{
if (lastAnimating != null && Instant.now().compareTo(lastAnimating.plus(waitDuration)) >= 0)
{
lastAnimation = IDLE;
lastAnimating = null;
// prevent interaction notifications from firing too
lastInteract = null;
lastInteracting = null;
return true;
}
}
else
{
lastAnimating = Instant.now();
}
return false;
}
private boolean checkMovementIdle(Duration waitDuration, Player local)
{
if (lastPosition == null)
{
lastPosition = local.getWorldLocation();
return false;
}
WorldPoint position = local.getWorldLocation();
if (lastPosition.equals(position))
{
if (notifyPosition
&& local.getAnimation() == IDLE
&& Instant.now().compareTo(lastMoving.plus(waitDuration)) >= 0)
{
notifyPosition = false;
// Return true only if we weren't just breaking out of an animation
return lastAnimation == IDLE;
}
}
else
{
notifyPosition = true;
lastPosition = position;
lastMoving = Instant.now();
}
return false;
}
private void resetTimers()
{
final Player local = client.getLocalPlayer();
// Reset animation idle timer
lastAnimating = null;
if (client.getGameState() == GameState.LOGIN_SCREEN || local == null || local.getAnimation() != lastAnimation)
{
lastAnimation = IDLE;
}
// Reset interaction idle timer
lastInteracting = null;
if (client.getGameState() == GameState.LOGIN_SCREEN || local == null || local.getInteracting() != lastInteract)
{
lastInteract = null;
}
}
}

View File

@@ -51,7 +51,7 @@ public class InventoryTagsOverlay extends WidgetItemOverlay
}
@Override
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
{
final String group = plugin.getTag(itemId);
if (group != null)
@@ -60,10 +60,10 @@ public class InventoryTagsOverlay extends WidgetItemOverlay
final DisplayMode displayMode = config.getDisplayMode();
if (color != null)
{
Rectangle bounds = itemWidget.getCanvasBounds();
Rectangle bounds = widgetItem.getCanvasBounds();
if (displayMode == DisplayMode.OUTLINE)
{
final BufferedImage outline = itemManager.getItemOutline(itemId, itemWidget.getQuantity(), color);
final BufferedImage outline = itemManager.getItemOutline(itemId, widgetItem.getQuantity(), color);
graphics.drawImage(outline, (int) bounds.getX(), (int) bounds.getY(), null);
}
else

View File

@@ -52,7 +52,7 @@ class ItemChargeOverlay extends WidgetItemOverlay
}
@Override
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
{
if (!displayOverlay())
{
@@ -153,7 +153,7 @@ class ItemChargeOverlay extends WidgetItemOverlay
charges = chargeItem.getCharges();
}
final Rectangle bounds = itemWidget.getCanvasBounds();
final Rectangle bounds = widgetItem.getCanvasBounds();
final TextComponent textComponent = new TextComponent();
textComponent.setPosition(new Point(bounds.x - 1, bounds.y + 15));
textComponent.setText(charges < 0 ? "?" : String.valueOf(charges));

View File

@@ -55,7 +55,7 @@ class ItemIdentificationOverlay extends WidgetItemOverlay
}
@Override
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
{
ItemIdentification iden = findItemIdentification(itemId);
if (iden == null)
@@ -116,7 +116,7 @@ class ItemIdentificationOverlay extends WidgetItemOverlay
}
graphics.setFont(FontManager.getRunescapeSmallFont());
renderText(graphics, itemWidget.getCanvasBounds(), iden);
renderText(graphics, widgetItem.getCanvasBounds(), iden);
}
private void renderText(Graphics2D graphics, Rectangle bounds, ItemIdentification iden)

View File

@@ -198,7 +198,7 @@ class ItemPricesOverlay extends Overlay
}
else if (id == ItemID.PLATINUM_TOKEN)
{
return QuantityFormatter.formatNumber(qty * 1000) + " gp";
return QuantityFormatter.formatNumber(qty * 1000L) + " gp";
}
ItemComposition itemDef = itemManager.getItemComposition(id);

View File

@@ -93,7 +93,7 @@ public class ItemStatOverlay extends Overlay
final MenuEntry entry = menu[menuSize - 1];
final int group = WidgetInfo.TO_GROUP(entry.getParam1());
final int child = WidgetInfo.getChildFromID(entry.getParam1());
final int child = WidgetInfo.TO_CHILD(entry.getParam1());
final Widget widget = client.getWidget(group, child);
if (widget == null

View File

@@ -28,11 +28,7 @@ import java.util.ArrayList;
import java.util.List;
import net.runelite.api.Client;
import net.runelite.api.Varbits;
import net.runelite.client.plugins.itemstats.Effect;
import net.runelite.client.plugins.itemstats.Positivity;
import net.runelite.client.plugins.itemstats.RangeStatChange;
import net.runelite.client.plugins.itemstats.StatChange;
import net.runelite.client.plugins.itemstats.StatsChanges;
import net.runelite.client.plugins.itemstats.*;
import net.runelite.client.plugins.itemstats.stats.Stat;
import net.runelite.client.plugins.itemstats.stats.Stats;

View File

@@ -36,6 +36,7 @@ import javax.inject.Singleton;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.coords.WorldPoint;
import static net.runelite.client.plugins.kourendlibrary.Book.*;
/**

View File

@@ -1,58 +0,0 @@
/*
* Copyright (c) 2018, OpenOSRS <https://github.com/open-osrs>
* 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.neverlogout;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.events.GameTick;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@PluginDescriptor(
name = "Never Logout",
enabledByDefault = false,
description = "Overrides the 5 minute AFK logout timer.",
tags = {"openosrs", "never log", "idle", "logout", "log", "never"}
)
public class NeverLogoutPlugin extends Plugin
{
@Inject
private Client client;
@Subscribe
private void onGameTick(GameTick gameTick)
{
if (client.getKeyboardIdleTicks() > 14900)
{
client.setKeyboardIdleTicks(0);
}
if (client.getMouseIdleTicks() > 14900)
{
client.setMouseIdleTicks(0);
}
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright (c) 2019, GeChallengeM <https://github.com/GeChallengeM>
* 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.nextattack;
import java.awt.Color;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.Actor;
import net.runelite.api.NPC;
import net.runelite.api.coords.WorldArea;
@Getter(AccessLevel.PACKAGE)
class MemorizedNPC
{
private NPC npc;
private int npcIndex;
private String npcName;
private int attackSpeed;
@Setter(AccessLevel.PACKAGE)
private int combatTimerEnd;
@Setter(AccessLevel.PACKAGE)
private int timeLeft;
@Setter(AccessLevel.PACKAGE)
private int flinchTimerEnd;
@Setter(AccessLevel.PACKAGE)
private Status status;
@Setter(AccessLevel.PACKAGE)
private WorldArea lastnpcarea;
@Setter(AccessLevel.PACKAGE)
private Actor lastinteracted;
MemorizedNPC(final NPC npc, final int attackSpeed, final WorldArea worldArea)
{
this.npc = npc;
this.npcIndex = npc.getIndex();
this.npcName = npc.getName();
this.attackSpeed = attackSpeed;
this.combatTimerEnd = -1;
this.flinchTimerEnd = -1;
this.timeLeft = 0;
this.status = Status.OUT_OF_COMBAT;
this.lastnpcarea = worldArea;
this.lastinteracted = null;
}
@Getter(AccessLevel.PACKAGE)
@AllArgsConstructor
enum Status
{
FLINCHING("Flinching", Color.GREEN),
IN_COMBAT_DELAY("In Combat Delay", Color.ORANGE),
IN_COMBAT("In Combat", Color.RED),
OUT_OF_COMBAT("Out of Combat", Color.BLUE);
private String name;
private Color color;
}
}

View File

@@ -1,91 +0,0 @@
/*
* Copyright (c) 2019, GeChallengeM <https://github.com/GeChallengeM>
* 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.nextattack;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
import net.runelite.client.config.Range;
@ConfigGroup("nextattack")
public interface NextAttackConfig extends Config
{
@ConfigSection(
name = "Attack range",
description = "",
position = 1
)
String rangeTitle = "Attack range";
@Range(
min = 1
)
@ConfigItem(
keyName = "AttackRange",
name = "NPC attack range",
description = "The attack range of the NPC.",
position = 2,
section = rangeTitle
)
default int getRange()
{
return 1;
}
@ConfigSection(
name = "Attack speed",
description = "",
position = 3
)
String speedTitle = "Attack speed";
@ConfigItem(
keyName = "CustomAttSpeedEnabled",
name = "Use custom speed",
description = "Use this if the timer is wrong.",
position = 4,
section = speedTitle
)
default boolean isCustomAttSpeed()
{
return false;
}
@Range(
min = 1
)
@ConfigItem(
keyName = "CustomAttSpeed",
name = "Custom NPC att speed",
description = "The attack speed of the NPC (amount of ticks between their attacks).",
position = 5,
section = speedTitle
)
default int getCustomAttSpeed()
{
return 4;
}
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright (c) 2018, GeChallengeM <https://github.com/GeChallengeM>
* 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.nextattack;
import java.awt.Dimension;
import java.awt.Graphics2D;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.Point;
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;
@Singleton
public class NextAttackOverlay extends Overlay
{
private final Client client;
private final NextAttackPlugin plugin;
@Inject
NextAttackOverlay(final Client client, final NextAttackPlugin plugin)
{
this.client = client;
this.plugin = plugin;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
}
@Override
public Dimension render(Graphics2D graphics)
{
for (MemorizedNPC npc : plugin.getMemorizedNPCs())
{
if (npc.getNpc().getInteracting() == client.getLocalPlayer() || client.getLocalPlayer().getInteracting() == npc.getNpc())
{
switch (npc.getStatus())
{
case FLINCHING:
npc.setTimeLeft(Math.max(0, npc.getFlinchTimerEnd() - client.getTickCount()));
break;
case IN_COMBAT_DELAY:
npc.setTimeLeft(Math.max(0, npc.getCombatTimerEnd() - client.getTickCount() - 7));
break;
case IN_COMBAT:
npc.setTimeLeft(Math.max(0, npc.getCombatTimerEnd() - client.getTickCount()));
break;
case OUT_OF_COMBAT:
default:
npc.setTimeLeft(0);
break;
}
Point textLocation = npc.getNpc().getCanvasTextLocation(graphics, Integer.toString(npc.getTimeLeft()), npc.getNpc().getLogicalHeight() + 40);
if (textLocation != null)
{
OverlayUtil.renderTextLocation(graphics, textLocation, Integer.toString(npc.getTimeLeft()), npc.getStatus().getColor());
}
}
}
return null;
}
}

View File

@@ -1,266 +0,0 @@
/*
* Copyright (c) 2019, GeChallengeM <https://github.com/GeChallengeM>
* 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.nextattack;
import com.google.inject.Provides;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.GraphicID;
import net.runelite.api.Hitsplat;
import net.runelite.api.NPC;
import net.runelite.api.coords.WorldArea;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.GraphicChanged;
import net.runelite.api.events.HitsplatApplied;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.NPCManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
name = "Next Attack Timer",
enabledByDefault = false,
description = "Adds a timer on NPC's for their projected next attack",
tags = {"openosrs", "flinch", "npc"}
)
public class NextAttackPlugin extends Plugin
{
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private NPCManager npcManager;
@Inject
private NextAttackConfig config;
@Inject
private NextAttackOverlay npcStatusOverlay;
@Getter(AccessLevel.PACKAGE)
private final Set<MemorizedNPC> memorizedNPCs = new HashSet<>();
private WorldArea lastPlayerLocation;
@Provides
NextAttackConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(NextAttackConfig.class);
}
@Override
protected void startUp()
{
overlayManager.add(npcStatusOverlay);
}
@Override
protected void shutDown()
{
overlayManager.remove(npcStatusOverlay);
memorizedNPCs.clear();
}
@Subscribe
private void onNpcSpawned(NpcSpawned npcSpawned)
{
final NPC npc = npcSpawned.getNpc();
final String npcName = npc.getName();
if (npcName == null || !Arrays.asList(npc.getComposition().getActions()).contains("Attack"))
{
return;
}
int AttackSpeed = npcManager.getAttackSpeed(npc.getId());
if (AttackSpeed == 0)
{
AttackSpeed = 4;
}
memorizedNPCs.add(new MemorizedNPC(npc, AttackSpeed, npc.getWorldArea()));
}
@Subscribe
private void onNpcDespawned(NpcDespawned npcDespawned)
{
final NPC npc = npcDespawned.getNpc();
memorizedNPCs.removeIf(c -> c.getNpc() == npc);
}
@Subscribe
private void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOGIN_SCREEN ||
event.getGameState() == GameState.HOPPING)
{
memorizedNPCs.clear();
}
}
@Subscribe
private void onHitsplatApplied(HitsplatApplied event)
{
if (event.getActor().getInteracting() != client.getLocalPlayer())
{
return;
}
final Hitsplat hitsplat = event.getHitsplat();
if ((hitsplat.getHitsplatType() == Hitsplat.HitsplatType.DAMAGE_ME || hitsplat.getHitsplatType() == Hitsplat.HitsplatType.BLOCK_ME) && event.getActor() instanceof NPC)
{
for (MemorizedNPC mn : memorizedNPCs)
{
if (mn.getNpcIndex() != ((NPC) event.getActor()).getIndex())
{
continue;
}
if (mn.getStatus() == MemorizedNPC.Status.OUT_OF_COMBAT || (mn.getStatus() == MemorizedNPC.Status.IN_COMBAT && mn.getCombatTimerEnd() - client.getTickCount() < 1) || mn.getLastinteracted() == null)
{
mn.setStatus(MemorizedNPC.Status.FLINCHING);
mn.setCombatTimerEnd(-1);
if (config.isCustomAttSpeed())
{
mn.setFlinchTimerEnd(client.getTickCount() + config.getCustomAttSpeed() / 2 + 1);
}
else
{
mn.setFlinchTimerEnd(client.getTickCount() + mn.getAttackSpeed() / 2 + 1);
}
}
}
}
}
@Subscribe
private void onGraphicChanged(GraphicChanged event)
{
if ((event.getActor().getGraphic() == GraphicID.SPLASH) && event.getActor() instanceof NPC)
{
for (MemorizedNPC mn : memorizedNPCs)
{
if (mn.getNpcIndex() != ((NPC) event.getActor()).getIndex())
{
continue;
}
if (mn.getStatus() == MemorizedNPC.Status.OUT_OF_COMBAT || (mn.getStatus() == MemorizedNPC.Status.IN_COMBAT && mn.getCombatTimerEnd() - client.getTickCount() < 2) || event.getActor().getInteracting() == null)
{
mn.setStatus(MemorizedNPC.Status.FLINCHING);
mn.setCombatTimerEnd(-1);
if (config.isCustomAttSpeed())
{
mn.setFlinchTimerEnd(client.getTickCount() + config.getCustomAttSpeed() / 2 + 2);
}
else
{
mn.setFlinchTimerEnd(client.getTickCount() + mn.getAttackSpeed() / 2 + 2);
}
}
}
}
}
private void checkStatus()
{
if (lastPlayerLocation == null)
{
return;
}
for (MemorizedNPC npc : memorizedNPCs)
{
final double CombatTime = npc.getCombatTimerEnd() - client.getTickCount();
final double FlinchTime = npc.getFlinchTimerEnd() - client.getTickCount();
if (npc.getNpc().getWorldArea() == null)
{
continue;
}
if (npc.getNpc().getInteracting() == client.getLocalPlayer())
{
//Checks: will the NPC attack this tick?
if (((npc.getNpc().getWorldArea().canMelee(client, lastPlayerLocation) && config.getRange() == 1) //Separate mechanics for meleerange-only NPC's because they have extra collisiondata checks (fences etc.) and can't attack diagonally
|| (lastPlayerLocation.hasLineOfSightTo(client, npc.getNpc().getWorldArea()) && npc.getNpc().getWorldArea().distanceTo(lastPlayerLocation) <= config.getRange() && config.getRange() > 1))
&& ((npc.getStatus() != MemorizedNPC.Status.FLINCHING && CombatTime < 9) || (npc.getStatus() == MemorizedNPC.Status.FLINCHING && FlinchTime < 2))
&& npc.getNpc().getAnimation() != -1 //Failsafe, attacking NPC's always have an animation.
&& !(npc.getLastnpcarea().distanceTo(lastPlayerLocation) == 0 && npc.getLastnpcarea() != npc.getNpc().getWorldArea())) //Weird mechanic: NPC's can't attack on the tick they do a random move
{
npc.setStatus(MemorizedNPC.Status.IN_COMBAT_DELAY);
npc.setLastnpcarea(npc.getNpc().getWorldArea());
npc.setLastinteracted(npc.getNpc().getInteracting());
if (config.isCustomAttSpeed())
{
npc.setCombatTimerEnd(client.getTickCount() + config.getCustomAttSpeed() + 8);
}
else
{
npc.setCombatTimerEnd(client.getTickCount() + npc.getAttackSpeed() + 8);
}
continue;
}
}
switch (npc.getStatus())
{
case IN_COMBAT:
if (CombatTime < 2)
{
npc.setStatus(MemorizedNPC.Status.OUT_OF_COMBAT);
}
break;
case IN_COMBAT_DELAY:
if (CombatTime < 9)
{
npc.setStatus(MemorizedNPC.Status.IN_COMBAT);
}
break;
case FLINCHING:
if (FlinchTime < 2)
{
npc.setStatus(MemorizedNPC.Status.IN_COMBAT);
npc.setCombatTimerEnd(client.getTickCount() + 8);
}
}
npc.setLastnpcarea(npc.getNpc().getWorldArea());
npc.setLastinteracted(npc.getNpc().getInteracting());
}
}
@Subscribe
private void onGameTick(GameTick event)
{
checkStatus();
lastPlayerLocation = client.getLocalPlayer().getWorldArea();
}
}

View File

@@ -74,7 +74,7 @@ public class RunepouchOverlay extends WidgetItemOverlay
}
@Override
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
{
if (itemId != ItemID.RUNE_POUCH && itemId != ItemID.RUNE_POUCH_L)
{
@@ -85,7 +85,7 @@ public class RunepouchOverlay extends WidgetItemOverlay
graphics.setFont(FontManager.getRunescapeSmallFont());
Point location = itemWidget.getCanvasLocation();
Point location = widgetItem.getCanvasLocation();
StringBuilder tooltipBuilder = new StringBuilder();
for (int i = 0; i < AMOUNT_VARBITS.length; i++)
@@ -142,7 +142,7 @@ public class RunepouchOverlay extends WidgetItemOverlay
String tooltip = tooltipBuilder.toString();
if (!tooltip.isEmpty()
&& itemWidget.getCanvasBounds().contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY())
&& widgetItem.getCanvasBounds().contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY())
&& (config.runePouchOverlayMode() == MOUSE_HOVER || config.runePouchOverlayMode() == BOTH))
{
tooltipManager.add(new Tooltip(tooltip));

View File

@@ -43,7 +43,7 @@ class ScreenMarkerCreationOverlay extends Overlay
{
this.plugin = plugin;
setPosition(OverlayPosition.DETACHED);
setLayer(OverlayLayer.ALWAYS_ON_TOP);
setLayer(OverlayLayer.ABOVE_WIDGETS);
setPriority(OverlayPriority.HIGH);
}

View File

@@ -75,7 +75,7 @@ class ScreenMarkerWidgetHighlightOverlay extends Overlay
final int childIdx = menuEntry.getParam0();
final int widgetId = menuEntry.getParam1();
final int groupId = WidgetInfo.TO_GROUP(widgetId);
final int componentId = WidgetInfo.getChildFromID(widgetId);
final int componentId = WidgetInfo.TO_CHILD(widgetId);
final Widget widget = client.getWidget(groupId, componentId);
if (widget == null)

View File

@@ -94,7 +94,7 @@ class SlayerOverlay extends WidgetItemOverlay
}
@Override
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
{
if (!ALL_SLAYER_ITEMS.contains(itemId))
{
@@ -117,7 +117,7 @@ class SlayerOverlay extends WidgetItemOverlay
graphics.setFont(FontManager.getRunescapeSmallFont());
final Rectangle bounds = itemWidget.getCanvasBounds();
final Rectangle bounds = widgetItem.getCanvasBounds();
final TextComponent textComponent = new TextComponent();
switch (itemId)

View File

@@ -39,7 +39,6 @@ import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.GameState;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
@@ -51,7 +50,6 @@ import net.runelite.api.NpcID;
import net.runelite.api.Player;
import net.runelite.api.VarPlayer;
import net.runelite.api.Varbits;
import net.runelite.api.WorldType;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ActorDeath;
import net.runelite.api.events.AnimationChanged;
@@ -64,10 +62,7 @@ import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.NpcChanged;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.events.WidgetHiddenChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
@@ -135,15 +130,14 @@ public class TimersPlugin extends Plugin
private boolean wasWearingEndurance;
private int lastRaidVarb;
private int lastWildernessVarb;
private int lastVengCooldownVarb;
private int lastIsVengeancedVarb;
private int lastPoisonVarp;
private int lastPvpVarb;
private int nextPoisonTick;
private WorldPoint lastPoint;
private TeleportWidget lastTeleportClicked;
private int lastAnimation;
private boolean loggedInRace;
private boolean widgetHiddenChangedOnPvpWorld;
private ElapsedTimer tzhaarTimer;
@@ -176,7 +170,6 @@ public class TimersPlugin extends Plugin
lastPoint = null;
lastTeleportClicked = null;
lastAnimation = -1;
loggedInRace = false;
widgetHiddenChangedOnPvpWorld = false;
lastPoisonVarp = 0;
nextPoisonTick = 0;
@@ -191,6 +184,7 @@ public class TimersPlugin extends Plugin
int vengCooldownVarb = client.getVar(Varbits.VENGEANCE_COOLDOWN);
int isVengeancedVarb = client.getVar(Varbits.VENGEANCE_ACTIVE);
int poisonVarp = client.getVar(VarPlayer.POISON);
int pvpVarb = client.getVar(Varbits.PVP_SPEC_ORB);
if (lastRaidVarb != raidVarb)
{
@@ -227,22 +221,6 @@ public class TimersPlugin extends Plugin
lastIsVengeancedVarb = isVengeancedVarb;
}
int inWilderness = client.getVar(Varbits.IN_WILDERNESS);
if (lastWildernessVarb != inWilderness
&& client.getGameState() == GameState.LOGGED_IN
&& !loggedInRace)
{
if (!WorldType.isPvpWorld(client.getWorldType())
&& inWilderness == 0)
{
log.debug("Left wilderness in non-PVP world, clearing Teleblock timer.");
removeGameTimer(TELEBLOCK);
}
lastWildernessVarb = inWilderness;
}
if (lastPoisonVarp != poisonVarp && config.showAntiPoison())
{
final int tickCount = client.getTickCount();
@@ -272,16 +250,16 @@ public class TimersPlugin extends Plugin
lastPoisonVarp = poisonVarp;
}
}
@Subscribe
public void onWidgetHiddenChanged(WidgetHiddenChanged event)
{
Widget widget = event.getWidget();
if (WorldType.isPvpWorld(client.getWorldType())
&& WidgetInfo.TO_GROUP(widget.getId()) == WidgetID.PVP_GROUP_ID)
if (lastPvpVarb != pvpVarb)
{
widgetHiddenChangedOnPvpWorld = true;
if (pvpVarb == 0)
{
log.debug("Left a PVP zone, clearing teleblock timer");
removeGameTimer(TELEBLOCK);
}
lastPvpVarb = pvpVarb;
}
}
@@ -763,8 +741,6 @@ public class TimersPlugin extends Plugin
@Subscribe
public void onGameTick(GameTick event)
{
loggedInRace = false;
Player player = client.getLocalPlayer();
WorldPoint currentWorldPoint = player.getWorldLocation();
@@ -826,9 +802,6 @@ public class TimersPlugin extends Plugin
removeTzhaarTimer(); // will be readded by the wave message
removeGameTimer(TELEBLOCK);
break;
case LOGGED_IN:
loggedInRace = true;
break;
}
}

View File

@@ -34,7 +34,6 @@ import net.runelite.api.Client;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.widgets.Widget;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
@@ -85,8 +84,6 @@ public class TitheFarmPlantOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
final Widget viewport = client.getViewportWidget();
for (TitheFarmPlant plant : plugin.getPlants())
{
if (plant.getState() == TitheFarmPlantState.DEAD)
@@ -103,7 +100,7 @@ public class TitheFarmPlantOverlay extends Overlay
final Point canvasLocation = Perspective.localToCanvas(client, localLocation, client.getPlane());
if (viewport != null && canvasLocation != null)
if (canvasLocation != null)
{
final ProgressPieComponent progressPieComponent = new ProgressPieComponent();
progressPieComponent.setPosition(canvasLocation);

View File

@@ -36,11 +36,12 @@ import net.runelite.api.MenuEntry;
import net.runelite.api.NPC;
import net.runelite.api.NPCComposition;
import net.runelite.api.ObjectComposition;
import net.runelite.api.ScriptID;
import net.runelite.api.SpriteID;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.WidgetHiddenChanged;
import net.runelite.api.events.ScriptPostFired;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
@@ -198,11 +199,12 @@ public class WikiPlugin extends Plugin
}
@Subscribe
private void onWidgetHiddenChanged(WidgetHiddenChanged ev)
public void onScriptPostFired(ScriptPostFired scriptPostFired)
{
if (ev.getWidget().getId() == WidgetInfo.MINIMAP_WIKI_BANNER.getId())
if (scriptPostFired.getScriptId() == ScriptID.WIKI_ICON_UPDATE)
{
ev.getWidget().setHidden(true);
Widget w = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER);
w.setHidden(true);
}
}

View File

@@ -26,7 +26,9 @@ package net.runelite.client.plugins.xptracker;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.function.Function;
import static net.runelite.client.plugins.xptracker.XpInfoBox.TWO_DECIMAL_FORMAT;
@Getter

View File

@@ -33,6 +33,7 @@ import javax.annotation.Nullable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity;
@@ -49,6 +50,7 @@ public abstract class Overlay implements LayoutableRenderableEntity
private OverlayPosition position = OverlayPosition.TOP_LEFT;
private OverlayPriority priority = OverlayPriority.NONE;
private OverlayLayer layer = OverlayLayer.UNDER_WIDGETS;
private final List<Integer> drawHooks = new ArrayList<>();
private final List<OverlayMenuEntry> menuEntries = new ArrayList<>();
private boolean resizable;
private int minimumSize = 32;
@@ -81,6 +83,16 @@ public abstract class Overlay implements LayoutableRenderableEntity
return this.getClass().getSimpleName();
}
protected void drawAfterInterface(int interfaceId)
{
drawHooks.add(interfaceId << 16 | 0xffff);
}
protected void drawAfterLayer(WidgetInfo layer)
{
drawHooks.add(layer.getId());
}
public void onMouseOver()
{
}

View File

@@ -26,6 +26,12 @@ package net.runelite.client.ui.overlay;
public enum OverlayLayer
{
/**
* Overlay is not rendered. Requires using drawAfterInterface() or drawAfterLayer()
* to specify when to draw.
*/
MANUAL,
/**
* Render right above the scene (that contains actors and the surface)
*/
@@ -45,9 +51,4 @@ public enum OverlayLayer
* Render overlay above all game elements
*/
ALWAYS_ON_TOP,
/**
* Render over the map, even when it's fullscreen
*/
ABOVE_MAP,
}

View File

@@ -25,21 +25,24 @@
package net.runelite.client.ui.overlay;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ArrayListMultimap;
import java.awt.Dimension;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.MenuAction;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigManager;
@@ -66,13 +69,8 @@ public class OverlayManager
@VisibleForTesting
static final Comparator<Overlay> OVERLAY_COMPARATOR = (a, b) ->
{
final OverlayPosition aPos = a.getPreferredPosition() != null
? a.getPreferredPosition()
: a.getPosition();
final OverlayPosition bPos = b.getPreferredPosition() != null
? b.getPreferredPosition()
: b.getPosition();
final OverlayPosition aPos = MoreObjects.firstNonNull(a.getPreferredPosition(), a.getPosition());
final OverlayPosition bPos = MoreObjects.firstNonNull(b.getPreferredPosition(), b.getPosition());
if (aPos != bPos)
{
@@ -84,7 +82,7 @@ public class OverlayManager
// For dynamic overlays, higher priority means to
// draw *later* so it is on top.
// For non-dynamic overlays, higher priority means
// draw *first* so that they are closer to their
// draw *earlier* so that they are closer to their
// defined position.
return aPos == OverlayPosition.DYNAMIC
? a.getPriority().compareTo(b.getPriority())
@@ -98,9 +96,16 @@ public class OverlayManager
@Getter(AccessLevel.PACKAGE)
private final List<Overlay> overlays = new ArrayList<>();
@Getter
private final List<WidgetItem> itemWidgets = new ArrayList<>();
@Setter
private Collection<WidgetItem> widgetItems = Collections.emptyList();
private final Map<OverlayLayer, List<Overlay>> overlayLayers = new EnumMap<>(OverlayLayer.class);
/**
* Valid keys are:
* OverlayLayer ABOVE_SCENE, UNDER_WIDGETS, and ALWAYS_ON_TOP
* A component id that is a layer
* An interface id << 16 | 0xffff
*/
private ArrayListMultimap<Object, Overlay> overlayMap = ArrayListMultimap.create();
private final ConfigManager configManager;
private final EventBus eventBus;
@@ -143,12 +148,12 @@ public class OverlayManager
event.consume();
Overlay overlay = overlays.get(event.getType());
Overlay overlay = overlays.get(event.getId());
if (overlay != null)
{
List<OverlayMenuEntry> menuEntries = overlay.getMenuEntries();
OverlayMenuEntry overlayMenuEntry = menuEntries.stream()
.filter(me -> me.getOption().equals(event.getOption()))
.filter(me -> me.getOption().equals(event.getMenuOption()))
.findAny()
.orElse(null);
if (overlayMenuEntry != null)
@@ -164,9 +169,19 @@ public class OverlayManager
* @param layer the layer
* @return An immutable list of all of the overlays on that layer
*/
synchronized List<Overlay> getLayer(OverlayLayer layer)
Collection<Overlay> getLayer(OverlayLayer layer)
{
return overlayLayers.get(layer);
return Collections.unmodifiableCollection(overlayMap.get(layer));
}
Collection<Overlay> getForInterface(int interfaceId)
{
return Collections.unmodifiableCollection(overlayMap.get(interfaceId << 16 | 0xffff));
}
Collection<Overlay> getForLayer(int layerId)
{
return Collections.unmodifiableCollection(overlayMap.get(layerId));
}
/**
@@ -282,11 +297,7 @@ public class OverlayManager
synchronized void rebuildOverlayLayers()
{
for (OverlayLayer l : OverlayLayer.values())
{
overlayLayers.put(l, new ArrayList<>());
}
ArrayListMultimap<Object, Overlay> overlayMap = ArrayListMultimap.create();
for (final Overlay overlay : overlays)
{
OverlayLayer layer = overlay.getLayer();
@@ -301,14 +312,33 @@ public class OverlayManager
}
}
overlayLayers.get(layer).add(overlay);
switch (layer)
{
case ABOVE_SCENE:
case UNDER_WIDGETS:
case ALWAYS_ON_TOP:
overlayMap.put(layer, overlay);
break;
case ABOVE_WIDGETS:
// draw after each of the top level interfaces
overlayMap.put(WidgetID.FIXED_VIEWPORT_GROUP_ID << 16 | 0xffff, overlay);
overlayMap.put(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID << 16 | 0xffff, overlay);
overlayMap.put(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID << 16 | 0xffff, overlay);
break;
}
for (int drawHook : overlay.getDrawHooks())
{
overlayMap.put(drawHook, overlay);
}
}
overlayLayers.forEach((layer, value) ->
for (Object key : overlayMap.keys())
{
value.sort(OVERLAY_COMPARATOR);
overlayLayers.put(layer, Collections.unmodifiableList(value));
});
overlayMap.get(key).sort(OVERLAY_COMPARATOR);
}
this.overlayMap = overlayMap;
}
private void loadOverlay(final Overlay overlay)

View File

@@ -39,6 +39,8 @@ import java.awt.Stroke;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -48,11 +50,13 @@ import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.KeyCode;
import net.runelite.api.MenuEntry;
import net.runelite.api.Varbits;
import net.runelite.api.events.BeforeRender;
import net.runelite.api.events.ClientTick;
import net.runelite.api.events.FocusChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyListener;
@@ -98,10 +102,9 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
// Overlay state validation
private Rectangle viewportBounds;
private Rectangle chatboxBounds;
private int viewportOffset;
private boolean chatboxHidden;
private boolean isResizeable;
private OverlayBounds snapCorners;
private OverlayBounds emptySnapCorners, snapCorners;
@Inject
private OverlayRenderer(
@@ -167,35 +170,51 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
public void onBeforeRender(BeforeRender event)
{
menuEntries = null;
if (client.getGameState() == GameState.LOGGED_IN)
{
if (shouldInvalidateBounds())
{
emptySnapCorners = buildSnapCorners();
}
// Create copy of snap corners because overlays will modify them
snapCorners = new OverlayBounds(emptySnapCorners);
}
}
public void render(Graphics2D graphics, final OverlayLayer layer)
public void renderOverlayLayer(Graphics2D graphics, final OverlayLayer layer)
{
if (layer != OverlayLayer.ABOVE_MAP
&& client.getWidget(WidgetInfo.FULLSCREEN_MAP_ROOT) != null
&& !client.getWidget(WidgetInfo.FULLSCREEN_MAP_ROOT).isHidden())
{
return;
}
final Collection<Overlay> overlays = overlayManager.getLayer(layer);
renderOverlays(graphics, overlays, layer);
}
final List<Overlay> overlays = overlayManager.getLayer(layer);
public void renderAfterInterface(Graphics2D graphics, int interfaceId, Collection<WidgetItem> widgetItems)
{
Collection<Overlay> overlays = overlayManager.getForInterface(interfaceId);
overlayManager.setWidgetItems(widgetItems);
renderOverlays(graphics, overlays, OverlayLayer.ABOVE_WIDGETS);
overlayManager.setWidgetItems(Collections.emptyList());
}
public void renderAfterLayer(Graphics2D graphics, Widget layer, Collection<WidgetItem> widgetItems)
{
Collection<Overlay> overlays = overlayManager.getForLayer(layer.getId());
overlayManager.setWidgetItems(widgetItems);
renderOverlays(graphics, overlays, OverlayLayer.ABOVE_WIDGETS);
overlayManager.setWidgetItems(Collections.emptyList());
}
private void renderOverlays(Graphics2D graphics, Collection<Overlay> overlays, OverlayLayer layer)
{
if (overlays == null
|| overlays.isEmpty()
|| client.getGameState() != GameState.LOGGED_IN
|| client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN) != null
|| client.getViewportWidget() == null)
|| client.getGameState() != GameState.LOGGED_IN)
{
return;
}
if (shouldInvalidateBounds())
{
snapCorners = buildSnapCorners();
}
// Create copy of snap corners because overlays will modify them
OverlayBounds snapCorners = new OverlayBounds(this.snapCorners);
OverlayUtil.setGraphicProperties(graphics);
// Draw snap corners
@@ -629,7 +648,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
// Check if the overlay is over a snapcorner and move it if so, unless it is a detached overlay
if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode)
{
final OverlayBounds snapCorners = this.snapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
final OverlayBounds snapCorners = this.emptySnapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
for (Rectangle snapCorner : snapCorners.getBounds())
{
@@ -795,43 +814,53 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
changed = true;
}
final boolean viewportChanged = !client.getViewportWidget().getBounds().equals(viewportBounds);
Widget viewportWidget = getViewportLayer();
Rectangle viewport = viewportWidget != null ? viewportWidget.getBounds() : new Rectangle();
final boolean viewportChanged = !viewport.equals(viewportBounds);
if (viewportChanged)
{
viewportBounds = client.getViewportWidget().getBounds();
changed = true;
}
final boolean viewportOffsetChanged = client.getViewportXOffset() != viewportOffset;
if (viewportOffsetChanged)
{
viewportOffset = client.getViewportXOffset();
viewportBounds = viewport;
changed = true;
}
return changed;
}
private Widget getViewportLayer()
{
if (client.isResized())
{
if (client.getVar(Varbits.SIDE_PANELS) == 1)
{
return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE);
}
else
{
return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX);
}
}
return client.getWidget(WidgetInfo.FIXED_VIEWPORT);
}
private OverlayBounds buildSnapCorners()
{
final Point topLeftPoint = new Point(
viewportOffset + BORDER,
viewportOffset + BORDER_TOP);
viewportBounds.x + BORDER,
viewportBounds.y + BORDER_TOP);
final Point topCenterPoint = new Point(
viewportOffset + viewportBounds.width / 2,
viewportOffset + BORDER
viewportBounds.x + viewportBounds.width / 2,
viewportBounds.y + BORDER
);
final Point topRightPoint = new Point(
viewportOffset + viewportBounds.width - BORDER,
viewportBounds.x + viewportBounds.width - BORDER,
topCenterPoint.y);
final Point bottomLeftPoint = new Point(
topLeftPoint.x,
viewportOffset + viewportBounds.height - BORDER);
viewportBounds.y + viewportBounds.height - BORDER);
final Point bottomRightPoint = new Point(
topRightPoint.x,
@@ -844,7 +873,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
}
final Point rightChatboxPoint = isResizeable ? new Point(
viewportOffset + chatboxBounds.width - BORDER,
viewportBounds.x + chatboxBounds.width - BORDER,
bottomLeftPoint.y) : bottomRightPoint;
final Point canvasTopRightPoint = isResizeable ? new Point(
@@ -880,7 +909,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
entry.setOption(overlayMenuEntry.getOption());
entry.setTarget(ColorUtil.wrapWithColorTag(overlayMenuEntry.getTarget(), JagexColors.MENU_TARGET));
entry.setType(overlayMenuEntry.getMenuAction().getId());
entry.setType(overlayManager.getOverlays().indexOf(overlay)); // overlay id
entry.setIdentifier(overlayManager.getOverlays().indexOf(overlay)); // overlay id
entries[i] = entry;
}

View File

@@ -28,68 +28,49 @@ import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Collection;
import lombok.AccessLevel;
import lombok.Setter;
import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetID.BANK_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.BANK_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.DEPOSIT_BOX_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_OTHER_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.EQUIPMENT_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.EQUIPMENT_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.GRAND_EXCHANGE_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.GUIDE_PRICES_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_SCREEN_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.SEED_VAULT_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.SHOP_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_OTHER_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_SCREEN_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_INVENTORY_GROUP_ID;
import static net.runelite.api.widgets.WidgetInfo.BANK_CONTENT_CONTAINER;
import static net.runelite.api.widgets.WidgetInfo.BANK_TAB_CONTAINER;
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetItem;
public abstract class WidgetItemOverlay extends Overlay
{
@Setter(AccessLevel.PACKAGE)
private OverlayManager overlayManager;
/**
* Interfaces to draw overlay over.
*/
private final Set<Integer> interfaceGroups = new HashSet<>();
protected WidgetItemOverlay()
{
super.setPosition(OverlayPosition.DYNAMIC);
super.setPriority(OverlayPriority.LOW);
super.setLayer(OverlayLayer.ABOVE_WIDGETS);
super.setLayer(OverlayLayer.MANUAL);
}
public abstract void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget);
public abstract void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem);
@Override
public Dimension render(Graphics2D graphics)
{
final List<WidgetItem> itemWidgets = overlayManager.getItemWidgets();
final Collection<WidgetItem> widgetItems = overlayManager.getWidgetItems();
final Rectangle originalClipBounds = graphics.getClipBounds();
Widget curClipParent = null;
for (WidgetItem widgetItem : itemWidgets)
for (WidgetItem widgetItem : widgetItems)
{
Widget widget = widgetItem.getWidget();
int interfaceGroup = TO_GROUP(widget.getId());
// Don't draw if this widget isn't one of the allowed nor in tag tab/item tab
if (!interfaceGroups.contains(interfaceGroup) ||
(interfaceGroup == BANK_GROUP_ID
&& (widget.getParentId() == BANK_CONTENT_CONTAINER.getId() || widget.getParentId() == BANK_TAB_CONTAINER.getId())))
{
continue;
}
Widget parent = widget.getParent();
Rectangle parentBounds = parent.getBounds();
Rectangle itemCanvasBounds = widgetItem.getCanvasBounds();
@@ -151,7 +132,7 @@ public abstract class WidgetItemOverlay extends Overlay
protected void showOnBank()
{
showOnInterfaces(BANK_GROUP_ID);
drawAfterLayer(WidgetInfo.BANK_ITEM_CONTAINER);
}
protected void showOnEquipment()
@@ -161,7 +142,7 @@ public abstract class WidgetItemOverlay extends Overlay
protected void showOnInterfaces(int... ids)
{
Arrays.stream(ids).forEach(interfaceGroups::add);
Arrays.stream(ids).forEach(this::drawAfterInterface);
}
// Don't allow setting position, priority, or layer

View File

@@ -80,6 +80,8 @@ public class WidgetOverlay extends Overlay
setPriority(OverlayPriority.HIGHEST);
setLayer(OverlayLayer.UNDER_WIDGETS);
setPosition(overlayPosition);
// It's almost possible to drawAfterInterface(widgetInfo.getGroupId()) here, but that fires
// *after* the native components are drawn, which is too late.
}
@Override

View File

@@ -197,7 +197,7 @@ public class InfoBoxOverlay extends OverlayPanel
InfoBox infoBox = hoveredComponent.getInfoBox();
OverlayMenuEntry overlayMenuEntry = infoBox.getMenuEntries().stream()
.filter(me -> me.getOption().equals(menuOptionClicked.getOption()))
.filter(me -> me.getOption().equals(menuOptionClicked.getMenuOption()))
.findAny()
.orElse(null);
if (overlayMenuEntry != null)

View File

@@ -32,6 +32,7 @@ import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.widgets.WidgetID;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.config.TooltipPositionType;
import net.runelite.client.ui.overlay.Overlay;
@@ -59,7 +60,9 @@ public class TooltipOverlay extends Overlay
this.runeLiteConfig = runeLiteConfig;
setPosition(OverlayPosition.TOOLTIP);
setPriority(OverlayPriority.HIGHEST);
setLayer(OverlayLayer.ALWAYS_ON_TOP);
setLayer(OverlayLayer.ABOVE_WIDGETS);
// additionally allow tooltips above the world map
drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID);
}
@Override

View File

@@ -39,6 +39,7 @@ import net.runelite.api.Point;
import net.runelite.api.RenderOverview;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.input.MouseManager;
import net.runelite.client.ui.FontManager;
@@ -73,7 +74,8 @@ public class WorldMapOverlay extends Overlay
this.worldMapPointManager = worldMapPointManager;
setPosition(OverlayPosition.DYNAMIC);
setPriority(OverlayPriority.HIGHEST);
setLayer(OverlayLayer.ABOVE_MAP);
setLayer(OverlayLayer.MANUAL);
drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID);
mouseManager.registerMouseListener(worldMapOverlayMouseListener);
}

View File

@@ -65,10 +65,7 @@ public class ObsidianSkin extends SubstanceSkin
final SubstanceColorSchemeBundle defaultSchemeBundle = new SubstanceColorSchemeBundle(
activeScheme, enabledScheme, enabledScheme);
//defaultSchemeBundle.registerColorScheme(enabledScheme, 0.6f,
// ComponentState.DISABLED_UNSELECTED);
//defaultSchemeBundle.registerColorScheme(activeScheme, 0.6f,
// ComponentState.DISABLED_SELECTED);
// borders
final SubstanceColorScheme borderDisabledSelectedScheme = schemes
@@ -82,9 +79,7 @@ public class ObsidianSkin extends SubstanceSkin
final SubstanceColorScheme markActiveScheme = schemes.get("RuneLite Mark Active");
defaultSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK,
ComponentState.getActiveStates());
//defaultSchemeBundle.registerColorScheme(markActiveScheme, 0.6f,
// ColorSchemeAssociationKind.MARK, ComponentState.DISABLED_SELECTED,
// ComponentState.DISABLED_UNSELECTED);
// separators
final SubstanceColorScheme separatorScheme = schemes.get("RuneLite Separator");
@@ -102,8 +97,7 @@ public class ObsidianSkin extends SubstanceSkin
final SubstanceColorSchemeBundle decorationsSchemeBundle = new SubstanceColorSchemeBundle(
activeScheme, enabledScheme, enabledScheme);
//decorationsSchemeBundle.registerColorScheme(enabledScheme, 0.5f,
// ComponentState.DISABLED_UNSELECTED);
// borders
decorationsSchemeBundle.registerColorScheme(borderDisabledSelectedScheme,
@@ -129,8 +123,7 @@ public class ObsidianSkin extends SubstanceSkin
final SubstanceColorSchemeBundle headerSchemeBundle = new SubstanceColorSchemeBundle(activeScheme,
enabledScheme, enabledScheme);
//headerSchemeBundle.registerColorScheme(enabledScheme, 0.5f,
// ComponentState.DISABLED_UNSELECTED);
// borders
final SubstanceColorScheme headerBorderScheme = schemes.get("RuneLite Header Border");
@@ -142,14 +135,6 @@ public class ObsidianSkin extends SubstanceSkin
headerSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK,
ComponentState.getActiveStates());
//headerSchemeBundle.registerHighlightColorScheme(activeScheme, 0.7f,
// ComponentState.ROLLOVER_UNSELECTED, ComponentState.ROLLOVER_ARMED,
// ComponentState.ARMED);
//headerSchemeBundle.registerHighlightColorScheme(activeScheme, 0.8f,
// ComponentState.SELECTED);
//headerSchemeBundle.registerHighlightColorScheme(activeScheme, 1.0f,
// ComponentState.ROLLOVER_SELECTED);
final SubstanceColorScheme headerWatermarkScheme = schemes.get("RuneLite Header Watermark");
this.registerDecorationAreaSchemeBundle(headerSchemeBundle, headerWatermarkScheme,