Merge pull request #3034 from open-osrs/upstream-2508-2
project: Merge upstream
This commit is contained in:
@@ -40,4 +40,5 @@ public class LootRecord
|
||||
private Object metadata;
|
||||
private Collection<GameItem> drops;
|
||||
private Instant time;
|
||||
private Integer world;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ public enum WorldType
|
||||
SKILL_TOTAL,
|
||||
HIGH_RISK,
|
||||
LAST_MAN_STANDING,
|
||||
TOURNAMENT,
|
||||
NOSAVE_MODE,
|
||||
DEADMAN,
|
||||
DEADMAN_TOURNAMENT,
|
||||
LEAGUE;
|
||||
TOURNAMENT,
|
||||
SEASONAL;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -90,8 +90,7 @@ public interface Model extends Renderable
|
||||
|
||||
short[] getFaceTextures();
|
||||
|
||||
float[][] getFaceTextureUCoordinates();
|
||||
float[][] getFaceTextureVCoordinates();
|
||||
float[] getFaceTextureUVCoordinates();
|
||||
|
||||
void calculateExtreme(int orientation);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -129,10 +129,7 @@ public abstract class Overlay implements LayoutableRenderableEntity
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
public void revalidate()
|
||||
{
|
||||
setPreferredPosition(null);
|
||||
setPreferredSize(null);
|
||||
setPreferredLocation(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -3260,5 +3260,15 @@
|
||||
"z1": 1,
|
||||
"z2": 2
|
||||
}
|
||||
],
|
||||
"10290": [ // Ardougne Monastery
|
||||
{
|
||||
"rx1": 43,
|
||||
"ry1": 17,
|
||||
"rx2": 49,
|
||||
"ry2": 17,
|
||||
"z1": 0,
|
||||
"z2": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -156,6 +156,12 @@
|
||||
"name": "Bronze 2h Sword",
|
||||
"xp": 37.5
|
||||
},
|
||||
{
|
||||
"level": 14,
|
||||
"icon": 25684,
|
||||
"name": "Barronite deposits",
|
||||
"xp": 30
|
||||
},
|
||||
{
|
||||
"level": 15,
|
||||
"icon": 2351,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user