/* * @Author: CGT (caogtaa@gmail.com) * @Date: 2020-01-16 22:08:55 * @Last Modified by: CGT (caogtaa@gmail.com) * @Last Modified time: 2020-01-16 22:08:55 */ const fs = require('fs'); const path = require('path'); function attachNode(node, parent, worldPos, callback) { // world position to relative position parent.addChild(node); node.position = parent.convertToNodeSpaceAR(worldPos); // todo: support undo if (callback) { callback(null, node); } } // load prefab by uuid, create instance under canvas or some parent node function insertNode(param, callback) { param = param || {worldX: 0, worldY: 0}; let worldPos = cc.v2(param.worldX, param.worldY); // todo: uniform param let parent = null; if (param.parentId) { // @ts-ignore parent = cc.engine.getInstanceById(param.parentId); } else if (param.parent) { // @ts-ignore parent = param.parent } else { // canvas can be renamed, should find cc.Canvas component in scene top level // parent = cc.find('Canvas'); let scene = cc.director.getScene(); for (let s of scene.children) { if (s.getComponent(cc.Canvas)) { parent = s; break; } } } if (!parent) { if (callback) callback('Canvas or parent node not found, cancel.', null); return; } if (param.uuid) { cc.loader.load( {uuid: param.uuid, type: 'uuid'}, null, function (error, prefab) { if (error) { Editor.log(error); if (callback) { callback(error, null); } return; } let node = cc.instantiate(prefab); attachNode(node, parent, worldPos, callback); } ); } else { let node = new cc.Node(); attachNode(node, parent, worldPos, callback); } } let gameType let semeID let gameID let partID let modeID let oldJson let wordCode let gameJson let typeArr = ['gameTest/', 'gameChild/', 'gameHome/', 'gameMath/', 'gamePass/', 'gameEndless/', 'gameChinese/', 'gameMathApp/', 'gamePoetry/', 'gamePinyin/'] let typeSemeArr = ['gameTestSeme/', 'gameChildSeme/', 'gameHomeSeme/', 'gameMathSeme/', 'gamePassSeme/', 'gameEndlessSeme/', 'gameChineseSeme/', 'gameMathAppSeme/', 'gamePoetrySeme/', 'gamePinyinSeme/'] function isEditor(event, param) { if (event && event.reply) { event.reply(null, 'Fine, thank you!'); } semeID = param.semeID gameID = param.gameID partID = param.partID modeID = param.modeID gameType = param.gameType wordCode = param.word ? param.word.charCodeAt(0).toString() : '' param.wordCode = wordCode let scene = cc.director.getScene(); let canvas let sceneName = scene.name for (let s of scene.children) { if (s.getComponent(cc.Canvas)) { canvas = s; break; } } if (sceneName != 'Editor' || !canvas) { event && event.reply('当前打开的场景不是Editor'); } param.editorLog = (data) => { Editor.log(data) } return {canvas, param} } // @ts-ignore module.exports = { 'create-node': function (event, param) { let selected = Editor.Selection.curSelection('node'); if (selected.length > 0) { param.parentId = selected[0]; } insertNode(param, (error, node) => { if (node) { // select new node Editor.Selection.select('node', node.uuid); // Editor.log(`'${node.name}' created`); } if (event.reply) { event.reply(error); } }); }, 'importGame': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') let stageArr = [semeID, gameID, partID] if (modeID == '0') { gameJson = FileHelper.getObjectFromFile(path.join(Editor.Project.path, '/assets/' + typeSemeArr[param.gameType] , addGameSGP('data_' + stageArr.join('_') + '.json', 3))) param.gameJson = gameJson } editor.clearNodes() let gamemode = ['', 'Drag', 'Select', 'Line', 'Maze', 'PageDrag', 'PageSelect', 'DrawImg', 'Show', 'PageShow', 'PageLine', 'Memory', 'EndlessSelect', 'Race', 'Couple', 'Hamster', 'WordMemory', 'PickUp'] let prefabUrl = 'db://assets/prefab/gameMode/' + gamemode[modeID == '0' ? gameJson.gameMode : parseInt(modeID)] + 'UI.prefab' let uuid = Editor.assetdb.remote.urlToUuid(prefabUrl) Editor.Ipc.sendToPanel('scene', 'scene:create-nodes-by-uuids', [uuid], cc.find('game', canvas)['_id'], (err) => { // if (err) return if (modeID > 0) return editor.initGameByJson(param) let node = cc.find('game', canvas).children[0] let urlKey = 'db://assets/' + typeSemeArr[param.gameType] + addGameSGP('', 3) let bgUrlKey = 'db://assets/' + typeSemeArr[param.gameType] + addGameSGP('', semeID % 100 == 0 || param.gameType == 7 ? 3 : 2) this.setSpriteByName(cc.find('bg', node), bgUrlKey, gameJson.bg) if (param.gameType == 9) { let bgTex = 'editBg' if (gameID == 100) { bgTex = 'testBg' } if (semeID == 300) { bgTex = 'readBg' } this.setSpriteByName(cc.find('bg', node), 'db://assets/gamePinyin/texture/Public/', bgTex) } else { this.setSpriteByName(cc.find('bg', node), bgUrlKey, gameJson.bg) } this.setSpriteByName(cc.find('title', node), urlKey, gameJson.bt) if (gameJson.bgNode) { for (let i = 0; i < gameJson.bgNode.length; i++) { let bgNode = cc.find('bgNode', node) if (bgNode) this.setSpriteByName(bgNode.children[i], urlKey, gameJson.bgNode[i].tex) } } if ([5, 6, 9, 10].includes(gameJson.gameMode)) { let page1 = cc.find('page/view/content/page1', node) let page2 = cc.find('page/view/content/page2', node) let page1Data = gameJson.node.filter(value => value.page == 1) let page2Data = gameJson.node.filter(value => value.page == 2) for (let i = 0; i < page1Data.length; i++) { this.setSpriteByName(page1.children[i], urlKey, page1Data[i].tex) } for (let i = 0; i < page2Data.length; i++) { this.setSpriteByName(page2.children[i], urlKey, page2Data[i].tex) } } else { for (let i = 0; i < gameJson.node.length; i++) { let gameNode = cc.find('gameNode', node) if (gameNode) { let spriteNode = gameNode.children[i] if (gameJson.gameMode == 4) { spriteNode = cc.find('sprite', gameNode.children[i]) } this.setSpriteByName(spriteNode, urlKey, gameJson.node[i].tex) } } } if (gameJson.answerNodes) { for (let i = 0; i < gameJson.answerNodes.length; i++) { let answerNode = cc.find('answer', node) if (answerNode) { for (let i = 0; i < answerNode.children.length; i++) { this.setSpriteByName(answerNode.children[i], urlKey, gameJson.answerNodes[i].tex) } } } } }, 1000) }, 'outGameJson': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') param.oldJson = gameJson let outJson = editor.outGameJson(param) this.writeOutJson(outJson, event, param) }, 'inBgAni': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') let yearID = semeID.substring(0, 2) let urlKey = 'db://assets/' + typeArr[param.gameType] + 'bgAni/' + yearID + '/' let getAniJonUrl = (ID) => { return path.join(Editor.Project.path, '/assets/' + typeArr[param.gameType] , 'bgAni', yearID, 'bgAni_' + ID + '_' + gameID + (param.gameType == 5 ? '_' + partID : '') + '.json') } let aniJson = FileHelper.getObjectFromFile(getAniJonUrl(yearID)) if (Object.keys(aniJson).length == 0) { aniJson = FileHelper.getObjectFromFile(getAniJonUrl(semeID)) } param.aniJson = aniJson editor.inBgAni(param) let bgNode = cc.find('game', canvas).children[0].getChildByName('bg') for (let key in aniJson) { let node = bgNode.getChildByName(key) let children = aniJson[key].children let initAniOrPar = (obj, node) => { if (obj.tex) this.setSpriteByName(node, urlKey, obj.tex) if (obj.ani) this.setAnimation(node, urlKey, obj.ani) if (obj.particle) this.setParticle(node, urlKey, obj.particle) } if (node) { initAniOrPar(aniJson[key], node) if (children) { for (let i = 0; i < children.length; i++) { initAniOrPar(children[i], node.children[i]) } } } } }, 'outBgAni': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') let outJson = editor.outBgAni(param) this.writeOutBgAniJson(outJson, event, param) }, 'saveGameJson': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let src = Editor.Project.path.replace('\\', '\/') + '/assets/' + typeSemeArr[param.gameType] + addGameSGP('', 3) let dst = Editor.Project.path.replace('\\', '\/') + '/gameRes/' + typeSemeArr[param.gameType] + addGameSGP('', 3) FileHelper.copyDir(src, dst) event.reply(null, '关卡保存成功'); Editor.log('关卡保存成功') }, 'writeOutJson': function (outJson, event, param) { let stageArr = [semeID, gameID, partID] let savePath = 'db://assets/' + typeSemeArr[param.gameType] + addGameSGP('data_' + stageArr.join('_') + '.json', 3) if (outJson.gameMode == 7) { outJson.drawPos = FileHelper.getObjectFromFile(Editor .url('packages://cc-ext-scene-menu/' + typeArr[param.gameType] + 'DrawImg/' + stageArr.join('_') + '.json') ) let errDrawPath = Editor .url('packages://cc-ext-scene-menu/' + typeArr[param.gameType] + 'DrawImg/' + stageArr.join('_') + '_e.json') if (fs.existsSync(errDrawPath)) { outJson.errDrawPos = FileHelper.getObjectFromFile(errDrawPath) } } fs.writeFileSync(path.join(Editor.Project.path, '/assets/' + typeSemeArr[param.gameType] , addGameSGP('data_' + stageArr.join('_') + '.json', 3)), JSON.stringify(outJson, null, 2)) if (!param.nofresh) { Editor.assetdb.refresh(savePath, (err, results) => { if (err) { event.reply('关卡导出失败'); } event.reply(null, '关卡导出成功'); }) } }, 'writeOutBgAniJson': function (outJson, event, param) { let yearID = semeID.substring(0, 2) let stageArr = [yearID, gameID] if (param.gameType == 5) { stageArr.push(partID) } if (param.gameType == 3 || param.gameType == 6) { stageArr[0] = semeID } let savePath = 'db://assets/' + typeArr[param.gameType] + 'bgAni/' + yearID + '/bgAni_' + stageArr.join('_') + '.json' fs.writeFileSync(path.join(Editor.Project.path, '/assets/' + typeArr[param.gameType] + 'bgAni/' , yearID, '/bgAni_' + stageArr.join('_') + '.json'), JSON.stringify(outJson, null, 2)) Editor.assetdb.refresh(savePath, (err, results) => { if (err) { event.reply('导出背景动画失败'); } event.reply(null, '导出导出背景动画成功'); }) }, 'guideImport': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') editor.clearNodes() let stageArr = [semeID, gameID] let urlLevel = 2 let guideUrl = path.join(Editor.Project.path, '/assets/' + typeSemeArr[param.gameType] , addGameSGP('guide/guide_' + stageArr.join('_') + '.json', urlLevel)) if (param.gameType == 6) { guideUrl = path.join(Editor.Project.path, '/assets/' + typeSemeArr[param.gameType] , wordCode, 'guide/guide_' + wordCode + '.json') } gameJson = FileHelper.getObjectFromFile(guideUrl) param.gameJson = gameJson let prefabUrl = 'db://assets/prefab/public/GuideUI.prefab' if (param.gameType == 6) { prefabUrl = 'db://assets/prefab/chinese/ChineseMainUI.prefab' } let uuid = Editor.assetdb.remote.urlToUuid(prefabUrl) Editor.Ipc.sendToPanel('scene', 'scene:create-nodes-by-uuids', [uuid], cc.find('game', canvas)['_id'], (err) => { // if (Object.keys(gameJson).length > 0) { editor.importGuide(param) let node = cc.find('game', canvas).children[0] if (param.gameType == 7) { let bgUrlKey = 'db://assets/' + typeSemeArr[param.gameType] + addGameSGP('', 2) + 'guide/' this.setSpriteByName(cc.find('bg', node), bgUrlKey, 'bg') } // } }, 1000) }, 'guideOut': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') let outJson = editor.outGuideJson(param) let stageArr = [semeID, gameID] let urlLevel = 2 let jsonUrl = path.join(Editor.Project.path, '/assets/' + typeSemeArr[param.gameType] , addGameSGP('guide/guide_' + stageArr.join('_') + '.json', urlLevel)) let savePath = 'db://assets/' + typeSemeArr[param.gameType] + addGameSGP('guide/guide_' + stageArr.join('_') + '.json', urlLevel) if (param.gameType == 6) { jsonUrl = path.join(Editor.Project.path, '/assets/' + typeSemeArr[param.gameType] , wordCode, '/guide/guide_' + wordCode + '.json') savePath = 'db://assets/' + typeSemeArr[param.gameType] + wordCode + '/' } FileHelper.mkDirsSync(path.dirname(jsonUrl)) fs.writeFileSync(jsonUrl, JSON.stringify(outJson, null, 2)) Editor.assetdb.refresh(savePath, (err, results) => { if (err) { event.reply('引导文件导出失败'); } event.reply(null, '引导文件导出成功'); }) }, 'savaGuide': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let urlLevel = 2 if (param.gameType == 6) { urlLevel = 3 } let assetsStartUrl = Editor.Project.path.replace('\\', '\/') + '/assets/' + typeSemeArr[param.gameType] let gameResStartUrl = Editor.Project.path.replace('\\', '\/') + '/gameRes/' + typeSemeArr[param.gameType] let getSrc = (key, level = 0) => { if (!level) level = urlLevel let src = assetsStartUrl + addGameSGP(key, level) return src } let getDst = (key, level = 0) => { if (!level) level = urlLevel let dst = gameResStartUrl + addGameSGP(key, level) return dst } if (param.gameType == 6) { FileHelper.copyDir(assetsStartUrl + wordCode + '/', gameResStartUrl + wordCode + '/') FileHelper.copyFile(assetsStartUrl + wordCode + '.meta', gameResStartUrl + wordCode + '.meta') } else { FileHelper.copyDir(getSrc('guide/'), getDst('guide/')) FileHelper.copyFile(getSrc('guide.meta'), getDst('guide.meta')) } event.reply(null, '引导文件保存成功'); Editor.log('引导文件保存成功') }, 'playGuide': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') editor.playGuide() }, 'playNodeGuide': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') editor.playNodeGuide() }, 'pauseGuide': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') editor.pauseGuide() }, 'resetGuide': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') editor.resetGuide() }, 'guidePageChange': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') editor.guideChangePage(param.guidePage) }, 'teacherImport': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') editor.clearNodes() let stageArr = [semeID, gameID] let urlLevel = 2 let teacherUrl = path.join(Editor.Project.path, '/assets/' + typeSemeArr[param.gameType] , addGameSGP('teacher/teacher_' + stageArr.join('_') + '.json', urlLevel)) gameJson = FileHelper.getObjectFromFile(teacherUrl) param.gameJson = gameJson let prefabUrl = 'db://assets/prefab/public/TeacherGuideUI.prefab' let uuid = Editor.assetdb.remote.urlToUuid(prefabUrl) Editor.Ipc.sendToPanel('scene', 'scene:create-nodes-by-uuids', [uuid], cc.find('game', canvas)['_id'], (err) => { // if (Object.keys(gameJson).length > 0) { editor.importTeacher(param) let node = cc.find('game', canvas).children[0] let urlKey = 'db://assets/' + typeSemeArr[param.gameType] + addGameSGP('', urlLevel) + '/teacher/' if (gameJson.bgNode) { for (let i = 0; i < gameJson.bgNode.length; i++) { let bgNode = cc.find('bgNode', node) if (bgNode) this.setSpriteByName(bgNode.children[i], urlKey, gameJson.bgNode[i].tex) } } for (let i = 0; i < gameJson.node.length; i++) { let gameNode = cc.find('gameNode', node) if (gameNode) { let spriteNode = gameNode.children[i] this.setSpriteByName(spriteNode, urlKey, gameJson.node[i].tex) } } // } }, 1000) }, 'teacherOut': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let editor = canvas.getComponent('Editor') let outJson = editor.outTeacherJson(param) let stageArr = [semeID, gameID] let urlLevel = 2 let jsonUrl = path.join(Editor.Project.path, '/assets/' + typeSemeArr[param.gameType] , addGameSGP('teacher/teacher_' + stageArr.join('_') + '.json', urlLevel)) let savePath = 'db://assets/' + typeSemeArr[param.gameType] + addGameSGP('teacher/teacher_' + stageArr.join('_') + '.json', urlLevel) FileHelper.mkDirsSync(path.dirname(jsonUrl)) fs.writeFileSync(jsonUrl, JSON.stringify(outJson, null, 2)) Editor.assetdb.refresh(savePath, (err, results) => { if (err) { event.reply('讲解文件导出失败'); } event.reply(null, '讲解文件导出成功'); }) }, 'savaTeacher': function (event, config) { let {canvas, param} = isEditor(event, config) if (!canvas) return let urlLevel = 2 let assetsStartUrl = Editor.Project.path.replace('\\', '\/') + '/assets/' + typeSemeArr[param.gameType] let gameResStartUrl = Editor.Project.path.replace('\\', '\/') + '/gameRes/' + typeSemeArr[param.gameType] let getSrc = (key, level = 0) => { if (!level) level = urlLevel let src = assetsStartUrl + addGameSGP(key, level) return src } let getDst = (key, level = 0) => { if (!level) level = urlLevel let dst = gameResStartUrl + addGameSGP(key, level) return dst } FileHelper.copyDir(getSrc('teacher/'), getDst('teacher/')) FileHelper.copyFile(getSrc('teacher.meta'), getDst('teacher.meta')) event.reply(null, '讲解文件保存成功'); Editor.log('讲解文件保存成功') }, 'setSpriteByName': function (node, urlKey, tex) { if (node && tex) { let uuid = Editor.assetdb.remote.urlToUuid(urlKey + tex + '.png/' + tex) if (uuid) { let data = { id: node.getComponent(cc.Sprite).uuid, path: "spriteFrame",//要修改的属性 type: "cc.SpriteFrame", value: {uuid: uuid}, isSubProp: false, } Editor.Ipc.sendToPanel('scene', 'scene:set-property', data); return true } } return true }, 'setAnimation': function (node, urlKey, ani) { if (node && ani) { let uuid = Editor.assetdb.remote.urlToUuid(urlKey + ani + '.anim') if (uuid) { let data = { id: node.getComponent(cc.Animation).uuid, path: "defaultClip",//要修改的属性 type: "cc.AnimationClip", value: {uuid: uuid}, isSubProp: false, } Editor.Ipc.sendToPanel('scene', 'scene:set-property', data); return true } } return true }, 'setParticle': function (node, urlKey, particle) { if (node && particle) { let uuid = Editor.assetdb.remote.urlToUuid(urlKey + particle + '.plist') if (uuid) { let data = { id: node.getComponent(cc.ParticleSystem).uuid, path: "file",//要修改的属性 type: "cc.ParticleAsset", value: {uuid: uuid}, isSubProp: false, } Editor.Ipc.sendToPanel('scene', 'scene:set-property', data); return true } } return true } } function addPreZero(num, length) { let numstr = num.toString() const l = numstr.length if (numstr.length >= length) { return numstr } for (let i = 0; i < length - l; i++) { numstr = `0${numstr}` } return numstr } function addGameSGP(data, level = 3) { let url = '' if (level >= 1) { url = url + 'S' + semeID + '/' // 是否包含S(课程) } if (level >= 2) { if (gameID) { url = url + 'G' + Math.addPreZero(gameID, 2) + '/' // 是否包含G(游戏) } } if (level >= 3) { if (partID) { url = url + 'P' + Math.addPreZero(partID, 2) + '/' // 是否包含P(关卡) } } return url + data } let FileHelper = { // 输出到文件 writeFile(fullPath, content) { if (!fullPath || !content) { Editor.error('writeFile: invalid params'); return; } fs.writeFile(fullPath, content, (err) => { if (err) { Editor.error(err); return; } Editor.log('Success to write file: ' + fullPath); }); }, // 返回文件内容的json对象 getObjectFromFile(fullPath) { let retObj = {}; if (!fs.existsSync(fullPath)) { Editor.warn('getObjectFromFile: NoExist path=' + fullPath); return retObj; } let str = this.getFileString(fullPath); if (!str) { Editor.warn('getObjectFromFile: invalid file=' + fullPath); return retObj; } retObj = JSON.parse(str); if (!retObj) { Editor.warn('getObjectFromFile: invalid object=' + fullPath); return retObj; } return retObj; }, // 返回文件内容的字符串形式 getFileString(fullPath) { if (fs.existsSync(fullPath)) { return fs.readFileSync(fullPath).toString(); } else { return undefined } }, copyFile(src, dst) { fs.writeFileSync(dst, fs.readFileSync(src)) }, mkDirsSync(dirname) { if (fs.existsSync(dirname)) { return true; } else if (this.mkDirsSync(path.dirname(dirname))) { fs.mkdirSync(dirname); return true; } return false; }, 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()) { this.delDir(curPath); // 递归删除文件夹 } else { fs.unlinkSync(curPath); // 删除文件 } }); fs.rmdirSync(dirPath); } }, copyDir(srcPath, dstPath) { this.delDir(dstPath) this.mkDirsSync(dstPath) let files = fs.readdirSync(srcPath) if (files) { files.forEach((file) => { if (fs.statSync(srcPath + file).isDirectory()) { this.copyDir(srcPath + file + '/', dstPath + file + '/') } else { this.copyFile(srcPath + file, dstPath + file) } }) } } };