Skip to content

Commit daf7681

Browse files
committed
Run extra validation for Parchment versions, fixes #988
Copies `ParchmentVersion` from Mavenizer, for now.
1 parent 6ff2376 commit daf7681

2 files changed

Lines changed: 156 additions & 1 deletion

File tree

src/main/java/net/minecraftforge/gradle/internal/MinecraftMappingsImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ abstract class MinecraftMappingsImpl implements MinecraftMappingsInternal {
2121
public MinecraftMappingsImpl(String channel, String version) {
2222
var problems = this.getObjects().newInstance(ForgeGradleProblems.class);
2323
this.channel = Util.checkMappingsParam(problems, channel, "channel");
24-
this.version = Util.checkMappingsParam(problems, version, "version");
24+
if (this.channel.equals("parchment"))
25+
this.version = ParchmentVersion.parse(Util.checkMappingsParam(problems, version, "version")).toFriendly();
26+
else
27+
this.version = Util.checkMappingsParam(problems, version, "version");
2528
}
2629

2730
@Override
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradle.internal;
6+
7+
import org.jspecify.annotations.NullUnmarked;
8+
9+
import java.util.regex.Pattern;
10+
11+
@NullUnmarked
12+
record ParchmentVersion(
13+
String timestamp,
14+
/* @Nullable */ String mcVersion,
15+
/* @Nullable */ String mapMcVersion
16+
) {
17+
private static final Pattern TIMESTAMP = Pattern.compile("\\d{4}.\\d{2}.\\d{2}");
18+
private static final Pattern MCP_TIMESTAMP = Pattern.compile("\\d{8}.\\d{6}");
19+
20+
// Parchment related things
21+
public static final String PARCHMENT_MAVEN = "https://maven.parchmentmc.org/";
22+
private static final String PARCHMENT_GROUP = "org.parchmentmc.data"; // Name is "parchment-{mcversion}'
23+
24+
/**
25+
* <pre>
26+
* Parchment names can be specified in many variants, including some 'shorthand's
27+
* Basing this implementation on https://parchmentmc.org/docs/getting-started
28+
*
29+
* Namely, (in case they change the site)
30+
*
31+
* For using Parchment on the same version of Minecraft:
32+
* YYYY.MM.DD-&lt;Environment MC version>
33+
* Examples:
34+
* 2021.12.12-1.17.1 for Minecraft 1.17.1
35+
* 2022.08.07-1.18.2 for Minecraft 1.18.2
36+
* 2022.08.14-1.19.2 for Minecraft 1.19.2
37+
*
38+
* For using Parchment for an older version on a newer MC version
39+
* &lt;Mapping's MC version>-YYYY.MM.DD-&lt;Environment MC version>
40+
* Examples:
41+
* 1.17.1-2021.12.12-1.18
42+
* Minecraft 1.17.1 mappings (2021.12.12-1.17.1) in an MC 1.18 environment
43+
* 1.18.2-2022.08.07-1.19.1
44+
* Minecraft 1.18.2 mappings (2021.08.07-1.18.2) in an MC 1.19.1 environment
45+
* 1.19.2-2022.08.14-1.20
46+
* Minecraft 1.19.2 mappings (2021.08.14-1.19.2) in an MC 1.20 environment
47+
*
48+
* Parchment also publishes 'snapshots', These are not supported by MCMaven, and as such will
49+
* throw an exception during parsing.
50+
* Example:
51+
* parchment-1.21.9/2025.10.05-nightly-SNAPSHOT
52+
* parchment-1.16.5/BLEEDING-SNAPSHOT
53+
* They have also published two known versions that don't follow the standard format. And I don't feel like supporting it.
54+
* parchment-1.16.5/20210607-SNAPSHOT
55+
* parchment-1.16.5/20210608-SNAPSHOT
56+
*
57+
* Tho undocumented, the implementation of Parchment's FG6 plugin supported specifying the MCP timestamp as part of the Environment MC version
58+
* https://github.com/ParchmentMC/Librarian/blob/c7f9878feb76d210aa65569fe38cad5297f439c5/src/main/java/org/parchmentmc/librarian/forgegradle/ParchmentMappingVersion.java#L52
59+
*
60+
* In addition to the above formats I DO support not specifying a Minecraft version. It will need to be filled in later
61+
* to find the correct download, but typically we can pull it from MCPConfig/other context.
62+
*
63+
* Note: This does not do any case sanitization
64+
*
65+
* @throws IllegalArgumentException if the version fails to parse
66+
*/
67+
public static ParchmentVersion parse(String version) {
68+
if (version == null)
69+
throw new IllegalArgumentException("Parchment mappings version must be present");
70+
71+
if (version.contains("-SNAPSHOT"))
72+
throw new IllegalArgumentException("Parchment snapshots are not supported: " + version);
73+
74+
var matcher = TIMESTAMP.matcher(version);
75+
if (!matcher.find())
76+
throw new IllegalArgumentException("Parchment version does not contain a timestamp: " + version);
77+
78+
int start = matcher.start();
79+
int end = matcher.end();
80+
81+
// Simple case, we just specify the timestamp
82+
if (start == 0 && end == version.length())
83+
return new ParchmentVersion(version, null, null);
84+
85+
var timestamp = matcher.group();
86+
String mcVersion = null;
87+
88+
// Minecraft Version is specified
89+
if (end < version.length()) {
90+
if (version.charAt(end) != '-' || end == version.length() - 1)
91+
throw new IllegalArgumentException("Parchment version does not specify Minecraft version: " + version);
92+
mcVersion = version.substring(end + 1);
93+
}
94+
95+
// Default mapping version is the same as mc version
96+
var mapMcVersion = stripMcp(mcVersion);
97+
98+
// Mappings MC version is specified
99+
if (start > 0) {
100+
if (version.charAt(start - 1) != '-' || start == 1)
101+
throw new IllegalArgumentException("Parchment version does not specify Mapping Minecraft version: " + version);
102+
mapMcVersion = version.substring(0, start - 1);
103+
}
104+
105+
return new ParchmentVersion(timestamp, mcVersion, mapMcVersion);
106+
}
107+
108+
/**
109+
* Variant of {@link #parse(String)} that returns null instead of throwing IllegalArgumentException
110+
*/
111+
public static ParchmentVersion tryParse(String version) {
112+
try {
113+
return parse(version);
114+
} catch (IllegalArgumentException e) {
115+
return null;
116+
}
117+
}
118+
119+
// Remove MCP timestamp if its on there.
120+
private static String stripMcp(String version) {
121+
if (version == null)
122+
return null;
123+
if (version.length() <= 17 || version.charAt(version.length() - 16) != '-')
124+
return version;
125+
126+
var matcher = MCP_TIMESTAMP.matcher(version);
127+
if (matcher.find() && matcher.start() == version.length() - 15)
128+
return version.substring(0, version.length() - 16);
129+
130+
return version;
131+
}
132+
133+
public ParchmentVersion withMinecraft(String mcVersion) {
134+
return new ParchmentVersion(timestamp, mcVersion, mapMcVersion == null ? mcVersion : mapMcVersion);
135+
}
136+
137+
public String toFriendly() {
138+
if (mapMcVersion == null) {
139+
if (mcVersion == null)
140+
return timestamp;
141+
return timestamp + '-' + mcVersion;
142+
}
143+
144+
if (mcVersion == null)
145+
return mapMcVersion + '-' + timestamp;
146+
147+
if (mapMcVersion.equals(stripMcp(mcVersion)))
148+
return timestamp + '-' + mcVersion;
149+
150+
return mapMcVersion + '-' + timestamp + '-' + mcVersion;
151+
}
152+
}

0 commit comments

Comments
 (0)