'use strict'; var configFileUrl = '\\packages\\hotupdate\\config.json'; var configFileUrl_test = '\\packages\\hotupdate\\config_test.json'; //版本控制变量 var versions = { }; //测试版 版本控制变量 var versions_test = { hall: '1', //大厅版本 Rummy: '1', // TeenPatti: '1', // //brnn:'1', // }; var url_subs_test = [ "assets/", "games/Rummy/", "games/TeenPatti/", "games/brnn/", ]; //版本控制变量 var versions_official = { hall: '1', //大厅版本 Rummy: '1', // TeenPatti: '1', // //brnn:'1' // }; var url_subs_official = [ "assets/", "games/Rummy/", "games/TeenPatti/", "games/brnn/", ]; //var url_head = 'http://yd-files.teenpattiplayer.com/IndiaGame/update/'; var url_head = 'http://d2ovxx8ky9h1zv.cloudfront.net/IndiaGame/update2/'; var url_head_test = 'https://ddjjzs.oss-cn-shenzhen.aliyuncs.com/update/ddjj_test/'; var url_subs = [ ]; //以filter-开头的文件夹作为打包大厅时的一个过滤条件 var packfliter = [ "filter-RUMMY", //Rummy "filter-DSP", //TeenPatti "filter-BRNN", //百人牛牛 ]; var autopack = false; //构建完成自动打包 var packType = -1; //打包类型:-1-大厅,0-捕鱼,1-拼十,2-五子棋,3-百人捞腌菜 var isTest = false; var dest = '/assets/'; var src = '/'; // var buildstring = '/build/jsb-link/'; var buildstring = '\\build\\jsb-link\\'; var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); var manifest = { packageUrl: '', remoteManifestUrl: '', remoteVersionUrl: '', version: '1.0.0', assets: {}, searchPaths: [] }; function readDir(srcpath, dir, obj) { if (!fs.existsSync(dir)) return; var stat = fs.statSync(dir); if (!stat.isDirectory()) { return; } var subpaths = fs.readdirSync(dir), subpath, size, md5, compressed, relative; for (var i = 0; i < subpaths.length; ++i) { if (subpaths[i][0] === '.') { continue; } subpath = path.join(dir, subpaths[i]); stat = fs.statSync(subpath); if (stat.isDirectory()) { readDir(srcpath, subpath, obj); } else if (stat.isFile()) { //跳过project.manifest if (path.basename(subpath).toLowerCase() === 'a8e36a08-ebce-47a1-8686-75b4bdc97058.manifest' || path.basename(subpath).toLowerCase() === 'ba6a908e-9b09-4d66-842f-a105cb3e59ea.json') continue; //过滤文件 var basenames = path.basename(subpath).split('.') if (basenames[0].length > 30) { var urlname = Editor.assetdb.uuidToUrl(basenames[0]) Editor.log(basenames[0] + "--" + urlname); //打包大厅 if (packType < 0) { //过滤掉需要排除的文件 if (urlname.indexOf('filter-') >= 0) { Editor.log('需要删除:' + subpath + ' url:' + urlname); //删除该文件 fs.unlink(subpath, function (error) { if (error) { console.log(error); return false; } Editor.log('成功删除!'); }) continue; } } } // Size in Bytes size = stat['size']; //md5 = crypto.createHash('md5').update(fs.readFileSync(subpath, 'binary')).digest('hex'); //这里fs.readFileSycn(subpath,"binary")返回的并非二进制类型,而是String。这会导致非文本文件md5计算错误。 md5 = crypto.createHash('md5').update(fs.readFileSync(subpath)).digest('hex'); compressed = path.extname(subpath).toLowerCase() === '.zip'; relative = path.relative(srcpath, subpath); relative = relative.replace(/\\/g, '/'); relative = encodeURI(relative); obj[relative] = { 'size': size, 'md5': md5 }; if (compressed) { obj[relative].compressed = true; } } } } var mkdirSync = function (path) { try { fs.mkdirSync(path); } catch (e) { if (e.code != 'EEXIST') throw e; } } // 递归创建目录 function mkdirsSync(dirname) { if (fs.existsSync(dirname)) { return true; } else { if (mkdirsSync(path.dirname(dirname))) { fs.mkdirSync(dirname); return true; } } } //拷贝文件到指定目录,并重建目录结构 function copyFile(fromfile, topath) { var pos = fromfile.indexOf(buildstring); if (pos < 0) { Editor.log('路径有问题,拷贝失败:' + fromfile); return; } var startp = pos + buildstring.length; var subdir = fromfile.substring(startp); var tofilename = topath + subdir; Editor.log('#####copy:' + tofilename); mkdirsSync(path.dirname(tofilename)); fs.writeFileSync(tofilename, fs.readFileSync(fromfile)); } function copying(srcpath, destpath, type) { if (!fs.existsSync(srcpath)) return; var stat = fs.statSync(srcpath); if (!stat.isDirectory()) { return; } var subpaths = fs.readdirSync(srcpath), subpath; for (var i = 0; i < subpaths.length; ++i) { if (subpaths[i][0] === '.') { continue; } subpath = path.join(srcpath, subpaths[i]); stat = fs.statSync(subpath); if (stat.isDirectory()) { copying(subpath, destpath, type); } else if (stat.isFile()) { //解析文件 var basenames = path.basename(subpath).split('.') var urlname = Editor.assetdb.uuidToUrl(basenames[0]) if (urlname != null) { //查找匹配的文件 if (urlname.indexOf(packfliter[packType]) >= 0) { Editor.log('需要拷贝:' + subpath + ' url:' + urlname); //拷贝该文件 copyFile(subpath, destpath); } } } } } function packing(srcpath, destpath, ver, type) { //版本覆盖 manifest.version = ver; manifest.assets = {}; manifest.searchPaths = []; packType = type; var profilename = 'project.manifest'; var versionename = 'version.manifest'; manifest.packageUrl = url_head + url_subs[packType + 1]; if (isTest) { manifest.packageUrl = url_head_test + url_subs[packType + 1]; } manifest.remoteManifestUrl = manifest.packageUrl + profilename; manifest.remoteVersionUrl = manifest.packageUrl + versionename; // Iterate res and src folder readDir(srcpath, path.join(srcpath, 'src'), manifest.assets); readDir(srcpath, path.join(srcpath, 'assets'), manifest.assets); var destManifest = path.join(destpath, profilename); var destVersion = path.join(destpath, versionename); mkdirSync(destpath); fs.writeFile(destManifest, JSON.stringify(manifest), (err) => { if (err) throw err; Editor.log('Manifest successfully generated'); }); //替换到assets/resources/native/a8/a8e36a08-ebce-47a1-8686-75b4bdc97058.manifest //需要注意:打包后的文件名变化情况 if (type < 0) { var packMainfest = srcpath + 'assets/resources/native/a8/a8e36a08-ebce-47a1-8686-75b4bdc97058.manifest'; fs.writeFile(packMainfest, JSON.stringify(manifest), (err) => { if (err) throw err; Editor.log('a8e36a08-ebce-47a1-8686-75b4bdc97058.manifest successfully replaced'); }); } delete manifest.assets; delete manifest.searchPaths; fs.writeFile(destVersion, JSON.stringify(manifest), (err) => { if (err) throw err; Editor.log('Version successfully generated'); }); } function onBuildFinish(options, callback) { if (!autopack) { Editor.log('已关闭自动打包'); } else { Editor.log('Building ' + options.platform + ' to ' + options.dest); // Editor.log(JSON.stringify(options)); src = options.dest + "/"; dest = options.dest + '/pack_assets_' + versions.hall + '/'; packing(src, dest, versions.hall, -1); } callback(); } function initConfig() { //test { let filePathUrl = Editor.Project.path + configFileUrl_test; if (fs.existsSync(filePathUrl)) { fs.readFile(filePathUrl, 'utf-8', function (err, data) { if (!err) { let saveData = JSON.parse(data.toString()); versions_test = saveData; } }.bind(this)); } else { let stringData = JSON.stringify(versions_test, null, '\t') fs.writeFileSync(filePathUrl, stringData); Editor.log("配置不存在文件,已自动创建"); } } //official { let filePathUrl = Editor.Project.path + configFileUrl; if (fs.existsSync(filePathUrl)) { fs.readFile(filePathUrl, 'utf-8', function (err, data) { if (!err) { let saveData = JSON.parse(data.toString()); versions_official = saveData; } }.bind(this)); } else { let stringData = JSON.stringify(versions_official, null, '\t') fs.writeFileSync(filePathUrl, stringData); Editor.log("配置不存在文件,已自动创建"); } } } function saveConfig() { let filePathUrl = Editor.Project.path + configFileUrl if (isTest) { filePathUrl = Editor.Project.path + configFileUrl_test; } fs.writeFile(filePathUrl, JSON.stringify(versions), function (error) { if (!error) { Editor.log("保存配置成功"); } }.bind(this)); } var inject_script = ` (function () { if (typeof window.jsb === 'object') { var hotUpdateSearchPaths = localStorage.getItem('HotUpdateSearchPaths'); if (hotUpdateSearchPaths) { var paths = JSON.parse(hotUpdateSearchPaths); jsb.fileUtils.setSearchPaths(paths); var fileList = []; var storagePath = paths[0] || ''; var tempPath = storagePath + '_temp/'; var baseOffset = tempPath.length; if (jsb.fileUtils.isDirectoryExist(tempPath) && !jsb.fileUtils.isFileExist(tempPath + 'project.manifest.temp')) { jsb.fileUtils.listFilesRecursively(tempPath, fileList); fileList.forEach(srcPath => { var relativePath = srcPath.substr(baseOffset); var dstPath = storagePath + relativePath; if (srcPath[srcPath.length] == '/') { cc.fileUtils.createDirectory(dstPath) } else { if (cc.fileUtils.isFileExist(dstPath)) { cc.fileUtils.removeFile(dstPath) } cc.fileUtils.renameFile(srcPath, dstPath); } }) cc.fileUtils.removeDirectory(tempPath); } } } })(); `; function writeMainJs() { var url = Editor.Project.path + buildstring + "main.js"; Editor.log(url) if (fs.existsSync(url)) { fs.readFile(url, 'utf-8', function (err, data) { if (err) { Editor.log(err); throw err; } var newStr = inject_script + data; fs.writeFile(url, newStr, function (err) { if (err) { Editor.log(err); throw err; } Editor.log("SearchPath updated in built main.js for hot update"); }); }); } } module.exports = { load() { // execute when package loaded //Editor.Builder.on('build-start', onStartBuild); // Editor.Builder.on('before-change-files', onBeforeBuildFinish); Editor.Builder.on('build-finished', onBuildFinish); }, unload() { // execute when package unloaded Editor.Builder.removeListener('build-finished', onBuildFinish); }, // register your ipc messages here messages: { 'getverinfo'(event) { initConfig(); if (isTest) { versions = versions_test; url_subs = url_subs_test; } else { versions = versions_official; url_subs = url_subs_official; } Editor.log('hall version:' + versions.hall); Editor.log('Rummy version:' + versions.Rummy); Editor.log('TeenPatti version:' + versions.TeenPatti); Editor.log('brnn version:' + versions.brnn); Editor.log('istest value:' + isTest); event.reply(null, { HallVersion: versions.hall, RummyVersion: versions.Rummy, TeenPattiVersion: versions.TeenPatti, BrnnVersion: versions.brnn, auto: autopack, istest: isTest }); }, 'open'() { // open entry panel registered in package.json Editor.Panel.open('hotupdate'); Editor.Ipc.sendToPanel('hotupdate', 'hotupdate:open'); }, // 'gen-mainfest' () { // Editor.log('Hello World!'); // // send ipc message to panel // // Editor.Ipc.sendToPanel('hotupdate', 'hotupdate:hello'); // }, 'HallVersion'(event, version) { Editor.log('打包大厅,version:' + version); // Editor.log('Editor.Project.path:' + Editor.Project.path); packType = -1; //执行打包 versions.hall = version; src = Editor.Project.path + buildstring; dest = src + 'pack_assets_' + versions.hall + '/'; packing(src, dest, versions.hall, packType); saveConfig(); writeMainJs(); }, 'RummyVersion'(event, version) { Editor.log('打包子游戏:Rummy,version:' + version); //执行打包 packType = 0; versions.Rummy = version; src = Editor.Project.path + buildstring; dest = src + 'pack_game_Rummy_' + versions.Rummy + '/'; //执行打包过程 if (packfliter[packType] != null) { //【1】从src下拷贝出子游戏的相关资源 copying(path.join(src, 'assets'), dest, packType); //copying(path.join(src, 'src'), dest, packType); //【2】开始打包 packing(dest, dest, versions.Rummy, packType); } }, 'TeenPattiVersion'(event, version) { Editor.log('打包子游戏:TeenPatti,version:' + version); //执行打包 packType = 1; versions.TeenPatti = version; src = Editor.Project.path + buildstring; dest = src + 'pack_game_TeenPatti_' + versions.TeenPatti + '/'; //执行打包过程 if (packfliter[packType] != null) { //【1】从src下拷贝出子游戏的相关资源 copying(path.join(src, 'assets'), dest, packType); //copying(path.join(src, 'src'), dest, packType); //【2】开始打包 packing(dest, dest, versions.TeenPatti, packType); } }, 'BrnnVersion'(event, version) { Editor.log('打包子游戏:百人牛牛,version:' + version); //执行打包 packType = 2; versions.brnn = version; src = Editor.Project.path + buildstring + "assets"; dest = src + 'pack_game_brnn_' + versions.brnn + '/'; //执行打包过程 if (packfliter[packType] != null) { //【1】从src下拷贝出子游戏的相关资源 copying(path.join(src, 'assets'), dest, packType); //copying(path.join(src, 'src'), dest, packType); //【2】开始打包 packing(dest, dest, versions.brnn, packType); } }, 'changeauto'(event, checked) { autopack = checked; if (autopack) Editor.log('已开启自动打包'); else Editor.log('已关闭自动打包'); }, 'settest'(event, checked) { Editor.log('+++++++++++++++++++++++++++++++++++++++++++++++'); isTest = checked; if (isTest) { versions = versions_test; url_subs = url_subs_test; Editor.log('目前在打正式包'); } else { versions = versions_official; url_subs = url_subs_official; Editor.log('目前在打测试包'); } } }, };