Electron开发Minecraft启动器

点击tags就可以看到上篇文章了
github

目录设置的有点不合理..不过没关系啦…不打算改了..
因为最近在看JavaScript设计模式.虽然功能不多,但是我尽量都模块化了~

创建一个Electron(app.js)

1
2
3
var electron = require('electron'); // 控制应用生命周期的模块。
var app=electron.app
var BrowserWindow = electron.BrowserWindow; // 创建原生浏览器窗口的模块

因为新版的创建方式改了..所以这个坑我踩了然后跳出来了.
创建浏览器窗口和设置标题等等…这些都能在官方API上找到
官方文档
其中模板是通过mainWindow.loadURL一个file链接…
这些都能在官方那个快速入门找到代码..实际上我也是搬抄过来的..没啥要说的.

前端框架/库的引入

利用webpack做前端依赖管理的时候..jquery这个坑了我一把,在electron必须要手动声明详情看template/index.html

1
window.$ = window.jQuery = require("../../../public/lib/jquery/dist/jquery.js")

手动挂载到全局后webpack才能导入..不仅如此..
包括我用Materialize框架需要用到一个库Hammer也是需要手动引入
值得一提的是,实际上Materialize.min.js已经包含了..因为electron中挂载原因所以得手动引入一个Hammer库.

前端与后端通信

关于后端的操作我都放在service端了..前端不做后端比如路径操作之类的.
先说说如何在前端操控后端的模板,其实很简单只需要手动引入一个模块也就是”remote”模块
这样你就可以通过这个remote模块引入后端库了 比如

1
2
var remote=require("remote")
var fs=remote.require("fs")

那么如何与后端通信呢?就是通过ipc这个模块,事件绑定的方式

1
2
var ipc=require("electron").ipcRenderer
ipc.send("close-main-window");

比如ipc.on(“xxx”)就是绑定后端触发的事件
ipc.send(“xxx”)向后端发送事件
okay.基本的都说完了..其他的没啥要说的了.因为有这些功能就可以与后端进行通信了。

判断java路径

有几种方法 一种是功能判断通过java指令来判断.从中提取相应的路径
还有一种就是直接找C盘目录…这个并不靠谱..我算是写死了
最靠谱的一种是通过注册表来判断java路径 这里我没实现..因为我还没发现bug..实在不行用户指定就okay了~
具体的可以看service/js下的searchjava

判断系统位数

nodejs并没有给出获取系统位数..倒是给出了一个CPU构架函数…shenmegui
这里也是通过执行cmd命令来提取相应的字符串

1
2
3
4
5
6
7
child_process.exec("wmic os get osarchitecture",function(error, stdout, stderr){
if(stdout.indexOf("64")!=-1){
cb("64")
}else{
cb("32")
}
})

Minecraft相关

读Minecraft版本

这里我实现的不太好..不过因为是自用的也就不顾及太多了..bug是慢慢修复的嘛
这里是获取.minecraft/assets/indexes/xxx.json这个json版本 不过貌似网上大多数都是读version目录的

读取MinecraftJson

也就是读取.minecraft/versions/1.7.10/1.7.10.json 这里的1.7.10是指版本
读取这个json里面的所有属性

替换minecraftArguments

这个minecraftArguments里面是有许多要替换的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
start_arg["id"]=getGameStartArg.id;
start_arg["assets"]=getGameStartArg.assets;
start_arg["mainClass"]=getGameStartArg.mainClass;
start_arg["minecraftArguments"]=getGameStartArg.minecraftArguments;
start_arg["uuid"]=getGameStartArg.uuid;
start_arg["token"]=getGameStartArg.token;
start_arg["twitch"]=getGameStartArg.twitch;
start_arg["libs"]=getGameStartArg.libs;
start_arg["type"]=getGameStartArg.type;
var _r=[
["${auth_player_name}",user_config['username']],
["${version_name}",start_arg['id']],
["${game_directory}",path.join(app_path,".minecraft")],
["${game_assets}","\""+path.join(app_path,"/.minecraft/assets")+"\""],
["${assets_root}","\""+path.join(app_path,"/.minecraft/assets")+"\""],
["${assets_index_name}",start_arg['assets']],
["${auth_uuid}",start_arg['uuid']],
["${auth_session}",start_arg['token']],
["${auth_access_token}",start_arg['token']],
["${user_properties}",start_arg['twitch']],
["${user_type}",start_arg['type']],
]

这里给出了一段需要替换的文本uuid和token以及twitch应该是正版登陆相关的..这个正版登陆没研究过 如果盗版就直接写一个 {}即可

寻找libraries并且转换为路径

这个应该就是最扯淡的了..至少我还没发现什么好办法..通过分析的方法找到规律后直接写正则表达式匹配一部分再利用函数替换一部分
目的就是要把org.apache.logging.log4j:log4j-api:2.0-beta9这个字符串转换为路径
这里找到只有最后的:后面是数字 那么把数字分开后前面那部分全部替换成点号 然后再把点号替换成/号 后面的自然也好办了
但是这个地方有个缺陷就是如果遇到需要加native-window这些部分的libs就需要重新写一套规则了 总而言之这个并不是一个好办法.我就直接pass掉了native-window部分的lib 因为目前没发现有什么bug 有bug了再修复 这些bug都是已知可控的

拼接字符串调用cmd命令运行游戏

首先在运行之前需要加一段字符串需要包含双引号所以需要转移比如 \”\”

1
"\"C:\\Program Files\\Java\\jre1.8.0_71\\bin\\javaw.exe\"

需要先加上javaw.exe的path后再在前后加上双引号才能加上其他的参数

1
2
3
var start_text="\""+path.join(user_config['java_path'])+"\""+" -Xincgc -Xmx"+user_config["memory_size"]+"M "+user_config["add_arg"]+" -Djava.library.path="+""+path.join(app_path,".minecraft\\versions\\1.7.10\\1.7.10-natives")+""
+" -cp "+""+libs.join(";")+path.join(app_path,".minecraft/versions/",user_config["version"],user_config["version"]+".jar")+""
+" "+mainClass+" "+start;

启动参数大概就是这些
首先是双引号的java_path user_config[‘java_path’] 然后再是内存大小user_config[“memory_size”] 然后再是附加参数user_config[“add_arg”] 这个可以为空
接下来就是比较重要的了也就是-Djava.library.path 很多人都运行不了就是缺少natives文件夹..至于怎么解压这个natives我还没研究过 因为自己的服务器natives已经固定好了..我看了一下其他人的natives也是正常的..如果硬要做到解压那么到时候再说吧
设置了natives目录后 接一个 -cp 参数 这里就是把libs添加进去了. 然后再是设置游戏版本的jar也就是.minecraft/versions/下的那个jar
设置完毕后加上mainClass这个是读json读取出来的 最后加上start 这里的start

1
start_arg["start"]=replaceGameStartArg(start_arg["minecraftArguments"],_r)

也就是把minecraftArguments里面的内容替换完毕后的文本

至此一个Minecraft启动器就已经编写完毕了…因为是最基本的..不过主要的已经写好了嘛 后面的可以慢慢来 荆轲刺秦王