Advertisement
Guest User

Untitled

a guest
Sep 18th, 2019
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.92 KB | None | 0 0
  1. /*
  2. * Copyright (c) 2017, Adam <Adam@sigterm.info>
  3. * Copyright (c) 2018, Lotto <https://github.com/devLotto>
  4. * Copyright (c) 2019, gregg1494 <https://github.com/gregg1494>
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright notice, this
  11. * list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  20. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. package net.runelite.client.plugins.worldhopper;
  28.  
  29. import com.google.common.base.Stopwatch;
  30. import com.google.common.collect.ImmutableList;
  31. import com.google.common.collect.ObjectArrays;
  32. import com.google.inject.Provides;
  33. import java.awt.image.BufferedImage;
  34. import java.io.IOException;
  35. import java.time.Duration;
  36. import java.time.Instant;
  37. import java.util.Comparator;
  38. import java.util.EnumSet;
  39. import java.util.HashMap;
  40. import java.util.List;
  41. import java.util.Map;
  42. import java.util.concurrent.Executors;
  43. import java.util.concurrent.ScheduledExecutorService;
  44. import java.util.concurrent.ScheduledFuture;
  45. import java.util.concurrent.TimeUnit;
  46. import javax.imageio.ImageIO;
  47. import javax.inject.Inject;
  48. import javax.swing.SwingUtilities;
  49. import lombok.AccessLevel;
  50. import lombok.Getter;
  51. import lombok.extern.slf4j.Slf4j;
  52. import net.runelite.api.ChatMessageType;
  53. import net.runelite.api.ChatPlayer;
  54. import net.runelite.api.ClanMember;
  55. import net.runelite.api.Client;
  56. import net.runelite.api.Friend;
  57. import net.runelite.api.GameState;
  58. import net.runelite.api.MenuAction;
  59. import net.runelite.api.MenuEntry;
  60. import net.runelite.api.Varbits;
  61. import net.runelite.api.events.ChatMessage;
  62. import net.runelite.api.events.ConfigChanged;
  63. import net.runelite.api.events.GameStateChanged;
  64. import net.runelite.api.events.GameTick;
  65. import net.runelite.api.events.MenuEntryAdded;
  66. import net.runelite.api.events.PlayerMenuOptionClicked;
  67. import net.runelite.api.events.VarbitChanged;
  68. import net.runelite.api.events.WorldListLoad;
  69. import net.runelite.api.widgets.WidgetInfo;
  70. import net.runelite.client.callback.ClientThread;
  71. import net.runelite.client.chat.ChatColorType;
  72. import net.runelite.client.chat.ChatMessageBuilder;
  73. import net.runelite.client.chat.ChatMessageManager;
  74. import net.runelite.client.chat.QueuedMessage;
  75. import net.runelite.client.config.ConfigManager;
  76. import net.runelite.client.eventbus.Subscribe;
  77. import net.runelite.client.input.KeyManager;
  78. import net.runelite.client.plugins.Plugin;
  79. import net.runelite.client.plugins.PluginDescriptor;
  80. import net.runelite.client.plugins.worldhopper.ping.Ping;
  81. import net.runelite.client.ui.ClientToolbar;
  82. import net.runelite.client.ui.NavigationButton;
  83. import net.runelite.client.ui.overlay.OverlayManager;
  84. import net.runelite.client.util.ExecutorServiceExceptionLogger;
  85. import net.runelite.client.util.HotkeyListener;
  86. import net.runelite.client.util.Text;
  87. import net.runelite.client.util.WorldUtil;
  88. import net.runelite.http.api.worlds.World;
  89. import net.runelite.http.api.worlds.WorldClient;
  90. import net.runelite.http.api.worlds.WorldResult;
  91. import net.runelite.http.api.worlds.WorldType;
  92. import org.apache.commons.lang3.ArrayUtils;
  93.  
  94. @PluginDescriptor(
  95. name = "World Hopper",
  96. description = "Allows you to quickly hop worlds"
  97. )
  98. @Slf4j
  99. public class WorldHopperPlugin extends Plugin
  100. {
  101. private static final int WORLD_FETCH_TIMER = 10;
  102. private static final int REFRESH_THROTTLE = 60_000; // ms
  103. private static final int TICK_THROTTLE = (int) Duration.ofMinutes(10).toMillis();
  104.  
  105. private static final int DISPLAY_SWITCHER_MAX_ATTEMPTS = 3;
  106.  
  107. private static final String HOP_TO = "Hop-to";
  108. private static final String KICK_OPTION = "Kick";
  109. private static final ImmutableList<String> BEFORE_OPTIONS = ImmutableList.of("Add friend", "Remove friend", KICK_OPTION);
  110. private static final ImmutableList<String> AFTER_OPTIONS = ImmutableList.of("Message");
  111.  
  112. @Inject
  113. private Client client;
  114.  
  115. @Inject
  116. private ClientThread clientThread;
  117.  
  118. @Inject
  119. private ConfigManager configManager;
  120.  
  121. @Inject
  122. private ClientToolbar clientToolbar;
  123.  
  124. @Inject
  125. private KeyManager keyManager;
  126.  
  127. @Inject
  128. private ChatMessageManager chatMessageManager;
  129.  
  130. @Inject
  131. private ScheduledExecutorService executorService;
  132.  
  133. @Inject
  134. private WorldHopperConfig config;
  135.  
  136. @Inject
  137. private OverlayManager overlayManager;
  138.  
  139. @Inject
  140. private WorldHopperPingOverlay worldHopperOverlay;
  141.  
  142. private ScheduledExecutorService hopperExecutorService;
  143.  
  144. private NavigationButton navButton;
  145. private WorldSwitcherPanel panel;
  146.  
  147. private net.runelite.api.World quickHopTargetWorld;
  148. private int displaySwitcherAttempts = 0;
  149.  
  150. @Getter
  151. private int lastWorld;
  152.  
  153. private int favoriteWorld1, favoriteWorld2;
  154.  
  155. private ScheduledFuture<?> worldResultFuture, pingFuture, currPingFuture;
  156. private WorldResult worldResult;
  157. private int currentWorld;
  158. private Instant lastFetch;
  159. private boolean firstRun;
  160.  
  161. @Getter(AccessLevel.PACKAGE)
  162. private int currentPing;
  163.  
  164. private final HotkeyListener previousKeyListener = new HotkeyListener(() -> config.previousKey())
  165. {
  166. @Override
  167. public void hotkeyPressed()
  168. {
  169. hop(true);
  170. }
  171. };
  172. private final HotkeyListener nextKeyListener = new HotkeyListener(() -> config.nextKey())
  173. {
  174. @Override
  175. public void hotkeyPressed()
  176. {
  177. hop(false);
  178. }
  179. };
  180.  
  181. @Provides
  182. WorldHopperConfig getConfig(ConfigManager configManager)
  183. {
  184. return configManager.getConfig(WorldHopperConfig.class);
  185. }
  186.  
  187. @Override
  188. protected void startUp() throws Exception
  189. {
  190. firstRun = true;
  191. currentPing = -1;
  192.  
  193. keyManager.registerKeyListener(previousKeyListener);
  194. keyManager.registerKeyListener(nextKeyListener);
  195.  
  196. panel = new WorldSwitcherPanel(this);
  197.  
  198. final BufferedImage icon;
  199. synchronized (ImageIO.class)
  200. {
  201. icon = ImageIO.read(getClass().getResourceAsStream("icon.png"));
  202. }
  203.  
  204. navButton = NavigationButton.builder()
  205. .tooltip("World Switcher")
  206. .icon(icon)
  207. .priority(3)
  208. .panel(panel)
  209. .build();
  210.  
  211. if (config.showSidebar())
  212. {
  213. clientToolbar.addNavigation(navButton);
  214. }
  215.  
  216. overlayManager.add(worldHopperOverlay);
  217.  
  218. panel.setFilterMode(config.subscriptionFilter());
  219.  
  220. // The plugin has its own executor for pings, as it blocks for a long time
  221. hopperExecutorService = new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor());
  222. // On first run this schedules an initial ping on hopperExecutorService
  223. worldResultFuture = executorService.scheduleAtFixedRate(this::tick, 0, WORLD_FETCH_TIMER, TimeUnit.MINUTES);
  224.  
  225. // Give some initial delay - this won't run until after pingInitialWorlds finishes from tick() anyway
  226. pingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingNextWorld, 15, 3, TimeUnit.SECONDS);
  227. currPingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingCurrentWorld, 15, 1, TimeUnit.SECONDS);
  228. }
  229.  
  230. @Override
  231. protected void shutDown() throws Exception
  232. {
  233. pingFuture.cancel(true);
  234. pingFuture = null;
  235.  
  236. currPingFuture.cancel(true);
  237. currPingFuture = null;
  238.  
  239. overlayManager.remove(worldHopperOverlay);
  240.  
  241. keyManager.unregisterKeyListener(previousKeyListener);
  242. keyManager.unregisterKeyListener(nextKeyListener);
  243.  
  244. worldResultFuture.cancel(true);
  245. worldResultFuture = null;
  246. worldResult = null;
  247. lastFetch = null;
  248.  
  249. clientToolbar.removeNavigation(navButton);
  250.  
  251. hopperExecutorService.shutdown();
  252. hopperExecutorService = null;
  253. }
  254.  
  255. @Subscribe
  256. public void onConfigChanged(final ConfigChanged event)
  257. {
  258. if (event.getGroup().equals(WorldHopperConfig.GROUP))
  259. {
  260. switch (event.getKey())
  261. {
  262. case "showSidebar":
  263. if (config.showSidebar())
  264. {
  265. clientToolbar.addNavigation(navButton);
  266. }
  267. else
  268. {
  269. clientToolbar.removeNavigation(navButton);
  270. }
  271. break;
  272. case "ping":
  273. if (config.ping())
  274. {
  275. SwingUtilities.invokeLater(() -> panel.showPing());
  276. }
  277. else
  278. {
  279. SwingUtilities.invokeLater(() -> panel.hidePing());
  280. }
  281. break;
  282. case "subscriptionFilter":
  283. panel.setFilterMode(config.subscriptionFilter());
  284. updateList();
  285. break;
  286. }
  287. }
  288. }
  289.  
  290. private void setFavoriteConfig(int world)
  291. {
  292. configManager.setConfiguration(WorldHopperConfig.GROUP, "favorite_" + world, true);
  293. }
  294.  
  295. private boolean isFavoriteConfig(int world)
  296. {
  297. Boolean favorite = configManager.getConfiguration(WorldHopperConfig.GROUP, "favorite_" + world, Boolean.class);
  298. return favorite != null && favorite;
  299. }
  300.  
  301. private void clearFavoriteConfig(int world)
  302. {
  303. configManager.unsetConfiguration(WorldHopperConfig.GROUP, "favorite_" + world);
  304. panel.resetAllFavoriteMenus();
  305. }
  306.  
  307. boolean isFavorite(World world)
  308. {
  309. int id = world.getId();
  310. return id == favoriteWorld1 || id == favoriteWorld2 || isFavoriteConfig(id);
  311. }
  312.  
  313. int getCurrentWorld()
  314. {
  315. return client.getWorld();
  316. }
  317.  
  318. void hopTo(World world)
  319. {
  320. hop(world.getId());
  321. }
  322.  
  323. void addToFavorites(World world)
  324. {
  325. log.debug("Adding world {} to favorites", world.getId());
  326. setFavoriteConfig(world.getId());
  327. panel.updateFavoriteMenu(world.getId(), true);
  328. }
  329.  
  330. void removeFromFavorites(World world)
  331. {
  332. log.debug("Removing world {} from favorites", world.getId());
  333. clearFavoriteConfig(world.getId());
  334. panel.updateFavoriteMenu(world.getId(), false);
  335. }
  336.  
  337. @Subscribe
  338. public void onVarbitChanged(VarbitChanged varbitChanged)
  339. {
  340. int old1 = favoriteWorld1;
  341. int old2 = favoriteWorld2;
  342.  
  343. favoriteWorld1 = client.getVar(Varbits.WORLDHOPPER_FAVROITE_1);
  344. favoriteWorld2 = client.getVar(Varbits.WORLDHOPPER_FAVROITE_2);
  345.  
  346. if (old1 != favoriteWorld1 || old2 != favoriteWorld2)
  347. {
  348. SwingUtilities.invokeLater(panel::updateList);
  349. }
  350. }
  351.  
  352. @Subscribe
  353. public void onMenuEntryAdded(MenuEntryAdded event)
  354. {
  355. if (!config.menuOption())
  356. {
  357. return;
  358. }
  359.  
  360. int groupId = WidgetInfo.TO_GROUP(event.getActionParam1());
  361. String option = event.getOption();
  362.  
  363. if (groupId == WidgetInfo.FRIENDS_LIST.getGroupId() || groupId == WidgetInfo.CLAN_CHAT.getGroupId())
  364. {
  365. boolean after;
  366.  
  367. if (AFTER_OPTIONS.contains(option))
  368. {
  369. after = true;
  370. }
  371. else if (BEFORE_OPTIONS.contains(option))
  372. {
  373. after = false;
  374. }
  375. else
  376. {
  377. return;
  378. }
  379.  
  380. // Don't add entry if user is offline
  381. ChatPlayer player = getChatPlayerFromName(event.getTarget());
  382.  
  383. if (player == null || player.getWorld() == 0 || player.getWorld() == client.getWorld()
  384. || worldResult == null)
  385. {
  386. return;
  387. }
  388.  
  389. World currentWorld = worldResult.findWorld(client.getWorld());
  390. World targetWorld = worldResult.findWorld(player.getWorld());
  391. if (targetWorld == null || currentWorld == null
  392. || (!currentWorld.getTypes().contains(WorldType.PVP) && targetWorld.getTypes().contains(WorldType.PVP)))
  393. {
  394. // Disable Hop-to a PVP world from a regular world
  395. return;
  396. }
  397.  
  398. final MenuEntry hopTo = new MenuEntry();
  399. hopTo.setOption(HOP_TO);
  400. hopTo.setTarget(event.getTarget());
  401. hopTo.setType(MenuAction.RUNELITE.getId());
  402. hopTo.setParam0(event.getActionParam0());
  403. hopTo.setParam1(event.getActionParam1());
  404.  
  405. insertMenuEntry(hopTo, client.getMenuEntries(), after);
  406. }
  407. }
  408.  
  409. private void insertMenuEntry(MenuEntry newEntry, MenuEntry[] entries, boolean after)
  410. {
  411. MenuEntry[] newMenu = ObjectArrays.concat(entries, newEntry);
  412.  
  413. if (after)
  414. {
  415. int menuEntryCount = newMenu.length;
  416. ArrayUtils.swap(newMenu, menuEntryCount - 1, menuEntryCount - 2);
  417. }
  418.  
  419. client.setMenuEntries(newMenu);
  420. }
  421.  
  422. @Subscribe
  423. public void onPlayerMenuOptionClicked(PlayerMenuOptionClicked event)
  424. {
  425. if (!event.getMenuOption().equals(HOP_TO))
  426. {
  427. return;
  428. }
  429.  
  430. ChatPlayer player = getChatPlayerFromName(event.getMenuTarget());
  431.  
  432. if (player != null)
  433. {
  434. hop(player.getWorld());
  435. }
  436. }
  437.  
  438. @Subscribe
  439. public void onGameStateChanged(GameStateChanged gameStateChanged)
  440. {
  441. // If the player has disabled the side bar plugin panel, do not update the UI
  442. if (config.showSidebar() && gameStateChanged.getGameState() == GameState.LOGGED_IN)
  443. {
  444. if (lastWorld != client.getWorld())
  445. {
  446. int newWorld = client.getWorld();
  447. panel.switchCurrentHighlight(newWorld, lastWorld);
  448. lastWorld = newWorld;
  449. }
  450. }
  451. }
  452.  
  453. @Subscribe
  454. public void onWorldListLoad(WorldListLoad worldListLoad)
  455. {
  456. if (!config.showSidebar())
  457. {
  458. return;
  459. }
  460.  
  461. Map<Integer, Integer> worldData = new HashMap<>();
  462.  
  463. for (net.runelite.api.World w : worldListLoad.getWorlds())
  464. {
  465. worldData.put(w.getId(), w.getPlayerCount());
  466. }
  467.  
  468. panel.updateListData(worldData);
  469. this.lastFetch = Instant.now(); // This counts as a fetch as it updates populations
  470. }
  471.  
  472. private void tick()
  473. {
  474. Instant now = Instant.now();
  475. if (lastFetch != null && now.toEpochMilli() - lastFetch.toEpochMilli() < TICK_THROTTLE)
  476. {
  477. log.debug("Throttling world refresh tick");
  478. return;
  479. }
  480.  
  481. fetchWorlds();
  482.  
  483. // Ping worlds once at startup
  484. if (firstRun)
  485. {
  486. firstRun = false;
  487. // On first run we ping all of the worlds at once to initialize the ping values
  488. hopperExecutorService.execute(this::pingInitialWorlds);
  489. }
  490. }
  491.  
  492. void refresh()
  493. {
  494. Instant now = Instant.now();
  495. if (lastFetch != null && now.toEpochMilli() - lastFetch.toEpochMilli() < REFRESH_THROTTLE)
  496. {
  497. log.debug("Throttling world refresh");
  498. return;
  499. }
  500.  
  501. fetchWorlds();
  502. }
  503.  
  504. private void fetchWorlds()
  505. {
  506. log.debug("Fetching worlds");
  507.  
  508. try
  509. {
  510. WorldResult worldResult = new WorldClient().lookupWorlds();
  511.  
  512. if (worldResult != null)
  513. {
  514. worldResult.getWorlds().sort(Comparator.comparingInt(World::getId));
  515. this.worldResult = worldResult;
  516. this.lastFetch = Instant.now();
  517. updateList();
  518. }
  519. }
  520. catch (IOException ex)
  521. {
  522. log.warn("Error looking up worlds", ex);
  523. }
  524. }
  525.  
  526. /**
  527. * This method ONLY updates the list's UI, not the actual world list and data it displays.
  528. */
  529. private void updateList()
  530. {
  531. SwingUtilities.invokeLater(() -> panel.populate(worldResult.getWorlds()));
  532. }
  533.  
  534. private void hop(boolean previous)
  535. {
  536. if (worldResult == null || client.getGameState() != GameState.LOGGED_IN)
  537. {
  538. return;
  539. }
  540.  
  541. World currentWorld = worldResult.findWorld(client.getWorld());
  542.  
  543. if (currentWorld == null)
  544. {
  545. return;
  546. }
  547.  
  548. EnumSet<WorldType> currentWorldTypes = currentWorld.getTypes().clone();
  549. // Make it so you always hop out of PVP and high risk worlds
  550. if (config.quickhopOutOfDanger())
  551. {
  552. currentWorldTypes.remove(WorldType.PVP);
  553. currentWorldTypes.remove(WorldType.HIGH_RISK);
  554. }
  555. // Don't regard these worlds as a type that must be hopped between
  556. currentWorldTypes.remove(WorldType.BOUNTY);
  557. currentWorldTypes.remove(WorldType.SKILL_TOTAL);
  558. currentWorldTypes.remove(WorldType.LAST_MAN_STANDING);
  559.  
  560. List<World> worlds = worldResult.getWorlds();
  561.  
  562. int worldIdx = worlds.indexOf(currentWorld);
  563. int totalLevel = client.getTotalLevel();
  564.  
  565. World world;
  566. do
  567. {
  568. /*
  569. Get the previous or next world in the list,
  570. starting over at the other end of the list
  571. if there are no more elements in the
  572. current direction of iteration.
  573. */
  574. if (previous)
  575. {
  576. worldIdx--;
  577.  
  578. if (worldIdx < 0)
  579. {
  580. worldIdx = worlds.size() - 1;
  581. }
  582. }
  583. else
  584. {
  585. worldIdx++;
  586.  
  587. if (worldIdx >= worlds.size())
  588. {
  589. worldIdx = 0;
  590. }
  591. }
  592.  
  593. world = worlds.get(worldIdx);
  594.  
  595. EnumSet<WorldType> types = world.getTypes().clone();
  596. if(totalLevel >= 300)
  597. types.remove(WorldType.BOUNTY);
  598. // Treat LMS world like casual world
  599. types.remove(WorldType.LAST_MAN_STANDING);
  600. types.remove(WorldType.HIGH_RISK);
  601.  
  602. if (types.contains(WorldType.SKILL_TOTAL))
  603. {
  604. try
  605. {
  606. int totalRequirement = Integer.parseInt(world.getActivity().substring(0, world.getActivity().indexOf(" ")));
  607.  
  608. if (totalLevel >= totalRequirement && totalRequirement < 1750)
  609. {
  610. types.remove(WorldType.SKILL_TOTAL);
  611. }
  612. }
  613. catch (NumberFormatException ex)
  614. {
  615. log.warn("Failed to parse total level requirement for target world", ex);
  616. }
  617. }
  618.  
  619. // Break out if we've found a good world to hop to
  620. if (currentWorldTypes.equals(types))
  621. {
  622. break;
  623. }
  624. }
  625. while (world != currentWorld);
  626.  
  627. if (world == currentWorld)
  628. {
  629. String chatMessage = new ChatMessageBuilder()
  630. .append(ChatColorType.NORMAL)
  631. .append("Couldn't find a world to quick-hop to.")
  632. .build();
  633.  
  634. chatMessageManager.queue(QueuedMessage.builder()
  635. .type(ChatMessageType.CONSOLE)
  636. .runeLiteFormattedMessage(chatMessage)
  637. .build());
  638. }
  639. else
  640. {
  641. hop(world.getId());
  642. }
  643. }
  644.  
  645. private void hop(int worldId)
  646. {
  647. // Don't try to hop if the world doesn't exist
  648. World world = worldResult.findWorld(worldId);
  649. if (world == null)
  650. {
  651. return;
  652. }
  653.  
  654. final net.runelite.api.World rsWorld = client.createWorld();
  655. rsWorld.setActivity(world.getActivity());
  656. rsWorld.setAddress(world.getAddress());
  657. rsWorld.setId(world.getId());
  658. rsWorld.setPlayerCount(world.getPlayers());
  659. rsWorld.setLocation(world.getLocation());
  660. rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes()));
  661.  
  662. if (client.getGameState() == GameState.LOGIN_SCREEN)
  663. {
  664. // on the login screen we can just change the world by ourselves
  665. client.changeWorld(rsWorld);
  666. return;
  667. }
  668.  
  669. if (config.showWorldHopMessage())
  670. {
  671. String chatMessage = new ChatMessageBuilder()
  672. .append(ChatColorType.NORMAL)
  673. .append("Quick-hopping to World ")
  674. .append(ChatColorType.HIGHLIGHT)
  675. .append(Integer.toString(world.getId()))
  676. .append(ChatColorType.NORMAL)
  677. .append("..")
  678. .build();
  679.  
  680. chatMessageManager
  681. .queue(QueuedMessage.builder()
  682. .type(ChatMessageType.CONSOLE)
  683. .runeLiteFormattedMessage(chatMessage)
  684. .build());
  685. }
  686.  
  687. quickHopTargetWorld = rsWorld;
  688. displaySwitcherAttempts = 0;
  689. }
  690.  
  691. @Subscribe
  692. public void onGameTick(GameTick event)
  693. {
  694. if (quickHopTargetWorld == null)
  695. {
  696. return;
  697. }
  698.  
  699. if (client.getWidget(WidgetInfo.WORLD_SWITCHER_LIST) == null)
  700. {
  701. client.openWorldHopper();
  702.  
  703. if (++displaySwitcherAttempts >= DISPLAY_SWITCHER_MAX_ATTEMPTS)
  704. {
  705. String chatMessage = new ChatMessageBuilder()
  706. .append(ChatColorType.NORMAL)
  707. .append("Failed to quick-hop after ")
  708. .append(ChatColorType.HIGHLIGHT)
  709. .append(Integer.toString(displaySwitcherAttempts))
  710. .append(ChatColorType.NORMAL)
  711. .append(" attempts.")
  712. .build();
  713.  
  714. chatMessageManager
  715. .queue(QueuedMessage.builder()
  716. .type(ChatMessageType.CONSOLE)
  717. .runeLiteFormattedMessage(chatMessage)
  718. .build());
  719.  
  720. resetQuickHopper();
  721. }
  722. }
  723. else
  724. {
  725. client.hopToWorld(quickHopTargetWorld);
  726. resetQuickHopper();
  727. }
  728. }
  729.  
  730. @Subscribe
  731. public void onChatMessage(ChatMessage event)
  732. {
  733. if (event.getType() != ChatMessageType.GAMEMESSAGE)
  734. {
  735. return;
  736. }
  737.  
  738. if (event.getMessage().equals("Please finish what you're doing before using the World Switcher."))
  739. {
  740. resetQuickHopper();
  741. }
  742. }
  743.  
  744. private void resetQuickHopper()
  745. {
  746. displaySwitcherAttempts = 0;
  747. quickHopTargetWorld = null;
  748. }
  749.  
  750. private ChatPlayer getChatPlayerFromName(String name)
  751. {
  752. String cleanName = Text.removeTags(name);
  753.  
  754. // Search clan members first, because if a friend is in the clan chat but their private
  755. // chat is 'off', then the hop-to option will not get shown in the menu (issue #5679).
  756. ClanMember[] clanMembers = client.getClanMembers();
  757.  
  758. if (clanMembers != null)
  759. {
  760. for (ClanMember clanMember : clanMembers)
  761. {
  762. if (clanMember != null && clanMember.getUsername().equals(cleanName))
  763. {
  764. return clanMember;
  765. }
  766. }
  767. }
  768.  
  769. Friend[] friends = client.getFriends();
  770.  
  771. if (friends != null)
  772. {
  773. for (Friend friend : friends)
  774. {
  775. if (friend != null && friend.getName().equals(cleanName))
  776. {
  777. return friend;
  778. }
  779. }
  780. }
  781.  
  782. return null;
  783. }
  784.  
  785. /**
  786. * Ping all worlds. This takes a long time and is only run on first run.
  787. */
  788. private void pingInitialWorlds()
  789. {
  790. if (worldResult == null || !config.showSidebar() || !config.ping())
  791. {
  792. return;
  793. }
  794.  
  795. Stopwatch stopwatch = Stopwatch.createStarted();
  796.  
  797. for (World world : worldResult.getWorlds())
  798. {
  799. int ping = Ping.ping(world);
  800. SwingUtilities.invokeLater(() -> panel.updatePing(world.getId(), ping));
  801. }
  802.  
  803. stopwatch.stop();
  804.  
  805. log.debug("Done pinging worlds in {}", stopwatch.elapsed());
  806. }
  807.  
  808. /**
  809. * Ping the next world
  810. */
  811. private void pingNextWorld()
  812. {
  813. if (worldResult == null || !config.showSidebar() || !config.ping())
  814. {
  815. return;
  816. }
  817.  
  818. List<World> worlds = worldResult.getWorlds();
  819. if (worlds.isEmpty())
  820. {
  821. return;
  822. }
  823.  
  824. if (currentWorld >= worlds.size())
  825. {
  826. // Wrap back around
  827. currentWorld = 0;
  828. }
  829.  
  830. World world = worlds.get(currentWorld++);
  831.  
  832. // If we are displaying the ping overlay, there is a separate scheduled task for the current world
  833. boolean displayPing = config.displayPing() && client.getGameState() == GameState.LOGGED_IN;
  834. if (displayPing && client.getWorld() == world.getId())
  835. {
  836. return;
  837. }
  838.  
  839. int ping = Ping.ping(world);
  840. log.trace("Ping for world {} is: {}", world.getId(), ping);
  841. SwingUtilities.invokeLater(() -> panel.updatePing(world.getId(), ping));
  842. }
  843.  
  844. /**
  845. * Ping the current world for the ping overlay
  846. */
  847. private void pingCurrentWorld()
  848. {
  849. // There is no reason to ping the current world if not logged in, as the overlay doesn't draw
  850. if (worldResult == null || !config.displayPing() || client.getGameState() != GameState.LOGGED_IN)
  851. {
  852. return;
  853. }
  854.  
  855. final World currentWorld = worldResult.findWorld(client.getWorld());
  856. if (currentWorld == null)
  857. {
  858. log.debug("unable to find current world: {}", client.getWorld());
  859. return;
  860. }
  861.  
  862. currentPing = Ping.ping(currentWorld);
  863. log.trace("Ping for current world is: {}", currentPing);
  864.  
  865. SwingUtilities.invokeLater(() -> panel.updatePing(currentWorld.getId(), currentPing));
  866. }
  867. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement