local geoip, remove maxmind dependency

This commit is contained in:
Minecon724 2024-01-21 19:08:54 +00:00
parent 3abb437c5b
commit 31afa3b10f
20 changed files with 437 additions and 164 deletions

View file

@ -1,3 +1,8 @@
Current:
- weather forecast https://openweathermap.org/forecast5
- multiple conditions
- on join event
Milestone: yesterday
- fix bugs
@ -8,6 +13,7 @@ Milestone: 0.5.1
Milestone: 0.6.0
- account for real sun movement, not just time
- release / debug separate versions
Milestone: future
- weather simulator (weather is clientside rn and doesnt have things such as lightning or other effects)

14
pom.xml
View file

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>pl.minecon724</groupId>
<artifactId>realweather</artifactId>
<version>0.5.0.1</version>
<version>0.5.1-DEV</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
@ -24,15 +24,9 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>4.2.0</version>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

View file

@ -1,35 +1,46 @@
package pl.minecon724.realweather;
import com.maxmind.geoip2.WebServiceClient;
import java.io.IOException;
import java.util.logging.Logger;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import pl.minecon724.realweather.map.WorldMap;
import pl.minecon724.realweather.realtime.RealTimeCommander;
import pl.minecon724.realweather.weather.WeatherCommander;
import pl.minecon724.realweather.weather.exceptions.DisabledException;
import pl.minecon724.realweather.weather.exceptions.ModuleDisabledException;
public class RW extends JavaPlugin {
FileConfiguration config;
public class RealWeatherPlugin extends JavaPlugin {
WebServiceClient client = null;
private final Logger logger = getLogger();
private FileConfiguration config;
@Override
public void onEnable() {
long start = System.currentTimeMillis();
saveDefaultConfig();
config = getConfig();
SubLogger.init(
getLogger(),
logger,
config.getBoolean("logging", false)
);
WorldMap.init(
config.getConfigurationSection("map")
);
ConfigurationSection mapConfigurationSection = config.getConfigurationSection("map");
try {
WorldMap.init(
mapConfigurationSection,
getDataFolder()
);
} catch (IOException e) {
logger.severe("Unable to initialize WorldMap:");
e.printStackTrace();
getServer().getPluginManager().disablePlugin(this);
}
WeatherCommander weatherCommander = new WeatherCommander(this);
try {
@ -37,9 +48,10 @@ public class RW extends JavaPlugin {
config.getConfigurationSection("weather")
);
weatherCommander.start();
} catch (DisabledException e) {
getLogger().info("Weather module disabled");
} catch (ModuleDisabledException e) {
logger.info("Weather is disabled by user");
} catch (IllegalArgumentException e) {
logger.severe("Couldn't initialize weather provider:");
e.printStackTrace();
getServer().getPluginManager().disablePlugin(this);
}
@ -50,11 +62,9 @@ public class RW extends JavaPlugin {
config.getConfigurationSection("time")
);
realTimeCommander.start();
} catch (DisabledException e) {
getLogger().info("Time module disabled");
} catch (ModuleDisabledException e) {
logger.info("Time is disabled by user");
}
long end = System.currentTimeMillis();
this.getLogger().info( String.format( this.getName() + " enabled! (%s ms)", Long.toString( end-start ) ) );
}
}

View file

