Improved ProtocolVersion + mcversion.json file automatically updated at build time from Pandacube API

This commit is contained in:
Marc Baloup 2023-06-16 17:28:25 +02:00
parent 70c4d59fdc
commit e6fc31e5ca
4 changed files with 385 additions and 14 deletions

View File

@ -85,6 +85,27 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>com.googlecode.maven-download-plugin</groupId>
<artifactId>download-maven-plugin</artifactId>
<version>1.7.0</version>
<executions>
<execution>
<id>mcversion-download</id>
<phase>compile</phase>
<goals>
<goal>wget</goal>
</goals>
</execution>
</executions>
<configuration>
<url>https://api.pandacube.fr/rest/mcversion</url>
<outputDirectory>${project.basedir}/src/main/resources/fr/pandacube/lib/core/mc_version</outputDirectory>
<outputFileName>mcversion.json</outputFileName>
<skipCache>true</skipCache>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -4,15 +4,23 @@ import fr.pandacube.lib.util.StringUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
/**
* Utility class to manipulate {@link String}s representing Minecraft versions.
*/
public class MinecraftVersionUtil { 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, &lt;0 if v1&lt;v2 and vice-versa.
*/
public static int compareVersions(String v1, String v2) { public static int compareVersions(String v1, String v2) {
int[] v1Int = decomposedVersion(v1); int[] v1Int = decomposedVersion(v1);
int[] v2Int = decomposedVersion(v2); 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) { public static int[] decomposedVersion(String v) {
try { try {
return Arrays.stream(v.split("\\.")).mapToInt(Integer::parseInt).toArray(); 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.
* <p>
* Two versions are consecutives if (considering {@code 1.X[.Y]}):
* <ul>
* <li>They are part of the same main version (X value)</li>
* <li>v1 has no Y value, and v2 has Y = 1 (eg. 1.19 and 1.19.1) OR
* both v1 and v2 has a Y value and those values are consecutives.
* </li>
* </ul>
* @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) { public static boolean areConsecutives(String v1, String v2) {
int[] v1Int = decomposedVersion(v1); int[] v1Int = decomposedVersion(v1);
int[] v2Int = decomposedVersion(v2); 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<String> versions, String finalWordSeparator) { public static String toString(List<String> versions, String finalWordSeparator) {
if (versions.isEmpty()) if (versions.isEmpty())
return ""; return "";

View File

@ -2,7 +2,8 @@ package fr.pandacube.lib.core.mc_version;
import fr.pandacube.lib.core.json.Json; import fr.pandacube.lib.core.json.Json;
import fr.pandacube.lib.util.Log; 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.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -11,9 +12,22 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers; import java.net.http.HttpResponse.BodyHandlers;
import java.time.Duration;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
/**
* Class handling a relationship table of known Minecraft version and their
* corresponding protocol version.
* <p>
* 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.
* <p>
* 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 { public class ProtocolVersion {
private static final String ONLINE_DATA_URL = "https://api.pandacube.fr/rest/mcversion"; 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.
* <p>
* <b>Note: </b>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) { public static void setRawData(MinecraftVersionList data) {
versionList.set(data); versionList.set(data);
} }
/**
* Gets the raw data used internally by this class.
* <p>
* <b>Note: </b>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() { public static MinecraftVersionList getRawData() {
initIfNecessary(); initIfNecessary();
return versionList.get(); return versionList.get();
@ -40,7 +69,9 @@ public class ProtocolVersion {
private static void init() { private static void init() {
// try online source first // try online source first
try { try {
HttpResponse<String> response = HttpClient.newHttpClient() HttpResponse<String> response = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.build()
.send(HttpRequest.newBuilder(URI.create(ONLINE_DATA_URL)).build(), .send(HttpRequest.newBuilder(URI.create(ONLINE_DATA_URL)).build(),
BodyHandlers.ofString() BodyHandlers.ofString()
); );
@ -70,19 +101,96 @@ public class ProtocolVersion {
} }
private static int getPVNOfVersion(String version) {
public static int ofVersion(String versionId) {
initIfNecessary(); initIfNecessary();
Integer v = versionList.get().protocolOfVersion().get(versionId); Integer v = versionList.get().protocolOfVersion().get(version);
return v == null ? -1 : v; return v == null ? -1 : v;
} }
private static List<String> getVersionsOfPVN(int pvn) {
public static List<String> getVersionsOfProtocol(int protocolVersion) {
initIfNecessary(); 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<String> 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<String> 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<String> versions;
private ProtocolVersion(int protocolVersionNumber, List<String> 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<ProtocolVersion> versions, String finalWordSeparator) {
return MinecraftVersionUtil.toString(versions.stream().flatMap(pv -> pv.versions.stream()).toList(), finalWordSeparator);
}
} }

View File

@ -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"
]
}
}