16 Commits

Author SHA1 Message Date
c009654c5c fix spaces
All checks were successful
Build / Explore-Gitea-Actions (push) Successful in 47s
2026-07-22 14:38:35 +00:00
ab2c9bf1d6 Add default value to jdbc url (#11)
All checks were successful
Build / Explore-Gitea-Actions (push) Successful in 40s
Co-authored-by: Ardakaz <ardakaz@duck.com>
Reviewed-on: #11
Reviewed-by: Ardakaz <ardakaz@duck.com>
Co-authored-by: ThePindabaas <thepindabaas@noreply.localhost>
Co-committed-by: ThePindabaas <thepindabaas@noreply.localhost>
2026-07-18 18:25:28 +00:00
7aec608825 add new db tables (#13)
Some checks failed
Build / Explore-Gitea-Actions (push) Has been cancelled
Co-authored-by: ThePindabaas <219561634+ThePindabaas@users.noreply.github.com>
Co-authored-by: Ardakaz <ardakaz@duck.com>
Reviewed-on: #13
Reviewed-by: Ardakaz <ardakaz@duck.com>
Co-authored-by: ThePindabaas <thepindabaas@noreply.localhost>
Co-committed-by: ThePindabaas <thepindabaas@noreply.localhost>
2026-07-18 18:24:26 +00:00
e980768210 Fix lack of space after animal type (#12)
All checks were successful
Build / Explore-Gitea-Actions (push) Successful in 44s
Reviewed-on: #12
Reviewed-by: Ardakaz <ardakaz@duck.com>
Co-authored-by: ThePindabaas <thepindabaas@noreply.localhost>
Co-committed-by: ThePindabaas <thepindabaas@noreply.localhost>
2026-07-15 12:13:12 +00:00
5064ac5903 Restrict block break if condition (#10)
All checks were successful
Build / Explore-Gitea-Actions (push) Successful in 51s
Co-authored-by: ThePindabaas <219561634+ThePindabaas@users.noreply.github.com>
Reviewed-on: #10
Reviewed-by: Ardakaz <ardakaz@duck.com>
Co-authored-by: ThePindabaas <thepindabaas@noreply.localhost>
Co-committed-by: ThePindabaas <thepindabaas@noreply.localhost>
2026-07-13 15:12:00 +00:00
55881630bc Set up parameterized jdbc connection (#8)
All checks were successful
Build / Explore-Gitea-Actions (push) Successful in 42s
Co-authored-by: ThePindabaas <219561634+ThePindabaas@users.noreply.github.com>
Reviewed-on: #8
Reviewed-by: Ardakaz <ardakaz@duck.com>
Co-authored-by: ThePindabaas <thepindabaas@noreply.localhost>
Co-committed-by: ThePindabaas <thepindabaas@noreply.localhost>
2026-07-03 11:07:53 +00:00
Ardakaz
4cd24ad467 Just organizing a bit and adding comments
All checks were successful
Build / Explore-Gitea-Actions (push) Successful in 45s
2026-06-29 10:52:24 +03:00
db3649a2f5 add newline at the end of files (#5)
All checks were successful
Build / Explore-Gitea-Actions (push) Successful in 44s
Co-authored-by: ThePindabaas <219561634+ThePindabaas@users.noreply.github.com>
Reviewed-on: #5
Reviewed-by: Ardakaz <ardakaz@duck.com>
Co-authored-by: ThePindabaas <thepindabaas@noreply.localhost>
Co-committed-by: ThePindabaas <thepindabaas@noreply.localhost>
2026-06-28 11:49:23 +00:00
fec5f78cbc Introduce build pipeline (#4)
All checks were successful
Build / Explore-Gitea-Actions (push) Successful in 44s
Co-authored-by: ThePindabaas <219561634+ThePindabaas@users.noreply.github.com>
Reviewed-on: #4
Co-authored-by: ThePindabaas <thepindabaas@noreply.localhost>
Co-committed-by: ThePindabaas <thepindabaas@noreply.localhost>
2026-06-28 11:23:50 +00:00
7d3363812f Merge pull request 'changed Armorstand Logic' (#3) from armorstand-DeathLogic into main
Reviewed-on: #3
2026-06-27 14:38:18 +00:00
urtypicalblahajlunatic
1329b616f5 debugged and fixed EntityDeathEvent 2026-06-27 16:21:36 +02:00
urtypicalblahajlunatic
4e65e1bcb2 armorstand changed from EntityHitEvent to EntityDeathEvent, SHOULD cause less fake errors 2026-06-27 14:29:49 +02:00
c89d885fd8 Update src/main/java/net/ardakaz/griefalert/GriefAlert.java
2nd try to frickign update this BS
(also removed cancel stuff)
2026-06-27 10:55:30 +00:00
a61436effa Update src/main/java/net/ardakaz/griefalert/GriefAlert.java
removed some unneeded cancel events
2026-06-27 10:48:19 +00:00
ThePindabaas
5913a8060a bump co version + change test to always succeed 2026-06-27 11:45:36 +02:00
48fd811f2a Merge pull request 'add-gradle project' (#1) from add-gradle into main
Reviewed-on: #1
2026-06-27 09:33:29 +00:00
8 changed files with 204 additions and 71 deletions

View File

@@ -0,0 +1,16 @@
name: Build
run-name: ${{ gitea.ref }} - ${{ gitea.sha }}
on: [push, workflow_dispatch]
jobs:
Explore-Gitea-Actions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '25'
- run: ./gradlew assemble
- run: ./gradlew test
- run: ./gradlew jar

19
.gitea/workflows/demo.yml Normal file
View File

@@ -0,0 +1,19 @@
name: Gitea Actions Demo
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
on: [workflow_dispatch]
jobs:
Explore-Gitea-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- name: Check out repository code
uses: actions/checkout@v4
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ gitea.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."

View File

@@ -20,7 +20,7 @@ repositories{
dependencies {
compileOnly "io.papermc.paper:paper-api:26.1.2.build.72-stable"
compileOnly "net.coreprotect:coreprotect:23.1"
compileOnly "net.coreprotect:coreprotect:23.2"
testImplementation(platform('org.junit:junit-bom:5.10.5'))
testImplementation('org.junit.jupiter:junit-jupiter')

View File

@@ -41,7 +41,6 @@ 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;
@@ -50,6 +49,10 @@ 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);
@@ -70,7 +73,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
}
}
// If we see a break before a placement, stop (block is gone)
if (parseResult.getActionId() == 0) {
if (parseResult.getActionId() == 0 && !parseResult.isRolledBack()) {
break;
}
}
@@ -90,6 +93,65 @@ 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() {
@@ -131,16 +193,26 @@ public class GriefAlert extends JavaPlugin implements Listener {
}
private void setupDatabase() {
String jdbcUrl = getConfig().getString("jdbc-url");
try {
connection = DriverManager.getConnection("jdbc:sqlite:" + getDataFolder().getAbsolutePath() + "/" + DB_FILE);
connection = DriverManager.getConnection(jdbcUrl);
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.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=?");
@@ -191,6 +263,10 @@ public class GriefAlert extends JavaPlugin implements Listener {
}
}
/*
EVENT LISTENERS
*/
@EventHandler(ignoreCancelled = true)
// Block break alerts
public void onBlockBreak(BlockBreakEvent event) {
@@ -272,15 +348,14 @@ public class GriefAlert extends JavaPlugin implements Listener {
// Armor Stand break alerts
@EventHandler(ignoreCancelled = true)
public void onArmorStandBreak(EntityDamageByEntityEvent event) {
public void onArmorStandBreak(EntityDeathEvent event) {
if (!(event.getEntity() instanceof ArmorStand armorStand)) return;
if (!(event.getDamager() instanceof Player player)) 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)) {
event.setCancelled(true);
return;
}
String playerName = player.getName();
@@ -289,6 +364,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
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
@@ -301,7 +377,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
int z = armorStand.getLocation().getBlockZ();
String worldName = armorStand.getWorld().getName();
if (isLocationIgnored(x, y, z, worldName)) {
event.setCancelled(true);
return;
}
String target = inspectBlock(armorStand.getLocation().getBlock(), player);
@@ -337,7 +412,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
}
}
//event handler for item frames
// Placing item to an item frame
@EventHandler(ignoreCancelled = true)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (!(event.getRightClicked() instanceof ItemFrame frame)) return;
@@ -348,7 +423,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
int z = frame.getLocation().getBlockZ();
String worldName = frame.getWorld().getName();
if (isLocationIgnored(x, y, z, worldName)) {
event.setCancelled(true);
return;
}
String target = inspectBlock(frame.getLocation().getBlock(), player);
@@ -372,7 +446,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
}
}
// Breaking item frame item (uses a different event then placing an item)
// Item frame stealing alerts
@EventHandler(ignoreCancelled = true)
public void onItemFrameDamage(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof ItemFrame frame)) return;
@@ -387,7 +461,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
String worldName = frame.getWorld().getName();
if (isLocationIgnored(x, y, z, worldName)) {
event.setCancelled(true);
return;
}
@@ -401,6 +474,7 @@ 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;
@@ -415,7 +489,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
String worldName = loc.getWorld().getName();
if (isLocationIgnored(x, y, z, worldName)) {
event.setCancelled(true);
return;
}
String target = inspectBlock(loc.getBlock(), player);
@@ -427,6 +500,7 @@ 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;
@@ -588,57 +662,6 @@ 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) {
@@ -666,7 +689,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
}
//farm animal handler
// Mob killing alerts
@EventHandler
public void onFarmAnimalDeath(EntityDeathEvent event) {
if (!(event.getEntity().getKiller() instanceof Player killer)) return;
@@ -702,6 +725,7 @@ 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;
@@ -758,13 +782,13 @@ public class GriefAlert extends JavaPlugin implements Listener {
action = "error 404 check with kleedje30";
}
String message = ChatColor.GRAY + player.getName() + action + " Copper " + " at " + x + " " + y + " " + z + getHumanWorldName(world);
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
// Log stripping alerts
@EventHandler
public void onLogStrip(PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
@@ -815,6 +839,10 @@ public class GriefAlert extends JavaPlugin implements Listener {
}, 1L);
}
/*
CoreProtect API
*/
private CoreProtectAPI getCoreProtect() {
Plugin plugin = getServer().getPluginManager().getPlugin("CoreProtect");

View File

@@ -0,0 +1,68 @@
package net.ardakaz.griefalert;
public class Migrations {
public static final String CREATE_TABLE_IGNORED_LOCATIONS =
"CREATE TABLE IF NOT EXISTS ignored_locations (" +
"x INTEGER, " +
"y INTEGER, " +
"z INTEGER, " +
"world TEXT, " +
"PRIMARY KEY (x, y, z, world)" +
")";
public static final String CREATE_TABLE_PLAYERS =
"CREATE TABLE IF NOT EXISTS players (" +
"id TEXT PRIMARY KEY, " +
"names TEXT NOT NULL, " +
"playtime INTEGER NOT NULL DEFAULT 0, " +
"firstseen INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
"lastseen INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP" +
")";
public static final String CREATE_TABLE_ACTIONS =
"CREATE TABLE IF NOT EXISTS actions (" +
"id INTEGER PRIMARY KEY, " +
"player TEXT NOT NULL, " +
"type TEXT NOT NULL, " +
"moderator TEXT NOT NULL, " +
"reason TEXT, " +
"time TEXT, " +
"timestamp INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
"FOREIGN KEY(player) REFERENCES players(id)" +
")";
public static final String CREATE_TABLE_ALERTS =
"CREATE TABLE IF NOT EXISTS alerts (" +
"id INTEGER PRIMARY KEY, " +
"player TEXT NOT NULL, " +
"action TEXT NOT NULL, " +
"target TEXT NOT NULL, " +
"target_amount INTEGER, " +
"target_player TEXT NOT NULL, " +
"x INTEGER NOT NULL, " +
"y INTEGER NOT NULL, " +
"z INTEGER NOT NULL, " +
"world TEXT NOT NULL, " +
"is_flagged INTEGER, " +
"flag_text TEXT, " +
"resolved_by TEXT, " +
"state TEXT NOT NULL DEFAULT 'UNRESOLVED', " +
"timestamp INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
"FOREIGN KEY(player) REFERENCES players(id)" +
")";
public static final String CREATE_TABLE_REPORTS =
"CREATE TABLE IF NOT EXISTS reports (" +
"id INTEGER PRIMARY KEY, " +
"player TEXT NOT NULL, " +
"x INTEGER NOT NULL, " +
"y INTEGER NOT NULL, " +
"z INTEGER NOT NULL, " +
"world TEXT NOT NULL, " +
"text TEXT NOT NULL, " +
"resolved_by TEXT, " +
"timestamp INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
"state TEXT NOT NULL DEFAULT 'UNRESOLVED'" +
")";
}

View File

@@ -1,6 +1,8 @@
# Ignore all stealing?
allow-stealing: false
jdbc-url: "./plugins/GriefAlert/database.db"
# Breaking these blocks don't cause alerts. (Material)
excluded-blocks:
- WHEAT

View File

@@ -7,6 +7,6 @@ import static org.junit.jupiter.api.Assertions.*;
class GriefAlertTest {
@Test
public void placeholderTest() {
assertTrue(false);
assertTrue(true);
}
}