Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
110fa1c8cf | |||
79408d801b | |||
2f6b42fef4 | |||
0c21d1b645 | |||
4186a1dedf | |||
480e157e1a | |||
a340441fae | |||
c706c8d0f0 | |||
02d9dabda9 | |||
6769c8e57f | |||
11383965a8 |
9
LICENSE
Normal file
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 ArdakazMC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
plugin.yml
27
plugin.yml
@ -1,13 +1,14 @@
|
||||
name: GriefAlert
|
||||
main: net.ardakaz.griefalert.GriefAlert
|
||||
version: 0.3
|
||||
api-version: 1.21
|
||||
depends: [CoreProtect]
|
||||
description: A simple grief alert plugin using the CoreProtect API.
|
||||
authors: [Ardakaz, kleedje30]
|
||||
commands:
|
||||
griefalert:
|
||||
description: GriefAlert staff commands
|
||||
usage: /griefalert <ignore|unignore|check>
|
||||
permission: griefalert.staff
|
||||
permission-message: You do not have permission to use this command.
|
||||
name: GriefAlert
|
||||
main: net.ardakaz.griefalert.GriefAlert
|
||||
version: 0.3.2
|
||||
api-version: 1.21
|
||||
depends: [CoreProtect]
|
||||
softdepend: [DiscordSRV]
|
||||
description: A simple grief alert plugin using the CoreProtect API.
|
||||
authors: [Ardakaz, kleedje30]
|
||||
commands:
|
||||
griefalert:
|
||||
description: GriefAlert staff commands
|
||||
usage: /griefalert <ignore|unignore|check>
|
||||
permission: griefalert.staff
|
||||
permission-message: You do not have permission to use this command.
|
@ -1,491 +1,491 @@
|
||||
package net.ardakaz.griefalert;
|
||||
|
||||
import net.coreprotect.CoreProtect;
|
||||
import net.coreprotect.CoreProtectAPI;
|
||||
import net.coreprotect.CoreProtectAPI.ParseResult;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
|
||||
|
||||
private static CoreProtectAPI coreProtectAPI;
|
||||
private Integer identicalAlerts = 1;
|
||||
private String lastAlert;
|
||||
|
||||
private Set<Material> EXCLUDED_BLOCKS;
|
||||
private Set<InventoryType> VALID_CONTAINERS;
|
||||
private String MAP_LINK;
|
||||
private Boolean ALLOW_STEALING;
|
||||
|
||||
private Connection connection;
|
||||
private final String DB_FILE = "ignored_locations.db";
|
||||
|
||||
// Init GriefAlert
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
coreProtectAPI = getCoreProtect();
|
||||
if (coreProtectAPI == null) {
|
||||
getLogger().severe("CoreProtect not found! Disabling plugin.");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
getServer().getPluginManager().registerEvents(this, this);
|
||||
|
||||
// Config
|
||||
saveDefaultConfig();
|
||||
List<String> excludedBlocks = getConfig().getStringList("excluded-blocks");
|
||||
EXCLUDED_BLOCKS = excludedBlocks.stream().map(Material::valueOf).collect(Collectors.toSet());
|
||||
List<String> validContainers = getConfig().getStringList("valid-containers");
|
||||
VALID_CONTAINERS = validContainers.stream().map(InventoryType::valueOf).collect(Collectors.toSet());
|
||||
MAP_LINK = getConfig().getString("map-link");
|
||||
ALLOW_STEALING = getConfig().getBoolean("allow-stealing");
|
||||
|
||||
setupDatabase();
|
||||
|
||||
getCommand("griefalert").setTabCompleter(this);
|
||||
|
||||
getLogger().info("GriefAlert has been enabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getLogger().info("GriefAlert has been disabled.");
|
||||
if (connection != null) {
|
||||
try { connection.close(); } catch (SQLException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupDatabase() {
|
||||
try {
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + getDataFolder().getAbsolutePath() + "/" + DB_FILE);
|
||||
Statement stmt = connection.createStatement();
|
||||
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS ignored_locations (x INTEGER, y INTEGER, z INTEGER, world TEXT, PRIMARY KEY (x, y, z, world))");
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
getLogger().severe("Could not set up SQLite database: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLocationIgnored(int x, int y, int z, String world) {
|
||||
try {
|
||||
PreparedStatement ps = connection.prepareStatement("SELECT 1 FROM ignored_locations WHERE x=? AND y=? AND z=? AND world=?");
|
||||
ps.setInt(1, x);
|
||||
ps.setInt(2, y);
|
||||
ps.setInt(3, z);
|
||||
ps.setString(4, world);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
boolean exists = rs.next();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return exists;
|
||||
} catch (SQLException e) {
|
||||
getLogger().warning("DB error: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addIgnoredLocation(int x, int y, int z, String world) {
|
||||
try {
|
||||
PreparedStatement ps = connection.prepareStatement("INSERT OR IGNORE INTO ignored_locations (x, y, z, world) VALUES (?, ?, ?, ?)");
|
||||
ps.setInt(1, x);
|
||||
ps.setInt(2, y);
|
||||
ps.setInt(3, z);
|
||||
ps.setString(4, world);
|
||||
int updated = ps.executeUpdate();
|
||||
ps.close();
|
||||
return updated > 0;
|
||||
} catch (SQLException e) {
|
||||
getLogger().warning("DB error: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean removeIgnoredLocation(int x, int y, int z, String world) {
|
||||
try {
|
||||
PreparedStatement ps = connection.prepareStatement("DELETE FROM ignored_locations WHERE x=? AND y=? AND z=? AND world=?");
|
||||
ps.setInt(1, x);
|
||||
ps.setInt(2, y);
|
||||
ps.setInt(3, z);
|
||||
ps.setString(4, world);
|
||||
int updated = ps.executeUpdate();
|
||||
ps.close();
|
||||
return updated > 0;
|
||||
} catch (SQLException e) {
|
||||
getLogger().warning("DB error: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
// Block break alerts
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
// Exclusion list
|
||||
if (EXCLUDED_BLOCKS.contains(event.getBlock().getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Event parser
|
||||
String playerName = event.getPlayer().getName();
|
||||
String blockType = event.getBlock().getType().toString();
|
||||
int x = event.getBlock().getX();
|
||||
int y = event.getBlock().getY();
|
||||
int z = event.getBlock().getZ();
|
||||
String worldName = event.getBlock().getWorld().getName();
|
||||
|
||||
// Check if grief
|
||||
String target = inspectBlock(event.getBlock(), event.getPlayer());
|
||||
if (target != null) {
|
||||
String message = ChatColor.GRAY + playerName + " broke " + blockType + " placed by " + target + " at " + x + " " + y + " " + z + getHumanWorldName(worldName);
|
||||
alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
|
||||
}
|
||||
}
|
||||
|
||||
// Stealing alerts
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (ALLOW_STEALING) {
|
||||
return;
|
||||
}
|
||||
boolean stealing;
|
||||
|
||||
// Event parser for inv
|
||||
if (!(event.getWhoClicked() instanceof Player)) return;
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
Inventory inventory = event.getInventory();
|
||||
Inventory clickedInventory = event.getClickedInventory();
|
||||
ItemStack item = event.getCurrentItem();
|
||||
|
||||
if (item == null || inventory.getLocation() == null || item.getType() == Material.AIR) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exclusion list
|
||||
if (!VALID_CONTAINERS.contains(inventory.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inv actions (needs fixing)
|
||||
InventoryAction action = event.getAction();
|
||||
if ((action == InventoryAction.PICKUP_ALL || action == InventoryAction.PICKUP_HALF ||
|
||||
action == InventoryAction.PICKUP_ONE || action == InventoryAction.PICKUP_SOME ||
|
||||
action == InventoryAction.MOVE_TO_OTHER_INVENTORY) && clickedInventory == inventory) {
|
||||
stealing = true;
|
||||
} else if (action == InventoryAction.PLACE_ALL || action == InventoryAction.PLACE_SOME ||
|
||||
action == InventoryAction.PLACE_ONE || (action == InventoryAction.MOVE_TO_OTHER_INVENTORY && clickedInventory != inventory)) {
|
||||
stealing = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Event parser for container + check if grief
|
||||
String target = inspectBlock(inventory.getLocation().getBlock(), player);
|
||||
if (target != null) {
|
||||
String playerName = player.getName();
|
||||
String itemName = item.getType().toString();
|
||||
int amount = item.getAmount();
|
||||
int x = inventory.getLocation().getBlockX();
|
||||
int y = inventory.getLocation().getBlockY();
|
||||
int z = inventory.getLocation().getBlockZ();
|
||||
String worldName = inventory.getLocation().getWorld().getName();
|
||||
if (stealing) {
|
||||
String message = ChatColor.GRAY + playerName + " took " + amount + " " + itemName + " from " + target + "'s container at " + x + " " + y + " " + z + getHumanWorldName(worldName);
|
||||
alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
|
||||
} else {
|
||||
String message = ChatColor.GRAY + playerName + " put " + amount + " " + itemName + " into " + target + "'s container at " + x + " " + y + " " + z + getHumanWorldName(worldName);
|
||||
alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!command.getName().equalsIgnoreCase("griefalert")) return false;
|
||||
if (args.length == 0) return false;
|
||||
String sub = args[0].toLowerCase();
|
||||
if (sub.equals("ignore")) {
|
||||
if (!sender.hasPermission("griefalert.staff.ignore")) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission.");
|
||||
return true;
|
||||
}
|
||||
String world;
|
||||
int x, y, z;
|
||||
if (args.length == 4) {
|
||||
// /griefalert ignore x y z (use sender's world)
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
|
||||
return true;
|
||||
}
|
||||
world = ((Player)sender).getWorld().getName();
|
||||
try {
|
||||
x = Integer.parseInt(args[1]);
|
||||
y = Integer.parseInt(args[2]);
|
||||
z = Integer.parseInt(args[3]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else if (args.length == 5) {
|
||||
// /griefalert ignore world x y z
|
||||
world = args[1];
|
||||
try {
|
||||
x = Integer.parseInt(args[2]);
|
||||
y = Integer.parseInt(args[3]);
|
||||
z = Integer.parseInt(args[4]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Usage: /griefalert ignore <world> <x> <y> <z> or /griefalert ignore <x> <y> <z>");
|
||||
return true;
|
||||
}
|
||||
boolean result = addIgnoredLocation(x, y, z, world);
|
||||
if (result) {
|
||||
sender.sendMessage(ChatColor.GREEN + "Location ignored.");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.YELLOW + "Location was already ignored.");
|
||||
}
|
||||
return true;
|
||||
} else if (sub.equals("unignore")) {
|
||||
if (!sender.hasPermission("griefalert.staff.UnIgnore")) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission.");
|
||||
return true;
|
||||
}
|
||||
String world;
|
||||
int x, y, z;
|
||||
if (args.length == 4) {
|
||||
// /griefalert unignore x y z (use sender's world)
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
|
||||
return true;
|
||||
}
|
||||
world = ((Player)sender).getWorld().getName();
|
||||
try {
|
||||
x = Integer.parseInt(args[1]);
|
||||
y = Integer.parseInt(args[2]);
|
||||
z = Integer.parseInt(args[3]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be valid.");
|
||||
return true;
|
||||
}
|
||||
} else if (args.length == 5) {
|
||||
// /griefalert unignore world x y z
|
||||
world = args[1];
|
||||
try {
|
||||
x = Integer.parseInt(args[2]);
|
||||
y = Integer.parseInt(args[3]);
|
||||
z = Integer.parseInt(args[4]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Usage: /griefalert unignore <world> <x> <y> <z> or /griefalert unignore <x> <y> <z>");
|
||||
return true;
|
||||
}
|
||||
boolean result = removeIgnoredLocation(x, y, z, world);
|
||||
if (result) {
|
||||
sender.sendMessage(ChatColor.GREEN + "Location unignored.");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.YELLOW + "Location was not ignored.");
|
||||
}
|
||||
return true;
|
||||
} else if (sub.equals("check")) {
|
||||
// /griefalert check <world> <x> <y> <z> or /griefalert check <x> <y> <z>
|
||||
String world;
|
||||
int x, y, z;
|
||||
if (args.length == 4) {
|
||||
// /griefalert check x y z (use sender's world)
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
|
||||
return true;
|
||||
}
|
||||
world = ((Player)sender).getWorld().getName();
|
||||
try {
|
||||
x = Integer.parseInt(args[1]);
|
||||
y = Integer.parseInt(args[2]);
|
||||
z = Integer.parseInt(args[3]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else if (args.length == 5) {
|
||||
// /griefalert check world x y z
|
||||
world = args[1];
|
||||
try {
|
||||
x = Integer.parseInt(args[2]);
|
||||
y = Integer.parseInt(args[3]);
|
||||
z = Integer.parseInt(args[4]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Usage: /griefalert check <world>(optional) <x> <y> <z> ");
|
||||
return true;
|
||||
}
|
||||
boolean ignored = isLocationIgnored(x, y, z, world);
|
||||
if (ignored) {
|
||||
sender.sendMessage(ChatColor.YELLOW + "GriefAlert is DISABLED at " + x + ", " + y + ", " + z + " in " + world + ".");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.GREEN + "GriefAlert is ENABLED at " + x + ", " + y + ", " + z + " in " + world + ".");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
sender.sendMessage(ChatColor.RED + "Unknown subcommand. Use: ignore, unignore, check");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (!command.getName().equalsIgnoreCase("griefalert")) return null;
|
||||
java.util.List<String> completions = new java.util.ArrayList<>();
|
||||
if (args.length == 1) {
|
||||
java.util.List<String> subs = java.util.Arrays.asList("ignore", "unignore", "check");
|
||||
for (String s : subs) {
|
||||
if (s.startsWith(args[0].toLowerCase())) completions.add(s);
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
if (args.length == 2 && (args[0].equalsIgnoreCase("ignore") || args[0].equalsIgnoreCase("unignore") || args[0].equalsIgnoreCase("check"))) {
|
||||
// Suggest world names for the 2nd argument
|
||||
for (org.bukkit.World world : org.bukkit.Bukkit.getWorlds()) {
|
||||
completions.add(world.getName());
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
// Optionally, you could add number tab completion for coordinates, but it's not necessary
|
||||
return null;
|
||||
}
|
||||
|
||||
// Sends the alert (or cancels it)
|
||||
private void alert(String message, String playerName, String mapLink, String target, int x, int y, int z, String world) {
|
||||
// Exclude trusted people
|
||||
Player griefer = Bukkit.getPlayer(playerName);
|
||||
if (griefer.hasPermission("griefalert.exclude") || griefer.hasPermission("griefalert.exclude." + target)) {
|
||||
return;
|
||||
}
|
||||
// Spam limiter
|
||||
String realAlertMessage = message;
|
||||
String[] alert1 = null;
|
||||
if (lastAlert != null) {
|
||||
alert1 = lastAlert.split(" ");
|
||||
}
|
||||
String[] alert2 = message.split(" ");
|
||||
if (alert1 != null) {
|
||||
if (alert1[2].equals(alert2[2]) && alert1[5].equals(alert2[5]) && alert1[1].equals("broke") && alert2[1].equals("broke")) {
|
||||
identicalAlerts += 1;
|
||||
} else if (Arrays.equals(alert1, alert2)) {
|
||||
identicalAlerts += 1;
|
||||
} else {
|
||||
identicalAlerts = 1;
|
||||
}
|
||||
}
|
||||
if (identicalAlerts == 4) {
|
||||
message = ChatColor.GRAY + "Same behavior continues.";
|
||||
mapLink = null;
|
||||
}
|
||||
if (identicalAlerts > 4) {
|
||||
return;
|
||||
}
|
||||
// Use direct location check
|
||||
if (world != null && isLocationIgnored(x, y, z, world)) {
|
||||
return; // Do not alert if location is ignored
|
||||
}
|
||||
// Send an event for external hooks
|
||||
GriefAlertEvent griefalert_event;
|
||||
if (mapLink != null && !mapLink.isEmpty()) {
|
||||
griefalert_event = new GriefAlertEvent(message + " (" + mapLink + ")");
|
||||
} else {
|
||||
griefalert_event = new GriefAlertEvent(message);
|
||||
}
|
||||
getServer().getPluginManager().callEvent(griefalert_event);
|
||||
// Notify staff ingame
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.hasPermission("griefalert.notify")) {
|
||||
player.sendMessage(message);
|
||||
}
|
||||
}
|
||||
lastAlert = realAlertMessage;
|
||||
}
|
||||
|
||||
// Block inspector: only the most recent placement counts for ownership.
|
||||
private static String inspectBlock(Block block, Player player) {
|
||||
List<String[]> lookup = coreProtectAPI.blockLookup(block, 50000000);
|
||||
if (lookup == null || lookup.size() == 0) {
|
||||
// Natural block
|
||||
return null;
|
||||
}
|
||||
// Find the most recent placement event only
|
||||
for (String[] result : lookup) {
|
||||
ParseResult parseResult = coreProtectAPI.parseResult(result);
|
||||
if (parseResult == null) continue;
|
||||
if (parseResult.getActionId() == 1 && !parseResult.isRolledBack() && !parseResult.getPlayer().startsWith("#")) {
|
||||
// If the current player placed it, it's theirs (no alert)
|
||||
if (parseResult.getPlayer().equals(player.getName())) {
|
||||
return null;
|
||||
} else {
|
||||
return parseResult.getPlayer();
|
||||
}
|
||||
}
|
||||
// If we see a break before a placement, stop (block is gone)
|
||||
if (parseResult.getActionId() == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// No valid placement found
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getHumanWorldName(String worldName) {
|
||||
String world = "";
|
||||
|
||||
if (worldName.endsWith("_nether")) {
|
||||
world = " in the Nether";
|
||||
}
|
||||
else if (worldName.endsWith("_the_end")) {
|
||||
world = " in the End";
|
||||
}
|
||||
|
||||
return world;
|
||||
}
|
||||
|
||||
private CoreProtectAPI getCoreProtect() {
|
||||
Plugin plugin = getServer().getPluginManager().getPlugin("CoreProtect");
|
||||
|
||||
if (plugin == null || !(plugin instanceof CoreProtect)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ((CoreProtect) plugin).getAPI();
|
||||
}
|
||||
package net.ardakaz.griefalert;
|
||||
|
||||
import net.coreprotect.CoreProtect;
|
||||
import net.coreprotect.CoreProtectAPI;
|
||||
import net.coreprotect.CoreProtectAPI.ParseResult;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
|
||||
|
||||
private static CoreProtectAPI coreProtectAPI;
|
||||
private Integer identicalAlerts = 1;
|
||||
private String lastAlert;
|
||||
|
||||
private Set<Material> EXCLUDED_BLOCKS;
|
||||
private Set<InventoryType> VALID_CONTAINERS;
|
||||
private String MAP_LINK;
|
||||
private Boolean ALLOW_STEALING;
|
||||
|
||||
private Connection connection;
|
||||
private final String DB_FILE = "ignored_locations.db";
|
||||
|
||||
// Init GriefAlert
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
coreProtectAPI = getCoreProtect();
|
||||
if (coreProtectAPI == null) {
|
||||
getLogger().severe("CoreProtect not found! Disabling plugin.");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
getServer().getPluginManager().registerEvents(this, this);
|
||||
|
||||
// Config
|
||||
saveDefaultConfig();
|
||||
List<String> excludedBlocks = getConfig().getStringList("excluded-blocks");
|
||||
EXCLUDED_BLOCKS = excludedBlocks.stream().map(Material::valueOf).collect(Collectors.toSet());
|
||||
List<String> validContainers = getConfig().getStringList("valid-containers");
|
||||
VALID_CONTAINERS = validContainers.stream().map(InventoryType::valueOf).collect(Collectors.toSet());
|
||||
MAP_LINK = getConfig().getString("map-link");
|
||||
ALLOW_STEALING = getConfig().getBoolean("allow-stealing");
|
||||
|
||||
setupDatabase();
|
||||
|
||||
getCommand("griefalert").setTabCompleter(this);
|
||||
|
||||
getLogger().info("GriefAlert has been enabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getLogger().info("GriefAlert has been disabled.");
|
||||
if (connection != null) {
|
||||
try { connection.close(); } catch (SQLException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupDatabase() {
|
||||
try {
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + getDataFolder().getAbsolutePath() + "/" + DB_FILE);
|
||||
Statement stmt = connection.createStatement();
|
||||
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS ignored_locations (x INTEGER, y INTEGER, z INTEGER, world TEXT, PRIMARY KEY (x, y, z, world))");
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
getLogger().severe("Could not set up SQLite database: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLocationIgnored(int x, int y, int z, String world) {
|
||||
try {
|
||||
PreparedStatement ps = connection.prepareStatement("SELECT 1 FROM ignored_locations WHERE x=? AND y=? AND z=? AND world=?");
|
||||
ps.setInt(1, x);
|
||||
ps.setInt(2, y);
|
||||
ps.setInt(3, z);
|
||||
ps.setString(4, world);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
boolean exists = rs.next();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return exists;
|
||||
} catch (SQLException e) {
|
||||
getLogger().warning("DB error: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addIgnoredLocation(int x, int y, int z, String world) {
|
||||
try {
|
||||
PreparedStatement ps = connection.prepareStatement("INSERT OR IGNORE INTO ignored_locations (x, y, z, world) VALUES (?, ?, ?, ?)");
|
||||
ps.setInt(1, x);
|
||||
ps.setInt(2, y);
|
||||
ps.setInt(3, z);
|
||||
ps.setString(4, world);
|
||||
int updated = ps.executeUpdate();
|
||||
ps.close();
|
||||
return updated > 0;
|
||||
} catch (SQLException e) {
|
||||
getLogger().warning("DB error: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean removeIgnoredLocation(int x, int y, int z, String world) {
|
||||
try {
|
||||
PreparedStatement ps = connection.prepareStatement("DELETE FROM ignored_locations WHERE x=? AND y=? AND z=? AND world=?");
|
||||
ps.setInt(1, x);
|
||||
ps.setInt(2, y);
|
||||
ps.setInt(3, z);
|
||||
ps.setString(4, world);
|
||||
int updated = ps.executeUpdate();
|
||||
ps.close();
|
||||
return updated > 0;
|
||||
} catch (SQLException e) {
|
||||
getLogger().warning("DB error: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
// Block break alerts
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
// Exclusion list
|
||||
if (EXCLUDED_BLOCKS.contains(event.getBlock().getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Event parser
|
||||
String playerName = event.getPlayer().getName();
|
||||
String blockType = event.getBlock().getType().toString();
|
||||
int x = event.getBlock().getX();
|
||||
int y = event.getBlock().getY();
|
||||
int z = event.getBlock().getZ();
|
||||
String worldName = event.getBlock().getWorld().getName();
|
||||
|
||||
// Check if grief
|
||||
String target = inspectBlock(event.getBlock(), event.getPlayer());
|
||||
if (target != null) {
|
||||
String message = ChatColor.GRAY + playerName + " broke " + blockType + " placed by " + target + " at " + x + " " + y + " " + z + getHumanWorldName(worldName);
|
||||
alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
|
||||
}
|
||||
}
|
||||
|
||||
// Stealing alerts
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (ALLOW_STEALING) {
|
||||
return;
|
||||
}
|
||||
boolean stealing;
|
||||
|
||||
// Event parser for inv
|
||||
if (!(event.getWhoClicked() instanceof Player)) return;
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
Inventory inventory = event.getInventory();
|
||||
Inventory clickedInventory = event.getClickedInventory();
|
||||
ItemStack item = event.getCurrentItem();
|
||||
|
||||
if (item == null || inventory.getLocation() == null || item.getType() == Material.AIR) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exclusion list
|
||||
if (!VALID_CONTAINERS.contains(inventory.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inv actions (needs fixing)
|
||||
InventoryAction action = event.getAction();
|
||||
if ((action == InventoryAction.PICKUP_ALL || action == InventoryAction.PICKUP_HALF ||
|
||||
action == InventoryAction.PICKUP_ONE || action == InventoryAction.PICKUP_SOME ||
|
||||
action == InventoryAction.MOVE_TO_OTHER_INVENTORY) && clickedInventory == inventory) {
|
||||
stealing = true;
|
||||
} else if (action == InventoryAction.PLACE_ALL || action == InventoryAction.PLACE_SOME ||
|
||||
action == InventoryAction.PLACE_ONE || (action == InventoryAction.MOVE_TO_OTHER_INVENTORY && clickedInventory != inventory)) {
|
||||
stealing = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Event parser for container + check if grief
|
||||
String target = inspectBlock(inventory.getLocation().getBlock(), player);
|
||||
if (target != null) {
|
||||
String playerName = player.getName();
|
||||
String itemName = item.getType().toString();
|
||||
int amount = item.getAmount();
|
||||
int x = inventory.getLocation().getBlockX();
|
||||
int y = inventory.getLocation().getBlockY();
|
||||
int z = inventory.getLocation().getBlockZ();
|
||||
String worldName = inventory.getLocation().getWorld().getName();
|
||||
if (stealing) {
|
||||
String message = ChatColor.GRAY + playerName + " took " + amount + " " + itemName + " from " + target + "'s container at " + x + " " + y + " " + z + getHumanWorldName(worldName);
|
||||
alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
|
||||
} else {
|
||||
String message = ChatColor.GRAY + playerName + " put " + amount + " " + itemName + " into " + target + "'s container at " + x + " " + y + " " + z + getHumanWorldName(worldName);
|
||||
alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!command.getName().equalsIgnoreCase("griefalert")) return false;
|
||||
if (args.length == 0) return false;
|
||||
String sub = args[0].toLowerCase();
|
||||
if (sub.equals("ignore")) {
|
||||
if (!sender.hasPermission("griefalert.staff.ignore")) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission.");
|
||||
return true;
|
||||
}
|
||||
String world;
|
||||
int x, y, z;
|
||||
if (args.length == 4) {
|
||||
// /griefalert ignore x y z (use sender's world)
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
|
||||
return true;
|
||||
}
|
||||
world = ((Player)sender).getWorld().getName();
|
||||
try {
|
||||
x = Integer.parseInt(args[1]);
|
||||
y = Integer.parseInt(args[2]);
|
||||
z = Integer.parseInt(args[3]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else if (args.length == 5) {
|
||||
// /griefalert ignore world x y z
|
||||
world = args[1];
|
||||
try {
|
||||
x = Integer.parseInt(args[2]);
|
||||
y = Integer.parseInt(args[3]);
|
||||
z = Integer.parseInt(args[4]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Usage: /griefalert ignore <world> <x> <y> <z> or /griefalert ignore <x> <y> <z>");
|
||||
return true;
|
||||
}
|
||||
boolean result = addIgnoredLocation(x, y, z, world);
|
||||
if (result) {
|
||||
sender.sendMessage(ChatColor.GREEN + "Location ignored.");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.YELLOW + "Location was already ignored.");
|
||||
}
|
||||
return true;
|
||||
} else if (sub.equals("unignore")) {
|
||||
if (!sender.hasPermission("griefalert.staff.UnIgnore")) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission.");
|
||||
return true;
|
||||
}
|
||||
String world;
|
||||
int x, y, z;
|
||||
if (args.length == 4) {
|
||||
// /griefalert unignore x y z (use sender's world)
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
|
||||
return true;
|
||||
}
|
||||
world = ((Player)sender).getWorld().getName();
|
||||
try {
|
||||
x = Integer.parseInt(args[1]);
|
||||
y = Integer.parseInt(args[2]);
|
||||
z = Integer.parseInt(args[3]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be valid.");
|
||||
return true;
|
||||
}
|
||||
} else if (args.length == 5) {
|
||||
// /griefalert unignore world x y z
|
||||
world = args[1];
|
||||
try {
|
||||
x = Integer.parseInt(args[2]);
|
||||
y = Integer.parseInt(args[3]);
|
||||
z = Integer.parseInt(args[4]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Usage: /griefalert unignore <world> <x> <y> <z> or /griefalert unignore <x> <y> <z>");
|
||||
return true;
|
||||
}
|
||||
boolean result = removeIgnoredLocation(x, y, z, world);
|
||||
if (result) {
|
||||
sender.sendMessage(ChatColor.GREEN + "Location unignored.");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.YELLOW + "Location was not ignored.");
|
||||
}
|
||||
return true;
|
||||
} else if (sub.equals("check")) {
|
||||
// /griefalert check <world> <x> <y> <z> or /griefalert check <x> <y> <z>
|
||||
String world;
|
||||
int x, y, z;
|
||||
if (args.length == 4) {
|
||||
// /griefalert check x y z (use sender's world)
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
|
||||
return true;
|
||||
}
|
||||
world = ((Player)sender).getWorld().getName();
|
||||
try {
|
||||
x = Integer.parseInt(args[1]);
|
||||
y = Integer.parseInt(args[2]);
|
||||
z = Integer.parseInt(args[3]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else if (args.length == 5) {
|
||||
// /griefalert check world x y z
|
||||
world = args[1];
|
||||
try {
|
||||
x = Integer.parseInt(args[2]);
|
||||
y = Integer.parseInt(args[3]);
|
||||
z = Integer.parseInt(args[4]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Coordinates must be numbers.");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Usage: /griefalert check <world>(optional) <x> <y> <z> ");
|
||||
return true;
|
||||
}
|
||||
boolean ignored = isLocationIgnored(x, y, z, world);
|
||||
if (ignored) {
|
||||
sender.sendMessage(ChatColor.YELLOW + "GriefAlert is DISABLED at " + x + ", " + y + ", " + z + " in " + world + ".");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.GREEN + "GriefAlert is ENABLED at " + x + ", " + y + ", " + z + " in " + world + ".");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
sender.sendMessage(ChatColor.RED + "Unknown subcommand. Use: ignore, unignore, check");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (!command.getName().equalsIgnoreCase("griefalert")) return null;
|
||||
java.util.List<String> completions = new java.util.ArrayList<>();
|
||||
if (args.length == 1) {
|
||||
java.util.List<String> subs = java.util.Arrays.asList("ignore", "unignore", "check");
|
||||
for (String s : subs) {
|
||||
if (s.startsWith(args[0].toLowerCase())) completions.add(s);
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
if (args.length == 2 && (args[0].equalsIgnoreCase("ignore") || args[0].equalsIgnoreCase("unignore") || args[0].equalsIgnoreCase("check"))) {
|
||||
// Suggest world names for the 2nd argument
|
||||
for (org.bukkit.World world : org.bukkit.Bukkit.getWorlds()) {
|
||||
completions.add(world.getName());
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
// Optionally, you could add number tab completion for coordinates, but it's not necessary
|
||||
return null;
|
||||
}
|
||||
|
||||
// Sends the alert (or cancels it)
|
||||
private void alert(String message, String playerName, String mapLink, String target, int x, int y, int z, String world) {
|
||||
// Exclude trusted people
|
||||
Player griefer = Bukkit.getPlayer(playerName);
|
||||
if (griefer.hasPermission("griefalert.exclude") || griefer.hasPermission("griefalert.exclude." + target)) {
|
||||
return;
|
||||
}
|
||||
// Spam limiter
|
||||
String realAlertMessage = message;
|
||||
String[] alert1 = null;
|
||||
if (lastAlert != null) {
|
||||
alert1 = lastAlert.split(" ");
|
||||
}
|
||||
String[] alert2 = message.split(" ");
|
||||
if (alert1 != null) {
|
||||
if (alert1[2].equals(alert2[2]) && alert1[5].equals(alert2[5]) && alert1[1].equals("broke") && alert2[1].equals("broke")) {
|
||||
identicalAlerts += 1;
|
||||
} else if (Arrays.equals(alert1, alert2)) {
|
||||
identicalAlerts += 1;
|
||||
} else {
|
||||
identicalAlerts = 1;
|
||||
}
|
||||
}
|
||||
if (identicalAlerts == 4) {
|
||||
message = ChatColor.GRAY + "Same behavior continues.";
|
||||
mapLink = null;
|
||||
}
|
||||
if (identicalAlerts > 4) {
|
||||
return;
|
||||
}
|
||||
// Use direct location check
|
||||
if (world != null && isLocationIgnored(x, y, z, world)) {
|
||||
return; // Do not alert if location is ignored
|
||||
}
|
||||
// Send an event for external hooks
|
||||
GriefAlertEvent griefalert_event;
|
||||
if (MAP_LINK != null && !MAP_LINK.isEmpty()) {
|
||||
griefalert_event = new GriefAlertEvent(message + " (" + mapLink + ")");
|
||||
} else {
|
||||
griefalert_event = new GriefAlertEvent(message);
|
||||
}
|
||||
getServer().getPluginManager().callEvent(griefalert_event);
|
||||
// Notify staff ingame
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.hasPermission("griefalert.notify")) {
|
||||
player.sendMessage(message);
|
||||
}
|
||||
}
|
||||
lastAlert = realAlertMessage;
|
||||
}
|
||||
|
||||
// Block inspector: only the most recent placement counts for ownership.
|
||||
private static String inspectBlock(Block block, Player player) {
|
||||
List<String[]> lookup = coreProtectAPI.blockLookup(block, 50000000);
|
||||
if (lookup == null || lookup.size() == 0) {
|
||||
// Natural block
|
||||
return null;
|
||||
}
|
||||
// Find the most recent placement event only
|
||||
for (String[] result : lookup) {
|
||||
ParseResult parseResult = coreProtectAPI.parseResult(result);
|
||||
if (parseResult == null) continue;
|
||||
if (parseResult.getActionId() == 1 && !parseResult.isRolledBack() && !parseResult.getPlayer().startsWith("#")) {
|
||||
// If the current player placed it, it's theirs (no alert)
|
||||
if (parseResult.getPlayer().equals(player.getName())) {
|
||||
return null;
|
||||
} else {
|
||||
return parseResult.getPlayer();
|
||||
}
|
||||
}
|
||||
// If we see a break before a placement, stop (block is gone)
|
||||
if (parseResult.getActionId() == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// No valid placement found
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getHumanWorldName(String worldName) {
|
||||
String world = "";
|
||||
|
||||
if (worldName.endsWith("_nether")) {
|
||||
world = " in the Nether";
|
||||
}
|
||||
else if (worldName.endsWith("_the_end")) {
|
||||
world = " in the End";
|
||||
}
|
||||
|
||||
return world;
|
||||
}
|
||||
|
||||
private CoreProtectAPI getCoreProtect() {
|
||||
Plugin plugin = getServer().getPluginManager().getPlugin("CoreProtect");
|
||||
|
||||
if (plugin == null || !(plugin instanceof CoreProtect)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ((CoreProtect) plugin).getAPI();
|
||||
}
|
||||
}
|
@ -1,28 +1,34 @@
|
||||
// "API" for other plugins
|
||||
|
||||
package net.ardakaz.griefalert;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
public class GriefAlertEvent extends Event {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private String alert = "";
|
||||
|
||||
public GriefAlertEvent(String alert) {
|
||||
this.alert = alert;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
public String getAlert() {
|
||||
return this.alert;
|
||||
}
|
||||
// "API" for other plugins
|
||||
|
||||
package net.ardakaz.griefalert;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
public class GriefAlertEvent extends Event {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private String alert = "";
|
||||
|
||||
public GriefAlertEvent(String alert) {
|
||||
this.alert = alert;
|
||||
|
||||
// Discord hook for 1.21.5
|
||||
if (Bukkit.getServer().getPluginManager().getPlugin("DiscordSRV") != null) {
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "discord broadcast #grief-alerts " + this.getAlert());
|
||||
}
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
public String getAlert() {
|
||||
return this.alert;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user