diff --git a/pandalib-core/pom.xml b/pandalib-core/pom.xml index b822750..7b0dba0 100644 --- a/pandalib-core/pom.xml +++ b/pandalib-core/pom.xml @@ -85,6 +85,27 @@ + + + com.googlecode.maven-download-plugin + download-maven-plugin + 1.7.0 + + + mcversion-download + compile + + wget + + + + + https://api.pandacube.fr/rest/mcversion + ${project.basedir}/src/main/resources/fr/pandacube/lib/core/mc_version + mcversion.json + true + + diff --git a/pandalib-core/src/main/java/fr/pandacube/lib/core/mc_version/MinecraftVersionUtil.java b/pandalib-core/src/main/java/fr/pandacube/lib/core/mc_version/MinecraftVersionUtil.java index 066ba20..8cb3e62 100644 --- a/pandalib-core/src/main/java/fr/pandacube/lib/core/mc_version/MinecraftVersionUtil.java +++ b/pandalib-core/src/main/java/fr/pandacube/lib/core/mc_version/MinecraftVersionUtil.java @@ -4,15 +4,23 @@ import fr.pandacube.lib.util.StringUtil; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; +/** + * Utility class to manipulate {@link String}s representing Minecraft versions. + */ public class MinecraftVersionUtil { - + /** + * Compare two Minecraft version strings. It uses the rules of semantic + * versionning to compare the versions. + * @param v1 the first version to compare. + * @param v2 the second version to compare. + * @return 0 if they are equal, <0 if v1<v2 and vice-versa. + */ public static int compareVersions(String v1, String v2) { int[] v1Int = decomposedVersion(v1); int[] v2Int = decomposedVersion(v2); @@ -27,7 +35,11 @@ public class MinecraftVersionUtil { } - + /** + * Decompose a version string into a series of integers. + * @param v a string representation of a version (eg. 1.19.1). + * @return an array of int representing the provided version (eg. [1, 19, 1]). + */ public static int[] decomposedVersion(String v) { try { return Arrays.stream(v.split("\\.")).mapToInt(Integer::parseInt).toArray(); @@ -36,7 +48,20 @@ public class MinecraftVersionUtil { } } - + /** + * Tells if the two provided Minecraft versions are consecutives. + *

+ * Two versions are consecutives if (considering {@code 1.X[.Y]}): + *

