From f72903c2a6fb7e86c8fa3a6dd40136def6e316bb Mon Sep 17 00:00:00 2001 From: M_Viper Date: Wed, 28 Jan 2026 17:34:09 +0100 Subject: [PATCH] Update from Git Manager GUI --- .../dev/viper/weathertime/DisplayMode.java | 32 ++ .../dev/viper/weathertime/MetricsManager.java | 4 +- .../java/dev/viper/weathertime/MoonPhase.java | 69 +++ .../dev/viper/weathertime/UpdateChecker.java | 48 +- .../dev/viper/weathertime/WeatherColors.java | 97 ++++ .../dev/viper/weathertime/WeatherFetcher.java | 64 ++- .../viper/weathertime/WeatherTimeData.java | 83 +++- .../weathertime/WeatherTimeSyncPlugin.java | 432 ++++++++++++------ .../dev/viper/weathertime/WindDirection.java | 83 ++++ src/main/resources/config.yml | 2 +- src/main/resources/plugin.yml | 2 +- 11 files changed, 742 insertions(+), 174 deletions(-) create mode 100644 src/main/java/dev/viper/weathertime/DisplayMode.java create mode 100644 src/main/java/dev/viper/weathertime/MoonPhase.java create mode 100644 src/main/java/dev/viper/weathertime/WeatherColors.java create mode 100644 src/main/java/dev/viper/weathertime/WindDirection.java diff --git a/src/main/java/dev/viper/weathertime/DisplayMode.java b/src/main/java/dev/viper/weathertime/DisplayMode.java new file mode 100644 index 0000000..a6608ae --- /dev/null +++ b/src/main/java/dev/viper/weathertime/DisplayMode.java @@ -0,0 +1,32 @@ +package dev.viper.weathertime; + +public enum DisplayMode { + COMPACT("Kompakt", 5), + STANDARD("Standard", 10), + DETAILED("Detailliert", 15); + + private final String displayName; + private final int lineCount; + + DisplayMode(String displayName, int lineCount) { + this.displayName = displayName; + this.lineCount = lineCount; + } + + public String getDisplayName() { + return displayName; + } + + public int getLineCount() { + return lineCount; + } + + public static DisplayMode fromString(String mode) { + for (DisplayMode dm : values()) { + if (dm.name().equalsIgnoreCase(mode)) { + return dm; + } + } + return STANDARD; + } +} diff --git a/src/main/java/dev/viper/weathertime/MetricsManager.java b/src/main/java/dev/viper/weathertime/MetricsManager.java index f959e3b..38c4cbb 100644 --- a/src/main/java/dev/viper/weathertime/MetricsManager.java +++ b/src/main/java/dev/viper/weathertime/MetricsManager.java @@ -8,7 +8,7 @@ public class MetricsManager { private final Metrics metrics; public MetricsManager(JavaPlugin plugin) { - int pluginId = 26865; // Deine Plugin-ID von bStats eintragen + int pluginId = 26865; // Deine Plugin-ID von bStats this.metrics = new Metrics(plugin, pluginId); // Optional: Eigene Charts hinzufügen @@ -18,4 +18,4 @@ public class MetricsManager { public Metrics getMetrics() { return metrics; } -} +} \ No newline at end of file diff --git a/src/main/java/dev/viper/weathertime/MoonPhase.java b/src/main/java/dev/viper/weathertime/MoonPhase.java new file mode 100644 index 0000000..4711a04 --- /dev/null +++ b/src/main/java/dev/viper/weathertime/MoonPhase.java @@ -0,0 +1,69 @@ +package dev.viper.weathertime; + +import org.bukkit.World; + +public class MoonPhase { + + /** + * Berechnet die aktuelle Mondphase basierend auf der Minecraft-Zeit + */ + public static String getPhase(World world) { + long fullTime = world.getFullTime(); + long daysPassed = fullTime / 24000L; + int phase = (int) (daysPassed % 8); + + switch (phase) { + case 0: return "🌑 Neumond"; + case 1: return "🌒 Zunehmende Sichel"; + case 2: return "🌓 Erstes Viertel"; + case 3: return "🌔 Zunehmender Mond"; + case 4: return "🌕 Vollmond"; + case 5: return "🌖 Abnehmender Mond"; + case 6: return "🌗 Letztes Viertel"; + case 7: return "🌘 Abnehmende Sichel"; + default: return "🌑 Neumond"; + } + } + + /** + * Gibt nur das Emoji der Mondphase zurück + */ + public static String getEmoji(World world) { + long fullTime = world.getFullTime(); + long daysPassed = fullTime / 24000L; + int phase = (int) (daysPassed % 8); + + switch (phase) { + case 0: return "🌑"; + case 1: return "🌒"; + case 2: return "🌓"; + case 3: return "🌔"; + case 4: return "🌕"; + case 5: return "🌖"; + case 6: return "🌗"; + case 7: return "🌘"; + default: return "🌑"; + } + } + + /** + * Gibt den Namen der Mondphase zurück (ohne Emoji) + */ + public static String getName(World world) { + long fullTime = world.getFullTime(); + long daysPassed = fullTime / 24000L; + int phase = (int) (daysPassed % 8); + + switch (phase) { + case 0: return "Neumond"; + case 1: return "Zunehmende Sichel"; + case 2: return "Erstes Viertel"; + case 3: return "Zunehmender Mond"; + case 4: return "Vollmond"; + case 5: return "Abnehmender Mond"; + case 6: return "Letztes Viertel"; + case 7: return "Abnehmende Sichel"; + default: return "Neumond"; + } + } +} diff --git a/src/main/java/dev/viper/weathertime/UpdateChecker.java b/src/main/java/dev/viper/weathertime/UpdateChecker.java index 8a6c7fe..ed3f914 100644 --- a/src/main/java/dev/viper/weathertime/UpdateChecker.java +++ b/src/main/java/dev/viper/weathertime/UpdateChecker.java @@ -2,6 +2,7 @@ package dev.viper.weathertime; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; +import org.json.JSONObject; import java.io.InputStream; import java.net.HttpURLConnection; @@ -9,8 +10,6 @@ import java.net.URL; import java.util.Scanner; import java.util.function.Consumer; -import org.json.JSONObject; - public class UpdateChecker { private final JavaPlugin plugin; private final int resourceId; @@ -21,16 +20,18 @@ public class UpdateChecker { } public void getLatestVersion(Consumer consumer) { - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - try { - HttpURLConnection connection = (HttpURLConnection) - new URL("https://api.spiget.org/v2/resources/" + resourceId + "/versions/latest").openConnection(); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + InputStream inputStream = null; + Scanner scanner = null; + try { + HttpURLConnection connection = (HttpURLConnection) + new URL("https://api.spiget.org/v2/resources/" + resourceId + "/versions/latest").openConnection(); - connection.setRequestMethod("GET"); - connection.addRequestProperty("User-Agent", "Mozilla/5.0"); + connection.setRequestMethod("GET"); + connection.addRequestProperty("User-Agent", "Mozilla/5.0"); - try (InputStream inputStream = connection.getInputStream(); - Scanner scanner = new Scanner(inputStream)) { + inputStream = connection.getInputStream(); + scanner = new Scanner(inputStream); String response = scanner.useDelimiter("\\A").next(); JSONObject json = new JSONObject(response); @@ -40,11 +41,24 @@ public class UpdateChecker { String cleanVersion = versionName.replaceAll("[^0-9.]", "").trim(); consumer.accept(cleanVersion.isEmpty() ? versionName : cleanVersion); + } catch (Exception e) { + plugin.getLogger().warning("Konnte keine Update-Info abrufen: " + e.getMessage()); + } finally { + if (scanner != null) { + try { + scanner.close(); + } catch (Exception e) { + // Ignore + } + } + if (inputStream != null) { + try { + inputStream.close(); + } catch (Exception e) { + // Ignore + } + } } - } catch (Exception e) { - plugin.getLogger().warning("Konnte keine Update-Info abrufen: " + e.getMessage()); - } - }); -} - -} + }); + } +} \ No newline at end of file diff --git a/src/main/java/dev/viper/weathertime/WeatherColors.java b/src/main/java/dev/viper/weathertime/WeatherColors.java new file mode 100644 index 0000000..d2fd878 --- /dev/null +++ b/src/main/java/dev/viper/weathertime/WeatherColors.java @@ -0,0 +1,97 @@ +package dev.viper.weathertime; + +import org.bukkit.ChatColor; + +public class WeatherColors { + + /** + * Gibt die Farbe basierend auf der Temperatur zurück + */ + public static ChatColor getTemperatureColor(double tempCelsius) { + if (tempCelsius < 0) { + return ChatColor.AQUA; // Unter 0°C - Hellblau (eisig) + } else if (tempCelsius < 10) { + return ChatColor.BLUE; // 0-10°C - Blau (kalt) + } else if (tempCelsius < 20) { + return ChatColor.GREEN; // 10-20°C - Grün (mild) + } else if (tempCelsius < 30) { + return ChatColor.YELLOW; // 20-30°C - Gelb (warm) + } else { + return ChatColor.RED; // Über 30°C - Rot (heiß) + } + } + + /** + * Gibt die Farbe basierend auf dem Wetter zurück + */ + public static ChatColor getWeatherColor(String weatherMain) { + switch (weatherMain.toLowerCase()) { + case "clear": + return ChatColor.GOLD; // Sonnig - Gold + case "clouds": + return ChatColor.GRAY; // Bewölkt - Grau + case "rain": + case "drizzle": + return ChatColor.BLUE; // Regen - Blau + case "thunderstorm": + return ChatColor.DARK_PURPLE; // Gewitter - Dunkelviolett + case "snow": + return ChatColor.WHITE; // Schnee - Weiß + case "mist": + case "fog": + case "haze": + return ChatColor.DARK_GRAY; // Nebel - Dunkelgrau + default: + return ChatColor.WHITE; + } + } + + /** + * Gibt die Farbe basierend auf der Luftfeuchtigkeit zurück + */ + public static ChatColor getHumidityColor(int humidity) { + if (humidity < 30) { + return ChatColor.RED; // Trocken + } else if (humidity < 60) { + return ChatColor.GREEN; // Angenehm + } else if (humidity < 80) { + return ChatColor.YELLOW; // Feucht + } else { + return ChatColor.AQUA; // Sehr feucht + } + } + + /** + * Gibt die Farbe basierend auf der Windgeschwindigkeit zurück (m/s) + */ + public static ChatColor getWindSpeedColor(double windSpeed) { + if (windSpeed < 5) { + return ChatColor.GREEN; // Leicht + } else if (windSpeed < 10) { + return ChatColor.YELLOW; // Mäßig + } else if (windSpeed < 15) { + return ChatColor.GOLD; // Frisch + } else if (windSpeed < 20) { + return ChatColor.RED; // Stark + } else { + return ChatColor.DARK_RED; // Sturm + } + } + + /** + * Gibt die Farbe basierend auf dem UV-Index zurück + */ + public static ChatColor getUVIndexColor(int uvIndex) { + if (uvIndex <= 2) { + return ChatColor.GREEN; // Niedrig + } else if (uvIndex <= 5) { + return ChatColor.YELLOW; // Mäßig + } else if (uvIndex <= 7) { + return ChatColor.GOLD; // Hoch + } else if (uvIndex <= 10) { + return ChatColor.RED; // Sehr hoch + } else { + return ChatColor.DARK_RED; // Extrem + } + } +} diff --git a/src/main/java/dev/viper/weathertime/WeatherFetcher.java b/src/main/java/dev/viper/weathertime/WeatherFetcher.java index d4bdf5d..a8efd94 100644 --- a/src/main/java/dev/viper/weathertime/WeatherFetcher.java +++ b/src/main/java/dev/viper/weathertime/WeatherFetcher.java @@ -44,16 +44,16 @@ public class WeatherFetcher { "https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=%s", location, apiKey, effectiveUnits); + BufferedReader in = null; try { JSONObject json; - try (BufferedReader in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString)))) { - StringBuilder content = new StringBuilder(); - String inputLine; - while ((inputLine = in.readLine()) != null) { - content.append(inputLine); - } - json = new JSONObject(content.toString()); + in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString))); + StringBuilder content = new StringBuilder(); + String inputLine; + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); } + json = new JSONObject(content.toString()); // Fehlerfall: Antwort-Code ungleich 200 if (json.has("cod") && json.getInt("cod") != 200) { @@ -79,11 +79,18 @@ public class WeatherFetcher { } // Temperatur immer in Celsius für WeatherTimeData speichern - double tempCelsius = effectiveUnits.equals("imperial") ? (temperature - 32) * 5 / 9 : temperature; + double tempCelsius = effectiveUnits.equals("imperial") ? (temperature - 32) * 5.0 / 9.0 : temperature; - // NEUE FELDER AUSLESEN + // FELDER AUSLESEN int humidity = json.getJSONObject("main").getInt("humidity"); double windSpeed = json.getJSONObject("wind").optDouble("speed", 0.0); + double windDeg = json.getJSONObject("wind").optDouble("deg", 0.0); + + int pressure = json.getJSONObject("main").optInt("pressure", 1013); + int clouds = json.getJSONObject("clouds").optInt("all", 0); + double feelsLikeTemp = json.getJSONObject("main").optDouble("feels_like", temperature); + double feelsLikeCelsius = effectiveUnits.equals("imperial") ? (feelsLikeTemp - 32) * 5.0 / 9.0 : feelsLikeTemp; + int visibility = json.optInt("visibility", 10000); // Standard 10km ZonedDateTime sunrise = Instant.ofEpochSecond(json.getJSONObject("sys").getLong("sunrise")) .atZone(ZoneId.of("UTC")) @@ -94,13 +101,22 @@ public class WeatherFetcher { .plusSeconds(timezoneShift); return new WeatherTimeData(dateTime, weatherMain, tempCelsius, - humidity, windSpeed, sunrise, sunset); + humidity, windSpeed, windDeg, sunrise, sunset, + pressure, clouds, feelsLikeCelsius, visibility); } catch (RuntimeException ru) { throw ru; } catch (Exception ex) { logger.warning("Fehler beim Abrufen von OpenWeatherMap: " + ex.getMessage()); throw new RuntimeException("Verbindung oder API-Fehler: " + ex.getMessage(), ex); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + // Ignore + } + } } } @@ -115,7 +131,9 @@ public class WeatherFetcher { "https://api.openweathermap.org/data/2.5/forecast?q=%s&appid=%s&units=%s", location, apiKey, effectiveUnits); - try (BufferedReader in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString)))) { + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString))); StringBuilder content = new StringBuilder(); String inputLine; while ((inputLine = in.readLine()) != null) { @@ -131,6 +149,14 @@ public class WeatherFetcher { } catch (Exception e) { logger.warning("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage()); throw new RuntimeException("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage(), e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + // Ignore + } + } } } @@ -145,12 +171,24 @@ public class WeatherFetcher { int status = connection.getResponseCode(); if (status != 200) { String err = "(keine Fehlerdetails)"; - try (BufferedReader errIn = new BufferedReader(new InputStreamReader(connection.getErrorStream()))) { + BufferedReader errIn = null; + try { + errIn = new BufferedReader(new InputStreamReader(connection.getErrorStream())); StringBuilder sb = new StringBuilder(); String l; while ((l = errIn.readLine()) != null) sb.append(l); err = sb.toString(); - } catch (Exception suppress) {} + } catch (Exception suppress) { + // Ignore + } finally { + if (errIn != null) { + try { + errIn.close(); + } catch (Exception e) { + // Ignore + } + } + } throw new RuntimeException("HTTP-Fehlercode: " + status + " – " + err); } return connection.getInputStream(); diff --git a/src/main/java/dev/viper/weathertime/WeatherTimeData.java b/src/main/java/dev/viper/weathertime/WeatherTimeData.java index 7ed4f9d..39cd9a4 100644 --- a/src/main/java/dev/viper/weathertime/WeatherTimeData.java +++ b/src/main/java/dev/viper/weathertime/WeatherTimeData.java @@ -4,7 +4,8 @@ import java.time.ZonedDateTime; /** * Zentrale Datenklasse für Wetter- und Zeitinformationen. - * Erweiterung: enthält jetzt auch Luftfeuchtigkeit, Windgeschwindigkeit und Sonnenauf/untergang. + * Erweiterung: enthält jetzt auch Luftfeuchtigkeit, Windgeschwindigkeit, Windrichtung, + * Sonnenauf/untergang, Luftdruck, Wolkendichte und UV-Index. */ public class WeatherTimeData { @@ -14,8 +15,14 @@ public class WeatherTimeData { private final int humidity; // Luftfeuchtigkeit in % private final double windSpeed; // Windgeschwindigkeit (m/s oder mph) + private final double windDeg; // Windrichtung in Grad (0-360) private final ZonedDateTime sunrise; // Sonnenaufgang private final ZonedDateTime sunset; // Sonnenuntergang + + private final int pressure; // Luftdruck in hPa + private final int clouds; // Wolkendichte in % + private final double feelsLike; // Gefühlte Temperatur in °C + private final int visibility; // Sichtweite in Metern public WeatherTimeData( ZonedDateTime dateTime, @@ -23,15 +30,25 @@ public class WeatherTimeData { double tempCelsius, int humidity, double windSpeed, + double windDeg, ZonedDateTime sunrise, - ZonedDateTime sunset) { + ZonedDateTime sunset, + int pressure, + int clouds, + double feelsLike, + int visibility) { this.dateTime = dateTime; this.weatherMain = weatherMain; this.tempCelsius = tempCelsius; this.humidity = humidity; this.windSpeed = windSpeed; + this.windDeg = windDeg; this.sunrise = sunrise; this.sunset = sunset; + this.pressure = pressure; + this.clouds = clouds; + this.feelsLike = feelsLike; + this.visibility = visibility; } public ZonedDateTime getDateTime() { @@ -44,7 +61,7 @@ public class WeatherTimeData { public double getTemp(String unit) { return "F".equalsIgnoreCase(unit) - ? (tempCelsius * 9 / 5) + 32 + ? (tempCelsius * 9.0 / 5.0) + 32.0 : tempCelsius; } @@ -56,6 +73,10 @@ public class WeatherTimeData { return windSpeed; } + public double getWindDeg() { + return windDeg; + } + public ZonedDateTime getSunrise() { return sunrise; } @@ -64,6 +85,62 @@ public class WeatherTimeData { return sunset; } + public int getPressure() { + return pressure; + } + + public int getClouds() { + return clouds; + } + + public double getFeelsLike(String unit) { + return "F".equalsIgnoreCase(unit) + ? (feelsLike * 9.0 / 5.0) + 32.0 + : feelsLike; + } + + public int getVisibility() { + return visibility; + } + + /** + * Berechnet einen einfachen UV-Index basierend auf Tageszeit, Wolken und Wetter + * (0-11+: 0-2=niedrig, 3-5=mäßig, 6-7=hoch, 8-10=sehr hoch, 11+=extrem) + */ + public int getUVIndex() { + int hour = dateTime.getHour(); + + // Nachts ist UV-Index 0 + if (hour < 6 || hour > 20) { + return 0; + } + + // Basis UV-Index je nach Tageszeit (Maximum mittags) + int baseUV; + if (hour >= 11 && hour <= 13) { + baseUV = 9; // Mittags am höchsten + } else if (hour >= 10 && hour <= 14) { + baseUV = 7; + } else if (hour >= 9 && hour <= 15) { + baseUV = 5; + } else { + baseUV = 3; + } + + // Reduzierung durch Wolken + baseUV = baseUV - (clouds / 20); + + // Reduzierung bei Regen/Schnee/Gewitter + if (weatherMain.equalsIgnoreCase("rain") || + weatherMain.equalsIgnoreCase("drizzle") || + weatherMain.equalsIgnoreCase("thunderstorm") || + weatherMain.equalsIgnoreCase("snow")) { + baseUV = Math.max(1, baseUV / 2); + } + + return Math.max(0, Math.min(11, baseUV)); + } + public String getFormattedTime(String format) { int hour = dateTime.getHour(); int minute = dateTime.getMinute(); diff --git a/src/main/java/dev/viper/weathertime/WeatherTimeSyncPlugin.java b/src/main/java/dev/viper/weathertime/WeatherTimeSyncPlugin.java index 7b2f60b..5c6bdb4 100644 --- a/src/main/java/dev/viper/weathertime/WeatherTimeSyncPlugin.java +++ b/src/main/java/dev/viper/weathertime/WeatherTimeSyncPlugin.java @@ -4,31 +4,28 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.platform.bukkit.BukkitAudiences; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.World; +import org.bukkit.*; +import org.bukkit.block.Block; import org.bukkit.command.*; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; +import org.bukkit.entity.Snowman; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scoreboard.*; import org.json.JSONArray; import org.json.JSONObject; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.block.Block; - - import java.io.File; import java.io.IOException; @@ -38,9 +35,12 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.*; -// <--- NEU: Einbinden der Hilfsklassen (keine Änderung am bestehenden Code) import dev.viper.weathertime.MetricsManager; import dev.viper.weathertime.UpdateChecker; +import dev.viper.weathertime.DisplayMode; +import dev.viper.weathertime.WeatherColors; +import dev.viper.weathertime.WindDirection; +import dev.viper.weathertime.MoonPhase; public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { @@ -51,17 +51,16 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { private final Map> playersWithDisplay = new HashMap<>(); private final Map playerLocations = new HashMap<>(); private final Map playerGUIs = new HashMap<>(); + private final Map playerScoreboards = new HashMap<>(); + private final Map playerDisplayModes = new HashMap<>(); private BukkitAudiences audiences; private BukkitRunnable weatherUpdateTask; private BukkitRunnable syncTask; private final Set processedLocations = new HashSet<>(); private FileConfiguration langConfig; - // NEU: bStats & Updater-Felder private MetricsManager metricsManager; private UpdateChecker updateChecker; - - // Variable, um die aktuell bekannte neue Version zu speichern private String latestVersion = null; @Override @@ -71,25 +70,19 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { loadConfig(); audiences = BukkitAudiences.create(this); - // bStats initialisieren metricsManager = new MetricsManager(this); - // Spigot UpdateChecker initialisieren (Resource-ID) updateChecker = new UpdateChecker(this, 127846); updateChecker.getLatestVersion(version -> { - // Version bereinigen: nur Zahlen und Punkte String cleanVersion = version.replaceAll("[^0-9.]", "").trim(); String currentVersion = getDescription().getVersion(); - // Nur dann melden, wenn cleanVersion wirklich neuer ist if (isVersionNewer(currentVersion, cleanVersion)) { - latestVersion = cleanVersion; // Neue Version merken + latestVersion = cleanVersion; - // Konsolen-Info getLogger().info("Neue Version verfügbar: " + cleanVersion + " (aktuell: " + currentVersion + ")"); getLogger().info("Download: https://www.spigotmc.org/resources/127846/"); - // Ingame-Info an alle aktuell online Operatoren for (Player player : Bukkit.getOnlinePlayers()) { if (player.isOp()) { player.sendMessage("§aEine neue Version von §eRealTimeWeather §aist verfügbar: §e" @@ -111,9 +104,13 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { startWeatherUpdateTask(); startSyncTask(); initializePlayerDisplays(); + + getLogger().info("=============================================="); + getLogger().info("RealTimeWeather nutzt SCOREBOARD-Anzeige!"); + getLogger().info("Die Wetteranzeige erscheint rechts am Bildschirm."); + getLogger().info("=============================================="); } - // Methode zum Versionsvergleich, damit nur wirklich neuere Versionen gemeldet werden private boolean isVersionNewer(String current, String latest) { String[] curParts = current.split("\\."); String[] latParts = latest.split("\\."); @@ -124,16 +121,15 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { int latNum = i < latParts.length ? Integer.parseInt(latParts[i]) : 0; if (latNum > curNum) { - return true; // neuere Version gefunden + return true; } if (latNum < curNum) { - return false; // keine neuere Version + return false; } } - return false; // Versionen sind gleich + return false; } - // Event Listener für Join-Nachricht public class UpdateNotifyListener implements Listener { @EventHandler @@ -155,10 +151,12 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { if (audiences != null) audiences.close(); for (Player player : Bukkit.getOnlinePlayers()) { if (playerGUIs.containsKey(player.getUniqueId())) player.closeInventory(); + if (playerScoreboards.containsKey(player.getUniqueId())) { + player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard()); + } } } - // =============== Config & Sprache =============== private void loadConfig() { FileConfiguration cfg = getConfig(); apiKey = cfg.getString("api-key", "").trim(); @@ -219,7 +217,13 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { private void setDoDaylightCycleForWorlds() { for (World world : Bukkit.getWorlds()) { WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults")); - if (config.enabled) world.setGameRuleValue("doDaylightCycle", "false"); + if (config.enabled) { + @SuppressWarnings("unchecked") + GameRule doDaylightCycle = (GameRule) GameRule.getByName("doDaylightCycle"); + if (doDaylightCycle != null) { + world.setGameRule(doDaylightCycle, false); + } + } } } @@ -232,6 +236,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { if (config.enabled && config.displayActionbar) worlds.add(world.getName()); } playersWithDisplay.put(player.getUniqueId(), worlds); + createScoreboardForPlayer(player); } } @@ -256,7 +261,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { WeatherTimeData data = worldWeatherData.get(world.getName()); if (data != null) { syncMinecraftTime(world, data.getDateTime()); - updateActionbarForWorld(world, data); + updateScoreboardForWorld(world, data); } } } @@ -267,6 +272,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { private void updateWeatherDataForAllWorlds() { for (World world : Bukkit.getWorlds()) { WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults")); + if (!config.enabled) { worldWeatherData.remove(world.getName()); continue; @@ -308,13 +314,8 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { case "snow": world.setStorm(true); world.setThundering(false); - - // ---- FAKE-SCHNEE ---- spawnTemporarySnowInWorld(world, WeatherTimeSyncPlugin.this); - - // ---- Schneemänner, temporär spawnen (z.B. 25 Stück) ---- spawnTemporarySnowmen(world, 25, WeatherTimeSyncPlugin.this); - break; default: world.setStorm(false); @@ -330,85 +331,77 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { } } - /** - * Fake-Schnee auf allen aktuell geladenen Chunks platzieren - */ - private void spawnTemporarySnowInWorld(World world, JavaPlugin plugin) { - List snowBlocks = new ArrayList<>(); + private void spawnTemporarySnowInWorld(World world, JavaPlugin plugin) { + List snowBlocks = new ArrayList<>(); - for (org.bukkit.Chunk chunk : world.getLoadedChunks()) { - int chunkX = chunk.getX() << 4; - int chunkZ = chunk.getZ() << 4; + for (org.bukkit.Chunk chunk : world.getLoadedChunks()) { + int chunkX = chunk.getX() << 4; + int chunkZ = chunk.getZ() << 4; - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - if (Math.random() > 0.7) continue; - int worldX = chunkX + x; - int worldZ = chunkZ + z; - int worldY = world.getHighestBlockYAt(worldX, worldZ); + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + if (Math.random() > 0.7) continue; + int worldX = chunkX + x; + int worldZ = chunkZ + z; + int worldY = world.getHighestBlockYAt(worldX, worldZ); - Block ground = world.getBlockAt(worldX, worldY - 1, worldZ); - Block above = world.getBlockAt(worldX, worldY, worldZ); + Block ground = world.getBlockAt(worldX, worldY - 1, worldZ); + Block above = world.getBlockAt(worldX, worldY, worldZ); - if (ground.getType().isSolid() && above.getType() == Material.AIR) { - above.setType(Material.SNOW); - snowBlocks.add(above); - } + if (ground.getType().isSolid() && above.getType() == Material.AIR) { + above.setType(Material.SNOW); + snowBlocks.add(above); } } } - - // Schnee entfernen - new BukkitRunnable() { - @Override - public void run() { - for (Block b : snowBlocks) { - if (b.getType() == Material.SNOW) { - b.setType(Material.AIR); - } - } - } - }.runTaskLater(plugin, 180 * 20L); // 3 Minuten bleibt der Schnee liegen } - /** - * Spawn temporärer Schneemänner in geladenen Chunks - */ - private void spawnTemporarySnowmen(World world, int count, JavaPlugin plugin) { - List snowmen = new ArrayList<>(); - Random random = new Random(); - - List loadedChunks = Arrays.asList(world.getLoadedChunks()); - - for (int i = 0; i < count; i++) { - if (loadedChunks.isEmpty()) break; - org.bukkit.Chunk chunk = loadedChunks.get(random.nextInt(loadedChunks.size())); - - int chunkX = chunk.getX() << 4; - int chunkZ = chunk.getZ() << 4; - int x = chunkX + random.nextInt(16); - int z = chunkZ + random.nextInt(16); - int y = world.getHighestBlockYAt(x, z); - - if (world.getBlockAt(x, y - 1, z).getType().isSolid()) { - org.bukkit.entity.Snowman snowman = (org.bukkit.entity.Snowman) - world.spawnEntity(new org.bukkit.Location(world, x + 0.5, y, z + 0.5), - org.bukkit.entity.EntityType.SNOW_GOLEM); - snowmen.add(snowman); + new BukkitRunnable() { + @Override + public void run() { + for (Block b : snowBlocks) { + if (b.getType() == Material.SNOW) { + b.setType(Material.AIR); + } } } + }.runTaskLater(plugin, 180 * 20L); + } - // Schneemänner nach 30 Sekunden wieder entfernen - new BukkitRunnable() { - @Override - public void run() { - for (org.bukkit.entity.Snowman s : snowmen) { - if (!s.isDead()) s.remove(); - } - } - }.runTaskLater(plugin, 180 * 20L); + private void spawnTemporarySnowmen(World world, int count, JavaPlugin plugin) { + List snowmen = new ArrayList<>(); + Random random = new Random(); + + List loadedChunks = Arrays.asList(world.getLoadedChunks()); + + for (int i = 0; i < count; i++) { + if (loadedChunks.isEmpty()) break; + org.bukkit.Chunk chunk = loadedChunks.get(random.nextInt(loadedChunks.size())); + + int chunkX = chunk.getX() << 4; + int chunkZ = chunk.getZ() << 4; + int x = chunkX + random.nextInt(16); + int z = chunkZ + random.nextInt(16); + int y = world.getHighestBlockYAt(x, z); + + if (world.getBlockAt(x, y - 1, z).getType().isSolid()) { + Snowman snowman = (Snowman) world.spawnEntity( + new Location(world, x + 0.5, y, z + 0.5), + EntityType.SNOW_GOLEM + ); + snowmen.add(snowman); + } } + new BukkitRunnable() { + @Override + public void run() { + for (Snowman s : snowmen) { + if (!s.isDead()) s.remove(); + } + } + }.runTaskLater(plugin, 180 * 20L); + } private void syncMinecraftTime(World world, ZonedDateTime dateTime) { int hour = dateTime.getHour(); @@ -416,17 +409,56 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { int second = dateTime.getSecond(); int minecraftTime = ((hour + 18) % 24) * 1000 + (minute * 1000 / 60) + (second * 1000 / 3600); world.setTime(minecraftTime); - world.setGameRuleValue("doDaylightCycle", "false"); + @SuppressWarnings("unchecked") + GameRule doDaylightCycle = (GameRule) GameRule.getByName("doDaylightCycle"); + if (doDaylightCycle != null) { + world.setGameRule(doDaylightCycle, false); + } } - // === Anzeige (Actionbar, jetzt mit Luftfeuchtigkeit, Wind, Sonne) === - private void updateActionbarForWorld(World world, WeatherTimeData data) { + private void createScoreboardForPlayer(Player player) { + Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + Objective objective = scoreboard.registerNewObjective("weather", "dummy", + ChatColor.GOLD + "" + ChatColor.BOLD + "⛅ Wetter Info"); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + + player.setScoreboard(scoreboard); + playerScoreboards.put(player.getUniqueId(), scoreboard); + } + + private void updateScoreboardForWorld(World world, WeatherTimeData data) { WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults")); - if (!config.enabled || !config.displayActionbar) return; + + if (!config.enabled || !config.displayActionbar) { + return; + } for (Player player : world.getPlayers()) { - if (!playersWithDisplay.getOrDefault(player.getUniqueId(), new HashSet<>()).contains(world.getName())) + Set displayWorlds = playersWithDisplay.getOrDefault(player.getUniqueId(), new HashSet<>()); + + if (!displayWorlds.contains(world.getName())) { + // Scoreboard entfernen wenn disabled + Scoreboard scoreboard = playerScoreboards.get(player.getUniqueId()); + if (scoreboard != null) { + player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard()); + playerScoreboards.remove(player.getUniqueId()); + } continue; + } + + Scoreboard scoreboard = playerScoreboards.get(player.getUniqueId()); + if (scoreboard == null) { + createScoreboardForPlayer(player); + scoreboard = playerScoreboards.get(player.getUniqueId()); + } + + Objective objective = scoreboard.getObjective("weather"); + if (objective == null) continue; + + // Alte Scores löschen + for (String entry : scoreboard.getEntries()) { + scoreboard.resetScores(entry); + } WeatherTimeData playerData = data; String location = playerLocations.getOrDefault(player.getUniqueId(), ""); @@ -435,43 +467,125 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, config.units, getLogger()); playerData = fetcher.fetchAsWeatherTimeData(); } catch (Exception e) { - String countryCode = getCountryCode(config.location); - audiences.player(player).sendMessage(Component.text( - getLocalizedMessage("forecast_error", countryCode, - "location", location, - "error", e.getMessage()), - NamedTextColor.RED)); continue; } } + // Display Mode des Spielers + DisplayMode mode = playerDisplayModes.getOrDefault(player.getUniqueId(), DisplayMode.STANDARD); + + // Daten vorbereiten String dateStr = playerData.getDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy")); String timeStr = playerData.getFormattedTime(config.timeFormat); String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F"; - String weatherIcon = config.displayWeatherIcon ? getWeatherSymbol(playerData.getWeatherMain()) + " " : ""; - String tempStr = String.format("%.1f%s", playerData.getTemp(config.units.equalsIgnoreCase("metric") ? "C" : "F"), tempUnit); + String weatherIcon = getWeatherSymbol(playerData.getWeatherMain()); + String weatherMain = getLocalizedWeatherMain(playerData.getWeatherMain(), getCountryCode(config.location)); + double temp = playerData.getTemp(config.units.equalsIgnoreCase("metric") ? "C" : "F"); + double tempCelsius = playerData.getTemp("C"); + String cityName = config.location.split(",")[0]; - String humidityStr = "💧 " + playerData.getHumidity() + "%"; - String windStr = "🌬️ " + String.format("%.1f", playerData.getWindSpeed()) + (config.units.equalsIgnoreCase("metric") ? " m/s" : " mph"); - String sunriseStr = "🌅 " + playerData.getSunrise().format(DateTimeFormatter.ofPattern("HH:mm")); - String sunsetStr = "🌇 " + playerData.getSunset().format(DateTimeFormatter.ofPattern("HH:mm")); + // Farben basierend auf Werten + ChatColor tempColor = WeatherColors.getTemperatureColor(tempCelsius); + ChatColor weatherColor = WeatherColors.getWeatherColor(playerData.getWeatherMain()); + ChatColor humidityColor = WeatherColors.getHumidityColor(playerData.getHumidity()); + ChatColor windColor = WeatherColors.getWindSpeedColor(playerData.getWindSpeed()); - Component message = Component.text() - .append(Component.text(dateStr + " ", NamedTextColor.AQUA, TextDecoration.BOLD)) - .append(Component.text("| " + timeStr + " ", NamedTextColor.YELLOW)) - .append(Component.text("| " + weatherIcon, NamedTextColor.WHITE)) - .append(Component.text("| " + tempStr + " ", NamedTextColor.GREEN)) - .append(Component.text("| " + humidityStr + " ", NamedTextColor.AQUA)) - .append(Component.text("| " + windStr + " ", NamedTextColor.GRAY)) - .append(Component.text("| " + sunriseStr + " ", NamedTextColor.GOLD)) - .append(Component.text("| " + sunsetStr, NamedTextColor.DARK_RED)) - .build(); + // Trennlinie + String separator = ChatColor.DARK_GRAY + "~" + ChatColor.GRAY + "~" + ChatColor.DARK_GRAY + "~" + + ChatColor.GRAY + "~" + ChatColor.DARK_GRAY + "~" + ChatColor.GRAY + "~" + + ChatColor.DARK_GRAY + "~" + ChatColor.GRAY + "~" + ChatColor.DARK_GRAY + "~"; - audiences.player(player).sendActionBar(message); + int line = 20; + + // === KOMPAKT MODE === + if (mode == DisplayMode.COMPACT) { + objective.getScore(" ").setScore(line--); + objective.getScore(ChatColor.AQUA + "📅 " + dateStr + " " + ChatColor.YELLOW + timeStr).setScore(line--); + objective.getScore(separator + "1").setScore(line--); + objective.getScore(weatherColor + weatherIcon + " " + ChatColor.GRAY + weatherMain).setScore(line--); + objective.getScore(tempColor + "🌡 " + String.format("%.1f%s", temp, tempUnit)).setScore(line--); + objective.getScore(separator + "2").setScore(line--); + objective.getScore(ChatColor.DARK_AQUA + "📍 " + cityName).setScore(line--); + objective.getScore(" ").setScore(line--); + } + // === STANDARD MODE === + else if (mode == DisplayMode.STANDARD) { + objective.getScore(" ").setScore(line--); + objective.getScore(ChatColor.AQUA + "📅 " + dateStr).setScore(line--); + objective.getScore(ChatColor.YELLOW + "🕐 " + timeStr).setScore(line--); + objective.getScore(separator + "1").setScore(line--); + objective.getScore(weatherColor + weatherIcon + " " + ChatColor.GRAY + weatherMain).setScore(line--); + objective.getScore(tempColor + "🌡 " + String.format("%.1f%s", temp, tempUnit)).setScore(line--); + objective.getScore(humidityColor + "💧 " + playerData.getHumidity() + "%").setScore(line--); + + // Windrichtung mit Pfeil + String windDir = WindDirection.getDirection(playerData.getWindDeg()); + String windArrow = WindDirection.getArrow(playerData.getWindDeg()); + objective.getScore(windColor + "🌬 " + String.format("%.1f", playerData.getWindSpeed()) + + (config.units.equalsIgnoreCase("metric") ? " m/s " : " mph ") + windArrow + " " + windDir).setScore(line--); + + objective.getScore(separator + "2").setScore(line--); + objective.getScore(ChatColor.GOLD + "🌅 " + playerData.getSunrise().format(DateTimeFormatter.ofPattern("HH:mm"))).setScore(line--); + objective.getScore(ChatColor.DARK_RED + "🌇 " + playerData.getSunset().format(DateTimeFormatter.ofPattern("HH:mm"))).setScore(line--); + + // Mondphase + objective.getScore(ChatColor.LIGHT_PURPLE + MoonPhase.getEmoji(world) + " " + MoonPhase.getName(world)).setScore(line--); + + objective.getScore(separator + "3").setScore(line--); + objective.getScore(ChatColor.DARK_AQUA + "📍 " + cityName).setScore(line--); + objective.getScore(" ").setScore(line--); + } + // === DETAILLIERT MODE === + else if (mode == DisplayMode.DETAILED) { + objective.getScore(" ").setScore(line--); + objective.getScore(ChatColor.AQUA + "📅 " + dateStr).setScore(line--); + objective.getScore(ChatColor.YELLOW + "🕐 " + timeStr).setScore(line--); + objective.getScore(separator + "1").setScore(line--); + objective.getScore(weatherColor + weatherIcon + " " + ChatColor.GRAY + weatherMain).setScore(line--); + objective.getScore(tempColor + "🌡 " + String.format("%.1f%s", temp, tempUnit)).setScore(line--); + + // Gefühlte Temperatur + double feelsLike = playerData.getFeelsLike(config.units.equalsIgnoreCase("metric") ? "C" : "F"); + ChatColor feelsLikeColor = WeatherColors.getTemperatureColor(playerData.getFeelsLike("C")); + objective.getScore(feelsLikeColor + "🌡️ Gefühlt: " + String.format("%.1f%s", feelsLike, tempUnit)).setScore(line--); + + objective.getScore(humidityColor + "💧 " + playerData.getHumidity() + "%").setScore(line--); + + // Windrichtung mit Pfeil + String windDir = WindDirection.getDirection(playerData.getWindDeg()); + String windArrow = WindDirection.getArrow(playerData.getWindDeg()); + objective.getScore(windColor + "🌬 " + String.format("%.1f", playerData.getWindSpeed()) + + (config.units.equalsIgnoreCase("metric") ? " m/s " : " mph ") + windArrow + " " + windDir).setScore(line--); + + // Luftdruck + objective.getScore(ChatColor.GRAY + "📊 " + playerData.getPressure() + " hPa").setScore(line--); + + // Wolkendichte + objective.getScore(ChatColor.WHITE + "☁️ Wolken: " + playerData.getClouds() + "%").setScore(line--); + + // Sichtweite + int visKm = playerData.getVisibility() / 1000; + objective.getScore(ChatColor.BLUE + "👁️ Sicht: " + visKm + " km").setScore(line--); + + // UV-Index + int uvIndex = playerData.getUVIndex(); + ChatColor uvColor = WeatherColors.getUVIndexColor(uvIndex); + objective.getScore(uvColor + "☀️ UV: " + uvIndex).setScore(line--); + + objective.getScore(separator + "2").setScore(line--); + objective.getScore(ChatColor.GOLD + "🌅 " + playerData.getSunrise().format(DateTimeFormatter.ofPattern("HH:mm"))).setScore(line--); + objective.getScore(ChatColor.DARK_RED + "🌇 " + playerData.getSunset().format(DateTimeFormatter.ofPattern("HH:mm"))).setScore(line--); + + // Mondphase + objective.getScore(ChatColor.LIGHT_PURPLE + MoonPhase.getPhase(world)).setScore(line--); + + objective.getScore(separator + "3").setScore(line--); + objective.getScore(ChatColor.DARK_AQUA + "📍 " + cityName).setScore(line--); + objective.getScore(" ").setScore(line--); + } } } - // === Events (z.B. Weltwechsel) === @EventHandler public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { Player player = event.getPlayer(); @@ -485,7 +599,21 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F"; String city = config.location.split(",")[0]; String message = String.format("%s: %s, %.1f%s", city, localizedWeather, data.getTemp(config.units.equalsIgnoreCase("metric") ? "C" : "F"), tempUnit); - audiences.player(player).sendActionBar(Component.text(message, NamedTextColor.GREEN)); + player.sendMessage(ChatColor.GREEN + message); + } + + @EventHandler + public void onPlayerJoinForDisplay(PlayerJoinEvent event) { + Player player = event.getPlayer(); + Set worlds = new HashSet<>(); + for (World world : Bukkit.getWorlds()) { + WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults")); + if (config.enabled && config.displayActionbar) { + worlds.add(world.getName()); + } + } + playersWithDisplay.put(player.getUniqueId(), worlds); + createScoreboardForPlayer(player); } @EventHandler @@ -521,7 +649,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { new WeatherForecastCommand().onCommand(player, null, "weatherforecast", new String[]{}); } else if (clickedItem.getType() == Material.OAK_SIGN) { player.closeInventory(); - String infoMessage = "RealTimeWeather Plugin\nVersion: 1.2\nAutor: M_Viper\nGetestete Minecraft-Version: 1.21.1 - 1.21.8"; + String infoMessage = "RealTimeWeather Plugin\nVersion: 1.3\nAutor: M_Viper\nGetestete Minecraft-Version: 1.21.1 - 1.21.11"; audiences.player(player).sendMessage(Component.text(infoMessage, NamedTextColor.AQUA)); } } @@ -531,8 +659,6 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { playerGUIs.remove(event.getPlayer().getUniqueId()); } - // === Hilfsmethoden & Modellklassen === - private String getLocalizedMessage(String key, String countryCode, String... placeholders) { String path = "languages." + (countryCode.isEmpty() ? "en" : countryCode.toLowerCase()) + "." + key; String message = langConfig.getString(path); @@ -610,7 +736,6 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { return inv; } - // ==== PlayerConfig etc. wie gehabt ==== private class PlayerConfig { private final File configFile; private final FileConfiguration config; @@ -633,7 +758,6 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { } } - // ==== Commands ==== private class WetterCommand implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { @@ -659,6 +783,9 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { .append(Component.text("/wetter query", NamedTextColor.YELLOW)) .append(Component.text(" - " + getLocalizedMessage("help_query", countryCode), NamedTextColor.WHITE)) .append(Component.newline()) + .append(Component.text("/wetter mode ", NamedTextColor.YELLOW)) + .append(Component.text(" - Anzeigemodus wechseln", NamedTextColor.WHITE)) + .append(Component.newline()) .append(Component.text("/wetter info", NamedTextColor.YELLOW)) .append(Component.text(" - " + getLocalizedMessage("help_info", countryCode), NamedTextColor.WHITE)) .append(Component.newline()) @@ -756,7 +883,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { return true; } case "info": { - String infoMessage = "RealTimeWeather Plugin\nVersion: 1.0\nAutor: M_Viper\nGetestete Minecraft-Version: 1.21.1 - 1.21.8"; + String infoMessage = "RealTimeWeather Plugin\nVersion: 1.3\nAutor: M_Viper\nGetestete Minecraft-Version: 1.21.1 - 1.21.11\n\nDie Wetteranzeige erscheint als SCOREBOARD rechts am Bildschirm."; audiences.sender(sender).sendMessage(Component.text(infoMessage, NamedTextColor.AQUA)); return true; } @@ -775,6 +902,31 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { guiPlayer.openInventory(createWeatherGUI(guiPlayer)); return true; } + case "mode": { + if (!(sender instanceof Player)) { + audiences.sender(sender).sendMessage(Component.text("Nur für Spieler", NamedTextColor.RED)); + return true; + } + Player modePlayer = (Player) sender; + + if (args.length != 2) { + DisplayMode currentMode = playerDisplayModes.getOrDefault(modePlayer.getUniqueId(), DisplayMode.STANDARD); + modePlayer.sendMessage(ChatColor.YELLOW + "Aktueller Anzeigemodus: " + ChatColor.GREEN + currentMode.getDisplayName()); + modePlayer.sendMessage(ChatColor.GRAY + "Verwendung: /wetter mode "); + modePlayer.sendMessage(ChatColor.GRAY + "- " + ChatColor.AQUA + "compact" + ChatColor.GRAY + ": Minimale Anzeige"); + modePlayer.sendMessage(ChatColor.GRAY + "- " + ChatColor.AQUA + "standard" + ChatColor.GRAY + ": Normale Anzeige (empfohlen)"); + modePlayer.sendMessage(ChatColor.GRAY + "- " + ChatColor.AQUA + "detailed" + ChatColor.GRAY + ": Alle verfügbaren Daten"); + return true; + } + + DisplayMode newMode = DisplayMode.fromString(args[1]); + playerDisplayModes.put(modePlayer.getUniqueId(), newMode); + + modePlayer.sendMessage(ChatColor.GREEN + "Anzeigemodus geändert zu: " + ChatColor.GOLD + newMode.getDisplayName()); + modePlayer.sendMessage(ChatColor.GRAY + "Das Scoreboard wird beim nächsten Update aktualisiert."); + + return true; + } default: audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("usage", countryCode), NamedTextColor.RED)); return true; @@ -861,16 +1013,22 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener { Set worlds = playersWithDisplay.computeIfAbsent(player.getUniqueId(), k -> new HashSet<>()); if (worlds.contains(worldName)) { worlds.remove(worldName); - audiences.player(player).sendMessage(Component.text(getLocalizedMessage("toggle_disabled", countryCode, "world", worldName), NamedTextColor.RED)); + // Scoreboard entfernen + player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard()); + playerScoreboards.remove(player.getUniqueId()); + audiences.player(player).sendMessage(Component.text( + getLocalizedMessage("toggle_disabled", countryCode, "world", worldName), NamedTextColor.RED)); } else { worlds.add(worldName); - audiences.player(player).sendMessage(Component.text(getLocalizedMessage("toggle_enabled", countryCode, "world", worldName), NamedTextColor.GREEN)); + // Scoreboard erstellen + createScoreboardForPlayer(player); + audiences.player(player).sendMessage(Component.text( + getLocalizedMessage("toggle_enabled", countryCode, "world", worldName), NamedTextColor.GREEN)); } return true; } } - // Modellklasse WorldConfig (nur als Speicher für die Welten-Settings) private static class WorldConfig { boolean enabled; String location; diff --git a/src/main/java/dev/viper/weathertime/WindDirection.java b/src/main/java/dev/viper/weathertime/WindDirection.java new file mode 100644 index 0000000..1fbecd1 --- /dev/null +++ b/src/main/java/dev/viper/weathertime/WindDirection.java @@ -0,0 +1,83 @@ +package dev.viper.weathertime; + +public class WindDirection { + + /** + * Konvertiert Windrichtung in Grad (0-360) zu Himmelsrichtung + */ + public static String getDirection(double degrees) { + // Normalisiere auf 0-360 + degrees = degrees % 360; + if (degrees < 0) degrees += 360; + + if (degrees >= 337.5 || degrees < 22.5) { + return "N"; // Nord + } else if (degrees >= 22.5 && degrees < 67.5) { + return "NO"; // Nordost + } else if (degrees >= 67.5 && degrees < 112.5) { + return "O"; // Ost + } else if (degrees >= 112.5 && degrees < 157.5) { + return "SO"; // Südost + } else if (degrees >= 157.5 && degrees < 202.5) { + return "S"; // Süd + } else if (degrees >= 202.5 && degrees < 247.5) { + return "SW"; // Südwest + } else if (degrees >= 247.5 && degrees < 292.5) { + return "W"; // West + } else { + return "NW"; // Nordwest + } + } + + /** + * Gibt den Pfeil-Emoji basierend auf der Windrichtung zurück + */ + public static String getArrow(double degrees) { + degrees = degrees % 360; + if (degrees < 0) degrees += 360; + + if (degrees >= 337.5 || degrees < 22.5) { + return "↓"; // Nord (Wind kommt von Norden, weht nach Süden) + } else if (degrees >= 22.5 && degrees < 67.5) { + return "↙"; // Nordost + } else if (degrees >= 67.5 && degrees < 112.5) { + return "←"; // Ost + } else if (degrees >= 112.5 && degrees < 157.5) { + return "↖"; // Südost + } else if (degrees >= 157.5 && degrees < 202.5) { + return "↑"; // Süd + } else if (degrees >= 202.5 && degrees < 247.5) { + return "↗"; // Südwest + } else if (degrees >= 247.5 && degrees < 292.5) { + return "→"; // West + } else { + return "↘"; // Nordwest + } + } + + /** + * Gibt die volle Bezeichnung der Windrichtung zurück + */ + public static String getFullName(double degrees) { + degrees = degrees % 360; + if (degrees < 0) degrees += 360; + + if (degrees >= 337.5 || degrees < 22.5) { + return "Nord"; + } else if (degrees >= 22.5 && degrees < 67.5) { + return "Nordost"; + } else if (degrees >= 67.5 && degrees < 112.5) { + return "Ost"; + } else if (degrees >= 112.5 && degrees < 157.5) { + return "Südost"; + } else if (degrees >= 157.5 && degrees < 202.5) { + return "Süd"; + } else if (degrees >= 202.5 && degrees < 247.5) { + return "Südwest"; + } else if (degrees >= 247.5 && degrees < 292.5) { + return "West"; + } else { + return "Nordwest"; + } + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 9388ab9..d5eb22d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -36,4 +36,4 @@ worlds: display-weather-icon: false display-position: "top-right" padding-right: 150 - sync-in-game-weather: false + sync-in-game-weather: false \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 14bb4f1..fb0286c 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: RealTimeWeather -version: 1.3 +version: 1.4 main: dev.viper.weathertime.WeatherTimeSyncPlugin api-version: 1.21