/** @format */ const gulp = require('gulp') const del = require('del') const shell = require('gulp-shell') const replace = require('gulp-replace') const fs = require('fs') const zip = require('gulp-zip') const path = require('path') const Sftp = require('ssh2-sftp-client') const https = require('https') const minimist = require('minimist') const GulpSSH = require('gulp-ssh') //操作pipe中文件的路径 const vinylPaths = require('vinyl-paths') //重命名文件 const rename = require('gulp-rename') // 配置 const knownOptions = { string: 'version', string: 'cocosPath', string: 'buildPath', string: 'debugBool', string: 'releaseBool', string: 'h5RemoteUrl', string: 'configUrl', string: 'packageName', string: 'keystorePath', string: 'isQQ', string: 'isTT', string: 'appid', string: 'appType', string: 'gameType', string: 'channel', default: { version: '1', cocosPath: 'D:/CocosEditors/Creator/2.4.12/CocosCreator.exe', buildPath: './build', debugBool: 'false', releaseBool: 'false', h5RemoteUrl: '/www/wwwroot/b22_client_h5_dev/', configUrl: '', packageName: 'com.company', autoCompile: 'false', keystorePath: 'D:/black_art.jks', appid: 'wx7a1fbe2f424a93b4', isQQ: 'false', isTT: 'false', appType: 1, gameType: 1, channel: '', }, } const options = minimist(process.argv.slice(2), knownOptions) const resServerConfig = { host: options.debugBool == 'true' || options.releaseBool == 'true' ? '47.107.63.156' : '47.107.63.156', port: 22, username: 'root', privateKey: fs.existsSync('D:\\cer\\id_rsa') ? fs.readFileSync('D:\\cer\\id_rsa') : null, } let getGulpSSH = (isTest = true) => { return new GulpSSH({ ignoreErrors: false, sshConfig: { host: isTest ? '43.139.94.120' : '43.139.94.120', port: 22, username: 'root', privateKey: fs.readFileSync('D:\\test_server_guangzhou.pem'), }, }) } const zipName = 'upload.zip' const testResUrl = '' const onlineResUrl = '' const localUploadUrl = path.join(options.buildPath, 'upload') const projectPath = 'D:\\b22_client' // shell let shellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=wechatgame;debug=${options.debugBool};"` let h5ShellTask = `${options.cocosPath} --path ./ --build "buildPath=${ options.buildPath };platform=web-mobile;embedWebDebugger=${options.debugBool == 'true' || options.releaseBool == 'true'};debug=${ options.debugBool };"` let IOSShellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=ios;template=link;debug=${options.debugBool};"` let AndroidShellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=android;template=link;debug=${options.debugBool};autoCompile=${options.autoCompile};useDebugKeystore=false;keystorePath=${options.keystorePath};keystorePassword=123456;keystoreAlias=key0;keystoreAliasPassword=123456;apiLevel=android-33;appABIs=['armeabi-v7a','arm64-v8a','x86','x86_64'];packageName=${options.packageName};md5Cache=false;"` let wxsubshellTask = `${options.cocosPath} --path ./wx_sub --build "buildPath=./build/;platform=wechatgame-subcontext"` let TTShellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=bytedance;debug=${options.debugBool};mainIsRemote=true;"` let win32ShellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=win32;template=link;debug=${options.debugBool};md5Cache=false;"` // 文件修改 gulp.task('copy:Regular', () => gulp .src('./assets/script/data/ConstValue.ts') .pipe(replace('DEBUG = true', 'DEBUG = ' + options.debugBool)) .pipe(replace('DEBUG = false', 'DEBUG = ' + options.debugBool)) .pipe(gulp.dest('./assets/script/data')), ) gulp.task('copy:index', () => gulp .src('./build-templates/web-mobile/index.html') .pipe( replace( '', ``, ), ) .pipe( replace( '', ``, ), ) .pipe(gulp.dest('./build-templates/web-mobile')), ) const updateJson = (jsonUrl, key, value, key2) => { const json = JSON.parse(fs.readFileSync(jsonUrl).toString()) if (key2) { json[key2][key] = value } else { json[key] = value } fs.writeFileSync(jsonUrl, JSON.stringify(json, '', ' ')) } gulp.task('copy:REMOTE_SERVER_ROOT', cb => { let url = options.debugBool == 'true' ? testResUrl : onlineResUrl url += options.isQQ == 'true' ? 'card-qq' : 'card-wx' updateJson('./settings/wechatgame.json', 'REMOTE_SERVER_ROOT', url) updateJson('./settings/wechatgame.json', 'appid', options.appid) updateJson('./settings/builder.json', 'REMOTE_SERVER_ROOT', url, 'wechatgame') updateJson('./settings/builder.json', 'appid', options.appid, 'wechatgame') cb() }) // 资源上传 const copy = (src, dst) => fs.writeFileSync(dst, fs.readFileSync(src)) const mkdirsSync = dirname => { if (fs.existsSync(dirname)) { return true } else if (mkdirsSync(path.dirname(dirname))) { fs.mkdirSync(dirname) return true } return false } const delDir = dirPath => { let files = [] if (fs.existsSync(dirPath)) { files = fs.readdirSync(dirPath) files.forEach(file => { const curPath = path.join(dirPath, file) if (fs.statSync(curPath).isDirectory()) { delDir(curPath) // 递归删除文件夹 } else { fs.unlinkSync(curPath) // 删除文件 } }) fs.rmdirSync(dirPath) } } const readFileList = (filePath, filesList = []) => { const files = fs.readdirSync(filePath) files.forEach(fileName => { const fullPath = path.join(filePath, fileName) if (fs.statSync(fullPath).isDirectory()) { readFileList(fullPath, filesList) // 递归读取文件 } else { filesList.push(fullPath) } }) return filesList } const readFileDirList = (filePath, filesList = []) => { const files = fs.readdirSync(filePath) files.forEach(fileName => { const fullPath = path.join(filePath, fileName) if (fs.statSync(fullPath).isDirectory()) { filesList.push(fullPath) readFileDirList(fullPath, filesList) // 递归读取文件夹 } }) return filesList } const curUpLoadResRecord = [] let UpLoadResRecordKeys = [] const UpLoadResRecordUrl = options.debugBool == 'true' ? './UpLoadResTestRecord.txt' : './UpLoadResRecord.txt' const uploadRes = (inputPath, platfrom) => { const files = readFileList(inputPath) if (!fs.existsSync(UpLoadResRecordUrl)) { fs.writeFileSync(UpLoadResRecordUrl, '', 'utf-8') } UpLoadResRecordKeys = fs.readFileSync(UpLoadResRecordUrl, 'utf-8').split('\r\n') UpLoadResRecordKeys = UpLoadResRecordKeys.filter(value => value != '') delDir(localUploadUrl) // 清空打包文件夹 mkdirsSync(localUploadUrl) // 建立打包文件夹 // 分析差异文件,拷贝到打包文件夹 for (let i = 0; i < files.length; i++) { if (UpLoadResRecordKeys.indexOf(files[i]) < 0 || files[i].indexOf('index.html') != -1) { const dist = files[i].replace(path.join(options.buildPath, platfrom), localUploadUrl) // console.log(i, files[i], dist); mkdirsSync(path.resolve(dist, '..')) // 确保拷贝前目录存在 if (fs.existsSync(files[i])) { copy(files[i], dist) } else { console.log(' uploadRes copy file:', files[i], 'no exist') } curUpLoadResRecord.push(files[i]) } } mkdirsSync(path.join(localUploadUrl, 'empty')) // 拷贝分享目录 /* const share = readFileList('./share'); for (let i = 0; i < share.length; i++) { const dist = path.join(localUploadUrl, share[i]); mkdirsSync(path.resolve(dist, '..')); // 确保拷贝前目录存在 copy(share[i], dist); } */ } gulp.task('copy:uploadRes', cb => { let platform = 'wechatgame' if (options.isTT == 'true') platform = 'bytedance' uploadRes(`${options.buildPath}/${platform}/remote/`, platform) cb() }) gulp.task('copy:uploadResH5', cb => { uploadRes(`${options.buildPath}/web-mobile/`, 'web-mobile') cb() }) gulp.task('Zip', () => gulp.src(`${localUploadUrl}/**/*`).pipe(zip(zipName)).pipe(gulp.dest(localUploadUrl))) let preTime = 0 let curByte = 0 const ftpUpload = (cb, remoteUrl) => { let sftp = new Sftp() sftp.connect(resServerConfig) .then(() => { console.log( 'sftp连接成功,上传中... ', zipName, 'localUploadUrl-->', path.join(localUploadUrl, zipName), 'remoteUrl--->', `${remoteUrl}${zipName}`, ) return sftp.fastPut(path.join(localUploadUrl, zipName), `${remoteUrl}${zipName}`, { step: (cur, chunk, total) => { if (preTime == 0) { preTime = Date.now() curByte = cur } const stepTime = Date.now() - preTime if (stepTime > 1000) { preTime = Date.now() const stepByte = cur - curByte console.log(((cur / total) * 100).toFixed(2), '% ', (stepByte / 1024).toFixed(2), 'kb/s') curByte = cur } }, }) }) .then(() => { console.log('上传完成!') cb() }) .catch(err => { console.log('sftp报错', err) }) .finally(data => { console.log('sftpfinally', data) sftp.end() }) } let unZipSucc = true let getDeleteJsonList = function (path, list) { let files = fs.readdirSync(path) files.forEach(item => { let stat = fs.statSync(path + item) if (stat.isDirectory()) { getDeleteJsonList(path + item + '/', list) } else if (stat.size > 0 * 1024) { list.push(path + item) } }) return list } gulp.task('clean:res', cb => { let platform = 'wechatgame' if (options.isTT == 'true') platform = 'bytedance' let list = [] let path = `${options.buildPath}/${platform}/remote/` getDeleteJsonList(path, list) console.log(list) del.sync(list, {force: true, allowEmpty: true}) cb() }) gulp.task('updateUploadUrl', cb => { if (unZipSucc) { let apendStr = '' for (let i = 0; i < curUpLoadResRecord.length; i++) { apendStr += `${curUpLoadResRecord[i]}\r\n` } fs.appendFileSync(UpLoadResRecordUrl, apendStr, 'utf-8') } else { console.log('远程解压缩失败') } cb() }) gulp.task('clearUpdateUploadUrl', cb => { fs.writeFileSync('./UpLoadResTestRecord.txt', '', 'utf-8') fs.writeFileSync('./UpLoadResRecord.txt', '', 'utf-8') cb() }) let getRemoteUrl = () => { let url = '' return url } gulp.task('SFTP', cb => ftpUpload(cb, getRemoteUrl())) gulp.task('H5SFTP', cb => ftpUpload(cb, options.h5RemoteUrl)) gulp.task('UnZip', cb => { cb() // return getGulpSSH() // .shell(['cd ' + options.h5RemoteUrl, 'unzip -Co upload.zip -d ./']) }) gulp.task('uploadQiniu', shell.task(`java -DwebRoot=${localUploadUrl} -DdirPath=${localUploadUrl} -jar qiniu.jar`)) gulp.task('uploadResContinueH5', gulp.series('copy:uploadResH5', 'Zip', 'updateUploadUrl')) gulp.task('uploadResContinueH5qiniu', gulp.series('copy:uploadResH5', 'uploadQiniu', 'updateUploadUrl')) gulp.task('uploadResContinue', gulp.series('copy:uploadRes', 'Zip', 'SFTP', 'UnZip', 'clean:res', 'updateUploadUrl')) Date.prototype.Format = function (fmt) { let o = { 'Y+': this.getFullYear(), // 年 'M+': this.getMonth() + 1, // 月份 'd+': this.getDate(), // 日 'h+': this.getHours(), // 小时 'm+': this.getMinutes(), // 分 's+': this.getSeconds(), // 秒 'q+': Math.floor((this.getMonth() + 3) / 3), // 季度 'S+': this.getMilliseconds(), // 毫秒 } if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, `${this.getFullYear()}`.substr(4 - RegExp.$1.length)) for (let k in o) if (new RegExp(`(${k})`).test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : `00${o[k]}`.substr(`${o[k]}`.length)) return fmt } gulp.task('version', () => { let filePath = './assets/resources/version.json' let obj = {} obj.time = new Date().Format('YYMMddhhmmss') obj.appType = options.appType obj.gameType = options.gameType fs.writeFileSync(filePath, JSON.stringify(obj)) return gulp .src('./build-templates/jsb-link/main.js') .pipe(replace(/window\._game_res_version = \'\d{12}\'/g, `window._game_res_version = \'${obj.time}\'`)) .pipe(gulp.dest('./build-templates/jsb-link/')) }) gulp.task( 'wxsub', gulp.series( /*'compile-wxsub','copywxsub'*/ cb => { cb() }, ), ) gulp.task('copywxsub', () => gulp.src('./wx_sub/build/**/*').pipe(gulp.dest(`${options.buildPath}/wechatgame`))) gulp.task('compile-wxsub', shell.task(wxsubshellTask)) gulp.task( 'WX', gulp.series('version', 'copy:Regular', 'copy:REMOTE_SERVER_ROOT', shell.task(shellTask), 'uploadResContinue'), ) gulp.task('H5', gulp.series('version', 'copy:Regular', 'copy:index', shell.task(h5ShellTask), 'uploadResContinueH5')) gulp.task( 'H5qiniu', gulp.series('version', 'copy:Regular', 'copy:index', shell.task(h5ShellTask), 'uploadResContinueH5qiniu'), ) gulp.task('IOS', gulp.series('version', 'copy:Regular', shell.task(IOSShellTask))) gulp.task('Android', gulp.series('version', 'copy:Regular', shell.task(AndroidShellTask))) gulp.task('TT', gulp.series('version', 'copy:Regular', shell.task(TTShellTask), 'uploadResContinue')) gulp.task('win32', gulp.series('version', 'copy:Regular', shell.task(win32ShellTask))) const {URL} = require('url') const cwd = process.cwd() const root = cwd ;(exts = ['.jpg', '.png']), (max = 5200000) // 5MB == 5242848.754299136 const tinypngoptions = { method: 'POST', hostname: 'tinypng.com', path: '/web/shrink', headers: { rejectUnauthorized: false, 'Postman-Token': Date.now(), 'Cache-Control': 'no-cache', 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', }, } // 生成随机IP, 赋值给 X-Forwarded-For function getRandomIP() { return Array.from(Array(4)) .map(() => parseInt(Math.random() * 255)) .join('.') } let allUploadFiles = [] let allSuccessUploadFiles = new Map() let curAllUploadCount = 0 let maxReq = 500 let fileUploadIDs = new Map() let tinyPngRecords = new Map() // 获取文件列表 function fileList(folder) { let files = fs.readdirSync(folder) files.forEach(file1 => { let file = path.join(folder, file1) let stats = fs.statSync(file) if ( // 必须是文件,小于5MB,后缀 jpg||png stats.size <= max && stats.isFile() && exts.includes(path.extname(file)) ) { // 通过 X-Forwarded-For 头部伪造客户端IP console.log('可以压缩:' + file) allUploadFiles.push(file) } if (stats.isDirectory()) fileList(file + '/') }) } let crypto = require('crypto') function MD5(img) { let buffer = fs.readFileSync(img) let fsHash = crypto.createHash('md5') fsHash.update(buffer) return fsHash.digest('hex') } function popUploadFiles(cb) { for (let i = 0; i < maxReq; i++) { let file = allUploadFiles.pop() if (file) { let hasRecord = false let recordData = tinyPngRecords.get(file) if (recordData && recordData == MD5(path.join(cwd, file))) { hasRecord = true } if (hasRecord) { allSuccessUploadFiles.set(file, true) if (allSuccessUploadFiles.size == curAllUploadCount) { cb() } else { let curCount = allSuccessUploadFiles.size if (curCount % maxReq == 0) popUploadFiles(cb) console.log('当前总进度:', allSuccessUploadFiles.size, '/', curAllUploadCount) } } else { fileUpload(file, cb) } } } } // 过滤文件格式,返回所有jpg,png图片 function fileFilter(file) { // fs.stat(file, (err, stats) => { // if (err) return console.error(err); // // }); } // 异步API,压缩图片 // {"error":"Bad request","message":"Request is invalid"} // {"input": { "size": 887, "type": "image/png" },"output": { "size": 785, "type": "image/png", "width": 81, "height": 81, "ratio": 0.885, "url": "https://tinypng.com/web/output/7aztz90nq5p9545zch8gjzqg5ubdatd6" }} function fileUpload(img, cb) { tinypngoptions.headers['X-Forwarded-For'] = getRandomIP() let fileUploadID = fileUploadIDs.get(img) if (fileUploadID) clearTimeout(fileUploadID) var req = https.request(tinypngoptions, function (res) { res.on('data', buf => { try { let obj = JSON.parse(buf.toString()) if (obj.error) { console.log(`[${img}]:压缩失败!报错:${obj.message}`) } fileUpdate(img, obj, cb) } catch (e) { } }) }) req.write(fs.readFileSync(img), 'binary') req.on('error', e => { console.error('fileUpload error:', e) }) req.end() fileUploadID = setTimeout(() => { req.destroy() fileUpload(img, cb) }, 10000) fileUploadIDs.set(img, fileUploadID) } // 该方法被循环调用,请求图片数据 function fileUpdate(imgpath, obj, cb, index) { const outputDir = path.join(cwd, '') let img = imgpath imgpath = path.join(cwd, '', imgpath.replace(cwd, '')) if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir) } let options = new URL(obj.output.url) let req = https.request(options, res => { let body = '' res.setEncoding('binary') res.on('data', function (data) { body += data }) res.on('end', function () { fs.writeFile(imgpath, body, 'binary', err => { if (err) console.error(err) console.log( `[${imgpath}] \n 压缩成功,原始大小-${obj.input.size},压缩大小-${obj.output.size},优化比例-${obj.output.ratio}`, ) // 替换文件md5或者新增 let recordData = tinyPngRecords.get(img) let fileMd5 = MD5(img) if (recordData) { let content = fs.readFileSync(tinyPngRecordUrl, 'utf-8') content.replace(img + '||' + recordData, img + '||' + fileMd5) fs.writeFileSync(tinyPngRecordUrl, content, 'utf-8') } else { let str = '\r\n' + img + '||' + fileMd5 fs.appendFileSync(tinyPngRecordUrl, str, 'utf-8') } let fileUploadID = fileUploadIDs.get(img) if (fileUploadID) clearTimeout(fileUploadID) allSuccessUploadFiles.set(img, true) if (allSuccessUploadFiles.size == curAllUploadCount) { cb() } else { let curCount = allSuccessUploadFiles.size if (curCount % maxReq == 0) popUploadFiles(cb) console.log('当前总进度:', allSuccessUploadFiles.size, '/', curAllUploadCount) } }) }) }) req.on('error', e => { console.error(e) }) req.end() } let tinyPngRecordUrl = './tinyPngRecordUrl.txt' gulp.task('tinypng', function (cb) { if (!fs.existsSync(tinyPngRecordUrl)) { fs.writeFileSync(tinyPngRecordUrl, '', 'utf-8') } let tinyPngRecordArr = fs.readFileSync(tinyPngRecordUrl, 'utf-8').split('\r\n') for (let i = 0; i < tinyPngRecordArr.length; i++) { let obj = tinyPngRecordArr[i].split('||') tinyPngRecords.set(obj[0], obj[1]) } fileList('./assets') curAllUploadCount = allUploadFiles.length console.log('tinypng curAllUploadCount:', curAllUploadCount) popUploadFiles(cb) }) let qiniu = require('qiniu') let qiniuJS = require('qiniu-js') var accessKey = 'AnddGCzvj0jyF4NxdRNhTo6EcnmN3ccOdbi03xVS' var secretKey = 'eR6wVv-CTunigvfxPxPrwTPPQARUud4O7us_PvRd' var mac = new qiniu.auth.digest.Mac(accessKey, secretKey) function uptoken(bucket, keyToOverwrite) { var options = { scope: bucket + ':' + keyToOverwrite, expires: 7200, } var putPolicy = new qiniu.rs.PutPolicy(options) var uploadToken = putPolicy.uploadToken(mac) return uploadToken } //构造上传函数 function qiniuUploadFile(localFile) { let key = localFile.replace(`${projectPath}/packages-hot-update/manifest/`, '') if (localFile.includes('build/jsb-link')) { key = localFile.replace(`${projectPath}/build/jsb-link/`, '') } key = 'hotupdate/' + key //生成上传 Token token = uptoken('zedu-cdn', key) let config = new qiniu.conf.Config() config.zone = qiniu.zone.Zone_z2 var formUploader = new qiniu.form_up.FormUploader(config) // 文件上传 formUploader.putFile(token, key, localFile, new qiniu.form_up.PutExtra(), function (respErr, respBody, respInfo) { if (respErr) { throw respErr } if (respInfo.statusCode == 200) { console.log('七牛上传成功:-------------》', respBody) } else { qiniuUploadFile(localFile) console.log('七牛上传失败:-------------》', respInfo) } }) } let upLoadHotAssets = {} const UpLoadHotUrl = './UpLoadHotResRecord.txt' const uploadHotRes = () => { let projectManifestUrl = `${projectPath}/packages-hot-update/manifest/project.manifest` let versionManifestUrl = `${projectPath}/packages-hot-update/manifest/version.manifest` let files = [] readFileList(`${projectPath}/build/jsb-link/assets`, files) readFileList(`${projectPath}/build/jsb-link/src`, files) if (!fs.existsSync(UpLoadHotUrl)) { fs.writeFileSync(UpLoadHotUrl, JSON.stringify({}), 'utf-8') } let curAssets = JSON.parse(fs.readFileSync(projectManifestUrl, 'utf-8')).assets upLoadHotAssets = JSON.parse(fs.readFileSync(UpLoadHotUrl, 'utf-8')) delDir(localUploadUrl) // 清空打包文件夹 mkdirsSync(localUploadUrl) // 建立打包文件夹 copy(projectManifestUrl, localUploadUrl + '\\project.manifest') copy(versionManifestUrl, localUploadUrl + '\\version.manifest') // 分析差异文件,拷贝到打包文件夹 for (let i = 0; i < files.length; i++) { let file = files[i] let srcKey = file.replace(`${projectPath}\\build\\jsb-link\\`, '').replace(new RegExp('\\\\', 'g'), '/') let resMd5 = upLoadHotAssets[srcKey] if (!resMd5 || curAssets[srcKey].md5 != resMd5) { const dist = file.replace(`${projectPath}\\build\\jsb-link`, localUploadUrl) mkdirsSync(path.resolve(dist, '..')) // 确保拷贝前目录存在 if (fs.existsSync(file)) { copy(file, dist) console.log(' uploadRes copy file:', files[i], dist) upLoadHotAssets[srcKey] = curAssets[srcKey].md5 } else { console.log(' uploadRes copy file:', file, 'no exist') } } } } gulp.task('updateHotUploadTxt', cb => { fs.writeFileSync(UpLoadHotUrl, JSON.stringify(upLoadHotAssets), 'utf-8') cb() }) gulp.task('QiniuHotFresh', cb => { var dirsToRefresh = ['https://cdn.black-art.cn/b22_hotupdate/'] var cdnManager = new qiniu.cdn.CdnManager(mac) //单次请求链接不可以超过10个,如果超过,请分批发送请求 cdnManager.refreshDirs(dirsToRefresh, function (err, respBody, respInfo) { if (err) { throw err } console.log(respInfo.statusCode) if (respInfo.statusCode == 200) { console.log(dirsToRefresh, '七牛cdn刷新成功') } }) cb() }) let bucketPathName = ['b22_hotupdate', 'b22_hotupdate'] gulp.task( 'uploadQiniuHot', shell.task( `java -DwebRoot=${localUploadUrl} -DdirPath=${localUploadUrl} -Dbucket=black-art-b22 -DbucketPath=${ bucketPathName[options.gameType] } -jar qiniu.jar`, ), ) gulp.task('copyUploadHot', cb => { uploadHotRes() cb() }) gulp.task('uploadHotUpdate', gulp.series('copyUploadHot', 'uploadQiniuHot', 'updateHotUploadTxt', 'QiniuHotFresh')) let semeWordPinyin = {} let semeStroke = {} const {pinyin} = require('pinyin-pro') gulp.task('excle2js', shell.task(` excel2x -i ${options.configUrl ? options.configUrl : 'D:\\b22_config'} -o ./assets/script/config -t ts_alone`)) gulp.task('updateConfig', gulp.series('excle2js')) gulp.task('copySpine', cb => { let desDir = 'D:\\b22_client\\assets\\texture\\Public\\role\\spine\\' let mainDir = 'D:\\b22_client\\assets\\texture\\MainUI\\spine\\' //delDir(desDir) if (!fs.existsSync(desDir)) { fs.mkdirSync(desDir) } let files = [] readFileDirList('D:\\b22_spine\\角色', files) readFileDirList('D:\\b22_spine\\怪物', files) //readFileDirList('D:\\b22_spine\\主场景', files) for (let i = 0; i < files.length; i++) { let file = files[i] if (file.includes('skelOutput')) { let spineFiles = [] readFileList(file, spineFiles) spineFiles.forEach((item) => { let des = file.includes('主场景') ? mainDir : desDir fs.copyFileSync(item, des + path.basename(item)) }) } } cb() }) gulp.task('exportSpine', cb => { let spineDir = 'D:\\b22_spine\\' let skelConfig = path.join(spineDir, 'export_skel_setting.json') let jsonConfig = path.join(spineDir, 'export_json_setting.json') let files = [] readFileList('D:\\b22_spine', files) let tasks = [] for (let i = 0; i < files.length; i++) { let file = files[i] if (file.includes('.spine')) { if (!fs.existsSync(`${path.dirname(file)}/skelOutput/`)) { fs.mkdirSync(`${path.dirname(file)}/skelOutput/`) } if (!fs.existsSync(`${path.dirname(file)}/jsonOutput/`)) { fs.mkdirSync(`${path.dirname(file)}/jsonOutput/`) } tasks.push(shell.task(`spine --input "${file}" --output "${path.dirname(file)}/skelOutput/" --export "${skelConfig}"`)) tasks.push(shell.task(`spine --input "${file}" --output "${path.dirname(file)}/jsonOutput/" --export "${jsonConfig}"`)) } } // 使用 gulp.series 执行所有命令 gulp.series(tasks)(cb) }) gulp.task('startinit', cb => { let filePath = './assets/resources/version.json' let obj = {} obj.time = new Date().Format('YYMMddhhmmss') obj.appType = 1 obj.gameType = 1 obj.channel = '' fs.writeFileSync(filePath, JSON.stringify(obj)) cb() })