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:
@@ -0,0 +1,85 @@
|
||||
import {RawDebugRenderPipeline} from "../raw";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
IntegrationParameters,
|
||||
IslandManager,
|
||||
ImpulseJointSet,
|
||||
MultibodyJointSet,
|
||||
RigidBodySet,
|
||||
} from "../dynamics";
|
||||
import {BroadPhase, Collider, ColliderSet, NarrowPhase} from "../geometry";
|
||||
import {QueryFilterFlags} from "./query_pipeline";
|
||||
|
||||
/**
|
||||
* The vertex and color buffers for debug-redering the physics scene.
|
||||
*/
|
||||
export class DebugRenderBuffers {
|
||||
/**
|
||||
* The lines to render. This is a flat array containing all the lines
|
||||
* to render. Each line is described as two consecutive point. Each
|
||||
* point is described as two (in 2D) or three (in 3D) consecutive
|
||||
* floats. For example, in 2D, the array: `[1, 2, 3, 4, 5, 6, 7, 8]`
|
||||
* describes the two segments `[[1, 2], [3, 4]]` and `[[5, 6], [7, 8]]`.
|
||||
*/
|
||||
public vertices: Float32Array;
|
||||
/**
|
||||
* The color buffer. There is one color per vertex, and each color
|
||||
* has four consecutive components (in RGBA format).
|
||||
*/
|
||||
public colors: Float32Array;
|
||||
|
||||
constructor(vertices: Float32Array, colors: Float32Array) {
|
||||
this.vertices = vertices;
|
||||
this.colors = colors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pipeline for rendering the physics scene.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `debugRenderPipeline.free()`
|
||||
* once you are done using it (and all the rigid-bodies it created).
|
||||
*/
|
||||
export class DebugRenderPipeline {
|
||||
raw: RawDebugRenderPipeline;
|
||||
public vertices: Float32Array;
|
||||
public colors: Float32Array;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this serialization pipeline.
|
||||
*/
|
||||
free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
this.vertices = undefined;
|
||||
this.colors = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawDebugRenderPipeline) {
|
||||
this.raw = raw || new RawDebugRenderPipeline();
|
||||
}
|
||||
|
||||
public render(
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
impulse_joints: ImpulseJointSet,
|
||||
multibody_joints: MultibodyJointSet,
|
||||
narrow_phase: NarrowPhase,
|
||||
filterFlags?: QueryFilterFlags,
|
||||
filterPredicate?: (collider: Collider) => boolean,
|
||||
) {
|
||||
this.raw.render(
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
impulse_joints.raw,
|
||||
multibody_joints.raw,
|
||||
narrow_phase.raw,
|
||||
filterFlags,
|
||||
colliders.castClosure(filterPredicate),
|
||||
);
|
||||
this.vertices = this.raw.vertices();
|
||||
this.colors = this.raw.colors();
|
||||
}
|
||||
}
|
||||
158
packages/physics/rapier2d/src/pipeline/event_queue.ts
Normal file
158
packages/physics/rapier2d/src/pipeline/event_queue.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import {RawContactForceEvent, RawEventQueue} from "../raw";
|
||||
import {RigidBodyHandle} from "../dynamics";
|
||||
import {Collider, ColliderHandle} from "../geometry";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
|
||||
/**
|
||||
* Flags indicating what events are enabled for colliders.
|
||||
*/
|
||||
export enum ActiveEvents {
|
||||
NONE = 0,
|
||||
/**
|
||||
* Enable collision events.
|
||||
*/
|
||||
COLLISION_EVENTS = 0b0001,
|
||||
/**
|
||||
* Enable contact force events.
|
||||
*/
|
||||
CONTACT_FORCE_EVENTS = 0b0010,
|
||||
}
|
||||
|
||||
/**
|
||||
* Event occurring when the sum of the magnitudes of the
|
||||
* contact forces between two colliders exceed a threshold.
|
||||
*
|
||||
* This object should **not** be stored anywhere. Its properties can only be
|
||||
* read from within the closure given to `EventHandler.drainContactForceEvents`.
|
||||
*/
|
||||
export class TempContactForceEvent {
|
||||
raw: RawContactForceEvent;
|
||||
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The first collider involved in the contact.
|
||||
*/
|
||||
public collider1(): ColliderHandle {
|
||||
return this.raw.collider1();
|
||||
}
|
||||
|
||||
/**
|
||||
* The second collider involved in the contact.
|
||||
*/
|
||||
public collider2(): ColliderHandle {
|
||||
return this.raw.collider2();
|
||||
}
|
||||
|
||||
/**
|
||||
* The sum of all the forces between the two colliders.
|
||||
*/
|
||||
public totalForce(): Vector {
|
||||
return VectorOps.fromRaw(this.raw.total_force());
|
||||
}
|
||||
|
||||
/**
|
||||
* The sum of the magnitudes of each force between the two colliders.
|
||||
*
|
||||
* Note that this is **not** the same as the magnitude of `self.total_force`.
|
||||
* Here we are summing the magnitude of all the forces, instead of taking
|
||||
* the magnitude of their sum.
|
||||
*/
|
||||
public totalForceMagnitude(): number {
|
||||
return this.raw.total_force_magnitude();
|
||||
}
|
||||
|
||||
/**
|
||||
* The world-space (unit) direction of the force with strongest magnitude.
|
||||
*/
|
||||
public maxForceDirection(): Vector {
|
||||
return VectorOps.fromRaw(this.raw.max_force_direction());
|
||||
}
|
||||
|
||||
/**
|
||||
* The magnitude of the largest force at a contact point of this contact pair.
|
||||
*/
|
||||
public maxForceMagnitude(): number {
|
||||
return this.raw.max_force_magnitude();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A structure responsible for collecting events generated
|
||||
* by the physics engine.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `eventQueue.free()`
|
||||
* once you are done using it.
|
||||
*/
|
||||
export class EventQueue {
|
||||
raw: RawEventQueue;
|
||||
|
||||
/**
|
||||
* Creates a new event collector.
|
||||
*
|
||||
* @param autoDrain -setting this to `true` is strongly recommended. If true, the collector will
|
||||
* be automatically drained before each `world.step(collector)`. If false, the collector will
|
||||
* keep all events in memory unless it is manually drained/cleared; this may lead to unbounded use of
|
||||
* RAM if no drain is performed.
|
||||
*/
|
||||
constructor(autoDrain: boolean, raw?: RawEventQueue) {
|
||||
this.raw = raw || new RawEventQueue(autoDrain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this event-queue.
|
||||
*/
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given javascript closure on each collision event of this collector, then clear
|
||||
* the internal collision event buffer.
|
||||
*
|
||||
* @param f - JavaScript closure applied to each collision event. The
|
||||
* closure must take three arguments: two integers representing the handles of the colliders
|
||||
* involved in the collision, and a boolean indicating if the collision started (true) or stopped
|
||||
* (false).
|
||||
*/
|
||||
public drainCollisionEvents(
|
||||
f: (
|
||||
handle1: ColliderHandle,
|
||||
handle2: ColliderHandle,
|
||||
started: boolean,
|
||||
) => void,
|
||||
) {
|
||||
this.raw.drainCollisionEvents(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given javascript closure on each contact force event of this collector, then clear
|
||||
* the internal collision event buffer.
|
||||
*
|
||||
* @param f - JavaScript closure applied to each collision event. The
|
||||
* closure must take one `TempContactForceEvent` argument.
|
||||
*/
|
||||
public drainContactForceEvents(f: (event: TempContactForceEvent) => void) {
|
||||
let event = new TempContactForceEvent();
|
||||
this.raw.drainContactForceEvents((raw: RawContactForceEvent) => {
|
||||
event.raw = raw;
|
||||
f(event);
|
||||
event.free();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all events contained by this collector
|
||||
*/
|
||||
public clear() {
|
||||
this.raw.clear();
|
||||
}
|
||||
}
|
||||
7
packages/physics/rapier2d/src/pipeline/index.ts
Normal file
7
packages/physics/rapier2d/src/pipeline/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export * from "./world";
|
||||
export * from "./physics_pipeline";
|
||||
export * from "./serialization_pipeline";
|
||||
export * from "./event_queue";
|
||||
export * from "./physics_hooks";
|
||||
export * from "./debug_render_pipeline";
|
||||
export * from "./query_pipeline";
|
||||
54
packages/physics/rapier2d/src/pipeline/physics_hooks.ts
Normal file
54
packages/physics/rapier2d/src/pipeline/physics_hooks.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import {RigidBodyHandle} from "../dynamics";
|
||||
import {ColliderHandle} from "../geometry";
|
||||
|
||||
export enum ActiveHooks {
|
||||
NONE = 0,
|
||||
FILTER_CONTACT_PAIRS = 0b0001,
|
||||
FILTER_INTERSECTION_PAIRS = 0b0010,
|
||||
// MODIFY_SOLVER_CONTACTS = 0b0100, /* Not supported yet in JS. */
|
||||
}
|
||||
|
||||
export enum SolverFlags {
|
||||
EMPTY = 0b000,
|
||||
COMPUTE_IMPULSE = 0b001,
|
||||
}
|
||||
|
||||
export interface PhysicsHooks {
|
||||
/**
|
||||
* Function that determines if contacts computation should happen between two colliders, and how the
|
||||
* constraints solver should behave for these contacts.
|
||||
*
|
||||
* This will only be executed and taken into account if at least one of the involved colliders contains the
|
||||
* `ActiveHooks.FILTER_CONTACT_PAIR` flag in its active hooks.
|
||||
*
|
||||
* @param collider1 − Handle of the first collider involved in the potential contact.
|
||||
* @param collider2 − Handle of the second collider involved in the potential contact.
|
||||
* @param body1 − Handle of the first body involved in the potential contact.
|
||||
* @param body2 − Handle of the second body involved in the potential contact.
|
||||
*/
|
||||
filterContactPair(
|
||||
collider1: ColliderHandle,
|
||||
collider2: ColliderHandle,
|
||||
body1: RigidBodyHandle,
|
||||
body2: RigidBodyHandle,
|
||||
): SolverFlags | null;
|
||||
|
||||
/**
|
||||
* Function that determines if intersection computation should happen between two colliders (where at least
|
||||
* one is a sensor).
|
||||
*
|
||||
* This will only be executed and taken into account if `one of the involved colliders contains the
|
||||
* `ActiveHooks.FILTER_INTERSECTION_PAIR` flag in its active hooks.
|
||||
*
|
||||
* @param collider1 − Handle of the first collider involved in the potential contact.
|
||||
* @param collider2 − Handle of the second collider involved in the potential contact.
|
||||
* @param body1 − Handle of the first body involved in the potential contact.
|
||||
* @param body2 − Handle of the second body involved in the potential contact.
|
||||
*/
|
||||
filterIntersectionPair(
|
||||
collider1: ColliderHandle,
|
||||
collider2: ColliderHandle,
|
||||
body1: RigidBodyHandle,
|
||||
body2: RigidBodyHandle,
|
||||
): boolean;
|
||||
}
|
||||
85
packages/physics/rapier2d/src/pipeline/physics_pipeline.ts
Normal file
85
packages/physics/rapier2d/src/pipeline/physics_pipeline.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import {RawPhysicsPipeline} from "../raw";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
IntegrationParameters,
|
||||
ImpulseJointSet,
|
||||
MultibodyJointSet,
|
||||
RigidBodyHandle,
|
||||
RigidBodySet,
|
||||
CCDSolver,
|
||||
IslandManager,
|
||||
} from "../dynamics";
|
||||
import {
|
||||
BroadPhase,
|
||||
ColliderHandle,
|
||||
ColliderSet,
|
||||
NarrowPhase,
|
||||
} from "../geometry";
|
||||
import {EventQueue} from "./event_queue";
|
||||
import {PhysicsHooks} from "./physics_hooks";
|
||||
|
||||
export class PhysicsPipeline {
|
||||
raw: RawPhysicsPipeline;
|
||||
|
||||
public free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawPhysicsPipeline) {
|
||||
this.raw = raw || new RawPhysicsPipeline();
|
||||
}
|
||||
|
||||
public step(
|
||||
gravity: Vector,
|
||||
integrationParameters: IntegrationParameters,
|
||||
islands: IslandManager,
|
||||
broadPhase: BroadPhase,
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
impulseJoints: ImpulseJointSet,
|
||||
multibodyJoints: MultibodyJointSet,
|
||||
ccdSolver: CCDSolver,
|
||||
eventQueue?: EventQueue,
|
||||
hooks?: PhysicsHooks,
|
||||
) {
|
||||
let rawG = VectorOps.intoRaw(gravity);
|
||||
|
||||
if (!!eventQueue) {
|
||||
this.raw.stepWithEvents(
|
||||
rawG,
|
||||
integrationParameters.raw,
|
||||
islands.raw,
|
||||
broadPhase.raw,
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
impulseJoints.raw,
|
||||
multibodyJoints.raw,
|
||||
ccdSolver.raw,
|
||||
eventQueue.raw,
|
||||
hooks,
|
||||
!!hooks ? hooks.filterContactPair : null,
|
||||
!!hooks ? hooks.filterIntersectionPair : null,
|
||||
);
|
||||
} else {
|
||||
this.raw.step(
|
||||
rawG,
|
||||
integrationParameters.raw,
|
||||
islands.raw,
|
||||
broadPhase.raw,
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
impulseJoints.raw,
|
||||
multibodyJoints.raw,
|
||||
ccdSolver.raw,
|
||||
);
|
||||
}
|
||||
|
||||
rawG.free();
|
||||
}
|
||||
}
|
||||
57
packages/physics/rapier2d/src/pipeline/query_pipeline.ts
Normal file
57
packages/physics/rapier2d/src/pipeline/query_pipeline.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import {RawRayColliderIntersection} from "../raw";
|
||||
import {
|
||||
ColliderHandle,
|
||||
ColliderSet,
|
||||
InteractionGroups,
|
||||
PointColliderProjection,
|
||||
Ray,
|
||||
RayColliderIntersection,
|
||||
RayColliderHit,
|
||||
Shape,
|
||||
ColliderShapeCastHit,
|
||||
} from "../geometry";
|
||||
import {IslandManager, RigidBodyHandle, RigidBodySet} from "../dynamics";
|
||||
import {Rotation, RotationOps, Vector, VectorOps} from "../math";
|
||||
|
||||
// NOTE: must match the bits in the QueryFilterFlags on the Rust side.
|
||||
/**
|
||||
* Flags for excluding whole sets of colliders from a scene query.
|
||||
*/
|
||||
export enum QueryFilterFlags {
|
||||
/**
|
||||
* Exclude from the query any collider attached to a fixed rigid-body and colliders with no rigid-body attached.
|
||||
*/
|
||||
EXCLUDE_FIXED = 0b0000_0001,
|
||||
/**
|
||||
* Exclude from the query any collider attached to a dynamic rigid-body.
|
||||
*/
|
||||
EXCLUDE_KINEMATIC = 0b0000_0010,
|
||||
/**
|
||||
* Exclude from the query any collider attached to a kinematic rigid-body.
|
||||
*/
|
||||
EXCLUDE_DYNAMIC = 0b0000_0100,
|
||||
/**
|
||||
* Exclude from the query any collider that is a sensor.
|
||||
*/
|
||||
EXCLUDE_SENSORS = 0b0000_1000,
|
||||
/**
|
||||
* Exclude from the query any collider that is not a sensor.
|
||||
*/
|
||||
EXCLUDE_SOLIDS = 0b0001_0000,
|
||||
/**
|
||||
* Excludes all colliders not attached to a dynamic rigid-body.
|
||||
*/
|
||||
ONLY_DYNAMIC = QueryFilterFlags.EXCLUDE_FIXED |
|
||||
QueryFilterFlags.EXCLUDE_KINEMATIC,
|
||||
/**
|
||||
* Excludes all colliders not attached to a kinematic rigid-body.
|
||||
*/
|
||||
ONLY_KINEMATIC = QueryFilterFlags.EXCLUDE_DYNAMIC |
|
||||
QueryFilterFlags.EXCLUDE_FIXED,
|
||||
/**
|
||||
* Exclude all colliders attached to a non-fixed rigid-body
|
||||
* (this will not exclude colliders not attached to any rigid-body).
|
||||
*/
|
||||
ONLY_FIXED = QueryFilterFlags.EXCLUDE_DYNAMIC |
|
||||
QueryFilterFlags.EXCLUDE_KINEMATIC,
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import {RawSerializationPipeline} from "../raw";
|
||||
import {Vector, VectorOps} from "../math";
|
||||
import {
|
||||
IntegrationParameters,
|
||||
IslandManager,
|
||||
ImpulseJointSet,
|
||||
MultibodyJointSet,
|
||||
RigidBodySet,
|
||||
} from "../dynamics";
|
||||
import {BroadPhase, ColliderSet, NarrowPhase} from "../geometry";
|
||||
import {World} from "./world";
|
||||
|
||||
/**
|
||||
* A pipeline for serializing the physics scene.
|
||||
*
|
||||
* To avoid leaking WASM resources, this MUST be freed manually with `serializationPipeline.free()`
|
||||
* once you are done using it (and all the rigid-bodies it created).
|
||||
*/
|
||||
export class SerializationPipeline {
|
||||
raw: RawSerializationPipeline;
|
||||
|
||||
/**
|
||||
* Release the WASM memory occupied by this serialization pipeline.
|
||||
*/
|
||||
free() {
|
||||
if (!!this.raw) {
|
||||
this.raw.free();
|
||||
}
|
||||
this.raw = undefined;
|
||||
}
|
||||
|
||||
constructor(raw?: RawSerializationPipeline) {
|
||||
this.raw = raw || new RawSerializationPipeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a complete physics state into a single byte array.
|
||||
* @param gravity - The current gravity affecting the simulation.
|
||||
* @param integrationParameters - The integration parameters of the simulation.
|
||||
* @param broadPhase - The broad-phase of the simulation.
|
||||
* @param narrowPhase - The narrow-phase of the simulation.
|
||||
* @param bodies - The rigid-bodies taking part into the simulation.
|
||||
* @param colliders - The colliders taking part into the simulation.
|
||||
* @param impulseJoints - The impulse joints taking part into the simulation.
|
||||
* @param multibodyJoints - The multibody joints taking part into the simulation.
|
||||
*/
|
||||
public serializeAll(
|
||||
gravity: Vector,
|
||||
integrationParameters: IntegrationParameters,
|
||||
islands: IslandManager,
|
||||
broadPhase: BroadPhase,
|
||||
narrowPhase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
impulseJoints: ImpulseJointSet,
|
||||
multibodyJoints: MultibodyJointSet,
|
||||
): Uint8Array {
|
||||
let rawGra = VectorOps.intoRaw(gravity);
|
||||
|
||||
const res = this.raw.serializeAll(
|
||||
rawGra,
|
||||
integrationParameters.raw,
|
||||
islands.raw,
|
||||
broadPhase.raw,
|
||||
narrowPhase.raw,
|
||||
bodies.raw,
|
||||
colliders.raw,
|
||||
impulseJoints.raw,
|
||||
multibodyJoints.raw,
|
||||
);
|
||||
rawGra.free();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize the complete physics state from a single byte array.
|
||||
*
|
||||
* @param data - The byte array to deserialize.
|
||||
*/
|
||||
public deserializeAll(data: Uint8Array): World {
|
||||
return World.fromRaw(this.raw.deserializeAll(data));
|
||||
}
|
||||
}
|
||||
1260
packages/physics/rapier2d/src/pipeline/world.ts
Normal file
1260
packages/physics/rapier2d/src/pipeline/world.ts
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user