refactor: reorganize package structure and decouple framework packages (#338)
* refactor: reorganize package structure and decouple framework packages ## Package Structure Reorganization - Reorganized 55 packages into categorized subdirectories: - packages/framework/ - Generic framework (Laya/Cocos compatible) - packages/engine/ - ESEngine core modules - packages/rendering/ - Rendering modules (WASM dependent) - packages/physics/ - Physics modules - packages/streaming/ - World streaming - packages/network-ext/ - Network extensions - packages/editor/ - Editor framework and plugins - packages/rust/ - Rust WASM engine - packages/tools/ - Build tools and SDK ## Framework Package Decoupling - Decoupled behavior-tree and blueprint packages from ESEngine dependencies - Created abstracted interfaces (IBTAssetManager, IBehaviorTreeAssetContent) - ESEngine-specific code moved to esengine/ subpath exports - Framework packages now usable with Cocos/Laya without ESEngine ## CI Configuration - Updated CI to only type-check and lint framework packages - Added type-check:framework and lint:framework scripts ## Breaking Changes - Package import paths changed due to directory reorganization - ESEngine integrations now use subpath imports (e.g., '@esengine/behavior-tree/esengine') * fix: update es-engine file path after directory reorganization * docs: update README to focus on framework over engine * ci: only build framework packages, remove Rust/WASM dependencies * fix: remove esengine subpath from behavior-tree and blueprint builds ESEngine integration code will only be available in full engine builds. Framework packages are now purely engine-agnostic. * fix: move network-protocols to framework, build both in CI * fix: update workflow paths from packages/core to packages/framework/core * fix: exclude esengine folder from type-check in behavior-tree and blueprint * fix: update network tsconfig references to new paths * fix: add test:ci:framework to only test framework packages in CI * fix: only build core and math npm packages in CI * fix: exclude test files from CodeQL and fix string escaping security issue
This commit is contained in:
91
packages/framework/blueprint/src/nodes/debug/Print.ts
Normal file
91
packages/framework/blueprint/src/nodes/debug/Print.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Print Node - Outputs a message for debugging
|
||||
* 打印节点 - 输出调试消息
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* Print node template
|
||||
* Print 节点模板
|
||||
*/
|
||||
export const PrintTemplate: BlueprintNodeTemplate = {
|
||||
type: 'Print',
|
||||
title: 'Print String',
|
||||
category: 'debug',
|
||||
color: '#785EF0',
|
||||
description: 'Prints a message to the console for debugging (打印消息到控制台用于调试)',
|
||||
keywords: ['log', 'debug', 'console', 'output', 'print'],
|
||||
inputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
type: 'string',
|
||||
displayName: 'Message',
|
||||
defaultValue: 'Hello Blueprint!'
|
||||
},
|
||||
{
|
||||
name: 'printToScreen',
|
||||
type: 'bool',
|
||||
displayName: 'Print to Screen',
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
name: 'duration',
|
||||
type: 'float',
|
||||
displayName: 'Duration',
|
||||
defaultValue: 2.0
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Print node executor
|
||||
* Print 节点执行器
|
||||
*/
|
||||
@RegisterNode(PrintTemplate)
|
||||
export class PrintExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
const message = context.evaluateInput(node.id, 'message', 'Hello Blueprint!');
|
||||
const printToScreen = context.evaluateInput(node.id, 'printToScreen', true);
|
||||
const duration = context.evaluateInput(node.id, 'duration', 2.0);
|
||||
|
||||
// Console output
|
||||
// 控制台输出
|
||||
console.log(`[Blueprint] ${message}`);
|
||||
|
||||
// Screen output via event (handled by runtime)
|
||||
// 通过事件输出到屏幕(由运行时处理)
|
||||
if (printToScreen) {
|
||||
const event = new CustomEvent('blueprint:print', {
|
||||
detail: {
|
||||
message: String(message),
|
||||
duration: Number(duration),
|
||||
entityId: context.entity.id,
|
||||
entityName: context.entity.name
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
nextExec: 'exec'
|
||||
};
|
||||
}
|
||||
}
|
||||
6
packages/framework/blueprint/src/nodes/debug/index.ts
Normal file
6
packages/framework/blueprint/src/nodes/debug/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Debug Nodes - Tools for debugging blueprints
|
||||
* 调试节点 - 蓝图调试工具
|
||||
*/
|
||||
|
||||
export * from './Print';
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Event Begin Play Node - Triggered when the blueprint starts
|
||||
* 开始播放事件节点 - 蓝图启动时触发
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* EventBeginPlay node template
|
||||
* EventBeginPlay 节点模板
|
||||
*/
|
||||
export const EventBeginPlayTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventBeginPlay',
|
||||
title: 'Event Begin Play',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered once when the blueprint starts executing (蓝图开始执行时触发一次)',
|
||||
keywords: ['start', 'begin', 'init', 'event'],
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* EventBeginPlay node executor
|
||||
* EventBeginPlay 节点执行器
|
||||
*/
|
||||
@RegisterNode(EventBeginPlayTemplate)
|
||||
export class EventBeginPlayExecutor implements INodeExecutor {
|
||||
execute(_node: BlueprintNode, _context: ExecutionContext): ExecutionResult {
|
||||
// Event nodes just trigger execution flow
|
||||
// 事件节点只触发执行流
|
||||
return {
|
||||
nextExec: 'exec'
|
||||
};
|
||||
}
|
||||
}
|
||||
118
packages/framework/blueprint/src/nodes/events/EventCollision.ts
Normal file
118
packages/framework/blueprint/src/nodes/events/EventCollision.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @zh 碰撞事件节点 - 碰撞发生时触发
|
||||
* @en Event Collision Node - Triggered on collision events
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* @zh EventCollisionEnter 节点模板
|
||||
* @en EventCollisionEnter node template
|
||||
*/
|
||||
export const EventCollisionEnterTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventCollisionEnter',
|
||||
title: 'Event Collision Enter',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered when collision starts / 碰撞开始时触发',
|
||||
keywords: ['collision', 'enter', 'hit', 'overlap', 'event'],
|
||||
menuPath: ['Event', 'Collision', 'Enter'],
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'otherEntityId',
|
||||
type: 'string',
|
||||
displayName: 'Other Entity'
|
||||
},
|
||||
{
|
||||
name: 'pointX',
|
||||
type: 'float',
|
||||
displayName: 'Point X'
|
||||
},
|
||||
{
|
||||
name: 'pointY',
|
||||
type: 'float',
|
||||
displayName: 'Point Y'
|
||||
},
|
||||
{
|
||||
name: 'normalX',
|
||||
type: 'float',
|
||||
displayName: 'Normal X'
|
||||
},
|
||||
{
|
||||
name: 'normalY',
|
||||
type: 'float',
|
||||
displayName: 'Normal Y'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh EventCollisionEnter 节点执行器
|
||||
* @en EventCollisionEnter node executor
|
||||
*/
|
||||
@RegisterNode(EventCollisionEnterTemplate)
|
||||
export class EventCollisionEnterExecutor implements INodeExecutor {
|
||||
execute(_node: BlueprintNode): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
outputs: {
|
||||
otherEntityId: '',
|
||||
pointX: 0,
|
||||
pointY: 0,
|
||||
normalX: 0,
|
||||
normalY: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh EventCollisionExit 节点模板
|
||||
* @en EventCollisionExit node template
|
||||
*/
|
||||
export const EventCollisionExitTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventCollisionExit',
|
||||
title: 'Event Collision Exit',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered when collision ends / 碰撞结束时触发',
|
||||
keywords: ['collision', 'exit', 'end', 'separate', 'event'],
|
||||
menuPath: ['Event', 'Collision', 'Exit'],
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'otherEntityId',
|
||||
type: 'string',
|
||||
displayName: 'Other Entity'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh EventCollisionExit 节点执行器
|
||||
* @en EventCollisionExit node executor
|
||||
*/
|
||||
@RegisterNode(EventCollisionExitTemplate)
|
||||
export class EventCollisionExitExecutor implements INodeExecutor {
|
||||
execute(_node: BlueprintNode): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
outputs: {
|
||||
otherEntityId: ''
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Event End Play Node - Triggered when the blueprint stops
|
||||
* 结束播放事件节点 - 蓝图停止时触发
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* EventEndPlay node template
|
||||
* EventEndPlay 节点模板
|
||||
*/
|
||||
export const EventEndPlayTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventEndPlay',
|
||||
title: 'Event End Play',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered once when the blueprint stops executing (蓝图停止执行时触发一次)',
|
||||
keywords: ['stop', 'end', 'destroy', 'event'],
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* EventEndPlay node executor
|
||||
* EventEndPlay 节点执行器
|
||||
*/
|
||||
@RegisterNode(EventEndPlayTemplate)
|
||||
export class EventEndPlayExecutor implements INodeExecutor {
|
||||
execute(_node: BlueprintNode, _context: ExecutionContext): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec'
|
||||
};
|
||||
}
|
||||
}
|
||||
79
packages/framework/blueprint/src/nodes/events/EventInput.ts
Normal file
79
packages/framework/blueprint/src/nodes/events/EventInput.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @zh 输入事件节点 - 输入触发时触发
|
||||
* @en Event Input Node - Triggered on input events
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* @zh EventInput 节点模板
|
||||
* @en EventInput node template
|
||||
*/
|
||||
export const EventInputTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventInput',
|
||||
title: 'Event Input',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered when input action occurs / 输入动作发生时触发',
|
||||
keywords: ['input', 'key', 'button', 'action', 'event'],
|
||||
menuPath: ['Event', 'Input'],
|
||||
inputs: [
|
||||
{
|
||||
name: 'action',
|
||||
type: 'string',
|
||||
displayName: 'Action',
|
||||
defaultValue: ''
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'action',
|
||||
type: 'string',
|
||||
displayName: 'Action'
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
type: 'float',
|
||||
displayName: 'Value'
|
||||
},
|
||||
{
|
||||
name: 'pressed',
|
||||
type: 'bool',
|
||||
displayName: 'Pressed'
|
||||
},
|
||||
{
|
||||
name: 'released',
|
||||
type: 'bool',
|
||||
displayName: 'Released'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh EventInput 节点执行器
|
||||
* @en EventInput node executor
|
||||
*
|
||||
* @zh 注意:事件节点的输出由 VM 在触发时通过 setOutputs 设置
|
||||
* @en Note: Event node outputs are set by VM via setOutputs when triggered
|
||||
*/
|
||||
@RegisterNode(EventInputTemplate)
|
||||
export class EventInputExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode, _context: ExecutionContext): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
outputs: {
|
||||
action: node.data?.action ?? '',
|
||||
value: 0,
|
||||
pressed: false,
|
||||
released: false
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @zh 消息事件节点 - 接收消息时触发
|
||||
* @en Event Message Node - Triggered when message is received
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* @zh EventMessage 节点模板
|
||||
* @en EventMessage node template
|
||||
*/
|
||||
export const EventMessageTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventMessage',
|
||||
title: 'Event Message',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered when a message is received / 接收到消息时触发',
|
||||
keywords: ['message', 'receive', 'broadcast', 'event', 'signal'],
|
||||
menuPath: ['Event', 'Message'],
|
||||
inputs: [
|
||||
{
|
||||
name: 'messageName',
|
||||
type: 'string',
|
||||
displayName: 'Message Name',
|
||||
defaultValue: ''
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'messageName',
|
||||
type: 'string',
|
||||
displayName: 'Message'
|
||||
},
|
||||
{
|
||||
name: 'senderId',
|
||||
type: 'string',
|
||||
displayName: 'Sender ID'
|
||||
},
|
||||
{
|
||||
name: 'payload',
|
||||
type: 'any',
|
||||
displayName: 'Payload'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh EventMessage 节点执行器
|
||||
* @en EventMessage node executor
|
||||
*/
|
||||
@RegisterNode(EventMessageTemplate)
|
||||
export class EventMessageExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
outputs: {
|
||||
messageName: node.data?.messageName ?? '',
|
||||
senderId: '',
|
||||
payload: null
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
132
packages/framework/blueprint/src/nodes/events/EventState.ts
Normal file
132
packages/framework/blueprint/src/nodes/events/EventState.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @zh 状态事件节点 - 状态机状态变化时触发
|
||||
* @en Event State Node - Triggered on state machine state changes
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* @zh EventStateEnter 节点模板
|
||||
* @en EventStateEnter node template
|
||||
*/
|
||||
export const EventStateEnterTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventStateEnter',
|
||||
title: 'Event State Enter',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered when entering a state / 进入状态时触发',
|
||||
keywords: ['state', 'enter', 'fsm', 'machine', 'event'],
|
||||
menuPath: ['Event', 'State', 'Enter'],
|
||||
inputs: [
|
||||
{
|
||||
name: 'stateName',
|
||||
type: 'string',
|
||||
displayName: 'State Name',
|
||||
defaultValue: ''
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'stateMachineId',
|
||||
type: 'string',
|
||||
displayName: 'State Machine'
|
||||
},
|
||||
{
|
||||
name: 'currentState',
|
||||
type: 'string',
|
||||
displayName: 'Current State'
|
||||
},
|
||||
{
|
||||
name: 'previousState',
|
||||
type: 'string',
|
||||
displayName: 'Previous State'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh EventStateEnter 节点执行器
|
||||
* @en EventStateEnter node executor
|
||||
*/
|
||||
@RegisterNode(EventStateEnterTemplate)
|
||||
export class EventStateEnterExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
outputs: {
|
||||
stateMachineId: '',
|
||||
currentState: node.data?.stateName ?? '',
|
||||
previousState: ''
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh EventStateExit 节点模板
|
||||
* @en EventStateExit node template
|
||||
*/
|
||||
export const EventStateExitTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventStateExit',
|
||||
title: 'Event State Exit',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered when exiting a state / 退出状态时触发',
|
||||
keywords: ['state', 'exit', 'leave', 'fsm', 'machine', 'event'],
|
||||
menuPath: ['Event', 'State', 'Exit'],
|
||||
inputs: [
|
||||
{
|
||||
name: 'stateName',
|
||||
type: 'string',
|
||||
displayName: 'State Name',
|
||||
defaultValue: ''
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'stateMachineId',
|
||||
type: 'string',
|
||||
displayName: 'State Machine'
|
||||
},
|
||||
{
|
||||
name: 'currentState',
|
||||
type: 'string',
|
||||
displayName: 'Current State'
|
||||
},
|
||||
{
|
||||
name: 'previousState',
|
||||
type: 'string',
|
||||
displayName: 'Previous State'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh EventStateExit 节点执行器
|
||||
* @en EventStateExit node executor
|
||||
*/
|
||||
@RegisterNode(EventStateExitTemplate)
|
||||
export class EventStateExitExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
outputs: {
|
||||
stateMachineId: '',
|
||||
currentState: '',
|
||||
previousState: node.data?.stateName ?? ''
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
50
packages/framework/blueprint/src/nodes/events/EventTick.ts
Normal file
50
packages/framework/blueprint/src/nodes/events/EventTick.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Event Tick Node - Triggered every frame
|
||||
* 每帧事件节点 - 每帧触发
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* EventTick node template
|
||||
* EventTick 节点模板
|
||||
*/
|
||||
export const EventTickTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventTick',
|
||||
title: 'Event Tick',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered every frame during execution (执行期间每帧触发)',
|
||||
keywords: ['update', 'frame', 'tick', 'event'],
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'deltaTime',
|
||||
type: 'float',
|
||||
displayName: 'Delta Seconds'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* EventTick node executor
|
||||
* EventTick 节点执行器
|
||||
*/
|
||||
@RegisterNode(EventTickTemplate)
|
||||
export class EventTickExecutor implements INodeExecutor {
|
||||
execute(_node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
outputs: {
|
||||
deltaTime: context.deltaTime
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
70
packages/framework/blueprint/src/nodes/events/EventTimer.ts
Normal file
70
packages/framework/blueprint/src/nodes/events/EventTimer.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @zh 定时器事件节点 - 定时器触发时调用
|
||||
* @en Event Timer Node - Triggered when timer fires
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* @zh EventTimer 节点模板
|
||||
* @en EventTimer node template
|
||||
*/
|
||||
export const EventTimerTemplate: BlueprintNodeTemplate = {
|
||||
type: 'EventTimer',
|
||||
title: 'Event Timer',
|
||||
category: 'event',
|
||||
color: '#CC0000',
|
||||
description: 'Triggered when a timer fires / 定时器触发时执行',
|
||||
keywords: ['timer', 'delay', 'schedule', 'event', 'interval'],
|
||||
menuPath: ['Event', 'Timer'],
|
||||
inputs: [
|
||||
{
|
||||
name: 'timerId',
|
||||
type: 'string',
|
||||
displayName: 'Timer ID',
|
||||
defaultValue: ''
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'timerId',
|
||||
type: 'string',
|
||||
displayName: 'Timer ID'
|
||||
},
|
||||
{
|
||||
name: 'isRepeating',
|
||||
type: 'bool',
|
||||
displayName: 'Is Repeating'
|
||||
},
|
||||
{
|
||||
name: 'timesFired',
|
||||
type: 'int',
|
||||
displayName: 'Times Fired'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* @zh EventTimer 节点执行器
|
||||
* @en EventTimer node executor
|
||||
*/
|
||||
@RegisterNode(EventTimerTemplate)
|
||||
export class EventTimerExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode): ExecutionResult {
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
outputs: {
|
||||
timerId: node.data?.timerId ?? '',
|
||||
isRepeating: false,
|
||||
timesFired: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
16
packages/framework/blueprint/src/nodes/events/index.ts
Normal file
16
packages/framework/blueprint/src/nodes/events/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @zh 事件节点 - 蓝图执行的入口点
|
||||
* @en Event Nodes - Entry points for blueprint execution
|
||||
*/
|
||||
|
||||
// 生命周期事件 | Lifecycle events
|
||||
export * from './EventBeginPlay';
|
||||
export * from './EventTick';
|
||||
export * from './EventEndPlay';
|
||||
|
||||
// 触发器事件 | Trigger events
|
||||
export * from './EventInput';
|
||||
export * from './EventCollision';
|
||||
export * from './EventMessage';
|
||||
export * from './EventTimer';
|
||||
export * from './EventState';
|
||||
11
packages/framework/blueprint/src/nodes/index.ts
Normal file
11
packages/framework/blueprint/src/nodes/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Blueprint Nodes - All node definitions and executors
|
||||
* 蓝图节点 - 所有节点定义和执行器
|
||||
*/
|
||||
|
||||
// Import all nodes to trigger registration
|
||||
// 导入所有节点以触发注册
|
||||
export * from './events';
|
||||
export * from './debug';
|
||||
export * from './time';
|
||||
export * from './math';
|
||||
122
packages/framework/blueprint/src/nodes/math/MathOperations.ts
Normal file
122
packages/framework/blueprint/src/nodes/math/MathOperations.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Math Operation Nodes - Basic arithmetic operations
|
||||
* 数学运算节点 - 基础算术运算
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
// Add Node (加法节点)
|
||||
export const AddTemplate: BlueprintNodeTemplate = {
|
||||
type: 'Add',
|
||||
title: 'Add',
|
||||
category: 'math',
|
||||
color: '#4CAF50',
|
||||
description: 'Adds two numbers together (将两个数字相加)',
|
||||
keywords: ['add', 'plus', 'sum', '+', 'math'],
|
||||
isPure: true,
|
||||
inputs: [
|
||||
{ name: 'a', type: 'float', displayName: 'A', defaultValue: 0 },
|
||||
{ name: 'b', type: 'float', displayName: 'B', defaultValue: 0 }
|
||||
],
|
||||
outputs: [
|
||||
{ name: 'result', type: 'float', displayName: 'Result' }
|
||||
]
|
||||
};
|
||||
|
||||
@RegisterNode(AddTemplate)
|
||||
export class AddExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
const a = Number(context.evaluateInput(node.id, 'a', 0));
|
||||
const b = Number(context.evaluateInput(node.id, 'b', 0));
|
||||
return { outputs: { result: a + b } };
|
||||
}
|
||||
}
|
||||
|
||||
// Subtract Node (减法节点)
|
||||
export const SubtractTemplate: BlueprintNodeTemplate = {
|
||||
type: 'Subtract',
|
||||
title: 'Subtract',
|
||||
category: 'math',
|
||||
color: '#4CAF50',
|
||||
description: 'Subtracts B from A (从 A 减去 B)',
|
||||
keywords: ['subtract', 'minus', '-', 'math'],
|
||||
isPure: true,
|
||||
inputs: [
|
||||
{ name: 'a', type: 'float', displayName: 'A', defaultValue: 0 },
|
||||
{ name: 'b', type: 'float', displayName: 'B', defaultValue: 0 }
|
||||
],
|
||||
outputs: [
|
||||
{ name: 'result', type: 'float', displayName: 'Result' }
|
||||
]
|
||||
};
|
||||
|
||||
@RegisterNode(SubtractTemplate)
|
||||
export class SubtractExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
const a = Number(context.evaluateInput(node.id, 'a', 0));
|
||||
const b = Number(context.evaluateInput(node.id, 'b', 0));
|
||||
return { outputs: { result: a - b } };
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply Node (乘法节点)
|
||||
export const MultiplyTemplate: BlueprintNodeTemplate = {
|
||||
type: 'Multiply',
|
||||
title: 'Multiply',
|
||||
category: 'math',
|
||||
color: '#4CAF50',
|
||||
description: 'Multiplies two numbers (将两个数字相乘)',
|
||||
keywords: ['multiply', 'times', '*', 'math'],
|
||||
isPure: true,
|
||||
inputs: [
|
||||
{ name: 'a', type: 'float', displayName: 'A', defaultValue: 0 },
|
||||
{ name: 'b', type: 'float', displayName: 'B', defaultValue: 1 }
|
||||
],
|
||||
outputs: [
|
||||
{ name: 'result', type: 'float', displayName: 'Result' }
|
||||
]
|
||||
};
|
||||
|
||||
@RegisterNode(MultiplyTemplate)
|
||||
export class MultiplyExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
const a = Number(context.evaluateInput(node.id, 'a', 0));
|
||||
const b = Number(context.evaluateInput(node.id, 'b', 1));
|
||||
return { outputs: { result: a * b } };
|
||||
}
|
||||
}
|
||||
|
||||
// Divide Node (除法节点)
|
||||
export const DivideTemplate: BlueprintNodeTemplate = {
|
||||
type: 'Divide',
|
||||
title: 'Divide',
|
||||
category: 'math',
|
||||
color: '#4CAF50',
|
||||
description: 'Divides A by B (A 除以 B)',
|
||||
keywords: ['divide', '/', 'math'],
|
||||
isPure: true,
|
||||
inputs: [
|
||||
{ name: 'a', type: 'float', displayName: 'A', defaultValue: 0 },
|
||||
{ name: 'b', type: 'float', displayName: 'B', defaultValue: 1 }
|
||||
],
|
||||
outputs: [
|
||||
{ name: 'result', type: 'float', displayName: 'Result' }
|
||||
]
|
||||
};
|
||||
|
||||
@RegisterNode(DivideTemplate)
|
||||
export class DivideExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
const a = Number(context.evaluateInput(node.id, 'a', 0));
|
||||
const b = Number(context.evaluateInput(node.id, 'b', 1));
|
||||
|
||||
// Prevent division by zero (防止除零)
|
||||
if (b === 0) {
|
||||
return { outputs: { result: 0 } };
|
||||
}
|
||||
|
||||
return { outputs: { result: a / b } };
|
||||
}
|
||||
}
|
||||
6
packages/framework/blueprint/src/nodes/math/index.ts
Normal file
6
packages/framework/blueprint/src/nodes/math/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Math Nodes - Mathematical operation nodes
|
||||
* 数学节点 - 数学运算节点
|
||||
*/
|
||||
|
||||
export * from './MathOperations';
|
||||
57
packages/framework/blueprint/src/nodes/time/Delay.ts
Normal file
57
packages/framework/blueprint/src/nodes/time/Delay.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Delay Node - Pauses execution for a specified duration
|
||||
* 延迟节点 - 暂停执行指定的时长
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* Delay node template
|
||||
* Delay 节点模板
|
||||
*/
|
||||
export const DelayTemplate: BlueprintNodeTemplate = {
|
||||
type: 'Delay',
|
||||
title: 'Delay',
|
||||
category: 'flow',
|
||||
color: '#FFFFFF',
|
||||
description: 'Pauses execution for a specified number of seconds (暂停执行指定的秒数)',
|
||||
keywords: ['wait', 'delay', 'pause', 'sleep', 'timer'],
|
||||
inputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: ''
|
||||
},
|
||||
{
|
||||
name: 'duration',
|
||||
type: 'float',
|
||||
displayName: 'Duration',
|
||||
defaultValue: 1.0
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'exec',
|
||||
type: 'exec',
|
||||
displayName: 'Completed'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Delay node executor
|
||||
* Delay 节点执行器
|
||||
*/
|
||||
@RegisterNode(DelayTemplate)
|
||||
export class DelayExecutor implements INodeExecutor {
|
||||
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
const duration = context.evaluateInput(node.id, 'duration', 1.0) as number;
|
||||
|
||||
return {
|
||||
nextExec: 'exec',
|
||||
delay: duration
|
||||
};
|
||||
}
|
||||
}
|
||||
45
packages/framework/blueprint/src/nodes/time/GetDeltaTime.ts
Normal file
45
packages/framework/blueprint/src/nodes/time/GetDeltaTime.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Get Delta Time Node - Returns the time since last frame
|
||||
* 获取增量时间节点 - 返回上一帧以来的时间
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* GetDeltaTime node template
|
||||
* GetDeltaTime 节点模板
|
||||
*/
|
||||
export const GetDeltaTimeTemplate: BlueprintNodeTemplate = {
|
||||
type: 'GetDeltaTime',
|
||||
title: 'Get Delta Time',
|
||||
category: 'time',
|
||||
color: '#4FC3F7',
|
||||
description: 'Returns the time elapsed since the last frame in seconds (返回上一帧以来经过的时间,单位秒)',
|
||||
keywords: ['delta', 'time', 'frame', 'dt'],
|
||||
isPure: true,
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'deltaTime',
|
||||
type: 'float',
|
||||
displayName: 'Delta Seconds'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* GetDeltaTime node executor
|
||||
* GetDeltaTime 节点执行器
|
||||
*/
|
||||
@RegisterNode(GetDeltaTimeTemplate)
|
||||
export class GetDeltaTimeExecutor implements INodeExecutor {
|
||||
execute(_node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
return {
|
||||
outputs: {
|
||||
deltaTime: context.deltaTime
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
45
packages/framework/blueprint/src/nodes/time/GetTime.ts
Normal file
45
packages/framework/blueprint/src/nodes/time/GetTime.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Get Time Node - Returns the total time since blueprint started
|
||||
* 获取时间节点 - 返回蓝图启动以来的总时间
|
||||
*/
|
||||
|
||||
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
|
||||
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
|
||||
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
|
||||
|
||||
/**
|
||||
* GetTime node template
|
||||
* GetTime 节点模板
|
||||
*/
|
||||
export const GetTimeTemplate: BlueprintNodeTemplate = {
|
||||
type: 'GetTime',
|
||||
title: 'Get Game Time',
|
||||
category: 'time',
|
||||
color: '#4FC3F7',
|
||||
description: 'Returns the total time since the blueprint started in seconds (返回蓝图启动以来的总时间,单位秒)',
|
||||
keywords: ['time', 'total', 'elapsed', 'game'],
|
||||
isPure: true,
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'time',
|
||||
type: 'float',
|
||||
displayName: 'Seconds'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* GetTime node executor
|
||||
* GetTime 节点执行器
|
||||
*/
|
||||
@RegisterNode(GetTimeTemplate)
|
||||
export class GetTimeExecutor implements INodeExecutor {
|
||||
execute(_node: BlueprintNode, context: ExecutionContext): ExecutionResult {
|
||||
return {
|
||||
outputs: {
|
||||
time: context.time
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
8
packages/framework/blueprint/src/nodes/time/index.ts
Normal file
8
packages/framework/blueprint/src/nodes/time/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Time Nodes - Time-related utility nodes
|
||||
* 时间节点 - 时间相关的工具节点
|
||||
*/
|
||||
|
||||
export * from './GetDeltaTime';
|
||||
export * from './GetTime';
|
||||
export * from './Delay';
|
||||
Reference in New Issue
Block a user