@ -4,19 +4,35 @@ import java.util.logging.Level;
import java.util.logging.Logger;
public class SubLogger {
// TODO TODO too many static
private static Logger LOGGER;
private static boolean ENABLED;
private String name;
/**
* Initialize the SubLogger
* @param logger parent logger, usually JavaPlugin#getLogger()
* @param enabled is logging enabled
*/
static void init(Logger logger, boolean enabled) {
LOGGER = logger;
ENABLED = enabled;
}
/**
* Instantiate a SubLogger instance
* @param name name, it will be prefixing messages
*/
public SubLogger(String name) {
this.name = name;
}
/**
* Log a message
* @param level
* @param format message, formatted like {@link String#format(String, Object...)}
* @param args args for formatting
*/
public void log(Level level, String format, Object... args) {
if (!ENABLED) return;
@ -27,7 +43,45 @@ public class SubLogger {
LOGGER.log(level, String.format("[%s] " + format, combinedArgs));
}
/**
* Log an info message
* see {@link SubLogger#log(Level, String, Object...)}
* @param format message
* @param args args
*/
public void info(String format, Object... args) {
this.log(Level.INFO, format, args);
}
public void info(String message) {
this.log(Level.INFO, message, new Object[0]);
}
/**
* Log a severe message
* see {@link SubLogger#log(Level, String, Object...)}
* @param format message
* @param args args
*/
public void severe(String format, Object... args) {
this.log(Level.SEVERE, format, args);
}
public void severe(String message) {
this.log(Level.SEVERE, message, new Object[0]);
}
/**
* Log a warning message
* see {@link SubLogger#log(Level, String, Object...)}
* @param format message
* @param args args
*/
public void warning(String format, Object... args) {
this.log(Level.WARNING, format, args);
}
public void warning(String message) {
this.log(Level.WARNING, message, new Object[0]);
}
}

View file

@ -0,0 +1,51 @@
package pl.minecon724.realweather.geoip;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import pl.minecon724.realweather.SubLogger;
public class DatabaseDownloader {
private SubLogger subLogger = new SubLogger("download");
private URL downloadUrl;
public DatabaseDownloader(URL downloadUrl) {
this.downloadUrl = downloadUrl;
}
// TODO verify
public void download(File file, boolean ipv6) throws IOException {
URL url = new URL(downloadUrl, ipv6 ? "ipv6.geo.gz" : "ipv4.geo.gz");
URLConnection connection = url.openConnection();
connection.connect();
InputStream inputStream = connection.getInputStream();
ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream);
file.getParentFile().mkdirs();
file.createNewFile();
FileOutputStream fileOutputStream = new FileOutputStream(file);
FileChannel fileChannel = fileOutputStream.getChannel();
long size = connection.getHeaderFieldLong("Content-Length", 0);
long position = 0;
while (position < size) {
position += fileChannel.transferFrom(readableByteChannel, position, 1048576);
subLogger.info("%d%%", (int)(1.0 * position / size * 100));
}
fileChannel.close();
fileOutputStream.close();
readableByteChannel.close();
inputStream.close(); // ok
}
}

View file

@ -0,0 +1,96 @@
package pl.minecon724.realweather.geoip;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Shorts;
import pl.minecon724.realweather.map.Coordinates;
public class GeoIPDatabase {
private byte formatVersion;
private long timestamp;
public HashMap<Integer, Coordinates> entries = new HashMap<>();
public void read(File file) throws IOException, FileNotFoundException {
if (!file.exists()) {
throw new FileNotFoundException();
}
if (timestamp != 0) {
throw new IOException("GeoIPDatabase can only be read once");
}
FileInputStream fileInputStream = new FileInputStream(file);
GZIPInputStream gzipInputStream = new GZIPInputStream(fileInputStream);
formatVersion = (byte) gzipInputStream.read();
byte[] bytes = gzipInputStream.readNBytes(2);
timestamp = recoverTime(bytes);
byte[] address;
Coordinates coordinates;
while (true) { // TODO true?
System.out.println(gzipInputStream.available());
address = gzipInputStream.readNBytes(4);
if (address.length == 0)
break;
coordinates = recoverCoordinates(gzipInputStream.readNBytes(6));
entries.put(IPUtils.toInt(address), coordinates);
}
gzipInputStream.close();
fileInputStream.close();
}
public String getTimestamp() {
return new SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
.format(new Date(timestamp * 1000));
}
public byte getFormatVersion() {
return formatVersion;
}
/**
* 2 bytes to 4 bytes wow magic
* @param bytes 2 bytes
* @return
*/
@SuppressWarnings("null") // TODO better way of this?
private long recoverTime(byte[] bytes) {
long timestamp = 1704067200; // first second of 2024
timestamp += Shorts.fromByteArray(bytes) * 60 * 10;
return timestamp;
}
/**
* Encoded to Coordinates
* @param bytes 3 bytes
* @return decoded Coordinates
*/
private Coordinates recoverCoordinates(byte[] bytes) {
int skewedLatitude = Ints.fromBytes(
(byte)0, bytes[0], bytes[1], bytes[2]
);
int skewedLongitude = Ints.fromBytes(
(byte)0, bytes[3], bytes[4], bytes[5]
);
double latitude = (skewedLatitude - 900000) / 10000.0;
double longitude = (skewedLongitude - 1800000) / 10000.0;
return new Coordinates(latitude, longitude);
}
}

View file

