Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/simplexity/simplepms/SimplePMs.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
import simplexity.simplepms.commands.SocialSpy;
import simplexity.simplepms.commands.Unblock;
import simplexity.simplepms.config.ConfigHandler;
import simplexity.simplepms.hooks.DiscordWebHook;
import simplexity.simplepms.listeners.JoinListener;
import simplexity.simplepms.listeners.PreCommandListener;
import simplexity.simplepms.listeners.PrivateMessageListener;
import simplexity.simplepms.listeners.QuitListener;
import simplexity.simplepms.logic.Constants;
import simplexity.simplepms.saving.SqlHandler;
Expand Down Expand Up @@ -47,6 +49,7 @@ private void registerListeners() {
getServer().getPluginManager().registerEvents(new QuitListener(), this);
getServer().getPluginManager().registerEvents(new PreCommandListener(), this);
getServer().getPluginManager().registerEvents(new JoinListener(), this);
getServer().getPluginManager().registerEvents(new PrivateMessageListener(), this);
}

private void loadConfigStuff() {
Expand Down Expand Up @@ -91,6 +94,7 @@ private void registerPermissions() {
@Override
public void onDisable() {
SqlHandler.getInstance().shutdownConnection();
DiscordWebHook.removeClient();
}

public static MiniMessage getMiniMessage() {
Expand Down
35 changes: 33 additions & 2 deletions src/main/java/simplexity/simplepms/config/ConfigHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
import simplexity.simplepms.SimplePMs;
import simplexity.simplepms.hooks.DiscordWebHook;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ConfigHandler {
Expand All @@ -22,12 +25,13 @@ public static ConfigHandler getInstance() {

private final Logger logger = SimplePMs.getInstance().getLogger();
private boolean mysqlEnabled, playersSendToConsole, playersSendToHiddenPlayers, consoleHasSocialSpy,
commandSpyEnabled, consoleHasCommandSpy, receiveSoundEnabled, sendSoundEnabled, spySoundEnabled;
commandSpyEnabled, consoleHasCommandSpy, receiveSoundEnabled, sendSoundEnabled, spySoundEnabled, webhookEnabled;
private NamespacedKey receiveSound = Registry.SOUNDS.getKey(Sound.BLOCK_NOTE_BLOCK_XYLOPHONE);
private NamespacedKey sendSound = Registry.SOUNDS.getKey(Sound.ENTITY_ALLAY_ITEM_THROWN);
private NamespacedKey spySound = Registry.SOUNDS.getKey(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM);
private float receivePitch, receiveVolume, sendPitch, sendVolume, spyPitch, spyVolume;
private String mysqlIp, mysqlName, mysqlUsername, mysqlPassword, normalFormat, socialSpyFormat;
private String mysqlIp, mysqlName, mysqlUsername, mysqlPassword, normalFormat, socialSpyFormat, webhookBody;
private URI webhookUri;
private final List<String> validNamesForConsole = new ArrayList<>();
private final HashSet<String> commandsToSpy = new HashSet<>();

Expand All @@ -54,9 +58,11 @@ public void loadConfigValues() {
receiveSoundEnabled = config.getBoolean("sounds.received.enabled", false);
sendSoundEnabled = config.getBoolean("sounds.sent.enabled", false);
spySoundEnabled = config.getBoolean("sounds.spy.enabled", false);
webhookEnabled = config.getBoolean("webhook.enabled", false);
if (receiveSoundEnabled) loadReceiveSoundInfo(config);
if (sendSoundEnabled) loadSendSoundInfo(config);
if (spySoundEnabled) loadSpySoundInfo(config);
if (webhookEnabled) loadWebhook(config);
}

private void updateHashSet(HashSet<String> set, List<String> list) {
Expand Down Expand Up @@ -85,6 +91,25 @@ private void loadSpySoundInfo(FileConfiguration config) {
spyVolume = getValidFloat(config.getDouble("sounds.spy.volume", 0.5));
}

private void loadWebhook(FileConfiguration config) {
webhookBody = config.getString("webhook.json-body", null);
String uri = config.getString("webhook.url", null);
if (uri == null || uri.isBlank()) {
logger.warning(LocaleMessage.LOG_ERROR_WEBHOOK_URL_BLANK.getMessage());
webhookEnabled = false;
return;
}
try {
webhookUri = URI.create(uri);
}
catch (IllegalArgumentException e) {
logger.log(Level.WARNING, LocaleMessage.LOG_ERROR_WEBHOOK_URL_MALFORMED.getMessage(), e);
webhookEnabled = false;
return;
}
if (webhookEnabled) DiscordWebHook.createClient();
}

private NamespacedKey getValidSound(String soundString, NamespacedKey defaultSound) {
NamespacedKey key = NamespacedKey.fromString(soundString);
if (key == null || Registry.SOUNDS.get(key) == null) {
Expand Down Expand Up @@ -219,4 +244,10 @@ public float getSpyPitch() {
public float getSpyVolume() {
return spyVolume;
}

public boolean isWebhookEnabled() { return webhookEnabled; }

public URI getWebhookUri() { return webhookUri; }

public String getWebhookBody() { return webhookBody; }
}
5 changes: 4 additions & 1 deletion src/main/java/simplexity/simplepms/config/LocaleMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ public enum LocaleMessage {
"https://jd.papermc.io/paper/1.21.5/io/papermc/paper/registry/keys/SoundEventKeys.html"),
LOG_ERROR_USING_DEFAULT_SOUND("console-error.using-default-sound", "Using %default-sound% until a valid sound is provided"),
LOG_ERROR_FLOAT_OUT_OF_RANGE("console-error.float-out-of-range", "The number %number% is out of range! Volume and pitch values must be a number between 0 and 2!"),
LOG_ERROR_USING_DEFAULT_FLOAT("console-error.using-default-float", "Setting to 1.0 until a valid value is provided");
LOG_ERROR_USING_DEFAULT_FLOAT("console-error.using-default-float", "Setting to 1.0 until a valid value is provided"),
LOG_ERROR_WEBHOOK_URL_BLANK("console-error.webhook.url.blank", "Webhook URL cannot be null or blank. Disabling webhooks."),
LOG_ERROR_WEBHOOK_URL_MALFORMED("console-error.webhook.url.malformed", "Webhook URL is malformed and does not meet expected standards. Disabling webhooks."),
LOG_ERROR_WEBHOOK_CLIENT_NOT_CREATED("console-error.webhook.client-not-created", "HTTP Client was not created, this should be impossible. Let Simplexity what happened.");


private final String path;
Expand Down
75 changes: 75 additions & 0 deletions src/main/java/simplexity/simplepms/hooks/DiscordWebHook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package simplexity.simplepms.hooks;

import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import simplexity.simplepms.SimplePMs;
import simplexity.simplepms.config.ConfigHandler;
import simplexity.simplepms.config.LocaleMessage;
import simplexity.simplepms.logic.MessageUtils;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;

public class DiscordWebHook {

public static HttpClient client;

public static void sendWebHook(CommandSender sender, CommandSender recipient, String message) {

if (client == null) {
SimplePMs.getInstance().getLogger().log(Level.WARNING, LocaleMessage.LOG_ERROR_WEBHOOK_CLIENT_NOT_CREATED.getMessage());
createClient();
}

String content = MessageUtils.getInstance().format(
ConfigHandler.getInstance().getWebhookBody(),
Map.of(
"sender", sender.getName(),
"sender_display_name", (sender instanceof Player player) ? PlainTextComponentSerializer.plainText().serialize(player.displayName()) : sender.getName(),
"sender_uuid", (sender instanceof Player player) ? player.getUniqueId().toString() : "",
"recipient", recipient.getName(),
"recipient_display_name", (recipient instanceof Player player) ? PlainTextComponentSerializer.plainText().serialize(player.displayName()) : recipient.getName(),
"recipient_uuid", (recipient instanceof Player player) ? player.getUniqueId().toString() : "",
"message", message,
"timestamp", Long.toString(System.currentTimeMillis()/1000)
)
);

try {
HttpRequest request = HttpRequest.newBuilder()
.uri(ConfigHandler.getInstance().getWebhookUri())
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(content))
.build();

CompletableFuture<HttpResponse<String>> asyncResponse = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
asyncResponse.thenAccept(response -> {
if (response.statusCode() < 200 || response.statusCode() >= 300) {
//noinspection StringTemplateMigration: String Template is considered preview and may be removed in a future release.
SimplePMs.getInstance().getLogger().log(Level.WARNING, "Webhook has failed to send, HTTP Status " + response.statusCode() + " with JSON Body:\n" + response.body());
}
});
}
catch (Exception e) {
e.printStackTrace();
}
}

public static void createClient() {
removeClient();
client = HttpClient.newHttpClient();
}

public static void removeClient() {
if (client == null) return;
client.close();
client = null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package simplexity.simplepms.listeners;

import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import simplexity.simplepms.config.ConfigHandler;
import simplexity.simplepms.events.PrivateMessageEvent;
import simplexity.simplepms.hooks.DiscordWebHook;

public class PrivateMessageListener implements Listener {

@EventHandler(priority = EventPriority.MONITOR)
public void onPrivateMessage(PrivateMessageEvent event) {
if (!ConfigHandler.getInstance().isWebhookEnabled()) return;
DiscordWebHook.sendWebHook(event.getInitiator(), event.getRecipient(), event.getMessageContent());
}

}
25 changes: 25 additions & 0 deletions src/main/java/simplexity/simplepms/logic/MessageUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@
import simplexity.simplepms.config.ConfigHandler;
import simplexity.simplepms.config.LocaleMessage;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MessageUtils {
private static MessageUtils instance;
private final MiniMessage miniMessage = SimplePMs.getMiniMessage();
private final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{([a-zA-Z0-9_]+)}");

private MessageUtils() {
}
Expand Down Expand Up @@ -87,4 +92,24 @@ public TagResolver papiTag(final Player player) {
});
}

public String format(String message, Map<String, String> values) {
Matcher matcher = PLACEHOLDER_PATTERN.matcher(message);
StringBuilder result = new StringBuilder();

int lastEnd = 0;
while (matcher.find()) {
result.append(message, lastEnd, matcher.start());

String key = matcher.group(1);
String value = values.get(key);

if (value != null) result.append(value);
else result.append(matcher.group());
lastEnd = matcher.end();
}
result.append(message, lastEnd, message.length());

return result.toString();
}

}
23 changes: 23 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,26 @@ sounds:
sound: minecraft:entity.item_frame.rotate_item
pitch: 1.8
volume: 0.5
###
# This adds Webhook Support focused for Discord
###
webhook:
enabled: false
url: ""
# This is the JSON Body to send to the webhook.
# The default value is modeled after https://docs.discord.com/developers/resources/webhook#execute-webhook
# These are the placeholders that can be used:
# <sender>: Sender's Username
# <sender_display_name>: Sender's Display Name (Nickname), Non-players will have the same name as <sender>
# <sender_uuid>: Sender's UUID, formatted as xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, this is blank for non-players.
# <recipient>: Recipient's Username
# <recipient_display_name>: Recipient's Display Name (Nickname), Non-players will have the same name as <recipient>
# <recipient_uuid>: Recipient's UUID, formatted as xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, this is blank for non-players.
# <message>: The message sent through SimplePMs.
# <timestamp>: Unix Timestamp (https://www.unixtimestamp.com/)
json-body: |
{
"content": "{message}\n-# {sender_display_name} ({sender}) sent {recipient_display_name} ({recipient}) this on <t:{timestamp}>",
"avatar_url": "https://mc-heads.net/avatar/{sender_uuid}",
"username": "{sender} > {recipient}"
}