字符串模板,顾名思义就是json中双引号内的${template}。
一般情况下,美元符号右边一个大括号内的内容,如果在同一个字符串内出现多次,那多半是同一个意思。我们首先请看原版的字符串模板吧!ps:还是以原版1.19.4作为例子,下面我将介绍我已经拼接好的。
<17.0.6的Java> -XX:+UseG1GC -XX:-UseAdaptiveSizePolicy -XX:-OmitStackTraceInFastThrow -Dfml.ignoreInvalidMinecraftCertificates=True -Dfml.ignorePatchDiscrepancies=True -Dlog4j2.formatMsgNoLookups=true -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump -Dos.name=Windows 10" -Dos.version=10.0 -Djava.library.path=${natives_directory} -Dminecraft.launcher.brand=${launcher_name} -Dminecraft.launcher.version=${launcher_version} -cp ${classpath} --username ${auth_player_name} --version ${version_name} --gameDir ${game_directory} --assetsDir ${assets_root} --assetIndex ${assets_index_name} --uuid ${auth_uuid} --accessToken ${auth_access_token} --clientId ${clientid} --xuid ${auth_xuid} --userType ${user_type} --versionType ${version_type}
哝,总的启动参数也就只有这么一点点,我们只是查找了其中的cp后面的classpath键值与替换了inheritsFrom键后面的东西吧!
如果大家觉得翻页太麻烦的话,可以将其复制到记事本里面,然后再观看哦!
好了,下面我们就来介绍一下如何使用上期所指认的所有方法吧!
首先,我们双击窗体按钮,进入Button1Click事件,这个事件的意思代表着按钮1的点击事件,然后我们就需要在里面写东西了
我们需要查看该版本是否是forge、fabric、quilt等模组加载器的版本,我们就需要判断其是否有inheritsFrom键。
开始写代码: 首先,在单元文件的implementation的上方,加上这样一句话:
var
Form1: TForm1;
lch: Launcher;
这样,我们就可以直接通过lch来调用Launcher中的所有内置代码了!
procedure TForm1.Button1Click(Sender: string);
begin //还是如此,我这里用双右划线代替。大家在使用Delphi实际操作时,必须用单右划线。
var spath := Concat(MinecraftPath, '\\versions\\', ComboBox1.Items[ComboBox1.ItemIndex]);
//上述代码是获取当前你从下拉框中选择的版本文件夹。众所周知,在下面的所有用到的方法中,我们都使用了lch去获取类里面的函数。
var yjson := GetOutsideDocument(lch.GetRealPath(spath, '.json')); //获取当前文件夹下的json文件内容。
var gjson := GetOutsideDocument(lch.GetRealPath(lch.GetInheritsFrom(spath, 'inheritsFrom'), '.json')); //获取是否含有inheritsFrom键文件内容。
var rjson := lch.ReplaceInheritsFrom(yjson, gjson); //当然,如果你觉得换成三行太麻烦了,你完全可以将上面两个变量直接填在这里面,但是我不太建议这么做。
//由于在前期工作我们已经做得相当完善了,因此,我们只需要用这么几个函数,即可将最正确的json文件给加载到内存之中给我们调用了。
var root := TJsonObject.ParseJSONValue(rjson) as TJsonObject; //将上述获取好的json转换成json对象形式。
var res := lch.SelectParam(root); //成功获取到拼接完成后的json文件。
//在这里,我们需要开始判断所有需要替换的字符串模板有哪些,其中包括了Vanilla、Forge、Fabric、Quilt的版本。
res := Concat(res, ' --width ', wt, ' --height ', ht); //新增最后两个参数,分别代表了长宽高。这里我一般会输入1000和800。
res := res //开始进行字符串替换。
.Replace('${auth_player_name}', UserName) //这里开始判断的是玩家名称【由于目前我们做的只有离线登录,正版登录的玩家名称后期再说了。】
.Replace('${version_name}', root.GetValue('id').Value) //这里开始判断的事玩家版本【其实随便填什么都可以啦!但是这里以json中的id值作为判断依据。】
.Replace('${game_directory}', Concat('"', MinecraftPath, '"')) //重点!敲黑板!此处应该填入的是一个路径,用于判断版本隔离的,
//大家可能会发现,BakaXL的该键值,总是指向<source>\versions\<versionname>下的目录。而PCL2,则会让各位选择版本隔离。【这点我们以后说,大家只需要做个了解即可。】
.Replace('${assets_root}', Concat('"', MinecraftPath, '\\assets', '"')) //assets_root一般指的是MC启动所需要的assets路径。这里依旧使用了两个右划号。
.Replace('${assets_index_name}', Root.GetValue('assets').Value) //其实,这里可以使用assetIndex->id代替的,也可以直接用assets。这个键值是原版就有的。然后assetIndex这个键后期我们说道下载的时候再介绍。
.Replace('${auth_uuid}', '0123456789abcdef0123456789abcdef') //这里需要填入一个无符号的32位uuid键作为玩家的唯一标识符。大家可以用Delphi内置函数随机生成一个UUID,但是这里建议每次进入游戏的UUID键值必须一致,否则可能会导致物品栏内的物品失踪的bug。
.Replace('${auth_access_token}', 'none') //这里填入你的access_token,想必大家应该看到过MCBBS的那个帖子了吧,这个作为玩家的正版登录令牌,在离线模式下无需此键【填入任何字符即可】,但是在正版登录中,你绝对不允许将带有access_token的启动参数发给对方。
.Replace('${user_type}', 'Legacy') //用户类型,一般如果是正版登录,则替换为Mojang、外置同理,如果是离线登录,则替换为Legacy。
.Replace('${version_type}', VersionType) //填入版本类型,一般是显示在游戏启动后的左下角以及游戏内按下F3后左上角显示的。
.Replace('${natives_directory}', Concat('"', lch.GetRealDirectory(spath, 'natives'), '"')) //这个路径填入Minecraft本地库路径,不过照常来说,官启的本地库路径一般在<C:\Users\<用户名>\AppData\Local\Temp>中,
//而HMCL、PCL、BakaXL所存放的本地库路径,则在<MC路径>\versions\<versionName>中。因此,我们需要适配这种情况。这里使用了一个自定义函数GetRealDirectory,我们稍后说。
.Replace('${launcher_name}', 'CourseLauncher') //定义你的启动器名称【暂不知其用途】
.Replace('${launcher_version}', '1.0') //定义你的启动器版本【暂不知其用途】
.Replace('${classpath}', Concat('"', lch.GetCPLibraries(root, MinecraftPath, spath), '"')) //使用GetCPLibraries键替换掉classpath键。
.Replace('${library_directory}', Concat('"', MinecraftPath, '\libraries', '"')) //这里可以直接填入libraries的路径。
.Replace('${classpath_separator}', ';')//这里是每个classpath的分开符号。
.Replace('${authlib_injector_param}', ''); //这里需要将Authlib-Injector暂时去掉,这个还是老样子,我们后期再说!
//替换到这种程度就可以了。
end;
最后,我们在上面写了一个GetRealDirectory的函数,这个函数我们也要去实现一下哦!
function Launcher.GetRealDirectory(path, suffix: string): String;
var // 同上
Dirs: TArray<String>;
begin
result := '';
if DirectoryExists(path) then // 判断文件夹是否存在
begin
Dirs := TDirectory.GetDirectories(path); // 获取文件
for var I in Dirs do begin // 循环判断
if I.IndexOf(suffix) <> -1 then begin// 判断是否在里面
result := I;
exit;
end;
end;
end;
end;
然后,我们就敲完所有的代码了!
我们可以在最后一个Replace的后面,建立一个messagebox用来查看我们的参数是否拼接正确哦,记住,我们所有的参数都只能在一行中实现,不允许出现分段或者多行哦!
我们在最后一步,在Replace完了之后,我们只需要再添加一个函数,用于启动我们的MC即可!
ShellExecute(Application.Handle, 'open', pchar(JavaPath), pchar(res), nil, SW_SHOWNORMAL);
//记住,这里的中间两个参数为pchar类型,意味着这是一个char指针类型。
只需要简简单单的一行,我们即可通过我们定义的Java启动MC了!这是一个Delphi的内置函数,用于执行cmd命令时用的。在这里面,我们也是首次使用到了我们的JavaPath哦!在使用这个函数的时候,我们需要引用一个单元文件:
uses
ShellAPI;
关于这个函数的使用教程,请参见:网址
具体功能见下:
参数 | 功能 |
---|---|
1 | 默认均为Application.Handle |
2 | 执行外部程序时填入open,打开网址时填入nil |
3 | 外部程序入口,如果是网址则填入网址 |
4 | 程序参数,如果没有可以填nil |
5 | 默认文件夹,直接填nil |
6 | 显示方式,这里只需了解两个,1.SW_SHOWNORMAL,正常显示,2.SW_HIDE,隐藏窗口显示。 |
好了,接下来,我们便可以正常的启动我们的MC了!你应该能看到,【假设你的MC已经被别的启动器下载并且被启动过至少一次。】【同样的,不仅如此,我们甚至还早已可以启动1.12.2以下以及远古版本了!】
我们造的轮子可真多,难道不是么?
哦,对了,此时此刻,你需要对你的MC版本进行Java版本判断,例如1.12.2的Forge只能使用java8启动、1.17以上版本只能使用Java17启动等。