如果有意向,可以编辑贡献完善本教程。
本教程部分内容参考了wiki.vg。
本教程介绍如何制作Minecraft启动器,并假定你已掌握任何一门编程语言。
基本原理
因为Minecraft制作时采用了“启动器+游戏文件”的模式:
- 将游戏文件单独存储,而通过启动器调用JVM执行游戏主文件并传入一些游戏参数来启动Minecraft。
- 游戏依赖库文件以及游戏资源文件由启动器补全。
- 玩家登录认证由启动器完成。
这使得我们能通过编写第三方启动器来接管游戏文件管理和登录认证。
准备
要编写一个启动器,你需要:
- 一门编程语言其开发环境
- 脑子和手
启动参数
启动参数将传入java.exe或javaw.exe,使JVM通过传入的主类正确地启动游戏。
启动参数分为JVM参数和Minecraft参数两部分。
获取参数
运行此命令可获取当前运行的Minecraft进程的参数:
wmic process where caption="javaw.exe" get caption,commandline /value>args.txt
此时args.txt大致有这样的文件内容:
Caption=javaw.exe CommandLine="**javaw或java路径**" -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump "-Dos.name=Windows 10" -Dos.version=10.0 -Xss1M -Djava.library.path=**natives文件夹路径** -Dminecraft.launcher.brand=minecraft-launcher -Dminecraft.launcher.version=2.1.3674 -cp **一大串用;分开的文件路径** -Xmx2G -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:G1HeapRegionSize=32M -Dlog4j.configurationFile=**log4j配置文件路径** net.minecraft.client.main.Main --username **用户名** --version **游戏版本** --gameDir **游戏路径** --assetsDir **资源文件路径** --assetIndex **资源索引版本** --uuid **用户uuid** --accessToken **登录令牌** --userType mojang --versionType release
删除除跟在CommandLine后以外的内容,将该文件后缀改为.bat,双击即可启动Minecraft。
运行前注意文件编码。并注意官方启动器的natives文件存储在临时文件夹下,可能因删除导致无法启动。
JVM参数
-X、-XX参数
配置JVM,如GC等:
-Xmx1024m最大堆大小为1024MB-Xmn128m新生代堆大小为128MB-XX:+UseG1GC开启G1-XX:-UseAdaptiveSizePolicy自动选择年轻代区大小和相应的Survivor区比例-XX:-OmitStackTraceInFastThrow省略异常栈信息从而快速抛出
-D参数
配置JVM系统属性,格式为-D<name>=<value>。
Dos.name=Windows 10 -Dos.version=10.0当前系统名称及版本-Dminecraft.launcher.brand=minecraft-launcher -Dminecraft.launcher.version=2.1.3674当前启动器名称及版本-Dlog4j.configurationFile=**文件路径**\client-1.12.xml游戏日志配置文件-Djava.library.path=**natives文件夹路径**当前系统下游戏运行所需的动态链接库
使用下列参数来跳过正版验证:
-Dfml.ignoreInvalidMinecraftCertificates=true-Dfml.ignorePatchDiscrepancies=true
-cp参数
后为所有当前版本Minecraft的依赖库文件路径,中间用;隔开。
Minecraft参数
以主类名开头,通常为net.minecraft.client.main.Main,若安装Mod加载器则一般为net.minecraft.launchwrapper.Launch
参数通常有:
--username后接用户名--version后接游戏版本--gameDir后接游戏路径--assetsDir后接资源文件路径--assetIndex后接资源索引版本--uuid后接用户uuid--accessToken后接登录令牌--userType后接用户类型--versionType后接版本类型,会显示在游戏主界面右下角- 等等,可能因版本而异
游戏文件
文件结构大致如下:
.minecraft\
|assets\(游戏资源文件(如牛的叫声))
|libraries\(游戏依赖库(含natives))
|resourcepacks\(材质包存放处)
|saves\(存档)
|screenshots\(截屏.F2)
|...
|versions\
|1.14.1\
|1.14.2.json
|1.14.2.jar
|...natives-timeout
|1.13.2\
|...
|launcher_profiles.json
版本清单文件
该文件可于https://launchermeta.mojang.com/mc/game/version_manifest.json下载。
内容通常如下:
{
"latest": {
"release": "1.14.1",
"snapshot": "1.14.2 Pre-Release 4"
},
"versions": [
{
"id": "1.14.2 Pre-Release 4",
"type": "snapshot",
"url": "https://launchermeta.mojang.com/v1/packages/f90f601344058a812144eb71a49552b30a70d589/1.14.2_Pre-Release_4.json",
"time": "2019-05-24T15:50:42+00:00",
"releaseTime": "2019-05-24T15:48:24+00:00"
},
{
"id": "1.14.2 Pre-Release 3",
"type": "snapshot",
"url": "https://launchermeta.mojang.com/v1/packages/48004350162b58ab677efb7db5cc417af13124ef/1.14.2_Pre-Release_3.json",
"time": "2019-05-24T15:40:12+00:00",
"releaseTime": "2019-05-22T13:12:51+00:00"
},
...
]
}
其中,latest中为当前最新版本,分为发布版和快照版。
version后为所有可下载的游戏版本,url后为该版本的json文件下载地址。
版本json文件
该文件一般下载后存储在.minecraft/versions文件夹下,有如下内容:
{
"arguments": {
"game": [
"--username",
"${auth_player_name}",
"--version",
"${version_name}",
...,
{
"rules": [
{
"action": "allow",
"features": {
"is_demo_user": true
}
}
],
"value": "--demo"
},
...
],
"jvm": [
{
"rules": [
{
"action": "allow",
"os": {
"name": "osx"
}
}
],
"value": [
"-XstartOnFirstThread"
]
},
...
],
"assetIndex": {
"id": "1.14",
"sha1": "702d433ca9a27a2b75dc4e95ac57921a34d82bd3",
"size": 226168,
"totalSize": 207233561,
"url": "https://launchermeta.mojang.com/v1/packages/702d433ca9a27a2b75dc4e95ac57921a34d82bd3/1.14.json"
},
"assets": "1.14",
"downloads": {
"client": {
"sha1": "f14e1ab15fb7455c81c487b2d82b29773e7cf4f6",
"size": 18794301,
"url": "https://launcher.mojang.com/v1/objects/f14e1ab15fb7455c81c487b2d82b29773e7cf4f6/client.jar"
},
"server": {
"sha1": "631e46624daaf9e8357fcb985e0fce489b020e74",
"size": 35932929,
"url": "https://launcher.mojang.com/v1/objects/631e46624daaf9e8357fcb985e0fce489b020e74/server.jar"
}
},
"id": "1.14.2 Pre-Release 4",
"libraries": [
{
"downloads": {
"artifact": {
"path": "com/mojang/patchy/1.1/patchy-1.1.jar",
"sha1": "aef610b34a1be37fa851825f12372b78424d8903",
"size": 15817,
"url": "https://libraries.minecraft.net/com/mojang/patchy/1.1/patchy-1.1.jar"
}
},
"name": "com.mojang:patchy:1.1"
},
...,
{
"downloads": {
"artifact": {
"path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1.jar",
"sha1": "2bb514e444994c6fece99a21f76e0c90438e377f",
"size": 317748,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1.jar"
},
"classifiers": {
"javadoc": {
"path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-javadoc.jar",
"sha1": "1f6b7050737559b775d797c0ea56612b8e373fd6",
"size": 1287174,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-javadoc.jar"
},
"natives-linux": {
"path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-natives-linux.jar",
"sha1": "9bdd47cd63ce102cec837a396c8ded597cb75a66",
"size": 87484,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-natives-linux.jar"
},
"natives-macos": {
"path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-natives-macos.jar",
"sha1": "5a4c271d150906858d475603dcb9479453c60555",
"size": 39835,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-natives-macos.jar"
},
"natives-windows": {
"path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-natives-windows.jar",
"sha1": "e799d06b8969db0610e68776e0eff4b6191098bd",
"size": 255871,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-natives-windows.jar"
},
"sources": {
"path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-sources.jar",
"sha1": "106f90ac41449004a969309488aa6e3a2f7d6731",
"size": 255671,
"url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-sources.jar"
}
}
},
...
],
"logging": {
"client": {
"argument": "-Dlog4j.configurationFile=${path}",
"file": {
"id": "client-1.12.xml",
"sha1": "ef4f57b922df243d0cef096efe808c72db042149",
"size": 877,
"url": "https://launcher.mojang.com/v1/objects/ef4f57b922df243d0cef096efe808c72db042149/client-1.12.xml"
},
"type": "log4j2-xml"
}
},
"mainClass": "net.minecraft.client.main.Main",
"minimumLauncherVersion": 21,
"releaseTime": "2019-05-24T15:48:24+00:00",
"time": "2019-05-24T15:48:24+00:00",
"type": "snapshot"
}
rules
用于可选条目,使用features判断并应用其action。
arguments
1.13后新增键,旧版本为gameArguments,且不提供JVM参数及rules规则。
${****}
字符串模板,替换相应内容来使用。
assetIndex
当前版本的资源文件索引,包含其下载地址等信息。
downloads
客户端及服务端,包含其下载地址等信息。
libraries
游戏所有依赖库,包含其下载地址等信息。
downloads下均含有artifact键,有些含有classifiers键。
- 只含有
artifact键的为-cp参数后所需拼接的路径,注意path键中为不完整路径,请补全为完整路径。 - 含有
classifiers键的为natives库,在游戏启动前将对应平台的含有jar文件解压至natives文件夹。
logging
log4j配置文件,包含其下载地址等信息。
libraries
主类名。
资源索引文件
一般位于.minecraft/assets/indexes路径下,用于指示objects文件的信息及其其下载地址。该文件可能需要不定期更新。
内容如下:
{
"objects": {
"icons/icon_16x16.png": {
"hash": "bdf48ef6b5d0d23bbb02e17d04865216179f510a",
"size": 3665
},
...
}
}
objects文件的下载地址为:
http://resources.download.minecraft.net/<hash的前两位字符>/<hash>
存储路径为:
.minecraft/assets/objects/<hash的前两位字符>/<hash>
并在.minecraft/assets/virtual/legacy/留下一份拷贝。
正版验证
Minecraft自1.6后使用了Yggdrasil验证方法,验证服务器为:
https://authserver.mojang.com
验证时需要:
- 为
POST请求 Content-Type设置为application/json- 负载以JSON编码
若请求成功则返回状态码200及一个JSON文档。
若失败则返回错误信息:
{
"error": "错误简要描述",
"errorMessage": "向用户显示的长描述",
"cause": "错误原因" // 可选的
}
具体错误信息可参考https://wiki.vg/Authentication#Errors。
验证账号密码
- 后缀:
/authenticate
- 负载:
{
"agent": {
"name": "Minecraft", // 默认为Minecraft,可选
"version": 1 // 未来可能会改(不会)
},
"username": "mojang用户名", // 可以是邮箱地址或旧版mojang用户名
"password": "密码",
"clientToken": "客户端标识符", // 可选的,用于复用该值
}
- 回应:
{
"accessToken": "随机令牌",
"clientToken": "客户端标识符",
"availableProfiles": [
{
"id": "profile identifier",
"name": "玩家名"
}
],
"selectedProfile": {
"id": "不含-的uuid",
"name": "玩家名"
}
}
(有删节,参考https://wiki.vg/Authentication#Authenticate)
你可以存储这个clientToken,用来标识这个客户端。
此处获取的uuid和accessToken即为启动参数中所需的,传入你刚刚获得的值,启动游戏后便能发现已显示正版皮肤,即完成了正版登录。
检验令牌有效性
accessToken具有有效期,可能因为一些原因失效。你可以发送请求,验证当前accessToken是否还是有效的.
- 后缀:
/validate
- 负载:
{
"accessToken": "valid accessToken",
"clientToken": "associated clientToken" //可选的
}
- 回应:
如果状态码为204 No Content则有效,而403 Forbidden为已失效。
刷新令牌
刷新一个accessToken,用于保持用户在游戏会话之间登录。
- 后缀:
/refresh
- 负载:
{
"accessToken": "valid accessToken",
"clientToken": "associated clientToken" //可选的
}
- 回应:
{
"accessToken": "随机令牌",
"clientToken": "客户端标识符",
"availableProfiles": [
{
"id": "profile identifier",
"name": "玩家名"
}
],
"selectedProfile": {
"id": "不含-的uuid",
"name": "玩家名"
}
}
(有删节,参考https://wiki.vg/Authentication#Refresh)
与“验证账号密码”中相同。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||