欢迎光临散文网 会员登陆 & 注册

教程/编写启动器

2023-07-25 18:12 作者:俏皮的方块鹦鹉  | 我要投稿


此特性为Java版独有。

本教程介绍如何制作Java版启动器,并假定你已掌握任何一门编程语言。

 

基本原理

因为Minecraft制作时采用了“启动器+游戏文件”的模式:

  • 将游戏文件单独存储,而通过启动器调用JVM(Java Virtual Machine)执行游戏主文件并传入一些游戏参数来启动Minecraft。

  • 游戏依赖库文件以及游戏资源文件由启动器补全。

  • 玩家登录认证由启动器完成。

这使得我们能通过编写第三方启动器来接管游戏文件管理和登录认证。

准备

要编写一个启动器,你需要:

  • 一门编程语言其开发环境

  • Java运行时环境(Java Runtime Environment,JRE),可于Java官网下载

并拥有支持下列功能的库:

  • 解析JSON文档(得到启动参数的关键)

  • 解压文件(解压natives文件,也可使用链接外部程序替代)

  • 网络库(正版验证、皮肤管理)

启动参数

启动参数将传入java.exejavaw.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文件夹路径> 当前系统下游戏运行所需的动态链接库

-cp参数

全称为-classpath,后为所有当前版本Minecraft的普通库文件路径及游戏主文件,中间用;隔开。

Minecraft参数

以主类名开头,通常为net.minecraft.client.main.Main,若安装Mod加载器则一般为net.minecraft.launchwrapper.Launch

参数通常有:

  • --username 后接用户名

  • --version 后接游戏版本

  • --gameDir 后接游戏路径

  • --assetsDir 后接资源文件路径

  • --assetIndex 后接资源索引版本

  • --uuid 后接用户uuid

  • --accessToken 后接登录令牌

  • --userType 后接用户类型

  • --versionType 后接版本类型,会显示在游戏主界面右下角

  • 等等,可能因版本而异,具体应参考当前版本json文件内提供的信息。

游戏文件

文件结构大致如下:

列表

  • .minecraft

    • [版本号]

    • [版本号].jar

    • [版本号].json

    • indexes

    • log_configs

    • objects

    • skins

    • [版本号].json

    • client-[版本号].xml

    • assets

    • resourcepacks

    • saves

    • screenshots

    • versions

    • launcher_profiles.json

    • launcher_profiles.json

    • options.txt

以上文件结构经过简化,具体可参考.minecraft页面。

JSON文件

Minecraft大多数信息使用JSON文档存储管理,使用这些JSON文件可以获取下载、管理及启动所需的大部分信息。

版本清单文件

主条目: /version_manifest.json

该文件可以在mojang官方服务器下载:

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中为当前最新版本,分为发布版和快照版。versions后为所有可下载的游戏版本,url后为该版本的json文件下载地址。

版本json文件

主条目: /version.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配置文件,包含其下载地址等信息。

  • mainClass

  • 主类名。

资源索引文件

一般存储于.minecraft/assets/indexes路径下,用于指示objects文件的信息及其下载地址。

该文件的下载地址等信息存储在版本json文件中,该文件可能需要不定期更新。

内容如下:

