From d4680b80d6c0c3badf1090c470d181f762b619f7 Mon Sep 17 00:00:00 2001 From: deutschich Date: Tue, 21 Oct 2025 17:39:46 +0200 Subject: [PATCH] Inital Commit --- .gitignore | 113 +++++++++++++++ pom.xml | 68 +++++++++ .../serverCountdown/CountdownManager.java | 133 ++++++++++++++++++ .../serverCountdown/LanguageManager.java | 62 ++++++++ .../serverCountdown/PlayerListener.java | 25 ++++ .../serverCountdown/PrepCDCommand.java | 38 +++++ .../serverCountdown/ServerCountdown.java | 40 ++++++ .../serverCountdown/StartCDCommand.java | 54 +++++++ src/main/resources/de.yml | 3 + src/main/resources/en.yml | 3 + src/main/resources/plugin.yml | 18 +++ 11 files changed, 557 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/user404_/serverCountdown/CountdownManager.java create mode 100644 src/main/java/com/user404_/serverCountdown/LanguageManager.java create mode 100644 src/main/java/com/user404_/serverCountdown/PlayerListener.java create mode 100644 src/main/java/com/user404_/serverCountdown/PrepCDCommand.java create mode 100644 src/main/java/com/user404_/serverCountdown/ServerCountdown.java create mode 100644 src/main/java/com/user404_/serverCountdown/StartCDCommand.java create mode 100644 src/main/resources/de.yml create mode 100644 src/main/resources/en.yml create mode 100644 src/main/resources/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4788b4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +target/ + +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next + +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# Common working directory +run/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c8a227f --- /dev/null +++ b/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + com.user404_ + ServerCountdown + 1.0.0-dev + jar + + ServerCountdown + + + 21 + UTF-8 + + + + clean package + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.3 + + + package + + shade + + + + + + + + src/main/resources + true + + + + + + + papermc-repo + https://repo.papermc.io/repository/maven-public/ + + + + + + io.papermc.paper + paper-api + 1.21.10-R0.1-SNAPSHOT + provided + + + diff --git a/src/main/java/com/user404_/serverCountdown/CountdownManager.java b/src/main/java/com/user404_/serverCountdown/CountdownManager.java new file mode 100644 index 0000000..6930334 --- /dev/null +++ b/src/main/java/com/user404_/serverCountdown/CountdownManager.java @@ -0,0 +1,133 @@ +package com.user404_.serverCountdown; + +import org.bukkit.*; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.*; + +public class CountdownManager { + private boolean isPreparing = false; + private boolean isRunning = false; + private Location teleportLocation; + private Map previousLocations = new HashMap<>(); + private BukkitRunnable teleportTask; + private BukkitRunnable countdownTask; + + public void startPreparation(Location loc) { + isPreparing = true; + teleportLocation = loc; + + for (Player p : Bukkit.getOnlinePlayers()) { + applyEffects(p); + previousLocations.put(p.getUniqueId(), p.getLocation().clone()); + } + + teleportTask = new BukkitRunnable() { + @Override + public void run() { + if (!isPreparing && !isRunning) { + cancel(); + return; + } + for (Player p : Bukkit.getOnlinePlayers()) { + if (teleportLocation != null) { + p.teleport(teleportLocation); + } + } + } + }; + teleportTask.runTaskTimer(ServerCountdown.getInstance(), 0, 200); // 10 Sekunden = 200 Ticks + } + + public void startCountdown(int seconds) { + if (!isPreparing) { + return; + } + + isPreparing = false; + isRunning = true; + + if (teleportTask != null) { + teleportTask.cancel(); + } + + countdownTask = new BukkitRunnable() { + int timeLeft = seconds; + + @Override + public void run() { + if (timeLeft <= 0) { + endCountdown(); + cancel(); + return; + } + + // Send title to all players + for (Player p : Bukkit.getOnlinePlayers()) { + String message = LanguageManager.getMessage(p, "countdown-title"); + message = message.replace("{0}", String.valueOf(timeLeft)); + p.sendTitle(message, "", 0, 40, 10); + } + + timeLeft--; + } + }; + countdownTask.runTaskTimer(ServerCountdown.getInstance(), 0, 20); // 1 Sekunde = 20 Ticks + } + + private void endCountdown() { + isRunning = false; + for (Player p : Bukkit.getOnlinePlayers()) { + removeEffects(p); + Location original = previousLocations.get(p.getUniqueId()); + if (original != null) { + p.teleport(original); + } + } + previousLocations.clear(); + + // Remove effects from all players, even if they're offline + for (UUID playerId : previousLocations.keySet()) { + Player player = Bukkit.getPlayer(playerId); + if (player != null && player.isOnline()) { + removeEffects(player); + } + } + } + + public void applyEffects(Player p) { + p.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Integer.MAX_VALUE, 255, false, false, false)); + p.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, Integer.MAX_VALUE, 255, false, false, false)); + p.addPotionEffect(new PotionEffect(PotionEffectType.MINING_FATIGUE, Integer.MAX_VALUE, 255, false, false, false)); + } + + public void removeEffects(Player p) { + p.removePotionEffect(PotionEffectType.BLINDNESS); + p.removePotionEffect(PotionEffectType.SLOWNESS); + p.removePotionEffect(PotionEffectType.MINING_FATIGUE); + } + + public Location getTeleportLocation() { + return teleportLocation; + } + + public boolean isPreparing() { + return isPreparing; + } + + public boolean isRunning() { + return isRunning; + } + + public void cleanup() { + if (teleportTask != null) { + teleportTask.cancel(); + } + if (countdownTask != null) { + countdownTask.cancel(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/serverCountdown/LanguageManager.java b/src/main/java/com/user404_/serverCountdown/LanguageManager.java new file mode 100644 index 0000000..577d971 --- /dev/null +++ b/src/main/java/com/user404_/serverCountdown/LanguageManager.java @@ -0,0 +1,62 @@ +package com.user404_.serverCountdown; + +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +public class LanguageManager { + private static final String LANG_FOLDER = "texts"; + + public static void copyDefaultLanguages() { + File dataFolder = ServerCountdown.getInstance().getDataFolder(); + File langFolder = new File(dataFolder, LANG_FOLDER); + + if (!langFolder.exists()) { + langFolder.mkdirs(); + } + + String[] languages = {"en.yml", "de.yml"}; + for (String lang : languages) { + File file = new File(langFolder, lang); + if (!file.exists()) { + try (InputStream in = ServerCountdown.class.getClassLoader().getResourceAsStream(lang)) { + if (in != null) { + Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING); + ServerCountdown.getInstance().getLogger().info("Created language file: " + lang); + } else { + ServerCountdown.getInstance().getLogger().warning("Could not find " + lang + " in resources!"); + } + } catch (IOException e) { + ServerCountdown.getInstance().getLogger().severe("Failed to create language file: " + lang); + e.printStackTrace(); + } + } + } + } + + public static String getMessage(Player p, String key) { + String language = "en"; // Default to English + if (p.getLocale() != null && p.getLocale().toLowerCase().contains("de")) { + language = "de"; + } + + File file = new File(ServerCountdown.getInstance().getDataFolder(), LANG_FOLDER + "/" + language + ".yml"); + FileConfiguration config = YamlConfiguration.loadConfiguration(file); + + String message = config.getString(key); + if (message == null) { + // Fallback to English if message not found + File enFile = new File(ServerCountdown.getInstance().getDataFolder(), LANG_FOLDER + "/en.yml"); + FileConfiguration enConfig = YamlConfiguration.loadConfiguration(enFile); + message = enConfig.getString(key, "Message not found: " + key); + } + + return message; + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/serverCountdown/PlayerListener.java b/src/main/java/com/user404_/serverCountdown/PlayerListener.java new file mode 100644 index 0000000..4a6f8e7 --- /dev/null +++ b/src/main/java/com/user404_/serverCountdown/PlayerListener.java @@ -0,0 +1,25 @@ +package com.user404_.serverCountdown; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerListener implements Listener { + private final CountdownManager countdownManager; + + public PlayerListener(CountdownManager countdownManager) { + this.countdownManager = countdownManager; + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent e) { + Player p = e.getPlayer(); + if (countdownManager.isPreparing() || countdownManager.isRunning()) { + countdownManager.applyEffects(p); + if (countdownManager.isPreparing() && countdownManager.getTeleportLocation() != null) { + p.teleport(countdownManager.getTeleportLocation()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/serverCountdown/PrepCDCommand.java b/src/main/java/com/user404_/serverCountdown/PrepCDCommand.java new file mode 100644 index 0000000..cde5344 --- /dev/null +++ b/src/main/java/com/user404_/serverCountdown/PrepCDCommand.java @@ -0,0 +1,38 @@ +package com.user404_.serverCountdown; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class PrepCDCommand implements CommandExecutor { + private final CountdownManager countdownManager; + + public PrepCDCommand(CountdownManager countdownManager) { + this.countdownManager = countdownManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cOnly players can use this command!"); + return true; + } + + Player player = (Player) sender; + + if (!player.hasPermission("servercountdown.cd.prep")) { + player.sendMessage("§cYou don't have permission to use this command!"); + return true; + } + + if (countdownManager.isPreparing() || countdownManager.isRunning()) { + player.sendMessage("§cCountdown is already active!"); + return true; + } + + countdownManager.startPreparation(player.getLocation()); + player.sendMessage("§aCountdown preparation started!"); + return true; + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/serverCountdown/ServerCountdown.java b/src/main/java/com/user404_/serverCountdown/ServerCountdown.java new file mode 100644 index 0000000..a10a9e7 --- /dev/null +++ b/src/main/java/com/user404_/serverCountdown/ServerCountdown.java @@ -0,0 +1,40 @@ +package com.user404_.serverCountdown; + +import org.bukkit.plugin.java.JavaPlugin; + +public class ServerCountdown extends JavaPlugin { + + private static ServerCountdown instance; + private CountdownManager countdownManager; + + @Override + public void onEnable() { + instance = this; + countdownManager = new CountdownManager(); + + getCommand("prepcd").setExecutor(new PrepCDCommand(countdownManager)); + getCommand("startcd").setExecutor(new StartCDCommand(countdownManager)); + getServer().getPluginManager().registerEvents(new PlayerListener(countdownManager), this); + + // Create language files + LanguageManager.copyDefaultLanguages(); + + getLogger().info("ServerCountdown enabled successfully!"); + } + + @Override + public void onDisable() { + if (countdownManager != null) { + countdownManager.cleanup(); + } + getLogger().info("ServerCountdown disabled!"); + } + + public static ServerCountdown getInstance() { + return instance; + } + + public CountdownManager getCountdownManager() { + return countdownManager; + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/serverCountdown/StartCDCommand.java b/src/main/java/com/user404_/serverCountdown/StartCDCommand.java new file mode 100644 index 0000000..4253c71 --- /dev/null +++ b/src/main/java/com/user404_/serverCountdown/StartCDCommand.java @@ -0,0 +1,54 @@ +package com.user404_.serverCountdown; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class StartCDCommand implements CommandExecutor { + private final CountdownManager countdownManager; + + public StartCDCommand(CountdownManager countdownManager) { + this.countdownManager = countdownManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cOnly players can use this command!"); + return true; + } + + Player player = (Player) sender; + + if (!player.hasPermission("servercountdown.cd.start")) { + player.sendMessage("§cYou don't have permission to use this command!"); + return true; + } + + if (args.length != 1) { + player.sendMessage("§cUsage: /startcd "); + return false; + } + + if (!countdownManager.isPreparing()) { + player.sendMessage("§cYou must prepare the countdown first with /prepcd!"); + return true; + } + + try { + int time = Integer.parseInt(args[0]); + if (time < 1 || time > 100) { + player.sendMessage("§cTime must be between 1 and 100 seconds!"); + return false; + } + + countdownManager.startCountdown(time); + player.sendMessage("§aCountdown started for " + time + " seconds!"); + } catch (NumberFormatException e) { + player.sendMessage("§cPlease enter a valid number!"); + return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/main/resources/de.yml b/src/main/resources/de.yml new file mode 100644 index 0000000..56146ce --- /dev/null +++ b/src/main/resources/de.yml @@ -0,0 +1,3 @@ +preparation-started: "Countdown-Vorbereitung gestartet!" +countdown-started: "Countdown gestartet!" +countdown-title: "§c{0}" \ No newline at end of file diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml new file mode 100644 index 0000000..29aba39 --- /dev/null +++ b/src/main/resources/en.yml @@ -0,0 +1,3 @@ +preparation-started: "Countdown preparation started!" +countdown-started: "Countdown started!" +countdown-title: "§c{0}" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..d948407 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,18 @@ +name: ServerCountdown +version: 1.0.0-dev +website: https://github.com/deutschich/ServerCountdown/ +main: com.user404_.serverCountdown.ServerCountdown +api-version: 1.21 +commands: + prepcd: + description: Prepares countdown + permission: servercountdown.cd.prep + startcd: + description: Starts countdown + usage: /