Upload folder via GUI - src

This commit is contained in:
Git Manager GUI
2026-04-28 21:46:16 +02:00
parent f571c9e8f8
commit 9f9d064139
3 changed files with 564 additions and 1 deletions

View File

@@ -50,6 +50,7 @@ import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.time.LocalDate;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
@@ -78,6 +79,7 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
private String apiKey = "";
private boolean flyRedeemDisabled = false;
private String incomeReceiver = "";
private int flyAboMaxDailySec = 21600; // 6 Stunden Standardlimit
// Sell-Feature
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 FlyCodeManager flyCodeManager;
private RankManager rankManager;
private FlyAboManager flyAboManager;
private static final String GUI_FLYCODES = ChatColor.GOLD + "✈ Deine Fly-Gutscheine";
private final Map<UUID, Integer> flyCodesPage = new HashMap<>();
@@ -135,6 +138,7 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
incomeReceiver = getConfig().getString("income-receiver", "");
sellEnabled = getConfig().getBoolean("sell.enabled", true);
sellPriceOffset = getConfig().getDouble("sell.price-offset", 0.0);
flyAboMaxDailySec = getConfig().getInt("fly-abo.max-daily-hours", 6) * 3600;
if (apiKey.isEmpty()) {
getLogger().warning("⚠️ Kein api-key in config.yml gesetzt!");
@@ -150,6 +154,8 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
flyManager = new FlyManager(this);
rankManager = new RankManager(this, flyCodeManager);
rankManager.startExpiryChecker();
flyAboManager = new FlyAboManager(this, flyCodeManager);
flyAboManager.startDailyResetChecker();
int intervalSeconds = getConfig().getInt("check-interval", 10);
long pollInterval = intervalSeconds * 20L;
@@ -162,6 +168,9 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
getCommand("flygive").setExecutor(new FlyGiveCommand());
getCommand("flypause").setExecutor(new FlyPauseCommand());
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("wpis").setExecutor(new ReloadCommand());
@@ -344,6 +353,11 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
@Override public void run() { rankManager.checkExpiredRanksForPlayer(p); }
}.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
new BukkitRunnable() {
@Override public void run() {
@@ -906,6 +920,16 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
}
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")) {
String cmd = cmdObj.get("cmd").getAsString()
.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
// ===========================================================
@@ -1667,6 +1819,133 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
}
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 ────────────────────────────────────────────────
String generateCode(String playerName, int durationSec, String label) {
@@ -2537,6 +2942,136 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
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
// ===========================================================

View File

@@ -51,4 +51,11 @@ sell:
# +5.0 → 5 % mehr als der WP-Ankaufspreis
# Hinweis: Den Basis-Ankaufspreis konfigurierst du im WP-Admin
# 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

View File

@@ -43,6 +43,18 @@ commands:
description: IngameShop Admin-Befehle
usage: /wpis <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:
ingameshop.orders:
@@ -71,4 +83,13 @@ permissions:
default: true
ingameshop.reload:
description: Kann die IngameShop-Config live neu laden
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