Skip to content

Commit 9e357e9

Browse files
authored
Merge branch 'main' into 28-improve-release-workflow
2 parents 55f04b4 + b05db01 commit 9e357e9

17 files changed

+805
-151
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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
import pro.cloudnode.smp.cloudnodemsg.command.MainCommand;
99
import pro.cloudnode.smp.cloudnodemsg.command.MessageCommand;
1010
import pro.cloudnode.smp.cloudnodemsg.command.ReplyCommand;
11+
import pro.cloudnode.smp.cloudnodemsg.command.TeamMessageCommand;
1112
import pro.cloudnode.smp.cloudnodemsg.command.UnIgnoreCommand;
1213
import pro.cloudnode.smp.cloudnodemsg.listener.AsyncChatListener;
14+
import pro.cloudnode.smp.cloudnodemsg.command.ToggleMessageCommand;
1315

1416
import java.util.Objects;
1517

@@ -33,6 +35,8 @@ public void onEnable() {
3335
Objects.requireNonNull(getCommand("reply")).setExecutor(new ReplyCommand());
3436
Objects.requireNonNull(getCommand("ignore")).setExecutor(new IgnoreCommand());
3537
Objects.requireNonNull(getCommand("unignore")).setExecutor(new UnIgnoreCommand());
38+
Objects.requireNonNull(getCommand("togglemsg")).setExecutor(new ToggleMessageCommand());
39+
Objects.requireNonNull(getCommand("teammsg")).setExecutor(new TeamMessageCommand());
3640

3741
getServer().getPluginManager().registerEvents(new AsyncChatListener(), this);
3842
}
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
package pro.cloudnode.smp.cloudnodemsg;
2+
3+
import net.kyori.adventure.text.Component;
4+
import org.bukkit.NamespacedKey;
5+
import org.bukkit.OfflinePlayer;
6+
import org.bukkit.command.CommandSender;
7+
import org.bukkit.entity.Player;
8+
import org.bukkit.persistence.PersistentDataType;
9+
import org.jetbrains.annotations.NotNull;
10+
import org.jetbrains.annotations.Nullable;
11+
import pro.cloudnode.smp.cloudnodemsg.error.InvalidPlayerError;
12+
13+
import java.util.Arrays;
14+
import java.util.HashSet;
15+
import java.util.Objects;
16+
import java.util.Optional;
17+
import java.util.UUID;
18+
19+
public final class Message {
20+
private final @NotNull OfflinePlayer sender;
21+
private final @NotNull OfflinePlayer recipient;
22+
private final @NotNull Component message;
23+
24+
public Message(@NotNull OfflinePlayer sender, @NotNull OfflinePlayer recipient, @NotNull Component message) {
25+
this.sender = sender;
26+
this.recipient = recipient;
27+
this.message = message;
28+
}
29+
30+
public Message(@NotNull OfflinePlayer sender, @NotNull OfflinePlayer recipient, @NotNull String message) {
31+
this(sender, recipient, Component.text(message));
32+
}
33+
34+
private @NotNull String playerOrServerUsername(final @NotNull OfflinePlayer player) throws InvalidPlayerError {
35+
if (player.getUniqueId().equals(console.getUniqueId()))
36+
return CloudnodeMSG.getInstance().config().consoleName();
37+
else {
38+
final @NotNull Optional<@NotNull String> name = Optional.ofNullable(player.getName());
39+
if (name.isEmpty()) throw new InvalidPlayerError();
40+
else return name.get();
41+
}
42+
}
43+
44+
public void send() throws InvalidPlayerError {
45+
final @NotNull String senderUsername = playerOrServerUsername(this.sender);
46+
final @NotNull String recipientUsername = playerOrServerUsername(this.recipient);
47+
48+
final @NotNull Optional<@NotNull Player> senderPlayer = Optional.ofNullable(this.sender.getPlayer());
49+
final @NotNull Optional<@NotNull Player> recipientPlayer = Optional.ofNullable(this.recipient.getPlayer());
50+
51+
sendMessage(sender, CloudnodeMSG.getInstance().config().outgoing(senderUsername, recipientUsername, message));
52+
if (senderPlayer.isPresent() && !Message.hasChannel(senderPlayer.get(), recipient))
53+
setReplyTo(sender, recipient);
54+
55+
sendSpyMessage(sender, recipient, message);
56+
57+
if (
58+
(recipientPlayer.isPresent() && Message.isIgnored(recipientPlayer.get(), sender))
59+
&&
60+
(senderPlayer.isPresent() && !senderPlayer.get().hasPermission(Permission.IGNORE_BYPASS))
61+
) return;
62+
sendMessage(recipient, CloudnodeMSG.getInstance().config()
63+
.incoming(senderUsername, recipientUsername, message));
64+
if (recipientPlayer.isPresent() && !Message.hasChannel(recipientPlayer.get(), sender))
65+
setReplyTo(recipient, sender);
66+
}
67+
68+
public final static @NotNull OfflinePlayer console = CloudnodeMSG.getInstance().getServer()
69+
.getOfflinePlayer(UUID.fromString("00000000-0000-0000-0000-000000000000"));
70+
71+
public static @NotNull OfflinePlayer offlinePlayer(final @NotNull CommandSender executor) {
72+
return executor instanceof final @NotNull Player player ? player : console;
73+
}
74+
75+
public static void sendMessage(final @NotNull OfflinePlayer recipient, final @NotNull Component message) {
76+
if (recipient.getUniqueId() == console.getUniqueId())
77+
CloudnodeMSG.getInstance().getServer().getConsoleSender().sendMessage(message);
78+
else if (recipient.isOnline()) Objects.requireNonNull(recipient.getPlayer()).sendMessage(message);
79+
}
80+
81+
/**
82+
* Send social spy to online players with permission
83+
*/
84+
public static void sendSpyMessage(final @NotNull OfflinePlayer sender, final @NotNull OfflinePlayer recipient, final @NotNull Component message) {
85+
final @NotNull String senderName = sender.getUniqueId().equals(console.getUniqueId()) ? CloudnodeMSG.getInstance().config().consoleName() : Optional.ofNullable(sender.getName()).orElse("Unknown Player");
86+
final @NotNull String recipientName = recipient.getUniqueId().equals(console.getUniqueId()) ? CloudnodeMSG.getInstance().config().consoleName() : Optional.ofNullable(recipient.getName()).orElse("Unknown Player");
87+
for (final @NotNull Player player : CloudnodeMSG.getInstance().getServer().getOnlinePlayers()) {
88+
if (
89+
!player.hasPermission(Permission.SPY)
90+
|| player.getUniqueId().equals(sender.getUniqueId())
91+
|| player.getUniqueId().equals(recipient.getUniqueId())
92+
) continue;
93+
sendMessage(player, CloudnodeMSG.getInstance().config().spy(senderName, recipientName, message));
94+
}
95+
if (!sender.getUniqueId().equals(console.getUniqueId()) && !recipient.getUniqueId().equals(console.getUniqueId()))
96+
sendMessage(console, CloudnodeMSG.getInstance().config().spy(senderName, recipientName, message));
97+
}
98+
99+
private static @Nullable UUID consoleReply;
100+
101+
public static final @NotNull NamespacedKey REPLY_TO = new NamespacedKey(CloudnodeMSG.getInstance(), "reply");
102+
103+
public static void setReplyTo(final @NotNull OfflinePlayer sender, final @NotNull OfflinePlayer recipient) {
104+
if (sender.getUniqueId().equals(console.getUniqueId())) consoleReply = recipient.getUniqueId();
105+
else if (sender.isOnline())
106+
Objects.requireNonNull(sender.getPlayer()).getPersistentDataContainer()
107+
.set(REPLY_TO, PersistentDataType.STRING, recipient.getUniqueId().toString());
108+
}
109+
110+
public static @NotNull Optional<@NotNull OfflinePlayer> getReplyTo(final @NotNull OfflinePlayer player) {
111+
if (player.getUniqueId().equals(console.getUniqueId())) return Optional.ofNullable(consoleReply)
112+
.map(uuid -> CloudnodeMSG.getInstance().getServer().getOfflinePlayer(uuid));
113+
if (player.isOnline())
114+
return Optional.ofNullable(Objects.requireNonNull(player.getPlayer()).getPersistentDataContainer()
115+
.get(REPLY_TO, PersistentDataType.STRING))
116+
.map(uuid -> CloudnodeMSG.getInstance().getServer().getOfflinePlayer(UUID.fromString(uuid)));
117+
return Optional.empty();
118+
}
119+
120+
public static void removeReplyTo(final @NotNull OfflinePlayer player) {
121+
if (player.getUniqueId().equals(console.getUniqueId())) consoleReply = null;
122+
else if (player.isOnline())
123+
Objects.requireNonNull(player.getPlayer()).getPersistentDataContainer().remove(REPLY_TO);
124+
}
125+
126+
public static final @NotNull NamespacedKey IGNORED_PLAYERS = new NamespacedKey(CloudnodeMSG.getInstance(), "ignored");
127+
public static final @NotNull NamespacedKey CHANNEL_RECIPIENT = new NamespacedKey(CloudnodeMSG.getInstance(), "channel-recipient");
128+
public static final @NotNull NamespacedKey CHANNEL_TEAM = new NamespacedKey(CloudnodeMSG.getInstance(), "channel-team");
129+
130+
/**
131+
* Get UUID set of ignored players from PDC string
132+
*
133+
* @param player The player
134+
*/
135+
public static @NotNull HashSet<@NotNull UUID> getIgnored(final @NotNull Player player) {
136+
final @NotNull Optional<@NotNull String> str = Optional.ofNullable(player.getPersistentDataContainer().get(IGNORED_PLAYERS, PersistentDataType.STRING));
137+
return str.map(s -> new HashSet<>(Arrays.stream(s.split(";")).filter(e -> !e.isEmpty()).map(UUID::fromString).toList()))
138+
.orElseGet(HashSet::new);
139+
}
140+
141+
/**
142+
* Check if a player is ignored
143+
*
144+
* @param player The player
145+
* @param ignored The ignored player
146+
*/
147+
public static boolean isIgnored(final @NotNull Player player, final @NotNull OfflinePlayer ignored) {
148+
return getIgnored(player).contains(ignored.getUniqueId());
149+
}
150+
151+
/**
152+
* Ignore a player
153+
*
154+
* @param player The player
155+
* @param ignore The player to ignore
156+
*/
157+
public static void ignore(final @NotNull Player player, final @NotNull OfflinePlayer ignore) {
158+
final @NotNull HashSet<@NotNull UUID> ignoredPlayers = getIgnored(player);
159+
ignoredPlayers.add(ignore.getUniqueId());
160+
player.getPersistentDataContainer().set(IGNORED_PLAYERS, PersistentDataType.STRING, String.join(";", ignoredPlayers.stream().map(UUID::toString).toList()));
161+
}
162+
163+
/**
164+
* Unignore a player
165+
*
166+
* @param player The player
167+
* @param ignored The player to unignore
168+
*/
169+
public static void unignore(final @NotNull Player player, final @NotNull OfflinePlayer ignored) {
170+
final @NotNull HashSet<@NotNull UUID> ignoredPlayers = getIgnored(player);
171+
ignoredPlayers.remove(ignored.getUniqueId());
172+
player.getPersistentDataContainer().set(IGNORED_PLAYERS, PersistentDataType.STRING, String.join(";", ignoredPlayers.stream().map(UUID::toString).toList()));
173+
}
174+
175+
public static final @NotNull NamespacedKey INCOMING_ENABLED = new NamespacedKey(CloudnodeMSG.getInstance(), "incoming_enabled");
176+
177+
/**
178+
* Allows player to receive private messages
179+
*
180+
* @param player The player
181+
*/
182+
public static void incomingEnable(final @NotNull Player player) {
183+
player.getPersistentDataContainer().set(INCOMING_ENABLED, PersistentDataType.BOOLEAN, true);
184+
}
185+
186+
/**
187+
* Denies player to receive private messages
188+
*
189+
* @param player The player
190+
*/
191+
public static void incomingDisable(final @NotNull Player player) {
192+
player.getPersistentDataContainer().set(INCOMING_ENABLED, PersistentDataType.BOOLEAN, false);
193+
}
194+
195+
/**
196+
* Check if a player allows private messages
197+
*
198+
* @param player The player
199+
*/
200+
public static boolean isIncomingEnabled(final @NotNull Player player) {
201+
return player.getPersistentDataContainer().getOrDefault(INCOMING_ENABLED, PersistentDataType.BOOLEAN, true);
202+
}
203+
204+
/**
205+
* Create DM channel to player
206+
*
207+
* @param player The player (you)
208+
* @param recipient The other end of the channel
209+
*/
210+
public static void createChannel(final @NotNull Player player, final @NotNull OfflinePlayer recipient) {
211+
player.getPersistentDataContainer().set(CHANNEL_RECIPIENT, PersistentDataType.STRING, recipient.getUniqueId().toString());
212+
player.getPersistentDataContainer().remove(CHANNEL_TEAM);
213+
}
214+
215+
/**
216+
* Exit DM channel
217+
*
218+
* @param player The player (you)
219+
*/
220+
public static void exitChannel(final @NotNull Player player) {
221+
player.getPersistentDataContainer().remove(CHANNEL_RECIPIENT);
222+
}
223+
224+
/**
225+
* Get DM channel recipient
226+
*
227+
* @param player The player
228+
*/
229+
public static @NotNull Optional<@NotNull OfflinePlayer> getChannel(final @NotNull Player player) {
230+
return Optional.ofNullable(player.getPersistentDataContainer().get(CHANNEL_RECIPIENT, PersistentDataType.STRING))
231+
.map(uuid -> CloudnodeMSG.getInstance().getServer().getOfflinePlayer(UUID.fromString(uuid)));
232+
}
233+
234+
/**
235+
* Check whether player has DM channel with recipient
236+
*
237+
* @param player The player
238+
* @param recipient The recipient
239+
*/
240+
public static boolean hasChannel(final @NotNull Player player, final @NotNull OfflinePlayer recipient) {
241+
final @NotNull Optional<@NotNull OfflinePlayer> channel = getChannel(player);
242+
return channel.isPresent() && channel.get().getUniqueId().equals(recipient.getUniqueId());
243+
}
244+
245+
/**
246+
* Team message channel
247+
*
248+
* @param player The player
249+
*/
250+
public static void createTeamChannel(final @NotNull Player player) {
251+
player.getPersistentDataContainer().set(CHANNEL_TEAM, PersistentDataType.BOOLEAN, true);
252+
player.getPersistentDataContainer().remove(CHANNEL_RECIPIENT);
253+
}
254+
255+
/**
256+
* Exit team message channel
257+
*
258+
* @param player The player
259+
*/
260+
public static void exitTeamChannel(final @NotNull Player player) {
261+
player.getPersistentDataContainer().remove(CHANNEL_TEAM);
262+
}
263+
264+
/**
265+
* Check whether player has a team message channel
266+
*
267+
* @param player The player
268+
*/
269+
public static boolean hasTeamChannel(final @NotNull Player player) {
270+
return player.getPersistentDataContainer().getOrDefault(CHANNEL_TEAM, PersistentDataType.BOOLEAN, false);
271+
}
272+
}

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

Lines changed: 25 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
*/
@@ -27,4 +32,24 @@ public final class Permission {
2732
* Player's messages are immune to ignoring
2833
*/
2934
public final static @NotNull String IGNORE_BYPASS = "cloudnodemsg.ignore.bypass";
35+
36+
/**
37+
* Allows using the /togglemsg command
38+
*/
39+
public final static @NotNull String TOGGLE = "cloudnodemsg.toggle";
40+
41+
/**
42+
* Allows using the /togglemsg command for others
43+
*/
44+
public final static @NotNull String TOGGLE_OTHER = "cloudnodemsg.toggle.other";
45+
46+
/**
47+
* Allows to send private message even when the target have their private messages toggled
48+
*/
49+
public final static @NotNull String TOGGLE_BYPASS = "cloudnodemsg.toggle.bypass";
50+
51+
/**
52+
* Allows to see the private messages of other players
53+
*/
54+
public final static @NotNull String SPY = "cloudnodemsg.spy";
3055
}

0 commit comments

Comments
 (0)