Default Worldhopper
This commit is contained in:
@@ -112,15 +112,4 @@ public interface WorldHopperConfig extends Config
|
|||||||
{
|
{
|
||||||
return SubscriptionFilterMode.BOTH;
|
return SubscriptionFilterMode.BOTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
|
||||||
keyName = "showHistory",
|
|
||||||
name = "Show history tab",
|
|
||||||
description = "Shows the history tab",
|
|
||||||
position = 7
|
|
||||||
)
|
|
||||||
default boolean showHistory()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,13 +75,13 @@ import net.runelite.client.eventbus.Subscribe;
|
|||||||
import net.runelite.client.input.KeyManager;
|
import net.runelite.client.input.KeyManager;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
|
import net.runelite.client.plugins.worldhopper.ping.Ping;
|
||||||
import net.runelite.client.ui.ClientToolbar;
|
import net.runelite.client.ui.ClientToolbar;
|
||||||
import net.runelite.client.ui.NavigationButton;
|
import net.runelite.client.ui.NavigationButton;
|
||||||
import net.runelite.client.util.ExecutorServiceExceptionLogger;
|
import net.runelite.client.util.ExecutorServiceExceptionLogger;
|
||||||
import net.runelite.client.util.HotkeyListener;
|
import net.runelite.client.util.HotkeyListener;
|
||||||
import net.runelite.client.util.Text;
|
import net.runelite.client.util.Text;
|
||||||
import net.runelite.client.util.WorldUtil;
|
import net.runelite.client.util.WorldUtil;
|
||||||
import net.runelite.client.util.ping.Ping;
|
|
||||||
import net.runelite.http.api.worlds.World;
|
import net.runelite.http.api.worlds.World;
|
||||||
import net.runelite.http.api.worlds.WorldClient;
|
import net.runelite.http.api.worlds.WorldClient;
|
||||||
import net.runelite.http.api.worlds.WorldResult;
|
import net.runelite.http.api.worlds.WorldResult;
|
||||||
@@ -258,49 +258,10 @@ public class WorldHopperPlugin extends Plugin
|
|||||||
panel.setFilterMode(config.subscriptionFilter());
|
panel.setFilterMode(config.subscriptionFilter());
|
||||||
updateList();
|
updateList();
|
||||||
break;
|
break;
|
||||||
case "showHistory":
|
|
||||||
panel.updateLayout();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean showHistory()
|
|
||||||
{
|
|
||||||
return config.showHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> getHistory()
|
|
||||||
{
|
|
||||||
Map<String, String> history = configManager.getConfiguration(WorldHopperConfig.GROUP, "history", Map.class);
|
|
||||||
if (history == null)
|
|
||||||
{
|
|
||||||
history = new HashMap<String, String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return history;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearHistory()
|
|
||||||
{
|
|
||||||
Map<String, String> history = getHistory();
|
|
||||||
history.clear();
|
|
||||||
configManager.setConfiguration(WorldHopperConfig.GROUP, "history", history);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToHistory()
|
|
||||||
{
|
|
||||||
addToHistory(client.getWorld());
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToHistory(int world)
|
|
||||||
{
|
|
||||||
long unixTime = System.currentTimeMillis() / 1000L;
|
|
||||||
Map<String, String> history = getHistory();
|
|
||||||
history.put(String.valueOf(world), String.valueOf(unixTime));
|
|
||||||
configManager.setConfiguration(WorldHopperConfig.GROUP, "history", history);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setFavoriteConfig(int world)
|
private void setFavoriteConfig(int world)
|
||||||
{
|
{
|
||||||
configManager.setConfiguration(WorldHopperConfig.GROUP, "favorite_" + world, true);
|
configManager.setConfiguration(WorldHopperConfig.GROUP, "favorite_" + world, true);
|
||||||
@@ -457,12 +418,6 @@ public class WorldHopperPlugin extends Plugin
|
|||||||
lastWorld = newWorld;
|
lastWorld = newWorld;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameStateChanged.getGameState() == GameState.LOGGED_IN)
|
|
||||||
{
|
|
||||||
addToHistory(client.getWorld());
|
|
||||||
panel.updateList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -699,8 +654,6 @@ public class WorldHopperPlugin extends Plugin
|
|||||||
|
|
||||||
quickHopTargetWorld = rsWorld;
|
quickHopTargetWorld = rsWorld;
|
||||||
displaySwitcherAttempts = 0;
|
displaySwitcherAttempts = 0;
|
||||||
|
|
||||||
addToHistory(worldId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
|
|||||||
@@ -26,26 +26,15 @@ package net.runelite.client.plugins.worldhopper;
|
|||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.GridBagConstraints;
|
|
||||||
import java.awt.GridBagLayout;
|
|
||||||
import java.awt.GridLayout;
|
import java.awt.GridLayout;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JTabbedPane;
|
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.border.Border;
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -64,10 +53,7 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
private static final int PLAYERS_COLUMN_WIDTH = 40;
|
private static final int PLAYERS_COLUMN_WIDTH = 40;
|
||||||
private static final int PING_COLUMN_WIDTH = 47;
|
private static final int PING_COLUMN_WIDTH = 47;
|
||||||
|
|
||||||
private final JPanel headerContainer;
|
|
||||||
private final JPanel headerHistContainer;
|
|
||||||
private final JPanel listContainer = new JPanel();
|
private final JPanel listContainer = new JPanel();
|
||||||
private final JPanel histContainer = new JPanel();
|
|
||||||
|
|
||||||
private WorldTableHeader worldHeader;
|
private WorldTableHeader worldHeader;
|
||||||
private WorldTableHeader playersHeader;
|
private WorldTableHeader playersHeader;
|
||||||
@@ -78,7 +64,6 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
private boolean ascendingOrder = true;
|
private boolean ascendingOrder = true;
|
||||||
|
|
||||||
private ArrayList<WorldTableRow> rows = new ArrayList<>();
|
private ArrayList<WorldTableRow> rows = new ArrayList<>();
|
||||||
private ArrayList<WorldTableRow> histRows = new ArrayList<>();
|
|
||||||
private WorldHopperPlugin plugin;
|
private WorldHopperPlugin plugin;
|
||||||
@Setter(AccessLevel.PACKAGE)
|
@Setter(AccessLevel.PACKAGE)
|
||||||
private SubscriptionFilterMode filterMode;
|
private SubscriptionFilterMode filterMode;
|
||||||
@@ -90,35 +75,12 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
setBorder(null);
|
setBorder(null);
|
||||||
setLayout(new DynamicGridLayout(0, 1));
|
setLayout(new DynamicGridLayout(0, 1));
|
||||||
|
|
||||||
headerContainer = buildHeader();
|
JPanel headerContainer = buildHeader();
|
||||||
headerHistContainer = buildHistoryHeader();
|
|
||||||
|
|
||||||
listContainer.setLayout(new GridLayout(0, 1));
|
listContainer.setLayout(new GridLayout(0, 1));
|
||||||
histContainer.setLayout(new GridLayout(0, 1));
|
|
||||||
|
|
||||||
updateLayout();
|
add(headerContainer);
|
||||||
}
|
add(listContainer);
|
||||||
|
|
||||||
void updateLayout()
|
|
||||||
{
|
|
||||||
if (this.getComponentCount() > 0)
|
|
||||||
{
|
|
||||||
for (Component c : this.getComponents())
|
|
||||||
{
|
|
||||||
this.remove(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plugin.showHistory())
|
|
||||||
{
|
|
||||||
Component tabs = createTabs();
|
|
||||||
add(tabs);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
add(headerContainer);
|
|
||||||
add(listContainer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchCurrentHighlight(int newWorld, int lastWorld)
|
void switchCurrentHighlight(int newWorld, int lastWorld)
|
||||||
@@ -134,18 +96,6 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
row.recolour(false);
|
row.recolour(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (WorldTableRow row : histRows)
|
|
||||||
{
|
|
||||||
if (row.getWorld().getId() == newWorld)
|
|
||||||
{
|
|
||||||
row.recolour(true);
|
|
||||||
}
|
|
||||||
else if (row.getWorld().getId() == lastWorld)
|
|
||||||
{
|
|
||||||
row.recolour(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateListData(Map<Integer, Integer> worldData)
|
void updateListData(Map<Integer, Integer> worldData)
|
||||||
@@ -160,16 +110,6 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (WorldTableRow worldTableRow : histRows)
|
|
||||||
{
|
|
||||||
World world = worldTableRow.getWorld();
|
|
||||||
Integer playerCount = worldData.get(world.getId());
|
|
||||||
if (playerCount != null)
|
|
||||||
{
|
|
||||||
worldTableRow.updatePlayerCount(playerCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the list is being ordered by player count, then it has to be re-painted
|
// If the list is being ordered by player count, then it has to be re-painted
|
||||||
// to properly display the new data
|
// to properly display the new data
|
||||||
if (orderIndex == WorldOrder.PLAYERS)
|
if (orderIndex == WorldOrder.PLAYERS)
|
||||||
@@ -194,21 +134,6 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (WorldTableRow worldTableRow : histRows)
|
|
||||||
{
|
|
||||||
if (worldTableRow.getWorld().getId() == world)
|
|
||||||
{
|
|
||||||
worldTableRow.setPing(ping);
|
|
||||||
|
|
||||||
// If the panel is sorted by ping, re-sort it
|
|
||||||
if (orderIndex == WorldOrder.PING)
|
|
||||||
{
|
|
||||||
updateList();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hidePing()
|
void hidePing()
|
||||||
@@ -217,11 +142,6 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
{
|
{
|
||||||
worldTableRow.hidePing();
|
worldTableRow.hidePing();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (WorldTableRow worldTableRow : histRows)
|
|
||||||
{
|
|
||||||
worldTableRow.hidePing();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void showPing()
|
void showPing()
|
||||||
@@ -230,11 +150,6 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
{
|
{
|
||||||
worldTableRow.showPing();
|
worldTableRow.showPing();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (WorldTableRow worldTableRow : histRows)
|
|
||||||
{
|
|
||||||
worldTableRow.showPing();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateList()
|
void updateList()
|
||||||
@@ -270,127 +185,16 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
});
|
});
|
||||||
|
|
||||||
listContainer.removeAll();
|
listContainer.removeAll();
|
||||||
histContainer.removeAll();
|
|
||||||
|
|
||||||
Map<String, String> history = plugin.getHistory();
|
|
||||||
Map<String, String> matchedHist = new HashMap<>();
|
|
||||||
for (int i = 0; i < rows.size(); i++)
|
for (int i = 0; i < rows.size(); i++)
|
||||||
{
|
{
|
||||||
WorldTableRow row = rows.get(i);
|
WorldTableRow row = rows.get(i);
|
||||||
row.setBackground(i % 2 == 0 ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR);
|
row.setBackground(i % 2 == 0 ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR);
|
||||||
listContainer.add(row);
|
listContainer.add(row);
|
||||||
|
|
||||||
String worldNum = String.valueOf(row.getWorld().getId());
|
|
||||||
if (history.containsKey(worldNum))
|
|
||||||
{
|
|
||||||
// Add toa list that we can sort later
|
|
||||||
matchedHist.put(worldNum, history.get(worldNum));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort by ascending
|
|
||||||
matchedHist = matchedHist.entrySet().stream()
|
|
||||||
.sorted(Map.Entry.<String, String>comparingByValue().reversed())
|
|
||||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
|
|
||||||
(e1, e2) -> e1, LinkedHashMap::new));
|
|
||||||
|
|
||||||
// Add matched rows to history list
|
|
||||||
Iterator it = matchedHist.entrySet().iterator();
|
|
||||||
int histRowCount = 0;
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
Map.Entry pair = (Map.Entry) it.next();
|
|
||||||
for (WorldTableRow r : rows)
|
|
||||||
{
|
|
||||||
WorldTableRow histRow = r;
|
|
||||||
histRow.setBackground(histRowCount % 2 == 0 ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR);
|
|
||||||
if (String.valueOf(r.getWorld().getId()).equals(pair.getKey()))
|
|
||||||
{
|
|
||||||
histContainer.add(r);
|
|
||||||
histRowCount++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
listContainer.revalidate();
|
listContainer.revalidate();
|
||||||
listContainer.repaint();
|
listContainer.repaint();
|
||||||
histContainer.revalidate();
|
|
||||||
histContainer.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
Component createTabs()
|
|
||||||
{
|
|
||||||
// Constraints for GB Layout
|
|
||||||
GridBagConstraints listConst = new GridBagConstraints();
|
|
||||||
listConst.gridx = 0;
|
|
||||||
listConst.gridy = 1;
|
|
||||||
listConst.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
GridBagConstraints headConst = new GridBagConstraints();
|
|
||||||
headConst.gridx = 0;
|
|
||||||
headConst.gridy = 0;
|
|
||||||
headConst.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
GridBagConstraints resetConst = new GridBagConstraints();
|
|
||||||
resetConst.gridx = 0;
|
|
||||||
resetConst.gridy = 2;
|
|
||||||
resetConst.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
|
|
||||||
// Border so that the scrollbar doesn't go over ping
|
|
||||||
Border paddingBorder = BorderFactory.createEmptyBorder(0, 0, 0, 5);
|
|
||||||
|
|
||||||
// Clear history button
|
|
||||||
JButton resetBtn = new JButton("Clear History");
|
|
||||||
resetBtn.addActionListener(e ->
|
|
||||||
{
|
|
||||||
plugin.clearHistory();
|
|
||||||
plugin.addToHistory();
|
|
||||||
updateList();
|
|
||||||
});
|
|
||||||
|
|
||||||
// World Selector page
|
|
||||||
JPanel worldPanel = new JPanel();
|
|
||||||
worldPanel.setBorder(paddingBorder);
|
|
||||||
worldPanel.setLayout(new GridBagLayout());
|
|
||||||
worldPanel.add(headerContainer, headConst);
|
|
||||||
worldPanel.add(listContainer, listConst);
|
|
||||||
|
|
||||||
// History page
|
|
||||||
JPanel histPanel = new JPanel();
|
|
||||||
histPanel.setBorder(paddingBorder);
|
|
||||||
histPanel.setLayout(new GridBagLayout());
|
|
||||||
histPanel.add(headerHistContainer, headConst);
|
|
||||||
histPanel.add(histContainer, listConst);
|
|
||||||
histPanel.add(resetBtn, resetConst);
|
|
||||||
|
|
||||||
JTabbedPane worldTabs = new JTabbedPane();
|
|
||||||
worldTabs.setName("tabs");
|
|
||||||
worldTabs.addTab("Worlds", worldPanel);
|
|
||||||
worldTabs.addTab("History", histPanel);
|
|
||||||
|
|
||||||
// This is a fix for preventing stretching of WorldTableRows
|
|
||||||
worldTabs.addChangeListener(e ->
|
|
||||||
{
|
|
||||||
switch (worldTabs.getSelectedIndex())
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
histPanel.remove(histContainer);
|
|
||||||
if (worldPanel.getComponentCount() < 2)
|
|
||||||
{
|
|
||||||
worldPanel.add(listContainer, listConst);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
worldPanel.remove(listContainer);
|
|
||||||
if (histPanel.getComponentCount() < 3)
|
|
||||||
{
|
|
||||||
histPanel.add(histContainer, listConst);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return worldTabs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateFavoriteMenu(int world, boolean favorite)
|
void updateFavoriteMenu(int world, boolean favorite)
|
||||||
@@ -402,14 +206,6 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
row.setFavoriteMenu(favorite);
|
row.setFavoriteMenu(favorite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (WorldTableRow row : histRows)
|
|
||||||
{
|
|
||||||
if (row.getWorld().getId() == world)
|
|
||||||
{
|
|
||||||
row.setFavoriteMenu(favorite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetAllFavoriteMenus()
|
void resetAllFavoriteMenus()
|
||||||
@@ -419,21 +215,10 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
row.setFavoriteMenu(false);
|
row.setFavoriteMenu(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (WorldTableRow row : histRows)
|
|
||||||
{
|
|
||||||
row.setFavoriteMenu(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void populate(List<World> worlds)
|
void populate(List<World> worlds)
|
||||||
{
|
{
|
||||||
Map<Integer, Integer> pingHistory = new HashMap<>();
|
|
||||||
|
|
||||||
for (WorldTableRow row : rows)
|
|
||||||
{
|
|
||||||
pingHistory.put(row.getWorld().getId(), row.getPing());
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.clear();
|
rows.clear();
|
||||||
|
|
||||||
for (int i = 0; i < worlds.size(); i++)
|
for (int i = 0; i < worlds.size(); i++)
|
||||||
@@ -456,8 +241,7 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer ping = pingHistory.getOrDefault(world.getId(), 0);
|
rows.add(buildRow(world, i % 2 == 0, world.getId() == plugin.getCurrentWorld() && plugin.getLastWorld() != 0, plugin.isFavorite(world)));
|
||||||
rows.add(buildRow(world, i % 2 == 0, world.getId() == plugin.getCurrentWorld() && plugin.getLastWorld() != 0, plugin.isFavorite(world), ping));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateList();
|
updateList();
|
||||||
@@ -493,35 +277,6 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
/**
|
/**
|
||||||
* Builds the entire table header.
|
* Builds the entire table header.
|
||||||
*/
|
*/
|
||||||
private JPanel buildHistoryHeader()
|
|
||||||
{
|
|
||||||
JPanel header = new JPanel(new BorderLayout());
|
|
||||||
JPanel leftSide = new JPanel(new BorderLayout());
|
|
||||||
JPanel rightSide = new JPanel(new BorderLayout());
|
|
||||||
|
|
||||||
WorldTableHeader pingHeader = new WorldTableHeader("Ping", false, ascendingOrder, plugin::refresh);
|
|
||||||
pingHeader.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0));
|
|
||||||
|
|
||||||
WorldTableHeader worldHeader = new WorldTableHeader("World", false, ascendingOrder, plugin::refresh);
|
|
||||||
worldHeader.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0));
|
|
||||||
|
|
||||||
WorldTableHeader playersHeader = new WorldTableHeader("#", false, ascendingOrder, plugin::refresh);
|
|
||||||
playersHeader.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0));
|
|
||||||
|
|
||||||
WorldTableHeader activityHeader = new WorldTableHeader("Activity", false, ascendingOrder, plugin::refresh);
|
|
||||||
|
|
||||||
leftSide.add(worldHeader, BorderLayout.WEST);
|
|
||||||
leftSide.add(playersHeader, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
rightSide.add(activityHeader, BorderLayout.CENTER);
|
|
||||||
rightSide.add(pingHeader, BorderLayout.EAST);
|
|
||||||
|
|
||||||
header.add(leftSide, BorderLayout.WEST);
|
|
||||||
header.add(rightSide, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JPanel buildHeader()
|
private JPanel buildHeader()
|
||||||
{
|
{
|
||||||
JPanel header = new JPanel(new BorderLayout());
|
JPanel header = new JPanel(new BorderLayout());
|
||||||
@@ -606,7 +361,7 @@ class WorldSwitcherPanel extends PluginPanel
|
|||||||
/**
|
/**
|
||||||
* Builds a table row, that displays the world's information.
|
* Builds a table row, that displays the world's information.
|
||||||
*/
|
*/
|
||||||
private WorldTableRow buildRow(World world, boolean stripe, boolean current, boolean favorite, Integer ping)
|
private WorldTableRow buildRow(World world, boolean stripe, boolean current, boolean favorite)
|
||||||
{
|
{
|
||||||
WorldTableRow row = new WorldTableRow(world, current, favorite,
|
WorldTableRow row = new WorldTableRow(world, current, favorite,
|
||||||
world1 ->
|
world1 ->
|
||||||
|
|||||||
@@ -96,9 +96,8 @@ class WorldTableRow extends JPanel
|
|||||||
this.world = world;
|
this.world = world;
|
||||||
this.onFavorite = onFavorite;
|
this.onFavorite = onFavorite;
|
||||||
this.updatedPlayerCount = world.getPlayers();
|
this.updatedPlayerCount = world.getPlayers();
|
||||||
this.
|
|
||||||
|
|
||||||
setLayout(new BorderLayout());
|
setLayout(new BorderLayout());
|
||||||
setBorder(new EmptyBorder(2, 0, 2, 0));
|
setBorder(new EmptyBorder(2, 0, 2, 0));
|
||||||
|
|
||||||
addMouseListener(new MouseAdapter()
|
addMouseListener(new MouseAdapter()
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.plugins.worldhopper.ping;
|
||||||
|
|
||||||
|
import com.sun.jna.Library;
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
interface IPHlpAPI extends Library
|
||||||
|
{
|
||||||
|
IPHlpAPI INSTANCE = Native.loadLibrary("IPHlpAPI", IPHlpAPI.class);
|
||||||
|
|
||||||
|
Pointer IcmpCreateFile();
|
||||||
|
|
||||||
|
boolean IcmpCloseHandle(Pointer handle);
|
||||||
|
|
||||||
|
int IcmpSendEcho(Pointer IcmpHandle, int DestinationAddress, Pointer RequestData, short RequestSize, Pointer RequestOptions, IcmpEchoReply ReplyBuffer, int ReplySize, int Timeout);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.plugins.worldhopper.ping;
|
||||||
|
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import com.sun.jna.platform.win32.WinDef;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IcmpEchoReply extends Structure
|
||||||
|
{
|
||||||
|
private static final int IP_OPTION_INFO_SIZE = 1 + 1 + 1 + 1 + (Pointer.SIZE == 8 ? 12 : 4); // on 64bit vms add 4 byte padding
|
||||||
|
public static final int SIZE = 4 + 4 + 4 + 2 + 2 + Pointer.SIZE + IP_OPTION_INFO_SIZE;
|
||||||
|
|
||||||
|
public WinDef.ULONG address;
|
||||||
|
public WinDef.ULONG status;
|
||||||
|
public WinDef.ULONG roundTripTime;
|
||||||
|
public WinDef.USHORT dataSize;
|
||||||
|
public WinDef.USHORT reserved;
|
||||||
|
public WinDef.PVOID data;
|
||||||
|
public WinDef.UCHAR ttl;
|
||||||
|
public WinDef.UCHAR tos;
|
||||||
|
public WinDef.UCHAR flags;
|
||||||
|
public WinDef.UCHAR optionsSize;
|
||||||
|
public WinDef.PVOID optionsData;
|
||||||
|
|
||||||
|
IcmpEchoReply(Pointer p)
|
||||||
|
{
|
||||||
|
super(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder()
|
||||||
|
{
|
||||||
|
return Arrays.asList("address", "status", "roundTripTime", "dataSize", "reserved", "data", "ttl", "tos", "flags", "optionsSize", "optionsData");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.plugins.worldhopper.ping;
|
||||||
|
|
||||||
|
import com.sun.jna.Memory;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.runelite.client.util.OSType;
|
||||||
|
import net.runelite.http.api.worlds.World;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class Ping
|
||||||
|
{
|
||||||
|
private static final String RUNELITE_PING = "RuneLitePing";
|
||||||
|
|
||||||
|
private static final int TIMEOUT = 2000;
|
||||||
|
private static final int PORT = 43594;
|
||||||
|
|
||||||
|
public static int ping(World world)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (OSType.getOSType())
|
||||||
|
{
|
||||||
|
case Windows:
|
||||||
|
return windowsPing(world);
|
||||||
|
default:
|
||||||
|
return tcpPing(world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
log.warn("error pinging", ex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int windowsPing(World world) throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPHlpAPI ipHlpAPI = IPHlpAPI.INSTANCE;
|
||||||
|
Pointer ptr = ipHlpAPI.IcmpCreateFile();
|
||||||
|
InetAddress inetAddress = InetAddress.getByName(world.getAddress());
|
||||||
|
byte[] address = inetAddress.getAddress();
|
||||||
|
String dataStr = RUNELITE_PING;
|
||||||
|
int dataLength = dataStr.length() + 1;
|
||||||
|
Pointer data = new Memory(dataLength);
|
||||||
|
data.setString(0L, dataStr);
|
||||||
|
IcmpEchoReply icmpEchoReply = new IcmpEchoReply(new Memory(IcmpEchoReply.SIZE + dataLength));
|
||||||
|
assert icmpEchoReply.size() == IcmpEchoReply.SIZE;
|
||||||
|
int packed = (address[0] & 0xff) | ((address[1] & 0xff) << 8) | ((address[2] & 0xff) << 16) | ((address[3] & 0xff) << 24);
|
||||||
|
int ret = ipHlpAPI.IcmpSendEcho(ptr, packed, data, (short) (dataLength), Pointer.NULL, icmpEchoReply, IcmpEchoReply.SIZE + dataLength, TIMEOUT);
|
||||||
|
if (ret != 1)
|
||||||
|
{
|
||||||
|
ipHlpAPI.IcmpCloseHandle(ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtt = Math.toIntExact(icmpEchoReply.roundTripTime.longValue());
|
||||||
|
ipHlpAPI.IcmpCloseHandle(ptr);
|
||||||
|
|
||||||
|
return rtt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int tcpPing(World world) throws IOException
|
||||||
|
{
|
||||||
|
try (Socket socket = new Socket())
|
||||||
|
{
|
||||||
|
socket.setSoTimeout(TIMEOUT);
|
||||||
|
InetAddress inetAddress = InetAddress.getByName(world.getAddress());
|
||||||
|
long start = System.nanoTime();
|
||||||
|
socket.connect(new InetSocketAddress(inetAddress, PORT));
|
||||||
|
long end = System.nanoTime();
|
||||||
|
return (int) ((end - start) / 1000000L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user