Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
7ae5eea24a | |||
ac318f4f78 | |||
fe3e1c1534 | |||
c7416baed5 | |||
98cad69efc | |||
64c994bc8b | |||
a1e29bc89e | |||
ede9d372f0 | |||
7761b5a1be | |||
032ada193a |
205
README.md
205
README.md
@@ -1,141 +1,108 @@
|
|||||||
# RealTimeWeather
|
# RealTimeWeather
|
||||||
|
|
||||||
Ein Minecraft-Plugin, das Echtzeit-Wetter und -Zeit in deine Welten bringt! **RealTimeWeather** synchronisiert das In-Game-Wetter und die Tageszeit mit Daten von OpenWeatherMap und bietet eine benutzerfreundliche GUI, Wettervorhersagen und anpassbare Anzeigeoptionen. Entwickelt für Minecraft 1.21.1.
|
**RealTimeWeather** ist ein Bukkit/Spigot/Paper-Plugin, das echte Wetter- und Zeitdaten aus der realen Welt in deine Minecraft-Welt synchronisiert und live auf der Actionbar anzeigt – inklusive Temperatur, Wettericon, Luftfeuchtigkeit, Windstärke und Sonnenauf-/untergang.
|
||||||
|
|
||||||
## Funktionen
|
## ⭐ Features
|
||||||
|
|
||||||
- **Echtzeit-Wetter**: Synchronisiert Regen, Gewitter oder klares Wetter mit realen Wetterdaten eines konfigurierbaren Orts.
|
- Echte Wetter- und Uhrzeit-Synchronisation pro Welt
|
||||||
- **Echtzeit-Zeit**: Passt die Minecraft-Tageszeit an die aktuelle Uhrzeit an (deaktiviert den Tageszyklus).
|
- Anzeige auf der Actionbar:
|
||||||
- **Actionbar-Anzeige**: Zeigt Datum, Uhrzeit, Wetter-Symbol (z. B. 🌧️) und Temperatur in der Actionbar an, mit Optionen für Position (oben links/rechts) und Symbolanzeige.
|
Datum, Uhrzeit, Wetter-Icon, Temperatur, Luftfeuchtigkeit 💧, Windgeschwindigkeit 🌬️, Sonnenaufgang 🌅 & Sonnenuntergang 🌇
|
||||||
- **Wettervorhersage**: 5-Tage-Wettervorhersage über den Befehl `/weatherforecast`.
|
- Eigene Location pro Spieler möglich (GUI & Befehl)
|
||||||
- **GUI**: Intuitive Benutzeroberfläche zum Festlegen von Orten, Umschalten der Anzeige und Abrufen von Informationen.
|
- Ingame-Vorhersage (5 Tage) als Command
|
||||||
- **Mehrsprachenunterstützung**: Unterstützt Deutsch (`de`) und Englisch (`en`) über `lang.yml`, mit einfacher Erweiterung für weitere Sprachen.
|
- Wetterumschaltung auf Server synchron mit echten Wetterdaten (optional)
|
||||||
- **Weltspezifische Konfiguration**: Unterschiedliche Einstellungen für jede Welt in `config.yml`.
|
- Volle Mehrsprachigkeit über lang.yml
|
||||||
- **Spielerindividuelle Orte**: Spieler können ihren eigenen Ort mit `/wetter setlocation` festlegen.
|
- Kompatibel mit Minecraft 1.19.x – 1.21.x
|
||||||
- **Berechtigungen**: Admin-Befehle sind durch Berechtigungen geschützt.
|
|
||||||
|
|
||||||
## Installation
|
## 🔧 Installation
|
||||||
|
|
||||||
1. **Download**: Lade die `RealTimeWeather.jar` aus den [Releases](https://github.com/M_Viper/RealTimeWeather/releases) herunter.
|
1. **Kopiere die Dateien:**<br>
|
||||||
2. **Plugin-Ordner**: Kopiere die JAR-Datei in den `plugins`-Ordner deines Minecraft-Servers.
|
Die JAR nach `/plugins/` kopieren, Server neu starten.
|
||||||
3. **API-Schlüssel**: Registriere dich bei [OpenWeatherMap](https://openweathermap.org/) für einen kostenlosen API-Schlüssel.
|
2. **OpenWeatherMap API-Key** im `/plugins/RealTimeWeather/config.yml` eintragen:
|
||||||
4. **Konfiguration**: Bearbeite die `config.yml` im Ordner `plugins/RealTimeWeather/` und füge deinen API-Schlüssel ein.
|
|
||||||
5. **Server starten**: Starte deinen Server, um das Plugin zu laden. Die `lang.yml` wird automatisch generiert.
|
|
||||||
|
|
||||||
## Konfiguration
|
api-key: "DEIN_OPENWEATHERMAP_API_KEY"
|
||||||
|
|
||||||
Die Konfigurationsdateien befinden sich im Ordner `plugins/RealTimeWeather/`.
|
Registriere gratis unter https://openweathermap.org.
|
||||||
|
|
||||||
### config.yml
|
3. **Plugin starten/neu laden:**<br>
|
||||||
|
`reload` Befehl (`/wetter reload`) oder Server-Neustart.
|
||||||
|
|
||||||
|
## ⚙️ Kurzes Setup
|
||||||
|
|
||||||
|
- Die wichtigsten Einstellungen sind in der `config.yml` dokumentiert (siehe unten).
|
||||||
|
- Du kannst für jede Welt eigene Locations, Anzeige-Modi oder Wettertypen setzen.
|
||||||
|
|
||||||
|
## 🕹️ Kommandos
|
||||||
|
|
||||||
|
| Befehl | Beschreibung |
|
||||||
|
|-----------------------|-----------------------------------------------|
|
||||||
|
| `/wetter help` | Alle Befehle und Kurzinfos anzeigen |
|
||||||
|
| `/wetter reload` | Konfiguration und Sprache neu laden |
|
||||||
|
| `/wetter setlocation <city,country>` | Eigene Stadt für Anzeige wählen |
|
||||||
|
| `/wetter query` | Zeigt das aktuelle Wetter für dich an |
|
||||||
|
| `/wetter info` | Infos zum Plugin |
|
||||||
|
| `/wetter gui` | Öffnet das GUI mit Schnell-Optionen |
|
||||||
|
| `/weatherforecast` | 5-Tage-Wetterprognose deiner Location |
|
||||||
|
| `/toggleweather` | Actionbar-Wetteranzeige für Welt (de)aktivieren |
|
||||||
|
|
||||||
|
## 📊 Live-Anzeige (Actionbar)
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
08.08.2025 18:31 ☁️ 21.7°C | 💧 68% | 🌬️ 2.5 m/s | 🌅 05:48 | 🌇 21:34
|
||||||
|
|
||||||
|
```yml
|
||||||
|
## 📝 Beispiel-config.yml
|
||||||
|
|
||||||
```yaml
|
|
||||||
api-key: "DEIN_API_KEY_HIER"
|
api-key: "DEIN_API_KEY_HIER"
|
||||||
update-interval: 60 # Sekunden
|
update-interval: 60
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
enabled: true # Plugin für Welten ohne spezifische Konfiguration aktivieren
|
enabled: true
|
||||||
location: "Berlin,de" # Stadt,Ländercode
|
location: "Berlin,de"
|
||||||
units: "metric" # metric = Celsius, imperial = Fahrenheit
|
units: "metric"
|
||||||
time-format: "24h" # "24h" oder "12h"
|
time-format: "24h"
|
||||||
display-actionbar: true
|
display-actionbar: true
|
||||||
display-weather-icon: true
|
display-weather-icon: true
|
||||||
display-position: "top-right" # top-left oder top-right
|
|
||||||
padding-right: 100 # Anzahl der Leerzeichen für top-right
|
display-position / padding-right werden zentriert ignoriert
|
||||||
|
display-position: "top-right"
|
||||||
|
padding-right: 100
|
||||||
|
sync-in-game-weather: true
|
||||||
|
|
||||||
worlds:
|
worlds:
|
||||||
world:
|
world:
|
||||||
enabled: true
|
enabled: true
|
||||||
location: "London,uk"
|
location: "Berlin,de"
|
||||||
units: "imperial"
|
units: "metric"
|
||||||
time-format: "12h"
|
time-format: "24h"
|
||||||
display-actionbar: true
|
display-actionbar: true
|
||||||
display-weather-icon: true
|
display-weather-icon: true
|
||||||
display-position: "top-left"
|
display-position: "top-left"
|
||||||
padding-right: 50
|
padding-right: 50
|
||||||
world_nether:
|
sync-in-game-weather: true
|
||||||
enabled: false
|
world_nether:
|
||||||
location: "Tokyo,jp"
|
enabled: false
|
||||||
units: "metric"
|
location: "Berlin,de"
|
||||||
time-format: "24h"
|
units: "metric"
|
||||||
display-actionbar: true
|
time-format: "24h"
|
||||||
display-weather-icon: false
|
display-actionbar: true
|
||||||
display-position: "top-right"
|
display-weather-icon: false
|
||||||
padding-right: 150
|
display-position: "top-right"
|
||||||
|
padding-right: 150
|
||||||
|
sync-in-game-weather: false
|
||||||
```
|
```
|
||||||
|
|
||||||
# RealTimeWeather
|
|
||||||
|
|
||||||
Ein Minecraft-Plugin, das Echtzeit-Wetter und -Zeit in deine Welten bringt. Synchronisiert Wetter und Tageszeit mit OpenWeatherMap-Daten. Entwickelt für Minecraft 1.21.1 - 1.21.8.
|
## 🧑💻 Erweiterungen
|
||||||
|
|
||||||
## Konfiguration
|
- Anzeige von Feuchtigkeit, Wind & Sonnenzeiten kann leicht deaktiviert/angepasst werden (siehe Actionbar-Code).
|
||||||
|
- Ländercodes und Städte werden in OpenWeatherMap-Syntax verwendet, z. B. `London,gb`, `Frankfurt,de`.
|
||||||
|
|
||||||
|
## ❤️ Lizenz
|
||||||
|
|
||||||
### lang.yml
|
[MIT License](LICENSE)
|
||||||
|
|
||||||
Enthält Übersetzungen für Deutsch (`de`) und Englisch (`en`). Beispiel für Deutsch:
|
---
|
||||||
|
|
||||||
```yaml
|
> Fragen, Feature-Wünsche oder Bugreports gerne als Gitea-Issue!
|
||||||
languages:
|
|
||||||
de:
|
|
||||||
help_header: "RealTimeWeather-Befehle"
|
|
||||||
help_help: "Diese Hilfenachricht anzeigen"
|
|
||||||
help_reload: "Die Plugin-Konfiguration neu laden (Berechtigung: realtimeweather.reload)"
|
|
||||||
help_setlocation: "Eigenen Wetterort für den Spieler festlegen (z.B. Berlin,de)"
|
|
||||||
help_query: "Aktuelles Wetter für den Spielerort oder die Welt anzeigen"
|
|
||||||
help_info: "Plugin-Informationen anzeigen"
|
|
||||||
help_gui: "GUI für Wettersteuerung öffnen"
|
|
||||||
help_weatherforecast: "Wettervorhersage für 5 Tage anzeigen"
|
|
||||||
help_toggleweather: "Wetteranzeige in der Actionbar ein-/ausschalten"
|
|
||||||
usage: "Verwendung: /wetter reload | setlocation <Ort> | query | info | gui | help"
|
|
||||||
usage_setlocation: "Verwendung: /wetter setlocation <Stadt,Land>"
|
|
||||||
no_permission: "Du hast keine Berechtigung für diesen Befehl!"
|
|
||||||
reload_success: "Konfiguration erfolgreich neu geladen!"
|
|
||||||
only_players: "Dieser Befehl ist nur für Spieler!"
|
|
||||||
plugin_disabled: "Plugin ist für die Welt {world} deaktiviert!"
|
|
||||||
location_set: "Ort auf {location} gesetzt!"
|
|
||||||
invalid_location: "Ungültiger Ort: {location}"
|
|
||||||
forecast_error: "Fehler beim Abrufen der Wetterdaten für {location}: {error}"
|
|
||||||
gui_title: "Wettersteuerung"
|
|
||||||
gui_setlocation: "Ort festlegen"
|
|
||||||
gui_setlocation_lore: "Eigenen Wetterort festlegen"
|
|
||||||
gui_toggleweather: "Wetteranzeige umschalten"
|
|
||||||
gui_toggleweather_lore: "Wetter-Actionbar ein-/ausschalten"
|
|
||||||
gui_forecast: "Wettervorhersage"
|
|
||||||
gui_forecast_lore: "5-Tage-Wettervorhersage anzeigen"
|
|
||||||
gui_info: "Info"
|
|
||||||
gui_info_lore: "Plugin-Informationen anzeigen"
|
|
||||||
gui_setlocation_prompt: "Gib den Ort ein (z.B. Berlin,de)"
|
|
||||||
toggle_enabled: "Wetteranzeige für {world} aktiviert!"
|
|
||||||
toggle_disabled: "Wetteranzeige für {world} deaktiviert!"
|
|
||||||
forecast_header: "Wettervorhersage für {location}"
|
|
||||||
weather:
|
|
||||||
clear: "Klar"
|
|
||||||
clouds: "Bewölkt"
|
|
||||||
rain: "Regen"
|
|
||||||
thunderstorm: "Gewitter"
|
|
||||||
snow: "Schnee"
|
|
||||||
mist: "Nebel"
|
|
||||||
fog: "Nebel"
|
|
||||||
haze: "Dunst"
|
|
||||||
en:
|
|
||||||
# Ähnliche Schlüssel wie oben, auf Englisch
|
|
||||||
```
|
|
||||||
|
|
||||||
# RealTimeWeather
|
|
||||||
|
|
||||||
Ein Minecraft-Plugin, das Echtzeit-Wetter und -Zeit in deine Welten bringt. Entwickelt für Minecraft 1.21.1.
|
|
||||||
|
|
||||||
## Befehle
|
|
||||||
|
|
||||||
- `/wetter help`: Zeigt die Hilfeübersicht an.
|
|
||||||
- `/wetter reload`: Lädt die Konfiguration neu (Berechtigung: `realtimeweather.reload`).
|
|
||||||
- `/wetter setlocation <city,country>`: Legt einen individuellen Ort für den Spieler fest.
|
|
||||||
- `/wetter query`: Zeigt aktuelles Wetter für den Spielerort oder die Welt.
|
|
||||||
- `/wetter info`: Zeigt Plugin-Informationen an.
|
|
||||||
- `/wetter gui`: Öffnet die Wetter-GUI.
|
|
||||||
- `/weatherforecast`: Zeigt die 5-Tage-Wettervorhersage.
|
|
||||||
- `/toggleweather`: Schaltet die Wetteranzeige in der Actionbar ein/aus.
|
|
||||||
|
|
||||||
## Berechtigungen
|
|
||||||
|
|
||||||
- `realtimeweather.reload`: Erlaubt `/wetter reload`.
|
|
||||||
- `realtimeweather.admin`: Erlaubt Admin-Benachrichtigungen bei Wetterabfrage-Fehlern.
|
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package dev.viper.weathertime;
|
package dev.viper.weathertime;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONArray;
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
@@ -11,6 +11,11 @@ import java.time.ZoneId;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holt Wetter und Zeitdaten asynchron von OpenWeatherMap.
|
||||||
|
* Liefert WeatherTimeData zurück, mit konsistentem Modell und Fehlerhandling.
|
||||||
|
* Erweiterung: Erfasst Luftfeuchtigkeit, Windgeschwindigkeit, Sonnenauf- und -untergang.
|
||||||
|
*/
|
||||||
public class WeatherFetcher {
|
public class WeatherFetcher {
|
||||||
|
|
||||||
private final String apiKey;
|
private final String apiKey;
|
||||||
@@ -19,54 +24,51 @@ public class WeatherFetcher {
|
|||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
|
||||||
public WeatherFetcher(String apiKey, String location, String units, Logger logger) {
|
public WeatherFetcher(String apiKey, String location, String units, Logger logger) {
|
||||||
this.apiKey = apiKey;
|
this.apiKey = apiKey == null ? "" : apiKey.trim();
|
||||||
this.location = location;
|
this.location = location == null ? "Berlin,de" : location.trim();
|
||||||
this.units = units.toLowerCase();
|
this.units = units == null ? "metric" : units.trim().toLowerCase();
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
if (!this.units.equals("metric") && !this.units.equals("imperial")) {
|
if (!this.units.equals("metric") && !this.units.equals("imperial")) {
|
||||||
logger.warning("Ungültige Einheit für " + location + ": " + units + ". Verwende 'metric' als Fallback.");
|
logger.warning("Ungültige Einheit für " + this.location + ": " + this.units + ". Verwende 'metric' als Fallback.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public WeatherData fetch() throws Exception {
|
/**
|
||||||
String effectiveUnits = units.equals("metric") || units.equals("imperial") ? units : "metric";
|
* Holt die aktuellen Wetter- und Zeitdaten inklusive Zusatzinfos.
|
||||||
|
* Wirft RuntimeExceptions mit klaren Messages bei Fehlern.
|
||||||
|
*/
|
||||||
|
public WeatherTimeData fetchAsWeatherTimeData() throws Exception {
|
||||||
|
if (apiKey.isEmpty()) throw new RuntimeException("API-Key fehlt.");
|
||||||
|
String effectiveUnits = (units.equals("metric") || units.equals("imperial")) ? units : "metric";
|
||||||
String urlString = String.format(
|
String urlString = String.format(
|
||||||
"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);
|
||||||
|
|
||||||
URL url = new URL(urlString);
|
try {
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
JSONObject json;
|
||||||
connection.setRequestMethod("GET");
|
try (BufferedReader in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString)))) {
|
||||||
connection.setConnectTimeout(5000);
|
|
||||||
connection.setReadTimeout(5000);
|
|
||||||
|
|
||||||
int status = connection.getResponseCode();
|
|
||||||
if (status != 200) {
|
|
||||||
logger.warning("HTTP-Fehlercode: " + status + " für Ort: " + location);
|
|
||||||
throw new RuntimeException("HTTP-Fehlercode: " + status + " für Ort: " + location);
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
in.close();
|
json = new JSONObject(content.toString());
|
||||||
connection.disconnect();
|
|
||||||
|
|
||||||
JSONObject json = new JSONObject(content.toString());
|
|
||||||
long dt = json.getLong("dt");
|
|
||||||
int timezoneShift;
|
|
||||||
try {
|
|
||||||
timezoneShift = json.getInt("timezone");
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.warning("Fehler beim Abrufen der Zeitzone für Ort: " + location + ": " + e.getMessage());
|
|
||||||
throw new RuntimeException("Fehler beim Abrufen der Zeitzone für Ort: " + location, e);
|
|
||||||
}
|
}
|
||||||
ZonedDateTime dateTime = Instant.ofEpochSecond(dt).atZone(ZoneId.of("UTC")).plusSeconds(timezoneShift);
|
|
||||||
|
// Fehlerfall: Antwort-Code ungleich 200
|
||||||
|
if (json.has("cod") && json.getInt("cod") != 200) {
|
||||||
|
String msg = json.has("message") ? json.getString("message") : "Unbekannter Fehler";
|
||||||
|
logger.warning("API Error für " + location + ": " + msg);
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
long dt = json.getLong("dt");
|
||||||
|
int timezoneShift = json.optInt("timezone", 0); // Zeitzonen-Offset in Sekunden
|
||||||
|
|
||||||
|
ZonedDateTime dateTime = Instant.ofEpochSecond(dt)
|
||||||
|
.atZone(ZoneId.of("UTC"))
|
||||||
|
.plusSeconds(timezoneShift);
|
||||||
|
|
||||||
String weatherMain = json.getJSONArray("weather").getJSONObject(0).getString("main");
|
String weatherMain = json.getJSONArray("weather").getJSONObject(0).getString("main");
|
||||||
double temperature = json.getJSONObject("main").getDouble("temp");
|
double temperature = json.getJSONObject("main").getDouble("temp");
|
||||||
|
|
||||||
@@ -76,48 +78,81 @@ public class WeatherFetcher {
|
|||||||
logger.warning("Unrealistische Temperatur für " + location + ": " + temperature + "°C. API-Fehler?");
|
logger.warning("Unrealistische Temperatur für " + location + ": " + temperature + "°C. API-Fehler?");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new WeatherData(dateTime, weatherMain, temperature);
|
// Temperatur immer in Celsius für WeatherTimeData speichern
|
||||||
|
double tempCelsius = effectiveUnits.equals("imperial") ? (temperature - 32) * 5 / 9 : temperature;
|
||||||
|
|
||||||
|
// NEUE FELDER AUSLESEN
|
||||||
|
int humidity = json.getJSONObject("main").getInt("humidity");
|
||||||
|
double windSpeed = json.getJSONObject("wind").optDouble("speed", 0.0);
|
||||||
|
|
||||||
|
ZonedDateTime sunrise = Instant.ofEpochSecond(json.getJSONObject("sys").getLong("sunrise"))
|
||||||
|
.atZone(ZoneId.of("UTC"))
|
||||||
|
.plusSeconds(timezoneShift);
|
||||||
|
|
||||||
|
ZonedDateTime sunset = Instant.ofEpochSecond(json.getJSONObject("sys").getLong("sunset"))
|
||||||
|
.atZone(ZoneId.of("UTC"))
|
||||||
|
.plusSeconds(timezoneShift);
|
||||||
|
|
||||||
|
return new WeatherTimeData(dateTime, weatherMain, tempCelsius,
|
||||||
|
humidity, windSpeed, sunrise, sunset);
|
||||||
|
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holt das Wetter-Vorhersage-JSON (5 Tage, 3-Stunden-Takt).
|
||||||
|
* Muss im Command asynchron ausgewertet werden!
|
||||||
|
*/
|
||||||
public JSONObject fetchForecast() throws Exception {
|
public JSONObject fetchForecast() throws Exception {
|
||||||
String effectiveUnits = units.equals("metric") || units.equals("imperial") ? units : "metric";
|
if (apiKey.isEmpty()) throw new RuntimeException("API-Key fehlt.");
|
||||||
|
String effectiveUnits = (units.equals("metric") || units.equals("imperial")) ? units : "metric";
|
||||||
String urlString = String.format(
|
String urlString = String.format(
|
||||||
"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);
|
||||||
URL url = new URL(urlString);
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
||||||
connection.setRequestMethod("GET");
|
|
||||||
connection.setConnectTimeout(5000);
|
|
||||||
connection.setReadTimeout(5000);
|
|
||||||
|
|
||||||
int status = connection.getResponseCode();
|
try (BufferedReader in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString)))) {
|
||||||
if (status != 200) {
|
|
||||||
logger.warning("HTTP-Fehlercode: " + status + " für Ort: " + location);
|
|
||||||
throw new RuntimeException("HTTP-Fehlercode: " + status + " für Ort: " + location);
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
in.close();
|
JSONObject json = new JSONObject(content.toString());
|
||||||
connection.disconnect();
|
if (json.has("cod") && (!"200".equals(json.get("cod").toString()))) {
|
||||||
|
String msg = json.has("message") ? json.getString("message") : "Unbekannter Fehler";
|
||||||
return new JSONObject(content.toString());
|
logger.warning("API Error (Forecast) für " + location + ": " + msg);
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warning("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage());
|
||||||
|
throw new RuntimeException("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WeatherData {
|
/** Öffnet eine HTTP-GET-Verbindung und liefert den InputStream der Response zurück (Timeouts gesetzt). */
|
||||||
ZonedDateTime dateTime;
|
private java.io.InputStream openConnectionStream(String urlString) throws Exception {
|
||||||
String weatherMain;
|
URL url = new URL(urlString);
|
||||||
double temperature;
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setConnectTimeout(6000);
|
||||||
|
connection.setReadTimeout(6000);
|
||||||
|
|
||||||
public WeatherData(ZonedDateTime dateTime, String weatherMain, double temperature) {
|
int status = connection.getResponseCode();
|
||||||
this.dateTime = dateTime;
|
if (status != 200) {
|
||||||
this.weatherMain = weatherMain;
|
String err = "(keine Fehlerdetails)";
|
||||||
this.temperature = temperature;
|
try (BufferedReader 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) {}
|
||||||
|
throw new RuntimeException("HTTP-Fehlercode: " + status + " – " + err);
|
||||||
}
|
}
|
||||||
|
return connection.getInputStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,57 +1,87 @@
|
|||||||
package dev.viper.weathertime;
|
package dev.viper.weathertime;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.ZoneOffset;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zentrale Datenklasse für Wetter- und Zeitinformationen.
|
||||||
|
* Erweiterung: enthält jetzt auch Luftfeuchtigkeit, Windgeschwindigkeit und Sonnenauf/untergang.
|
||||||
|
*/
|
||||||
public class WeatherTimeData {
|
public class WeatherTimeData {
|
||||||
private final boolean rain;
|
|
||||||
private final boolean thunder;
|
|
||||||
private final long unixTime;
|
|
||||||
private final double tempCelsius;
|
|
||||||
|
|
||||||
public WeatherTimeData(boolean rain, boolean thunder, long unixTime, double tempCelsius) {
|
private final ZonedDateTime dateTime; // Lokale Zeit am Standort
|
||||||
this.rain = rain;
|
private final String weatherMain; // Hauptwetterbeschreibung (z. B. "Clear", "Rain")
|
||||||
this.thunder = thunder;
|
private final double tempCelsius; // Temperatur in °C
|
||||||
this.unixTime = unixTime;
|
|
||||||
|
private final int humidity; // Luftfeuchtigkeit in %
|
||||||
|
private final double windSpeed; // Windgeschwindigkeit (m/s oder mph)
|
||||||
|
private final ZonedDateTime sunrise; // Sonnenaufgang
|
||||||
|
private final ZonedDateTime sunset; // Sonnenuntergang
|
||||||
|
|
||||||
|
public WeatherTimeData(
|
||||||
|
ZonedDateTime dateTime,
|
||||||
|
String weatherMain,
|
||||||
|
double tempCelsius,
|
||||||
|
int humidity,
|
||||||
|
double windSpeed,
|
||||||
|
ZonedDateTime sunrise,
|
||||||
|
ZonedDateTime sunset) {
|
||||||
|
this.dateTime = dateTime;
|
||||||
|
this.weatherMain = weatherMain;
|
||||||
this.tempCelsius = tempCelsius;
|
this.tempCelsius = tempCelsius;
|
||||||
|
this.humidity = humidity;
|
||||||
|
this.windSpeed = windSpeed;
|
||||||
|
this.sunrise = sunrise;
|
||||||
|
this.sunset = sunset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRain() {
|
public ZonedDateTime getDateTime() {
|
||||||
return rain;
|
return dateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isThunder() {
|
public String getWeatherMain() {
|
||||||
return thunder;
|
return weatherMain;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getTemp(String unit) {
|
public double getTemp(String unit) {
|
||||||
return unit.equalsIgnoreCase("F") ? (tempCelsius * 9 / 5) + 32 : tempCelsius;
|
return "F".equalsIgnoreCase(unit)
|
||||||
|
? (tempCelsius * 9 / 5) + 32
|
||||||
|
: tempCelsius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHumidity() {
|
||||||
|
return humidity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getWindSpeed() {
|
||||||
|
return windSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZonedDateTime getSunrise() {
|
||||||
|
return sunrise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZonedDateTime getSunset() {
|
||||||
|
return sunset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFormattedTime(String format) {
|
public String getFormattedTime(String format) {
|
||||||
LocalTime time = Instant.ofEpochSecond(unixTime)
|
int hour = dateTime.getHour();
|
||||||
.atOffset(ZoneOffset.UTC)
|
int minute = dateTime.getMinute();
|
||||||
.toLocalTime();
|
|
||||||
|
|
||||||
if ("12h".equalsIgnoreCase(format)) {
|
if ("12h".equalsIgnoreCase(format)) {
|
||||||
int hour = time.getHour();
|
|
||||||
String ampm = hour >= 12 ? "PM" : "AM";
|
String ampm = hour >= 12 ? "PM" : "AM";
|
||||||
hour = hour % 12;
|
hour = hour % 12;
|
||||||
if (hour == 0) hour = 12;
|
if (hour == 0) hour = 12;
|
||||||
return String.format("%02d:%02d %s", hour, time.getMinute(), ampm);
|
return String.format("%02d:%02d %s", hour, minute, ampm);
|
||||||
} else {
|
|
||||||
return String.format("%02d:%02d", time.getHour(), time.getMinute());
|
|
||||||
}
|
}
|
||||||
|
return String.format("%02d:%02d", hour, minute);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long toMinecraftTime() {
|
public long toMinecraftTime() {
|
||||||
LocalTime time = Instant.ofEpochSecond(unixTime)
|
int hour = dateTime.getHour();
|
||||||
.atOffset(ZoneOffset.UTC)
|
int minute = dateTime.getMinute();
|
||||||
.toLocalTime();
|
int second = dateTime.getSecond();
|
||||||
|
return ((hour + 18) % 24) * 1000L
|
||||||
int hour = time.getHour();
|
+ (minute * 1000L / 60)
|
||||||
int minute = time.getMinute();
|
+ (second * 1000L / 3600);
|
||||||
return (hour * 1000L / 24) + (minute * 1000L / (24 * 60));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,9 +7,7 @@ import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.*;
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
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.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -32,67 +30,56 @@ import java.time.Instant;
|
|||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
private String apiKey;
|
private String apiKey;
|
||||||
private int updateInterval;
|
private int updateInterval;
|
||||||
private final HashMap<String, WorldConfig> worldConfigs = new HashMap<>();
|
private final Map<String, WorldConfig> worldConfigs = new HashMap<>();
|
||||||
private final HashMap<String, WeatherData> worldWeatherData = new HashMap<>();
|
private final Map<String, WeatherTimeData> worldWeatherData = new HashMap<>();
|
||||||
private final HashMap<UUID, HashSet<String>> playersWithDisplay = new HashMap<>();
|
private final Map<UUID, Set<String>> playersWithDisplay = new HashMap<>();
|
||||||
private final HashMap<UUID, String> playerLocations = new HashMap<>();
|
private final Map<UUID, String> playerLocations = new HashMap<>();
|
||||||
private final HashMap<UUID, Inventory> playerGUIs = new HashMap<>();
|
private final Map<UUID, Inventory> playerGUIs = new HashMap<>();
|
||||||
private BukkitAudiences audiences;
|
private BukkitAudiences audiences;
|
||||||
private BukkitRunnable weatherUpdateTask;
|
private BukkitRunnable weatherUpdateTask;
|
||||||
private BukkitRunnable syncTask;
|
private BukkitRunnable syncTask;
|
||||||
private final HashSet<String> processedLocations = new HashSet<>();
|
private final Set<String> processedLocations = new HashSet<>();
|
||||||
private FileConfiguration langConfig;
|
private FileConfiguration langConfig;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
saveDefaultConfig();
|
saveDefaultConfig();
|
||||||
loadLanguageConfig(); // Zuerst laden, um sicherzustellen, dass Übersetzungen verfügbar sind
|
loadLanguageConfig();
|
||||||
loadConfig();
|
loadConfig();
|
||||||
this.audiences = BukkitAudiences.create(this);
|
audiences = BukkitAudiences.create(this);
|
||||||
|
|
||||||
getCommand("wetter").setExecutor(new WetterCommand());
|
Objects.requireNonNull(getCommand("wetter")).setExecutor(new WetterCommand());
|
||||||
getCommand("weatherforecast").setExecutor(new WeatherForecastCommand());
|
Objects.requireNonNull(getCommand("weatherforecast")).setExecutor(new WeatherForecastCommand());
|
||||||
getCommand("toggleweather").setExecutor(new ToggleWeatherCommand());
|
Objects.requireNonNull(getCommand("toggleweather")).setExecutor(new ToggleWeatherCommand());
|
||||||
|
|
||||||
getServer().getPluginManager().registerEvents(this, this);
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
|
|
||||||
setDoDaylightCycleForWorlds();
|
setDoDaylightCycleForWorlds();
|
||||||
startWeatherUpdateTask();
|
startWeatherUpdateTask();
|
||||||
startSyncTask();
|
startSyncTask();
|
||||||
|
|
||||||
initializePlayerDisplays();
|
initializePlayerDisplays();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
if (weatherUpdateTask != null) {
|
if (weatherUpdateTask != null) weatherUpdateTask.cancel();
|
||||||
weatherUpdateTask.cancel();
|
if (syncTask != null) syncTask.cancel();
|
||||||
}
|
if (audiences != null) audiences.close();
|
||||||
if (syncTask != null) {
|
|
||||||
syncTask.cancel();
|
|
||||||
}
|
|
||||||
if (audiences != null) {
|
|
||||||
audiences.close();
|
|
||||||
}
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
if (playerGUIs.containsKey(player.getUniqueId())) {
|
if (playerGUIs.containsKey(player.getUniqueId())) player.closeInventory();
|
||||||
player.closeInventory();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============== Config & Sprache ===============
|
||||||
private void loadConfig() {
|
private void loadConfig() {
|
||||||
FileConfiguration cfg = getConfig();
|
FileConfiguration cfg = getConfig();
|
||||||
apiKey = cfg.getString("api-key");
|
apiKey = cfg.getString("api-key", "").trim();
|
||||||
updateInterval = cfg.getInt("update-interval", 60);
|
updateInterval = cfg.getInt("update-interval", 60);
|
||||||
worldConfigs.clear();
|
worldConfigs.clear();
|
||||||
|
|
||||||
@@ -125,8 +112,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
worldConfigs.put(worldName, worldConfig);
|
worldConfigs.put(worldName, worldConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (apiKey.isEmpty()) {
|
||||||
if (apiKey == null || apiKey.trim().isEmpty()) {
|
|
||||||
getLogger().severe("API-Key ist nicht gesetzt! Bitte in config.yml eintragen.");
|
getLogger().severe("API-Key ist nicht gesetzt! Bitte in config.yml eintragen.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,48 +123,34 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
||||||
if (!langFile.exists()) {
|
if (!langFile.exists()) {
|
||||||
saveResource("lang.yml", false);
|
saveResource("lang.yml", false);
|
||||||
getLogger().info("lang.yml wurde aus den Ressourcen kopiert.");
|
|
||||||
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
||||||
} else if (langConfig.getConfigurationSection("languages") == null) {
|
} else if (langConfig.getConfigurationSection("languages") == null) {
|
||||||
getLogger().warning("lang.yml enthält keinen 'languages'-Abschnitt. Standardwerte werden verwendet.");
|
saveResource("lang.yml", true);
|
||||||
saveResource("lang.yml", true); // Überschreibe mit Standardwerten
|
|
||||||
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
||||||
}
|
}
|
||||||
// Debugging: Verfügbare Sprachen protokollieren
|
|
||||||
getLogger().info("Verfügbare Sprachen in lang.yml: " + langConfig.getConfigurationSection("languages").getKeys(false));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
getLogger().severe("Fehler beim Laden von lang.yml: " + e.getMessage());
|
saveResource("lang.yml", true);
|
||||||
saveResource("lang.yml", true); // Überschreibe bei Fehler mit Standardwerten
|
|
||||||
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
||||||
getLogger().info("lang.yml wurde nach Fehler mit Standardwerten überschrieben.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (config.enabled) world.setGameRuleValue("doDaylightCycle", "false");
|
||||||
world.setGameRuleValue("doDaylightCycle", "false");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLocalizedMessage(String key, String countryCode, String... placeholders) {
|
private void initializePlayerDisplays() {
|
||||||
String path = "languages." + (countryCode.isEmpty() ? "en" : countryCode.toLowerCase()) + "." + key;
|
playersWithDisplay.clear();
|
||||||
String message = langConfig.getString(path);
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
if (message == null) {
|
Set<String> worlds = new HashSet<>();
|
||||||
path = "languages.en." + key;
|
for (World world : Bukkit.getWorlds()) {
|
||||||
message = langConfig.getString(path);
|
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
|
||||||
if (message == null) {
|
if (config.enabled && config.displayActionbar) worlds.add(world.getName());
|
||||||
// Nur Warnung für fehlende Übersetzungen, keine Debugging-Info für jede Suche
|
|
||||||
getLogger().warning("Übersetzung für Schlüssel '" + key + "' in Sprache '" + countryCode + "' und Fallback 'en' nicht gefunden!");
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
playersWithDisplay.put(player.getUniqueId(), worlds);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < placeholders.length - 1; i += 2) {
|
|
||||||
message = message.replace("{" + placeholders[i] + "}", placeholders[i + 1]);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startWeatherUpdateTask() {
|
private void startWeatherUpdateTask() {
|
||||||
@@ -199,9 +171,9 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
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) continue;
|
if (!config.enabled) continue;
|
||||||
WeatherData data = worldWeatherData.get(world.getName());
|
WeatherTimeData data = worldWeatherData.get(world.getName());
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
syncMinecraftTime(world, data.dateTime);
|
syncMinecraftTime(world, data.getDateTime());
|
||||||
updateActionbarForWorld(world, data);
|
updateActionbarForWorld(world, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +193,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
for (String otherWorld : worldWeatherData.keySet()) {
|
for (String otherWorld : worldWeatherData.keySet()) {
|
||||||
WorldConfig otherConfig = worldConfigs.getOrDefault(otherWorld, worldConfigs.get("defaults"));
|
WorldConfig otherConfig = worldConfigs.getOrDefault(otherWorld, worldConfigs.get("defaults"));
|
||||||
if (otherConfig.location.equals(config.location)) {
|
if (otherConfig.location.equals(config.location)) {
|
||||||
WeatherData existingData = worldWeatherData.get(otherWorld);
|
WeatherTimeData existingData = worldWeatherData.get(otherWorld);
|
||||||
if (existingData != null) {
|
if (existingData != null) {
|
||||||
worldWeatherData.put(world.getName(), existingData);
|
worldWeatherData.put(world.getName(), existingData);
|
||||||
break;
|
break;
|
||||||
@@ -232,73 +204,41 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
WeatherFetcher fetcher = new WeatherFetcher(apiKey, config.location, config.units, getLogger());
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, config.location, config.units, getLogger());
|
||||||
WeatherFetcher.WeatherData weatherData = fetcher.fetch();
|
WeatherTimeData weatherData = fetcher.fetchAsWeatherTimeData();
|
||||||
WeatherData newData = new WeatherData(
|
worldWeatherData.put(world.getName(), weatherData);
|
||||||
weatherData.dateTime,
|
|
||||||
weatherData.weatherMain,
|
|
||||||
weatherData.temperature
|
|
||||||
);
|
|
||||||
worldWeatherData.put(world.getName(), newData);
|
|
||||||
processedLocations.add(config.location);
|
processedLocations.add(config.location);
|
||||||
|
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
syncMinecraftTime(world, weatherData.dateTime);
|
syncMinecraftTime(world, weatherData.getDateTime());
|
||||||
if (config.syncInGameWeather) {
|
if (config.syncInGameWeather) {
|
||||||
int durationTicks = 20 * 60 * 5; // 5 Minuten
|
switch (weatherData.getWeatherMain().toLowerCase()) {
|
||||||
switch (weatherData.weatherMain.toLowerCase()) {
|
|
||||||
case "rain":
|
case "rain":
|
||||||
case "drizzle":
|
case "drizzle":
|
||||||
world.setStorm(true);
|
world.setStorm(true);
|
||||||
world.setThundering(false);
|
world.setThundering(false);
|
||||||
world.setWeatherDuration(durationTicks);
|
|
||||||
break;
|
break;
|
||||||
case "thunderstorm":
|
case "thunderstorm":
|
||||||
world.setStorm(true);
|
world.setStorm(true);
|
||||||
world.setThundering(true);
|
world.setThundering(true);
|
||||||
world.setWeatherDuration(durationTicks);
|
|
||||||
break;
|
break;
|
||||||
case "snow":
|
case "snow":
|
||||||
world.setStorm(true);
|
world.setStorm(true);
|
||||||
world.setThundering(false);
|
world.setThundering(false);
|
||||||
world.setWeatherDuration(durationTicks);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
world.setStorm(false);
|
world.setStorm(false);
|
||||||
world.setThundering(false);
|
world.setThundering(false);
|
||||||
world.setWeatherDuration(durationTicks);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.runTask(this);
|
}.runTask(this);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
getLogger().warning("Fehler beim Abrufen von Wetter/Zeit für Welt " + world.getName() + ": " + e.getMessage());
|
getLogger().warning("Fehler beim Abrufen von Wetter/Zeit für Welt " + world.getName() + ": " + e.getMessage());
|
||||||
String countryCode = getCountryCode(config.location);
|
|
||||||
String errorMsg = getLocalizedMessage("forecast_error", countryCode, "location", config.location, "error", e.getMessage());
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
||||||
if (player.hasPermission("realtimeweather.admin")) {
|
|
||||||
audiences.player(player).sendMessage(Component.text(errorMsg, NamedTextColor.RED));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializePlayerDisplays() {
|
|
||||||
playersWithDisplay.clear();
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
||||||
HashSet<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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void syncMinecraftTime(World world, ZonedDateTime dateTime) {
|
private void syncMinecraftTime(World world, ZonedDateTime dateTime) {
|
||||||
int hour = dateTime.getHour();
|
int hour = dateTime.getHour();
|
||||||
@@ -309,172 +249,80 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
world.setGameRuleValue("doDaylightCycle", "false");
|
world.setGameRuleValue("doDaylightCycle", "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateActionbarForWorld(World world, WeatherData data) {
|
// === Anzeige (Actionbar, jetzt mit Luftfeuchtigkeit, Wind, Sonne) ===
|
||||||
|
private void updateActionbarForWorld(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())) {
|
if (!playersWithDisplay.getOrDefault(player.getUniqueId(), new HashSet<>()).contains(world.getName()))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
WeatherData playerData = data;
|
WeatherTimeData playerData = data;
|
||||||
String location = playerLocations.getOrDefault(player.getUniqueId(), "");
|
String location = playerLocations.getOrDefault(player.getUniqueId(), "");
|
||||||
if (!location.isEmpty()) {
|
if (!location.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, config.units, getLogger());
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, config.units, getLogger());
|
||||||
WeatherFetcher.WeatherData fetched = fetcher.fetch();
|
playerData = fetcher.fetchAsWeatherTimeData();
|
||||||
playerData = new WeatherData(fetched.dateTime, fetched.weatherMain, fetched.temperature);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String countryCode = getCountryCode(config.location);
|
String countryCode = getCountryCode(config.location);
|
||||||
audiences.player(player).sendMessage(Component.text(
|
audiences.player(player).sendMessage(Component.text(
|
||||||
getLocalizedMessage("forecast_error", countryCode, "location", location, "error", e.getMessage()),
|
getLocalizedMessage("forecast_error", countryCode,
|
||||||
|
"location", location,
|
||||||
|
"error", e.getMessage()),
|
||||||
NamedTextColor.RED));
|
NamedTextColor.RED));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String dateStr = playerData.dateTime.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
|
String dateStr = playerData.getDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
|
||||||
String timeStr = formatTime(playerData.dateTime, 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.weatherMain) + " " : "";
|
String weatherIcon = config.displayWeatherIcon ? getWeatherSymbol(playerData.getWeatherMain()) + " " : "";
|
||||||
String tempStr = String.format("%.1f%s", playerData.temperature, tempUnit);
|
String tempStr = String.format("%.1f%s", playerData.getTemp(config.units.equalsIgnoreCase("metric") ? "C" : "F"), tempUnit);
|
||||||
|
|
||||||
|
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"));
|
||||||
|
|
||||||
Component message = Component.text()
|
Component message = Component.text()
|
||||||
.append(Component.text(dateStr + " ", NamedTextColor.AQUA, TextDecoration.BOLD))
|
.append(Component.text(dateStr + " ", NamedTextColor.AQUA, TextDecoration.BOLD))
|
||||||
.append(Component.text(timeStr + " ", NamedTextColor.YELLOW))
|
.append(Component.text("| " + timeStr + " ", NamedTextColor.YELLOW))
|
||||||
.append(Component.text(weatherIcon, NamedTextColor.WHITE))
|
.append(Component.text("| " + weatherIcon, NamedTextColor.WHITE))
|
||||||
.append(Component.text(tempStr, NamedTextColor.GREEN))
|
.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();
|
.build();
|
||||||
|
|
||||||
Component paddedMessage;
|
audiences.player(player).sendActionBar(message);
|
||||||
if ("top-right".equalsIgnoreCase(config.displayPosition)) {
|
|
||||||
paddedMessage = Component.text()
|
|
||||||
.append(Component.text(" ".repeat(config.paddingRight)))
|
|
||||||
.append(message)
|
|
||||||
.build();
|
|
||||||
} else {
|
|
||||||
paddedMessage = Component.text()
|
|
||||||
.append(message)
|
|
||||||
.append(Component.text(" ".repeat(20)))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
audiences.player(player).sendActionBar(paddedMessage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatTime(ZonedDateTime dateTime, String timeFormat) {
|
// === Events (z.B. Weltwechsel) ===
|
||||||
int hour = dateTime.getHour();
|
|
||||||
int minute = dateTime.getMinute();
|
|
||||||
int second = dateTime.getSecond();
|
|
||||||
|
|
||||||
if ("12h".equalsIgnoreCase(timeFormat)) {
|
|
||||||
String ampm = hour >= 12 ? "PM" : "AM";
|
|
||||||
int hour12 = hour % 12;
|
|
||||||
if (hour12 == 0) hour12 = 12;
|
|
||||||
return String.format("%d:%02d:%02d %s", hour12, minute, second, ampm);
|
|
||||||
} else {
|
|
||||||
return String.format("%02d:%02d:%02d", hour, minute, second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getWeatherSymbol(String weatherMain) {
|
|
||||||
String w = weatherMain.toLowerCase();
|
|
||||||
switch (w) {
|
|
||||||
case "clear": return "☀️";
|
|
||||||
case "clouds": return "☁️";
|
|
||||||
case "rain": return "🌧️";
|
|
||||||
case "thunderstorm": return "⛈️";
|
|
||||||
case "snow": return "❄️";
|
|
||||||
case "mist":
|
|
||||||
case "fog":
|
|
||||||
case "haze": return "🌫️";
|
|
||||||
default: return weatherMain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getLocalizedWeatherMain(String weatherMain, String countryCode) {
|
|
||||||
String key = "weather." + weatherMain.toLowerCase();
|
|
||||||
return getLocalizedMessage(key, countryCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getCountryCode(String location) {
|
|
||||||
if (location == null || !location.contains(",")) {
|
|
||||||
getLogger().warning("Ungültiges Location-Format: " + location + ". Fallback auf 'en'.");
|
|
||||||
return "en";
|
|
||||||
}
|
|
||||||
String[] parts = location.split(",");
|
|
||||||
String countryCode = parts.length > 1 ? parts[1].trim().toLowerCase() : "en";
|
|
||||||
// Überprüfe, ob der Sprachcode in lang.yml existiert
|
|
||||||
if (!langConfig.contains("languages." + countryCode)) {
|
|
||||||
getLogger().warning("Sprache '" + countryCode + "' nicht in lang.yml gefunden. Fallback auf 'en'.");
|
|
||||||
return "en";
|
|
||||||
}
|
|
||||||
return countryCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Inventory createWeatherGUI(Player player) {
|
|
||||||
String countryCode = getCountryCode(worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults")).location);
|
|
||||||
|
|
||||||
Inventory inv = Bukkit.createInventory(null, 9, getLocalizedMessage("gui_title", countryCode));
|
|
||||||
|
|
||||||
ItemStack setLocation = new ItemStack(Material.BOOK);
|
|
||||||
ItemStack toggleWeather = new ItemStack(Material.REDSTONE_TORCH);
|
|
||||||
ItemStack forecast = new ItemStack(Material.PAPER);
|
|
||||||
ItemStack info = new ItemStack(Material.OAK_SIGN);
|
|
||||||
|
|
||||||
ItemMeta setLocationMeta = setLocation.getItemMeta();
|
|
||||||
setLocationMeta.setDisplayName(getLocalizedMessage("gui_setlocation", countryCode));
|
|
||||||
setLocationMeta.setLore(Arrays.asList(getLocalizedMessage("gui_setlocation_lore", countryCode)));
|
|
||||||
setLocation.setItemMeta(setLocationMeta);
|
|
||||||
|
|
||||||
ItemMeta toggleWeatherMeta = toggleWeather.getItemMeta();
|
|
||||||
toggleWeatherMeta.setDisplayName(getLocalizedMessage("gui_toggleweather", countryCode));
|
|
||||||
toggleWeatherMeta.setLore(Arrays.asList(getLocalizedMessage("gui_toggleweather_lore", countryCode)));
|
|
||||||
toggleWeather.setItemMeta(toggleWeatherMeta);
|
|
||||||
|
|
||||||
ItemMeta forecastMeta = forecast.getItemMeta();
|
|
||||||
forecastMeta.setDisplayName(getLocalizedMessage("gui_forecast", countryCode));
|
|
||||||
forecastMeta.setLore(Arrays.asList(getLocalizedMessage("gui_forecast_lore", countryCode)));
|
|
||||||
forecast.setItemMeta(forecastMeta);
|
|
||||||
|
|
||||||
ItemMeta infoMeta = info.getItemMeta();
|
|
||||||
infoMeta.setDisplayName(getLocalizedMessage("gui_info", countryCode));
|
|
||||||
infoMeta.setLore(Arrays.asList(getLocalizedMessage("gui_info_lore", countryCode)));
|
|
||||||
info.setItemMeta(infoMeta);
|
|
||||||
|
|
||||||
inv.setItem(2, setLocation);
|
|
||||||
inv.setItem(3, toggleWeather);
|
|
||||||
inv.setItem(4, forecast);
|
|
||||||
inv.setItem(5, info);
|
|
||||||
|
|
||||||
playerGUIs.put(player.getUniqueId(), inv);
|
|
||||||
return inv;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
|
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
World world = player.getWorld();
|
World world = player.getWorld();
|
||||||
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
|
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
|
||||||
if (!config.enabled) return;
|
if (!config.enabled) return;
|
||||||
WeatherData data = worldWeatherData.get(world.getName());
|
WeatherTimeData data = worldWeatherData.get(world.getName());
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
||||||
String countryCode = getCountryCode(config.location);
|
String countryCode = getCountryCode(config.location);
|
||||||
String localizedWeather = getLocalizedWeatherMain(data.weatherMain, countryCode);
|
String localizedWeather = getLocalizedWeatherMain(data.getWeatherMain(), countryCode);
|
||||||
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.temperature, 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));
|
audiences.player(player).sendActionBar(Component.text(message, NamedTextColor.GREEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClick(InventoryClickEvent event) {
|
public void onInventoryClick(InventoryClickEvent event) {
|
||||||
Player player = (Player) event.getWhoClicked();
|
Player player = (Player) event.getWhoClicked();
|
||||||
if (!playerGUIs.containsKey(player.getUniqueId()) || event.getInventory() != playerGUIs.get(player.getUniqueId())) {
|
Inventory expectedGUI = playerGUIs.get(player.getUniqueId());
|
||||||
return;
|
if (expectedGUI == null || event.getInventory() != expectedGUI) return;
|
||||||
}
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
ItemStack clickedItem = event.getCurrentItem();
|
ItemStack clickedItem = event.getCurrentItem();
|
||||||
if (clickedItem == null || clickedItem.getType() == Material.AIR) return;
|
if (clickedItem == null || clickedItem.getType() == Material.AIR) return;
|
||||||
@@ -488,7 +336,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
getLocalizedMessage("gui_setlocation_prompt", countryCode), NamedTextColor.YELLOW));
|
getLocalizedMessage("gui_setlocation_prompt", countryCode), NamedTextColor.YELLOW));
|
||||||
} else if (clickedItem.getType() == Material.REDSTONE_TORCH) {
|
} else if (clickedItem.getType() == Material.REDSTONE_TORCH) {
|
||||||
String worldName = player.getWorld().getName();
|
String worldName = player.getWorld().getName();
|
||||||
HashSet<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(
|
audiences.player(player).sendMessage(Component.text(
|
||||||
@@ -510,62 +358,101 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClose(InventoryCloseEvent event) {
|
public void onInventoryClose(InventoryCloseEvent event) {
|
||||||
Player player = (Player) event.getPlayer();
|
playerGUIs.remove(event.getPlayer().getUniqueId());
|
||||||
playerGUIs.remove(player.getUniqueId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class WeatherData {
|
// === Hilfsmethoden & Modellklassen ===
|
||||||
ZonedDateTime dateTime;
|
|
||||||
String weatherMain;
|
|
||||||
double temperature;
|
|
||||||
|
|
||||||
public WeatherData(ZonedDateTime dateTime, String weatherMain, double temperature) {
|
private String getLocalizedMessage(String key, String countryCode, String... placeholders) {
|
||||||
this.dateTime = dateTime;
|
String path = "languages." + (countryCode.isEmpty() ? "en" : countryCode.toLowerCase()) + "." + key;
|
||||||
this.weatherMain = weatherMain;
|
String message = langConfig.getString(path);
|
||||||
this.temperature = temperature;
|
if (message == null) {
|
||||||
|
path = "languages.en." + key;
|
||||||
|
message = langConfig.getString(path, key);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < placeholders.length - 1; i += 2) {
|
||||||
|
message = message.replace("{" + placeholders[i] + "}", placeholders[i + 1]);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getWeatherSymbol(String weatherMain) {
|
||||||
|
switch (weatherMain.toLowerCase()) {
|
||||||
|
case "clear": return "☀️";
|
||||||
|
case "clouds": return "☁️";
|
||||||
|
case "rain": return "🌧️";
|
||||||
|
case "thunderstorm": return "⛈️";
|
||||||
|
case "snow": return "❄️";
|
||||||
|
case "mist":
|
||||||
|
case "fog":
|
||||||
|
case "haze": return "🌫️";
|
||||||
|
default: return weatherMain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class WorldConfig {
|
private String getLocalizedWeatherMain(String weatherMain, String countryCode) {
|
||||||
boolean enabled;
|
String key = "weather." + weatherMain.toLowerCase();
|
||||||
String location;
|
return getLocalizedMessage(key, countryCode);
|
||||||
String units;
|
|
||||||
String timeFormat;
|
|
||||||
boolean displayActionbar;
|
|
||||||
boolean displayWeatherIcon;
|
|
||||||
String displayPosition;
|
|
||||||
int paddingRight;
|
|
||||||
boolean syncInGameWeather;
|
|
||||||
|
|
||||||
public WorldConfig(boolean enabled, String location, String units, String timeFormat, boolean displayActionbar,
|
|
||||||
boolean displayWeatherIcon, String displayPosition, int paddingRight, boolean syncInGameWeather) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
this.location = location;
|
|
||||||
this.units = units;
|
|
||||||
this.timeFormat = timeFormat;
|
|
||||||
this.displayActionbar = displayActionbar;
|
|
||||||
this.displayWeatherIcon = displayWeatherIcon;
|
|
||||||
this.displayPosition = displayPosition;
|
|
||||||
this.paddingRight = paddingRight;
|
|
||||||
this.syncInGameWeather = syncInGameWeather;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getCountryCode(String location) {
|
||||||
|
if (location == null || !location.contains(",")) return "en";
|
||||||
|
String[] parts = location.split(",");
|
||||||
|
String countryCode = parts.length > 1 ? parts[1].trim().toLowerCase() : "en";
|
||||||
|
if (!langConfig.contains("languages." + countryCode)) return "en";
|
||||||
|
return countryCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Inventory createWeatherGUI(Player player) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults")).location);
|
||||||
|
Inventory inv = Bukkit.createInventory(null, 9, getLocalizedMessage("gui_title", countryCode));
|
||||||
|
ItemStack setLocation = new ItemStack(Material.BOOK);
|
||||||
|
ItemStack toggleWeather = new ItemStack(Material.REDSTONE_TORCH);
|
||||||
|
ItemStack forecast = new ItemStack(Material.PAPER);
|
||||||
|
ItemStack info = new ItemStack(Material.OAK_SIGN);
|
||||||
|
|
||||||
|
ItemMeta setLocationMeta = setLocation.getItemMeta();
|
||||||
|
setLocationMeta.setDisplayName(getLocalizedMessage("gui_setlocation", countryCode));
|
||||||
|
setLocationMeta.setLore(Collections.singletonList(getLocalizedMessage("gui_setlocation_lore", countryCode)));
|
||||||
|
setLocation.setItemMeta(setLocationMeta);
|
||||||
|
|
||||||
|
ItemMeta toggleWeatherMeta = toggleWeather.getItemMeta();
|
||||||
|
toggleWeatherMeta.setDisplayName(getLocalizedMessage("gui_toggleweather", countryCode));
|
||||||
|
toggleWeatherMeta.setLore(Collections.singletonList(getLocalizedMessage("gui_toggleweather_lore", countryCode)));
|
||||||
|
toggleWeather.setItemMeta(toggleWeatherMeta);
|
||||||
|
|
||||||
|
ItemMeta forecastMeta = forecast.getItemMeta();
|
||||||
|
forecastMeta.setDisplayName(getLocalizedMessage("gui_forecast", countryCode));
|
||||||
|
forecastMeta.setLore(Collections.singletonList(getLocalizedMessage("gui_forecast_lore", countryCode)));
|
||||||
|
forecast.setItemMeta(forecastMeta);
|
||||||
|
|
||||||
|
ItemMeta infoMeta = info.getItemMeta();
|
||||||
|
infoMeta.setDisplayName(getLocalizedMessage("gui_info", countryCode));
|
||||||
|
infoMeta.setLore(Collections.singletonList(getLocalizedMessage("gui_info_lore", countryCode)));
|
||||||
|
info.setItemMeta(infoMeta);
|
||||||
|
|
||||||
|
inv.setItem(2, setLocation);
|
||||||
|
inv.setItem(3, toggleWeather);
|
||||||
|
inv.setItem(4, forecast);
|
||||||
|
inv.setItem(5, info);
|
||||||
|
|
||||||
|
playerGUIs.put(player.getUniqueId(), 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;
|
||||||
|
|
||||||
public PlayerConfig(UUID playerId) {
|
public PlayerConfig(UUID playerId) {
|
||||||
File playerDir = new File(getDataFolder(), "players");
|
File playerDir = new File(getDataFolder(), "players");
|
||||||
playerDir.mkdirs();
|
playerDir.mkdirs();
|
||||||
configFile = new File(playerDir, playerId.toString() + ".yml");
|
configFile = new File(playerDir, playerId.toString() + ".yml");
|
||||||
config = YamlConfiguration.loadConfiguration(configFile);
|
config = YamlConfiguration.loadConfiguration(configFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLocation() {
|
public String getLocation() {
|
||||||
return config.getString("location", "");
|
return config.getString("location", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLocation(String location) {
|
public void setLocation(String location) {
|
||||||
config.set("location", location);
|
config.set("location", location);
|
||||||
try {
|
try {
|
||||||
@@ -576,18 +463,17 @@ 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) {
|
||||||
if (args.length == 0) {
|
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
if (args.length == 0) {
|
||||||
getLocalizedMessage("usage", countryCode), NamedTextColor.RED));
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("usage", countryCode), NamedTextColor.RED));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
switch (args[0].toLowerCase(Locale.ROOT)) {
|
||||||
if (args[0].equalsIgnoreCase("help")) {
|
case "help": {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
|
||||||
Component helpMessage = Component.text()
|
Component helpMessage = Component.text()
|
||||||
.append(Component.text(getLocalizedMessage("help_header", countryCode), NamedTextColor.AQUA, TextDecoration.BOLD))
|
.append(Component.text(getLocalizedMessage("help_header", countryCode), NamedTextColor.AQUA, TextDecoration.BOLD))
|
||||||
.append(Component.newline())
|
.append(Component.newline())
|
||||||
@@ -618,52 +504,34 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
audiences.sender(sender).sendMessage(helpMessage);
|
audiences.sender(sender).sendMessage(helpMessage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case "reload": {
|
||||||
if (args[0].equalsIgnoreCase("reload")) {
|
|
||||||
if (!sender.hasPermission("realtimeweather.reload")) {
|
if (!sender.hasPermission("realtimeweather.reload")) {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("no_permission", countryCode), NamedTextColor.RED));
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("no_permission", countryCode), NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (weatherUpdateTask != null) weatherUpdateTask.cancel();
|
||||||
if (weatherUpdateTask != null) {
|
if (syncTask != null) syncTask.cancel();
|
||||||
weatherUpdateTask.cancel();
|
|
||||||
}
|
|
||||||
if (syncTask != null) {
|
|
||||||
syncTask.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
loadConfig();
|
loadConfig();
|
||||||
loadLanguageConfig();
|
loadLanguageConfig();
|
||||||
worldWeatherData.clear();
|
worldWeatherData.clear();
|
||||||
processedLocations.clear();
|
processedLocations.clear();
|
||||||
initializePlayerDisplays();
|
initializePlayerDisplays();
|
||||||
|
|
||||||
setDoDaylightCycleForWorlds();
|
setDoDaylightCycleForWorlds();
|
||||||
startWeatherUpdateTask();
|
startWeatherUpdateTask();
|
||||||
startSyncTask();
|
startSyncTask();
|
||||||
processedLocations.clear();
|
processedLocations.clear();
|
||||||
updateWeatherDataForAllWorlds();
|
updateWeatherDataForAllWorlds();
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("reload_success", countryCode), NamedTextColor.GREEN));
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("reload_success", countryCode), NamedTextColor.GREEN));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case "setlocation": {
|
||||||
if (args[0].equalsIgnoreCase("setlocation")) {
|
|
||||||
if (!(sender instanceof Player)) {
|
if (!(sender instanceof Player)) {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("usage_setlocation", countryCode), NamedTextColor.RED));
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("usage_setlocation", countryCode), NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Player player = (Player) sender;
|
Player player = (Player) sender;
|
||||||
@@ -673,114 +541,90 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, "metric", getLogger());
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, "metric", getLogger());
|
||||||
fetcher.fetch(); // Teste, ob der Ort gültig ist
|
fetcher.fetchAsWeatherTimeData();
|
||||||
PlayerConfig playerConfig = new PlayerConfig(player.getUniqueId());
|
PlayerConfig playerConfig = new PlayerConfig(player.getUniqueId());
|
||||||
playerConfig.setLocation(location);
|
playerConfig.setLocation(location);
|
||||||
playerLocations.put(player.getUniqueId(), location);
|
playerLocations.put(player.getUniqueId(), location);
|
||||||
String countryCode = getCountryCode(location);
|
String cc = getCountryCode(location);
|
||||||
audiences.player(player).sendMessage(Component.text(
|
audiences.player(player).sendMessage(Component.text(getLocalizedMessage("location_set", cc, "location", location), NamedTextColor.GREEN));
|
||||||
getLocalizedMessage("location_set", countryCode, "location", location),
|
|
||||||
NamedTextColor.GREEN));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
audiences.player(player).sendMessage(Component.text(getLocalizedMessage("invalid_location", countryCode, "location", location), NamedTextColor.RED));
|
||||||
audiences.player(player).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("invalid_location", countryCode, "location", location),
|
|
||||||
NamedTextColor.RED));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.runTaskAsynchronously(WeatherTimeSyncPlugin.this);
|
}.runTaskAsynchronously(WeatherTimeSyncPlugin.this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case "query": {
|
||||||
if (args[0].equalsIgnoreCase("query")) {
|
|
||||||
if (!(sender instanceof Player)) {
|
if (!(sender instanceof Player)) {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Player player = (Player) sender;
|
Player queryPlayer = (Player) sender;
|
||||||
WorldConfig config = worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults"));
|
WorldConfig config = worldConfigs.getOrDefault(queryPlayer.getWorld().getName(), worldConfigs.get("defaults"));
|
||||||
if (!config.enabled) {
|
if (!config.enabled) {
|
||||||
String countryCode = getCountryCode(config.location);
|
audiences.player(queryPlayer).sendMessage(Component.text(getLocalizedMessage("plugin_disabled", countryCode, "world", queryPlayer.getWorld().getName()), NamedTextColor.RED));
|
||||||
audiences.player(player).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("plugin_disabled", countryCode, "world", player.getWorld().getName()),
|
|
||||||
NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String location = playerLocations.getOrDefault(player.getUniqueId(), config.location);
|
String queryLocation = playerLocations.getOrDefault(queryPlayer.getUniqueId(), config.location);
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, config.units, getLogger());
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, queryLocation, config.units, getLogger());
|
||||||
WeatherFetcher.WeatherData data = fetcher.fetch();
|
WeatherTimeData data = fetcher.fetchAsWeatherTimeData();
|
||||||
String countryCode = getCountryCode(location);
|
String cc = getCountryCode(queryLocation);
|
||||||
String localizedWeather = getLocalizedWeatherMain(data.weatherMain, countryCode);
|
String localizedWeather = getLocalizedWeatherMain(data.getWeatherMain(), cc);
|
||||||
String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F";
|
String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F";
|
||||||
String city = location.split(",")[0];
|
String city = queryLocation.split(",")[0];
|
||||||
String message = String.format("%s: %s, %.1f%s", city, localizedWeather, data.temperature, tempUnit);
|
String message = String.format("%s: %s, %.1f%s", city, localizedWeather, data.getTemp(config.units.equalsIgnoreCase("metric") ? "C" : "F"), tempUnit);
|
||||||
audiences.player(player).sendMessage(Component.text(message, NamedTextColor.GREEN));
|
audiences.player(queryPlayer).sendMessage(Component.text(message, NamedTextColor.GREEN));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String countryCode = getCountryCode(config.location);
|
audiences.player(queryPlayer).sendMessage(Component.text(getLocalizedMessage("forecast_error", countryCode, "location", queryLocation, "error", e.getMessage()), NamedTextColor.RED));
|
||||||
audiences.player(player).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("forecast_error", countryCode, "location", location, "error", e.getMessage()),
|
|
||||||
NamedTextColor.RED));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.runTaskAsynchronously(WeatherTimeSyncPlugin.this);
|
}.runTaskAsynchronously(WeatherTimeSyncPlugin.this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case "info": {
|
||||||
if (args[0].equalsIgnoreCase("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.0\nAutor: M_Viper\nGetestete Minecraft-Version: 1.21.1 - 1.21.8";
|
||||||
audiences.sender(sender).sendMessage(Component.text(infoMessage, NamedTextColor.AQUA));
|
audiences.sender(sender).sendMessage(Component.text(infoMessage, NamedTextColor.AQUA));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case "gui": {
|
||||||
if (args[0].equalsIgnoreCase("gui")) {
|
|
||||||
if (!(sender instanceof Player)) {
|
if (!(sender instanceof Player)) {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
|
||||||
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Player player = (Player) sender;
|
Player guiPlayer = (Player) sender;
|
||||||
WorldConfig config = worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults"));
|
WorldConfig guiConfig = worldConfigs.getOrDefault(guiPlayer.getWorld().getName(), worldConfigs.get("defaults"));
|
||||||
if (!config.enabled) {
|
if (!guiConfig.enabled) {
|
||||||
String countryCode = getCountryCode(config.location);
|
String cc = getCountryCode(guiConfig.location);
|
||||||
audiences.player(player).sendMessage(Component.text(
|
audiences.player(guiPlayer).sendMessage(Component.text(getLocalizedMessage("plugin_disabled", cc, "world", guiPlayer.getWorld().getName()), NamedTextColor.RED));
|
||||||
getLocalizedMessage("plugin_disabled", countryCode, "world", player.getWorld().getName()),
|
|
||||||
NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
player.openInventory(createWeatherGUI(player));
|
guiPlayer.openInventory(createWeatherGUI(guiPlayer));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class WeatherForecastCommand implements CommandExecutor {
|
private class WeatherForecastCommand 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) {
|
||||||
if (!(sender instanceof Player)) {
|
if (!(sender instanceof Player)) {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Player player = (Player) sender;
|
Player player = (Player) sender;
|
||||||
WorldConfig config = worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults"));
|
WorldConfig config = worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults"));
|
||||||
if (!config.enabled) {
|
if (!config.enabled) {
|
||||||
String countryCode = getCountryCode(config.location);
|
String countryCode = getCountryCode(config.location);
|
||||||
audiences.player(player).sendMessage(Component.text(
|
audiences.player(player).sendMessage(Component.text(getLocalizedMessage("plugin_disabled", countryCode, "world", player.getWorld().getName()), NamedTextColor.RED));
|
||||||
getLocalizedMessage("plugin_disabled", countryCode, "world", player.getWorld().getName()),
|
|
||||||
NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String location = playerLocations.getOrDefault(player.getUniqueId(), config.location);
|
String location = playerLocations.getOrDefault(player.getUniqueId(), config.location);
|
||||||
@@ -832,8 +676,7 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
if (!(sender instanceof Player)) {
|
if (!(sender instanceof Player)) {
|
||||||
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
audiences.sender(sender).sendMessage(Component.text(
|
audiences.sender(sender).sendMessage(Component.text(getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Player player = (Player) sender;
|
Player player = (Player) sender;
|
||||||
@@ -841,23 +684,46 @@ public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
|||||||
WorldConfig config = worldConfigs.getOrDefault(worldName, worldConfigs.get("defaults"));
|
WorldConfig config = worldConfigs.getOrDefault(worldName, worldConfigs.get("defaults"));
|
||||||
if (!config.enabled) {
|
if (!config.enabled) {
|
||||||
String countryCode = getCountryCode(config.location);
|
String countryCode = getCountryCode(config.location);
|
||||||
audiences.player(player).sendMessage(Component.text(
|
audiences.player(player).sendMessage(Component.text(getLocalizedMessage("plugin_disabled", countryCode, "world", worldName), NamedTextColor.RED));
|
||||||
getLocalizedMessage("plugin_disabled", countryCode, "world", worldName),
|
|
||||||
NamedTextColor.RED));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String countryCode = getCountryCode(config.location);
|
String countryCode = getCountryCode(config.location);
|
||||||
HashSet<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(
|
audiences.player(player).sendMessage(Component.text(getLocalizedMessage("toggle_disabled", countryCode, "world", worldName), NamedTextColor.RED));
|
||||||
getLocalizedMessage("toggle_disabled", countryCode, "world", worldName), NamedTextColor.RED));
|
|
||||||
} else {
|
} else {
|
||||||
worlds.add(worldName);
|
worlds.add(worldName);
|
||||||
audiences.player(player).sendMessage(Component.text(
|
audiences.player(player).sendMessage(Component.text(getLocalizedMessage("toggle_enabled", countryCode, "world", worldName), NamedTextColor.GREEN));
|
||||||
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 {
|
||||||
|
boolean enabled;
|
||||||
|
String location;
|
||||||
|
String units;
|
||||||
|
String timeFormat;
|
||||||
|
boolean displayActionbar;
|
||||||
|
boolean displayWeatherIcon;
|
||||||
|
String displayPosition;
|
||||||
|
int paddingRight;
|
||||||
|
boolean syncInGameWeather;
|
||||||
|
|
||||||
|
public WorldConfig(boolean enabled, String location, String units, String timeFormat,
|
||||||
|
boolean displayActionbar, boolean displayWeatherIcon,
|
||||||
|
String displayPosition, int paddingRight, boolean syncInGameWeather) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
this.location = location;
|
||||||
|
this.units = units;
|
||||||
|
this.timeFormat = timeFormat;
|
||||||
|
this.displayActionbar = displayActionbar;
|
||||||
|
this.displayWeatherIcon = displayWeatherIcon;
|
||||||
|
this.displayPosition = displayPosition;
|
||||||
|
this.paddingRight = paddingRight;
|
||||||
|
this.syncInGameWeather = syncInGameWeather;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -1,14 +1,20 @@
|
|||||||
|
# OpenWeatherMap API-Key – hier eintragen
|
||||||
api-key: "DEIN_API_KEY_HIER"
|
api-key: "DEIN_API_KEY_HIER"
|
||||||
|
|
||||||
|
# Update-Intervall in Sekunden (Standard: 60)
|
||||||
update-interval: 60
|
update-interval: 60
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
enabled: true
|
enabled: true
|
||||||
location: "Berlin,de"
|
location: "Berlin,de" # Stadt,Land
|
||||||
units: "metric"
|
units: "metric" # metric = °C, imperial = °F
|
||||||
time-format: "24h"
|
time-format: "24h" # oder "12h"
|
||||||
display-actionbar: true
|
display-actionbar: true
|
||||||
display-weather-icon: true
|
display-weather-icon: true
|
||||||
display-position: "top-right"
|
display-position: "top-right"
|
||||||
padding-right: 100
|
padding-right: 100
|
||||||
|
sync-in-game-weather: true
|
||||||
|
|
||||||
worlds:
|
worlds:
|
||||||
world:
|
world:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -19,6 +25,8 @@ worlds:
|
|||||||
display-weather-icon: true
|
display-weather-icon: true
|
||||||
display-position: "top-left"
|
display-position: "top-left"
|
||||||
padding-right: 50
|
padding-right: 50
|
||||||
|
sync-in-game-weather: true
|
||||||
|
|
||||||
world_nether:
|
world_nether:
|
||||||
enabled: false
|
enabled: false
|
||||||
location: "Berlin,de"
|
location: "Berlin,de"
|
||||||
@@ -28,3 +36,4 @@ worlds:
|
|||||||
display-weather-icon: false
|
display-weather-icon: false
|
||||||
display-position: "top-right"
|
display-position: "top-right"
|
||||||
padding-right: 150
|
padding-right: 150
|
||||||
|
sync-in-game-weather: false
|
||||||
|
@@ -2,6 +2,7 @@ name: RealTimeWeather
|
|||||||
version: 1.0
|
version: 1.0
|
||||||
main: dev.viper.weathertime.WeatherTimeSyncPlugin
|
main: dev.viper.weathertime.WeatherTimeSyncPlugin
|
||||||
api-version: 1.21
|
api-version: 1.21
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
wetter:
|
wetter:
|
||||||
description: Manages real-time weather and time synchronization
|
description: Manages real-time weather and time synchronization
|
||||||
@@ -15,6 +16,7 @@ commands:
|
|||||||
description: Toggles the weather display for the current world
|
description: Toggles the weather display for the current world
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: realtimeweather.toggle
|
permission: realtimeweather.toggle
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
realtimeweather.use:
|
realtimeweather.use:
|
||||||
description: Allows usage of the /wetter command
|
description: Allows usage of the /wetter command
|
||||||
|
Reference in New Issue
Block a user