From d58c80cd2f1c855372bc195967ec1e70146cf4e9 Mon Sep 17 00:00:00 2001 From: EnZaXD <60033407+FlorianMichael@users.noreply.github.com> Date: Wed, 14 Feb 2024 09:51:56 +0100 Subject: [PATCH] Add ProtocolVersionRange API (#3691) --- .../api/protocol/ProtocolVersion.java | 26 +-- .../api/protocol/version/ProtocolVersion.java | 30 +-- .../version/ProtocolVersionRange.java | 180 ++++++++++++++++++ ...VersionRange.java => SubVersionRange.java} | 18 +- .../common/protocol/ProtocolVersionTest.java | 12 ++ 5 files changed, 222 insertions(+), 44 deletions(-) create mode 100644 api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersionRange.java rename api/src/main/java/com/viaversion/viaversion/api/protocol/version/{VersionRange.java => SubVersionRange.java} (86%) diff --git a/api-legacy/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolVersion.java b/api-legacy/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolVersion.java index 5cff8669c..98387c3c7 100644 --- a/api-legacy/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolVersion.java +++ b/api-legacy/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolVersion.java @@ -23,7 +23,7 @@ package us.myles.ViaVersion.api.protocol; import com.google.common.base.Preconditions; -import com.viaversion.viaversion.api.protocol.version.VersionRange; +import com.viaversion.viaversion.api.protocol.version.SubVersionRange; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.util.ArrayList; @@ -42,23 +42,23 @@ public class ProtocolVersion { private static final Int2ObjectMap versions = new Int2ObjectOpenHashMap<>(); private static final List versionList = new ArrayList<>(); - public static final ProtocolVersion v1_4_6 = register(51, "1.4.6/7", new VersionRange("1.4", 6, 7)); + public static final ProtocolVersion v1_4_6 = register(51, "1.4.6/7", new SubVersionRange("1.4", 6, 7)); public static final ProtocolVersion v1_5_1 = register(60, "1.5.1"); public static final ProtocolVersion v1_5_2 = register(61, "1.5.2"); public static final ProtocolVersion v_1_6_1 = register(73, "1.6.1"); public static final ProtocolVersion v_1_6_2 = register(74, "1.6.2"); public static final ProtocolVersion v_1_6_3 = register(77, "1.6.3"); public static final ProtocolVersion v_1_6_4 = register(78, "1.6.4"); - public static final ProtocolVersion v1_7_1 = register(4, "1.7-1.7.5", new VersionRange("1.7", 0, 5)); - public static final ProtocolVersion v1_7_6 = register(5, "1.7.6-1.7.10", new VersionRange("1.7", 6, 10)); + public static final ProtocolVersion v1_7_1 = register(4, "1.7-1.7.5", new SubVersionRange("1.7", 0, 5)); + public static final ProtocolVersion v1_7_6 = register(5, "1.7.6-1.7.10", new SubVersionRange("1.7", 6, 10)); public static final ProtocolVersion v1_8 = register(47, "1.8.x"); public static final ProtocolVersion v1_9 = register(107, "1.9"); public static final ProtocolVersion v1_9_1 = register(108, "1.9.1"); public static final ProtocolVersion v1_9_2 = register(109, "1.9.2"); - public static final ProtocolVersion v1_9_3 = register(110, "1.9.3/4", new VersionRange("1.9", 3, 4)); + public static final ProtocolVersion v1_9_3 = register(110, "1.9.3/4", new SubVersionRange("1.9", 3, 4)); public static final ProtocolVersion v1_10 = register(210, "1.10.x"); public static final ProtocolVersion v1_11 = register(315, "1.11"); - public static final ProtocolVersion v1_11_1 = register(316, "1.11.1/2", new VersionRange("1.11", 1, 2)); + public static final ProtocolVersion v1_11_1 = register(316, "1.11.1/2", new SubVersionRange("1.11", 1, 2)); public static final ProtocolVersion v1_12 = register(335, "1.12"); public static final ProtocolVersion v1_12_1 = register(338, "1.12.1"); public static final ProtocolVersion v1_12_2 = register(340, "1.12.2"); @@ -77,16 +77,16 @@ public class ProtocolVersion { public static final ProtocolVersion v1_16_1 = register(736, "1.16.1"); public static final ProtocolVersion v1_16_2 = register(751, "1.16.2"); public static final ProtocolVersion v1_16_3 = register(753, "1.16.3"); - public static final ProtocolVersion v1_16_4 = register(754, "1.16.4/5", new VersionRange("1.16", 4, 5)); + public static final ProtocolVersion v1_16_4 = register(754, "1.16.4/5", new SubVersionRange("1.16", 4, 5)); public static final ProtocolVersion v1_17 = register(755, "1.17"); public static final ProtocolVersion v1_17_1 = register(756, "1.17.1"); - public static final ProtocolVersion v1_18 = register(757, "1.18/1.18.1", new VersionRange("1.18", 0, 1)); + public static final ProtocolVersion v1_18 = register(757, "1.18/1.18.1", new SubVersionRange("1.18", 0, 1)); public static final ProtocolVersion v1_18_2 = register(758, "1.18.2"); public static final ProtocolVersion v1_19 = register(759, "1.19"); - public static final ProtocolVersion v1_19_1 = register(760, "1.19.1/2", new VersionRange("1.19", 1, 2)); + public static final ProtocolVersion v1_19_1 = register(760, "1.19.1/2", new SubVersionRange("1.19", 1, 2)); public static final ProtocolVersion v1_19_3 = register(761, "1.19.3"); public static final ProtocolVersion v1_19_4 = register(762, "1.19.4"); - public static final ProtocolVersion v1_20 = register(763, "1.20/1.20.1", new VersionRange("1.20", 0, 1)); + public static final ProtocolVersion v1_20 = register(763, "1.20/1.20.1", new SubVersionRange("1.20", 0, 1)); public static final ProtocolVersion v1_20_2 = register(764, "1.20.2"); public static final ProtocolVersion v1_20_3 = register(765, "1.20.3"); public static final ProtocolVersion unknown = register(-1, "UNKNOWN"); @@ -99,11 +99,11 @@ public class ProtocolVersion { return register(version, snapshotVersion, name, null); } - public static ProtocolVersion register(int version, String name, @Nullable VersionRange versionRange) { + public static ProtocolVersion register(int version, String name, @Nullable SubVersionRange versionRange) { return register(version, -1, name, versionRange); } - public static ProtocolVersion register(int version, int snapshotVersion, String name, @Nullable VersionRange versionRange) { + public static ProtocolVersion register(int version, int snapshotVersion, String name, @Nullable SubVersionRange versionRange) { ProtocolVersion protocol = new ProtocolVersion(version, snapshotVersion, name, versionRange); versionList.add(protocol); versions.put(protocol.getVersion(), protocol); @@ -166,7 +166,7 @@ public class ProtocolVersion { this(version, -1, name, null); } - public ProtocolVersion(int version, int snapshotVersion, String name, @Nullable VersionRange versionRange) { + public ProtocolVersion(int version, int snapshotVersion, String name, @Nullable SubVersionRange versionRange) { this.version = version; this.snapshotVersion = snapshotVersion; this.name = name; diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersion.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersion.java index d394910b2..ca5d185de 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersion.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersion.java @@ -42,16 +42,16 @@ public class ProtocolVersion implements Comparable { private static final Map> VERSIONS = new EnumMap<>(VersionType.class); private static final List VERSION_LIST = new ArrayList<>(); - public static final ProtocolVersion v1_7_1 = register(4, "1.7.2-1.7.5", new VersionRange("1.7", 2, 5)); - public static final ProtocolVersion v1_7_6 = register(5, "1.7.6-1.7.10", new VersionRange("1.7", 6, 10)); - public static final ProtocolVersion v1_8 = register(47, "1.8.x", new VersionRange("1.8", 0, 9)); + public static final ProtocolVersion v1_7_1 = register(4, "1.7.2-1.7.5", new SubVersionRange("1.7", 2, 5)); + public static final ProtocolVersion v1_7_6 = register(5, "1.7.6-1.7.10", new SubVersionRange("1.7", 6, 10)); + public static final ProtocolVersion v1_8 = register(47, "1.8.x", new SubVersionRange("1.8", 0, 9)); public static final ProtocolVersion v1_9 = register(107, "1.9"); public static final ProtocolVersion v1_9_1 = register(108, "1.9.1"); public static final ProtocolVersion v1_9_2 = register(109, "1.9.2"); - public static final ProtocolVersion v1_9_3 = register(110, "1.9.3/1.9.4", new VersionRange("1.9", 3, 4)); - public static final ProtocolVersion v1_10 = register(210, "1.10.x", new VersionRange("1.10", 0, 2)); + public static final ProtocolVersion v1_9_3 = register(110, "1.9.3/1.9.4", new SubVersionRange("1.9", 3, 4)); + public static final ProtocolVersion v1_10 = register(210, "1.10.x", new SubVersionRange("1.10", 0, 2)); public static final ProtocolVersion v1_11 = register(315, "1.11"); - public static final ProtocolVersion v1_11_1 = register(316, "1.11.1/1.11.2", new VersionRange("1.11", 1, 2)); + public static final ProtocolVersion v1_11_1 = register(316, "1.11.1/1.11.2", new SubVersionRange("1.11", 1, 2)); public static final ProtocolVersion v1_12 = register(335, "1.12"); public static final ProtocolVersion v1_12_1 = register(338, "1.12.1"); public static final ProtocolVersion v1_12_2 = register(340, "1.12.2"); @@ -70,18 +70,18 @@ public class ProtocolVersion implements Comparable { public static final ProtocolVersion v1_16_1 = register(736, "1.16.1"); public static final ProtocolVersion v1_16_2 = register(751, "1.16.2"); public static final ProtocolVersion v1_16_3 = register(753, "1.16.3"); - public static final ProtocolVersion v1_16_4 = register(754, "1.16.4/1.16.5", new VersionRange("1.16", 4, 5)); + public static final ProtocolVersion v1_16_4 = register(754, "1.16.4/1.16.5", new SubVersionRange("1.16", 4, 5)); public static final ProtocolVersion v1_17 = register(755, "1.17"); public static final ProtocolVersion v1_17_1 = register(756, "1.17.1"); - public static final ProtocolVersion v1_18 = register(757, "1.18/1.18.1", new VersionRange("1.18", 0, 1)); + public static final ProtocolVersion v1_18 = register(757, "1.18/1.18.1", new SubVersionRange("1.18", 0, 1)); public static final ProtocolVersion v1_18_2 = register(758, "1.18.2"); public static final ProtocolVersion v1_19 = register(759, "1.19"); - public static final ProtocolVersion v1_19_1 = register(760, "1.19.1/1.19.2", new VersionRange("1.19", 1, 2)); + public static final ProtocolVersion v1_19_1 = register(760, "1.19.1/1.19.2", new SubVersionRange("1.19", 1, 2)); public static final ProtocolVersion v1_19_3 = register(761, "1.19.3"); public static final ProtocolVersion v1_19_4 = register(762, "1.19.4"); - public static final ProtocolVersion v1_20 = register(763, "1.20/1.20.1", new VersionRange("1.20", 0, 1)); + public static final ProtocolVersion v1_20 = register(763, "1.20/1.20.1", new SubVersionRange("1.20", 0, 1)); public static final ProtocolVersion v1_20_2 = register(764, "1.20.2"); - public static final ProtocolVersion v1_20_3 = register(765, "1.20.3/1.20.4", new VersionRange("1.20", 3, 4)); + public static final ProtocolVersion v1_20_3 = register(765, "1.20.3/1.20.4", new SubVersionRange("1.20", 3, 4)); public static final ProtocolVersion v1_20_5 = register(766, 176, "1.20.5"); public static final ProtocolVersion unknown = register(-1, "UNKNOWN"); @@ -95,7 +95,7 @@ public class ProtocolVersion implements Comparable { return protocolVersion; } - public static ProtocolVersion register(int version, String name, @Nullable VersionRange versionRange) { + public static ProtocolVersion register(int version, String name, @Nullable SubVersionRange versionRange) { final ProtocolVersion protocolVersion = new ProtocolVersion(VersionType.RELEASE, version, -1, name, versionRange); register(protocolVersion); return protocolVersion; @@ -133,7 +133,7 @@ public class ProtocolVersion implements Comparable { /** * Returns a ProtocolVersion instance, even if this protocol version - * has not been registered. See {@link #isRegistered(VersionType, int)} berorehand or {@link #isKnown()}. + * has not been registered. See {@link #isRegistered(VersionType, int)} beforehand or {@link #isKnown()}. * * @param versionType protocol version type * @param version protocol version @@ -209,7 +209,7 @@ public class ProtocolVersion implements Comparable { } @Deprecated/*(forRemoval = true)*/ - public ProtocolVersion(int version, int snapshotVersion, String name, @Nullable VersionRange versionRange) { + public ProtocolVersion(int version, int snapshotVersion, String name, @Nullable SubVersionRange versionRange) { this(VersionType.RELEASE, version, snapshotVersion, name, versionRange); } @@ -222,7 +222,7 @@ public class ProtocolVersion implements Comparable { * @param name version name * @param versionRange range of versions that are supported by this protocol version, null if not a range */ - public ProtocolVersion(VersionType versionType, int version, int snapshotVersion, String name, @Nullable VersionRange versionRange) { + public ProtocolVersion(VersionType versionType, int version, int snapshotVersion, String name, @Nullable SubVersionRange versionRange) { this.versionType = versionType; this.version = version; this.snapshotVersion = snapshotVersion; diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersionRange.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersionRange.java new file mode 100644 index 000000000..7c5d88a40 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/version/ProtocolVersionRange.java @@ -0,0 +1,180 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.protocol.version; + +import com.google.common.collect.Range; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Wrapper class file for {@link com.google.common.collect.Range} to support multiple ranges. This class is used to + * compare {@link ProtocolVersion} objects. + */ +public class ProtocolVersionRange { + + private List> ranges; + + private ProtocolVersionRange(final List> ranges) { + if (ranges != null) { + this.ranges = new ArrayList<>(ranges); + } + } + + /** + * Returns a range that contains all versions. + * + * @return the range + */ + public static ProtocolVersionRange all() { + return new ProtocolVersionRange(null); + } + + /** + * Returns a range that contains only the given version. + * + * @param min the version + * @param max the version + * @return the range + */ + public static ProtocolVersionRange of(final ProtocolVersion min, final ProtocolVersion max) { + return new ProtocolVersionRange(Collections.singletonList(Range.open(min, max))); + } + + /** + * Returns a range that contains only the given version. + * + * @param range the version + * @return the range + */ + public static ProtocolVersionRange of(final Range range) { + return new ProtocolVersionRange(Collections.singletonList(range)); + } + + /** + * Returns a range that contains only the given version. The list can be immutable. + * + * @param ranges the version + * @return the range + */ + public static ProtocolVersionRange of(final List> ranges) { + return new ProtocolVersionRange(ranges); + } + + /** + * Adds a new range to this range. This method is only available if the range is not already containing all versions. + * + * @param range the range to add + * @return this range + */ + public ProtocolVersionRange add(final Range range) { + if (ranges == null) { + throw new UnsupportedOperationException("Range already contains all versions. Cannot add a new range."); + } + ranges.add(range); + return this; + } + + /** + * Checks if the given version is included in this range. + * + * @param version the version + * @return {@code true} if the version is included + */ + public boolean contains(final ProtocolVersion version) { + if (this.ranges == null) return true; + return this.ranges.stream().anyMatch(range -> range.contains(version)); + } + + @Override + public String toString() { + if (this.ranges != null) { + StringBuilder rangeString = new StringBuilder(); + int i = 0; + for (Range range : this.ranges) { + i++; + final ProtocolVersion min = range.hasLowerBound() ? range.lowerEndpoint() : null; + final ProtocolVersion max = range.hasUpperBound() ? range.upperEndpoint() : null; + + if (min == null) rangeString.append("<= ").append(max.getName()); + else if (max == null) rangeString.append(">= ").append(min.getName()); + else if (Objects.equals(min, max)) rangeString.append(min.getName()); + else rangeString.append(min.getName()).append(" - ").append(max.getName()); + + if (i != this.ranges.size()) { + rangeString.append(", "); + } + } + return rangeString.toString(); + } + return "*"; + } + + @Override + public boolean equals(final Object object) { + if (this == object) return true; + if (object == null || getClass() != object.getClass()) return false; + ProtocolVersionRange that = (ProtocolVersionRange) object; + return Objects.equals(ranges, that.ranges); + } + + @Override + public int hashCode() { + return Objects.hash(ranges); + } + + /** + * Parses a range from a string. + * + * @param str the string + * @return the range + */ + public static ProtocolVersionRange fromString(final String str) { + if ("*".equals(str)) return all(); + else if (str.contains(",")) { + String[] rangeParts = str.split(", "); + ProtocolVersionRange versionRange = null; + + for (String part : rangeParts) { + if (versionRange == null) versionRange = of(parseSinglePart(part)); + else versionRange.add(parseSinglePart(part)); + } + return versionRange; + } else { + return of(parseSinglePart(str)); + } + } + + private static Range parseSinglePart(final String part) { + if (part.startsWith("<= ")) return Range.atMost(ProtocolVersion.getClosest(part.substring(3))); + else if (part.startsWith(">= ")) return Range.atLeast(ProtocolVersion.getClosest(part.substring(3))); + else if (part.contains(" - ")) { + String[] rangeParts = part.split(" - "); + ProtocolVersion min = ProtocolVersion.getClosest(rangeParts[0]); + ProtocolVersion max = ProtocolVersion.getClosest(rangeParts[1]); + return Range.open(min, max); + } else return Range.singleton(ProtocolVersion.getClosest(part)); + } + +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/version/VersionRange.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/version/SubVersionRange.java similarity index 86% rename from api/src/main/java/com/viaversion/viaversion/api/protocol/version/VersionRange.java rename to api/src/main/java/com/viaversion/viaversion/api/protocol/version/SubVersionRange.java index 1aaab848d..26c72bbc8 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/version/VersionRange.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/version/SubVersionRange.java @@ -24,7 +24,7 @@ package com.viaversion.viaversion.api.protocol.version; import com.google.common.base.Preconditions; -public class VersionRange { +public class SubVersionRange { private final String baseVersion; private final int rangeFrom; private final int rangeTo; @@ -36,7 +36,7 @@ public class VersionRange { * @param rangeFrom minor version the range begins at, must be greater than or equal to 0 * @param rangeTo minor version the range ends at, must be greater than {@code rangeFrom} */ - public VersionRange(String baseVersion, int rangeFrom, int rangeTo) { + public SubVersionRange(String baseVersion, int rangeFrom, int rangeTo) { Preconditions.checkNotNull(baseVersion); Preconditions.checkArgument(rangeFrom >= 0); Preconditions.checkArgument(rangeTo > rangeFrom); @@ -72,18 +72,4 @@ public class VersionRange { return rangeTo; } - @Deprecated/*(forRemoval = true)*/ - public String getBaseVersion() { - return baseVersion; - } - - @Deprecated/*(forRemoval = true)*/ - public int getRangeFrom() { - return rangeFrom; - } - - @Deprecated/*(forRemoval = true)*/ - public int getRangeTo() { - return rangeTo; - } } diff --git a/common/src/test/java/com/viaversion/viaversion/common/protocol/ProtocolVersionTest.java b/common/src/test/java/com/viaversion/viaversion/common/protocol/ProtocolVersionTest.java index 6b377f0ab..9f46fba90 100644 --- a/common/src/test/java/com/viaversion/viaversion/common/protocol/ProtocolVersionTest.java +++ b/common/src/test/java/com/viaversion/viaversion/common/protocol/ProtocolVersionTest.java @@ -17,7 +17,9 @@ */ package com.viaversion.viaversion.common.protocol; +import com.google.common.collect.Range; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersionRange; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -43,4 +45,14 @@ public class ProtocolVersionTest { void testGet() { Assertions.assertEquals(ProtocolVersion.v1_16_3, ProtocolVersion.getProtocol(753)); } + + @Test + void testProtocolVersionRange() { + Assertions.assertTrue(ProtocolVersionRange.of(Range.atLeast(ProtocolVersion.v1_8)).contains(ProtocolVersion.v1_10)); + Assertions.assertFalse(ProtocolVersionRange.of(Range.atLeast(ProtocolVersion.v1_8)).contains(ProtocolVersion.v1_7_1)); + Assertions.assertTrue(ProtocolVersionRange.of(ProtocolVersion.v1_8, ProtocolVersion.v1_10).contains(ProtocolVersion.v1_9)); + + final ProtocolVersionRange complexRange = ProtocolVersionRange.of(Range.atLeast(ProtocolVersion.v1_11)).add(Range.singleton(ProtocolVersion.v1_8)).add(Range.lessThan(ProtocolVersion.v1_7_1)); + Assertions.assertEquals(complexRange.toString(), ProtocolVersionRange.fromString(complexRange.toString()).toString()); + } }