Merge remote-tracking branch 'runelite/master'
This commit is contained in:
@@ -32,6 +32,9 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.TrayIcon;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
@@ -42,6 +45,13 @@ import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Singleton;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
@@ -60,6 +70,23 @@ import net.runelite.client.util.OSType;
|
||||
@Slf4j
|
||||
public class Notifier
|
||||
{
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum NativeCustomOff
|
||||
{
|
||||
NATIVE("Native"),
|
||||
CUSTOM("Custom"),
|
||||
OFF("Off");
|
||||
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// Default timeout of notification in milliseconds
|
||||
private static final int DEFAULT_TIMEOUT = 10000;
|
||||
private static final String DOUBLE_QUOTE = "\"";
|
||||
@@ -127,9 +154,13 @@ public class Notifier
|
||||
sendNotification(appName, message, type);
|
||||
}
|
||||
|
||||
if (runeLiteConfig.enableNotificationSound())
|
||||
switch (runeLiteConfig.notificationSound())
|
||||
{
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
case NATIVE:
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
break;
|
||||
case CUSTOM:
|
||||
executorService.submit(this::playCustomSound);
|
||||
}
|
||||
|
||||
if (runeLiteConfig.enableGameMessageNotification() && client.getGameState() == GameState.LOGGED_IN)
|
||||
@@ -366,4 +397,48 @@ public class Notifier
|
||||
return "normal";
|
||||
}
|
||||
}
|
||||
|
||||
private void playCustomSound()
|
||||
{
|
||||
Clip clip = null;
|
||||
|
||||
// Try to load the user sound from ~/.runelite/notification.wav
|
||||
File file = new File(RuneLite.RUNELITE_DIR, "notification.wav");
|
||||
if (file.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
InputStream fileStream = new BufferedInputStream(new FileInputStream(file));
|
||||
try (AudioInputStream sound = AudioSystem.getAudioInputStream(fileStream))
|
||||
{
|
||||
clip = AudioSystem.getClip();
|
||||
clip.open(sound);
|
||||
}
|
||||
}
|
||||
catch (UnsupportedAudioFileException | IOException | LineUnavailableException e)
|
||||
{
|
||||
clip = null;
|
||||
log.warn("Unable to play notification sound", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (clip == null)
|
||||
{
|
||||
// Otherwise load from the classpath
|
||||
InputStream fileStream = new BufferedInputStream(Notifier.class.getResourceAsStream("notification.wav"));
|
||||
try (AudioInputStream sound = AudioSystem.getAudioInputStream(fileStream))
|
||||
{
|
||||
clip = AudioSystem.getClip();
|
||||
clip.open(sound);
|
||||
}
|
||||
catch (UnsupportedAudioFileException | IOException | LineUnavailableException e)
|
||||
{
|
||||
log.warn("Unable to play builtin notification sound", e);
|
||||
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
return;
|
||||
}
|
||||
}
|
||||
clip.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ package net.runelite.client.config;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.ui.ContainableFrame;
|
||||
|
||||
@ConfigGroup("runelite")
|
||||
@@ -213,14 +214,14 @@ public interface RuneLiteConfig extends Config
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "notificationSound",
|
||||
name = "Enable sound on notifications",
|
||||
name = "Notification sound",
|
||||
description = "Enables the playing of a beep sound when notifications are displayed",
|
||||
position = 16,
|
||||
titleSection = "notificationsTitle"
|
||||
)
|
||||
default boolean enableNotificationSound()
|
||||
default Notifier.NativeCustomOff notificationSound()
|
||||
{
|
||||
return true;
|
||||
return Notifier.NativeCustomOff.NATIVE;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
|
||||
@@ -148,4 +148,15 @@ public interface ClanChatConfig extends Config
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "confirmKicks",
|
||||
name = "Confirm Kicks",
|
||||
description = "Shows a chat prompt to confirm kicks",
|
||||
position = 10
|
||||
)
|
||||
default boolean confirmKicks()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ package net.runelite.client.plugins.clanchat;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.Runnables;
|
||||
import com.google.inject.Provides;
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -74,6 +75,7 @@ import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.events.ConfigChanged;
|
||||
import net.runelite.client.game.ClanManager;
|
||||
import net.runelite.client.game.SpriteManager;
|
||||
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_OPAQUE_BACKGROUND;
|
||||
@@ -120,6 +122,9 @@ public class ClanChatPlugin extends Plugin
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private ChatboxPanelManager chatboxPanelManager;
|
||||
|
||||
private List<String> chats = new ArrayList<>();
|
||||
private ClanChatIndicator clanMemberCounter;
|
||||
private int clanJoinedTick;
|
||||
@@ -134,6 +139,8 @@ public class ClanChatPlugin extends Plugin
|
||||
private boolean clanTabChat;
|
||||
private String clanname;
|
||||
|
||||
private boolean kickConfirmed = false;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static CopyOnWriteArrayList<Player> getClanMembers()
|
||||
{
|
||||
@@ -521,14 +528,37 @@ public class ClanChatPlugin extends Plugin
|
||||
@Subscribe
|
||||
private void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent)
|
||||
{
|
||||
if (!scriptCallbackEvent.getEventName().equalsIgnoreCase("clanchatInput"))
|
||||
switch (scriptCallbackEvent.getEventName())
|
||||
{
|
||||
return;
|
||||
}
|
||||
case "clanchatInput":
|
||||
{
|
||||
final int[] intStack = client.getIntStack();
|
||||
final int size = client.getIntStackSize();
|
||||
intStack[size - 1] = config.clanTabChat() ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
case "confirmClanKick":
|
||||
{
|
||||
if (!config.confirmKicks() || kickConfirmed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
final int[] intStack = client.getIntStack();
|
||||
final int size = client.getIntStackSize();
|
||||
intStack[size - 1] = this.clanTabChat ? 1 : 0;
|
||||
// Set a flag so the script doesn't instantly kick them
|
||||
final int[] intStack = client.getIntStack();
|
||||
final int size = client.getIntStackSize();
|
||||
intStack[size - 1] = 1;
|
||||
|
||||
// Get name of player we are trying to kick
|
||||
final String[] stringStack = client.getStringStack();
|
||||
final int stringSize = client.getStringStackSize();
|
||||
final String kickPlayerName = stringStack[stringSize - 1];
|
||||
|
||||
// Show a chatbox panel confirming the kick
|
||||
clientThread.invokeLater(() -> confirmKickPlayer(kickPlayerName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getClanAmount()
|
||||
@@ -642,6 +672,21 @@ public class ClanChatPlugin extends Plugin
|
||||
clanMemberCounter = null;
|
||||
}
|
||||
|
||||
private void confirmKickPlayer(final String kickPlayerName)
|
||||
{
|
||||
chatboxPanelManager.openTextMenuInput("Attempting to kick: " + kickPlayerName)
|
||||
.option("1. Confirm kick", () ->
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
kickConfirmed = true;
|
||||
client.runScript(ScriptID.CLAN_SEND_KICK, kickPlayerName);
|
||||
kickConfirmed = false;
|
||||
})
|
||||
)
|
||||
.option("2. Cancel", Runnables::doNothing)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void addClanCounter()
|
||||
{
|
||||
if (!this.showClanCounter || clanMemberCounter != null || clanMembers.isEmpty())
|
||||
|
||||
@@ -26,28 +26,33 @@
|
||||
package net.runelite.client.plugins.devtools;
|
||||
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.TrayIcon;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
class DevToolsPanel extends PluginPanel
|
||||
{
|
||||
private final Client client;
|
||||
private final Notifier notifier;
|
||||
private final DevToolsPlugin plugin;
|
||||
|
||||
private final WidgetInspector widgetInspector;
|
||||
private final VarInspector varInspector;
|
||||
|
||||
@Inject
|
||||
private DevToolsPanel(Client client, DevToolsPlugin plugin, WidgetInspector widgetInspector, VarInspector varInspector)
|
||||
private DevToolsPanel(Client client, DevToolsPlugin plugin, WidgetInspector widgetInspector, VarInspector varInspector, Notifier notifier)
|
||||
{
|
||||
super();
|
||||
this.client = client;
|
||||
this.plugin = plugin;
|
||||
this.widgetInspector = widgetInspector;
|
||||
this.varInspector = varInspector;
|
||||
this.notifier = notifier;
|
||||
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
@@ -135,6 +140,13 @@ class DevToolsPanel extends PluginPanel
|
||||
|
||||
container.add(plugin.getSoundEffects());
|
||||
|
||||
final JButton notificationBtn = new JButton("Notification");
|
||||
notificationBtn.addActionListener(e ->
|
||||
{
|
||||
notifier.notify("Wow!", TrayIcon.MessageType.ERROR);
|
||||
});
|
||||
container.add(notificationBtn);
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ enum ItemIdentification
|
||||
RANARR_SEED(Type.SEED, "Ranarr", "R", ItemID.RANARR_SEED),
|
||||
TOADFLAX_SEED(Type.SEED, "Toad", "TOA", ItemID.TOADFLAX_SEED),
|
||||
IRIT_SEED(Type.SEED, "Irit", "I", ItemID.IRIT_SEED),
|
||||
AVANTOE_SEED(Type.SEED, "Avantoe", "A", ItemID.AVANTOE_SEED),
|
||||
AVANTOE_SEED(Type.SEED, "Avan", "A", ItemID.AVANTOE_SEED),
|
||||
KWUARM_SEED(Type.SEED, "Kwuarm", "K", ItemID.KWUARM_SEED),
|
||||
SNAPDRAGON_SEED(Type.SEED, "Snap", "S", ItemID.SNAPDRAGON_SEED),
|
||||
CADANTINE_SEED(Type.SEED, "Cadan", "C", ItemID.CADANTINE_SEED),
|
||||
@@ -56,7 +56,7 @@ enum ItemIdentification
|
||||
RANARR(Type.HERB, "Ranarr", "R", ItemID.RANARR_WEED, ItemID.GRIMY_RANARR_WEED),
|
||||
TOADFLAX(Type.HERB, "Toad", "TOA", ItemID.TOADFLAX, ItemID.GRIMY_TOADFLAX),
|
||||
IRIT(Type.HERB, "Irit", "I", ItemID.IRIT_LEAF, ItemID.GRIMY_IRIT_LEAF),
|
||||
AVANTOE(Type.HERB, "Avantoe", "A", ItemID.AVANTOE, ItemID.GRIMY_AVANTOE),
|
||||
AVANTOE(Type.HERB, "Avan", "A", ItemID.AVANTOE, ItemID.GRIMY_AVANTOE),
|
||||
KWUARM(Type.HERB, "Kwuarm", "K", ItemID.KWUARM, ItemID.GRIMY_KWUARM),
|
||||
SNAPDRAGON(Type.HERB, "Snap", "S", ItemID.SNAPDRAGON, ItemID.GRIMY_SNAPDRAGON),
|
||||
CADANTINE(Type.HERB, "Cadan", "C", ItemID.CADANTINE, ItemID.GRIMY_CADANTINE),
|
||||
|
||||
@@ -129,7 +129,7 @@ public class SlayerPlugin extends Plugin
|
||||
//NPC messages
|
||||
private static final Pattern NPC_ASSIGN_MESSAGE = Pattern.compile(".*(?:Your new task is to kill|You are to bring balance to)\\s*(?<amount>\\d+) (?<name>.+?)(?: (?:in|on|south of) (?:the )?(?<location>.+))?\\.");
|
||||
private static final Pattern NPC_ASSIGN_BOSS_MESSAGE = Pattern.compile("^Excellent. You're now assigned to kill (?:the )?(.*) (\\d+) times.*Your reward point tally is (.*)\\.$");
|
||||
private static final Pattern NPC_ASSIGN_FIRST_MESSAGE = Pattern.compile("^We'll start you off hunting (.*), you'll need to kill (\\d*) of them.");
|
||||
private static final Pattern NPC_ASSIGN_FIRST_MESSAGE = Pattern.compile("^We'll start you off (?:hunting|bringing balance to) (.*), you'll need to kill (\\d*) of them\\.$");
|
||||
private static final Pattern NPC_CURRENT_MESSAGE = Pattern.compile("^You're still (?:hunting|bringing balance to) (?<name>.+)(?: (?:in|on|south of) (?:the )?(?<location>.+), with|; you have) (?<amount>\\d+) to go\\..*");
|
||||
|
||||
private static final int GROTESQUE_GUARDIANS_REGION = 6727;
|
||||
|
||||
@@ -172,6 +172,7 @@ public class TwitchPlugin extends Plugin implements TwitchListener, ChatboxInput
|
||||
.sender("Twitch")
|
||||
.name(sender)
|
||||
.runeLiteFormattedMessage(chatMessage)
|
||||
.timestamp((int) (System.currentTimeMillis() / 1000))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -28,14 +28,16 @@ package net.runelite.client.plugins.woodcutting;
|
||||
import java.time.Instant;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
class TreeRespawn
|
||||
{
|
||||
private final Tree tree;
|
||||
private final LocalPoint location;
|
||||
private final int lenX;
|
||||
private final int lenY;
|
||||
private final WorldPoint worldLocation;
|
||||
private final Instant startTime;
|
||||
private final int respawnTime;
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ import net.runelite.api.GameObject;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.MenuOpcode;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.AnimationChanged;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameObjectChanged;
|
||||
@@ -217,8 +219,12 @@ public class WoodcuttingPlugin extends Plugin
|
||||
{
|
||||
if (tree.getRespawnTime() != null && !recentlyLoggedIn)
|
||||
{
|
||||
Point max = object.getSceneMaxLocation();
|
||||
Point min = object.getSceneMinLocation();
|
||||
int lenX = max.getX() - min.getX();
|
||||
int lenY = max.getY() - min.getY();
|
||||
log.debug("Adding respawn timer for {} tree at {}", tree, object.getLocalLocation());
|
||||
TreeRespawn treeRespawn = new TreeRespawn(tree, object.getLocalLocation(), Instant.now(), (int) tree.getRespawnTime().toMillis());
|
||||
TreeRespawn treeRespawn = new TreeRespawn(tree, lenX, lenY, WorldPoint.fromScene(client, min.getX(), min.getY(), client.getPlane()), Instant.now(), (int) tree.getRespawnTime().toMillis());
|
||||
respawns.add(treeRespawn);
|
||||
}
|
||||
|
||||
@@ -240,9 +246,9 @@ public class WoodcuttingPlugin extends Plugin
|
||||
{
|
||||
switch (event.getGameState())
|
||||
{
|
||||
case LOADING:
|
||||
case HOPPING:
|
||||
respawns.clear();
|
||||
case LOADING:
|
||||
treeObjects.clear();
|
||||
break;
|
||||
case LOGGED_IN:
|
||||
|
||||
@@ -103,10 +103,17 @@ class WoodcuttingTreesOverlay extends Overlay
|
||||
Instant now = Instant.now();
|
||||
for (TreeRespawn treeRespawn : respawns)
|
||||
{
|
||||
LocalPoint loc = treeRespawn.getLocation();
|
||||
LocalPoint minLocation = LocalPoint.fromWorld(client, treeRespawn.getWorldLocation());
|
||||
if (minLocation == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LocalPoint centeredLocation = new LocalPoint(
|
||||
minLocation.getX() + treeRespawn.getLenX() * Perspective.LOCAL_HALF_TILE_SIZE,
|
||||
minLocation.getY() + treeRespawn.getLenY() * Perspective.LOCAL_HALF_TILE_SIZE);
|
||||
float percent = (now.toEpochMilli() - treeRespawn.getStartTime().toEpochMilli()) / (float) treeRespawn.getRespawnTime();
|
||||
Point point = Perspective.localToCanvas(client, loc, client.getPlane());
|
||||
Point point = Perspective.localToCanvas(client, centeredLocation, client.getPlane());
|
||||
if (point == null || percent > 1.0f)
|
||||
{
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user