Skip to content

Commit b612614

Browse files
committed
Merge branch 'main' into 4-add-mail-functionality
2 parents 40b8f3e + b05db01 commit b612614

File tree

10 files changed

+251
-0
lines changed

10 files changed

+251
-0
lines changed

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "maven"
9+
directory: "/"
10+
schedule:
11+
interval: "weekly"

src/main/java/pro/cloudnode/smp/cloudnodemsg/CloudnodeMSG.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public void onEnable() {
4949
Objects.requireNonNull(getCommand("ignore")).setExecutor(new IgnoreCommand());
5050
Objects.requireNonNull(getCommand("unignore")).setExecutor(new UnIgnoreCommand());
5151
Objects.requireNonNull(getCommand("togglemsg")).setExecutor(new ToggleMessageCommand());
52+
Objects.requireNonNull(getCommand("teammsg")).setExecutor(new TeamMessageCommand());
5253
Objects.requireNonNull(getCommand("mail")).setExecutor(new MailCommand());
5354

5455
getServer().getPluginManager().registerEvents(new AsyncChatListener(), this);

src/main/java/pro/cloudnode/smp/cloudnodemsg/Message.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ else if (sender.isOnline())
110110

111111
public static final @NotNull NamespacedKey IGNORED_PLAYERS = new NamespacedKey(CloudnodeMSG.getInstance(), "ignored");
112112
public static final @NotNull NamespacedKey CHANNEL_RECIPIENT = new NamespacedKey(CloudnodeMSG.getInstance(), "channel-recipient");
113+
public static final @NotNull NamespacedKey CHANNEL_TEAM = new NamespacedKey(CloudnodeMSG.getInstance(), "channel-team");
113114

114115
/**
115116
* Get UUID set of ignored players from PDC string
@@ -193,6 +194,7 @@ public static boolean isIncomingEnabled(final @NotNull Player player) {
193194
*/
194195
public static void createChannel(final @NotNull Player player, final @NotNull OfflinePlayer recipient) {
195196
player.getPersistentDataContainer().set(CHANNEL_RECIPIENT, PersistentDataType.STRING, recipient.getUniqueId().toString());
197+
player.getPersistentDataContainer().remove(CHANNEL_TEAM);
196198
}
197199

198200
/**
@@ -224,4 +226,32 @@ public static boolean hasChannel(final @NotNull Player player, final @NotNull Of
224226
final @NotNull Optional<@NotNull OfflinePlayer> channel = getChannel(player);
225227
return channel.isPresent() && channel.get().getUniqueId().equals(recipient.getUniqueId());
226228
}
229+
230+
/**
231+
* Team message channel
232+
*
233+
* @param player The player
234+
*/
235+
public static void createTeamChannel(final @NotNull Player player) {
236+
player.getPersistentDataContainer().set(CHANNEL_TEAM, PersistentDataType.BOOLEAN, true);
237+
player.getPersistentDataContainer().remove(CHANNEL_RECIPIENT);
238+
}
239+
240+
/**
241+
* Exit team message channel
242+
*
243+
* @param player The player
244+
*/
245+
public static void exitTeamChannel(final @NotNull Player player) {
246+
player.getPersistentDataContainer().remove(CHANNEL_TEAM);
247+
}
248+
249+
/**
250+
* Check whether player has a team message channel
251+
*
252+
* @param player The player
253+
*/
254+
public static boolean hasTeamChannel(final @NotNull Player player) {
255+
return player.getPersistentDataContainer().getOrDefault(CHANNEL_TEAM, PersistentDataType.BOOLEAN, false);
256+
}
227257
}

src/main/java/pro/cloudnode/smp/cloudnodemsg/Permission.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ public final class Permission {
88
*/
99
public final static @NotNull String USE = "cloudnodemsg.use";
1010

11+
/**
12+
* Allow using the team message command (/teammsg)
13+
*/
14+
public final static @NotNull String USE_TEAM = "cloudnodemsg.use.team";
15+
1116
/**
1217
* Allows reloading the plugin
1318
*/

src/main/java/pro/cloudnode/smp/cloudnodemsg/PluginConfig.java

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
77
import org.bukkit.OfflinePlayer;
88
import org.bukkit.configuration.file.FileConfiguration;
9+
import org.bukkit.scoreboard.Team;
910
import org.jetbrains.annotations.NotNull;
1011

1112
import java.util.HashMap;
@@ -87,6 +88,28 @@ public PluginConfig(final @NotNull FileConfiguration config) {
8788
);
8889
}
8990

