Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {
implementation(libs.alpslib.utils) {
exclude(group = "com.github.cryptomorin", module = "XSeries")
}
implementation(libs.alpslib.geo)
implementation(libs.com.alpsbte.canvas)
implementation(libs.com.github.cryptomorin.xseries)
implementation(libs.net.wesjd.anvilgui)
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fawe-bom = "1.56" # Ref: https://github.com/IntellectualSites/bom
bstats = "3.+" # https://central.sonatype.com/artifact/org.bstats/bstats-bukkit
bluemap-api = "2.+" # Ref: https://github.com/BlueMap-Minecraft/BlueMapAPI
net-buildtheearth-projection = "1.+" # Ref: https://github.com/BuildTheEarth/projection
alpslib-geo = "1.0.0" # https://mvn.alps-bte.com/service/rest/repository/browse/alps-bte/com/alpsbte/alpslib/alpslib-geo/

[libraries]
com-alpsbte-alpslib-alpslib-libpsterra = { module = "com.alpsbte.alpslib:alpslib-libpsterra", version.ref = "com-alpsbte-alpslib-alpslib-libpsterra" }
Expand All @@ -41,6 +42,7 @@ fawe-bom = { module = "com.intellectualsites.bom:bom-newest", version.ref = "faw
bstats-bukkit = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" }
bluemap-api = { module = "de.bluecolored:bluemap-api", version.ref = "bluemap-api" }
net-buildtheearth-projection = { module = "net.buildtheearth:projection", version.ref = "net-buildtheearth-projection"}
alpslib-geo = { module = "com.alpsbte.alpslib:alpslib-geo", version.ref = "alpslib-geo" }

[plugins]
lombok = { id = "io.freefair.lombok", version.ref = "io-freefair-lombok" }
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
//mavenLocal() // NEVER use in Production/Commits!
// mavenLocal() // NEVER use in Production/Commits!
maven {
url = uri("https://repo.papermc.io/repository/maven-public/")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import net.buildtheearth.buildteamtools.modules.navigation.components.warps.model.WarpGroup;
import net.buildtheearth.buildteamtools.modules.network.NetworkModule;
import net.buildtheearth.buildteamtools.modules.network.model.BuildTeam;
import net.buildtheearth.buildteamtools.modules.network.model.Region;
import net.buildtheearth.model.GeographicalCoordinate;
import net.buildtheearth.model.MinecraftCoordinate;
import net.md_5.bungee.api.chat.ClickEvent;
Expand All @@ -21,8 +22,10 @@
import org.bukkit.UnsafeValues;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NonNull;

@UtilityClass
public class NavUtils {
Expand Down Expand Up @@ -90,32 +93,34 @@ public static void sendNoIpMessage(@NotNull Player player, String buildteam) {
public static @Nullable NavSwitchType determineSwitchPossibilityOrMsgPlayerIfNone(@NotNull Player player, @NotNull BuildTeam targetBuildTeam) {
if (targetBuildTeam.isConnected() && targetBuildTeam.getServerName() != null) {
return NavSwitchType.NETWORK;
} else if (targetBuildTeam.getIP() != null) {
if (isTransferCapable(player, targetBuildTeam)) {
return NavSwitchType.TRANSFER;
} else {
sendNotConnectedMessage(player, targetBuildTeam.getIP(), targetBuildTeam.getName());
return null;
}
} else {
}

if (targetBuildTeam.getIP() == null) {
sendNoIpMessage(player, targetBuildTeam.getName());
return null;
}

if (isTransferCapable(player, targetBuildTeam)) {
return NavSwitchType.TRANSFER;
}

sendNotConnectedMessage(player, targetBuildTeam.getIP(), targetBuildTeam.getName());
return null;
}

public enum NavSwitchType {
TRANSFER, NETWORK
}

public static void switchToTeam(BuildTeam team, Player clickPlayer) {
var type = NavUtils.determineSwitchPossibilityOrMsgPlayerIfNone(clickPlayer, team);

if (type != null) {
if (type == NavUtils.NavSwitchType.NETWORK) {
NavUtils.sendPlayerToConnectedServer(clickPlayer, team.getServerName());
} else if (type == NavUtils.NavSwitchType.TRANSFER) {
NavUtils.transferPlayer(clickPlayer, team.getIP());
}
NavSwitchType type = determineSwitchPossibilityOrMsgPlayerIfNone(clickPlayer, team);
if (type == null) {
return;
}

switch (type) {
case NETWORK -> sendPlayerToConnectedServer(clickPlayer, team.getServerName());
case TRANSFER -> transferPlayer(clickPlayer, team.getIP());
}
}

Expand All @@ -140,7 +145,8 @@ public static void switchToTeam(BuildTeam team, Player clickPlayer) {
* @param pitch Player's pitch
* @return A bukkit location matching the coordinates, yaw and pitch specified. Height is terrain elevation +2.
*/
public static Location getLocationFromCoordinatesYawPitch(GeographicalCoordinate coordinate, float yaw, float pitch) {
@Contract("_, _, _ -> new")
public static @NonNull Location getLocationFromCoordinatesYawPitch(GeographicalCoordinate coordinate, float yaw, float pitch) {
try {
MinecraftCoordinate mcCoord = Projection.toMinecraft(coordinate);

Expand Down Expand Up @@ -170,7 +176,33 @@ public static Location getLocationFromCoordinatesYawPitch(GeographicalCoordinate
* @param coordinate Latitude and longitude of the location
* @return A bukkit location matching the coordinates. Height is terrain elevation +2.
*/
public static Location getLocationFromCoordinates(GeographicalCoordinate coordinate) {
@Contract("_ -> new")
public static @NonNull Location getLocationFromCoordinates(GeographicalCoordinate coordinate) {
return getLocationFromCoordinatesYawPitch(coordinate, 0, 0);
}

/**
* Returns the CCA2 code of the country of the given country name.
*/
public static String getCCA2FromCountryName(String countryName, Player clickPlayer) {
Region region = findRegionByName(countryName);
if (region != null) {
return region.getCountryCodeCca2();
}

clickPlayer.sendMessage(ChatHelper.getErrorString("Could not find the country of the location! Please report that"));
return "";
}

private static @Nullable Region findRegionByName(String countryName) {
BuildTeam buildTeam = NetworkModule.getInstance().getBuildTeam();
if (buildTeam == null) {
return null;
}

return buildTeam.getRegions().stream()
.filter(region -> region.getName().equals(countryName))
.findFirst()
.orElse(null);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.buildtheearth.buildteamtools.modules.navigation;

import com.alpsbte.alpslib.geo.rgc.RgcHandler;
import com.alpsbte.alpslib.utils.ChatHelper;
import lombok.Getter;
import net.buildtheearth.buildteamtools.BuildTeamTools;
import net.buildtheearth.buildteamtools.modules.Module;
Expand All @@ -21,6 +23,19 @@
import net.buildtheearth.buildteamtools.utils.io.ConfigPaths;
import net.buildtheearth.buildteamtools.utils.io.ConfigUtil;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NonNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;

/**
* Manages all things related to universal tpll
Expand All @@ -36,7 +51,9 @@ public class NavigationModule extends Module {
private TpllComponent tpllComponent;
@Getter
private BluemapComponent bluemapComponent;

@Getter
@Nullable
private RgcHandler rgcHandler = null;
Comment thread
Zoriot marked this conversation as resolved.

private static NavigationModule instance = null;

Expand All @@ -60,15 +77,79 @@ public void enable() {
navigatorComponent = new NavigatorComponent();
tpllComponent = new TpllComponent();

// Check if BlueMap plugin is enabled and config allows BlueMap integration
boolean bluemapConfigEnabled = BuildTeamTools.getInstance().getConfig(ConfigUtil.NAVIGATION)
.getBoolean(ConfigPaths.Navigation.BLUEMAP_ENABLED, true);
var navConfig = BuildTeamTools.getInstance().getConfig(ConfigUtil.NAVIGATION);
Comment thread
Zoriot marked this conversation as resolved.
initializeRgcHandler(navConfig);
initializeBluemapComponent(navConfig);

super.enable();
}

private void initializeRgcHandler(@NonNull FileConfiguration navConfig) {
if (!navConfig.getBoolean(ConfigPaths.Navigation.RGC_LOCAL_DB_ENABLED, false)) {
return;
}

File rgcFile = resolveRgcDatabaseFile(navConfig);
ChatHelper.logDebug("Reverse Geocode local database support is enabled. Checking for local database file at: %s", rgcFile.getAbsolutePath());

if (rgcFile.exists()) {
rgcHandler = createRgcHandler(rgcFile);
return;
}

downloadRgcDatabaseAsync(rgcFile, navConfig);
}

private @NonNull File resolveRgcDatabaseFile(@NonNull FileConfiguration navConfig) {
String path = navConfig.getString(ConfigPaths.Navigation.RGC_LOCAL_DB_PATH, "bs.file");
return BuildTeamTools.getInstance().getDataPath()
.resolve("modules/navigation")
.resolve(path)
.toFile();
}

@Contract("_ -> new")
private @NonNull RgcHandler createRgcHandler(File rgcFile) {
return new RgcHandler(rgcFile, BuildTeamTools.getInstance().getSLF4JLogger(), false);
}

private void downloadRgcDatabaseAsync(File rgcFile, FileConfiguration navConfig) {
BuildTeamTools.getInstance().getComponentLogger().info(
"Reverse Geocode local database is enabled but the file does not exist at the specified path, installing it from the configured url.");
Bukkit.getScheduler().runTaskAsynchronously(BuildTeamTools.getInstance(), () -> {
try {
downloadRgcDatabase(rgcFile, navConfig);
Bukkit.getScheduler().runTask(BuildTeamTools.getInstance(), () -> {
rgcHandler = createRgcHandler(rgcFile);
BuildTeamTools.getInstance().getComponentLogger().info(
"Successfully downloaded Reverse Geocode local database and enabled local database support for Reverse Geocoding.");
});
} catch (Exception e) {
BuildTeamTools.getInstance().getComponentLogger().error(
"Failed to download Reverse Geocode local database from the configured url, disabling local database support for Reverse Geocoding.", e);
navConfig.set(ConfigPaths.Navigation.RGC_LOCAL_DB_ENABLED, false);
}
});
}

private void downloadRgcDatabase(@NonNull File rgcFile, FileConfiguration navConfig) throws IOException {
if (!rgcFile.getParentFile().mkdirs()) {
BuildTeamTools.getInstance().getComponentLogger().warn(
"Failed to create parent directories for Reverse Geocode local database file. Make sure the plugin has the necessary permissions to create directories and files in the plugin data folder.");
}
URL url = URI.create(navConfig.getString(ConfigPaths.Navigation.RGC_LOCAL_DB_UPDATE_URL, "")).toURL();
try (ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(rgcFile)) {
FileChannel fileChannel = fileOutputStream.getChannel();
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
}
}

private void initializeBluemapComponent(@NonNull FileConfiguration navConfig) {
boolean bluemapConfigEnabled = navConfig.getBoolean(ConfigPaths.Navigation.BLUEMAP_ENABLED, true);
if (Bukkit.getPluginManager().isPluginEnabled("BlueMap") && bluemapConfigEnabled) {
bluemapComponent = new BluemapComponent();
}

super.enable();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ public static void createWarp(@NonNull Player creator, WarpGroup group) {
String regionName = result[0];
String countryCodeCCA2 = result[1].toUpperCase();

if (countryCodeCCA2.isEmpty()) countryCodeCCA2 = NavUtils.getCCA2FromCountryName(regionName, creator);

//Check if the team owns this region/country
boolean ownsRegion = NetworkModule.getInstance().ownsRegion(regionName, countryCodeCCA2);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import net.buildtheearth.OutOfProjectionBoundsException;
import net.buildtheearth.Projection;
import net.buildtheearth.buildteamtools.BuildTeamTools;
import net.buildtheearth.buildteamtools.modules.navigation.NavUtils;
import net.buildtheearth.buildteamtools.modules.navigation.components.warps.model.Warp;
import net.buildtheearth.buildteamtools.modules.network.NetworkModule;
import net.buildtheearth.buildteamtools.modules.network.api.OpenStreetMapAPI;
Expand Down Expand Up @@ -144,6 +145,9 @@ protected void setItemClickEventsAsync() {
String regionName = result[0];
String countryCodeCCA2 = result[1].toUpperCase();

if (countryCodeCCA2.isEmpty())
countryCodeCCA2 = NavUtils.getCCA2FromCountryName(regionName, clickPlayer);

//Check if the team owns this region/country
boolean ownsRegion = NetworkModule.getInstance().ownsRegion(regionName, countryCodeCCA2);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package net.buildtheearth.buildteamtools.modules.network.api;
Comment thread
Zoriot marked this conversation as resolved.

import com.alpsbte.alpslib.geo.AdminLevel;
import com.alpsbte.alpslib.utils.ChatHelper;
import net.buildtheearth.buildteamtools.BuildTeamTools;
import net.buildtheearth.buildteamtools.modules.navigation.NavigationModule;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.jspecify.annotations.NonNull;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
Expand All @@ -15,6 +20,44 @@
* @return The country name and country code belonging to this location
*/
public static @NotNull CompletableFuture<String[]> getCountryFromLocationAsync(double @NotNull [] coordinates) {
if (canUseRgcHandler()) {
return getCountryFromRgcAsync(coordinates);
}
return getCountryFromPhotonAsync(coordinates);
}

private static boolean canUseRgcHandler() {
return NavigationModule.getInstance().isEnabled()
&& NavigationModule.getInstance().getRgcHandler() != null;
}

private static @NotNull CompletableFuture<String[]> getCountryFromRgcAsync(double @NonNull [] coordinates) {
CompletableFuture<String[]> future = new CompletableFuture<>();
ChatHelper.logDebug("Using custom file API to get country from location: %s, %s", coordinates[0], coordinates[1]);

if (!Bukkit.isPrimaryThread()) {
ChatHelper.logDebug("Not on main thread: scheduling RGC lookup on main thread...");
Bukkit.getScheduler().runTask(BuildTeamTools.getInstance(), () -> completeRgcLookup(coordinates, future));
return future;
}

completeRgcLookup(coordinates, future);
return future;
}

private static void completeRgcLookup(double[] coordinates, CompletableFuture<String[]> future) {
try {
if (NavigationModule.getInstance().getRgcHandler() == null) throw new AssertionError("RgcHandler have to be initialized first");
var location = NavigationModule.getInstance().getRgcHandler()
.locationFromCoordinates((float) coordinates[0], (float) coordinates[1]);
ChatHelper.logDebug("RGC lookup successful: %s", location);

Check notice on line 53 in src/main/java/net/buildtheearth/buildteamtools/modules/network/api/OpenStreetMapAPI.java

View workflow job for this annotation

GitHub Actions / Qodana for JVM

Constant values

Value `location` is always 'null'

Check warning on line 53 in src/main/java/net/buildtheearth/buildteamtools/modules/network/api/OpenStreetMapAPI.java

View workflow job for this annotation

GitHub Actions / Qodana for JVM

Confusing argument to varargs method

Confusing argument `location`, unclear if a varargs or non-varargs call is desired
future.complete(new String[]{location.get(AdminLevel.COUNTRY), ""});
} catch (Exception ex) {
future.completeExceptionally(ex);
}
}

private static @NotNull CompletableFuture<String[]> getCountryFromPhotonAsync(double @NonNull [] coordinates) {
CompletableFuture<String[]> future = new CompletableFuture<>();
String url = "https://photon.komoot.io/reverse?lat=" + coordinates[0] + "&lon=" + coordinates[1] + "&lang=en";
Comment thread
Zoriot marked this conversation as resolved.
Comment thread
Zoriot marked this conversation as resolved.

Expand All @@ -23,18 +66,7 @@
API.getAsync(url, new API.ApiResponseCallback() {
@Override
public void onResponse(String response) {
JSONObject jsonObject = API.createJSONObject(response);

ChatHelper.logDebug("Response from OpenStreetMap: %s", jsonObject);

JSONObject featuresObject = (JSONObject) ((JSONArray) jsonObject.get("features")).getFirst();

JSONObject propertiesObject = (JSONObject) featuresObject.get("properties");

String countryCodeCca2 = (String) propertiesObject.get("countrycode");
String countryName = (String) propertiesObject.get("country");

future.complete(new String[]{countryName, countryCodeCca2});
completePhotonLookup(response, future);
}

@Override
Expand All @@ -44,4 +76,17 @@
});
return future;
}

private static void completePhotonLookup(String response, @NonNull CompletableFuture<String[]> future) {
JSONObject jsonObject = API.createJSONObject(response);
ChatHelper.logDebug("Response from OpenStreetMap: %s", jsonObject);

JSONObject featuresObject = (JSONObject) ((JSONArray) jsonObject.get("features")).getFirst();
JSONObject propertiesObject = (JSONObject) featuresObject.get("properties");

String countryCodeCca2 = (String) propertiesObject.get("countrycode");
String countryName = (String) propertiesObject.get("country");

future.complete(new String[]{countryName, countryCodeCca2});
}
}
Loading
Loading