Compare commits
2 Commits
main
...
7247547d18
| Author | SHA1 | Date | |
|---|---|---|---|
| 7247547d18 | |||
| 06f7474591 |
@@ -1,9 +1,5 @@
|
|||||||
package net.ardakaz.griefalert;
|
package net.ardakaz.griefalert;
|
||||||
|
|
||||||
import net.ardakaz.griefalert.database.DatabaseService;
|
|
||||||
import net.ardakaz.griefalert.database.Migrations;
|
|
||||||
import net.ardakaz.griefalert.database.PlayerRepository;
|
|
||||||
import net.ardakaz.griefalert.listener.PlayerListener;
|
|
||||||
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;
|
||||||
@@ -32,7 +28,6 @@ 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.PluginManager;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
@@ -40,10 +35,6 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
@@ -57,8 +48,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|||||||
private String MAP_LINK;
|
private String MAP_LINK;
|
||||||
private Boolean ALLOW_STEALING;
|
private Boolean ALLOW_STEALING;
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
private DatabaseService database;
|
|
||||||
private Logger logger;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
UTILITY FUNCTIONS
|
UTILITY FUNCTIONS
|
||||||
@@ -166,7 +155,6 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|||||||
// Init GriefAlert
|
// Init GriefAlert
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
logger = getLogger();
|
|
||||||
|
|
||||||
coreProtectAPI = getCoreProtect();
|
coreProtectAPI = getCoreProtect();
|
||||||
if (coreProtectAPI == null) {
|
if (coreProtectAPI == null) {
|
||||||
@@ -175,6 +163,7 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
saveDefaultConfig();
|
saveDefaultConfig();
|
||||||
@@ -187,18 +176,9 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
setupDatabase();
|
setupDatabase();
|
||||||
|
|
||||||
PlayerRepository playerRepository = new PlayerRepository(database, logger);
|
|
||||||
PlayerListener playerListener = new PlayerListener(playerRepository, logger);
|
|
||||||
|
|
||||||
|
|
||||||
PluginManager pluginManager = getServer().getPluginManager();
|
|
||||||
pluginManager.registerEvents(this, this);
|
|
||||||
pluginManager.registerEvents(playerListener, this);
|
|
||||||
|
|
||||||
getCommand("griefalert").setTabCompleter(this);
|
getCommand("griefalert").setTabCompleter(this);
|
||||||
|
|
||||||
getLogger().info("GriefAlert has been enabled.");
|
getLogger().info("GriefAlert has been enabled.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -213,19 +193,19 @@ public class GriefAlert extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupDatabase() {
|
private void setupDatabase() {
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
|
||||||
|
|
||||||
String jdbcUrl = getConfig().getString("jdbc-url");
|
String jdbcUrl = getConfig().getString("jdbc-url");
|
||||||
try {
|
try {
|
||||||
connection = DriverManager.getConnection(jdbcUrl);
|
connection = DriverManager.getConnection(jdbcUrl);
|
||||||
database = new DatabaseService(executor, connection);
|
Statement stmt = connection.createStatement();
|
||||||
logger.info("Connected to " + jdbcUrl);
|
stmt.executeUpdate(Migrations.CREATE_TABLE_IGNORED_LOCATIONS);
|
||||||
|
stmt.executeUpdate(Migrations.CREATE_TABLE_PLAYERS);
|
||||||
CompletableFuture<Void> migrationExecution = new Migrations(database, logger).execute();
|
stmt.executeUpdate(Migrations.CREATE_TABLE_ACTIONS);
|
||||||
migrationExecution.join();
|
stmt.executeUpdate(Migrations.CREATE_TABLE_ALERTS);
|
||||||
logger.info("Database migration finished");
|
stmt.executeUpdate(Migrations.CREATE_TABLE_REPORTS);
|
||||||
|
stmt.close();
|
||||||
|
getLogger().info("Connected to "+jdbcUrl);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.severe("Could not set up SQLite database: " + e.getMessage());
|
getLogger().severe("Could not set up SQLite database: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,8 @@
|
|||||||
package net.ardakaz.griefalert.database;
|
package net.ardakaz.griefalert;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
public class Migrations {
|
public class Migrations {
|
||||||
|
|
||||||
private DatabaseService database;
|
public static final String CREATE_TABLE_IGNORED_LOCATIONS =
|
||||||
private Logger logger;
|
|
||||||
|
|
||||||
public Migrations(DatabaseService database, Logger logger) {
|
|
||||||
this.database = database;
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String CREATE_TABLE_IGNORED_LOCATIONS =
|
|
||||||
"CREATE TABLE IF NOT EXISTS ignored_locations (" +
|
"CREATE TABLE IF NOT EXISTS ignored_locations (" +
|
||||||
"x INTEGER, " +
|
"x INTEGER, " +
|
||||||
"y INTEGER, " +
|
"y INTEGER, " +
|
||||||
@@ -24,16 +11,16 @@ public class Migrations {
|
|||||||
"PRIMARY KEY (x, y, z, world)" +
|
"PRIMARY KEY (x, y, z, world)" +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
private static final String CREATE_TABLE_PLAYERS =
|
public static final String CREATE_TABLE_PLAYERS =
|
||||||
"CREATE TABLE IF NOT EXISTS players (" +
|
"CREATE TABLE IF NOT EXISTS players (" +
|
||||||
"id TEXT PRIMARY KEY, " +
|
"id TEXT PRIMARY KEY, " +
|
||||||
"names TEXT NOT NULL, " +
|
"names TEXT NOT NULL, " +
|
||||||
"firstseen INTEGER NOT NULL, " +
|
"playtime INTEGER NOT NULL DEFAULT 0, " +
|
||||||
"lastseen INTEGER NOT NULL, " +
|
"firstseen INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
|
||||||
"playtime INTEGER NOT NULL DEFAULT 0 " +
|
"lastseen INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP" +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
private static final String CREATE_TABLE_ACTIONS =
|
public static final String CREATE_TABLE_ACTIONS =
|
||||||
"CREATE TABLE IF NOT EXISTS actions (" +
|
"CREATE TABLE IF NOT EXISTS actions (" +
|
||||||
"id INTEGER PRIMARY KEY, " +
|
"id INTEGER PRIMARY KEY, " +
|
||||||
"player TEXT NOT NULL, " +
|
"player TEXT NOT NULL, " +
|
||||||
@@ -45,7 +32,7 @@ public class Migrations {
|
|||||||
"FOREIGN KEY(player) REFERENCES players(id)" +
|
"FOREIGN KEY(player) REFERENCES players(id)" +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
private static final String CREATE_TABLE_ALERTS =
|
public static final String CREATE_TABLE_ALERTS =
|
||||||
"CREATE TABLE IF NOT EXISTS alerts (" +
|
"CREATE TABLE IF NOT EXISTS alerts (" +
|
||||||
"id INTEGER PRIMARY KEY, " +
|
"id INTEGER PRIMARY KEY, " +
|
||||||
"player TEXT NOT NULL, " +
|
"player TEXT NOT NULL, " +
|
||||||
@@ -65,7 +52,7 @@ public class Migrations {
|
|||||||
"FOREIGN KEY(player) REFERENCES players(id)" +
|
"FOREIGN KEY(player) REFERENCES players(id)" +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
private static final String CREATE_TABLE_REPORTS =
|
public static final String CREATE_TABLE_REPORTS =
|
||||||
"CREATE TABLE IF NOT EXISTS reports (" +
|
"CREATE TABLE IF NOT EXISTS reports (" +
|
||||||
"id INTEGER PRIMARY KEY, " +
|
"id INTEGER PRIMARY KEY, " +
|
||||||
"player TEXT NOT NULL, " +
|
"player TEXT NOT NULL, " +
|
||||||
@@ -78,19 +65,4 @@ public class Migrations {
|
|||||||
"timestamp INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
|
"timestamp INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
|
||||||
"state TEXT NOT NULL DEFAULT 'UNRESOLVED'" +
|
"state TEXT NOT NULL DEFAULT 'UNRESOLVED'" +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
public CompletableFuture<Void> execute() {
|
|
||||||
return database.submit(connection -> {
|
|
||||||
try(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);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.severe("Failed to execute database migrations: " + e.getMessage());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package net.ardakaz.griefalert.database;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface DatabaseOperation<T> {
|
|
||||||
T execute(Connection connection) throws SQLException;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package net.ardakaz.griefalert.database;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
public class DatabaseService {
|
|
||||||
|
|
||||||
private final ExecutorService executor;
|
|
||||||
private final Connection connection;
|
|
||||||
|
|
||||||
public DatabaseService(ExecutorService executor, Connection connection) {
|
|
||||||
this.executor = executor;
|
|
||||||
this.connection = connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> CompletableFuture<T> submit(DatabaseOperation<T> operation) {
|
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
|
||||||
try {
|
|
||||||
return operation.execute(connection);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}, executor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package net.ardakaz.griefalert.database;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public record PlayerEntity(String id, List<String> names, long playtime, long firstSeen, long lastSeen) {
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
package net.ardakaz.griefalert.database;
|
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
public class PlayerRepository {
|
|
||||||
private Logger logger;
|
|
||||||
private final DatabaseService database;
|
|
||||||
|
|
||||||
public PlayerRepository(DatabaseService database, Logger logger) {
|
|
||||||
this.database = database;
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<PlayerEntity> get(String uuid) {
|
|
||||||
return database.submit(connection -> {
|
|
||||||
|
|
||||||
try (PreparedStatement ps = connection.prepareStatement("SELECT * FROM players WHERE id=?")) {
|
|
||||||
ps.setString(1, uuid);
|
|
||||||
|
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
|
||||||
if (rs.next()) {
|
|
||||||
return new PlayerEntity(
|
|
||||||
rs.getString("id"),
|
|
||||||
Arrays.stream(rs.getString("names").split(",")).toList(),
|
|
||||||
rs.getLong("playtime"),
|
|
||||||
rs.getLong("firstseen"),
|
|
||||||
rs.getLong("lastseen")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.severe("DB error: " + e.getMessage());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<Void> upsert(PlayerEntity entity) {
|
|
||||||
return database.submit(connection -> {
|
|
||||||
String upsert = """
|
|
||||||
INSERT INTO players(id, names, firstseen, lastseen) VALUES(?,?,?,?)
|
|
||||||
ON CONFLICT(id)
|
|
||||||
DO UPDATE SET names=excluded.names, playtime=?, lastseen=excluded.lastseen;
|
|
||||||
""";
|
|
||||||
|
|
||||||
try (PreparedStatement ps = connection.prepareStatement(upsert)) {
|
|
||||||
ps.setString(1, entity.id());
|
|
||||||
String names = String.join(",", entity.names());
|
|
||||||
ps.setString(2, names);
|
|
||||||
ps.setLong(3, entity.firstSeen());
|
|
||||||
ps.setLong(4, entity.lastSeen());
|
|
||||||
ps.setLong(5, entity.playtime());
|
|
||||||
|
|
||||||
ps.executeUpdate();
|
|
||||||
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.severe("Failed to save player: " + entity);
|
|
||||||
logger.severe(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<Void> updateNames(String id, List<String> names) {
|
|
||||||
return database.submit(connection -> {
|
|
||||||
String update = """
|
|
||||||
UPDATE players
|
|
||||||
SET names = ?
|
|
||||||
WHERE id = ?
|
|
||||||
""";
|
|
||||||
|
|
||||||
try (PreparedStatement ps = connection.prepareStatement(update)) {
|
|
||||||
ps.setString(1, String.join(",", names));
|
|
||||||
ps.setString(2, id);
|
|
||||||
|
|
||||||
ps.executeUpdate();
|
|
||||||
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.severe("Failed to update names for playerID: " + id);
|
|
||||||
logger.severe(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
package net.ardakaz.griefalert.listener;
|
|
||||||
|
|
||||||
import net.ardakaz.griefalert.database.PlayerEntity;
|
|
||||||
import net.ardakaz.griefalert.database.PlayerRepository;
|
|
||||||
import org.bukkit.Statistic;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
public class PlayerListener implements Listener {
|
|
||||||
|
|
||||||
private Logger logger;
|
|
||||||
private PlayerRepository repository;
|
|
||||||
|
|
||||||
public PlayerListener(PlayerRepository repository, Logger logger) {
|
|
||||||
this.logger = logger;
|
|
||||||
this.repository = repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerLogin(PlayerJoinEvent event) {
|
|
||||||
Player eventPlayer = event.getPlayer();
|
|
||||||
repository.get(
|
|
||||||
eventPlayer.getUniqueId().toString()
|
|
||||||
).thenAccept(dbPlayer -> {
|
|
||||||
if (dbPlayer == null) {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
repository.upsert(new PlayerEntity(
|
|
||||||
eventPlayer.getUniqueId().toString(),
|
|
||||||
List.of(eventPlayer.getName()),
|
|
||||||
0,
|
|
||||||
now,
|
|
||||||
now
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
List<String> newNames = updateNames(eventPlayer.getName(), dbPlayer.names());
|
|
||||||
repository.updateNames(dbPlayer.id(), newNames);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerLogout(PlayerQuitEvent event) {
|
|
||||||
Player eventPlayer = event.getPlayer();
|
|
||||||
long playtimeSeconds = eventPlayer.getStatistic(Statistic.PLAY_ONE_MINUTE) / 20L;
|
|
||||||
repository.get(
|
|
||||||
eventPlayer.getUniqueId().toString()
|
|
||||||
).thenAccept(dbPlayer -> {
|
|
||||||
if (dbPlayer != null) {
|
|
||||||
PlayerEntity updatedPlayer = new PlayerEntity(
|
|
||||||
dbPlayer.id(),
|
|
||||||
dbPlayer.names(),
|
|
||||||
playtimeSeconds,
|
|
||||||
dbPlayer.firstSeen(),
|
|
||||||
System.currentTimeMillis()
|
|
||||||
);
|
|
||||||
repository.upsert(updatedPlayer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> updateNames(String currentName, List<String> historicalNames) {
|
|
||||||
List<String> newNames = new ArrayList<>(historicalNames);
|
|
||||||
while (newNames.contains(currentName)) {
|
|
||||||
newNames.remove(currentName);
|
|
||||||
}
|
|
||||||
newNames.add(currentName);
|
|
||||||
return newNames;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user