俗话说得好,分而治之。既然我们已经将脚本一分为五了,那么接下来就只需要一项一项地再分析,研究写法,就能取得辉煌的阶段性研究成果了~
参考资料:
Java路径
首先贴出来:
"C:\\Program Files\\Java\\jdk-15.0.2\\bin\\java.exe"
这一部分需要使用英文引号括起来,内容为一个指向java.exe的绝对路径(指向javaw.exe也可以)。例如,这里指向的是jdk 15的路径。
对于Minecraft 1.8.9来说,这项参数也可以指向Java 8, jdk 11, jdk 16, jdk 17,都是可以正常启动的。
比如说,很多启动器都拥有查找已安装Java版本的功能。Java的默认安装目录为C:\Program Files\Java,只要让启动器在此默认目录内递归搜索,寻找名为“java.exe”的可执行程序即可。
不过,作为一款入门级别的启动器,我们可以跳过自动查询的部分,毕竟相比于后面的部分——自动查询也不算很难。作为替代,我们可以把电脑里常用于启动Minecraft的Java版本路径存储起来。
java_path = "C:\\Program Files\\Java\\jdk-15.0.2\\bin\\java.exe"
或者,我建议您将Java路径存储在一个配置文件中,然后让Python读取此配置文件即可。配置文件不一定需要是conf格式或yaml格式,您大可以用JSON格式的文档来存储——反正Python原生支持读取写入JSON,而且相对来说比较简单。
"java_list":[{"version": "8", "path": "C:/Program Files/Java/jre1.8.0_261/bin/java.exe"},{"version": "11", "path": "C:/Program Files/Java/jdk-11.0.13.8-hotspot/bin/java.exe"},{"version": "17", "path": "C:/Program Files/Java/jdk-17.0.1.12-hotspot/bin/java.exe"}]
下面是Python中,读取JSON文档所需的代码。
import json # Python中处理JSON文档所用的库,为内置库,不需另外安装。def java_versions_list():"""此函数将从本地缓存的目录中取出已保存的Java版本。:return: 返回缓存中的Java版本列表,请注意:列表中的版本以字典形式存储。"""with open(file=config.game_versions_json_path, encoding="utf-8") as game_local_dict:java_versions_list: list = json.load(game_local_dict)["java_list"]for i in java_versions_list:j: str = i["path"]n: list = j.split("/")m: str = "\\"l: str = m.join(n)i["path"] = lreturn java_versions_list# config.game_versions_json_path是该配置文件的路径。# 在JSON中,路径里的斜杠为/,下方将其替换成了\\。使用\\而不是\是为了防止Python将其转义。
您可以在此时测试此代码:
java_version_list = java_versions_list()for i in java_version_list:print(i)# 不要用一样的名字嗷
{"version": "8", "path": "C:/Program Files/Java/jre1.8.0_261/bin/java.exe"}{"version": "11", "path": "C:/Program Files/Java/jdk-11.0.13.8-hotspot/bin/java.exe"}{"version": "17", "path": "C:/Program Files/Java/jdk-17.0.1.12-hotspot/bin/java.exe"}
然后在需要时,读取此列表,遍历其中每一个字典的“version”键,就可以获得Java的版本列表;在选择一个版本之后,再从中找到对应的字典,读取“path”键的值,就是路径了。
当然还有其他写法,记得读取方式要与写法相对应。至于如何向JSON存入数据,我们将在以后说明。您可以暂时手动输入一些信息来应应急(?)
JVM参数
JVM参数,先上模板。
-Dminecraft.client.jar=D:\FCL\.minecraft\versions\1.8.9\1.8.9.jar -Xmn128m -Xmx5858m -Djava.library.path=D:\FCL\.minecraft\versions\1.8.9\natives-windows-x86_64
| -Dminecraft.client.jar= | 指定版本的client.jar所在目录。 |
|---|---|
| -Djava.library.path= | 指定版本的natives库解压到的目录(后续介绍)。 |
| -Xmn -Xmx | 允许Minecraft运行的最小和最大内存。 |
指定版本的client.jar所在目录,就是该版本jar文件的绝对目录。版本jar文件一般位于.minecraft\versions\中。
natives库将在之后进行介绍。
Xmn是最小内存,Xmx是最大内存。
将这些参数依次拼接,就是JVM参数。在前文HMCL生成的启动脚本中还有更多的参数,那些我们暂不做深入研究。
现在,在Python中,您可以使用以下方案来获得上面的这些参数。我们假设您已经拥有一个完整的Minecraft 1.8.9的游戏(包括assets文件夹中、libraries文件夹中、versions文件夹中的所有文件全部完整,并且已经由HMCL、PCL等启动器启动过至少一次),那么您可以将您的Python工程源码与.minecraft文件夹按如下目录存放:
- .minecraft[游戏根目录]
- assets(子目录不再展开)
- libraries(子目录不再展开)
- versions
- 1.8.9
- 1.8.9.jar
- 1.8.9.json
- 1.8.9
- (其他目录不再展示)
- FCL[启动器附加文件目录](方便扔一些奇怪的东西进去给启动器当外部资源调用)
- 《您的启动器源码》
在这里面找找,有没有哪个文件夹的名字里包含“natives”,这个文件夹大概率就是“-Djava.library.path=”需要的参数路径,把文件夹的路径填进去吧。
下面的Python代码可以让您获取您的项目源码绝对路径。在打包成exe文件之后,该代码可以得出此exe文件的绝对路径。然后您可以用其来拼接成.minecraft的路径,这也是启动器在同目录下管理.minecraft文件夹的方式。
import osself_path = os.getcwd()print(self_path)
-cp库路径
这可不是你们爱磕的cp,这里是很多很多很多的jar文件,就是跟client.jar一个格式的文件。在启动参数中需要拼接很多个指向这些jar文件的绝对路径,包括client.jar也不例外地要再来一遍。
-cp D:\FCL\.minecraft\libraries\com\mojang\netty\1.8.8\netty-1.8.8.jar;D:\FCL\.minecraft\libraries\oshi-project\oshi-core\1.1\oshi-core-1.1.jar;D:\FCL\.minecraft\libraries\net\java\dev\jna\jna\3.4.0\jna-3.4.0.jar;D:\FCL\.minecraft\libraries\net\java\dev\jna\platform\3.4.0\platform-3.4.0.jar;D:\FCL\.minecraft\libraries\com\ibm\icu\icu4j-core-mojang\51.2\icu4j-core-mojang-51.2.jar;D:\FCL\.minecraft\libraries\net\sf\jopt-simple\jopt-simple\4.6\jopt-simple-4.6.jar;D:\FCL\.minecraft\libraries\com\paulscode\codecjorbis\20101023\codecjorbis-20101023.jar;D:\FCL\.minecraft\libraries\com\paulscode\codecwav\20101023\codecwav-20101023.jar;D:\FCL\.minecraft\libraries\com\paulscode\libraryjavasound\20101123\libraryjavasound-20101123.jar;D:\FCL\.minecraft\libraries\com\paulscode\librarylwjglopenal\20100824\librarylwjglopenal-20100824.jar;D:\FCL\.minecraft\libraries\com\paulscode\soundsystem\20120107\soundsystem-20120107.jar;D:\FCL\.minecraft\libraries\io\netty\netty-all\4.0.23.Final\netty-all-4.0.23.Final.jar;D:\FCL\.minecraft\libraries\com\google\guava\guava\17.0\guava-17.0.jar;D:\FCL\.minecraft\libraries\org\apache\commons\commons-lang3\3.3.2\commons-lang3-3.3.2.jar;D:\FCL\.minecraft\libraries\commons-io\commons-io\2.4\commons-io-2.4.jar;D:\FCL\.minecraft\libraries\commons-codec\commons-codec\1.9\commons-codec-1.9.jar;D:\FCL\.minecraft\libraries\net\java\jinput\jinput\2.0.5\jinput-2.0.5.jar;D:\FCL\.minecraft\libraries\net\java\jutils\jutils\1.0.0\jutils-1.0.0.jar;D:\FCL\.minecraft\libraries\com\google\code\gson\gson\2.2.4\gson-2.2.4.jar;D:\FCL\.minecraft\libraries\com\mojang\authlib\1.5.21\authlib-1.5.21.jar;D:\FCL\.minecraft\libraries\com\mojang\realms\1.7.59\realms-1.7.59.jar;D:\FCL\.minecraft\libraries\org\apache\commons\commons-compress\1.8.1\commons-compress-1.8.1.jar;D:\FCL\.minecraft\libraries\org\apache\httpcomponents\httpclient\4.3.3\httpclient-4.3.3.jar;D:\FCL\.minecraft\libraries\commons-logging\commons-logging\1.1.3\commons-logging-1.1.3.jar;D:\FCL\.minecraft\libraries\org\apache\httpcomponents\httpcore\4.3.2\httpcore-4.3.2.jar;D:\FCL\.minecraft\libraries\org\apache\logging\log4j\log4j-api\2.0-beta9\log4j-api-2.0-beta9.jar;D:\FCL\.minecraft\libraries\org\apache\logging\log4j\log4j-core\2.0-beta9\log4j-core-2.0-beta9.jar;D:\FCL\.minecraft\libraries\org\lwjgl\lwjgl\lwjgl\2.9.4-nightly-20150209\lwjgl-2.9.4-nightly-20150209.jar;D:\FCL\.minecraft\libraries\org\lwjgl\lwjgl\lwjgl_util\2.9.4-nightly-20150209\lwjgl_util-2.9.4-nightly-20150209.jar;D:\FCL\.minecraft\libraries\tv\twitch\twitch\6.5\twitch-6.5.jar;D:\FCL\.minecraft\versions\1.8.9\1.8.9.jar
这么多东西是怎么来的呢?
是在该版本的JSON文档内。
一个完整的1.8.9JSON文档包含的内容应当如下:
{"assetIndex": {"id": "1.8","sha1": "f6ad102bcaa53b1a58358f16e376d548d44933ec","size": 78494,"totalSize": 114885064,"url": "https://launchermeta.mojang.com/v1/packages/f6ad102bcaa53b1a58358f16e376d548d44933ec/1.8.json"},"assets": "1.8","complianceLevel": 0,"downloads": {"client": {"sha1": "3870888a6c3d349d3771a3e9d16c9bf5e076b908","size": 8461484,"url": "https://launcher.mojang.com/v1/objects/3870888a6c3d349d3771a3e9d16c9bf5e076b908/client.jar"},"server": {"sha1": "b58b2ceb36e01bcd8dbf49c8fb66c55a9f0676cd","size": 8320755,"url": "https://launcher.mojang.com/v1/objects/b58b2ceb36e01bcd8dbf49c8fb66c55a9f0676cd/server.jar"},"windows_server": {"sha1": "5143618265b8a2d1d28bcadf206b7327738c2670","size": 8714995,"url": "https://launcher.mojang.com/v1/objects/5143618265b8a2d1d28bcadf206b7327738c2670/windows_server.exe"}},"id": "原版1.8.9","javaVersion": {"component": "jre-legacy","majorVersion": 8},"libraries": [{"downloads": {"artifact": {"path": "com/mojang/netty/1.8.8/netty-1.8.8.jar","sha1": "0a796914d1c8a55b4da9f4a8856dd9623375d8bb","size": 15966,"url": "https://libraries.minecraft.net/com/mojang/netty/1.8.8/netty-1.8.8.jar"}},"name": "com.mojang:netty:1.8.8"},{"downloads": {"artifact": {"path": "oshi-project/oshi-core/1.1/oshi-core-1.1.jar","sha1": "9ddf7b048a8d701be231c0f4f95fd986198fd2d8","size": 30973,"url": "https://libraries.minecraft.net/oshi-project/oshi-core/1.1/oshi-core-1.1.jar"}},"name": "oshi-project:oshi-core:1.1"},{"downloads": {"artifact": {"path": "net/java/dev/jna/jna/3.4.0/jna-3.4.0.jar","sha1": "803ff252fedbd395baffd43b37341dc4a150a554","size": 1008730,"url": "https://libraries.minecraft.net/net/java/dev/jna/jna/3.4.0/jna-3.4.0.jar"}},"name": "net.java.dev.jna:jna:3.4.0"},{"downloads": {"artifact": {"path": "net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar","sha1": "e3f70017be8100d3d6923f50b3d2ee17714e9c13","size": 913436,"url": "https://libraries.minecraft.net/net/java/dev/jna/platform/3.4.0/platform-3.4.0.jar"}},"name": "net.java.dev.jna:platform:3.4.0"},{"downloads": {"artifact": {"path": "com/ibm/icu/icu4j-core-mojang/51.2/icu4j-core-mojang-51.2.jar","sha1": "63d216a9311cca6be337c1e458e587f99d382b84","size": 1634692,"url": "https://libraries.minecraft.net/com/ibm/icu/icu4j-core-mojang/51.2/icu4j-core-mojang-51.2.jar"}},"name": "com.ibm.icu:icu4j-core-mojang:51.2"},{"downloads": {"artifact": {"path": "net/sf/jopt-simple/jopt-simple/4.6/jopt-simple-4.6.jar","sha1": "306816fb57cf94f108a43c95731b08934dcae15c","size": 62477,"url": "https://libraries.minecraft.net/net/sf/jopt-simple/jopt-simple/4.6/jopt-simple-4.6.jar"}},"name": "net.sf.jopt-simple:jopt-simple:4.6"},{"downloads": {"artifact": {"path": "com/paulscode/codecjorbis/20101023/codecjorbis-20101023.jar","sha1": "c73b5636faf089d9f00e8732a829577de25237ee","size": 103871,"url": "https://libraries.minecraft.net/com/paulscode/codecjorbis/20101023/codecjorbis-20101023.jar"}},"name": "com.paulscode:codecjorbis:20101023"},{"downloads": {"artifact": {"path": "com/paulscode/codecwav/20101023/codecwav-20101023.jar","sha1": "12f031cfe88fef5c1dd36c563c0a3a69bd7261da","size": 5618,"url": "https://libraries.minecraft.net/com/paulscode/codecwav/20101023/codecwav-20101023.jar"}},"name": "com.paulscode:codecwav:20101023"},{"downloads": {"artifact": {"path": "com/paulscode/libraryjavasound/20101123/libraryjavasound-20101123.jar","sha1": "5c5e304366f75f9eaa2e8cca546a1fb6109348b3","size": 21679,"url": "https://libraries.minecraft.net/com/paulscode/libraryjavasound/20101123/libraryjavasound-20101123.jar"}},"name": "com.paulscode:libraryjavasound:20101123"},{"downloads": {"artifact": {"path": "com/paulscode/librarylwjglopenal/20100824/librarylwjglopenal-20100824.jar","sha1": "73e80d0794c39665aec3f62eee88ca91676674ef","size": 18981,"url": "https://libraries.minecraft.net/com/paulscode/librarylwjglopenal/20100824/librarylwjglopenal-20100824.jar"}},"name": "com.paulscode:librarylwjglopenal:20100824"},{"downloads": {"artifact": {"path": "com/paulscode/soundsystem/20120107/soundsystem-20120107.jar","sha1": "419c05fe9be71f792b2d76cfc9b67f1ed0fec7f6","size": 65020,"url": "https://libraries.minecraft.net/com/paulscode/soundsystem/20120107/soundsystem-20120107.jar"}},"name": "com.paulscode:soundsystem:20120107"},{"downloads": {"artifact": {"path": "io/netty/netty-all/4.0.23.Final/netty-all-4.0.23.Final.jar","sha1": "0294104aaf1781d6a56a07d561e792c5d0c95f45","size": 1779991,"url": "https://libraries.minecraft.net/io/netty/netty-all/4.0.23.Final/netty-all-4.0.23.Final.jar"}},"name": "io.netty:netty-all:4.0.23.Final"},{"downloads": {"artifact": {"path": "com/google/guava/guava/17.0/guava-17.0.jar","sha1": "9c6ef172e8de35fd8d4d8783e4821e57cdef7445","size": 2243036,"url": "https://libraries.minecraft.net/com/google/guava/guava/17.0/guava-17.0.jar"}},"name": "com.google.guava:guava:17.0"},{"downloads": {"artifact": {"path": "org/apache/commons/commons-lang3/3.3.2/commons-lang3-3.3.2.jar","sha1": "90a3822c38ec8c996e84c16a3477ef632cbc87a3","size": 412739,"url": "https://libraries.minecraft.net/org/apache/commons/commons-lang3/3.3.2/commons-lang3-3.3.2.jar"}},"name": "org.apache.commons:commons-lang3:3.3.2"},{"downloads": {"artifact": {"path": "commons-io/commons-io/2.4/commons-io-2.4.jar","sha1": "b1b6ea3b7e4aa4f492509a4952029cd8e48019ad","size": 185140,"url": "https://libraries.minecraft.net/commons-io/commons-io/2.4/commons-io-2.4.jar"}},"name": "commons-io:commons-io:2.4"},{"downloads": {"artifact": {"path": "commons-codec/commons-codec/1.9/commons-codec-1.9.jar","sha1": "9ce04e34240f674bc72680f8b843b1457383161a","size": 263965,"url": "https://libraries.minecraft.net/commons-codec/commons-codec/1.9/commons-codec-1.9.jar"}},"name": "commons-codec:commons-codec:1.9"},{"downloads": {"artifact": {"path": "net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar","sha1": "39c7796b469a600f72380316f6b1f11db6c2c7c4","size": 208338,"url": "https://libraries.minecraft.net/net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar"}},"name": "net.java.jinput:jinput:2.0.5"},{"downloads": {"artifact": {"path": "net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar","sha1": "e12fe1fda814bd348c1579329c86943d2cd3c6a6","size": 7508,"url": "https://libraries.minecraft.net/net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar"}},"name": "net.java.jutils:jutils:1.0.0"},{"downloads": {"artifact": {"path": "com/google/code/gson/gson/2.2.4/gson-2.2.4.jar","sha1": "a60a5e993c98c864010053cb901b7eab25306568","size": 190432,"url": "https://libraries.minecraft.net/com/google/code/gson/gson/2.2.4/gson-2.2.4.jar"}},"name": "com.google.code.gson:gson:2.2.4"},{"downloads": {"artifact": {"path": "com/mojang/authlib/1.5.21/authlib-1.5.21.jar","sha1": "aefba0d5b53fbcb70860bc8046ab95d5854c07a5","size": 64412,"url": "https://libraries.minecraft.net/com/mojang/authlib/1.5.21/authlib-1.5.21.jar"}},"name": "com.mojang:authlib:1.5.21"},{"downloads": {"artifact": {"path": "com/mojang/realms/1.7.59/realms-1.7.59.jar","sha1": "9c6c59b742d8e038a15f64c1aa273a893a658424","size": 1198123,"url": "https://libraries.minecraft.net/com/mojang/realms/1.7.59/realms-1.7.59.jar"}},"name": "com.mojang:realms:1.7.59"},{"downloads": {"artifact": {"path": "org/apache/commons/commons-compress/1.8.1/commons-compress-1.8.1.jar","sha1": "a698750c16740fd5b3871425f4cb3bbaa87f529d","size": 365552,"url": "https://libraries.minecraft.net/org/apache/commons/commons-compress/1.8.1/commons-compress-1.8.1.jar"}},"name": "org.apache.commons:commons-compress:1.8.1"},{"downloads": {"artifact": {"path": "org/apache/httpcomponents/httpclient/4.3.3/httpclient-4.3.3.jar","sha1": "18f4247ff4572a074444572cee34647c43e7c9c7","size": 589512,"url": "https://libraries.minecraft.net/org/apache/httpcomponents/httpclient/4.3.3/httpclient-4.3.3.jar"}},"name": "org.apache.httpcomponents:httpclient:4.3.3"},{"downloads": {"artifact": {"path": "commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar","sha1": "f6f66e966c70a83ffbdb6f17a0919eaf7c8aca7f","size": 62050,"url": "https://libraries.minecraft.net/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar"}},"name": "commons-logging:commons-logging:1.1.3"},{"downloads": {"artifact": {"path": "org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jar","sha1": "31fbbff1ddbf98f3aa7377c94d33b0447c646b6e","size": 282269,"url": "https://libraries.minecraft.net/org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jar"}},"name": "org.apache.httpcomponents:httpcore:4.3.2"},{"downloads": {"artifact": {"path": "org/apache/logging/log4j/log4j-api/2.0-beta9/log4j-api-2.0-beta9.jar","sha1": "1dd66e68cccd907880229f9e2de1314bd13ff785","size": 108161,"url": "https://libraries.minecraft.net/org/apache/logging/log4j/log4j-api/2.0-beta9/log4j-api-2.0-beta9.jar"}},"name": "org.apache.logging.log4j:log4j-api:2.0-beta9"},{"downloads": {"artifact": {"path": "org/apache/logging/log4j/log4j-core/2.0-beta9/log4j-core-2.0-beta9.jar","sha1": "678861ba1b2e1fccb594bb0ca03114bb05da9695","size": 681134,"url": "https://libraries.minecraft.net/org/apache/logging/log4j/log4j-core/2.0-beta9/log4j-core-2.0-beta9.jar"}},"name": "org.apache.logging.log4j:log4j-core:2.0-beta9"},{"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar","sha1": "697517568c68e78ae0b4544145af031c81082dfe","size": 1047168,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar"}},"name": "org.lwjgl.lwjgl:lwjgl:2.9.4-nightly-20150209","rules": [{"action": "allow"},{"action": "disallow","os": {"name": "osx"}}]},{"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl_util/2.9.4-nightly-20150209/lwjgl_util-2.9.4-nightly-20150209.jar","sha1": "d51a7c040a721d13efdfbd34f8b257b2df882ad0","size": 173887,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl_util/2.9.4-nightly-20150209/lwjgl_util-2.9.4-nightly-20150209.jar"}},"name": "org.lwjgl.lwjgl:lwjgl_util:2.9.4-nightly-20150209","rules": [{"action": "allow"},{"action": "disallow","os": {"name": "osx"}}]},{"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar","sha1": "b04f3ee8f5e43fa3b162981b50bb72fe1acabb33","size": 22,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar"},"classifiers": {"natives-linux": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar","sha1": "931074f46c795d2f7b30ed6395df5715cfd7675b","size": 578680,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar"},"natives-osx": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar","sha1": "bcab850f8f487c3f4c4dbabde778bb82bd1a40ed","size": 426822,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar"},"natives-windows": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-windows.jar","sha1": "b84d5102b9dbfabfeb5e43c7e2828d98a7fc80e0","size": 613748,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-windows.jar"}}},"extract": {"exclude": ["META-INF/"]},"name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.4-nightly-20150209","natives": {"linux": "natives-linux","osx": "natives-osx","windows": "natives-windows"},"rules": [{"action": "allow"},{"action": "disallow","os": {"name": "osx"}}]},{"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl/2.9.2-nightly-20140822/lwjgl-2.9.2-nightly-20140822.jar","sha1": "7707204c9ffa5d91662de95f0a224e2f721b22af","size": 1045632,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl/2.9.2-nightly-20140822/lwjgl-2.9.2-nightly-20140822.jar"}},"name": "org.lwjgl.lwjgl:lwjgl:2.9.2-nightly-20140822","rules": [{"action": "allow","os": {"name": "osx"}}]},{"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl_util/2.9.2-nightly-20140822/lwjgl_util-2.9.2-nightly-20140822.jar","sha1": "f0e612c840a7639c1f77f68d72a28dae2f0c8490","size": 173887,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl_util/2.9.2-nightly-20140822/lwjgl_util-2.9.2-nightly-20140822.jar"}},"name": "org.lwjgl.lwjgl:lwjgl_util:2.9.2-nightly-20140822","rules": [{"action": "allow","os": {"name": "osx"}}]},{"downloads": {"classifiers": {"natives-linux": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-linux.jar","sha1": "d898a33b5d0a6ef3fed3a4ead506566dce6720a5","size": 578539,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-linux.jar"},"natives-osx": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar","sha1": "79f5ce2fea02e77fe47a3c745219167a542121d7","size": 468116,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar"},"natives-windows": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-windows.jar","sha1": "78b2a55ce4dc29c6b3ec4df8ca165eba05f9b341","size": 613680,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-windows.jar"}}},"extract": {"exclude": ["META-INF/"]},"name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.2-nightly-20140822","natives": {"linux": "natives-linux","osx": "natives-osx","windows": "natives-windows"},"rules": [{"action": "allow","os": {"name": "osx"}}]},{"downloads": {"classifiers": {"natives-linux": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar","sha1": "7ff832a6eb9ab6a767f1ade2b548092d0fa64795","size": 10362,"url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar"},"natives-osx": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-osx.jar","sha1": "53f9c919f34d2ca9de8c51fc4e1e8282029a9232","size": 12186,"url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-osx.jar"},"natives-windows": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-windows.jar","sha1": "385ee093e01f587f30ee1c8a2ee7d408fd732e16","size": 155179,"url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-windows.jar"}}},"extract": {"exclude": ["META-INF/"]},"name": "net.java.jinput:jinput-platform:2.0.5","natives": {"linux": "natives-linux","osx": "natives-osx","windows": "natives-windows"}},{"downloads": {"artifact": {"path": "tv/twitch/twitch/6.5/twitch-6.5.jar","sha1": "320a2dfd18513a5f41b4e75729df684488cbd925","size": 55977,"url": "https://libraries.minecraft.net/tv/twitch/twitch/6.5/twitch-6.5.jar"}},"name": "tv.twitch:twitch:6.5"},{"downloads": {"classifiers": {"natives-osx": {"path": "tv/twitch/twitch-platform/6.5/twitch-platform-6.5-natives-osx.jar","sha1": "5f9d1ee26257b3a33f0ca06fed335ef462af659f","size": 455359,"url": "https://libraries.minecraft.net/tv/twitch/twitch-platform/6.5/twitch-platform-6.5-natives-osx.jar"},"natives-windows-32": {"path": "tv/twitch/twitch-platform/6.5/twitch-platform-6.5-natives-windows-32.jar","sha1": "206c4ccaecdbcfd2a1631150c69a97bbc9c20c11","size": 474225,"url": "https://libraries.minecraft.net/tv/twitch/twitch-platform/6.5/twitch-platform-6.5-natives-windows-32.jar"},"natives-windows-64": {"path": "tv/twitch/twitch-platform/6.5/twitch-platform-6.5-natives-windows-64.jar","sha1": "9fdd0fd5aed0817063dcf95b69349a171f447ebd","size": 580098,"url": "https://libraries.minecraft.net/tv/twitch/twitch-platform/6.5/twitch-platform-6.5-natives-windows-64.jar"}}},"extract": {"exclude": ["META-INF/"]},"name": "tv.twitch:twitch-platform:6.5","natives": {"linux": "natives-linux","osx": "natives-osx","windows": "natives-windows-${arch}"},"rules": [{"action": "allow"},{"action": "disallow","os": {"name": "linux"}}]},{"downloads": {"classifiers": {"natives-windows-32": {"path": "tv/twitch/twitch-external-platform/4.5/twitch-external-platform-4.5-natives-windows-32.jar","sha1": "18215140f010c05b9f86ef6f0f8871954d2ccebf","size": 5654047,"url": "https://libraries.minecraft.net/tv/twitch/twitch-external-platform/4.5/twitch-external-platform-4.5-natives-windows-32.jar"},"natives-windows-64": {"path": "tv/twitch/twitch-external-platform/4.5/twitch-external-platform-4.5-natives-windows-64.jar","sha1": "c3cde57891b935d41b6680a9c5e1502eeab76d86","size": 7457619,"url": "https://libraries.minecraft.net/tv/twitch/twitch-external-platform/4.5/twitch-external-platform-4.5-natives-windows-64.jar"}}},"extract": {"exclude": ["META-INF/"]},"name": "tv.twitch:twitch-external-platform:4.5","natives": {"windows": "natives-windows-${arch}"},"rules": [{"action": "allow","os": {"name": "windows"}}]}],"logging": {"client": {"argument": "-Dlog4j.configurationFile=${path}","file": {"id": "client-1.7.xml","sha1": "50c9cc4af6d853d9fc137c84bcd153e2bd3a9a82","size": 966,"url": "https://launcher.mojang.com/v1/objects/50c9cc4af6d853d9fc137c84bcd153e2bd3a9a82/client-1.7.xml"},"type": "log4j2-xml"}},"mainClass": "net.minecraft.client.main.Main","minecraftArguments": "--username ${auth_player_name} --version ${version_name} --gameDir ${game_directory} --assetsDir ${assets_root} --assetIndex ${assets_index_name} --uuid ${auth_uuid} --accessToken ${auth_access_token} --userProperties ${user_properties} --userType ${user_type}","minimumLauncherVersion": 14,"releaseTime": "2015-12-03T17:24:39+08:00","time": "2015-12-03T17:24:39+08:00","type": "release","clientVersion": "1.8.9"}
不要慌,真的只是看起来这么多而已。
我们要的是里面的“libraries”键对应的内容,但是这里面存放着两种不同类型的东西,统称为Minecraft运行所需的“库文件”。
下面是其中一种键的格式:
{"downloads": {"artifact": {"path": "tv/twitch/twitch/6.5/twitch-6.5.jar","sha1": "320a2dfd18513a5f41b4e75729df684488cbd925","size": 55977,"url": "https://libraries.minecraft.net/tv/twitch/twitch/6.5/twitch-6.5.jar"}},"name": "tv.twitch:twitch:6.5"}
上面的这种格式中,我们可以只看“downloads”键,其对应了一个“artifact”键,然后就包括了四个键,分别是“path”:该库文件相对libraries文件夹的正确存放路径、“sha1”:该库文件的sha1校验码、“size”该库文件的大小、“url”:该库文件的下载地址。
从“artifact”中提取“url”,即可下载该库文件,然后记得将“libraries”文件夹的绝对路径拼接上“path”键对应的路径,作为该库文件的存放位置。
但是有的时候,您还会看到下面这样的情况,属于这种格式的变种:
{"downloads": {"artifact": {"path": "org/lwjgl/lwjgl/lwjgl_util/2.9.2-nightly-20140822/lwjgl_util-2.9.2-nightly-20140822.jar","sha1": "f0e612c840a7639c1f77f68d72a28dae2f0c8490","size": 173887,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl_util/2.9.2-nightly-20140822/lwjgl_util-2.9.2-nightly-20140822.jar"}},"name": "org.lwjgl.lwjgl:lwjgl_util:2.9.2-nightly-20140822","rules": [{"action": "allow","os": {"name": "osx"}}]},
多了一个“rules”键,然后是“action”键和另一个“os”键;“action”的值是“allow”,而“os”则指定了一个操作系统“osx”,即macOS。
翻译成人话就是,这个库,仅macOS系统上运行的Minecraft需要,其他平台并不需要。
注意,有时这个“action”后面跟的值是“disallow”,记得在您的代码中写好处理此的部分。
再往下则是其中另一种键的格式。
{"downloads": {"classifiers": {"natives-linux": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-linux.jar","sha1": "d898a33b5d0a6ef3fed3a4ead506566dce6720a5","size": 578539,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-linux.jar"},"natives-osx": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar","sha1": "79f5ce2fea02e77fe47a3c745219167a542121d7","size": 468116,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar"},"natives-windows": {"path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-windows.jar","sha1": "78b2a55ce4dc29c6b3ec4df8ca165eba05f9b341","size": 613680,"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.2-nightly-20140822/lwjgl-platform-2.9.2-nightly-20140822-natives-windows.jar"}}},"extract": {"exclude": ["META-INF/"]},"name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.2-nightly-20140822","natives": {"linux": "natives-linux","osx": "natives-osx","windows": "natives-windows"},"rules": [{"action": "allow","os": {"name": "osx"}}]}
对于这种,“downloads”键下有一个“classifiers”键,此库文件被称作natives库文件,其他的库文件则是普通库文件。
首先,既然这个“downloads”下面有一个“rules”键,那我们就应该先读取“rules”,用之前的办法判断该库是否需要下载,比如对我(Windows)来说这就是一个可以pass掉的natives库。
{"downloads": {"classifiers": {"natives-linux": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar","sha1": "7ff832a6eb9ab6a767f1ade2b548092d0fa64795","size": 10362,"url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar"},"natives-osx": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-osx.jar","sha1": "53f9c919f34d2ca9de8c51fc4e1e8282029a9232","size": 12186,"url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-osx.jar"},"natives-windows": {"path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-windows.jar","sha1": "385ee093e01f587f30ee1c8a2ee7d408fd732e16","size": 155179,"url": "https://libraries.minecraft.net/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-windows.jar"}}},"extract": {"exclude": ["META-INF/"]},"name": "net.java.jinput:jinput-platform:2.0.5","natives": {"linux": "natives-linux","osx": "natives-osx","windows": "natives-windows"}},
比如这里是一个我需要下载的natives库文件,我就需要读“classifiers”键,然后往下读“natives-windows”键,再读里面的“url”键来获取下载地址、“path”键来获取存放相对路径。
注意:包括普通库文件和natives库文件在内,有的库文件还区分“natives-windows-64”,这部分可以在代码中使用if嵌套解决。
natives库文件不需要在生成启动脚本时把路径加入到“-cp”后面,它们用不在此。您需要做的,是把natives库文件解压到一个指定目录,然后把这个指定目录填到前面JVM参数里的“-Djava.library.path”里面。这就是JVM里那个奇怪的natives库参数的处理办法。
众所周知,jar文件的本质就是zip文件,解压到一个指定目录是完全没有问题的。至于这个目录到底应该在哪,Mojang并没有规定,您可以参考以下两种做法:
- Minecraft官方启动器:将natives库文件全部解压到一个临时目录,每次启动都重新解压。
- 大部分第三方启动器:将其解压到位于游戏目录中的一个永久目录,只要玩家不手动删,不会重新解压。
记得在将启动脚本送到cmd里面之前先解压哦,不然Minecraft是无法启动的。您可以在读取JSON时用if语句完成这一点:如果有“classifiers”键,就当做natives库文件处理;否则当做普通库文件处理。
参考一下我使用Python完成这一步骤的代码:
import threading, func # func为一在其他地方定义的类def download_libraries(version_json_path: str, libraries_path: str):"""读取版本JSON文件,并依据其中的内容下载补全libraries文件。下载操作由另一函数执行。:param libraries_path: 需要为libraries文件夹路径:param version_json_path: 需要为该版本的JSON路径。:return: 此函数无论是否顺利执行都不返回值。"""dividing_str = "\\"with open(file=version_json_path, encoding="utf-8") as json_file:json_data = json.load(json_file)libraries_list = json_data['libraries']for i in libraries_list:file_temp_1 = i['downloads']if "classifiers" in file_temp_1:file_temp_1_ = file_temp_1['classifiers']if "natives-windows-64" in file_temp_1_:file_temp_2 = file_temp_1_['natives-windows-64']elif "natives-windows" in file_temp_1_:file_temp_2 = file_temp_1_['natives-windows']else:return Noneelif "artifact" in file_temp_1:file_temp_2 = file_temp_1['artifact']else:return Nonefile_url = str(file_temp_2['url'])file_name_ = str(file_temp_2['path']).split("/")file_name = libraries_path + dividing_str.join(file_name_)file_sha1 = str(file_temp_2['sha1'])download_package = (file_url, file_name, file_sha1)print(download_package)func.threading_manager.acquire()threading.Thread(target=func.download_something, args=(0, download_package)).start()func.threading_manager.release()return None# threading模块用来创建子线程以下载,主线程能够继续循环下一项,可节省时间。# acquire和release用法均源自threading模块,您可以单独寻找该模块的教程以学习。
import config # 一个写在其他地方的用来放语言文本的类def get_libraries_json(self: int, game_version_info: list):"""返回拼接成的“-cp”+普通库1+普通库2+……:param game_version_info: 该版本的相关信息组成的列表,需要:[0]版本名称,[1]版本JSON路径,[2]版本libraries路径,[3]版本游戏本体路径,[4]版本natives文件路径:return 从该JSON文件中提取出的,可直接拼接成脚本使用的代码片段"""output_path = []game_version_name = game_version_info[0]game_version_json_path = game_version_info[1]libraries_path = game_version_info[2]minecraft_jar_path = game_version_info[3]natives_path = game_version_info[4]with open(file=game_version_json_path) as json_file:json_data = json.load(json_file)info_back_type_list = json_data['libraries']for i in info_back_type_list:if "rules" in i:data_temp_1 = list(i['rules'])if len(data_temp_1) == 1: # 如果“rules”键对应的列表长度为1,则该列表为允许allowing_list = list(dict(dict(data_temp_1[0])["os"])['name'])if not "windows" in allowing_list:continueif len(data_temp_1) == 2: # 如果对应的列表长度为2, 则列表第二项为禁止disallowing_list = list(dict(dict(data_temp_1[1])['os'])['name'])if "windows" in disallowing_list:continue# ↑那些规则是我自己推断出来的,不一定对每隔版本都适用data_temp_2 = dict(i['downloads'])if "classifiers" in data_temp_2:print("调试:0")func.zip_natives(0, data_temp_2, libraries_path, natives_path)continueelif not 'artifact' in data_temp_2:continueelse:data_temp_2_ = dict(data_temp_2['artifact'])data_temp_3 = str(data_temp_2_['path'])data_temp_4 = list(data_temp_3.split("/"))dividing_str_1 = "\\"data_temp_5 = dividing_str_1.join(data_temp_4)real_path = libraries_path + data_temp_5if not real_path in output_path:output_path.append(real_path)output_path.append(minecraft_jar_path)dividing_str_2 = ";"output_path_str = dividing_str_2.join(output_path)print(config.lang_Functions_successfully_split_cp_path + game_version_name)print(output_path_str)return output_path_str
那,这边一部分也就搞定了,顺便解决了natives文件夹的问题。
在这里面找找,有没有哪个文件夹的名字里包含“natives”,这个文件夹大概率就是“-Djava.library.path=”需要的参数路径,把文件夹的路径填进去吧。
现在您知道为什么可以这么办了嘛?因为第三方启动器的创作者也跟我们的思路一样!如果你找到了这样一个包括“natives”字样的文件夹,说明该启动器的作者也是把natives库文件解压到了这样一个永久目录!
哦对了,记得在-cp部分,每两个绝对路径中间是用英文“;”隔开的,并且在最后要加上该版本client.jar的路径,否则JVM会报错“找不到主类”。
主类就是下面那个东西……
主类
主类是最简单的部分了。我们再次拿出这张图:
看到上面那个“mainClass”了嘛?
那个对应的“net.minecraft.client.main.Main”就是主类,接在-cp部分的后面就行,主类搞定。
Minecraft参数
还是上面那张图,先别往下滑!
“minecraftArguments”键,后面跟着的,就是Minecraft参数的模板。我们需要在这个模板上替换掉一些东西,下面是Minecraft 1.8.9的模板。
--username ${auth_player_name} --version ${version_name} --gameDir ${game_directory} --assetsDir ${assets_root} --assetIndex ${assets_index_name} --uuid ${auth_uuid} --accessToken ${auth_access_token} --userProperties ${user_properties} --userType ${user_type}
(新版本的)参数通常有:
- —username 后接用户名。
- —version 后接游戏版本。
- —gameDir 后接游戏路径。
- —assetsDir 后接资源文件路径。
- —assetIndex 后接资源索引版本。
- —uuid 后接用户UUID。
- —accessToken 后接登录令牌。
- —userType 后接用户类型。
- —versionType 后接版本类型,会显示在游戏主界面右下角。
- —width 后接窗口宽度。
- —height 后接窗口高度。
- —server 后接服务器地址,游戏进入时将直接连入服务器
- —port 后接服务器的端口号
- 等等,可能因版本而异,具体应参考当前版本json文件内提供的信息。
连带着${abaabaabaaba}这个整体,一起替换成其他东西即可。并不是所有的参数都必须提供,比如你可以不写—width和—height,游戏还是能启动的。
啊对了,有的参数可以直接从版本JSON中顺便读取,比如—assetIndex后面就跟“assets”键对的“1.8”就行,而—versionType可以跟“type”键的值“release”;另外有的参数我们目前提供不了的,比如—uuid,可以去找一个UUID生成网站暂时随意填一个,—accessToken可以先{}这样空着,而—userType可以填legacy,就是离线模式了。
(其实—accessToken是令牌,我们现在获取不到令牌,所以就算—userType填了mojang——验证不了身份照样进离线模式,懒得话一律写mojang就行了)
Python中替换长字符串中的短字符串可以使用replace语句。由于不同版本的上面参数有差异,我就不放出来了,这一步毕竟也不是很难(?真的
拼接
上面五个,拼起来,然后print出来,复制一下敲到cmd里试试叭!
