progress
This commit is contained in:
parent
7e25cc216a
commit
c628cdb9af
20 changed files with 654 additions and 124 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"Ведите",
|
||||
"Навыки",
|
||||
"typedataset"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { BehaviorTreesPresentation } from "../../features/behavior_trees/behavior_trees";
|
||||
import { DatasetsPresentation } from "../../features/datasets/datasets_presentation";
|
||||
import { ProjectsPresentation } from "../../features/projects/projects_presentation";
|
||||
// import { ProjectsPresentation } from "../../features/_projects/projects_presentation";
|
||||
|
@ -6,4 +7,4 @@ import { Routes } from "../interfaces/router";
|
|||
|
||||
extensions();
|
||||
|
||||
export const httpRoutes: Routes[] = [new ProjectsPresentation(), new DatasetsPresentation()].map((el) => el.call());
|
||||
export const httpRoutes: Routes[] = [new ProjectsPresentation(), new DatasetsPresentation(), new BehaviorTreesPresentation()].map((el) => el.call());
|
||||
|
|
147
server/src/core/models/skill_model.ts
Normal file
147
server/src/core/models/skill_model.ts
Normal file
|
@ -0,0 +1,147 @@
|
|||
import { IsArray, IsString, ValidateNested } from "class-validator";
|
||||
import { Type } from "class-transformer";
|
||||
|
||||
export interface SkillPoseEstimation {
|
||||
SkillPackage: ISkillPackage;
|
||||
Module: IModule;
|
||||
Launch: ILaunch;
|
||||
ROS2: IRos2;
|
||||
BTAction: IBTAction[];
|
||||
Interface: IInterface;
|
||||
Settings: ISetting[];
|
||||
xxx: IXxx;
|
||||
}
|
||||
|
||||
export interface IBTAction {
|
||||
name: string;
|
||||
format: string;
|
||||
type: string;
|
||||
param: string[];
|
||||
result: string[];
|
||||
}
|
||||
|
||||
export interface IInterface {
|
||||
Input: IPut[];
|
||||
Output: IPut[];
|
||||
}
|
||||
|
||||
export interface IPut {
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface ILaunch {
|
||||
executable: string;
|
||||
}
|
||||
|
||||
export interface IModule {
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface IRos2 {
|
||||
node_name: string;
|
||||
}
|
||||
|
||||
export interface ISetting {
|
||||
name: string;
|
||||
value: number | string;
|
||||
}
|
||||
|
||||
export interface ISkillPackage {
|
||||
name: string;
|
||||
version: string;
|
||||
format: string;
|
||||
}
|
||||
|
||||
export interface IXxx {
|
||||
cameraLink: string;
|
||||
topicImage: string;
|
||||
topicCameraInfo: string;
|
||||
}
|
||||
|
||||
export class SkillPackage implements ISkillPackage {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
version: string;
|
||||
@IsString()
|
||||
format: string;
|
||||
}
|
||||
export class Module implements IModule {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
description: string;
|
||||
}
|
||||
export class BTAction implements IBTAction {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
format: string;
|
||||
@IsString()
|
||||
type: string;
|
||||
@IsArray()
|
||||
param: string[];
|
||||
@IsArray()
|
||||
result: string[];
|
||||
}
|
||||
export class Launch implements ILaunch {
|
||||
@IsString()
|
||||
executable: string;
|
||||
}
|
||||
export class Ros2 implements IRos2 {
|
||||
@IsString()
|
||||
node_name: string;
|
||||
}
|
||||
export class Put implements IPut {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
type: string;
|
||||
}
|
||||
export class Interface implements IInterface {
|
||||
@ValidateNested()
|
||||
@Type(() => Put)
|
||||
Input: IPut[];
|
||||
@ValidateNested()
|
||||
@Type(() => Put)
|
||||
Output: IPut[];
|
||||
}
|
||||
export class Setting implements ISetting {
|
||||
name: string;
|
||||
value: string | number;
|
||||
}
|
||||
export class Xxx implements IXxx {
|
||||
cameraLink: string;
|
||||
topicImage: string;
|
||||
topicCameraInfo: string;
|
||||
}
|
||||
export class SkillModelPoseEstimation implements SkillPoseEstimation {
|
||||
@ValidateNested()
|
||||
@Type(() => SkillPackage)
|
||||
SkillPackage: ISkillPackage;
|
||||
@ValidateNested()
|
||||
@Type(() => Module)
|
||||
Module: IModule;
|
||||
@ValidateNested()
|
||||
@Type(() => Launch)
|
||||
Launch: ILaunch;
|
||||
@ValidateNested()
|
||||
@Type(() => Ros2)
|
||||
ROS2: IRos2;
|
||||
@ValidateNested()
|
||||
@IsArray()
|
||||
@Type(() => BTAction)
|
||||
BTAction: IBTAction[];
|
||||
@ValidateNested()
|
||||
@Type(() => Interface)
|
||||
Interface: IInterface;
|
||||
@ValidateNested()
|
||||
@IsArray()
|
||||
@Type(() => Setting)
|
||||
Settings: ISetting[];
|
||||
@ValidateNested()
|
||||
@Type(() => Xxx)
|
||||
xxx: IXxx;
|
||||
}
|
12
server/src/features/behavior_trees/behavior_trees.ts
Normal file
12
server/src/features/behavior_trees/behavior_trees.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { CoreHttpController } from "../../core/controllers/http_controller";
|
||||
import { DatasetValidationModel } from "../datasets/models/dataset_validation_model";
|
||||
import { GetBehaviorTreeSkillsUseCase } from "./get_bt_usecase";
|
||||
export class BehaviorTreesPresentation extends CoreHttpController<DatasetValidationModel> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "behavior/trees",
|
||||
validationModel: DatasetValidationModel,
|
||||
});
|
||||
super.get(new GetBehaviorTreeSkillsUseCase().call);
|
||||
}
|
||||
}
|
154
server/src/features/behavior_trees/get_bt_usecase.ts
Normal file
154
server/src/features/behavior_trees/get_bt_usecase.ts
Normal file
|
@ -0,0 +1,154 @@
|
|||
import { Result } from "../../core/helpers/result";
|
||||
|
||||
export class GetBehaviorTreeSkillsUseCase {
|
||||
call = () => {
|
||||
return Result.ok({
|
||||
skills: [
|
||||
{
|
||||
SkillPackage: {
|
||||
name: "Robossembler",
|
||||
version: "1.0",
|
||||
format: "1",
|
||||
},
|
||||
Module: {
|
||||
name: "PoseEstimation",
|
||||
description: "Pose Estimation skill with DOPE",
|
||||
},
|
||||
Launch: {
|
||||
executable: "pe_dope_lc.py",
|
||||
},
|
||||
ROS2: {
|
||||
node_name: "lc_dope",
|
||||
},
|
||||
BTAction: [
|
||||
{
|
||||
name: "peConfigure",
|
||||
format: "yaml",
|
||||
type: "run",
|
||||
param: ["object_name", "weights_file"],
|
||||
result: ["Pose"],
|
||||
},
|
||||
{
|
||||
name: "peStop",
|
||||
format: "yaml",
|
||||
type: "stop",
|
||||
param: [],
|
||||
result: [],
|
||||
},
|
||||
],
|
||||
Interface: {
|
||||
Input: [
|
||||
{
|
||||
name: "cameraLink",
|
||||
type: "CAMERA",
|
||||
},
|
||||
{
|
||||
name: "object_name",
|
||||
type: "MODEL",
|
||||
},
|
||||
],
|
||||
Output: [
|
||||
{
|
||||
name: "pose_estimation_topic",
|
||||
type: "POSE",
|
||||
},
|
||||
],
|
||||
},
|
||||
Settings: [
|
||||
{
|
||||
name: "cameraLink",
|
||||
value: "inner_rgbd_camera",
|
||||
},
|
||||
{
|
||||
name: "pose",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
name: "publishDelay",
|
||||
value: 0.5,
|
||||
},
|
||||
{
|
||||
name: "tf2_send_pose",
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
name: "mesh_scale",
|
||||
value: 0.001,
|
||||
},
|
||||
],
|
||||
xxx: {
|
||||
cameraLink: "inner_rgbd_camera",
|
||||
topicImage: "/inner_rgbd_camera/image",
|
||||
topicCameraInfo: "/inner_rgbd_camera/camera_info",
|
||||
},
|
||||
},
|
||||
{
|
||||
SkillPackage: {
|
||||
name: "Robossembler",
|
||||
version: "1.0",
|
||||
format: "1",
|
||||
},
|
||||
Module: {
|
||||
name: "ObjectDetection",
|
||||
description: "Object detection skill with YOLOv8",
|
||||
},
|
||||
Launch: {
|
||||
executable: "detection_lifecycle.py",
|
||||
},
|
||||
ROS2: {
|
||||
node_name: "lc_detection",
|
||||
},
|
||||
BTAction: [
|
||||
{
|
||||
name: "odConfigure",
|
||||
format: "yaml",
|
||||
args: ["SettingPath", "server_name", "server_timeout"],
|
||||
result: ["boundBox"],
|
||||
},
|
||||
{
|
||||
name: "odStop",
|
||||
format: "yaml",
|
||||
args: ["server_name", "server_timeout"],
|
||||
result: [],
|
||||
},
|
||||
],
|
||||
Interface: {
|
||||
Input: [
|
||||
{
|
||||
name: "cameraLink",
|
||||
type: "string",
|
||||
group: "STD_USER",
|
||||
},
|
||||
{
|
||||
name: "topicImage",
|
||||
type: "Image",
|
||||
group: "sensor_msgs.msg",
|
||||
},
|
||||
],
|
||||
Output: [
|
||||
{
|
||||
name: "boundBox",
|
||||
type: "BoundBox",
|
||||
group: ".msg",
|
||||
},
|
||||
],
|
||||
},
|
||||
Settings: [
|
||||
{
|
||||
name: "publishDelay",
|
||||
value: 0.5,
|
||||
},
|
||||
{
|
||||
name: "server_timeout",
|
||||
value: 1000,
|
||||
},
|
||||
{
|
||||
name: "server_name",
|
||||
value: "/object_detection/change_state",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
}
|
183
ui/src/core/model/skill_model.ts
Normal file
183
ui/src/core/model/skill_model.ts
Normal file
|
@ -0,0 +1,183 @@
|
|||
import { IsArray, IsString, ValidateNested } from "class-validator";
|
||||
import { Type } from "class-transformer";
|
||||
import { ISkillView } from "../../features/behavior_tree_builder/presentation/ui/skill_tree/skill_tree";
|
||||
import { v4 } from "uuid";
|
||||
|
||||
export interface ISkillPoseEstimation {
|
||||
SkillPackage: ISkillPackage;
|
||||
Module: IModule;
|
||||
Launch: ILaunch;
|
||||
ROS2: IRos2;
|
||||
BTAction: IBTAction[];
|
||||
Interface: IInterface;
|
||||
Settings: ISetting[];
|
||||
xxx: IXxx;
|
||||
}
|
||||
|
||||
export interface IBTAction {
|
||||
name: string;
|
||||
format: string;
|
||||
type: string;
|
||||
param: string[];
|
||||
result: string[];
|
||||
}
|
||||
|
||||
export interface IInterface {
|
||||
Input: IPut[];
|
||||
Output: IPut[];
|
||||
}
|
||||
|
||||
export interface IPut {
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface ILaunch {
|
||||
executable: string;
|
||||
}
|
||||
|
||||
export interface IModule {
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface IRos2 {
|
||||
node_name: string;
|
||||
}
|
||||
|
||||
export interface ISetting {
|
||||
name: string;
|
||||
value: number | string;
|
||||
}
|
||||
|
||||
export interface ISkillPackage {
|
||||
name: string;
|
||||
version: string;
|
||||
format: string;
|
||||
}
|
||||
|
||||
export interface IXxx {
|
||||
cameraLink: string;
|
||||
topicImage: string;
|
||||
topicCameraInfo: string;
|
||||
}
|
||||
|
||||
export class SkillPackage implements ISkillPackage {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
version: string;
|
||||
@IsString()
|
||||
format: string;
|
||||
}
|
||||
export class Module implements IModule {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
description: string;
|
||||
}
|
||||
export class BTAction implements IBTAction {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
format: string;
|
||||
@IsString()
|
||||
type: string;
|
||||
@IsArray()
|
||||
param: string[];
|
||||
@IsArray()
|
||||
result: string[];
|
||||
}
|
||||
export class Launch implements ILaunch {
|
||||
@IsString()
|
||||
executable: string;
|
||||
}
|
||||
export class Ros2 implements IRos2 {
|
||||
@IsString()
|
||||
node_name: string;
|
||||
}
|
||||
export class Put implements IPut {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
type: string;
|
||||
}
|
||||
export class Interface implements IInterface {
|
||||
@ValidateNested()
|
||||
@Type(() => Put)
|
||||
Input: IPut[];
|
||||
@ValidateNested()
|
||||
@Type(() => Put)
|
||||
Output: IPut[];
|
||||
}
|
||||
export class Setting implements ISetting {
|
||||
name: string;
|
||||
value: string | number;
|
||||
}
|
||||
export class Xxx implements IXxx {
|
||||
cameraLink: string;
|
||||
topicImage: string;
|
||||
topicCameraInfo: string;
|
||||
}
|
||||
export class SkillModelPoseEstimation implements ISkillPoseEstimation {
|
||||
@ValidateNested()
|
||||
@Type(() => SkillPackage)
|
||||
SkillPackage: ISkillPackage;
|
||||
@ValidateNested()
|
||||
@Type(() => Module)
|
||||
Module: IModule;
|
||||
@ValidateNested()
|
||||
@Type(() => Launch)
|
||||
Launch: ILaunch;
|
||||
@ValidateNested()
|
||||
@Type(() => Ros2)
|
||||
ROS2: IRos2;
|
||||
@ValidateNested()
|
||||
@IsArray()
|
||||
@Type(() => BTAction)
|
||||
BTAction: IBTAction[];
|
||||
@ValidateNested()
|
||||
@Type(() => Interface)
|
||||
Interface: IInterface;
|
||||
@ValidateNested()
|
||||
@IsArray()
|
||||
@Type(() => Setting)
|
||||
Settings: ISetting[];
|
||||
@ValidateNested()
|
||||
@Type(() => Xxx)
|
||||
xxx: IXxx;
|
||||
}
|
||||
|
||||
export class Skills {
|
||||
@IsArray()
|
||||
@Type(() => SkillModelPoseEstimation)
|
||||
skills: SkillModelPoseEstimation[];
|
||||
toSkillView(): ISkillView[] {
|
||||
return this.skills.map((el) => {
|
||||
return {
|
||||
name: el.Module.name,
|
||||
children: el.BTAction.map((act) => {
|
||||
// return { name: `${el.Module.name} - ${act.name}` };
|
||||
return { name: act.name, uuid: v4() };
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
getSkillDo(name: string) {
|
||||
return this.skills.reduce((acc, el) => {
|
||||
if (el.BTAction.find((el) => el.name.isEqual(name))) {
|
||||
acc = el.Module.name;
|
||||
}
|
||||
return acc;
|
||||
}, "error");
|
||||
}
|
||||
getSkillsNames() {
|
||||
return this.skills
|
||||
.map((el) => {
|
||||
return el.BTAction.map((act) => {
|
||||
return { name: act.name };
|
||||
});
|
||||
})
|
||||
.flat(1);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import DetailsScreen, { DetailsScreenPath } from "../../features/details/details
|
|||
import { AssemblesScreen, AssemblesScreenPath } from "../../features/assembles/assembles_screen";
|
||||
import SimulationScreen, { SimulationScreenPath } from "../../features/simulations/simulations_screen";
|
||||
import { EstimateScreen, EstimateScreenPath } from "../../features/estimate/estimate_screen";
|
||||
import { SkillPath, SkillScreen } from "../../features/skils/skills_screen";
|
||||
|
||||
const idURL = ":id";
|
||||
|
||||
|
@ -67,9 +68,12 @@ export const router = createBrowserRouter([
|
|||
path: SimulationScreenPath,
|
||||
element: <SimulationScreen />,
|
||||
},
|
||||
|
||||
{
|
||||
path: EstimateScreenPath,
|
||||
element: <EstimateScreen />,
|
||||
},
|
||||
{
|
||||
path: SkillPath,
|
||||
element: <SkillScreen />,
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -31,3 +31,6 @@ export function CoreButton(props: IButtonProps) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ import { DetailsScreenPath } from "../../../features/details/details_screen";
|
|||
import { SimulationScreenPath } from "../../../features/simulations/simulations_screen";
|
||||
import { EstimateScreenPath } from "../../../features/estimate/estimate_screen";
|
||||
import { BehaviorTreeBuilderPath } from "../../../features/behavior_tree_builder/presentation/behavior_tree_builder_screen";
|
||||
import { SkillPath as SkillScreenPath } from "../../../features/skils/skills_screen";
|
||||
export interface IBlockProps {
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
|
@ -45,6 +46,7 @@ const Block = (props: IBlockProps) => {
|
|||
export interface IMainPageProps {
|
||||
page: string;
|
||||
bodyChildren?: JSX.Element;
|
||||
panelChildren?: JSX.Element;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
export const MainPage = (props: IMainPageProps) => {
|
||||
|
@ -53,7 +55,8 @@ export const MainPage = (props: IMainPageProps) => {
|
|||
{ name: "Сборки", path: AssemblesScreenPath, icon: "Assembly" },
|
||||
{ name: "Датасеты", path: DatasetsScreenPath, icon: "Datasets" },
|
||||
{ name: "Сцена", path: SceneManagerPath, icon: "Layers" },
|
||||
{ name: "Навыки", path: BehaviorTreeBuilderPath, icon: "Rocket" },
|
||||
{ name: "Навыки", path: SkillScreenPath, icon: "Layers" },
|
||||
{ name: "Поведение", path: BehaviorTreeBuilderPath, icon: "Rocket" },
|
||||
{ name: "Симуляция", path: SimulationScreenPath, icon: "Simulation" },
|
||||
{ name: "Оценка", path: EstimateScreenPath, icon: "Grade" },
|
||||
];
|
||||
|
@ -118,7 +121,9 @@ export const MainPage = (props: IMainPageProps) => {
|
|||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div style={{ width: 241, height: window.innerHeight, backgroundColor: "#F7F2FA", borderRadius: 16 }}> </div>
|
||||
<div style={{ width: 241, height: window.innerHeight, backgroundColor: "#F7F2FA", borderRadius: 16 }}>
|
||||
{props.panelChildren}{" "}
|
||||
</div>
|
||||
{props.bodyChildren}
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { Result } from "../../../core/helper/result";
|
||||
import { Skills } from "../../../core/model/skill_model";
|
||||
import { HttpError, HttpMethod, HttpRepository } from "../../../core/repository/http_repository";
|
||||
|
||||
export class BehaviorTreeBuilderRepository extends HttpRepository {
|
||||
getBtSkills = async ():Promise<Result<HttpError, Skills>> => {
|
||||
return await this._jsonToClassInstanceRequest<Skills>(HttpMethod.GET, "/behavior/trees", Skills) as unknown as Promise<Result<HttpError, Skills>>;
|
||||
};
|
||||
}
|
|
@ -3,6 +3,7 @@ import { NodeEditor } from "rete";
|
|||
import { AreaExtra, Schemes } from "../presentation/ui/editor/editor";
|
||||
import { Result } from "../../../core/helper/result";
|
||||
import { AreaPlugin } from "rete-area-plugin";
|
||||
import { Skills } from "../../../core/model/skill_model";
|
||||
|
||||
export interface BtDrawDragAndDropView {
|
||||
x: number;
|
||||
|
@ -15,21 +16,31 @@ export class BtNodeView extends TypedEvent<BtDrawDragAndDropView> {}
|
|||
export class ReteObserver extends TypedEvent<any> {}
|
||||
export class BtBuilderModel {
|
||||
public static result = "";
|
||||
static fromReteScene(editor: NodeEditor<Schemes>, area: AreaPlugin<Schemes, AreaExtra>): Result<string, string> {
|
||||
static fromReteScene(
|
||||
editor: NodeEditor<Schemes>,
|
||||
area: AreaPlugin<Schemes, AreaExtra>,
|
||||
skills?: Skills
|
||||
): Result<string, string> {
|
||||
try {
|
||||
this.result = "";
|
||||
this.getFirstSequence(editor).map((sortedSequence) => {
|
||||
const firstNodeId = sortedSequence.getKeyFromValueIsExists(1) as string;
|
||||
this.findSequence(firstNodeId, editor, sortedSequence, 2);
|
||||
this.result += `<${this.getNodeLabelAtId(editor, firstNodeId)} id="${firstNodeId}">`;
|
||||
this.toXML(sortedSequence as Map<string, number>, editor, area, firstNodeId);
|
||||
this.result += `</${this.getNodeLabelAtId(editor, firstNodeId)}>`;
|
||||
this.result += `<${this.getNodeLabelAtId(editor, firstNodeId, skills)}>`;
|
||||
this.toXML(sortedSequence as Map<string, number>, editor, area, firstNodeId, skills);
|
||||
this.result += `</${this.getNodeLabelAtId(editor, firstNodeId, skills)}>`;
|
||||
});
|
||||
return Result.ok(this.result);
|
||||
} catch (error) {
|
||||
return Result.error("BtBuilderModel fromReteScene error");
|
||||
}
|
||||
}
|
||||
public static getNodeLabelAtId(editor: NodeEditor<Schemes>, id: string) {
|
||||
public static getNodeLabelAtId(editor: NodeEditor<Schemes>, id: string, skills?: Skills) {
|
||||
if (skills?.getSkillsNames().find((el) => el.name.isEqual(editor.getNode(id).label))) {
|
||||
return `Action ID="RbsBtAction" do="${skills.getSkillDo(editor.getNode(id).label)}" command="${
|
||||
editor.getNode(id).label
|
||||
}" server_name="rbs_interface" server_timeout="1000"`;
|
||||
}
|
||||
return editor.getNode(id).label;
|
||||
}
|
||||
|
||||
|
@ -37,18 +48,20 @@ export class BtBuilderModel {
|
|||
sortedSequence: Map<string, number>,
|
||||
editor: NodeEditor<Schemes>,
|
||||
area: AreaPlugin<Schemes, AreaExtra>,
|
||||
activeElementId = ""
|
||||
activeElementId = "",
|
||||
skills?: Skills
|
||||
) {
|
||||
editor.getConnections().forEach((el) => {
|
||||
if (el.source === activeElementId) {
|
||||
this.result += `<${this.getNodeLabelAtId(editor, el.target)} id="${el.target}">`;
|
||||
this.toXML(sortedSequence, editor, area, el.target);
|
||||
this.result += `<${this.getNodeLabelAtId(editor, el.target, skills)}>`;
|
||||
this.toXML(sortedSequence, editor, area, el.target, skills);
|
||||
this.result += `</${this.getNodeLabelAtId(editor, el.target)}>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static getBtPriorities(ids: string[]) {}
|
||||
|
||||
public static findSequence(
|
||||
nodeId: string,
|
||||
editor: NodeEditor<Schemes>,
|
||||
|
|
|
@ -1,51 +1,37 @@
|
|||
import * as React from "react";
|
||||
import { CoreText, CoreTextType } from "../../../core/ui/text/text";
|
||||
import { Button, Input } from "antd";
|
||||
|
||||
import { useRete } from "rete-react-plugin";
|
||||
import { createEditor } from "./ui/editor/editor";
|
||||
import { SkillTree } from "./ui/skill_tree/skill_tree";
|
||||
import { BehaviorTreeBuilderStore } from "./behavior_tree_builder_store";
|
||||
import { MainPage } from "../../../core/ui/pages/main_page";
|
||||
import { CoreButton } from "../../../core/ui/button/button";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
export const behaviorTreeBuilderScreenPath = "behavior/tree/screen/path";
|
||||
|
||||
const skills = {
|
||||
name: "",
|
||||
children: [
|
||||
{
|
||||
name: "Actions",
|
||||
children: [{ name: "MoveToPose", interface: "Vector3", out: "vo" }],
|
||||
},
|
||||
{
|
||||
name: "Control",
|
||||
children: [
|
||||
{ name: "Fallback", interface: "Vector3", out: "vo" },
|
||||
{ name: "Sequence", interface: "Vector3", out: "vo" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
export const behaviorTreeBuilderStore = new BehaviorTreeBuilderStore();
|
||||
|
||||
export const BehaviorTreeBuilderPath = "/behavior/tree/";
|
||||
export function BehaviorTreeBuilderScreen() {
|
||||
|
||||
export const BehaviorTreeBuilderScreen = observer(() => {
|
||||
const store = behaviorTreeBuilderStore;
|
||||
const [ref] = useRete(createEditor);
|
||||
// @ts-expect-error
|
||||
const [ref] = useRete<HTMLDivElement>(createEditor);
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
|
||||
store.dragZoneSetOffset(
|
||||
// @ts-expect-error
|
||||
ref.current.offsetTop,
|
||||
// @ts-expect-error
|
||||
ref.current.offsetLeft,
|
||||
// @ts-expect-error
|
||||
ref.current.clientWidth,
|
||||
// @ts-expect-error
|
||||
ref.current.clientHeight
|
||||
);
|
||||
|
||||
if (ref.current)
|
||||
store.dragZoneSetOffset(
|
||||
// @ts-expect-error
|
||||
ref.current.offsetTop,
|
||||
// @ts-expect-error
|
||||
ref.current.offsetLeft,
|
||||
// @ts-expect-error
|
||||
ref.current.clientWidth,
|
||||
// @ts-expect-error
|
||||
ref.current.clientHeight
|
||||
);
|
||||
return () => {
|
||||
store.dispose();
|
||||
};
|
||||
|
@ -54,11 +40,17 @@ export function BehaviorTreeBuilderScreen() {
|
|||
return (
|
||||
<MainPage
|
||||
page={"Навыки"}
|
||||
panelChildren={
|
||||
<>
|
||||
{store.skills ? <SkillTree skills={store.skillTree} dragEnd={store.dragEnd} /> : null}
|
||||
<div style={{ width: 100, height: 40 }}>
|
||||
<CoreButton onClick={() => store.saveBt()} text="SAVE BT" />
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
bodyChildren={
|
||||
<>
|
||||
<div style={{ display: "flex", width: "100%" }}>
|
||||
{/* <SkillTree dragEnd={store.dragEnd} skills={skills} /> */}
|
||||
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
|
@ -72,4 +64,4 @@ export function BehaviorTreeBuilderScreen() {
|
|||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -7,6 +7,9 @@ import { NodeEditor } from "rete";
|
|||
import { AreaExtra, Schemes } from "./ui/editor/editor";
|
||||
import { AreaPlugin } from "rete-area-plugin";
|
||||
import { NodeBehaviorTree } from "../model/node_behavior_tree";
|
||||
import { BehaviorTreeBuilderRepository } from "../data/behavior_tree_builder_repository";
|
||||
import { Skills } from "../../../core/model/skill_model";
|
||||
import { ISkillView } from "./ui/skill_tree/skill_tree";
|
||||
|
||||
interface I2DArea {
|
||||
x: number;
|
||||
|
@ -20,9 +23,11 @@ export class BehaviorTreeBuilderStore extends UiErrorState<HttpError> {
|
|||
this.reteNode?.emit("200");
|
||||
}
|
||||
validateBt() {}
|
||||
skills?: Skills;
|
||||
area?: I2DArea;
|
||||
btNodeView: BtNodeView = new BtNodeView();
|
||||
reteNode?: ReteObserver;
|
||||
behaviorTreeBuilderRepository = new BehaviorTreeBuilderRepository();
|
||||
canRun = true;
|
||||
nodes: NodeBehaviorTree[] = [
|
||||
{
|
||||
|
@ -32,64 +37,24 @@ export class BehaviorTreeBuilderStore extends UiErrorState<HttpError> {
|
|||
inputs: ["a"],
|
||||
position: { x: -488.1303402823156, y: -227.90861570911895 },
|
||||
},
|
||||
{
|
||||
label: "Sequence",
|
||||
id: "2",
|
||||
outputs: ["a"],
|
||||
inputs: ["a"],
|
||||
connectTo: "1",
|
||||
position: { x: 119.95735514023244, y: -182.24902817216878 },
|
||||
},
|
||||
{
|
||||
label: "Sequence",
|
||||
id: "6",
|
||||
outputs: ["a"],
|
||||
inputs: ["a"],
|
||||
connectTo: "2",
|
||||
position: { x: 402.06111561958505, y: -100.97814086372247 },
|
||||
},
|
||||
{
|
||||
label: "MoveToPose",
|
||||
id: "7",
|
||||
outputs: ["a"],
|
||||
inputs: ["a"],
|
||||
connectTo: "6",
|
||||
position: { x: 932.0688448287292, y: 90.10780461923443 },
|
||||
},
|
||||
{
|
||||
label: "MoveToPose",
|
||||
id: "8",
|
||||
outputs: ["a"],
|
||||
inputs: ["a"],
|
||||
connectTo: "6",
|
||||
position: { x: 898.1684213039546, y: -119.80545806921208 },
|
||||
},
|
||||
{
|
||||
label: "MoveToPose",
|
||||
id: "3",
|
||||
outputs: [],
|
||||
inputs: ["a"],
|
||||
connectTo: "1",
|
||||
position: { x: 208.65749743442188, y: 16.256489050033785 },
|
||||
},
|
||||
{
|
||||
label: "MoveToPose",
|
||||
id: "4",
|
||||
outputs: [],
|
||||
inputs: ["a"],
|
||||
connectTo: "1",
|
||||
position: { x: -50.46426323140673, y: 99.22642447650014 },
|
||||
},
|
||||
{
|
||||
label: "Sequence",
|
||||
id: "5",
|
||||
outputs: ["a"],
|
||||
inputs: ["a"],
|
||||
connectTo: "1",
|
||||
position: { x: -234.54554662642457, y: 245.4012710608967 },
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
skillTree: ISkillView = {
|
||||
name: "",
|
||||
children: [
|
||||
{
|
||||
name: "Actions",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "Control",
|
||||
children: [
|
||||
{ name: "Fallback", interface: "Vector3", out: "vo" },
|
||||
{ name: "Sequence", interface: "Vector3", out: "vo" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
|
@ -99,10 +64,9 @@ export class BehaviorTreeBuilderStore extends UiErrorState<HttpError> {
|
|||
JSON.parse(value) as BtNodeView[];
|
||||
}
|
||||
bt = async (editor: NodeEditor<Schemes>, area: AreaPlugin<Schemes, AreaExtra>) => {
|
||||
(await BtBuilderModel.fromReteScene(editor, area)).fold(
|
||||
(await BtBuilderModel.fromReteScene(editor, area, this.skills)).fold(
|
||||
(s) => {
|
||||
console.log(
|
||||
xmlFormat(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
console.log(xmlFormat(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root main_tree_to_execute="Main">
|
||||
<BehaviorTree ID="Main">
|
||||
${s}
|
||||
|
@ -117,15 +81,12 @@ export class BehaviorTreeBuilderStore extends UiErrorState<HttpError> {
|
|||
</Action>
|
||||
</TreeNodesModel>
|
||||
|
||||
</root>`)
|
||||
);
|
||||
</root>`));
|
||||
},
|
||||
(_) => _
|
||||
);
|
||||
};
|
||||
copyBt = () => {
|
||||
this.reteNode?.emit("200");
|
||||
};
|
||||
|
||||
errorHandingStrategy: (error: HttpError) => void;
|
||||
|
||||
dragEnd = (e: EventTarget) => {
|
||||
|
@ -155,7 +116,20 @@ export class BehaviorTreeBuilderStore extends UiErrorState<HttpError> {
|
|||
}
|
||||
}
|
||||
|
||||
async init(): Promise<any> {}
|
||||
async init(): Promise<any> {
|
||||
(await this.behaviorTreeBuilderRepository.getBtSkills()).fold(
|
||||
(model) => {
|
||||
this.skills = model;
|
||||
this.skillTree.children = this.skillTree.children?.map((el) => {
|
||||
if (el.name === "Actions") {
|
||||
el.children = model.toSkillView();
|
||||
}
|
||||
return el;
|
||||
});
|
||||
},
|
||||
(e) => console.log(e)
|
||||
);
|
||||
}
|
||||
dragZoneSetOffset(offsetTop: number, offsetWidth: number, width: number, height: number) {
|
||||
this.area = {
|
||||
x: offsetTop,
|
||||
|
|
|
@ -93,7 +93,7 @@ export function CustomNode<Scheme extends ClassicScheme>(props: Props<Scheme>) {
|
|||
const controls = Object.entries(props.data.controls);
|
||||
const selected = props.data.selected || false;
|
||||
const { id, label, width, height } = props.data;
|
||||
|
||||
console.log(label)
|
||||
sortByIndex(inputs);
|
||||
sortByIndex(outputs);
|
||||
sortByIndex(controls);
|
||||
|
|
|
@ -21,6 +21,7 @@ export async function createEditor(container: HTMLElement) {
|
|||
|
||||
behaviorTreeBuilderStore.btNodeView.on(async (event) => {
|
||||
setTimeout(async () => {
|
||||
console.log(event)
|
||||
const node = new ClassicPreset.Node(event.name);
|
||||
|
||||
const { x, y } = areaContainer.area.pointer;
|
||||
|
@ -33,6 +34,7 @@ export async function createEditor(container: HTMLElement) {
|
|||
});
|
||||
|
||||
observer.on(() => {
|
||||
console.log(200)
|
||||
behaviorTreeBuilderStore.bt(editor, areaContainer);
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ const { RefSocket, RefControl } = Presets.classic;
|
|||
type NodeExtraData = { width?: number; height?: number };
|
||||
|
||||
export const NodeStyles = styled.div<NodeExtraData & { selected: boolean; styles?: (props: any) => any }>`
|
||||
background: blue;
|
||||
background: red;
|
||||
border: 2px solid grey;
|
||||
|
||||
cursor: pointer;
|
||||
|
@ -97,7 +97,6 @@ export function SequenceNode<Scheme extends ClassicScheme>(props: Props<Scheme>)
|
|||
const selected = props.data.selected || false;
|
||||
|
||||
const { id, label, width, height } = props.data;
|
||||
|
||||
sortByIndex(inputs);
|
||||
sortByIndex(outputs);
|
||||
sortByIndex(controls);
|
||||
|
|
|
@ -2,8 +2,16 @@ import * as React from "react";
|
|||
import TreeView, { EventCallback, IBranchProps, INode, LeafProps, flattenTree } from "react-accessible-treeview";
|
||||
import { IFlatMetadata } from "react-accessible-treeview/dist/TreeView/utils";
|
||||
import { CallBackEventTarget } from "../../../../../core/extensions/extensions";
|
||||
|
||||
export interface ISkillView {
|
||||
name: string;
|
||||
children?: ISkillView[];
|
||||
id?: string;
|
||||
interface?: string;
|
||||
out?: string;
|
||||
}
|
||||
export interface ISkillTreeProps {
|
||||
skills: any;
|
||||
skills: ISkillView;
|
||||
dragEnd: CallBackEventTarget;
|
||||
}
|
||||
|
||||
|
@ -16,12 +24,12 @@ interface IRefListerProps {
|
|||
}
|
||||
|
||||
export const RefListener = (props: IRefListerProps) => {
|
||||
const ref = React.useRef<HTMLDataElement>(null);
|
||||
const ref = React.useRef<HTMLSpanElement>(null);
|
||||
React.useEffect(() => {
|
||||
if (ref.current) {
|
||||
ref.current.addEventListener("dragend", (e) => {
|
||||
// @ts-expect-error
|
||||
if (e.target.innerHTML) {
|
||||
if (e && e.target && e.target.innerHTML) {
|
||||
// @ts-expect-error
|
||||
props.dragEnd(e);
|
||||
}
|
||||
|
@ -36,13 +44,13 @@ export const RefListener = (props: IRefListerProps) => {
|
|||
props.handleSelect(e);
|
||||
}}
|
||||
/>
|
||||
<span ref={ref} style={{ color: "white" }} draggable="true">
|
||||
<span ref={ref} style={{ color: "black" }} draggable="true">
|
||||
{props.element.name}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export function SkillTree(props: ISkillTreeProps) {
|
||||
export const SkillTree = (props: ISkillTreeProps) => {
|
||||
return (
|
||||
<div>
|
||||
<TreeView
|
||||
|
@ -66,4 +74,4 @@ export function SkillTree(props: ISkillTreeProps) {
|
|||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
20
ui/src/features/skils/skills_screen.tsx
Normal file
20
ui/src/features/skils/skills_screen.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { MainPage } from "../../core/ui/pages/main_page";
|
||||
|
||||
export const SkillPath = "/skills";
|
||||
export const SkillScreen = () => {
|
||||
return (
|
||||
<>
|
||||
<MainPage
|
||||
page={"Навыки"}
|
||||
|
||||
bodyChildren={
|
||||
<>
|
||||
<div style={{ display: "flex", width: "100%" }}>
|
||||
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
3
ui/src/features/skils/skills_store.tsx
Normal file
3
ui/src/features/skils/skills_store.tsx
Normal file
|
@ -0,0 +1,3 @@
|
|||
export class SkillStore{
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@ export interface ISocketListerProps {
|
|||
export const SocketLister = observer((props: ISocketListerProps) => {
|
||||
return (
|
||||
<div>
|
||||
{socketListerStore.socketHasDisconnect ? (
|
||||
{/* {socketListerStore.socketHasDisconnect ? (
|
||||
<ReloadIcon
|
||||
onClick={() => {
|
||||
socketListerStore.reconnect();
|
||||
|
@ -25,7 +25,7 @@ export const SocketLister = observer((props: ISocketListerProps) => {
|
|||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
{props.children}
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue