Merge pull request #3034 from open-osrs/upstream-2508-2

project: Merge upstream
This commit is contained in:
Owain van Brakel
2021-09-07 03:30:20 +02:00
committed by GitHub
57 changed files with 983 additions and 619 deletions

View File

@@ -40,4 +40,5 @@ public class LootRecord
private Object metadata;
private Collection<GameItem> drops;
private Instant time;
private Integer world;
}

View File

@@ -32,8 +32,8 @@ public enum WorldType
SKILL_TOTAL,
HIGH_RISK,
LAST_MAN_STANDING,
TOURNAMENT,
NOSAVE_MODE,
DEADMAN,
DEADMAN_TOURNAMENT,
LEAGUE;
TOURNAMENT,
SEASONAL;
}

View File

@@ -295,7 +295,7 @@ public interface Actor extends Renderable, Locatable
void setSpotAnimFrame(int spotAnimFrame);
/**
* Gets the canvas area of the current tile the actor is standing on.
* Gets the canvas area of the current tiles the actor is standing on.
*
* @return the current tile canvas area
*/

View File

@@ -90,8 +90,7 @@ public interface Model extends Renderable
short[] getFaceTextures();
float[][] getFaceTextureUCoordinates();
float[][] getFaceTextureVCoordinates();
float[] getFaceTextureUVCoordinates();
void calculateExtreme(int orientation);

View File

@@ -26,10 +26,12 @@ package net.runelite.api;
import java.util.Collection;
import java.util.EnumSet;
import lombok.AllArgsConstructor;
/**
* An enumeration of possible world types.
*/
@AllArgsConstructor
public enum WorldType
{
/**
@@ -57,29 +59,24 @@ public enum WorldType
*/
LAST_MAN_STANDING(1 << 14),
/**
* Tournament world type.
* Beta worlds without profiles that are saved.
*/
TOURNAMENT(1 << 25),
NOSAVE_MODE(1 << 25),
/**
* Deadman Tournament world type.
* Tournament world type
*/
DEADMAN_TOURNAMENT(1 << 26),
TOURNAMENT_WORLD(1 << 26),
/**
* Deadman world type.
*/
DEADMAN(1 << 29),
/**
* League world type
* Seasonal world type for leagues and seasonal deadman.
*/
LEAGUE(1 << 30);
SEASONAL(1 << 30);
private final int mask;
WorldType(int mask)
{
this.mask = mask;
}
private static final EnumSet<WorldType> PVP_WORLD_TYPES = EnumSet.of(
DEADMAN, // dmmt worlds are also flaged as DEADMAN
PVP

View File

@@ -430,6 +430,7 @@ public class WidgetID
static final int SPEC_ORB = 29;
static final int SPEC_CLICKBOX = 31;
static final int WORLDMAP_ORB = 43;
static final int WIKI_BANNER_PARENT = 44;
static final int WIKI_BANNER = 45;
static final int WORLDMAP_OPTIONS = 48;
}

View File

@@ -182,6 +182,7 @@ public enum WidgetInfo
MINIMAP_SPEC_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.SPEC_ORB),
MINIMAP_SPEC_CLICKBOX(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.SPEC_CLICKBOX),
MINIMAP_WORLDMAP_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.WORLDMAP_ORB),
MINIMAP_WIKI_BANNER_PARENT(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.WIKI_BANNER_PARENT),
MINIMAP_WIKI_BANNER(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.WIKI_BANNER),
MINIMAP_WORLDMAP_OPTIONS(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.WORLDMAP_OPTIONS),

View File

