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: /