diff --git a/build.gradle b/build.gradle index c7e86a77..116477c4 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,7 @@ configurations { attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION)) attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, "changelog")) } - project.components.findByName("java").addVariantsFromConfiguration(it) { } + project.components.findByName("java").addVariantsFromConfiguration(it) {} } } @@ -190,7 +190,7 @@ tasks.withType(GenerateModuleMetadata).configureEach { gradlePlugin { website = 'https://github.com/neoforged/ModDevGradle' - vcsUrl = 'https://github.com/neoforged/ModDevGradle.git' + vcsUrl = 'https://github.com/neoforged/ModDevGradle.git' plugins { moddev { @@ -243,13 +243,68 @@ tasks.withType(PluginUnderTestMetadata).configureEach { it.inputs.file(shadowJar.archiveFile) } +abstract class GenerateVersionOrder extends DefaultTask { + @OutputFile + abstract RegularFileProperty getOutput() + + @TaskAction + void run() { + final json = new JsonSlurper() + final manifest = json.parse('https://piston-meta.mojang.com/mc/game/version_manifest_v2.json'.toURL()) + List versions = manifest.versions.collect { it.id } + + Comparator BY_LENGTH_REVERSED = Comparator.comparingInt { it.length() }.reversed() + var indicesByLength = versions.stream().sorted(BY_LENGTH_REVERSED).map(versions::indexOf).map(String::valueOf).toList() + + final clazz = """ +package net.neoforged.moddevgradle.internal.generated; + +import java.util.List; + +public final class MinecraftVersionList { + private MinecraftVersionList() { + } + + /** + * Released Minecraft Versions as of ${java.time.Instant.now()} from latest to oldest. + */ + public static final List VERSIONS = List.of("${versions.join("\", \"")}"); + + // Indices into VERSIONS sorted by descending length of the version id + private static final int[] BY_LENGTH = {${indicesByLength.join(", ")}}; + + /** + * Finds the index of the longest matching prefix or -1 if none match. + * Prefix matches must terminate with one of the given separator characters to be found valid. + */ + public static int indexOfByPrefix(String version, String separators) { + for (var versionIdx : BY_LENGTH) { + var versionText = VERSIONS.get(versionIdx); + if (version.startsWith(versionText) && (versionText.length() == version.length() || separators.indexOf(version.charAt(versionText.length())) != -1)) { + return versionIdx; + } + } + return -1; + } +} +""" + output.get().asFile.write(clazz) + } +} + +tasks.register('generateVersionOrder', GenerateVersionOrder) { + output = project.file('src/generated/java/net/neoforged/moddevgradle/internal/generated/MinecraftVersionList.java') + group = 'build' + description = "Generates a listing of known Minecraft versions for the purposes of Version comparison" +} + abstract class GenerateRepoFilter extends DefaultTask { @OutputFile abstract RegularFileProperty getOutput() @EqualsAndHashCode @TupleConstructor - static class Artifact implements Comparable { + static class Artifact implements Comparable { String group, module @Override diff --git a/src/generated/java/net/neoforged/moddevgradle/internal/generated/MinecraftVersionList.java b/src/generated/java/net/neoforged/moddevgradle/internal/generated/MinecraftVersionList.java new file mode 100644 index 00000000..f3ab5e5f --- /dev/null +++ b/src/generated/java/net/neoforged/moddevgradle/internal/generated/MinecraftVersionList.java @@ -0,0 +1,31 @@ + +package net.neoforged.moddevgradle.internal.generated; + +import java.util.List; + +public final class MinecraftVersionList { + private MinecraftVersionList() { + } + + /** + * Released Minecraft Versions as of 2024-12-06T12:54:48.337462300Z from latest to oldest. + */ + public static final List VERSIONS = List.of("1.21.4", "1.21.4-rc3", "1.21.4-rc2", "1.21.4-rc1", "1.21.4-pre3", "1.21.4-pre2", "1.21.4-pre1", "24w46a", "24w45a", "24w44a", "1.21.3", "1.21.2", "1.21.2-rc2", "1.21.2-rc1", "1.21.2-pre5", "1.21.2-pre4", "1.21.2-pre3", "1.21.2-pre2", "1.21.2-pre1", "24w40a", "24w39a", "24w38a", "24w37a", "24w36a", "24w35a", "24w34a", "24w33a", "1.21.1", "1.21.1-rc1", "1.21", "1.21-rc1", "1.21-pre4", "1.21-pre3", "1.21-pre2", "1.21-pre1", "24w21b", "24w21a", "24w20a", "24w19b", "24w19a", "24w18a", "1.20.6", "1.20.6-rc1", "1.20.5", "1.20.5-rc3", "1.20.5-rc2", "1.20.5-rc1", "1.20.5-pre4", "1.20.5-pre3", "1.20.5-pre2", "1.20.5-pre1", "24w14a", "24w14potato", "24w13a", "24w12a", "24w11a", "24w10a", "24w09a", "24w07a", "24w06a", "24w05b", "24w05a", "24w04a", "24w03b", "24w03a", "23w51b", "23w51a", "1.20.4", "1.20.4-rc1", "1.20.3", "1.20.3-rc1", "1.20.3-pre4", "1.20.3-pre3", "1.20.3-pre2", "1.20.3-pre1", "23w46a", "23w45a", "23w44a", "23w43b", "23w43a", "23w42a", "23w41a", "23w40a", "1.20.2", "1.20.2-rc2", "1.20.2-rc1", "1.20.2-pre4", "1.20.2-pre3", "1.20.2-pre2", "1.20.2-pre1", "23w35a", "23w33a", "23w32a", "23w31a", "1.20.1", "1.20.1-rc1", "1.20", "1.20-rc1", "1.20-pre7", "1.20-pre6", "1.20-pre5", "1.20-pre4", "1.20-pre3", "1.20-pre2", "1.20-pre1", "23w18a", "23w17a", "23w16a", "23w14a", "23w13a_or_b", "23w13a", "23w12a", "1.19.4", "1.19.4-rc3", "1.19.4-rc2", "1.19.4-rc1", "1.19.4-pre4", "1.19.4-pre3", "1.19.4-pre2", "1.19.4-pre1", "23w07a", "23w06a", "23w05a", "23w04a", "23w03a", "1.19.3", "1.19.3-rc3", "1.19.3-rc2", "1.19.3-rc1", "1.19.3-pre3", "1.19.3-pre2", "1.19.3-pre1", "22w46a", "22w45a", "22w44a", "22w43a", "22w42a", "1.19.2", "1.19.2-rc2", "1.19.2-rc1", "1.19.1", "1.19.1-rc3", "1.19.1-rc2", "1.19.1-pre6", "1.19.1-pre5", "1.19.1-pre4", "1.19.1-pre3", "1.19.1-pre2", "1.19.1-rc1", "1.19.1-pre1", "22w24a", "1.19", "1.19-rc2", "1.19-rc1", "1.19-pre5", "1.19-pre4", "1.19-pre3", "1.19-pre2", "1.19-pre1", "22w19a", "22w18a", "22w17a", "22w16b", "22w16a", "22w15a", "22w14a", "22w13oneblockatatime", "22w13a", "22w12a", "22w11a", "1.18.2", "1.18.2-rc1", "1.18.2-pre3", "1.18.2-pre2", "1.18.2-pre1", "22w07a", "22w06a", "22w05a", "22w03a", "1.18.1", "1.18.1-rc3", "1.18.1-rc2", "1.18.1-rc1", "1.18.1-pre1", "1.18", "1.18-rc4", "1.18-rc3", "1.18-rc2", "1.18-rc1", "1.18-pre8", "1.18-pre7", "1.18-pre6", "1.18-pre5", "1.18-pre4", "1.18-pre3", "1.18-pre2", "1.18-pre1", "21w44a", "21w43a", "21w42a", "21w41a", "21w40a", "21w39a", "21w38a", "21w37a", "1.17.1", "1.17.1-rc2", "1.17.1-rc1", "1.17.1-pre3", "1.17.1-pre2", "1.17.1-pre1", "1.17", "1.17-rc2", "1.17-rc1", "1.17-pre5", "1.17-pre4", "1.17-pre3", "1.17-pre2", "1.17-pre1", "21w20a", "21w19a", "21w18a", "21w17a", "21w16a", "21w15a", "21w14a", "21w13a", "21w11a", "21w10a", "21w08b", "21w08a", "21w07a", "21w06a", "21w05b", "21w05a", "21w03a", "1.16.5", "1.16.5-rc1", "20w51a", "20w49a", "20w48a", "20w46a", "20w45a", "1.16.4", "1.16.4-rc1", "1.16.4-pre2", "1.16.4-pre1", "1.16.3", "1.16.3-rc1", "1.16.2", "1.16.2-rc2", "1.16.2-rc1", "1.16.2-pre3", "1.16.2-pre2", "1.16.2-pre1", "20w30a", "20w29a", "20w28a", "20w27a", "1.16.1", "1.16", "1.16-rc1", "1.16-pre8", "1.16-pre7", "1.16-pre6", "1.16-pre5", "1.16-pre4", "1.16-pre3", "1.16-pre2", "1.16-pre1", "20w22a", "20w21a", "20w20b", "20w20a", "20w19a", "20w18a", "20w17a", "20w16a", "20w15a", "20w14a", "20w14infinite", "20w13b", "20w13a", "20w12a", "20w11a", "20w10a", "20w09a", "20w08a", "20w07a", "20w06a", "1.15.2", "1.15.2-pre2", "1.15.2-pre1", "1.15.1", "1.15.1-pre1", "1.15", "1.15-pre7", "1.15-pre6", "1.15-pre5", "1.15-pre4", "1.15-pre3", "1.15-pre2", "1.15-pre1", "19w46b", "19w46a", "19w45b", "19w45a", "19w44a", "19w42a", "19w41a", "19w40a", "19w39a", "19w38b", "19w38a", "19w37a", "19w36a", "19w35a", "19w34a", "1.14.4", "1.14.4-pre7", "1.14.4-pre6", "1.14.4-pre5", "1.14.4-pre4", "1.14.4-pre3", "1.14.4-pre2", "1.14.4-pre1", "1.14.3", "1.14.3-pre4", "1.14.3-pre3", "1.14.3-pre2", "1.14.3-pre1", "1.14.2", "1.14.2 Pre-Release 4", "1.14.2 Pre-Release 3", "1.14.2 Pre-Release 2", "1.14.2 Pre-Release 1", "1.14.1", "1.14.1 Pre-Release 2", "1.14.1 Pre-Release 1", "1.14", "1.14 Pre-Release 5", "1.14 Pre-Release 4", "1.14 Pre-Release 3", "1.14 Pre-Release 2", "1.14 Pre-Release 1", "19w14b", "19w14a", "3D Shareware v1.34", "19w13b", "19w13a", "19w12b", "19w12a", "19w11b", "19w11a", "19w09a", "19w08b", "19w08a", "19w07a", "19w06a", "19w05a", "19w04b", "19w04a", "19w03c", "19w03b", "19w03a", "19w02a", "18w50a", "18w49a", "18w48b", "18w48a", "18w47b", "18w47a", "18w46a", "18w45a", "18w44a", "18w43c", "18w43b", "18w43a", "1.13.2", "1.13.2-pre2", "1.13.2-pre1", "1.13.1", "1.13.1-pre2", "1.13.1-pre1", "18w33a", "18w32a", "18w31a", "18w30b", "18w30a", "1.13", "1.13-pre10", "1.13-pre9", "1.13-pre8", "1.13-pre7", "1.13-pre6", "1.13-pre5", "1.13-pre4", "1.13-pre3", "1.13-pre2", "1.13-pre1", "18w22c", "18w22b", "18w22a", "18w21b", "18w21a", "18w20c", "18w20b", "18w20a", "18w19b", "18w19a", "18w16a", "18w15a", "18w14b", "18w14a", "18w11a", "18w10d", "18w10c", "18w10b", "18w10a", "18w09a", "18w08b", "18w08a", "18w07c", "18w07b", "18w07a", "18w06a", "18w05a", "18w03b", "18w03a", "18w02a", "18w01a", "17w50a", "17w49b", "17w49a", "17w48a", "17w47b", "17w47a", "17w46a", "17w45b", "17w45a", "17w43b", "17w43a", "1.12.2", "1.12.2-pre2", "1.12.2-pre1", "1.12.1", "1.12.1-pre1", "17w31a", "1.12", "1.12-pre7", "1.12-pre6", "1.12-pre5", "1.12-pre4", "1.12-pre3", "1.12-pre2", "1.12-pre1", "17w18b", "17w18a", "17w17b", "17w17a", "17w16b", "17w16a", "17w15a", "17w14a", "17w13b", "17w13a", "17w06a", "1.11.2", "1.11.1", "16w50a", "1.11", "1.11-pre1", "16w44a", "16w43a", "16w42a", "16w41a", "16w40a", "16w39c", "16w39b", "16w39a", "16w38a", "16w36a", "16w35a", "16w33a", "16w32b", "16w32a", "1.10.2", "1.10.1", "1.10", "1.10-pre2", "1.10-pre1", "16w21b", "16w21a", "16w20a", "1.9.4", "1.9.3", "1.9.3-pre3", "1.9.3-pre2", "1.9.3-pre1", "16w15b", "16w15a", "16w14a", "1.RV-Pre1", "1.9.2", "1.9.1", "1.9.1-pre3", "1.9.1-pre2", "1.9.1-pre1", "1.9", "1.9-pre4", "1.9-pre3", "1.9-pre2", "1.9-pre1", "16w07b", "16w07a", "16w06a", "16w05b", "16w05a", "16w04a", "16w03a", "16w02a", "15w51b", "15w51a", "15w50a", "15w49b", "1.8.9", "15w49a", "15w47c", "15w47b", "15w47a", "15w46a", "15w45a", "15w44b", "15w44a", "15w43c", "15w43b", "15w43a", "15w42a", "15w41b", "15w41a", "15w40b", "15w40a", "15w39c", "15w39b", "15w39a", "15w38b", "15w38a", "15w37a", "15w36d", "15w36c", "15w36b", "15w36a", "15w35e", "15w35d", "15w35c", "15w35b", "15w35a", "15w34d", "15w34c", "15w34b", "15w34a", "15w33c", "15w33b", "15w33a", "15w32c", "15w32b", "15w32a", "15w31c", "15w31b", "15w31a", "1.8.8", "1.8.7", "1.8.6", "1.8.5", "1.8.4", "15w14a", "1.8.3", "1.8.2", "1.8.2-pre7", "1.8.2-pre6", "1.8.2-pre5", "1.8.2-pre4", "1.8.2-pre3", "1.8.2-pre2", "1.8.2-pre1", "1.8.1", "1.8.1-pre5", "1.8.1-pre4", "1.8.1-pre3", "1.8.1-pre2", "1.8.1-pre1", "1.8", "1.8-pre3", "1.8-pre2", "1.8-pre1", "14w34d", "14w34c", "14w34b", "14w34a", "14w33c", "14w33b", "14w33a", "14w32d", "14w32c", "14w32b", "14w32a", "14w31a", "14w30c", "14w30b", "14w30a", "14w29b", "14w29a", "14w28b", "14w28a", "14w27b", "14w27a", "14w26c", "14w26b", "14w26a", "14w25b", "14w25a", "14w21b", "14w21a", "14w20b", "14w20a", "1.7.10", "1.7.10-pre4", "1.7.10-pre3", "1.7.10-pre2", "1.7.10-pre1", "14w19a", "14w18b", "14w18a", "14w17a", "14w11b", "1.7.9", "1.7.8", "1.7.7", "1.7.6", "14w11a", "1.7.6-pre2", "1.7.6-pre1", "14w10c", "14w10b", "14w10a", "14w08a", "1.7.5", "14w07a", "14w06b", "14w06a", "14w05b", "14w05a", "14w04b", "14w04a", "14w03b", "14w03a", "14w02c", "14w02b", "14w02a", "1.7.4", "1.7.3", "13w49a", "13w48b", "13w48a", "13w47e", "13w47d", "13w47c", "13w47b", "13w47a", "1.7.2", "1.7.1", "1.7", "13w43a", "13w42b", "13w42a", "13w41b", "13w41a", "13w39b", "13w39a", "13w38c", "13w38b", "13w38a", "1.6.4", "13w37b", "1.6.3", "13w37a", "13w36b", "13w36a", "1.6.2", "1.6.1", "1.6", "13w26a", "13w25c", "13w25b", "13w25a", "13w24b", "13w24a", "13w23b", "13w23a", "13w22a", "13w21b", "13w21a", "13w19a", "13w18c", "13w18b", "13w18a", "13w17a", "1.5.2", "13w16b", "13w16a", "1.5.1", "1.5", "1.4.7", "1.4.5", "1.4.6", "1.4.4", "1.4.3", "1.4.2", "1.4.1", "1.4", "1.3.2", "1.3.1", "1.3", "1.2.5", "1.2.4", "1.2.3", "1.2.2", "1.2.1", "1.1", "1.0", "b1.8.1", "b1.8", "b1.7.3", "b1.7.2", "b1.7", "b1.6.6", "b1.6.5", "b1.6.4", "b1.6.3", "b1.6.2", "b1.6.1", "b1.6", "b1.5_01", "b1.5", "b1.4_01", "b1.4", "b1.3_01", "b1.3b", "b1.2_02", "b1.2_01", "b1.2", "b1.1_02", "b1.1_01", "b1.0.2", "b1.0_01", "b1.0", "a1.2.6", "a1.2.5", "a1.2.4_01", "a1.2.3_04", "a1.2.3_02", "a1.2.3_01", "a1.2.3", "a1.2.2b", "a1.2.2a", "a1.2.1_01", "a1.2.1", "a1.2.0_02", "a1.2.0_01", "a1.2.0", "a1.1.2_01", "a1.1.2", "a1.1.0", "a1.0.17_04", "a1.0.17_02", "a1.0.16", "a1.0.15", "a1.0.14", "a1.0.11", "a1.0.5_01", "a1.0.4", "inf-20100618", "c0.30_01c", "c0.0.13a", "c0.0.13a_03", "c0.0.11a", "rd-161348", "rd-160052", "rd-20090515", "rd-132328", "rd-132211"); + + // Indices into VERSIONS sorted by descending length of the version id + private static final int[] BY_LENGTH = {166, 332, 333, 334, 335, 337, 338, 340, 341, 342, 343, 344, 347, 280, 781, 4, 5, 6, 14, 15, 16, 17, 18, 47, 48, 49, 50, 52, 71, 72, 73, 74, 86, 87, 88, 89, 109, 116, 117, 118, 119, 129, 130, 131, 143, 144, 145, 146, 147, 149, 172, 173, 174, 183, 208, 209, 210, 245, 246, 252, 253, 254, 291, 292, 294, 319, 320, 321, 322, 323, 324, 325, 327, 328, 329, 330, 379, 380, 382, 383, 443, 444, 446, 626, 627, 628, 629, 784, 788, 1, 2, 3, 12, 13, 28, 42, 44, 45, 46, 68, 70, 84, 85, 95, 113, 114, 115, 126, 127, 128, 138, 139, 141, 142, 148, 171, 180, 181, 182, 206, 207, 237, 244, 248, 250, 251, 390, 496, 497, 498, 505, 506, 507, 578, 579, 580, 581, 582, 583, 584, 586, 587, 588, 589, 590, 640, 641, 773, 774, 31, 32, 33, 34, 98, 99, 100, 101, 102, 103, 104, 154, 155, 156, 157, 158, 189, 190, 191, 192, 193, 194, 195, 196, 214, 215, 216, 217, 218, 262, 263, 264, 265, 266, 267, 268, 269, 296, 297, 298, 299, 300, 301, 302, 391, 392, 393, 394, 395, 396, 397, 398, 399, 449, 450, 451, 452, 453, 454, 455, 471, 489, 490, 502, 758, 759, 760, 761, 765, 767, 768, 770, 779, 782, 786, 787, 789, 790, 30, 97, 152, 153, 185, 186, 187, 188, 212, 213, 261, 509, 510, 511, 512, 592, 593, 594, 783, 785, 742, 744, 746, 748, 749, 751, 752, 754, 763, 764, 775, 776, 777, 778, 0, 7, 8, 9, 10, 11, 19, 20, 21, 22, 23, 24, 25, 26, 27, 35, 36, 37, 38, 39, 40, 41, 43, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 75, 76, 77, 78, 79, 80, 81, 82, 83, 90, 91, 92, 93, 94, 105, 106, 107, 108, 110, 111, 112, 120, 121, 122, 123, 124, 125, 132, 133, 134, 135, 136, 137, 140, 150, 159, 160, 161, 162, 163, 164, 165, 167, 168, 169, 170, 175, 176, 177, 178, 179, 197, 198, 199, 200, 201, 202, 203, 204, 205, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 238, 239, 240, 241, 242, 243, 247, 249, 255, 256, 257, 258, 259, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 293, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 326, 331, 336, 345, 346, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 381, 384, 385, 386, 387, 388, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 445, 447, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 491, 492, 493, 499, 500, 501, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 575, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 630, 631, 632, 633, 634, 639, 642, 643, 644, 645, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 661, 662, 663, 664, 665, 666, 667, 668, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 683, 685, 686, 687, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 708, 709, 730, 732, 733, 735, 736, 737, 738, 739, 740, 753, 756, 757, 762, 766, 769, 771, 772, 780, 494, 495, 503, 504, 525, 570, 571, 572, 573, 574, 576, 577, 585, 635, 636, 637, 638, 646, 659, 660, 669, 670, 682, 684, 688, 689, 707, 710, 712, 713, 714, 715, 716, 717, 718, 720, 721, 723, 724, 725, 726, 727, 747, 29, 96, 151, 184, 211, 260, 295, 339, 389, 448, 470, 488, 731, 734, 741, 743, 745, 750, 755, 508, 591, 671, 690, 711, 719, 722, 728, 729}; + + /** + * Finds the index of the longest matching prefix or -1 if none match. + * Prefix matches must terminate with one of the given separator characters to be found valid. + */ + public static int indexOfByPrefix(String version, String separators) { + for (var versionIdx : BY_LENGTH) { + var versionText = VERSIONS.get(versionIdx); + if (version.startsWith(versionText) && (versionText.length() == version.length() || separators.indexOf(version.charAt(versionText.length())) != -1)) { + return versionIdx; + } + } + return -1; + } +} diff --git a/src/main/java/net/neoforged/minecraftdependencies/MinecraftDistribution.java b/src/main/java/net/neoforged/minecraftdependencies/MinecraftDistribution.java index 76b3b3ea..da9cd0a5 100644 --- a/src/main/java/net/neoforged/minecraftdependencies/MinecraftDistribution.java +++ b/src/main/java/net/neoforged/minecraftdependencies/MinecraftDistribution.java @@ -5,7 +5,6 @@ /** * The source of this attribute is the list of dependencies declared by the server and client Minecraft distributions. - *

* * @see GradleMinecraftDependencies project */ diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index 0938d0d8..b74406c5 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -8,6 +8,7 @@ import net.neoforged.moddevgradle.dsl.NeoForgeExtension; import net.neoforged.moddevgradle.dsl.RunModel; import net.neoforged.moddevgradle.internal.utils.ExtensionUtils; +import net.neoforged.moddevgradle.internal.utils.VersionCapabilities; import net.neoforged.moddevgradle.tasks.JarJar; import net.neoforged.nfrtgradle.CreateMinecraftArtifacts; import net.neoforged.nfrtgradle.DownloadAssets; @@ -324,7 +325,7 @@ public void apply(Project project) { modulePath -> modulePath.getDependencies().addLater(modulePathDependency), legacyClassPath -> legacyClassPath.extendsFrom(additionalClasspath), downloadAssets.flatMap(DownloadAssets::getAssetPropertiesFile), - extension.getNeoFormVersion() + extension.getNeoFormVersion().map(VersionCapabilities::ofNeoFormVersion) ); setupJarJar(project); @@ -494,7 +495,7 @@ static void setupRuns(Project project, Consumer configureModulePath, Consumer configureLegacyClasspath, Provider assetPropertiesFile, - Provider neoFormVersion + Provider versionCapabilities ) { var ideIntegration = IdeIntegration.of(project, branding); @@ -522,7 +523,7 @@ static void setupRuns(Project project, configureLegacyClasspath, assetPropertiesFile, devLaunchConfig, - neoFormVersion, + versionCapabilities, createLaunchScriptsTask ); prepareRunTasks.put(run, prepareRunTask); @@ -547,7 +548,7 @@ private static TaskProvider setupRunInGradle( Consumer configureLegacyClasspath, // TODO: can be removed in favor of directly passing a configuration for the moddev libraries Provider assetPropertiesFile, Configuration devLaunchConfig, - Provider neoFormVersion, + Provider versionCapabilities, TaskProvider createLaunchScriptsTask) { var ideIntegration = IdeIntegration.of(project, branding); var configurations = project.getConfigurations(); @@ -616,7 +617,7 @@ private static TaskProvider setupRunInGradle( task.getProgramArguments().set(run.getProgramArguments()); task.getJvmArguments().set(run.getJvmArguments()); task.getGameLogLevel().set(run.getLogLevel()); - task.getNeoFormVersion().set(neoFormVersion); + task.getVersionCapabilities().set(versionCapabilities); }); ideIntegration.runTaskOnProjectSync(prepareRunTask); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/NeoDevFacade.java b/src/main/java/net/neoforged/moddevgradle/internal/NeoDevFacade.java index 997f95f4..68c61f70 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/NeoDevFacade.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/NeoDevFacade.java @@ -2,6 +2,7 @@ import net.neoforged.moddevgradle.dsl.ModModel; import net.neoforged.moddevgradle.dsl.RunModel; +import net.neoforged.moddevgradle.internal.utils.VersionCapabilities; import org.gradle.api.DomainObjectCollection; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; @@ -43,7 +44,8 @@ public static void setupRuns(Project project, configureModulePath, configureAdditionalClasspath, assetPropertiesFile, - project.getObjects().property(String.class) // empty provider + // This overload of the method was only used by NeoForge 1.21.3 + project.provider(() -> VersionCapabilities.ofMinecraftVersion("1.21.3")) ); } @@ -65,7 +67,7 @@ public static void setupRuns(Project project, configureModulePath, configureAdditionalClasspath, assetPropertiesFile, - neoFormVersion + neoFormVersion.map(VersionCapabilities::ofNeoFormVersion) ); } diff --git a/src/main/java/net/neoforged/moddevgradle/internal/PrepareRunOrTest.java b/src/main/java/net/neoforged/moddevgradle/internal/PrepareRunOrTest.java index 3663ac34..e50297ad 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/PrepareRunOrTest.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/PrepareRunOrTest.java @@ -3,7 +3,7 @@ import net.neoforged.moddevgradle.internal.utils.FileUtils; import net.neoforged.moddevgradle.internal.utils.OperatingSystem; import net.neoforged.moddevgradle.internal.utils.StringUtils; -import net.neoforged.moddevgradle.internal.utils.VersionUtils; +import net.neoforged.moddevgradle.internal.utils.VersionCapabilities; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; import org.gradle.api.file.ConfigurableFileCollection; @@ -98,15 +98,17 @@ abstract class PrepareRunOrTest extends DefaultTask { /** * Only used when {@link #getRunTypeTemplatesSource()} is empty, * to know whether the associated Minecraft version requires one or two data runs. + * Defaults to latest. */ - @Optional @Input - public abstract Property getNeoFormVersion(); + @Optional + public abstract Property getVersionCapabilities(); private final ProgramArgsFormat programArgsFormat; protected PrepareRunOrTest(ProgramArgsFormat programArgsFormat) { this.programArgsFormat = programArgsFormat; + getVersionCapabilities().convention(VersionCapabilities.latest()); } protected abstract UserDevRunType resolveRunType(UserDevConfig userDevConfig); @@ -190,11 +192,7 @@ private UserDevConfig getSimulatedUserDevConfigForVanilla() { true, "net.minecraft.server.Main", commonArgs, List.of(), Map.of(), Map.of() )); - var splitData = getNeoFormVersion() - .map(VersionUtils::hasSplitDataRuns) - .orElse(false) // Default to single run for backwards compatibility - .get(); - if (splitData) { + if (getVersionCapabilities().getOrElse(VersionCapabilities.latest()).splitDataRuns()) { runTypes.put("clientData", new UserDevRunType( true, "net.minecraft.client.data.Main", commonArgs, List.of(), Map.of(), Map.of() )); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/utils/VersionCapabilities.java b/src/main/java/net/neoforged/moddevgradle/internal/utils/VersionCapabilities.java new file mode 100644 index 00000000..947af323 --- /dev/null +++ b/src/main/java/net/neoforged/moddevgradle/internal/utils/VersionCapabilities.java @@ -0,0 +1,120 @@ +package net.neoforged.moddevgradle.internal.utils; + +import net.neoforged.moddevgradle.internal.generated.MinecraftVersionList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.util.regex.Pattern; + +/** + * Models the changing capabilities of the modding platform and Vanilla, which we tie to the Minecraft version. + * @param javaVersion Which Java version Vanilla uses to compile and run. + * @param splitDataRuns Whether Vanilla has separate main classes for generating client and server data. + */ +public record VersionCapabilities(int javaVersion, boolean splitDataRuns) implements Serializable { + private static final Logger LOG = LoggerFactory.getLogger(VersionCapabilities.class); + + private static final VersionCapabilities LATEST = new VersionCapabilities(21, true); + + private static final Pattern NEOFORGE_PATTERN = Pattern.compile("^(\\d+\\.\\d+)\\.\\d+(|-.*)$"); + + private static final int MC_24W45A_INDEX = getReferenceVersionIndex("24w45a"); + private static final int MC_24W14A_INDEX = getReferenceVersionIndex("24w14a"); + private static final int MC_1_18_PRE2_INDEX = getReferenceVersionIndex("1.18-pre2"); + private static final int MC_21W19A_INDEX = getReferenceVersionIndex("21w19a"); + + public static VersionCapabilities latest() { + return LATEST; + } + + public static VersionCapabilities ofMinecraftVersion(String minecraftVersion) { + var versionIndex = MinecraftVersionList.VERSIONS.indexOf(minecraftVersion); + if (versionIndex == -1) { + LOG.info("Minecraft Version {} is unknown. Assuming latest capabilities.", versionIndex); + return LATEST; + } + + return ofVersionIndex(versionIndex); + } + + public static VersionCapabilities ofVersionIndex(int versionIndex) { + var javaVersion = getJavaVersion(versionIndex); + var splitData = hasSplitDataEntrypoints(versionIndex); + + return new VersionCapabilities(javaVersion, splitData); + } + + static int getJavaVersion(int versionIndex) { + if (versionIndex <= MC_24W14A_INDEX) { + return 21; + } else if (versionIndex <= MC_1_18_PRE2_INDEX) { + return 17; + } else if (versionIndex <= MC_21W19A_INDEX) { + return 16; + } else { + return 8; + } + } + + static boolean hasSplitDataEntrypoints(int versionIndex) { + return versionIndex <= MC_24W45A_INDEX; + } + + static int indexOfNeoForgeVersion(String version) { + // NeoForge omits the "1." at the start of the Minecraft version and just adds an incrementing last digit + var matcher = NEOFORGE_PATTERN.matcher(version); + if (!matcher.matches()) { + return -1; + } + return MinecraftVersionList.VERSIONS.indexOf("1." + matcher.group(1)); + } + + public static VersionCapabilities ofNeoForgeVersion(String version) { + var index = indexOfNeoForgeVersion(version); + if (index == -1) { + LOG.warn("Failed to parse MC version from NeoForge version {}. Using capabilities of latest known Minecraft version.", version); + return LATEST; + } + + return ofVersionIndex(index); + } + + static int indexOfNeoFormVersion(String version) { + // Examples: 1.21- + return MinecraftVersionList.indexOfByPrefix(version, "-"); + } + + public static VersionCapabilities ofNeoFormVersion(String version) { + var index = indexOfNeoFormVersion(version); + if (index == -1) { + LOG.warn("Failed to parse MC version from NeoForm version {}. Using capabilities of latest known Minecraft version.", version); + return LATEST; + } + + return ofVersionIndex(index); + } + + static int indexOfForgeVersion(String version) { + // Forge versions are generally "-" + return MinecraftVersionList.indexOfByPrefix(version, "-"); + } + + public static VersionCapabilities ofForgeVersion(String version) { + var index = indexOfForgeVersion(version); + if (index == -1) { + LOG.warn("Failed to parse MC version from Forge version {}. Using capabilities of latest known Minecraft version.", version); + return LATEST; + } + + return ofVersionIndex(index); + } + + private static int getReferenceVersionIndex(String v) { + var idx = MinecraftVersionList.VERSIONS.indexOf(v); + if (idx == -1) { + throw new IllegalArgumentException("Reference version " + v + " is not in version list!"); + } + return idx; + } +} diff --git a/src/main/java/net/neoforged/moddevgradle/internal/utils/VersionUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/utils/VersionUtils.java deleted file mode 100644 index cd106808..00000000 --- a/src/main/java/net/neoforged/moddevgradle/internal/utils/VersionUtils.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.neoforged.moddevgradle.internal.utils; - -import java.util.Objects; -import java.util.regex.Pattern; - -public final class VersionUtils { - private VersionUtils() {} - - private static final Pattern RELEASE_PATTERN = Pattern.compile("1\\.(\\d+)(?:.(\\d+))?(?:-.*)?$"); - - /** - * Checks whether the provided NeoForm version should have split client and server data runs. - */ - public static boolean hasSplitDataRuns(String neoFormVersion) { - // Snapshots starting from 24w45a - if (neoFormVersion.length() >= 5 && neoFormVersion.charAt(2) == 'w') { - try { - var year = Integer.parseInt(neoFormVersion.substring(0, 2)); - var week = Integer.parseInt(neoFormVersion.substring(3, 5)); - - return year > 24 || (year == 24 && week >= 45); - } catch (NumberFormatException ignored) {} - } - // Releases starting from 1.21.4 - var matcher = RELEASE_PATTERN.matcher(neoFormVersion); - if (matcher.find()) { - try { - int minor = Integer.parseInt(matcher.group(1)); - // If there is no patch version, the second group has a null value - int patch = Integer.parseInt(Objects.requireNonNullElse(matcher.group(2), "0")); - - return minor > 21 || (minor == 21 && patch >= 4); - } catch (NumberFormatException ignored) {} - } - // Assume other version patterns are newer and therefore split - return true; - } -} diff --git a/src/test/java/net/neoforged/moddevgradle/internal/VersionUtilsTest.java b/src/test/java/net/neoforged/moddevgradle/internal/VersionUtilsTest.java deleted file mode 100644 index c497fe45..00000000 --- a/src/test/java/net/neoforged/moddevgradle/internal/VersionUtilsTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package net.neoforged.moddevgradle.internal; - -import net.neoforged.moddevgradle.internal.utils.VersionUtils; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static org.assertj.core.api.Assertions.assertThat; - -public class VersionUtilsTest { - @ParameterizedTest() - @CsvSource({ - "1.21.4,true", - "1.21.4-pre1-20241120.190508,true", - "1.21.3,false", - "24w45a,true", - "24w44a,false", - "1.21.3-pre1,false", - "25w01a,true", - "23w07a,false", - "1.20,false", - "1.20-pre1,false", - "1.21,false", - "1.21-pre1-20240529.150918,false", - "1.21-pre1,false", - "1.22,true", - "1.22-pre1,true" - }) - public void testSplitDataRunsCorrectness(String neoFormVersion, boolean splitDataRuns) { - assertThat(VersionUtils.hasSplitDataRuns(neoFormVersion)) - .isEqualTo(splitDataRuns); - } - - @ParameterizedTest - @CsvSource({ - "1", - "1.", - "1.21.", - "test", - "24w", - "24w5", - "24w50", - "2aw50", - "24242", - }) - public void testSplitDataRunsDoesNotCrash(String neoFormVersion) { - assertThat(VersionUtils.hasSplitDataRuns(neoFormVersion)) - .isTrue(); - } -} diff --git a/src/test/java/net/neoforged/moddevgradle/internal/utils/VersionCapabilitiesTest.java b/src/test/java/net/neoforged/moddevgradle/internal/utils/VersionCapabilitiesTest.java new file mode 100644 index 00000000..cb15b318 --- /dev/null +++ b/src/test/java/net/neoforged/moddevgradle/internal/utils/VersionCapabilitiesTest.java @@ -0,0 +1,132 @@ +package net.neoforged.moddevgradle.internal.utils; + +import net.neoforged.moddevgradle.internal.generated.MinecraftVersionList; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class VersionCapabilitiesTest { + @ParameterizedTest() + @CsvSource({ + "1.21.4,21", + "1.21.4-pre1-20241120.190508,21", + "1.21.3,21", + "24w45a,21", + "24w44a,21", + "1.21.3-pre1,21", + "25w01a,21", + "23w07a,17", + "1.20,17", + "1.20-pre1,17", + "1.21,21", + "1.21-pre1-20240529.150918,21", + "1.21-pre1,21", + "1.22,21", + "1.22-pre1,21", + "1.0,8", + "1.14.2 Pre-Release 2,8", + "21w19a,16", + }) + public void testJavaVersion(String neoFormVersion, int javaVersion) { + assertThat(VersionCapabilities.ofNeoFormVersion(neoFormVersion).javaVersion()) + .isEqualTo(javaVersion); + } + + @ParameterizedTest() + @CsvSource({ + "21.4.8-beta,1.21.4", + "21.4.10-beta-pr-1744-gh-1582,1.21.4", + "21.4.10,1.21.4", + "26.1.10,", + }) + public void testNeoForgeVersionParsing(String neoForgeVersion, String minecraftVersion) { + var idx = VersionCapabilities.indexOfNeoForgeVersion(neoForgeVersion); + String actual; + if (idx == -1) { + actual = null; + } else { + actual = MinecraftVersionList.VERSIONS.get(idx); + } + assertEquals(minecraftVersion, actual); + } + + @ParameterizedTest() + @CsvSource({ + "1.7.2-10.12.2.1161-mc172,1.7.2", + "1.10-12.18.0.2000-1.10.0,1.10", + "1.12.2-14.23.5.2860,1.12.2", + "1.20.1-47.3.12,1.20.1", + }) + public void testForgeVersionParsing(String forgeVersion, String minecraftVersion) { + var idx = VersionCapabilities.indexOfForgeVersion(forgeVersion); + String actual; + if (idx == -1) { + actual = null; + } else { + actual = MinecraftVersionList.VERSIONS.get(idx); + } + assertEquals(minecraftVersion, actual); + } + + @ParameterizedTest() + @CsvSource({ + // This checks that a separator must follow the prefix match since this matches the 1.20.1 prefix, but + // should not be recognized as such. + "1.20.12-20200101202020,", + "1.20.1-20200101202020,1.20.1", + "1.20.1,1.20.1", + "1.20.1-rc1,1.20.1-rc1", + }) + public void testNeoFormVersionParsing(String neoFormVersion, String minecraftVersion) { + var idx = VersionCapabilities.indexOfNeoFormVersion(neoFormVersion); + String actual; + if (idx == -1) { + actual = null; + } else { + actual = MinecraftVersionList.VERSIONS.get(idx); + } + assertEquals(minecraftVersion, actual); + } + + @ParameterizedTest() + @CsvSource({ + "1.21.4,true", + "1.21.4-pre1-20241120.190508,true", + "1.21.3,false", + "24w45a,true", + "24w44a,false", + "1.21.3-pre1,false", + "25w01a,true", + "23w07a,false", + "1.20,false", + "1.20-pre1,false", + "1.21,false", + "1.21-pre1-20240529.150918,false", + "1.21-pre1,false", + "1.22,true", + "1.22-pre1,true" + }) + public void testSplitDataRunsCorrectness(String neoFormVersion, boolean splitDataRuns) { + assertThat(VersionCapabilities.ofNeoFormVersion(neoFormVersion).splitDataRuns()) + .isEqualTo(splitDataRuns); + } + + @ParameterizedTest + @CsvSource({ + "1", + "1.", + "1.21.", + "test", + "24w", + "24w5", + "24w50", + "2aw50", + "24242", + }) + public void testSplitDataRunsDoesNotCrash(String neoFormVersion) { + assertThat(VersionCapabilities.ofNeoFormVersion(neoFormVersion).splitDataRuns()) + .isTrue(); + } +}