怎样开发一个Minecraft启动器(Java版)


Minecraft 玩了很久,一定用过各种启动器。除了官方启动器之外,还有许多第三方开发的启动器,例如: HMCLMultiMCPrism LauncherATLauncherGDLauncher


启动器适合人群特点
HMCLMod 玩家中文友好,功能全面
Prism Launcher多实例管理轻量、稳定
ATLauncher整合包玩家大型 Mod 包支持
GDLauncher现代化 UI云同步(付费)
Lunar ClientPvP 玩家性能优化
Betacraft怀旧玩家支持远古版本
TLauncher盗版玩家(不推荐)风险高

你一定好奇,这些启动器是怎么开发出来的,我们是不是可以自己动手开发一个自己的启动器?

答案当然是可以的,而且实现一个启动器其实并不困难。启动器本质上只做两件事:把游戏所需的文件下载好,再拼出一条正确的 Java 命令把它跑起来。本文以 Java 版客户端和服务端为例,把这条流水线一步步拆开。

想了解启动器工作原理,我们首先可以看看官方启动器是怎么运行的。 下载微软官方的启动器 ,安装并启动它。启动游戏客户端,然后在控制台使用命令查看启动器进程:

  • Windows:
wmic process where caption="javaw.exe" get caption,commandline /value
  • Linux/macOS:
ps aux | grep java

你会看到一条很长的 java 启动命令,里面带了 classpath、一堆 JVM 参数和游戏参数——启动器的工作就是把这条命令拼出来。下面我们一步步还原它。


启动器的核心:元数据🔗

版本清单 version_manifest.json🔗

所有版本的信息都汇总在一份清单文件里:

https://launchermeta.mojang.com/mc/game/version_manifest.json

注意这是 Mojang 的旧域名,现在会 301 跳转到 piston-meta.mojang.com。只要你的 HTTP 客户端跟随重定向(大多数语言默认如此),这个地址就能正常使用。

清单内容分两部分:

{
  "latest": {
    "release": "26.2",
    "snapshot": "26.3-snapshot-9"
  },
  "versions": [
    {
      "id": "26.2",
      "type": "release",
      "url": "https://piston-meta.mojang.com/v1/packages/<sha1>/26.2.json",
      "time": "2026-08-17T11:52:59+00:00",
      "releaseTime": "2026-08-17T11:46:16+00:00"
    }
  ]
}
  • latest:最新正式版 / 快照版版本号,方便快速定位
  • versions:全部版本条目(约近千条),每条的核心是 idtypeurl

版本 type 有四种:release(正式版)、snapshot(快照)、old_alphaold_beta(远古版本)。

这份清单约 243 KB、近千条记录,建议缓存到本地,非必要不重复拉取;需要「检查更新」时再重新下载一次即可。

单版本 JSON🔗

清单里每个版本的 url 字段,指向这个版本的具体配置,形如:

https://piston-meta.mojang.com/v1/packages/<sha1>/<版本号>.json

获取元数据的流程就是三个请求:

GET version_manifest.json
  → 在 versions[] 里按 id 匹配目标版本
  → 取该条目的 url
GET <url>                 // 单版本 JSON,一个版本的全部配置

单版本 JSON 长什么样🔗

单版本 JSON 是启动器的「唯一事实来源」,下载什么、怎么启动全看它。关键字段:

字段作用
mainClass主类,客户端如 net.minecraft.client.main.Main
arguments现代格式:jvm(JVM 参数,可带规则)+ game(游戏参数模板)
downloadsclient / server jar 的下载信息(url + sha1 + size)
libraries依赖库列表(Maven 坐标 + 平台规则 + natives)
assetIndex资源索引 JSON 的 id / url / sha1
javaVersionmajorVersion,决定用哪个 Java 大版本
{
  "mainClass": "net.minecraft.client.main.Main",
  "javaVersion": { "majorVersion": 21 },
  "downloads": {
    "client": {
      "sha1": "<sha1>",
      "size": 39193383,
      "url": "https://piston-data.mojang.com/v1/objects/<sha1>/client.jar"
    },
    "server": {
      "sha1": "<sha1>",
      "size": 60894273,
      "url": "https://piston-data.mojang.com/v1/objects/<sha1>/server.jar"
    }
  },
  "assetIndex": {
    "id": "32",
    "sha1": "<sha1>",
    "url": "https://piston-meta.mojang.com/v1/packages/<sha1>/32.json"
  },
  "arguments": { "jvm": [...], "game": [...] },
  "libraries": [ ... ]
}

一个细节:老版本(约 1.13 之前)没有 arguments 字段,用的是字符串模板 minecraftArguments,把参数拼成一行再按空格拆分。新老格式都要兼容。

开发客户端启动器🔗

客户端启动器的流程四步:下载本体 → 下载资源 → 下载依赖 → 组装命令启动

1. 下载游戏本体🔗

downloads.client,下载后按 sha1 校验。校验通过的文件可以留档复用,下次启动跳过:

url  = version_json.downloads.client.url
sha1 = version_json.downloads.client.sha1

if 文件不存在 或 SHA-1 不匹配:
    下载 url → versions/<id>/client/<id>.jar
    校验 SHA-1
else:
    跳过

2. 下载资源文件🔗

资源文件(贴图、音效等)是另一套系统,由 assetIndex 索引:

  1. 下载 assetIndex.urlassets/indexes/<id>.json
  2. 该 JSON 的 objects 字段列出每个资源的 hash 和大小
  3. 从固定基址下载,两字符分片定位
https://resources.download.minecraft.net/<hash 前两位>/<hash>

例如 hash = a1b2c3...,地址就是 https://resources.download.minecraft.net/a1/a1b2c3...,保存到 assets/objects/<hash前两位>/<hash>

