package com.dirtbagmc.dirtreferrals; import java.io.File; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class DatabaseManager { private final DirtReferralsPlugin plugin; private Connection connection; public DatabaseManager(DirtReferralsPlugin plugin) { this.plugin = plugin; } public void initialize() { try { if (!plugin.getDataFolder().exists()) { plugin.getDataFolder().mkdirs(); } String fileName = plugin.getConfig().getString("database.file", "referrals.db"); File dbFile = new File(plugin.getDataFolder(), fileName); connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath()); createTables(); } catch (SQLException e) { plugin.getLogger().severe("Failed to initialize SQLite database."); e.printStackTrace(); } } private void createTables() throws SQLException { try (Statement statement = connection.createStatement()) { statement.executeUpdate(""" CREATE TABLE IF NOT EXISTS players ( uuid TEXT PRIMARY KEY, name TEXT NOT NULL, referral_count INTEGER NOT NULL DEFAULT 0 ) """); statement.executeUpdate(""" CREATE TABLE IF NOT EXISTS referrals ( id INTEGER PRIMARY KEY AUTOINCREMENT, referrer_uuid TEXT NOT NULL, referred_uuid TEXT NOT NULL, referred_name TEXT NOT NULL, join_host TEXT, ip_address TEXT, counted INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL ) """); statement.executeUpdate(""" CREATE TABLE IF NOT EXISTS player_ips ( id INTEGER PRIMARY KEY AUTOINCREMENT, player_uuid TEXT NOT NULL, ip_address TEXT NOT NULL, created_at INTEGER NOT NULL ) """); statement.executeUpdate(""" CREATE TABLE IF NOT EXISTS claimed_rewards ( referrer_uuid TEXT NOT NULL, milestone INTEGER NOT NULL, claimed_at INTEGER NOT NULL, PRIMARY KEY (referrer_uuid, milestone) ) """); } } public void close() { if (connection != null) { try { connection.close(); } catch (SQLException e) { plugin.getLogger().severe("Failed to close database connection."); e.printStackTrace(); } } } public void upsertPlayer(UUID uuid, String name) { String sql = """ INSERT INTO players (uuid, name, referral_count) VALUES (?, ?, 0) ON CONFLICT(uuid) DO UPDATE SET name = excluded.name """; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, uuid.toString()); ps.setString(2, name); ps.executeUpdate(); } catch (SQLException e) { plugin.getLogger().severe("Failed to upsert player " + name); e.printStackTrace(); } } public String getPlayerName(UUID uuid) { String sql = "SELECT name FROM players WHERE uuid = ?"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, uuid.toString()); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return rs.getString("name"); } } } catch (SQLException e) { plugin.getLogger().severe("Failed to get player name."); e.printStackTrace(); } return null; } public UUID getPlayerUuidByName(String name) { String sql = "SELECT uuid FROM players WHERE LOWER(name) = LOWER(?)"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, name); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return UUID.fromString(rs.getString("uuid")); } } } catch (SQLException e) { plugin.getLogger().severe("Failed to get UUID by player name."); e.printStackTrace(); } return null; } public int getReferralCount(UUID uuid) { String sql = "SELECT referral_count FROM players WHERE uuid = ?"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, uuid.toString()); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return rs.getInt("referral_count"); } } } catch (SQLException e) { plugin.getLogger().severe("Failed to get referral count."); e.printStackTrace(); } return 0; } public void setReferralCount(UUID uuid, int count) { String sql = "UPDATE players SET referral_count = ? WHERE uuid = ?"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setInt(1, count); ps.setString(2, uuid.toString()); ps.executeUpdate(); } catch (SQLException e) { plugin.getLogger().severe("Failed to set referral count."); e.printStackTrace(); } } public void addReferralCount(UUID uuid, int amount) { setReferralCount(uuid, Math.max(0, getReferralCount(uuid) + amount)); } public boolean hasReferralRecord(UUID referrerUuid, UUID referredUuid) { String sql = "SELECT 1 FROM referrals WHERE referrer_uuid = ? AND referred_uuid = ? LIMIT 1"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, referrerUuid.toString()); ps.setString(2, referredUuid.toString()); try (ResultSet rs = ps.executeQuery()) { return rs.next(); } } catch (SQLException e) { plugin.getLogger().severe("Failed checking referral record."); e.printStackTrace(); } return false; } public boolean hasAnyReferralRecordForReferred(UUID referredUuid) { String sql = "SELECT 1 FROM referrals WHERE referred_uuid = ? LIMIT 1"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, referredUuid.toString()); try (ResultSet rs = ps.executeQuery()) { return rs.next(); } } catch (SQLException e) { plugin.getLogger().severe("Failed checking referred player history."); e.printStackTrace(); } return false; } public void insertReferral(UUID referrerUuid, UUID referredUuid, String referredName, String joinHost, String ipAddress, boolean counted) { String sql = """ INSERT INTO referrals (referrer_uuid, referred_uuid, referred_name, join_host, ip_address, counted, created_at) VALUES (?, ?, ?, ?, ?, ?, ?) """; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, referrerUuid.toString()); ps.setString(2, referredUuid.toString()); ps.setString(3, referredName); ps.setString(4, joinHost); ps.setString(5, ipAddress); ps.setInt(6, counted ? 1 : 0); ps.setLong(7, System.currentTimeMillis()); ps.executeUpdate(); } catch (SQLException e) { plugin.getLogger().severe("Failed to insert referral."); e.printStackTrace(); } } public void addPlayerIp(UUID playerUuid, String ipAddress) { String checkSql = "SELECT 1 FROM player_ips WHERE player_uuid = ? AND ip_address = ? LIMIT 1"; String insertSql = "INSERT INTO player_ips (player_uuid, ip_address, created_at) VALUES (?, ?, ?)"; try (PreparedStatement check = connection.prepareStatement(checkSql)) { check.setString(1, playerUuid.toString()); check.setString(2, ipAddress); try (ResultSet rs = check.executeQuery()) { if (rs.next()) { return; } } } catch (SQLException e) { plugin.getLogger().severe("Failed checking existing player IP."); e.printStackTrace(); return; } try (PreparedStatement insert = connection.prepareStatement(insertSql)) { insert.setString(1, playerUuid.toString()); insert.setString(2, ipAddress); insert.setLong(3, System.currentTimeMillis()); insert.executeUpdate(); } catch (SQLException e) { plugin.getLogger().severe("Failed storing player IP."); e.printStackTrace(); } } public boolean playerHasIp(UUID playerUuid, String ipAddress) { String sql = "SELECT 1 FROM player_ips WHERE player_uuid = ? AND ip_address = ? LIMIT 1"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, playerUuid.toString()); ps.setString(2, ipAddress); try (ResultSet rs = ps.executeQuery()) { return rs.next(); } } catch (SQLException e) { plugin.getLogger().severe("Failed checking player IP."); e.printStackTrace(); } return false; } public boolean anyReferralUsesIpForReferrer(UUID referrerUuid, String ipAddress) { String sql = "SELECT 1 FROM referrals WHERE referrer_uuid = ? AND ip_address = ? LIMIT 1"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, referrerUuid.toString()); ps.setString(2, ipAddress); try (ResultSet rs = ps.executeQuery()) { return rs.next(); } } catch (SQLException e) { plugin.getLogger().severe("Failed checking referral IP reuse."); e.printStackTrace(); } return false; } public boolean hasClaimedReward(UUID referrerUuid, int milestone) { String sql = "SELECT 1 FROM claimed_rewards WHERE referrer_uuid = ? AND milestone = ? LIMIT 1"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, referrerUuid.toString()); ps.setInt(2, milestone); try (ResultSet rs = ps.executeQuery()) { return rs.next(); } } catch (SQLException e) { plugin.getLogger().severe("Failed checking claimed reward."); e.printStackTrace(); } return false; } public void setRewardClaimed(UUID referrerUuid, int milestone) { String sql = """ INSERT OR IGNORE INTO claimed_rewards (referrer_uuid, milestone, claimed_at) VALUES (?, ?, ?) """; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setString(1, referrerUuid.toString()); ps.setInt(2, milestone); ps.setLong(3, System.currentTimeMillis()); ps.executeUpdate(); } catch (SQLException e) { plugin.getLogger().severe("Failed marking reward as claimed."); e.printStackTrace(); } } public List getTopReferrers(int limit) { List results = new ArrayList<>(); String sql = "SELECT uuid, name, referral_count FROM players ORDER BY referral_count DESC, name ASC LIMIT ?"; try (PreparedStatement ps = connection.prepareStatement(sql)) { ps.setInt(1, limit); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { results.add(new TopEntry( UUID.fromString(rs.getString("uuid")), rs.getString("name"), rs.getInt("referral_count") )); } } } catch (SQLException e) { plugin.getLogger().severe("Failed loading top referrers."); e.printStackTrace(); } return results; } }