Dateien nach "src/main/java/dev/viper/weathertime" hochladen
This commit is contained in:
123
src/main/java/dev/viper/weathertime/WeatherFetcher.java
Normal file
123
src/main/java/dev/viper/weathertime/WeatherFetcher.java
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package dev.viper.weathertime;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class WeatherFetcher {
|
||||||
|
|
||||||
|
private final String apiKey;
|
||||||
|
private final String location;
|
||||||
|
private final String units;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
|
public WeatherFetcher(String apiKey, String location, String units, Logger logger) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
this.location = location;
|
||||||
|
this.units = units.toLowerCase();
|
||||||
|
this.logger = logger;
|
||||||
|
if (!this.units.equals("metric") && !this.units.equals("imperial")) {
|
||||||
|
logger.warning("Ungültige Einheit für " + location + ": " + units + ". Verwende 'metric' als Fallback.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WeatherData fetch() throws Exception {
|
||||||
|
String effectiveUnits = units.equals("metric") || units.equals("imperial") ? units : "metric";
|
||||||
|
|
||||||
|
String urlString = String.format(
|
||||||
|
"https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=%s",
|
||||||
|
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();
|
||||||
|
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();
|
||||||
|
String inputLine;
|
||||||
|
|
||||||
|
while ((inputLine = in.readLine()) != null) {
|
||||||
|
content.append(inputLine);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
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);
|
||||||
|
String weatherMain = json.getJSONArray("weather").getJSONObject(0).getString("main");
|
||||||
|
double temperature = json.getJSONObject("main").getDouble("temp");
|
||||||
|
|
||||||
|
if (effectiveUnits.equals("imperial") && (temperature < -50 || temperature > 150)) {
|
||||||
|
logger.warning("Unrealistische Temperatur für " + location + ": " + temperature + "°F. API-Fehler?");
|
||||||
|
} else if (effectiveUnits.equals("metric") && (temperature < -50 || temperature > 60)) {
|
||||||
|
logger.warning("Unrealistische Temperatur für " + location + ": " + temperature + "°C. API-Fehler?");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WeatherData(dateTime, weatherMain, temperature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject fetchForecast() throws Exception {
|
||||||
|
String effectiveUnits = units.equals("metric") || units.equals("imperial") ? units : "metric";
|
||||||
|
|
||||||
|
String urlString = String.format(
|
||||||
|
"https://api.openweathermap.org/data/2.5/forecast?q=%s&appid=%s&units=%s",
|
||||||
|
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();
|
||||||
|
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();
|
||||||
|
String inputLine;
|
||||||
|
while ((inputLine = in.readLine()) != null) {
|
||||||
|
content.append(inputLine);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
connection.disconnect();
|
||||||
|
|
||||||
|
return new JSONObject(content.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WeatherData {
|
||||||
|
ZonedDateTime dateTime;
|
||||||
|
String weatherMain;
|
||||||
|
double temperature;
|
||||||
|
|
||||||
|
public WeatherData(ZonedDateTime dateTime, String weatherMain, double temperature) {
|
||||||
|
this.dateTime = dateTime;
|
||||||
|
this.weatherMain = weatherMain;
|
||||||
|
this.temperature = temperature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
src/main/java/dev/viper/weathertime/WeatherTimeData.java
Normal file
57
src/main/java/dev/viper/weathertime/WeatherTimeData.java
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package dev.viper.weathertime;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
this.rain = rain;
|
||||||
|
this.thunder = thunder;
|
||||||
|
this.unixTime = unixTime;
|
||||||
|
this.tempCelsius = tempCelsius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRain() {
|
||||||
|
return rain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isThunder() {
|
||||||
|
return thunder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTemp(String unit) {
|
||||||
|
return unit.equalsIgnoreCase("F") ? (tempCelsius * 9 / 5) + 32 : tempCelsius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFormattedTime(String format) {
|
||||||
|
LocalTime time = Instant.ofEpochSecond(unixTime)
|
||||||
|
.atOffset(ZoneOffset.UTC)
|
||||||
|
.toLocalTime();
|
||||||
|
|
||||||
|
if ("12h".equalsIgnoreCase(format)) {
|
||||||
|
int hour = time.getHour();
|
||||||
|
String ampm = hour >= 12 ? "PM" : "AM";
|
||||||
|
hour = hour % 12;
|
||||||
|
if (hour == 0) hour = 12;
|
||||||
|
return String.format("%02d:%02d %s", hour, time.getMinute(), ampm);
|
||||||
|
} else {
|
||||||
|
return String.format("%02d:%02d", time.getHour(), time.getMinute());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long toMinecraftTime() {
|
||||||
|
LocalTime time = Instant.ofEpochSecond(unixTime)
|
||||||
|
.atOffset(ZoneOffset.UTC)
|
||||||
|
.toLocalTime();
|
||||||
|
|
||||||
|
int hour = time.getHour();
|
||||||
|
int minute = time.getMinute();
|
||||||
|
return (hour * 1000L / 24) + (minute * 1000L / (24 * 60));
|
||||||
|
}
|
||||||
|
}
|
863
src/main/java/dev/viper/weathertime/WeatherTimeSyncPlugin.java
Normal file
863
src/main/java/dev/viper/weathertime/WeatherTimeSyncPlugin.java
Normal file
@@ -0,0 +1,863 @@
|
|||||||
|
package dev.viper.weathertime;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
|
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class WeatherTimeSyncPlugin extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
|
private String apiKey;
|
||||||
|
private int updateInterval;
|
||||||
|
private final HashMap<String, WorldConfig> worldConfigs = new HashMap<>();
|
||||||
|
private final HashMap<String, WeatherData> worldWeatherData = new HashMap<>();
|
||||||
|
private final HashMap<UUID, HashSet<String>> playersWithDisplay = new HashMap<>();
|
||||||
|
private final HashMap<UUID, String> playerLocations = new HashMap<>();
|
||||||
|
private final HashMap<UUID, Inventory> playerGUIs = new HashMap<>();
|
||||||
|
private BukkitAudiences audiences;
|
||||||
|
private BukkitRunnable weatherUpdateTask;
|
||||||
|
private BukkitRunnable syncTask;
|
||||||
|
private final HashSet<String> processedLocations = new HashSet<>();
|
||||||
|
private FileConfiguration langConfig;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
saveDefaultConfig();
|
||||||
|
loadLanguageConfig(); // Zuerst laden, um sicherzustellen, dass Übersetzungen verfügbar sind
|
||||||
|
loadConfig();
|
||||||
|
this.audiences = BukkitAudiences.create(this);
|
||||||
|
|
||||||
|
getCommand("wetter").setExecutor(new WetterCommand());
|
||||||
|
getCommand("weatherforecast").setExecutor(new WeatherForecastCommand());
|
||||||
|
getCommand("toggleweather").setExecutor(new ToggleWeatherCommand());
|
||||||
|
|
||||||
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
|
|
||||||
|
setDoDaylightCycleForWorlds();
|
||||||
|
startWeatherUpdateTask();
|
||||||
|
startSyncTask();
|
||||||
|
|
||||||
|
initializePlayerDisplays();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
if (weatherUpdateTask != null) {
|
||||||
|
weatherUpdateTask.cancel();
|
||||||
|
}
|
||||||
|
if (syncTask != null) {
|
||||||
|
syncTask.cancel();
|
||||||
|
}
|
||||||
|
if (audiences != null) {
|
||||||
|
audiences.close();
|
||||||
|
}
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (playerGUIs.containsKey(player.getUniqueId())) {
|
||||||
|
player.closeInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadConfig() {
|
||||||
|
FileConfiguration cfg = getConfig();
|
||||||
|
apiKey = cfg.getString("api-key");
|
||||||
|
updateInterval = cfg.getInt("update-interval", 60);
|
||||||
|
worldConfigs.clear();
|
||||||
|
|
||||||
|
WorldConfig defaultConfig = new WorldConfig(
|
||||||
|
cfg.getBoolean("defaults.enabled", true),
|
||||||
|
cfg.getString("defaults.location", "Berlin,de"),
|
||||||
|
cfg.getString("defaults.units", "metric"),
|
||||||
|
cfg.getString("defaults.time-format", "24h"),
|
||||||
|
cfg.getBoolean("defaults.display-actionbar", true),
|
||||||
|
cfg.getBoolean("defaults.display-weather-icon", true),
|
||||||
|
cfg.getString("defaults.display-position", "top-right"),
|
||||||
|
cfg.getInt("defaults.padding-right", 100),
|
||||||
|
cfg.getBoolean("defaults.sync-in-game-weather", true)
|
||||||
|
);
|
||||||
|
worldConfigs.put("defaults", defaultConfig);
|
||||||
|
|
||||||
|
if (cfg.isConfigurationSection("worlds")) {
|
||||||
|
for (String worldName : cfg.getConfigurationSection("worlds").getKeys(false)) {
|
||||||
|
WorldConfig worldConfig = new WorldConfig(
|
||||||
|
cfg.getBoolean("worlds." + worldName + ".enabled", defaultConfig.enabled),
|
||||||
|
cfg.getString("worlds." + worldName + ".location", defaultConfig.location),
|
||||||
|
cfg.getString("worlds." + worldName + ".units", defaultConfig.units),
|
||||||
|
cfg.getString("worlds." + worldName + ".time-format", defaultConfig.timeFormat),
|
||||||
|
cfg.getBoolean("worlds." + worldName + ".display-actionbar", defaultConfig.displayActionbar),
|
||||||
|
cfg.getBoolean("worlds." + worldName + ".display-weather-icon", defaultConfig.displayWeatherIcon),
|
||||||
|
cfg.getString("worlds." + worldName + ".display-position", defaultConfig.displayPosition),
|
||||||
|
cfg.getInt("worlds." + worldName + ".padding-right", defaultConfig.paddingRight),
|
||||||
|
cfg.getBoolean("worlds." + worldName + ".sync-in-game-weather", defaultConfig.syncInGameWeather)
|
||||||
|
);
|
||||||
|
worldConfigs.put(worldName, worldConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiKey == null || apiKey.trim().isEmpty()) {
|
||||||
|
getLogger().severe("API-Key ist nicht gesetzt! Bitte in config.yml eintragen.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadLanguageConfig() {
|
||||||
|
File langFile = new File(getDataFolder(), "lang.yml");
|
||||||
|
try {
|
||||||
|
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
||||||
|
if (!langFile.exists()) {
|
||||||
|
saveResource("lang.yml", false);
|
||||||
|
getLogger().info("lang.yml wurde aus den Ressourcen kopiert.");
|
||||||
|
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
||||||
|
} else if (langConfig.getConfigurationSection("languages") == null) {
|
||||||
|
getLogger().warning("lang.yml enthält keinen 'languages'-Abschnitt. Standardwerte werden verwendet.");
|
||||||
|
saveResource("lang.yml", true); // Überschreibe mit Standardwerten
|
||||||
|
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) {
|
||||||
|
getLogger().severe("Fehler beim Laden von lang.yml: " + e.getMessage());
|
||||||
|
saveResource("lang.yml", true); // Überschreibe bei Fehler mit Standardwerten
|
||||||
|
langConfig = YamlConfiguration.loadConfiguration(langFile);
|
||||||
|
getLogger().info("lang.yml wurde nach Fehler mit Standardwerten überschrieben.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDoDaylightCycleForWorlds() {
|
||||||
|
for (World world : Bukkit.getWorlds()) {
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
|
||||||
|
if (config.enabled) {
|
||||||
|
world.setGameRuleValue("doDaylightCycle", "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getLocalizedMessage(String key, String countryCode, String... placeholders) {
|
||||||
|
String path = "languages." + (countryCode.isEmpty() ? "en" : countryCode.toLowerCase()) + "." + key;
|
||||||
|
String message = langConfig.getString(path);
|
||||||
|
if (message == null) {
|
||||||
|
path = "languages.en." + key;
|
||||||
|
message = langConfig.getString(path);
|
||||||
|
if (message == null) {
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < placeholders.length - 1; i += 2) {
|
||||||
|
message = message.replace("{" + placeholders[i] + "}", placeholders[i + 1]);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startWeatherUpdateTask() {
|
||||||
|
weatherUpdateTask = new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
processedLocations.clear();
|
||||||
|
updateWeatherDataForAllWorlds();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
weatherUpdateTask.runTaskTimerAsynchronously(this, 0L, updateInterval * 20L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startSyncTask() {
|
||||||
|
syncTask = new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (World world : Bukkit.getWorlds()) {
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
|
||||||
|
if (!config.enabled) continue;
|
||||||
|
WeatherData data = worldWeatherData.get(world.getName());
|
||||||
|
if (data != null) {
|
||||||
|
syncMinecraftTime(world, data.dateTime);
|
||||||
|
updateActionbarForWorld(world, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
syncTask.runTaskTimer(this, 0L, 20L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateWeatherDataForAllWorlds() {
|
||||||
|
for (World world : Bukkit.getWorlds()) {
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
|
||||||
|
if (!config.enabled) {
|
||||||
|
worldWeatherData.remove(world.getName());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (processedLocations.contains(config.location)) {
|
||||||
|
for (String otherWorld : worldWeatherData.keySet()) {
|
||||||
|
WorldConfig otherConfig = worldConfigs.getOrDefault(otherWorld, worldConfigs.get("defaults"));
|
||||||
|
if (otherConfig.location.equals(config.location)) {
|
||||||
|
WeatherData existingData = worldWeatherData.get(otherWorld);
|
||||||
|
if (existingData != null) {
|
||||||
|
worldWeatherData.put(world.getName(), existingData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, config.location, config.units, getLogger());
|
||||||
|
WeatherFetcher.WeatherData weatherData = fetcher.fetch();
|
||||||
|
WeatherData newData = new WeatherData(
|
||||||
|
weatherData.dateTime,
|
||||||
|
weatherData.weatherMain,
|
||||||
|
weatherData.temperature
|
||||||
|
);
|
||||||
|
worldWeatherData.put(world.getName(), newData);
|
||||||
|
processedLocations.add(config.location);
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
syncMinecraftTime(world, weatherData.dateTime);
|
||||||
|
if (config.syncInGameWeather) {
|
||||||
|
int durationTicks = 20 * 60 * 5; // 5 Minuten
|
||||||
|
switch (weatherData.weatherMain.toLowerCase()) {
|
||||||
|
case "rain":
|
||||||
|
case "drizzle":
|
||||||
|
world.setStorm(true);
|
||||||
|
world.setThundering(false);
|
||||||
|
world.setWeatherDuration(durationTicks);
|
||||||
|
break;
|
||||||
|
case "thunderstorm":
|
||||||
|
world.setStorm(true);
|
||||||
|
world.setThundering(true);
|
||||||
|
world.setWeatherDuration(durationTicks);
|
||||||
|
break;
|
||||||
|
case "snow":
|
||||||
|
world.setStorm(true);
|
||||||
|
world.setThundering(false);
|
||||||
|
world.setWeatherDuration(durationTicks);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
world.setStorm(false);
|
||||||
|
world.setThundering(false);
|
||||||
|
world.setWeatherDuration(durationTicks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTask(this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
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) {
|
||||||
|
int hour = dateTime.getHour();
|
||||||
|
int minute = dateTime.getMinute();
|
||||||
|
int second = dateTime.getSecond();
|
||||||
|
int minecraftTime = ((hour + 18) % 24) * 1000 + (minute * 1000 / 60) + (second * 1000 / 3600);
|
||||||
|
world.setTime(minecraftTime);
|
||||||
|
world.setGameRuleValue("doDaylightCycle", "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateActionbarForWorld(World world, WeatherData data) {
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
|
||||||
|
if (!config.enabled || !config.displayActionbar) return;
|
||||||
|
|
||||||
|
for (Player player : world.getPlayers()) {
|
||||||
|
if (!playersWithDisplay.getOrDefault(player.getUniqueId(), new HashSet<>()).contains(world.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
WeatherData playerData = data;
|
||||||
|
String location = playerLocations.getOrDefault(player.getUniqueId(), "");
|
||||||
|
if (!location.isEmpty()) {
|
||||||
|
try {
|
||||||
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, config.units, getLogger());
|
||||||
|
WeatherFetcher.WeatherData fetched = fetcher.fetch();
|
||||||
|
playerData = new WeatherData(fetched.dateTime, fetched.weatherMain, fetched.temperature);
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String dateStr = playerData.dateTime.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
|
||||||
|
String timeStr = formatTime(playerData.dateTime, config.timeFormat);
|
||||||
|
String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F";
|
||||||
|
String weatherIcon = config.displayWeatherIcon ? getWeatherSymbol(playerData.weatherMain) + " " : "";
|
||||||
|
String tempStr = String.format("%.1f%s", playerData.temperature, tempUnit);
|
||||||
|
|
||||||
|
Component message = Component.text()
|
||||||
|
.append(Component.text(dateStr + " ", NamedTextColor.AQUA, TextDecoration.BOLD))
|
||||||
|
.append(Component.text(timeStr + " ", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(weatherIcon, NamedTextColor.WHITE))
|
||||||
|
.append(Component.text(tempStr, NamedTextColor.GREEN))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Component paddedMessage;
|
||||||
|
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) {
|
||||||
|
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
|
||||||
|
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
World world = player.getWorld();
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(world.getName(), worldConfigs.get("defaults"));
|
||||||
|
if (!config.enabled) return;
|
||||||
|
WeatherData data = worldWeatherData.get(world.getName());
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
|
String countryCode = getCountryCode(config.location);
|
||||||
|
String localizedWeather = getLocalizedWeatherMain(data.weatherMain, countryCode);
|
||||||
|
String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F";
|
||||||
|
String city = config.location.split(",")[0];
|
||||||
|
String message = String.format("%s: %s, %.1f%s", city, localizedWeather, data.temperature, tempUnit);
|
||||||
|
audiences.player(player).sendActionBar(Component.text(message, NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInventoryClick(InventoryClickEvent event) {
|
||||||
|
Player player = (Player) event.getWhoClicked();
|
||||||
|
if (!playerGUIs.containsKey(player.getUniqueId()) || event.getInventory() != playerGUIs.get(player.getUniqueId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.setCancelled(true);
|
||||||
|
ItemStack clickedItem = event.getCurrentItem();
|
||||||
|
if (clickedItem == null || clickedItem.getType() == Material.AIR) return;
|
||||||
|
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults"));
|
||||||
|
String countryCode = getCountryCode(config.location);
|
||||||
|
|
||||||
|
if (clickedItem.getType() == Material.BOOK) {
|
||||||
|
player.closeInventory();
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("gui_setlocation_prompt", countryCode), NamedTextColor.YELLOW));
|
||||||
|
} else if (clickedItem.getType() == Material.REDSTONE_TORCH) {
|
||||||
|
String worldName = player.getWorld().getName();
|
||||||
|
HashSet<String> worlds = playersWithDisplay.computeIfAbsent(player.getUniqueId(), k -> new HashSet<>());
|
||||||
|
if (worlds.contains(worldName)) {
|
||||||
|
worlds.remove(worldName);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("toggle_disabled", countryCode, "world", worldName), NamedTextColor.RED));
|
||||||
|
} else {
|
||||||
|
worlds.add(worldName);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("toggle_enabled", countryCode, "world", worldName), NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
} else if (clickedItem.getType() == Material.PAPER) {
|
||||||
|
player.closeInventory();
|
||||||
|
new WeatherForecastCommand().onCommand(player, null, "weatherforecast", new String[]{});
|
||||||
|
} else if (clickedItem.getType() == Material.OAK_SIGN) {
|
||||||
|
player.closeInventory();
|
||||||
|
String infoMessage = "RealTimeWeather Plugin\nVersion: 1.0\nAutor: M_Viper\nGetestete Minecraft-Version: 1.21.1 - 1.21.8";
|
||||||
|
audiences.player(player).sendMessage(Component.text(infoMessage, NamedTextColor.AQUA));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInventoryClose(InventoryCloseEvent event) {
|
||||||
|
Player player = (Player) event.getPlayer();
|
||||||
|
playerGUIs.remove(player.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class WeatherData {
|
||||||
|
ZonedDateTime dateTime;
|
||||||
|
String weatherMain;
|
||||||
|
double temperature;
|
||||||
|
|
||||||
|
public WeatherData(ZonedDateTime dateTime, String weatherMain, double temperature) {
|
||||||
|
this.dateTime = dateTime;
|
||||||
|
this.weatherMain = weatherMain;
|
||||||
|
this.temperature = temperature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PlayerConfig {
|
||||||
|
private final File configFile;
|
||||||
|
private final FileConfiguration config;
|
||||||
|
|
||||||
|
public PlayerConfig(UUID playerId) {
|
||||||
|
File playerDir = new File(getDataFolder(), "players");
|
||||||
|
playerDir.mkdirs();
|
||||||
|
configFile = new File(playerDir, playerId.toString() + ".yml");
|
||||||
|
config = YamlConfiguration.loadConfiguration(configFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return config.getString("location", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(String location) {
|
||||||
|
config.set("location", location);
|
||||||
|
try {
|
||||||
|
config.save(configFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().warning("Fehler beim Speichern der Spieler-Konfiguration: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WetterCommand implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (args.length == 0) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("usage", countryCode), NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("help")) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
Component helpMessage = Component.text()
|
||||||
|
.append(Component.text(getLocalizedMessage("help_header", countryCode), NamedTextColor.AQUA, TextDecoration.BOLD))
|
||||||
|
.append(Component.newline())
|
||||||
|
.append(Component.text("/wetter help", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(" - " + getLocalizedMessage("help_help", countryCode), NamedTextColor.WHITE))
|
||||||
|
.append(Component.newline())
|
||||||
|
.append(Component.text("/wetter reload", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(" - " + getLocalizedMessage("help_reload", countryCode), NamedTextColor.WHITE))
|
||||||
|
.append(Component.newline())
|
||||||
|
.append(Component.text("/wetter setlocation <city,country>", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(" - " + getLocalizedMessage("help_setlocation", countryCode), NamedTextColor.WHITE))
|
||||||
|
.append(Component.newline())
|
||||||
|
.append(Component.text("/wetter query", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(" - " + getLocalizedMessage("help_query", countryCode), NamedTextColor.WHITE))
|
||||||
|
.append(Component.newline())
|
||||||
|
.append(Component.text("/wetter info", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(" - " + getLocalizedMessage("help_info", countryCode), NamedTextColor.WHITE))
|
||||||
|
.append(Component.newline())
|
||||||
|
.append(Component.text("/wetter gui", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(" - " + getLocalizedMessage("help_gui", countryCode), NamedTextColor.WHITE))
|
||||||
|
.append(Component.newline())
|
||||||
|
.append(Component.text("/weatherforecast", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(" - " + getLocalizedMessage("help_weatherforecast", countryCode), NamedTextColor.WHITE))
|
||||||
|
.append(Component.newline())
|
||||||
|
.append(Component.text("/toggleweather", NamedTextColor.YELLOW))
|
||||||
|
.append(Component.text(" - " + getLocalizedMessage("help_toggleweather", countryCode), NamedTextColor.WHITE))
|
||||||
|
.build();
|
||||||
|
audiences.sender(sender).sendMessage(helpMessage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("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));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherUpdateTask != null) {
|
||||||
|
weatherUpdateTask.cancel();
|
||||||
|
}
|
||||||
|
if (syncTask != null) {
|
||||||
|
syncTask.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadConfig();
|
||||||
|
loadConfig();
|
||||||
|
loadLanguageConfig();
|
||||||
|
worldWeatherData.clear();
|
||||||
|
processedLocations.clear();
|
||||||
|
initializePlayerDisplays();
|
||||||
|
|
||||||
|
setDoDaylightCycleForWorlds();
|
||||||
|
startWeatherUpdateTask();
|
||||||
|
startSyncTask();
|
||||||
|
processedLocations.clear();
|
||||||
|
updateWeatherDataForAllWorlds();
|
||||||
|
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("reload_success", countryCode), NamedTextColor.GREEN));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("setlocation")) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length != 2) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("usage_setlocation", countryCode), NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Player player = (Player) sender;
|
||||||
|
String location = args[1];
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, "metric", getLogger());
|
||||||
|
fetcher.fetch(); // Teste, ob der Ort gültig ist
|
||||||
|
PlayerConfig playerConfig = new PlayerConfig(player.getUniqueId());
|
||||||
|
playerConfig.setLocation(location);
|
||||||
|
playerLocations.put(player.getUniqueId(), location);
|
||||||
|
String countryCode = getCountryCode(location);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("location_set", countryCode, "location", location),
|
||||||
|
NamedTextColor.GREEN));
|
||||||
|
} catch (Exception e) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("invalid_location", countryCode, "location", location),
|
||||||
|
NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(WeatherTimeSyncPlugin.this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("query")) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Player player = (Player) sender;
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults"));
|
||||||
|
if (!config.enabled) {
|
||||||
|
String countryCode = getCountryCode(config.location);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("plugin_disabled", countryCode, "world", player.getWorld().getName()),
|
||||||
|
NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String location = playerLocations.getOrDefault(player.getUniqueId(), config.location);
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, config.units, getLogger());
|
||||||
|
WeatherFetcher.WeatherData data = fetcher.fetch();
|
||||||
|
String countryCode = getCountryCode(location);
|
||||||
|
String localizedWeather = getLocalizedWeatherMain(data.weatherMain, countryCode);
|
||||||
|
String tempUnit = config.units.equalsIgnoreCase("metric") ? "°C" : "°F";
|
||||||
|
String city = location.split(",")[0];
|
||||||
|
String message = String.format("%s: %s, %.1f%s", city, localizedWeather, data.temperature, tempUnit);
|
||||||
|
audiences.player(player).sendMessage(Component.text(message, NamedTextColor.GREEN));
|
||||||
|
} 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(WeatherTimeSyncPlugin.this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("info")) {
|
||||||
|
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));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("gui")) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Player player = (Player) sender;
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults"));
|
||||||
|
if (!config.enabled) {
|
||||||
|
String countryCode = getCountryCode(config.location);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("plugin_disabled", countryCode, "world", player.getWorld().getName()),
|
||||||
|
NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
player.openInventory(createWeatherGUI(player));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("usage", countryCode), NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WeatherForecastCommand implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Player player = (Player) sender;
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(player.getWorld().getName(), worldConfigs.get("defaults"));
|
||||||
|
if (!config.enabled) {
|
||||||
|
String countryCode = getCountryCode(config.location);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("plugin_disabled", countryCode, "world", player.getWorld().getName()),
|
||||||
|
NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String location = playerLocations.getOrDefault(player.getUniqueId(), config.location);
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
WeatherFetcher fetcher = new WeatherFetcher(apiKey, location, config.units, getLogger());
|
||||||
|
JSONObject json = fetcher.fetchForecast();
|
||||||
|
JSONArray list = json.getJSONArray("list");
|
||||||
|
|
||||||
|
String[] locationParts = location.split(",");
|
||||||
|
String countryCode = locationParts.length > 1 ? locationParts[1].trim() : "";
|
||||||
|
String city = locationParts[0].trim();
|
||||||
|
|
||||||
|
String forecastMessage = getLocalizedMessage("forecast_header", countryCode, "location", city);
|
||||||
|
Component message = Component.text(forecastMessage, NamedTextColor.AQUA);
|
||||||
|
|
||||||
|
for (int i = 0; i < list.length() && i < 40; i += 8) {
|
||||||
|
JSONObject forecast = list.getJSONObject(i);
|
||||||
|
long dt = forecast.getLong("dt");
|
||||||
|
String weatherMain = forecast.getJSONArray("weather").getJSONObject(0).getString("main");
|
||||||
|
double temp = forecast.getJSONObject("main").getDouble("temp");
|
||||||
|
ZonedDateTime dateTime = Instant.ofEpochSecond(dt).atZone(ZoneId.of("UTC"));
|
||||||
|
|
||||||
|
String localizedWeatherMain = getLocalizedWeatherMain(weatherMain, countryCode);
|
||||||
|
|
||||||
|
message = message.append(Component.newline())
|
||||||
|
.append(Component.text(
|
||||||
|
dateTime.format(DateTimeFormatter.ofPattern("dd.MM.yyyy")) + ": " +
|
||||||
|
localizedWeatherMain + ", " + String.format("%.1f%s", temp, config.units.equalsIgnoreCase("metric") ? "°C" : "°F"),
|
||||||
|
NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
audiences.player(player).sendMessage(message);
|
||||||
|
} 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(WeatherTimeSyncPlugin.this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ToggleWeatherCommand implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (!(sender instanceof Player)) {
|
||||||
|
String countryCode = getCountryCode(worldConfigs.get("defaults").location);
|
||||||
|
audiences.sender(sender).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("only_players", countryCode), NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Player player = (Player) sender;
|
||||||
|
String worldName = player.getWorld().getName();
|
||||||
|
WorldConfig config = worldConfigs.getOrDefault(worldName, worldConfigs.get("defaults"));
|
||||||
|
if (!config.enabled) {
|
||||||
|
String countryCode = getCountryCode(config.location);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("plugin_disabled", countryCode, "world", worldName),
|
||||||
|
NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String countryCode = getCountryCode(config.location);
|
||||||
|
HashSet<String> worlds = playersWithDisplay.computeIfAbsent(player.getUniqueId(), k -> new HashSet<>());
|
||||||
|
if (worlds.contains(worldName)) {
|
||||||
|
worlds.remove(worldName);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("toggle_disabled", countryCode, "world", worldName), NamedTextColor.RED));
|
||||||
|
} else {
|
||||||
|
worlds.add(worldName);
|
||||||
|
audiences.player(player).sendMessage(Component.text(
|
||||||
|
getLocalizedMessage("toggle_enabled", countryCode, "world", worldName), NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user