91+
/**
92+
* Team message
93+
* <p>Uses the vanilla teams from `/team`</p>
94+
* <p>Placeholders:</p>
95+
* <ul>
96+
* <li>{@code <sender>} - the username of the message sender</li>
97+
* <li>{@code <team>} - team</li>
98+
* <li>{@code <message>} - the message text</li>
99+
* </ul>
100+
*
101+
* @param sender The username of the message sender
102+
* @param team The team
103+
* @param message The message text
104+
*/
105+
public @NotNull Component team(final @NotNull String sender, final @NotNull Team team, final @NotNull Component message) {
106+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("team"))
107+
.replace("<sender>", sender),
108+
Placeholder.component("team", team.displayName()),
109+
Placeholder.component("message", message)
110+
);
111+
}
112+
90113
/**
91114
* Private message format as seen by people with the spy permission and console
92115
* <p>Placeholders:</p>
@@ -108,6 +131,27 @@ public PluginConfig(final @NotNull FileConfiguration config) {
108131
);
109132
}
110133

134+
/**
135+
* Team message format as seen by people with the spy permission and console
136+
* <p>Placeholders:</p>
137+
* <ul>
138+
* <li>{@code <sender>} - the username of the message sender</li>
139+
* <li>{@code <team>} - team</li>
140+
* <li>{@code <message>} - the message text</li>
141+
* </ul>
142+
*
143+
* @param sender The username of the message sender
144+
* @param team The team
145+
* @param message The message text
146+
*/
147+
public @NotNull Component teamSpy(final @NotNull String sender, final @NotNull Team team, final @NotNull Component message) {
148+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("team-spy"))
149+
.replace("<sender>", sender),
150+
Placeholder.component("team", team.displayName()),
151+
Placeholder.component("message", message)
152+
);
153+
}
154+
111155
/**
112156
* Player has successfully been ignored
113157
* <p>Placeholders:</p>
@@ -191,6 +235,40 @@ public PluginConfig(final @NotNull FileConfiguration config) {
191235
.replace("<recipient>", Message.name(recipient)));
192236
}
193237

238+
/**
239+
* Team chat channel created
240+
* <p>Placeholders:</p>
241+
* <ul>
242+
* <li>{@code <sender>} - the username of the message sender</li>
243+
* <li>{@code <team>} - team</li>
244+
* </ul>
245+
*
246+
* @param sender The username of the message sender
247+
* @param team The team@
248+
*/
249+
public @NotNull Component channelTeamCreated(final @NotNull String sender, final @NotNull Team team) {
250+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("channel.team-created"))
251+
.replace("<sender>", sender),
252+
Placeholder.component("team", team.displayName()));
253+
}
254+
255+
/**
256+
* Team chat channel closed
257+
* <p>Placeholders:</p>
258+
* <ul>
259+
* <li>{@code <sender>} - the username of the message sender</li>
260+
* <li>{@code <team>} - team</li>
261+
* </ul>
262+
*
263+
* @param sender The username of the message sender
264+
* @param team The team
265+
*/
266+
public @NotNull Component channelTeamClosed(final @NotNull String sender, final @NotNull Team team) {
267+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("channel.team-closed"))
268+
.replace("<sender>", sender),
269+
Placeholder.component("team", team.displayName()));
270+
}
271+
194272
/**
195273
* Command usage format
196274
* <p>Placeholders:</p>
@@ -419,5 +497,12 @@ public int mailNotifyInterval() {
419497
Placeholder.unparsed("player", Message.name(player))
420498
);
421499
}
500+
501+
/**
502+
* Trying to message a team, but not in one
503+
*/
504+
public @NotNull Component notInTeam() {
505+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("errors.not-in-team")));
506+
}
422507
}
423508

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package pro.cloudnode.smp.cloudnodemsg.command;
2+
3+
import net.kyori.adventure.text.Component;
4+
import org.bukkit.command.CommandSender;
5+
import org.bukkit.entity.Player;
6+
import org.bukkit.scoreboard.Team;
7+
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
9+
import pro.cloudnode.smp.cloudnodemsg.CloudnodeMSG;
10+
import pro.cloudnode.smp.cloudnodemsg.Message;
11+
import pro.cloudnode.smp.cloudnodemsg.Permission;
12+
import pro.cloudnode.smp.cloudnodemsg.error.NoPermissionError;
13+
import pro.cloudnode.smp.cloudnodemsg.error.NotPlayerError;
14+
15+
import java.util.ArrayList;
16+
import java.util.HashSet;
17+
import java.util.List;
18+
import java.util.Optional;
19+
import java.util.Set;
20+
21+
public class TeamMessageCommand extends Command {
22+
@Override
23+
public boolean run(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
24+
if (!sender.hasPermission(Permission.USE_TEAM)) return new NoPermissionError().send(sender);
25+
if (!(sender instanceof Player player)) return new NotPlayerError().send(sender);
26+
final @NotNull Optional<@NotNull Team> team = Optional.ofNullable(player.getScoreboard().getPlayerTeam(player));
27+
if (team.isEmpty()) return sendMessage(player, CloudnodeMSG.getInstance().config().notInTeam());
28+
if (args.length == 0) {
29+
if (Message.hasTeamChannel(player)) {
30+
Message.exitTeamChannel(player);
31+
return sendMessage(player, CloudnodeMSG.getInstance().config().channelTeamClosed(player.getName(), team.get()));
32+
}
33+
else {
34+
Message.createTeamChannel(player);
35+
return sendMessage(player, CloudnodeMSG.getInstance().config().channelTeamCreated(player.getName(), team.get()));
36+
}
37+
}
38+
return sendTeamMessage(player, team.get(), Component.text(String.join(" ", args)));
39+
}
40+
41+
@Override
42+
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command command, @NotNull String label, @NotNull String[] args) {
43+
return new ArrayList<>();
44+
}
45+
46+
/**
47+
* Send message to online team members
48+
*/
49+
public static boolean sendTeamMessage(final @NotNull Player sender, final @NotNull Team team, final @NotNull Component message) {
50+
for (final @NotNull Player player : sender.getServer().getOnlinePlayers()) {
51+
if (Optional.ofNullable(player.getScoreboard().getPlayerTeam(player)).map(t -> t.equals(team)).orElse(false))
52+
sendMessage(player, CloudnodeMSG.getInstance().config().team(sender.getName(), team, message));
53+
else if (player.hasPermission(Permission.SPY)) sendMessage(player, CloudnodeMSG.getInstance().config().teamSpy(sender.getName(), team, message));
54+
}
55+
sender.getServer().getConsoleSender().sendMessage(CloudnodeMSG.getInstance().config().teamSpy(sender.getName(), team, message));
56+
57+
return true;
58+
}
59+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package pro.cloudnode.smp.cloudnodemsg.error;
2+
3+
import pro.cloudnode.smp.cloudnodemsg.CloudnodeMSG;
4+
5+
/**
6+
* Only players can use this command
7+
*/
8+
public final class NotInTeamError extends Error {
9+
/**
10+
* Only players can use this command
11+
*/
12+
public NotInTeamError() {
13+
super(CloudnodeMSG.getInstance().config().notInTeam());
14+
}
15+
}

