123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- const fs = require('fs');
- const spawn = require('child_process').spawn;
- const spawnSync = require('child_process').spawnSync;
- const path = require('path');
- const scanf = require('scanf');
- const HTMLParser = require('node-html-parser');
-
- const hw = require(path.join(__dirname, 'GTBOT.node'));
-
- /**
- * option: {
- * nox_path: E:/nox/Nox,
- * open_count: 2,
- * close_time: 1000(ms)
- * }
- */
-
- class GT_Nox_Command{
- /**
- * @param {String} noxName 夜神內部Id e.g. Nox_1,Nox_2
- * @param {String} noxPath 夜神的安裝位置, 預設為 C:/Program Files (x86)/Nox
- */
- constructor(titleTable,option){
- this.titleToNoxIdTable = titleTable;
- if(typeof option !== "object") option = {};
- this.noxPath = option.nox_path?option.nox_path:"C:/Program Files (x86)/Nox";
- this.openCount = option.open_count?option.open_count:1;
- this.closeTime = option.close_time?option.close_time:1000;
-
- this.nox_command_file = path.join(this.noxPath,"bin","Nox.exe");
-
- this.errorExec = [];
- }
-
- nox_command(titleName,option){
- let argv_arr = ["-clone:" + this.titleToNoxIdTable[titleName] ];
- if(typeof option === "object"){
- for(let i in option){
- let temp = "-" + i + ":" + option[i];
- argv_arr[argv_arr.length] = temp;
- }
- }
- else if(typeof option === "string"){
- argv_arr[argv_arr.length] = option;
- }
-
- let cmd = spawn(this.nox_command_file, argv_arr, {
- detached: true
- });
- cmd.stdout.on('data', (data) => {
- // console.log(`stdout: \n${data}`);
- });
- cmd.stderr.on('data', (data) => {
- // console.log(`stderr: ${data}`);
- });
- cmd.on('close', (code) => {
- // console.log(`child process exited with code $[code]`);
- });
- }
-
- static checkOpen(title,cb){
- let count = 0;
- let intervalTemp = setInterval(function(){
- let mainW = hw.findWindowEx(0, 0, "Qt5QWindowIcon" , title);
- if(mainW){
- // init 時會有一個 title 是""的東西
- let check1 = hw.findWindowEx(mainW, 0, "Qt5QWindowIcon" , '');
- let check2 = hw.findWindowEx(mainW, 0, "Qt5QWindowIcon" , 'default_title_barWindow');
- if(check1 === check2){
- if(++count > 3){
- clearInterval(intervalTemp);
- cb();
- }
- }
- }
- },1000);
- }
-
- open_process(titleName){
- if(this.titleToNoxIdTable[titleName] === undefined){
- this.errorExec[this.errorExec.length] = titleName;
- return;
- }
- this.nox_command(titleName);
- GT_Nox_Command.checkOpen(titleName,function(){
- this.finish_open();
- }.bind(this));
- }
-
- finish_open(){
- if(this.open_arr.length <= 0){
- let msg = {};
- if(this.errorExec.length > 0){
- msg.err = this.errorExec.slice(0);;
- }
- this.finish_open_cb(msg);
- this.errorExec = [];
- return;
- }
- else{
- let nextOpen = this.open_arr.shift();
- this.open_process(nextOpen);
- }
- }
-
- /**
- * 開啟模擬器
- * @param {Array || String} titleNameArr 要開啟哪些APK
- * @param {Function} cb 開完了,你要做啥
- * option{
- * cpu:1,
- * memory: 960(or 1024),
- * resolution: '320x240',
- * dpi: 120,
- * root:false
- * }
- */
- openNox(titleNameArr,cb){
- let titleArr;
- if( Array.isArray(titleNameArr) ){
- titleArr = titleNameArr;
- }
- else if(typeof titleNameArr === "string"){
- titleArr = [titleNameArr]
- }
-
- this.open_arr = titleArr;
- this.finish_open_cb = cb;
-
- for(let i=0;i < this.openCount;i++){
- let nextOpen = this.open_arr.shift();
- this.open_process(nextOpen,i);
- if(this.open_arr.length === 0){
- break;
- }
- }
- }
-
- colse_process(closeTitle){
- if(this.titleToNoxIdTable[closeTitle] === undefined){
- this.errorExec[this.errorExec.length] = closeTitle;
- return;
- }
- this.nox_command(closeTitle,"-quit");
- }
-
- /**
- * 關閉模擬器
- * @param {Array || String} titleNameArr 要關哪些APK
- * @param {Function} cb 關完了,你要做啥
- */
- closeNox(titleNameArr,cb){
- let titleArr;
- if( Array.isArray(titleNameArr) ){
- titleArr = titleNameArr;
- }
- else if(typeof titleNameArr === "string"){
- titleArr = [titleNameArr]
- }
- // console.log(cb);
- this.activeFlage = true;
-
- let closeCount = 1;
- this.colse_process(titleArr[0]);
- let closeItl = setInterval(function(){
- this.colse_process(titleArr[closeCount]);
- closeCount++;
- if(closeCount >= titleArr.length){
- clearInterval(closeItl);
- let msg = {};
- if(this.errorExec.length > 0){
- msg.err = this.errorExec.slice(0);;
- }
- this.errorExec = [];
- if(typeof cb === 'function'){
- cb(msg);
- }
- }
- }.bind(this),this.closeTime);
- }
-
- restartNox(titleNameArr,cb){
- let titleArr;
- if( Array.isArray(titleNameArr) ){
- titleArr = titleNameArr;
- }
- else if(typeof titleNameArr === "string"){
- titleArr = [titleNameArr]
- }
-
- this.closeNox(titleArr,function(){
- setTimeout(()=>{
- this.openNox(titleArr,cb);
- },5000);
- }.bind(this));
- }
-
- /**
- * 安裝APK
- * @param {String} apk_path apk 的絕對位置
- */
- install_apk(apk_path){
- if(typeof apk_path !== "string"){
- console.log("你的apk path呢!");
- return;
- }
- this.nox_command("'-apk:" + apk_path + "'");
- }
-
- /**
- * 執行某個App,預設開托蘭
- * @param {string} appId app的唯一Id
- */
- run_app(appId){
- if(appId === undefined){
- appId = "com.asobimo.toramonline";
- }
-
- this.nox_command({package:appId});
- }
- }
-
- class adb_ctrl{
- constructor(option){
- this.nox_path = option.nox_path?option.nox_path:"C:/Program Files (x86)/Nox";
- this.adb_file = path.join(this.nox_path,"bin","nox_adb.exe");
-
- this.setMultiNoxList.call(this);
-
- // title 對應 Nox_id
- /**
- * {
- * atk01: Nox_1
- * }
- */
- // this.nox_table = {};
- // port 對應 title
- /**
- * {
- * 61025: Nox_1
- * }
- */
- // this.port_table = {};
-
- this.nox_cmd = new GT_Nox_Command(this.nox_table,option);
- // this.connect();
- }
-
- openNox(titleArr,cb){
- this.nox_cmd.openNox.call(this.nox_cmd,titleArr,cb);
- }
-
- closeNox(titleArr,cb){
- this.nox_cmd.closeNox.call(this.nox_cmd,titleArr,cb);
- }
-
- restartNox(titleArr,cb){
- this.nox_cmd.restartNox.call(this.nox_cmd,titleArr,cb);
- }
-
- exec_adb_cb(argv,cb){
- const status = spawn(this.adb_file, argv);
- status.stdout.setEncoding('utf8');
- status.stderr.setEncoding('utf8');
- let stdout = "";
- let err = false;
- let errInfo = "";
- status.stdout.on('data', (data) => {
- stdout += (data + "||");
- });
-
- status.stderr.on('data', (data) => {
- errInfo += (data + "||");
- });
-
- status.on('close', (code) => {
- cb({
- err: err,
- errInfo: errInfo,
- data: stdout
- });
- });
- }
-
- exec_adb(argv){
- return new Promise( (resolve, reject) => {
- const status = spawn(this.adb_file, argv);
- status.stdout.setEncoding('utf8');
- status.stderr.setEncoding('utf8');
- let stdout;
- status.stdout.on('data', (data) => {
- stdout = data;
- // console.log(data);
- });
-
- status.stderr.on('data', (data) => {
- // console.log("err",data);
- resolve({
- err: true,
- data: data
- });
- });
-
- status.on('close', (code) => {
- resolve({
- err: false,
- data:stdout
- });
- });
- });
- }
-
- delay(time){
- return new Promise( (resolve, reject) => {
- setTimeout(function(){
- resolve();
- },time);
- });
- }
-
- /**
- * 找multiNox 路徑
- */
- setMultiNoxList(){
- let multi_list;
- let multi_file = path.join(process.env.LOCALAPPDATA,'MultiPlayerManager','multiplayer.xml');
- try{
- multi_list = fs.readFileSync(multi_file,{encoding:"utf-8"});
- }
- catch(e){
- console.log(e);
- console.log("找不到夜神多工器啦 冠霆要你滾");
- scanf("%d");
- }
- if(multi_list === undefined){
- return;
- }
-
- let document = HTMLParser.parse(multi_list);
-
- let Instance = document.querySelectorAll("Instance");
- this.nox_table = {};
- this.port_table = {};
- this.title_to_device_table = {};
- for(let i=0;i < Instance.length;i++){
- let temp = Instance[i].attributes;
- if(temp.id === "Nox_0"){
- temp.id = "nox";
- }
- this.nox_table[temp.name] = temp.id;
- let yee = fs.readFileSync(this.nox_path + '/bin/BignoxVMS/' + temp.id + '/' + temp.id + '.vbox',{encoding:"utf-8"});
- let port = yee.split('<Forwarding name="port2" proto="1" hostip="127.0.0.1" hostport="')[1].slice(0,5);
-
- this.port_table[port] = temp.name;
- this.title_to_device_table[temp.name] = port;
- }
- // console.log(this.nox_table);
- // console.log(this.port_table);
- }
-
- /**
- * adb 初始化, adb 操作時,必做喔
- */
- async adb_init(){
- // var killServer = spawnSync(this.adb_file, ["kill-server"] ,{encoding: "utf-8"});
- let killServer = await this.exec_adb(["kill-server"]);
- if(killServer.err){
- if(killServer.data.indexOf("server not running") === -1){
- console.log("kill出錯啦~");
- console.log(killServer);
- scanf("%d");
- return "err";
- }
- }
- let startServer = await this.exec_adb( ["start-server"] );
- if(startServer.err){
- console.log("start出錯啦~");
- console.log(startServer);
- scanf("%d");
- return "err";
- }
- console.log("初始化完成~ 天佑冠霆啦!!");
- }
-
- scanNox(){
- return new Promise( (resolve, reject) => {
- let count = 0;
- let max = Object.keys(this.port_table).length;
- // console.log("scan囉");
- // console.log(Object.keys(this.port_table).length);
- function afterScan(data){
- count++;
- // console.log(count);
- // console.log(data);
- if(max === count){
- resolve();
- }
- }
- for(let i in this.port_table){
- this.exec_adb_cb( ["connect","127.0.0.1:" + i] ,afterScan);
- }
- });
- }
-
- /**
- * 連結目前所有已開的夜神模擬器
- */
- async connect(){
- await this.adb_init();
- if(this.port_table === undefined){
- return "err";
- }
-
- await this.scanNox();
-
- var devices = await this.exec_adb( ["devices"] );
- // console.log(devices);
- if(devices.err){
- console.log("devices出錯啦~");
- console.log(devices);
- scanf("%d");
- return "err";
- }
-
- let all_devices = devices.data.split("List of devices attached\r\n")[1];
- let devices_list = all_devices.split("\tdevice\r\n");
- devices_list = devices_list.reverse().slice(1);
-
- this.devices_list = devices_list;
- this.devices_count = devices_list.length;
- this.installed_count = 0;
- // console.log(devices_list);
-
- // console.log("你要更新的裝置數量:" + this.devices_count);
- }
-
- async disconnect(){
- let killServer = await this.exec_adb(["kill-server"]);
- if(killServer.err){
- if(killServer.data.indexOf("server not running") === -1){
- console.log("kill出錯啦~");
- console.log(killServer);
- scanf("%d");
- return "err";
- }
- }
- }
-
- /**
- * 停止toram跟cloneApp 的App
- */
- async close_toram(titleName){
- let device = this.title_to_device_table[titleName];
- if(device === undefined) return {err: "noThis"};
- // for(let i=0; i < this.devices_count;i++){
- // let status = await this.exec_adb( ["-s", this.devices_list[i] ,"shell","dumpsys activity | grep top-activity"] );
- let status = await this.exec_adb( ["-s", "127.0.0.1:" + device ,"shell","am","force-stop","com.asobimo.toramonline"] );
- status = await this.exec_adb( ["-s", "127.0.0.1:" + device ,"shell","am","force-stop","com.zhuowang.cloneapp"] );
-
- return {};
- // }
- // this.nox_cmd.run_app("com.zhuowang.cloneapp:platform.gameplugin.P00");
- // this.nox_cmd.run_app();
- }
- }
-
- module.exports = adb_ctrl;
-
- // let aa = new adb_ctrl({
- // nox_path: "F:/Nox",
- // open_count: 1,
- // });
-
- // let atkArr = [];
- // for(let i=1;i< 3;i++){
- // atkArr[atkArr.length] = "atk0" + i;
- // }
-
- // async function yee(gtadb){
- // // await gtadb.adb_init.call(gtadb);
- // await gtadb.connect();
-
- // await gtadb.close_toram("atk01");
- // await gtadb.close_toram("atk02");
- // }
-
- // yee(aa);
|