{     "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/留下一份拷贝。

启动器配置文件

主条目: launcher_profiles.json

该文件不是必须的,但它是官方启动器的配置文件。所以可用于与官方启动器数据互通,以及forge安装检验。

最简单的配置文件为:

{     "profiles": {         "(Default)": {             "gameDir": "<游戏目录>",             "lastVersionId": "1.14.1",             "name": "(Default)"         }     },     "selectedProfileName": "(Default)",     等等乱七八糟的配置 }

profiles为启动器中创建的所有配置文件。

游戏主文件

通常存储于.minecraft/versions/<version>/<version>.jar,下载地址等信息存储在版本json文件中,下载时注意将该文件重命名为对应版本号。

依赖库文件

通常存储于.minecraft/libraries/路径下,下载地址等信息存储在版本json文件中。

普通库文件

在启动前需拼接在启动参数的-cp参数后。

natives库文件

在启动前需解压至natives路径下。

资源文件

通常存储在.minecraft/assets/objects/,并在.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/ZH:Authentication#错误。

验证账号密码

  • 后缀:

/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/ZH:Authentication#Authentication)

你可以存储这个clientToken,用来标识这个客户端。

此处获取的uuidaccessToken即为启动参数中所需的,传入你刚刚获得的值,启动游戏后便能发现已显示正版皮肤,即完成了正版登录。

检验令牌有效性

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/ZH:Authentication#Refresh)

与“验证账号密码”中相同。

启动游戏

  1. 首先必须保证启动参数中出现的所有文件及提供的资源索引文件中的object文件都存在且未被损坏。

  2. 选定一个natives路径,可以自由选定,也可像官方启动器一样使用临时路径。将natives库文件解压至该路径,并将该路径使用-Djava.library.path=传入游戏。

  3. 完成正版验证,得到uuid及accessToken

  4. 拼接启动参数,创建游戏进程

  5. 处理游戏输出及游戏错误

支持forge等Mod加载器

运行forge等Mod加载器的安装包后,可以发现:

  • 启动器配置文件中添加了一条新安装的配置

  • .minecraft/libraries/文件夹中多了一些文件

  • .minecraft/versions/文件夹中多了一个版本json文件(也可能会有jar文件)

额外的版本json文件

该文件相比原版的版本json文件文件多了inheritsFromjar键,而且其他键内容明显是不完整的。

  • inheritsFrom

  • 该参数指定了当前版本所继承的原版版本,意思为除此 版本json文件外,同时使用 inheritsFrom中指定的 版本json文件内容。即, -cp参数后同时包含两个 版本json文件指定的 普通库文件,且 natives库文件也同时包含两个 版本json文件指定的,且该 版本json文件优先于原版 版本json文件。

  • jar

  • 该参数指定了 -cp参数后的 游戏主文件。

  • 除此之外, 版本json文件中的 libraries键的格式也有些不一样了,如:

{   "name": "org.ow2.asm:asm-all:5.0.3",   "serverreq": true }, {   "name": "jline:jline:2.13",   "url": "http://files.minecraftforge.net/maven/",   "checksums": [     "2d9530d0a25daffaffda7c35037b046b627bb171"   ],   "serverreq": true,   "clientreq": false }

不再有downloads键了,只剩下nameurl,文件路径及下载路径需要根据一定规则拼接。

name键的格式为:

<package>:<name>:<version>

我们将它变形重组一下:

<package>/<name>/<version>/<name>-<version>.jar

前方接上.minecraft/libraries/即为文件路径,而接上url的内容即为下载地址。

serverreqclientreq用于区分客户端和服务端的需要。

优化下载

有时,在官方服务器下载文件会很缓慢,这时可以考虑使用第三方镜像下载。

当前常用的第三方镜像有:

  • BMCLAPI

另外,Minecraft的依赖库文件和资源索引文件很多为小文件,可以考虑使用多线程下载来优化速度。

皮肤管理

皮肤管理需要使用Mojang API:

api.mojang.com

可通过发送GET请求获得Mojang API的状态:

https://status.mojang.com/check

获取皮肤及披风

可通过发送GET请求获得皮肤及披风地址:

https://sessionserver.mojang.com/session/minecraft/profile/<uuid>

  • 响应:

{    "id": "<配置标识符>",    "name": "<玩家名>",    "properties": [         {            "name": "textures",            "value": "<base64字符串>"        }    ] }

解码该base64字符串,可获得另一JSON文档:

{    "timestamp": <java time in ms>,    "profileId": "<配置uuid>",    "profileName": "<玩家名>",    "textures": {        "SKIN": {            "url": "<玩家皮肤URL>"        },        "CAPE": {            "url": "<玩家披风URL>"        }    } }

更换皮肤

发送POST请求至:

https://api.mojang.com/user/profile/<uuid>/skin

  • 头:

Authorization: Bearer <access token>

  • 负载:

model=<""/"slim">&url=<皮肤url>

空字符串为Steve模型,“slim”为Alex模型。

上传皮肤

发送PUT请求至:

https://api.mojang.com/user/profile/<uuid>/skin

  • 头:

Authorization: Bearer <access token>

  • 负载:

由两部分组成:

  • model:人物模型,空字符串为Steve模型,“slim”为Alex模型。

  • file:原始图像文件数据

重置皮肤

发送DELETE请求至:

https://api.mojang.com/user/profile/<uuid>/skin

  • 头:

Authorization: Bearer <access token>

还好我学过java😊


教程/编写启动器的评论 (共 条)

分享到微博请遵守国家法律