Update from Git Manager GUI

This commit is contained in:
2026-01-28 17:34:09 +01:00
parent e2b3abb65d
commit f72903c2a6
11 changed files with 742 additions and 174 deletions

View File

@@ -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;
}
}

View File

@@ -8,7 +8,7 @@ public class MetricsManager {
private final Metrics metrics; private final Metrics metrics;
public MetricsManager(JavaPlugin plugin) { 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); this.metrics = new Metrics(plugin, pluginId);
// Optional: Eigene Charts hinzufügen // Optional: Eigene Charts hinzufügen

View File

@@ -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";
}
}
}

View File

@@ -2,6 +2,7 @@ package dev.viper.weathertime;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.json.JSONObject;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
@@ -9,8 +10,6 @@ import java.net.URL;
import java.util.Scanner; import java.util.Scanner;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.json.JSONObject;
public class UpdateChecker { public class UpdateChecker {
private final JavaPlugin plugin; private final JavaPlugin plugin;
private final int resourceId; private final int resourceId;
@@ -22,6 +21,8 @@ public class UpdateChecker {
public void getLatestVersion(Consumer<String> consumer) { public void getLatestVersion(Consumer<String> consumer) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
InputStream inputStream = null;
Scanner scanner = null;
try { try {
HttpURLConnection connection = (HttpURLConnection) HttpURLConnection connection = (HttpURLConnection)
new URL("https://api.spiget.org/v2/resources/" + resourceId + "/versions/latest").openConnection(); new URL("https://api.spiget.org/v2/resources/" + resourceId + "/versions/latest").openConnection();
@@ -29,8 +30,8 @@ public class UpdateChecker {
connection.setRequestMethod("GET"); connection.setRequestMethod("GET");
connection.addRequestProperty("User-Agent", "Mozilla/5.0"); connection.addRequestProperty("User-Agent", "Mozilla/5.0");
try (InputStream inputStream = connection.getInputStream(); inputStream = connection.getInputStream();
Scanner scanner = new Scanner(inputStream)) { scanner = new Scanner(inputStream);
String response = scanner.useDelimiter("\\A").next(); String response = scanner.useDelimiter("\\A").next();
JSONObject json = new JSONObject(response); JSONObject json = new JSONObject(response);
@@ -40,11 +41,24 @@ public class UpdateChecker {
String cleanVersion = versionName.replaceAll("[^0-9.]", "").trim(); String cleanVersion = versionName.replaceAll("[^0-9.]", "").trim();
consumer.accept(cleanVersion.isEmpty() ? versionName : cleanVersion); consumer.accept(cleanVersion.isEmpty() ? versionName : cleanVersion);
}
} catch (Exception e) { } catch (Exception e) {
plugin.getLogger().warning("Konnte keine Update-Info abrufen: " + e.getMessage()); 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
}
}
} }
}); });
} }
} }

View File

@@ -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
}
}
}

View File

