204 lines
5.8 KiB
TypeScript
204 lines
5.8 KiB
TypeScript
import { message } from "antd";
|
|
import * as fs from "fs";
|
|
import * as path from "path";
|
|
import Settings from "../main-process/Settings";
|
|
import { BehaviorNodeModel, BehaviorTreeModel, GraphNodeModel } from "./BehaviorTreeModel";
|
|
|
|
interface INodeDataLike {
|
|
path?: string;
|
|
id: string | number;
|
|
}
|
|
|
|
export const isSubtree = (nodeData: INodeDataLike) => {
|
|
return nodeData.path && nodeData.id.toString() !== "1";
|
|
};
|
|
|
|
const parsingStack: string[] = [];
|
|
|
|
export const cloneNodeData = (nodeData: GraphNodeModel) => {
|
|
const newData: BehaviorNodeModel = {
|
|
id: Number(nodeData.id),
|
|
name: nodeData.name,
|
|
desc: nodeData.desc,
|
|
path: nodeData.path,
|
|
};
|
|
if (nodeData.input) {
|
|
newData.input = [];
|
|
for (let v of nodeData.input) {
|
|
newData.input.push(v || "");
|
|
}
|
|
}
|
|
if (nodeData.output) {
|
|
newData.output = [];
|
|
for (let v of nodeData.output) {
|
|
newData.output.push(v || "");
|
|
}
|
|
}
|
|
if (nodeData.args) {
|
|
newData.args = {};
|
|
for (let k in nodeData.args) {
|
|
let v = nodeData.args[k];
|
|
newData.args[k] = v;
|
|
}
|
|
}
|
|
if (nodeData.children && !isSubtree(nodeData)) {
|
|
newData.children = [];
|
|
for (let child of nodeData.children) {
|
|
newData.children.push(cloneNodeData(child));
|
|
}
|
|
}
|
|
return newData;
|
|
};
|
|
|
|
export const refreshNodeId = (nodeData: GraphNodeModel, id?: number) => {
|
|
if (!id) {
|
|
id = 1;
|
|
}
|
|
nodeData.id = (id++).toString();
|
|
if (nodeData.children) {
|
|
nodeData.children.forEach((child) => {
|
|
child.parent = nodeData.id;
|
|
id = refreshNodeId(child, id);
|
|
});
|
|
}
|
|
return id;
|
|
};
|
|
|
|
export const calcTreeNodeSize = (treeNode: GraphNodeModel) => {
|
|
var height = 40 + 2;
|
|
const updateHeight = (obj: any) => {
|
|
if (Array.isArray(obj) || (obj && Object.keys(obj).length > 0)) {
|
|
const { str, line } = toBreakWord(`参数:${JSON.stringify(obj)}`, 35);
|
|
height += 20 * line;
|
|
}
|
|
};
|
|
if (treeNode.path) {
|
|
height += 20;
|
|
}
|
|
updateHeight(treeNode.args);
|
|
updateHeight(treeNode.input);
|
|
updateHeight(treeNode.output);
|
|
return [200, height];
|
|
};
|
|
|
|
export const createTreeData = (bNode: BehaviorNodeModel, settings: Settings, parent?: string) => {
|
|
let treeData: GraphNodeModel = {
|
|
id: bNode.id.toString(),
|
|
name: bNode.name,
|
|
desc: bNode.desc,
|
|
args: bNode.args,
|
|
input: bNode.input,
|
|
output: bNode.output,
|
|
debug: bNode.debug,
|
|
conf: settings.getNodeConf(bNode.name),
|
|
parent: parent,
|
|
};
|
|
|
|
treeData.size = calcTreeNodeSize(treeData);
|
|
|
|
if (!parent) {
|
|
parsingStack.length = 0;
|
|
}
|
|
|
|
if (bNode.children) {
|
|
treeData.children = [];
|
|
bNode.children.forEach((child) => {
|
|
treeData.children.push(createTreeData(child, settings, treeData.id));
|
|
});
|
|
} else if (bNode.path) {
|
|
if (parsingStack.indexOf(bNode.path) >= 0) {
|
|
treeData.path = bNode.path;
|
|
treeData.size = calcTreeNodeSize(treeData);
|
|
message.error(`循环引用节点:${bNode.path}`, 4);
|
|
return treeData;
|
|
}
|
|
parsingStack.push(bNode.path);
|
|
try {
|
|
const subtreePath = settings.workdir + "/" + bNode.path;
|
|
const str = fs.readFileSync(subtreePath, "utf8");
|
|
treeData = createTreeData(JSON.parse(str).root, settings, treeData.id);
|
|
treeData.path = bNode.path;
|
|
treeData.size = calcTreeNodeSize(treeData);
|
|
} catch (error) {
|
|
message.error(`解析子树失败:${bNode.path}`);
|
|
console.log("parse subtree:", error);
|
|
}
|
|
parsingStack.pop();
|
|
}
|
|
calcTreeNodeSize(treeData);
|
|
return treeData;
|
|
};
|
|
|
|
export const createBuildData = (path: string, settings: Settings): BehaviorNodeModel | null => {
|
|
try {
|
|
path = settings.workdir + "/" + path;
|
|
const str = fs.readFileSync(path, "utf8");
|
|
let treeModel = JSON.parse(str);
|
|
const data = createTreeData(treeModel.root, settings);
|
|
refreshNodeId(data);
|
|
treeModel.root = createFileData(data, true);
|
|
return treeModel as BehaviorNodeModel;
|
|
} catch (error) {
|
|
console.log("build error:", path, error);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const createFileData = (gNode: GraphNodeModel, includeSubtree?: boolean) => {
|
|
const nodeData: BehaviorNodeModel = {
|
|
id: Number(gNode.id),
|
|
name: gNode.name,
|
|
desc: gNode.desc || undefined,
|
|
args: gNode.args || undefined,
|
|
input: gNode.input || undefined,
|
|
output: gNode.output || undefined,
|
|
debug: gNode.debug,
|
|
path: gNode.path,
|
|
};
|
|
if (gNode.children && (includeSubtree || !isSubtree(gNode))) {
|
|
nodeData.children = [];
|
|
gNode.children.forEach((child) => {
|
|
nodeData.children.push(createFileData(child, includeSubtree));
|
|
});
|
|
}
|
|
return nodeData;
|
|
};
|
|
|
|
export const getRemoteSettings = () => {
|
|
return require("@electron/remote").getGlobal("settings") as Settings;
|
|
};
|
|
|
|
export const fileName2treeName = (filename: string) => {
|
|
return path.basename(filename).slice(0, -5);
|
|
};
|
|
|
|
export const createNewTree = (filename: string) => {
|
|
const tree: BehaviorTreeModel = {
|
|
name: fileName2treeName(filename),
|
|
root: {
|
|
id: 1,
|
|
name: "Sequence",
|
|
desc: "新建行为树",
|
|
},
|
|
};
|
|
return tree;
|
|
};
|
|
|
|
export const toBreakWord = (str: string, len: number, char = "\n") => {
|
|
var strTemp = "";
|
|
var line = 1;
|
|
if (str.length <= len) {
|
|
return { str, line };
|
|
}
|
|
while (str.length > len) {
|
|
strTemp += str.substr(0, len) + char;
|
|
str = str.substr(len, str.length);
|
|
line++;
|
|
}
|
|
strTemp += str;
|
|
return {
|
|
str: strTemp,
|
|
line,
|
|
};
|
|
};
|