大版本资源文件动辄上千个,适合多线程并发下载。

3. 下载依赖库🔗

libraries 是 Maven 坐标列表,每一项要先解析:

  • 坐标 → 路径at.yawk.lz4:lz4-java:1.10.1at/yawk/lz4/lz4-java/1.10.1/lz4-java-1.10.1.jar,基址 https://libraries.minecraft.net/
  • 规则过滤:很多库带 rules,按当前 OS / 架构决定是否下载(例如 LWJGL 的 macOS 版只有 osx 才需要)
  • natives:带 natives-linux / natives-osx 之类分类器的 jar 是原生库,历史版本需要解压出 .dylib/.dll/.so 放到 natives/ 目录;较新版本游戏会在运行时自行从 classpath 解压,直接留在 classpath 即可

4. 组装启动命令🔗

所有文件就绪后,拼 Java 命令:

java
  -Xms512M -Xmx2G                    # 内存,启动器自己定
  <arguments.jvm 展开后的参数>        # 含 -Djava.library.path=<natives目录>
  -Dminecraft.launcher.brand=<品牌>
  -Dminecraft.launcher.version=<版本>
  -cp <classpath>                     # client.jar + 所有依赖库,用 OS 分隔符(:/;)拼接
  net.minecraft.client.main.Main      # mainClass
  <arguments.game 展开后的游戏参数>

两个要点:

JVM 参数与游戏参数都要「展开规则 + 替换 token」arguments 里的条目可能是纯字符串,也可能是带 rules 的对象——规则匹配当前 OS/特性才包含。例如 macOS 才有 -XstartOnFirstThread

[
  {
    "rules": [{ "action": "allow", "os": { "name": "osx" } }],
    "value": "-XstartOnFirstThread"
  }
]

游戏参数里的 ${token} 要替换成实际值

Token
${auth_player_name}玩家名
${game_directory}游戏目录
${assets_root}assets/ 目录
${assets_index_name}资源索引 id
${auth_uuid}玩家 UUID
${auth_access_token}登录凭证
${user_type}legacy(离线)或 msa

离线登录很简单--accessToken 0--uuid 给一个随机 UUID、--userType legacy 即可进入游戏(正版验证是另一套流程,见下文进阶)。

组装完成的伪代码:

准备(version):
    json = 获取单版本JSON(version)
    if not exists(client.jar):   下载(client.jar, sha1 校验)
    if not exists(assetIndex):   下载(assetIndex.json)
    for obj in assetIndex.objects:  并发下载(基址 + 分片定位, sha1 校验)
    for lib in resolve(libraries): 并发下载(按规则过滤, sha1 校验)
    解压 natives(如需)

启动(version):
    命令 = [java 路径]
    命令 += ["-Xms512M", "-Xmx2G"]
    命令 += 展开(jvm 参数)          # 规则过滤 + token 替换
    命令 += ["-cp", classpath 拼接]
    命令 += [mainClass]
    命令 += 展开(游戏参数)          # token 替换 + 补全 --username/--uuid/--accessToken
    spawn(命令)
    if 进程在几秒内退出: 读取日志, 回显失败原因

启动后游戏会在几秒内真正开始渲染。启动器可以做一个「短窗口崩溃检测」:进程刚起就退出,多半是 natives 缺失、classpath 拼错或 JVM 崩溃,此时把日志尾部回显给用户,比一句「启动失败」有用得多。

开发服务端启动器🔗

服务端和客户端共用同一套元数据入口:同样是版本清单 → 单版本 JSON,只是取 downloads.server 下载 server.jar,然后初始化配置并启动。

1. 下载服务端🔗

url  = version_json.downloads.server.url
下载 url → server/server.jar
校验 SHA-1

不需要额外的服务端清单——官方原版服务端的下载地址就藏在单版本 JSON 里。

2. 初始化配置🔗

原版服务端首次启动前需要两个文件:

  • eula.txt:接受协议才允许运行,内容一行 eula=true
  • server.properties:不存在的关键项可以补齐,如 online-mode=false(离线登录局域网)、server-ip=

3. 启动🔗

java -Xms512M -Xmx2G -jar server.jar --nogui

--nogui 在无图形界面的服务器/容器里去掉 GUI 窗口。生产环境通常用 screensystemd 守护进程托管,让服务端常驻并在崩溃后自动拉起。

服务端启动器伪代码:

准备服务端(version):
    json = 获取单版本JSON(version)
    下载(downloads.server.url → server.jar, sha1 校验)
    写入 eula.txt = "eula=true"
    补齐 server.properties(online-mode 等)

启动服务端(version):
    spawn(java, -Xms, -Xmx, -jar, server.jar, --nogui)

进阶话题🔗

  • 下载健壮性:每个文件都做 SHA-1 校验;已存在且校验通过就跳过,实现断点续传的体验;资源与依赖多线程并发下载,把上千个文件的耗时压下来。
  • 第三方服务端:Paper 等服务端有自己的 PaperMC API v2 ,接口路径是 projects/paper → versions → builds → 具体 build 的 download,可以拿到比 vanilla 更可选的构建产物。
  • Mod 加载器:Fabric、Forge、OptiFine 各有自己的安装器或 profile JSON,本质都是在 librariesclasspath、JVM 参数上做叠加。例如 OptiFine 会写一份 launcher_profiles.json 供安装器识别,Fabric 会解析自己版本清单的附加 JSON。
  • 正版认证:离线只需要占位符;正版走 Microsoft OAuth 登录流程,换取 access token 后填进 --accessToken--uuid,并处理 refresh token 过期。
  • Java 版本选择:按 javaVersion.majorVersion 匹配对应的大版本 Java;老版本(1.17 之前)需要 Java 8,现代版本需要 Java 17/21,当前 26.x 需要 Java 25。

参考链接: