Upload folder via GUI - src
This commit is contained in:
@@ -50,6 +50,7 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
@@ -78,6 +79,7 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
private String apiKey = "";
|
private String apiKey = "";
|
||||||
private boolean flyRedeemDisabled = false;
|
private boolean flyRedeemDisabled = false;
|
||||||
private String incomeReceiver = "";
|
private String incomeReceiver = "";
|
||||||
|
private int flyAboMaxDailySec = 21600; // 6 Stunden Standardlimit
|
||||||
|
|
||||||
// Sell-Feature
|
// Sell-Feature
|
||||||
private double sellPriceOffset = 0.0; // z.B. -10.0 = -10 % vom WordPress-Ankaufspreis
|
private double sellPriceOffset = 0.0; // z.B. -10.0 = -10 % vom WordPress-Ankaufspreis
|
||||||
@@ -93,6 +95,7 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
private FlyManager flyManager;
|
private FlyManager flyManager;
|
||||||
private FlyCodeManager flyCodeManager;
|
private FlyCodeManager flyCodeManager;
|
||||||
private RankManager rankManager;
|
private RankManager rankManager;
|
||||||
|
private FlyAboManager flyAboManager;
|
||||||
|
|
||||||
private static final String GUI_FLYCODES = ChatColor.GOLD + "✈ Deine Fly-Gutscheine";
|
private static final String GUI_FLYCODES = ChatColor.GOLD + "✈ Deine Fly-Gutscheine";
|
||||||
private final Map<UUID, Integer> flyCodesPage = new HashMap<>();
|
private final Map<UUID, Integer> flyCodesPage = new HashMap<>();
|
||||||
@@ -135,6 +138,7 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
incomeReceiver = getConfig().getString("income-receiver", "");
|
incomeReceiver = getConfig().getString("income-receiver", "");
|
||||||
sellEnabled = getConfig().getBoolean("sell.enabled", true);
|
sellEnabled = getConfig().getBoolean("sell.enabled", true);
|
||||||
sellPriceOffset = getConfig().getDouble("sell.price-offset", 0.0);
|
sellPriceOffset = getConfig().getDouble("sell.price-offset", 0.0);
|
||||||
|
flyAboMaxDailySec = getConfig().getInt("fly-abo.max-daily-hours", 6) * 3600;
|
||||||
|
|
||||||
if (apiKey.isEmpty()) {
|
if (apiKey.isEmpty()) {
|
||||||
getLogger().warning("⚠️ Kein api-key in config.yml gesetzt!");
|
getLogger().warning("⚠️ Kein api-key in config.yml gesetzt!");
|
||||||
@@ -150,6 +154,8 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
flyManager = new FlyManager(this);
|
flyManager = new FlyManager(this);
|
||||||
rankManager = new RankManager(this, flyCodeManager);
|
rankManager = new RankManager(this, flyCodeManager);
|
||||||
rankManager.startExpiryChecker();
|
rankManager.startExpiryChecker();
|
||||||
|
flyAboManager = new FlyAboManager(this, flyCodeManager);
|
||||||
|
flyAboManager.startDailyResetChecker();
|
||||||
|
|
||||||
int intervalSeconds = getConfig().getInt("check-interval", 10);
|
int intervalSeconds = getConfig().getInt("check-interval", 10);
|
||||||
long pollInterval = intervalSeconds * 20L;
|
long pollInterval = intervalSeconds * 20L;
|
||||||
@@ -162,6 +168,9 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
getCommand("flygive").setExecutor(new FlyGiveCommand());
|
getCommand("flygive").setExecutor(new FlyGiveCommand());
|
||||||
getCommand("flypause").setExecutor(new FlyPauseCommand());
|
getCommand("flypause").setExecutor(new FlyPauseCommand());
|
||||||
getCommand("rankinfo").setExecutor(new RankInfoCommand());
|
getCommand("rankinfo").setExecutor(new RankInfoCommand());
|
||||||
|
getCommand("flyabo").setExecutor(new FlyAboCommand());
|
||||||
|
getCommand("flyabocancel").setExecutor(new FlyAboCancelCommand());
|
||||||
|
getCommand("flyabogive").setExecutor(new FlyAboGiveCommand());
|
||||||
getCommand("sell").setExecutor(new SellCommand());
|
getCommand("sell").setExecutor(new SellCommand());
|
||||||
getCommand("wpis").setExecutor(new ReloadCommand());
|
getCommand("wpis").setExecutor(new ReloadCommand());
|
||||||
|
|
||||||
@@ -344,6 +353,11 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
@Override public void run() { rankManager.checkExpiredRanksForPlayer(p); }
|
@Override public void run() { rankManager.checkExpiredRanksForPlayer(p); }
|
||||||
}.runTaskAsynchronously(this);
|
}.runTaskAsynchronously(this);
|
||||||
|
|
||||||
|
// Fly-Abo prüfen und ggf. Fly für heute bereitstellen
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() { flyAboManager.onPlayerJoin(p); }
|
||||||
|
}.runTaskAsynchronously(this);
|
||||||
|
|
||||||
// Ausstehende Fly-Codes anzeigen
|
// Ausstehende Fly-Codes anzeigen
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
@@ -906,6 +920,16 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
anyCode = true;
|
anyCode = true;
|
||||||
|
|
||||||
|
} else if ("fly_abo".equals(type)) {
|
||||||
|
// Fly-Abo: Tage-basiertes Abonnement mit tägl. Stunden-Limit
|
||||||
|
int days = cmdObj.has("days")
|
||||||
|
? cmdObj.get("days").getAsInt() : 30;
|
||||||
|
String label = cmdObj.has("label")
|
||||||
|
? cmdObj.get("label").getAsString()
|
||||||
|
: "Fly-Abo " + days + " Tage";
|
||||||
|
flyAboManager.grantAbo(player, days, label);
|
||||||
|
anyCode = true;
|
||||||
|
|
||||||
} else if ("generic".equals(type) && cmdObj.has("cmd")) {
|
} else if ("generic".equals(type) && cmdObj.has("cmd")) {
|
||||||
String cmd = cmdObj.get("cmd").getAsString()
|
String cmd = cmdObj.get("cmd").getAsString()
|
||||||
.replace("{player}", player.getName());
|
.replace("{player}", player.getName());
|
||||||
@@ -1283,6 +1307,134 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// FLY-ABO COMMANDS
|
||||||
|
// ===========================================================
|
||||||
|
|
||||||
|
/** /flyabo – Abo-Status anzeigen */
|
||||||
|
private class FlyAboCommand implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command,
|
||||||
|
String label, String[] args) {
|
||||||
|
if (!(sender instanceof Player)) { sender.sendMessage("Nur für Spieler."); return true; }
|
||||||
|
Player p = (Player) sender;
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
FlyAboManager.AboEntry abo = flyAboManager.getActiveAbo(p.getName());
|
||||||
|
Bukkit.getScheduler().runTask(IngameShopSpigot.this, () -> {
|
||||||
|
p.sendMessage(ChatColor.GOLD + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||||
|
p.sendMessage(ChatColor.YELLOW + "✈ Dein Fly-Abo:");
|
||||||
|
p.sendMessage(ChatColor.GOLD + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||||
|
if (abo == null) {
|
||||||
|
p.sendMessage(ChatColor.GRAY + " Kein aktives Fly-Abo.");
|
||||||
|
p.sendMessage(ChatColor.GRAY + " Im Shop erhältlich: " + ChatColor.AQUA + "viper-network.de");
|
||||||
|
} else {
|
||||||
|
p.sendMessage(ChatColor.AQUA + " Status: " + ChatColor.GREEN + "✔ Aktiv");
|
||||||
|
p.sendMessage(ChatColor.AQUA + " Paket: " + ChatColor.WHITE + abo.label);
|
||||||
|
p.sendMessage(ChatColor.AQUA + " Läuft ab: " + ChatColor.YELLOW + abo.expiresAt);
|
||||||
|
if (abo.cancelled)
|
||||||
|
p.sendMessage(ChatColor.RED + " ⚠ Kündigung vorgemerkt – läuft zum o.g. Datum aus");
|
||||||
|
int usedSec = flyAboManager.getUsedTodaySec(p.getName());
|
||||||
|
int maxSec = flyAboMaxDailySec;
|
||||||
|
int remSec = Math.max(0, maxSec - usedSec);
|
||||||
|
p.sendMessage(ChatColor.AQUA + " Heute geflogen: "
|
||||||
|
+ ChatColor.WHITE + flyManager.formatTime(usedSec)
|
||||||
|
+ ChatColor.GRAY + " / "
|
||||||
|
+ ChatColor.WHITE + flyManager.formatTime(maxSec));
|
||||||
|
p.sendMessage(ChatColor.AQUA + " Heute noch verfügbar: "
|
||||||
|
+ (remSec > 0 ? ChatColor.GREEN : ChatColor.RED)
|
||||||
|
+ flyManager.formatTime(remSec));
|
||||||
|
}
|
||||||
|
p.sendMessage(ChatColor.GOLD + "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(IngameShopSpigot.this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** /flyabocancel – Abo zum Ablauf kündigen */
|
||||||
|
private class FlyAboCancelCommand implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command,
|
||||||
|
String label, String[] args) {
|
||||||
|
if (!(sender instanceof Player)) { sender.sendMessage("Nur für Spieler."); return true; }
|
||||||
|
Player p = (Player) sender;
|
||||||
|
// Bestätigung erforderlich
|
||||||
|
if (args.length == 0 || !args[0].equalsIgnoreCase("confirm")) {
|
||||||
|
p.sendMessage(ChatColor.YELLOW + "⚠ Möchtest du dein Fly-Abo wirklich kündigen?");
|
||||||
|
p.sendMessage(ChatColor.GRAY + " Das Abo läuft bis zum Ablaufdatum weiter.");
|
||||||
|
p.sendMessage(ChatColor.WHITE + " Bestätigen: " + ChatColor.RED + "/flyabocancel confirm");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
boolean ok = flyAboManager.cancelAbo(p.getName());
|
||||||
|
Bukkit.getScheduler().runTask(IngameShopSpigot.this, () -> {
|
||||||
|
if (ok) {
|
||||||
|
p.sendMessage(ChatColor.YELLOW + "✈ Dein Fly-Abo wurde zur Kündigung vorgemerkt.");
|
||||||
|
p.sendMessage(ChatColor.GRAY + " Es bleibt bis zum Ablaufdatum aktiv.");
|
||||||
|
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1.0F, 0.8F);
|
||||||
|
} else {
|
||||||
|
p.sendMessage(ChatColor.RED + "✗ Kein aktives Fly-Abo gefunden.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(IngameShopSpigot.this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** /flyabogive <Spieler> <Tage> [Label] – Admin gibt Abo manuell */
|
||||||
|
private class FlyAboGiveCommand implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command,
|
||||||
|
String label, String[] args) {
|
||||||
|
if (!sender.hasPermission("ingameshop.flyabogive")) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "✗ Keine Berechtigung.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + "Verwendung: /flyabogive <Spieler> <Tage> [Label]");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String targetName = args[0];
|
||||||
|
int days;
|
||||||
|
try { days = Integer.parseInt(args[1]); }
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "✗ Tage muss eine Zahl sein.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String aboLabel = args.length >= 3
|
||||||
|
? String.join(" ", Arrays.copyOfRange(args, 2, args.length))
|
||||||
|
: "Fly-Abo " + days + " Tage";
|
||||||
|
Player target = Bukkit.getPlayer(targetName);
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
flyAboManager.grantAboByName(targetName, days, aboLabel);
|
||||||
|
Bukkit.getScheduler().runTask(IngameShopSpigot.this, () -> {
|
||||||
|
sender.sendMessage(ChatColor.GREEN + "✔ Fly-Abo (" + days + " Tage) an "
|
||||||
|
+ ChatColor.YELLOW + targetName + ChatColor.GREEN + " vergeben.");
|
||||||
|
if (target != null && target.isOnline()) {
|
||||||
|
target.sendMessage("");
|
||||||
|
target.sendMessage(ChatColor.GOLD + "✈ ════════════════════════════");
|
||||||
|
target.sendMessage(ChatColor.YELLOW + " Fly-Abo aktiviert!");
|
||||||
|
target.sendMessage(ChatColor.GRAY + " Paket: " + ChatColor.WHITE + aboLabel);
|
||||||
|
target.sendMessage(ChatColor.GRAY + " Tägl. Limit: " + ChatColor.WHITE
|
||||||
|
+ flyManager.formatTime(flyAboMaxDailySec));
|
||||||
|
target.sendMessage(ChatColor.GRAY + " Status: /flyabo");
|
||||||
|
target.sendMessage(ChatColor.GOLD + " ════════════════════════════");
|
||||||
|
target.sendMessage("");
|
||||||
|
target.playSound(target.getLocation(),
|
||||||
|
Sound.ENTITY_PLAYER_LEVELUP, 1.0F, 1.2F);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(IngameShopSpigot.this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
// HTTP HILFSMETHODEN
|
// HTTP HILFSMETHODEN
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
@@ -1667,6 +1819,133 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
return seconds + "s";
|
return seconds + "s";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wie grantFly, aber schreibt jede Sekunde die Nutzung in die Abo-Usage-Tabelle.
|
||||||
|
* Stoppt automatisch wenn dailyLimitSec gesamt verbraucht ist.
|
||||||
|
*/
|
||||||
|
void grantFlyWithAboTracking(Player player, int seconds, String aboLabel,
|
||||||
|
String playerName, int dailyLimitSec) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
int existing = flySeconds.getOrDefault(uuid, 0);
|
||||||
|
int total = existing + seconds;
|
||||||
|
flySeconds.put(uuid, total);
|
||||||
|
flyStartSecs.put(uuid, total);
|
||||||
|
paused.remove(uuid);
|
||||||
|
|
||||||
|
player.setAllowFlight(true);
|
||||||
|
player.setFlying(true);
|
||||||
|
player.sendMessage(ChatColor.AQUA + "✈ Fly-Abo aktiv! Heute noch: "
|
||||||
|
+ ChatColor.YELLOW + formatTime(seconds));
|
||||||
|
|
||||||
|
BossBar bar = flyBossBars.get(uuid);
|
||||||
|
if (bar == null) {
|
||||||
|
bar = Bukkit.createBossBar(
|
||||||
|
buildAboBarTitle(seconds, dailyLimitSec, false),
|
||||||
|
BarColor.GREEN, BarStyle.SEGMENTED_10);
|
||||||
|
bar.addPlayer(player);
|
||||||
|
flyBossBars.put(uuid, bar);
|
||||||
|
} else {
|
||||||
|
bar.setTitle(buildAboBarTitle(seconds, dailyLimitSec, false));
|
||||||
|
bar.setProgress(1.0);
|
||||||
|
bar.setColor(BarColor.GREEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flyTasks.containsKey(uuid)) flyTasks.get(uuid).cancel();
|
||||||
|
|
||||||
|
final BossBar finalBar = bar;
|
||||||
|
// Jede 30s Usage in DB schreiben
|
||||||
|
final int[] dbBuffer = {0};
|
||||||
|
|
||||||
|
BukkitTask t = new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
Player p = Bukkit.getPlayer(uuid);
|
||||||
|
if (p == null || !p.isOnline()) {
|
||||||
|
// DB-Puffer flushen
|
||||||
|
if (dbBuffer[0] > 0) {
|
||||||
|
final int toFlush = dbBuffer[0];
|
||||||
|
dbBuffer[0] = 0;
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
flyCodeManager.addUsedTodaySec(playerName, toFlush);
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(plugin);
|
||||||
|
}
|
||||||
|
removeBossBar(uuid);
|
||||||
|
flyTasks.remove(uuid);
|
||||||
|
paused.remove(uuid);
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (paused.contains(uuid)) {
|
||||||
|
int rem = flySeconds.getOrDefault(uuid, 0);
|
||||||
|
finalBar.setTitle(buildAboBarTitle(rem, dailyLimitSec, true));
|
||||||
|
finalBar.setColor(BarColor.WHITE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int remaining = flySeconds.getOrDefault(uuid, 0) - 1;
|
||||||
|
dbBuffer[0]++;
|
||||||
|
// Alle 30s in DB flushen
|
||||||
|
if (dbBuffer[0] >= 30) {
|
||||||
|
final int toFlush = dbBuffer[0];
|
||||||
|
dbBuffer[0] = 0;
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
flyCodeManager.addUsedTodaySec(playerName, toFlush);
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(plugin);
|
||||||
|
}
|
||||||
|
if (remaining <= 0) {
|
||||||
|
// Letzten Rest flushen
|
||||||
|
if (dbBuffer[0] > 0) {
|
||||||
|
final int toFlush = dbBuffer[0];
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
flyCodeManager.addUsedTodaySec(playerName, toFlush);
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(plugin);
|
||||||
|
}
|
||||||
|
flySeconds.remove(uuid);
|
||||||
|
flyTasks.remove(uuid);
|
||||||
|
flyStartSecs.remove(uuid);
|
||||||
|
removeBossBar(uuid);
|
||||||
|
p.setFlying(false);
|
||||||
|
p.setAllowFlight(false);
|
||||||
|
p.sendMessage(ChatColor.RED + "✈ Fly-Abo Tageslimit erreicht!");
|
||||||
|
p.sendMessage(ChatColor.GRAY + " Morgen stehen dir wieder "
|
||||||
|
+ ChatColor.WHITE + formatTime(dailyLimitSec)
|
||||||
|
+ ChatColor.GRAY + " zur Verfügung.");
|
||||||
|
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1.0F, 0.5F);
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flySeconds.put(uuid, remaining);
|
||||||
|
int start = flyStartSecs.getOrDefault(uuid, remaining);
|
||||||
|
double progress = Math.max(0.0, Math.min(1.0, (double) remaining / start));
|
||||||
|
finalBar.setProgress(progress);
|
||||||
|
finalBar.setTitle(buildAboBarTitle(remaining, dailyLimitSec, false));
|
||||||
|
if (remaining <= 300) finalBar.setColor(BarColor.RED);
|
||||||
|
else if (remaining <= 1800) finalBar.setColor(BarColor.YELLOW);
|
||||||
|
else finalBar.setColor(BarColor.GREEN);
|
||||||
|
if (remaining == 3600 || remaining == 1800
|
||||||
|
|| remaining == 600 || remaining == 300
|
||||||
|
|| remaining == 60 || remaining == 30 || remaining == 10) {
|
||||||
|
p.sendMessage(ChatColor.YELLOW + "✈ Fly-Abo noch " + formatTime(remaining) + " heute!");
|
||||||
|
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 0.5F, 1.2F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimer(plugin, 20L, 20L);
|
||||||
|
flyTasks.put(uuid, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildAboBarTitle(int seconds, int dailyMax, boolean isPaused) {
|
||||||
|
if (isPaused)
|
||||||
|
return ChatColor.GRAY + "⏸ Fly-Abo pausiert: "
|
||||||
|
+ ChatColor.WHITE + formatTime(seconds);
|
||||||
|
return ChatColor.GREEN + "✈ Fly-Abo: "
|
||||||
|
+ ChatColor.YELLOW + formatTime(seconds)
|
||||||
|
+ ChatColor.GRAY + " / " + formatTime(dailyMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
@@ -1909,6 +2188,132 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Fly-Abo CRUD ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
void createAboTable() {
|
||||||
|
String sqlAbo =
|
||||||
|
"CREATE TABLE IF NOT EXISTS wis_fly_abos ("
|
||||||
|
+ " id INT AUTO_INCREMENT PRIMARY KEY,"
|
||||||
|
+ " player_name VARCHAR(64) NOT NULL COLLATE utf8mb4_general_ci,"
|
||||||
|
+ " label VARCHAR(128) NOT NULL,"
|
||||||
|
+ " cancelled TINYINT(1) NOT NULL DEFAULT 0,"
|
||||||
|
+ " expires_at DATETIME NOT NULL,"
|
||||||
|
+ " granted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,"
|
||||||
|
+ " UNIQUE KEY uq_player (player_name)"
|
||||||
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||||
|
String sqlUsage =
|
||||||
|
"CREATE TABLE IF NOT EXISTS wis_fly_abo_usage ("
|
||||||
|
+ " id INT AUTO_INCREMENT PRIMARY KEY,"
|
||||||
|
+ " player_name VARCHAR(64) NOT NULL COLLATE utf8mb4_general_ci,"
|
||||||
|
+ " usage_date DATE NOT NULL,"
|
||||||
|
+ " used_sec INT NOT NULL DEFAULT 0,"
|
||||||
|
+ " UNIQUE KEY uq_player_date (player_name, usage_date)"
|
||||||
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||||
|
try (Statement stmt = connection.createStatement()) {
|
||||||
|
stmt.execute(sqlAbo);
|
||||||
|
stmt.execute(sqlUsage);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.SEVERE, "Abo-Tabellen-Erstellung fehlgeschlagen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveAbo(String playerName, int days, String label) {
|
||||||
|
String sql =
|
||||||
|
"INSERT INTO wis_fly_abos (player_name, label, cancelled, expires_at)"
|
||||||
|
+ " VALUES (?, ?, 0, DATE_ADD(NOW(), INTERVAL ? DAY))"
|
||||||
|
+ " ON DUPLICATE KEY UPDATE"
|
||||||
|
+ " label = ?, cancelled = 0,"
|
||||||
|
+ " expires_at = IF(expires_at > NOW(),"
|
||||||
|
+ " DATE_ADD(expires_at, INTERVAL ? DAY),"
|
||||||
|
+ " DATE_ADD(NOW(), INTERVAL ? DAY)),"
|
||||||
|
+ " granted_at = NOW()";
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
|
ps.setString(1, playerName);
|
||||||
|
ps.setString(2, label);
|
||||||
|
ps.setInt(3, days);
|
||||||
|
ps.setString(4, label);
|
||||||
|
ps.setInt(5, days);
|
||||||
|
ps.setInt(6, days);
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "saveAbo SQL Fehler", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean cancelAbo(String playerName) {
|
||||||
|
String sql =
|
||||||
|
"UPDATE wis_fly_abos SET cancelled = 1"
|
||||||
|
+ " WHERE player_name = ? AND expires_at > NOW() AND cancelled = 0";
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
|
ps.setString(1, playerName);
|
||||||
|
return ps.executeUpdate() == 1;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "cancelAbo SQL Fehler", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlyAboManager.AboEntry getActiveAbo(String playerName) {
|
||||||
|
String sql =
|
||||||
|
"SELECT label, cancelled,"
|
||||||
|
+ " DATE_FORMAT(expires_at, '%d.%m.%Y') AS expires_fmt"
|
||||||
|
+ " FROM wis_fly_abos"
|
||||||
|
+ " WHERE player_name = ? AND expires_at > NOW()";
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
|
ps.setString(1, playerName);
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (rs.next())
|
||||||
|
return new FlyAboManager.AboEntry(
|
||||||
|
rs.getString("label"),
|
||||||
|
rs.getString("expires_fmt"),
|
||||||
|
rs.getInt("cancelled") == 1);
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "getActiveAbo SQL Fehler", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanupExpiredAbos(String playerName) {
|
||||||
|
String sql = "DELETE FROM wis_fly_abos WHERE player_name = ? AND expires_at <= NOW()";
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
|
ps.setString(1, playerName);
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "cleanupExpiredAbos SQL Fehler", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getUsedTodaySec(String playerName) {
|
||||||
|
String sql =
|
||||||
|
"SELECT used_sec FROM wis_fly_abo_usage"
|
||||||
|
+ " WHERE player_name = ? AND usage_date = CURDATE()";
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
|
ps.setString(1, playerName);
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (rs.next()) return rs.getInt("used_sec");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "getUsedTodaySec SQL Fehler", e);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addUsedTodaySec(String playerName, int seconds) {
|
||||||
|
String sql =
|
||||||
|
"INSERT INTO wis_fly_abo_usage (player_name, usage_date, used_sec)"
|
||||||
|
+ " VALUES (?, CURDATE(), ?)"
|
||||||
|
+ " ON DUPLICATE KEY UPDATE used_sec = used_sec + ?";
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(sql)) {
|
||||||
|
ps.setString(1, playerName);
|
||||||
|
ps.setInt(2, seconds);
|
||||||
|
ps.setInt(3, seconds);
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.WARNING, "addUsedTodaySec SQL Fehler", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Fly-Code CRUD ────────────────────────────────────────────────
|
// ── Fly-Code CRUD ────────────────────────────────────────────────
|
||||||
|
|
||||||
String generateCode(String playerName, int durationSec, String label) {
|
String generateCode(String playerName, int durationSec, String label) {
|
||||||
@@ -2537,6 +2942,136 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// FLY ABO MANAGER
|
||||||
|
// ===========================================================
|
||||||
|
|
||||||
|
private class FlyAboManager {
|
||||||
|
|
||||||
|
private final IngameShopSpigot plugin;
|
||||||
|
private final FlyCodeManager db;
|
||||||
|
|
||||||
|
FlyAboManager(IngameShopSpigot plugin, FlyCodeManager db) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.db = db;
|
||||||
|
db.createAboTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Abo vergeben (über Order) ──────────────────────────────────
|
||||||
|
|
||||||
|
void grantAbo(Player player, int days, String label) {
|
||||||
|
grantAboByName(player.getName(), days, label);
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
player.sendMessage("");
|
||||||
|
player.sendMessage(ChatColor.GOLD + "✈ ════════════════════════════");
|
||||||
|
player.sendMessage(ChatColor.YELLOW + " Fly-Abo aktiviert!");
|
||||||
|
player.sendMessage(ChatColor.GRAY + " Paket: " + ChatColor.WHITE + label);
|
||||||
|
player.sendMessage(ChatColor.GRAY + " Laufzeit: " + ChatColor.WHITE + days + " Tag(e)");
|
||||||
|
player.sendMessage(ChatColor.GRAY + " Tägl. Limit: " + ChatColor.WHITE
|
||||||
|
+ flyManager.formatTime(flyAboMaxDailySec));
|
||||||
|
player.sendMessage(ChatColor.GRAY + " Status: " + ChatColor.WHITE + "/flyabo");
|
||||||
|
player.sendMessage(ChatColor.GOLD + " ════════════════════════════");
|
||||||
|
player.sendMessage("");
|
||||||
|
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1.0F, 1.2F);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void grantAboByName(String playerName, int days, String label) {
|
||||||
|
db.saveAbo(playerName, days, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Abo kündigen ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
boolean cancelAbo(String playerName) {
|
||||||
|
return db.cancelAbo(playerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Abo-Status lesen ──────────────────────────────────────────
|
||||||
|
|
||||||
|
AboEntry getActiveAbo(String playerName) {
|
||||||
|
return db.getActiveAbo(playerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getUsedTodaySec(String playerName) {
|
||||||
|
return db.getUsedTodaySec(playerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Beim Join: Abo prüfen ─────────────────────────────────────
|
||||||
|
|
||||||
|
void onPlayerJoin(Player player) {
|
||||||
|
AboEntry abo = db.getActiveAbo(player.getName());
|
||||||
|
if (abo == null) return;
|
||||||
|
|
||||||
|
// Abgelaufenes Abo bereinigen
|
||||||
|
db.cleanupExpiredAbos(player.getName());
|
||||||
|
abo = db.getActiveAbo(player.getName());
|
||||||
|
if (abo == null) {
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () ->
|
||||||
|
player.sendMessage(ChatColor.RED + "✈ Dein Fly-Abo ist abgelaufen."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usedToday = db.getUsedTodaySec(player.getName());
|
||||||
|
int remaining = Math.max(0, flyAboMaxDailySec - usedToday);
|
||||||
|
if (remaining <= 0) {
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
player.sendMessage(ChatColor.YELLOW + "✈ Fly-Abo aktiv – Tageslimit heute bereits aufgebraucht.");
|
||||||
|
player.sendMessage(ChatColor.GRAY + " Morgen stehen dir wieder "
|
||||||
|
+ ChatColor.WHITE + flyManager.formatTime(flyAboMaxDailySec)
|
||||||
|
+ ChatColor.GRAY + " zur Verfügung.");
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fly mit verbleibender Tageszeit gewähren, aber in Abo-Modus
|
||||||
|
final int grantSec = remaining;
|
||||||
|
final String aboLabel = abo.label;
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||||
|
flyManager.grantFlyWithAboTracking(player, grantSec, aboLabel,
|
||||||
|
player.getName(), flyAboMaxDailySec);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Täglicher Reset-Check ─────────────────────────────────────
|
||||||
|
|
||||||
|
void startDailyResetChecker() {
|
||||||
|
// Alle 5 Minuten prüfen ob Tagesdatum gewechselt hat → online Spieler neu versorgen
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
AboEntry abo = db.getActiveAbo(p.getName());
|
||||||
|
if (abo == null) return;
|
||||||
|
// Wenn Tageslimit noch nicht erreicht und kein Fly aktiv → erneut gewähren
|
||||||
|
int usedToday = db.getUsedTodaySec(p.getName());
|
||||||
|
int remaining = Math.max(0, flyAboMaxDailySec - usedToday);
|
||||||
|
if (remaining > 0
|
||||||
|
&& flyManager.getRemainingSeconds(p.getUniqueId()) <= 0) {
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () ->
|
||||||
|
flyManager.grantFlyWithAboTracking(p, remaining, abo.label,
|
||||||
|
p.getName(), flyAboMaxDailySec));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskTimer(plugin, 20L * 300, 20L * 300); // alle 5 Minuten
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Data class ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
static class AboEntry {
|
||||||
|
final String label, expiresAt;
|
||||||
|
final boolean cancelled;
|
||||||
|
AboEntry(String label, String expiresAt, boolean cancelled) {
|
||||||
|
this.label = label;
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
// SELL MANAGER
|
// SELL MANAGER
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
|
|||||||
@@ -52,3 +52,10 @@ sell:
|
|||||||
# Hinweis: Den Basis-Ankaufspreis konfigurierst du im WP-Admin
|
# Hinweis: Den Basis-Ankaufspreis konfigurierst du im WP-Admin
|
||||||
# unter Items → <Item bearbeiten> → "Ankauf aktivieren"
|
# unter Items → <Item bearbeiten> → "Ankauf aktivieren"
|
||||||
price-offset: -10.0
|
price-offset: -10.0
|
||||||
|
# ──────────────────────────────────────────────
|
||||||
|
# Fly-Abo Einstellungen
|
||||||
|
# ──────────────────────────────────────────────
|
||||||
|
fly-abo:
|
||||||
|
# Maximale Fly-Zeit pro Tag in Stunden
|
||||||
|
# Standard: 6 (= 6 Stunden = 21.600 Sekunden)
|
||||||
|
max-daily-hours: 6
|
||||||
@@ -43,6 +43,18 @@ commands:
|
|||||||
description: IngameShop Admin-Befehle
|
description: IngameShop Admin-Befehle
|
||||||
usage: /wpis <reload>
|
usage: /wpis <reload>
|
||||||
permission: ingameshop.reload
|
permission: ingameshop.reload
|
||||||
|
flyabo:
|
||||||
|
description: Zeigt deinen Fly-Abo Status und Tageslimit an
|
||||||
|
usage: /flyabo
|
||||||
|
permission: ingameshop.flyabo
|
||||||
|
flyabocancel:
|
||||||
|
description: Kündigt dein Fly-Abo zum Ablaufdatum
|
||||||
|
usage: /flyabocancel [confirm]
|
||||||
|
permission: ingameshop.flyabocancel
|
||||||
|
flyabogive:
|
||||||
|
description: Gibt einem Spieler ein Fly-Abo (Admin)
|
||||||
|
usage: /flyabogive <Spieler> <Tage> [Label]
|
||||||
|
permission: ingameshop.flyabogive
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
ingameshop.orders:
|
ingameshop.orders:
|
||||||
@@ -72,3 +84,12 @@ permissions:
|
|||||||
ingameshop.reload:
|
ingameshop.reload:
|
||||||
description: Kann die IngameShop-Config live neu laden
|
description: Kann die IngameShop-Config live neu laden
|
||||||
default: op
|
default: op
|
||||||
|
ingameshop.flyabo:
|
||||||
|
description: Kann eigenen Fly-Abo-Status einsehen
|
||||||
|
default: true
|
||||||
|
ingameshop.flyabocancel:
|
||||||
|
description: Kann eigenes Fly-Abo kündigen
|
||||||
|
default: true
|
||||||
|
ingameshop.flyabogive:
|
||||||
|
description: Kann Spielern Fly-Abos manuell vergeben (Admin)
|
||||||
|
default: op
|
||||||
Reference in New Issue
Block a user