+ * @param v1 the first version. + * @param v2 the second version. + * @return thue if the second version is consecutive to the first one. + */ public static boolean areConsecutives(String v1, String v2) { int[] v1Int = decomposedVersion(v1); int[] v2Int = decomposedVersion(v2); @@ -62,6 +87,17 @@ public class MinecraftVersionUtil { + /** + * Generate a string representation of the provided list of version, with + * merged consecutive versions and using + * {@link StringUtil#joinGrammatically(CharSequence, CharSequence, List)}. + * + * @param versions the minecraft versions list to use. + * @param finalWordSeparator the word separator between the two last versions in the returned string, like "and", + * "or" or any other word of any language. The spaces before and after are already + * concatenated. + * @return a string representation of the provided list of version. + */ public static String toString(List versions, String finalWordSeparator) { if (versions.isEmpty()) return ""; diff --git a/pandalib-core/src/main/java/fr/pandacube/lib/core/mc_version/ProtocolVersion.java b/pandalib-core/src/main/java/fr/pandacube/lib/core/mc_version/ProtocolVersion.java index 888eced..7b3b351 100644 --- a/pandalib-core/src/main/java/fr/pandacube/lib/core/mc_version/ProtocolVersion.java +++ b/pandalib-core/src/main/java/fr/pandacube/lib/core/mc_version/ProtocolVersion.java @@ -2,7 +2,8 @@ package fr.pandacube.lib.core.mc_version; import fr.pandacube.lib.core.json.Json; import fr.pandacube.lib.util.Log; -import org.jetbrains.annotations.ApiStatus.Internal; +import fr.pandacube.lib.util.MinecraftVersion; +import fr.pandacube.lib.util.StringUtil; import java.io.InputStream; import java.io.InputStreamReader; @@ -11,9 +12,22 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; +import java.time.Duration; import java.util.List; import java.util.concurrent.atomic.AtomicReference; +/** + * Class handling a relationship table of known Minecraft version and their + * corresponding protocol version. + *

+ * The data if fetch updated data from an external API on startup. If it fails, + * it uses the data stored in the current package at build time. + *

+ * The public static methos are used to fetch an instance of {@link ProtocolVersion} + * based on the provided protocol version (eg. 763) or Minecraft version (eg. "1.20.1"). + * An instance of this class provides information related to a protocol version + * (the protocol version number and all the corresponding Minecraft versions). + */ public class ProtocolVersion { private static final String ONLINE_DATA_URL = "https://api.pandacube.fr/rest/mcversion"; @@ -28,10 +42,25 @@ public class ProtocolVersion { } } - + /** + * Replace the currently used data cache by a new source. + *

+ * Note: this method is not meant to be used by the final user of + * this class. Use it only if you have a better data source. + * @param data the data to use instead of the provided (external API or packaged file) + */ public static void setRawData(MinecraftVersionList data) { versionList.set(data); } + + /** + * Gets the raw data used internally by this class. + *

+ * Note: this method is not meant to be used by the final user of + * this class. Use it only if you know what you do. + * @return the current instance of {@link MinecraftVersionUtil} uses + * internally by this class. + */ public static MinecraftVersionList getRawData() { initIfNecessary(); return versionList.get(); @@ -40,7 +69,9 @@ public class ProtocolVersion { private static void init() { // try online source first try { - HttpResponse response = HttpClient.newHttpClient() + HttpResponse response = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(5)) + .build() .send(HttpRequest.newBuilder(URI.create(ONLINE_DATA_URL)).build(), BodyHandlers.ofString() ); @@ -70,19 +101,96 @@ public class ProtocolVersion { } - - - public static int ofVersion(String versionId) { + private static int getPVNOfVersion(String version) { initIfNecessary(); - Integer v = versionList.get().protocolOfVersion().get(versionId); + Integer v = versionList.get().protocolOfVersion().get(version); return v == null ? -1 : v; } - - public static List getVersionsOfProtocol(int protocolVersion) { + private static List getVersionsOfPVN(int pvn) { initIfNecessary(); - return versionList.get().versionsOfProtocol().get(protocolVersion); + return versionList.get().versionsOfProtocol().get(pvn); + } + + /** + * Gets the {@link ProtocolVersion} associated with the provided Minecraft version. + * @param version The Minecraft version, in the format "X.X[.X]" (eg. "1.17" or "1.8.8"). + * @return an instance of {@link ProtocolVersion}. + */ + public static ProtocolVersion ofVersion(String version) { + int pvn = getPVNOfVersion(version); + if (pvn == -1) + return null; + List versions = getVersionsOfPVN(pvn); + if (versions == null) { + versions = List.of(version); + } + return new ProtocolVersion(pvn, List.copyOf(versions)); + } + + /** + * Gets the {@link ProtocolVersion} associated with the provided protocol version number. + * @param pvn The protocol version number. + * @return an instance of {@link ProtocolVersion}. + */ + public static ProtocolVersion ofProtocol(int pvn) { + List versions = getVersionsOfPVN(pvn); + if (versions == null) { + return null; + } + return new ProtocolVersion(pvn, List.copyOf(versions)); } + + + /** + * The protocol version number. + */ + public final int protocolVersionNumber; + /** + * All Minecraft version supported by this protocol version number. + */ + public final List versions; + + private ProtocolVersion(int protocolVersionNumber, List versions) { + this.protocolVersionNumber = protocolVersionNumber; + this.versions = versions; + } + + @Override + public String toString() { + return "ProtocolVersion{protocol=" + protocolVersionNumber + ", toString(\"and\")=" + toString("and") + "}"; + } + + /** + * Returns a string representation of all the Minecraft version of this enum value, using + * {@link StringUtil#joinGrammatically(CharSequence, CharSequence, List)}. + * + * @param finalWordSeparator the word separator between the two last versions in the returned string, like "and", + * "or" or any other word of any language. The spaces before and after are already + * concatenated. + * @return a string representation of this {@link ProtocolVersion}. + */ + public String toString(String finalWordSeparator) { + return displayOptimizedListOfVersions(List.of(this), finalWordSeparator); + } + + + /** + * Generate a string representation of the provided list of version, using + * {@link StringUtil#joinGrammatically(CharSequence, CharSequence, List)}. + * + * @param versions the minecraft versions to list + * @param finalWordSeparator the word separator between the two last versions in the returned string, like "and", + * "or" or any other word of any language. The spaces before and after are already + * concatenated. + * @return a string representation of the provided list of version. + */ + public static String displayOptimizedListOfVersions(List versions, String finalWordSeparator) { + return MinecraftVersionUtil.toString(versions.stream().flatMap(pv -> pv.versions.stream()).toList(), finalWordSeparator); + } + + + } diff --git a/pandalib-core/src/main/resources/fr/pandacube/lib/core/mc_version/mcversion.json b/pandalib-core/src/main/resources/fr/pandacube/lib/core/mc_version/mcversion.json new file mode 100644 index 0000000..b982dd5 --- /dev/null +++ b/pandalib-core/src/main/resources/fr/pandacube/lib/core/mc_version/mcversion.json @@ -0,0 +1,206 @@ +{ + "protocolOfVersion": { + "1.20.1": 763, + "1.20": 763, + "1.19.4": 762, + "1.19.3": 761, + "1.19.2": 760, + "1.19.1": 760, + "1.19": 759, + "1.18.2": 758, + "1.18.1": 757, + "1.18": 757, + "1.17.1": 756, + "1.17": 755, + "1.16.5": 754, + "1.16.4": 754, + "1.16.3": 753, + "1.16.2": 751, + "1.16.1": 736, + "1.16": 735, + "1.15.2": 578, + "1.15.1": 575, + "1.15": 573, + "1.14.4": 498, + "1.14.3": 490, + "1.14.2": 485, + "1.14.1": 480, + "1.14": 477, + "1.13.2": 404, + "1.13.1": 401, + "1.13": 393, + "1.12.2": 340, + "1.12.1": 338, + "1.12": 335, + "1.11.2": 316, + "1.11.1": 316, + "1.11": 315, + "1.10.2": 210, + "1.10.1": 210, + "1.10": 210, + "1.9.4": 110, + "1.9.3": 110, + "1.9.2": 109, + "1.9.1": 108, + "1.9": 107, + "1.8.9": 47, + "1.8.8": 47, + "1.8.7": 47, + "1.8.6": 47, + "1.8.5": 47, + "1.8.4": 47, + "1.8.3": 47, + "1.8.2": 47, + "1.8.1": 47, + "1.8": 47, + "1.7.10": 5, + "1.7.9": 5, + "1.7.8": 5, + "1.7.7": 5, + "1.7.6": 5, + "1.7.5": 4, + "1.7.4": 4, + "1.7.3": 4, + "1.7.2": 4 + }, + "versionsOfProtocol": { + "763": [ + "1.20", + "1.20.1" + ], + "762": [ + "1.19.4" + ], + "761": [ + "1.19.3" + ], + "760": [ + "1.19.1", + "1.19.2" + ], + "759": [ + "1.19" + ], + "758": [ + "1.18.2" + ], + "757": [ + "1.18", + "1.18.1" + ], + "756": [ + "1.17.1" + ], + "755": [ + "1.17" + ], + "754": [ + "1.16.4", + "1.16.5" + ], + "753": [ + "1.16.3" + ], + "751": [ + "1.16.2" + ], + "736": [ + "1.16.1" + ], + "735": [ + "1.16" + ], + "578": [ + "1.15.2" + ], + "575": [ + "1.15.1" + ], + "573": [ + "1.15" + ], + "498": [ + "1.14.4" + ], + "490": [ + "1.14.3" + ], + "485": [ + "1.14.2" + ], + "480": [ + "1.14.1" + ], + "477": [ + "1.14" + ], + "404": [ + "1.13.2" + ], + "401": [ + "1.13.1" + ], + "393": [ + "1.13" + ], + "340": [ + "1.12.2" + ], + "338": [ + "1.12.1" + ], + "335": [ + "1.12" + ], + "316": [ + "1.11.1", + "1.11.2" + ], + "315": [ + "1.11" + ], + "210": [ + "1.10", + "1.10.1", + "1.10.2" + ], + "110": [ + "1.9.3", + "1.9.4" + ], + "109": [ + "1.9.2" + ], + "108": [ + "1.9.1" + ], + "107": [ + "1.9" + ], + "47": [ + "1.8", + "1.8.1", + "1.8.2", + "1.8.3", + "1.8.4", + "1.8.5", + "1.8.6", + "1.8.7", + "1.8.8", + "1.8.9" + ], + "5": [ + "1.7.6", + "1.7.7", + "1.7.8", + "1.7.9", + "1.7.10" + ], + "4": [ + "1.7.2", + "1.7.3", + "1.7.4", + "1.7.5" + ] + } +} \ No newline at end of file