@@ -188,7 +188,7 @@ public class SessionManager
}
catch (IOException ex)
{
log.warn("Unable to logout of session", ex);
log.warn("Unable to sign out of session", ex);
}
accountSession = null; // No more account
@@ -227,7 +227,7 @@ public class SessionManager
@Subscribe
public void onLoginResponse(LoginResponse loginResponse)
{
log.debug("Now logged in as {}", loginResponse.getUsername());
log.debug("Now signed in as {}", loginResponse.getUsername());
AccountSession session = getAccountSession();
session.setUsername(loginResponse.getUsername());

View File

@@ -35,10 +35,10 @@ import net.runelite.api.WorldType;
public enum RuneScapeProfileType
{
STANDARD(client -> true),
BETA(client -> client.getWorldType().contains(WorldType.TOURNAMENT)),
BETA(client -> client.getWorldType().contains(WorldType.NOSAVE_MODE)),
DEADMAN(client -> client.getWorldType().contains(WorldType.DEADMAN)),
TRAILBLAZER_LEAGUE,
DEADMAN_REBORN(client -> client.getWorldType().contains(WorldType.DEADMAN_TOURNAMENT))
DEADMAN_REBORN(client -> client.getWorldType().contains(WorldType.SEASONAL))
;
private final Predicate<Client> test;

View File

@@ -44,12 +44,16 @@ import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.util.ReflectUtil;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
@Slf4j
@RequiredArgsConstructor
@ThreadSafe
public class EventBus
{
private static final Marker DEDUPLICATE = MarkerFactory.getMarker("DEDUPLICATE");
@Value
public static class Subscriber
{
@@ -82,7 +86,7 @@ public class EventBus
*/
public EventBus()
{
this((e) -> log.warn("Uncaught exception in event subscriber", e));
this((e) -> log.warn(DEDUPLICATE, "Uncaught exception in event subscriber", e));
}
/**

View File

@@ -196,6 +196,7 @@ public enum ItemMapping
ITEM_SANGUINESTI_STAFF(SANGUINESTI_STAFF_UNCHARGED, SANGUINESTI_STAFF, HOLY_SANGUINESTI_STAFF_UNCHARGED, HOLY_SANGUINESTI_STAFF),
ITEM_SCYTHE_OF_VITUR(SCYTHE_OF_VITUR_UNCHARGED, SCYTHE_OF_VITUR, HOLY_SCYTHE_OF_VITUR_UNCHARGED, HOLY_SCYTHE_OF_VITUR, SANGUINE_SCYTHE_OF_VITUR_UNCHARGED, SANGUINE_SCYTHE_OF_VITUR),
ITEM_TOME_OF_FIRE(TOME_OF_FIRE_EMPTY, TOME_OF_FIRE),
ITEM_TOME_OF_WATER(TOME_OF_WATER_EMPTY, TOME_OF_WATER),
ITEM_CRAWS_BOW(CRAWS_BOW_U, CRAWS_BOW),
ITEM_VIGGORAS_CHAINMACE(VIGGORAS_CHAINMACE_U, VIGGORAS_CHAINMACE),
ITEM_THAMMARONS_SCEPTRE(THAMMARONS_SCEPTRE_U, THAMMARONS_SCEPTRE),
@@ -255,6 +256,7 @@ public enum ItemMapping
ITEM_VOLATILE_ORB(VOLATILE_ORB, VOLATILE_NIGHTMARE_STAFF),
ITEM_NIGHTMARE_STAFF(NIGHTMARE_STAFF, ELDRITCH_NIGHTMARE_STAFF, HARMONISED_NIGHTMARE_STAFF, VOLATILE_NIGHTMARE_STAFF),
ITEM_GHARZI_RAPIER(GHRAZI_RAPIER, HOLY_GHRAZI_RAPIER),
ITEM_MASTER_SCROLL_BOOK(MASTER_SCROLL_BOOK_EMPTY, MASTER_SCROLL_BOOK),
// Trouver Parchment
ITEM_TROUVER_PARCHMENT(

View File

@@ -75,14 +75,14 @@ public class AccountPlugin extends Plugin
loginButton = NavigationButton.builder()
.tab(false)
.icon(LOGIN_IMAGE)
.tooltip("Log in to RuneLite")
.tooltip("Sign in to RuneLite")
.onClick(this::loginClick)
.build();
logoutButton = NavigationButton.builder()
.tab(false)
.icon(LOGOUT_IMAGE)
.tooltip("Log out of RuneLite")
.tooltip("Sign out of RuneLite")
.onClick(this::logoutClick)
.build();
@@ -113,7 +113,7 @@ public class AccountPlugin extends Plugin
private void logoutClick()
{
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(null,
"Are you sure you want to log out from RuneLite?", "Logout Confirmation",
"Are you sure you want to sign out of RuneLite?", "Sign Out Confirmation",
JOptionPane.YES_NO_OPTION))
{
executor.execute(sessionManager::logout);

View File

@@ -35,7 +35,6 @@ import java.util.Set;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.NPC;
import net.runelite.api.NPCComposition;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.Tile;
@@ -157,11 +156,7 @@ class AgilityOverlay extends Overlay
Color color = config.sepulchreHighlightColor();
for (NPC npc : npcs)
{
NPCComposition npcComposition = npc.getComposition();
int size = npcComposition.getSize();
LocalPoint lp = npc.getLocalLocation();
Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size);
Polygon tilePoly = npc.getCanvasTilePoly();
if (tilePoly != null)
{
OverlayUtil.renderPolygon(graphics, tilePoly, color);

View File

@@ -1738,12 +1738,12 @@ public class ChatCommandsPlugin extends Plugin
return new HiscoreLookup(localPlayer.getName(), hiscoreEndpoint);
}
// Public chat on a leagues world is always league hiscores, regardless of icon
if (chatMessage.getType() == ChatMessageType.PUBLICCHAT || chatMessage.getType() == ChatMessageType.MODCHAT)
{
if (client.getWorldType().contains(WorldType.LEAGUE))
// Public chat on a seasonal world is always seasonal or tournament hiscores, regardless of icon
if (client.getWorldType().contains(WorldType.SEASONAL))
{
return new HiscoreLookup(player, HiscoreEndpoint.LEAGUE);
return new HiscoreLookup(player, HiscoreEndpoint.TOURNAMENT);
}
}
@@ -1789,9 +1789,9 @@ public class ChatCommandsPlugin extends Plugin
private HiscoreEndpoint getLocalHiscoreEndpointType()
{
EnumSet<WorldType> worldType = client.getWorldType();
if (worldType.contains(WorldType.LEAGUE))
if (worldType.contains(WorldType.SEASONAL))
{
return HiscoreEndpoint.LEAGUE;
return HiscoreEndpoint.TOURNAMENT;
}
return toEndPoint(client.getAccountType());

View File

@@ -389,8 +389,7 @@ class SceneUploader
final short[] faceTextures = model.getFaceTextures();
final byte[] facePriorities = model.getFaceRenderPriorities();
float[][] u = model.getFaceTextureUCoordinates();
float[][] v = model.getFaceTextureVCoordinates();
float[] uv = model.getFaceTextureUVCoordinates();
int len = 0;
for (int face = 0; face < triangleCount; ++face)
@@ -432,7 +431,7 @@ class SceneUploader
if (faceTextures != null)
{
pushUvForFace(faceTextures, u, v, face, uvBuffer);
pushUvForFace(faceTextures, uv, face, uvBuffer);
}
len += 3;
@@ -559,11 +558,9 @@ class SceneUploader
vertexBuffer.put(a, b, c, packedAlphaPriority | color3);
float[][] u = model.getFaceTextureUCoordinates();
float[][] v = model.getFaceTextureVCoordinates();
if (padUvs || faceTextures != null)
{
pushUvForFace(faceTextures, u, v, face, uvBuffer);
pushUvForFace(faceTextures, model.getFaceTextureUVCoordinates(), face, uvBuffer);
}
return 3;
@@ -584,15 +581,15 @@ class SceneUploader
return alpha | priority;
}
private static void pushUvForFace(short[] faceTextures, float[][] u, float[][] v, int face, GpuFloatBuffer uvBuffer)
private static void pushUvForFace(short[] faceTextures, float[] uv, int face, GpuFloatBuffer uvBuffer)
{
float[] uf, vf;
if (faceTextures != null && u != null && v != null && (uf = u[face]) != null && (vf = v[face]) != null)
if (faceTextures != null && faceTextures[face] != -1 && uv != null)
{
int idx = face * 6;
float texture = faceTextures[face] + 1f;
uvBuffer.put(texture, uf[0], vf[0], 0f);
uvBuffer.put(texture, uf[1], vf[1], 0f);
uvBuffer.put(texture, uf[2], vf[2], 0f);
uvBuffer.put(texture, uv[idx], uv[idx + 1], 0f);
uvBuffer.put(texture, uv[idx + 2], uv[idx + 3], 0f);
uvBuffer.put(texture, uv[idx + 4], uv[idx + 5], 0f);
}
else
{

View File

@@ -479,9 +479,9 @@ public class GrandExchangePlugin extends Plugin
private WorldType getGeWorldType()
{
EnumSet<net.runelite.api.WorldType> worldTypes = client.getWorldType();
if (worldTypes.contains(net.runelite.api.WorldType.DEADMAN_TOURNAMENT))
if (worldTypes.contains(net.runelite.api.WorldType.SEASONAL))
{
return WorldType.DEADMAN_TOURNAMENT;
return WorldType.SEASONAL;
}
else if (worldTypes.contains(net.runelite.api.WorldType.DEADMAN))
{

View File

@@ -265,7 +265,7 @@ public class HiscorePlugin extends Plugin
{
EnumSet<WorldType> wTypes = client.getWorldType();
if (wTypes.contains(WorldType.DEADMAN_TOURNAMENT))
if (wTypes.contains(WorldType.SEASONAL))
{
return HiscoreEndpoint.TOURNAMENT;
}
@@ -273,10 +273,6 @@ public class HiscorePlugin extends Plugin
{
return HiscoreEndpoint.DEADMAN;
}
else if (wTypes.contains(WorldType.LEAGUE))
{
return HiscoreEndpoint.LEAGUE;
}
}
return HiscoreEndpoint.NORMAL;
}

View File

@@ -189,7 +189,7 @@ public class InfoPanel extends PluginPanel
syncPanel = buildLinkPanel(IMPORT_ICON, "Import signed-out", "settings", () ->
{
final int result = JOptionPane.showOptionDialog(syncPanel,
"<html>This will overwrite your settings with settings from your local profile, which<br/>is the profile used when not logged into RuneLite with a RuneLite account.</html>",
"<html>This will overwrite your settings with settings from your local profile, which<br/>is the profile used when not signed into RuneLite with a RuneLite account.</html>",
"Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
null, new String[]{"Yes", "No"}, "No");
@@ -303,14 +303,14 @@ public class InfoPanel extends PluginPanel
{
emailLabel.setContentType("text/plain");
emailLabel.setText(name);
loggedLabel.setText("Logged in as");
loggedLabel.setText("Signed in as");
actionsContainer.add(syncPanel, 0);
}
else
{
emailLabel.setContentType("text/html");
emailLabel.setText("<a href=\"" + RUNELITE_LOGIN + "\">Login</a> to sync settings to the cloud.");
loggedLabel.setText("Not logged in");
emailLabel.setText("<a href=\"" + RUNELITE_LOGIN + "\">Sign in</a> to sync settings to the cloud.");
loggedLabel.setText("Not signed in");
actionsContainer.remove(syncPanel);
}
}

View File

@@ -50,6 +50,7 @@ import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.ItemID;
import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
@@ -375,8 +376,32 @@ class LootTrackerBox extends JPanel
final long gePrice = item.getTotalGePrice();
final long haPrice = item.getTotalHaPrice();
final String ignoredLabel = item.isIgnored() ? " - Ignored" : "";
return "<html>" + name + " x " + quantity + ignoredLabel
+ "<br>GE: " + QuantityFormatter.quantityToStackSize(gePrice)
+ "<br>HA: " + QuantityFormatter.quantityToStackSize(haPrice) + "</html>";
final StringBuilder sb = new StringBuilder("<html>");
sb.append(name).append(" x ").append(QuantityFormatter.formatNumber(quantity)).append(ignoredLabel);
if (item.getId() == ItemID.COINS_995)
{
sb.append("</html>");
return sb.toString();
}
sb.append("<br>GE: ").append(QuantityFormatter.quantityToStackSize(gePrice));
if (quantity > 1)
{
sb.append(" (").append(QuantityFormatter.quantityToStackSize(item.getGePrice())).append(" ea)");
}
if (item.getId() == ItemID.PLATINUM_TOKEN)
{
sb.append("</html>");
return sb.toString();
}
sb.append("<br>HA: ").append(QuantityFormatter.quantityToStackSize(haPrice));
if (quantity > 1)
{
sb.append(" (").append(QuantityFormatter.quantityToStackSize(item.getHaPrice())).append(" ea)");
}
sb.append("</html>");
return sb.toString();
}
}

View File

@@ -92,7 +92,7 @@ public interface LootTrackerConfig extends Config
@ConfigItem(
keyName = "syncPanel",
name = "Synchronize panel contents",
description = "Synchronize your local loot tracker with your server data (requires being logged in).<br/>" +
description = "Synchronize your local loot tracker with your server data (requires being signed in).<br/>" +
" This means the panel is filled with portions of your remote data on startup<br/>" +
" and deleting data in the panel also deletes it on the server."
)

View File

@@ -74,6 +74,7 @@ import net.runelite.api.ObjectID;
import net.runelite.api.Player;
import net.runelite.api.Skill;
import net.runelite.api.SpriteID;
import net.runelite.api.WorldType;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameStateChanged;
@@ -479,7 +480,7 @@ public class LootTrackerPlugin extends Plugin
if (config.saveLoot())
{
LootRecord lootRecord = new LootRecord(name, type, metadata, toGameItems(items), Instant.now());
LootRecord lootRecord = new LootRecord(name, type, metadata, toGameItems(items), Instant.now(), getLootWorldId());
synchronized (queuedLoots)
{
queuedLoots.add(lootRecord);
@@ -489,6 +490,12 @@ public class LootTrackerPlugin extends Plugin
eventBus.post(new LootReceived(name, combatLevel, type, items));
}
private Integer getLootWorldId()
{
// For the wiki to determine drop rates based on dmm brackets
return client.getWorldType().contains(WorldType.SEASONAL) ? client.getWorld() : null;
}
@Subscribe
public void onNpcLootReceived(final NpcLootReceived npcLootReceived)
{

View File

@@ -50,6 +50,10 @@ import static net.runelite.api.ObjectID.ORE_VEIN_26661;
import static net.runelite.api.ObjectID.ORE_VEIN_26662;
import static net.runelite.api.ObjectID.ORE_VEIN_26663;
import static net.runelite.api.ObjectID.ORE_VEIN_26664;
import static net.runelite.api.ObjectID.ROCKS_41547;
import static net.runelite.api.ObjectID.ROCKS_41548;
import static net.runelite.api.ObjectID.ROCKS_41549;
import static net.runelite.api.ObjectID.ROCKS_41550;
import net.runelite.api.Player;
import net.runelite.api.WallObject;
import net.runelite.api.coords.WorldPoint;
@@ -79,12 +83,12 @@ import net.runelite.client.ui.overlay.OverlayMenuEntry;
@PluginDependency(XpTrackerPlugin.class)
public class MiningPlugin extends Plugin
{
private static final Pattern MINING_PATERN = Pattern.compile(
private static final Pattern MINING_PATTERN = Pattern.compile(
"You " +
"(?:manage to|just)" +
" (?:mined?|quarry) " +
"(?:some|an?) " +
"(?:copper|tin|clay|iron|silver|coal|gold|mithril|adamantite|runeite|amethyst|sandstone|granite|Opal|piece of Jade|Red Topaz|Emerald|Sapphire|Ruby|Diamond)" +
"(?:copper|tin|clay|iron|silver|coal|gold|mithril|adamantite|runeite|amethyst|sandstone|granite|barronite shards|barronite deposit|Opal|piece of Jade|Red Topaz|Emerald|Sapphire|Ruby|Diamond)" +
"(?:\\.|!)");
@Inject
@@ -343,10 +347,20 @@ public class MiningPlugin extends Plugin
respawns.add(rockRespawn);
break;
}
case ROCKS_41549: // Depleted barronite vein
case ROCKS_41550: // Depleted barronite vein
{
Rock rock = Rock.BARRONITE;
RockRespawn rockRespawn = new RockRespawn(rock, object.getWorldLocation(), Instant.now(), (int) rock.getRespawnTime(region).toMillis(), rock.getZOffset());
respawns.add(rockRespawn);
break;
}
case ORE_VEIN_26661: // Motherlode vein
case ORE_VEIN_26662: // Motherlode vein
case ORE_VEIN_26663: // Motherlode vein
case ORE_VEIN_26664: // Motherlode vein
case ROCKS_41547: // Barronite vein
case ROCKS_41548: // Barronite vein
{
// If the vein respawns before the timer is up, remove it
final WorldPoint point = object.getWorldLocation();
@@ -361,7 +375,7 @@ public class MiningPlugin extends Plugin
{
if (event.getType() == ChatMessageType.SPAM || event.getType() == ChatMessageType.GAMEMESSAGE)
{
if (MINING_PATERN.matcher(event.getMessage()).matches())
if (MINING_PATTERN.matcher(event.getMessage()).matches())
{
if (session == null)
{

View File

@@ -97,7 +97,8 @@ enum Rock
EFH_SALT(Duration.of(9, GAME_TICKS), 0, ROCKS_33255),
TE_SALT(Duration.of(9, GAME_TICKS), 0, ROCKS_33256),
BASALT(Duration.of(9, GAME_TICKS), 0, ROCKS_33257),
DAEYALT_ESSENCE(Duration.of(MiningRocksOverlay.DAEYALT_MAX_RESPAWN_TIME, GAME_TICKS), 0, DAEYALT_ESSENCE_39095);
DAEYALT_ESSENCE(Duration.of(MiningRocksOverlay.DAEYALT_MAX_RESPAWN_TIME, GAME_TICKS), 0, DAEYALT_ESSENCE_39095),
BARRONITE(Duration.of(89, GAME_TICKS), 140);
private static final int WILDERNESS_RESOURCE_AREA = 12605;
private static final int MISCELLANIA = 10044;

View File

@@ -162,10 +162,7 @@ public class NpcSceneOverlay extends Overlay
if (highlightedNpc.isTile())
{
int size = npcComposition.getSize();
LocalPoint lp = actor.getLocalLocation();
Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size);
Polygon tilePoly = actor.getCanvasTilePoly();
renderPoly(graphics, borderColor, fillColor, tilePoly);
}

View File

@@ -116,7 +116,7 @@ public class OpponentInfoPlugin extends Plugin
}
final EnumSet<WorldType> worldType = client.getWorldType();
if (worldType.contains(WorldType.DEADMAN_TOURNAMENT))
if (worldType.contains(WorldType.SEASONAL))
{
hiscoreEndpoint = HiscoreEndpoint.TOURNAMENT;
}
@@ -124,10 +124,6 @@ public class OpponentInfoPlugin extends Plugin
{
hiscoreEndpoint = HiscoreEndpoint.DEADMAN;
}
else if (worldType.contains(WorldType.LEAGUE))
{
hiscoreEndpoint = HiscoreEndpoint.LEAGUE;
}
else
{
hiscoreEndpoint = HiscoreEndpoint.NORMAL;

View File

@@ -46,6 +46,7 @@ import static net.runelite.api.Constants.ROOF_FLAG_HOVERED;
import static net.runelite.api.Constants.ROOF_FLAG_POSITION;
import net.runelite.api.GameState;
import net.runelite.api.Tile;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
@@ -246,14 +247,17 @@ public class RoofRemovalPlugin extends Plugin
continue;
}
int regionID = tile.getWorldLocation().getRegionID() << 2 | z;
// Properly account for instances shifting worldpoints around
final WorldPoint wp = WorldPoint.fromLocalInstance(client, tile.getLocalLocation(), tile.getPlane());
int regionID = wp.getRegionID() << 2 | z;
if (!overrides.containsKey(regionID))
{
continue;
}
int rx = tile.getWorldLocation().getRegionX();
int ry = tile.getWorldLocation().getRegionY();
int rx = wp.getRegionX();
int ry = wp.getRegionY();
long[] region = overrides.get(regionID);
if ((region[ry] & (1L << rx)) != 0)
{

View File

@@ -46,6 +46,9 @@ import net.runelite.client.util.SwingUtil;
@Getter
public class TimeablePanel<T> extends JPanel
{
private static final ImageIcon NOTIFY_ICON = new ImageIcon(ImageUtil.loadImageResource(TimeTrackingPlugin.class, "notify_icon.png"));
private static final ImageIcon NOTIFY_SELECTED_ICON = new ImageIcon(ImageUtil.loadImageResource(TimeTrackingPlugin.class, "notify_selected_icon.png"));
private final T timeable;
private final JLabel icon = new JLabel();
private final JLabel farmingContractIcon = new JLabel();
@@ -84,13 +87,10 @@ public class TimeablePanel<T> extends JPanel
infoPanel.add(text);
infoPanel.add(estimate);
ImageIcon notifyIcon = new ImageIcon(ImageUtil.loadImageResource(TimeTrackingPlugin.class, "notify_icon.png"));
ImageIcon notifySelectedIcon = new ImageIcon(ImageUtil.loadImageResource(TimeTrackingPlugin.class, "notify_selected_icon.png"));
notifyButton.setPreferredSize(new Dimension(30, 16));
notifyButton.setBorder(new EmptyBorder(0, 0, 0, 10));
notifyButton.setIcon(notifyIcon);
notifyButton.setSelectedIcon(notifySelectedIcon);
notifyButton.setIcon(NOTIFY_ICON);
notifyButton.setSelectedIcon(NOTIFY_SELECTED_ICON);
SwingUtil.removeButtonDecorations(notifyButton);
SwingUtil.addModalTooltip(notifyButton, "Disable notifications", "Enable notifications");

View File

@@ -118,13 +118,12 @@ public class WikiPlugin extends Plugin
private void removeWidgets()
{
Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS);
if (minimapOrbs == null)
Widget wikiBannerParent = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER_PARENT);
if (wikiBannerParent == null)
{
return;
}
Widget[] children = minimapOrbs.getChildren();
Widget[] children = wikiBannerParent.getChildren();
if (children == null || children.length < 1)
{
return;
@@ -152,8 +151,8 @@ public class WikiPlugin extends Plugin
private void addWidgets()
{
Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS);
if (minimapOrbs == null)
Widget wikiBannerParent = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER_PARENT);
if (wikiBannerParent == null)
{
return;
}
@@ -164,12 +163,12 @@ public class WikiPlugin extends Plugin
vanilla.setHidden(true);
}
icon = minimapOrbs.createChild(0, WidgetType.GRAPHIC);
icon = wikiBannerParent.createChild(0, WidgetType.GRAPHIC);
icon.setSpriteId(SpriteID.WIKI_DESELECTED);
icon.setOriginalX(0);
icon.setOriginalY(0);
icon.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT);
icon.setYPositionMode(WidgetPositionMode.ABSOLUTE_BOTTOM);
icon.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
icon.setYPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
icon.setOriginalWidth(40);
icon.setOriginalHeight(14);
icon.setTargetVerb("Lookup");

View File

@@ -1,364 +1,402 @@
/*
* Copyright (c) 2018, Psikoi <https://github.com/Psikoi>
* 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.worldhopper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.client.ui.FontManager;
import net.runelite.client.util.ImageUtil;
import net.runelite.http.api.worlds.World;
import net.runelite.http.api.worlds.WorldRegion;
import net.runelite.http.api.worlds.WorldType;
class WorldTableRow extends JPanel
{
private static final ImageIcon FLAG_AUS;
private static final ImageIcon FLAG_UK;
private static final ImageIcon FLAG_US;
private static final ImageIcon FLAG_GER;
private static final int WORLD_COLUMN_WIDTH = 60;
private static final int PLAYERS_COLUMN_WIDTH = 40;
private static final int PING_COLUMN_WIDTH = 35;
private static final Color CURRENT_WORLD = new Color(66, 227, 17);
private static final Color DANGEROUS_WORLD = new Color(251, 62, 62);
private static final Color TOURNAMENT_WORLD = new Color(79, 145, 255);
private static final Color MEMBERS_WORLD = new Color(210, 193, 53);
private static final Color FREE_WORLD = new Color(200, 200, 200);
private static final Color LEAGUE_WORLD = new Color(133, 177, 178);
static
{
FLAG_AUS = new ImageIcon(ImageUtil.loadImageResource(WorldHopperPlugin.class, "flag_aus.png"));
FLAG_UK = new ImageIcon(ImageUtil.loadImageResource(WorldHopperPlugin.class, "flag_uk.png"));
FLAG_US = new ImageIcon(ImageUtil.loadImageResource(WorldHopperPlugin.class, "flag_us.png"));
FLAG_GER = new ImageIcon(ImageUtil.loadImageResource(WorldHopperPlugin.class, "flag_ger.png"));
}
private final JMenuItem favoriteMenuOption = new JMenuItem();
private JLabel worldField;
private JLabel playerCountField;
private JLabel activityField;
private JLabel pingField;
private final BiConsumer<World, Boolean> onFavorite;
@Getter
private final World world;
@Getter(AccessLevel.PACKAGE)
private int updatedPlayerCount;
private int ping;
private Color lastBackground;
WorldTableRow(World world, boolean current, boolean favorite, Integer ping, Consumer<World> onSelect, BiConsumer<World, Boolean> onFavorite)
{
this.world = world;
this.onFavorite = onFavorite;
this.updatedPlayerCount = world.getPlayers();
setLayout(new BorderLayout());
setBorder(new EmptyBorder(2, 0, 2, 0));
addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
if (onSelect != null)
{
onSelect.accept(world);
}
}
}
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
setBackground(getBackground().brighter());
}
}
@Override
public void mouseReleased(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
setBackground(getBackground().darker());
}
}
@Override
public void mouseEntered(MouseEvent mouseEvent)
{
WorldTableRow.this.lastBackground = getBackground();
setBackground(getBackground().brighter());
}
@Override
public void mouseExited(MouseEvent mouseEvent)
{
setBackground(lastBackground);
}
});
setFavoriteMenu(favorite);
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
popupMenu.add(favoriteMenuOption);
setComponentPopupMenu(popupMenu);
JPanel leftSide = new JPanel(new BorderLayout());
JPanel rightSide = new JPanel(new BorderLayout());
leftSide.setOpaque(false);
rightSide.setOpaque(false);
JPanel worldField = buildWorldField();
worldField.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0));
worldField.setOpaque(false);
JPanel pingField = buildPingField(ping);
pingField.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0));
pingField.setOpaque(false);
JPanel playersField = buildPlayersField();
playersField.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0));
playersField.setOpaque(false);
JPanel activityField = buildActivityField();
activityField.setBorder(new EmptyBorder(5, 5, 5, 5));
activityField.setOpaque(false);
recolour(current);
leftSide.add(worldField, BorderLayout.WEST);
leftSide.add(playersField, BorderLayout.CENTER);
rightSide.add(activityField, BorderLayout.CENTER);
rightSide.add(pingField, BorderLayout.EAST);
add(leftSide, BorderLayout.WEST);
add(rightSide, BorderLayout.CENTER);
}
void setFavoriteMenu(boolean favorite)
{
String favoriteAction = favorite ?
"Remove " + world.getId() + " from favorites" :
"Add " + world.getId() + " to favorites";
favoriteMenuOption.setText(favoriteAction);
for (ActionListener listener : favoriteMenuOption.getActionListeners())
{
favoriteMenuOption.removeActionListener(listener);
}
favoriteMenuOption.addActionListener(e ->
{
onFavorite.accept(world, !favorite);
});
}
void updatePlayerCount(int playerCount)
{
this.updatedPlayerCount = playerCount;
playerCountField.setText(playerCountString(playerCount));
}
private static String playerCountString(int playerCount)
{
return playerCount < 0 ? "OFF" : Integer.toString(playerCount);
}
void setPing(int ping)
{
this.ping = ping;
pingField.setText(ping <= 0 ? "-" : Integer.toString(ping));
}
void hidePing()
{
pingField.setText("-");
}
void showPing()
{
setPing(ping); // to update pingField
}
int getPing()
{
return ping;
}
public void recolour(boolean current)
{
playerCountField.setForeground(current ? CURRENT_WORLD : Color.WHITE);
pingField.setForeground(current ? CURRENT_WORLD : Color.WHITE);
if (current)
{
activityField.setForeground(CURRENT_WORLD);
worldField.setForeground(CURRENT_WORLD);
return;
}
else if (world.getTypes().contains(WorldType.PVP)
|| world.getTypes().contains(WorldType.HIGH_RISK)
|| world.getTypes().contains(WorldType.DEADMAN))
{
activityField.setForeground(DANGEROUS_WORLD);
}
else if (world.getTypes().contains(WorldType.LEAGUE))
{
activityField.setForeground(LEAGUE_WORLD);
}
else if (world.getTypes().contains(WorldType.TOURNAMENT))
{
activityField.setForeground(TOURNAMENT_WORLD);
}
else
{
activityField.setForeground(Color.WHITE);
}
worldField.setForeground(world.getTypes().contains(WorldType.MEMBERS) ? MEMBERS_WORLD : FREE_WORLD);
}
/**
* Builds the players list field (containing the amount of players logged in that world).
*/
private JPanel buildPlayersField()
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
playerCountField = new JLabel(playerCountString(world.getPlayers()));
playerCountField.setFont(FontManager.getRunescapeSmallFont());
column.add(playerCountField, BorderLayout.WEST);
return column;
}
private JPanel buildPingField(Integer ping)
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
pingField = new JLabel("-");
pingField.setFont(FontManager.getRunescapeSmallFont());
column.add(pingField, BorderLayout.EAST);
if (ping != null)
{
setPing(ping);
}
return column;
}
/**
* Builds the activity list field (containing that world's activity/theme).
*/
private JPanel buildActivityField()
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
activityField = new JLabel(world.getActivity());
activityField.setFont(FontManager.getRunescapeSmallFont());
column.add(activityField, BorderLayout.WEST);
return column;
}
/**
* Builds the world list field (containing the country's flag and the world index).
*/
private JPanel buildWorldField()
{
JPanel column = new JPanel(new BorderLayout(7, 0));
column.setBorder(new EmptyBorder(0, 5, 0, 5));
worldField = new JLabel(world.getId() + "");
ImageIcon flagIcon = getFlag(world.getRegion());
if (flagIcon != null)
{
JLabel flag = new JLabel(flagIcon);
column.add(flag, BorderLayout.WEST);
}
column.add(worldField, BorderLayout.CENTER);
return column;
}
private static ImageIcon getFlag(WorldRegion region)
{
if (region == null)
{
return null;
}
switch (region)
{
case UNITED_STATES_OF_AMERICA:
return FLAG_US;
case UNITED_KINGDOM:
return FLAG_UK;
case AUSTRALIA:
return FLAG_AUS;
case GERMANY:
return FLAG_GER;
default:
return null;
}
}
}
/*
* Copyright (c) 2018, Psikoi <https://github.com/Psikoi>
* 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.worldhopper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.client.ui.FontManager;
import net.runelite.client.util.ImageUtil;
import net.runelite.http.api.worlds.World;
import net.runelite.http.api.worlds.WorldRegion;
import net.runelite.http.api.worlds.WorldType;
class WorldTableRow extends JPanel
{
private static final ImageIcon FLAG_AUS;
private static final ImageIcon FLAG_UK;
private static final ImageIcon FLAG_US;
private static final ImageIcon FLAG_GER;
private static final int WORLD_COLUMN_WIDTH = 60;
private static final int PLAYERS_COLUMN_WIDTH = 40;
private static final int PING_COLUMN_WIDTH = 35;
private static final Color CURRENT_WORLD = new Color(66, 227, 17);
private static final Color DANGEROUS_WORLD = new Color(251, 62, 62);
private static final Color TOURNAMENT_WORLD = new Color(79, 145, 255);
private static final Color MEMBERS_WORLD = new Color(210, 193, 53);
private static final Color FREE_WORLD = new Color(200, 200, 200);
private static final Color SEASONAL_WORLD = new Color(133, 177, 178);
static
{
FLAG_AUS = new ImageIcon(ImageUtil.loadImageResource(WorldHopperPlugin.class, "flag_aus.png"));
FLAG_UK = new ImageIcon(ImageUtil.loadImageResource(WorldHopperPlugin.class, "flag_uk.png"));
FLAG_US = new ImageIcon(ImageUtil.loadImageResource(WorldHopperPlugin.class, "flag_us.png"));
FLAG_GER = new ImageIcon(ImageUtil.loadImageResource(WorldHopperPlugin.class, "flag_ger.png"));
}
private final JMenuItem favoriteMenuOption = new JMenuItem();
private JLabel worldField;
private JLabel playerCountField;
private JLabel activityField;
private JLabel pingField;
private final BiConsumer<World, Boolean> onFavorite;
@Getter
private final World world;
@Getter(AccessLevel.PACKAGE)
private int updatedPlayerCount;
private int ping;
private Color lastBackground;
WorldTableRow(World world, boolean current, boolean favorite, Integer ping, Consumer<World> onSelect, BiConsumer<World, Boolean> onFavorite)
{
this.world = world;
this.onFavorite = onFavorite;
this.updatedPlayerCount = world.getPlayers();
setLayout(new BorderLayout());
setBorder(new EmptyBorder(2, 0, 2, 0));
addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
if (onSelect != null)
{
onSelect.accept(world);
}
}
}
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
setBackground(getBackground().brighter());
}
}
@Override
public void mouseReleased(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
setBackground(getBackground().darker());
}
}
@Override
public void mouseEntered(MouseEvent mouseEvent)
{
WorldTableRow.this.lastBackground = getBackground();
setBackground(getBackground().brighter());
}
@Override
public void mouseExited(MouseEvent mouseEvent)
{
setBackground(lastBackground);
}
});
setFavoriteMenu(favorite);
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
popupMenu.add(favoriteMenuOption);
setComponentPopupMenu(popupMenu);
JPanel leftSide = new JPanel(new BorderLayout());
JPanel rightSide = new JPanel(new BorderLayout());
leftSide.setOpaque(false);
rightSide.setOpaque(false);
JPanel worldField = buildWorldField();
worldField.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0));
worldField.setOpaque(false);
JPanel pingField = buildPingField(ping);
pingField.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0));
pingField.setOpaque(false);
JPanel playersField = buildPlayersField();
playersField.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0));
playersField.setOpaque(false);
JPanel activityField = buildActivityField();
activityField.setBorder(new EmptyBorder(5, 5, 5, 5));
activityField.setOpaque(false);
recolour(current);
leftSide.add(worldField, BorderLayout.WEST);
leftSide.add(playersField, BorderLayout.CENTER);
rightSide.add(activityField, BorderLayout.CENTER);
rightSide.add(pingField, BorderLayout.EAST);
add(leftSide, BorderLayout.WEST);
add(rightSide, BorderLayout.CENTER);
}
void setFavoriteMenu(boolean favorite)
{
String favoriteAction = favorite ?
"Remove " + world.getId() + " from favorites" :
"Add " + world.getId() + " to favorites";
favoriteMenuOption.setText(favoriteAction);
for (ActionListener listener : favoriteMenuOption.getActionListeners())
{
favoriteMenuOption.removeActionListener(listener);
}
favoriteMenuOption.addActionListener(e ->
{
onFavorite.accept(world, !favorite);
});
}
void updatePlayerCount(int playerCount)
{
this.updatedPlayerCount = playerCount;
playerCountField.setText(playerCountString(playerCount));
}
private static String playerCountString(int playerCount)
{
return playerCount < 0 ? "OFF" : Integer.toString(playerCount);
}
void setPing(int ping)
{
this.ping = ping;
pingField.setText(ping <= 0 ? "-" : Integer.toString(ping));
}
void hidePing()
{
pingField.setText("-");
}
void showPing()
{
setPing(ping); // to update pingField
}
int getPing()
{
return ping;
}
public void recolour(boolean current)
{
playerCountField.setForeground(current ? CURRENT_WORLD : Color.WHITE);
pingField.setForeground(current ? CURRENT_WORLD : Color.WHITE);
if (current)
{
activityField.setForeground(CURRENT_WORLD);
worldField.setForeground(CURRENT_WORLD);
return;
}
else if (world.getTypes().contains(WorldType.PVP)
|| world.getTypes().contains(WorldType.HIGH_RISK)
|| world.getTypes().contains(WorldType.DEADMAN))
{
activityField.setForeground(DANGEROUS_WORLD);
}
else if (world.getTypes().contains(WorldType.SEASONAL))
{
activityField.setForeground(SEASONAL_WORLD);
}
else if (world.getTypes().contains(WorldType.NOSAVE_MODE))
{
activityField.setForeground(TOURNAMENT_WORLD);
}
else
{
activityField.setForeground(Color.WHITE);
}
worldField.setForeground(world.getTypes().contains(WorldType.MEMBERS) ? MEMBERS_WORLD : FREE_WORLD);
}
/**
* Builds the players list field (containing the amount of players logged in that world).
*/
private JPanel buildPlayersField()
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
playerCountField = new JLabel(playerCountString(world.getPlayers()));
playerCountField.setFont(FontManager.getRunescapeSmallFont());
column.add(playerCountField, BorderLayout.WEST);
return column;
}
private JPanel buildPingField(Integer ping)
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
pingField = new JLabel("-");
pingField.setFont(FontManager.getRunescapeSmallFont());
column.add(pingField, BorderLayout.EAST);
if (ping != null)
{
setPing(ping);
}
return column;
}
/**
* Builds the activity list field (containing that world's activity/theme).
*/
private JPanel buildActivityField()
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
String activity = world.getActivity();
activityField = new JLabel(activity);
activityField.setFont(FontManager.getRunescapeSmallFont());
if (activity != null && activity.length() > 16)
{
activityField.setToolTipText(activity);
// Pass up events - https://stackoverflow.com/a/14932443
activityField.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
dispatchEvent(e);
}
@Override
public void mousePressed(MouseEvent e)
{
dispatchEvent(e);
}
@Override
public void mouseReleased(MouseEvent e)
{
dispatchEvent(e);
}
@Override
public void mouseEntered(MouseEvent e)
{
dispatchEvent(e);
}
@Override
public void mouseExited(MouseEvent e)
{
dispatchEvent(e);
}
});
}
column.add(activityField, BorderLayout.WEST);
return column;
}
/**
* Builds the world list field (containing the country's flag and the world index).
*/
private JPanel buildWorldField()
{
JPanel column = new JPanel(new BorderLayout(7, 0));
column.setBorder(new EmptyBorder(0, 5, 0, 5));
worldField = new JLabel(world.getId() + "");
ImageIcon flagIcon = getFlag(world.getRegion());
if (flagIcon != null)
{
JLabel flag = new JLabel(flagIcon);
column.add(flag, BorderLayout.WEST);
}
column.add(worldField, BorderLayout.CENTER);
return column;
}
private static ImageIcon getFlag(WorldRegion region)
{
if (region == null)
{
return null;
}
switch (region)
{
case UNITED_STATES_OF_AMERICA:
return FLAG_US;
case UNITED_KINGDOM:
return FLAG_UK;
case AUSTRALIA:
return FLAG_AUS;
case GERMANY:
return FLAG_GER;
default:
return null;
}
}
}

