4 Commits

Author SHA1 Message Date
Ardakaz
8e28ba0b87 Cleaning up 2026-05-19 15:49:03 +03:00
f59c484d6b Upload files to "src/net/ardakaz/griefalert"
added copper block waxing and unwaxing and dusting off logic, (might need a little extra rework because changing its state is considered "replacing" which sorta breaks the logic)

added log stripping detection (same issue as copper blocks)
2026-04-30 09:03:51 +00:00
c3c2113619 Doing some cleaning 2025-11-06 17:37:52 +02:00
da586e55fd Update README.md 2025-08-25 18:54:07 +00:00
4 changed files with 886 additions and 769 deletions

View File

@@ -1,3 +1,34 @@
# GriefAlert # GriefAlert
A simple grief alert plugin using CoreProtect API. GriefAlert a simple plugin that alerts the staff when someone is griefing on the server.
**CoreProtect is required for this plugin to work.** DiscordSRV is recommended.
## Features
* Alerts the staff when players break blocks, steal items or kill mobs in other players' builds.
* Alerts go to the chat of ingame staff and optionally Discord.
* Players and coordinates can be excluded from alerts.
## Permissions
* `griefalert.notify` - Gives an ability to view alerts in the chat.
* `griefalert.exclude` - Completely excludes a player from triggering alerts.
* `griefalert.exclude.<player>` - Excludes a player from triggering alerts when touching the specified player's stuff.
* `griefalert.staff` - Ability to use staff commands.
## Commands
* `/griefalert ignore [world] <x> <y> <z>` - Ignores a location from alerts.
* `/griefalert unignore [world] <x> <y> <z>`
* `/griefalert check [world] <x> <y> <z>` - Tells if a location is ignored.
## Discord support
If you have DiscordSRV installed, you can add this to it's alerts.yml:
```yaml
- Trigger: net.ardakaz.griefalert.GriefAlertEvent
Channel: grief-alerts
Content: "${getAlert()}"
```
You'll also have to specify the grief-alerts channel in config.yml.

View File

@@ -1,6 +1,6 @@
name: GriefAlert name: GriefAlert
main: net.ardakaz.griefalert.GriefAlert main: net.ardakaz.griefalert.GriefAlert
version: 0.5 version: 0.6
api-version: 1.21 api-version: 1.21
depends: [CoreProtect] depends: [CoreProtect]
softdepend: [DiscordSRV] softdepend: [DiscordSRV]

View File