@@ -44,16 +44,16 @@ public class WeatherFetcher {
"https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=%s", "https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=%s",
location, apiKey, effectiveUnits); location, apiKey, effectiveUnits);
BufferedReader in = null;
try { try {
JSONObject json; JSONObject json;
try (BufferedReader in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString)))) { in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString)));
StringBuilder content = new StringBuilder(); StringBuilder content = new StringBuilder();
String inputLine; String inputLine;
while ((inputLine = in.readLine()) != null) { while ((inputLine = in.readLine()) != null) {
content.append(inputLine); content.append(inputLine);
} }
json = new JSONObject(content.toString()); json = new JSONObject(content.toString());
}
// Fehlerfall: Antwort-Code ungleich 200 // Fehlerfall: Antwort-Code ungleich 200
if (json.has("cod") && json.getInt("cod") != 200) { if (json.has("cod") && json.getInt("cod") != 200) {
@@ -79,11 +79,18 @@ public class WeatherFetcher {
} }
// Temperatur immer in Celsius für WeatherTimeData speichern // 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"); int humidity = json.getJSONObject("main").getInt("humidity");
double windSpeed = json.getJSONObject("wind").optDouble("speed", 0.0); 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")) ZonedDateTime sunrise = Instant.ofEpochSecond(json.getJSONObject("sys").getLong("sunrise"))
.atZone(ZoneId.of("UTC")) .atZone(ZoneId.of("UTC"))
@@ -94,13 +101,22 @@ public class WeatherFetcher {
.plusSeconds(timezoneShift); .plusSeconds(timezoneShift);
return new WeatherTimeData(dateTime, weatherMain, tempCelsius, return new WeatherTimeData(dateTime, weatherMain, tempCelsius,
humidity, windSpeed, sunrise, sunset); humidity, windSpeed, windDeg, sunrise, sunset,
pressure, clouds, feelsLikeCelsius, visibility);
} catch (RuntimeException ru) { } catch (RuntimeException ru) {
throw ru; throw ru;
} catch (Exception ex) { } catch (Exception ex) {
logger.warning("Fehler beim Abrufen von OpenWeatherMap: " + ex.getMessage()); logger.warning("Fehler beim Abrufen von OpenWeatherMap: " + ex.getMessage());
throw new RuntimeException("Verbindung oder API-Fehler: " + ex.getMessage(), ex); 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", "https://api.openweathermap.org/data/2.5/forecast?q=%s&appid=%s&units=%s",
location, apiKey, effectiveUnits); 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(); StringBuilder content = new StringBuilder();
String inputLine; String inputLine;
while ((inputLine = in.readLine()) != null) { while ((inputLine = in.readLine()) != null) {
@@ -131,6 +149,14 @@ public class WeatherFetcher {
} catch (Exception e) { } catch (Exception e) {
logger.warning("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage()); logger.warning("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage());
throw new RuntimeException("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage(), e); 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(); int status = connection.getResponseCode();
if (status != 200) { if (status != 200) {
String err = "(keine Fehlerdetails)"; 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(); StringBuilder sb = new StringBuilder();
String l; String l;
while ((l = errIn.readLine()) != null) sb.append(l); while ((l = errIn.readLine()) != null) sb.append(l);
err = sb.toString(); 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); throw new RuntimeException("HTTP-Fehlercode: " + status + " " + err);
} }
return connection.getInputStream(); return connection.getInputStream();

View File

@@ -4,7 +4,8 @@ import java.time.ZonedDateTime;
/** /**
* Zentrale Datenklasse für Wetter- und Zeitinformationen. * 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 { public class WeatherTimeData {
@@ -14,24 +15,40 @@ public class WeatherTimeData {
private final int humidity; // Luftfeuchtigkeit in % private final int humidity; // Luftfeuchtigkeit in %
private final double windSpeed; // Windgeschwindigkeit (m/s oder mph) 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 sunrise; // Sonnenaufgang
private final ZonedDateTime sunset; // Sonnenuntergang 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( public WeatherTimeData(
ZonedDateTime dateTime, ZonedDateTime dateTime,
String weatherMain, String weatherMain,
double tempCelsius, double tempCelsius,
int humidity, int humidity,
double windSpeed, double windSpeed,
double windDeg,
ZonedDateTime sunrise, ZonedDateTime sunrise,
ZonedDateTime sunset) { ZonedDateTime sunset,
int pressure,
int clouds,
double feelsLike,
int visibility) {
this.dateTime = dateTime; this.dateTime = dateTime;
this.weatherMain = weatherMain; this.weatherMain = weatherMain;
this.tempCelsius = tempCelsius; this.tempCelsius = tempCelsius;
this.humidity = humidity; this.humidity = humidity;
this.windSpeed = windSpeed; this.windSpeed = windSpeed;
this.windDeg = windDeg;
this.sunrise = sunrise; this.sunrise = sunrise;
this.sunset = sunset; this.sunset = sunset;
this.pressure = pressure;
this.clouds = clouds;
this.feelsLike = feelsLike;
this.visibility = visibility;
} }
public ZonedDateTime getDateTime() { public ZonedDateTime getDateTime() {
@@ -44,7 +61,7 @@ public class WeatherTimeData {
public double getTemp(String unit) { public double getTemp(String unit) {
return "F".equalsIgnoreCase(unit) return "F".equalsIgnoreCase(unit)
? (tempCelsius * 9 / 5) + 32 ? (tempCelsius * 9.0 / 5.0) + 32.0
: tempCelsius; : tempCelsius;
} }
@@ -56,6 +73,10 @@ public class WeatherTimeData {
return windSpeed; return windSpeed;
} }
public double getWindDeg() {
return windDeg;
}
public ZonedDateTime getSunrise() { public ZonedDateTime getSunrise() {
return sunrise; return sunrise;
} }
@@ -64,6 +85,62 @@ public class WeatherTimeData {
return sunset; 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) { public String getFormattedTime(String format) {
int hour = dateTime.getHour(); int hour = dateTime.getHour();
int minute = dateTime.getMinute(); int minute = dateTime.getMinute();

View File

@@ -4,31 +4,28 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Bukkit; import org.bukkit.*;
import org.bukkit.Material; import org.bukkit.block.Block;
import org.bukkit.World;
import org.bukkit.command.*; import org.bukkit.command.*;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Snowman;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scoreboard.*;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; 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.File;
import java.io.IOException; import java.io.IOException;
@@ -38,9 +35,12 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
// <--- NEU: Einbinden der Hilfsklassen (keine Änderung am bestehenden Code)
import dev.viper.weathertime.MetricsManager; import dev.viper.weathertime.MetricsManager;
import dev.viper.weathertime.UpdateChecker; 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 { public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
@@ -51,17 +51,16 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
private final Map<UUID, Set<String>> playersWithDisplay = new HashMap<>(); private final Map<UUID, Set<String>> playersWithDisplay = new HashMap<>();
private final Map<UUID, String> playerLocations = new HashMap<>(); private final Map<UUID, String> playerLocations = new HashMap<>();
private final Map<UUID, Inventory> playerGUIs = new HashMap<>(); private final Map<UUID, Inventory> playerGUIs = new HashMap<>();
private final Map<UUID, Scoreboard> playerScoreboards = new HashMap<>();
private final Map<UUID, DisplayMode> playerDisplayModes = new HashMap<>();
private BukkitAudiences audiences; private BukkitAudiences audiences;
private BukkitRunnable weatherUpdateTask; private BukkitRunnable weatherUpdateTask;
private BukkitRunnable syncTask; private BukkitRunnable syncTask;
private final Set<String> processedLocations = new HashSet<>(); private final Set<String> processedLocations = new HashSet<>();
private FileConfiguration langConfig; private FileConfiguration langConfig;
// NEU: bStats & Updater-Felder
private MetricsManager metricsManager; private MetricsManager metricsManager;
private UpdateChecker updateChecker; private UpdateChecker updateChecker;
// Variable, um die aktuell bekannte neue Version zu speichern
private String latestVersion = null; private String latestVersion = null;
@Override @Override
@@ -71,25 +70,19 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
loadConfig(); loadConfig();
audiences = BukkitAudiences.create(this); audiences = BukkitAudiences.create(this);
// bStats initialisieren
metricsManager = new MetricsManager(this); metricsManager = new MetricsManager(this);
// Spigot UpdateChecker initialisieren (Resource-ID)
updateChecker = new UpdateChecker(this, 127846); updateChecker = new UpdateChecker(this, 127846);
updateChecker.getLatestVersion(version -> { updateChecker.getLatestVersion(version -> {
// Version bereinigen: nur Zahlen und Punkte
String cleanVersion = version.replaceAll("[^0-9.]", "").trim(); String cleanVersion = version.replaceAll("[^0-9.]", "").trim();
String currentVersion = getDescription().getVersion(); String currentVersion = getDescription().getVersion();
// Nur dann melden, wenn cleanVersion wirklich neuer ist
if (isVersionNewer(currentVersion, cleanVersion)) { if (isVersionNewer(currentVersion, cleanVersion)) {
latestVersion = cleanVersion; // Neue Version merken latestVersion = cleanVersion;
// Konsolen-Info
getLogger().info("Neue Version verfügbar: " + cleanVersion + " (aktuell: " + currentVersion + ")"); getLogger().info("Neue Version verfügbar: " + cleanVersion + " (aktuell: " + currentVersion + ")");
getLogger().info("Download: https://www.spigotmc.org/resources/127846/"); getLogger().info("Download: https://www.spigotmc.org/resources/127846/");
// Ingame-Info an alle aktuell online Operatoren
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
if (player.isOp()) { if (player.isOp()) {
player.sendMessage("§aEine neue Version von §eRealTimeWeather §aist verfügbar: §e" player.sendMessage("§aEine neue Version von §eRealTimeWeather §aist verfügbar: §e"
@@ -111,9 +104,13 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
startWeatherUpdateTask(); startWeatherUpdateTask();
startSyncTask(); startSyncTask();
initializePlayerDisplays(); 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) { private boolean isVersionNewer(String current, String latest) {
String[] curParts = current.split("\\."); String[] curParts = current.split("\\.");
String[] latParts = latest.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; int latNum = i < latParts.length ? Integer.parseInt(latParts[i]) : 0;
if (latNum > curNum) { if (latNum > curNum) {
return true; // neuere Version gefunden return true;
} }
if (latNum < curNum) { 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 { public class UpdateNotifyListener implements Listener {
@EventHandler @EventHandler
@@ -155,10 +151,12 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
if (audiences != null) audiences.close(); if (audiences != null) audiences.close();
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
if (playerGUIs.containsKey(player.getUniqueId())) player.closeInventory(); if (playerGUIs.containsKey(player.getUniqueId())) player.closeInventory();
if (playerScoreboards.containsKey(player.getUniqueId())) {
player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
}
} }
} }
// =============== Config & Sprache ===============
private void loadConfig() { private void loadConfig() {
FileConfiguration cfg = getConfig(); FileConfiguration cfg = getConfig();
apiKey = cfg.getString("api-key", "").trim(); apiKey = cfg.getString("api-key", "").trim();
@@ -219,7 +217,13 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
private void setDoDaylightCycleForWorlds() { private void setDoDaylightCycleForWorlds() {
for (World world : Bukkit.getWorlds()) { for (World world : Bukkit.getWorlds()) {
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults")); WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
if (config.enabled) world.setGameRuleValue("doDaylightCycle", "false"); if (config.enabled) {
@SuppressWarnings("unchecked")
GameRule<Boolean> doDaylightCycle = (GameRule<Boolean>) 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()); if (config.enabled && config.displayActionbar) worlds.add(world.getName());
} }
playersWithDisplay.put(player.getUniqueId(), worlds); playersWithDisplay.put(player.getUniqueId(), worlds);
createScoreboardForPlayer(player);
} }
} }
@@ -256,7 +261,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
WeatherTimeData data = worldWeatherData.get(world.getName()); WeatherTimeData data = worldWeatherData.get(world.getName());
if (data != null) { if (data != null) {
syncMinecraftTime(world, data.getDateTime()); syncMinecraftTime(world, data.getDateTime());
updateActionbarForWorld(world, data); updateScoreboardForWorld(world, data);
} }
} }
} }
@@ -267,6 +272,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
private void updateWeatherDataForAllWorlds() { private void updateWeatherDataForAllWorlds() {
for (World world : Bukkit.getWorlds()) { for (World world : Bukkit.getWorlds()) {
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults")); WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
if (!config.enabled) { if (!config.enabled) {
worldWeatherData.remove(world.getName()); worldWeatherData.remove(world.getName());
continue; continue;
@@ -308,13 +314,8 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
case "snow": case "snow":
world.setStorm(true); world.setStorm(true);
world.setThundering(false); world.setThundering(false);
// ---- FAKE-SCHNEE ----
spawnTemporarySnowInWorld(world, WeatherTimeSyncPlugin.this); spawnTemporarySnowInWorld(world, WeatherTimeSyncPlugin.this);
// ---- Schneemänner, temporär spawnen (z.B. 25 Stück) ----
spawnTemporarySnowmen(world, 25, WeatherTimeSyncPlugin.this); spawnTemporarySnowmen(world, 25, WeatherTimeSyncPlugin.this);
break; break;
default: default:
world.setStorm(false); world.setStorm(false);
@@ -330,9 +331,6 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
} }
} }
/**
* Fake-Schnee auf allen aktuell geladenen Chunks platzieren
*/
private void spawnTemporarySnowInWorld(World world, JavaPlugin plugin) { private void spawnTemporarySnowInWorld(World world, JavaPlugin plugin) {
List<Block> snowBlocks = new ArrayList<>(); List<Block> snowBlocks = new ArrayList<>();
@@ -358,7 +356,6 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
} }
} }
// Schnee entfernen
new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
@@ -368,14 +365,11 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
} }
} }
} }
}.runTaskLater(plugin, 180 * 20L); // 3 Minuten bleibt der Schnee liegen }.runTaskLater(plugin, 180 * 20L);
} }
/**
* Spawn temporärer Schneemänner in geladenen Chunks
*/
private void spawnTemporarySnowmen(World world, int count, JavaPlugin plugin) { private void spawnTemporarySnowmen(World world, int count, JavaPlugin plugin) {
List<org.bukkit.entity.Snowman> snowmen = new ArrayList<>(); List<Snowman> snowmen = new ArrayList<>();
Random random = new Random(); Random random = new Random();
List<org.bukkit.Chunk> loadedChunks = Arrays.asList(world.getLoadedChunks()); List<org.bukkit.Chunk> loadedChunks = Arrays.asList(world.getLoadedChunks());
@@ -391,42 +385,80 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
int y = world.getHighestBlockYAt(x, z); int y = world.getHighestBlockYAt(x, z);
if (world.getBlockAt(x, y - 1, z).getType().isSolid()) { if (world.getBlockAt(x, y - 1, z).getType().isSolid()) {
org.bukkit.entity.Snowman snowman = (org.bukkit.entity.Snowman) Snowman snowman = (Snowman) world.spawnEntity(
world.spawnEntity(new org.bukkit.Location(world, x + 0.5, y, z + 0.5), new Location(world, x + 0.5, y, z + 0.5),
org.bukkit.entity.EntityType.SNOW_GOLEM); EntityType.SNOW_GOLEM
);
snowmen.add(snowman); snowmen.add(snowman);
} }
} }
// Schneemänner nach 30 Sekunden wieder entfernen
new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
for (org.bukkit.entity.Snowman s : snowmen) { for (Snowman s : snowmen) {
if (!s.isDead()) s.remove(); if (!s.isDead()) s.remove();
} }
} }
}.runTaskLater(plugin, 180 * 20L); }.runTaskLater(plugin, 180 * 20L);
} }
private void syncMinecraftTime(World world, ZonedDateTime dateTime) { private void syncMinecraftTime(World world, ZonedDateTime dateTime) {
int hour = dateTime.getHour(); int hour = dateTime.getHour();
int minute = dateTime.getMinute(); int minute = dateTime.getMinute();
int second = dateTime.getSecond(); int second = dateTime.getSecond();
int minecraftTime = ((hour + 18) % 24) * 1000 + (minute * 1000 / 60) + (second * 1000 / 3600); int minecraftTime = ((hour + 18) % 24) * 1000 + (minute * 1000 / 60) + (second * 1000 / 3600);
world.setTime(minecraftTime); world.setTime(minecraftTime);
world.setGameRuleValue("doDaylightCycle", "false"); @SuppressWarnings("unchecked")
GameRule<Boolean> doDaylightCycle = (GameRule<Boolean>) GameRule.getByName("doDaylightCycle");
if (doDaylightCycle != null) {
world.setGameRule(doDaylightCycle, false);
}
} }
// === Anzeige (Actionbar, jetzt mit Luftfeuchtigkeit, Wind, Sonne) === private void createScoreboardForPlayer(Player player) {
private void updateActionbarForWorld(World world, WeatherTimeData data) { 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")); 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()) { for (Player player : world.getPlayers()) {
if (!playersWithDisplay.getOrDefault(player.getUniqueId(), new HashSet<>()).contains(world.getName())) Set<String> 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; 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; WeatherTimeData playerData = data;
String location = playerLocations.getOrDefault(player.getUniqueId(), ""); 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()); WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, config.units, getLogger());
playerData = fetcher.fetchAsWeatherTimeData(); playerData = fetcher.fetchAsWeatherTimeData();
} catch (Exception e) { } 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; 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 dateStr = playerData.getDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
String timeStr = playerData.getFormattedTime(config.timeFormat); String timeStr = playerData.getFormattedTime(config.timeFormat);
String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F"; String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F";
String weatherIcon = config.displayWeatherIcon ? getWeatherSymbol(playerData.getWeatherMain()) + " " : ""; String weatherIcon = getWeatherSymbol(playerData.getWeatherMain());
String tempStr = String.format("%.1f%s", playerData.getTemp(config.units.equalsIgnoreCase("metric") ? "C" : "F"), tempUnit); 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() + "%"; // Farben basierend auf Werten
String windStr = "🌬️ " + String.format("%.1f", playerData.getWindSpeed()) + (config.units.equalsIgnoreCase("metric") ? " m/s" : " mph"); ChatColor tempColor = WeatherColors.getTemperatureColor(tempCelsius);
String sunriseStr = "🌅 " + playerData.getSunrise().format(DateTimeFormatter.ofPattern("HH:mm")); ChatColor weatherColor = WeatherColors.getWeatherColor(playerData.getWeatherMain());
String sunsetStr = "🌇 " + playerData.getSunset().format(DateTimeFormatter.ofPattern("HH:mm")); ChatColor humidityColor = WeatherColors.getHumidityColor(playerData.getHumidity());
ChatColor windColor = WeatherColors.getWindSpeedColor(playerData.getWindSpeed());
Component message = Component.text() // Trennlinie
.append(Component.text(dateStr + " ", NamedTextColor.AQUA, TextDecoration.BOLD)) String separator = ChatColor.DARK_GRAY + "~" + ChatColor.GRAY + "~" + ChatColor.DARK_GRAY + "~" +
.append(Component.text("| " + timeStr + " ", NamedTextColor.YELLOW)) ChatColor.GRAY + "~" + ChatColor.DARK_GRAY + "~" + ChatColor.GRAY + "~" +
.append(Component.text("| " + weatherIcon, NamedTextColor.WHITE)) ChatColor.DARK_GRAY + "~" + ChatColor.GRAY + "~" + ChatColor.DARK_GRAY + "~";
.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();
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 @EventHandler
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
@@ -485,7 +599,21 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F"; String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F";
String city = config.location.split(",")[0]; 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); 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<String> 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 @EventHandler
@@ -521,7 +649,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
new WeatherForecastCommand().onCommand(player, null, "weatherforecast", new String[]{}); new WeatherForecastCommand().onCommand(player, null, "weatherforecast", new String[]{});
} else if (clickedItem.getType() == Material.OAK_SIGN) { } else if (clickedItem.getType() == Material.OAK_SIGN) {
player.closeInventory(); 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)); 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()); playerGUIs.remove(event.getPlayer().getUniqueId());
} }
// === Hilfsmethoden & Modellklassen ===
private String getLocalizedMessage(String key, String countryCode, String... placeholders) { private String getLocalizedMessage(String key, String countryCode, String... placeholders) {
String path = "languages." + (countryCode.isEmpty() ? "en" : countryCode.toLowerCase()) + "." + key; String path = "languages." + (countryCode.isEmpty() ? "en" : countryCode.toLowerCase()) + "." + key;
String message = langConfig.getString(path); String message = langConfig.getString(path);
@@ -610,7 +736,6 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
return inv; return inv;
} }
// ==== PlayerConfig etc. wie gehabt ====
private class PlayerConfig { private class PlayerConfig {
private final File configFile; private final File configFile;
private final FileConfiguration config; private final FileConfiguration config;
@@ -633,7 +758,6 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
} }
} }
// ==== Commands ====
private class WetterCommand implements CommandExecutor { private class WetterCommand implements CommandExecutor {
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 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("/wetter query", NamedTextColor.YELLOW))
.append(Component.text(" - " + getLocalizedMessage("help_query", countryCode), NamedTextColor.WHITE)) .append(Component.text(" - " + getLocalizedMessage("help_query", countryCode), NamedTextColor.WHITE))
.append(Component.newline()) .append(Component.newline())
.append(Component.text("/wetter mode <compact|standard|detailed>", NamedTextColor.YELLOW))
.append(Component.text(" - Anzeigemodus wechseln", NamedTextColor.WHITE))
.append(Component.newline())
.append(Component.text("/wetter info", NamedTextColor.YELLOW)) .append(Component.text("/wetter info", NamedTextColor.YELLOW))
.append(Component.text(" - " + getLocalizedMessage("help_info", countryCode), NamedTextColor.WHITE)) .append(Component.text(" - " + getLocalizedMessage("help_info", countryCode), NamedTextColor.WHITE))
.append(Component.newline()) .append(Component.newline())
@@ -756,7 +883,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
return true; return true;
} }
case "info": { 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)); audiences.sender(sender).sendMessage(Component.text(infoMessage, NamedTextColor.AQUA));
return true; return true;
} }
@@ -775,6 +902,31 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
guiPlayer.openInventory(createWeatherGUI(guiPlayer)); guiPlayer.openInventory(createWeatherGUI(guiPlayer));
return true; 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 <compact|standard|detailed>");
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: default:
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("usage", countryCode), NamedTextColor.RED)); audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("usage", countryCode), NamedTextColor.RED));
return true; return true;
@@ -861,16 +1013,22 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
Set<String> worlds = playersWithDisplay.computeIfAbsent(player.getUniqueId(), k -> new HashSet<>()); Set<String> worlds = playersWithDisplay.computeIfAbsent(player.getUniqueId(), k -> new HashSet<>());
if (worlds.contains(worldName)) { if (worlds.contains(worldName)) {
worlds.remove(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 { } else {
worlds.add(worldName); 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; return true;
} }
} }
// Modellklasse WorldConfig (nur als Speicher für die Welten-Settings)
private static class WorldConfig { private static class WorldConfig {
boolean enabled; boolean enabled;
String location; String location;

View File

@@ -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";
}
}
}

View File

@@ -1,5 +1,5 @@
name: RealTimeWeather name: RealTimeWeather
version: 1.3 version: 1.4
main: dev.viper.weathertime.WeatherTimeSyncPlugin main: dev.viper.weathertime.WeatherTimeSyncPlugin
api-version: 1.21 api-version: 1.21