View File

@@ -61,6 +61,8 @@ enum MiningSiteLocation
BLAST_MINE_WEST(new WorldPoint(1471, 3865, 0), new Rock(22, Ore.HARD_ROCK)),
BRIMHAVEN_NORTH(new WorldPoint(2732, 3225, 0), new Rock(10, Ore.GOLD)),
BRIMHAVEN_SOUTH_(new WorldPoint(2743, 3150, 0), new Rock(6, Ore.GOLD)),
CAMDOZAAL_MINES_EAST(new WorldPoint(2934, 5811, 0), new Rock(8, Ore.BARRONITE), new Rock(1, Ore.CLAY), new Rock(2, Ore.TIN), new Rock(1, Ore.COPPER)),
CAMDOZAAL_MINES_WEST(new WorldPoint(2914, 5811, 0), new Rock(10, Ore.BARRONITE), new Rock(2, Ore.COPPER), new Rock(2, Ore.CLAY), new Rock(1, Ore.TIN)),
CENTRAL_FREMENIK_ISLES(new WorldPoint(2374, 3850, 0), new Rock(7, Ore.COAL), new Rock(1, Ore.RUNITE)),
CITHAREDE_ABBEY(new WorldPoint(3400, 3170, 0), new Rock(3, Ore.IRON), new Rock (3, Ore.COAL)),
COAL_TRUCKS(new WorldPoint(2580, 3484, 0), new Rock(18, Ore.COAL)),
@@ -238,6 +240,7 @@ enum MiningSiteLocation
TIN("Tin"),
LIMESTONE("Limestone"),
BLURITE("Blurite"),
BARRONITE("Barronite"),
IRON("Iron"),
ELEMENTAL("Elemental"),
SILVER("Silver"),

