|
|
|
|
@@ -29,6 +29,7 @@ import org.bukkit.inventory.Inventory;
|
|
|
|
|
import org.bukkit.inventory.ItemStack;
|
|
|
|
|
import org.bukkit.plugin.Plugin;
|
|
|
|
|
import org.bukkit.plugin.java.JavaPlugin;
|
|
|
|
|
import org.bukkit.projectiles.ProjectileSource;
|
|
|
|
|
|
|
|
|
|
import java.sql.*;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
@@ -41,6 +42,7 @@ import java.util.stream.Collectors;
|
|
|
|
|
public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
|
|
|
|
|
private static CoreProtectAPI coreProtectAPI;
|
|
|
|
|
private final String DB_FILE = "ignored_locations.db";
|
|
|
|
|
private Integer identicalAlerts = 1;
|
|
|
|
|
private String lastAlert;
|
|
|
|
|
private Set<Material> EXCLUDED_BLOCKS;
|
|
|
|
|
@@ -49,10 +51,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
private Boolean ALLOW_STEALING;
|
|
|
|
|
private Connection connection;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
UTILITY FUNCTIONS
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
@@ -73,7 +71,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// If we see a break before a placement, stop (block is gone)
|
|
|
|
|
if (parseResult.getActionId() == 0 && !parseResult.isRolledBack()) {
|
|
|
|
|
if (parseResult.getActionId() == 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -93,65 +91,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
return world;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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() && mapLink != null) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
INITIALIZATION
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Init GriefAlert
|
|
|
|
|
@Override
|
|
|
|
|
public void onEnable() {
|
|
|
|
|
@@ -193,22 +132,16 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setupDatabase() {
|
|
|
|
|
String jdbcUrl = getConfig().getString("jdbc-url");
|
|
|
|
|
try {
|
|
|
|
|
connection = DriverManager.getConnection(jdbcUrl);
|
|
|
|
|
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();
|
|
|
|
|
getLogger().info("Connected to "+jdbcUrl);
|
|
|
|
|
} catch (SQLException e) {
|
|
|
|
|
getLogger().severe("Could not set up SQLite database: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
LOCATION IGNORING
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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=?");
|
|
|
|
|
@@ -259,10 +192,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
EVENT LISTENERS
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
|
// Block break alerts
|
|
|
|
|
public void onBlockBreak(BlockBreakEvent event) {
|
|
|
|
|
@@ -408,7 +337,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Placing item to an item frame
|
|
|
|
|
//event handler for item frames
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
|
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
|
|
|
|
if (!(event.getRightClicked() instanceof ItemFrame frame)) return;
|
|
|
|
|
@@ -442,7 +371,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Item frame stealing alerts
|
|
|
|
|
// Breaking item frame item (uses a different event then placing an item)
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
|
public void onItemFrameDamage(EntityDamageByEntityEvent event) {
|
|
|
|
|
if (!(event.getEntity() instanceof ItemFrame frame)) return;
|
|
|
|
|
@@ -470,7 +399,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Item frame breaking alerts
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
|
public void onItemFrameBreak(HangingBreakByEntityEvent event) {
|
|
|
|
|
if (!(event.getEntity() instanceof ItemFrame frame)) return;
|
|
|
|
|
@@ -496,7 +424,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Command handler
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
|
|
|
|
if (!command.getName().equalsIgnoreCase("griefalert")) return false;
|
|
|
|
|
@@ -658,6 +585,57 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
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() && mapLink != null) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//pet alert(dog and cat only)
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void onPetKill(EntityDeathEvent event) {
|
|
|
|
|
@@ -685,7 +663,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mob killing alerts
|
|
|
|
|
//farm animal handler
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void onFarmAnimalDeath(EntityDeathEvent event) {
|
|
|
|
|
if (!(event.getEntity().getKiller() instanceof Player killer)) return;
|
|
|
|
|
@@ -721,7 +699,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
and its waxed, ill assume ur unwaxing, and therefor sending an alert
|
|
|
|
|
but some of this code was written at 1am so idk how and why im why and howing */
|
|
|
|
|
|
|
|
|
|
// Waxing/unwaxing alerts
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void onBlockClick(PlayerInteractEvent event) {
|
|
|
|
|
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
|
|
|
|
@@ -784,7 +761,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
}, 1L);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Log stripping alerts
|
|
|
|
|
//stripping logs
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void onLogStrip(PlayerInteractEvent event) {
|
|
|
|
|
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
|
|
|
|
@@ -835,9 +812,53 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|
|
|
|
}, 1L);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
CoreProtect API
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//Ender Crystal shenanigans
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void onEndCrystalDeath(EntityDamageByEntityEvent event){
|
|
|
|
|
//if its not an endercrystal it should not do logic for enderCrystal
|
|
|
|
|
if(!(event.getEntity() instanceof EnderCrystal)) return;
|
|
|
|
|
Location loc = event.getEntity().getLocation();
|
|
|
|
|
|
|
|
|
|
int x = loc.getBlockX();
|
|
|
|
|
int y = loc.getBlockY();
|
|
|
|
|
int z = loc.getBlockZ();
|
|
|
|
|
String world = loc.getWorld().getName();
|
|
|
|
|
//Placeholder
|
|
|
|
|
Player damager = null;
|
|
|
|
|
//if its a Player then its a player (damage is like sword or fist or whatever)
|
|
|
|
|
if(event.getDamager() instanceof Player player){
|
|
|
|
|
damager = player;
|
|
|
|
|
//if its not hit by a player, its from a projectile which we need ownership off
|
|
|
|
|
}else if(event.getDamager() instanceof Projectile projectile){
|
|
|
|
|
ProjectileSource source = projectile.getShooter();
|
|
|
|
|
|
|
|
|
|
if(source instanceof Player player){
|
|
|
|
|
damager = player;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(damager == null){
|
|
|
|
|
return; //idk what it is, (i do) but it wasnt a player
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isLocationIgnored(x, y, z, world)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Block block = loc.getBlock();
|
|
|
|
|
|
|
|
|
|
String target = inspectBlock(block, damager);
|
|
|
|
|
if (target == null) return;
|
|
|
|
|
//cuz Blåhaj is cute so if you damage your own stuff u gucci
|
|
|
|
|
if (target.equals(damager.getName())) return;
|
|
|
|
|
|
|
|
|
|
String message = ChatColor.GRAY + damager.getName() + " destroyed an ender crystal owned by " + target + " at " + x + " " + y + " " + z;
|
|
|
|
|
alert(message, damager.getName(), "[Map Link](" + MAP_LINK + "/?worldname=" + world + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, world);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private CoreProtectAPI getCoreProtect() {
|
|
|
|
|
Plugin plugin = getServer().getPluginManager().getPlugin("CoreProtect");
|
|
|
|
|
|