argument with options treat as enum
This commit is contained in:
1 parent
49bfc76fc6
commit
767d8aba95
14 files changed
+105
-133
No files matched your search
@@ -45,14 +45,10 @@ export interface NodeDef {
|
||||
| "json?"
|
||||
| "json[]"
|
||||
| "json[]?"
|
||||
| "enum"
|
||||
| "enum?"
|
||||
| "enum[]"
|
||||
| "enum[]?"
|
||||
| "code"
|
||||
| "code?"
|
||||
| "code[]"
|
||||
| "code[]?";
|
||||
| "expr"
|
||||
| "expr?"
|
||||
| "expr[]"
|
||||
| "expr[]?";
|
||||
desc: string;
|
||||
default?: unknown;
|
||||
/** Input `value`, only one is allowed between `value` and this arg.*/
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "behavior3editor",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "behavior3editor",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "behavior3editor",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"main": "dist-electron/main/index.js",
|
||||
"description": "行为树编辑器",
|
||||
"author": "zhandouxiaojiji & codetypes",
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
"tree.export": "Export",
|
||||
"tree.firstid": "First id",
|
||||
"tree.group": "Enable Node Grouping",
|
||||
"tree.group.placeholder": "Select node groups",
|
||||
"tree.vars": "Define Variables",
|
||||
"tree.vars.name": "name",
|
||||
"tree.vars.invalidName": "Invalid variable name",
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
"tree.export": "导出",
|
||||
"tree.firstid": "起始标识",
|
||||
"tree.group": "启用节点分组",
|
||||
"tree.group.placeholder": "选择节点分组",
|
||||
"tree.vars": "定义变量",
|
||||
"tree.vars.name": "变量名",
|
||||
"tree.vars.invalidName": "变量名不合法",
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"args": [
|
||||
{
|
||||
"name": "builtin",
|
||||
"type": "enum",
|
||||
"type": "string",
|
||||
"desc": "事件",
|
||||
"options": [
|
||||
{
|
||||
@@ -332,7 +332,10 @@
|
||||
},
|
||||
{
|
||||
"name": "MoveToPos",
|
||||
"type": "Action (Client)",
|
||||
"type": "Action",
|
||||
"group": [
|
||||
"Client"
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "x",
|
||||
@@ -349,7 +352,10 @@
|
||||
},
|
||||
{
|
||||
"name": "MoveToTarget",
|
||||
"type": "Action (Server)",
|
||||
"type": "Action",
|
||||
"group": [
|
||||
"Server"
|
||||
],
|
||||
"input": [
|
||||
"{目标}"
|
||||
],
|
||||
@@ -357,7 +363,12 @@
|
||||
},
|
||||
{
|
||||
"name": "TestB3",
|
||||
"type": "Action (Client|Server|Test)",
|
||||
"type": "Action",
|
||||
"group": [
|
||||
"Client",
|
||||
"Server",
|
||||
"Test"
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "time",
|
||||
@@ -387,7 +398,7 @@
|
||||
{
|
||||
"name": "status",
|
||||
"desc": "状态",
|
||||
"type": "enum",
|
||||
"type": "string",
|
||||
"options": [
|
||||
{
|
||||
"name": "成功",
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"id": 6,
|
||||
"name": "Check",
|
||||
"args": {
|
||||
"value": "target[0].x > 0 |"
|
||||
"value": "target[0].x > 0 "
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -95,6 +95,13 @@
|
||||
"output": [
|
||||
"context"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "Listen",
|
||||
"args": {
|
||||
"builtin": "afterRunFailure"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+11
-14
@@ -1,16 +1,24 @@
|
||||
{
|
||||
"version": "1.8.0",
|
||||
"name": "hero",
|
||||
"desc": "英雄测试AI",
|
||||
"firstid": 1,
|
||||
"export": true,
|
||||
"group": [
|
||||
"Client",
|
||||
"Server"
|
||||
],
|
||||
"import": [],
|
||||
"declvar": [],
|
||||
"root": {
|
||||
"id": 1,
|
||||
"name": "Selector",
|
||||
"desc": "英雄测试AI",
|
||||
"args": {},
|
||||
"children": [
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Sequence",
|
||||
"desc": "攻击",
|
||||
"args": {},
|
||||
"children": [
|
||||
{
|
||||
"id": 3,
|
||||
@@ -28,7 +36,6 @@
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Attack",
|
||||
"args": {},
|
||||
"input": [
|
||||
"enemy"
|
||||
]
|
||||
@@ -46,7 +53,6 @@
|
||||
"id": 6,
|
||||
"name": "Sequence",
|
||||
"desc": "移动",
|
||||
"args": {},
|
||||
"children": [
|
||||
{
|
||||
"id": 7,
|
||||
@@ -64,7 +70,6 @@
|
||||
{
|
||||
"id": 8,
|
||||
"name": "MoveToTarget",
|
||||
"args": {},
|
||||
"input": [
|
||||
"enemy"
|
||||
]
|
||||
@@ -75,12 +80,10 @@
|
||||
"id": 9,
|
||||
"name": "Sequence",
|
||||
"desc": "逃跑",
|
||||
"args": {},
|
||||
"children": [
|
||||
{
|
||||
"id": 10,
|
||||
"name": "GetHp",
|
||||
"args": {},
|
||||
"output": [
|
||||
"hp"
|
||||
]
|
||||
@@ -110,11 +113,5 @@
|
||||
"name": "Idle"
|
||||
}
|
||||
]
|
||||
},
|
||||
"desc": "英雄测试AI",
|
||||
"version": "1.8.0",
|
||||
"firstid": 1,
|
||||
"group": [],
|
||||
"import": [],
|
||||
"declvar": []
|
||||
}
|
||||
}
|
||||
+22
-14
@@ -1,5 +1,14 @@
|
||||
{
|
||||
"version": "1.8.0",
|
||||
"name": "monster",
|
||||
"desc": "怪物测试AI",
|
||||
"firstid": 1,
|
||||
"export": true,
|
||||
"group": [
|
||||
"Test"
|
||||
],
|
||||
"import": [],
|
||||
"declvar": [],
|
||||
"root": {
|
||||
"id": 1,
|
||||
"name": "Sequence",
|
||||
@@ -26,26 +35,30 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"id": 6,
|
||||
"name": "Cmp",
|
||||
"args": {
|
||||
"gt": 50,
|
||||
"value": "hp"
|
||||
"value": "hp",
|
||||
"gt": 50
|
||||
},
|
||||
"input": [
|
||||
""
|
||||
"hp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"id": 7,
|
||||
"name": "TestB3",
|
||||
"desc": "攻击",
|
||||
"args": {
|
||||
"str": "Attack!"
|
||||
"time": 1,
|
||||
"open": true,
|
||||
"check": "1",
|
||||
"name": "1",
|
||||
"status": "FAILURE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"id": 8,
|
||||
"name": "Sequence",
|
||||
"desc": "新建行为树",
|
||||
"path": "workdir/subtree1.json"
|
||||
@@ -53,7 +66,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"id": 11,
|
||||
"name": "Log",
|
||||
"desc": "逃跑",
|
||||
"args": {
|
||||
@@ -61,10 +74,5 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"desc": "怪物测试AI",
|
||||
"firstid": 1,
|
||||
"group": [],
|
||||
"import": [],
|
||||
"declvar": []
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule src/behavior3 updated: d6e3f08950...b3e20e8578.
@@ -8,7 +8,6 @@ import {
|
||||
import {
|
||||
AutoComplete,
|
||||
Button,
|
||||
Checkbox,
|
||||
Divider,
|
||||
Flex,
|
||||
Form,
|
||||
@@ -29,9 +28,9 @@ import { useShallow } from "zustand/react/shallow";
|
||||
import { ExpressionEvaluator } from "../behavior3/src/behavior3";
|
||||
import { EditNode, EditTree, useWorkspace } from "../contexts/workspace-context";
|
||||
import {
|
||||
hasArgOptions,
|
||||
ImportDef,
|
||||
isBoolType,
|
||||
isEnumType,
|
||||
isExprType,
|
||||
isFloatType,
|
||||
isIntType,
|
||||
@@ -141,49 +140,6 @@ const VarDefItem: FC<VarItemProps> = ({ name, onChange, onRemove, disabled, ...p
|
||||
);
|
||||
};
|
||||
|
||||
interface GroupDefItemProps {
|
||||
disabled?: boolean;
|
||||
value?: string[];
|
||||
onChange?: (value: string[]) => void;
|
||||
}
|
||||
|
||||
const GroupDefItem: FC<GroupDefItemProps> = ({ disabled, onChange, ...props }) => {
|
||||
const [value, setValue] = useState<string[]>(props.value ?? []);
|
||||
const form = useFormInstance();
|
||||
const workspace = useWorkspace(
|
||||
useShallow((state) => ({
|
||||
groupDefs: state.groupDefs,
|
||||
}))
|
||||
);
|
||||
return (
|
||||
<Flex
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: 10,
|
||||
rowGap: 2,
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
{workspace.groupDefs.map((g) => (
|
||||
<Checkbox
|
||||
key={g}
|
||||
disabled={disabled}
|
||||
checked={value.includes(g)}
|
||||
onChange={(e) => {
|
||||
const arr = e.target.checked ? [...value, g] : value.filter((v) => v !== g);
|
||||
setValue(arr);
|
||||
onChange?.(arr);
|
||||
form.submit();
|
||||
}}
|
||||
>
|
||||
{g}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
const TreeInspector: FC = () => {
|
||||
const workspace = useWorkspace(
|
||||
useShallow((state) => ({
|
||||
@@ -360,6 +316,7 @@ const TreeInspector: FC = () => {
|
||||
mode="multiple"
|
||||
suffixIcon={null}
|
||||
onChange={form.submit}
|
||||
placeholder={t("tree.group.placeholder")}
|
||||
options={workspace.groupDefs.map((g) => ({ label: g, value: g }))}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -1160,29 +1117,29 @@ const NodeInspector: FC = () => {
|
||||
}),
|
||||
]}
|
||||
>
|
||||
{isStringType(type) && (
|
||||
{!hasArgOptions(arg) && isStringType(type) && (
|
||||
<TextArea autoSize disabled={disabled} onBlur={form.submit} />
|
||||
)}
|
||||
{isJsonType(type) && (
|
||||
{!hasArgOptions(arg) && isJsonType(type) && (
|
||||
<TextArea autoSize disabled={disabled} onBlur={form.submit} />
|
||||
)}
|
||||
{isIntType(type) && (
|
||||
{!hasArgOptions(arg) && isIntType(type) && (
|
||||
<InputNumber
|
||||
disabled={disabled}
|
||||
onBlur={form.submit}
|
||||
precision={0}
|
||||
/>
|
||||
)}
|
||||
{isFloatType(type) && (
|
||||
{!hasArgOptions(arg) && isFloatType(type) && (
|
||||
<InputNumber disabled={disabled} onBlur={form.submit} />
|
||||
)}
|
||||
{isBoolType(type) && (
|
||||
{!hasArgOptions(arg) && isBoolType(type) && (
|
||||
<Switch disabled={disabled} onChange={form.submit} />
|
||||
)}
|
||||
{isExprType(type) && (
|
||||
{!hasArgOptions(arg) && isExprType(type) && (
|
||||
<Input disabled={disabled} onBlur={form.submit} />
|
||||
)}
|
||||
{isEnumType(type) && (
|
||||
{hasArgOptions(arg) && (
|
||||
<Select
|
||||
showSearch
|
||||
disabled={disabled}
|
||||
@@ -1289,21 +1246,25 @@ const NodeInspector: FC = () => {
|
||||
}),
|
||||
]}
|
||||
>
|
||||
{isStringType(type) && (
|
||||
{!hasArgOptions(arg) && isStringType(type) && (
|
||||
<TextArea autoSize disabled={disabled} onBlur={form.submit} />
|
||||
)}
|
||||
{isJsonType(type) && (
|
||||
{!hasArgOptions(arg) && isJsonType(type) && (
|
||||
<TextArea autoSize disabled={disabled} onBlur={form.submit} />
|
||||
)}
|
||||
{isIntType(type) && (
|
||||
{!hasArgOptions(arg) && isIntType(type) && (
|
||||
<InputNumber disabled={disabled} onBlur={form.submit} precision={0} />
|
||||
)}
|
||||
{isFloatType(type) && (
|
||||
{!hasArgOptions(arg) && isFloatType(type) && (
|
||||
<InputNumber disabled={disabled} onBlur={form.submit} />
|
||||
)}
|
||||
{isBoolType(type) && <Switch disabled={disabled} onChange={form.submit} />}
|
||||
{isExprType(type) && <Input disabled={disabled} onBlur={form.submit} />}
|
||||
{isEnumType(type) && (
|
||||
{!hasArgOptions(arg) && isBoolType(type) && (
|
||||
<Switch disabled={disabled} onChange={form.submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isExprType(type) && (
|
||||
<Input disabled={disabled} onBlur={form.submit} />
|
||||
)}
|
||||
{hasArgOptions(arg) && (
|
||||
<Select
|
||||
showSearch
|
||||
disabled={disabled}
|
||||
@@ -1584,7 +1545,7 @@ const NodeDefInspector: FC = () => {
|
||||
rules={[{ required }]}
|
||||
>
|
||||
<Select disabled={true}>
|
||||
{["float", "int", "string", "code", "enum", "boolean"].map((value) => {
|
||||
{["float", "int", "string", "code", "boolean"].map((value) => {
|
||||
return (
|
||||
<Select.Option key={value} value={value}>
|
||||
{value}
|
||||
|
||||
@@ -291,7 +291,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
const workspace = get();
|
||||
let buildScript = dialog.showOpenDialogSync({
|
||||
properties: ["openFile"],
|
||||
defaultPath: workspace.workdir,
|
||||
defaultPath: workspace.workdir.replaceAll("/", Path.sep),
|
||||
filters: [{ name: "Javascript", extensions: ["js"] }],
|
||||
})?.[0];
|
||||
if (buildScript) {
|
||||
@@ -412,7 +412,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
const workspace = get();
|
||||
const scriptPath = dialog.showOpenDialogSync({
|
||||
properties: ["openFile"],
|
||||
defaultPath: workspace.workdir,
|
||||
defaultPath: workspace.workdir.replaceAll("/", Path.sep),
|
||||
filters: [{ name: "Javascript", extensions: ["js"] }],
|
||||
})?.[0];
|
||||
if (scriptPath) {
|
||||
|
||||
+2
-8
@@ -1,13 +1,7 @@
|
||||
import type { TreeGraphData as G6TreeGraphData } from "@antv/g6";
|
||||
import { NodeDef } from "../behavior3/src/behavior3";
|
||||
|
||||
declare module "../behavior3/src/behavior3" {
|
||||
interface NodeDef {
|
||||
group?: string[];
|
||||
}
|
||||
}
|
||||
|
||||
export const VERSION = "1.8.0";
|
||||
export const VERSION = "1.8.1";
|
||||
|
||||
export type NodeType = NodeDef["type"] | "Other" | "Error";
|
||||
export type NodeArg = Exclude<NodeDef["args"], undefined>[number];
|
||||
@@ -16,9 +10,9 @@ export const isIntType = (type: string) => type.startsWith("int");
|
||||
export const isFloatType = (type: string) => type.startsWith("float");
|
||||
export const isStringType = (type: string) => type.startsWith("string");
|
||||
export const isBoolType = (type: string) => type.startsWith("bool");
|
||||
export const isEnumType = (type: string) => type.startsWith("enum");
|
||||
export const isExprType = (type: string) => type.startsWith("expr") || type.startsWith("code");
|
||||
export const isJsonType = (type: string) => type.startsWith("json");
|
||||
export const hasArgOptions = (arg: NodeArg) => arg.options !== undefined;
|
||||
|
||||
export interface NodeModel {
|
||||
id: number;
|
||||
|
||||
+13
-17
@@ -2,9 +2,9 @@ import * as fs from "fs";
|
||||
import { ExpressionEvaluator, NodeDef } from "../behavior3/src/behavior3";
|
||||
import {
|
||||
FileVarDecl,
|
||||
hasArgOptions,
|
||||
ImportDef,
|
||||
isBoolType,
|
||||
isEnumType,
|
||||
isExprType,
|
||||
isFloatType,
|
||||
isIntType,
|
||||
@@ -67,13 +67,7 @@ export const initWorkdir = (path: string, handler: typeof alertError) => {
|
||||
nodeDefs = new NodeDefs();
|
||||
for (const v of nodeDefData) {
|
||||
nodeDefs.set(v.name, v);
|
||||
|
||||
const group = v.type.match(/\(([\w|]+)\)/)?.[1];
|
||||
if (group) {
|
||||
v.type = v.type.match(/^\w+/)![0] as NodeDef["type"];
|
||||
v.group = group.split("|");
|
||||
v.group.forEach((g) => groups.add(g));
|
||||
}
|
||||
v.group?.forEach((g) => groups.add(g));
|
||||
}
|
||||
groupDefs = Array.from(groups).sort();
|
||||
};
|
||||
@@ -218,15 +212,6 @@ export const checkNodeArgValue = (
|
||||
}
|
||||
hasError = true;
|
||||
}
|
||||
} else if (isEnumType(type)) {
|
||||
const isEnum = !!arg.options?.find((option) => option.value === value);
|
||||
const isOptional = value === undefined && isNodeArgOptional(arg);
|
||||
if (!(isEnum || isOptional)) {
|
||||
if (verbose) {
|
||||
error(data, `'${arg.name}=${JSON.stringify(value)}' is not a one of the option values`);
|
||||
}
|
||||
hasError = true;
|
||||
}
|
||||
} else if (isExprType(type)) {
|
||||
const isExpr = typeof value === "string" && value;
|
||||
const isOptional = (value === undefined || value === "") && isNodeArgOptional(arg);
|
||||
@@ -257,6 +242,17 @@ export const checkNodeArgValue = (
|
||||
error(data, `unknown arg type '${arg.type}'`);
|
||||
}
|
||||
|
||||
if (hasArgOptions(arg)) {
|
||||
const found = !!arg.options?.find((option) => option.value === value);
|
||||
const isOptional = value === undefined && isNodeArgOptional(arg);
|
||||
if (!(found || isOptional)) {
|
||||
if (verbose) {
|
||||
error(data, `'${arg.name}=${JSON.stringify(value)}' is not a one of the option values`);
|
||||
}
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !hasError;
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user