Skip to content

Commit 2222966

Browse files
authored
Added optional chat format (#63)
2 parents 0ab0c28 + 180290a commit 2222966

File tree

7 files changed

+125
-3
lines changed

7 files changed

+125
-3
lines changed

.github/workflows/release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ jobs:
5858
version: ${{ github.event.release.tag_name }}
5959
changelog: ${{ github.event.release.body }}
6060
loaders: paper
61+
dependencies: |-
62+
[{
63+
"project_id": "lKEzGugV",
64+
"dependency_type": "optional"
65+
}]
6166
game-versions: |-
6267
1.20.x
6368
1.21.x

.run/Package.run.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="Package" type="MavenRunConfiguration" factoryName="Maven">
3+
<MavenSettings>
4+
<option name="myGeneralSettings" />
5+
<option name="myRunnerSettings" />
6+
<option name="myRunnerParameters">
7+
<MavenRunnerParameters>
8+
<option name="cmdOptions" />
9+
<option name="profiles">
10+
<set />
11+
</option>
12+
<option name="goals">
13+
<list>
14+
<option value="package" />
15+
</list>
16+
</option>
17+
<option name="multimoduleDir" />
18+
<option name="pomFileName" />
19+
<option name="profilesMap">
20+
<map />
21+
</option>
22+
<option name="projectsCmdOptionValues">
23+
<list />
24+
</option>
25+
<option name="resolveToWorkspace" value="false" />
26+
<option name="workingDirPath" value="$PROJECT_DIR$" />
27+
</MavenRunnerParameters>
28+
</option>
29+
</MavenSettings>
30+
<method v="2" />
31+
</configuration>
32+
</component>

pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
<id>sonatype</id>
7373
<url>https://oss.sonatype.org/content/groups/public/</url>
7474
</repository>
75+
<repository>
76+
<id>placeholderapi</id>
77+
<url>https://repo.extendedclip.com/releases/</url>
78+
</repository>
7579
</repositories>
7680

7781
<dependencies>
@@ -81,5 +85,11 @@
8185
<version>1.20.2-R0.1-SNAPSHOT</version>
8286
<scope>provided</scope>
8387
</dependency>
88+
<dependency>
89+
<groupId>me.clip</groupId>
90+
<artifactId>placeholderapi</artifactId>
91+
<version>2.11.6</version>
92+
<scope>provided</scope>
93+
</dependency>
8494
</dependencies>
8595
</project>

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
package pro.cloudnode.smp.cloudnodemsg;
22

3+
import io.papermc.paper.chat.ChatRenderer;
4+
import me.clip.placeholderapi.PlaceholderAPI;
5+
import net.kyori.adventure.audience.Audience;
6+
import net.kyori.adventure.key.Key;
37
import net.kyori.adventure.text.Component;
8+
import net.kyori.adventure.text.event.ClickEvent;
9+
import net.kyori.adventure.text.event.HoverEvent;
10+
import net.kyori.adventure.text.format.TextColor;
411
import net.kyori.adventure.text.minimessage.MiniMessage;
12+
import net.kyori.adventure.text.minimessage.tag.Tag;
513
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
14+
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
15+
import org.bukkit.OfflinePlayer;
616
import org.bukkit.configuration.file.FileConfiguration;
17+
import org.bukkit.entity.Player;
718
import org.bukkit.scoreboard.Team;
819
import org.jetbrains.annotations.NotNull;
20+
import org.jetbrains.annotations.Nullable;
921

1022
import java.util.Objects;
23+
import java.util.Optional;
1124

1225
public final class PluginConfig {
1326
public @NotNull FileConfiguration config;
@@ -305,6 +318,44 @@ public PluginConfig(final @NotNull FileConfiguration config) {
305318
);
306319
}
307320

321+
/**
322+
* Chat format
323+
*/
324+
public @NotNull Optional<@NotNull ChatRenderer> chatFormat() {
325+
final @Nullable String str = config.getString("chat-format");
326+
if (str == null || str.equals("null") || str.isBlank())
327+
return Optional.empty();
328+
return Optional.of((source, sourceDisplayName, message, viewer) -> MiniMessage.miniMessage().deserialize(
329+
str,
330+
Placeholder.component("message", message),
331+
TagResolver.resolver("papi", (args, ctx) -> {
332+
String placeholder = args.popOr("placeholder expected").value().trim();
333+
if (!placeholder.startsWith("%") && !placeholder.endsWith("%"))
334+
placeholder = "%" + placeholder + "%";
335+
if (!CloudnodeMSG.getInstance().getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
336+
CloudnodeMSG.getInstance().getLogger().severe("Attempted to use PlaceholderAPI placeholder `" + placeholder
337+
+ "` in chat format, but PlaceholderAPI is not present!");
338+
return Tag.inserting(Component.text(PlaceholderAPI.setPlaceholders(source, placeholder)));
339+
}),
340+
TagResolver.resolver("has-team", (args, ctx) -> {
341+
final String text = args.popOr("text expected").value();
342+
final Team team = source.getScoreboard().getPlayerTeam(source);
343+
if (team == null) {
344+
if (args.hasNext())
345+
return Tag.inserting(MiniMessage.miniMessage().deserialize(args.popOr("expected fallback value").value()));
346+
else return Tag.inserting(Component.empty());
347+
}
348+
return Tag.inserting(ctx.deserialize(text,
349+
Placeholder.component("team", team.displayName())
350+
));
351+
}),
352+
TagResolver.resolver("player", (args, ctx) -> Tag.inserting(
353+
Component.text(source.getName())
354+
.clickEvent(ClickEvent.suggestCommand("/tell " + source.getName() + " "))
355+
))
356+
));
357+
}
358+
308359
/**
309360
* No permission
310361
*/

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package pro.cloudnode.smp.cloudnodemsg.listener;
22

3+
import io.papermc.paper.chat.ChatRenderer;
34
import io.papermc.paper.event.player.AsyncChatEvent;
45
import net.kyori.adventure.audience.Audience;
6+
import net.kyori.adventure.text.Component;
57
import org.bukkit.OfflinePlayer;
68
import org.bukkit.Server;
79
import org.bukkit.entity.Player;
@@ -23,7 +25,7 @@
2325
import java.util.Set;
2426

2527
public final class AsyncChatListener implements Listener {
26-
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
28+
@EventHandler(priority = EventPriority.LOWEST)
2729
public void ignore(final @NotNull AsyncChatEvent event) {
2830
final @NotNull Set<@NotNull Audience> audience = event.viewers();
2931
final @NotNull Iterator<@NotNull Audience> iterator = audience.iterator();
@@ -41,7 +43,7 @@ public void ignore(final @NotNull AsyncChatEvent event) {
4143
}
4244
}
4345

44-
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
46+
@EventHandler(priority = EventPriority.HIGHEST)
4547
public void channels(final @NotNull AsyncChatEvent event) {
4648
final @NotNull Player sender = event.getPlayer();
4749
final @NotNull Optional<@NotNull OfflinePlayer> channelRecipient = Message.getChannel(sender);
@@ -55,7 +57,7 @@ public void channels(final @NotNull AsyncChatEvent event) {
5557
}
5658
}
5759

58-
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
60+
@EventHandler(priority = EventPriority.HIGHEST)
5961
public void teamChannel(final @NotNull AsyncChatEvent event) {
6062
final @NotNull Player sender = event.getPlayer();
6163
if (!Message.hasTeamChannel(sender)) return;
@@ -68,4 +70,10 @@ public void teamChannel(final @NotNull AsyncChatEvent event) {
6870
}
6971
TeamMessageCommand.sendTeamMessage(sender, team.get(), event.message());
7072
}
73+
74+
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
75+
public void chatFormat(final @NotNull AsyncChatEvent event) {
76+
final @NotNull Optional<@NotNull ChatRenderer> format = CloudnodeMSG.getInstance().config().chatFormat();
77+
format.ifPresent(event::renderer);
78+
}
7179
}

src/main/resources/config.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,20 @@ toggle:
8888
# <player> - the player's username
8989
other: "<green>(!) Re-enabled receiving of private messages for <gray><player></gray>.</green>"
9090

91+
# Set custom global/public chat format. Disabled by default.
92+
#
93+
# Placeholders:
94+
# <has-team:'if yes':'if no'> - show a different message based on whether the player is in a team
95+
# <team> - the player's team display name (only works in <has-team>)
96+
# <player> - the name of the player, when clicked suggests command `/tell` followed by the player's name
97+
# <message> - the message being sent in chat
98+
# <papi:…> - use a PlaceholderAPI placeholder, example `<papi:%player_displayname%>` or `<papi:player_displayname>`.
99+
# Requires PlaceholderAPI to be installed.
100+
#
101+
# Example:
102+
#chat-format: <has-team:'<dark_gray>[<white><team></white>]</dark_gray> '><white><player></white><dark_gray>:</dark_gray> <gray><message></gray>
103+
chat-format: null
104+
91105
# Error messages
92106
errors:
93107
# No permission

src/main/resources/plugin.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ version: '${project.version}'
33
main: pro.cloudnode.smp.cloudnodemsg.CloudnodeMSG
44
api-version: '1.20'
55
author: Cloudnode
6+
softdepend:
7+
- PlaceholderAPI
68
commands:
79
message:
810
description: Send a private message

0 commit comments

Comments
 (0)