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.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.PlayerInteractAtEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import java.sql.*; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; public class GriefAlert extends JavaPlugin implements Listener { private static CoreProtectAPI coreProtectAPI; private Integer identicalAlerts = 1; private String lastAlert; private Set EXCLUDED_BLOCKS; private Set VALID_CONTAINERS; private String MAP_LINK; 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 lookup = coreProtectAPI.blockLookup(block, 50000000); if (lookup == null || lookup.isEmpty()) { // 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 && !parseResult.isRolledBack()) { 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; } // 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() { 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 excludedBlocks = getConfig().getStringList("excluded-blocks"); EXCLUDED_BLOCKS = excludedBlocks.stream().map(Material::valueOf).collect(Collectors.toSet()); List 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() { String jdbcUrl = getConfig().getString("jdbc-url"); try { connection = DriverManager.getConnection(jdbcUrl); Statement stmt = connection.createStatement(); stmt.executeUpdate(Migrations.CREATE_TABLE_IGNORED_LOCATIONS); stmt.executeUpdate(Migrations.CREATE_TABLE_PLAYERS); stmt.executeUpdate(Migrations.CREATE_TABLE_ACTIONS); stmt.executeUpdate(Migrations.CREATE_TABLE_ALERTS); stmt.executeUpdate(Migrations.CREATE_TABLE_REPORTS); 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=?"); 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; } } /* EVENT LISTENERS */ @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 player)) return; 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) { 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); } } } // Armor Stand break alerts @EventHandler(ignoreCancelled = true) public void onArmorStandBreak(EntityDeathEvent event) { if (!(event.getEntity() instanceof ArmorStand armorStand)) return; if(!(event.getDamageSource().getCausingEntity() instanceof Player player)) return; int x = armorStand.getLocation().getBlockX(); int y = armorStand.getLocation().getBlockY(); int z = armorStand.getLocation().getBlockZ(); String worldName = armorStand.getWorld().getName(); if (isLocationIgnored(x, y, z, worldName)) { return; } String playerName = player.getName(); String target = inspectBlock(armorStand.getLocation().getBlock(), player); if (target != null) { String message = ChatColor.GRAY + playerName + " broke an armor stand 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); } } // Armor Stand item interaction alerts @EventHandler(ignoreCancelled = true) public void onArmorStandInteract(PlayerInteractAtEntityEvent event) { if (!(event.getRightClicked() instanceof ArmorStand armorStand)) return; Player player = event.getPlayer(); int x = armorStand.getLocation().getBlockX(); int y = armorStand.getLocation().getBlockY(); int z = armorStand.getLocation().getBlockZ(); String worldName = armorStand.getWorld().getName(); if (isLocationIgnored(x, y, z, worldName)) { return; } String target = inspectBlock(armorStand.getLocation().getBlock(), player); if (target != null) { String playerName = player.getName(); ItemStack handItem = player.getInventory().getItemInMainHand(); // Determine which slot is being interacted with //org.bukkit.inventory.EquipmentSlot slot = event.getHand(); EntityEquipment equipment = armorStand.getEquipment(); ItemStack armorItem = null; event.getClickedPosition();// Approximate slot by Y position (not perfect, but Bukkit API is limited so it is what it is :3) double yPos = event.getClickedPosition().getY(); if (yPos > 1.6) armorItem = equipment.getHelmet(); else if (yPos > 1.2) armorItem = equipment.getChestplate(); else if (yPos > 0.8) armorItem = equipment.getLeggings(); else if (yPos > 0.1) armorItem = equipment.getBoots(); else armorItem = equipment.getItemInMainHand(); boolean handEmpty = handItem.getType() == Material.AIR; boolean armorEmpty = armorItem == null || armorItem.getType() == Material.AIR; String action; //this works at the instance of interaction before items get moved around if (handEmpty && !armorEmpty) { action = "took " + armorItem.getType(); } else if (!handEmpty && armorEmpty) { action = "added " + handItem.getType(); } else if (!handEmpty) { action = "swapped " + armorItem.getType() + " with " + handItem.getType(); } else { action = "interacted with"; } String message = ChatColor.GRAY + playerName + " " + action + " on an armor stand 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); } } // Placing item to an item frame @EventHandler(ignoreCancelled = true) public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { if (!(event.getRightClicked() instanceof ItemFrame frame)) return; Player player = event.getPlayer(); int x = frame.getLocation().getBlockX(); int y = frame.getLocation().getBlockY(); int z = frame.getLocation().getBlockZ(); String worldName = frame.getWorld().getName(); if (isLocationIgnored(x, y, z, worldName)) { return; } String target = inspectBlock(frame.getLocation().getBlock(), player); if (target != null) { ItemStack itemInFrame = frame.getItem(); ItemStack handItem = player.getInventory().getItemInMainHand(); boolean handEmpty = handItem == null || handItem.getType() == Material.AIR; boolean frameEmpty = itemInFrame == null || itemInFrame.getType() == Material.AIR; String playerName = player.getName(); String action; if (!handEmpty && frameEmpty) { action = "added " + handItem.getType(); } else { return; } String message = ChatColor.GRAY + playerName + " " + action + " an item to an item frame 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); } } // Item frame stealing alerts @EventHandler(ignoreCancelled = true) public void onItemFrameDamage(EntityDamageByEntityEvent event) { if (!(event.getEntity() instanceof ItemFrame frame)) return; if (!(event.getDamager() instanceof Player player)) return; ItemStack item = frame.getItem(); String playerName = player.getName(); int x = frame.getLocation().getBlockX(); int y = frame.getLocation().getBlockY(); int z = frame.getLocation().getBlockZ(); String worldName = frame.getWorld().getName(); if (isLocationIgnored(x, y, z, worldName)) { return; } String target = inspectBlock(frame.getLocation().getBlock(), player); if (target == null || target.equals(player.getName())) return; if (item.getType() == Material.AIR) return; // At this point, the player is removing the item String action = "took " + item.getType(); String message = ChatColor.GRAY + playerName + " " + action + " from an item frame 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); } // Item frame breaking alerts @EventHandler(ignoreCancelled = true) public void onItemFrameBreak(HangingBreakByEntityEvent event) { if (!(event.getEntity() instanceof ItemFrame frame)) return; if (!(event.getRemover() instanceof Player player)) return; String playerName = player.getName(); Location loc = frame.getLocation(); int x = loc.getBlockX(); int y = loc.getBlockY(); int z = loc.getBlockZ(); String worldName = loc.getWorld().getName(); if (isLocationIgnored(x, y, z, worldName)) { return; } String target = inspectBlock(loc.getBlock(), player); if (target == null || target.equals(player.getName())) return; String action = "broke an item frame"; String message = ChatColor.GRAY + playerName + " " + action + " 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); } // Command handler @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 a 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 or /griefalert ignore "); 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 or /griefalert unignore "); 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 or /griefalert check 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 (optional) "); 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 onTabComplete(CommandSender sender, Command command, String alias, String[] args) { if (!command.getName().equalsIgnoreCase("griefalert")) return null; java.util.List completions = new java.util.ArrayList<>(); if (args.length == 1) { java.util.List 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; } //pet alert(dog and cat only) @EventHandler public void onPetKill(EntityDeathEvent event) { if (!(event.getEntity() instanceof Tameable tameable)) return; if (!tameable.isTamed()) return; //checks if wolf or cat or not if (!(event.getEntity() instanceof Wolf) && !(event.getEntity() instanceof Cat)) return; AnimalTamer Owner = tameable.getOwner(); if (Owner == null) return; if (!(event.getEntity().getKiller() instanceof Player killer)) return; //if owner kills nothing happens if (killer.getUniqueId().equals(Owner.getUniqueId())) return; int x = event.getEntity().getLocation().getBlockX(); int y = event.getEntity().getLocation().getBlockY(); int z = event.getEntity().getLocation().getBlockZ(); String worldName = event.getEntity().getWorld().getName(); String pet = event.getEntity().getType().name(); String message = ChatColor.GRAY + killer.getName() + " killed" + " " + pet + " in " + Owner.getName() + "'s build at " + x + " " + y + " " + z + getHumanWorldName(worldName); alert(message, killer.getName(), "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", Owner.getName(), x, y, z, worldName); } // Mob killing alerts @EventHandler public void onFarmAnimalDeath(EntityDeathEvent event) { if (!(event.getEntity().getKiller() instanceof Player killer)) return; List alertanimals = getConfig().getStringList("triggered-animals"); String typeName = event.getEntityType().name(); if (!alertanimals.contains(typeName)) return; Block blockBelow = event.getEntity().getLocation().subtract(0, 1, 0).getBlock(); String animalOwner = inspectBlock(blockBelow, killer); if (animalOwner == null) return; if (animalOwner.equals(killer.getName())) return; int x = event.getEntity().getLocation().getBlockX(); int y = event.getEntity().getLocation().getBlockY(); int z = event.getEntity().getLocation().getBlockZ(); String worldName = event.getEntity().getWorld().getName(); String message = ChatColor.GRAY + killer.getName() + " killed" + " " + typeName + " in " + animalOwner + "'s build at " + x + " " + y + " " + z + getHumanWorldName(worldName); alert(message, killer.getName(), "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", animalOwner, x, y, z, worldName); } /*code i hope for copper waxing/unwaxing theres no proper onwax() or onUnWax() so im kinda gonna try to just check a situation like, if ur holding an axe, left clicking a copper block 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; Player player = event.getPlayer(); Block block = event.getClickedBlock(); ItemStack item = event.getItem(); if (block == null || item == null) return; Material before = block.getType(); int x = block.getX(); int y = block.getY(); int z = block.getZ(); String world = block.getWorld().getName(); if (isLocationIgnored(x, y, z, world)) { return; } boolean isCopper = before.name().contains("COPPER"); //if aint copper it can no copper and means no copper affected if (!isCopper) return; //for waxing logic might not even be needed //boolean isHoneycomb = item.getType() == Material.HONEYCOMB; //for unwax logic and also might not be needed //boolean isAxe = item.getType().toString().endsWith("_AXE"); String target = inspectBlock(block, player); if (Objects.equals(target, player.getName())) return; if (target == null) return; Bukkit.getScheduler().runTaskLater(this, () -> { String action; Material after = block.getType(); if (before == after) return; boolean wasWaxed = before.name().startsWith("WAXED_"); boolean isWaxed = after.name().startsWith("WAXED_"); if (wasWaxed && !isWaxed) { action = "Unwaxed"; } else if (!wasWaxed && isWaxed) { action = "Waxed"; } else if (item != null && item.getType().name().endsWith("_AXE")) { action = "undusted"; } else { action = "error 404 check with kleedje30"; } String message = ChatColor.GRAY + player.getName() + " " + action + " Copper" + " at " + x + " " + y + " " + z + getHumanWorldName(world); alert(message, player.getName(), "[Map Link](" + MAP_LINK + "/?worldname=" + world + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, world); }, 1L); } // Log stripping alerts @EventHandler public void onLogStrip(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; Player player = event.getPlayer(); Block block = event.getClickedBlock(); ItemStack item = event.getItem(); if (block == null || item == null) return; Material before = block.getType(); int x = block.getX(); int y = block.getY(); int z = block.getZ(); String world = block.getWorld().getName(); boolean isWood = before.name().contains("LOG"); if (!isWood) return; if (isLocationIgnored(x, y, z, world)) { return; } String target = inspectBlock(block, player); if (target == null) return; if (target.equals(player.getName())) return; Bukkit.getScheduler().runTaskLater(this, () -> { String action; Material after = block.getType(); if (before == after) return; if (!before.name().contains("STRIPPED") && after.name().contains("STRIPPED")) { action = "Stripped"; } else { return; } String message = ChatColor.GRAY + player.getName() + action + " a(n) " + before + " at " + x + " " + y + " " + z + getHumanWorldName(world); alert(message, player.getName(), "[Map Link](" + MAP_LINK + "/?worldname=" + world + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, world); }, 1L); } /* CoreProtect API */ private CoreProtectAPI getCoreProtect() { Plugin plugin = getServer().getPluginManager().getPlugin("CoreProtect"); if (!(plugin instanceof CoreProtect)) { return null; } return ((CoreProtect) plugin).getAPI(); } }