Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf112e6877 | |||
| a9d2d7a911 | |||
| e351990d74 | |||
| fbeead1900 | |||
| 1f9a2c2198 | |||
| 9ef3e7e14b |
12
pom.xml
12
pom.xml
@@ -8,7 +8,7 @@
|
||||
|
||||
<groupId>viper</groupId>
|
||||
<artifactId>ButtonControl</artifactId>
|
||||
<version>1.6</version>
|
||||
<version>1.9</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>ButtonControl</name>
|
||||
|
||||
@@ -29,11 +29,12 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- bStats Bukkit -->
|
||||
<!-- bStats Bukkit (optional) -->
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- org.json für UpdateChecker JSON-Parsing -->
|
||||
@@ -42,6 +43,13 @@
|
||||
<artifactId>json</artifactId>
|
||||
<version>20240303</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL Connector/J für optionales Datenbank-Backend -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>8.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -83,9 +83,14 @@ public class ButtonListener implements Listener {
|
||||
|
||||
event.setCancelled(true);
|
||||
List<String> connectedBlocks = dataManager.getConnectedBlocks(buttonId);
|
||||
if (connectedBlocks != null && !connectedBlocks.isEmpty()) {
|
||||
boolean hasConnectedBlocks = connectedBlocks != null && !connectedBlocks.isEmpty();
|
||||
boolean secretTriggered = plugin.triggerSecretWall(buttonId);
|
||||
|
||||
if (hasConnectedBlocks) {
|
||||
toggleConnectedBlocks(player, playerUUID, connectedBlocks);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (!hasConnectedBlocks && !secretTriggered) {
|
||||
player.sendMessage(configManager.getMessage("keine-bloecke-verbunden"));
|
||||
}
|
||||
}
|
||||
@@ -202,8 +207,12 @@ public class ButtonListener implements Listener {
|
||||
boolean anyIronDoorOpened = false, anyIronDoorClosed = false;
|
||||
boolean anyIronTrapOpened = false, anyIronTrapClosed = false;
|
||||
boolean anyLampOn = false, anyLampOff = false;
|
||||
boolean anyGrateOpened = false, anyGrateClosed = false;
|
||||
boolean anyCreakingHeartOn = false, anyCreakingHeartOff = false;
|
||||
boolean anyNoteBlockPlayed = false;
|
||||
boolean anyBellPlayed = false;
|
||||
boolean anyDispenserTriggered = false;
|
||||
boolean anyDropperTriggered = false;
|
||||
|
||||
boolean soundsEnabled = configManager.getConfig().getBoolean("sounds.enabled", true);
|
||||
|
||||
@@ -268,18 +277,28 @@ public class ButtonListener implements Listener {
|
||||
else { if (!wasOpen) anyTrapOpened = true; else anyTrapClosed = true; }
|
||||
}
|
||||
}
|
||||
// ── Redstone-Lampe ────────────────────────────────────────────
|
||||
else if (mat == Material.REDSTONE_LAMP) {
|
||||
Lightable lamp = (Lightable) targetBlock.getBlockData();
|
||||
boolean wasLit = lamp.isLit();
|
||||
lamp.setLit(!wasLit);
|
||||
targetBlock.setBlockData(lamp);
|
||||
if (soundsEnabled) {
|
||||
playConfigSound(location,
|
||||
wasLit ? "sounds.lamp-off" : "sounds.lamp-on",
|
||||
"BLOCK_LEVER_CLICK");
|
||||
// ── Lampen (Redstone + Kupferlampen) ─────────────────────────
|
||||
else if (isLamp(mat)) {
|
||||
if (targetBlock.getBlockData() instanceof Lightable) {
|
||||
Lightable lamp = (Lightable) targetBlock.getBlockData();
|
||||
boolean wasLit = lamp.isLit();
|
||||
lamp.setLit(!wasLit);
|
||||
targetBlock.setBlockData(lamp);
|
||||
if (soundsEnabled) {
|
||||
playConfigSound(location,
|
||||
wasLit ? "sounds.lamp-off" : "sounds.lamp-on",
|
||||
"BLOCK_LEVER_CLICK");
|
||||
}
|
||||
if (!wasLit) anyLampOn = true; else anyLampOff = true;
|
||||
}
|
||||
}
|
||||
// ── Gitter (alle *_GRATE + Eisenstangen) ─────────────────────
|
||||
else if (plugin.isGrate(mat) || (mat == Material.AIR && plugin.isManagedOpenGrateLocation(locStr))) {
|
||||
Boolean nowOpen = plugin.toggleGrate(targetBlock);
|
||||
if (nowOpen != null) {
|
||||
if (nowOpen) anyGrateOpened = true;
|
||||
else anyGrateClosed = true;
|
||||
}
|
||||
if (!wasLit) anyLampOn = true; else anyLampOff = true;
|
||||
}
|
||||
// ── Notenblock ────────────────────────────────────────────────
|
||||
else if (mat == Material.NOTE_BLOCK) {
|
||||
@@ -294,6 +313,27 @@ public class ButtonListener implements Listener {
|
||||
targetBlock.getWorld().playSound(location, Sound.BLOCK_BELL_USE, 3.0f, 1.0f);
|
||||
anyBellPlayed = true;
|
||||
}
|
||||
// ── Spender / Werfer ──────────────────────────────────────────
|
||||
else if (mat == Material.DISPENSER) {
|
||||
if (triggerContainer(targetBlock, "dispense")) {
|
||||
targetBlock.getWorld().playSound(location, Sound.BLOCK_DISPENSER_DISPENSE, 1.0f, 1.0f);
|
||||
anyDispenserTriggered = true;
|
||||
}
|
||||
}
|
||||
else if (mat == Material.DROPPER) {
|
||||
if (triggerContainer(targetBlock, "drop")) {
|
||||
targetBlock.getWorld().playSound(location, Sound.BLOCK_DISPENSER_DISPENSE, 1.0f, 1.0f);
|
||||
anyDropperTriggered = true;
|
||||
}
|
||||
}
|
||||
// ── Creaking Heart ────────────────────────────────────────────
|
||||
else if (isCreakingHeart(mat)) {
|
||||
Boolean nowActive = plugin.togglePersistentCreakingHeart(targetBlock);
|
||||
if (nowActive != null) {
|
||||
if (nowActive) anyCreakingHeartOn = true;
|
||||
else anyCreakingHeartOff = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Feedback-Nachrichten
|
||||
@@ -309,8 +349,14 @@ public class ButtonListener implements Listener {
|
||||
if (anyTrapClosed) player.sendMessage(configManager.getMessage("fallturen-geschlossen"));
|
||||
if (anyLampOn) player.sendMessage(configManager.getMessage("lampen-eingeschaltet"));
|
||||
if (anyLampOff) player.sendMessage(configManager.getMessage("lampen-ausgeschaltet"));
|
||||
if (anyGrateOpened) player.sendMessage(configManager.getMessage("gitter-geoeffnet"));
|
||||
if (anyGrateClosed) player.sendMessage(configManager.getMessage("gitter-geschlossen"));
|
||||
if (anyCreakingHeartOn) player.sendMessage(configManager.getMessage("creaking-heart-aktiviert"));
|
||||
if (anyCreakingHeartOff) player.sendMessage(configManager.getMessage("creaking-heart-deaktiviert"));
|
||||
if (anyNoteBlockPlayed) player.sendMessage(configManager.getMessage("notenblock-ausgeloest"));
|
||||
if (anyBellPlayed) player.sendMessage(configManager.getMessage("glocke-gelaeutet"));
|
||||
if (anyDispenserTriggered) player.sendMessage(configManager.getMessage("spender-ausgeloest"));
|
||||
if (anyDropperTriggered) player.sendMessage(configManager.getMessage("werfer-ausgeloest"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,6 +376,17 @@ public class ButtonListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean triggerContainer(Block block, String methodName) {
|
||||
try {
|
||||
Object state = block.getState();
|
||||
java.lang.reflect.Method method = state.getClass().getMethod(methodName);
|
||||
Object result = method.invoke(state);
|
||||
return !(result instanceof Boolean) || (Boolean) result;
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Limits
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -360,8 +417,8 @@ public class ButtonListener implements Listener {
|
||||
>= configManager.getMaxTrapdoors()) {
|
||||
player.sendMessage(configManager.getMessage("max-fallturen-erreicht")); return false;
|
||||
}
|
||||
} else if (type == Material.REDSTONE_LAMP) {
|
||||
if (connected.stream().filter(l -> getMaterialAt(l) == Material.REDSTONE_LAMP).count()
|
||||
} else if (isLamp(type)) {
|
||||
if (connected.stream().filter(l -> isLamp(getMaterialAt(l))).count()
|
||||
>= configManager.getMaxLamps()) {
|
||||
player.sendMessage(configManager.getMessage("max-lampen-erreicht")); return false;
|
||||
}
|
||||
@@ -375,6 +432,16 @@ public class ButtonListener implements Listener {
|
||||
>= configManager.getMaxBells()) {
|
||||
player.sendMessage(configManager.getMessage("max-glocken-erreicht")); return false;
|
||||
}
|
||||
} else if (type == Material.DISPENSER) {
|
||||
if (connected.stream().filter(l -> getMaterialAt(l) == Material.DISPENSER).count()
|
||||
>= configManager.getMaxDispensers()) {
|
||||
player.sendMessage(configManager.getMessage("max-spender-erreicht")); return false;
|
||||
}
|
||||
} else if (type == Material.DROPPER) {
|
||||
if (connected.stream().filter(l -> getMaterialAt(l) == Material.DROPPER).count()
|
||||
>= configManager.getMaxDroppers()) {
|
||||
player.sendMessage(configManager.getMessage("max-werfer-erreicht")); return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -415,11 +482,20 @@ public class ButtonListener implements Listener {
|
||||
private boolean isDoor(Material m) { return m.name().endsWith("_DOOR") && m != Material.IRON_DOOR; }
|
||||
private boolean isGate(Material m) { return m.name().endsWith("_FENCE_GATE"); }
|
||||
private boolean isTrapdoor(Material m) { return m.name().endsWith("_TRAPDOOR") && m != Material.IRON_TRAPDOOR; }
|
||||
private boolean isLamp(Material m) {
|
||||
return m == Material.REDSTONE_LAMP
|
||||
|| "COPPER_BULB".equals(m.name())
|
||||
|| m.name().endsWith("_COPPER_BULB");
|
||||
}
|
||||
private boolean isCreakingHeart(Material m) { return "CREAKING_HEART".equals(m.name()); }
|
||||
|
||||
private boolean isInteractableTarget(Material m) {
|
||||
return isDoor(m) || isGate(m) || isTrapdoor(m)
|
||||
|| m == Material.IRON_DOOR || m == Material.IRON_TRAPDOOR
|
||||
|| m == Material.REDSTONE_LAMP || m == Material.NOTE_BLOCK || m == Material.BELL;
|
||||
|| isLamp(m) || plugin.isGrate(m)
|
||||
|| m == Material.NOTE_BLOCK || m == Material.BELL
|
||||
|| m == Material.DISPENSER || m == Material.DROPPER
|
||||
|| isCreakingHeart(m);
|
||||
}
|
||||
|
||||
private Material getMaterialAt(String locString) {
|
||||
|
||||
@@ -15,7 +15,7 @@ public class ButtonTabCompleter implements TabCompleter {
|
||||
|
||||
private final List<String> commands = Arrays.asList(
|
||||
"info", "reload", "note", "list", "rename", "schedule",
|
||||
"trust", "untrust", "public", "private"
|
||||
"trust", "untrust", "public", "private", "undo", "secret"
|
||||
);
|
||||
|
||||
private final List<String> instruments = Arrays.asList(
|
||||
@@ -44,6 +44,26 @@ public class ButtonTabCompleter implements TabCompleter {
|
||||
case "rename":
|
||||
completions.add("<Name>");
|
||||
break;
|
||||
case "secret":
|
||||
StringUtil.copyPartialMatches(args[1], Arrays.asList("select", "info", "add", "remove", "clear", "delay", "animation"), completions);
|
||||
break;
|
||||
}
|
||||
} else if (args.length == 3 && args[0].equalsIgnoreCase("secret") && args[1].equalsIgnoreCase("delay")) {
|
||||
completions.add("3");
|
||||
completions.add("5");
|
||||
completions.add("10");
|
||||
completions.add("30");
|
||||
completions.add("60");
|
||||
} else if (args.length == 3 && args[0].equalsIgnoreCase("secret") && args[1].equalsIgnoreCase("animation")) {
|
||||
completions.add("instant");
|
||||
completions.add("wave");
|
||||
completions.add("reverse");
|
||||
completions.add("center");
|
||||
}
|
||||
|
||||
if (args.length == 2 && args[0].equalsIgnoreCase("secret")) {
|
||||
if (completions.isEmpty()) {
|
||||
StringUtil.copyPartialMatches(args[1], Arrays.asList("select", "info", "add", "remove", "clear", "delay", "animation"), completions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,12 +68,15 @@ public class ConfigManager {
|
||||
def(config, "max-gates", 20);
|
||||
def(config, "max-trapdoors", 20);
|
||||
def(config, "max-bells", 5);
|
||||
def(config, "max-dispensers", 20);
|
||||
def(config, "max-droppers", 20);
|
||||
def(config, "default-note", "PIANO");
|
||||
def(config, "double-note-enabled", true);
|
||||
def(config, "double-note-delay-ms", 1000);
|
||||
def(config, "motion-detection-radius", 5.0);
|
||||
def(config, "motion-close-delay-ms", 5000);
|
||||
def(config, "motion-trigger-cooldown-ms", 2000);
|
||||
def(config, "timed-container-interval-ticks", 40);
|
||||
|
||||
// Optionales MySQL-Backend
|
||||
def(config, "mysql.enabled", false);
|
||||
@@ -122,9 +125,20 @@ public class ConfigManager {
|
||||
def(lang, "lampen-eingeschaltet", "§aLampen wurden eingeschaltet.");
|
||||
def(lang, "lampen-ausgeschaltet", "§cLampen wurden ausgeschaltet.");
|
||||
def(lang, "max-lampen-erreicht", "§cMaximale Anzahl an Lampen erreicht.");
|
||||
// Creaking Heart
|
||||
def(lang, "creaking-heart-aktiviert", "§aKnarrherz wurde aktiviert.");
|
||||
def(lang, "creaking-heart-deaktiviert", "§cKnarrherz wurde deaktiviert.");
|
||||
// Gitter
|
||||
def(lang, "gitter-geoeffnet", "§aGitter wurden geöffnet.");
|
||||
def(lang, "gitter-geschlossen", "§cGitter wurden geschlossen.");
|
||||
// Glocken
|
||||
def(lang, "glocke-gelaeutet", "§aGlocke wurde geläutet.");
|
||||
def(lang, "max-glocken-erreicht", "§cMaximale Anzahl an Glocken erreicht.");
|
||||
// Spender / Werfer
|
||||
def(lang, "spender-ausgeloest", "§aSpender wurden ausgelöst.");
|
||||
def(lang, "werfer-ausgeloest", "§aWerfer wurden ausgelöst.");
|
||||
def(lang, "max-spender-erreicht", "§cMaximale Anzahl an Spendern erreicht.");
|
||||
def(lang, "max-werfer-erreicht", "§cMaximale Anzahl an Werfern erreicht.");
|
||||
// Notenblöcke
|
||||
def(lang, "notenblock-ausgeloest", "§aNotenblock-Klingel wurde ausgelöst.");
|
||||
def(lang, "instrument-gesetzt", "§aDein Instrument wurde auf %s gesetzt.");
|
||||
@@ -179,6 +193,8 @@ public class ConfigManager {
|
||||
public int getMaxGates() { return config.getInt("max-gates", 20); }
|
||||
public int getMaxTrapdoors() { return config.getInt("max-trapdoors", 20); }
|
||||
public int getMaxBells() { return config.getInt("max-bells", 5); }
|
||||
public int getMaxDispensers() { return config.getInt("max-dispensers", 20); }
|
||||
public int getMaxDroppers() { return config.getInt("max-droppers", 20); }
|
||||
|
||||
public String getMessage(String key) {
|
||||
return lang.getString(key, "§cNachricht fehlt: " + key);
|
||||
|
||||
@@ -96,24 +96,29 @@ public class DataManager {
|
||||
}
|
||||
// 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
|
||||
// Alle zugehörigen Daten (Name, Status, Trust, Zeitplan, Verbindungen, Secret) 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);
|
||||
|
||||
// Secret-Wall-Daten ebenfalls entfernen
|
||||
data.set("secret-walls." + buttonId, null);
|
||||
|
||||
// Sicherheitshalber bei ALLEN Spielern den Button-Eintrag löschen
|
||||
if (data.getConfigurationSection("players") != null) {
|
||||
for (String uuid : data.getConfigurationSection("players").getKeys(false)) {
|
||||
data.set("players." + uuid + ".buttons." + buttonId, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
removeMotionSensorSettings(location);
|
||||
@@ -238,6 +243,34 @@ public class DataManager {
|
||||
return data.getLong("schedules." + buttonId + ".close-time", -1);
|
||||
}
|
||||
|
||||
public void setScheduleShotDelayTicks(String buttonId, int ticks) {
|
||||
if (mySQLStorage != null) {
|
||||
mySQLStorage.setScheduleShotDelayTicks(buttonId, ticks);
|
||||
return;
|
||||
}
|
||||
data.set("schedules." + buttonId + ".shot-delay-ticks", ticks);
|
||||
saveData();
|
||||
}
|
||||
|
||||
public int getScheduleShotDelayTicks(String buttonId) {
|
||||
if (mySQLStorage != null) return mySQLStorage.getScheduleShotDelayTicks(buttonId);
|
||||
return data.getInt("schedules." + buttonId + ".shot-delay-ticks", -1);
|
||||
}
|
||||
|
||||
public void setScheduleTriggerMode(String buttonId, String mode) {
|
||||
if (mySQLStorage != null) {
|
||||
mySQLStorage.setScheduleTriggerMode(buttonId, mode);
|
||||
return;
|
||||
}
|
||||
data.set("schedules." + buttonId + ".trigger-mode", mode);
|
||||
saveData();
|
||||
}
|
||||
|
||||
public String getScheduleTriggerMode(String buttonId) {
|
||||
if (mySQLStorage != null) return mySQLStorage.getScheduleTriggerMode(buttonId);
|
||||
return data.getString("schedules." + buttonId + ".trigger-mode");
|
||||
}
|
||||
|
||||
/** Entfernt den kompletten Zeitplan für einen Controller. */
|
||||
public void clearSchedule(String buttonId) {
|
||||
if (mySQLStorage != null) {
|
||||
@@ -349,6 +382,61 @@ public class DataManager {
|
||||
saveData();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Secret-Wall (Geheimwand)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public void setSecretBlocks(String buttonId, List<String> blocks) {
|
||||
if (mySQLStorage != null) {
|
||||
mySQLStorage.setSecretBlocks(buttonId, blocks);
|
||||
return;
|
||||
}
|
||||
data.set("secret-walls." + buttonId + ".blocks", blocks);
|
||||
saveData();
|
||||
}
|
||||
|
||||
public List<String> getSecretBlocks(String buttonId) {
|
||||
if (mySQLStorage != null) return mySQLStorage.getSecretBlocks(buttonId);
|
||||
return data.getStringList("secret-walls." + buttonId + ".blocks");
|
||||
}
|
||||
|
||||
public void setSecretRestoreDelayMs(String buttonId, long delayMs) {
|
||||
if (mySQLStorage != null) {
|
||||
mySQLStorage.setSecretRestoreDelayMs(buttonId, delayMs);
|
||||
return;
|
||||
}
|
||||
data.set("secret-walls." + buttonId + ".delay-ms", delayMs);
|
||||
saveData();
|
||||
}
|
||||
|
||||
public long getSecretRestoreDelayMs(String buttonId) {
|
||||
if (mySQLStorage != null) return mySQLStorage.getSecretRestoreDelayMs(buttonId);
|
||||
return data.getLong("secret-walls." + buttonId + ".delay-ms", 5000L);
|
||||
}
|
||||
|
||||
public void setSecretAnimation(String buttonId, String animation) {
|
||||
if (mySQLStorage != null) {
|
||||
mySQLStorage.setSecretAnimation(buttonId, animation);
|
||||
return;
|
||||
}
|
||||
data.set("secret-walls." + buttonId + ".animation", animation);
|
||||
saveData();
|
||||
}
|
||||
|
||||
public String getSecretAnimation(String buttonId) {
|
||||
if (mySQLStorage != null) return mySQLStorage.getSecretAnimation(buttonId);
|
||||
return data.getString("secret-walls." + buttonId + ".animation", "wave");
|
||||
}
|
||||
|
||||
public void clearSecret(String buttonId) {
|
||||
if (mySQLStorage != null) {
|
||||
mySQLStorage.clearSecret(buttonId);
|
||||
return;
|
||||
}
|
||||
data.set("secret-walls." + buttonId, null);
|
||||
saveData();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Speichern – asynchron
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@@ -2,13 +2,22 @@ package viper;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
// Import aus dem korrekten verschobenen Package:
|
||||
import org.bstats.bukkit.Metrics;
|
||||
|
||||
|
||||
|
||||
public class MetricsHandler {
|
||||
|
||||
private static final int BSTATS_PLUGIN_ID = 26862;
|
||||
|
||||
public static void startMetrics(JavaPlugin plugin) {
|
||||
new Metrics(plugin, BSTATS_PLUGIN_ID);
|
||||
try {
|
||||
Class<?> metricsClass = Class.forName("org.bstats.bukkit.Metrics");
|
||||
metricsClass.getConstructor(JavaPlugin.class, int.class)
|
||||
.newInstance(plugin, BSTATS_PLUGIN_ID);
|
||||
} catch (ClassNotFoundException e) {
|
||||
plugin.getLogger().info("bStats nicht gefunden – Telemetrie deaktiviert.");
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("bStats konnte nicht initialisiert werden: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ public class MySQLStorage {
|
||||
plugin.getLogger().info("MySQL aktiviert.");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("MySQL konnte nicht initialisiert werden, verwende data.yml: " + e.getMessage());
|
||||
plugin.getLogger().warning("MySQL Verbindung fehlgeschlagen - verwende data.yml für Datenspeicherung.");
|
||||
plugin.getLogger().fine("Fehlerdetails: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +94,9 @@ public class MySQLStorage {
|
||||
st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_schedules ("
|
||||
+ "button_id VARCHAR(64) PRIMARY KEY,"
|
||||
+ "open_time BIGINT,"
|
||||
+ "close_time BIGINT"
|
||||
+ "close_time BIGINT,"
|
||||
+ "shot_delay_ticks INT,"
|
||||
+ "trigger_mode VARCHAR(16)"
|
||||
+ ")");
|
||||
|
||||
st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_trust ("
|
||||
@@ -117,6 +120,27 @@ public class MySQLStorage {
|
||||
+ "radius DOUBLE,"
|
||||
+ "delay_ms BIGINT"
|
||||
+ ")");
|
||||
|
||||
st.executeUpdate("CREATE TABLE IF NOT EXISTS bc_secret_walls ("
|
||||
+ "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_secret_settings ("
|
||||
+ "button_id VARCHAR(64) PRIMARY KEY,"
|
||||
+ "delay_ms BIGINT NOT NULL,"
|
||||
+ "animation VARCHAR(16) NOT NULL DEFAULT 'wave'"
|
||||
+ ")");
|
||||
|
||||
st.executeUpdate("ALTER TABLE bc_schedules "
|
||||
+ "ADD COLUMN IF NOT EXISTS shot_delay_ticks INT");
|
||||
|
||||
st.executeUpdate("ALTER TABLE bc_schedules "
|
||||
+ "ADD COLUMN IF NOT EXISTS trigger_mode VARCHAR(16)");
|
||||
|
||||
st.executeUpdate("ALTER TABLE bc_secret_settings "
|
||||
+ "ADD COLUMN IF NOT EXISTS animation VARCHAR(16) NOT NULL DEFAULT 'wave'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +219,9 @@ public class MySQLStorage {
|
||||
"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 = ?"
|
||||
"DELETE FROM bc_button_connections WHERE button_id = ?",
|
||||
"DELETE FROM bc_secret_walls WHERE button_id = ?",
|
||||
"DELETE FROM bc_secret_settings WHERE button_id = ?"
|
||||
};
|
||||
for (String q : queries) {
|
||||
try (PreparedStatement ps = getConnection().prepareStatement(q)) {
|
||||
@@ -295,12 +321,11 @@ public class MySQLStorage {
|
||||
}
|
||||
|
||||
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))"
|
||||
String q = "INSERT INTO bc_schedules (button_id, open_time, close_time, shot_delay_ticks, trigger_mode) VALUES (?, ?, -1, -1, 'simultaneous')"
|
||||
+ " 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());
|
||||
@@ -321,12 +346,11 @@ public class MySQLStorage {
|
||||
}
|
||||
|
||||
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), ?)"
|
||||
String q = "INSERT INTO bc_schedules (button_id, open_time, close_time, shot_delay_ticks, trigger_mode) VALUES (?, -1, ?, -1, 'simultaneous')"
|
||||
+ " 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.setLong(2, ticks);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL setScheduleCloseTime Fehler: " + e.getMessage());
|
||||
@@ -346,6 +370,58 @@ public class MySQLStorage {
|
||||
}
|
||||
}
|
||||
|
||||
public void setScheduleShotDelayTicks(String buttonId, int ticks) {
|
||||
String q = "INSERT INTO bc_schedules (button_id, open_time, close_time, shot_delay_ticks, trigger_mode) VALUES (?, -1, -1, ?, 'simultaneous')"
|
||||
+ " ON DUPLICATE KEY UPDATE shot_delay_ticks = VALUES(shot_delay_ticks)";
|
||||
try (PreparedStatement ps = getConnection().prepareStatement(q)) {
|
||||
ps.setString(1, buttonId);
|
||||
ps.setInt(2, ticks);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL setScheduleShotDelayTicks Fehler: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public int getScheduleShotDelayTicks(String buttonId) {
|
||||
String q = "SELECT shot_delay_ticks FROM bc_schedules WHERE button_id = ? LIMIT 1";
|
||||
try (PreparedStatement ps = getConnection().prepareStatement(q)) {
|
||||
ps.setString(1, buttonId);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (!rs.next()) return -1;
|
||||
int delay = rs.getInt(1);
|
||||
return rs.wasNull() ? -1 : delay;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL getScheduleShotDelayTicks Fehler: " + e.getMessage());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void setScheduleTriggerMode(String buttonId, String mode) {
|
||||
String q = "INSERT INTO bc_schedules (button_id, open_time, close_time, shot_delay_ticks, trigger_mode) VALUES (?, -1, -1, -1, ?)"
|
||||
+ " ON DUPLICATE KEY UPDATE trigger_mode = VALUES(trigger_mode)";
|
||||
try (PreparedStatement ps = getConnection().prepareStatement(q)) {
|
||||
ps.setString(1, buttonId);
|
||||
ps.setString(2, mode);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL setScheduleTriggerMode Fehler: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public String getScheduleTriggerMode(String buttonId) {
|
||||
String q = "SELECT trigger_mode 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.getString(1) : null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL getScheduleTriggerMode Fehler: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearSchedule(String buttonId) {
|
||||
String q = "DELETE FROM bc_schedules WHERE button_id = ?";
|
||||
try (PreparedStatement ps = getConnection().prepareStatement(q)) {
|
||||
@@ -490,6 +566,104 @@ public class MySQLStorage {
|
||||
}
|
||||
}
|
||||
|
||||
public void setSecretBlocks(String buttonId, List<String> blocks) {
|
||||
String del = "DELETE FROM bc_secret_walls WHERE button_id = ?";
|
||||
String ins = "INSERT INTO bc_secret_walls (button_id, block_location) VALUES (?, ?)";
|
||||
try (PreparedStatement psDel = getConnection().prepareStatement(del);
|
||||
PreparedStatement psIns = getConnection().prepareStatement(ins)) {
|
||||
psDel.setString(1, buttonId);
|
||||
psDel.executeUpdate();
|
||||
|
||||
for (String block : blocks) {
|
||||
psIns.setString(1, buttonId);
|
||||
psIns.setString(2, block);
|
||||
psIns.addBatch();
|
||||
}
|
||||
psIns.executeBatch();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL setSecretBlocks Fehler: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getSecretBlocks(String buttonId) {
|
||||
List<String> result = new ArrayList<>();
|
||||
String q = "SELECT block_location FROM bc_secret_walls 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 getSecretBlocks Fehler: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setSecretRestoreDelayMs(String buttonId, long delayMs) {
|
||||
String q = "INSERT INTO bc_secret_settings (button_id, delay_ms) VALUES (?, ?)"
|
||||
+ " ON DUPLICATE KEY UPDATE delay_ms = VALUES(delay_ms)";
|
||||
try (PreparedStatement ps = getConnection().prepareStatement(q)) {
|
||||
ps.setString(1, buttonId);
|
||||
ps.setLong(2, delayMs);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL setSecretRestoreDelayMs Fehler: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public long getSecretRestoreDelayMs(String buttonId) {
|
||||
String q = "SELECT delay_ms FROM bc_secret_settings 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) : 5000L;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL getSecretRestoreDelayMs Fehler: " + e.getMessage());
|
||||
return 5000L;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSecretAnimation(String buttonId, String animation) {
|
||||
String q = "INSERT INTO bc_secret_settings (button_id, delay_ms, animation) VALUES (?, COALESCE((SELECT delay_ms FROM bc_secret_settings WHERE button_id = ?), 5000), ?)"
|
||||
+ " ON DUPLICATE KEY UPDATE animation = VALUES(animation)";
|
||||
try (PreparedStatement ps = getConnection().prepareStatement(q)) {
|
||||
ps.setString(1, buttonId);
|
||||
ps.setString(2, buttonId);
|
||||
ps.setString(3, animation);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL setSecretAnimation Fehler: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public String getSecretAnimation(String buttonId) {
|
||||
String q = "SELECT animation FROM bc_secret_settings 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) : "wave";
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL getSecretAnimation Fehler: " + e.getMessage());
|
||||
return "wave";
|
||||
}
|
||||
}
|
||||
|
||||
public void clearSecret(String buttonId) {
|
||||
String q1 = "DELETE FROM bc_secret_walls WHERE button_id = ?";
|
||||
String q2 = "DELETE FROM bc_secret_settings WHERE button_id = ?";
|
||||
try (PreparedStatement ps1 = getConnection().prepareStatement(q1);
|
||||
PreparedStatement ps2 = getConnection().prepareStatement(q2)) {
|
||||
ps1.setString(1, buttonId);
|
||||
ps1.executeUpdate();
|
||||
ps2.setString(1, buttonId);
|
||||
ps2.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("MySQL clearSecret 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)) {
|
||||
|
||||
@@ -16,11 +16,14 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* GUI zur Konfiguration der zeitgesteuerten Automatisierung eines Controllers.
|
||||
*
|
||||
* Layout (9×3 = 27 Slots):
|
||||
* Slot 4 – Abschuss-Verzögerung Werfer/Spender (REPEATER) ← Links/Rechts: ±1 Tick | Shift: ±5
|
||||
* Slot 6 – Schuss-Modus (COMPARATOR) ← Klick: gleichzeitig / nacheinander
|
||||
* Slot 10 – Öffnungszeit (LIME_DYE / Sonne) ← Links/Rechts: ±1h | Shift: ±15min
|
||||
* Slot 13 – Aktivierung an/aus (LEVER)
|
||||
* Slot 16 – Schließzeit (RED_DYE / Mond) ← Links/Rechts: ±1h | Shift: ±15min
|
||||
@@ -39,6 +42,8 @@ public class ScheduleGUI implements Listener {
|
||||
// Aktuelle Werte während die GUI offen ist
|
||||
private long openTime;
|
||||
private long closeTime;
|
||||
private int shotDelayTicks;
|
||||
private String triggerMode;
|
||||
private boolean enabled;
|
||||
|
||||
public ScheduleGUI(ButtonControl plugin, Player player, String buttonId) {
|
||||
@@ -51,8 +56,16 @@ public class ScheduleGUI implements Listener {
|
||||
// Gespeicherte Werte laden (oder Standardwerte)
|
||||
long savedOpen = dataManager.getScheduleOpenTime(buttonId);
|
||||
long savedClose = dataManager.getScheduleCloseTime(buttonId);
|
||||
int savedShotDelay = dataManager.getScheduleShotDelayTicks(buttonId);
|
||||
String savedTriggerMode = dataManager.getScheduleTriggerMode(buttonId);
|
||||
this.openTime = savedOpen >= 0 ? savedOpen : plugin.timeToTicks(7, 0); // 07:00
|
||||
this.closeTime = savedClose >= 0 ? savedClose : plugin.timeToTicks(19, 0); // 19:00
|
||||
this.shotDelayTicks = savedShotDelay >= 0
|
||||
? savedShotDelay
|
||||
: Math.max(1, plugin.getConfigManager().getConfig().getInt("timed-container-shot-delay-ticks", 2));
|
||||
this.triggerMode = normalizeTriggerMode(savedTriggerMode != null
|
||||
? savedTriggerMode
|
||||
: plugin.getConfigManager().getConfig().getString("timed-container-trigger-mode", "simultaneous"));
|
||||
this.enabled = savedOpen >= 0;
|
||||
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
@@ -72,6 +85,12 @@ public class ScheduleGUI implements Listener {
|
||||
ItemStack filler = makeItem(Material.GRAY_STAINED_GLASS_PANE, ChatColor.RESET + "");
|
||||
for (int i = 0; i < 27; i++) inv.setItem(i, filler);
|
||||
|
||||
// Slot 4 – Abschuss-Verzögerung
|
||||
inv.setItem(4, makeDelayItem());
|
||||
|
||||
// Slot 6 – Modus
|
||||
inv.setItem(6, makeModeItem());
|
||||
|
||||
// Slot 10 – Öffnungszeit
|
||||
inv.setItem(10, makeTimeItem(
|
||||
Material.LIME_DYE,
|
||||
@@ -106,6 +125,65 @@ public class ScheduleGUI implements Listener {
|
||||
"§7Speichert den aktuellen Zeitplan."));
|
||||
}
|
||||
|
||||
private ItemStack makeDelayItem() {
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§e§l" + shotDelayTicks + " Ticks §7(" + formatShotDelaySeconds() + "s§7)");
|
||||
if (isSequentialMode()) {
|
||||
lore.add("§7Aktuell: §f" + shotDelayTicks + " Ticks zwischen einzelnen Geräten");
|
||||
} else if (shotDelayTicks <= 1) {
|
||||
lore.add("§7Aktuell: §falle verbundenen Werfer schießen jeden Tick");
|
||||
} else {
|
||||
lore.add("§7Aktuell: §f" + shotDelayTicks + " Ticks zwischen gemeinsamen Schüssen");
|
||||
}
|
||||
lore.add("");
|
||||
lore.add("§7Linksklick: §f+1 Tick");
|
||||
lore.add("§7Rechtsklick: §f−1 Tick");
|
||||
lore.add("§7Shift+Links: §f+5 Ticks");
|
||||
lore.add("§7Shift+Rechts: §f−5 Ticks");
|
||||
lore.add("§8(1 Tick = schnellstmöglich)");
|
||||
|
||||
ItemStack item = new ItemStack(Material.REPEATER);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName("§b§lAbschuss-Verzögerung");
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack makeModeItem() {
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add(isSequentialMode()
|
||||
? "§e§lNacheinander"
|
||||
: "§e§lGleichzeitig");
|
||||
lore.add("");
|
||||
lore.add("§7Klick: §fModus wechseln");
|
||||
lore.add("§8Gleichzeitig = alle Werfer zusammen");
|
||||
lore.add("§8Nacheinander = Geräte rotieren der Reihe nach");
|
||||
|
||||
ItemStack item = new ItemStack(Material.COMPARATOR);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName("§d§lSchuss-Modus");
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private String formatShotDelaySeconds() {
|
||||
return String.format(Locale.US, "%.2f", shotDelayTicks / 20.0);
|
||||
}
|
||||
|
||||
private boolean isSequentialMode() {
|
||||
return "sequential".equals(triggerMode);
|
||||
}
|
||||
|
||||
private String normalizeTriggerMode(String mode) {
|
||||
return "sequential".equalsIgnoreCase(mode) ? "sequential" : "simultaneous";
|
||||
}
|
||||
|
||||
private ItemStack makeTimeItem(Material mat, String name, long ticks, String... loreLines) {
|
||||
String timeStr = plugin.ticksToTime(ticks);
|
||||
List<String> lore = new ArrayList<>();
|
||||
@@ -153,7 +231,20 @@ public class ScheduleGUI implements Listener {
|
||||
// Schrittgröße: Shift = 15 Min (250 Ticks), sonst 1 Std (1000 Ticks)
|
||||
long step = event.isShiftClick() ? 250L : 1000L;
|
||||
|
||||
if (slot == 10) {
|
||||
if (slot == 4) {
|
||||
int delayStep = event.isShiftClick() ? 5 : 1;
|
||||
if (event.isLeftClick()) shotDelayTicks += delayStep;
|
||||
if (event.isRightClick()) shotDelayTicks -= delayStep;
|
||||
if (shotDelayTicks < 1) shotDelayTicks = 1;
|
||||
if (shotDelayTicks > 200) shotDelayTicks = 200;
|
||||
inv.setItem(4, makeDelayItem());
|
||||
|
||||
} else if (slot == 6) {
|
||||
triggerMode = isSequentialMode() ? "simultaneous" : "sequential";
|
||||
inv.setItem(4, makeDelayItem());
|
||||
inv.setItem(6, makeModeItem());
|
||||
|
||||
} else if (slot == 10) {
|
||||
// Öffnungszeit anpassen
|
||||
if (event.isLeftClick()) openTime = (openTime + step + 24000) % 24000;
|
||||
if (event.isRightClick()) openTime = (openTime - step + 24000) % 24000;
|
||||
@@ -203,10 +294,18 @@ public class ScheduleGUI implements Listener {
|
||||
if (enabled) {
|
||||
dataManager.setScheduleOpenTime(buttonId, openTime);
|
||||
dataManager.setScheduleCloseTime(buttonId, closeTime);
|
||||
dataManager.setScheduleShotDelayTicks(buttonId, shotDelayTicks);
|
||||
dataManager.setScheduleTriggerMode(buttonId, triggerMode);
|
||||
player.sendMessage("§a[BC] §7Zeitplan gespeichert: §aÖffnet §7um §e"
|
||||
+ plugin.ticksToTime(openTime)
|
||||
+ " §7· §cSchließt §7um §e"
|
||||
+ plugin.ticksToTime(closeTime));
|
||||
+ plugin.ticksToTime(closeTime)
|
||||
+ " §7· §bDelay §e"
|
||||
+ shotDelayTicks
|
||||
+ "§7 Ticks §8("
|
||||
+ formatShotDelaySeconds()
|
||||
+ "s§8) §7· §dModus §e"
|
||||
+ (isSequentialMode() ? "nacheinander" : "gleichzeitig"));
|
||||
} else {
|
||||
dataManager.clearSchedule(buttonId);
|
||||
player.sendMessage("§7[BC] Zeitplan deaktiviert.");
|
||||
|
||||
@@ -7,6 +7,8 @@ max-noteblocks: 10
|
||||
max-gates: 20
|
||||
max-trapdoors: 20
|
||||
max-bells: 5
|
||||
max-dispensers: 20
|
||||
max-droppers: 20
|
||||
|
||||
# ── Notenblöcke ─────────────────────────────────────────────────────────────
|
||||
default-note: "PIANO"
|
||||
@@ -19,6 +21,14 @@ motion-detection-radius: 5.0
|
||||
motion-close-delay-ms: 5000
|
||||
# Cooldown: wie lange nach dem Schließen der Sensor nicht erneut auslöst
|
||||
motion-trigger-cooldown-ms: 2000
|
||||
# Legacy-Fallback für ältere Zeitpläne ohne eigenen GUI-Delay-Wert
|
||||
# (20 Ticks = 1 Sekunde)
|
||||
timed-container-interval-ticks: 40
|
||||
# Standardwert für die Zeit zwischen einzelnen Abschüssen im Zeitplan
|
||||
# Wird verwendet, bis ein Controller in der GUI einen eigenen Wert speichert
|
||||
timed-container-shot-delay-ticks: 2
|
||||
# Standardmodus für Zeitplan-Werfer/Spender: simultaneous oder sequential
|
||||
timed-container-trigger-mode: simultaneous
|
||||
|
||||
# ── Optionales MySQL-Backend ────────────────────────────────────────────────
|
||||
mysql:
|
||||
|
||||
@@ -25,8 +25,16 @@ max-fallturen-erreicht: "§cMaximale Anzahl an Falltüren erreicht."
|
||||
lampen-eingeschaltet: "§aLampen wurden eingeschaltet."
|
||||
lampen-ausgeschaltet: "§cLampen wurden ausgeschaltet."
|
||||
max-lampen-erreicht: "§cMaximale Anzahl an Lampen erreicht."
|
||||
creaking-heart-aktiviert: "§aKnarrherz wurde aktiviert."
|
||||
creaking-heart-deaktiviert: "§cKnarrherz wurde deaktiviert."
|
||||
gitter-geoeffnet: "§aGitter wurden geöffnet."
|
||||
gitter-geschlossen: "§cGitter wurden geschlossen."
|
||||
glocke-gelaeutet: "§aGlocke wurde geläutet."
|
||||
max-glocken-erreicht: "§cMaximale Anzahl an Glocken erreicht."
|
||||
spender-ausgeloest: "§aSpender wurden ausgelöst."
|
||||
werfer-ausgeloest: "§aWerfer wurden ausgelöst."
|
||||
max-spender-erreicht: "§cMaximale Anzahl an Spendern erreicht."
|
||||
max-werfer-erreicht: "§cMaximale Anzahl an Werfern erreicht."
|
||||
|
||||
# ── Notenblöcke ──────────────────────────────────────────────────────────────
|
||||
notenblock-ausgeloest: "§aNotenblock-Klingel wurde ausgelöst."
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: ButtonControl
|
||||
version: 1.7
|
||||
version: 1.9
|
||||
main: viper.ButtonControl
|
||||
api-version: 1.21
|
||||
author: M_Viper
|
||||
@@ -11,7 +11,7 @@ description: >
|
||||
commands:
|
||||
bc:
|
||||
description: Hauptbefehl für ButtonControl
|
||||
usage: /bc <info|reload|note|list|rename|schedule|trust|untrust|public|private>
|
||||
usage: "/bc <info|reload|note|list|rename|schedule|trust|untrust|public|private|undo|secret> (Secret: select|info|add|remove|clear|delay|animation)"
|
||||
aliases: [buttoncontrol]
|
||||
|
||||
permissions:
|
||||
|
||||
Reference in New Issue
Block a user