View File

@@ -63,6 +63,7 @@ public class XpGlobesOverlay extends Overlay
private static final int MINIMUM_STEP = 10;
private static final int PROGRESS_RADIUS_START = 90;
private static final int PROGRESS_RADIUS_REMAINDER = 0;
private static final int PROGRESS_BACKGROUND_SIZE = 5;
private static final int TOOLTIP_RECT_SIZE_X = 150;
private static final Color DARK_OVERLAY_COLOR = new Color(0, 0, 0, 180);
static final String FLIP_ACTION = "Flip";
@@ -108,31 +109,34 @@ public class XpGlobesOverlay extends Overlay
return null;
}
int curDrawPosition = 0;
// The progress arc is drawn either side of the perimeter of the background. This value accounts for that
// when calculating draw positions and overall size of the overlay
final int progressArcOffset = (int) Math.ceil(Math.max(PROGRESS_BACKGROUND_SIZE, config.progressArcStrokeWidth()) / 2.0);
int curDrawPosition = progressArcOffset;
for (final XpGlobe xpGlobe : xpGlobes)
{
int startXp = xpTrackerService.getStartGoalXp(xpGlobe.getSkill());
int goalXp = xpTrackerService.getEndGoalXp(xpGlobe.getSkill());
if (config.alignOrbsVertically())
{
renderProgressCircle(graphics, xpGlobe, startXp, goalXp, 0, curDrawPosition, getBounds());
renderProgressCircle(graphics, xpGlobe, startXp, goalXp, progressArcOffset, curDrawPosition, getBounds());
}
else
{
renderProgressCircle(graphics, xpGlobe, startXp, goalXp, curDrawPosition, 0, getBounds());
renderProgressCircle(graphics, xpGlobe, startXp, goalXp, curDrawPosition, progressArcOffset, getBounds());
}
curDrawPosition += MINIMUM_STEP + config.xpOrbSize();
}
// Get length of markers
final int markersLength = (queueSize * (config.xpOrbSize())) + ((MINIMUM_STEP) * (queueSize - 1));
final int markersLength = (queueSize * (config.xpOrbSize() + progressArcOffset)) + ((MINIMUM_STEP) * (queueSize - 1));
if (config.alignOrbsVertically())
{
return new Dimension(config.xpOrbSize(), markersLength);
return new Dimension(config.xpOrbSize() + progressArcOffset * 2, markersLength);
}
else
{
return new Dimension(markersLength, config.xpOrbSize());
return new Dimension(markersLength, config.xpOrbSize() + progressArcOffset * 2);
}
}
@@ -184,7 +188,7 @@ public class XpGlobesOverlay extends Overlay
x, y,
config.xpOrbSize(), config.xpOrbSize(),
PROGRESS_RADIUS_REMAINDER, radiusToGoalXp,
5,
PROGRESS_BACKGROUND_SIZE,
config.progressOrbOutLineColor()
);
drawProgressArc(

View File

@@ -50,7 +50,6 @@ import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.api.WorldType;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
@@ -125,7 +124,7 @@ class XpInfoBox extends JPanel
// Create open xp tracker menu
final JMenuItem openXpTracker = new JMenuItem("Open Wise Old Man");
openXpTracker.addActionListener(e -> LinkBrowser.browse(XpPanel.buildXpTrackerUrl(
client.getLocalPlayer(), skill, client.getWorldType().contains(WorldType.LEAGUE))));
client.getLocalPlayer(), skill)));
// Create reset menu
final JMenuItem reset = new JMenuItem("Reset");

