diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 2569ffc..c90d886 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -50,6 +50,7 @@
+
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index 6e6eec1..79ee123 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,6 +1,5 @@
-
\ No newline at end of file
diff --git a/src/main/java/pro/cloudnode/smp/cloudnodemsg/Message.java b/src/main/java/pro/cloudnode/smp/cloudnodemsg/Message.java
index 3d00820..9947814 100644
--- a/src/main/java/pro/cloudnode/smp/cloudnodemsg/Message.java
+++ b/src/main/java/pro/cloudnode/smp/cloudnodemsg/Message.java
@@ -89,6 +89,17 @@ public void send(final @NotNull Context context) throws InvalidPlayerError {
setReplyTo(sender, recipient);
if (recipient.getUniqueId().equals(console.getUniqueId()) || (recipientPlayer.isPresent() && !Message.hasChannel(recipientPlayer.get(), sender)))
setReplyTo(recipient, sender);
+
+ senderPlayer.ifPresent(player -> CloudnodeMSG.getInstance()
+ .config()
+ .sound(PluginConfig.SoundEvent.PERSONAL_OUTGOING)
+ .ifPresent(sound -> sound.play(player))
+ );
+ recipientPlayer.ifPresent(player -> CloudnodeMSG.getInstance()
+ .config()
+ .sound(PluginConfig.SoundEvent.PERSONAL_INCOMING)
+ .ifPresent(sound -> sound.play(player))
+ );
}
public final static @NotNull OfflinePlayer console = CloudnodeMSG.getInstance().getServer()
@@ -315,7 +326,7 @@ public static boolean hasTeamChannel(final @NotNull Player player) {
/**
* The context in which this message is sent
*/
- public static enum Context {
+ public enum Context {
/**
* Message sent via command (i.e. no special context)
*/
diff --git a/src/main/java/pro/cloudnode/smp/cloudnodemsg/PluginConfig.java b/src/main/java/pro/cloudnode/smp/cloudnodemsg/PluginConfig.java
index 2aa305e..3e3bb77 100644
--- a/src/main/java/pro/cloudnode/smp/cloudnodemsg/PluginConfig.java
+++ b/src/main/java/pro/cloudnode/smp/cloudnodemsg/PluginConfig.java
@@ -12,7 +12,10 @@
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
+import org.bukkit.NamespacedKey;
import org.bukkit.OfflinePlayer;
+import org.bukkit.Registry;
+import org.bukkit.Sound;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.Team;
@@ -356,6 +359,34 @@ public PluginConfig(final @NotNull FileConfiguration config) {
));
}
+ public @NotNull Optional<@NotNull ConfiguredSound> sound(final @NotNull SoundEvent event) {
+ final @Nullable String name = config.getString(String.format("sound.%s.sound", event.key));
+ if (name == null || name.isBlank() || name.equalsIgnoreCase("null") || name.equalsIgnoreCase("none")) {
+ return Optional.empty();
+ }
+
+ final @Nullable NamespacedKey key = name.indexOf(':') > -1
+ ? NamespacedKey.fromString(name)
+ : NamespacedKey.minecraft(name);
+
+ if (key == null) {
+ CloudnodeMSG.getInstance().getLogger().warning(String.format("Invalid sound identifier ‘%s’ for sound event ‘%s’", name, event.key));
+ return Optional.empty();
+ }
+
+ final @Nullable Sound sound = Registry.SOUNDS.get(key);
+
+ if (sound == null) {
+ CloudnodeMSG.getInstance().getLogger().warning(String.format("Unknown sound ‘%s’ for sound event ‘%s’", name, event.key));
+ return Optional.empty();
+ }
+
+ final float volume = (float) config.getDouble(String.format("sound.%s.volume", event.key), 1.0);
+ final float pitch = (float) config.getDouble(String.format("sound.%s.pitch", event.key), 1.0);
+
+ return Optional.of(new ConfiguredSound(sound, volume, pitch));
+ }
+
/**
* No permission
*/
@@ -476,5 +507,23 @@ public PluginConfig(final @NotNull FileConfiguration config) {
public @NotNull Component notInTeam() {
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("errors.not-in-team")));
}
-}
+ public enum SoundEvent {
+ PERSONAL_INCOMING("personal.incoming"),
+ PERSONAL_OUTGOING("personal.outgoing"),
+ TEAM_INCOMING("team.incoming"),
+ TEAM_OUTGOING("team.outgoing");
+
+ public final @NotNull String key;
+
+ SoundEvent(final @NotNull String key) {
+ this.key = key;
+ }
+ }
+
+ public record ConfiguredSound(@NotNull Sound sound, float volume, float pitch) {
+ public void play(final @NotNull Player player) {
+ player.playSound(player, sound, volume, pitch);
+ }
+ }
+}
diff --git a/src/main/java/pro/cloudnode/smp/cloudnodemsg/command/TeamMessageCommand.java b/src/main/java/pro/cloudnode/smp/cloudnodemsg/command/TeamMessageCommand.java
index 0d377ba..a85a6ef 100644
--- a/src/main/java/pro/cloudnode/smp/cloudnodemsg/command/TeamMessageCommand.java
+++ b/src/main/java/pro/cloudnode/smp/cloudnodemsg/command/TeamMessageCommand.java
@@ -9,6 +9,7 @@
import pro.cloudnode.smp.cloudnodemsg.CloudnodeMSG;
import pro.cloudnode.smp.cloudnodemsg.Message;
import pro.cloudnode.smp.cloudnodemsg.Permissions;
+import pro.cloudnode.smp.cloudnodemsg.PluginConfig;
import pro.cloudnode.smp.cloudnodemsg.error.NoPermissionError;
import pro.cloudnode.smp.cloudnodemsg.error.NotInTeamError;
import pro.cloudnode.smp.cloudnodemsg.error.NotPlayerError;
@@ -48,7 +49,19 @@ public boolean run(final @NotNull CommandSender sender, final @NotNull String la
* Send message to online team members
*/
public static boolean sendTeamMessage(final @NotNull Player sender, final @NotNull Team team, final @NotNull Component message) {
+ CloudnodeMSG.getInstance()
+ .config()
+ .sound(PluginConfig.SoundEvent.TEAM_OUTGOING)
+ .ifPresent(sound -> sound.play(sender));
+
for (final @NotNull Player player : sender.getServer().getOnlinePlayers()) {
+ if (!sender.getUniqueId().equals(player.getUniqueId())) {
+ CloudnodeMSG.getInstance()
+ .config()
+ .sound(PluginConfig.SoundEvent.TEAM_INCOMING)
+ .ifPresent(sound -> sound.play(player));
+ }
+
if (Message.isIgnored(player, sender)) continue;
if (Optional.ofNullable(player.getScoreboard().getPlayerTeam(player)).map(t -> t.equals(team))
.orElse(false))
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 6012eb5..7f52e55 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -3,11 +3,11 @@
# - the username of the message sender
# - the username of the message recipient
# - the message text
-incoming: ' >[<#60a5fa>#60a5fa> -> <#bfdbfe>me#bfdbfe>]<#dbeafe>#dbeafe>'
+incoming: >[<#60a5fa>#60a5fa> -> <#bfdbfe>me#bfdbfe>]<#dbeafe>#dbeafe>
# Outgoing message format (sender's point of view)
# Same placeholders as incoming
-outgoing: ' >[<#93c5fd>me#93c5fd> -> <#60a5fa>#60a5fa>]<#dbeafe>#dbeafe>'
+outgoing: >[<#93c5fd>me#93c5fd> -> <#60a5fa>#60a5fa>]<#dbeafe>#dbeafe>
# Team message
# Uses the vanilla teams from `/team`
@@ -15,24 +15,24 @@ outgoing: ' >[<#93c5fd>me#93
# - the username of the message sender
# - team display name
# - the message text
-team: '[] :'
+team: [] :
# Private message format as seen by people with the spy permission and console
# Same placeholders as incoming
-spy: '[SPY] [ > -> >] '
+spy: [SPY] [ > -> >]
# Team message format as seen by people with the spy permission and console
# Same placeholders as team
-team-spy: '[SPY][] >:'
+team-spy: [SPY][] >:
# Player has successfully been ignored
# Placeholders:
# - the player's username
-ignored: "(!) You will no longer see messages from ."
+ignored: (!) You will no longer see messages from .
# Player has successfully been unignored
# Same placeholders as ignored
-unignored: "(!) You are no longer ignoring ."
+unignored: (!) You are no longer ignoring .
channel:
# Message channel created
@@ -63,30 +63,30 @@ channel:
team-closed: (!) Your chat messages will now be public.
# Name for console/server that should appear as or in messages
-console-name: "Server"
+console-name: Server
# Command usage format
# Placeholders:
# - the command name
# - the command usage parameters
-usage: "(!) Usage:/"
+usage: (!) Usage:/
# Plugin reloaded
-reloaded: "(!) Plugin successfully reloaded."
+reloaded: (!) Plugin successfully reloaded.
toggle:
disable:
# Disable private messages
- message: "(!) Receiving private messages is now disabled. Run again to re-enable."
+ message: (!) Receiving private messages is now disabled. Run again to re-enable.
# Placeholders:
# - the player's username
- other: "(!) Receiving private messages now disabled for ."
+ other: (!) Receiving private messages now disabled for .
enable:
# Enable private messages
- message: "(!) You can now receive private messages again."
+ message: (!) You can now receive private messages again.
# Placeholders:
# - the player's username
- other: "(!) Re-enabled receiving of private messages for ."
+ other: (!) Re-enabled receiving of private messages for .
# Set custom global/public chat format. Disabled by default.
#
@@ -102,53 +102,85 @@ toggle:
#chat-format: [] '>:
chat-format: null
+# Play a sound…
+sound:
+ personal:
+ # …when receiving a private message
+ incoming:
+ # The ID of the sound.
+ # Set to null, none, or "" to disable.
+ sound: entity.chicken.egg
+
+ # Volume of the sound from 0.0 to 1.0. Decrease to be quieter.
+ volume: 1.0
+
+ # Pitch of the sound from 0.5 to 2.0.
+ # Optional: defaults to 1.0.
+ # Values below 1.0 lower the pitch and increase the duration;
+ # values above 1.0 raise the pitch and reduce the duration.
+ pitch: 0.82
+
+ # …when sending a private message
+ outgoing:
+ sound: null
+
+ team:
+ # …when receiving a team message
+ incoming:
+ sound: ui.hud.bubble_pop
+ pitch: .7
+
+ # …when sending a team message
+ outgoing:
+ sound: null
+
# Error messages
errors:
# No permission
- no-permission: "(!) You don't have permission to use this command."
+ no-permission: (!) You don't have permission to use this command.
# Player has no username (somehow)
- invalid-player: "(!) Invalid player."
+ invalid-player: (!) Invalid player.
# Player not found
# Placeholders:
# - the player's username
- player-not-found: "(!) Player not found."
+ player-not-found: (!) Player not found.
- message-yourself: "(!) You can't send a message to yourself."
+ message-yourself: (!) You can't send a message to yourself.
- nobody-reply: "(!) You have no one to reply to."
+ nobody-reply: (!) You have no one to reply to.
# The player that messaged you is no longer online
# Placeholders:
# - the player's username
- reply-offline: "(!) Player is no longer online."
+ reply-offline: (!) Player is no longer online.
# Only players can use this command
- not-player: "(!) You must be a player to use this command."
+ not-player: (!) You must be a player to use this command.
# That player is not ignored
# Placeholders:
# - the player's username
- not-ignored: "(!) You are not ignoring that player."
+ not-ignored: (!) You are not ignoring that player.
# Player cannot be ignored
# Placeholders:
# - the player's username
- cannot-ignore: "(!) You cannot ignore ."
+ cannot-ignore: (!) You cannot ignore .
# You are trying to ignore yourself
- ignore-yourself: "(!) You cannot ignore yourself."
+ ignore-yourself: (!) You cannot ignore yourself.
# Target player has never joined the server
# Placeholders:
# - the player's username
- never-joined: "(!) has never joined this server."
+ never-joined: (!) has never joined this server.
# Target player have disabled their incoming private messages.
# Placeholders:
# - the player's username
- incoming-disabled: "(!) You cannot message because they have disabled private messages."
+ incoming-disabled: (!) You cannot message because they have disabled private messages.
# Trying to message a team, but not in one
- not-in-team: "(!) You are not in a team."
+ not-in-team: (!) You are not in a team.