src/main/java/pro/cloudnode/smp/cloudnodemsg/listener/AsyncChatListener.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import org.bukkit.event.EventHandler;
99
import org.bukkit.event.EventPriority;
1010
import org.bukkit.event.Listener;
11+
import org.bukkit.scoreboard.Team;
1112
import org.jetbrains.annotations.NotNull;
1213
import pro.cloudnode.smp.cloudnodemsg.CloudnodeMSG;
1314
import pro.cloudnode.smp.cloudnodemsg.Permission;
15+
import pro.cloudnode.smp.cloudnodemsg.command.TeamMessageCommand;
1416
import pro.cloudnode.smp.cloudnodemsg.error.InvalidPlayerError;
1517
import pro.cloudnode.smp.cloudnodemsg.Message;
1618

@@ -57,4 +59,18 @@ public void channels(final @NotNull AsyncChatEvent event) {
5759
e.log().send(sender);
5860
}
5961
}
62+
63+
@EventHandler (priority = EventPriority.HIGHEST)
64+
public void teamChannel(final @NotNull AsyncChatEvent event) {
65+
final @NotNull Player sender = event.getPlayer();
66+
if (!Message.hasTeamChannel(sender)) return;
67+
event.setCancelled(true);
68+
final @NotNull Optional<@NotNull Team> team = Optional.ofNullable(sender.getScoreboard().getPlayerTeam(sender));
69+
if (team.isEmpty()) {
70+
Message.exitTeamChannel(sender);
71+
sender.sendMessage(CloudnodeMSG.getInstance().config().notInTeam());
72+
return;
73+
}
74+
TeamMessageCommand.sendTeamMessage(sender, team.get(), event.message());
75+
}
6076
}