View File

@@ -41,7 +41,6 @@ import javax.swing.border.EmptyBorder;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.Skill;
import net.runelite.api.WorldType;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
@@ -84,7 +83,7 @@ class XpPanel extends PluginPanel
// Create open xp tracker menu
final JMenuItem openXpTracker = new JMenuItem("Open Wise Old Man");
openXpTracker.addActionListener(e -> LinkBrowser.browse(XpPanel.buildXpTrackerUrl(
client.getLocalPlayer(), Skill.OVERALL, client.getWorldType().contains(WorldType.LEAGUE))));
client.getLocalPlayer(), Skill.OVERALL)));
// Create reset all menu
final JMenuItem reset = new JMenuItem("Reset All");
@@ -147,18 +146,16 @@ class XpPanel extends PluginPanel
add(errorPanel);
}
static String buildXpTrackerUrl(final Actor player, final Skill skill, boolean leagueWorld)
static String buildXpTrackerUrl(final Actor player, final Skill skill)
{
if (player == null)
{
return "";
}
final String host = leagueWorld ? "trailblazer.wiseoldman.net" : "wiseoldman.net";
return new HttpUrl.Builder()
.scheme("https")
.host(host)
.host("wiseoldman.net")
.addPathSegment("players")
.addPathSegment(player.getName())
.addPathSegment("gained")

View File

@@ -70,12 +70,10 @@ enum XpWorldType
{
switch (type)
{
case TOURNAMENT:
case NOSAVE_MODE:
return TOURNEY;
case DEADMAN:
return DMM;
case LEAGUE:
return LEAGUE;
default:
return NORMAL;
}

View File

@@ -143,9 +143,9 @@ public class XpUpdaterPlugin extends Plugin
private void updateCml(String username, EnumSet<WorldType> worldTypes)
{
if (config.cml()
&& !worldTypes.contains(WorldType.LEAGUE)
&& !worldTypes.contains(WorldType.SEASONAL)
&& !worldTypes.contains(WorldType.DEADMAN)
&& !worldTypes.contains(WorldType.TOURNAMENT))
&& !worldTypes.contains(WorldType.NOSAVE_MODE))
{
HttpUrl url = new HttpUrl.Builder()
.scheme("https")
@@ -168,9 +168,9 @@ public class XpUpdaterPlugin extends Plugin
private void updateTempleosrs(String username, EnumSet<WorldType> worldTypes)
{
if (config.templeosrs()
&& !worldTypes.contains(WorldType.LEAGUE)
&& !worldTypes.contains(WorldType.SEASONAL)
&& !worldTypes.contains(WorldType.DEADMAN)
&& !worldTypes.contains(WorldType.TOURNAMENT))
&& !worldTypes.contains(WorldType.NOSAVE_MODE))
{
HttpUrl url = new HttpUrl.Builder()
.scheme("https")
@@ -192,9 +192,9 @@ public class XpUpdaterPlugin extends Plugin
private void updateWom(String username, EnumSet<WorldType> worldTypes)
{
if (config.wiseoldman()
&& !worldTypes.contains(WorldType.LEAGUE)
&& !worldTypes.contains(WorldType.SEASONAL)
&& !worldTypes.contains(WorldType.DEADMAN)
&& !worldTypes.contains(WorldType.TOURNAMENT))
&& !worldTypes.contains(WorldType.NOSAVE_MODE))
{
HttpUrl url = new HttpUrl.Builder()
.scheme("https")

View File

@@ -129,10 +129,7 @@ public abstract class Overlay implements LayoutableRenderableEntity
return null;
}
public void reset()
public void revalidate()
{
setPreferredPosition(null);
setPreferredSize(null);
setPreferredLocation(null);
}
}

View File

@@ -289,8 +289,11 @@ public class OverlayManager
*/
public synchronized void resetOverlay(final Overlay overlay)
{
overlay.reset();
overlay.setPreferredPosition(null);
overlay.setPreferredSize(null);
overlay.setPreferredLocation(null);
saveOverlay(overlay);
overlay.revalidate();
}
synchronized void rebuildOverlayLayers()

View File

@@ -69,11 +69,14 @@ import net.runelite.client.ui.JagexColors;
import net.runelite.client.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import net.runelite.client.util.ColorUtil;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
@Singleton
@Slf4j
public class OverlayRenderer extends MouseAdapter implements KeyListener
{
private static final Marker DEDUPLICATE = MarkerFactory.getMarker("DEDUPLICATE");
private static final int BORDER = 5;
private static final int BORDER_TOP = BORDER + 15;
private static final int PADDING = 2;
@@ -289,25 +292,18 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
final Dimension dimension = bounds.getSize();
final Point preferredLocation = overlay.getPreferredLocation();
Point location;
Rectangle snapCorner = null;
// If the final position is not modified, layout it
if (overlayPosition != OverlayPosition.DETACHED && (preferredLocation == null || overlay.getPreferredPosition() != null))
{
final Rectangle snapCorner = snapCorners.forPosition(overlayPosition);
snapCorner = snapCorners.forPosition(overlayPosition);
final Point translation = OverlayUtil.transformPosition(overlayPosition, dimension); // offset from corner
// Target x/y to draw the overlay
int destX = (int) snapCorner.getX() + translation.x;
int destY = (int) snapCorner.getY() + translation.y;
int destX = snapCorner.x + translation.x;
int destY = snapCorner.y + translation.y;
// Clamp the target position to ensure it is on screen or within parent bounds
location = clampOverlayLocation(destX, destY, dimension.width, dimension.height, overlay);
// Diff final position to target position in order to add it to the snap corner padding. The
// overlay effectively takes up the difference of (clamped location - target location) in
// addition to its normal dimensions.
int dX = location.x - destX;
int dY = location.y - destY;
final Point padding = OverlayUtil.padPosition(overlayPosition, dimension, PADDING); // overlay size + fixed padding
// translate corner for padding and any difference due to the position clamping
snapCorner.translate(padding.x + dX, padding.y + dY);
}
else
{
@@ -324,6 +320,12 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
safeRender(client, overlay, layer, graphics, location);
// Adjust snap corner based on where the overlay was drawn
if (snapCorner != null && bounds.width + bounds.height > 0)
{
OverlayUtil.shiftSnapCorner(overlayPosition, snapCorner, bounds, PADDING);
}
// Restore graphics2d properties prior to drawing bounds
graphics.setTransform(transform);
graphics.setStroke(stroke);
@@ -703,7 +705,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
{
OverlayPosition position = snapCorners.fromBounds(snapCorner);
if (position == currentManagedOverlay.getPosition())
if (position == getCorrectedOverlayPosition(currentManagedOverlay))
{
// overlay moves back to default position
position = null;
@@ -711,6 +713,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
currentManagedOverlay.setPreferredPosition(position);
currentManagedOverlay.setPreferredLocation(null); // from dragging
currentManagedOverlay.revalidate();
break;
}
}
@@ -786,7 +789,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
}
catch (Exception ex)
{
log.warn("Error during overlay rendering", ex);
log.warn(DEDUPLICATE, "Error during overlay rendering", ex);
return;
}

View File

@@ -30,6 +30,7 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
@@ -201,33 +202,32 @@ public class OverlayUtil
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
public static java.awt.Point padPosition(OverlayPosition position, Dimension dimension, final int padding)
static void shiftSnapCorner(OverlayPosition overlayPosition, Rectangle snapCorner, Rectangle bounds, int padding)
{
final java.awt.Point result = new java.awt.Point();
switch (position)
// translate corner for padding and also based on where the overlay bounds are now
int sX = snapCorner.x, sY = snapCorner.y;
switch (overlayPosition)
{
case DYNAMIC:
case TOOLTIP:
break;
case BOTTOM_LEFT:
result.x += dimension.width + (dimension.width == 0 ? 0 : padding);
sX = bounds.x + bounds.width + padding;
break;
case BOTTOM_RIGHT:
result.x -= dimension.width + (dimension.width == 0 ? 0 : padding);
sX = bounds.x - padding;
break;
case TOP_LEFT:
case TOP_CENTER:
case CANVAS_TOP_RIGHT:
case TOP_RIGHT:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
sY = bounds.y + bounds.height + padding;
break;
case ABOVE_CHATBOX_RIGHT:
result.y -= dimension.height + (dimension.height == 0 ? 0 : padding);
sY = bounds.y - padding;
break;
default:
throw new IllegalArgumentException();
}
return result;
snapCorner.x = sX;
snapCorner.y = sY;
}
public static java.awt.Point transformPosition(OverlayPosition position, Dimension dimension)

View File

@@ -121,9 +121,9 @@ public class WidgetOverlay extends Overlay
assert widget != null;
final Rectangle bounds = getBounds();
// OverlayRenderer sets the overlay bounds to the preferred location if one is set prior to calling render()
// for detached overlays.
if (getPosition() != OverlayPosition.DETACHED || getPreferredLocation() != null)
// OverlayRenderer sets the overlay bounds to where it would like the overlay to render at prior to calling
// render(). If the overlay has a preferred location or position set we update the widget position to that.
if (getPreferredLocation() != null || getPreferredPosition() != null)
{
// The widget relative pos is relative to the parent
widget.setRelativeX(bounds.x - parent.x);
@@ -188,9 +188,8 @@ public class WidgetOverlay extends Overlay
}
@Override
public void reset()
public void revalidate()
{
super.reset();
// Revalidate must be called on the client thread, so defer til next frame
revalidate = true;
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2021, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.util;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;
import java.util.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
public class DeduplicationFilter extends TurboFilter
{
private static final Marker deduplicateMarker = MarkerFactory.getMarker("DEDUPLICATE");
private static final int CACHE_SIZE = 8;
private static final int DUPLICATE_LOG_COUNT = 1000;
@RequiredArgsConstructor
@EqualsAndHashCode(exclude = {"count"})
private static class LogException
{
private final String message;
private final StackTraceElement[] stackTraceElements;
private volatile int count;
}
private final Deque<LogException> cache = new ConcurrentLinkedDeque<>();
@Override
public void stop()
{
cache.clear();
super.stop();
}
@Override
public FilterReply decide(Marker marker, Logger logger, Level level, String s, Object[] objects, Throwable throwable)
{
if (marker != deduplicateMarker || logger.isDebugEnabled() || throwable == null)
{
return FilterReply.NEUTRAL;
}
LogException logException = new LogException(s, throwable.getStackTrace());
for (LogException e : cache)
{
if (logException.equals(e))
{
// this iinc is not atomic, but doesn't matter in practice
if (++e.count % DUPLICATE_LOG_COUNT == 0)
{
logger.warn("following log message logged " + DUPLICATE_LOG_COUNT + " times!");
return FilterReply.NEUTRAL;
}
return FilterReply.DENY;
}
}
synchronized (cache)
{
if (cache.size() >= CACHE_SIZE)
{
cache.pop();
}
cache.push(logException);
}
return FilterReply.NEUTRAL;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2021, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.util;
import javax.swing.PopupFactory;
/**
* Dummy popup factory for Java 8
*/
class MacOSPopupFactory extends PopupFactory
{
}

View File

@@ -51,6 +51,7 @@ import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.LookAndFeel;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
@@ -112,6 +113,14 @@ public class SwingUtil
try
{
UIManager.setLookAndFeel(laf);
if (OSType.getOSType() == OSType.MacOS)
{
// On MacOS Substance doesn't install its own popup factory, and the default one uses lightweight
// components unless the Aqua LAF is used. Lightweight components do not render correctly over AWT
// canvases on MacOS - so replace the popup factory one with that forces heavy components.
PopupFactory.setSharedInstance(new MacOSPopupFactory());
}
}
catch (UnsupportedLookAndFeelException ex)
{

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2021, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.util;
import java.awt.Component;
import javax.swing.Popup;
import javax.swing.PopupFactory;
/**
* Popup factory for Java 11 which forces heavyweight popups. Lightweight popups do not render correctly
* over AWT canvases on OSX.
*/
class MacOSPopupFactory extends PopupFactory
{
@Override
protected Popup getPopup(Component owner, Component contents, int x, int y, boolean isHeavyWeightPopup) throws IllegalArgumentException
{
return super.getPopup(owner, contents, x, y, true);
}
}

View File

@@ -24,6 +24,8 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<configuration scan="true">
<turboFilter class="net.runelite.client.util.DeduplicationFilter"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</Pattern>

View File

@@ -3260,5 +3260,15 @@
"z1": 1,
"z2": 2
}
],
"10290": [ // Ardougne Monastery
{
"rx1": 43,
"ry1": 17,
"rx2": 49,
"ry2": 17,
"z1": 0,
"z2": 0
}
]
}

View File

@@ -78,6 +78,12 @@
"name": "Baked Potato",
"xp": 15
},
{
"level": 7,
"icon": 25654,
"name": "Guppy",
"xp": 12
},
{
"level": 8,
"icon": 2048,
@@ -228,6 +234,12 @@
"name": "Cup of tea",
"xp": 52
},
{
"level": 20,
"icon": 25660,
"name": "Cavefish",
"xp": 23
},
{
"level": 21,
"icon": 9988,
@@ -378,6 +390,12 @@
"name": "Choc Saturday",
"xp": 170
},
{
"level": 33,
"icon": 25666,
"name": "Tetra",
"xp": 31
},
{
"level": 34,
"icon": 7178,
@@ -516,6 +534,12 @@
"name": "Fried Mushrooms",
"xp": 60
},
{
"level": 46,
"icon": 25672,
"name": "Catfish",
"xp": 43
},
{
"level": 47,
"icon": 7188,

View File

@@ -24,6 +24,12 @@
"name": "Raw Karambwanji",
"xp": 5
},
{
"level": 7,
"icon": 25652,
"name": "Raw Guppy",
"xp": 8
},
{
"level": 10,
"icon": 345,
@@ -48,6 +54,12 @@
"name": "Raw Trout",
"xp": 50
},
{
"level": 20,
"icon": 25658,
"name": "Raw Cavefish",
"xp": 16
},
{
"level": 23,
"icon": 341,
@@ -72,6 +84,12 @@
"name": "Raw Salmon",
"xp": 70
},
{
"level": 33,
"icon": 25664,
"name": "Raw Tetra",
"xp": 24
},
{
"level": 35,
"icon": 359,
@@ -102,6 +120,12 @@
"name": "Raw Bass",
"xp": 100
},
{
"level": 46,
"icon": 25670,
"name": "Raw Catfish",
"xp": 33
},
{
"level": 48,
"icon": 11328,

View File

@@ -36,6 +36,18 @@
"name": "Limestone",
"xp": 26.5
},
{
"level": 14,
"icon": 25683,
"name": "Barronite shards",
"xp": 16
},
{
"level": 14,
"icon": 25684,
"name": "Barronite deposit",
"xp": 32
},
{
"level": 15,
"icon": 440,

View File

@@ -11,6 +11,10 @@
{
"name": "Chaos Altar (700%)",
"value": 6
},
{
"name": "Morytania Diary 3 Shades(150%)",
"value": 0.5
}
],
"actions": [
@@ -219,8 +223,7 @@
"level": 1,
"icon": 3396,
"name": "Loar Remains",
"xp": 33,
"ignoreBonus": true
"xp": 33
},
{
"level": 1,
@@ -274,8 +277,7 @@
"level": 1,
"icon": 3398,
"name": "Phrin Remains",
"xp": 46.5,
"ignoreBonus": true
"xp": 46.5
},
{
"level": 1,
@@ -287,8 +289,7 @@
"level": 1,
"icon": 3400,
"name": "Riyl Remains",
"xp": 59.5,
"ignoreBonus": true
"xp": 59.5
},
{
"level": 1,
@@ -312,8 +313,7 @@
"level": 1,
"icon": 3402,
"name": "Asyn Remains",
"xp": 82.5,
"ignoreBonus": true
"xp": 82.5
},
{
"level": 1,
@@ -325,8 +325,7 @@
"level": 1,
"icon": 3404,
"name": "Fiyr Remains",
"xp": 84,
"ignoreBonus": true
"xp": 84
},
{
"level": 1,
@@ -363,6 +362,36 @@
"icon": 22124,
"name": "Superior Dragon Bones",
"xp": 150
},
{
"level": 1,
"icon": 25419,
"name": "Urium Remains",
"xp": 120
},
{
"level": 1,
"icon": 25654,
"name": "Guppy",
"xp": 4
},
{
"level": 1,
"icon": 25660,
"name": "Cavefish",
"xp": 7
},
{
"level": 1,
"icon": 25666,
"name": "Tetra",
"xp": 10
},
{
"level": 1,
"icon": 25672,
"name": "Cavefish",
"xp": 16
}
]
}

View File

@@ -102,6 +102,12 @@
"name": "Mind Rune",
"xp": 5.5
},
{
"level": 2,
"icon": 25696,
"name": "Mind core",
"xp": 55
},
{
"level": 5,
"icon": 555,
@@ -156,6 +162,12 @@
"name": "Body Rune",
"xp": 7.5
},
{
"level": 20,
"icon": 25698,
"name": "Body core",
"xp": 75
},
{
"level": 23,
"icon": 4699,
@@ -174,6 +186,12 @@
"name": "Chaos Rune",
"xp": 8.5
},
{
"level": 35,
"icon": 25700,
"name": "Chaos core",
"xp": 85
},
{
"level": 40,
"icon": 9075,

View File

@@ -156,6 +156,12 @@
"name": "Bronze 2h Sword",
"xp": 37.5
},
{
"level": 14,
"icon": 25684,
"name": "Barronite deposits",
"xp": 30
},
{
"level": 15,
"icon": 2351,

View File

@@ -1451,11 +1451,11 @@ public abstract class RSClientMixin implements RSClient
"|MenuAction|: MenuOption={} MenuTarget={} Id={} Opcode={}/{} Param0={} Param1={} CanvasX={} CanvasY={}",
menuOptionClicked.getMenuOption(), menuOptionClicked.getMenuTarget(), menuOptionClicked.getId(),
menuOptionClicked.getMenuAction(), opcode + (decremented ? 2000 : 0),
menuOptionClicked.getActionParam(), menuOptionClicked.getWidgetId(), canvasX, canvasY
menuOptionClicked.getParam0(), menuOptionClicked.getParam1(), canvasX, canvasY
);
}
copy$menuAction(menuOptionClicked.getActionParam(), menuOptionClicked.getWidgetId(),
copy$menuAction(menuOptionClicked.getParam0(), menuOptionClicked.getParam1(),
menuOptionClicked.getMenuAction() == UNKNOWN ? opcode : menuOptionClicked.getMenuAction().getId(),
menuOptionClicked.getId(), menuOptionClicked.getMenuOption(), menuOptionClicked.getMenuTarget(),
canvasX, canvasY);

View File

@@ -41,10 +41,7 @@ public abstract class RSModelDataMixin implements RSModelData
private static RSClient client;
@Inject
private float[][] faceTextureUCoordinates;
@Inject
private float[][] faceTextureVCoordinates;
private float[] faceTextureUVCoordinates;
@Copy("toModel")
@Replace("toModel")
@@ -59,14 +56,13 @@ public abstract class RSModelDataMixin implements RSModelData
return null;
}
if (faceTextureUCoordinates == null)
if (faceTextureUVCoordinates == null)
{
computeTextureUVCoordinates();
}
RSModel rsModel = (RSModel) model;
rsModel.setFaceTextureUCoordinates(faceTextureUCoordinates);
rsModel.setFaceTextureVCoordinates(faceTextureVCoordinates);
rsModel.setFaceTextureUVCoordinates(faceTextureUVCoordinates);
return model;
}
@@ -94,40 +90,35 @@ public abstract class RSModelDataMixin implements RSModelData
final byte[] textureCoords = getTextureCoords();
int faceCount = getTriangleFaceCount();
this.faceTextureUCoordinates = new float[faceCount][];
this.faceTextureVCoordinates = new float[faceCount][];
float[] faceTextureUCoordinates = new float[faceCount * 6];
for (int i = 0; i < faceCount; i++)
{
int trianglePointX = trianglePointsX[i];
int trianglePointY = trianglePointsY[i];
int trianglePointZ = trianglePointsZ[i];
int textureCoordinate = textureCoords != null && textureCoords[i] != -1 ? textureCoords[i] & 255 : -1;
short textureIdx;
textureIdx = faceTextures[i];
short textureIdx = faceTextures[i];
if (textureIdx != -1)
{
float[] u = new float[3];
float[] v = new float[3];
int triangleVertexIdx1;
int triangleVertexIdx2;
int triangleVertexIdx3;
if (textureCoordinate == -1)
if (textureCoords != null && textureCoords[i] != -1)
{
int textureCoordinate = textureCoords[i] & 255;
triangleVertexIdx1 = texTriangleX[textureCoordinate];
triangleVertexIdx2 = texTriangleY[textureCoordinate];
triangleVertexIdx3 = texTriangleZ[textureCoordinate];
}
else
{
triangleVertexIdx1 = trianglePointX;
triangleVertexIdx2 = trianglePointY;
triangleVertexIdx3 = trianglePointZ;
}
else
{
triangleVertexIdx1 = texTriangleX[textureCoordinate];
triangleVertexIdx2 = texTriangleY[textureCoordinate];
triangleVertexIdx3 = texTriangleZ[textureCoordinate];
}
float triangleX = (float) vertexPositionsX[triangleVertexIdx1];
float triangleY = (float) vertexPositionsY[triangleVertexIdx1];
@@ -157,22 +148,29 @@ public abstract class RSModelDataMixin implements RSModelData
float f_902_ = f_885_ * f_898_ - f_886_ * f_897_;
float f_903_ = 1.0F / (f_900_ * f_882_ + f_901_ * f_883_ + f_902_ * f_884_);
u[0] = (f_900_ * f_888_ + f_901_ * f_889_ + f_902_ * f_890_) * f_903_;
u[1] = (f_900_ * f_891_ + f_901_ * f_892_ + f_902_ * f_893_) * f_903_;
u[2] = (f_900_ * f_894_ + f_901_ * f_895_ + f_902_ * f_896_) * f_903_;
float u0 = (f_900_ * f_888_ + f_901_ * f_889_ + f_902_ * f_890_) * f_903_;
float u1 = (f_900_ * f_891_ + f_901_ * f_892_ + f_902_ * f_893_) * f_903_;
float u2 = (f_900_ * f_894_ + f_901_ * f_895_ + f_902_ * f_896_) * f_903_;
f_900_ = f_883_ * f_899_ - f_884_ * f_898_;
f_901_ = f_884_ * f_897_ - f_882_ * f_899_;
f_902_ = f_882_ * f_898_ - f_883_ * f_897_;
f_903_ = 1.0F / (f_900_ * f_885_ + f_901_ * f_886_ + f_902_ * f_887_);
v[0] = (f_900_ * f_888_ + f_901_ * f_889_ + f_902_ * f_890_) * f_903_;
v[1] = (f_900_ * f_891_ + f_901_ * f_892_ + f_902_ * f_893_) * f_903_;
v[2] = (f_900_ * f_894_ + f_901_ * f_895_ + f_902_ * f_896_) * f_903_;
float v0 = (f_900_ * f_888_ + f_901_ * f_889_ + f_902_ * f_890_) * f_903_;
float v1 = (f_900_ * f_891_ + f_901_ * f_892_ + f_902_ * f_893_) * f_903_;
float v2 = (f_900_ * f_894_ + f_901_ * f_895_ + f_902_ * f_896_) * f_903_;
this.faceTextureUCoordinates[i] = u;
this.faceTextureVCoordinates[i] = v;
int idx = i * 6;
faceTextureUCoordinates[idx] = u0;
faceTextureUCoordinates[idx + 1] = v0;
faceTextureUCoordinates[idx + 2] = u1;
faceTextureUCoordinates[idx + 3] = v1;
faceTextureUCoordinates[idx + 4] = u2;
faceTextureUCoordinates[idx + 5] = v2;
}
}
this.faceTextureUVCoordinates = faceTextureUCoordinates;
}
}

