From 318837e402a60906b2990b7a8af660ff9b60bf50 Mon Sep 17 00:00:00 2001 From: Kim Date: Sun, 16 Jun 2024 21:08:58 +0200 Subject: [PATCH] New notification + new command Added push for PlayerDeath and the ability to push custom messages by using the command /spe message close #2 --- README.md | 58 ++++--- pom.xml | 10 +- ...Config.java => KonfigurationsManager.java} | 26 ++- src/main/java/de/liebki/Start.java | 149 ++++++++++++------ .../java/de/liebki/events/EventManager.java | 141 ++++++++++++----- .../java/de/liebki/manager/PushManager.java | 11 +- src/main/resources/plugin.yml | 5 +- 7 files changed, 279 insertions(+), 121 deletions(-) rename src/main/java/de/liebki/{Config.java => KonfigurationsManager.java} (75%) diff --git a/README.md b/README.md index 147ef42..436010b 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,37 @@ # SimplePushEvents Plugin ## Description -This Spigot plugin, for use with the latest Minecraft version, automatically sends notifications to a push service (ntfy.sh), when players join, leave, execute specific commands or the server starts/shuts down. -It helps server you and your players to stay informed about server activities in real-time. +This Spigot plugin, for use with the latest Minecraft version, automatically sends notifications to a push service (ntfy.sh), when players join, leave, execute specific commands, do certain things or the server starts/shuts down. +This helps server owners and players stay informed about server activities in real-time. ## Ideas If you have ideas for more events, open an issue. + ## Java Version Compatible with Minecraft 1.20.6 and requires Java 21. ## Features -- Sends push notifications when a player joins or leaves the server. - Notifies when the server starts up or shuts down. -- Configurable message content and status for each event. +- Sends push notifications when + - a player joins or leaves the server. + - a player unlocks an advancement. + - a player creates a portal. + - a player dies (including the death message). + - executes `/spe [message content]` for custom notifications (with custom permissions). +- Change the message format or disable/enable them entirely. - Easy integration with the ntfy.sh push service. - Quick setup with minimal configuration required. - Checks and notifies for specific player commands: - - `op` - - `deop` - - `ban` - - `banip` - - `pardon` - - `pardonip` - - `whitelist` + - `/op` + - `/deop` + - `/ban` + - `/banip` + - `/pardon` + - `/pardonip` + - `/whitelist` ## Setup @@ -45,13 +51,12 @@ To set up the SimplePushEvents plugin, follow these steps: ## Plugin Configuration - Before deploying the plugin, ensure you configure the following parameters in the `options.yml` file: ```yaml donottouch: configexists: true - pushchannel: 1dea3f4db2bb + pushchannel: 7fc647dd98 messages: general: title: 'Minecraft Server:' @@ -61,11 +66,31 @@ messages: poweroff: status: true content: The server is shutting down! + chatcommand: + status: true + content: '[%PLAYER%] wrote: %MESSAGE%' + permission: spe.usechatcommand player: advancement: status: true content: 'The player %PLAYER% unlocked the advancement: %NAME%' + join: + status: true + content: The player %PLAYER% joined! + leave: + status: true + content: The player %PLAYER% left! + count: + status: true + content: 'Players online right now: %ONLINE%/%MAX%' + death: + status: true + content: 'The Player %PLAYER% died: %MESSAGE%' + portalcreation: + status: true + content: The Player %PLAYER% created a portal at %LOCATION% command: + disableall: false op: status: true content: The player %PLAYER% executed /op for %TARGET% ! @@ -87,13 +112,6 @@ messages: whitelist: status: true content: 'The player %PLAYER% used a whitelist command: %CONTENT%' - join: - status: true - content: The player %PLAYER% joined! - leave: - status: true - content: The player %PLAYER% left! - ``` diff --git a/pom.xml b/pom.xml index 4c6978f..ad9ca84 100644 --- a/pom.xml +++ b/pom.xml @@ -4,10 +4,16 @@ 4.0.0 de.liebki simplepushevents - 0.0.4 + 0.0.5 simplepushevents + + 21 + 21 + + + jar @@ -35,7 +41,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.6.0 package diff --git a/src/main/java/de/liebki/Config.java b/src/main/java/de/liebki/KonfigurationsManager.java similarity index 75% rename from src/main/java/de/liebki/Config.java rename to src/main/java/de/liebki/KonfigurationsManager.java index b189763..44669a4 100644 --- a/src/main/java/de/liebki/Config.java +++ b/src/main/java/de/liebki/KonfigurationsManager.java @@ -1,3 +1,10 @@ +/* + * + * Copyright liebki: https://github.com/liebki | https://kmliebl.de + * You may use this class when stating where it is from and from whom. + * + */ + package de.liebki; import java.io.File; @@ -7,43 +14,52 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; -public class Config { +/** + * Custom class to create and use config files more easy in a plugin + */ +public class KonfigurationsManager { private File file; private FileConfiguration fileConfig; - public Config(String path, String fileName, Runnable callback, Plugin plugin) { + public KonfigurationsManager(String path, String fileName, Runnable callback, Plugin plugin) { if (!fileName.contains(".yml")) { fileName = fileName + ".yml"; } + file = new File(path, fileName); fileConfig = YamlConfiguration.loadConfiguration(file); if (!file.exists()) { fileConfig.options().copyDefaults(true); callback.run(); + try { fileConfig.save(file); } catch (IOException exception) { exception.printStackTrace(); } + } } - public Config(String path, String fileName, Plugin plugin) { + public KonfigurationsManager(String path, String fileName, Plugin plugin) { if (!fileName.contains(".yml")) { fileName = fileName + ".yml"; } + file = new File(path, fileName); fileConfig = YamlConfiguration.loadConfiguration(file); if (!file.exists()) { + fileConfig.options().copyDefaults(true); try { fileConfig.save(file); } catch (IOException exception) { exception.printStackTrace(); } + } } @@ -54,6 +70,7 @@ public FileConfiguration getConfig() { public void saveConfig() { try { fileConfig.save(file); + } catch (IOException exception) { exception.printStackTrace(); } @@ -63,6 +80,7 @@ public Boolean check(String path) { if (fileConfig.get(path) == null) { return false; } + return true; } @@ -71,7 +89,7 @@ public void set(String path, Object wert) { saveConfig(); } - public T get(String path) { + public T get(String path) { if (fileConfig.getString(path) == null) { return null; } diff --git a/src/main/java/de/liebki/Start.java b/src/main/java/de/liebki/Start.java index 496b242..5904a14 100644 --- a/src/main/java/de/liebki/Start.java +++ b/src/main/java/de/liebki/Start.java @@ -3,6 +3,9 @@ import java.util.UUID; import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import de.liebki.events.EventManager; @@ -10,79 +13,126 @@ public class Start extends JavaPlugin { - public Config config; + public KonfigurationsManager config; private PushManager pushManager; + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + boolean isActive = config.get("messages.general.chatcommand.status"); + + String commandPermission = config.get("messages.general.chatcommand.permission"); + if (player.hasPermission(commandPermission) && isActive) { + String msg = String.join(" ", args); + String configMessage = config.get("messages.general.chatcommand.content"); + + configMessage = configMessage.replace("%PLAYER%", player.getName()).replace("%MESSAGE%", msg); + pushManager.SendMessage(configMessage); + } + + } + + return true; + } + @Override public void onEnable() { - config = new Config("plugins/simplepushevents", "options.yml", this); - if (!config.check("donottouch.configexists")) { + config = new KonfigurationsManager("plugins/simplepushevents", "options.yml", this); + boolean configExists = config.check("donottouch.configexists"); - String uuid = CreateShortUuid(); + if (!configExists) { + CreateConfigDefaults(); + } - config.set("donottouch.configexists", true); - config.set("donottouch.pushchannel", uuid); + pushManager = new PushManager(this); + EventManager eventManager = new EventManager(this, pushManager); - config.set("messages.general.title", "Minecraft Server:"); + getServer().getPluginManager().registerEvents(eventManager, this); + Bukkit.getConsoleSender().sendMessage("§4SimplePushEvents powering on"); - config.set("messages.general.startup.status", true); - config.set("messages.general.startup.content", "The server is online now!"); + boolean isActive = config.get("messages.general.startup.status"); + if (isActive) { + String configMessage = config.get("messages.general.startup.content"); + pushManager.SendMessage(configMessage); + } + } - config.set("messages.general.poweroff.status", true); - config.set("messages.general.poweroff.content", "The server is shutting down!"); + /** + * To create the default config values at the first starts or after deletion + */ + private void CreateConfigDefaults() { + String uuid = CreateShortUuid(); - config.set("messages.player.advancement.status", true); - config.set("messages.player.advancement.content", "The player %PLAYER% unlocked the advancement: %NAME%"); + config.set("donottouch.configexists", true); + config.set("donottouch.pushchannel", uuid); - config.set("messages.player.command.op.status", true); - config.set("messages.player.command.op.content", "The player %PLAYER% executed /op for %TARGET% !"); + config.set("messages.general.title", "Minecraft Server:"); - config.set("messages.player.command.deop.status", true); - config.set("messages.player.command.deop.content", "The player %PLAYER% executed /deop for %TARGET% !"); + config.set("messages.general.startup.status", true); + config.set("messages.general.startup.content", "The server is online now!"); - config.set("messages.player.command.ban.status", true); - config.set("messages.player.command.ban.content", "The player %PLAYER% executed /ban for %TARGET% !"); + config.set("messages.general.poweroff.status", true); + config.set("messages.general.poweroff.content", "The server is shutting down!"); - config.set("messages.player.command.banip.status", true); - config.set("messages.player.command.banip.content", "The player %PLAYER% executed /ban-ip for %TARGET% !"); + config.set("messages.general.chatcommand.status", true); + config.set("messages.general.chatcommand.content", "[%PLAYER%] wrote: %MESSAGE%"); + config.set("messages.general.chatcommand.permission", "spe.usechatcommand"); - config.set("messages.player.command.pardon.status", true); - config.set("messages.player.command.pardon.content", "The player %PLAYER% executed /pardon for %TARGET% !"); + config.set("messages.player.advancement.status", true); + config.set("messages.player.advancement.content", "The player %PLAYER% unlocked the advancement: %NAME%"); - config.set("messages.player.command.pardonip.status", true); - config.set("messages.player.command.pardonip.content", - "The player %PLAYER% executed /pardon-ip for %TARGET% !"); + config.set("messages.player.join.status", true); + config.set("messages.player.join.content", "The player %PLAYER% joined!"); - config.set("messages.player.command.whitelist.status", true); - config.set("messages.player.command.whitelist.content", - "The player %PLAYER% used a whitelist command: %CONTENT%"); + config.set("messages.player.leave.status", true); + config.set("messages.player.leave.content", "The player %PLAYER% left!"); - config.set("messages.player.join.status", true); - config.set("messages.player.join.content", "The player %PLAYER% joined!"); + config.set("messages.player.count.status", true); + config.set("messages.player.count.content", "Players online right now: %ONLINE%/%MAX%"); - config.set("messages.player.leave.status", true); - config.set("messages.player.leave.content", "The player %PLAYER% left!"); + config.set("messages.player.death.status", true); + config.set("messages.player.death.content", "The Player %PLAYER% died: %MESSAGE%"); - config.saveConfig(); - } + config.set("messages.player.portalcreation.status", true); + config.set("messages.player.portalcreation.content", "The Player %PLAYER% created a portal at %LOCATION%"); - pushManager = new PushManager(this); - EventManager eventManager = new EventManager(this, pushManager); + config.set("messages.player.command.disableall", false); - getServer().getPluginManager().registerEvents(eventManager, this); - Bukkit.getConsoleSender().sendMessage("§4SimplePushEvents powering on"); + config.set("messages.player.command.op.status", true); + config.set("messages.player.command.op.content", "The player %PLAYER% executed /op for %TARGET% !"); - boolean IsActive = (boolean) config.get("messages.general.startup.status"); - if (IsActive) { - String configMessage = (String) config.get("messages.general.startup.content"); - pushManager.SendMessage(configMessage); - } + config.set("messages.player.command.deop.status", true); + config.set("messages.player.command.deop.content", "The player %PLAYER% executed /deop for %TARGET% !"); + + config.set("messages.player.command.ban.status", true); + config.set("messages.player.command.ban.content", "The player %PLAYER% executed /ban for %TARGET% !"); + + config.set("messages.player.command.banip.status", true); + config.set("messages.player.command.banip.content", "The player %PLAYER% executed /ban-ip for %TARGET% !"); + + config.set("messages.player.command.pardon.status", true); + config.set("messages.player.command.pardon.content", "The player %PLAYER% executed /pardon for %TARGET% !"); + config.set("messages.player.command.pardonip.status", true); + config.set("messages.player.command.pardonip.content", + "The player %PLAYER% executed /pardon-ip for %TARGET% !"); + + config.set("messages.player.command.whitelist.status", true); + config.set("messages.player.command.whitelist.content", + "The player %PLAYER% used a whitelist command: %CONTENT%"); + + config.saveConfig(); } - String CreateShortUuid() { + /** + * To create a (hopefully) short UUID-like string, unique for every server + * + * @return UUID-like string + */ + private String CreateShortUuid() { String base = (UUID.randomUUID() + Bukkit.getServer().getIp()).trim(); - base = base.replace("-", "").substring(6, base.length() / 2); + base = base.replace("-", "").substring(8, base.length() / 2); return base; } @@ -91,12 +141,11 @@ String CreateShortUuid() { public void onDisable() { Bukkit.getConsoleSender().sendMessage("§4SimplePushEvents powering off"); - boolean IsActive = (boolean) config.get("messages.general.poweroff.status"); - if (IsActive) { - String configMessage = (String) config.get("messages.general.poweroff.content"); + boolean isActive = config.get("messages.general.poweroff.status"); + if (isActive) { + String configMessage = config.get("messages.general.poweroff.content"); pushManager.SendMessage(configMessage); } - } } \ No newline at end of file diff --git a/src/main/java/de/liebki/events/EventManager.java b/src/main/java/de/liebki/events/EventManager.java index c4b0bcf..e1d01dd 100644 --- a/src/main/java/de/liebki/events/EventManager.java +++ b/src/main/java/de/liebki/events/EventManager.java @@ -3,14 +3,19 @@ import java.util.HashMap; import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.advancement.Advancement; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerAdvancementDoneEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.world.PortalCreateEvent; import de.liebki.Start; import de.liebki.manager.PushManager; @@ -37,90 +42,146 @@ public EventManager(Start plugin, PushManager pushManager) { commandMap.put("/whitelist", "messages.player.command.whitelist"); } + private boolean ConfigStatus(String configPath) { + return plugin.config.get(configPath); + } + @EventHandler public void onPlayerCommand(PlayerCommandPreprocessEvent e) { - String commandText = e.getMessage(); - Player player = e.getPlayer(); - - if (player.isOp()) { - String playerName = player.getName(); - String messageToPushSend = ""; - - for (Map.Entry entry : commandMap.entrySet()) { - if (commandText.startsWith(entry.getKey())) { - boolean isActive = (boolean) plugin.config.get(entry.getValue() + ".status"); - - if (isActive) { - if (entry.getKey().equals("/whitelist")) { - messageToPushSend = (String) plugin.config.get(entry.getValue() + ".content"); - messageToPushSend = messageToPushSend.replace("%CONTENT%", commandText).replace("%PLAYER%", - playerName); - } else { - String[] parts = commandText.split(" "); - if (parts.length > 1) { - String targetPlayer = parts[1]; - messageToPushSend = (String) plugin.config.get(entry.getValue() + ".content"); - - messageToPushSend = messageToPushSend.replace("%PLAYER%", playerName) - .replace("%TARGET%", targetPlayer); + if (!ConfigStatus("messages.player.command.disableall")) { + String commandText = e.getMessage(); + Player player = e.getPlayer(); + + if (player.isOp()) { + String playerName = player.getName(); + String messageToPushSend = ""; + + for (Map.Entry entry : commandMap.entrySet()) { + if (commandText.startsWith(entry.getKey())) { + boolean isActive = plugin.config.get(entry.getValue() + ".status"); + + if (isActive) { + if (entry.getKey().equals("/whitelist")) { + messageToPushSend = plugin.config.get(entry.getValue() + ".content"); + messageToPushSend = messageToPushSend.replace("%CONTENT%", commandText) + .replace("%PLAYER%", playerName); + + } else { + String[] parts = commandText.split(" "); + if (parts.length > 1) { + String targetPlayer = parts[1]; + messageToPushSend = plugin.config.get(entry.getValue() + ".content"); + + messageToPushSend = messageToPushSend.replace("%PLAYER%", playerName) + .replace("%TARGET%", targetPlayer); + } } + } + break; } - break; + } + + if (!messageToPushSend.isEmpty()) { + pushManager.SendMessage(messageToPushSend); } } + } + + } - if (!messageToPushSend.isEmpty()) { - pushManager.SendMessage(messageToPushSend); + @EventHandler + public void OnPortalCreate(PortalCreateEvent event) { + if (event.getEntity() instanceof Player && ConfigStatus("messages.player.portalcreation.status")) { + try { + String playerName = event.getEntity().getName(); + Location portalLocation = event.getBlocks().get(0).getLocation(); + + World world = portalLocation.getWorld(); + String locationText = "[World: " + world + ", X: " + portalLocation.getX() + ", Y: " + + portalLocation.getY() + ",Z: " + portalLocation.getZ() + "]"; + + String configMessage = plugin.config.get("messages.player.portalcreation.content"); + configMessage = configMessage.replace("%PLAYER%", playerName).replace("%LOCATION%", locationText); + + pushManager.SendMessage(configMessage); + } catch (Exception e) { + Bukkit.getConsoleSender().sendMessage("Error in OnPortalCreate(): \n" + e.getMessage()); } } + } @EventHandler public void OnPlayerAdvancement(PlayerAdvancementDoneEvent event) { - boolean IsActive = (boolean) plugin.config.get("messages.player.advancement.status"); - - if (IsActive) { + if (ConfigStatus("messages.player.advancement.status")) { try { String playerName = event.getPlayer().getName(); Advancement AdvancementObj = event.getAdvancement(); String AdvancementName = AdvancementObj.getDisplay().getTitle(); - String configMessage = (String) plugin.config.get("messages.player.advancement.content"); + String configMessage = plugin.config.get("messages.player.advancement.content"); configMessage = configMessage.replace("%PLAYER%", playerName).replace("%NAME%", AdvancementName); pushManager.SendMessage(configMessage); } catch (Exception e) { if (!e.getMessage().contains("Cannot invoke")) { - throw e; + Bukkit.getConsoleSender().sendMessage("Error in OnPlayerAdvancement(): \n" + e.getMessage()); } } } } @EventHandler - public void OnPlayerJoin(PlayerJoinEvent event) { - boolean IsActive = (boolean) plugin.config.get("messages.player.join.status"); + public void OnPlayerDeath(PlayerDeathEvent event) { + if (ConfigStatus("messages.player.death.status")) { + String playerName = event.getEntity().getName(); + String deathCause = event.getDeathMessage(); + + String configMessage = plugin.config.get("messages.player.death.content"); + configMessage = configMessage.replace("%PLAYER%", playerName).replace("%MESSAGE%", deathCause); - if (IsActive) { + pushManager.SendMessage(configMessage); + } + } + + @EventHandler + public void OnPlayerJoin(PlayerJoinEvent event) { + if (ConfigStatus("messages.player.join.status")) { String playerName = event.getPlayer().getName(); - String configMessage = (String) plugin.config.get("messages.player.join.content"); + String configMessage = plugin.config.get("messages.player.join.content"); configMessage = configMessage.replace("%PLAYER%", playerName); pushManager.SendMessage(configMessage); } + + MessagePlayerCount(); } @EventHandler public void OnPlayerLeave(PlayerQuitEvent event) { - boolean IsActive = (boolean) plugin.config.get("messages.player.leave.status"); - - if (IsActive) { + if (ConfigStatus("messages.player.leave.status")) { String playerName = event.getPlayer().getName(); - String configMessage = (String) plugin.config.get("messages.player.leave.content"); + String configMessage = plugin.config.get("messages.player.leave.content"); configMessage = configMessage.replace("%PLAYER%", playerName); pushManager.SendMessage(configMessage); } + + MessagePlayerCount(); + } + + /** + * If enabled, sends a push of the current and max players online + */ + private void MessagePlayerCount() { + if (ConfigStatus("messages.player.count.status")) { + String configMessage = plugin.config.get("messages.player.count.content"); + + configMessage = configMessage.replace("%ONLINE%", String.valueOf(Bukkit.getOnlinePlayers().size() - 1)) + .replace("%MAX%", String.valueOf(Bukkit.getMaxPlayers())); + pushManager.SendMessage(configMessage); + } } + } diff --git a/src/main/java/de/liebki/manager/PushManager.java b/src/main/java/de/liebki/manager/PushManager.java index 35df3b5..16dfc7f 100644 --- a/src/main/java/de/liebki/manager/PushManager.java +++ b/src/main/java/de/liebki/manager/PushManager.java @@ -19,19 +19,24 @@ public PushManager(Start plugin) { this.plugin = plugin; } + /** + * To send a certain message to ntfy.sh to be pushed to all subscribers + * + * @param content The message to push + */ public void SendMessage(String content) { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://ntfy.sh/" + (String) plugin.config.get("donottouch.pushchannel"))) + .uri(URI.create("http://ntfy.sh/" + plugin.config.get("donottouch.pushchannel"))) .POST(BodyPublishers.ofString(content)) - .setHeader("Title", (String) plugin.config.get("messages.general.title")) + .setHeader("Title", plugin.config.get("messages.general.title")) .setHeader("Priority", "urgent").setHeader("Content-Type", "application/x-www-form-urlencoded").build(); try { client.send(request, HttpResponse.BodyHandlers.ofString()); } catch (IOException | InterruptedException e) { - Bukkit.getConsoleSender().sendMessage("The message could not be sent using the push service!"); + Bukkit.getConsoleSender().sendMessage("Error in SendMessage(): \n" + e.getMessage()); } } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 4e096e5..7a8357a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,6 @@ name: SimplePushEvents main: de.liebki.Start -version: 0.0.4 +version: 0.0.5 api-version: "1.16" -commands: \ No newline at end of file +commands: + spe: \ No newline at end of file