src/main/resources/config.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,22 @@ incoming: '<click:suggest_command:/msg <sender> ><dark_gray>[<#60a5fa><sender></
4141
# Same placeholders as incoming
4242
outgoing: '<click:suggest_command:/msg <recipient> ><dark_gray>[<#93c5fd>me</#93c5fd> <white>-></white> <#60a5fa><recipient></#60a5fa>]</dark_gray></click> <reset><#dbeafe><message></#dbeafe>'
4343

44+
# Team message
45+
# Uses the vanilla teams from `/team`
46+
# Placeholders:
47+
# <sender> - the username of the message sender
48+
# <team> - team display name
49+
# <message> - the message text
50+
team: '<click:suggest_command:/tm ><dark_gray>[<white><team></white>] <gray><sender></gray>:</dark_gray> <white><message></white></click>'
51+
4452
# Private message format as seen by people with the spy permission and console
4553
# Same placeholders as incoming
4654
spy: '<dark_gray>[SPY] [<click:suggest_command:/msg <sender> ><gray><sender></gray></click> -> <click:suggest_command:/msg <recipient> ><gray><recipient></gray></click>] <gray><message></gray></dark_gray>'
4755

56+
# Team message format as seen by people with the spy permission and console
57+
# Same placeholders as team
58+
team-spy: '<dark_gray>[SPY]</dark_gray> <dark_gray>[<white><team></white>] <gray><click:suggest_command:/msg <sender> ><sender></click></gray>:</dark_gray> <gray><message></gray>'
59+
4860
# Player has successfully been ignored
4961
# Placeholders:
5062
# <player> - the player's username
@@ -72,6 +84,16 @@ channel:
7284
# <recipient> - the username of the message recipient
7385
offline: <red>(!) Player <gray><recipient></gray> is offline. Your chat messages have been switched back to <gray>public</gray>.</red>
7486

87+
# Team chat channel created
88+
# Placeholders:
89+
# <sender> - the username of the message sender
90+
# <team> - team display name
91+
team-created: <green>(!) Your chat messages will now be sent as private team messages in <gray><team></gray>. To re-enable public messages, run <click:suggest_command:/teammsg><gray>/teammsg</gray></click></green>
92+
93+
# Team chat channel closed
94+
# Same placeholders as created
95+
team-closed: <yellow>(!) Your chat messages will now be <gray>public</gray>.</yellow>
96+
7597
# Name for console/server that should appear as <sender> or <recipient> in messages
7698
console-name: "Server"
7799

@@ -166,3 +188,6 @@ errors:
166188
# Placeholders:
167189
# <player> - the player's username
168190
incoming-disabled: "<red>(!) You cannot message <gray><player></gray> because they have disabled private messages.</red>"
191+
192+
# Trying to message a team, but not in one
193+
not-in-team: "<red>(!) You are not in a team.</red>"

src/main/resources/plugin.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ commands:
2727
description: Toggles private messages from a player
2828
usage: /<command> <player>
2929
aliases: [ "toggledms", "togglepms" ]
30+
teammsg:
31+
description: Send a private message to your teammates
32+
usage: /<command> <message>
33+
aliases: [ "tmsg", "teamchat" , "tm" ]
3034
mail:
3135
description: Send and receive offline messages
3236
usage: /<command>

0 commit comments

Comments
 (0)