@ -0,0 +1,32 @@
package pl.minecon724.realweather.geoip;
import com.google.common.primitives.Ints;
public class IPUtils {
public static byte[] getSubnetStart(byte[] addressBytes, byte subnet) {
int address = toInt(addressBytes);
int mask = 0xFFFFFFFF << (32 - subnet);
return fromInt(address & mask);
}
@SuppressWarnings("null")
public static int toInt(byte[] address) {
return Ints.fromByteArray(address);
}
public static byte[] fromInt(int value) {
return Ints.toByteArray(value);
}
public static String toString(byte[] address) {
String s = "";
for (int i=0; i<4; i++) {
s += Integer.toString(address[i] & 0xFF);
if (i < 3) s += ".";
}
return s;
}
}

View file

@ -1,7 +1,5 @@
package pl.minecon724.realweather.map;
import com.maxmind.geoip2.record.Location;
public class Coordinates {
public double latitude, longitude;
@ -38,11 +36,4 @@ public class Coordinates {
private static double wrapDouble(double min, double max, double val) {
return min + (val - min) % (max - min);
}
public static Coordinates fromGeoIpLocation(Location location) {
return new Coordinates(
location.getLatitude(),
location.getLongitude()
);
}
}

View file

@ -1,30 +1,48 @@
package pl.minecon724.realweather.map;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import com.maxmind.geoip2.WebServiceClient;
import com.maxmind.geoip2.exception.GeoIp2Exception;
import pl.minecon724.realweather.SubLogger;
import pl.minecon724.realweather.geoip.DatabaseDownloader;
import pl.minecon724.realweather.geoip.GeoIPDatabase;
import pl.minecon724.realweather.geoip.IPUtils;
import pl.minecon724.realweather.map.exceptions.GeoIPException;
public class GeoLocator {
private static GeoLocator INSTANCE = null;
private WebServiceClient client;
private Map<InetAddress, Coordinates> cache;
private SubLogger subLogger = new SubLogger("geolocator");
private GeoIPDatabase database;
private HashMap<InetAddress, Coordinates> cache = new HashMap<>();
public static void init(int accountId, String apiKey) {
public static void init(File databaseFile, String downloadUrl) throws IOException {
INSTANCE = new GeoLocator(
new WebServiceClient.Builder(accountId, apiKey)
.host("geolite.info").build());
new GeoIPDatabase());
INSTANCE.load(databaseFile, downloadUrl);
}
public GeoLocator(WebServiceClient client) {
this.client = client;
this.cache = new HashMap<>();
public GeoLocator(GeoIPDatabase database) {
this.database = database;
}
public void load(File databaseFile, String downloadUrl) throws IOException {
subLogger.info("This product includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com");
try {
database.read(databaseFile);
} catch (FileNotFoundException e) {
new DatabaseDownloader(new URL(downloadUrl))
.download(databaseFile, false);
database.read(databaseFile);
}
subLogger.info("Database: %s", INSTANCE.database.getTimestamp());
}
/**
@ -34,35 +52,37 @@ public class GeoLocator {
* @throws GeoIp2Exception
* @throws IOException
*/
public static Coordinates getCoordinates(InetAddress address)
public static Coordinates getCoordinates(InetAddress inetAddress)
throws GeoIPException {
GeoLocator instance = INSTANCE;
Coordinates coordinates = null;
coordinates = instance.lookup(address);
Coordinates coordinates = INSTANCE.cache.get(inetAddress);
if (coordinates != null)
return coordinates;
try {
coordinates = Coordinates.fromGeoIpLocation(
instance.client.city(address).getLocation()
byte[] address = inetAddress.getAddress();
byte subnet = 32;
while (coordinates == null) {
if (subnet == 0) {
INSTANCE.subLogger.info("Not found :(");
coordinates = new Coordinates(0, 0);
break;
}
int query = IPUtils.toInt(address);
coordinates = INSTANCE.database.entries.get(
query
);
} catch (IOException | GeoIp2Exception e) {
throw new GeoIPException(e.getMessage());
INSTANCE.subLogger.info("trying %s/%d = %d", IPUtils.toString(address), subnet, query);
address = IPUtils.getSubnetStart(address, --subnet);
}
instance.store(address, coordinates);
INSTANCE.subLogger.info("Done, caching");
INSTANCE.cache.put(inetAddress, coordinates);
return coordinates;
}
private Coordinates lookup(InetAddress address) {
return this.cache.get(address);
}
private void store(InetAddress address, Coordinates coordinates) {
this.cache.put(address, coordinates);
}
}

View file

@ -1,5 +1,8 @@
package pl.minecon724.realweather.map;
import java.io.File;
import java.io.IOException;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
@ -24,8 +27,8 @@ public class WorldMap {
this.point = point;
}
public static void init(ConfigurationSection config)
throws IllegalArgumentException {
public static void init(ConfigurationSection config, File dataFolder)
throws IOException {
Type type;
@ -45,8 +48,8 @@ public class WorldMap {
} else if (type == Type.PLAYER) {
GeoLocator.init(
config.getInt("player.geolite2_accountId"),
config.getString("player.geolite2_api_key")
dataFolder.toPath().resolve("geoip/ipv4.geo.gz").toFile(),
config.getString("player.download_url", "https://inferior.network/geoip/")
);
} else if (type == Type.GLOBE) {

View file

@ -14,11 +14,11 @@ import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import pl.minecon724.realweather.RW;
import pl.minecon724.realweather.weather.exceptions.DisabledException;
import pl.minecon724.realweather.RealWeatherPlugin;
import pl.minecon724.realweather.weather.exceptions.ModuleDisabledException;
public class RealTimeCommander implements Listener {
private RW plugin;
private RealWeatherPlugin plugin;
private List<String> worldNames;
private double scale;
@ -31,15 +31,15 @@ public class RealTimeCommander implements Listener {
private RealTimeTask task;
private PlayerTimeSyncTask playerTimeSyncTask;
public RealTimeCommander(RW plugin) {
public RealTimeCommander(RealWeatherPlugin plugin) {
this.plugin = plugin;
}
public void init(ConfigurationSection config)
throws DisabledException {
throws ModuleDisabledException {
if (!config.getBoolean("enabled"))
throw new DisabledException();
throw new ModuleDisabledException();
try {
timezone = ZoneId.of(config.getString("timezone"));

View file

@ -1,6 +1,5 @@
package pl.minecon724.realweather.weather;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@ -9,7 +8,7 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitRunnable;
import pl.minecon724.realweather.RW;
import pl.minecon724.realweather.RealWeatherPlugin;
import pl.minecon724.realweather.SubLogger;
import pl.minecon724.realweather.map.Coordinates;
import pl.minecon724.realweather.map.WorldMap;
@ -17,13 +16,14 @@ import pl.minecon724.realweather.map.WorldMap.Type;
import pl.minecon724.realweather.map.exceptions.GeoIPException;
import pl.minecon724.realweather.weather.WeatherState.State;
import pl.minecon724.realweather.weather.events.WeatherSyncEvent;
import pl.minecon724.realweather.weather.exceptions.WeatherProviderException;
import pl.minecon724.realweather.weather.provider.Provider;
public class GetStateTask extends BukkitRunnable {
private SubLogger subLogger = new SubLogger("weather updater");
private RW plugin;
private RealWeatherPlugin plugin;
private Provider provider;
private WorldMap worldMap;
@ -32,7 +32,7 @@ public class GetStateTask extends BukkitRunnable {
private PluginManager pluginManager = Bukkit.getPluginManager();
public GetStateTask(
RW plugin,
RealWeatherPlugin plugin,
Provider provider,
WorldMap worldMap
) {
@ -92,8 +92,9 @@ public class GetStateTask extends BukkitRunnable {
}
}
}
} catch (IOException e) {
subLogger.info("Error updating: %s", e.getMessage());
} catch (WeatherProviderException e) {
subLogger.info("Weather provider error");
e.printStackTrace();
}
}

View file

@ -26,7 +26,7 @@ public class WeatherChanger implements Listener {
@EventHandler
public void onWorldLoad(WorldLoadEvent event) {
World world = event.getWorld();
subLogger.info("World %s is loading", world.getName());
subLogger.info("World %s has been loaded", world.getName());
if (worldNames.contains(world.getName())) {
worlds.add(world);

View file

@ -1,20 +1,20 @@
package pl.minecon724.realweather.weather;
import java.io.IOException;
import java.util.List;
import org.bukkit.configuration.ConfigurationSection;
import pl.minecon724.realweather.RW;
import pl.minecon724.realweather.RealWeatherPlugin;
import pl.minecon724.realweather.SubLogger;
import pl.minecon724.realweather.map.Coordinates;
import pl.minecon724.realweather.map.WorldMap;
import pl.minecon724.realweather.weather.exceptions.DisabledException;
import pl.minecon724.realweather.weather.exceptions.ModuleDisabledException;
import pl.minecon724.realweather.weather.exceptions.WeatherProviderException;
import pl.minecon724.realweather.weather.provider.Provider;
public class WeatherCommander {
private WorldMap worldMap = WorldMap.getInstance();
private RW plugin;
private RealWeatherPlugin plugin;
private boolean enabled;
private List<String> worldNames;
@ -26,23 +26,23 @@ public class WeatherCommander {
private SubLogger subLogger = new SubLogger("weather");
public WeatherCommander(RW plugin) {
public WeatherCommander(RealWeatherPlugin plugin) {
this.plugin = plugin;
}
/**
* Initialize weather commander
* @param config "weather" ConfigurationSection
* @throws DisabledException if disabled in config
* @throws ModuleDisabledException if disabled in config
* @throws ProviderException if invalid provider config
*/
public void init(ConfigurationSection config)
throws DisabledException, IllegalArgumentException {
throws ModuleDisabledException, IllegalArgumentException {
enabled = config.getBoolean("enabled");
if (!enabled)
throw new DisabledException();
throw new ModuleDisabledException();
worldNames = config.getStringList("worlds");
@ -59,15 +59,15 @@ public class WeatherCommander {
try {
provider.request_state(new Coordinates(0, 0));
} catch (IOException e) {
subLogger.info("Provider test failed, errors may occur", new Object[0]);
} catch (WeatherProviderException e) {
subLogger.severe("Provider test failed, errors may occur");
e.printStackTrace();
}
plugin.getServer().getPluginManager().registerEvents(
new WeatherChanger(worldNames), plugin);
subLogger.info("done", new Object[0]);
subLogger.info("done");
}
public void start() {

View file

@ -1,5 +1,5 @@
package pl.minecon724.realweather.weather.exceptions;
public class DisabledException extends Exception {
public class ModuleDisabledException extends Exception {
}

View file

@ -0,0 +1,9 @@
package pl.minecon724.realweather.weather.exceptions;
public class WeatherProviderException extends Exception {
public WeatherProviderException(String message) {
super(message);
}
}

View file

@ -1,18 +1,19 @@
package pl.minecon724.realweather.weather.provider;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.common.base.Charsets;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonReader;
import pl.minecon724.realweather.map.Coordinates;
import pl.minecon724.realweather.weather.WeatherState.*;
import pl.minecon724.realweather.weather.exceptions.WeatherProviderException;
public class OpenWeatherMapProvider implements Provider {
@ -24,6 +25,11 @@ public class OpenWeatherMapProvider implements Provider {
this.apiKey = apiKey;
}
@Override
public String getName() {
return "OpenWeatherMap";
}
public void init() {
try {
endpoint = new URL("https://api.openweathermap.org");
@ -32,34 +38,40 @@ public class OpenWeatherMapProvider implements Provider {
}
}
public State request_state(Coordinates coordinates) throws IOException {
JSONObject json = new JSONObject();
public State request_state(Coordinates coordinates) throws WeatherProviderException {
JsonObject jsonObject;
try {
URL url = new URL(
endpoint + String.format("/data/2.5/weather?lat=%s&lon=%s&appid=%s",
Double.toString(coordinates.latitude), Double.toString(coordinates.longitude), apiKey
String.format("%s/data/2.5/weather?lat=%f&lon=%f&appid=%s",
endpoint, coordinates.latitude, coordinates.longitude, apiKey
));
InputStream is = url.openStream();
BufferedReader rd = new BufferedReader( new InputStreamReader(is, Charset.forName("UTF-8")) );
StringBuilder sb = new StringBuilder();
int c;
while ((c = rd.read()) != -1) {
sb.append((char) c);
}
is.close();
json = new JSONObject(sb.toString());
BufferedReader rd = new BufferedReader(
new InputStreamReader(is, Charsets.UTF_8));
JsonReader jsonReader = new JsonReader(rd);
jsonObject = new Gson().fromJson(jsonReader, JsonObject.class);
} catch (Exception e) {
throw new IOException("Couldn't contact openweathermap");
e.printStackTrace();
throw new WeatherProviderException("Couldn't contact openweathermap");
}
int stateId;
try {
stateId = json.getJSONArray("weather")
.getJSONObject(0).getInt("id");
} catch (JSONException e) {
throw new IOException("Invalid data from openweathermap");
stateId = jsonObject.getAsJsonArray("weather")
.get(0).getAsJsonObject()
.get("id").getAsInt();
/*
* org.json comparison:
* stateId = json.getJSONArray("weather").getJSONObject(0).getInt("id");
* so is it truly worth it? yes see loading jsonobject from inputstream
*/
} catch (Exception e) {
e.printStackTrace();
throw new WeatherProviderException("Invalid data from openweathermap");
}
// Here comes the mess
@ -67,60 +79,44 @@ public class OpenWeatherMapProvider implements Provider {
ConditionLevel level = ConditionLevel.LIGHT;
if (stateId < 300) {
condition = Condition.THUNDER;
switch (stateId) {
case 200:
case 210:
case 230:
switch (stateId % 10) {
case 0: // 200, 210, 230
level = ConditionLevel.LIGHT;
break;
case 201:
case 211:
case 221:
case 231:
case 1: // 201, 211, 221, 231
level = ConditionLevel.MODERATE;
break;
case 202:
case 212:
case 232:
case 2: // 202, 212, 232
level = ConditionLevel.HEAVY;
}
} else if (stateId < 400) {
condition = Condition.DRIZZLE;
switch (stateId) {
case 300:
case 310:
switch (stateId % 10) {
case 0: // 300, 310
level = ConditionLevel.LIGHT;
break;
case 301:
case 311:
case 313:
case 321:
case 1: // 301, 311, 321
case 3: // 313
level = ConditionLevel.MODERATE;
break;
case 302:
case 312:
case 314:
case 2: // 302, 312
case 4: // 314
level = ConditionLevel.HEAVY;
}
} else if (stateId < 600) {
condition = Condition.RAIN;
switch (stateId) {
case 500:
case 520:
switch (stateId % 10) {
case 0: // 500, 520
level = ConditionLevel.LIGHT;
break;
case 501:
case 511:
case 521:
case 531:
case 1: // 501, 511, 521, 531
level = ConditionLevel.MODERATE;
break;
case 502:
case 522:
case 2: // 502, 522
level = ConditionLevel.HEAVY;
break;
case 503:
case 504:
case 3: // 503
case 4: // 504
level = ConditionLevel.EXTREME;
}
} else if (stateId < 700) {
@ -165,7 +161,16 @@ public class OpenWeatherMapProvider implements Provider {
}
@Override
public String getName() {
return "OpenWeatherMap";
public State[] request_state(Coordinates[] coordinates) throws WeatherProviderException {
// OpenWeatherMap doesnt support bulk requests
int length = coordinates.length;
State[] states = new State[length];
for (int i=0; i<length; i++) {
states[i] = request_state(coordinates[i]);
}
return states;
}
}

View file

@ -1,12 +1,13 @@
package pl.minecon724.realweather.weather.provider;
import java.io.IOException;
import pl.minecon724.realweather.map.Coordinates;
import pl.minecon724.realweather.weather.WeatherState;
import pl.minecon724.realweather.weather.WeatherState.State;
import pl.minecon724.realweather.weather.exceptions.WeatherProviderException;
public interface Provider {
public void init();
public WeatherState.State request_state(Coordinates coordinates) throws IOException;
public String getName();
public State request_state(Coordinates coordinates) throws WeatherProviderException;
public State[] request_state(Coordinates[] coordinates) throws WeatherProviderException;
}

View file

@ -25,9 +25,7 @@ map:
longitude: -89.485937
player:
# Get your own @ https://www.maxmind.com/en/geolite2/signup
geolite2_accountId: 710438
geolite2_api_key: 'qLeseHp4QNQcqRGn'
empty: for now
globe:
# Valid latitude range: -90 to 90

View file

@ -1,9 +1,11 @@
name: RealWeather
author: Minecon724
version: ${project.version}
api-version: 1.16
load: STARTUP
author: Minecon724
main: pl.minecon724.realweather.RW
main: pl.minecon724.realweather.RealWeatherPlugin
libraries:
- org.json:json:20231013
- com.maxmind.geoip2:geoip2:4.2.0
- com.google.code.gson:gson:2.10.1