@@ -3,7 +3,6 @@ package net.ardakaz.griefalert;
import net.coreprotect.CoreProtect; import net.coreprotect.CoreProtect;
import net.coreprotect.CoreProtectAPI; import net.coreprotect.CoreProtectAPI;
import net.coreprotect.CoreProtectAPI.ParseResult; import net.coreprotect.CoreProtectAPI.ParseResult;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
@@ -11,57 +10,85 @@ import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter; import org.bukkit.entity.*;
import org.bukkit.entity.AnimalTamer;
import org.bukkit.entity.Cat;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Wolf;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.player.PlayerInteractAtEntityEvent; import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent; 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.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.entity.ArmorStand;
import java.sql.Connection; import java.sql.*;
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.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.entity.ItemFrame;
public class GriefAlert extends JavaPlugin implements Listener {
public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
private static CoreProtectAPI coreProtectAPI; private static CoreProtectAPI coreProtectAPI;
private final String DB_FILE = "ignored_locations.db";
private Integer identicalAlerts = 1; private Integer identicalAlerts = 1;
private String lastAlert; private String lastAlert;
private Set<Material> EXCLUDED_BLOCKS; private Set<Material> EXCLUDED_BLOCKS;
private Set<InventoryType> VALID_CONTAINERS; private Set<InventoryType> VALID_CONTAINERS;
private String MAP_LINK; private String MAP_LINK;
private Boolean ALLOW_STEALING; private Boolean ALLOW_STEALING;
private Connection connection; private Connection connection;
private final String DB_FILE = "ignored_locations.db";
// 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.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) {
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;
}
// Init GriefAlert // Init GriefAlert
@Override @Override
@@ -96,7 +123,10 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
public void onDisable() { public void onDisable() {
getLogger().info("GriefAlert has been disabled."); getLogger().info("GriefAlert has been disabled.");
if (connection != null) { if (connection != null) {
try { connection.close(); } catch (SQLException ignored) {} try {
connection.close();
} catch (SQLException ignored) {
}
} }
} }
@@ -161,13 +191,13 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
} }
} }
@EventHandler (ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
// Block break alerts // Block break alerts
public void onBlockBreak(BlockBreakEvent event) { public void onBlockBreak(BlockBreakEvent event) {
// Exclusion list // Exclusion list
if (EXCLUDED_BLOCKS.contains(event.getBlock().getType())) { if (EXCLUDED_BLOCKS.contains(event.getBlock().getType())) {
return; return;
} }
// Event parser // Event parser
String playerName = event.getPlayer().getName(); String playerName = event.getPlayer().getName();
@@ -186,46 +216,44 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
} }
// Stealing alerts // Stealing alerts
@EventHandler (ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent event) { public void onInventoryClick(InventoryClickEvent event) {
if (ALLOW_STEALING) { if (ALLOW_STEALING) {
return; return;
} }
boolean stealing; boolean stealing;
// Event parser for inv // Event parser for inv
if (!(event.getWhoClicked() instanceof Player)) return; if (!(event.getWhoClicked() instanceof Player player)) return;
Player player = (Player) event.getWhoClicked();
Inventory inventory = event.getInventory(); Inventory inventory = event.getInventory();
Inventory clickedInventory = event.getClickedInventory(); Inventory clickedInventory = event.getClickedInventory();
ItemStack item = event.getCurrentItem(); ItemStack item = event.getCurrentItem();
if (item == null || inventory.getLocation() == null || item.getType() == Material.AIR) { if (item == null || inventory.getLocation() == null || item.getType() == Material.AIR) {
return; return;
} }
// Exclusion list // Exclusion list
if (!VALID_CONTAINERS.contains(inventory.getType())) { if (!VALID_CONTAINERS.contains(inventory.getType())) {
return; return;
} }
// Inv actions (needs fixing) // Inv actions (needs fixing)
InventoryAction action = event.getAction(); InventoryAction action = event.getAction();
if ((action == InventoryAction.PICKUP_ALL || action == InventoryAction.PICKUP_HALF || if ((action == InventoryAction.PICKUP_ALL || action == InventoryAction.PICKUP_HALF ||
action == InventoryAction.PICKUP_ONE || action == InventoryAction.PICKUP_SOME || action == InventoryAction.PICKUP_ONE || action == InventoryAction.PICKUP_SOME ||
action == InventoryAction.MOVE_TO_OTHER_INVENTORY) && clickedInventory == inventory) { action == InventoryAction.MOVE_TO_OTHER_INVENTORY) && clickedInventory == inventory) {
stealing = true; stealing = true;
} else if (action == InventoryAction.PLACE_ALL || action == InventoryAction.PLACE_SOME || } else if (action == InventoryAction.PLACE_ALL || action == InventoryAction.PLACE_SOME || action == InventoryAction.PLACE_ONE || action == InventoryAction.MOVE_TO_OTHER_INVENTORY) {
action == InventoryAction.PLACE_ONE || (action == InventoryAction.MOVE_TO_OTHER_INVENTORY && clickedInventory != inventory)) { stealing = false;
stealing = false;
} else { } else {
return; return;
} }
// Event parser for container + check if grief // Event parser for container + check if grief
String target = inspectBlock(inventory.getLocation().getBlock(), player); String target = inspectBlock(inventory.getLocation().getBlock(), player);
if (target != null) { if (target != null) {
String playerName = player.getName(); String playerName = player.getName();
String itemName = item.getType().toString(); String itemName = item.getType().toString();
int amount = item.getAmount(); int amount = item.getAmount();
int x = inventory.getLocation().getBlockX(); int x = inventory.getLocation().getBlockX();
@@ -245,10 +273,8 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
// Armor Stand break alerts // Armor Stand break alerts
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onArmorStandBreak(EntityDamageByEntityEvent event) { public void onArmorStandBreak(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof ArmorStand)) return; if (!(event.getEntity() instanceof ArmorStand armorStand)) return;
if (!(event.getDamager() instanceof Player)) return; if (!(event.getDamager() instanceof Player player)) return;
Player player = (Player) event.getDamager();
ArmorStand armorStand = (ArmorStand) event.getEntity();
int x = armorStand.getLocation().getBlockX(); int x = armorStand.getLocation().getBlockX();
int y = armorStand.getLocation().getBlockY(); int y = armorStand.getLocation().getBlockY();
int z = armorStand.getLocation().getBlockZ(); int z = armorStand.getLocation().getBlockZ();
@@ -268,9 +294,8 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
// Armor Stand item interaction alerts // Armor Stand item interaction alerts
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onArmorStandInteract(PlayerInteractAtEntityEvent event) { public void onArmorStandInteract(PlayerInteractAtEntityEvent event) {
if (!(event.getRightClicked() instanceof ArmorStand)) return; if (!(event.getRightClicked() instanceof ArmorStand armorStand)) return;
Player player = event.getPlayer(); Player player = event.getPlayer();
ArmorStand armorStand = (ArmorStand) event.getRightClicked();
int x = armorStand.getLocation().getBlockX(); int x = armorStand.getLocation().getBlockX();
int y = armorStand.getLocation().getBlockY(); int y = armorStand.getLocation().getBlockY();
int z = armorStand.getLocation().getBlockZ(); int z = armorStand.getLocation().getBlockZ();
@@ -287,41 +312,37 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
//org.bukkit.inventory.EquipmentSlot slot = event.getHand(); //org.bukkit.inventory.EquipmentSlot slot = event.getHand();
EntityEquipment equipment = armorStand.getEquipment(); EntityEquipment equipment = armorStand.getEquipment();
ItemStack armorItem = null; ItemStack armorItem = null;
if (event.getClickedPosition() != null) { event.getClickedPosition();// Approximate slot by Y position (not perfect, but Bukkit API is limited so it is what it is :3)
// Approximate slot by Y position (not perfect, but Bukkit API is limited so it is what it is :3) double yPos = event.getClickedPosition().getY();
double yPos = event.getClickedPosition().getY(); if (yPos > 1.6) armorItem = equipment.getHelmet();
if (yPos > 1.6) armorItem = equipment.getHelmet(); else if (yPos > 1.2) armorItem = equipment.getChestplate();
else if (yPos > 1.2) armorItem = equipment.getChestplate(); else if (yPos > 0.8) armorItem = equipment.getLeggings();
else if (yPos > 0.8) armorItem = equipment.getLeggings(); else if (yPos > 0.1) armorItem = equipment.getBoots();
else if (yPos > 0.1) armorItem = equipment.getBoots(); else armorItem = equipment.getItemInMainHand();
else armorItem = equipment.getItemInMainHand(); boolean handEmpty = handItem.getType() == Material.AIR;
} else {
armorItem = equipment.getItemInMainHand();
}
boolean handEmpty = handItem == null || handItem.getType() == Material.AIR;
boolean armorEmpty = armorItem == null || armorItem.getType() == Material.AIR; boolean armorEmpty = armorItem == null || armorItem.getType() == Material.AIR;
String action; String action;
//this works at the instance of interaction before items get moved around //this works at the instance of interaction before items get moved around
if (handEmpty && !armorEmpty) { if (handEmpty && !armorEmpty) {
action = "took " + armorItem.getType().toString(); action = "took " + armorItem.getType();
} else if (!handEmpty && armorEmpty) { } else if (!handEmpty && armorEmpty) {
action = "added " + handItem.getType().toString(); action = "added " + handItem.getType();
} else if (!handEmpty && !armorEmpty) { } else if (!handEmpty) {
action = "swapped " + armorItem.getType().toString() + " with " + handItem.getType().toString(); action = "swapped " + armorItem.getType() + " with " + handItem.getType();
} else { } else {
action = "interacted with"; action = "interacted with";
} }
String message = ChatColor.GRAY + playerName + " " + action + " on an armor stand owned by " + target + " at " + x + " " + y + " " + z + getHumanWorldName(worldName); 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); alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
} }
} }
//event handler for item frames //event handler for item frames
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event){ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if(!(event.getRightClicked() instanceof ItemFrame)) return; if (!(event.getRightClicked() instanceof ItemFrame frame)) return;
Player player = event.getPlayer(); Player player = event.getPlayer();
ItemFrame frame = (ItemFrame) event.getRightClicked();
int x = frame.getLocation().getBlockX(); int x = frame.getLocation().getBlockX();
int y = frame.getLocation().getBlockY(); int y = frame.getLocation().getBlockY();
int z = frame.getLocation().getBlockZ(); int z = frame.getLocation().getBlockZ();
@@ -331,37 +352,32 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
return; return;
} }
String target = inspectBlock(frame.getLocation().getBlock(), player); String target = inspectBlock(frame.getLocation().getBlock(), player);
if(target !=null){ if (target != null) {
ItemStack itemInFrame = frame.getItem(); ItemStack itemInFrame = frame.getItem();
ItemStack handItem = player.getInventory().getItemInMainHand(); ItemStack handItem = player.getInventory().getItemInMainHand();
boolean handEmpty = handItem ==null || handItem.getType() == Material.AIR; boolean handEmpty = handItem == null || handItem.getType() == Material.AIR;
boolean frameEmpty = itemInFrame ==null || itemInFrame.getType() == Material.AIR; boolean frameEmpty = itemInFrame == null || itemInFrame.getType() == Material.AIR;
String playerName = player.getName(); String playerName = player.getName();
String action; String action;
if (!handEmpty && frameEmpty) { if (!handEmpty && frameEmpty) {
action = "added " + handItem.getType(); action = "added " + handItem.getType();
} } else {
else { return;
return; }
}
String message = ChatColor.GRAY + playerName + " " + action + " an item to an item frame owned by " + target + " at " + x + " " + y + " " + z + getHumanWorldName(worldName); 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); alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
} }
} }
// 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;
if (!(event.getDamager() instanceof Player player)) return;
//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)) return;
if (!(event.getDamager() instanceof Player)) return;
ItemFrame frame = (ItemFrame) event.getEntity();
Player player = (Player) event.getDamager();
ItemStack item = frame.getItem(); ItemStack item = frame.getItem();
String playerName = player.getName(); String playerName = player.getName();
@@ -371,31 +387,27 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
String worldName = frame.getWorld().getName(); String worldName = frame.getWorld().getName();
if (isLocationIgnored(x, y, z, worldName)) { if (isLocationIgnored(x, y, z, worldName)) {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
String target = inspectBlock(frame.getLocation().getBlock(), player);
String target = inspectBlock(frame.getLocation().getBlock(), player);
if (target == null || target.equals(player.getName())) return; if (target == null || target.equals(player.getName())) return;
if (item.getType() == Material.AIR) return;
if (item == null || item.getType() == Material.AIR) return;
// At this point, the player is removing the item // At this point, the player is removing the item
String action = "took " + item.getType(); String action = "took " + item.getType();
String message = ChatColor.GRAY + playerName + " " + action + " from item frame owned by " + target + " at " + x + " " + y + " " + z + getHumanWorldName(worldName); 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); alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
} }
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onItemFrameBreak(HangingBreakByEntityEvent event){ public void onItemFrameBreak(HangingBreakByEntityEvent event) {
if (!(event.getEntity() instanceof ItemFrame)) return; if (!(event.getEntity() instanceof ItemFrame frame)) return;
if (!(event.getRemover() instanceof Player)) return; if (!(event.getRemover() instanceof Player player)) return;
ItemFrame frame = (ItemFrame) event.getEntity();
Player player = (Player) event.getRemover();
String playerName = player.getName(); String playerName = player.getName();
Location loc = frame.getLocation(); Location loc = frame.getLocation();
int x = loc.getBlockX(); int x = loc.getBlockX();
int y = loc.getBlockY(); int y = loc.getBlockY();
@@ -407,17 +419,14 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
return; return;
} }
String target = inspectBlock(loc.getBlock(), player); String target = inspectBlock(loc.getBlock(), player);
if (target ==null || target.equals(player.getName())) return; if (target == null || target.equals(player.getName())) return;
String action = "broke an item frame"; String action = "broke an item frame";
String message = ChatColor.GRAY + playerName + " " + action + " owned by " + target + " at " + x + " " + y + " " + z + getHumanWorldName(worldName); 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); alert(message, playerName, "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", target, x, y, z, worldName);
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!command.getName().equalsIgnoreCase("griefalert")) return false; if (!command.getName().equalsIgnoreCase("griefalert")) return false;
@@ -425,7 +434,7 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
String sub = args[0].toLowerCase(); String sub = args[0].toLowerCase();
if (sub.equals("ignore")) { if (sub.equals("ignore")) {
if (!sender.hasPermission("griefalert.staff.ignore")) { if (!sender.hasPermission("griefalert.staff.ignore")) {
sender.sendMessage(ChatColor.RED + "You do not have permission."); sender.sendMessage(ChatColor.RED + "You do not have a permission.");
return true; return true;
} }
String world; String world;
@@ -436,7 +445,7 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world."); sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
return true; return true;
} }
world = ((Player)sender).getWorld().getName(); world = ((Player) sender).getWorld().getName();
try { try {
x = Integer.parseInt(args[1]); x = Integer.parseInt(args[1]);
y = Integer.parseInt(args[2]); y = Integer.parseInt(args[2]);
@@ -480,7 +489,7 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world."); sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
return true; return true;
} }
world = ((Player)sender).getWorld().getName(); world = ((Player) sender).getWorld().getName();
try { try {
x = Integer.parseInt(args[1]); x = Integer.parseInt(args[1]);
y = Integer.parseInt(args[2]); y = Integer.parseInt(args[2]);
@@ -521,7 +530,7 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world."); sender.sendMessage(ChatColor.RED + "Only players can use this command without specifying a world.");
return true; return true;
} }
world = ((Player)sender).getWorld().getName(); world = ((Player) sender).getWorld().getName();
try { try {
x = Integer.parseInt(args[1]); x = Integer.parseInt(args[1]);
y = Integer.parseInt(args[2]); y = Integer.parseInt(args[2]);
@@ -615,7 +624,7 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
} }
// Send an event for external hooks // Send an event for external hooks
GriefAlertEvent griefalert_event; GriefAlertEvent griefalert_event;
if (MAP_LINK != null && !MAP_LINK.isEmpty() && mapLink != null) { if (MAP_LINK != null && !MAP_LINK.isEmpty() && mapLink != null) {
griefalert_event = new GriefAlertEvent(message + " (" + mapLink + ")"); griefalert_event = new GriefAlertEvent(message + " (" + mapLink + ")");
} else { } else {
griefalert_event = new GriefAlertEvent(message); griefalert_event = new GriefAlertEvent(message);
@@ -630,42 +639,14 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
lastAlert = realAlertMessage; 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;
}
//pet alert(dog and cat only) //pet alert(dog and cat only)
@EventHandler @EventHandler
public void onPetKill(EntityDeathEvent event){ public void onPetKill(EntityDeathEvent event) {
if (!(event.getEntity() instanceof Tameable tameable)) return; if (!(event.getEntity() instanceof Tameable tameable)) return;
if (!tameable.isTamed()) return; if (!tameable.isTamed()) return;
//checks if wolf or cat or not //checks if wolf or cat or not
if (!(event.getEntity() instanceof Wolf) && !(event.getEntity()instanceof Cat)) return; if (!(event.getEntity() instanceof Wolf) && !(event.getEntity() instanceof Cat)) return;
AnimalTamer Owner = tameable.getOwner(); AnimalTamer Owner = tameable.getOwner();
@@ -680,19 +661,20 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
String worldName = event.getEntity().getWorld().getName(); String worldName = event.getEntity().getWorld().getName();
String pet = event.getEntity().getType().name(); String pet = event.getEntity().getType().name();
String message = ChatColor.GRAY + killer.getName() + " killed" +" " + pet + " "+ "owned by " + Owner.getName() + " at " + x + " " + y + " " + z + getHumanWorldName(worldName); 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); alert(message, killer.getName(), "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", Owner.getName(), x, y, z, worldName);
} }
//farm animal handler //farm animal handler
@EventHandler @EventHandler
public void onFarmAnimalDeath(EntityDeathEvent event){ public void onFarmAnimalDeath(EntityDeathEvent event) {
if(!(event.getEntity().getKiller() instanceof Player killer)) return; if (!(event.getEntity().getKiller() instanceof Player killer)) return;
List<String> alertanimals = getConfig().getStringList("triggered-animals"); List<String> alertanimals = getConfig().getStringList("triggered-animals");
String typeName = event.getEntityType().name(); String typeName = event.getEntityType().name();
if(! alertanimals.contains(typeName)) return; if (!alertanimals.contains(typeName)) return;
Block blockBelow = event.getEntity().getLocation().subtract(0, 1, 0).getBlock(); Block blockBelow = event.getEntity().getLocation().subtract(0, 1, 0).getBlock();
String animalOwner = inspectBlock(blockBelow, killer); String animalOwner = inspectBlock(blockBelow, killer);
@@ -708,30 +690,135 @@ public class GriefAlert extends JavaPlugin implements Listener, TabCompleter {
String worldName = event.getEntity().getWorld().getName(); String worldName = event.getEntity().getWorld().getName();
String message = ChatColor.GRAY + killer.getName() + " killed" +" " + typeName + " "+ "owned by " + animalOwner + " at " + x + " " + y + " " + z + getHumanWorldName(worldName); 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); alert(message, killer.getName(), "[Map Link](" + MAP_LINK + "/?worldname=" + worldName + "&zoom=7&x=" + x + "&y=" + y + "&z=" + z + ")", animalOwner, x, y, z, worldName);
} }
private static String getHumanWorldName(String worldName) { /*code i hope for copper waxing/unwaxing theres no proper onwax() or onUnWax()
String world = ""; 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 */
if (worldName.endsWith("_nether")) { @EventHandler
world = " in the Nether"; public void onBlockClick(PlayerInteractEvent event) {
} if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
else if (worldName.endsWith("_the_end")) {
world = " in the End"; 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;
} }
return world; 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);
}
//stripping logs
@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);
}
private CoreProtectAPI getCoreProtect() { private CoreProtectAPI getCoreProtect() {
Plugin plugin = getServer().getPluginManager().getPlugin("CoreProtect"); Plugin plugin = getServer().getPluginManager().getPlugin("CoreProtect");
if (plugin == null || !(plugin instanceof CoreProtect)) { if (!(plugin instanceof CoreProtect)) {
return null; return null;
} }

View File

@@ -2,19 +2,18 @@
package net.ardakaz.griefalert; package net.ardakaz.griefalert;
import org.bukkit.Bukkit;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
public class GriefAlertEvent extends Event { public class GriefAlertEvent extends Event {
private static final HandlerList HANDLERS = new HandlerList(); private static final HandlerList HANDLERS = new HandlerList();
private String alert = ""; private String alert = "";
public GriefAlertEvent(String alert) { public GriefAlertEvent(String alert) {
this.alert = alert; this.alert = alert;
} }
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return HANDLERS; return HANDLERS;
} }