123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- import {existsSync, readFile, readFileSync, writeFileSync} from 'fs-extra';
- import path, {join} from 'path';
- import {exists} from "fs";
- let currentUuid: string = '';
- let currentName: string = '';
- let scriptPath: string = 'db://assets/script/'
- let savePath: string = scriptPath + 'fsm/'
- /**
- * @zh 如果希望兼容 3.3 之前的版本可以使用下方的代码
- * @en You can add the code below if you want compatibility with versions prior to 3.3
- */
- // Editor.Panel.define = Editor.Panel.define || function(options: any) { return options }
- module.exports = Editor.Panel.define({
- listeners: {
- show() {
- },
- hide() {
- },
- },
- template: readFileSync(join(__dirname, '../../../static/template/default/index.html'), 'utf-8'),
- style: readFileSync(join(__dirname, '../../../static/style/default/index.css'), 'utf-8'),
- $: {
- iframe: '#iframe',
- },
- methods: {
- async import() {
- let self = this
- let path = await Editor.Message.request('asset-db', 'query-path', savePath);
- if (!path) {
- return
- }
- //Editor.log(defaultPath);
- Editor.Dialog.select({
- title: "提示 : 聚焦资源管理器中fsm目录下的状态机代码可以快速导入状态机",
- path: path,
- filters: [
- {name: 'fsm', extensions: ["ts"]}
- ],
- }).then(async (args) => {
- if (args?.filePaths && args.filePaths.length > 0) {
- let fspath = args.filePaths[0];
- let uuid = await Editor.Message.request('asset-db', 'query-uuid', fspath);
- checkAndLoadFsm(self.$.iframe, uuid, fspath, () => {
- Editor.Dialog.error("导入的文件不是状态机代码");
- });
- }
- });
- },
- async checkSameName(args: any) {
- let fileName = args.className + ".ts";
- let filePath = await Editor.Message.request('asset-db', 'query-path', savePath + fileName);
- let isFileExists = existsSync(filePath as string);
- this.$.iframe.contentWindow.postMessage({
- message: "export-callback",
- data: {isFileExists, className: args.className}
- }, '*');
- },
- panelClose() {
- currentName = '';
- currentUuid = '';
- },
- reset() {
- currentName = '';
- currentUuid = '';
- },
- save(args: any) {
- let self = this
- let preClassName = null;
- if (args.isExport) {
- preClassName = args.className;
- } else {
- if (currentName && currentUuid) {
- preClassName = currentName.split(".")[0];
- } else {
- //todo 加锁
- self.$.iframe.contentWindow.postMessage({
- message: "save-callback",
- data: {error: true}
- }, '*');
- return;
- }
- }
- //Editor.log("isExport",args.isExport);
- let modelAsObj = args.model;
- let nodeDataArray = modelAsObj.nodeDataArray;
- let linkDataArray = modelAsObj.linkDataArray;
- let keyToNodeDataArray = [];
- let initial = "";
- let events = [];
- let callbacks: any = {};
- let stateNameInterface = [];
- let uniqueStateNameArray = [];
- let eventNameInterface = [];
- let uniqueEventNameArray = [];
- let eventNameConfig = [];
- let stateNameConfig = [];
- let callbacksConfig = [];
- //let callbacksInterface = [];
- let triggersConfig = [];
- let uniqueCallbacksArray = [];
- let callbacksImplementConfig = [];
- for (let i = 0, l = nodeDataArray.length; i < l; i++) {
- keyToNodeDataArray[nodeDataArray[i].key] = nodeDataArray[i];
- if (nodeDataArray[i].isInit) {
- initial = nodeDataArray[i].text;
- }
- let stateName = nodeDataArray[i].text;
- let localPreCallbacks = JSON.parse(nodeDataArray[i].callbacks).enter;
- if (!!localPreCallbacks.length) {
- let localPreCallbacksDecorators = localPreCallbacks.filter(filterForEmptyString).map(fsmCallbacksDecorator);
- callbacks[`onenter${stateName}`] = localPreCallbacksDecorators;
- }
- let localPostCallbacks = JSON.parse(nodeDataArray[i].callbacks).leave;
- if (!!localPostCallbacks.length) {
- let localPostCallbacksDecorators = localPostCallbacks.filter(filterForEmptyString).map(fsmCallbacksDecorator);
- callbacks[`onleave${stateName}`] = localPostCallbacksDecorators;
- }
- //stateNameInterface.push(`${stateName}:string`);
- //stateNameConfig.push(`${stateName}:"${stateName}"`);
- uniqueStateNameArray[stateName] = true;
- for (let i = 0, l = localPreCallbacks.length; i < l; i++) {
- let callbackName = localPreCallbacks[i];
- uniqueCallbacksArray[callbackName] = true;
- //callbacksConfig.push(`protected abstract ${callbackName}(eventName:string,from:string,to:string,...args:any[])`);
- }
- for (let i = 0, l = localPostCallbacks.length; i < l; i++) {
- let callbackName = localPostCallbacks[i];
- uniqueCallbacksArray[callbackName] = true;
- //callbacksConfig.push(`protected abstract ${callbackName}(eventName:string,from:string,to:string,...args:any[])`);
- }
- }
- for (let i = 0, l = linkDataArray.length; i < l; i++) {
- let name = linkDataArray[i].text || "event";
- let from = keyToNodeDataArray[linkDataArray[i].from].text;
- let to = keyToNodeDataArray[linkDataArray[i].to].text;
- events.push({name, from, to});
- let eventName = name;
- let localPreCallbacks = JSON.parse(linkDataArray[i].callbacks).before;
- if (!!localPreCallbacks.length) {
- let localPreCallbacksDecorators = localPreCallbacks.filter(filterForEmptyString).map(fsmCallbacksDecorator);
- let callbacksIdxName = `onbefore${eventName}`;
- if (callbacks[callbacksIdxName] === undefined) {
- callbacks[callbacksIdxName] = {};
- }
- callbacks[callbacksIdxName][from] = localPreCallbacksDecorators;
- }
- let localPostCallbacks = JSON.parse(linkDataArray[i].callbacks).after;
- if (!!localPostCallbacks.length) {
- let localPostCallbacksDecorators = localPostCallbacks.filter(filterForEmptyString).map(fsmCallbacksDecorator);
- //callbacks[`onafter${eventName}`] = localPostCallbacksDecorators;
- let callbacksIdxName = `onafter${eventName}`;
- if (callbacks[callbacksIdxName] === undefined) {
- callbacks[callbacksIdxName] = {};
- }
- callbacks[callbacksIdxName][from] = localPostCallbacksDecorators;
- }
- //eventNameInterface.push(`${eventName}:string`);
- //eventNameConfig.push(`${eventName}:"${eventName}"`);
- //triggersConfig.push(`public ${eventName}(...args:any[]): void {this.fsm["${eventName}"](...args);}`);
- uniqueEventNameArray[eventName] = true;
- for (let i = 0, l = localPreCallbacks.length; i < l; i++) {
- let callbackName = localPreCallbacks[i];
- uniqueCallbacksArray[callbackName] = true;
- //callbacksConfig.push(`protected abstract ${callbackName}(eventName:string,from:string,to:string,...args:any[])`);
- }
- for (let i = 0, l = localPostCallbacks.length; i < l; i++) {
- let callbackName = localPostCallbacks[i];
- uniqueCallbacksArray[callbackName] = true;
- //callbacksConfig.push(`protected abstract ${callbackName}(eventName:string,from:string,to:string,...args:any[])`);
- }
- }
- let globalCallbacksText = modelAsObj.globalCallbacksText
- let globalCallbacksObj = JSON.parse(globalCallbacksText);
- let globalEnterCallbacks = globalCallbacksObj.enter;
- let globalLeaveCallbacks = globalCallbacksObj.leave;
- let globalBeforeCallbacks = globalCallbacksObj.before;
- let globalAfterCallbacks = globalCallbacksObj.after;
- if (!!globalEnterCallbacks.length) {
- let globalEnterCallbacksDecorators = globalEnterCallbacks.filter(filterForEmptyString).map(fsmCallbacksDecorator);
- callbacks[`onenterstate`] = globalEnterCallbacksDecorators;
- }
- if (!!globalLeaveCallbacks.length) {
- let globalLeaveCallbacksDecorators = globalLeaveCallbacks.filter(filterForEmptyString).map(fsmCallbacksDecorator);
- callbacks[`onleavestate`] = globalLeaveCallbacksDecorators;
- }
- if (!!globalBeforeCallbacks.length) {
- let globalBeforeCallbacksDecorators = globalBeforeCallbacks.filter(filterForEmptyString).map(fsmCallbacksDecorator);
- callbacks[`onbeforeevent`] = globalBeforeCallbacksDecorators;
- }
- if (!!globalAfterCallbacks.length) {
- let globalAfterCallbacksDecorators = globalAfterCallbacks.filter(filterForEmptyString).map(fsmCallbacksDecorator);
- callbacks[`onafterevent`] = globalAfterCallbacksDecorators;
- }
- for (let i = 0, l = globalEnterCallbacks.length; i < l; i++) {
- let callbackName = globalEnterCallbacks[i];
- uniqueCallbacksArray[callbackName] = true;
- //callbacksConfig.push(`protected abstract ${callbackName}(eventName:string,from:string,to:string,...args:any[])`);
- }
- for (let i = 0, l = globalLeaveCallbacks.length; i < l; i++) {
- let callbackName = globalLeaveCallbacks[i];
- uniqueCallbacksArray[callbackName] = true;
- //callbacksConfig.push(`protected abstract ${callbackName}(eventName:string,from:string,to:string,...args:any[])`);
- }
- for (let i = 0, l = globalBeforeCallbacks.length; i < l; i++) {
- let callbackName = globalBeforeCallbacks[i];
- uniqueCallbacksArray[callbackName] = true;
- //callbacksConfig.push(`protected abstract ${callbackName}(eventName:string,from:string,to:string,...args:any[])`);
- }
- for (let i = 0, l = globalAfterCallbacks.length; i < l; i++) {
- let callbackName = globalAfterCallbacks[i];
- uniqueCallbacksArray[callbackName] = true;
- //callbacksConfig.push(`protected abstract ${callbackName}(eventName:string,from:string,to:string,...args:any[])`);
- }
- let uniqueCallbacksIdxArray = Object.keys(uniqueCallbacksArray);
- for (let i = 0, l = uniqueCallbacksIdxArray.length; i < l; i++) {
- let callbackName = uniqueCallbacksIdxArray[i];
- callbacksConfig.push(`public abstract ${callbackName}(eventName: string, from: string, to: string, ...args: any[]) : void`);
- //callbacksInterface.push(`${callbackName}(eventName:string,from:string,to:string,...args:any[]) : void`);
- //callbacksImplementConfig.push(`protected ${callbackName} = (eventName:string,from:string,to:string,...args:any[]): void => {}`);
- }
- let uniqueEventNameIdxArray = Object.keys(uniqueEventNameArray);
- for (let i = 0, l = uniqueEventNameIdxArray.length; i < l; i++) {
- let eventName = uniqueEventNameIdxArray[i];
- triggersConfig.push(`public ${eventName}(...args: any[]): void { this.fsm['${eventName}'](...args); }`);
- eventNameInterface.push(`${eventName}: string`);
- eventNameConfig.push(`${eventName}: '${eventName}'`);
- }
- let uniqueStateNameIdxArray = Object.keys(uniqueStateNameArray);
- for (let i = 0, l = uniqueStateNameIdxArray.length; i < l; i++) {
- let stateName = uniqueStateNameIdxArray[i];
- stateNameInterface.push(`${stateName}: string`);
- stateNameConfig.push(`${stateName}: '${stateName}'`);
- }
- let fsmConfig = {
- initial,
- events,
- callbacks
- }
- //let dist = {};
- //dist.flowForFsm = fsmConfig;
- //dist.flowForGoJs = JSON.parse(myDiagram.model.toJson());
- //console.log(dist);
- //editKey = null;
- //selectLink = false;
- //editor.setText(JSON.stringify(dist));
- //editor.setMode("code");
- //editor.expandAll();
- var fsmConfigDecorator = JSON.stringify(fsmConfig).replace(/"#/g, "").replace(/#"/g, "")
- .replace(/"/g, "'").replace(/{'/g, "{").replace(/':/g, ": ").replace(/,'/g, ",")
- //var flowForFsm = new File([fsmConfigDecorator], "flowForFsm.json", {type: "text/plain;charset=utf-8"});
- //saveAs(flowForFsm);
- //var flowForGoJs = new File([myDiagram.model.toJson()], "flowForGoJs.json", {type: "text/plain;charset=utf-8"});
- //saveAs(flowForGoJs);
- // if(exportType === "exportGoJs"){
- // //var flowForGoJsFile = new File([myDiagram.model.toJson()], "flow-for-gojs.json", {type: "text/plain;charset=utf-8"});
- // var flowForGoJsFile = new File([JSON.stringify(modelAsObj)], "FlowForGojs.json", {type: "text/plain;charset=utf-8"});
- // saveAs(flowForGoJsFile);
- // return;
- // }else if(exportType === "all"){
- // //var flowForGoJsFile = new File([myDiagram.model.toJson()], "flow-for-gojs.json", {type: "text/plain;charset=utf-8"});
- // var flowForGoJsFile = new File([JSON.stringify(modelAsObj)], "FlowForGojs.json", {type: "text/plain;charset=utf-8"});
- // saveAs(flowForGoJsFile);
- // }
- //let className = currentName.split(".")[0];
- //console.log(fsmConfigDecorator);
- let tsString = tsTemplate.replace(/#fsmConfig#/g, fsmConfigDecorator)
- .replace(/#className#/g, preClassName)
- .replace(/#gojsConfig#/g, "###" + JSON.stringify(modelAsObj) + "###")
- .replace(/#stateNameConfig#/g, stateNameConfig.join(",\n ") + ",")
- .replace(/#eventNameConfig#/g, eventNameConfig.join(",\n ") + ",")
- .replace(/#stateNameInterface#/g, stateNameInterface.join(";\n ") + ";\n")
- .replace(/#eventNameInterface#/g, eventNameInterface.join(";\n ") + ";\n")
- .replace(/#triggersConfig#/g, triggersConfig.join("\n ") + "\n")
- if (callbacksConfig.length > 0) {
- tsString = tsString.replace(/#callbacksConfig#/g, callbacksConfig.join("\n ") + "\n")
- } else {
- tsString = tsString.replace(/#callbacksConfig#/g, "") // 仅去掉标签
- }
- //.replace(/#callbacksImplementConfig#/g,callbacksImplementConfig.join(";\n ") + ";\n")
- //.replace(/#callbacksInterface#/g,callbacksInterface.join("\n ") + ";\n");
- //console.log(tsString);
- //todo 验证fsm和状态机库的存在性 done
- // let isFsmFolderExists = Editor.assetdb.existsByPath(savePath);
- // Editor.log(isFsmFolderExists);
- // if (!isFsmFolderExists) {
- // Editor.Ipc.sendToMain("asset-db:create-asset", savePath, function (err, result) {
- // //todo 验证状态机库的存在性
- // })
- // } else {
- checkAndCreateFsmFolder(() => {
- checkAndMoveStateMachineLib(async () => {
- //todo 验证文件存在性
- let path = await Editor.Message.request('asset-db', 'query-path', savePath + preClassName + '.ts');
- writeFileSync(path as string, tsString);
- Editor.Message.request("asset-db", 'refresh-asset', savePath + preClassName + '.ts').then((results) => {
- Editor.Dialog.info(preClassName + '.ts' + " 保存成功!", {
- buttons: ["好的,我知道了"],
- title: "提示",
- detail: preClassName + '.ts' + " 将会被保存于路径 " + savePath
- }).then((result) => {
- self.$.iframe.contentWindow.postMessage({message: "save-callback", data: {}}, '*');
- });
- });
- });
- }, tsString);
- },
- // modify 下划线
- async selectionSelected(type: string, uuid: string) {
- //Editor.log(e);
- //Editor.log("args",args);
- //Editor.log(uuidArray[0]);
- if (type !== 'asset') {
- //Editor.log("before return");
- return;
- } else {
- let fspath = await Editor.Message.request('asset-db', 'query-path', uuid);
- if (fspath && uuid) {
- checkAndLoadFsm(this.$.iframe, uuid, fspath, () => {
- //Editor.Dialog.error("导入的文件不是状态机代码");
- });
- }
- }
- },
- },
- ready() {
- let self = this as any
- window.addEventListener('message', (event) => {
- // 处理消息
- if (self[event.data.message]) self[event.data.message](event.data.args, event.data.callback)
- // 你可以在这里根据需要处理接收到的消息
- });
- },
- beforeClose() {
- },
- close() {
- },
- });
- let checkAndCreateFsmFolder = async function (nextCb: Function, tsString: string) {
- let isFsmFolderExists = await Editor.Message.request('asset-db', 'query-path', savePath);
- //Editor.log("FsmFolder", isFsmFolderExists);
- if (!isFsmFolderExists) {
- Editor.Message.request("asset-db", "create-asset", savePath, tsString).then((results) => {
- if (results && nextCb) {
- nextCb();
- }
- })
- } else {
- if (nextCb) {
- nextCb();
- }
- }
- }
- let checkAndMoveStateMachineLib = async (nextCb: Function) => {
- let isStateMachineLibExists = await Editor.Message.request('asset-db', 'query-path', savePath + "StateMachine.ts");
- let originalStateMachineLib = await Editor.Message.request('asset-db', 'query-path', "extensions://visual-fsm/panel/StateMachine.ts");
- //Editor.log("StateMachineLib", isStateMachineLibExists);
- if (!isStateMachineLibExists) {
- writeFileSync(isStateMachineLibExists as string, readFileSync(originalStateMachineLib as string));
- Editor.Message.request("asset-db", "refresh-asset", savePath + "StateMachine.ts").then((results) => {
- if (nextCb) {
- nextCb();
- }
- });
- } else {
- if (nextCb) {
- nextCb();
- }
- }
- }
- let fsmCallbacksDecorator = function (rawCallback: any) {
- return `#this.${rawCallback}#`
- //return `#target.${rawCallback}#`
- }
- let filterForEmptyString = function (rawCallback: any) {
- if (rawCallback === null || rawCallback.length === 0) {
- return false;
- }
- return true;
- }
- let checkAndLoadFsm = function (iframe: any, uuid: any, filePath: any, failcb: Function) {
- //选中后判断是否是状态机代码
- if (filePath) {
- let postfix = path.extname(filePath);
- let name = path.basename(filePath);
- //Editor.log(postfix);
- //Editor.log(name);
- if (postfix === '.ts') {
- //是代码
- //判断是否是状态机代码
- readFile(filePath, 'utf-8', function (err, data) {
- let gojsResultRegArray = /###(.*)###/.exec(data);
- if (gojsResultRegArray !== null && gojsResultRegArray.length >= 2) {
- let gojsResult = gojsResultRegArray[1];
- //是状态机代码
- //进入编辑模式 修改后需要提醒是导出还是修改保存,还是取消
- currentUuid = uuid;
- currentName = name;
- let reEditFsmParam = {
- name: currentName,
- model: gojsResult
- };
- //todo
- // 添加回调锁,控制异步
- iframe.contentWindow.postMessage({message: "re-edit-fsm", data: reEditFsmParam}, '*');
- } else {
- //Editor.log("fail");
- if (failcb !== undefined) {
- failcb();
- }
- }
- })
- } else {
- //Editor.log("fail");
- if (failcb !== undefined) {
- failcb();
- }
- }
- } else {
- //Editor.log("fail");
- if (failcb !== undefined) {
- failcb();
- }
- }
- }
- let tsTemplate = `
- //#gojsConfig#
- interface StateNameInterface {
- #stateNameInterface#
- }
- interface EventNameInterface {
- #eventNameInterface#
- }
- import StateMachine from './StateMachine';
- export abstract class #className# extends cc.Component {
- public fsm: any;
- public fsmTrigger (eventName:string, ...args: any[]) {
- this.fsm[eventName](...args);
- }
- public fsmIs(stateName: string):boolean {
- return this.fsm.is(stateName);
- }
- public fsmCan(eventName: string):boolean {
- return this.fsm.can(eventName);
- }
- public fsmCannot(eventName: string):boolean {
- return this.fsm.cannot(eventName);
- }
- public fsmCurrent():string {
- return this.fsm.current;
- }
- public fsmStartUp() {
- this.fsm = StateMachine.create(#fsmConfig#, this);
- }
- public readonly stateName: StateNameInterface = {
- #stateNameConfig#
- };
- public readonly eventName: EventNameInterface = {
- #eventNameConfig#
- };
- #triggersConfig#
- #callbacksConfig#
- }
- `;
|