1818package org .jackhuang .hmcl .game ;
1919
2020import com .google .gson .JsonParseException ;
21+ import org .jackhuang .hmcl .util .DigestUtils ;
2122import org .jackhuang .hmcl .util .gson .JsonUtils ;
2223import org .jenkinsci .constant_pool_scanner .ConstantPool ;
2324import org .jenkinsci .constant_pool_scanner .ConstantPoolScanner ;
3132import java .util .List ;
3233import java .util .Map ;
3334import java .util .Optional ;
34- import java .util .stream . Collectors ;
35+ import java .util .regex . Pattern ;
3536import java .util .stream .StreamSupport ;
3637import java .util .zip .ZipEntry ;
3738import java .util .zip .ZipFile ;
@@ -45,6 +46,96 @@ final class GameVersion {
4546 private GameVersion () {
4647 }
4748
49+ // For Minecraft 1.0 rc versions and versions earlier than Alpha 1.0.6,
50+ // it is difficult to obtain the game version from the JAR.
51+ // For these versions, we get the version number based on their SHA-1 hash.
52+ private static final Map <String , String > KNOWN_VERSIONS = Map .<String , String >ofEntries (
53+ Map .entry ("4df7880d26414b400640f0b8e54344df2b66c51a" , "1.0.0-rc1" ),
54+ Map .entry ("9e04e60eef3fb4657b406dcb3ad5e3a675ecf6af" , "1.0.0-rc2-1" ),
55+ Map .entry ("6a6b67d34149afc47cf9608b3967582639097df9" , "1.0.0-rc2-2" ),
56+ Map .entry ("6e54fbe19b7797f3e3a2cb9feb5da41a40926db8" , "1.0.0-rc2-3" ),
57+ Map .entry ("fe189e91a3e7166d46fad8ce53ba0ce34b4c5f97" , "a1.0.5" ),
58+ Map .entry ("73f569bf5556580979606049204835ae1a54f04d" , "a1.0.5_01" ),
59+ Map .entry ("e5838277b3bb193e58408713f1fc6e005c5f3c0c" , "a1.0.4" ),
60+ Map .entry ("31e9736457ef3e0bfea69c720137a1bd8ba7caae" , "a1.0.3" ),
61+ Map .entry ("4f9ce27cfc6394af533fde11a90b6a233dd908bf" , "a1.0.2_02" ),
62+ Map .entry ("7457e763ad81eee1e63628d628647f53806dab7c" , "a1.0.2_01" ),
63+ Map .entry ("02c57723da508aab36455782904bfd6e3e1023e6" , "a1.0.1_01" ),
64+ Map .entry ("88c1931650b0e5be349017e124a7785a745111e9" , "inf-20100630-2" ),
65+ Map .entry ("121fff417950ad72005ca4d882ca6269e874547b" , "inf-20100630-1" ),
66+ Map .entry ("eb50bce3cb542488b3039aa0f4c3c0ec7595ab24" , "inf-20100629" ),
67+ Map .entry ("4d31259a71c5886b987b9eca6034ca5552079eed" , "inf-20100627" ),
68+ Map .entry ("d9fc6416186e1454945ab135f37c730c7d2c1adc" , "inf-20100625-2" ),
69+ Map .entry ("990b531a26ae8e475032915938763c12cdb2dcf9" , "inf-20100625-1" ),
70+ Map .entry ("644c050e846035e06a6637bffa2afee1e5769c8c" , "inf-20100624" ),
71+ Map .entry ("d3eb1dce5a6c86dd0d6483ba56223276dcf32c30" , "inf-20100617-3" ),
72+ Map .entry ("06641eca013fe5032a5f1a9d1289599f0970a735" , "inf-20100617-2" ),
73+ Map .entry ("89eab2c1a353707cc00f074dffba9cb7a4f5e304" , "inf-20100618" ),
74+ Map .entry ("47518a623da068728b50b4b53436dea4621b7bf8" , "inf-20100615" ),
75+ Map .entry ("421318a554f17463a56a271d08e9597941d066d9" , "inf-20100611" ),
76+ Map .entry ("a9efb36c142bf835d3d410150856dc9ceeaae81b" , "inf-20100608" ),
77+ Map .entry ("7bbf38d53dd47753af266be4e1c5865342a26974" , "inf-20100607" ),
78+ Map .entry ("27010a5137abd2c8d8df85e99c14f5406ec197b3" , "inf-20100420" ),
79+ Map .entry ("a91c9d8e0184eda610213b1a5425fbfa078cb191" , "inf-20100415" ),
80+ Map .entry ("86dd3b1558352b38d4d15c7ec51b9131bd7aed4b" , "inf-20100414" ),
81+ Map .entry ("7b39167f14d9f0ce7af6819433856be7b82d2412" , "inf-20100413" ),
82+ Map .entry ("a74c8ee1ecd57999e242952697bbde6cc0904f99" , "inf-20100330" ),
83+ Map .entry ("47b1b32430a211520993552ba0a5e00c1af44724" , "inf-20100327" ),
84+ Map .entry ("99da3b55b4db292faca59824e3ec76bf53a7eae6" , "inf-20100325" ),
85+ Map .entry ("2c89471a81858d37ab0b01e042131878b6853b38" , "inf-20100321" ),
86+ Map .entry ("7f1c48fc6d61dd0cbfd41b84fb0b0a22944aa02c" , "inf-20100320" ),
87+ Map .entry ("ad7b3cd706098ac05c7dba61dacb40bafcd47db6" , "inf-20100316" ),
88+ Map .entry ("65a00a10001978538ab8eef1a2533f47d4ecbe23" , "inf-20100313" ),
89+ Map .entry ("801ce486bb7fd1b43a56bc5d226dfb1370c08678" , "in-20100223" ),
90+ Map .entry ("af3d7f95ca75e130a9c5c74be0a9c09600a15686" , "in-20100219" ),
91+ Map .entry ("2ba9e9a2bdac1e8af6a36819e9bb01375889b078" , "in-20100218" ),
92+ Map .entry ("dcbe38d0e4ac2caec7e5c0f9ebcb0ec9179dcdff" , "in-20100214-2" ),
93+ Map .entry ("e6bb9306dab60626ba6ffd24fc9742fd272f5acb" , "in-20100214-1" ),
94+ Map .entry ("f1ae7e37e52b33753b35402e581eb65dc5bba877" , "in-20100212-2" ),
95+ Map .entry ("5275aaf68d6388ef8278b575e95ae83ad641fe3e" , "in-20100212-1" ),
96+ Map .entry ("fa8525be5612d00f6001be7d4cdb764b66e88f9d" , "in-20100207-2" ),
97+ Map .entry ("054e3d3f4e2c0463f80aa323767e018e6c23c1cd" , "in-20100207-1" ),
98+ Map .entry ("049b002cdd164e5c5e9b78780b12ab4dc2e80120" , "in-20100206-2103" ),
99+ Map .entry ("b2abb22e001abf01ca7555ced5d6024350955d70" , "in-20100203" ),
100+ Map .entry ("38d4df5132077ac60f0bdf67564f5fff4ee309e2" , "in-20100201-3" ),
101+ Map .entry ("1f2ca31fc761207bcabc07f0cf4b725a9a3286e4" , "in-20100201-2" ),
102+ Map .entry ("c871e820d5356b88b3ad854789162f8b9227c80c" , "in-20100130" ),
103+ Map .entry ("03b858d31c090b629f406aa1d548ac7b25341f02" , "in-20100129" ),
104+ Map .entry ("3f2418f906d438b26ae6c9dbbadf3942f5845504" , "in-20100128-2304" ),
105+ Map .entry ("baf0c7b1e231f0984e1c35e27f38eea2743f8ee2" , "in-20100125-2" ),
106+ Map .entry ("2cd03bcfc26c95bcf31b5d5e1d4dda7dc071ca6a" , "in-20100125-1" ),
107+ Map .entry ("a0b58472ebf12f7e562b09b8a51dcb4cacc57005" , "in-20100111-1" ),
108+ Map .entry ("38958105bfe0f7064b3c4996905cb6978d4d4b0b" , "in-20100105" ),
109+ Map .entry ("3161652a6835c61817fda6fe13245c57528ed418" , "in-20091231-2" ),
110+ Map .entry ("94ee2e7aa7d093fa8dfc684baa8bd8afe002580f" , "in-20091223-2" ),
111+ Map .entry ("54622801f5ef1bcc1549a842c5b04cb5d5583005" , "c0.30_01c" ),
112+ Map .entry ("51bc951530207b538596941a6f353f87dfc24233" , "c0.30-2" ),
113+ Map .entry ("619ea74c6d0ae5c0125d1e31e299105e100139ab" , "c0.30-1" ),
114+ Map .entry ("6a6f92b691f9d6b7ca991a6db8a1cfc6e319815b" , "c0.29_02" ),
115+ Map .entry ("bb5e7f1c231f45fd630f30a75570937c103f5b55" , "c0.29_01" ),
116+ Map .entry ("7ccde270abacd028d3618be99537ccf7071a605b" , "c0.28_01" ),
117+ Map .entry ("aff4060249dd6152012218e120d7aad5e758de83" , "c0.27_st" ),
118+ Map .entry ("349630cb1b895335c38b499f84dc28d9f8a38513" , "c0.25_05_st" ),
119+ Map .entry ("0b387d2087edda894fae4af00de5ac202dbffa7c" , "c0.24_st_03" ),
120+ Map .entry ("85159cea8663ed720be88ca0ee008a5830b0829a" , "c0.0.22a_05" ),
121+ Map .entry ("83b6483feb88136b6b4662b553d8f80f5f88efa5" , "c0.0.21a" ),
122+ Map .entry ("c2f8fddde4691d7c567c0c049ad4d03eb6b9e61c" , "c0.0.20a_01" ),
123+ Map .entry ("e2b248f1013933af9f801729418409fb7198de1b" , "c0.0.19a_06-2" ),
124+ Map .entry ("a78468abd491d6c661c000f60d6270a692ba4710" , "c0.0.18a_02" ),
125+ Map .entry ("ca840460a6589552c9d1978ca121bf3e7c16a010" , "c0.0.17a" ),
126+ Map .entry ("741eb3f84097fdcc0327230e018a0f8cd39addfb" , "c0.0.16a_02" ),
127+ Map .entry ("936d575b1ab1a04a341ad43d76e441e88d2cd987" , "c0.0.13a" ),
128+ Map .entry ("e8aa74a5bee547097375d44ffb2e407b2ea8ee4d" , "c0.0.14a_08" ),
129+ Map .entry ("b9884f960f2b28a36b34db3447963f1ff4058aa4" , "c0.0.23a_01" ),
130+ Map .entry ("7ba9e63aec8a15a99ecd47900c848cdce8a51a03" , "c0.0.13a_03" ),
131+ Map .entry ("501ea8a6274faffe0144d3b24ed56797ce0765ff" , "c0.0.12a_03" ),
132+ Map .entry ("3a799f179b6dcac5f3a46846d687ebbd95856984" , "c0.0.11a" ),
133+ Map .entry ("6323bd14ed7f83852e17ebc8ec418e55c97ddfe4" , "rd-161348" ),
134+ Map .entry ("b100be8097195b6c9112046dc6a80d326c8df839" , "rd-160052" ),
135+ Map .entry ("12dace5a458617d3f90337a7ebde86c0593a6899" , "rd-132328" ),
136+ Map .entry ("393e8d4b4d708587e2accd7c5221db65365e1075" , "rd-132211" )
137+ );
138+
48139 private static Optional <String > getVersionFromJson (InputStream versionJson ) {
49140 try {
50141 Map <?, ?> version = JsonUtils .fromNonNullJsonFully (versionJson , Map .class );
@@ -59,21 +150,23 @@ private static Optional<String> getVersionFromJson(InputStream versionJson) {
59150 }
60151
61152 private static Optional <String > getVersionOfClassMinecraft (InputStream bytecode ) throws IOException {
153+ final String constantPrefix = "Minecraft Minecraft " ;
62154 ConstantPool pool = ConstantPoolScanner .parse (bytecode , ConstantType .STRING );
63-
64- return StreamSupport .stream (pool .list (StringConstant .class ).spliterator (), false )
65- .map (StringConstant ::get )
66- .filter (s -> s .startsWith ("Minecraft Minecraft " ))
67- .map (s -> s .substring ("Minecraft Minecraft " .length ()))
68- .findFirst ();
155+ for (StringConstant constant : pool .list (StringConstant .class )) {
156+ String value = constant .get ();
157+ if (value .startsWith (constantPrefix )) {
158+ return Optional .of (value .substring (constantPrefix .length ()));
159+ }
160+ }
161+ return Optional .empty ();
69162 }
70163
71164 private static Optional <String > getVersionFromClassMinecraftServer (InputStream bytecode ) throws IOException {
72165 ConstantPool pool = ConstantPoolScanner .parse (bytecode , ConstantType .STRING );
73166
74167 List <String > list = StreamSupport .stream (pool .list (StringConstant .class ).spliterator (), false )
75168 .map (StringConstant ::get )
76- .collect ( Collectors . toList () );
169+ .toList ();
77170
78171 int idx = -1 ;
79172
@@ -83,8 +176,9 @@ private static Optional<String> getVersionFromClassMinecraftServer(InputStream b
83176 break ;
84177 }
85178
179+ Pattern pattern = Pattern .compile (".*[0-9].*" );
86180 for (int i = idx - 1 ; i >= 0 ; --i )
87- if (list .get (i ).matches (".*[0-9].*" ))
181+ if (pattern . matcher ( list .get (i )) .matches ())
88182 return Optional .of (list .get (i ));
89183
90184 return Optional .empty ();
@@ -108,10 +202,16 @@ public static Optional<String> minecraftVersion(Path file) {
108202 Optional <String > result = getVersionOfClassMinecraft (is );
109203 if (result .isPresent ()) {
110204 String version = result .get ();
111- if (version .startsWith ("Beta " )) {
112- result = Optional .of ("b" + version .substring ("Beta " .length ()));
205+ // For Minecraft 1.0 rc1/rc2-1/rc2-2, this value is "RC1"
206+ // For Minecraft 1.0 rc2-3, this value is "RC2"
207+ if (!version .equals ("RC1" ) && !version .equals ("RC2" )) {
208+ if (version .startsWith ("Beta " )) {
209+ result = Optional .of ("b" + version .substring ("Beta " .length ()));
210+ } else if (version .startsWith ("Alpha v" )) {
211+ result = Optional .of ("a" + version .substring ("Alpha v" .length ()));
212+ }
213+ return result ;
113214 }
114- return result ;
115215 }
116216 }
117217 }
@@ -122,7 +222,12 @@ public static Optional<String> minecraftVersion(Path file) {
122222 return getVersionFromClassMinecraftServer (is );
123223 }
124224 }
125- return Optional .empty ();
225+ } catch (IOException ignored ) {
226+ }
227+
228+ try {
229+ String digest = DigestUtils .digestToString ("SHA-1" , file );
230+ return Optional .ofNullable (KNOWN_VERSIONS .get (digest ));
126231 } catch (IOException e ) {
127232 return Optional .empty ();
128233 }
0 commit comments