View File

@@ -61,51 +61,36 @@ public abstract class RSModelMixin implements RSModel
private int rl$uvBufferOffset;
@Inject
private float[][] rl$faceTextureUCoordinates;
@Inject
private float[][] rl$faceTextureVCoordinates;
private float[] rl$faceTextureUVCoordinates;
@MethodHook(value = "<init>", end = true)
@Inject
public void rl$init(RSModel[] models, int length)
{
int count = 0;
for (int i = 0; i < length; ++i)
if (this.getFaceTextures() != null)
{
RSModel model = models[i];
if (model != null)
int count = this.getTrianglesCount();
float[] uv = new float[count * 6];
int idx = 0;
for (int i = 0; i < length; ++i)
{
count += model.getTrianglesCount();
}
}
float[][] u = new float[count][];
float[][] v = new float[count][];
int idx = 0;
for (int i = 0; i < length; ++i)
{
RSModel model = models[i];
if (model != null)
{
float[][] modelU = model.getFaceTextureUCoordinates();
float[][] modelV = model.getFaceTextureVCoordinates();
for (int j = 0; j < model.getTrianglesCount(); ++j)
RSModel model = models[i];
if (model != null)
{
if (modelU != null && modelV != null)
float[] modelUV = model.getFaceTextureUVCoordinates();
if (modelUV != null)
{
u[idx] = modelU[j];
v[idx] = modelV[j];
System.arraycopy(modelUV, 0, uv, idx, model.getTrianglesCount() * 6);
}
++idx;
idx += model.getTrianglesCount() * 6;
}
}
}
setFaceTextureUCoordinates(u);
setFaceTextureVCoordinates(v);
setFaceTextureUVCoordinates(uv);
}
}
@Override
@@ -169,8 +154,7 @@ public abstract class RSModelMixin implements RSModel
if (model != null && model != this)
{
RSModel rsModel = (RSModel) model;
rsModel.setFaceTextureUCoordinates(rl$faceTextureUCoordinates);
rsModel.setFaceTextureVCoordinates(rl$faceTextureVCoordinates);
rsModel.setFaceTextureUVCoordinates(rl$faceTextureUVCoordinates);
}
return model;
}
@@ -192,8 +176,7 @@ public abstract class RSModelMixin implements RSModel
{
// Animated models are usually a shared Model instance that is global
RSModel rsModel = (RSModel) sharedModel;
rsModel.setFaceTextureUCoordinates(rl$faceTextureUCoordinates);
rsModel.setFaceTextureVCoordinates(rl$faceTextureVCoordinates);
rsModel.setFaceTextureUVCoordinates(rl$faceTextureUVCoordinates);
}
@Inject
@@ -385,29 +368,15 @@ public abstract class RSModelMixin implements RSModel
@Inject
@Override
public float[][] getFaceTextureUCoordinates()
public float[] getFaceTextureUVCoordinates()
{
return rl$faceTextureUCoordinates;
return rl$faceTextureUVCoordinates;
}
@Inject
@Override
public void setFaceTextureUCoordinates(float[][] faceTextureUCoordinates)
public void setFaceTextureUVCoordinates(float[] faceTextureUVCoordinates)
{
this.rl$faceTextureUCoordinates = faceTextureUCoordinates;
}
@Inject
@Override
public float[][] getFaceTextureVCoordinates()
{
return rl$faceTextureVCoordinates;
}
@Inject
@Override
public void setFaceTextureVCoordinates(float[][] faceTextureVCoordinates)
{
this.rl$faceTextureVCoordinates = faceTextureVCoordinates;
this.rl$faceTextureUVCoordinates = faceTextureUVCoordinates;
}
}

