From 99a817d33d45eca2681b9a38d426b213c85cf8d3 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Tue, 17 Mar 2026 10:11:41 +0100 Subject: [PATCH] Update from Git Manager GUI --- src/main/java/viper/ButtonControl.java | 73 ++++ src/main/java/viper/ConfigManager.java | 13 + src/main/java/viper/DataManager.java | 115 +++++- src/main/java/viper/MySQLStorage.java | 506 +++++++++++++++++++++++++ src/main/resources/config.yml | 18 + src/main/resources/plugin.yml | 2 +- 6 files changed, 722 insertions(+), 5 deletions(-) create mode 100644 src/main/java/viper/MySQLStorage.java diff --git a/src/main/java/viper/ButtonControl.java b/src/main/java/viper/ButtonControl.java index 9d297c2..747f3e4 100644 --- a/src/main/java/viper/ButtonControl.java +++ b/src/main/java/viper/ButtonControl.java @@ -17,6 +17,8 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.Note; import org.bukkit.Note.Tone; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; import java.util.ArrayList; import java.util.Arrays; @@ -37,6 +39,9 @@ public class ButtonControl extends JavaPlugin { // Zeitgesteuerte Automation – verhindert mehrfaches Auslösen pro Zustandswechsel private final Map timedControllerLastState = new HashMap<>(); + // Actionbar-Status pro Spieler für die Namensanzeige + private final Map lastControllerActionbar = new HashMap<>(); + @Override public void onEnable() { configManager = new ConfigManager(this); @@ -84,10 +89,18 @@ public class ButtonControl extends JavaPlugin { getServer().getScheduler().runTaskTimer(this, this::checkDaylightSensors, 0L, 20L * 10); getServer().getScheduler().runTaskTimer(this, this::checkMotionSensors, 0L, 10L); getServer().getScheduler().runTaskTimer(this, this::checkTimedControllers, 0L, 20L * 5); + getServer().getScheduler().runTaskTimer(this, this::updateControllerNameActionBar, 0L, 5L); getLogger().info("ButtonControl v" + getDescription().getVersion() + " wurde erfolgreich aktiviert!"); } + @Override + public void onDisable() { + if (dataManager != null) { + dataManager.shutdown(); + } + } + // ----------------------------------------------------------------------- // Update-Hilfe // ----------------------------------------------------------------------- @@ -278,6 +291,65 @@ public class ButtonControl extends JavaPlugin { } } + // ----------------------------------------------------------------------- + // Controller-Name bei Blickkontakt (Actionbar) + // ----------------------------------------------------------------------- + + private void updateControllerNameActionBar() { + if (!configManager.getConfig().getBoolean("controller-name-display.enabled", true)) { + clearAllControllerActionBars(); + return; + } + + int maxDistance = Math.max(1, + configManager.getConfig().getInt("controller-name-display.max-look-distance", 8)); + String format = configManager.getConfig().getString( + "controller-name-display.format", "§6Controller: §f%s"); + + for (Player player : getServer().getOnlinePlayers()) { + String message = null; + Block target = player.getTargetBlockExact(maxDistance); + if (isValidController(target)) { + String targetLoc = toLoc(target); + String buttonId = dataManager.getButtonIdForLocation(targetLoc); + if (buttonId != null) { + boolean canSee = dataManager.canAccess(buttonId, player.getUniqueId()) + || player.hasPermission("buttoncontrol.admin"); + String name = dataManager.getControllerName(buttonId); + if (canSee && name != null && !name.trim().isEmpty()) { + message = String.format(format, name); + } + } + } + + java.util.UUID uuid = player.getUniqueId(); + String previous = lastControllerActionbar.get(uuid); + if (message == null) { + if (previous != null) { + sendActionBar(player, " "); + lastControllerActionbar.remove(uuid); + } + } else if (!message.equals(previous)) { + sendActionBar(player, message); + lastControllerActionbar.put(uuid, message); + } + } + } + + private void clearAllControllerActionBars() { + if (lastControllerActionbar.isEmpty()) return; + for (Player player : getServer().getOnlinePlayers()) { + if (lastControllerActionbar.containsKey(player.getUniqueId())) { + sendActionBar(player, " "); + } + } + lastControllerActionbar.clear(); + } + + private void sendActionBar(Player player, String message) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); + } + // ----------------------------------------------------------------------- // Bewegungsmelder // ----------------------------------------------------------------------- @@ -379,6 +451,7 @@ public class ButtonControl extends JavaPlugin { configManager.reloadConfig(); dataManager.reloadData(); timedControllerLastState.clear(); + clearAllControllerActionBars(); sender.sendMessage(configManager.getMessage("konfiguration-neugeladen")); return true; } diff --git a/src/main/java/viper/ConfigManager.java b/src/main/java/viper/ConfigManager.java index d5ea7b2..507507d 100644 --- a/src/main/java/viper/ConfigManager.java +++ b/src/main/java/viper/ConfigManager.java @@ -75,6 +75,19 @@ public class ConfigManager { def(config, "motion-close-delay-ms", 5000); def(config, "motion-trigger-cooldown-ms", 2000); + // Optionales MySQL-Backend + def(config, "mysql.enabled", false); + def(config, "mysql.host", "127.0.0.1"); + def(config, "mysql.port", 3306); + def(config, "mysql.database", "buttoncontrol"); + def(config, "mysql.user", "root"); + def(config, "mysql.password", ""); + + // Controller-Namensanzeige beim Anschauen + def(config, "controller-name-display.enabled", true); + def(config, "controller-name-display.max-look-distance", 8); + def(config, "controller-name-display.format", "§6Controller: §f%s"); + // Sounds (NEU) def(config, "sounds.enabled", true); def(config, "sounds.door-open", "BLOCK_WOODEN_DOOR_OPEN"); diff --git a/src/main/java/viper/DataManager.java b/src/main/java/viper/DataManager.java index 5bb61a2..11ce9d3 100644 --- a/src/main/java/viper/DataManager.java +++ b/src/main/java/viper/DataManager.java @@ -14,10 +14,19 @@ public class DataManager { private final ButtonControl plugin; private FileConfiguration data; private File dataFile; + private MySQLStorage mySQLStorage; public DataManager(ButtonControl plugin) { this.plugin = plugin; loadData(); + initializeStorage(); + } + + private void initializeStorage() { + mySQLStorage = new MySQLStorage(plugin); + if (!mySQLStorage.initialize()) { + mySQLStorage = null; + } } private void loadData() { @@ -28,6 +37,16 @@ public class DataManager { public void reloadData() { data = YamlConfiguration.loadConfiguration(dataFile); + if (mySQLStorage != null) { + mySQLStorage.close(); + } + initializeStorage(); + } + + public void shutdown() { + if (mySQLStorage != null) { + mySQLStorage.close(); + } } // ----------------------------------------------------------------------- @@ -35,12 +54,14 @@ public class DataManager { // ----------------------------------------------------------------------- public boolean canAccess(String buttonId, UUID playerUUID) { + if (mySQLStorage != null) return mySQLStorage.canAccess(buttonId, playerUUID); if (isPublic(buttonId)) return true; if (isOwner(buttonId, playerUUID)) return true; return data.getStringList("trust." + buttonId).contains(playerUUID.toString()); } public boolean isOwner(String buttonId, UUID playerUUID) { + if (mySQLStorage != null) return mySQLStorage.isOwner(buttonId, playerUUID); return data.contains("players." + playerUUID + ".buttons." + buttonId) || data.contains("players." + playerUUID + ".placed-controllers"); // Zweite Bedingung: prüft ob irgendein placed-controller dieser UUID die buttonId enthält @@ -51,10 +72,15 @@ public class DataManager { // ----------------------------------------------------------------------- public String getButtonIdForLocation(String location) { + if (mySQLStorage != null) return mySQLStorage.getButtonIdForLocation(location); return getButtonIdForPlacedController(location); } public void registerController(String location, UUID ownerUUID, String buttonId) { + if (mySQLStorage != null) { + mySQLStorage.registerController(location, ownerUUID, buttonId); + return; + } data.set("players." + ownerUUID + ".placed-controllers." + location, buttonId); // Leere buttons-Liste anlegen damit isOwner() sofort greift if (!data.contains("players." + ownerUUID + ".buttons." + buttonId)) { @@ -64,16 +90,38 @@ public class DataManager { } public void removeController(String location) { - if (data.getConfigurationSection("players") == null) return; - for (String uuid : data.getConfigurationSection("players").getKeys(false)) { - String path = "players." + uuid + ".placed-controllers." + location; - if (data.contains(path)) data.set(path, null); + if (mySQLStorage != null) { + mySQLStorage.removeController(location); + return; + } + // buttonId vor dem Löschen des Location-Eintrags ermitteln + String buttonId = getButtonIdForPlacedController(location); + String ownerUUID = null; + if (data.getConfigurationSection("players") != null) { + for (String uuid : data.getConfigurationSection("players").getKeys(false)) { + String path = "players." + uuid + ".placed-controllers." + location; + if (data.contains(path)) { + data.set(path, null); + ownerUUID = uuid; + } + } + } + // Alle zugehörigen Daten (Name, Status, Trust, Zeitplan, Verbindungen) bereinigen + if (buttonId != null) { + data.set("names." + buttonId, null); + data.set("public-status." + buttonId, null); + data.set("trust." + buttonId, null); + data.set("schedules." + buttonId, null); + if (ownerUUID != null) { + data.set("players." + ownerUUID + ".buttons." + buttonId, null); + } } removeMotionSensorSettings(location); saveData(); } public String getButtonIdForPlacedController(String location) { + if (mySQLStorage != null) return mySQLStorage.getButtonIdForPlacedController(location); if (data.getConfigurationSection("players") == null) return null; for (String uuid : data.getConfigurationSection("players").getKeys(false)) { String val = data.getString("players." + uuid + ".placed-controllers." + location); @@ -83,6 +131,7 @@ public class DataManager { } public List getAllPlacedControllers() { + if (mySQLStorage != null) return mySQLStorage.getAllPlacedControllers(); List result = new ArrayList<>(); if (data.getConfigurationSection("players") == null) return result; for (String uuid : data.getConfigurationSection("players").getKeys(false)) { @@ -97,11 +146,16 @@ public class DataManager { // ----------------------------------------------------------------------- public void setConnectedBlocks(String playerUUID, String buttonId, List blocks) { + if (mySQLStorage != null) { + mySQLStorage.setConnectedBlocks(playerUUID, buttonId, blocks); + return; + } data.set("players." + playerUUID + ".buttons." + buttonId, blocks); saveData(); } public List getConnectedBlocks(String buttonId) { + if (mySQLStorage != null) return mySQLStorage.getConnectedBlocks(buttonId); if (data.getConfigurationSection("players") == null) return new ArrayList<>(); for (String uuid : data.getConfigurationSection("players").getKeys(false)) { String path = "players." + uuid + ".buttons." + buttonId; @@ -115,6 +169,7 @@ public class DataManager { * Wird aufgerufen wenn ein verbundener Block abgebaut wird. */ public boolean removeFromAllConnectedBlocks(String locStr) { + if (mySQLStorage != null) return mySQLStorage.removeFromAllConnectedBlocks(locStr); if (data.getConfigurationSection("players") == null) return false; boolean changed = false; for (String uuid : data.getConfigurationSection("players").getKeys(false)) { @@ -138,11 +193,16 @@ public class DataManager { // ----------------------------------------------------------------------- public void setControllerName(String buttonId, String name) { + if (mySQLStorage != null) { + mySQLStorage.setControllerName(buttonId, name); + return; + } data.set("names." + buttonId, name); saveData(); } public String getControllerName(String buttonId) { + if (mySQLStorage != null) return mySQLStorage.getControllerName(buttonId); return data.getString("names." + buttonId); } @@ -151,25 +211,39 @@ public class DataManager { // ----------------------------------------------------------------------- public void setScheduleOpenTime(String buttonId, long ticks) { + if (mySQLStorage != null) { + mySQLStorage.setScheduleOpenTime(buttonId, ticks); + return; + } data.set("schedules." + buttonId + ".open-time", ticks); saveData(); } public long getScheduleOpenTime(String buttonId) { + if (mySQLStorage != null) return mySQLStorage.getScheduleOpenTime(buttonId); return data.getLong("schedules." + buttonId + ".open-time", -1); } public void setScheduleCloseTime(String buttonId, long ticks) { + if (mySQLStorage != null) { + mySQLStorage.setScheduleCloseTime(buttonId, ticks); + return; + } data.set("schedules." + buttonId + ".close-time", ticks); saveData(); } public long getScheduleCloseTime(String buttonId) { + if (mySQLStorage != null) return mySQLStorage.getScheduleCloseTime(buttonId); return data.getLong("schedules." + buttonId + ".close-time", -1); } /** Entfernt den kompletten Zeitplan für einen Controller. */ public void clearSchedule(String buttonId) { + if (mySQLStorage != null) { + mySQLStorage.clearSchedule(buttonId); + return; + } data.set("schedules." + buttonId, null); saveData(); } @@ -179,6 +253,10 @@ public class DataManager { // ----------------------------------------------------------------------- public void addTrustedPlayer(String buttonId, UUID targetUUID) { + if (mySQLStorage != null) { + mySQLStorage.addTrustedPlayer(buttonId, targetUUID); + return; + } List trusted = data.getStringList("trust." + buttonId); if (!trusted.contains(targetUUID.toString())) { trusted.add(targetUUID.toString()); @@ -188,6 +266,10 @@ public class DataManager { } public void removeTrustedPlayer(String buttonId, UUID targetUUID) { + if (mySQLStorage != null) { + mySQLStorage.removeTrustedPlayer(buttonId, targetUUID); + return; + } List trusted = data.getStringList("trust." + buttonId); trusted.remove(targetUUID.toString()); data.set("trust." + buttonId, trusted); @@ -195,11 +277,16 @@ public class DataManager { } public void setPublic(String buttonId, boolean isPublic) { + if (mySQLStorage != null) { + mySQLStorage.setPublic(buttonId, isPublic); + return; + } data.set("public-status." + buttonId, isPublic); saveData(); } public boolean isPublic(String buttonId) { + if (mySQLStorage != null) return mySQLStorage.isPublic(buttonId); return data.getBoolean("public-status." + buttonId, false); } @@ -208,11 +295,16 @@ public class DataManager { // ----------------------------------------------------------------------- public void setPlayerInstrument(UUID playerUUID, String instrument) { + if (mySQLStorage != null) { + mySQLStorage.setPlayerInstrument(playerUUID, instrument); + return; + } data.set("players." + playerUUID + ".instrument", instrument); saveData(); } public String getPlayerInstrument(UUID playerUUID) { + if (mySQLStorage != null) return mySQLStorage.getPlayerInstrument(playerUUID); return data.getString("players." + playerUUID + ".instrument"); } @@ -221,24 +313,38 @@ public class DataManager { // ----------------------------------------------------------------------- public void setMotionSensorRadius(String location, double radius) { + if (mySQLStorage != null) { + mySQLStorage.setMotionSensorRadius(location, radius); + return; + } data.set("motion-sensors." + location + ".radius", radius); saveData(); } public double getMotionSensorRadius(String location) { + if (mySQLStorage != null) return mySQLStorage.getMotionSensorRadius(location); return data.getDouble("motion-sensors." + location + ".radius", -1); } public void setMotionSensorDelay(String location, long delay) { + if (mySQLStorage != null) { + mySQLStorage.setMotionSensorDelay(location, delay); + return; + } data.set("motion-sensors." + location + ".delay", delay); saveData(); } public long getMotionSensorDelay(String location) { + if (mySQLStorage != null) return mySQLStorage.getMotionSensorDelay(location); return data.getLong("motion-sensors." + location + ".delay", -1); } public void removeMotionSensorSettings(String location) { + if (mySQLStorage != null) { + mySQLStorage.removeMotionSensorSettings(location); + return; + } data.set("motion-sensors." + location, null); saveData(); } @@ -252,6 +358,7 @@ public class DataManager { * Verhindert I/O-Lags auf dem Main-Thread. */ public void saveData() { + if (mySQLStorage != null) return; final String serialized; try { serialized = data.saveToString(); diff --git a/src/main/java/viper/MySQLStorage.java b/src/main/java/viper/MySQLStorage.java new file mode 100644 index 0000000..1c00ca0 --- /dev/null +++ b/src/main/java/viper/MySQLStorage.java @@ -0,0 +1,506 @@ +package viper; + +import org.bukkit.configuration.file.FileConfiguration; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class MySQLStorage { + private final ButtonControl plugin; + + private final String host; + private final int port; + private final String database; + private final String user; + private final String password; + private final boolean enabled; + + private Connection connection; + + public MySQLStorage(ButtonControl plugin) { + this.plugin = plugin; + + FileConfiguration cfg = plugin.getConfigManager().getConfig(); + this.enabled = cfg.getBoolean("mysql.enabled", false); + this.host = cfg.getString("mysql.host", "127.0.0.1"); + this.port = cfg.getInt("mysql.port", 3306); + this.database = cfg.getString("mysql.database", "buttoncontrol"); + this.user = cfg.getString("mysql.user", "root"); + this.password = cfg.getString("mysql.password", ""); + } + + public boolean initialize() { + if (!enabled) return false; + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + getConnection(); + createTables(); + plugin.getLogger().info("MySQL aktiviert."); + return true; + } catch (Exception e) { + plugin.getLogger().warning("MySQL konnte nicht initialisiert werden, verwende data.yml: " + e.getMessage()); + return false; + } + } + + public void close() { + if (connection != null) { + try { + connection.close(); + } catch (SQLException ignored) { + } + connection = null; + } + } + + private Connection getConnection() throws SQLException { + if (connection != null && connection.isValid(2)) { + return connection; + } + String url = "jdbc:mysql://" + host + ":" + port + "/" + database + + "?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"; + connection = DriverManager.getConnection(url, user, password); + return connection; + } + + private void createTables() throws SQLException { + try (Statement st = getConnection().createStatement()) { + st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_controllers (" + + "location VARCHAR(128) PRIMARY KEY," + + "owner_uuid VARCHAR(36) NOT NULL," + + "button_id VARCHAR(64) NOT NULL" + + ")"); + + st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_button_connections (" + + "owner_uuid VARCHAR(36) NOT NULL," + + "button_id VARCHAR(64) NOT NULL," + + "block_location VARCHAR(128) NOT NULL," + + "PRIMARY KEY (button_id, block_location)" + + ")"); + + st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_controller_names (" + + "button_id VARCHAR(64) PRIMARY KEY," + + "name VARCHAR(64)" + + ")"); + + st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_schedules (" + + "button_id VARCHAR(64) PRIMARY KEY," + + "open_time BIGINT," + + "close_time BIGINT" + + ")"); + + st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_trust (" + + "button_id VARCHAR(64) NOT NULL," + + "target_uuid VARCHAR(36) NOT NULL," + + "PRIMARY KEY (button_id, target_uuid)" + + ")"); + + st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_public_status (" + + "button_id VARCHAR(64) PRIMARY KEY," + + "is_public BOOLEAN NOT NULL" + + ")"); + + st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_player_settings (" + + "player_uuid VARCHAR(36) PRIMARY KEY," + + "instrument VARCHAR(32)" + + ")"); + + st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_motion_sensors (" + + "location VARCHAR(128) PRIMARY KEY," + + "radius DOUBLE," + + "delay_ms BIGINT" + + ")"); + } + } + + public boolean canAccess(String buttonId, UUID playerUUID) { + return isPublic(buttonId) || isOwner(buttonId, playerUUID) || isTrusted(buttonId, playerUUID); + } + + public boolean isOwner(String buttonId, UUID playerUUID) { + String uuid = playerUUID.toString(); + String q1 = "SELECT 1 FROM bc_controllers WHERE button_id = ? AND owner_uuid = ? LIMIT 1"; + String q2 = "SELECT 1 FROM bc_button_connections WHERE button_id = ? AND owner_uuid = ? LIMIT 1"; + try (PreparedStatement ps1 = getConnection().prepareStatement(q1); + PreparedStatement ps2 = getConnection().prepareStatement(q2)) { + ps1.setString(1, buttonId); + ps1.setString(2, uuid); + try (ResultSet rs = ps1.executeQuery()) { + if (rs.next()) return true; + } + ps2.setString(1, buttonId); + ps2.setString(2, uuid); + try (ResultSet rs = ps2.executeQuery()) { + return rs.next(); + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL isOwner Fehler: " + e.getMessage()); + return false; + } + } + + public String getButtonIdForLocation(String location) { + String q = "SELECT button_id FROM bc_controllers WHERE location = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, location); + try (ResultSet rs = ps.executeQuery()) { + return rs.next() ? rs.getString(1) : null; + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getButtonIdForLocation Fehler: " + e.getMessage()); + return null; + } + } + + public void registerController(String location, UUID ownerUUID, String buttonId) { + String q = "INSERT INTO bc_controllers (location, owner_uuid, button_id) VALUES (?, ?, ?)" + + " ON DUPLICATE KEY UPDATE owner_uuid = VALUES(owner_uuid), button_id = VALUES(button_id)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, location); + ps.setString(2, ownerUUID.toString()); + ps.setString(3, buttonId); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL registerController Fehler: " + e.getMessage()); + } + } + + public void removeController(String location) { + // buttonId vor dem Löschen ermitteln + String buttonId = getButtonIdForLocation(location); + String q = "DELETE FROM bc_controllers WHERE location = ?"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, location); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL removeController Fehler: " + e.getMessage()); + } + // Alle zugehörigen Tabellen bereinigen + if (buttonId != null) { + deleteButtonData(buttonId); + } + removeMotionSensorSettings(location); + } + + private void deleteButtonData(String buttonId) { + String[] queries = { + "DELETE FROM bc_controller_names WHERE button_id = ?", + "DELETE FROM bc_public_status WHERE button_id = ?", + "DELETE FROM bc_trust WHERE button_id = ?", + "DELETE FROM bc_schedules WHERE button_id = ?", + "DELETE FROM bc_button_connections WHERE button_id = ?" + }; + for (String q : queries) { + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL deleteButtonData Fehler: " + e.getMessage()); + } + } + } + + public String getButtonIdForPlacedController(String location) { + return getButtonIdForLocation(location); + } + + public List getAllPlacedControllers() { + List result = new ArrayList<>(); + String q = "SELECT location FROM bc_controllers"; + try (PreparedStatement ps = getConnection().prepareStatement(q); + ResultSet rs = ps.executeQuery()) { + while (rs.next()) result.add(rs.getString(1)); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getAllPlacedControllers Fehler: " + e.getMessage()); + } + return result; + } + + public void setConnectedBlocks(String playerUUID, String buttonId, List blocks) { + String del = "DELETE FROM bc_button_connections WHERE owner_uuid = ? AND button_id = ?"; + String ins = "INSERT INTO bc_button_connections (owner_uuid, button_id, block_location) VALUES (?, ?, ?)"; + try (PreparedStatement psDel = getConnection().prepareStatement(del); + PreparedStatement psIns = getConnection().prepareStatement(ins)) { + psDel.setString(1, playerUUID); + psDel.setString(2, buttonId); + psDel.executeUpdate(); + + for (String block : blocks) { + psIns.setString(1, playerUUID); + psIns.setString(2, buttonId); + psIns.setString(3, block); + psIns.addBatch(); + } + psIns.executeBatch(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL setConnectedBlocks Fehler: " + e.getMessage()); + } + } + + public List getConnectedBlocks(String buttonId) { + List result = new ArrayList<>(); + String q = "SELECT block_location FROM bc_button_connections WHERE button_id = ?"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) result.add(rs.getString(1)); + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getConnectedBlocks Fehler: " + e.getMessage()); + } + return result; + } + + public boolean removeFromAllConnectedBlocks(String locStr) { + String q = "DELETE FROM bc_button_connections WHERE block_location = ?"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, locStr); + return ps.executeUpdate() > 0; + } catch (SQLException e) { + plugin.getLogger().warning("MySQL removeFromAllConnectedBlocks Fehler: " + e.getMessage()); + return false; + } + } + + public void setControllerName(String buttonId, String name) { + String q = "INSERT INTO bc_controller_names (button_id, name) VALUES (?, ?)" + + " ON DUPLICATE KEY UPDATE name = VALUES(name)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.setString(2, name); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL setControllerName Fehler: " + e.getMessage()); + } + } + + public String getControllerName(String buttonId) { + String q = "SELECT name FROM bc_controller_names WHERE button_id = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + try (ResultSet rs = ps.executeQuery()) { + return rs.next() ? rs.getString(1) : null; + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getControllerName Fehler: " + e.getMessage()); + return null; + } + } + + public void setScheduleOpenTime(String buttonId, long ticks) { + String q = "INSERT INTO bc_schedules (button_id, open_time, close_time) VALUES (?, ?, COALESCE((SELECT close_time FROM bc_schedules WHERE button_id = ?), -1))" + + " ON DUPLICATE KEY UPDATE open_time = VALUES(open_time)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.setLong(2, ticks); + ps.setString(3, buttonId); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL setScheduleOpenTime Fehler: " + e.getMessage()); + } + } + + public long getScheduleOpenTime(String buttonId) { + String q = "SELECT open_time FROM bc_schedules WHERE button_id = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + try (ResultSet rs = ps.executeQuery()) { + return rs.next() ? rs.getLong(1) : -1; + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getScheduleOpenTime Fehler: " + e.getMessage()); + return -1; + } + } + + public void setScheduleCloseTime(String buttonId, long ticks) { + String q = "INSERT INTO bc_schedules (button_id, open_time, close_time) VALUES (?, COALESCE((SELECT open_time FROM bc_schedules WHERE button_id = ?), -1), ?)" + + " ON DUPLICATE KEY UPDATE close_time = VALUES(close_time)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.setString(2, buttonId); + ps.setLong(3, ticks); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL setScheduleCloseTime Fehler: " + e.getMessage()); + } + } + + public long getScheduleCloseTime(String buttonId) { + String q = "SELECT close_time FROM bc_schedules WHERE button_id = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + try (ResultSet rs = ps.executeQuery()) { + return rs.next() ? rs.getLong(1) : -1; + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getScheduleCloseTime Fehler: " + e.getMessage()); + return -1; + } + } + + public void clearSchedule(String buttonId) { + String q = "DELETE FROM bc_schedules WHERE button_id = ?"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL clearSchedule Fehler: " + e.getMessage()); + } + } + + public void addTrustedPlayer(String buttonId, UUID targetUUID) { + String q = "INSERT IGNORE INTO bc_trust (button_id, target_uuid) VALUES (?, ?)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.setString(2, targetUUID.toString()); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL addTrustedPlayer Fehler: " + e.getMessage()); + } + } + + public void removeTrustedPlayer(String buttonId, UUID targetUUID) { + String q = "DELETE FROM bc_trust WHERE button_id = ? AND target_uuid = ?"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.setString(2, targetUUID.toString()); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL removeTrustedPlayer Fehler: " + e.getMessage()); + } + } + + public void setPublic(String buttonId, boolean isPublic) { + String q = "INSERT INTO bc_public_status (button_id, is_public) VALUES (?, ?)" + + " ON DUPLICATE KEY UPDATE is_public = VALUES(is_public)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.setBoolean(2, isPublic); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL setPublic Fehler: " + e.getMessage()); + } + } + + public boolean isPublic(String buttonId) { + String q = "SELECT is_public FROM bc_public_status WHERE button_id = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + try (ResultSet rs = ps.executeQuery()) { + return rs.next() && rs.getBoolean(1); + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL isPublic Fehler: " + e.getMessage()); + return false; + } + } + + public void setPlayerInstrument(UUID playerUUID, String instrument) { + String q = "INSERT INTO bc_player_settings (player_uuid, instrument) VALUES (?, ?)" + + " ON DUPLICATE KEY UPDATE instrument = VALUES(instrument)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, playerUUID.toString()); + ps.setString(2, instrument); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL setPlayerInstrument Fehler: " + e.getMessage()); + } + } + + public String getPlayerInstrument(UUID playerUUID) { + String q = "SELECT instrument FROM bc_player_settings WHERE player_uuid = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, playerUUID.toString()); + try (ResultSet rs = ps.executeQuery()) { + return rs.next() ? rs.getString(1) : null; + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getPlayerInstrument Fehler: " + e.getMessage()); + return null; + } + } + + public void setMotionSensorRadius(String location, double radius) { + String q = "INSERT INTO bc_motion_sensors (location, radius, delay_ms) VALUES (?, ?, COALESCE((SELECT delay_ms FROM bc_motion_sensors WHERE location = ?), -1))" + + " ON DUPLICATE KEY UPDATE radius = VALUES(radius)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, location); + ps.setDouble(2, radius); + ps.setString(3, location); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL setMotionSensorRadius Fehler: " + e.getMessage()); + } + } + + public double getMotionSensorRadius(String location) { + String q = "SELECT radius FROM bc_motion_sensors WHERE location = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, location); + try (ResultSet rs = ps.executeQuery()) { + return rs.next() ? rs.getDouble(1) : -1; + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getMotionSensorRadius Fehler: " + e.getMessage()); + return -1; + } + } + + public void setMotionSensorDelay(String location, long delay) { + String q = "INSERT INTO bc_motion_sensors (location, radius, delay_ms) VALUES (?, COALESCE((SELECT radius FROM bc_motion_sensors WHERE location = ?), -1), ?)" + + " ON DUPLICATE KEY UPDATE delay_ms = VALUES(delay_ms)"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, location); + ps.setString(2, location); + ps.setLong(3, delay); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL setMotionSensorDelay Fehler: " + e.getMessage()); + } + } + + public long getMotionSensorDelay(String location) { + String q = "SELECT delay_ms FROM bc_motion_sensors WHERE location = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, location); + try (ResultSet rs = ps.executeQuery()) { + return rs.next() ? rs.getLong(1) : -1; + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL getMotionSensorDelay Fehler: " + e.getMessage()); + return -1; + } + } + + public void removeMotionSensorSettings(String location) { + String q = "DELETE FROM bc_motion_sensors WHERE location = ?"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, location); + ps.executeUpdate(); + } catch (SQLException e) { + plugin.getLogger().warning("MySQL removeMotionSensorSettings Fehler: " + e.getMessage()); + } + } + + private boolean isTrusted(String buttonId, UUID playerUUID) { + String q = "SELECT 1 FROM bc_trust WHERE button_id = ? AND target_uuid = ? LIMIT 1"; + try (PreparedStatement ps = getConnection().prepareStatement(q)) { + ps.setString(1, buttonId); + ps.setString(2, playerUUID.toString()); + try (ResultSet rs = ps.executeQuery()) { + return rs.next(); + } + } catch (SQLException e) { + plugin.getLogger().warning("MySQL isTrusted Fehler: " + e.getMessage()); + return false; + } + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 0346b79..f0e1bfe 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -20,6 +20,24 @@ motion-close-delay-ms: 5000 # Cooldown: wie lange nach dem Schließen der Sensor nicht erneut auslöst motion-trigger-cooldown-ms: 2000 +# ── Optionales MySQL-Backend ──────────────────────────────────────────────── +mysql: + # false = data.yml verwenden, true = MySQL verwenden + enabled: false + host: "127.0.0.1" + port: 3306 + database: "controll" + user: "controll" + password: "controll" + +# ── Controller-Name beim Anschauen ────────────────────────────────────────── +controller-name-display: + enabled: true + # Distanz in Blöcken für die Blickerkennung + max-look-distance: 8 + # %s = Name aus /bc rename + format: "§6Controller: §f%s" + # ── Sounds beim Öffnen/Schließen (NEU) ────────────────────────────────────── # Auf false setzen um alle Controller-Sounds zu deaktivieren sounds: diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 31823a3..20af5e2 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ButtonControl -version: 1.6 +version: 1.7 main: viper.ButtonControl api-version: 1.21 author: M_Viper