From ecfecaf19410e91437764cf42e9a61276ae6a09b Mon Sep 17 00:00:00 2001 From: Flarp Date: Thu, 28 Dec 2023 16:54:23 -0500 Subject: First commit --- .../java/dev/deeve/containeraudit/ChestEvent.java | 14 +++ .../dev/deeve/containeraudit/ChestListener.java | 95 ++++++++++++++++ .../java/dev/deeve/containeraudit/Database.java | 125 +++++++++++++++++++++ src/main/java/dev/deeve/containeraudit/Plugin.java | 44 ++++++++ src/main/resources/plugin.yml | 4 + 5 files changed, 282 insertions(+) create mode 100644 src/main/java/dev/deeve/containeraudit/ChestEvent.java create mode 100644 src/main/java/dev/deeve/containeraudit/ChestListener.java create mode 100644 src/main/java/dev/deeve/containeraudit/Database.java create mode 100644 src/main/java/dev/deeve/containeraudit/Plugin.java create mode 100644 src/main/resources/plugin.yml (limited to 'src/main') diff --git a/src/main/java/dev/deeve/containeraudit/ChestEvent.java b/src/main/java/dev/deeve/containeraudit/ChestEvent.java new file mode 100644 index 0000000..a59e0ea --- /dev/null +++ b/src/main/java/dev/deeve/containeraudit/ChestEvent.java @@ -0,0 +1,14 @@ +package dev.deeve.containeraudit; + +import java.time.LocalDateTime; + +public class ChestEvent { + private int count; + private String block; + private int x; + private int y; + private int z; + private String player; + private String type; + private LocalDateTime timestamp; +} diff --git a/src/main/java/dev/deeve/containeraudit/ChestListener.java b/src/main/java/dev/deeve/containeraudit/ChestListener.java new file mode 100644 index 0000000..bc93b9c --- /dev/null +++ b/src/main/java/dev/deeve/containeraudit/ChestListener.java @@ -0,0 +1,95 @@ +package dev.deeve.containeraudit; + +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + + +public class ChestListener implements Listener { + + public static List ignore; + + public ChestListener(List ignore) { + ChestListener.ignore = ignore; + } + + @EventHandler + public final void onInventoryClick(InventoryClickEvent event) { + String playerName = event.getWhoClicked().getName(); + Inventory inventory = event.getClickedInventory(); + + if (inventory == null || ignore.contains(playerName)) return; + + + + Location loc = inventory.getLocation(); + + InventoryAction action = event.getAction(); + + if (inventory.getType() == InventoryType.CHEST && (action == InventoryAction.COLLECT_TO_CURSOR || + action == InventoryAction.PICKUP_ALL || + action == InventoryAction.PICKUP_HALF || + action == InventoryAction.PICKUP_ONE || + action == InventoryAction.PICKUP_SOME || + action == InventoryAction.MOVE_TO_OTHER_INVENTORY)) { + + // we are taking from the chest + Database.logInventoryEvent(playerName, true, loc, event.getCurrentItem()); + + } else if (inventory.getType() == InventoryType.CHEST && (action == InventoryAction.PLACE_ALL || + action == InventoryAction.PLACE_ONE || + action == InventoryAction.PLACE_SOME || + action == InventoryAction.HOTBAR_MOVE_AND_READD || + action == InventoryAction.HOTBAR_SWAP)) { + + // we are placing into the chest + Database.logInventoryEvent(playerName, false, loc, event.getCursor()); + + } else if (inventory.getType() == InventoryType.CHEST && (action == InventoryAction.SWAP_WITH_CURSOR)) { + + // we are swapping what is in our cursor with what is in the given slot, reverse + Database.logInventoryEvent(playerName, true, loc, event.getCursor()); + Database.logInventoryEvent(playerName, false, loc, event.getCurrentItem()); + + } + + + } + + @EventHandler + public final void onBlockPlace(BlockPlaceEvent event) { + Block placedBlock = event.getBlock(); + String playerName = event.getPlayer().getName(); + + if (ignore.contains(playerName)) return; + + if (placedBlock.getType() == Material.CHEST) + Database.logBlockEvent(playerName, "PLACE", placedBlock.getLocation()); + + } + + @EventHandler + public final void onBlockBreak(BlockBreakEvent event) { + Block placedBlock = event.getBlock(); + String playerName = event.getPlayer().getName(); + + if (ignore.contains(playerName)) return; + + if (placedBlock.getType() == Material.CHEST) + Database.logBlockEvent(playerName, "BREAK", placedBlock.getLocation()); + + } +} diff --git a/src/main/java/dev/deeve/containeraudit/Database.java b/src/main/java/dev/deeve/containeraudit/Database.java new file mode 100644 index 0000000..ad409f4 --- /dev/null +++ b/src/main/java/dev/deeve/containeraudit/Database.java @@ -0,0 +1,125 @@ +package dev.deeve.containeraudit; + +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.inventory.ItemStack; +import org.bukkit.Location; +import org.bukkit.Bukkit; + +import java.sql.PreparedStatement; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.sql.Connection; +import java.sql.ResultSet; + +public class Database { + static Connection connection; + static Logger logger; + + public static void connect(String path, Logger logger) throws SQLException { + connection = DriverManager.getConnection("jdbc:sqlite:" + path); + Database.logger = logger; + } + + static String playerID(Player player) { + return player.getUniqueId().toString().replaceAll("-", ""); + } + + public static void createTables() throws SQLException { + PreparedStatement chestEventCreate = connection.prepareStatement( + "CREATE TABLE IF NOT EXISTS chest_events (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "player TEXT NOT NULL, " + + "x REAL NOT NULL, " + + "y REAL NOT NULL, " + + "z REAL NOT NULL, " + + "block TEXT NOT NULL," + + "count INTEGER NOT NULL," + + "event_type TEXT NOT NULL," + + "timestamp INTEGER NOT NULL" + + ")" + ); + chestEventCreate.executeUpdate(); + + PreparedStatement chestCreate = connection.prepareStatement( + "CREATE TABLE IF NOT EXISTS chests (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "actor TEXT NOT NULL, " + + "action TEXT NOT NULL," + + "x REAL NOT NULL, " + + "y REAL NOT NULL, " + + "z REAL NOT NULL," + + "timestamp INTEGER NOT NULL" + + ")" + ); + + chestCreate.executeUpdate(); + + PreparedStatement viewCreate = connection.prepareStatement( + "CREATE VIEW IF NOT EXISTS chest_block_events AS " + + "SELECT * FROM chests AS placed_chest FULL OUTER JOIN chests AS broke_chest ON " + + "broke_chest.action = \"BREAK\" AND placed_chest.action = \"PLACE\" AND " + + " placed_chest.x = broke_chest.x AND placed_chest.y = broke_chest.y AND placed_chest.z = broke_chest.z AND " + + "broke_chest.timestamp = (SELECT MIN(timestamp) FROM chests WHERE timestamp > placed_chest.timestamp) WHERE " + + " placed_chest.action = \"PLACE\" OR broke_chest.action = \"BREAK\";" + ); + + viewCreate.executeUpdate(); + + // software engineering is dead + PreparedStatement shmiewShmeate = connection.prepareStatement("CREATE VIEW IF NOT EXISTS chest_event_owned AS SELECT chest_events.id, chest_events.player, chest_events.x, chest_events.y, chest_events.z, chest_events.timestamp AS event_timestamp, action, block, `count`, chests.timestamp AS chest_placed_timestamp, chests.actor AS chest_owner FROM chest_events LEFT JOIN chests ON chests.timestamp = (SELECT MAX(timestamp) FROM chests WHERE chest_events.x = x AND chest_events.y = y AND chest_events.z = z AND chests.action = \"PLACE\" AND chest_events.timestamp > timestamp)"); + shmiewShmeate.executeUpdate(); + + + } + + public static void logInventoryEvent(String player, boolean pickup, Location loc, ItemStack stack) { + try { + PreparedStatement statement = connection.prepareStatement( + "INSERT INTO chest_events (player, x, y, z, block, count, event_type, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); + + statement.setString(1, player); + statement.setInt(2, loc.getBlockX()); + statement.setInt(3, loc.getBlockY()); + statement.setInt(4, loc.getBlockZ()); + statement.setString(5, stack.getType().getKey().toString()); + statement.setInt(6, stack.getAmount()); + statement.setString(7, pickup ? "PICKUP" : "PLACE"); + statement.setLong(8, Instant.now().getEpochSecond()); + + statement.executeUpdate(); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error occured when inserting into chest_events"); + ex.printStackTrace(); + } + + } + + public static void logBlockEvent(String player, String type, Location loc) { + try { + PreparedStatement statement = connection.prepareStatement( + "INSERT INTO chests (actor, action, x, y, z, timestamp) VALUES (?, ?, ?, ?, ?, ?)"); + + statement.setString(1, player); + statement.setString(2, type); + statement.setInt(3, loc.getBlockX()); + statement.setInt(4, loc.getBlockY()); + statement.setInt(5, loc.getBlockZ()); + statement.setLong(6, Instant.now().getEpochSecond()); + + statement.executeUpdate(); + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error occured when inserting into chests"); + ex.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/dev/deeve/containeraudit/Plugin.java b/src/main/java/dev/deeve/containeraudit/Plugin.java new file mode 100644 index 0000000..a92d6c0 --- /dev/null +++ b/src/main/java/dev/deeve/containeraudit/Plugin.java @@ -0,0 +1,44 @@ +package dev.deeve.containeraudit; + + +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.logging.Logger; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.sql.SQLException; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class Plugin extends JavaPlugin { + public static Logger logger; + + + public void onEnable() { + logger = getLogger(); + getDataFolder().mkdirs(); + + try { + Database.connect(new File(getDataFolder(), "database.db").getPath(), logger); + List ignores = new ArrayList(); + Path okay = Paths.get(getDataFolder().getPath(), "okay.txt"); + + if (Files.exists(okay)) { + ignores = Files.readAllLines(okay); + } + + getServer().getPluginManager().registerEvents(new ChestListener(ignores), this); + Database.createTables(); + } + catch (SQLException | IOException ex) { + logger.log(Level.SEVERE, "Database error: (not enabling plugin)"); + ex.printStackTrace(); + return; + } + + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..7f6135b --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,4 @@ +main: dev.deeve.containeraudit.Plugin +name: ContainerAudit +version: 0.0.1 +api-version: 1.19 \ No newline at end of file -- cgit v1.2.3