View File

@@ -24,6 +24,7 @@
*/
package net.runelite.mixins;
import java.awt.Polygon;
import java.awt.Shape;
import net.runelite.api.AnimationID;
import net.runelite.api.NPCComposition;
@@ -169,6 +170,22 @@ public abstract class RSNPCMixin implements RSNPC
return composition;
}
@Inject
@Override
public Polygon getCanvasTilePoly()
{
NPCComposition transformedComposition = this.getTransformedComposition();
if (transformedComposition == null)
{
return null;
}
else
{
int size = transformedComposition.getSize();
return Perspective.getCanvasTileAreaPoly(client, this.getLocalLocation(), size);
}
}
@Inject
@Override
public Shape getConvexHull()

View File

@@ -169,9 +169,6 @@ public interface RSModel extends RSRenderable, Model
*/
Shape getConvexHull(int localX, int localY, int orientation, int tileHeight);
float[][] getFaceTextureUCoordinates();
void setFaceTextureUCoordinates(float[][] rl$faceTextureUCoordinates);
float[][] getFaceTextureVCoordinates();
void setFaceTextureVCoordinates(float[][] rl$faceTextureVCoordinates);
float[] getFaceTextureUVCoordinates();
void setFaceTextureUVCoordinates(float[] rl$faceTextureUVCoordinates);
}