diff --git a/public/locales/en.json b/public/locales/en.json index fef1539..ea4938e 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -1,5 +1,6 @@ { "about": "About Behavior3", + "add": "Add", "actuaSize": "Actual Size", "build": "Build", "batch": "Batch Script", @@ -18,6 +19,7 @@ "donotSave": "Don't Save", "duplicate": "Duplicate", "editSubtree": "Edit Subtree", + "fieldRequired": "Field '{{field}}' is required", "forceReload": "Force Reload", "fullscreen": "Toggle Full Screen", "hide": "Hide Behavior3", @@ -77,6 +79,11 @@ "tree.desc": "Tree desc", "tree.export": "Export", "tree.firstid": "First id", + "tree.vars": "Variable Definition", + "tree.vars.name": "name", + "tree.vars.invalidName": "Invalid variable name", + "tree.vars.desc": "description", + "tree.vars.imports": "Variable References", "regnode.input": "Input: ", "regnode.output": "Output: ", @@ -85,9 +92,6 @@ "regnode.subtree": "Subtree: ", "node.args": "Const arguments", - "node.args.add": "Add Sub Item", - "node.input.add": "Add Input Item", - "node.output.add": "Add Output Item", "node.children.unlimited": "Unlimited", "node.children": "Num children", "node.debug": "Debug", @@ -95,7 +99,6 @@ "node.desc": "Node desc", "node.disabled": "Disabled", "node.editSubtreeDenied": "Unable to edit the subtree node", - "node.fileRequired": "Field '{{field}}' is required", "node.id": "Node id", "node.inputVariable": "Input variables", "node.invalidValue": "Invalid value", diff --git a/public/locales/zh.json b/public/locales/zh.json index 4a6de34..dedb7b1 100644 --- a/public/locales/zh.json +++ b/public/locales/zh.json @@ -1,5 +1,6 @@ { "about": "关于 Behavior3", + "add": "添加", "actualSize": "实际大小", "build": "构建", "batch": "批处理脚本", @@ -18,6 +19,7 @@ "donotSave": "不保存", "duplicate": "生成副本", "editSubtree": "编辑子树", + "fieldRequired": "字段“{{field}}”必填", "forceReload": "强制重新加载", "fullscreen": "切换全屏", "hide": "隐藏 Behavior3", @@ -77,6 +79,11 @@ "tree.desc": "说明", "tree.export": "导出", "tree.firstid": "起始标识", + "tree.vars": "变量定义", + "tree.vars.name": "变量名", + "tree.vars.invalidName": "变量名不合法", + "tree.vars.desc": "变量说明", + "tree.vars.imports": "变量引用", "regnode.input": "输入:", "regnode.output": "输出:", @@ -85,9 +92,6 @@ "regnode.subtree": "子树:", "node.args": "常量参数", - "node.args.add": "添加子项", - "node.input.add": "添加输入项", - "node.output.add": "添加输出项", "node.children.unlimited": "无限制", "node.children": "子节点数量", "node.debug": "调试", @@ -95,7 +99,6 @@ "node.desc": "节点说明", "node.disabled": "禁用", "node.editSubtreeDenied": "不能编辑子树节点", - "node.fileRequired": "字段“{{field}}”必填", "node.id": "节点标识", "node.inputVariable": "输入变量", "node.invalidValue": "无效的值", diff --git a/sample/vars/declare-core.json b/sample/vars/declare-core.json new file mode 100644 index 0000000..d139597 --- /dev/null +++ b/sample/vars/declare-core.json @@ -0,0 +1,23 @@ +{ + "name": "def-core", + "desc": "", + "firstid": 1, + "export": true, + "declare": { + "imports": [], + "vars": [ + { + "name": "context", + "desc": "上下文" + }, + { + "name": "version", + "desc": "版本" + } + ] + }, + "root": { + "id": 1, + "name": "Sequence" + } +} \ No newline at end of file diff --git a/sample/vars/declare-vars.json b/sample/vars/declare-vars.json new file mode 100644 index 0000000..2998f3b --- /dev/null +++ b/sample/vars/declare-vars.json @@ -0,0 +1,25 @@ +{ + "name": "declare-vars", + "desc": "", + "firstid": 1, + "export": true, + "declare": { + "imports": [ + "vars/declare-core.json" + ], + "vars": [ + { + "name": "owner", + "desc": "所有者" + }, + { + "name": "skill", + "desc": "技能" + } + ] + }, + "root": { + "id": 1, + "name": "Sequence" + } +} \ No newline at end of file diff --git a/sample/vars/test-subtree.json b/sample/vars/test-subtree.json new file mode 100644 index 0000000..77abdc5 --- /dev/null +++ b/sample/vars/test-subtree.json @@ -0,0 +1,23 @@ +{ + "name": "test-subtree", + "desc": "", + "firstid": 1, + "export": true, + "declare": { + "imports": [], + "vars": [] + }, + "root": { + "id": 1, + "name": "Sequence", + "children": [ + { + "id": 2, + "name": "Log", + "args": { + "message": "hello" + } + } + ] + } +} \ No newline at end of file diff --git a/sample/vars/test-vars.json b/sample/vars/test-vars.json new file mode 100644 index 0000000..78f4dae --- /dev/null +++ b/sample/vars/test-vars.json @@ -0,0 +1,51 @@ +{ + "name": "test-vars", + "desc": "", + "firstid": 1, + "export": true, + "declare": { + "imports": [ + "vars/declare-core.json", + "vars/declare-vars.json" + ], + "vars": [ + { + "name": "target", + "desc": "目标" + } + ] + }, + "root": { + "id": 1, + "name": "Sequence", + "children": [ + { + "id": 2, + "name": "Sequence", + "path": "vars/test-subtree.json" + }, + { + "id": 4, + "name": "FindEnemy", + "args": {}, + "output": [ + "target" + ] + }, + { + "id": 5, + "name": "Attack", + "input": [ + "target" + ] + }, + { + "id": 6, + "name": "Check", + "args": { + "value": "target.x > 0" + } + } + ] + } +} \ No newline at end of file diff --git a/sample/workspace.b3-workspace b/sample/workspace.b3-workspace index 577cdcc..be3beb0 100644 --- a/sample/workspace.b3-workspace +++ b/sample/workspace.b3-workspace @@ -1,5 +1,21 @@ { "files": [ + { + "path": "vars/declare-core.json", + "desc": "" + }, + { + "path": "vars/declare-vars.json", + "desc": "" + }, + { + "path": "vars/test-subtree.json", + "desc": "" + }, + { + "path": "vars/test-vars.json", + "desc": "" + }, { "path": "workdir/hero.json", "desc": "英雄测试AI" diff --git a/src/components/editor.tsx b/src/components/editor.tsx index 47fc4f1..ef6503d 100644 --- a/src/components/editor.tsx +++ b/src/components/editor.tsx @@ -464,6 +464,8 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . editor.export = editTree.data.export !== false; if (editor.data.firstid !== editTree.data.firstid) { editor.firstid = editTree.data.firstid ?? 1; + editor.declare.vars = editTree.data.declare.vars || []; + editor.declare.imports = editTree.data.declare.imports || []; refresh(); } onChange(); @@ -1042,7 +1044,10 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . useKeyDown(Hotkey.Undo, keysRef, () => undo()); useKeyDown(Hotkey.Redo, keysRef, () => redo()); useKeyDown([Hotkey.Insert, Hotkey.Enter], keysRef, () => createNode()); - useKeyDown([Hotkey.Delete, Hotkey.Backspace], keysRef, () => deleteNode()); + useKeyDown([Hotkey.Delete, Hotkey.Backspace], keysRef, () => { + console.log("delete"); + deleteNode(); + }); editor.dispatch = (event: EditEvent, data: unknown) => { switch (event) { @@ -1055,6 +1060,7 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . break; } case "delete": { + console.log("delete1"); deleteNode(); break; } @@ -1217,6 +1223,8 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . } else if ((e.ctrlKey || e.metaKey) && e.code === "KeyG") { searchByType("id"); } + console.log(e.code); + e.stopPropagation(); }; const recursiveOpenCollapsed = (id: string) => { @@ -1281,7 +1289,7 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . } onFocus={() => setFilterOption({ ...filterOption, isFocused: true })} onBlur={() => setFilterOption({ ...filterOption, isFocused: false })} - onKeyDown={handleKeyDown} + onKeyDownCapture={handleKeyDown} suffix={ {filterOption.filterType !== "id" && ( diff --git a/src/components/inspector.tsx b/src/components/inspector.tsx index f29a96a..89c57f9 100644 --- a/src/components/inspector.tsx +++ b/src/components/inspector.tsx @@ -1,4 +1,4 @@ -import { EditOutlined, MinusCircleOutlined, PlusOutlined } from "@ant-design/icons"; +import { AimOutlined, EditOutlined, MinusCircleOutlined, PlusOutlined } from "@ant-design/icons"; import { AutoComplete, Button, @@ -8,6 +8,7 @@ import { Input, InputNumber, Select, + Space, Switch, } from "antd"; import TextArea from "antd/es/input/TextArea"; @@ -19,6 +20,7 @@ import { useDebounceCallback } from "usehooks-ts"; import { useShallow } from "zustand/react/shallow"; import { EditNode, EditTree, useWorkspace } from "../contexts/workspace-context"; import { + ImportDef, isBoolType, isEnumType, isExprType, @@ -28,6 +30,7 @@ import { isStringType, NodeModel, TreeGraphData, + VarDef, } from "../misc/b3type"; import { checkNodeArgValue, @@ -37,6 +40,7 @@ import { isNodeArgOptional, isValidVariableName, isVariadic, + loadImportedVars, } from "../misc/b3util"; import { Hotkey, isMacos } from "../misc/keys"; import { mergeClassNames } from "../misc/util"; @@ -50,6 +54,9 @@ const TreeInspector: FC = () => { useShallow((state) => ({ editing: state.editing, editingTree: state.editingTree!, + allFiles: state.allFiles, + relative: state.relative, + fileTree: state.fileTree, })) ); const { t } = useTranslation(); @@ -58,13 +65,31 @@ const TreeInspector: FC = () => { // set form values useEffect(() => { const data = workspace.editingTree.data; + loadImportedVars(data.declare.imports); form.resetFields(); form.setFieldValue("name", data.name); form.setFieldValue("desc", data.desc); form.setFieldValue("export", data.export !== false); form.setFieldValue("firstid", data.firstid); + form.setFieldValue("declare.vars", data.declare?.vars); + form.setFieldValue("declare.imports", data.declare?.imports); }, [workspace.editingTree]); + // auto complete for subtree + const subtreeOptions = useMemo(() => { + const options: OptionType[] = []; + workspace.allFiles.forEach((file) => { + const value = workspace.relative(file.path); + const desc = ""; //fileNode.desc ? `(${fileNode.desc})` : ""; + options.push({ + label: `${value}${desc}`, + value: value, + }); + }); + options.sort((a, b) => a.value.localeCompare(b.value)); + return options; + }, [workspace.allFiles, workspace.fileTree]); + const finish = (values: any) => { workspace.editing?.dispatch("updateTree", { data: { @@ -72,6 +97,18 @@ const TreeInspector: FC = () => { desc: values.desc || undefined, export: values.export, firstid: Number(values.firstid), + declare: { + vars: (values["declare.vars"] as VarDef[]) + .filter((v) => v && v.name) + .sort((a, b) => a.name.localeCompare(b.name)), + imports: (values["declare.imports"] as ImportDef[]) + .filter((v) => v && v.path) + .sort((a, b) => a.path.localeCompare(b.path)) + .map((v) => ({ + path: v.path, + vars: v.vars ?? [], + })), + }, }, } as EditTree); }; @@ -85,19 +122,238 @@ const TreeInspector: FC = () => { className={mergeClassNames("b3-inspector-content", isMacos ? "" : "b3-overflow")} style={{ overflow: "auto", height: "100%" }} > -
- - - - -